14632Seric # include "sendmail.h" 24632Seric # include <sys/stat.h> 38348Seric # include <dir.h> 44634Seric # include <signal.h> 54632Seric # include <errno.h> 64632Seric 75182Seric # ifndef QUEUE 8*10090Seric SCCSID(@(#)queue.c 3.62 01/03/83 (no queueing)); 95182Seric # else QUEUE 104632Seric 11*10090Seric SCCSID(@(#)queue.c 3.62 01/03/83); 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; 544632Seric 555037Seric /* 565037Seric ** Create control file. 575037Seric */ 584632Seric 597812Seric tf = newstr(queuename(e, 't')); 607812Seric tfp = fopen(tf, "w"); 617812Seric if (tfp == NULL) 624632Seric { 637812Seric syserr("queueup: cannot create temp file %s", tf); 644632Seric return; 654632Seric } 669048Seric (void) chmod(tf, FileMode); 674632Seric 684632Seric # ifdef DEBUG 697677Seric if (tTd(40, 1)) 707812Seric printf("queueing in %s\n", tf); 714632Seric # endif DEBUG 724632Seric 734632Seric /* 746980Seric ** If there is no data file yet, create one. 756980Seric */ 766980Seric 776980Seric if (e->e_df == NULL) 786980Seric { 796980Seric register FILE *dfp; 809389Seric extern putbody(); 816980Seric 827812Seric e->e_df = newstr(queuename(e, 'd')); 836980Seric dfp = fopen(e->e_df, "w"); 846980Seric if (dfp == NULL) 856980Seric { 866980Seric syserr("queueup: cannot create %s", e->e_df); 877812Seric (void) fclose(tfp); 886980Seric return; 896980Seric } 909048Seric (void) chmod(e->e_df, FileMode); 9110066Seric (*e->e_putbody)(dfp, ProgMailer, FALSE, e, FALSE); 927009Seric (void) fclose(dfp); 939389Seric e->e_putbody = putbody; 946980Seric } 956980Seric 966980Seric /* 974632Seric ** Output future work requests. 989377Seric ** Priority should be first, since it is read by orderq. 994632Seric */ 1004632Seric 1019377Seric /* output message priority */ 1029377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1039377Seric 1049630Seric /* output creation time */ 1059630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1069630Seric 1074632Seric /* output name of data file */ 1087812Seric fprintf(tfp, "D%s\n", e->e_df); 1094632Seric 1104632Seric /* output name of sender */ 1117812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1124632Seric 1134632Seric /* output list of recipient addresses */ 1146980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1154632Seric { 1167763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1177763Seric bitset(QQUEUEUP, q->q_flags)) 1188245Seric { 1197812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1209377Seric if (announce) 1219377Seric { 1229377Seric e->e_to = q->q_paddr; 1239377Seric message(Arpa_Info, "queued"); 1249377Seric if (LogLevel > 4) 1259377Seric logdelivery("queued"); 1269377Seric e->e_to = NULL; 1279377Seric } 1289387Seric #ifdef DEBUG 1299387Seric if (tTd(40, 1)) 1309387Seric { 1319387Seric printf("queueing "); 1329387Seric printaddr(q, FALSE); 1339387Seric } 1349387Seric #endif DEBUG 1358245Seric } 1364632Seric } 1374632Seric 1389377Seric /* 1399377Seric ** Output headers for this message. 1409377Seric ** Expand macros completely here. Queue run will deal with 1419377Seric ** everything as absolute headers. 1429377Seric ** All headers that must be relative to the recipient 1439377Seric ** can be cracked later. 1449377Seric */ 1459377Seric 1469377Seric define('g', "$f", e); 1476980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1484632Seric { 1494632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1504632Seric continue; 1517812Seric fprintf(tfp, "H"); 1524632Seric if (h->h_mflags != 0 && bitset(H_CHECK|H_ACHECK, h->h_flags)) 1537812Seric mfdecode(h->h_mflags, tfp); 1547763Seric if (bitset(H_DEFAULT, h->h_flags)) 1557763Seric { 1567763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 1578236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 1587763Seric } 1598245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 1609348Seric { 1619348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 16210066Seric (MAILER *) NULL, FALSE); 1639348Seric } 1647763Seric else 1658245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 1664632Seric } 1674632Seric 1684632Seric /* 1694632Seric ** Clean up. 1704632Seric */ 1714632Seric 1727812Seric (void) fclose(tfp); 1737812Seric qf = queuename(e, 'q'); 1749377Seric holdsigs(); 1757812Seric (void) unlink(qf); 1767812Seric if (link(tf, qf) < 0) 1777812Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 1786980Seric else 1797812Seric (void) unlink(tf); 1809377Seric rlsesigs(); 1817391Seric 1827677Seric # ifdef LOG 1837677Seric /* save log info */ 1847878Seric if (LogLevel > 15) 1857878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 1867677Seric # endif LOG 1874632Seric } 1884632Seric /* 1894632Seric ** RUNQUEUE -- run the jobs in the queue. 1904632Seric ** 1914632Seric ** Gets the stuff out of the queue in some presumably logical 1924632Seric ** order and processes them. 1934632Seric ** 1944632Seric ** Parameters: 1954632Seric ** none. 1964632Seric ** 1974632Seric ** Returns: 1984632Seric ** none. 1994632Seric ** 2004632Seric ** Side Effects: 2014632Seric ** runs things in the mail queue. 2024632Seric */ 2034632Seric 2044639Seric runqueue(forkflag) 2054639Seric bool forkflag; 2064632Seric { 2077466Seric /* 2087466Seric ** See if we want to go off and do other useful work. 2097466Seric */ 2104639Seric 2114639Seric if (forkflag) 2124639Seric { 2137943Seric int pid; 2147943Seric 2157943Seric pid = dofork(); 2167943Seric if (pid != 0) 2174639Seric { 2187943Seric /* parent -- pick up intermediate zombie */ 2199377Seric (void) waitfor(pid); 2207690Seric if (QueueIntvl != 0) 2219348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2224639Seric return; 2234639Seric } 2247943Seric /* child -- double fork */ 2257943Seric if (fork() != 0) 2267943Seric exit(EX_OK); 2274639Seric } 2287876Seric # ifdef LOG 2297876Seric if (LogLevel > 11) 2307943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2317876Seric # endif LOG 2324639Seric 2337466Seric /* 2347466Seric ** Start making passes through the queue. 2357466Seric ** First, read and sort the entire queue. 2367466Seric ** Then, process the work in that order. 2377466Seric ** But if you take too long, start over. 2387466Seric */ 2397466Seric 2407943Seric /* order the existing work requests */ 24110070Seric (void) orderq(); 2427690Seric 2437943Seric /* process them once at a time */ 2447943Seric while (WorkQ != NULL) 2454639Seric { 2467943Seric WORK *w = WorkQ; 2477881Seric 2487943Seric WorkQ = WorkQ->w_next; 2497943Seric dowork(w); 2507943Seric free(w->w_name); 2517943Seric free((char *) w); 2524639Seric } 2537943Seric finis(); 2544634Seric } 2554634Seric /* 2564632Seric ** ORDERQ -- order the work queue. 2574632Seric ** 2584632Seric ** Parameters: 2594632Seric ** none. 2604632Seric ** 2614632Seric ** Returns: 2624632Seric ** none. 2634632Seric ** 2644632Seric ** Side Effects: 2654632Seric ** Sets WorkQ to the queue of available work, in order. 2664632Seric */ 2674632Seric 2684632Seric # define WLSIZE 120 /* max size of worklist per sort */ 2694632Seric 2704632Seric orderq() 2714632Seric { 2726625Sglickman register struct direct *d; 2734632Seric register WORK *w; 2744632Seric register WORK **wp; /* parent of w */ 2756625Sglickman DIR *f; 2764632Seric register int i; 2774632Seric WORK wlist[WLSIZE]; 27810070Seric int wn = -1; 2794632Seric extern workcmpf(); 2804632Seric 2814632Seric /* clear out old WorkQ */ 2824632Seric for (w = WorkQ; w != NULL; ) 2834632Seric { 2844632Seric register WORK *nw = w->w_next; 2854632Seric 2864632Seric WorkQ = nw; 2874632Seric free(w->w_name); 2884632Seric free((char *) w); 2894632Seric w = nw; 2904632Seric } 2914632Seric 2924632Seric /* open the queue directory */ 2938148Seric f = opendir("."); 2944632Seric if (f == NULL) 2954632Seric { 2968148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 29710070Seric return (0); 2984632Seric } 2994632Seric 3004632Seric /* 3014632Seric ** Read the work directory. 3024632Seric */ 3034632Seric 30410070Seric while ((d = readdir(f)) != NULL) 3054632Seric { 3069377Seric FILE *cf; 3074632Seric char lbuf[MAXNAME]; 3084632Seric 3094632Seric /* is this an interesting entry? */ 3107812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3114632Seric continue; 3124632Seric 31310070Seric /* yes -- open control file (if not too many files) */ 31410070Seric if (++wn >= WLSIZE) 31510070Seric continue; 3168148Seric cf = fopen(d->d_name, "r"); 3174632Seric if (cf == NULL) 3184632Seric { 3197055Seric /* this may be some random person sending hir msgs */ 3207055Seric /* syserr("orderq: cannot open %s", cbuf); */ 321*10090Seric #ifdef DEBUG 322*10090Seric if (tTd(41, 2)) 323*10090Seric printf("orderq: cannot open %s (%d)\n", 324*10090Seric d->d_name, errno); 325*10090Seric #endif DEBUG 3267055Seric errno = 0; 327*10090Seric wn--; 3284632Seric continue; 3294632Seric } 3308148Seric wlist[wn].w_name = newstr(d->d_name); 3314632Seric 3324632Seric /* extract useful information */ 3334632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3344632Seric { 3359377Seric if (lbuf[0] == 'P') 3364632Seric { 3375037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3384632Seric break; 3394632Seric } 3404632Seric } 3414632Seric (void) fclose(cf); 3424632Seric } 3436625Sglickman (void) closedir(f); 344*10090Seric wn++; 3454632Seric 3464632Seric /* 3474632Seric ** Sort the work directory. 3484632Seric */ 3494632Seric 3504632Seric qsort(wlist, wn, sizeof *wlist, workcmpf); 3514632Seric 3524632Seric /* 3534632Seric ** Convert the work list into canonical form. 3549377Seric ** Should be turning it into a list of envelopes here perhaps. 3554632Seric */ 3564632Seric 3574632Seric wp = &WorkQ; 3584632Seric for (i = 0; i < wn; i++) 3594632Seric { 3604632Seric w = (WORK *) xalloc(sizeof *w); 3614632Seric w->w_name = wlist[i].w_name; 3624632Seric w->w_pri = wlist[i].w_pri; 3634632Seric w->w_next = NULL; 3644632Seric *wp = w; 3654632Seric wp = &w->w_next; 3664632Seric } 3674632Seric 3684632Seric # ifdef DEBUG 3697677Seric if (tTd(40, 1)) 3704632Seric { 3714632Seric for (w = WorkQ; w != NULL; w = w->w_next) 3725037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 3734632Seric } 3744632Seric # endif DEBUG 37510070Seric 376*10090Seric return (wn); 3774632Seric } 3784632Seric /* 3797677Seric ** WORKCMPF -- compare function for ordering work. 3804632Seric ** 3814632Seric ** Parameters: 3824632Seric ** a -- the first argument. 3834632Seric ** b -- the second argument. 3844632Seric ** 3854632Seric ** Returns: 3864632Seric ** -1 if a < b 3874632Seric ** 0 if a == b 3884632Seric ** 1 if a > b 3894632Seric ** 3904632Seric ** Side Effects: 3914632Seric ** none. 3924632Seric */ 3934632Seric 3944632Seric # define PRIFACT 1800 /* bytes each priority point is worth */ 3954632Seric 3964632Seric workcmpf(a, b) 3975037Seric register WORK *a; 3985037Seric register WORK *b; 3994632Seric { 4005037Seric if (a->w_pri == b->w_pri) 4014632Seric return (0); 4025037Seric else if (a->w_pri > b->w_pri) 4034632Seric return (1); 4044632Seric else 4054632Seric return (-1); 4064632Seric } 4074632Seric /* 4084632Seric ** DOWORK -- do a work request. 4094632Seric ** 4104632Seric ** Parameters: 4114632Seric ** w -- the work request to be satisfied. 4124632Seric ** 4134632Seric ** Returns: 4144632Seric ** none. 4154632Seric ** 4164632Seric ** Side Effects: 4174632Seric ** The work request is satisfied if possible. 4184632Seric */ 4194632Seric 4204632Seric dowork(w) 4214632Seric register WORK *w; 4224632Seric { 4234632Seric register int i; 4244632Seric 4254632Seric # ifdef DEBUG 4267677Seric if (tTd(40, 1)) 4275037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4284632Seric # endif DEBUG 4294632Seric 4304632Seric /* 4314632Seric ** Fork for work. 4324632Seric */ 4334632Seric 4344632Seric i = fork(); 4354632Seric if (i < 0) 4364632Seric { 4374632Seric syserr("dowork: cannot fork"); 4384632Seric return; 4394632Seric } 4404632Seric 4414632Seric if (i == 0) 4424632Seric { 4434632Seric /* 4444632Seric ** CHILD 4458148Seric ** Lock the control file to avoid duplicate deliveries. 4468148Seric ** Then run the file as though we had just read it. 4477350Seric ** We save an idea of the temporary name so we 4487350Seric ** can recover on interrupt. 4494632Seric */ 4504632Seric 4517763Seric /* set basic modes, etc. */ 4527356Seric (void) alarm(0); 4539338Seric CurEnv->e_flags &= ~EF_FATALERRS; 4544632Seric QueueRun = TRUE; 4559387Seric SendMode = SM_DELIVER; 4569377Seric ErrorMode = EM_MAIL; 4578148Seric CurEnv->e_id = &w->w_name[2]; 4587876Seric # ifdef LOG 4597876Seric if (LogLevel > 11) 4607881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 4617881Seric getpid()); 4627876Seric # endif LOG 4637763Seric 4647763Seric /* don't use the headers from sendmail.cf... */ 4657763Seric CurEnv->e_header = NULL; 4669348Seric (void) chompheader("from: $q", TRUE); 4677763Seric 4687763Seric /* create the link to the control file during processing */ 4697812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 4706980Seric { 4717812Seric /* being processed by another queuer */ 4727881Seric # ifdef LOG 4737881Seric if (LogLevel > 4) 4747881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 4757881Seric # endif LOG 4766980Seric exit(EX_OK); 4776980Seric } 4786980Seric 4796980Seric /* do basic system initialization */ 4804632Seric initsys(); 4816980Seric 4826980Seric /* read the queue control file */ 4839630Seric readqf(CurEnv, TRUE); 4849338Seric CurEnv->e_flags |= EF_INQUEUE; 4859377Seric eatheader(CurEnv); 4866980Seric 4876980Seric /* do the delivery */ 4889338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 4899282Seric sendall(CurEnv, SM_DELIVER); 4906980Seric 4916980Seric /* if still not sent, perhaps we should time out.... */ 4924634Seric # ifdef DEBUG 4937677Seric if (tTd(40, 3)) 4947886Seric printf("curtime=%ld, TimeOut=%ld\n", curtime(), 4957860Seric CurEnv->e_ctime + TimeOut); 4964634Seric # endif DEBUG 4979338Seric if (curtime() > CurEnv->e_ctime + TimeOut) 4989338Seric CurEnv->e_flags |= EF_TIMEOUT; 4996980Seric 5006980Seric /* finish up and exit */ 5014632Seric finis(); 5024632Seric } 5034632Seric 5044632Seric /* 5054632Seric ** Parent -- pick up results. 5064632Seric */ 5074632Seric 5084632Seric errno = 0; 5099377Seric (void) waitfor(i); 5104632Seric } 5114632Seric /* 5124632Seric ** READQF -- read queue file and set up environment. 5134632Seric ** 5144632Seric ** Parameters: 5159377Seric ** e -- the envelope of the job to run. 5169630Seric ** full -- if set, read in all information. Otherwise just 5179630Seric ** read in info needed for a queue print. 5184632Seric ** 5194632Seric ** Returns: 5204632Seric ** none. 5214632Seric ** 5224632Seric ** Side Effects: 5234632Seric ** cf is read and created as the current job, as though 5244632Seric ** we had been invoked by argument. 5254632Seric */ 5264632Seric 5279630Seric readqf(e, full) 5289377Seric register ENVELOPE *e; 5299630Seric bool full; 5304632Seric { 5314632Seric register FILE *f; 5327785Seric char buf[MAXFIELD]; 5339348Seric extern char *fgetfolded(); 5349377Seric register char *p; 5354632Seric 5364632Seric /* 5374632Seric ** Open the file created by queueup. 5384632Seric */ 5394632Seric 5409377Seric p = queuename(e, 'q'); 5419377Seric f = fopen(p, "r"); 5424632Seric if (f == NULL) 5434632Seric { 5449377Seric syserr("readqf: no control file %s", p); 5454632Seric return; 5464632Seric } 5479377Seric FileName = p; 5489377Seric LineNumber = 0; 5494632Seric 5504632Seric /* 5514632Seric ** Read and process the file. 5524632Seric */ 5534632Seric 5549630Seric if (Verbose && full) 5559377Seric printf("\nRunning %s\n", e->e_id); 5567785Seric while (fgetfolded(buf, sizeof buf, f) != NULL) 5574632Seric { 5584632Seric switch (buf[0]) 5594632Seric { 5604632Seric case 'R': /* specify recipient */ 5619618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 5624632Seric break; 5634632Seric 5644632Seric case 'H': /* header */ 5659630Seric if (full) 5669630Seric (void) chompheader(&buf[1], FALSE); 5674632Seric break; 5684632Seric 5694632Seric case 'S': /* sender */ 5704634Seric setsender(newstr(&buf[1])); 5714632Seric break; 5724632Seric 5734632Seric case 'D': /* data file name */ 5749630Seric if (!full) 5759630Seric break; 5769377Seric e->e_df = newstr(&buf[1]); 5779544Seric e->e_dfp = fopen(e->e_df, "r"); 5789544Seric if (e->e_dfp == NULL) 5799377Seric syserr("readqf: cannot open %s", e->e_df); 5804632Seric break; 5814632Seric 5827860Seric case 'T': /* init time */ 5839377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 5844632Seric break; 5854632Seric 5864634Seric case 'P': /* message priority */ 5879377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 5885037Seric 5895037Seric /* make sure that big things get sent eventually */ 5909377Seric e->e_msgpriority -= WKTIMEFACT; 5914634Seric break; 5924634Seric 5935902Seric case 'M': /* define macro */ 5949630Seric if (full) 5959630Seric define(buf[1], newstr(&buf[2]), e); 5965902Seric break; 5975902Seric 5984632Seric default: 5999377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 6004632Seric break; 6014632Seric } 6024632Seric } 6039377Seric 6049377Seric FileName = NULL; 6054632Seric } 6064632Seric /* 6074632Seric ** TIMEOUT -- process timeout on queue file. 6084632Seric ** 6094632Seric ** Parameters: 6109338Seric ** e -- the envelope that timed out. 6114632Seric ** 6124632Seric ** Returns: 6134632Seric ** none. 6144632Seric ** 6154632Seric ** Side Effects: 6164632Seric ** Returns a message to the sender saying that this 6174632Seric ** message has timed out. 6184632Seric */ 6194632Seric 6209338Seric timeout(e) 6219338Seric register ENVELOPE *e; 6224632Seric { 6237369Seric char buf[MAXLINE]; 6247860Seric extern char *pintvl(); 6257369Seric 6264634Seric # ifdef DEBUG 6277677Seric if (tTd(40, 3)) 6289338Seric printf("timeout(%s)\n", e->e_id); 6294634Seric # endif DEBUG 6309338Seric e->e_to = NULL; 6316991Seric message(Arpa_Info, "Message has timed out"); 6324634Seric 6334634Seric /* return message to sender */ 6347860Seric (void) sprintf(buf, "Cannot send mail for %s", pintvl(TimeOut, FALSE)); 6359338Seric (void) returntosender(buf, &e->e_from, TRUE); 6364634Seric 6374634Seric /* arrange to remove files from queue */ 6389338Seric e->e_flags |= EF_CLRQUEUE; 6394632Seric } 6409630Seric /* 6419630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6429630Seric ** 6439630Seric ** Parameters: 6449630Seric ** none. 6459630Seric ** 6469630Seric ** Returns: 6479630Seric ** none. 6489630Seric ** 6499630Seric ** Side Effects: 6509630Seric ** Prints a listing of the mail queue on the standard output. 6519630Seric */ 6525182Seric 6539630Seric printqueue() 6549630Seric { 6559630Seric register WORK *w; 6569630Seric FILE *f; 65710070Seric int nrequests; 6589630Seric char buf[MAXLINE]; 6599630Seric 6609630Seric /* 6619630Seric ** Read and order the queue. 6629630Seric */ 6639630Seric 66410070Seric nrequests = orderq(); 6659630Seric 6669630Seric /* 6679630Seric ** Print the work list that we have read. 6689630Seric */ 6699630Seric 6709630Seric /* first see if there is anything */ 67110070Seric if (nrequests <= 0) 6729630Seric { 67310070Seric printf("Mail queue is empty\n"); 6749630Seric return; 6759630Seric } 6769630Seric 67710070Seric printf("\t\tMail Queue (%d requests", nrequests); 67810070Seric if (nrequests > WLSIZE) 67910070Seric printf(", only %d printed", WLSIZE); 68010070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6819630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6829630Seric { 6839630Seric struct stat st; 68410070Seric char lf[20]; 68510070Seric auto time_t submittime = 0; 68610070Seric long dfsize = -1; 6879630Seric 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; 6969630Seric f = fopen(w->w_name, "r"); 6979630Seric if (f == NULL) 6989630Seric { 6999630Seric printf(" (finished)\n"); 70010070Seric errno = 0; 7019630Seric continue; 7029630Seric } 7039630Seric while (fgets(buf, sizeof buf, f) != NULL) 7049630Seric { 7059630Seric fixcrlf(buf, TRUE); 7069630Seric switch (buf[0]) 7079630Seric { 7089630Seric case 'S': /* sender name */ 70910070Seric printf("%8d %.16s %.40s", dfsize, 71010070Seric ctime(&submittime), &buf[1]); 7119630Seric break; 7129630Seric 7139630Seric case 'R': /* recipient name */ 71410070Seric printf("\n\t\t\t\t %.40s", &buf[1]); 7159630Seric break; 7169630Seric 7179630Seric case 'T': /* creation time */ 71810070Seric sscanf(&buf[1], "%ld", &submittime); 7199630Seric break; 72010070Seric 72110070Seric case 'D': /* data file name */ 72210070Seric if (stat(&buf[1], &st) >= 0) 72310070Seric dfsize = st.st_size; 72410070Seric break; 7259630Seric } 7269630Seric } 72710070Seric if (submittime == (time_t) 0) 72810070Seric printf(" (no control file)"); 7299630Seric printf("\n"); 7309630Seric fclose(f); 7319630Seric } 7329630Seric } 7339630Seric 7345182Seric # endif QUEUE 735