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*23098Seric static char SccsId[] = "@(#)queue.c 5.3 (Berkeley) 06/08/85 (no queueing)"; 205182Seric # else QUEUE 214632Seric 22*23098Seric static char SccsId[] = "@(#)queue.c 5.3 (Berkeley) 06/08/85"; 235182Seric 244632Seric /* 259377Seric ** Work queue. 269377Seric */ 279377Seric 289377Seric struct work 299377Seric { 309377Seric char *w_name; /* name of control file */ 319377Seric long w_pri; /* priority of message, see below */ 329377Seric struct work *w_next; /* next in queue */ 339377Seric }; 349377Seric 359377Seric typedef struct work WORK; 369377Seric 379377Seric WORK *WorkQ; /* queue of things to be done */ 389377Seric /* 394632Seric ** QUEUEUP -- queue a message up for future transmission. 404632Seric ** 414632Seric ** Parameters: 426980Seric ** e -- the envelope to queue up. 436999Seric ** queueall -- if TRUE, queue all addresses, rather than 446999Seric ** just those with the QQUEUEUP flag set. 459377Seric ** announce -- if TRUE, tell when you are queueing up. 464632Seric ** 474632Seric ** Returns: 484632Seric ** none. 494632Seric ** 504632Seric ** Side Effects: 519377Seric ** The current request are saved in a control file. 524632Seric */ 534632Seric 549377Seric queueup(e, queueall, announce) 556980Seric register ENVELOPE *e; 566999Seric bool queueall; 579377Seric bool announce; 584632Seric { 597812Seric char *tf; 607812Seric char *qf; 617763Seric char buf[MAXLINE]; 627812Seric register FILE *tfp; 634632Seric register HDR *h; 645007Seric register ADDRESS *q; 6510173Seric MAILER nullmailer; 664632Seric 675037Seric /* 6817477Seric ** Create control file. 695037Seric */ 704632Seric 7117477Seric tf = newstr(queuename(e, 't')); 7217477Seric tfp = fopen(tf, "w"); 737812Seric if (tfp == NULL) 744632Seric { 7517477Seric syserr("queueup: cannot create temp file %s", tf); 7617477Seric return; 774632Seric } 7817477Seric (void) chmod(tf, FileMode); 794632Seric 804632Seric # ifdef DEBUG 817677Seric if (tTd(40, 1)) 8217468Seric printf("queueing %s\n", e->e_id); 834632Seric # endif DEBUG 844632Seric 854632Seric /* 866980Seric ** If there is no data file yet, create one. 876980Seric */ 886980Seric 896980Seric if (e->e_df == NULL) 906980Seric { 916980Seric register FILE *dfp; 929389Seric extern putbody(); 936980Seric 947812Seric e->e_df = newstr(queuename(e, 'd')); 956980Seric dfp = fopen(e->e_df, "w"); 966980Seric if (dfp == NULL) 976980Seric { 986980Seric syserr("queueup: cannot create %s", e->e_df); 997812Seric (void) fclose(tfp); 1006980Seric return; 1016980Seric } 1029048Seric (void) chmod(e->e_df, FileMode); 10310173Seric (*e->e_putbody)(dfp, ProgMailer, e); 1047009Seric (void) fclose(dfp); 1059389Seric e->e_putbody = putbody; 1066980Seric } 1076980Seric 1086980Seric /* 1094632Seric ** Output future work requests. 1109377Seric ** Priority should be first, since it is read by orderq. 1114632Seric */ 1124632Seric 1139377Seric /* output message priority */ 1149377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1159377Seric 1169630Seric /* output creation time */ 1179630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1189630Seric 1194632Seric /* output name of data file */ 1207812Seric fprintf(tfp, "D%s\n", e->e_df); 1214632Seric 12210108Seric /* message from envelope, if it exists */ 12310108Seric if (e->e_message != NULL) 12410108Seric fprintf(tfp, "M%s\n", e->e_message); 12510108Seric 1264632Seric /* output name of sender */ 1277812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1284632Seric 1294632Seric /* output list of recipient addresses */ 1306980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1314632Seric { 1327763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1337763Seric bitset(QQUEUEUP, q->q_flags)) 1348245Seric { 1357812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1369377Seric if (announce) 1379377Seric { 1389377Seric e->e_to = q->q_paddr; 1399377Seric message(Arpa_Info, "queued"); 1409377Seric if (LogLevel > 4) 1419377Seric logdelivery("queued"); 1429377Seric e->e_to = NULL; 1439377Seric } 1449387Seric #ifdef DEBUG 1459387Seric if (tTd(40, 1)) 1469387Seric { 1479387Seric printf("queueing "); 1489387Seric printaddr(q, FALSE); 1499387Seric } 1509387Seric #endif DEBUG 1518245Seric } 1524632Seric } 1534632Seric 1549377Seric /* 1559377Seric ** Output headers for this message. 1569377Seric ** Expand macros completely here. Queue run will deal with 1579377Seric ** everything as absolute headers. 1589377Seric ** All headers that must be relative to the recipient 1599377Seric ** can be cracked later. 16010173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 16110173Seric ** no effect on the addresses as they are output. 1629377Seric */ 1639377Seric 16410686Seric bzero((char *) &nullmailer, sizeof nullmailer); 16510173Seric nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 16610349Seric nullmailer.m_eol = "\n"; 16710173Seric 16816147Seric define('g', "\001f", e); 1696980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1704632Seric { 17110686Seric extern bool bitzerop(); 17210686Seric 17312015Seric /* don't output null headers */ 1744632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1754632Seric continue; 17612015Seric 17712015Seric /* don't output resent headers on non-resent messages */ 17812015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 17912015Seric continue; 18012015Seric 18112015Seric /* output this header */ 1827812Seric fprintf(tfp, "H"); 18312015Seric 18412015Seric /* if conditional, output the set of conditions */ 18510686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 18610686Seric { 18710686Seric int j; 18810686Seric 189*23098Seric (void) putc('?', tfp); 19010686Seric for (j = '\0'; j <= '\177'; j++) 19110686Seric if (bitnset(j, h->h_mflags)) 192*23098Seric (void) putc(j, tfp); 193*23098Seric (void) putc('?', tfp); 19410686Seric } 19512015Seric 19612015Seric /* output the header: expand macros, convert addresses */ 1977763Seric if (bitset(H_DEFAULT, h->h_flags)) 1987763Seric { 1997763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 2008236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 2017763Seric } 2028245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 2039348Seric { 2049348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 20510173Seric &nullmailer); 2069348Seric } 2077763Seric else 2088245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 2094632Seric } 2104632Seric 2114632Seric /* 2124632Seric ** Clean up. 2134632Seric */ 2144632Seric 21517477Seric (void) fclose(tfp); 21617468Seric qf = queuename(e, 'q'); 21717468Seric if (tf != NULL) 21817468Seric { 21917468Seric holdsigs(); 22017468Seric (void) unlink(qf); 22117468Seric if (link(tf, qf) < 0) 22217468Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 22317468Seric else 22417468Seric (void) unlink(tf); 22517468Seric rlsesigs(); 22617468Seric } 2277391Seric 2287677Seric # ifdef LOG 2297677Seric /* save log info */ 2307878Seric if (LogLevel > 15) 2317878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 2327677Seric # endif LOG 2334632Seric } 2344632Seric /* 2354632Seric ** RUNQUEUE -- run the jobs in the queue. 2364632Seric ** 2374632Seric ** Gets the stuff out of the queue in some presumably logical 2384632Seric ** order and processes them. 2394632Seric ** 2404632Seric ** Parameters: 2414632Seric ** none. 2424632Seric ** 2434632Seric ** Returns: 2444632Seric ** none. 2454632Seric ** 2464632Seric ** Side Effects: 2474632Seric ** runs things in the mail queue. 2484632Seric */ 2494632Seric 2504639Seric runqueue(forkflag) 2514639Seric bool forkflag; 2524632Seric { 2537466Seric /* 2547466Seric ** See if we want to go off and do other useful work. 2557466Seric */ 2564639Seric 2574639Seric if (forkflag) 2584639Seric { 2597943Seric int pid; 2607943Seric 2617943Seric pid = dofork(); 2627943Seric if (pid != 0) 2634639Seric { 2647943Seric /* parent -- pick up intermediate zombie */ 2659377Seric (void) waitfor(pid); 2667690Seric if (QueueIntvl != 0) 2679348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2684639Seric return; 2694639Seric } 2707943Seric /* child -- double fork */ 2717943Seric if (fork() != 0) 2727943Seric exit(EX_OK); 2734639Seric } 2747876Seric # ifdef LOG 2757876Seric if (LogLevel > 11) 2767943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2777876Seric # endif LOG 2784639Seric 2797466Seric /* 28010205Seric ** Release any resources used by the daemon code. 28110205Seric */ 28210205Seric 28310205Seric # ifdef DAEMON 28410205Seric clrdaemon(); 28510205Seric # endif DAEMON 28610205Seric 28710205Seric /* 2887466Seric ** Start making passes through the queue. 2897466Seric ** First, read and sort the entire queue. 2907466Seric ** Then, process the work in that order. 2917466Seric ** But if you take too long, start over. 2927466Seric */ 2937466Seric 2947943Seric /* order the existing work requests */ 29510070Seric (void) orderq(); 2967690Seric 2977943Seric /* process them once at a time */ 2987943Seric while (WorkQ != NULL) 2994639Seric { 3007943Seric WORK *w = WorkQ; 3017881Seric 3027943Seric WorkQ = WorkQ->w_next; 3037943Seric dowork(w); 3047943Seric free(w->w_name); 3057943Seric free((char *) w); 3064639Seric } 3077943Seric finis(); 3084634Seric } 3094634Seric /* 3104632Seric ** ORDERQ -- order the work queue. 3114632Seric ** 3124632Seric ** Parameters: 3134632Seric ** none. 3144632Seric ** 3154632Seric ** Returns: 31610121Seric ** The number of request in the queue (not necessarily 31710121Seric ** the number of requests in WorkQ however). 3184632Seric ** 3194632Seric ** Side Effects: 3204632Seric ** Sets WorkQ to the queue of available work, in order. 3214632Seric */ 3224632Seric 3234632Seric # define WLSIZE 120 /* max size of worklist per sort */ 3244632Seric 3254632Seric orderq() 3264632Seric { 3276625Sglickman register struct direct *d; 3284632Seric register WORK *w; 3294632Seric register WORK **wp; /* parent of w */ 3306625Sglickman DIR *f; 3314632Seric register int i; 33210121Seric WORK wlist[WLSIZE+1]; 33310070Seric int wn = -1; 3344632Seric extern workcmpf(); 3354632Seric 3364632Seric /* clear out old WorkQ */ 3374632Seric for (w = WorkQ; w != NULL; ) 3384632Seric { 3394632Seric register WORK *nw = w->w_next; 3404632Seric 3414632Seric WorkQ = nw; 3424632Seric free(w->w_name); 3434632Seric free((char *) w); 3444632Seric w = nw; 3454632Seric } 3464632Seric 3474632Seric /* open the queue directory */ 3488148Seric f = opendir("."); 3494632Seric if (f == NULL) 3504632Seric { 3518148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 35210070Seric return (0); 3534632Seric } 3544632Seric 3554632Seric /* 3564632Seric ** Read the work directory. 3574632Seric */ 3584632Seric 35910070Seric while ((d = readdir(f)) != NULL) 3604632Seric { 3619377Seric FILE *cf; 3624632Seric char lbuf[MAXNAME]; 3634632Seric 3644632Seric /* is this an interesting entry? */ 3657812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3664632Seric continue; 3674632Seric 36810070Seric /* yes -- open control file (if not too many files) */ 36910070Seric if (++wn >= WLSIZE) 37010070Seric continue; 3718148Seric cf = fopen(d->d_name, "r"); 3724632Seric if (cf == NULL) 3734632Seric { 3747055Seric /* this may be some random person sending hir msgs */ 3757055Seric /* syserr("orderq: cannot open %s", cbuf); */ 37610090Seric #ifdef DEBUG 37710090Seric if (tTd(41, 2)) 37810090Seric printf("orderq: cannot open %s (%d)\n", 37910090Seric d->d_name, errno); 38010090Seric #endif DEBUG 3817055Seric errno = 0; 38210090Seric wn--; 3834632Seric continue; 3844632Seric } 3858148Seric wlist[wn].w_name = newstr(d->d_name); 3864632Seric 3874632Seric /* extract useful information */ 3884632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3894632Seric { 3909377Seric if (lbuf[0] == 'P') 3914632Seric { 3925037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3934632Seric break; 3944632Seric } 3954632Seric } 3964632Seric (void) fclose(cf); 3974632Seric } 3986625Sglickman (void) closedir(f); 39910090Seric wn++; 4004632Seric 4014632Seric /* 4024632Seric ** Sort the work directory. 4034632Seric */ 4044632Seric 40510121Seric qsort(wlist, min(wn, WLSIZE), sizeof *wlist, workcmpf); 4064632Seric 4074632Seric /* 4084632Seric ** Convert the work list into canonical form. 4099377Seric ** Should be turning it into a list of envelopes here perhaps. 4104632Seric */ 4114632Seric 4124632Seric wp = &WorkQ; 41310121Seric for (i = min(wn, WLSIZE); --i >= 0; ) 4144632Seric { 4154632Seric w = (WORK *) xalloc(sizeof *w); 4164632Seric w->w_name = wlist[i].w_name; 4174632Seric w->w_pri = wlist[i].w_pri; 4184632Seric w->w_next = NULL; 4194632Seric *wp = w; 4204632Seric wp = &w->w_next; 4214632Seric } 4224632Seric 4234632Seric # ifdef DEBUG 4247677Seric if (tTd(40, 1)) 4254632Seric { 4264632Seric for (w = WorkQ; w != NULL; w = w->w_next) 4275037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 4284632Seric } 4294632Seric # endif DEBUG 43010070Seric 43110090Seric return (wn); 4324632Seric } 4334632Seric /* 4347677Seric ** WORKCMPF -- compare function for ordering work. 4354632Seric ** 4364632Seric ** Parameters: 4374632Seric ** a -- the first argument. 4384632Seric ** b -- the second argument. 4394632Seric ** 4404632Seric ** Returns: 44110121Seric ** 1 if a < b 4424632Seric ** 0 if a == b 44310121Seric ** -1 if a > b 4444632Seric ** 4454632Seric ** Side Effects: 4464632Seric ** none. 4474632Seric */ 4484632Seric 4494632Seric workcmpf(a, b) 4505037Seric register WORK *a; 4515037Seric register WORK *b; 4524632Seric { 4535037Seric if (a->w_pri == b->w_pri) 4544632Seric return (0); 4555037Seric else if (a->w_pri > b->w_pri) 45610121Seric return (-1); 45710121Seric else 4584632Seric return (1); 4594632Seric } 4604632Seric /* 4614632Seric ** DOWORK -- do a work request. 4624632Seric ** 4634632Seric ** Parameters: 4644632Seric ** w -- the work request to be satisfied. 4654632Seric ** 4664632Seric ** Returns: 4674632Seric ** none. 4684632Seric ** 4694632Seric ** Side Effects: 4704632Seric ** The work request is satisfied if possible. 4714632Seric */ 4724632Seric 4734632Seric dowork(w) 4744632Seric register WORK *w; 4754632Seric { 4764632Seric register int i; 4774632Seric 4784632Seric # ifdef DEBUG 4797677Seric if (tTd(40, 1)) 4805037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4814632Seric # endif DEBUG 4824632Seric 4834632Seric /* 4844632Seric ** Fork for work. 4854632Seric */ 4864632Seric 4874632Seric i = fork(); 4884632Seric if (i < 0) 4894632Seric { 4904632Seric syserr("dowork: cannot fork"); 4914632Seric return; 4924632Seric } 4934632Seric 4944632Seric if (i == 0) 4954632Seric { 4964632Seric /* 4974632Seric ** CHILD 4988148Seric ** Lock the control file to avoid duplicate deliveries. 4998148Seric ** Then run the file as though we had just read it. 5007350Seric ** We save an idea of the temporary name so we 5017350Seric ** can recover on interrupt. 5024632Seric */ 5034632Seric 5047763Seric /* set basic modes, etc. */ 5057356Seric (void) alarm(0); 50610195Seric closexscript(CurEnv); 5079338Seric CurEnv->e_flags &= ~EF_FATALERRS; 5084632Seric QueueRun = TRUE; 5099377Seric ErrorMode = EM_MAIL; 5108148Seric CurEnv->e_id = &w->w_name[2]; 5117876Seric # ifdef LOG 5127876Seric if (LogLevel > 11) 5137881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 5147881Seric getpid()); 5157876Seric # endif LOG 5167763Seric 5177763Seric /* don't use the headers from sendmail.cf... */ 5187763Seric CurEnv->e_header = NULL; 5197763Seric 52017468Seric /* lock the control file during processing */ 5217812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 5226980Seric { 5237812Seric /* being processed by another queuer */ 5247881Seric # ifdef LOG 5257881Seric if (LogLevel > 4) 5267881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 5277881Seric # endif LOG 5286980Seric exit(EX_OK); 5296980Seric } 5306980Seric 5316980Seric /* do basic system initialization */ 5324632Seric initsys(); 5336980Seric 5346980Seric /* read the queue control file */ 53517477Seric readqf(CurEnv, TRUE); 5369338Seric CurEnv->e_flags |= EF_INQUEUE; 5379377Seric eatheader(CurEnv); 5386980Seric 5396980Seric /* do the delivery */ 5409338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 5419282Seric sendall(CurEnv, SM_DELIVER); 5426980Seric 5436980Seric /* finish up and exit */ 5444632Seric finis(); 5454632Seric } 5464632Seric 5474632Seric /* 5484632Seric ** Parent -- pick up results. 5494632Seric */ 5504632Seric 5514632Seric errno = 0; 5529377Seric (void) waitfor(i); 5534632Seric } 5544632Seric /* 5554632Seric ** READQF -- read queue file and set up environment. 5564632Seric ** 5574632Seric ** Parameters: 5589377Seric ** e -- the envelope of the job to run. 5599630Seric ** full -- if set, read in all information. Otherwise just 5609630Seric ** read in info needed for a queue print. 5614632Seric ** 5624632Seric ** Returns: 5634632Seric ** none. 5644632Seric ** 5654632Seric ** Side Effects: 5664632Seric ** cf is read and created as the current job, as though 5674632Seric ** we had been invoked by argument. 5684632Seric */ 5694632Seric 57017477Seric readqf(e, full) 5719377Seric register ENVELOPE *e; 5729630Seric bool full; 5734632Seric { 57417477Seric char *qf; 57517477Seric register FILE *qfp; 5767785Seric char buf[MAXFIELD]; 5779348Seric extern char *fgetfolded(); 5784632Seric 5794632Seric /* 58017468Seric ** Read and process the file. 5814632Seric */ 5824632Seric 58317477Seric qf = queuename(e, 'q'); 58417477Seric qfp = fopen(qf, "r"); 58517477Seric if (qfp == NULL) 58617477Seric { 58717477Seric syserr("readqf: no control file %s", qf); 58817477Seric return; 58917477Seric } 59017477Seric FileName = qf; 5919377Seric LineNumber = 0; 5929630Seric if (Verbose && full) 5939377Seric printf("\nRunning %s\n", e->e_id); 59417468Seric while (fgetfolded(buf, sizeof buf, qfp) != NULL) 5954632Seric { 5964632Seric switch (buf[0]) 5974632Seric { 5984632Seric case 'R': /* specify recipient */ 5999618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 6004632Seric break; 6014632Seric 6024632Seric case 'H': /* header */ 6039630Seric if (full) 6049630Seric (void) chompheader(&buf[1], FALSE); 6054632Seric break; 6064632Seric 60710108Seric case 'M': /* message */ 60810108Seric e->e_message = newstr(&buf[1]); 60910108Seric break; 61010108Seric 6114632Seric case 'S': /* sender */ 6124634Seric setsender(newstr(&buf[1])); 6134632Seric break; 6144632Seric 6154632Seric case 'D': /* data file name */ 6169630Seric if (!full) 6179630Seric break; 6189377Seric e->e_df = newstr(&buf[1]); 6199544Seric e->e_dfp = fopen(e->e_df, "r"); 6209544Seric if (e->e_dfp == NULL) 6219377Seric syserr("readqf: cannot open %s", e->e_df); 6224632Seric break; 6234632Seric 6247860Seric case 'T': /* init time */ 6259377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 6264632Seric break; 6274632Seric 6284634Seric case 'P': /* message priority */ 6299377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 6305037Seric 6315037Seric /* make sure that big things get sent eventually */ 6329377Seric e->e_msgpriority -= WKTIMEFACT; 6334634Seric break; 6344634Seric 6354632Seric default: 6369377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 6374632Seric break; 6384632Seric } 6394632Seric } 6409377Seric 6419377Seric FileName = NULL; 6424632Seric } 6434632Seric /* 6449630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6459630Seric ** 6469630Seric ** Parameters: 6479630Seric ** none. 6489630Seric ** 6499630Seric ** Returns: 6509630Seric ** none. 6519630Seric ** 6529630Seric ** Side Effects: 6539630Seric ** Prints a listing of the mail queue on the standard output. 6549630Seric */ 6555182Seric 6569630Seric printqueue() 6579630Seric { 6589630Seric register WORK *w; 6599630Seric FILE *f; 66010070Seric int nrequests; 6619630Seric char buf[MAXLINE]; 6629630Seric 6639630Seric /* 6649630Seric ** Read and order the queue. 6659630Seric */ 6669630Seric 66710070Seric nrequests = orderq(); 6689630Seric 6699630Seric /* 6709630Seric ** Print the work list that we have read. 6719630Seric */ 6729630Seric 6739630Seric /* first see if there is anything */ 67410070Seric if (nrequests <= 0) 6759630Seric { 67610070Seric printf("Mail queue is empty\n"); 6779630Seric return; 6789630Seric } 6799630Seric 68010096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 68110070Seric if (nrequests > WLSIZE) 68210070Seric printf(", only %d printed", WLSIZE); 68310070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6849630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6859630Seric { 6869630Seric struct stat st; 68710070Seric auto time_t submittime = 0; 68810070Seric long dfsize = -1; 68910108Seric char lf[20]; 69010108Seric char message[MAXLINE]; 6919630Seric 69217468Seric f = fopen(w->w_name, "r"); 69317468Seric if (f == NULL) 69417468Seric { 69517468Seric errno = 0; 69617468Seric continue; 69717468Seric } 6989630Seric printf("%7s", w->w_name + 2); 699*23098Seric (void) strcpy(lf, w->w_name); 70010070Seric lf[0] = 'l'; 70110070Seric if (stat(lf, &st) >= 0) 70210070Seric printf("*"); 70310070Seric else 70410070Seric printf(" "); 70510070Seric errno = 0; 70617468Seric 70710108Seric message[0] = '\0'; 7089630Seric while (fgets(buf, sizeof buf, f) != NULL) 7099630Seric { 7109630Seric fixcrlf(buf, TRUE); 7119630Seric switch (buf[0]) 7129630Seric { 71310108Seric case 'M': /* error message */ 714*23098Seric (void) strcpy(message, &buf[1]); 71510108Seric break; 71610108Seric 7179630Seric case 'S': /* sender name */ 71813015Seric printf("%8ld %.16s %.45s", dfsize, 71912517Seric ctime(&submittime), &buf[1]); 72010108Seric if (message[0] != '\0') 72112517Seric printf("\n\t\t\t\t (%.43s)", message); 7229630Seric break; 7239630Seric 7249630Seric case 'R': /* recipient name */ 72512517Seric printf("\n\t\t\t\t %.45s", &buf[1]); 7269630Seric break; 7279630Seric 7289630Seric case 'T': /* creation time */ 729*23098Seric (void) sscanf(&buf[1], "%ld", &submittime); 7309630Seric break; 73110070Seric 73210070Seric case 'D': /* data file name */ 73310070Seric if (stat(&buf[1], &st) >= 0) 73410070Seric dfsize = st.st_size; 73510070Seric break; 7369630Seric } 7379630Seric } 73810070Seric if (submittime == (time_t) 0) 73910070Seric printf(" (no control file)"); 7409630Seric printf("\n"); 741*23098Seric (void) fclose(f); 7429630Seric } 7439630Seric } 7449630Seric 7455182Seric # endif QUEUE 74617468Seric /* 74717468Seric ** QUEUENAME -- build a file name in the queue directory for this envelope. 74817468Seric ** 74917468Seric ** Assigns an id code if one does not already exist. 75017468Seric ** This code is very careful to avoid trashing existing files 75117468Seric ** under any circumstances. 75217468Seric ** We first create an nf file that is only used when 75317468Seric ** assigning an id. This file is always empty, so that 75417468Seric ** we can never accidently truncate an lf file. 75517468Seric ** 75617468Seric ** Parameters: 75717468Seric ** e -- envelope to build it in/from. 75817468Seric ** type -- the file type, used as the first character 75917468Seric ** of the file name. 76017468Seric ** 76117468Seric ** Returns: 76217468Seric ** a pointer to the new file name (in a static buffer). 76317468Seric ** 76417468Seric ** Side Effects: 76517468Seric ** Will create the lf and qf files if no id code is 76617468Seric ** already assigned. This will cause the envelope 76717468Seric ** to be modified. 76817468Seric */ 76917468Seric 77017468Seric char * 77117468Seric queuename(e, type) 77217468Seric register ENVELOPE *e; 77317468Seric char type; 77417468Seric { 77517468Seric static char buf[MAXNAME]; 77617468Seric static int pid = -1; 77717468Seric char c1 = 'A'; 77817468Seric char c2 = 'A'; 77917468Seric 78017468Seric if (e->e_id == NULL) 78117468Seric { 78217468Seric char qf[20]; 78317468Seric char nf[20]; 78417468Seric char lf[20]; 78517468Seric 78617468Seric /* find a unique id */ 78717468Seric if (pid != getpid()) 78817468Seric { 78917468Seric /* new process -- start back at "AA" */ 79017468Seric pid = getpid(); 79117468Seric c1 = 'A'; 79217468Seric c2 = 'A' - 1; 79317468Seric } 79417468Seric (void) sprintf(qf, "qfAA%05d", pid); 795*23098Seric (void) strcpy(lf, qf); 79617468Seric lf[0] = 'l'; 797*23098Seric (void) strcpy(nf, qf); 79817468Seric nf[0] = 'n'; 79917468Seric 80017468Seric while (c1 < '~' || c2 < 'Z') 80117468Seric { 80217468Seric int i; 80317468Seric 80417468Seric if (c2 >= 'Z') 80517468Seric { 80617468Seric c1++; 80717468Seric c2 = 'A' - 1; 80817468Seric } 80917477Seric lf[2] = nf[2] = qf[2] = c1; 81017477Seric lf[3] = nf[3] = qf[3] = ++c2; 81117468Seric # ifdef DEBUG 81217468Seric if (tTd(7, 20)) 81317468Seric printf("queuename: trying \"%s\"\n", nf); 81417468Seric # endif DEBUG 81517468Seric 81617468Seric # ifdef QUEUE 81717468Seric if (access(lf, 0) >= 0 || access(qf, 0) >= 0) 81817468Seric continue; 81917468Seric errno = 0; 82017468Seric i = creat(nf, FileMode); 82117468Seric if (i < 0) 82217468Seric { 82317468Seric (void) unlink(nf); /* kernel bug */ 82417468Seric continue; 82517468Seric } 82617468Seric (void) close(i); 82717468Seric i = link(nf, lf); 82817468Seric (void) unlink(nf); 82917468Seric if (i < 0) 83017468Seric continue; 83117468Seric if (link(lf, qf) >= 0) 83217468Seric break; 83317468Seric (void) unlink(lf); 83417468Seric # else QUEUE 83517982Seric if (close(creat(qf, FileMode)) >= 0) 83617982Seric break; 83717468Seric # endif QUEUE 83817468Seric } 83917468Seric if (c1 >= '~' && c2 >= 'Z') 84017468Seric { 84117468Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 84217468Seric qf, QueueDir); 84317468Seric exit(EX_OSERR); 84417468Seric } 84517468Seric e->e_id = newstr(&qf[2]); 84617468Seric define('i', e->e_id, e); 84717468Seric # ifdef DEBUG 84817468Seric if (tTd(7, 1)) 84917468Seric printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 85017468Seric # ifdef LOG 85117468Seric if (LogLevel > 16) 85217468Seric syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 85317468Seric # endif LOG 85417468Seric # endif DEBUG 85517468Seric } 85617468Seric 85717468Seric if (type == '\0') 85817468Seric return (NULL); 85917468Seric (void) sprintf(buf, "%cf%s", type, e->e_id); 86017468Seric # ifdef DEBUG 86117468Seric if (tTd(7, 2)) 86217468Seric printf("queuename: %s\n", buf); 86317468Seric # endif DEBUG 86417468Seric return (buf); 86517468Seric } 86617468Seric /* 86717468Seric ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 86817468Seric ** 86917468Seric ** Parameters: 87017468Seric ** e -- the envelope to unlock. 87117468Seric ** 87217468Seric ** Returns: 87317468Seric ** none 87417468Seric ** 87517468Seric ** Side Effects: 87617468Seric ** unlocks the queue for `e'. 87717468Seric */ 87817468Seric 87917468Seric unlockqueue(e) 88017468Seric ENVELOPE *e; 88117468Seric { 88217468Seric /* remove the transcript */ 88317468Seric #ifdef DEBUG 88417468Seric # ifdef LOG 88517468Seric if (LogLevel > 19) 88617468Seric syslog(LOG_DEBUG, "%s: unlock", e->e_id); 88717468Seric # endif LOG 88817468Seric if (!tTd(51, 4)) 88917468Seric #endif DEBUG 89017468Seric xunlink(queuename(e, 'x')); 89117468Seric 89217468Seric # ifdef QUEUE 89317468Seric /* last but not least, remove the lock */ 89417468Seric xunlink(queuename(e, 'l')); 89517468Seric # endif QUEUE 89617468Seric } 897