14632Seric # include "sendmail.h" 24632Seric # include <sys/stat.h> 313707Ssam # include <sys/dir.h> 44634Seric # include <signal.h> 54632Seric # include <errno.h> 64632Seric 75182Seric # ifndef QUEUE 8*17477Seric SCCSID(@(#)queue.c 4.4 12/06/84 (no queueing)); 95182Seric # else QUEUE 104632Seric 11*17477Seric SCCSID(@(#)queue.c 4.4 12/06/84); 125182Seric 134632Seric /* 149377Seric ** Work queue. 159377Seric */ 169377Seric 179377Seric struct work 189377Seric { 199377Seric char *w_name; /* name of control file */ 209377Seric long w_pri; /* priority of message, see below */ 219377Seric struct work *w_next; /* next in queue */ 229377Seric }; 239377Seric 249377Seric typedef struct work WORK; 259377Seric 269377Seric WORK *WorkQ; /* queue of things to be done */ 279377Seric /* 284632Seric ** QUEUEUP -- queue a message up for future transmission. 294632Seric ** 304632Seric ** Parameters: 316980Seric ** e -- the envelope to queue up. 326999Seric ** queueall -- if TRUE, queue all addresses, rather than 336999Seric ** just those with the QQUEUEUP flag set. 349377Seric ** announce -- if TRUE, tell when you are queueing up. 354632Seric ** 364632Seric ** Returns: 374632Seric ** none. 384632Seric ** 394632Seric ** Side Effects: 409377Seric ** The current request are saved in a control file. 414632Seric */ 424632Seric 439377Seric queueup(e, queueall, announce) 446980Seric register ENVELOPE *e; 456999Seric bool queueall; 469377Seric bool announce; 474632Seric { 487812Seric char *tf; 497812Seric char *qf; 507763Seric char buf[MAXLINE]; 517812Seric register FILE *tfp; 524632Seric register HDR *h; 535007Seric register ADDRESS *q; 5410173Seric MAILER nullmailer; 554632Seric 565037Seric /* 57*17477Seric ** Create control file. 585037Seric */ 594632Seric 60*17477Seric tf = newstr(queuename(e, 't')); 61*17477Seric tfp = fopen(tf, "w"); 627812Seric if (tfp == NULL) 634632Seric { 64*17477Seric syserr("queueup: cannot create temp file %s", tf); 65*17477Seric return; 664632Seric } 67*17477Seric (void) chmod(tf, FileMode); 684632Seric 694632Seric # ifdef DEBUG 707677Seric if (tTd(40, 1)) 7117468Seric printf("queueing %s\n", e->e_id); 724632Seric # endif DEBUG 734632Seric 744632Seric /* 756980Seric ** If there is no data file yet, create one. 766980Seric */ 776980Seric 786980Seric if (e->e_df == NULL) 796980Seric { 806980Seric register FILE *dfp; 819389Seric extern putbody(); 826980Seric 837812Seric e->e_df = newstr(queuename(e, 'd')); 846980Seric dfp = fopen(e->e_df, "w"); 856980Seric if (dfp == NULL) 866980Seric { 876980Seric syserr("queueup: cannot create %s", e->e_df); 887812Seric (void) fclose(tfp); 896980Seric return; 906980Seric } 919048Seric (void) chmod(e->e_df, FileMode); 9210173Seric (*e->e_putbody)(dfp, ProgMailer, e); 937009Seric (void) fclose(dfp); 949389Seric e->e_putbody = putbody; 956980Seric } 966980Seric 976980Seric /* 984632Seric ** Output future work requests. 999377Seric ** Priority should be first, since it is read by orderq. 1004632Seric */ 1014632Seric 1029377Seric /* output message priority */ 1039377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1049377Seric 1059630Seric /* output creation time */ 1069630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1079630Seric 1084632Seric /* output name of data file */ 1097812Seric fprintf(tfp, "D%s\n", e->e_df); 1104632Seric 11110108Seric /* message from envelope, if it exists */ 11210108Seric if (e->e_message != NULL) 11310108Seric fprintf(tfp, "M%s\n", e->e_message); 11410108Seric 1154632Seric /* output name of sender */ 1167812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1174632Seric 1184632Seric /* output list of recipient addresses */ 1196980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1204632Seric { 1217763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1227763Seric bitset(QQUEUEUP, q->q_flags)) 1238245Seric { 1247812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1259377Seric if (announce) 1269377Seric { 1279377Seric e->e_to = q->q_paddr; 1289377Seric message(Arpa_Info, "queued"); 1299377Seric if (LogLevel > 4) 1309377Seric logdelivery("queued"); 1319377Seric e->e_to = NULL; 1329377Seric } 1339387Seric #ifdef DEBUG 1349387Seric if (tTd(40, 1)) 1359387Seric { 1369387Seric printf("queueing "); 1379387Seric printaddr(q, FALSE); 1389387Seric } 1399387Seric #endif DEBUG 1408245Seric } 1414632Seric } 1424632Seric 1439377Seric /* 1449377Seric ** Output headers for this message. 1459377Seric ** Expand macros completely here. Queue run will deal with 1469377Seric ** everything as absolute headers. 1479377Seric ** All headers that must be relative to the recipient 1489377Seric ** can be cracked later. 14910173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 15010173Seric ** no effect on the addresses as they are output. 1519377Seric */ 1529377Seric 15310686Seric bzero((char *) &nullmailer, sizeof nullmailer); 15410173Seric nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 15510349Seric nullmailer.m_eol = "\n"; 15610173Seric 15716147Seric define('g', "\001f", e); 1586980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1594632Seric { 16010686Seric extern bool bitzerop(); 16110686Seric 16212015Seric /* don't output null headers */ 1634632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1644632Seric continue; 16512015Seric 16612015Seric /* don't output resent headers on non-resent messages */ 16712015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 16812015Seric continue; 16912015Seric 17012015Seric /* output this header */ 1717812Seric fprintf(tfp, "H"); 17212015Seric 17312015Seric /* if conditional, output the set of conditions */ 17410686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 17510686Seric { 17610686Seric int j; 17710686Seric 17810686Seric putc('?', tfp); 17910686Seric for (j = '\0'; j <= '\177'; j++) 18010686Seric if (bitnset(j, h->h_mflags)) 18110686Seric putc(j, tfp); 18210686Seric putc('?', tfp); 18310686Seric } 18412015Seric 18512015Seric /* output the header: expand macros, convert addresses */ 1867763Seric if (bitset(H_DEFAULT, h->h_flags)) 1877763Seric { 1887763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 1898236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 1907763Seric } 1918245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 1929348Seric { 1939348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 19410173Seric &nullmailer); 1959348Seric } 1967763Seric else 1978245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 1984632Seric } 1994632Seric 2004632Seric /* 2014632Seric ** Clean up. 2024632Seric */ 2034632Seric 204*17477Seric (void) fclose(tfp); 20517468Seric qf = queuename(e, 'q'); 20617468Seric if (tf != NULL) 20717468Seric { 20817468Seric holdsigs(); 20917468Seric (void) unlink(qf); 21017468Seric if (link(tf, qf) < 0) 21117468Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 21217468Seric else 21317468Seric (void) unlink(tf); 21417468Seric rlsesigs(); 21517468Seric } 2167391Seric 2177677Seric # ifdef LOG 2187677Seric /* save log info */ 2197878Seric if (LogLevel > 15) 2207878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 2217677Seric # endif LOG 2224632Seric } 2234632Seric /* 2244632Seric ** RUNQUEUE -- run the jobs in the queue. 2254632Seric ** 2264632Seric ** Gets the stuff out of the queue in some presumably logical 2274632Seric ** order and processes them. 2284632Seric ** 2294632Seric ** Parameters: 2304632Seric ** none. 2314632Seric ** 2324632Seric ** Returns: 2334632Seric ** none. 2344632Seric ** 2354632Seric ** Side Effects: 2364632Seric ** runs things in the mail queue. 2374632Seric */ 2384632Seric 2394639Seric runqueue(forkflag) 2404639Seric bool forkflag; 2414632Seric { 2427466Seric /* 2437466Seric ** See if we want to go off and do other useful work. 2447466Seric */ 2454639Seric 2464639Seric if (forkflag) 2474639Seric { 2487943Seric int pid; 2497943Seric 2507943Seric pid = dofork(); 2517943Seric if (pid != 0) 2524639Seric { 2537943Seric /* parent -- pick up intermediate zombie */ 2549377Seric (void) waitfor(pid); 2557690Seric if (QueueIntvl != 0) 2569348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2574639Seric return; 2584639Seric } 2597943Seric /* child -- double fork */ 2607943Seric if (fork() != 0) 2617943Seric exit(EX_OK); 2624639Seric } 2637876Seric # ifdef LOG 2647876Seric if (LogLevel > 11) 2657943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2667876Seric # endif LOG 2674639Seric 2687466Seric /* 26910205Seric ** Release any resources used by the daemon code. 27010205Seric */ 27110205Seric 27210205Seric # ifdef DAEMON 27310205Seric clrdaemon(); 27410205Seric # endif DAEMON 27510205Seric 27610205Seric /* 2777466Seric ** Start making passes through the queue. 2787466Seric ** First, read and sort the entire queue. 2797466Seric ** Then, process the work in that order. 2807466Seric ** But if you take too long, start over. 2817466Seric */ 2827466Seric 2837943Seric /* order the existing work requests */ 28410070Seric (void) orderq(); 2857690Seric 2867943Seric /* process them once at a time */ 2877943Seric while (WorkQ != NULL) 2884639Seric { 2897943Seric WORK *w = WorkQ; 2907881Seric 2917943Seric WorkQ = WorkQ->w_next; 2927943Seric dowork(w); 2937943Seric free(w->w_name); 2947943Seric free((char *) w); 2954639Seric } 2967943Seric finis(); 2974634Seric } 2984634Seric /* 2994632Seric ** ORDERQ -- order the work queue. 3004632Seric ** 3014632Seric ** Parameters: 3024632Seric ** none. 3034632Seric ** 3044632Seric ** Returns: 30510121Seric ** The number of request in the queue (not necessarily 30610121Seric ** the number of requests in WorkQ however). 3074632Seric ** 3084632Seric ** Side Effects: 3094632Seric ** Sets WorkQ to the queue of available work, in order. 3104632Seric */ 3114632Seric 3124632Seric # define WLSIZE 120 /* max size of worklist per sort */ 3134632Seric 3144632Seric orderq() 3154632Seric { 3166625Sglickman register struct direct *d; 3174632Seric register WORK *w; 3184632Seric register WORK **wp; /* parent of w */ 3196625Sglickman DIR *f; 3204632Seric register int i; 32110121Seric WORK wlist[WLSIZE+1]; 32210070Seric int wn = -1; 3234632Seric extern workcmpf(); 3244632Seric 3254632Seric /* clear out old WorkQ */ 3264632Seric for (w = WorkQ; w != NULL; ) 3274632Seric { 3284632Seric register WORK *nw = w->w_next; 3294632Seric 3304632Seric WorkQ = nw; 3314632Seric free(w->w_name); 3324632Seric free((char *) w); 3334632Seric w = nw; 3344632Seric } 3354632Seric 3364632Seric /* open the queue directory */ 3378148Seric f = opendir("."); 3384632Seric if (f == NULL) 3394632Seric { 3408148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 34110070Seric return (0); 3424632Seric } 3434632Seric 3444632Seric /* 3454632Seric ** Read the work directory. 3464632Seric */ 3474632Seric 34810070Seric while ((d = readdir(f)) != NULL) 3494632Seric { 3509377Seric FILE *cf; 3514632Seric char lbuf[MAXNAME]; 3524632Seric 3534632Seric /* is this an interesting entry? */ 3547812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3554632Seric continue; 3564632Seric 35710070Seric /* yes -- open control file (if not too many files) */ 35810070Seric if (++wn >= WLSIZE) 35910070Seric continue; 3608148Seric cf = fopen(d->d_name, "r"); 3614632Seric if (cf == NULL) 3624632Seric { 3637055Seric /* this may be some random person sending hir msgs */ 3647055Seric /* syserr("orderq: cannot open %s", cbuf); */ 36510090Seric #ifdef DEBUG 36610090Seric if (tTd(41, 2)) 36710090Seric printf("orderq: cannot open %s (%d)\n", 36810090Seric d->d_name, errno); 36910090Seric #endif DEBUG 3707055Seric errno = 0; 37110090Seric wn--; 3724632Seric continue; 3734632Seric } 3748148Seric wlist[wn].w_name = newstr(d->d_name); 3754632Seric 3764632Seric /* extract useful information */ 3774632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3784632Seric { 3799377Seric if (lbuf[0] == 'P') 3804632Seric { 3815037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3824632Seric break; 3834632Seric } 3844632Seric } 3854632Seric (void) fclose(cf); 3864632Seric } 3876625Sglickman (void) closedir(f); 38810090Seric wn++; 3894632Seric 3904632Seric /* 3914632Seric ** Sort the work directory. 3924632Seric */ 3934632Seric 39410121Seric qsort(wlist, min(wn, WLSIZE), sizeof *wlist, workcmpf); 3954632Seric 3964632Seric /* 3974632Seric ** Convert the work list into canonical form. 3989377Seric ** Should be turning it into a list of envelopes here perhaps. 3994632Seric */ 4004632Seric 4014632Seric wp = &WorkQ; 40210121Seric for (i = min(wn, WLSIZE); --i >= 0; ) 4034632Seric { 4044632Seric w = (WORK *) xalloc(sizeof *w); 4054632Seric w->w_name = wlist[i].w_name; 4064632Seric w->w_pri = wlist[i].w_pri; 4074632Seric w->w_next = NULL; 4084632Seric *wp = w; 4094632Seric wp = &w->w_next; 4104632Seric } 4114632Seric 4124632Seric # ifdef DEBUG 4137677Seric if (tTd(40, 1)) 4144632Seric { 4154632Seric for (w = WorkQ; w != NULL; w = w->w_next) 4165037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 4174632Seric } 4184632Seric # endif DEBUG 41910070Seric 42010090Seric return (wn); 4214632Seric } 4224632Seric /* 4237677Seric ** WORKCMPF -- compare function for ordering work. 4244632Seric ** 4254632Seric ** Parameters: 4264632Seric ** a -- the first argument. 4274632Seric ** b -- the second argument. 4284632Seric ** 4294632Seric ** Returns: 43010121Seric ** 1 if a < b 4314632Seric ** 0 if a == b 43210121Seric ** -1 if a > b 4334632Seric ** 4344632Seric ** Side Effects: 4354632Seric ** none. 4364632Seric */ 4374632Seric 4384632Seric workcmpf(a, b) 4395037Seric register WORK *a; 4405037Seric register WORK *b; 4414632Seric { 4425037Seric if (a->w_pri == b->w_pri) 4434632Seric return (0); 4445037Seric else if (a->w_pri > b->w_pri) 44510121Seric return (-1); 44610121Seric else 4474632Seric return (1); 4484632Seric } 4494632Seric /* 4504632Seric ** DOWORK -- do a work request. 4514632Seric ** 4524632Seric ** Parameters: 4534632Seric ** w -- the work request to be satisfied. 4544632Seric ** 4554632Seric ** Returns: 4564632Seric ** none. 4574632Seric ** 4584632Seric ** Side Effects: 4594632Seric ** The work request is satisfied if possible. 4604632Seric */ 4614632Seric 4624632Seric dowork(w) 4634632Seric register WORK *w; 4644632Seric { 4654632Seric register int i; 4664632Seric 4674632Seric # ifdef DEBUG 4687677Seric if (tTd(40, 1)) 4695037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4704632Seric # endif DEBUG 4714632Seric 4724632Seric /* 4734632Seric ** Fork for work. 4744632Seric */ 4754632Seric 4764632Seric i = fork(); 4774632Seric if (i < 0) 4784632Seric { 4794632Seric syserr("dowork: cannot fork"); 4804632Seric return; 4814632Seric } 4824632Seric 4834632Seric if (i == 0) 4844632Seric { 4854632Seric /* 4864632Seric ** CHILD 4878148Seric ** Lock the control file to avoid duplicate deliveries. 4888148Seric ** Then run the file as though we had just read it. 4897350Seric ** We save an idea of the temporary name so we 4907350Seric ** can recover on interrupt. 4914632Seric */ 4924632Seric 4937763Seric /* set basic modes, etc. */ 4947356Seric (void) alarm(0); 49510195Seric closexscript(CurEnv); 4969338Seric CurEnv->e_flags &= ~EF_FATALERRS; 4974632Seric QueueRun = TRUE; 4989377Seric ErrorMode = EM_MAIL; 4998148Seric CurEnv->e_id = &w->w_name[2]; 5007876Seric # ifdef LOG 5017876Seric if (LogLevel > 11) 5027881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 5037881Seric getpid()); 5047876Seric # endif LOG 5057763Seric 5067763Seric /* don't use the headers from sendmail.cf... */ 5077763Seric CurEnv->e_header = NULL; 5087763Seric 50917468Seric /* lock the control file during processing */ 5107812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 5116980Seric { 5127812Seric /* being processed by another queuer */ 5137881Seric # ifdef LOG 5147881Seric if (LogLevel > 4) 5157881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 5167881Seric # endif LOG 5176980Seric exit(EX_OK); 5186980Seric } 5196980Seric 5206980Seric /* do basic system initialization */ 5214632Seric initsys(); 5226980Seric 5236980Seric /* read the queue control file */ 524*17477Seric readqf(CurEnv, TRUE); 5259338Seric CurEnv->e_flags |= EF_INQUEUE; 5269377Seric eatheader(CurEnv); 5276980Seric 5286980Seric /* do the delivery */ 5299338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 5309282Seric sendall(CurEnv, SM_DELIVER); 5316980Seric 5326980Seric /* finish up and exit */ 5334632Seric finis(); 5344632Seric } 5354632Seric 5364632Seric /* 5374632Seric ** Parent -- pick up results. 5384632Seric */ 5394632Seric 5404632Seric errno = 0; 5419377Seric (void) waitfor(i); 5424632Seric } 5434632Seric /* 5444632Seric ** READQF -- read queue file and set up environment. 5454632Seric ** 5464632Seric ** Parameters: 5479377Seric ** e -- the envelope of the job to run. 5489630Seric ** full -- if set, read in all information. Otherwise just 5499630Seric ** read in info needed for a queue print. 5504632Seric ** 5514632Seric ** Returns: 5524632Seric ** none. 5534632Seric ** 5544632Seric ** Side Effects: 5554632Seric ** cf is read and created as the current job, as though 5564632Seric ** we had been invoked by argument. 5574632Seric */ 5584632Seric 559*17477Seric readqf(e, full) 5609377Seric register ENVELOPE *e; 5619630Seric bool full; 5624632Seric { 563*17477Seric char *qf; 564*17477Seric register FILE *qfp; 5657785Seric char buf[MAXFIELD]; 5669348Seric extern char *fgetfolded(); 5674632Seric 5684632Seric /* 56917468Seric ** Read and process the file. 5704632Seric */ 5714632Seric 572*17477Seric qf = queuename(e, 'q'); 573*17477Seric qfp = fopen(qf, "r"); 574*17477Seric if (qfp == NULL) 575*17477Seric { 576*17477Seric syserr("readqf: no control file %s", qf); 577*17477Seric return; 578*17477Seric } 579*17477Seric FileName = qf; 5809377Seric LineNumber = 0; 5819630Seric if (Verbose && full) 5829377Seric printf("\nRunning %s\n", e->e_id); 58317468Seric while (fgetfolded(buf, sizeof buf, qfp) != NULL) 5844632Seric { 5854632Seric switch (buf[0]) 5864632Seric { 5874632Seric case 'R': /* specify recipient */ 5889618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 5894632Seric break; 5904632Seric 5914632Seric case 'H': /* header */ 5929630Seric if (full) 5939630Seric (void) chompheader(&buf[1], FALSE); 5944632Seric break; 5954632Seric 59610108Seric case 'M': /* message */ 59710108Seric e->e_message = newstr(&buf[1]); 59810108Seric break; 59910108Seric 6004632Seric case 'S': /* sender */ 6014634Seric setsender(newstr(&buf[1])); 6024632Seric break; 6034632Seric 6044632Seric case 'D': /* data file name */ 6059630Seric if (!full) 6069630Seric break; 6079377Seric e->e_df = newstr(&buf[1]); 6089544Seric e->e_dfp = fopen(e->e_df, "r"); 6099544Seric if (e->e_dfp == NULL) 6109377Seric syserr("readqf: cannot open %s", e->e_df); 6114632Seric break; 6124632Seric 6137860Seric case 'T': /* init time */ 6149377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 6154632Seric break; 6164632Seric 6174634Seric case 'P': /* message priority */ 6189377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 6195037Seric 6205037Seric /* make sure that big things get sent eventually */ 6219377Seric e->e_msgpriority -= WKTIMEFACT; 6224634Seric break; 6234634Seric 6244632Seric default: 6259377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 6264632Seric break; 6274632Seric } 6284632Seric } 6299377Seric 6309377Seric FileName = NULL; 6314632Seric } 6324632Seric /* 6339630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6349630Seric ** 6359630Seric ** Parameters: 6369630Seric ** none. 6379630Seric ** 6389630Seric ** Returns: 6399630Seric ** none. 6409630Seric ** 6419630Seric ** Side Effects: 6429630Seric ** Prints a listing of the mail queue on the standard output. 6439630Seric */ 6445182Seric 6459630Seric printqueue() 6469630Seric { 6479630Seric register WORK *w; 6489630Seric FILE *f; 64910070Seric int nrequests; 6509630Seric char buf[MAXLINE]; 6519630Seric 6529630Seric /* 6539630Seric ** Read and order the queue. 6549630Seric */ 6559630Seric 65610070Seric nrequests = orderq(); 6579630Seric 6589630Seric /* 6599630Seric ** Print the work list that we have read. 6609630Seric */ 6619630Seric 6629630Seric /* first see if there is anything */ 66310070Seric if (nrequests <= 0) 6649630Seric { 66510070Seric printf("Mail queue is empty\n"); 6669630Seric return; 6679630Seric } 6689630Seric 66910096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 67010070Seric if (nrequests > WLSIZE) 67110070Seric printf(", only %d printed", WLSIZE); 67210070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6739630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6749630Seric { 6759630Seric struct stat st; 67610070Seric auto time_t submittime = 0; 67710070Seric long dfsize = -1; 67817468Seric int fd; 67910108Seric char lf[20]; 68010108Seric char message[MAXLINE]; 6819630Seric 68217468Seric f = fopen(w->w_name, "r"); 68317468Seric if (f == NULL) 68417468Seric { 68517468Seric errno = 0; 68617468Seric continue; 68717468Seric } 6889630Seric printf("%7s", w->w_name + 2); 68910070Seric strcpy(lf, w->w_name); 69010070Seric lf[0] = 'l'; 69110070Seric if (stat(lf, &st) >= 0) 69210070Seric printf("*"); 69310070Seric else 69410070Seric printf(" "); 69510070Seric errno = 0; 69617468Seric 69710108Seric message[0] = '\0'; 6989630Seric while (fgets(buf, sizeof buf, f) != NULL) 6999630Seric { 7009630Seric fixcrlf(buf, TRUE); 7019630Seric switch (buf[0]) 7029630Seric { 70310108Seric case 'M': /* error message */ 70410108Seric strcpy(message, &buf[1]); 70510108Seric break; 70610108Seric 7079630Seric case 'S': /* sender name */ 70813015Seric printf("%8ld %.16s %.45s", dfsize, 70912517Seric ctime(&submittime), &buf[1]); 71010108Seric if (message[0] != '\0') 71112517Seric printf("\n\t\t\t\t (%.43s)", message); 7129630Seric break; 7139630Seric 7149630Seric case 'R': /* recipient name */ 71512517Seric printf("\n\t\t\t\t %.45s", &buf[1]); 7169630Seric break; 7179630Seric 7189630Seric case 'T': /* creation time */ 71910070Seric sscanf(&buf[1], "%ld", &submittime); 7209630Seric break; 72110070Seric 72210070Seric case 'D': /* data file name */ 72310070Seric if (stat(&buf[1], &st) >= 0) 72410070Seric dfsize = st.st_size; 72510070Seric break; 7269630Seric } 7279630Seric } 72810070Seric if (submittime == (time_t) 0) 72910070Seric printf(" (no control file)"); 7309630Seric printf("\n"); 7319630Seric fclose(f); 7329630Seric } 7339630Seric } 7349630Seric 7355182Seric # endif QUEUE 73617468Seric /* 73717468Seric ** QUEUENAME -- build a file name in the queue directory for this envelope. 73817468Seric ** 73917468Seric ** Assigns an id code if one does not already exist. 74017468Seric ** This code is very careful to avoid trashing existing files 74117468Seric ** under any circumstances. 74217468Seric ** We first create an nf file that is only used when 74317468Seric ** assigning an id. This file is always empty, so that 74417468Seric ** we can never accidently truncate an lf file. 74517468Seric ** 74617468Seric ** Parameters: 74717468Seric ** e -- envelope to build it in/from. 74817468Seric ** type -- the file type, used as the first character 74917468Seric ** of the file name. 75017468Seric ** 75117468Seric ** Returns: 75217468Seric ** a pointer to the new file name (in a static buffer). 75317468Seric ** 75417468Seric ** Side Effects: 75517468Seric ** Will create the lf and qf files if no id code is 75617468Seric ** already assigned. This will cause the envelope 75717468Seric ** to be modified. 75817468Seric */ 75917468Seric 76017468Seric char * 76117468Seric queuename(e, type) 76217468Seric register ENVELOPE *e; 76317468Seric char type; 76417468Seric { 76517468Seric static char buf[MAXNAME]; 76617468Seric static int pid = -1; 76717468Seric char c1 = 'A'; 76817468Seric char c2 = 'A'; 76917468Seric 77017468Seric if (e->e_id == NULL) 77117468Seric { 77217468Seric char qf[20]; 77317468Seric char nf[20]; 77417468Seric char lf[20]; 77517468Seric 77617468Seric /* find a unique id */ 77717468Seric if (pid != getpid()) 77817468Seric { 77917468Seric /* new process -- start back at "AA" */ 78017468Seric pid = getpid(); 78117468Seric c1 = 'A'; 78217468Seric c2 = 'A' - 1; 78317468Seric } 78417468Seric (void) sprintf(qf, "qfAA%05d", pid); 78517468Seric strcpy(lf, qf); 78617468Seric lf[0] = 'l'; 78717468Seric strcpy(nf, qf); 78817468Seric nf[0] = 'n'; 78917468Seric 79017468Seric while (c1 < '~' || c2 < 'Z') 79117468Seric { 79217468Seric int i; 79317468Seric 79417468Seric if (c2 >= 'Z') 79517468Seric { 79617468Seric c1++; 79717468Seric c2 = 'A' - 1; 79817468Seric } 799*17477Seric lf[2] = nf[2] = qf[2] = c1; 800*17477Seric lf[3] = nf[3] = qf[3] = ++c2; 80117468Seric # ifdef DEBUG 80217468Seric if (tTd(7, 20)) 80317468Seric printf("queuename: trying \"%s\"\n", nf); 80417468Seric # endif DEBUG 80517468Seric 80617468Seric # ifdef QUEUE 80717468Seric if (access(lf, 0) >= 0 || access(qf, 0) >= 0) 80817468Seric continue; 80917468Seric errno = 0; 81017468Seric i = creat(nf, FileMode); 81117468Seric if (i < 0) 81217468Seric { 81317468Seric (void) unlink(nf); /* kernel bug */ 81417468Seric continue; 81517468Seric } 81617468Seric (void) close(i); 81717468Seric i = link(nf, lf); 81817468Seric (void) unlink(nf); 81917468Seric if (i < 0) 82017468Seric continue; 82117468Seric if (link(lf, qf) >= 0) 82217468Seric break; 82317468Seric (void) unlink(lf); 82417468Seric # else QUEUE 82517468Seric if (close(creat(qf, FileMode)) < 0) 82617468Seric continue; 82717468Seric # endif QUEUE 82817468Seric } 82917468Seric if (c1 >= '~' && c2 >= 'Z') 83017468Seric { 83117468Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 83217468Seric qf, QueueDir); 83317468Seric exit(EX_OSERR); 83417468Seric } 83517468Seric e->e_id = newstr(&qf[2]); 83617468Seric define('i', e->e_id, e); 83717468Seric # ifdef DEBUG 83817468Seric if (tTd(7, 1)) 83917468Seric printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 84017468Seric # ifdef LOG 84117468Seric if (LogLevel > 16) 84217468Seric syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 84317468Seric # endif LOG 84417468Seric # endif DEBUG 84517468Seric } 84617468Seric 84717468Seric if (type == '\0') 84817468Seric return (NULL); 84917468Seric (void) sprintf(buf, "%cf%s", type, e->e_id); 85017468Seric # ifdef DEBUG 85117468Seric if (tTd(7, 2)) 85217468Seric printf("queuename: %s\n", buf); 85317468Seric # endif DEBUG 85417468Seric return (buf); 85517468Seric } 85617468Seric /* 85717468Seric ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 85817468Seric ** 85917468Seric ** Parameters: 86017468Seric ** e -- the envelope to unlock. 86117468Seric ** 86217468Seric ** Returns: 86317468Seric ** none 86417468Seric ** 86517468Seric ** Side Effects: 86617468Seric ** unlocks the queue for `e'. 86717468Seric */ 86817468Seric 86917468Seric unlockqueue(e) 87017468Seric ENVELOPE *e; 87117468Seric { 87217468Seric /* remove the transcript */ 87317468Seric #ifdef DEBUG 87417468Seric # ifdef LOG 87517468Seric if (LogLevel > 19) 87617468Seric syslog(LOG_DEBUG, "%s: unlock", e->e_id); 87717468Seric # endif LOG 87817468Seric if (!tTd(51, 4)) 87917468Seric #endif DEBUG 88017468Seric xunlink(queuename(e, 'x')); 88117468Seric 88217468Seric # ifdef QUEUE 88317468Seric /* last but not least, remove the lock */ 88417468Seric xunlink(queuename(e, 'l')); 88517468Seric # endif QUEUE 88617468Seric } 887