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*10205Seric SCCSID(@(#)queue.c 3.69 01/08/83 (no queueing)); 95182Seric # else QUEUE 104632Seric 11*10205Seric SCCSID(@(#)queue.c 3.69 01/08/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; 5410173Seric MAILER nullmailer; 554632Seric 565037Seric /* 575037Seric ** Create control file. 585037Seric */ 594632Seric 607812Seric tf = newstr(queuename(e, 't')); 617812Seric tfp = fopen(tf, "w"); 627812Seric if (tfp == NULL) 634632Seric { 647812Seric syserr("queueup: cannot create temp file %s", tf); 654632Seric return; 664632Seric } 679048Seric (void) chmod(tf, FileMode); 684632Seric 694632Seric # ifdef DEBUG 707677Seric if (tTd(40, 1)) 717812Seric printf("queueing in %s\n", tf); 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 15310173Seric bzero(&nullmailer, sizeof nullmailer); 15410173Seric nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 15510173Seric 1569377Seric define('g', "$f", e); 1576980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1584632Seric { 1594632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1604632Seric continue; 1617812Seric fprintf(tfp, "H"); 1624632Seric if (h->h_mflags != 0 && bitset(H_CHECK|H_ACHECK, h->h_flags)) 1637812Seric mfdecode(h->h_mflags, tfp); 1647763Seric if (bitset(H_DEFAULT, h->h_flags)) 1657763Seric { 1667763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 1678236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 1687763Seric } 1698245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 1709348Seric { 1719348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 17210173Seric &nullmailer); 1739348Seric } 1747763Seric else 1758245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 1764632Seric } 1774632Seric 1784632Seric /* 1794632Seric ** Clean up. 1804632Seric */ 1814632Seric 1827812Seric (void) fclose(tfp); 1837812Seric qf = queuename(e, 'q'); 1849377Seric holdsigs(); 1857812Seric (void) unlink(qf); 1867812Seric if (link(tf, qf) < 0) 1877812Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 1886980Seric else 1897812Seric (void) unlink(tf); 1909377Seric rlsesigs(); 1917391Seric 1927677Seric # ifdef LOG 1937677Seric /* save log info */ 1947878Seric if (LogLevel > 15) 1957878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 1967677Seric # endif LOG 1974632Seric } 1984632Seric /* 1994632Seric ** RUNQUEUE -- run the jobs in the queue. 2004632Seric ** 2014632Seric ** Gets the stuff out of the queue in some presumably logical 2024632Seric ** order and processes them. 2034632Seric ** 2044632Seric ** Parameters: 2054632Seric ** none. 2064632Seric ** 2074632Seric ** Returns: 2084632Seric ** none. 2094632Seric ** 2104632Seric ** Side Effects: 2114632Seric ** runs things in the mail queue. 2124632Seric */ 2134632Seric 2144639Seric runqueue(forkflag) 2154639Seric bool forkflag; 2164632Seric { 2177466Seric /* 2187466Seric ** See if we want to go off and do other useful work. 2197466Seric */ 2204639Seric 2214639Seric if (forkflag) 2224639Seric { 2237943Seric int pid; 2247943Seric 2257943Seric pid = dofork(); 2267943Seric if (pid != 0) 2274639Seric { 2287943Seric /* parent -- pick up intermediate zombie */ 2299377Seric (void) waitfor(pid); 2307690Seric if (QueueIntvl != 0) 2319348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2324639Seric return; 2334639Seric } 2347943Seric /* child -- double fork */ 2357943Seric if (fork() != 0) 2367943Seric exit(EX_OK); 2374639Seric } 2387876Seric # ifdef LOG 2397876Seric if (LogLevel > 11) 2407943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2417876Seric # endif LOG 2424639Seric 2437466Seric /* 244*10205Seric ** Release any resources used by the daemon code. 245*10205Seric */ 246*10205Seric 247*10205Seric # ifdef DAEMON 248*10205Seric clrdaemon(); 249*10205Seric # endif DAEMON 250*10205Seric 251*10205Seric /* 2527466Seric ** Start making passes through the queue. 2537466Seric ** First, read and sort the entire queue. 2547466Seric ** Then, process the work in that order. 2557466Seric ** But if you take too long, start over. 2567466Seric */ 2577466Seric 2587943Seric /* order the existing work requests */ 25910070Seric (void) orderq(); 2607690Seric 2617943Seric /* process them once at a time */ 2627943Seric while (WorkQ != NULL) 2634639Seric { 2647943Seric WORK *w = WorkQ; 2657881Seric 2667943Seric WorkQ = WorkQ->w_next; 2677943Seric dowork(w); 2687943Seric free(w->w_name); 2697943Seric free((char *) w); 2704639Seric } 2717943Seric finis(); 2724634Seric } 2734634Seric /* 2744632Seric ** ORDERQ -- order the work queue. 2754632Seric ** 2764632Seric ** Parameters: 2774632Seric ** none. 2784632Seric ** 2794632Seric ** Returns: 28010121Seric ** The number of request in the queue (not necessarily 28110121Seric ** the number of requests in WorkQ however). 2824632Seric ** 2834632Seric ** Side Effects: 2844632Seric ** Sets WorkQ to the queue of available work, in order. 2854632Seric */ 2864632Seric 2874632Seric # define WLSIZE 120 /* max size of worklist per sort */ 2884632Seric 2894632Seric orderq() 2904632Seric { 2916625Sglickman register struct direct *d; 2924632Seric register WORK *w; 2934632Seric register WORK **wp; /* parent of w */ 2946625Sglickman DIR *f; 2954632Seric register int i; 29610121Seric WORK wlist[WLSIZE+1]; 29710070Seric int wn = -1; 2984632Seric extern workcmpf(); 2994632Seric 3004632Seric /* clear out old WorkQ */ 3014632Seric for (w = WorkQ; w != NULL; ) 3024632Seric { 3034632Seric register WORK *nw = w->w_next; 3044632Seric 3054632Seric WorkQ = nw; 3064632Seric free(w->w_name); 3074632Seric free((char *) w); 3084632Seric w = nw; 3094632Seric } 3104632Seric 3114632Seric /* open the queue directory */ 3128148Seric f = opendir("."); 3134632Seric if (f == NULL) 3144632Seric { 3158148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 31610070Seric return (0); 3174632Seric } 3184632Seric 3194632Seric /* 3204632Seric ** Read the work directory. 3214632Seric */ 3224632Seric 32310070Seric while ((d = readdir(f)) != NULL) 3244632Seric { 3259377Seric FILE *cf; 3264632Seric char lbuf[MAXNAME]; 3274632Seric 3284632Seric /* is this an interesting entry? */ 3297812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3304632Seric continue; 3314632Seric 33210070Seric /* yes -- open control file (if not too many files) */ 33310070Seric if (++wn >= WLSIZE) 33410070Seric continue; 3358148Seric cf = fopen(d->d_name, "r"); 3364632Seric if (cf == NULL) 3374632Seric { 3387055Seric /* this may be some random person sending hir msgs */ 3397055Seric /* syserr("orderq: cannot open %s", cbuf); */ 34010090Seric #ifdef DEBUG 34110090Seric if (tTd(41, 2)) 34210090Seric printf("orderq: cannot open %s (%d)\n", 34310090Seric d->d_name, errno); 34410090Seric #endif DEBUG 3457055Seric errno = 0; 34610090Seric wn--; 3474632Seric continue; 3484632Seric } 3498148Seric wlist[wn].w_name = newstr(d->d_name); 3504632Seric 3514632Seric /* extract useful information */ 3524632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3534632Seric { 3549377Seric if (lbuf[0] == 'P') 3554632Seric { 3565037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3574632Seric break; 3584632Seric } 3594632Seric } 3604632Seric (void) fclose(cf); 3614632Seric } 3626625Sglickman (void) closedir(f); 36310090Seric wn++; 3644632Seric 3654632Seric /* 3664632Seric ** Sort the work directory. 3674632Seric */ 3684632Seric 36910121Seric qsort(wlist, min(wn, WLSIZE), sizeof *wlist, workcmpf); 3704632Seric 3714632Seric /* 3724632Seric ** Convert the work list into canonical form. 3739377Seric ** Should be turning it into a list of envelopes here perhaps. 3744632Seric */ 3754632Seric 3764632Seric wp = &WorkQ; 37710121Seric for (i = min(wn, WLSIZE); --i >= 0; ) 3784632Seric { 3794632Seric w = (WORK *) xalloc(sizeof *w); 3804632Seric w->w_name = wlist[i].w_name; 3814632Seric w->w_pri = wlist[i].w_pri; 3824632Seric w->w_next = NULL; 3834632Seric *wp = w; 3844632Seric wp = &w->w_next; 3854632Seric } 3864632Seric 3874632Seric # ifdef DEBUG 3887677Seric if (tTd(40, 1)) 3894632Seric { 3904632Seric for (w = WorkQ; w != NULL; w = w->w_next) 3915037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 3924632Seric } 3934632Seric # endif DEBUG 39410070Seric 39510090Seric return (wn); 3964632Seric } 3974632Seric /* 3987677Seric ** WORKCMPF -- compare function for ordering work. 3994632Seric ** 4004632Seric ** Parameters: 4014632Seric ** a -- the first argument. 4024632Seric ** b -- the second argument. 4034632Seric ** 4044632Seric ** Returns: 40510121Seric ** 1 if a < b 4064632Seric ** 0 if a == b 40710121Seric ** -1 if a > b 4084632Seric ** 4094632Seric ** Side Effects: 4104632Seric ** none. 4114632Seric */ 4124632Seric 4134632Seric workcmpf(a, b) 4145037Seric register WORK *a; 4155037Seric register WORK *b; 4164632Seric { 4175037Seric if (a->w_pri == b->w_pri) 4184632Seric return (0); 4195037Seric else if (a->w_pri > b->w_pri) 42010121Seric return (-1); 42110121Seric else 4224632Seric return (1); 4234632Seric } 4244632Seric /* 4254632Seric ** DOWORK -- do a work request. 4264632Seric ** 4274632Seric ** Parameters: 4284632Seric ** w -- the work request to be satisfied. 4294632Seric ** 4304632Seric ** Returns: 4314632Seric ** none. 4324632Seric ** 4334632Seric ** Side Effects: 4344632Seric ** The work request is satisfied if possible. 4354632Seric */ 4364632Seric 4374632Seric dowork(w) 4384632Seric register WORK *w; 4394632Seric { 4404632Seric register int i; 4414632Seric 4424632Seric # ifdef DEBUG 4437677Seric if (tTd(40, 1)) 4445037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4454632Seric # endif DEBUG 4464632Seric 4474632Seric /* 4484632Seric ** Fork for work. 4494632Seric */ 4504632Seric 4514632Seric i = fork(); 4524632Seric if (i < 0) 4534632Seric { 4544632Seric syserr("dowork: cannot fork"); 4554632Seric return; 4564632Seric } 4574632Seric 4584632Seric if (i == 0) 4594632Seric { 4604632Seric /* 4614632Seric ** CHILD 4628148Seric ** Lock the control file to avoid duplicate deliveries. 4638148Seric ** Then run the file as though we had just read it. 4647350Seric ** We save an idea of the temporary name so we 4657350Seric ** can recover on interrupt. 4664632Seric */ 4674632Seric 4687763Seric /* set basic modes, etc. */ 4697356Seric (void) alarm(0); 47010195Seric closexscript(CurEnv); 4719338Seric CurEnv->e_flags &= ~EF_FATALERRS; 4724632Seric QueueRun = TRUE; 4739377Seric ErrorMode = EM_MAIL; 4748148Seric CurEnv->e_id = &w->w_name[2]; 4757876Seric # ifdef LOG 4767876Seric if (LogLevel > 11) 4777881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 4787881Seric getpid()); 4797876Seric # endif LOG 4807763Seric 4817763Seric /* don't use the headers from sendmail.cf... */ 4827763Seric CurEnv->e_header = NULL; 4839348Seric (void) chompheader("from: $q", TRUE); 4847763Seric 4857763Seric /* create the link to the control file during processing */ 4867812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 4876980Seric { 4887812Seric /* being processed by another queuer */ 4897881Seric # ifdef LOG 4907881Seric if (LogLevel > 4) 4917881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 4927881Seric # endif LOG 4936980Seric exit(EX_OK); 4946980Seric } 4956980Seric 4966980Seric /* do basic system initialization */ 4974632Seric initsys(); 4986980Seric 4996980Seric /* read the queue control file */ 5009630Seric readqf(CurEnv, TRUE); 5019338Seric CurEnv->e_flags |= EF_INQUEUE; 5029377Seric eatheader(CurEnv); 5036980Seric 5046980Seric /* do the delivery */ 5059338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 5069282Seric sendall(CurEnv, SM_DELIVER); 5076980Seric 5086980Seric /* finish up and exit */ 5094632Seric finis(); 5104632Seric } 5114632Seric 5124632Seric /* 5134632Seric ** Parent -- pick up results. 5144632Seric */ 5154632Seric 5164632Seric errno = 0; 5179377Seric (void) waitfor(i); 5184632Seric } 5194632Seric /* 5204632Seric ** READQF -- read queue file and set up environment. 5214632Seric ** 5224632Seric ** Parameters: 5239377Seric ** e -- the envelope of the job to run. 5249630Seric ** full -- if set, read in all information. Otherwise just 5259630Seric ** read in info needed for a queue print. 5264632Seric ** 5274632Seric ** Returns: 5284632Seric ** none. 5294632Seric ** 5304632Seric ** Side Effects: 5314632Seric ** cf is read and created as the current job, as though 5324632Seric ** we had been invoked by argument. 5334632Seric */ 5344632Seric 5359630Seric readqf(e, full) 5369377Seric register ENVELOPE *e; 5379630Seric bool full; 5384632Seric { 5394632Seric register FILE *f; 5407785Seric char buf[MAXFIELD]; 5419348Seric extern char *fgetfolded(); 5429377Seric register char *p; 5434632Seric 5444632Seric /* 5454632Seric ** Open the file created by queueup. 5464632Seric */ 5474632Seric 5489377Seric p = queuename(e, 'q'); 5499377Seric f = fopen(p, "r"); 5504632Seric if (f == NULL) 5514632Seric { 5529377Seric syserr("readqf: no control file %s", p); 5534632Seric return; 5544632Seric } 5559377Seric FileName = p; 5569377Seric LineNumber = 0; 5574632Seric 5584632Seric /* 5594632Seric ** Read and process the file. 5604632Seric */ 5614632Seric 5629630Seric if (Verbose && full) 5639377Seric printf("\nRunning %s\n", e->e_id); 5647785Seric while (fgetfolded(buf, sizeof buf, f) != NULL) 5654632Seric { 5664632Seric switch (buf[0]) 5674632Seric { 5684632Seric case 'R': /* specify recipient */ 5699618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 5704632Seric break; 5714632Seric 5724632Seric case 'H': /* header */ 5739630Seric if (full) 5749630Seric (void) chompheader(&buf[1], FALSE); 5754632Seric break; 5764632Seric 57710108Seric case 'M': /* message */ 57810108Seric e->e_message = newstr(&buf[1]); 57910108Seric break; 58010108Seric 5814632Seric case 'S': /* sender */ 5824634Seric setsender(newstr(&buf[1])); 5834632Seric break; 5844632Seric 5854632Seric case 'D': /* data file name */ 5869630Seric if (!full) 5879630Seric break; 5889377Seric e->e_df = newstr(&buf[1]); 5899544Seric e->e_dfp = fopen(e->e_df, "r"); 5909544Seric if (e->e_dfp == NULL) 5919377Seric syserr("readqf: cannot open %s", e->e_df); 5924632Seric break; 5934632Seric 5947860Seric case 'T': /* init time */ 5959377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 5964632Seric break; 5974632Seric 5984634Seric case 'P': /* message priority */ 5999377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 6005037Seric 6015037Seric /* make sure that big things get sent eventually */ 6029377Seric e->e_msgpriority -= WKTIMEFACT; 6034634Seric break; 6044634Seric 6054632Seric default: 6069377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 6074632Seric break; 6084632Seric } 6094632Seric } 6109377Seric 6119377Seric FileName = NULL; 6124632Seric } 6134632Seric /* 6149630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6159630Seric ** 6169630Seric ** Parameters: 6179630Seric ** none. 6189630Seric ** 6199630Seric ** Returns: 6209630Seric ** none. 6219630Seric ** 6229630Seric ** Side Effects: 6239630Seric ** Prints a listing of the mail queue on the standard output. 6249630Seric */ 6255182Seric 6269630Seric printqueue() 6279630Seric { 6289630Seric register WORK *w; 6299630Seric FILE *f; 63010070Seric int nrequests; 6319630Seric char buf[MAXLINE]; 6329630Seric 6339630Seric /* 6349630Seric ** Read and order the queue. 6359630Seric */ 6369630Seric 63710070Seric nrequests = orderq(); 6389630Seric 6399630Seric /* 6409630Seric ** Print the work list that we have read. 6419630Seric */ 6429630Seric 6439630Seric /* first see if there is anything */ 64410070Seric if (nrequests <= 0) 6459630Seric { 64610070Seric printf("Mail queue is empty\n"); 6479630Seric return; 6489630Seric } 6499630Seric 65010096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 65110070Seric if (nrequests > WLSIZE) 65210070Seric printf(", only %d printed", WLSIZE); 65310070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6549630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6559630Seric { 6569630Seric struct stat st; 65710070Seric auto time_t submittime = 0; 65810070Seric long dfsize = -1; 65910108Seric char lf[20]; 66010108Seric char message[MAXLINE]; 6619630Seric 6629630Seric printf("%7s", w->w_name + 2); 66310070Seric strcpy(lf, w->w_name); 66410070Seric lf[0] = 'l'; 66510070Seric if (stat(lf, &st) >= 0) 66610070Seric printf("*"); 66710070Seric else 66810070Seric printf(" "); 66910070Seric errno = 0; 6709630Seric f = fopen(w->w_name, "r"); 6719630Seric if (f == NULL) 6729630Seric { 6739630Seric printf(" (finished)\n"); 67410070Seric errno = 0; 6759630Seric continue; 6769630Seric } 67710108Seric message[0] = '\0'; 6789630Seric while (fgets(buf, sizeof buf, f) != NULL) 6799630Seric { 6809630Seric fixcrlf(buf, TRUE); 6819630Seric switch (buf[0]) 6829630Seric { 68310108Seric case 'M': /* error message */ 68410108Seric strcpy(message, &buf[1]); 68510108Seric break; 68610108Seric 6879630Seric case 'S': /* sender name */ 68810108Seric if (message[0] != '\0') 68910108Seric { 69010108Seric (void) strcat(buf, " ("); 69110108Seric (void) strcat(buf, message); 69210108Seric (void) strcat(buf, ")"); 69310108Seric } 69410070Seric printf("%8d %.16s %.40s", dfsize, 69510070Seric ctime(&submittime), &buf[1]); 6969630Seric break; 6979630Seric 6989630Seric case 'R': /* recipient name */ 69910070Seric printf("\n\t\t\t\t %.40s", &buf[1]); 7009630Seric break; 7019630Seric 7029630Seric case 'T': /* creation time */ 70310070Seric sscanf(&buf[1], "%ld", &submittime); 7049630Seric break; 70510070Seric 70610070Seric case 'D': /* data file name */ 70710070Seric if (stat(&buf[1], &st) >= 0) 70810070Seric dfsize = st.st_size; 70910070Seric break; 7109630Seric } 7119630Seric } 71210070Seric if (submittime == (time_t) 0) 71310070Seric printf(" (no control file)"); 7149630Seric printf("\n"); 7159630Seric fclose(f); 7169630Seric } 7179630Seric } 7189630Seric 7195182Seric # endif QUEUE 720