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

ctlopen.c

/*
 *    Copyright 1990 by Rayan S. Zachariassen, all rights reserved.
 *    This will be free software, but only when it is finished.
 */

/*
 *    Copyright 1994-2003 by Matti Aarnio
 *
 * To really understand how headers (and their converted versions)
 * are processed you do need to draw a diagram.
 * Basically:
 *    rp->desc->headers[]    is index to ALL of the headers, and
 *    rp->desc->headerscvt[] is index to ALL of the CONVERTED headers.
 * Elements on these arrays are  "char *strings[]" which are the
 * actual headers.
 * There are multiple-kind headers depending upon how they have been
 * rewritten, and those do tack together for each recipients (rp->)
 * There
 *    rp->newmsgheader    is a pointer to an element on  rp->desc->headers[]
 *    rp->newmsgheadercvt is respectively an elt on  rp->desc->headerscvt[]
 *
 * The routine-collection   mimeheaders.c  creates converted headers,
 * if the receiving system needs them. Converted data is created only
 * once per  rewrite-rule group, so there should not be messages which
 * report  "Received: ... convert XXXX convert XXXX convert XXXX; ..."
 * for as many times as there there are recipients for the message.
 * [mea@utu.fi] - 25-Jul-94
 */

#include "hostenv.h"
#include <ctype.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/wait.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include <sysexits.h>

#include "ta.h"

#include "mail.h"
#include "zmalloc.h"
#include "libz.h"
#include "libc.h"

#if defined(HAVE_MMAP)
#include <sys/mman.h>
#endif

#include <errno.h>

extern int errno;

#ifndef strrchr
extern char *strrchr();
#endif

static struct taddress *ctladdr __((struct ctldesc *d, char *cp));

int ta_use_mmap;


#ifndef     MAXPATHLEN
#define     MAXPATHLEN 1024
#endif      /* !MAXPATHLEN */


void
ctlfree(dp,anyp)
      struct ctldesc *dp;
      void *anyp;
{
      unsigned long lowlim  = (unsigned long) dp->contents;
      unsigned long highlim = (unsigned long)(((char*)lowlim) + dp->contentsize);
#if 0
      fprintf(stderr,"# ctlfree(%p) (%p,%p] @%p\n", anyp,
            lowlim, highlim, __builtin_return_address(0));
#endif
      if (anyp && (((unsigned long)anyp) < lowlim ||
                 ((unsigned long)anyp) >= highlim))
        free(anyp);     /* It isn't within DP->CONTENTS data.. */
}

void *
ctlrealloc(dp,anyp,size)
      struct ctldesc *dp;
      void *anyp;
      size_t size;
{
      void * lowlim  = (void *) dp->contents;
      void * highlim = (void *)(((char*)lowlim) + dp->contentsize);
      void *anyp2;
#if 0
      fprintf(stderr,"# ctlrealloc(%p,%lu) (%p,%p] @%p\n", anyp, size,
            lowlim, highlim, __builtin_return_address(0));
#endif
      /* If old one isn't our local thing, delete it! */
      if (anyp < lowlim || anyp >= highlim)
        return realloc(anyp, size); /* realloc(); it isn't within DP->CONTENTS data.. */

      /* Allocate a new storage.. */
      anyp2 = (void*) malloc(size);
      if (!anyp) return NULL;

      memcpy(anyp2,anyp,size);

      return anyp2;
}

void
ctlclose(dp)
      struct ctldesc *dp;
{
      struct taddress *ap;
      struct rcpt *rp;
      char ***msghpp;

      for (rp = dp->recipients; rp != NULL; rp = rp->next) {
        if (rp->lockoffset == 0)
          continue;
        diagnostic(NULL, rp, EX_TEMPFAIL, 0, "address was left locked!!");
      }
#ifdef HAVE_MMAP
      if (ta_use_mmap > 0) {
        if (dp->let_buffer != NULL)
          munmap((void*)dp->let_buffer, dp->let_end - dp->let_buffer);
        dp->let_buffer = dp->let_end = NULL;
        if (dp->ctlmap != NULL)
          munmap((void*)dp->ctlmap, dp->contentsize);
        dp->ctlmap = NULL;
      } else
#endif
        {
          if (dp->let_buffer_size)
            free((void*)(dp->let_buffer));
          dp->let_buffer = dp->let_end = NULL;
        }
      dp->let_buffer_size = 0;

      if (dp->ctlfd >= 0)
        close(dp->ctlfd);
      if (dp->msgfd >= 0)
        close(dp->msgfd);

      for (ap = dp->ta_chain; ap != NULL; ap = dp->ta_chain) {
        dp->ta_chain = ap->ta_next;
        free((char *)ap);
      }
      dp->ta_chain = dp->senders = NULL;

      for (rp = dp->rp_chain; rp != NULL; rp = dp->rp_chain) {
        dp->rp_chain = rp->rp_next;
        if (rp->top_received) free((void*)(rp->top_received));
        rp->top_received = NULL;
        if (rp->lockoffset) {
          fprintf(stdout, "# undiagnosed: %s %d\n", dp->msgfile, rp->id);
        }
        rp->lockoffset = 0;

        free((void *)rp);
      }
      dp->recipients = NULL;

      /* Free ALL dp->msgheader's, if they have been reallocated.
         Don't free on individual recipients, only on this global set.. */

      for (msghpp = dp->msgheaders; msghpp &&  *msghpp; ++msghpp) {
        char **msghp = *msghpp;
        for ( ; msghp && *msghp ; ++msghp )
          ctlfree(dp,*msghp);
        free(*msghpp);
      }
      free(dp->msgheaders);
      dp->msgheaders = NULL;

      for (msghpp = dp->msgheaderscvt; msghpp &&  *msghpp; ++msghpp) {
        char **msghp = *msghpp;
        for ( ; msghp && *msghp ; ++msghp )
          free(*msghp); /* These CVTs are always malloc()ed strings */
        free(*msghpp);
      }
      free(dp->msgheaderscvt);
      dp->msgheaderscvt = NULL;

      if (dp->offset != NULL)
        free((void*)dp->offset);
      dp->offset = NULL;

      if (dp->contents != NULL)
        free((void*)dp->contents);
      dp->contents = NULL;
      if (dp->taspoolid)
        free((void*)dp->taspoolid);
      dp->taspoolid = NULL;


      free( (void*) dp );

}


static void
free_last_ap(d)
      struct ctldesc *d; /* Chain in for latter free()ing */
{
      struct taddress *ap = d->ta_chain;
      d->ta_chain = ap->ta_next;
      ap->ta_next = NULL;
      free((void*)ap);
}

static struct taddress *
ctladdr(d,cp)
      struct ctldesc *d; /* Chain in for latter free()ing */
      char *cp;
{
      struct taddress *ap;

      ap = (struct taddress *)malloc(sizeof (struct taddress));
      if (ap == NULL)
            return NULL;
      ap->link = NULL;

      /* Link in the free-up chain */
      ap->ta_next = d->ta_chain;
      d->ta_chain = ap;

      /* While space: */
      while (*cp == ' ' || *cp == '\t') ++cp;

      /* CHANNEL: */
      ap->channel = cp;
      cp = skip821address(cp);
      if (*cp) *cp++ = '\0';

      /* While space: */
      while (*cp == ' ' || *cp == '\t') ++cp;

      /* HOST: */
      ap->host = cp;
      /* While not space: */
      cp = skip821address(cp);
      if (*cp) *cp++ = '\0';

      /* While space: */
      while (*cp == ' ' || *cp == '\t') ++cp;

      /* USER: */
      ap->user = cp;
      cp = skip821address(cp);
      if (*cp) *cp++ = '\0';

      /* PRIVILEGE: */
      ap->misc = cp;
      return ap;
}

#ifdef __STDC__

struct ctldesc *
ctlopen(const char *file, const char *channel, const char *host,
      int *exitflagp, int (*selectaddr)(const char *, const char *, void *),
      void *saparam)

#else

struct ctldesc *
ctlopen(file, channel, host, exitflagp, selectaddr, saparam)
      const char *file, *channel, *host;
      int *exitflagp;
      int (*selectaddr)  __((const char *, const char *, void *));
      void *saparam;
#endif
{
      register char *s, *contents;
      char *mfpath, *delayslot;
      int  i, n;
      struct taddress *ap;
      struct rcpt *rp = NULL, *prevrp = NULL;
      struct stat stbuf;
      char ***msgheaders = NULL;
      char ***msgheaderscvt = NULL;
      int  headers_cnt;
      int  headers_spc;
      int  largest_headersize = 80; /* Some magic minimum.. */
      char dirprefix[8];
      char spoolid[30];
      int  mypid = getpid();
      long format = 0;

      struct ctldesc *d;

      if (selectaddr == ctlsticky)
        ctlsticky(NULL,NULL,NULL); /* Reset the internal state.. */

      d = (struct ctldesc *)malloc(sizeof(*d));
      if (!d) return NULL;

      memset(d,0,sizeof(*d));

      if (*file >= 'A') {
        char *p;
        /* Has some hash subdirectory in front of itself */
        strncpy(dirprefix,file,sizeof(dirprefix));
        dirprefix[sizeof(dirprefix)-1] = 0;
        p = strrchr(dirprefix,'/');
        if (p) *++p = 0;
        /*  "A/B/"  */
      } else
        dirprefix[0] = 0;


      d->msgfd = -1; /* The zero is not always good for your health .. */
      d->ctlfd = open(file, O_RDWR, 0);
      if (d->ctlfd < 0) {
        char cwd[MAXPATHLEN], buf[MAXPATHLEN+MAXPATHLEN+100];
        int e = errno;  /* Save it over the getwd() */

#ifdef      HAVE_GETCWD
        getcwd(cwd,MAXPATHLEN);
#else
        getwd(cwd);
#endif
        sprintf(buf,
              "Cannot open control file \"%%s\" from \"%s\" for \"%%s/%%s\" as uid %d!",
              cwd, (int)geteuid());
        errno = e;
        if (host == NULL)
          host = "-";
        warning(buf, file, channel, host);
        ctlclose(d);
        return NULL;
      }
      if (fstat(d->ctlfd, &stbuf) < 0) {
        warning("Cannot stat control file \"%s\"! (%m)", file);
        ctlclose(d);
        return NULL;
      }
      if (!S_ISREG(stbuf.st_mode)) {
        warning("Control file \"%s\" is not a regular file!", file);
        close(d->ctlfd);
        return NULL;
      }
      /* 4 is the minimum number of characters per line */
      n = sizeof (long) * (stbuf.st_size / 4);
      d->contents = contents = s = malloc((u_int)stbuf.st_size+1);
      if (d->contents == NULL) {
        warning("Out of virtual memory!", (char *)NULL);
        exit(EX_SOFTWARE);
      }
      d->offset = (long *)malloc((u_int)n);
      if (d->offset == NULL) {
        warning("Out of virtual memory!", (char *)NULL);
        exit(EX_SOFTWARE);
      }

      fcntl(d->ctlfd, F_SETFD, 1); /* Close-on-exec */

#if defined(HAVE_MMAP)
      if (ta_use_mmap == 0) { /* uninitialized */
        const char *s = getzenv("TA_USE_MMAP");
        if (s && *s == '1')
          ta_use_mmap = 1;
        else
          ta_use_mmap = -1;
      }
      if (ta_use_mmap > 0) {
#ifndef MAP_VARIABLE
# define MAP_VARIABLE 0
#endif
#ifndef MAP_FILE
# define MAP_FILE 0
#endif
        /* We do recipient locking via MMAP_SHARED RD/WR !
           Less syscalls.. */
        d->ctlmap = (char *)mmap(NULL, stbuf.st_size,
                           PROT_READ|PROT_WRITE,
                           MAP_FILE|MAP_SHARED|MAP_VARIABLE,
                           d->ctlfd, 0);
        if ((int)d->ctlmap == -1)
          d->ctlmap = NULL; /* Failed ?? */
      }
#else
      d->ctlmap = NULL;
#endif
      d->contentsize = (int) stbuf.st_size;
      contents[ d->contentsize ] = 0; /* Treat it as a long string.. */
      if (read(d->ctlfd, contents, d->contentsize) != d->contentsize) {
        warning("Wrong size read from control file \"%s\"! (%m)",
              file);
        ctlclose(d);
        return NULL;
      }
      n = markoff(contents, d->contentsize, d->offset, file);
      if (n < 4) {
        int was_turnme = (contents[0] == _CF_TURNME);
        /*
         * If it is less than the minimum possible number of control
         * lines, then there is something wrong...
         */
        ctlclose(d);

        /* Is it perhaps just the ETRN request file ?
           and manual expirer gave it to us ?  Never mind then.. */
        if (was_turnme) return NULL;

        warning("Truncated or illegal control file \"%s\"!", file);
        /* exit(EX_PROTOCOL); */
        sleep(60);
        return NULL;
      }

      s = strrchr(file,'/');  /* In case the file in in a subdir.. */
      if (s)
        d->ctlid = atol(s+1);
      else
        d->ctlid = atol(file);
      d->senders = NULL;
      d->recipients = NULL;
      d->ta_chain   = NULL;
      d->rp_chain   = NULL;
      d->rcpnts_total = 0;
      d->rcpnts_remaining = 0;
      d->rcpnts_failed = 0;
      d->logident   = "none";
      d->envid      = NULL;
      d->dsnretmode = NULL;
      d->verbose    = NULL;

      headers_cnt = 0;
      headers_spc = 2;
      for (i = 0; i < n; ++i)
        if (contents[ d->offset[i] ] == _CF_MSGHEADERS)
          ++headers_spc;

      msgheaders = (char***)malloc(sizeof(char***) *
                             (headers_spc+1));
      msgheaderscvt = (char***)malloc(sizeof(char***) *
                              (headers_spc+1));

      d->msgheaders    = msgheaders;            /* Original headers     */
      d->msgheaderscvt = msgheaderscvt;   /* Modified set         */


      /* run through the file and set up the information we need */
      for (i = 0; i < n; ++i) {
        if (*exitflagp && d->recipients == NULL)
          break;
        /* Shudder... we trash the memory block here.. */
        s = contents + d->offset[i];

        switch (*s) {
        case _CF_FORMAT:
          ++s;
          format = 0;
          sscanf(s,"%li",&format);
          if (format & (~_CF_FORMAT_KNOWN_SET)) {
            warning("Unsupported SCHEDULER file format flags seen: 0x%x at file '%s'",
                  format, file);
            *exitflagp = 1;
            break;
          }
          break;

        case _CF_SENDER:
          ap = ctladdr(d,s+2);
          if (ap == NULL) {
            warning("Out of virtual memory!", (char *)NULL);
            *exitflagp = 1;
            break;
          }
          ap->link  = d->senders;
          /* Test if this is "error"-channel..
             If it is,  ap->user  points to NUL string. */
          /* mea: altered the scheme, we must detect the "error" channel
             otherwise */
          /* if (strcmp(ap->channel,"error")==0)
               ap->user = ""; */
          d->senders = ap;
          break;

        case _CF_RECIPIENT:
          ++s;
          /* Calculate statistics .. Scheduler asks for it.. */
          d->rcpnts_total += 1;
          if (*s == _CFTAG_NOTOK) {
            d->rcpnts_failed    += 1;
            prevrp = NULL;
          } else if (*s != _CFTAG_OK) {
            d->rcpnts_remaining += 1;
          }

          if (*s != _CFTAG_NORMAL || d->senders == NULL)
            break;

          ++s;
          /* Unconditionally expecting _CF_FORMAT_TA_PID !! */
          s += _CFTAG_RCPTPIDSIZE;
          delayslot = NULL;
          if ((format & _CF_FORMAT_DELAY1) || *s == ' ' ||
            (*s >= '0' && *s <= '9')) {
            /* Newer DELAY data slot - _CFTAG_RCPTDELAYSIZE bytes */
            delayslot = s;
            s += _CFTAG_RCPTDELAYSIZE;
          }
          ap = ctladdr(d,s);
          if (ap == NULL) {
            warning("Out of virtual memory!", (char *)NULL);
            *exitflagp = 1;
            break;
          }

          if ((channel != NULL  &&  strcmp(channel, ap->channel) != 0)
            || (selectaddr != NULL
                && !(*selectaddr)(host, (const char *)ap->host, saparam))
            || (selectaddr == NULL
                && host != NULL && cistrcmp(host,ap->host) !=0)
            || !lockaddr(d->ctlfd, d->ctlmap, d->offset[i]+1,
                       _CFTAG_NORMAL, _CFTAG_LOCK, file, host, mypid)) {
            free_last_ap(d);
            break;
          }
          ap->link = d->senders; /* point at sender address */
          rp = (struct rcpt *)malloc(sizeof (struct rcpt));
          if (rp == NULL) {
            lockaddr(d->ctlfd, d->ctlmap, d->offset[i]+1,
                   _CFTAG_LOCK, _CFTAG_DEFER, file, host, mypid);
            warning("Out of virtual memory!", (char *)NULL);
            *exitflagp = 1;
            free_last_ap(d);
            break;
          }
          memset(rp, 0, sizeof(*rp));
          rp->rp_next = d->rp_chain;
          d->rp_chain = rp;

          rp->addr = ap;
          rp->delayslot = delayslot;
          rp->id = d->offset[i];
          /* XX: XOR locks are different */
          rp->lockoffset = rp->id + 1;
          rp->next = d->recipients;
          rp->desc = d;
          /* rp->orcpt  = NULL;
             rp->inrcpt = NULL;
             rp->ezmlm  = NULL;
             rp->notify = NULL; */
          rp->notifyflgs = _DSN_NOTIFY_FAILURE; /* Default behaviour */
          d->recipients = rp;
          rp->status = EX_OK;
          /* rp->newmsgheader = NULL; */
          rp->drptoffset   = -1;
          rp->headeroffset = -1;
          prevrp = rp;
          break;

        case _CF_RCPTNOTARY:
          /*  IETF-NOTARY-DSN  DATA */
          ++s;
          if (prevrp != NULL) {
            prevrp->drptoffset = d->offset[i];
            while (*s) {
            while (*s && (*s == ' ' || *s == '\t')) ++s;
            if (CISTREQN("NOTIFY=",s,7)) {
              char *p;
              s += 7;
              prevrp->notify = p = s;
              while (*s && *s != ' ' && *s != '\t') ++s;
              if (*s) *s++ = 0;
              prevrp->notifyflgs = 0;
              while (*p) {
                if (CISTREQN("NEVER",p,5)) {
                  p += 5;
                  prevrp->notifyflgs |= _DSN_NOTIFY_NEVER;
                } else if (CISTREQN("DELAY",p,5)) {
                  p += 5;
                  prevrp->notifyflgs |= _DSN_NOTIFY_DELAY;
                } else if (CISTREQN("SUCCESS",p,7)) {
                  p += 7;
                  prevrp->notifyflgs |= _DSN_NOTIFY_SUCCESS;
                } else if (CISTREQN("FAILURE",p,7)) {
                  p += 7;
                  prevrp->notifyflgs |= _DSN_NOTIFY_FAILURE;
                } else if (CISTREQN("TRACE",p,5)) {
                  p += 5;
                  prevrp->notifyflgs |= _DSN_NOTIFY_TRACE;
                } else
                  break; /* Burp !? */
                if (*p == ',') ++p;
              }
              continue;
            }
            if (CISTREQN("BY=",s,3)) {
              long val = 0;
              int  neg = 0, cnt = 0;
              s += 3;
              if (*s == '-') neg = 1, ++s;
              while ('0' <= *s && *s <= '9') {
                val = val * 10L + (*s - '0');
                ++cnt;
                ++s;
              }
              if (neg) val = -val;
              prevrp->deliverby = val;
              if (*s == ';') ++s;
              while (*s && *s != ' ' && *s != '\t') {
                switch (*s) {
                case 'R': case 'r':
                  prevrp->deliverbyflgs |= _DELIVERBY_R;
                  break;
                case 'N': case 'n':
                  prevrp->deliverbyflgs |= _DELIVERBY_N;
                  break;
                case 'T': case 't':
                  prevrp->deliverbyflgs |= _DELIVERBY_T;
                  break;
                default:
                  break;
                }
                ++s;
              }
              while (*s && *s != ' ' && *s != '\t') ++s;
              if (*s) *s++ = 0;
              continue;
            }
            if (CISTREQN("ORCPT=",s,6)) {
              s += 6;
              prevrp->orcpt = s;
              while (*s && *s != ' ' && *s != '\t') ++s;
              if (*s) *s++ = 0;
              continue;
            }
            if (CISTREQN("INRCPT=",s,7)) {
              s += 7;
              prevrp->inrcpt = s;
              while (*s && *s != ' ' && *s != '\t') ++s;
              if (*s) *s++ = 0;
              continue;
            }
            if (CISTREQN("INFROM=",s,7)) {
              s += 7;
              prevrp->infrom = s;
              while (*s && *s != ' ' && *s != '\t') ++s;
              if (*s) *s++ = 0;
              continue;
            }
            if (CISTREQN("EZMLM=",s,6)) {
              s += 6;
              prevrp->ezmlm = s;
              while (*s && *s != ' ' && *s != '\t') ++s;
              if (*s) *s++ = 0;
              continue;
            }
            /* XX: BOO! Unknown value! */
            while (*s && *s != ' ' && *s != '\t') ++s;
            }
            /* Previous entry added, no more..! */
            prevrp = NULL;
          }
          break;

        case _CF_MSGHEADERS:
          {
            char **msgheader = NULL;
            char *ss;
            int  headerlines = 0;
            int  headerspace = 0;
            int  headersize  = strlen(s);

            if (headersize > largest_headersize)
            largest_headersize = headersize;
            /* position pointer at start of the header */
            while (*s && *s != '\n')
            ++s;
            ++s;

            /* Collect all the headers into individual "lines",
             keep folding information ('\n' chars) in them,
             if some particular header happens to be a folded one.. */

            while (*s) {
            if (headerlines >= headerspace) {
              headerspace += 8;
              msgheader = (char**)realloc((void*) msgheader,
                                    sizeof(void*) * (headerspace+1));
            }
            ss = s;
            /* Scan the string, until we see a newline *not* followed
               by a SPACE, or a TAB. */
            while (*ss) {
              while (*ss && *ss != '\n') ++ss;
              if (*ss == '\n' && (ss[1] == ' ' || ss[1] == '\t'))
                ++ss;
              else
                break;
            }
            if (*ss == '\n') *ss++ = '\0';
            msgheader[headerlines++] = s;
            msgheader[headerlines  ] = NULL;
            s = ss;
            }

            /* And the global connection.. */
            msgheaders   [headers_cnt] = msgheader;
            msgheaderscvt[headers_cnt] = NULL;

            /* fill in header * of recent recipients */
            for (rp = d->recipients;
               rp != NULL && rp->newmsgheader == NULL;
               rp = rp->next) {
            rp->newmsgheader    = &msgheaders   [headers_cnt];
            rp->newmsgheadercvt = &msgheaderscvt[headers_cnt];
            rp->headeroffset    = d->offset[i] + 2;
            }

            msgheaders   [++headers_cnt] = NULL;
            msgheaderscvt[  headers_cnt] = NULL;
          }
          break;
        case _CF_MESSAGEID:
          d->msgfile = s+2;
          break;
        case _CF_DSNENVID:
          d->envid = s+2;
          break;
        case _CF_DSNRETMODE:
          d->dsnretmode = s+2;
          break;
        case _CF_BODYOFFSET:
          d->msgbodyoffset = (long)atoi(s+2);
          break;
        case _CF_LOGIDENT:
          d->logident = s+2;
          break;
        case _CF_VERBOSE:
          d->verbose = s+2;
          break;
        default:        /* We don't use them all... */
          break;
        }
      }

      /* Sometimes we bail out before terminating NULLs are added->.
         probably before anything is added-> */
      msgheaders   [headers_cnt] = NULL;
      msgheaderscvt[headers_cnt] = NULL;

      if (d->recipients == NULL) {
        ctlclose(d);
        return NULL;
      }

#ifdef USE_ALLOCA
      mfpath = alloca((u_int)5 + sizeof(QUEUEDIR)
                  + strlen(dirprefix) + strlen(d->msgfile));
#else
      mfpath = malloc((u_int)5 + sizeof(QUEUEDIR)
                  + strlen(dirprefix) + strlen(d->msgfile));
#endif
      sprintf(mfpath, "../%s/%s%s", QUEUEDIR, dirprefix, d->msgfile);
      if ((d->msgfd = open(mfpath, O_RDONLY, 0)) < 0) {
        int e = errno;
        for (rp = d->recipients; rp != NULL; rp = rp->next) {
          diagnostic(NULL, rp, EX_UNAVAILABLE, 0,
                   "message file is missing(!) -- possibly due to delivery scheduler restart.  Consider resending your message");
        }
        errno = e;
        warning("Cannot open message file \"%s\"! (errno=%d)", mfpath, errno);
#ifndef USE_ALLOCA
        free(mfpath);
#endif
        ctlclose(d);
        return NULL;
      }
      if (fstat(d->msgfd,&stbuf) < 0) {
        stbuf.st_mode = S_IFCHR; /* Make it to be something what it
                              clearly can't be.. */
      }
      if (!S_ISREG(stbuf.st_mode)) {
        for (rp = d->recipients; rp != NULL; rp = rp->next) {
          diagnostic(NULL, rp, EX_UNAVAILABLE, 0,
                   "Message file is not a regular file!");
        }
        warning("Cannot open message file \"%s\"! (%m)", mfpath);
#ifndef USE_ALLOCA
        free(mfpath);
#endif
        ctlclose(d);
        return NULL;
      }

      d->msginonumber = (long)stbuf.st_ino;

      fcntl(d->msgfd, F_SETFD, 1); /* Close-on-exec */

#if defined(HAVE_MMAP)
      if (ta_use_mmap > 0) {
        d->let_buffer = (char *)mmap(NULL, stbuf.st_size, PROT_READ,
                               MAP_FILE|MAP_SHARED|MAP_VARIABLE,
                               d->msgfd, 0);
        if ((long)d->let_buffer == -1L) {
          warning("Out of MMAP() memory! Tried to map in (r/o) %d bytes (%m)",
                stbuf.st_size);
#ifndef USE_ALLOCA
          free(mfpath);
#endif
          ctlclose(d);
          return NULL;
        }
        d->let_end    = d->let_buffer + stbuf.st_size;
        d->let_buffer_size = 0;
      } else
#endif
        {
          d->let_buffer_size = 63*1024;
          d->let_buffer      = malloc(d->let_buffer_size + 8);
          d->let_end         = d->let_buffer + d->let_buffer_size;
        }

#ifndef USE_ALLOCA
      free(mfpath);
#endif

      /* The message file mtime -- arrival of the message to the system */
      d->msgmtime = stbuf.st_mtime;

      /* Estimate the size of the message file when sent out.. */
      d->msgsizeestimate  = stbuf.st_size - d->msgbodyoffset;
      d->msgsizeestimate += largest_headersize;
      /* A nice fudge factor, usually this is enough..                 */
      /* Add 3% for CRLFs.. -- assume average line length of 35 chars. */
      d->msgsizeestimate += (3 * d->msgsizeestimate) / 100;

      taspoolid(spoolid, d->msgmtime, d->msginonumber);
      d->taspoolid = strdup(spoolid);
      if (!d->taspoolid) {
        ctlclose(d);
        return NULL;
      }

      return d;
}

int
ctlsticky(spec_host, addr_host, cbparam)
      const char *spec_host, *addr_host;
      void *cbparam;
{
      static const char *hostref = NULL;

      if (hostref == NULL) {
        if (spec_host != NULL)
          hostref = spec_host;
        else
          hostref = addr_host;
      }
      if (spec_host == NULL && addr_host == NULL) {
        hostref = NULL;
        return 0;
      }
      return cistrcmp(hostref, addr_host) == 0;
}

Generated by  Doxygen 1.6.0   Back to index