home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / queue.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-24  |  28.4 KB  |  1,381 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #include "sendmail.h"
  22.  
  23. #ifndef lint
  24. # ifdef QUEUE
  25. static char sccsid[] = "@(#)queue.c    5.30 (Berkeley) 6/1/90 (with queueing)";
  26. static char  rcsid[] = "@(#)$Id: queue.c,v 5.30.0.28 1991/06/24 14:26:25 paul Exp $ (with queueing)";
  27. # else /* !QUEUE */
  28. static char sccsid[] = "@(#)queue.c    5.30 (Berkeley) 6/1/90 (without queueing)";
  29. static char  rcsid[] = "@(#)$Id: queue.c,v 5.30.0.28 1991/06/24 14:26:25 paul Exp $ (without queueing)";
  30. # endif /* QUEUE */
  31. #endif /* not lint */
  32.  
  33. #include <sys/stat.h>
  34. #ifndef direct
  35. # include <sys/dir.h>
  36. #endif /* !direct */
  37. #include <errno.h>
  38. #ifdef ISC
  39. # include <net/errno.h>
  40. #endif /* ISC */
  41. #include <pwd.h>
  42.  
  43. #ifdef __STDC__
  44. static char * getctluser(ADDRESS *);
  45. static void setctluser(const char *);
  46. #else /* !__STDC__ */
  47. static char * getctluser();
  48. static void setctluser();
  49. #endif /* __STDC__ */
  50. static void clrctluser();
  51.  
  52. #ifdef QUEUE
  53.  
  54. /*
  55. **  Work queue.
  56. */
  57.  
  58. struct work
  59. {
  60.     char        *w_name;    /* name of control file */
  61.     long        w_pri;        /* priority of message, see below */
  62.     TIME_TYPE    w_ctime;    /* creation time of message */
  63.     struct work    *w_next;    /* next in queue */
  64. };
  65.  
  66. typedef struct work    WORK;
  67. extern int la;
  68.  
  69. WORK    *WorkQ;            /* queue of things to be done */
  70.  
  71. # ifdef __STDC__
  72. static int orderq(int);
  73. static int workcmpf(const WORK *, const WORK *);
  74. static void dowork(WORK *);
  75. static FILE * readqf(ENVELOPE *, int);
  76. # else /* !__STDC__ */
  77. static int orderq();
  78. static int workcmpf();
  79. static void dowork();
  80. static FILE * readqf();
  81. # endif /* __STDC__ */
  82. /*
  83. **  QUEUEUP -- queue a message up for future transmission.
  84. **
  85. **    Parameters:
  86. **        e -- the envelope to queue up.
  87. **        queueall -- if TRUE, queue all addresses, rather than
  88. **            just those with the QQUEUEUP flag set.
  89. **        announce -- if TRUE, tell when you are queueing up.
  90. **
  91. **    Returns:
  92. **        locked FILE* to q file
  93. **
  94. **    Side Effects:
  95. **        The current request are saved in a control file.
  96. */
  97.  
  98. FILE *
  99. queueup(e, queueall, announce)
  100.     register ENVELOPE *e;
  101.     bool queueall;
  102.     bool announce;
  103. {
  104.     char *qf;
  105.     char buf[MAXLINE], tf[MAXLINE];
  106.     register FILE *tfp;
  107.     register HDR *h;
  108.     register ADDRESS *q;
  109.     MAILER nullmailer;
  110.     int fd;
  111.     char *macSvalue = macvalue('s', e);
  112.     char *OrigUser = NULL;        /* Alias user list expanded from */
  113.  
  114.     /*
  115.     **  Create control file.
  116.     */
  117.  
  118.     do {
  119.         (void) strcpy(tf, queuename(e, 't'));
  120.         fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
  121.         if (fd < 0)
  122.         {
  123.             if ( errno != EEXIST)
  124.             {
  125.                 syserr("queueup: cannot create temp file %s",
  126.                     tf);
  127.                 return NULL;
  128.             }
  129.             else
  130.             {
  131.                 syserr("queueup: temp file %s exists, sleeping",
  132.                     tf);
  133.                 Xsleep(30);
  134.             }
  135.         }
  136.         else
  137.         {
  138.             if (flock(fd, LOCK_EX|LOCK_NB) < 0)
  139.             {
  140.                 if (errno != EWOULDBLOCK && errno != EAGAIN)
  141.                     syserr("cannot flock(%s)", tf);
  142.                 close(fd);
  143.                 fd = -1;
  144.                 Xsleep(1);
  145.             }
  146.         }
  147.     } while (fd < 0);
  148.  
  149.     if ((tfp = fdopen(fd, "w")) == NULL)
  150.         syserr("cannot fdopen(%s)", tf);
  151.     if (tTd(40, 1))
  152.         printf("queueing %s\n", e->e_id);
  153.  
  154.     /*
  155.     **  If there is no data file yet, create one.
  156.     */
  157.  
  158.     if (e->e_df == NULL)
  159.     {
  160.         register FILE *dfp;
  161.  
  162.         e->e_df = newstr(queuename(e, 'd'));
  163. #if defined(O_SYNC)
  164.         if (SuperSafe)
  165.             fd = open(e->e_df, O_WRONLY|O_CREAT|O_SYNC, FileMode);
  166.         else
  167. #endif /* O_SYNC */
  168.         fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode);
  169.         if (fd < 0)
  170.         {
  171.             syserr("queueup: cannot create %s", e->e_df);
  172.             (void) fclose(tfp);
  173.             (void) unlink(tf);
  174.             return NULL;
  175.         }
  176.         if ((dfp = fdopen(fd, "w")) == NULL)
  177.             syserr("cannot fdopen(%s)", e->e_df);
  178.  
  179.         (*e->e_putbody)(dfp, ProgMailer, e);
  180.         (void) fflush(dfp);
  181. #if !defined(O_SYNC)
  182.         if (SuperSafe)
  183.             (void) fsync(fileno(dfp));
  184. #endif /* !O_SYNC */
  185.         (void) fclose(dfp);
  186.         e->e_putbody = putbody;
  187.     }
  188.  
  189.     /*
  190.     **  Output future work requests.
  191.     **    Priority and creation time should be first, since
  192.     **    they are required by orderq.
  193.     */
  194.  
  195.     /* output message priority */
  196.     fprintf(tfp, "P%ld\n", e->e_msgpriority);
  197.  
  198.     /* output creation time */
  199.     fprintf(tfp, "T%ld\n", e->e_ctime);
  200.  
  201.     /* output name of data file */
  202.     fprintf(tfp, "D%s\n", e->e_df);
  203.  
  204.     /* message from envelope, if it exists */
  205.     if (e->e_message != NULL)
  206.         fprintf(tfp, "M%s\n", e->e_message);
  207.  
  208. # ifdef QUEUE_MACVALUE /* Save some macro values in the queue file */
  209.     {
  210.         char *p, *q;
  211.  
  212.         for (p = "rs"; *p; p++)
  213.         {
  214.             q = macvalue(*p, e);
  215.             if (q != NULL && *q)
  216.                 fprintf(tfp, "%c%c%s\n", QUEUE_MACVALUE, *p, q);
  217.         }
  218.     }
  219. # endif /* QUEUE_MACVALUE */
  220.  
  221.     /* output name of sender */
  222.     fprintf(tfp, "S%s\n", e->e_from.q_paddr);
  223.  
  224.     /* output list of recipient addresses */
  225.     for (q = e->e_sendqueue; q != NULL; q = q->q_next)
  226.     {
  227.         if (queueall ? !bitset(QDONTSEND, q->q_flags) :
  228.                    bitset(QQUEUEUP, q->q_flags))
  229.         {
  230.             char *ctluser;
  231.  
  232.             if ((ctluser = getctluser(q)) != NULL)
  233.                 fprintf(tfp, "C%s\n", ctluser);
  234.             fprintf(tfp, "R%s\n", q->q_paddr);
  235.             if (announce)
  236.             {
  237.                 e->e_to = q->q_paddr;
  238.                 message(Arpa_Info, "queued");
  239.                 if (LogLevel > 4)
  240.                     logdelivery(NULL, "queued");
  241.                 e->e_to = NULL;
  242.             }
  243.             if (tTd(40, 1))
  244.             {
  245.                 printf("queueing ");
  246.                 printaddr(q, FALSE);
  247.             }
  248.             if (OrigUser != MACNULL)
  249.             {
  250.                 register ADDRESS *qq;
  251.  
  252.                 qq = q;
  253.                 while (qq->q_alias != NULL)
  254.                     qq = qq->q_alias;
  255.                 if (OrigUser != NULL && OrigUser != qq->q_paddr)
  256.                     OrigUser = MACNULL;
  257.                 else
  258.                     OrigUser = qq->q_paddr;
  259.             }
  260.         }
  261.     }
  262.  
  263.     /* output list of error recipients */
  264.     for (q = e->e_errorqueue; q != NULL; q = q->q_next)
  265.     {
  266.         if (!bitset(QDONTSEND, q->q_flags))
  267.         {
  268.             char *ctluser;
  269.  
  270.             if ((ctluser = getctluser(q)) != NULL)
  271.                 fprintf(tfp, "C%s\n", ctluser);
  272.             fprintf(tfp, "E%s\n", q->q_paddr);
  273.         }
  274.     }
  275.  
  276.     /*
  277.     **  Output headers for this message.
  278.     **    Expand macros completely here.  Queue run will deal with
  279.     **    everything as absolute headers.
  280.     **        All headers that must be relative to the recipient
  281.     **        can be cracked later.
  282.     **    We set up a "null mailer" -- i.e., a mailer that will have
  283.     **    no effect on the addresses as they are output.
  284.     */
  285.  
  286.     bzero((char *) &nullmailer, sizeof nullmailer);
  287.     nullmailer.m_re_rwset = nullmailer.m_se_rwset = -1;
  288.     nullmailer.m_rh_rwset = nullmailer.m_sh_rwset = -1;
  289.     nullmailer.m_eol = "\n";
  290.  
  291.     define('g', "\001f", e);
  292.     define('m', OrigUser, e);
  293.     for (h = e->e_header; h != NULL; h = h->h_link)
  294.     {
  295.         /* don't output null headers */
  296.         if (h->h_value == NULL || h->h_value[0] == '\0')
  297.             continue;
  298.  
  299.         /* don't output resent headers on non-resent messages */
  300.         if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
  301.             continue;
  302.  
  303.         /* output this header */
  304.         fprintf(tfp, "H");
  305.  
  306.         /* if conditional, output the set of conditions */
  307.         if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
  308.         {
  309.             int j;
  310.  
  311.             (void) putc('?', tfp);
  312.             for (j = '\0'; j <= '\177'; j++)
  313.                 if (bitnset(j, h->h_mflags))
  314.                     (void) putc(j, tfp);
  315.             (void) putc('?', tfp);
  316.         }
  317.  
  318.         /* output the header: expand macros, convert addresses */
  319.         if (bitset(H_DEFAULT, h->h_flags))
  320.         {
  321.             /*
  322.              * Use DeclHostName in headers that aren't H_RCPT
  323.              * or H_FROM.  Restore the original value after the
  324.              * expand().
  325.              */
  326.             if (!bitset(H_RCPT|H_FROM, h->h_flags) && DeclHostName)
  327.                 define('s', DeclHostName, e);
  328.             (void) expand(h->h_value, buf, &buf[(sizeof(buf)-1)], e);
  329.             fprintf(tfp, "%s: %s\n", h->h_field, buf);
  330.             if (!bitset(H_RCPT|H_FROM, h->h_flags) && DeclHostName)
  331.                 define('s', macSvalue, e);
  332.         }
  333.         else if (bitset(H_FROM|H_RCPT, h->h_flags))
  334.         {
  335.             commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),
  336.                  &nullmailer);
  337.         }
  338.         else
  339.             fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
  340.     }
  341.  
  342.     /*
  343.     **  Clean up.
  344.     */
  345.  
  346.     qf = queuename(e, 'q');
  347. #ifdef LACK_RENAME
  348.     (void) unlink(qf);
  349.     if (link(tf, qf) < 0)
  350.         syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df);
  351.     (void) unlink(tf);
  352. #else /* !LACK_RENAME */
  353.     if (rename(tf, qf) < 0)
  354.         syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df);
  355. #endif /* LACK_RENAME */
  356.     errno = 0;
  357.  
  358. # ifdef LOG
  359.     /* save log info */
  360.     if (LogLevel > 15)
  361.         syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s", e->e_id, qf, e->e_df);
  362. # endif /* LOG */
  363.     (void) fflush(tfp);
  364.     return tfp;
  365. }
  366. /*
  367. **  RUNQUEUE -- run the jobs in the queue.
  368. **
  369. **    Gets the stuff out of the queue in some presumably logical
  370. **    order and processes them.
  371. **
  372. **    Parameters:
  373. **        forkflag -- TRUE if the queue scanning should be done in
  374. **            a child process.  We double-fork so it is not our
  375. **            child and we don't have to clean up after it.
  376. **
  377. **    Returns:
  378. **        none.
  379. **
  380. **    Side Effects:
  381. **        runs things in the mail queue.
  382. */
  383.  
  384. void
  385. runqueue(forkflag)
  386.     bool forkflag;
  387. {
  388.     /*
  389.     **  If no work will ever be selected, don't even bother reading
  390.     **  the queue.
  391.     */
  392.  
  393.     la = getla();    /* get load average */
  394.  
  395.     if (shouldqueue(-100000000L))
  396.     {
  397.         if (Verbose)
  398.             printf("Skipping queue run -- load average too high\n");
  399.  
  400.         if (forkflag)
  401.             return;
  402.         finis();
  403.     }
  404.  
  405.     /*
  406.     **  See if we want to go off and do other useful work.
  407.     */
  408.  
  409.     if (forkflag)
  410.     {
  411.         int pid;
  412.  
  413.         pid = dofork();
  414.         if (pid > 0 && tTd(4, 2))
  415.             printf("runqueue: forking (pid = %d)\n", pid);
  416.         if (pid != 0)
  417.         {
  418.             /* parent -- pick up intermediate zombie */
  419. # ifndef SIGCHLD
  420.             (void) waitfor(pid);
  421. # else /* SIGCHLD */
  422.             (void) signal(SIGCHLD, reapchild);
  423. # endif /* !SIGCHLD */
  424.             if (QueueIntvl != 0)
  425.                 (void) setevent(QueueIntvl, runqueue, TRUE);
  426.             return;
  427.         }
  428.         /* child -- double fork */
  429. # ifndef SIGCHLD
  430.         if (fork() != 0)
  431.             exit(EX_OK);
  432. # else /* SIGCHLD */
  433.         (void) signal(SIGCHLD, SIG_DFL);
  434. # endif /* !SIGCHLD */
  435.     }
  436.  
  437.     setproctitle("running queue: %s", QueueDir);
  438.  
  439. # ifdef LOG
  440.     if (LogLevel > 11)
  441.         syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());
  442. # endif /* LOG */
  443.  
  444.     /*
  445.     **  Release any resources used by the daemon code.
  446.     */
  447.  
  448. # ifdef DAEMON
  449.     clrdaemon();
  450. # endif /* DAEMON */
  451.  
  452. #if !defined(DBM_AUTOBUILD) || ( !defined(NDBM) && !defined(OTHERDBM) )
  453.     /*
  454.     **  Make sure the alias database is open.
  455.     */
  456.  
  457.     initaliases(FALSE);
  458. #endif /* !DBM_AUTOBUILD || (!NDBM && !OTHERDBM) */
  459.  
  460.     /*
  461.     **  Start making passes through the queue.
  462.     **    First, read and sort the entire queue.
  463.     **    Then, process the work in that order.
  464.     **        But if you take too long, start over.
  465.     */
  466.  
  467.     /* order the existing work requests */
  468.     (void) orderq(FALSE);
  469.  
  470.     /* process them once at a time */
  471.     while (WorkQ != NULL)
  472.     {
  473.         WORK *w = WorkQ;
  474.  
  475.         WorkQ = WorkQ->w_next;
  476.         dowork(w);
  477.         free(w->w_name);
  478.         free((char *) w);
  479.     }
  480.  
  481.     /* exit without the usual cleanup */
  482.     exit(ExitStat);
  483. }
  484. /*
  485. **  ORDERQ -- order the work queue.
  486. **
  487. **    Parameters:
  488. **        doall -- if set, include everything in the queue (even
  489. **            the jobs that cannot be run because the load
  490. **            average is too high).  Otherwise, exclude those
  491. **            jobs.
  492. **
  493. **    Returns:
  494. **        The number of request in the queue (not necessarily
  495. **        the number of requests in WorkQ however).
  496. **
  497. **    Side Effects:
  498. **        Sets WorkQ to the queue of available work, in order.
  499. */
  500.  
  501. # define NEED_P        001
  502. # define NEED_T        002
  503. # define NEED_M        004
  504.  
  505. static int
  506. orderq(doall)
  507.     bool doall;
  508. {
  509.     register struct direct *d;
  510.     register WORK *w;
  511.     DIR *f;
  512.     register int i;
  513.     WORK wlist[QUEUESIZE+1];
  514.     int wn = -1;
  515.     extern char *MatchRecipient, *MatchSender, *QueueID;
  516.  
  517.     /* clear out old WorkQ */
  518.     for (w = WorkQ; w != NULL; )
  519.     {
  520.         register WORK *nw = w->w_next;
  521.  
  522.         WorkQ = nw;
  523.         free(w->w_name);
  524.         free((char *) w);
  525.         w = nw;
  526.     }
  527.  
  528.     /* open the queue directory */
  529.     f = opendir(".");
  530.     if (f == NULL)
  531.     {
  532.         syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
  533.         return (0);
  534.     }
  535.  
  536.     /*
  537.     **  Read the work directory.
  538.     */
  539.  
  540.     while ((d = readdir(f)) != NULL)
  541.     {
  542.         FILE *cf;
  543.         char lbuf[MAXNAME];
  544.  
  545.         /* is this an interesting entry? */
  546.         if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
  547.             continue;
  548.  
  549.         /* yes -- open control file (if not too many files) */
  550.         if (++wn >= QUEUESIZE)
  551.             continue;
  552.         cf = fopen(d->d_name, "r");
  553.         if (cf == NULL)
  554.         {
  555.             /* this may be some random person sending their msgs */
  556.             /* syserr("orderq: cannot open %s", cbuf); */
  557.             if (tTd(41, 2))
  558.                 printf("orderq: cannot open %s (%d)\n",
  559.                     d->d_name, errno);
  560.             errno = 0;
  561.             wn--;
  562.             continue;
  563.         }
  564.         w = &wlist[wn];
  565.         w->w_name = newstr(d->d_name);
  566.  
  567.         /* make sure jobs in creation don't clog queue */
  568.         w->w_pri = 0x7fffffff;
  569.         w->w_ctime = 0;
  570.  
  571.         /* extract useful information */
  572.         i = NEED_P | NEED_T;
  573.         if (MatchRecipient || MatchSender || QueueID)
  574.             i |= NEED_M;
  575.  
  576.         while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
  577.         {
  578.             switch (lbuf[0])
  579.             {
  580.               case 'P':
  581.                 w->w_pri = atol(&lbuf[1]);
  582.                 i &= ~NEED_P;
  583.                 break;
  584.  
  585.               case 'T':
  586.                 w->w_ctime = atol(&lbuf[1]);
  587.                 i &= ~NEED_T;
  588.                 break;
  589.  
  590.               case 'D':
  591.                 /* We are running a certain queued message  */
  592.                 if (QueueID && ((QueueID[0] == 'A' &&
  593.                     !strncmp(&lbuf[3], QueueID, 7)) ||
  594.                     (!strncmp(&lbuf[5], QueueID, 5))))
  595.                     i &= ~NEED_M;
  596.                 break;
  597.  
  598.               case 'R':
  599.               case 'S':
  600.               {
  601.                 int    k, matchlen, recplen;
  602.                 char    *mr;
  603.  
  604.                 /*
  605.                  * Trying to match something in the Sender or
  606.                  * Recipient field.
  607.                  */
  608.                 mr = (*lbuf == 'R') ? MatchRecipient
  609.                             : MatchSender;
  610.                 if (mr && (i & NEED_M))
  611.                 {
  612.                     matchlen = strlen(mr);
  613.                     recplen = strlen(&lbuf[1]);
  614.                     for (k = 1; (recplen - matchlen) >= 0;
  615.                          k++)
  616.                     {
  617.                         if (!strncasecmp(mr, &lbuf[k],
  618.                             matchlen))
  619.                         {
  620.                             i &= ~NEED_M;
  621.                             break;
  622.                         }
  623.                         recplen--;
  624.                     }
  625.                 }
  626.                 break;
  627.               }
  628.             }
  629.         }
  630.         (void) fclose(cf);
  631.  
  632.         if (!doall && (shouldqueue(w->w_pri) || i == NEED_M))
  633.         {
  634.             /* don't even bother sorting this job in */
  635.             wn--;
  636.         }
  637.     }
  638.     (void) closedir(f);
  639.     wn++;
  640.  
  641.     /*
  642.     **  Sort the work directory.
  643.     */
  644.  
  645.     qsort(wlist, (size_t) min(wn, QUEUESIZE), sizeof (WORK),
  646. #  ifdef __GNUC__
  647.         /* prevent bogus warnings */ (int (*)())
  648. #  endif /* __GNUC__ */
  649.         workcmpf);
  650.  
  651.     /*
  652.     **  Convert the work list into canonical form.
  653.     **    Should be turning it into a list of envelopes here perhaps.
  654.     */
  655.  
  656.     WorkQ = NULL;
  657.     for (i = min(wn, QUEUESIZE); --i >= 0; )
  658.     {
  659.         w = (WORK *) xalloc(sizeof (WORK));
  660.         w->w_name = wlist[i].w_name;
  661.         w->w_pri = wlist[i].w_pri;
  662.         w->w_ctime = wlist[i].w_ctime;
  663.         w->w_next = WorkQ;
  664.         WorkQ = w;
  665.     }
  666.  
  667.     if (tTd(40, 1))
  668.     {
  669.         for (w = WorkQ; w != NULL; w = w->w_next)
  670.             printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
  671.     }
  672.  
  673.     return (wn);
  674. }
  675. /*
  676. **  WORKCMPF -- compare function for ordering work.
  677. **
  678. **    Parameters:
  679. **        a -- the first argument.
  680. **        b -- the second argument.
  681. **
  682. **    Returns:
  683. **        -1 if a < b
  684. **         0 if a == b
  685. **        +1 if a > b
  686. **
  687. **    Side Effects:
  688. **        none.
  689. */
  690.  
  691. static int
  692. workcmpf(a, b)
  693.     register const WORK *a;
  694.     register const WORK *b;
  695. {
  696.     long pa = a->w_pri + a->w_ctime;
  697.     long pb = b->w_pri + b->w_ctime;
  698.  
  699.     if (pa == pb)
  700.         return (0);
  701.     else if (pa > pb)
  702.         return (1);
  703.     else
  704.         return (-1);
  705. }
  706. /*
  707. **  DOWORK -- do a work request.
  708. **
  709. **    Parameters:
  710. **        w -- the work request to be satisfied.
  711. **
  712. **    Returns:
  713. **        none.
  714. **
  715. **    Side Effects:
  716. **        The work request is satisfied if possible.
  717. */
  718.  
  719. static void
  720. dowork(w)
  721.     register WORK *w;
  722. {
  723.     register int i;
  724.  
  725.     if (tTd(40, 1))
  726.         printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
  727.  
  728.     /*
  729.     **  Ignore jobs that are too expensive for the moment.
  730.     */
  731.  
  732.     if (shouldqueue(w->w_pri))
  733.     {
  734.         if (Verbose)
  735.             printf("\nSkipping %s\n", w->w_name + 2);
  736.         return;
  737.     }
  738.  
  739.     /*
  740.     **  Fork for work.
  741.     */
  742.  
  743.     if (ForkQueueRuns)
  744.     {
  745.         i = fork();
  746.         if (i > 0 && tTd(4, 2))
  747.             printf("dowork: forking (pid = %d)\n", i);
  748.         if (i < 0)
  749.         {
  750.             syserr("dowork: cannot fork");
  751.             return;
  752.         }
  753.     }
  754.     else
  755.     {
  756.         i = 0;
  757.     }
  758.  
  759.     if (i == 0)
  760.     {
  761.         FILE *qflock;
  762.  
  763.         /*
  764.         **  CHILD
  765.         **    Lock the control file to avoid duplicate deliveries.
  766.         **        Then run the file as though we had just read it.
  767.         **    We save an idea of the temporary name so we
  768.         **        can recover on interrupt.
  769.         */
  770.  
  771.         /* set basic modes, etc. */
  772.         (void) alarm(0);
  773.         clearenvelope(CurEnv, FALSE);
  774.         QueueRun = TRUE;
  775.         ErrorMode = EM_MAIL;
  776.         CurEnv->e_id = &w->w_name[2];
  777. # ifdef LOG
  778.         if (LogLevel > 11)
  779.             syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id,
  780.                    getpid());
  781. # endif /* LOG */
  782.  
  783.         /* don't use the headers from sendmail.cf... */
  784.         CurEnv->e_header = NULL;
  785.  
  786.         /* read the queue control file */
  787.         /*  and lock the control file during processing */
  788.         if ((qflock=readqf(CurEnv, TRUE)) == NULL)
  789.         {
  790.             if (ForkQueueRuns)
  791.                 exit(EX_OK);
  792.             else
  793.                 return;
  794.         }
  795.  
  796.         CurEnv->e_flags |= EF_INQUEUE;
  797.         eatheader(CurEnv, NULL);
  798.  
  799.         /* do the delivery */
  800.         if (!bitset(EF_FATALERRS, CurEnv->e_flags))
  801.             sendall(CurEnv, SM_DELIVER);
  802.  
  803.         /* finish up and exit */
  804.         if (ForkQueueRuns)
  805.             finis();
  806.         else
  807.             dropenvelope(CurEnv);
  808.         (void) fclose(qflock);
  809.     }
  810.     else
  811.     {
  812.         /*
  813.         **  Parent -- pick up results.
  814.         */
  815.  
  816.         errno = 0;
  817.         (void) waitfor(i);
  818.     }
  819. }
  820. /*
  821. **  READQF -- read queue file and set up environment.
  822. **
  823. **    Parameters:
  824. **        e -- the envelope of the job to run.
  825. **        full -- if set, read in all information.  Otherwise just
  826. **            read in info needed for a queue print.
  827. **
  828. **    Returns:
  829. **        FILE * pointing to flock()ed fd so it can be closed
  830. **        after the mail is delivered
  831. **
  832. **    Side Effects:
  833. **        cf is read and created as the current job, as though
  834. **        we had been invoked by argument.
  835. */
  836.  
  837. static FILE *
  838. readqf(e, full)
  839.     register ENVELOPE *e;
  840.     bool full;
  841. {
  842.     char *qf;
  843.     register FILE *qfp;
  844.     char buf[MAXFIELD];
  845.     int gotctluser = 0;
  846.  
  847.     /*
  848.     **  Read and process the file.
  849.     */
  850.  
  851.     qf = queuename(e, 'q');
  852.     /*
  853.      * We can't get an exclusive lock on a file that isn't opened for
  854.      * writing on most systems - sigh!
  855.      */
  856.     qfp = fopen(qf, "r+");
  857.     if (qfp == NULL)
  858.     {
  859.         if (errno != ENOENT)
  860.             syserr("readqf: no control file %s", qf);
  861.         return NULL;
  862.     }
  863.  
  864.     if (flock(fileno(qfp), LOCK_EX|LOCK_NB) < 0)
  865.     {
  866. # ifdef LOG
  867.         /* being processed by another queuer */
  868.         if (Verbose)
  869.             printf("%s: locked\n", CurEnv->e_id);
  870. # endif /* LOG */
  871.         (void) fclose(qfp);
  872.         return NULL;
  873.     }
  874.  
  875.     /* do basic system initialization */
  876.     initsys();
  877.  
  878.     FileName = qf;
  879.     LineNumber = 0;
  880.     if (Verbose && full)
  881.         printf("\nRunning %s\n", e->e_id);
  882.     while (fgetfolded(buf, sizeof buf, qfp) != NULL)
  883.     {
  884.         if (tTd(40, 4))
  885.             printf("+++++ %s\n", buf);
  886.         switch (buf[0])
  887.         {
  888.           case 'C':        /* specify controlling user */
  889.             setctluser(&buf[1]);
  890.             gotctluser = 1;
  891.             break;
  892.  
  893.           case 'R':        /* specify recipient */
  894.             sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue);
  895.             break;
  896.  
  897.           case 'E':        /* specify error recipient */
  898.             sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue);
  899.             break;
  900.  
  901.           case 'H':        /* header */
  902.             if (full)
  903.                 (void) chompheader(&buf[1], FALSE);
  904.             break;
  905.  
  906.           case 'M':        /* message */
  907.             e->e_message = newstr(&buf[1]);
  908.             break;
  909.  
  910.           case 'S':        /* sender */
  911.             setsender(newstr(&buf[1]));
  912.             break;
  913.  
  914.           case 'D':        /* data file name */
  915.             if (!full)
  916.                 break;
  917.             e->e_df = newstr(&buf[1]);
  918.             e->e_dfp = fopen(e->e_df, "r");
  919.             if (e->e_dfp == NULL)
  920.                 syserr("readqf: cannot open %s", e->e_df);
  921.             break;
  922.  
  923.           case 'T':        /* init time */
  924.             e->e_ctime = atol(&buf[1]);
  925.             break;
  926.  
  927.           case 'P':        /* message priority */
  928.             e->e_msgpriority = atol(&buf[1]) + WkTimeFact;
  929.             break;
  930.  
  931. # ifdef QUEUE_MACVALUE /* if macro values saved in queue file, restore them */
  932.           case QUEUE_MACVALUE:
  933.             setoption('M', &buf[1], FALSE, TRUE);
  934.             break;
  935. # endif /* QUEUE_MACVALUE */
  936.  
  937.           case '\0':        /* blank line; ignore */
  938.             break;
  939.  
  940.           default:
  941.             syserr("readqf(%s:%d): bad line \"%s\"", e->e_id,
  942.                 LineNumber, buf);
  943.             break;
  944.         }
  945.         /*
  946.         **  The `C' queue file command operates on the next line,
  947.         **  so we use "gotctluser" to maintain state as follows:
  948.         **      0 - no controlling user,
  949.         **      1 - controlling user has been set but not used,
  950.         **      2 - controlling user must be used on next iteration.
  951.         */
  952.         if (gotctluser == 1)
  953.             gotctluser++;
  954.         else if (gotctluser == 2)
  955.         {
  956.             clrctluser();
  957.             gotctluser = 0;
  958.         }
  959.     }
  960.  
  961.     /* clear controlling user in case we break out prematurely */
  962.     clrctluser();
  963.  
  964.     FileName = NULL;
  965.  
  966.     /*
  967.     **  If we haven't read any lines, this queue file is empty.
  968.     **  Arrange to remove it without referencing any null pointers.
  969.     */
  970.  
  971.     if (LineNumber == 0)
  972.     {
  973.         errno = 0;
  974.         e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
  975.     }
  976.     return qfp;
  977. }
  978. /*
  979. **  PRINTQUEUE -- print out a representation of the mail queue
  980. **
  981. **    Parameters:
  982. **        none.
  983. **
  984. **    Returns:
  985. **        none.
  986. **
  987. **    Side Effects:
  988. **        Prints a listing of the mail queue on the standard output.
  989. */
  990.  
  991. void
  992. printqueue()
  993. {
  994.     register WORK *w;
  995.     FILE *f;
  996.     int nrequests;
  997.     char buf[MAXLINE];
  998.     char cbuf[MAXLINE];
  999.  
  1000.     /*
  1001.     **  Read and order the queue.
  1002.     */
  1003.  
  1004.     nrequests = orderq(TRUE);
  1005.  
  1006.     /*
  1007.     **  Print the work list that we have read.
  1008.     */
  1009.  
  1010.     /* first see if there is anything */
  1011.     if (nrequests <= 0)
  1012.     {
  1013.         printf("Mail queue is empty\n");
  1014.         return;
  1015.     }
  1016.  
  1017.     la = getla();    /* get load average */
  1018.  
  1019.     printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
  1020.     if (nrequests > QUEUESIZE)
  1021.         printf(", only %d printed", QUEUESIZE);
  1022.     if (Verbose)
  1023.         printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
  1024.     else
  1025.         printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
  1026.     for (w = WorkQ; w != NULL; w = w->w_next)
  1027.     {
  1028.         struct stat st;
  1029.         auto TIME_TYPE submittime = 0;
  1030.         long dfsize = -1;
  1031.         char message[MAXLINE];
  1032.  
  1033.         f = fopen(w->w_name, "r");
  1034.         if (f == NULL)
  1035.         {
  1036.             errno = 0;
  1037.             continue;
  1038.         }
  1039.         printf("%7s", w->w_name + 2);
  1040.         if (flock(fileno(f), LOCK_SH|LOCK_NB) < 0)
  1041.             printf("*");
  1042.         else if (shouldqueue(w->w_pri))
  1043.             printf("X");
  1044.         else
  1045.             printf(" ");
  1046.         errno = 0;
  1047.  
  1048.         message[0] = '\0';
  1049.         cbuf[0] = '\0';
  1050.         while (fgets(buf, sizeof buf, f) != NULL)
  1051.         {
  1052.             fixcrlf(buf, TRUE);
  1053.             switch (buf[0])
  1054.             {
  1055.               case 'M':    /* error message */
  1056.                 (void) strcpy(message, &buf[1]);
  1057.                 break;
  1058.  
  1059.               case 'S':    /* sender name */
  1060.                 if (Verbose)
  1061.                     printf("%8ld %10ld %.12s %.38s", dfsize,
  1062.                         w->w_pri, ctime(&submittime) + 4,
  1063.                         &buf[1]);
  1064.                 else
  1065.                     printf("%8ld %.16s %.45s", dfsize,
  1066.                         ctime(&submittime), &buf[1]);
  1067.                 if (message[0] != '\0')
  1068.                     printf("\n\t\t (%.60s)", message);
  1069.                 break;
  1070.               case 'C':    /* controlling user */
  1071.                 if (strlen(buf) < MAXLINE-3)    /* sanity */
  1072.                     (void) strcat(buf, ") ");
  1073.                 cbuf[0] = cbuf[1] = '(';
  1074.                 (void) strncpy(&cbuf[2], &buf[1], MAXLINE-1);
  1075.                 cbuf[MAXLINE-1] = '\0';
  1076.                 break;
  1077.  
  1078.               case 'R':    /* recipient name */
  1079.                 if (cbuf[0] != '\0')
  1080.                 {
  1081.                     /* prepend controlling user to `buf' */
  1082.                     (void) strncat(cbuf, &buf[1],
  1083.                                   MAXLINE-strlen(cbuf));
  1084.                     cbuf[MAXLINE-1] = '\0';
  1085.                     (void) strcpy(buf, cbuf);
  1086.                     cbuf[0] = '\0';
  1087.                 }
  1088.                 if (Verbose)
  1089.                     printf("\n\t\t\t\t\t %.38s", &buf[1]);
  1090.                 else
  1091.                     printf("\n\t\t\t\t  %.45s", &buf[1]);
  1092.                 break;
  1093.  
  1094.               case 'T':    /* creation time */
  1095.                 submittime = atol(&buf[1]);
  1096.                 break;
  1097.  
  1098.               case 'D':    /* data file name */
  1099.                 if (stat(&buf[1], &st) >= 0)
  1100.                     dfsize = st.st_size;
  1101.                 break;
  1102.             }
  1103.         }
  1104.         if (submittime == (TIME_TYPE) 0)
  1105.             printf(" (no control file)");
  1106.         printf("\n");
  1107.         (void) fclose(f);
  1108.     }
  1109. }
  1110.  
  1111. #endif /* QUEUE */
  1112. /*
  1113. **  QUEUENAME -- build a file name in the queue directory for this envelope.
  1114. **
  1115. **    Assigns an id code if one does not already exist.
  1116. **    This code is very careful to avoid trashing existing files
  1117. **    under any circumstances.
  1118. **
  1119. **    Parameters:
  1120. **        e -- envelope to build it in/from.
  1121. **        type -- the file type, used as the first character
  1122. **            of the file name.
  1123. **
  1124. **    Returns:
  1125. **        a pointer to the new file name (in a static buffer).
  1126. **
  1127. **    Side Effects:
  1128. **        Will create the qf file if no id code is
  1129. **        already assigned.  This will cause the envelope
  1130. **        to be modified.
  1131. */
  1132.  
  1133. char *
  1134. queuename(e, type)
  1135.     register ENVELOPE *e;
  1136.     char type;
  1137. {
  1138.     static char buf[MAXNAME];
  1139.     static int pid = -1;
  1140.     char c1 = 'A';
  1141.     char c2 = 'A';
  1142.  
  1143.     if (e->e_id == NULL)
  1144.     {
  1145.         char qf[20];
  1146.  
  1147.         /* find a unique id */
  1148.         if (pid != getpid())
  1149.         {
  1150.             /* new process -- start back at "AA" */
  1151.             pid = getpid();
  1152.             c1 = 'A';
  1153.             c2 = 'A' - 1;
  1154.         }
  1155.         (void) sprintf(qf, "qfAA%05d", pid);
  1156.  
  1157.         while (c1 < '~' || c2 < 'Z')
  1158.         {
  1159.             int i;
  1160.  
  1161.             if (c2 >= 'Z')
  1162.             {
  1163.                 c1++;
  1164.                 c2 = 'A' - 1;
  1165.             }
  1166.             qf[2] = c1;
  1167.             qf[3] = ++c2;
  1168.             if (tTd(7, 20))
  1169.                 printf("queuename: trying \"%s\"\n", qf);
  1170.  
  1171.             i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
  1172.             if (i < 0)
  1173.             {
  1174.                 if (errno != EEXIST)
  1175.                 {
  1176.                     syserr("queuename: Cannot create \"%s\" in \"%s\"",
  1177.                         qf, QueueDir);
  1178.                     exit(EX_UNAVAILABLE);
  1179.                 }
  1180.             }
  1181.             else
  1182.             {
  1183.                 (void) close(i);
  1184.                 break;
  1185.             }
  1186.         }
  1187.         if (c1 >= '~' && c2 >= 'Z')
  1188.         {
  1189.             syserr("queuename: Cannot create \"%s\" in \"%s\"",
  1190.                 qf, QueueDir);
  1191.             exit(EX_OSERR);
  1192.         }
  1193.         e->e_id = newstr(&qf[2]);
  1194.         define('i', e->e_id, e);
  1195.         if (tTd(7, 1))
  1196.             printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
  1197. #ifdef LOG
  1198.         if (LogLevel > 16)
  1199.             syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
  1200. #endif /* LOG */
  1201.     }
  1202.  
  1203.     if (type == '\0')
  1204.         return (NULL);
  1205.     (void) sprintf(buf, "%cf%s", type, e->e_id);
  1206.     if (tTd(7, 2))
  1207.         printf("queuename: %s\n", buf);
  1208.     return (buf);
  1209. }
  1210. /*
  1211. **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
  1212. **
  1213. **    Parameters:
  1214. **        e -- the envelope to unlock.
  1215. **
  1216. **    Returns:
  1217. **        none
  1218. **
  1219. **    Side Effects:
  1220. **        unlocks the queue for `e'.
  1221. */
  1222.  
  1223. void
  1224. unlockqueue(e)
  1225.     ENVELOPE *e;
  1226. {
  1227.     /* remove the transcript */
  1228. #ifdef LOG
  1229.     if (LogLevel > 19)
  1230.         syslog(LOG_DEBUG, "%s: unlock", e->e_id);
  1231. #endif /* LOG */
  1232.     if (!tTd(51, 4))
  1233.         xunlink(queuename(e, 'x'));
  1234.  
  1235. }
  1236. /*
  1237. **  GETCTLUSER -- return controlling user if mailing to prog or file
  1238. **
  1239. **    Check for a "|" or "/" at the beginning of the address.  If
  1240. **    found, return a controlling username.
  1241. **
  1242. **    Parameters:
  1243. **        a - the address to check out
  1244. **
  1245. **    Returns:
  1246. **        Either NULL, if we werent mailing to a program or file,
  1247. **        or a controlling user name (possibly in getpwuid's
  1248. **        static buffer).
  1249. **
  1250. **    Side Effects:
  1251. **        none.
  1252. */
  1253.  
  1254. static char *
  1255. getctluser(a)
  1256.     ADDRESS *a;
  1257. {
  1258.     struct passwd *pw;
  1259.     char *retstr;
  1260.  
  1261.     /*
  1262.     **  Get unquoted user for file, program or user.name check.
  1263.     **  N.B. remove this code block to always emit controlling
  1264.     **  addresses (at the expense of backward compatibility).
  1265.     */
  1266.  
  1267.     {
  1268.         char buf[MAXNAME];
  1269.         (void) strncpy(buf, a->q_paddr, MAXNAME);
  1270.         buf[MAXNAME-1] = '\0';
  1271.         stripquotes(buf, TRUE);
  1272.  
  1273.         if (buf[0] != '|' && buf[0] != '/')
  1274.             return((char *)NULL);
  1275.     }
  1276.  
  1277.     a = getctladdr(a);        /* find controlling address */
  1278.  
  1279.     if (a != NULL && a->q_uid != 0 && (pw = getpwuid(a->q_uid)) != NULL)
  1280.         retstr = pw->pw_name;
  1281.     else                /* use default user */
  1282.         retstr = DefUser;
  1283.  
  1284.     if (tTd(40, 5))
  1285.         printf("Set controlling user for `%s' to `%s'\n",
  1286.                (a == NULL)? "<null>": a->q_paddr, retstr);
  1287.  
  1288.     return(retstr);
  1289. }
  1290. /*
  1291. **  SETCTLUSER - sets `CtlUser' to controlling user
  1292. **  CLRCTLUSER - clears controlling user (no params, nothing returned)
  1293. **
  1294. **    These routines manipulate `CtlUser'.
  1295. **
  1296. **    Parameters:
  1297. **        str  - controlling user as passed to setctluser()
  1298. **
  1299. **    Returns:
  1300. **        None.
  1301. **
  1302. **    Side Effects:
  1303. **        `CtlUser' is changed.
  1304. */
  1305.  
  1306. static char CtlUser[MAXNAME];
  1307.  
  1308. static void
  1309. setctluser(str)
  1310.     register const char *str;
  1311. {
  1312.     (void) strncpy(CtlUser, str, MAXNAME);
  1313.     CtlUser[MAXNAME-1] = '\0';
  1314. }
  1315.  
  1316. static void
  1317. clrctluser()
  1318. {
  1319.     CtlUser[0] = '\0';
  1320. }
  1321.  
  1322. /*
  1323. **  SETCTLADDR -- create a controlling address
  1324. **
  1325. **    If global variable `CtlUser' is set and we are given a valid
  1326. **    address, make that address a controlling address; change the
  1327. **    `q_uid', `q_gid', and `q_ruser' fields and set QGOODUID.
  1328. **
  1329. **    Parameters:
  1330. **        a - address for which control uid/gid info may apply
  1331. **
  1332. **    Returns:
  1333. **        None.    
  1334. **
  1335. **    Side Effects:
  1336. **        Fills in uid/gid fields in address and sets QGOODUID
  1337. **        flag if appropriate.
  1338. */
  1339.  
  1340. void
  1341. setctladdr(a)
  1342.     ADDRESS *a;
  1343. {
  1344.     struct passwd *pw;
  1345.  
  1346.     /*
  1347.     **  If there is no current controlling user, or we were passed a
  1348.     **  NULL addr ptr or we already have a controlling user, return.
  1349.     */
  1350.  
  1351.     if (CtlUser[0] == '\0' || a == NULL || a->q_ruser)
  1352.         return;
  1353.  
  1354.     /*
  1355.     **  Set up addr fields for controlling user.  If `CtlUser' is no
  1356.     **  longer valid, use the default user/group.
  1357.     */
  1358.  
  1359.     if ((pw = getpwnam(CtlUser)) != NULL)
  1360.     {
  1361.         if (a->q_home)
  1362.             free(a->q_home);
  1363.         a->q_home = newstr(pw->pw_dir);
  1364.         a->q_uid = pw->pw_uid;
  1365.         a->q_gid = pw->pw_gid;
  1366.         a->q_ruser = newstr(CtlUser);
  1367.     }
  1368.     else
  1369.     {
  1370.         a->q_uid = DefUid;
  1371.         a->q_gid = DefGid;
  1372.         a->q_ruser = newstr(DefUser);
  1373.     }
  1374.  
  1375.     a->q_flags |= QGOODUID;        /* flag as a "ctladdr"  */
  1376.  
  1377.     if (tTd(40, 5))
  1378.         printf("Restored controlling user for `%s' to `%s'\n",
  1379.                a->q_paddr, a->q_ruser);
  1380. }
  1381.