1*22708Sdist /* 2*22708Sdist ** Sendmail 3*22708Sdist ** Copyright (c) 1983 Eric P. Allman 4*22708Sdist ** Berkeley, California 5*22708Sdist ** 6*22708Sdist ** Copyright (c) 1983 Regents of the University of California. 7*22708Sdist ** All rights reserved. The Berkeley software License Agreement 8*22708Sdist ** specifies the terms and conditions for redistribution. 9*22708Sdist */ 10*22708Sdist 11*22708Sdist #ifndef lint 12*22708Sdist static char SccsId[] = "@(#)queue.c 5.1 (Berkeley) 06/07/85"; 13*22708Sdist #endif not lint 14*22708Sdist 154632Seric # include "sendmail.h" 164632Seric # include <sys/stat.h> 1713707Ssam # include <sys/dir.h> 184634Seric # include <signal.h> 194632Seric # include <errno.h> 204632Seric 215182Seric # ifndef QUEUE 22*22708Sdist SCCSID(@(#)queue.c 5.1 06/07/85 (no queueing)); 235182Seric # else QUEUE 244632Seric 25*22708Sdist SCCSID(@(#)queue.c 5.1 06/07/85); 265182Seric 274632Seric /* 289377Seric ** Work queue. 299377Seric */ 309377Seric 319377Seric struct work 329377Seric { 339377Seric char *w_name; /* name of control file */ 349377Seric long w_pri; /* priority of message, see below */ 359377Seric struct work *w_next; /* next in queue */ 369377Seric }; 379377Seric 389377Seric typedef struct work WORK; 399377Seric 409377Seric WORK *WorkQ; /* queue of things to be done */ 419377Seric /* 424632Seric ** QUEUEUP -- queue a message up for future transmission. 434632Seric ** 444632Seric ** Parameters: 456980Seric ** e -- the envelope to queue up. 466999Seric ** queueall -- if TRUE, queue all addresses, rather than 476999Seric ** just those with the QQUEUEUP flag set. 489377Seric ** announce -- if TRUE, tell when you are queueing up. 494632Seric ** 504632Seric ** Returns: 514632Seric ** none. 524632Seric ** 534632Seric ** Side Effects: 549377Seric ** The current request are saved in a control file. 554632Seric */ 564632Seric 579377Seric queueup(e, queueall, announce) 586980Seric register ENVELOPE *e; 596999Seric bool queueall; 609377Seric bool announce; 614632Seric { 627812Seric char *tf; 637812Seric char *qf; 647763Seric char buf[MAXLINE]; 657812Seric register FILE *tfp; 664632Seric register HDR *h; 675007Seric register ADDRESS *q; 6810173Seric MAILER nullmailer; 694632Seric 705037Seric /* 7117477Seric ** Create control file. 725037Seric */ 734632Seric 7417477Seric tf = newstr(queuename(e, 't')); 7517477Seric tfp = fopen(tf, "w"); 767812Seric if (tfp == NULL) 774632Seric { 7817477Seric syserr("queueup: cannot create temp file %s", tf); 7917477Seric return; 804632Seric } 8117477Seric (void) chmod(tf, FileMode); 824632Seric 834632Seric # ifdef DEBUG 847677Seric if (tTd(40, 1)) 8517468Seric printf("queueing %s\n", e->e_id); 864632Seric # endif DEBUG 874632Seric 884632Seric /* 896980Seric ** If there is no data file yet, create one. 906980Seric */ 916980Seric 926980Seric if (e->e_df == NULL) 936980Seric { 946980Seric register FILE *dfp; 959389Seric extern putbody(); 966980Seric 977812Seric e->e_df = newstr(queuename(e, 'd')); 986980Seric dfp = fopen(e->e_df, "w"); 996980Seric if (dfp == NULL) 1006980Seric { 1016980Seric syserr("queueup: cannot create %s", e->e_df); 1027812Seric (void) fclose(tfp); 1036980Seric return; 1046980Seric } 1059048Seric (void) chmod(e->e_df, FileMode); 10610173Seric (*e->e_putbody)(dfp, ProgMailer, e); 1077009Seric (void) fclose(dfp); 1089389Seric e->e_putbody = putbody; 1096980Seric } 1106980Seric 1116980Seric /* 1124632Seric ** Output future work requests. 1139377Seric ** Priority should be first, since it is read by orderq. 1144632Seric */ 1154632Seric 1169377Seric /* output message priority */ 1179377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1189377Seric 1199630Seric /* output creation time */ 1209630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1219630Seric 1224632Seric /* output name of data file */ 1237812Seric fprintf(tfp, "D%s\n", e->e_df); 1244632Seric 12510108Seric /* message from envelope, if it exists */ 12610108Seric if (e->e_message != NULL) 12710108Seric fprintf(tfp, "M%s\n", e->e_message); 12810108Seric 1294632Seric /* output name of sender */ 1307812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1314632Seric 1324632Seric /* output list of recipient addresses */ 1336980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1344632Seric { 1357763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1367763Seric bitset(QQUEUEUP, q->q_flags)) 1378245Seric { 1387812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1399377Seric if (announce) 1409377Seric { 1419377Seric e->e_to = q->q_paddr; 1429377Seric message(Arpa_Info, "queued"); 1439377Seric if (LogLevel > 4) 1449377Seric logdelivery("queued"); 1459377Seric e->e_to = NULL; 1469377Seric } 1479387Seric #ifdef DEBUG 1489387Seric if (tTd(40, 1)) 1499387Seric { 1509387Seric printf("queueing "); 1519387Seric printaddr(q, FALSE); 1529387Seric } 1539387Seric #endif DEBUG 1548245Seric } 1554632Seric } 1564632Seric 1579377Seric /* 1589377Seric ** Output headers for this message. 1599377Seric ** Expand macros completely here. Queue run will deal with 1609377Seric ** everything as absolute headers. 1619377Seric ** All headers that must be relative to the recipient 1629377Seric ** can be cracked later. 16310173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 16410173Seric ** no effect on the addresses as they are output. 1659377Seric */ 1669377Seric 16710686Seric bzero((char *) &nullmailer, sizeof nullmailer); 16810173Seric nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 16910349Seric nullmailer.m_eol = "\n"; 17010173Seric 17116147Seric define('g', "\001f", e); 1726980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1734632Seric { 17410686Seric extern bool bitzerop(); 17510686Seric 17612015Seric /* don't output null headers */ 1774632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1784632Seric continue; 17912015Seric 18012015Seric /* don't output resent headers on non-resent messages */ 18112015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 18212015Seric continue; 18312015Seric 18412015Seric /* output this header */ 1857812Seric fprintf(tfp, "H"); 18612015Seric 18712015Seric /* if conditional, output the set of conditions */ 18810686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 18910686Seric { 19010686Seric int j; 19110686Seric 19210686Seric putc('?', tfp); 19310686Seric for (j = '\0'; j <= '\177'; j++) 19410686Seric if (bitnset(j, h->h_mflags)) 19510686Seric putc(j, tfp); 19610686Seric putc('?', tfp); 19710686Seric } 19812015Seric 19912015Seric /* output the header: expand macros, convert addresses */ 2007763Seric if (bitset(H_DEFAULT, h->h_flags)) 2017763Seric { 2027763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 2038236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 2047763Seric } 2058245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 2069348Seric { 2079348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 20810173Seric &nullmailer); 2099348Seric } 2107763Seric else 2118245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 2124632Seric } 2134632Seric 2144632Seric /* 2154632Seric ** Clean up. 2164632Seric */ 2174632Seric 21817477Seric (void) fclose(tfp); 21917468Seric qf = queuename(e, 'q'); 22017468Seric if (tf != NULL) 22117468Seric { 22217468Seric holdsigs(); 22317468Seric (void) unlink(qf); 22417468Seric if (link(tf, qf) < 0) 22517468Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 22617468Seric else 22717468Seric (void) unlink(tf); 22817468Seric rlsesigs(); 22917468Seric } 2307391Seric 2317677Seric # ifdef LOG 2327677Seric /* save log info */ 2337878Seric if (LogLevel > 15) 2347878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 2357677Seric # endif LOG 2364632Seric } 2374632Seric /* 2384632Seric ** RUNQUEUE -- run the jobs in the queue. 2394632Seric ** 2404632Seric ** Gets the stuff out of the queue in some presumably logical 2414632Seric ** order and processes them. 2424632Seric ** 2434632Seric ** Parameters: 2444632Seric ** none. 2454632Seric ** 2464632Seric ** Returns: 2474632Seric ** none. 2484632Seric ** 2494632Seric ** Side Effects: 2504632Seric ** runs things in the mail queue. 2514632Seric */ 2524632Seric 2534639Seric runqueue(forkflag) 2544639Seric bool forkflag; 2554632Seric { 2567466Seric /* 2577466Seric ** See if we want to go off and do other useful work. 2587466Seric */ 2594639Seric 2604639Seric if (forkflag) 2614639Seric { 2627943Seric int pid; 2637943Seric 2647943Seric pid = dofork(); 2657943Seric if (pid != 0) 2664639Seric { 2677943Seric /* parent -- pick up intermediate zombie */ 2689377Seric (void) waitfor(pid); 2697690Seric if (QueueIntvl != 0) 2709348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2714639Seric return; 2724639Seric } 2737943Seric /* child -- double fork */ 2747943Seric if (fork() != 0) 2757943Seric exit(EX_OK); 2764639Seric } 2777876Seric # ifdef LOG 2787876Seric if (LogLevel > 11) 2797943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2807876Seric # endif LOG 2814639Seric 2827466Seric /* 28310205Seric ** Release any resources used by the daemon code. 28410205Seric */ 28510205Seric 28610205Seric # ifdef DAEMON 28710205Seric clrdaemon(); 28810205Seric # endif DAEMON 28910205Seric 29010205Seric /* 2917466Seric ** Start making passes through the queue. 2927466Seric ** First, read and sort the entire queue. 2937466Seric ** Then, process the work in that order. 2947466Seric ** But if you take too long, start over. 2957466Seric */ 2967466Seric 2977943Seric /* order the existing work requests */ 29810070Seric (void) orderq(); 2997690Seric 3007943Seric /* process them once at a time */ 3017943Seric while (WorkQ != NULL) 3024639Seric { 3037943Seric WORK *w = WorkQ; 3047881Seric 3057943Seric WorkQ = WorkQ->w_next; 3067943Seric dowork(w); 3077943Seric free(w->w_name); 3087943Seric free((char *) w); 3094639Seric } 3107943Seric finis(); 3114634Seric } 3124634Seric /* 3134632Seric ** ORDERQ -- order the work queue. 3144632Seric ** 3154632Seric ** Parameters: 3164632Seric ** none. 3174632Seric ** 3184632Seric ** Returns: 31910121Seric ** The number of request in the queue (not necessarily 32010121Seric ** the number of requests in WorkQ however). 3214632Seric ** 3224632Seric ** Side Effects: 3234632Seric ** Sets WorkQ to the queue of available work, in order. 3244632Seric */ 3254632Seric 3264632Seric # define WLSIZE 120 /* max size of worklist per sort */ 3274632Seric 3284632Seric orderq() 3294632Seric { 3306625Sglickman register struct direct *d; 3314632Seric register WORK *w; 3324632Seric register WORK **wp; /* parent of w */ 3336625Sglickman DIR *f; 3344632Seric register int i; 33510121Seric WORK wlist[WLSIZE+1]; 33610070Seric int wn = -1; 3374632Seric extern workcmpf(); 3384632Seric 3394632Seric /* clear out old WorkQ */ 3404632Seric for (w = WorkQ; w != NULL; ) 3414632Seric { 3424632Seric register WORK *nw = w->w_next; 3434632Seric 3444632Seric WorkQ = nw; 3454632Seric free(w->w_name); 3464632Seric free((char *) w); 3474632Seric w = nw; 3484632Seric } 3494632Seric 3504632Seric /* open the queue directory */ 3518148Seric f = opendir("."); 3524632Seric if (f == NULL) 3534632Seric { 3548148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 35510070Seric return (0); 3564632Seric } 3574632Seric 3584632Seric /* 3594632Seric ** Read the work directory. 3604632Seric */ 3614632Seric 36210070Seric while ((d = readdir(f)) != NULL) 3634632Seric { 3649377Seric FILE *cf; 3654632Seric char lbuf[MAXNAME]; 3664632Seric 3674632Seric /* is this an interesting entry? */ 3687812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3694632Seric continue; 3704632Seric 37110070Seric /* yes -- open control file (if not too many files) */ 37210070Seric if (++wn >= WLSIZE) 37310070Seric continue; 3748148Seric cf = fopen(d->d_name, "r"); 3754632Seric if (cf == NULL) 3764632Seric { 3777055Seric /* this may be some random person sending hir msgs */ 3787055Seric /* syserr("orderq: cannot open %s", cbuf); */ 37910090Seric #ifdef DEBUG 38010090Seric if (tTd(41, 2)) 38110090Seric printf("orderq: cannot open %s (%d)\n", 38210090Seric d->d_name, errno); 38310090Seric #endif DEBUG 3847055Seric errno = 0; 38510090Seric wn--; 3864632Seric continue; 3874632Seric } 3888148Seric wlist[wn].w_name = newstr(d->d_name); 3894632Seric 3904632Seric /* extract useful information */ 3914632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3924632Seric { 3939377Seric if (lbuf[0] == 'P') 3944632Seric { 3955037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3964632Seric break; 3974632Seric } 3984632Seric } 3994632Seric (void) fclose(cf); 4004632Seric } 4016625Sglickman (void) closedir(f); 40210090Seric wn++; 4034632Seric 4044632Seric /* 4054632Seric ** Sort the work directory. 4064632Seric */ 4074632Seric 40810121Seric qsort(wlist, min(wn, WLSIZE), sizeof *wlist, workcmpf); 4094632Seric 4104632Seric /* 4114632Seric ** Convert the work list into canonical form. 4129377Seric ** Should be turning it into a list of envelopes here perhaps. 4134632Seric */ 4144632Seric 4154632Seric wp = &WorkQ; 41610121Seric for (i = min(wn, WLSIZE); --i >= 0; ) 4174632Seric { 4184632Seric w = (WORK *) xalloc(sizeof *w); 4194632Seric w->w_name = wlist[i].w_name; 4204632Seric w->w_pri = wlist[i].w_pri; 4214632Seric w->w_next = NULL; 4224632Seric *wp = w; 4234632Seric wp = &w->w_next; 4244632Seric } 4254632Seric 4264632Seric # ifdef DEBUG 4277677Seric if (tTd(40, 1)) 4284632Seric { 4294632Seric for (w = WorkQ; w != NULL; w = w->w_next) 4305037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 4314632Seric } 4324632Seric # endif DEBUG 43310070Seric 43410090Seric return (wn); 4354632Seric } 4364632Seric /* 4377677Seric ** WORKCMPF -- compare function for ordering work. 4384632Seric ** 4394632Seric ** Parameters: 4404632Seric ** a -- the first argument. 4414632Seric ** b -- the second argument. 4424632Seric ** 4434632Seric ** Returns: 44410121Seric ** 1 if a < b 4454632Seric ** 0 if a == b 44610121Seric ** -1 if a > b 4474632Seric ** 4484632Seric ** Side Effects: 4494632Seric ** none. 4504632Seric */ 4514632Seric 4524632Seric workcmpf(a, b) 4535037Seric register WORK *a; 4545037Seric register WORK *b; 4554632Seric { 4565037Seric if (a->w_pri == b->w_pri) 4574632Seric return (0); 4585037Seric else if (a->w_pri > b->w_pri) 45910121Seric return (-1); 46010121Seric else 4614632Seric return (1); 4624632Seric } 4634632Seric /* 4644632Seric ** DOWORK -- do a work request. 4654632Seric ** 4664632Seric ** Parameters: 4674632Seric ** w -- the work request to be satisfied. 4684632Seric ** 4694632Seric ** Returns: 4704632Seric ** none. 4714632Seric ** 4724632Seric ** Side Effects: 4734632Seric ** The work request is satisfied if possible. 4744632Seric */ 4754632Seric 4764632Seric dowork(w) 4774632Seric register WORK *w; 4784632Seric { 4794632Seric register int i; 4804632Seric 4814632Seric # ifdef DEBUG 4827677Seric if (tTd(40, 1)) 4835037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4844632Seric # endif DEBUG 4854632Seric 4864632Seric /* 4874632Seric ** Fork for work. 4884632Seric */ 4894632Seric 4904632Seric i = fork(); 4914632Seric if (i < 0) 4924632Seric { 4934632Seric syserr("dowork: cannot fork"); 4944632Seric return; 4954632Seric } 4964632Seric 4974632Seric if (i == 0) 4984632Seric { 4994632Seric /* 5004632Seric ** CHILD 5018148Seric ** Lock the control file to avoid duplicate deliveries. 5028148Seric ** Then run the file as though we had just read it. 5037350Seric ** We save an idea of the temporary name so we 5047350Seric ** can recover on interrupt. 5054632Seric */ 5064632Seric 5077763Seric /* set basic modes, etc. */ 5087356Seric (void) alarm(0); 50910195Seric closexscript(CurEnv); 5109338Seric CurEnv->e_flags &= ~EF_FATALERRS; 5114632Seric QueueRun = TRUE; 5129377Seric ErrorMode = EM_MAIL; 5138148Seric CurEnv->e_id = &w->w_name[2]; 5147876Seric # ifdef LOG 5157876Seric if (LogLevel > 11) 5167881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 5177881Seric getpid()); 5187876Seric # endif LOG 5197763Seric 5207763Seric /* don't use the headers from sendmail.cf... */ 5217763Seric CurEnv->e_header = NULL; 5227763Seric 52317468Seric /* lock the control file during processing */ 5247812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 5256980Seric { 5267812Seric /* being processed by another queuer */ 5277881Seric # ifdef LOG 5287881Seric if (LogLevel > 4) 5297881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 5307881Seric # endif LOG 5316980Seric exit(EX_OK); 5326980Seric } 5336980Seric 5346980Seric /* do basic system initialization */ 5354632Seric initsys(); 5366980Seric 5376980Seric /* read the queue control file */ 53817477Seric readqf(CurEnv, TRUE); 5399338Seric CurEnv->e_flags |= EF_INQUEUE; 5409377Seric eatheader(CurEnv); 5416980Seric 5426980Seric /* do the delivery */ 5439338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 5449282Seric sendall(CurEnv, SM_DELIVER); 5456980Seric 5466980Seric /* finish up and exit */ 5474632Seric finis(); 5484632Seric } 5494632Seric 5504632Seric /* 5514632Seric ** Parent -- pick up results. 5524632Seric */ 5534632Seric 5544632Seric errno = 0; 5559377Seric (void) waitfor(i); 5564632Seric } 5574632Seric /* 5584632Seric ** READQF -- read queue file and set up environment. 5594632Seric ** 5604632Seric ** Parameters: 5619377Seric ** e -- the envelope of the job to run. 5629630Seric ** full -- if set, read in all information. Otherwise just 5639630Seric ** read in info needed for a queue print. 5644632Seric ** 5654632Seric ** Returns: 5664632Seric ** none. 5674632Seric ** 5684632Seric ** Side Effects: 5694632Seric ** cf is read and created as the current job, as though 5704632Seric ** we had been invoked by argument. 5714632Seric */ 5724632Seric 57317477Seric readqf(e, full) 5749377Seric register ENVELOPE *e; 5759630Seric bool full; 5764632Seric { 57717477Seric char *qf; 57817477Seric register FILE *qfp; 5797785Seric char buf[MAXFIELD]; 5809348Seric extern char *fgetfolded(); 5814632Seric 5824632Seric /* 58317468Seric ** Read and process the file. 5844632Seric */ 5854632Seric 58617477Seric qf = queuename(e, 'q'); 58717477Seric qfp = fopen(qf, "r"); 58817477Seric if (qfp == NULL) 58917477Seric { 59017477Seric syserr("readqf: no control file %s", qf); 59117477Seric return; 59217477Seric } 59317477Seric FileName = qf; 5949377Seric LineNumber = 0; 5959630Seric if (Verbose && full) 5969377Seric printf("\nRunning %s\n", e->e_id); 59717468Seric while (fgetfolded(buf, sizeof buf, qfp) != NULL) 5984632Seric { 5994632Seric switch (buf[0]) 6004632Seric { 6014632Seric case 'R': /* specify recipient */ 6029618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 6034632Seric break; 6044632Seric 6054632Seric case 'H': /* header */ 6069630Seric if (full) 6079630Seric (void) chompheader(&buf[1], FALSE); 6084632Seric break; 6094632Seric 61010108Seric case 'M': /* message */ 61110108Seric e->e_message = newstr(&buf[1]); 61210108Seric break; 61310108Seric 6144632Seric case 'S': /* sender */ 6154634Seric setsender(newstr(&buf[1])); 6164632Seric break; 6174632Seric 6184632Seric case 'D': /* data file name */ 6199630Seric if (!full) 6209630Seric break; 6219377Seric e->e_df = newstr(&buf[1]); 6229544Seric e->e_dfp = fopen(e->e_df, "r"); 6239544Seric if (e->e_dfp == NULL) 6249377Seric syserr("readqf: cannot open %s", e->e_df); 6254632Seric break; 6264632Seric 6277860Seric case 'T': /* init time */ 6289377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 6294632Seric break; 6304632Seric 6314634Seric case 'P': /* message priority */ 6329377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 6335037Seric 6345037Seric /* make sure that big things get sent eventually */ 6359377Seric e->e_msgpriority -= WKTIMEFACT; 6364634Seric break; 6374634Seric 6384632Seric default: 6399377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 6404632Seric break; 6414632Seric } 6424632Seric } 6439377Seric 6449377Seric FileName = NULL; 6454632Seric } 6464632Seric /* 6479630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6489630Seric ** 6499630Seric ** Parameters: 6509630Seric ** none. 6519630Seric ** 6529630Seric ** Returns: 6539630Seric ** none. 6549630Seric ** 6559630Seric ** Side Effects: 6569630Seric ** Prints a listing of the mail queue on the standard output. 6579630Seric */ 6585182Seric 6599630Seric printqueue() 6609630Seric { 6619630Seric register WORK *w; 6629630Seric FILE *f; 66310070Seric int nrequests; 6649630Seric char buf[MAXLINE]; 6659630Seric 6669630Seric /* 6679630Seric ** Read and order the queue. 6689630Seric */ 6699630Seric 67010070Seric nrequests = orderq(); 6719630Seric 6729630Seric /* 6739630Seric ** Print the work list that we have read. 6749630Seric */ 6759630Seric 6769630Seric /* first see if there is anything */ 67710070Seric if (nrequests <= 0) 6789630Seric { 67910070Seric printf("Mail queue is empty\n"); 6809630Seric return; 6819630Seric } 6829630Seric 68310096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 68410070Seric if (nrequests > WLSIZE) 68510070Seric printf(", only %d printed", WLSIZE); 68610070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6879630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6889630Seric { 6899630Seric struct stat st; 69010070Seric auto time_t submittime = 0; 69110070Seric long dfsize = -1; 69217468Seric int fd; 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); 70310070Seric 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 */ 71810108Seric 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 */ 73310070Seric 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"); 7459630Seric 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); 79917468Seric strcpy(lf, qf); 80017468Seric lf[0] = 'l'; 80117468Seric 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