Logo Search packages:      
Sourcecode: mailavenger version File versions  Download package

copymsg.c

/* $Id$ */

/*
 *
 * Copyright (C) 2004 David Mazieres (dm@uun.org)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "local.h"
#include <ctype.h>

enum { maxbuf = 1024 * 1024 };

const char *opt_tmplate = "/tmp/msg.XXXXXXXXXX";
const char *opt_from;
const char *opt_recip;
char *msg_ufline;
char *msg_rpline;
char *msg_dtline;

static const char delto[] = "Delivered-To: ";

void
initfile (char **path, int *wfd, int *rfd, struct stat *sbp)
{
  mode_t m = umask (077);
  *path = xmalloc (strlen (opt_tmplate) + 1);
  for (;;) {
    strcpy (*path, opt_tmplate);
    *wfd = mkstemp (*path);
    if (*wfd < 0) {
      perror (*path);
      exit (EX_OSERR);
    }
    *rfd = open (*path, O_RDONLY);
    if (*rfd >= 0) {
      struct stat sb1, sb2;
      if (fstat (*wfd, &sb1) || fstat (*rfd, &sb2)) {
      perror (*path);
      exit (EX_OSERR);
      }
      if (sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino) {
      if (sbp)
        *sbp = sb1;
      umask (m);
      return;
      }
    }
    fprintf (stderr, "%s: file %s changed while opening\n", progname, *path);
    close (*rfd);
    close (*wfd);
  }
}

void
set_msgvars (struct lnbuf *bufp, FILE *in)
{
  time_t tm = time (NULL);
  char *date = ctime (&tm);
  const char *from;
  int size, res;

  if (bufp) {
    if (readln (bufp, in, maxbuf) != LNBUF_OK)
      exit (EX_DATAERR);
    if (!strncmp (bufp->buf, "From ", 5)) {
      if (!opt_from) {
      char *f1 = bufp->buf + 5, *f2;
      for (f2 = f1; *f2 && !isspace (*f2); f2++)
        ;
      if (f2 > f1) {
        *f2 = '\0';
        opt_from = strcpy (xmalloc (f2 - f1 + 1), f1);
      }
      }
      bufp->size = 0;
      if (readln (bufp, in, maxbuf) != LNBUF_OK)
      exit (EX_DATAERR);
    }

    if (!strncasecmp (bufp->buf, "Return-Path:", 12)) {
      if (!opt_from) {
      char *f1 = bufp->buf + 12, *f2 = bufp->buf + bufp->size;
      while (isspace (*f1))
        f1++;
      if (*f1++ == '<') {
        while (f2 > f1 && *--f2 != '>')
          ;
        if (f2 > f1) {
          *f2 = '\0';
          opt_from = strcpy (xmalloc (f2 - f1 + 1), f1);
          bufp->size = 0;
        }
      }
      }
      else
      bufp->size = 0;
    }
  }

  from = opt_from;
  size = strlen (date);
  if (size > 0 && date[size - 1] == '\n')
    date[size - 1] = '\0';
  if (!from || !*from || !strcmp (opt_from, "@"))
    from = "MAILER-DAEMON";
  size = 8 + strlen (from) + strlen (date);
  msg_ufline = xmalloc (size);
  res = sprintf (msg_ufline, "From %s  %s", from, date);
  assert (res + 1 == size);

  if (!strcmp (from, "MAILER-DAEMON"))
    from = "";
  msg_rpline = xmalloc (sizeof ("Return-Path: <>") + strlen (from));
  sprintf (msg_rpline, "Return-Path: <%s>", from);

  if (opt_recip) {
    msg_dtline = xmalloc (sizeof (delto) + strlen (opt_recip));
    sprintf (msg_dtline, "%s%s", delto, opt_recip);
  }
}

int
nocopymsg (FILE *in)
{
  struct lnbuf buf;
  long skip;

  off_t pos = lseek (fileno (in), 0, SEEK_CUR);
  if (pos == -1)
    return -1;

  bzero (&buf, sizeof (buf));

  set_msgvars (&buf, in);
  skip = ftell (in);
  if (skip < 0) {
    perror ("ftell");
    exit (EX_OSERR);
  }
  assert (buf.size <= (unsigned long) skip);
  if (lseek (fileno (in), skip - buf.size, SEEK_SET) == -1) {
    perror ("re-lseek");
    exit (EX_OSERR);
  }
  free (buf.buf);
  return 0;
}

void
copymsg (int outfd, FILE *in)
{
  struct lnbuf buf;
  FILE *out = fdopen (dup (outfd), "w");
  int in_headers = 1, rl_res = 1, last_size = 1;

  if (!out) {
    perror ("fdopen");
    exit (EX_OSERR);
  }
  bzero (&buf, sizeof (buf));

  set_msgvars (&buf, in);
  if (msg_dtline && fprintf (out, "%s\n", msg_dtline) < 0) {
    perror ("write");
    exit (EX_OSERR);
  }

  while (rl_res) {
#if 0
    if (rl_res != LNBUF_TOOBIG && buf.size >= 5
      && !strncmp (buf.buf, "From ", 5))
      fprintf (out, ">");
#endif
    if (buf.size && fwrite (buf.buf, 1, buf.size, out) != buf.size) {
      perror ("write");
      exit (EX_OSERR);
    }
    switch (rl_res) {
    case LNBUF_EOFNL:
      fprintf (out, "\n");
      break;
    case LNBUF_NOMEM:
      fprintf (stderr, "out of memory reading header line\n");
      exit (EX_OSERR);
      break;
    case LNBUF_TOOBIG:
      if (in_headers) {
      fprintf (stderr, "line too long in header\n");
      exit (EX_DATAERR);
      }
      break;
    case LNBUF_IOERR:
      fprintf (stderr, "Error reading message\n");
      exit (EX_OSERR);
      break;
    }
    if (in_headers) {
      if (buf.size == 1)
      in_headers = 0;
      else if (opt_recip
             && !strncasecmp (delto, buf.buf, sizeof (delto) - 1)) {
      char *ap = buf.buf + sizeof (delto) - 1;
      char *addr = strnnsep (&ap, " \t\r\n");
      if (addr && !strcmp (addr, opt_recip)) {
        fprintf (stderr, "message already delivered to %s; possible loop\n",
               opt_recip);
        exit (EX_SOFTWARE);
      }
      }
    }
    last_size = buf.size;
    rl_res = readln (&buf, in, maxbuf);
  }
#if 0
  if (last_size != 1)
    fprintf (out, "\n");
#endif

  fclose (out);
  free (buf.buf);
}


Generated by  Doxygen 1.6.0   Back to index