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*10108Seric SCCSID(@(#)queue.c 3.65 01/03/83 (no queueing)); 95182Seric # else QUEUE 104632Seric 11*10108Seric SCCSID(@(#)queue.c 3.65 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 110*10108Seric /* message from envelope, if it exists */ 111*10108Seric if (e->e_message != NULL) 112*10108Seric fprintf(tfp, "M%s\n", e->e_message); 113*10108Seric 1144632Seric /* output name of sender */ 1157812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1164632Seric 1174632Seric /* output list of recipient addresses */ 1186980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1194632Seric { 1207763Seric if (queueall ? !bitset(QDONTSEND, q->q_flags) : 1217763Seric bitset(QQUEUEUP, q->q_flags)) 1228245Seric { 1237812Seric fprintf(tfp, "R%s\n", q->q_paddr); 1249377Seric if (announce) 1259377Seric { 1269377Seric e->e_to = q->q_paddr; 1279377Seric message(Arpa_Info, "queued"); 1289377Seric if (LogLevel > 4) 1299377Seric logdelivery("queued"); 1309377Seric e->e_to = NULL; 1319377Seric } 1329387Seric #ifdef DEBUG 1339387Seric if (tTd(40, 1)) 1349387Seric { 1359387Seric printf("queueing "); 1369387Seric printaddr(q, FALSE); 1379387Seric } 1389387Seric #endif DEBUG 1398245Seric } 1404632Seric } 1414632Seric 1429377Seric /* 1439377Seric ** Output headers for this message. 1449377Seric ** Expand macros completely here. Queue run will deal with 1459377Seric ** everything as absolute headers. 1469377Seric ** All headers that must be relative to the recipient 1479377Seric ** can be cracked later. 1489377Seric */ 1499377Seric 1509377Seric define('g', "$f", e); 1516980Seric for (h = e->e_header; h != NULL; h = h->h_link) 1524632Seric { 1534632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 1544632Seric continue; 1557812Seric fprintf(tfp, "H"); 1564632Seric if (h->h_mflags != 0 && bitset(H_CHECK|H_ACHECK, h->h_flags)) 1577812Seric mfdecode(h->h_mflags, tfp); 1587763Seric if (bitset(H_DEFAULT, h->h_flags)) 1597763Seric { 1607763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 1618236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 1627763Seric } 1638245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 1649348Seric { 1659348Seric commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 16610066Seric (MAILER *) NULL, FALSE); 1679348Seric } 1687763Seric else 1698245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 1704632Seric } 1714632Seric 1724632Seric /* 1734632Seric ** Clean up. 1744632Seric */ 1754632Seric 1767812Seric (void) fclose(tfp); 1777812Seric qf = queuename(e, 'q'); 1789377Seric holdsigs(); 1797812Seric (void) unlink(qf); 1807812Seric if (link(tf, qf) < 0) 1817812Seric syserr("cannot link(%s, %s), df=%s", tf, qf, e->e_df); 1826980Seric else 1837812Seric (void) unlink(tf); 1849377Seric rlsesigs(); 1857391Seric 1867677Seric # ifdef LOG 1877677Seric /* save log info */ 1887878Seric if (LogLevel > 15) 1897878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 1907677Seric # endif LOG 1914632Seric } 1924632Seric /* 1934632Seric ** RUNQUEUE -- run the jobs in the queue. 1944632Seric ** 1954632Seric ** Gets the stuff out of the queue in some presumably logical 1964632Seric ** order and processes them. 1974632Seric ** 1984632Seric ** Parameters: 1994632Seric ** none. 2004632Seric ** 2014632Seric ** Returns: 2024632Seric ** none. 2034632Seric ** 2044632Seric ** Side Effects: 2054632Seric ** runs things in the mail queue. 2064632Seric */ 2074632Seric 2084639Seric runqueue(forkflag) 2094639Seric bool forkflag; 2104632Seric { 2117466Seric /* 2127466Seric ** See if we want to go off and do other useful work. 2137466Seric */ 2144639Seric 2154639Seric if (forkflag) 2164639Seric { 2177943Seric int pid; 2187943Seric 2197943Seric pid = dofork(); 2207943Seric if (pid != 0) 2214639Seric { 2227943Seric /* parent -- pick up intermediate zombie */ 2239377Seric (void) waitfor(pid); 2247690Seric if (QueueIntvl != 0) 2259348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 2264639Seric return; 2274639Seric } 2287943Seric /* child -- double fork */ 2297943Seric if (fork() != 0) 2307943Seric exit(EX_OK); 2314639Seric } 2327876Seric # ifdef LOG 2337876Seric if (LogLevel > 11) 2347943Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 2357876Seric # endif LOG 2364639Seric 2377466Seric /* 2387466Seric ** Start making passes through the queue. 2397466Seric ** First, read and sort the entire queue. 2407466Seric ** Then, process the work in that order. 2417466Seric ** But if you take too long, start over. 2427466Seric */ 2437466Seric 2447943Seric /* order the existing work requests */ 24510070Seric (void) orderq(); 2467690Seric 2477943Seric /* process them once at a time */ 2487943Seric while (WorkQ != NULL) 2494639Seric { 2507943Seric WORK *w = WorkQ; 2517881Seric 2527943Seric WorkQ = WorkQ->w_next; 2537943Seric dowork(w); 2547943Seric free(w->w_name); 2557943Seric free((char *) w); 2564639Seric } 2577943Seric finis(); 2584634Seric } 2594634Seric /* 2604632Seric ** ORDERQ -- order the work queue. 2614632Seric ** 2624632Seric ** Parameters: 2634632Seric ** none. 2644632Seric ** 2654632Seric ** Returns: 2664632Seric ** none. 2674632Seric ** 2684632Seric ** Side Effects: 2694632Seric ** Sets WorkQ to the queue of available work, in order. 2704632Seric */ 2714632Seric 2724632Seric # define WLSIZE 120 /* max size of worklist per sort */ 2734632Seric 2744632Seric orderq() 2754632Seric { 2766625Sglickman register struct direct *d; 2774632Seric register WORK *w; 2784632Seric register WORK **wp; /* parent of w */ 2796625Sglickman DIR *f; 2804632Seric register int i; 2814632Seric WORK wlist[WLSIZE]; 28210070Seric int wn = -1; 2834632Seric extern workcmpf(); 2844632Seric 2854632Seric /* clear out old WorkQ */ 2864632Seric for (w = WorkQ; w != NULL; ) 2874632Seric { 2884632Seric register WORK *nw = w->w_next; 2894632Seric 2904632Seric WorkQ = nw; 2914632Seric free(w->w_name); 2924632Seric free((char *) w); 2934632Seric w = nw; 2944632Seric } 2954632Seric 2964632Seric /* open the queue directory */ 2978148Seric f = opendir("."); 2984632Seric if (f == NULL) 2994632Seric { 3008148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 30110070Seric return (0); 3024632Seric } 3034632Seric 3044632Seric /* 3054632Seric ** Read the work directory. 3064632Seric */ 3074632Seric 30810070Seric while ((d = readdir(f)) != NULL) 3094632Seric { 3109377Seric FILE *cf; 3114632Seric char lbuf[MAXNAME]; 3124632Seric 3134632Seric /* is this an interesting entry? */ 3147812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 3154632Seric continue; 3164632Seric 31710070Seric /* yes -- open control file (if not too many files) */ 31810070Seric if (++wn >= WLSIZE) 31910070Seric continue; 3208148Seric cf = fopen(d->d_name, "r"); 3214632Seric if (cf == NULL) 3224632Seric { 3237055Seric /* this may be some random person sending hir msgs */ 3247055Seric /* syserr("orderq: cannot open %s", cbuf); */ 32510090Seric #ifdef DEBUG 32610090Seric if (tTd(41, 2)) 32710090Seric printf("orderq: cannot open %s (%d)\n", 32810090Seric d->d_name, errno); 32910090Seric #endif DEBUG 3307055Seric errno = 0; 33110090Seric wn--; 3324632Seric continue; 3334632Seric } 3348148Seric wlist[wn].w_name = newstr(d->d_name); 3354632Seric 3364632Seric /* extract useful information */ 3374632Seric while (fgets(lbuf, sizeof lbuf, cf) != NULL) 3384632Seric { 3399377Seric if (lbuf[0] == 'P') 3404632Seric { 3415037Seric (void) sscanf(&lbuf[1], "%ld", &wlist[wn].w_pri); 3424632Seric break; 3434632Seric } 3444632Seric } 3454632Seric (void) fclose(cf); 3464632Seric } 3476625Sglickman (void) closedir(f); 34810090Seric wn++; 3494632Seric 3504632Seric /* 3514632Seric ** Sort the work directory. 3524632Seric */ 3534632Seric 3544632Seric qsort(wlist, wn, sizeof *wlist, workcmpf); 3554632Seric 3564632Seric /* 3574632Seric ** Convert the work list into canonical form. 3589377Seric ** Should be turning it into a list of envelopes here perhaps. 3594632Seric */ 3604632Seric 3614632Seric wp = &WorkQ; 3624632Seric for (i = 0; i < wn; i++) 3634632Seric { 3644632Seric w = (WORK *) xalloc(sizeof *w); 3654632Seric w->w_name = wlist[i].w_name; 3664632Seric w->w_pri = wlist[i].w_pri; 3674632Seric w->w_next = NULL; 3684632Seric *wp = w; 3694632Seric wp = &w->w_next; 3704632Seric } 3714632Seric 3724632Seric # ifdef DEBUG 3737677Seric if (tTd(40, 1)) 3744632Seric { 3754632Seric for (w = WorkQ; w != NULL; w = w->w_next) 3765037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 3774632Seric } 3784632Seric # endif DEBUG 37910070Seric 38010090Seric return (wn); 3814632Seric } 3824632Seric /* 3837677Seric ** WORKCMPF -- compare function for ordering work. 3844632Seric ** 3854632Seric ** Parameters: 3864632Seric ** a -- the first argument. 3874632Seric ** b -- the second argument. 3884632Seric ** 3894632Seric ** Returns: 3904632Seric ** -1 if a < b 3914632Seric ** 0 if a == b 3924632Seric ** 1 if a > b 3934632Seric ** 3944632Seric ** Side Effects: 3954632Seric ** none. 3964632Seric */ 3974632Seric 3984632Seric # define PRIFACT 1800 /* bytes each priority point is worth */ 3994632Seric 4004632Seric workcmpf(a, b) 4015037Seric register WORK *a; 4025037Seric register WORK *b; 4034632Seric { 4045037Seric if (a->w_pri == b->w_pri) 4054632Seric return (0); 4065037Seric else if (a->w_pri > b->w_pri) 4074632Seric return (1); 4084632Seric else 4094632Seric return (-1); 4104632Seric } 4114632Seric /* 4124632Seric ** DOWORK -- do a work request. 4134632Seric ** 4144632Seric ** Parameters: 4154632Seric ** w -- the work request to be satisfied. 4164632Seric ** 4174632Seric ** Returns: 4184632Seric ** none. 4194632Seric ** 4204632Seric ** Side Effects: 4214632Seric ** The work request is satisfied if possible. 4224632Seric */ 4234632Seric 4244632Seric dowork(w) 4254632Seric register WORK *w; 4264632Seric { 4274632Seric register int i; 4284632Seric 4294632Seric # ifdef DEBUG 4307677Seric if (tTd(40, 1)) 4315037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 4324632Seric # endif DEBUG 4334632Seric 4344632Seric /* 4354632Seric ** Fork for work. 4364632Seric */ 4374632Seric 4384632Seric i = fork(); 4394632Seric if (i < 0) 4404632Seric { 4414632Seric syserr("dowork: cannot fork"); 4424632Seric return; 4434632Seric } 4444632Seric 4454632Seric if (i == 0) 4464632Seric { 4474632Seric /* 4484632Seric ** CHILD 4498148Seric ** Lock the control file to avoid duplicate deliveries. 4508148Seric ** Then run the file as though we had just read it. 4517350Seric ** We save an idea of the temporary name so we 4527350Seric ** can recover on interrupt. 4534632Seric */ 4544632Seric 4557763Seric /* set basic modes, etc. */ 4567356Seric (void) alarm(0); 4579338Seric CurEnv->e_flags &= ~EF_FATALERRS; 4584632Seric QueueRun = TRUE; 4599377Seric ErrorMode = EM_MAIL; 4608148Seric CurEnv->e_id = &w->w_name[2]; 4617876Seric # ifdef LOG 4627876Seric if (LogLevel > 11) 4637881Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 4647881Seric getpid()); 4657876Seric # endif LOG 4667763Seric 4677763Seric /* don't use the headers from sendmail.cf... */ 4687763Seric CurEnv->e_header = NULL; 4699348Seric (void) chompheader("from: $q", TRUE); 4707763Seric 4717763Seric /* create the link to the control file during processing */ 4727812Seric if (link(w->w_name, queuename(CurEnv, 'l')) < 0) 4736980Seric { 4747812Seric /* being processed by another queuer */ 4757881Seric # ifdef LOG 4767881Seric if (LogLevel > 4) 4777881Seric syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 4787881Seric # endif LOG 4796980Seric exit(EX_OK); 4806980Seric } 4816980Seric 4826980Seric /* do basic system initialization */ 4834632Seric initsys(); 4846980Seric 4856980Seric /* read the queue control file */ 4869630Seric readqf(CurEnv, TRUE); 4879338Seric CurEnv->e_flags |= EF_INQUEUE; 4889377Seric eatheader(CurEnv); 4896980Seric 4906980Seric /* do the delivery */ 4919338Seric if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 4929282Seric sendall(CurEnv, SM_DELIVER); 4936980Seric 4946980Seric /* finish up and exit */ 4954632Seric finis(); 4964632Seric } 4974632Seric 4984632Seric /* 4994632Seric ** Parent -- pick up results. 5004632Seric */ 5014632Seric 5024632Seric errno = 0; 5039377Seric (void) waitfor(i); 5044632Seric } 5054632Seric /* 5064632Seric ** READQF -- read queue file and set up environment. 5074632Seric ** 5084632Seric ** Parameters: 5099377Seric ** e -- the envelope of the job to run. 5109630Seric ** full -- if set, read in all information. Otherwise just 5119630Seric ** read in info needed for a queue print. 5124632Seric ** 5134632Seric ** Returns: 5144632Seric ** none. 5154632Seric ** 5164632Seric ** Side Effects: 5174632Seric ** cf is read and created as the current job, as though 5184632Seric ** we had been invoked by argument. 5194632Seric */ 5204632Seric 5219630Seric readqf(e, full) 5229377Seric register ENVELOPE *e; 5239630Seric bool full; 5244632Seric { 5254632Seric register FILE *f; 5267785Seric char buf[MAXFIELD]; 5279348Seric extern char *fgetfolded(); 5289377Seric register char *p; 5294632Seric 5304632Seric /* 5314632Seric ** Open the file created by queueup. 5324632Seric */ 5334632Seric 5349377Seric p = queuename(e, 'q'); 5359377Seric f = fopen(p, "r"); 5364632Seric if (f == NULL) 5374632Seric { 5389377Seric syserr("readqf: no control file %s", p); 5394632Seric return; 5404632Seric } 5419377Seric FileName = p; 5429377Seric LineNumber = 0; 5434632Seric 5444632Seric /* 5454632Seric ** Read and process the file. 5464632Seric */ 5474632Seric 5489630Seric if (Verbose && full) 5499377Seric printf("\nRunning %s\n", e->e_id); 5507785Seric while (fgetfolded(buf, sizeof buf, f) != NULL) 5514632Seric { 5524632Seric switch (buf[0]) 5534632Seric { 5544632Seric case 'R': /* specify recipient */ 5559618Seric sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 5564632Seric break; 5574632Seric 5584632Seric case 'H': /* header */ 5599630Seric if (full) 5609630Seric (void) chompheader(&buf[1], FALSE); 5614632Seric break; 5624632Seric 563*10108Seric case 'M': /* message */ 564*10108Seric e->e_message = newstr(&buf[1]); 565*10108Seric break; 566*10108Seric 5674632Seric case 'S': /* sender */ 5684634Seric setsender(newstr(&buf[1])); 5694632Seric break; 5704632Seric 5714632Seric case 'D': /* data file name */ 5729630Seric if (!full) 5739630Seric break; 5749377Seric e->e_df = newstr(&buf[1]); 5759544Seric e->e_dfp = fopen(e->e_df, "r"); 5769544Seric if (e->e_dfp == NULL) 5779377Seric syserr("readqf: cannot open %s", e->e_df); 5784632Seric break; 5794632Seric 5807860Seric case 'T': /* init time */ 5819377Seric (void) sscanf(&buf[1], "%ld", &e->e_ctime); 5824632Seric break; 5834632Seric 5844634Seric case 'P': /* message priority */ 5859377Seric (void) sscanf(&buf[1], "%ld", &e->e_msgpriority); 5865037Seric 5875037Seric /* make sure that big things get sent eventually */ 5889377Seric e->e_msgpriority -= WKTIMEFACT; 5894634Seric break; 5904634Seric 5914632Seric default: 5929377Seric syserr("readqf(%s): bad line \"%s\"", e->e_id, buf); 5934632Seric break; 5944632Seric } 5954632Seric } 5969377Seric 5979377Seric FileName = NULL; 5984632Seric } 5994632Seric /* 6009630Seric ** PRINTQUEUE -- print out a representation of the mail queue 6019630Seric ** 6029630Seric ** Parameters: 6039630Seric ** none. 6049630Seric ** 6059630Seric ** Returns: 6069630Seric ** none. 6079630Seric ** 6089630Seric ** Side Effects: 6099630Seric ** Prints a listing of the mail queue on the standard output. 6109630Seric */ 6115182Seric 6129630Seric printqueue() 6139630Seric { 6149630Seric register WORK *w; 6159630Seric FILE *f; 61610070Seric int nrequests; 6179630Seric char buf[MAXLINE]; 6189630Seric 6199630Seric /* 6209630Seric ** Read and order the queue. 6219630Seric */ 6229630Seric 62310070Seric nrequests = orderq(); 6249630Seric 6259630Seric /* 6269630Seric ** Print the work list that we have read. 6279630Seric */ 6289630Seric 6299630Seric /* first see if there is anything */ 63010070Seric if (nrequests <= 0) 6319630Seric { 63210070Seric printf("Mail queue is empty\n"); 6339630Seric return; 6349630Seric } 6359630Seric 63610096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 63710070Seric if (nrequests > WLSIZE) 63810070Seric printf(", only %d printed", WLSIZE); 63910070Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 6409630Seric for (w = WorkQ; w != NULL; w = w->w_next) 6419630Seric { 6429630Seric struct stat st; 64310070Seric auto time_t submittime = 0; 64410070Seric long dfsize = -1; 645*10108Seric char lf[20]; 646*10108Seric char message[MAXLINE]; 6479630Seric 6489630Seric printf("%7s", w->w_name + 2); 64910070Seric strcpy(lf, w->w_name); 65010070Seric lf[0] = 'l'; 65110070Seric if (stat(lf, &st) >= 0) 65210070Seric printf("*"); 65310070Seric else 65410070Seric printf(" "); 65510070Seric errno = 0; 6569630Seric f = fopen(w->w_name, "r"); 6579630Seric if (f == NULL) 6589630Seric { 6599630Seric printf(" (finished)\n"); 66010070Seric errno = 0; 6619630Seric continue; 6629630Seric } 663*10108Seric message[0] = '\0'; 6649630Seric while (fgets(buf, sizeof buf, f) != NULL) 6659630Seric { 6669630Seric fixcrlf(buf, TRUE); 6679630Seric switch (buf[0]) 6689630Seric { 669*10108Seric case 'M': /* error message */ 670*10108Seric strcpy(message, &buf[1]); 671*10108Seric break; 672*10108Seric 6739630Seric case 'S': /* sender name */ 674*10108Seric if (message[0] != '\0') 675*10108Seric { 676*10108Seric (void) strcat(buf, " ("); 677*10108Seric (void) strcat(buf, message); 678*10108Seric (void) strcat(buf, ")"); 679*10108Seric } 68010070Seric printf("%8d %.16s %.40s", dfsize, 68110070Seric ctime(&submittime), &buf[1]); 6829630Seric break; 6839630Seric 6849630Seric case 'R': /* recipient name */ 68510070Seric printf("\n\t\t\t\t %.40s", &buf[1]); 6869630Seric break; 6879630Seric 6889630Seric case 'T': /* creation time */ 68910070Seric sscanf(&buf[1], "%ld", &submittime); 6909630Seric break; 69110070Seric 69210070Seric case 'D': /* data file name */ 69310070Seric if (stat(&buf[1], &st) >= 0) 69410070Seric dfsize = st.st_size; 69510070Seric break; 6969630Seric } 6979630Seric } 69810070Seric if (submittime == (time_t) 0) 69910070Seric printf(" (no control file)"); 7009630Seric printf("\n"); 7019630Seric fclose(f); 7029630Seric } 7039630Seric } 7049630Seric 7055182Seric # endif QUEUE 706