122708Sdist /* 222708Sdist ** Sendmail 322708Sdist ** Copyright (c) 1983 Eric P. Allman 422708Sdist ** Berkeley, California 522708Sdist ** 622708Sdist ** Copyright (c) 1983 Regents of the University of California. 722708Sdist ** All rights reserved. The Berkeley software License Agreement 822708Sdist ** specifies the terms and conditions for redistribution. 922708Sdist */ 1022708Sdist 1122708Sdist 124632Seric # include "sendmail.h" 134632Seric # include <sys/stat.h> 1413707Ssam # include <sys/dir.h> 154634Seric # include <signal.h> 164632Seric # include <errno.h> 174632Seric 185182Seric # ifndef QUEUE 1923116Seric # ifndef lint 20*29866Seric static char SccsId[] = "@(#)queue.c 5.22 (Berkeley) 10/14/86 (no queueing)"; 2123116Seric # endif not lint 225182Seric # else QUEUE 234632Seric 2423116Seric # ifndef lint 25*29866Seric static char SccsId[] = "@(#)queue.c 5.22 (Berkeley) 10/14/86"; 2623116Seric # endif not lint 275182Seric 284632Seric /* 299377Seric ** Work queue. 309377Seric */ 319377Seric 329377Seric struct work 339377Seric { 349377Seric char *w_name; /* name of control file */ 359377Seric long w_pri; /* priority of message, see below */ 3625013Seric time_t w_ctime; /* creation time of message */ 379377Seric struct work *w_next; /* next in queue */ 389377Seric }; 399377Seric 409377Seric typedef struct work WORK; 419377Seric 429377Seric WORK *WorkQ; /* queue of things to be done */ 439377Seric /* 444632Seric ** QUEUEUP -- queue a message up for future transmission. 454632Seric ** 464632Seric ** Parameters: 476980Seric ** e -- the envelope to queue up. 486999Seric ** queueall -- if TRUE, queue all addresses, rather than 496999Seric ** just those with the QQUEUEUP flag set. 509377Seric ** announce -- if TRUE, tell when you are queueing up. 514632Seric ** 524632Seric ** Returns: 534632Seric ** none. 544632Seric ** 554632Seric ** Side Effects: 569377Seric ** The current request are saved in a control file. 574632Seric */ 584632Seric 599377Seric queueup(e, queueall, announce) 606980Seric register ENVELOPE *e; 616999Seric bool queueall; 629377Seric bool announce; 634632Seric { 647812Seric char *tf; 657812Seric char *qf; 667763Seric char buf[MAXLINE]; 677812Seric register FILE *tfp; 684632Seric register HDR *h; 695007Seric register ADDRESS *q; 7010173Seric MAILER nullmailer; 714632Seric 725037Seric /* 7317477Seric ** Create control file. 745037Seric */ 754632Seric 7617477Seric tf = newstr(queuename(e, 't')); 7717477Seric tfp = fopen(tf, "w"); 787812Seric if (tfp == NULL) 794632Seric { 8017477Seric syserr("queueup: cannot create temp file %s", tf); 8117477Seric return; 824632Seric } 8317477Seric (void) chmod(tf, FileMode); 844632Seric 854632Seric # ifdef DEBUG 867677Seric if (tTd(40, 1)) 8717468Seric printf("queueing %s\n", e->e_id); 884632Seric # endif DEBUG 894632Seric 904632Seric /* 916980Seric ** If there is no data file yet, create one. 926980Seric */ 936980Seric 946980Seric if (e->e_df == NULL) 956980Seric { 966980Seric register FILE *dfp; 979389Seric extern putbody(); 986980Seric 997812Seric e->e_df = newstr(queuename(e, 'd')); 1006980Seric dfp = fopen(e->e_df, "w"); 1016980Seric if (dfp == NULL) 1026980Seric { 1036980Seric syserr("queueup: cannot create %s", e->e_df); 1047812Seric (void) fclose(tfp); 1056980Seric return; 1066980Seric } 1079048Seric (void) chmod(e->e_df, FileMode); 10810173Seric (*e->e_putbody)(dfp, ProgMailer, e); 1097009Seric (void) fclose(dfp); 1109389Seric e->e_putbody = putbody; 1116980Seric } 1126980Seric 1136980Seric /* 1144632Seric ** Output future work requests. 11525687Seric ** Priority and creation time should be first, since 11625687Seric ** they are required by orderq. 1174632Seric */ 1184632Seric 1199377Seric /* output message priority */ 1209377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1219377Seric 1229630Seric /* output creation time */ 1239630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1249630Seric 1254632Seric /* output name of data file */ 1267812Seric fprintf(tfp, "D%s\n", e->e_df); 1274632Seric 12810108Seric /* message from envelope, if it exists */ 12910108Seric if (e->e_message != NULL) 13010108Seric fprintf(tfp, "M%s\n", e->e_message); 13110108Seric 1324632Seric /* output name of sender */ 1337812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1344632Seric 1354632Seric /* output list of recipient addresses */ 1366980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1374632Seric { 1387763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1397763Seric bitset(QQUEUEUP, q->q_flags)) 1408245Seric { 1417812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1429377Seric if (announce) 1439377Seric { 1449377Seric e->e_to = q->q_paddr; 1459377Seric message(Arpa_Info, "queued"); 1469377Seric if (LogLevel > 4) 1479377Seric logdelivery("queued"); 1489377Seric e->e_to = NULL; 1499377Seric } 1509387Seric #ifdef DEBUG 1519387Seric if (tTd(40, 1)) 1529387Seric { 1539387Seric printf("queueing "); 1549387Seric printaddr(q, FALSE); 1559387Seric } 1569387Seric #endif DEBUG 1578245Seric } 1584632Seric } 1594632Seric 16025687Seric /* output list of error recipients */ 16125687Seric for (q = e->e_errorqueue; q != NULL; q = q->q_next) 16225687Seric { 16326504Seric if (!bitset(QDONTSEND, q->q_flags)) 16426504Seric fprintf(tfp, "E%s\n", q->q_paddr); 16525687Seric } 16625687Seric 1679377Seric /* 1689377Seric ** Output headers for this message. 1699377Seric ** Expand macros completely here. Queue run will deal with 1709377Seric ** everything as absolute headers. 1719377Seric ** All headers that must be relative to the recipient 1729377Seric ** can be cracked later. 17310173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 17410173Seric ** no effect on the addresses as they are output. 1759377Seric */ 1769377Seric 17710686Seric bzero((char *) &nullmailer, sizeof nullmailer); 17810173Seric nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 17910349Seric nullmailer.m_eol = "\n"; 18010173Seric 18116147Seric define('g', "\001f", e); 1826980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1834632Seric { 18410686Seric extern bool bitzerop(); 18510686Seric 18612015Seric /* don't output null headers */ 1874632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1884632Seric continue; 18912015Seric 19012015Seric /* don't output resent headers on non-resent messages */ 19112015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 19212015Seric continue; 19312015Seric 19412015Seric /* output this header */ 1957812Seric fprintf(tfp, "H"); 19612015Seric 19712015Seric /* if conditional, output the set of conditions */ 19810686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 19910686Seric { 20010686Seric int j; 20110686Seric 20223098Seric (void) putc('?', tfp); 20310686Seric for (j = '\0'; j <= '\177'; j++) 20410686Seric if (bitnset(j, h->h_mflags)) 20523098Seric (void) putc(j, tfp); 20623098Seric (void) putc('?', tfp); 20710686Seric } 20812015Seric 20912015Seric /* output the header: expand macros, convert addresses */ 2107763Seric if (bitset(H_DEFAULT, h->h_flags)) 2117763Seric { 2127763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 2138236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 2147763Seric } 2158245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 2169348Seric { 2179348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 21810173Seric &nullmailer); 2199348Seric } 2207763Seric else 2218245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 2224632Seric } 2234632Seric 2244632Seric /* 2254632Seric ** Clean up. 2264632Seric */ 2274632Seric 22817477Seric (void) fclose(tfp); 22917468Seric qf = queuename(e, 'q'); 23017468Seric if (tf != NULL) 23117468Seric { 23217468Seric (void) unlink(qf); 23324968Seric if (rename(tf, qf) < 0) 23424968Seric syserr("cannot unlink(%s, %s), df=%s", tf, qf, e->e_df); 23524968Seric errno = 0; 23617468Seric } 2377391Seric 2387677Seric # ifdef LOG 2397677Seric /* save log info */ 2407878Seric if (LogLevel > 15) 2417878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 2427677Seric # endif LOG 2434632Seric } 2444632Seric /* 2454632Seric ** RUNQUEUE -- run the jobs in the queue. 2464632Seric ** 2474632Seric ** Gets the stuff out of the queue in some presumably logical 2484632Seric ** order and processes them. 2494632Seric ** 2504632Seric ** Parameters: 25124941Seric ** forkflag -- TRUE if the queue scanning should be done in 25224941Seric ** a child process. We double-fork so it is not our 25324941Seric ** child and we don't have to clean up after it. 2544632Seric ** 2554632Seric ** Returns: 2564632Seric ** none. 2574632Seric ** 2584632Seric ** Side Effects: 2594632Seric ** runs things in the mail queue. 2604632Seric */ 2614632Seric 2624639Seric runqueue(forkflag) 2634639Seric bool forkflag; 2644632Seric { 26524953Seric extern bool shouldqueue(); 26624953Seric 2677466Seric /* 26824953Seric ** If no work will ever be selected, don't even bother reading 26924953Seric ** the queue. 27024953Seric */ 27124953Seric 27224953Seric if (shouldqueue(-100000000L)) 27324953Seric { 27424953Seric if (Verbose) 27524953Seric printf("Skipping queue run -- load average too high\n"); 27624953Seric 27724953Seric if (forkflag) 27824953Seric return; 27924953Seric finis(); 28024953Seric } 28124953Seric 28224953Seric /* 2837466Seric ** See if we want to go off and do other useful work. 2847466Seric */ 2854639Seric 2864639Seric if (forkflag) 2874639Seric { 2887943Seric int pid; 2897943Seric 2907943Seric pid = dofork(); 2917943Seric if (pid != 0) 2924639Seric { 29325184Seric extern reapchild(); 29425184Seric 2957943Seric /* parent -- pick up intermediate zombie */ 29625184Seric #ifndef SIGCHLD 2979377Seric (void) waitfor(pid); 29825184Seric #else SIGCHLD 29925184Seric (void) signal(SIGCHLD, reapchild); 30025184Seric #endif SIGCHLD 3017690Seric if (QueueIntvl != 0) 3029348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 3034639Seric return; 3044639Seric } 3057943Seric /* child -- double fork */ 30625184Seric #ifndef SIGCHLD 3077943Seric if (fork() != 0) 3087943Seric exit(EX_OK); 30925184Seric #else SIGCHLD 31025184Seric (void) signal(SIGCHLD, SIG_DFL); 31125184Seric #endif SIGCHLD 3124639Seric } 31324941Seric 31424941Seric setproctitle("running queue"); 31524941Seric 3167876Seric # ifdef LOG 3177876Seric if (LogLevel > 11) 3187943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 3197876Seric # endif LOG 3204639Seric 3217466Seric /* 32210205Seric ** Release any resources used by the daemon code. 32310205Seric */ 32410205Seric 32510205Seric # ifdef DAEMON 32610205Seric clrdaemon(); 32710205Seric # endif DAEMON 32810205Seric 32910205Seric /* 33027175Seric ** Make sure the alias database is open. 33127175Seric */ 33227175Seric 33327175Seric initaliases(AliasFile, FALSE); 33427175Seric 33527175Seric /* 3367466Seric ** Start making passes through the queue. 3377466Seric ** First, read and sort the entire queue. 3387466Seric ** Then, process the work in that order. 3397466Seric ** But if you take too long, start over. 3407466Seric */ 3417466Seric 3427943Seric /* order the existing work requests */ 34324954Seric (void) orderq(FALSE); 3447690Seric 3457943Seric /* process them once at a time */ 3467943Seric while (WorkQ != NULL) 3474639Seric { 3487943Seric WORK *w = WorkQ; 3497881Seric 3507943Seric WorkQ = WorkQ->w_next; 3517943Seric dowork(w); 3527943Seric free(w->w_name); 3537943Seric free((char *) w); 3544639Seric } 355*29866Seric 356*29866Seric /* exit without the usual cleanup */ 357*29866Seric exit(ExitStat); 3584634Seric } 3594634Seric /* 3604632Seric ** ORDERQ -- order the work queue. 3614632Seric ** 3624632Seric ** Parameters: 36324941Seric ** doall -- if set, include everything in the queue (even 36424941Seric ** the jobs that cannot be run because the load 36524941Seric ** average is too high). Otherwise, exclude those 36624941Seric ** jobs. 3674632Seric ** 3684632Seric ** Returns: 36910121Seric ** The number of request in the queue (not necessarily 37010121Seric ** the number of requests in WorkQ however). 3714632Seric ** 3724632Seric ** Side Effects: 3734632Seric ** Sets WorkQ to the queue of available work, in order. 3744632Seric */ 3754632Seric 37625687Seric # define NEED_P 001 37725687Seric # define NEED_T 002 3784632Seric 37924941Seric orderq(doall) 38024941Seric bool doall; 3814632Seric { 3826625Sglickman register struct direct *d; 3834632Seric register WORK *w; 3846625Sglickman DIR *f; 3854632Seric register int i; 38625687Seric WORK wlist[QUEUESIZE+1]; 38710070Seric int wn = -1; 3884632Seric extern workcmpf(); 3894632Seric 3904632Seric /* clear out old WorkQ */ 3914632Seric for (w = WorkQ; w != NULL; ) 3924632Seric { 3934632Seric register WORK *nw = w->w_next; 3944632Seric 3954632Seric WorkQ = nw; 3964632Seric free(w->w_name); 3974632Seric free((char *) w); 3984632Seric w = nw; 3994632Seric } 4004632Seric 4014632Seric /* open the queue directory */ 4028148Seric f = opendir("."); 4034632Seric if (f == NULL) 4044632Seric { 4058148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 40610070Seric return (0); 4074632Seric } 4084632Seric 4094632Seric /* 4104632Seric ** Read the work directory. 4114632Seric */ 4124632Seric 41310070Seric while ((d = readdir(f)) != NULL) 4144632Seric { 4159377Seric FILE *cf; 4164632Seric char lbuf[MAXNAME]; 4174632Seric 4184632Seric /* is this an interesting entry? */ 4197812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 4204632Seric continue; 4214632Seric 42210070Seric /* yes -- open control file (if not too many files) */ 42325687Seric if (++wn >= QUEUESIZE) 42410070Seric continue; 4258148Seric cf = fopen(d->d_name, "r"); 4264632Seric if (cf == NULL) 4274632Seric { 4287055Seric /* this may be some random person sending hir msgs */ 4297055Seric /* syserr("orderq: cannot open %s", cbuf); */ 43010090Seric #ifdef DEBUG 43110090Seric if (tTd(41, 2)) 43210090Seric printf("orderq: cannot open %s (%d)\n", 43310090Seric d->d_name, errno); 43410090Seric #endif DEBUG 4357055Seric errno = 0; 43610090Seric wn--; 4374632Seric continue; 4384632Seric } 43925687Seric w = &wlist[wn]; 44025687Seric w->w_name = newstr(d->d_name); 4414632Seric 44225027Seric /* make sure jobs in creation don't clog queue */ 44325687Seric w->w_pri = 0x7fffffff; 44425687Seric w->w_ctime = 0; 44525027Seric 4464632Seric /* extract useful information */ 44725687Seric i = NEED_P | NEED_T; 44825687Seric while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 4494632Seric { 45024954Seric extern long atol(); 45124954Seric 45224941Seric switch (lbuf[0]) 4534632Seric { 45424941Seric case 'P': 45525687Seric w->w_pri = atol(&lbuf[1]); 45625687Seric i &= ~NEED_P; 4574632Seric break; 45825013Seric 45925013Seric case 'T': 46025687Seric w->w_ctime = atol(&lbuf[1]); 46125687Seric i &= ~NEED_T; 46225013Seric break; 4634632Seric } 4644632Seric } 4654632Seric (void) fclose(cf); 46624953Seric 46725687Seric if (!doall && shouldqueue(w->w_pri)) 46824953Seric { 46924953Seric /* don't even bother sorting this job in */ 47024953Seric wn--; 47124953Seric } 4724632Seric } 4736625Sglickman (void) closedir(f); 47410090Seric wn++; 4754632Seric 4764632Seric /* 4774632Seric ** Sort the work directory. 4784632Seric */ 4794632Seric 48025687Seric qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); 4814632Seric 4824632Seric /* 4834632Seric ** Convert the work list into canonical form. 4849377Seric ** Should be turning it into a list of envelopes here perhaps. 4854632Seric */ 4864632Seric 48724981Seric WorkQ = NULL; 48825687Seric for (i = min(wn, QUEUESIZE); --i >= 0; ) 4894632Seric { 4904632Seric w = (WORK *) xalloc(sizeof *w); 4914632Seric w->w_name = wlist[i].w_name; 4924632Seric w->w_pri = wlist[i].w_pri; 49325013Seric w->w_ctime = wlist[i].w_ctime; 49424981Seric w->w_next = WorkQ; 49524981Seric WorkQ = w; 4964632Seric } 4974632Seric 4984632Seric # ifdef DEBUG 4997677Seric if (tTd(40, 1)) 5004632Seric { 5014632Seric for (w = WorkQ; w != NULL; w = w->w_next) 5025037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 5034632Seric } 5044632Seric # endif DEBUG 50510070Seric 50610090Seric return (wn); 5074632Seric } 5084632Seric /* 5097677Seric ** WORKCMPF -- compare function for ordering work. 5104632Seric ** 5114632Seric ** Parameters: 5124632Seric ** a -- the first argument. 5134632Seric ** b -- the second argument. 5144632Seric ** 5154632Seric ** Returns: 51624981Seric ** -1 if a < b 51724981Seric ** 0 if a == b 51824981Seric ** +1 if a > b 5194632Seric ** 5204632Seric ** Side Effects: 5214632Seric ** none. 5224632Seric */ 5234632Seric 5244632Seric workcmpf(a, b) 5255037Seric register WORK *a; 5265037Seric register WORK *b; 5274632Seric { 52825013Seric long pa = a->w_pri + a->w_ctime; 52925013Seric long pb = b->w_pri + b->w_ctime; 53024941Seric 53124941Seric if (pa == pb) 5324632Seric return (0); 53324941Seric else if (pa > pb) 53424981Seric return (1); 53524981Seric else 53610121Seric return (-1); 5374632Seric } 5384632Seric /* 5394632Seric ** DOWORK -- do a work request. 5404632Seric ** 5414632Seric ** Parameters: 5424632Seric ** w -- the work request to be satisfied. 5434632Seric ** 5444632Seric ** Returns: 5454632Seric ** none. 5464632Seric ** 5474632Seric ** Side Effects: 5484632Seric ** The work request is satisfied if possible. 5494632Seric */ 5504632Seric 5514632Seric dowork(w) 5524632Seric register WORK *w; 5534632Seric { 5544632Seric register int i; 55524941Seric extern bool shouldqueue(); 5564632Seric 5574632Seric # ifdef DEBUG 5587677Seric if (tTd(40, 1)) 5595037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 5604632Seric # endif DEBUG 5614632Seric 5624632Seric /* 56324941Seric ** Ignore jobs that are too expensive for the moment. 5644632Seric */ 5654632Seric 56624941Seric if (shouldqueue(w->w_pri)) 5674632Seric { 56824941Seric if (Verbose) 56924967Seric printf("\nSkipping %s\n", w->w_name + 2); 5704632Seric return; 5714632Seric } 5724632Seric 57324941Seric /* 57424941Seric ** Fork for work. 57524941Seric */ 57624941Seric 57724941Seric if (ForkQueueRuns) 57824941Seric { 57924941Seric i = fork(); 58024941Seric if (i < 0) 58124941Seric { 58224941Seric syserr("dowork: cannot fork"); 58324941Seric return; 58424941Seric } 58524941Seric } 58624941Seric else 58724941Seric { 58824941Seric i = 0; 58924941Seric } 59024941Seric 5914632Seric if (i == 0) 5924632Seric { 5934632Seric /* 5944632Seric ** CHILD 5958148Seric ** Lock the control file to avoid duplicate deliveries. 5968148Seric ** Then run the file as though we had just read it. 5977350Seric ** We save an idea of the temporary name so we 5987350Seric ** can recover on interrupt. 5994632Seric */ 6004632Seric 6017763Seric /* set basic modes, etc. */ 6027356Seric (void) alarm(0); 60325612Seric clearenvelope(CurEnv, FALSE); 6044632Seric QueueRun = TRUE; 6059377Seric ErrorMode = EM_MAIL; 6068148Seric CurEnv->e_id = &w->w_name[2]; 6077876Seric # ifdef LOG 6087876Seric if (LogLevel > 11) 6097881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 6107881Seric getpid()); 6117876Seric # endif LOG 6127763Seric 6137763Seric /* don't use the headers from sendmail.cf... */ 6147763Seric CurEnv->e_header = NULL; 6157763Seric 61617468Seric /* lock the control file during processing */ 6177812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 6186980Seric { 6197812Seric /* being processed by another queuer */ 6207881Seric # ifdef LOG 6217881Seric if (LogLevel > 4) 6227881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 6237881Seric # endif LOG 62424941Seric if (ForkQueueRuns) 62524941Seric exit(EX_OK); 62624941Seric else 62724941Seric return; 6286980Seric } 6296980Seric 6306980Seric /* do basic system initialization */ 6314632Seric initsys(); 6326980Seric 6336980Seric /* read the queue control file */ 63417477Seric readqf(CurEnv, TRUE); 6359338Seric CurEnv->e_flags |= EF_INQUEUE; 6369377Seric eatheader(CurEnv); 6376980Seric 6386980Seric /* do the delivery */ 6399338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 6409282Seric sendall(CurEnv, SM_DELIVER); 6416980Seric 6426980Seric /* finish up and exit */ 64324941Seric if (ForkQueueRuns) 64424941Seric finis(); 64524941Seric else 64624941Seric dropenvelope(CurEnv); 6474632Seric } 64824941Seric else 64924941Seric { 65024941Seric /* 65124941Seric ** Parent -- pick up results. 65224941Seric */ 6534632Seric 65424941Seric errno = 0; 65524941Seric (void) waitfor(i); 65624941Seric } 6574632Seric } 6584632Seric /* 6594632Seric ** READQF -- read queue file and set up environment. 6604632Seric ** 6614632Seric ** Parameters: 6629377Seric ** e -- the envelope of the job to run. 6639630Seric ** full -- if set, read in all information. Otherwise just 6649630Seric ** read in info needed for a queue print. 6654632Seric ** 6664632Seric ** Returns: 6674632Seric ** none. 6684632Seric ** 6694632Seric ** Side Effects: 6704632Seric ** cf is read and created as the current job, as though 6714632Seric ** we had been invoked by argument. 6724632Seric */ 6734632Seric 67417477Seric readqf(e, full) 6759377Seric register ENVELOPE *e; 6769630Seric bool full; 6774632Seric { 67817477Seric char *qf; 67917477Seric register FILE *qfp; 6807785Seric char buf[MAXFIELD]; 6819348Seric extern char *fgetfolded(); 68224954Seric extern long atol(); 6834632Seric 6844632Seric /* 68517468Seric ** Read and process the file. 6864632Seric */ 6874632Seric 68817477Seric qf = queuename(e, 'q'); 68917477Seric qfp = fopen(qf, "r"); 69017477Seric if (qfp == NULL) 69117477Seric { 69217477Seric syserr("readqf: no control file %s", qf); 69317477Seric return; 69417477Seric } 69517477Seric FileName = qf; 6969377Seric LineNumber = 0; 6979630Seric if (Verbose && full) 6989377Seric printf("\nRunning %s\n", e->e_id); 69917468Seric while (fgetfolded(buf, sizeof buf, qfp) != NULL) 7004632Seric { 70126504Seric # ifdef DEBUG 70226504Seric if (tTd(40, 4)) 70326504Seric printf("+++++ %s\n", buf); 70426504Seric # endif DEBUG 7054632Seric switch (buf[0]) 7064632Seric { 7074632Seric case 'R': /* specify recipient */ 7089618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 7094632Seric break; 7104632Seric 71125687Seric case 'E': /* specify error recipient */ 71225687Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue); 71325687Seric break; 71425687Seric 7154632Seric case 'H': /* header */ 7169630Seric if (full) 7179630Seric (void) chompheader(&buf[1], FALSE); 7184632Seric break; 7194632Seric 72010108Seric case 'M': /* message */ 72110108Seric e->e_message = newstr(&buf[1]); 72210108Seric break; 72310108Seric 7244632Seric case 'S': /* sender */ 7254634Seric setsender(newstr(&buf[1])); 7264632Seric break; 7274632Seric 7284632Seric case 'D': /* data file name */ 7299630Seric if (!full) 7309630Seric break; 7319377Seric e->e_df = newstr(&buf[1]); 7329544Seric e->e_dfp = fopen(e->e_df, "r"); 7339544Seric if (e->e_dfp == NULL) 7349377Seric syserr("readqf: cannot open %s", e->e_df); 7354632Seric break; 7364632Seric 7377860Seric case 'T': /* init time */ 73824941Seric e->e_ctime = atol(&buf[1]); 7394632Seric break; 7404632Seric 7414634Seric case 'P': /* message priority */ 74225008Seric e->e_msgpriority = atol(&buf[1]) + WkTimeFact; 7434634Seric break; 7444634Seric 74524941Seric case '\0': /* blank line; ignore */ 74624941Seric break; 74724941Seric 7484632Seric default: 74924941Seric syserr("readqf(%s:%d): bad line \"%s\"", e->e_id, 75024941Seric LineNumber, buf); 7514632Seric break; 7524632Seric } 7534632Seric } 7549377Seric 75524954Seric (void) fclose(qfp); 7569377Seric FileName = NULL; 75724941Seric 75824941Seric /* 75924941Seric ** If we haven't read any lines, this queue file is empty. 76024941Seric ** Arrange to remove it without referencing any null pointers. 76124941Seric */ 76224941Seric 76324941Seric if (LineNumber == 0) 76424941Seric { 76524941Seric errno = 0; 76624941Seric e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 76724941Seric } 7684632Seric } 7694632Seric /* 7709630Seric ** PRINTQUEUE -- print out a representation of the mail queue 7719630Seric ** 7729630Seric ** Parameters: 7739630Seric ** none. 7749630Seric ** 7759630Seric ** Returns: 7769630Seric ** none. 7779630Seric ** 7789630Seric ** Side Effects: 7799630Seric ** Prints a listing of the mail queue on the standard output. 7809630Seric */ 7815182Seric 7829630Seric printqueue() 7839630Seric { 7849630Seric register WORK *w; 7859630Seric FILE *f; 78610070Seric int nrequests; 7879630Seric char buf[MAXLINE]; 7889630Seric 7899630Seric /* 7909630Seric ** Read and order the queue. 7919630Seric */ 7929630Seric 79324941Seric nrequests = orderq(TRUE); 7949630Seric 7959630Seric /* 7969630Seric ** Print the work list that we have read. 7979630Seric */ 7989630Seric 7999630Seric /* first see if there is anything */ 80010070Seric if (nrequests <= 0) 8019630Seric { 80210070Seric printf("Mail queue is empty\n"); 8039630Seric return; 8049630Seric } 8059630Seric 80610096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 80725687Seric if (nrequests > QUEUESIZE) 80825687Seric printf(", only %d printed", QUEUESIZE); 80924979Seric if (Verbose) 81025032Seric printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 81124979Seric else 81224979Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 8139630Seric for (w = WorkQ; w != NULL; w = w->w_next) 8149630Seric { 8159630Seric struct stat st; 81610070Seric auto time_t submittime = 0; 81710070Seric long dfsize = -1; 81810108Seric char lf[20]; 81910108Seric char message[MAXLINE]; 82024941Seric extern bool shouldqueue(); 8219630Seric 82217468Seric f = fopen(w->w_name, "r"); 82317468Seric if (f == NULL) 82417468Seric { 82517468Seric errno = 0; 82617468Seric continue; 82717468Seric } 8289630Seric printf("%7s", w->w_name + 2); 82923098Seric (void) strcpy(lf, w->w_name); 83010070Seric lf[0] = 'l'; 83110070Seric if (stat(lf, &st) >= 0) 83210070Seric printf("*"); 83324941Seric else if (shouldqueue(w->w_pri)) 83424941Seric printf("X"); 83510070Seric else 83610070Seric printf(" "); 83710070Seric errno = 0; 83817468Seric 83910108Seric message[0] = '\0'; 8409630Seric while (fgets(buf, sizeof buf, f) != NULL) 8419630Seric { 8429630Seric fixcrlf(buf, TRUE); 8439630Seric switch (buf[0]) 8449630Seric { 84510108Seric case 'M': /* error message */ 84623098Seric (void) strcpy(message, &buf[1]); 84710108Seric break; 84810108Seric 8499630Seric case 'S': /* sender name */ 85024979Seric if (Verbose) 85125027Seric printf("%8ld %10ld %.12s %.38s", dfsize, 85225027Seric w->w_pri, ctime(&submittime) + 4, 85324979Seric &buf[1]); 85424979Seric else 85524979Seric printf("%8ld %.16s %.45s", dfsize, 85624979Seric ctime(&submittime), &buf[1]); 85710108Seric if (message[0] != '\0') 85825027Seric printf("\n\t\t (%.60s)", message); 8599630Seric break; 8609630Seric 8619630Seric case 'R': /* recipient name */ 86224979Seric if (Verbose) 86325027Seric printf("\n\t\t\t\t\t %.38s", &buf[1]); 86424979Seric else 86524979Seric printf("\n\t\t\t\t %.45s", &buf[1]); 8669630Seric break; 8679630Seric 8689630Seric case 'T': /* creation time */ 86924941Seric submittime = atol(&buf[1]); 8709630Seric break; 87110070Seric 87210070Seric case 'D': /* data file name */ 87310070Seric if (stat(&buf[1], &st) >= 0) 87410070Seric dfsize = st.st_size; 87510070Seric break; 8769630Seric } 8779630Seric } 87810070Seric if (submittime == (time_t) 0) 87910070Seric printf(" (no control file)"); 8809630Seric printf("\n"); 88123098Seric (void) fclose(f); 8829630Seric } 8839630Seric } 8849630Seric 8855182Seric # endif QUEUE 88617468Seric /* 88717468Seric ** QUEUENAME -- build a file name in the queue directory for this envelope. 88817468Seric ** 88917468Seric ** Assigns an id code if one does not already exist. 89017468Seric ** This code is very careful to avoid trashing existing files 89117468Seric ** under any circumstances. 89217468Seric ** We first create an nf file that is only used when 89317468Seric ** assigning an id. This file is always empty, so that 89417468Seric ** we can never accidently truncate an lf file. 89517468Seric ** 89617468Seric ** Parameters: 89717468Seric ** e -- envelope to build it in/from. 89817468Seric ** type -- the file type, used as the first character 89917468Seric ** of the file name. 90017468Seric ** 90117468Seric ** Returns: 90217468Seric ** a pointer to the new file name (in a static buffer). 90317468Seric ** 90417468Seric ** Side Effects: 90517468Seric ** Will create the lf and qf files if no id code is 90617468Seric ** already assigned. This will cause the envelope 90717468Seric ** to be modified. 90817468Seric */ 90917468Seric 91017468Seric char * 91117468Seric queuename(e, type) 91217468Seric register ENVELOPE *e; 91317468Seric char type; 91417468Seric { 91517468Seric static char buf[MAXNAME]; 91617468Seric static int pid = -1; 91717468Seric char c1 = 'A'; 91817468Seric char c2 = 'A'; 91917468Seric 92017468Seric if (e->e_id == NULL) 92117468Seric { 92217468Seric char qf[20]; 92317468Seric char nf[20]; 92417468Seric char lf[20]; 92517468Seric 92617468Seric /* find a unique id */ 92717468Seric if (pid != getpid()) 92817468Seric { 92917468Seric /* new process -- start back at "AA" */ 93017468Seric pid = getpid(); 93117468Seric c1 = 'A'; 93217468Seric c2 = 'A' - 1; 93317468Seric } 93417468Seric (void) sprintf(qf, "qfAA%05d", pid); 93523098Seric (void) strcpy(lf, qf); 93617468Seric lf[0] = 'l'; 93723098Seric (void) strcpy(nf, qf); 93817468Seric nf[0] = 'n'; 93917468Seric 94017468Seric while (c1 < '~' || c2 < 'Z') 94117468Seric { 94217468Seric int i; 94317468Seric 94417468Seric if (c2 >= 'Z') 94517468Seric { 94617468Seric c1++; 94717468Seric c2 = 'A' - 1; 94817468Seric } 94917477Seric lf[2] = nf[2] = qf[2] = c1; 95017477Seric lf[3] = nf[3] = qf[3] = ++c2; 95117468Seric # ifdef DEBUG 95217468Seric if (tTd(7, 20)) 95317468Seric printf("queuename: trying \"%s\"\n", nf); 95417468Seric # endif DEBUG 95517468Seric 95617468Seric # ifdef QUEUE 95717468Seric if (access(lf, 0) >= 0 || access(qf, 0) >= 0) 95817468Seric continue; 95917468Seric errno = 0; 96017468Seric i = creat(nf, FileMode); 96117468Seric if (i < 0) 96217468Seric { 96317468Seric (void) unlink(nf); /* kernel bug */ 96417468Seric continue; 96517468Seric } 96617468Seric (void) close(i); 96717468Seric i = link(nf, lf); 96817468Seric (void) unlink(nf); 96917468Seric if (i < 0) 97017468Seric continue; 97117468Seric if (link(lf, qf) >= 0) 97217468Seric break; 97317468Seric (void) unlink(lf); 97417468Seric # else QUEUE 97517982Seric if (close(creat(qf, FileMode)) >= 0) 97617982Seric break; 97717468Seric # endif QUEUE 97817468Seric } 97917468Seric if (c1 >= '~' && c2 >= 'Z') 98017468Seric { 98117468Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 98217468Seric qf, QueueDir); 98317468Seric exit(EX_OSERR); 98417468Seric } 98517468Seric e->e_id = newstr(&qf[2]); 98617468Seric define('i', e->e_id, e); 98717468Seric # ifdef DEBUG 98817468Seric if (tTd(7, 1)) 98917468Seric printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 99017468Seric # ifdef LOG 99117468Seric if (LogLevel > 16) 99217468Seric syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 99317468Seric # endif LOG 99417468Seric # endif DEBUG 99517468Seric } 99617468Seric 99717468Seric if (type == '\0') 99817468Seric return (NULL); 99917468Seric (void) sprintf(buf, "%cf%s", type, e->e_id); 100017468Seric # ifdef DEBUG 100117468Seric if (tTd(7, 2)) 100217468Seric printf("queuename: %s\n", buf); 100317468Seric # endif DEBUG 100417468Seric return (buf); 100517468Seric } 100617468Seric /* 100717468Seric ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 100817468Seric ** 100917468Seric ** Parameters: 101017468Seric ** e -- the envelope to unlock. 101117468Seric ** 101217468Seric ** Returns: 101317468Seric ** none 101417468Seric ** 101517468Seric ** Side Effects: 101617468Seric ** unlocks the queue for `e'. 101717468Seric */ 101817468Seric 101917468Seric unlockqueue(e) 102017468Seric ENVELOPE *e; 102117468Seric { 102217468Seric /* remove the transcript */ 102317468Seric #ifdef DEBUG 102417468Seric # ifdef LOG 102517468Seric if (LogLevel > 19) 102617468Seric syslog(LOG_DEBUG, "%s: unlock", e->e_id); 102717468Seric # endif LOG 102817468Seric if (!tTd(51, 4)) 102917468Seric #endif DEBUG 103017468Seric xunlink(queuename(e, 'x')); 103117468Seric 103217468Seric # ifdef QUEUE 103317468Seric /* last but not least, remove the lock */ 103417468Seric xunlink(queuename(e, 'l')); 103517468Seric # endif QUEUE 103617468Seric } 1037