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 19*23116Seric # ifndef lint 20*23116Seric static char SccsId[] = "@(#)queue.c 5.4 (Berkeley) 06/08/85 (no queueing)"; 21*23116Seric # endif not lint 225182Seric # else QUEUE 234632Seric 24*23116Seric # ifndef lint 25*23116Seric static char SccsId[] = "@(#)queue.c 5.4 (Berkeley) 06/08/85"; 26*23116Seric # 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 */ 369377Seric struct work *w_next; /* next in queue */ 379377Seric }; 389377Seric 399377Seric typedef struct work WORK; 409377Seric 419377Seric WORK *WorkQ; /* queue of things to be done */ 429377Seric /* 434632Seric ** QUEUEUP -- queue a message up for future transmission. 444632Seric ** 454632Seric ** Parameters: 466980Seric ** e -- the envelope to queue up. 476999Seric ** queueall -- if TRUE, queue all addresses, rather than 486999Seric ** just those with the QQUEUEUP flag set. 499377Seric ** announce -- if TRUE, tell when you are queueing up. 504632Seric ** 514632Seric ** Returns: 524632Seric ** none. 534632Seric ** 544632Seric ** Side Effects: 559377Seric ** The current request are saved in a control file. 564632Seric */ 574632Seric 589377Seric queueup(e, queueall, announce) 596980Seric register ENVELOPE *e; 606999Seric bool queueall; 619377Seric bool announce; 624632Seric { 637812Seric char *tf; 647812Seric char *qf; 657763Seric char buf[MAXLINE]; 667812Seric register FILE *tfp; 674632Seric register HDR *h; 685007Seric register ADDRESS *q; 6910173Seric MAILER nullmailer; 704632Seric 715037Seric /* 7217477Seric ** Create control file. 735037Seric */ 744632Seric 7517477Seric tf = newstr(queuename(e, 't')); 7617477Seric tfp = fopen(tf, "w"); 777812Seric if (tfp == NULL) 784632Seric { 7917477Seric syserr("queueup: cannot create temp file %s", tf); 8017477Seric return; 814632Seric } 8217477Seric (void) chmod(tf, FileMode); 834632Seric 844632Seric # ifdef DEBUG 857677Seric if (tTd(40, 1)) 8617468Seric printf("queueing %s\n", e->e_id); 874632Seric # endif DEBUG 884632Seric 894632Seric /* 906980Seric ** If there is no data file yet, create one. 916980Seric */ 926980Seric 936980Seric if (e->e_df == NULL) 946980Seric { 956980Seric register FILE *dfp; 969389Seric extern putbody(); 976980Seric 987812Seric e->e_df = newstr(queuename(e, 'd')); 996980Seric dfp = fopen(e->e_df, "w"); 1006980Seric if (dfp == NULL) 1016980Seric { 1026980Seric syserr("queueup: cannot create %s", e->e_df); 1037812Seric (void) fclose(tfp); 1046980Seric return; 1056980Seric } 1069048Seric (void) chmod(e->e_df, FileMode); 10710173Seric (*e->e_putbody)(dfp, ProgMailer, e); 1087009Seric (void) fclose(dfp); 1099389Seric e->e_putbody = putbody; 1106980Seric } 1116980Seric 1126980Seric /* 1134632Seric ** Output future work requests. 1149377Seric ** Priority should be first, since it is read by orderq. 1154632Seric */ 1164632Seric 1179377Seric /* output message priority */ 1189377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1199377Seric 1209630Seric /* output creation time */ 1219630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1229630Seric 1234632Seric /* output name of data file */ 1247812Seric fprintf(tfp, "D%s\n", e->e_df); 1254632Seric 12610108Seric /* message from envelope, if it exists */ 12710108Seric if (e->e_message != NULL) 12810108Seric fprintf(tfp, "M%s\n", e->e_message); 12910108Seric 1304632Seric /* output name of sender */ 1317812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1324632Seric 1334632Seric /* output list of recipient addresses */ 1346980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1354632Seric { 1367763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1377763Seric bitset(QQUEUEUP, q->q_flags)) 1388245Seric { 1397812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1409377Seric if (announce) 1419377Seric { 1429377Seric e->e_to = q->q_paddr; 1439377Seric message(Arpa_Info, "queued"); 1449377Seric if (LogLevel > 4) 1459377Seric logdelivery("queued"); 1469377Seric e->e_to = NULL; 1479377Seric } 1489387Seric #ifdef DEBUG 1499387Seric if (tTd(40, 1)) 1509387Seric { 1519387Seric printf("queueing "); 1529387Seric printaddr(q, FALSE); 1539387Seric } 1549387Seric #endif DEBUG 1558245Seric } 1564632Seric } 1574632Seric 1589377Seric /* 1599377Seric ** Output headers for this message. 1609377Seric ** Expand macros completely here. Queue run will deal with 1619377Seric ** everything as absolute headers. 1629377Seric ** All headers that must be relative to the recipient 1639377Seric ** can be cracked later. 16410173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 16510173Seric ** no effect on the addresses as they are output. 1669377Seric */ 1679377Seric 16810686Seric bzero((char *) &nullmailer, sizeof nullmailer); 16910173Seric nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 17010349Seric nullmailer.m_eol = "\n"; 17110173Seric 17216147Seric define('g', "\001f", e); 1736980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1744632Seric { 17510686Seric extern bool bitzerop(); 17610686Seric 17712015Seric /* don't output null headers */ 1784632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1794632Seric continue; 18012015Seric 18112015Seric /* don't output resent headers on non-resent messages */ 18212015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 18312015Seric continue; 18412015Seric 18512015Seric /* output this header */ 1867812Seric fprintf(tfp, "H"); 18712015Seric 18812015Seric /* if conditional, output the set of conditions */ 18910686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 19010686Seric { 19110686Seric int j; 19210686Seric 19323098Seric (void) putc('?', tfp); 19410686Seric for (j = '\0'; j <= '\177'; j++) 19510686Seric if (bitnset(j, h->h_mflags)) 19623098Seric (void) putc(j, tfp); 19723098Seric (void) putc('?', tfp); 19810686Seric } 19912015Seric 20012015Seric /* output the header: expand macros, convert addresses */ 2017763Seric if (bitset(H_DEFAULT, h->h_flags)) 2027763Seric { 2037763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 2048236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 2057763Seric } 2068245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 2079348Seric { 2089348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 20910173Seric &nullmailer); 2109348Seric } 2117763Seric else 2128245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 2134632Seric } 2144632Seric 2154632Seric /* 2164632Seric ** Clean up. 2174632Seric */ 2184632Seric 21917477Seric (void) fclose(tfp); 22017468Seric qf = queuename(e, 'q'); 22117468Seric if (tf != NULL) 22217468Seric { 22317468Seric holdsigs(); 22417468Seric (void) unlink(qf); 22517468Seric if (link(tf, qf) < 0) 22617468Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 22717468Seric else 22817468Seric (void) unlink(tf); 22917468Seric rlsesigs(); 23017468Seric } 2317391Seric 2327677Seric # ifdef LOG 2337677Seric /* save log info */ 2347878Seric if (LogLevel > 15) 2357878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 2367677Seric # endif LOG 2374632Seric } 2384632Seric /* 2394632Seric ** RUNQUEUE -- run the jobs in the queue. 2404632Seric ** 2414632Seric ** Gets the stuff out of the queue in some presumably logical 2424632Seric ** order and processes them. 2434632Seric ** 2444632Seric ** Parameters: 2454632Seric ** none. 2464632Seric ** 2474632Seric ** Returns: 2484632Seric ** none. 2494632Seric ** 2504632Seric ** Side Effects: 2514632Seric ** runs things in the mail queue. 2524632Seric */ 2534632Seric 2544639Seric runqueue(forkflag) 2554639Seric bool forkflag; 2564632Seric { 2577466Seric /* 2587466Seric ** See if we want to go off and do other useful work. 2597466Seric */ 2604639Seric 2614639Seric if (forkflag) 2624639Seric { 2637943Seric int pid; 2647943Seric 2657943Seric pid = dofork(); 2667943Seric if (pid != 0) 2674639Seric { 2687943Seric /* parent -- pick up intermediate zombie */ 2699377Seric (void) waitfor(pid); 2707690Seric if (QueueIntvl != 0) 2719348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2724639Seric return; 2734639Seric } 2747943Seric /* child -- double fork */ 2757943Seric if (fork() != 0) 2767943Seric exit(EX_OK); 2774639Seric } 2787876Seric # ifdef LOG 2797876Seric if (LogLevel > 11) 2807943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2817876Seric # endif LOG 2824639Seric 2837466Seric /* 28410205Seric ** Release any resources used by the daemon code. 28510205Seric */ 28610205Seric 28710205Seric # ifdef DAEMON 28810205Seric clrdaemon(); 28910205Seric # endif DAEMON 29010205Seric 29110205Seric /* 2927466Seric ** Start making passes through the queue. 2937466Seric ** First, read and sort the entire queue. 2947466Seric ** Then, process the work in that order. 2957466Seric ** But if you take too long, start over. 2967466Seric */ 2977466Seric 2987943Seric /* order the existing work requests */ 29910070Seric (void) orderq(); 3007690Seric 3017943Seric /* process them once at a time */ 3027943Seric while (WorkQ != NULL) 3034639Seric { 3047943Seric WORK *w = WorkQ; 3057881Seric 3067943Seric WorkQ = WorkQ->w_next; 3077943Seric dowork(w); 3087943Seric free(w->w_name); 3097943Seric free((char *) w); 3104639Seric } 3117943Seric finis(); 3124634Seric } 3134634Seric /* 3144632Seric ** ORDERQ -- order the work queue. 3154632Seric ** 3164632Seric ** Parameters: 3174632Seric ** none. 3184632Seric ** 3194632Seric ** Returns: 32010121Seric ** The number of request in the queue (not necessarily 32110121Seric ** the number of requests in WorkQ however). 3224632Seric ** 3234632Seric ** Side Effects: 3244632Seric ** Sets WorkQ to the queue of available work, in order. 3254632Seric */ 3264632Seric 3274632Seric # define WLSIZE 120 /* max size of worklist per sort */ 3284632Seric 3294632Seric orderq() 3304632Seric { 3316625Sglickman register struct direct *d; 3324632Seric register WORK *w; 3334632Seric register WORK **wp; /* parent of w */ 3346625Sglickman DIR *f; 3354632Seric register int i; 33610121Seric WORK wlist[WLSIZE+1]; 33710070Seric int wn = -1; 3384632Seric extern workcmpf(); 3394632Seric 3404632Seric /* clear out old WorkQ */ 3414632Seric for (w = WorkQ; w != NULL; ) 3424632Seric { 3434632Seric register WORK *nw = w->w_next; 3444632Seric 3454632Seric WorkQ = nw; 3464632Seric free(w->w_name); 3474632Seric free((char *) w); 3484632Seric w = nw; 3494632Seric } 3504632Seric 3514632Seric /* open the queue directory */ 3528148Seric f = opendir("."); 3534632Seric if (f == NULL) 3544632Seric { 3558148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 35610070Seric return (0); 3574632Seric } 3584632Seric 3594632Seric /* 3604632Seric ** Read the work directory. 3614632Seric */ 3624632Seric 36310070Seric while ((d = readdir(f)) != NULL) 3644632Seric { 3659377Seric FILE *cf; 3664632Seric char lbuf[MAXNAME]; 3674632Seric 3684632Seric /* is this an interesting entry? */ 3697812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3704632Seric continue; 3714632Seric 37210070Seric /* yes -- open control file (if not too many files) */ 37310070Seric if (++wn >= WLSIZE) 37410070Seric continue; 3758148Seric cf = fopen(d->d_name, "r"); 3764632Seric if (cf == NULL) 3774632Seric { 3787055Seric /* this may be some random person sending hir msgs */ 3797055Seric /* syserr("orderq: cannot open %s", cbuf); */ 38010090Seric #ifdef DEBUG 38110090Seric if (tTd(41, 2)) 38210090Seric printf("orderq: cannot open %s (%d)\n", 38310090Seric d->d_name, errno); 38410090Seric #endif DEBUG 3857055Seric errno = 0; 38610090Seric wn--; 3874632Seric continue; 3884632Seric } 3898148Seric wlist[wn].w_name = newstr(d->d_name); 3904632Seric 3914632Seric /* extract useful information */ 3924632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3934632Seric { 3949377Seric if (lbuf[0] == 'P') 3954632Seric { 3965037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3974632Seric break; 3984632Seric } 3994632Seric } 4004632Seric (void) fclose(cf); 4014632Seric } 4026625Sglickman (void) closedir(f); 40310090Seric wn++; 4044632Seric 4054632Seric /* 4064632Seric ** Sort the work directory. 4074632Seric */ 4084632Seric 409*23116Seric qsort((char *) wlist, min(wn, WLSIZE), sizeof *wlist, workcmpf); 4104632Seric 4114632Seric /* 4124632Seric ** Convert the work list into canonical form. 4139377Seric ** Should be turning it into a list of envelopes here perhaps. 4144632Seric */ 4154632Seric 4164632Seric wp = &WorkQ; 41710121Seric for (i = min(wn, WLSIZE); --i >= 0; ) 4184632Seric { 4194632Seric w = (WORK *) xalloc(sizeof *w); 4204632Seric w->w_name = wlist[i].w_name; 4214632Seric w->w_pri = wlist[i].w_pri; 4224632Seric w->w_next = NULL; 4234632Seric *wp = w; 4244632Seric wp = &w->w_next; 4254632Seric } 4264632Seric 4274632Seric # ifdef DEBUG 4287677Seric if (tTd(40, 1)) 4294632Seric { 4304632Seric for (w = WorkQ; w != NULL; w = w->w_next) 4315037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 4324632Seric } 4334632Seric # endif DEBUG 43410070Seric 43510090Seric return (wn); 4364632Seric } 4374632Seric /* 4387677Seric ** WORKCMPF -- compare function for ordering work. 4394632Seric ** 4404632Seric ** Parameters: 4414632Seric ** a -- the first argument. 4424632Seric ** b -- the second argument. 4434632Seric ** 4444632Seric ** Returns: 44510121Seric ** 1 if a < b 4464632Seric ** 0 if a == b 44710121Seric ** -1 if a > b 4484632Seric ** 4494632Seric ** Side Effects: 4504632Seric ** none. 4514632Seric */ 4524632Seric 4534632Seric workcmpf(a, b) 4545037Seric register WORK *a; 4555037Seric register WORK *b; 4564632Seric { 4575037Seric if (a->w_pri == b->w_pri) 4584632Seric return (0); 4595037Seric else if (a->w_pri > b->w_pri) 46010121Seric return (-1); 46110121Seric else 4624632Seric return (1); 4634632Seric } 4644632Seric /* 4654632Seric ** DOWORK -- do a work request. 4664632Seric ** 4674632Seric ** Parameters: 4684632Seric ** w -- the work request to be satisfied. 4694632Seric ** 4704632Seric ** Returns: 4714632Seric ** none. 4724632Seric ** 4734632Seric ** Side Effects: 4744632Seric ** The work request is satisfied if possible. 4754632Seric */ 4764632Seric 4774632Seric dowork(w) 4784632Seric register WORK *w; 4794632Seric { 4804632Seric register int i; 4814632Seric 4824632Seric # ifdef DEBUG 4837677Seric if (tTd(40, 1)) 4845037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4854632Seric # endif DEBUG 4864632Seric 4874632Seric /* 4884632Seric ** Fork for work. 4894632Seric */ 4904632Seric 4914632Seric i = fork(); 4924632Seric if (i < 0) 4934632Seric { 4944632Seric syserr("dowork: cannot fork"); 4954632Seric return; 4964632Seric } 4974632Seric 4984632Seric if (i == 0) 4994632Seric { 5004632Seric /* 5014632Seric ** CHILD 5028148Seric ** Lock the control file to avoid duplicate deliveries. 5038148Seric ** Then run the file as though we had just read it. 5047350Seric ** We save an idea of the temporary name so we 5057350Seric ** can recover on interrupt. 5064632Seric */ 5074632Seric 5087763Seric /* set basic modes, etc. */ 5097356Seric (void) alarm(0); 51010195Seric closexscript(CurEnv); 5119338Seric CurEnv->e_flags &= ~EF_FATALERRS; 5124632Seric QueueRun = TRUE; 5139377Seric ErrorMode = EM_MAIL; 5148148Seric CurEnv->e_id = &w->w_name[2]; 5157876Seric # ifdef LOG 5167876Seric if (LogLevel > 11) 5177881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 5187881Seric getpid()); 5197876Seric # endif LOG 5207763Seric 5217763Seric /* don't use the headers from sendmail.cf... */ 5227763Seric CurEnv->e_header = NULL; 5237763Seric 52417468Seric /* lock the control file during processing */ 5257812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 5266980Seric { 5277812Seric /* being processed by another queuer */ 5287881Seric # ifdef LOG 5297881Seric if (LogLevel > 4) 5307881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 5317881Seric # endif LOG 5326980Seric exit(EX_OK); 5336980Seric } 5346980Seric 5356980Seric /* do basic system initialization */ 5364632Seric initsys(); 5376980Seric 5386980Seric /* read the queue control file */ 53917477Seric readqf(CurEnv, TRUE); 5409338Seric CurEnv->e_flags |= EF_INQUEUE; 5419377Seric eatheader(CurEnv); 5426980Seric 5436980Seric /* do the delivery */ 5449338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 5459282Seric sendall(CurEnv, SM_DELIVER); 5466980Seric 5476980Seric /* finish up and exit */ 5484632Seric finis(); 5494632Seric } 5504632Seric 5514632Seric /* 5524632Seric ** Parent -- pick up results. 5534632Seric */ 5544632Seric 5554632Seric errno = 0; 5569377Seric (void) waitfor(i); 5574632Seric } 5584632Seric /* 5594632Seric ** READQF -- read queue file and set up environment. 5604632Seric ** 5614632Seric ** Parameters: 5629377Seric ** e -- the envelope of the job to run. 5639630Seric ** full -- if set, read in all information. Otherwise just 5649630Seric ** read in info needed for a queue print. 5654632Seric ** 5664632Seric ** Returns: 5674632Seric ** none. 5684632Seric ** 5694632Seric ** Side Effects: 5704632Seric ** cf is read and created as the current job, as though 5714632Seric ** we had been invoked by argument. 5724632Seric */ 5734632Seric 57417477Seric readqf(e, full) 5759377Seric register ENVELOPE *e; 5769630Seric bool full; 5774632Seric { 57817477Seric char *qf; 57917477Seric register FILE *qfp; 5807785Seric char buf[MAXFIELD]; 5819348Seric extern char *fgetfolded(); 5824632Seric 5834632Seric /* 58417468Seric ** Read and process the file. 5854632Seric */ 5864632Seric 58717477Seric qf = queuename(e, 'q'); 58817477Seric qfp = fopen(qf, "r"); 58917477Seric if (qfp == NULL) 59017477Seric { 59117477Seric syserr("readqf: no control file %s", qf); 59217477Seric return; 59317477Seric } 59417477Seric FileName = qf; 5959377Seric LineNumber = 0; 5969630Seric if (Verbose && full) 5979377Seric printf("\nRunning %s\n", e->e_id); 59817468Seric while (fgetfolded(buf, sizeof buf, qfp) != NULL) 5994632Seric { 6004632Seric switch (buf[0]) 6014632Seric { 6024632Seric case 'R': /* specify recipient */ 6039618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 6044632Seric break; 6054632Seric 6064632Seric case 'H': /* header */ 6079630Seric if (full) 6089630Seric (void) chompheader(&buf[1], FALSE); 6094632Seric break; 6104632Seric 61110108Seric case 'M': /* message */ 61210108Seric e->e_message = newstr(&buf[1]); 61310108Seric break; 61410108Seric 6154632Seric case 'S': /* sender */ 6164634Seric setsender(newstr(&buf[1])); 6174632Seric break; 6184632Seric 6194632Seric case 'D': /* data file name */ 6209630Seric if (!full) 6219630Seric break; 6229377Seric e->e_df = newstr(&buf[1]); 6239544Seric e->e_dfp = fopen(e->e_df, "r"); 6249544Seric if (e->e_dfp == NULL) 6259377Seric syserr("readqf: cannot open %s", e->e_df); 6264632Seric break; 6274632Seric 6287860Seric case 'T': /* init time */ 6299377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 6304632Seric break; 6314632Seric 6324634Seric case 'P': /* message priority */ 6339377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 6345037Seric 6355037Seric /* make sure that big things get sent eventually */ 6369377Seric e->e_msgpriority -= WKTIMEFACT; 6374634Seric break; 6384634Seric 6394632Seric default: 6409377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 6414632Seric break; 6424632Seric } 6434632Seric } 6449377Seric 6459377Seric FileName = NULL; 6464632Seric } 6474632Seric /* 6489630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6499630Seric ** 6509630Seric ** Parameters: 6519630Seric ** none. 6529630Seric ** 6539630Seric ** Returns: 6549630Seric ** none. 6559630Seric ** 6569630Seric ** Side Effects: 6579630Seric ** Prints a listing of the mail queue on the standard output. 6589630Seric */ 6595182Seric 6609630Seric printqueue() 6619630Seric { 6629630Seric register WORK *w; 6639630Seric FILE *f; 66410070Seric int nrequests; 6659630Seric char buf[MAXLINE]; 6669630Seric 6679630Seric /* 6689630Seric ** Read and order the queue. 6699630Seric */ 6709630Seric 67110070Seric nrequests = orderq(); 6729630Seric 6739630Seric /* 6749630Seric ** Print the work list that we have read. 6759630Seric */ 6769630Seric 6779630Seric /* first see if there is anything */ 67810070Seric if (nrequests <= 0) 6799630Seric { 68010070Seric printf("Mail queue is empty\n"); 6819630Seric return; 6829630Seric } 6839630Seric 68410096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 68510070Seric if (nrequests > WLSIZE) 68610070Seric printf(", only %d printed", WLSIZE); 68710070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6889630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6899630Seric { 6909630Seric struct stat st; 69110070Seric auto time_t submittime = 0; 69210070Seric long dfsize = -1; 69310108Seric char lf[20]; 69410108Seric char message[MAXLINE]; 6959630Seric 69617468Seric f = fopen(w->w_name, "r"); 69717468Seric if (f == NULL) 69817468Seric { 69917468Seric errno = 0; 70017468Seric continue; 70117468Seric } 7029630Seric printf("%7s", w->w_name + 2); 70323098Seric (void) strcpy(lf, w->w_name); 70410070Seric lf[0] = 'l'; 70510070Seric if (stat(lf, &st) >= 0) 70610070Seric printf("*"); 70710070Seric else 70810070Seric printf(" "); 70910070Seric errno = 0; 71017468Seric 71110108Seric message[0] = '\0'; 7129630Seric while (fgets(buf, sizeof buf, f) != NULL) 7139630Seric { 7149630Seric fixcrlf(buf, TRUE); 7159630Seric switch (buf[0]) 7169630Seric { 71710108Seric case 'M': /* error message */ 71823098Seric (void) strcpy(message, &buf[1]); 71910108Seric break; 72010108Seric 7219630Seric case 'S': /* sender name */ 72213015Seric printf("%8ld %.16s %.45s", dfsize, 72312517Seric ctime(&submittime), &buf[1]); 72410108Seric if (message[0] != '\0') 72512517Seric printf("\n\t\t\t\t (%.43s)", message); 7269630Seric break; 7279630Seric 7289630Seric case 'R': /* recipient name */ 72912517Seric printf("\n\t\t\t\t %.45s", &buf[1]); 7309630Seric break; 7319630Seric 7329630Seric case 'T': /* creation time */ 73323098Seric (void) sscanf(&buf[1], "%ld", &submittime); 7349630Seric break; 73510070Seric 73610070Seric case 'D': /* data file name */ 73710070Seric if (stat(&buf[1], &st) >= 0) 73810070Seric dfsize = st.st_size; 73910070Seric break; 7409630Seric } 7419630Seric } 74210070Seric if (submittime == (time_t) 0) 74310070Seric printf(" (no control file)"); 7449630Seric printf("\n"); 74523098Seric (void) fclose(f); 7469630Seric } 7479630Seric } 7489630Seric 7495182Seric # endif QUEUE 75017468Seric /* 75117468Seric ** QUEUENAME -- build a file name in the queue directory for this envelope. 75217468Seric ** 75317468Seric ** Assigns an id code if one does not already exist. 75417468Seric ** This code is very careful to avoid trashing existing files 75517468Seric ** under any circumstances. 75617468Seric ** We first create an nf file that is only used when 75717468Seric ** assigning an id. This file is always empty, so that 75817468Seric ** we can never accidently truncate an lf file. 75917468Seric ** 76017468Seric ** Parameters: 76117468Seric ** e -- envelope to build it in/from. 76217468Seric ** type -- the file type, used as the first character 76317468Seric ** of the file name. 76417468Seric ** 76517468Seric ** Returns: 76617468Seric ** a pointer to the new file name (in a static buffer). 76717468Seric ** 76817468Seric ** Side Effects: 76917468Seric ** Will create the lf and qf files if no id code is 77017468Seric ** already assigned. This will cause the envelope 77117468Seric ** to be modified. 77217468Seric */ 77317468Seric 77417468Seric char * 77517468Seric queuename(e, type) 77617468Seric register ENVELOPE *e; 77717468Seric char type; 77817468Seric { 77917468Seric static char buf[MAXNAME]; 78017468Seric static int pid = -1; 78117468Seric char c1 = 'A'; 78217468Seric char c2 = 'A'; 78317468Seric 78417468Seric if (e->e_id == NULL) 78517468Seric { 78617468Seric char qf[20]; 78717468Seric char nf[20]; 78817468Seric char lf[20]; 78917468Seric 79017468Seric /* find a unique id */ 79117468Seric if (pid != getpid()) 79217468Seric { 79317468Seric /* new process -- start back at "AA" */ 79417468Seric pid = getpid(); 79517468Seric c1 = 'A'; 79617468Seric c2 = 'A' - 1; 79717468Seric } 79817468Seric (void) sprintf(qf, "qfAA%05d", pid); 79923098Seric (void) strcpy(lf, qf); 80017468Seric lf[0] = 'l'; 80123098Seric (void) strcpy(nf, qf); 80217468Seric nf[0] = 'n'; 80317468Seric 80417468Seric while (c1 < '~' || c2 < 'Z') 80517468Seric { 80617468Seric int i; 80717468Seric 80817468Seric if (c2 >= 'Z') 80917468Seric { 81017468Seric c1++; 81117468Seric c2 = 'A' - 1; 81217468Seric } 81317477Seric lf[2] = nf[2] = qf[2] = c1; 81417477Seric lf[3] = nf[3] = qf[3] = ++c2; 81517468Seric # ifdef DEBUG 81617468Seric if (tTd(7, 20)) 81717468Seric printf("queuename: trying \"%s\"\n", nf); 81817468Seric # endif DEBUG 81917468Seric 82017468Seric # ifdef QUEUE 82117468Seric if (access(lf, 0) >= 0 || access(qf, 0) >= 0) 82217468Seric continue; 82317468Seric errno = 0; 82417468Seric i = creat(nf, FileMode); 82517468Seric if (i < 0) 82617468Seric { 82717468Seric (void) unlink(nf); /* kernel bug */ 82817468Seric continue; 82917468Seric } 83017468Seric (void) close(i); 83117468Seric i = link(nf, lf); 83217468Seric (void) unlink(nf); 83317468Seric if (i < 0) 83417468Seric continue; 83517468Seric if (link(lf, qf) >= 0) 83617468Seric break; 83717468Seric (void) unlink(lf); 83817468Seric # else QUEUE 83917982Seric if (close(creat(qf, FileMode)) >= 0) 84017982Seric break; 84117468Seric # endif QUEUE 84217468Seric } 84317468Seric if (c1 >= '~' && c2 >= 'Z') 84417468Seric { 84517468Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 84617468Seric qf, QueueDir); 84717468Seric exit(EX_OSERR); 84817468Seric } 84917468Seric e->e_id = newstr(&qf[2]); 85017468Seric define('i', e->e_id, e); 85117468Seric # ifdef DEBUG 85217468Seric if (tTd(7, 1)) 85317468Seric printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 85417468Seric # ifdef LOG 85517468Seric if (LogLevel > 16) 85617468Seric syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 85717468Seric # endif LOG 85817468Seric # endif DEBUG 85917468Seric } 86017468Seric 86117468Seric if (type == '\0') 86217468Seric return (NULL); 86317468Seric (void) sprintf(buf, "%cf%s", type, e->e_id); 86417468Seric # ifdef DEBUG 86517468Seric if (tTd(7, 2)) 86617468Seric printf("queuename: %s\n", buf); 86717468Seric # endif DEBUG 86817468Seric return (buf); 86917468Seric } 87017468Seric /* 87117468Seric ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 87217468Seric ** 87317468Seric ** Parameters: 87417468Seric ** e -- the envelope to unlock. 87517468Seric ** 87617468Seric ** Returns: 87717468Seric ** none 87817468Seric ** 87917468Seric ** Side Effects: 88017468Seric ** unlocks the queue for `e'. 88117468Seric */ 88217468Seric 88317468Seric unlockqueue(e) 88417468Seric ENVELOPE *e; 88517468Seric { 88617468Seric /* remove the transcript */ 88717468Seric #ifdef DEBUG 88817468Seric # ifdef LOG 88917468Seric if (LogLevel > 19) 89017468Seric syslog(LOG_DEBUG, "%s: unlock", e->e_id); 89117468Seric # endif LOG 89217468Seric if (!tTd(51, 4)) 89317468Seric #endif DEBUG 89417468Seric xunlink(queuename(e, 'x')); 89517468Seric 89617468Seric # ifdef QUEUE 89717468Seric /* last but not least, remove the lock */ 89817468Seric xunlink(queuename(e, 'l')); 89917468Seric # endif QUEUE 90017468Seric } 901