1: /*
   2: **  Sendmail
   3: **  Copyright (c) 1983  Eric P. Allman
   4: **  Berkeley, California
   5: **
   6: **  Copyright (c) 1983 Regents of the University of California.
   7: **  All rights reserved.  The Berkeley software License Agreement
   8: **  specifies the terms and conditions for redistribution.
   9: */
  10: 
  11: 
  12: # include "sendmail.h"
  13: # include <sys/stat.h>
  14: # include <sys/dir.h>
  15: # include <signal.h>
  16: # include <errno.h>
  17: 
  18: # ifndef QUEUE
  19: # ifndef lint
  20: static char SccsId[] = "@(#)queue.c	5.21 (Berkeley) 4/17/86	(no queueing)";
  21: # endif not lint
  22: # else QUEUE
  23: 
  24: # ifndef lint
  25: static char SccsId[] = "@(#)queue.c	5.21 (Berkeley) 4/17/86";
  26: # endif not lint
  27: 
  28: /*
  29: **  Work queue.
  30: */
  31: 
  32: struct work
  33: {
  34:     char        *w_name;    /* name of control file */
  35:     long        w_pri;      /* priority of message, see below */
  36:     time_t      w_ctime;    /* creation time of message */
  37:     struct work *w_next;    /* next in queue */
  38: };
  39: 
  40: typedef struct work WORK;
  41: 
  42: WORK    *WorkQ;         /* queue of things to be done */
  43: /*
  44: **  QUEUEUP -- queue a message up for future transmission.
  45: **
  46: **	Parameters:
  47: **		e -- the envelope to queue up.
  48: **		queueall -- if TRUE, queue all addresses, rather than
  49: **			just those with the QQUEUEUP flag set.
  50: **		announce -- if TRUE, tell when you are queueing up.
  51: **
  52: **	Returns:
  53: **		none.
  54: **
  55: **	Side Effects:
  56: **		The current request are saved in a control file.
  57: */
  58: 
  59: queueup(e, queueall, announce)
  60:     register ENVELOPE *e;
  61:     bool queueall;
  62:     bool announce;
  63: {
  64:     char *tf;
  65:     char *qf;
  66:     char buf[MAXLINE];
  67:     register FILE *tfp;
  68:     register HDR *h;
  69:     register ADDRESS *q;
  70:     MAILER nullmailer;
  71: 
  72:     /*
  73: 	**  Create control file.
  74: 	*/
  75: 
  76:     tf = newstr(queuename(e, 't'));
  77:     tfp = fopen(tf, "w");
  78:     if (tfp == NULL)
  79:     {
  80:         syserr("queueup: cannot create temp file %s", tf);
  81:         return;
  82:     }
  83:     (void) chmod(tf, FileMode);
  84: 
  85: # ifdef DEBUG
  86:     if (tTd(40, 1))
  87:         printf("queueing %s\n", e->e_id);
  88: # endif DEBUG
  89: 
  90:     /*
  91: 	**  If there is no data file yet, create one.
  92: 	*/
  93: 
  94:     if (e->e_df == NULL)
  95:     {
  96:         register FILE *dfp;
  97:         extern putbody();
  98: 
  99:         e->e_df = newstr(queuename(e, 'd'));
 100:         dfp = fopen(e->e_df, "w");
 101:         if (dfp == NULL)
 102:         {
 103:             syserr("queueup: cannot create %s", e->e_df);
 104:             (void) fclose(tfp);
 105:             return;
 106:         }
 107:         (void) chmod(e->e_df, FileMode);
 108:         (*e->e_putbody)(dfp, ProgMailer, e);
 109:         (void) fclose(dfp);
 110:         e->e_putbody = putbody;
 111:     }
 112: 
 113:     /*
 114: 	**  Output future work requests.
 115: 	**	Priority and creation time should be first, since
 116: 	**	they are required by orderq.
 117: 	*/
 118: 
 119:     /* output message priority */
 120:     fprintf(tfp, "P%ld\n", e->e_msgpriority);
 121: 
 122:     /* output creation time */
 123:     fprintf(tfp, "T%ld\n", e->e_ctime);
 124: 
 125:     /* output name of data file */
 126:     fprintf(tfp, "D%s\n", e->e_df);
 127: 
 128:     /* message from envelope, if it exists */
 129:     if (e->e_message != NULL)
 130:         fprintf(tfp, "M%s\n", e->e_message);
 131: 
 132:     /* output name of sender */
 133:     fprintf(tfp, "S%s\n", e->e_from.q_paddr);
 134: 
 135:     /* output list of recipient addresses */
 136:     for (q = e->e_sendqueue; q != NULL; q = q->q_next)
 137:     {
 138:         if (queueall ? !bitset(QDONTSEND, q->q_flags) :
 139:                    bitset(QQUEUEUP, q->q_flags))
 140:         {
 141:             fprintf(tfp, "R%s\n", q->q_paddr);
 142:             if (announce)
 143:             {
 144:                 e->e_to = q->q_paddr;
 145:                 message(Arpa_Info, "queued");
 146:                 if (LogLevel > 4)
 147:                     logdelivery("queued");
 148:                 e->e_to = NULL;
 149:             }
 150: #ifdef DEBUG
 151:             if (tTd(40, 1))
 152:             {
 153:                 printf("queueing ");
 154:                 printaddr(q, FALSE);
 155:             }
 156: #endif DEBUG
 157:         }
 158:     }
 159: 
 160:     /* output list of error recipients */
 161:     for (q = e->e_errorqueue; q != NULL; q = q->q_next)
 162:     {
 163:         if (!bitset(QDONTSEND, q->q_flags))
 164:             fprintf(tfp, "E%s\n", q->q_paddr);
 165:     }
 166: 
 167:     /*
 168: 	**  Output headers for this message.
 169: 	**	Expand macros completely here.  Queue run will deal with
 170: 	**	everything as absolute headers.
 171: 	**		All headers that must be relative to the recipient
 172: 	**		can be cracked later.
 173: 	**	We set up a "null mailer" -- i.e., a mailer that will have
 174: 	**	no effect on the addresses as they are output.
 175: 	*/
 176: 
 177:     bzero((char *) &nullmailer, sizeof nullmailer);
 178:     nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1;
 179:     nullmailer.m_eol = "\n";
 180: 
 181:     define('g', "\001f", e);
 182:     for (h = e->e_header; h != NULL; h = h->h_link)
 183:     {
 184:         extern bool bitzerop();
 185: 
 186:         /* don't output null headers */
 187:         if (h->h_value == NULL || h->h_value[0] == '\0')
 188:             continue;
 189: 
 190:         /* don't output resent headers on non-resent messages */
 191:         if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
 192:             continue;
 193: 
 194:         /* output this header */
 195:         fprintf(tfp, "H");
 196: 
 197:         /* if conditional, output the set of conditions */
 198:         if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
 199:         {
 200:             int j;
 201: 
 202:             (void) putc('?', tfp);
 203:             for (j = '\0'; j <= '\177'; j++)
 204:                 if (bitnset(j, h->h_mflags))
 205:                     (void) putc(j, tfp);
 206:             (void) putc('?', tfp);
 207:         }
 208: 
 209:         /* output the header: expand macros, convert addresses */
 210:         if (bitset(H_DEFAULT, h->h_flags))
 211:         {
 212:             (void) expand(h->h_value, buf, &buf[sizeof buf], e);
 213:             fprintf(tfp, "%s: %s\n", h->h_field, buf);
 214:         }
 215:         else if (bitset(H_FROM|H_RCPT, h->h_flags))
 216:         {
 217:             commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),
 218:                  &nullmailer);
 219:         }
 220:         else
 221:             fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
 222:     }
 223: 
 224:     /*
 225: 	**  Clean up.
 226: 	*/
 227: 
 228:     (void) fclose(tfp);
 229:     qf = queuename(e, 'q');
 230:     if (tf != NULL)
 231:     {
 232:         (void) unlink(qf);
 233:         if (rename(tf, qf) < 0)
 234:             syserr("cannot unlink(%s, %s), df=%s", tf, qf, e->e_df);
 235:         errno = 0;
 236:     }
 237: 
 238: # ifdef LOG
 239:     /* save log info */
 240:     if (LogLevel > 15)
 241:         syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
 242: # endif LOG
 243: }
 244: /*
 245: **  RUNQUEUE -- run the jobs in the queue.
 246: **
 247: **	Gets the stuff out of the queue in some presumably logical
 248: **	order and processes them.
 249: **
 250: **	Parameters:
 251: **		forkflag -- TRUE if the queue scanning should be done in
 252: **			a child process.  We double-fork so it is not our
 253: **			child and we don't have to clean up after it.
 254: **
 255: **	Returns:
 256: **		none.
 257: **
 258: **	Side Effects:
 259: **		runs things in the mail queue.
 260: */
 261: 
 262: runqueue(forkflag)
 263:     bool forkflag;
 264: {
 265:     extern bool shouldqueue();
 266: 
 267:     /*
 268: 	**  If no work will ever be selected, don't even bother reading
 269: 	**  the queue.
 270: 	*/
 271: 
 272:     if (shouldqueue(-100000000L))
 273:     {
 274:         if (Verbose)
 275:             printf("Skipping queue run -- load average too high\n");
 276: 
 277:         if (forkflag)
 278:             return;
 279:         finis();
 280:     }
 281: 
 282:     /*
 283: 	**  See if we want to go off and do other useful work.
 284: 	*/
 285: 
 286:     if (forkflag)
 287:     {
 288:         int pid;
 289: 
 290:         pid = dofork();
 291:         if (pid != 0)
 292:         {
 293:             extern reapchild();
 294: 
 295:             /* parent -- pick up intermediate zombie */
 296: #ifndef SIGCHLD
 297:             (void) waitfor(pid);
 298: #else SIGCHLD
 299:             (void) signal(SIGCHLD, reapchild);
 300: #endif SIGCHLD
 301:             if (QueueIntvl != 0)
 302:                 (void) setevent(QueueIntvl, runqueue, TRUE);
 303:             return;
 304:         }
 305:         /* child -- double fork */
 306: #ifndef SIGCHLD
 307:         if (fork() != 0)
 308:             exit(EX_OK);
 309: #else SIGCHLD
 310:         (void) signal(SIGCHLD, SIG_DFL);
 311: #endif SIGCHLD
 312:     }
 313: 
 314:     setproctitle("running queue");
 315: 
 316: # ifdef LOG
 317:     if (LogLevel > 11)
 318:         syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());
 319: # endif LOG
 320: 
 321:     /*
 322: 	**  Release any resources used by the daemon code.
 323: 	*/
 324: 
 325: # ifdef DAEMON
 326:     clrdaemon();
 327: # endif DAEMON
 328: 
 329:     /*
 330: 	**  Make sure the alias database is open.
 331: 	*/
 332: 
 333:     initaliases(AliasFile, FALSE);
 334: 
 335:     /*
 336: 	**  Start making passes through the queue.
 337: 	**	First, read and sort the entire queue.
 338: 	**	Then, process the work in that order.
 339: 	**		But if you take too long, start over.
 340: 	*/
 341: 
 342:     /* order the existing work requests */
 343:     (void) orderq(FALSE);
 344: 
 345:     /* process them once at a time */
 346:     while (WorkQ != NULL)
 347:     {
 348:         WORK *w = WorkQ;
 349: 
 350:         WorkQ = WorkQ->w_next;
 351:         dowork(w);
 352:         free(w->w_name);
 353:         free((char *) w);
 354:     }
 355:     finis();
 356: }
 357: /*
 358: **  ORDERQ -- order the work queue.
 359: **
 360: **	Parameters:
 361: **		doall -- if set, include everything in the queue (even
 362: **			the jobs that cannot be run because the load
 363: **			average is too high).  Otherwise, exclude those
 364: **			jobs.
 365: **
 366: **	Returns:
 367: **		The number of request in the queue (not necessarily
 368: **		the number of requests in WorkQ however).
 369: **
 370: **	Side Effects:
 371: **		Sets WorkQ to the queue of available work, in order.
 372: */
 373: 
 374: # define NEED_P     001
 375: # define NEED_T     002
 376: 
 377: orderq(doall)
 378:     bool doall;
 379: {
 380:     register struct direct *d;
 381:     register WORK *w;
 382:     DIR *f;
 383:     register int i;
 384:     WORK wlist[QUEUESIZE+1];
 385:     int wn = -1;
 386:     extern workcmpf();
 387: 
 388:     /* clear out old WorkQ */
 389:     for (w = WorkQ; w != NULL; )
 390:     {
 391:         register WORK *nw = w->w_next;
 392: 
 393:         WorkQ = nw;
 394:         free(w->w_name);
 395:         free((char *) w);
 396:         w = nw;
 397:     }
 398: 
 399:     /* open the queue directory */
 400:     f = opendir(".");
 401:     if (f == NULL)
 402:     {
 403:         syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
 404:         return (0);
 405:     }
 406: 
 407:     /*
 408: 	**  Read the work directory.
 409: 	*/
 410: 
 411:     while ((d = readdir(f)) != NULL)
 412:     {
 413:         FILE *cf;
 414:         char lbuf[MAXNAME];
 415: 
 416:         /* is this an interesting entry? */
 417:         if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
 418:             continue;
 419: 
 420:         /* yes -- open control file (if not too many files) */
 421:         if (++wn >= QUEUESIZE)
 422:             continue;
 423:         cf = fopen(d->d_name, "r");
 424:         if (cf == NULL)
 425:         {
 426:             /* this may be some random person sending hir msgs */
 427:             /* syserr("orderq: cannot open %s", cbuf); */
 428: #ifdef DEBUG
 429:             if (tTd(41, 2))
 430:                 printf("orderq: cannot open %s (%d)\n",
 431:                     d->d_name, errno);
 432: #endif DEBUG
 433:             errno = 0;
 434:             wn--;
 435:             continue;
 436:         }
 437:         w = &wlist[wn];
 438:         w->w_name = newstr(d->d_name);
 439: 
 440:         /* make sure jobs in creation don't clog queue */
 441:         w->w_pri = 0x7fffffff;
 442:         w->w_ctime = 0;
 443: 
 444:         /* extract useful information */
 445:         i = NEED_P | NEED_T;
 446:         while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
 447:         {
 448:             extern long atol();
 449: 
 450:             switch (lbuf[0])
 451:             {
 452:               case 'P':
 453:                 w->w_pri = atol(&lbuf[1]);
 454:                 i &= ~NEED_P;
 455:                 break;
 456: 
 457:               case 'T':
 458:                 w->w_ctime = atol(&lbuf[1]);
 459:                 i &= ~NEED_T;
 460:                 break;
 461:             }
 462:         }
 463:         (void) fclose(cf);
 464: 
 465:         if (!doall && shouldqueue(w->w_pri))
 466:         {
 467:             /* don't even bother sorting this job in */
 468:             wn--;
 469:         }
 470:     }
 471:     (void) closedir(f);
 472:     wn++;
 473: 
 474:     /*
 475: 	**  Sort the work directory.
 476: 	*/
 477: 
 478:     qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
 479: 
 480:     /*
 481: 	**  Convert the work list into canonical form.
 482: 	**	Should be turning it into a list of envelopes here perhaps.
 483: 	*/
 484: 
 485:     WorkQ = NULL;
 486:     for (i = min(wn, QUEUESIZE); --i >= 0; )
 487:     {
 488:         w = (WORK *) xalloc(sizeof *w);
 489:         w->w_name = wlist[i].w_name;
 490:         w->w_pri = wlist[i].w_pri;
 491:         w->w_ctime = wlist[i].w_ctime;
 492:         w->w_next = WorkQ;
 493:         WorkQ = w;
 494:     }
 495: 
 496: # ifdef DEBUG
 497:     if (tTd(40, 1))
 498:     {
 499:         for (w = WorkQ; w != NULL; w = w->w_next)
 500:             printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
 501:     }
 502: # endif DEBUG
 503: 
 504:     return (wn);
 505: }
 506: /*
 507: **  WORKCMPF -- compare function for ordering work.
 508: **
 509: **	Parameters:
 510: **		a -- the first argument.
 511: **		b -- the second argument.
 512: **
 513: **	Returns:
 514: **		-1 if a < b
 515: **		 0 if a == b
 516: **		+1 if a > b
 517: **
 518: **	Side Effects:
 519: **		none.
 520: */
 521: 
 522: workcmpf(a, b)
 523:     register WORK *a;
 524:     register WORK *b;
 525: {
 526:     long pa = a->w_pri + a->w_ctime;
 527:     long pb = b->w_pri + b->w_ctime;
 528: 
 529:     if (pa == pb)
 530:         return (0);
 531:     else if (pa > pb)
 532:         return (1);
 533:     else
 534:         return (-1);
 535: }
 536: /*
 537: **  DOWORK -- do a work request.
 538: **
 539: **	Parameters:
 540: **		w -- the work request to be satisfied.
 541: **
 542: **	Returns:
 543: **		none.
 544: **
 545: **	Side Effects:
 546: **		The work request is satisfied if possible.
 547: */
 548: 
 549: dowork(w)
 550:     register WORK *w;
 551: {
 552:     register int i;
 553:     extern bool shouldqueue();
 554: 
 555: # ifdef DEBUG
 556:     if (tTd(40, 1))
 557:         printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
 558: # endif DEBUG
 559: 
 560:     /*
 561: 	**  Ignore jobs that are too expensive for the moment.
 562: 	*/
 563: 
 564:     if (shouldqueue(w->w_pri))
 565:     {
 566:         if (Verbose)
 567:             printf("\nSkipping %s\n", w->w_name + 2);
 568:         return;
 569:     }
 570: 
 571:     /*
 572: 	**  Fork for work.
 573: 	*/
 574: 
 575:     if (ForkQueueRuns)
 576:     {
 577:         i = fork();
 578:         if (i < 0)
 579:         {
 580:             syserr("dowork: cannot fork");
 581:             return;
 582:         }
 583:     }
 584:     else
 585:     {
 586:         i = 0;
 587:     }
 588: 
 589:     if (i == 0)
 590:     {
 591:         /*
 592: 		**  CHILD
 593: 		**	Lock the control file to avoid duplicate deliveries.
 594: 		**		Then run the file as though we had just read it.
 595: 		**	We save an idea of the temporary name so we
 596: 		**		can recover on interrupt.
 597: 		*/
 598: 
 599:         /* set basic modes, etc. */
 600:         (void) alarm(0);
 601:         clearenvelope(CurEnv, FALSE);
 602:         QueueRun = TRUE;
 603:         ErrorMode = EM_MAIL;
 604:         CurEnv->e_id = &w->w_name[2];
 605: # ifdef LOG
 606:         if (LogLevel > 11)
 607:             syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id,
 608:                    getpid());
 609: # endif LOG
 610: 
 611:         /* don't use the headers from sendmail.cf... */
 612:         CurEnv->e_header = NULL;
 613: 
 614:         /* lock the control file during processing */
 615:         if (link(w->w_name, queuename(CurEnv, 'l')) < 0)
 616:         {
 617:             /* being processed by another queuer */
 618: # ifdef LOG
 619:             if (LogLevel > 4)
 620:                 syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id);
 621: # endif LOG
 622:             if (ForkQueueRuns)
 623:                 exit(EX_OK);
 624:             else
 625:                 return;
 626:         }
 627: 
 628:         /* do basic system initialization */
 629:         initsys();
 630: 
 631:         /* read the queue control file */
 632:         readqf(CurEnv, TRUE);
 633:         CurEnv->e_flags |= EF_INQUEUE;
 634:         eatheader(CurEnv);
 635: 
 636:         /* do the delivery */
 637:         if (!bitset(EF_FATALERRS, CurEnv->e_flags))
 638:             sendall(CurEnv, SM_DELIVER);
 639: 
 640:         /* finish up and exit */
 641:         if (ForkQueueRuns)
 642:             finis();
 643:         else
 644:             dropenvelope(CurEnv);
 645:     }
 646:     else
 647:     {
 648:         /*
 649: 		**  Parent -- pick up results.
 650: 		*/
 651: 
 652:         errno = 0;
 653:         (void) waitfor(i);
 654:     }
 655: }
 656: /*
 657: **  READQF -- read queue file and set up environment.
 658: **
 659: **	Parameters:
 660: **		e -- the envelope of the job to run.
 661: **		full -- if set, read in all information.  Otherwise just
 662: **			read in info needed for a queue print.
 663: **
 664: **	Returns:
 665: **		none.
 666: **
 667: **	Side Effects:
 668: **		cf is read and created as the current job, as though
 669: **		we had been invoked by argument.
 670: */
 671: 
 672: readqf(e, full)
 673:     register ENVELOPE *e;
 674:     bool full;
 675: {
 676:     char *qf;
 677:     register FILE *qfp;
 678:     char buf[MAXFIELD];
 679:     extern char *fgetfolded();
 680:     extern long atol();
 681: 
 682:     /*
 683: 	**  Read and process the file.
 684: 	*/
 685: 
 686:     qf = queuename(e, 'q');
 687:     qfp = fopen(qf, "r");
 688:     if (qfp == NULL)
 689:     {
 690:         syserr("readqf: no control file %s", qf);
 691:         return;
 692:     }
 693:     FileName = qf;
 694:     LineNumber = 0;
 695:     if (Verbose && full)
 696:         printf("\nRunning %s\n", e->e_id);
 697:     while (fgetfolded(buf, sizeof buf, qfp) != NULL)
 698:     {
 699: # ifdef DEBUG
 700:         if (tTd(40, 4))
 701:             printf("+++++ %s\n", buf);
 702: # endif DEBUG
 703:         switch (buf[0])
 704:         {
 705:           case 'R':     /* specify recipient */
 706:             sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue);
 707:             break;
 708: 
 709:           case 'E':     /* specify error recipient */
 710:             sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue);
 711:             break;
 712: 
 713:           case 'H':     /* header */
 714:             if (full)
 715:                 (void) chompheader(&buf[1], FALSE);
 716:             break;
 717: 
 718:           case 'M':     /* message */
 719:             e->e_message = newstr(&buf[1]);
 720:             break;
 721: 
 722:           case 'S':     /* sender */
 723:             setsender(newstr(&buf[1]));
 724:             break;
 725: 
 726:           case 'D':     /* data file name */
 727:             if (!full)
 728:                 break;
 729:             e->e_df = newstr(&buf[1]);
 730:             e->e_dfp = fopen(e->e_df, "r");
 731:             if (e->e_dfp == NULL)
 732:                 syserr("readqf: cannot open %s", e->e_df);
 733:             break;
 734: 
 735:           case 'T':     /* init time */
 736:             e->e_ctime = atol(&buf[1]);
 737:             break;
 738: 
 739:           case 'P':     /* message priority */
 740:             e->e_msgpriority = atol(&buf[1]) + WkTimeFact;
 741:             break;
 742: 
 743:           case '\0':        /* blank line; ignore */
 744:             break;
 745: 
 746:           default:
 747:             syserr("readqf(%s:%d): bad line \"%s\"", e->e_id,
 748:                 LineNumber, buf);
 749:             break;
 750:         }
 751:     }
 752: 
 753:     (void) fclose(qfp);
 754:     FileName = NULL;
 755: 
 756:     /*
 757: 	**  If we haven't read any lines, this queue file is empty.
 758: 	**  Arrange to remove it without referencing any null pointers.
 759: 	*/
 760: 
 761:     if (LineNumber == 0)
 762:     {
 763:         errno = 0;
 764:         e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
 765:     }
 766: }
 767: /*
 768: **  PRINTQUEUE -- print out a representation of the mail queue
 769: **
 770: **	Parameters:
 771: **		none.
 772: **
 773: **	Returns:
 774: **		none.
 775: **
 776: **	Side Effects:
 777: **		Prints a listing of the mail queue on the standard output.
 778: */
 779: 
 780: printqueue()
 781: {
 782:     register WORK *w;
 783:     FILE *f;
 784:     int nrequests;
 785:     char buf[MAXLINE];
 786: 
 787:     /*
 788: 	**  Read and order the queue.
 789: 	*/
 790: 
 791:     nrequests = orderq(TRUE);
 792: 
 793:     /*
 794: 	**  Print the work list that we have read.
 795: 	*/
 796: 
 797:     /* first see if there is anything */
 798:     if (nrequests <= 0)
 799:     {
 800:         printf("Mail queue is empty\n");
 801:         return;
 802:     }
 803: 
 804:     printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
 805:     if (nrequests > QUEUESIZE)
 806:         printf(", only %d printed", QUEUESIZE);
 807:     if (Verbose)
 808:         printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
 809:     else
 810:         printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
 811:     for (w = WorkQ; w != NULL; w = w->w_next)
 812:     {
 813:         struct stat st;
 814:         auto time_t submittime = 0;
 815:         long dfsize = -1;
 816:         char lf[20];
 817:         char message[MAXLINE];
 818:         extern bool shouldqueue();
 819: 
 820:         f = fopen(w->w_name, "r");
 821:         if (f == NULL)
 822:         {
 823:             errno = 0;
 824:             continue;
 825:         }
 826:         printf("%7s", w->w_name + 2);
 827:         (void) strcpy(lf, w->w_name);
 828:         lf[0] = 'l';
 829:         if (stat(lf, &st) >= 0)
 830:             printf("*");
 831:         else if (shouldqueue(w->w_pri))
 832:             printf("X");
 833:         else
 834:             printf(" ");
 835:         errno = 0;
 836: 
 837:         message[0] = '\0';
 838:         while (fgets(buf, sizeof buf, f) != NULL)
 839:         {
 840:             fixcrlf(buf, TRUE);
 841:             switch (buf[0])
 842:             {
 843:               case 'M': /* error message */
 844:                 (void) strcpy(message, &buf[1]);
 845:                 break;
 846: 
 847:               case 'S': /* sender name */
 848:                 if (Verbose)
 849:                     printf("%8ld %10ld %.12s %.38s", dfsize,
 850:                         w->w_pri, ctime(&submittime) + 4,
 851:                         &buf[1]);
 852:                 else
 853:                     printf("%8ld %.16s %.45s", dfsize,
 854:                         ctime(&submittime), &buf[1]);
 855:                 if (message[0] != '\0')
 856:                     printf("\n\t\t (%.60s)", message);
 857:                 break;
 858: 
 859:               case 'R': /* recipient name */
 860:                 if (Verbose)
 861:                     printf("\n\t\t\t\t\t %.38s", &buf[1]);
 862:                 else
 863:                     printf("\n\t\t\t\t  %.45s", &buf[1]);
 864:                 break;
 865: 
 866:               case 'T': /* creation time */
 867:                 submittime = atol(&buf[1]);
 868:                 break;
 869: 
 870:               case 'D': /* data file name */
 871:                 if (stat(&buf[1], &st) >= 0)
 872:                     dfsize = st.st_size;
 873:                 break;
 874:             }
 875:         }
 876:         if (submittime == (time_t) 0)
 877:             printf(" (no control file)");
 878:         printf("\n");
 879:         (void) fclose(f);
 880:     }
 881: }
 882: 
 883: # endif QUEUE
 884: /*
 885: **  QUEUENAME -- build a file name in the queue directory for this envelope.
 886: **
 887: **	Assigns an id code if one does not already exist.
 888: **	This code is very careful to avoid trashing existing files
 889: **	under any circumstances.
 890: **		We first create an nf file that is only used when
 891: **		assigning an id.  This file is always empty, so that
 892: **		we can never accidently truncate an lf file.
 893: **
 894: **	Parameters:
 895: **		e -- envelope to build it in/from.
 896: **		type -- the file type, used as the first character
 897: **			of the file name.
 898: **
 899: **	Returns:
 900: **		a pointer to the new file name (in a static buffer).
 901: **
 902: **	Side Effects:
 903: **		Will create the lf and qf files if no id code is
 904: **		already assigned.  This will cause the envelope
 905: **		to be modified.
 906: */
 907: 
 908: char *
 909: queuename(e, type)
 910:     register ENVELOPE *e;
 911:     char type;
 912: {
 913:     static char buf[MAXNAME];
 914:     static int pid = -1;
 915:     char c1 = 'A';
 916:     char c2 = 'A';
 917: 
 918:     if (e->e_id == NULL)
 919:     {
 920:         char qf[20];
 921:         char nf[20];
 922:         char lf[20];
 923: 
 924:         /* find a unique id */
 925:         if (pid != getpid())
 926:         {
 927:             /* new process -- start back at "AA" */
 928:             pid = getpid();
 929:             c1 = 'A';
 930:             c2 = 'A' - 1;
 931:         }
 932:         (void) sprintf(qf, "qfAA%05d", pid);
 933:         (void) strcpy(lf, qf);
 934:         lf[0] = 'l';
 935:         (void) strcpy(nf, qf);
 936:         nf[0] = 'n';
 937: 
 938:         while (c1 < '~' || c2 < 'Z')
 939:         {
 940:             int i;
 941: 
 942:             if (c2 >= 'Z')
 943:             {
 944:                 c1++;
 945:                 c2 = 'A' - 1;
 946:             }
 947:             lf[2] = nf[2] = qf[2] = c1;
 948:             lf[3] = nf[3] = qf[3] = ++c2;
 949: # ifdef DEBUG
 950:             if (tTd(7, 20))
 951:                 printf("queuename: trying \"%s\"\n", nf);
 952: # endif DEBUG
 953: 
 954: # ifdef QUEUE
 955:             if (access(lf, 0) >= 0 || access(qf, 0) >= 0)
 956:                 continue;
 957:             errno = 0;
 958:             i = creat(nf, FileMode);
 959:             if (i < 0)
 960:             {
 961:                 (void) unlink(nf);  /* kernel bug */
 962:                 continue;
 963:             }
 964:             (void) close(i);
 965:             i = link(nf, lf);
 966:             (void) unlink(nf);
 967:             if (i < 0)
 968:                 continue;
 969:             if (link(lf, qf) >= 0)
 970:                 break;
 971:             (void) unlink(lf);
 972: # else QUEUE
 973:             if (close(creat(qf, FileMode)) >= 0)
 974:                 break;
 975: # endif QUEUE
 976:         }
 977:         if (c1 >= '~' && c2 >= 'Z')
 978:         {
 979:             syserr("queuename: Cannot create \"%s\" in \"%s\"",
 980:                 qf, QueueDir);
 981:             exit(EX_OSERR);
 982:         }
 983:         e->e_id = newstr(&qf[2]);
 984:         define('i', e->e_id, e);
 985: # ifdef DEBUG
 986:         if (tTd(7, 1))
 987:             printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
 988: # ifdef LOG
 989:         if (LogLevel > 16)
 990:             syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
 991: # endif LOG
 992: # endif DEBUG
 993:     }
 994: 
 995:     if (type == '\0')
 996:         return (NULL);
 997:     (void) sprintf(buf, "%cf%s", type, e->e_id);
 998: # ifdef DEBUG
 999:     if (tTd(7, 2))
1000:         printf("queuename: %s\n", buf);
1001: # endif DEBUG
1002:     return (buf);
1003: }
1004: /*
1005: **  UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1006: **
1007: **	Parameters:
1008: **		e -- the envelope to unlock.
1009: **
1010: **	Returns:
1011: **		none
1012: **
1013: **	Side Effects:
1014: **		unlocks the queue for `e'.
1015: */
1016: 
1017: unlockqueue(e)
1018:     ENVELOPE *e;
1019: {
1020:     /* remove the transcript */
1021: #ifdef DEBUG
1022: # ifdef LOG
1023:     if (LogLevel > 19)
1024:         syslog(LOG_DEBUG, "%s: unlock", e->e_id);
1025: # endif LOG
1026:     if (!tTd(51, 4))
1027: #endif DEBUG
1028:         xunlink(queuename(e, 'x'));
1029: 
1030: # ifdef QUEUE
1031:     /* last but not least, remove the lock */
1032:     xunlink(queuename(e, 'l'));
1033: # endif QUEUE
1034: }

Defined functions

dowork defined in line 549; used 1 times
orderq defined in line 377; used 2 times
printqueue defined in line 780; used 1 times
readqf defined in line 672; used 1 times
runqueue defined in line 262; used 3 times
workcmpf defined in line 522; used 2 times

Defined variables

SccsId defined in line 25; never used
WorkQ defined in line 42; used 11 times

Defined struct's

work defined in line 32; used 4 times

Defined typedef's

WORK defined in line 40; used 10 times

Defined macros

NEED_P defined in line 374; used 2 times
NEED_T defined in line 375; used 2 times
Last modified: 1986-04-18
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2627
Valid CSS Valid XHTML 1.0 Strict