1294Seric # include <stdio.h> 2294Seric # include <pwd.h> 3294Seric # include <signal.h> 4294Seric # include "dlvrmail.h" 5294Seric # ifdef LOG 6294Seric # include <log.h> 7294Seric # endif LOG 8294Seric 9*2089Seric static char SccsId[] = "@(#)deliver.c 2.4 01/08/81"; 10405Seric 11294Seric /* 12294Seric ** DELIVER -- Deliver a message to a particular address. 13294Seric ** 14294Seric ** Algorithm: 15294Seric ** Compute receiving network (i.e., mailer), host, & user. 16294Seric ** If local, see if this is really a program name. 17294Seric ** Build argument for the mailer. 18294Seric ** Create pipe through edit fcn if appropriate. 19294Seric ** Fork. 20294Seric ** Child: call mailer 21294Seric ** Parent: call editfcn if specified. 22294Seric ** Wait for mailer to finish. 23294Seric ** Interpret exit status. 24294Seric ** 25294Seric ** Parameters: 26294Seric ** to -- the address to deliver the message to. 27294Seric ** editfcn -- if non-NULL, we want to call this function 28294Seric ** to output the letter (instead of just out- 29294Seric ** putting it raw). 30294Seric ** 31294Seric ** Returns: 32294Seric ** zero -- successfully delivered. 33294Seric ** else -- some failure, see ExitStat for more info. 34294Seric ** 35294Seric ** Side Effects: 36294Seric ** The standard input is passed off to someone. 37294Seric ** 38294Seric ** WARNING: 39294Seric ** The standard input is shared amongst all children, 40294Seric ** including the file pointer. It is critical that the 41294Seric ** parent waits for the child to finish before forking 42294Seric ** another child. 43294Seric ** 44294Seric ** Called By: 45294Seric ** main 46294Seric ** savemail 47294Seric ** 48294Seric ** Files: 49570Seric ** standard input -- must be opened to the message to 50294Seric ** deliver. 51294Seric */ 52294Seric 53294Seric deliver(to, editfcn) 54294Seric addrq *to; 55294Seric int (*editfcn)(); 56294Seric { 57294Seric register struct mailer *m; 58294Seric char *host; 59294Seric char *user; 60294Seric extern struct passwd *getpwnam(); 61294Seric char **pvp; 62294Seric extern char **buildargv(); 63294Seric auto int st; 64294Seric register int i; 65294Seric register char *p; 66294Seric int pid; 67294Seric int pvect[2]; 68294Seric extern FILE *fdopen(); 69294Seric extern int errno; 70294Seric FILE *mfile; 71294Seric extern putheader(); 72294Seric extern pipesig(); 731824Seric extern bool GotHdr; 741828Seric extern char *index(); 75294Seric 76294Seric /* 77294Seric ** Compute receiving mailer, host, and to addreses. 78294Seric ** Do some initialization first. To is the to address 79294Seric ** for error messages. 80294Seric */ 81294Seric 82294Seric To = to->q_paddr; 83294Seric m = to->q_mailer; 84294Seric user = to->q_user; 85294Seric host = to->q_host; 861518Seric Errors = 0; 87294Seric errno = 0; 88294Seric # ifdef DEBUG 89294Seric if (Debug) 90294Seric printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); 91294Seric # endif DEBUG 92294Seric 93294Seric /* 94294Seric ** Remove quote bits from user/host. 95294Seric */ 96294Seric 97294Seric for (p = user; (*p++ &= 0177) != '\0'; ) 98294Seric continue; 99294Seric if (host != NULL) 100294Seric for (p = host; (*p++ &= 0177) != '\0'; ) 101294Seric continue; 102294Seric 103294Seric /* 104294Seric ** Strip quote bits from names if the mailer wants it. 105294Seric */ 106294Seric 107294Seric if (flagset(M_STRIPQ, m->m_flags)) 108294Seric { 109294Seric stripquotes(user); 110294Seric stripquotes(host); 111294Seric } 112294Seric 113294Seric /* 114294Seric ** See if this user name is "special". 115294Seric ** If the user is a program, diddle with the mailer spec. 116294Seric ** If the user name has a slash in it, assume that this 117294Seric ** is a file -- send it off without further ado. 118294Seric ** Note that this means that editfcn's will not 119294Seric ** be applied to the message. 120294Seric */ 121294Seric 122294Seric if (m == &Mailer[0]) 123294Seric { 124294Seric if (*user == '|') 125294Seric { 126294Seric user++; 127294Seric m = &Mailer[1]; 128294Seric } 129294Seric else 130294Seric { 131294Seric if (index(user, '/') != NULL) 132294Seric { 133294Seric i = mailfile(user); 134294Seric giveresponse(i, TRUE, m); 135294Seric return (i); 136294Seric } 137294Seric } 138294Seric } 139294Seric 140294Seric /* 1411389Seric ** See if the user exists. 1421389Seric ** Strictly, this is only needed to print a pretty 1431389Seric ** error message. 1441389Seric ** 1451389Seric ** >>>>>>>>>> This clause assumes that the local mailer 1461389Seric ** >> NOTE >> cannot do any further aliasing; that 1471389Seric ** >>>>>>>>>> function is subsumed by delivermail. 148294Seric */ 149294Seric 150294Seric if (m == &Mailer[0]) 151294Seric { 152294Seric if (getpwnam(user) == NULL) 153294Seric { 154294Seric giveresponse(EX_NOUSER, TRUE, m); 155294Seric return (EX_NOUSER); 156294Seric } 157294Seric } 158294Seric 159294Seric /* 160294Seric ** If the mailer wants a From line, insert a new editfcn. 161294Seric */ 162294Seric 1631828Seric if (flagset(M_HDR, m->m_flags) && editfcn == NULL && (!GotHdr || flagset(M_FHDR, m->m_flags))) 164294Seric editfcn = putheader; 165294Seric 166294Seric /* 167294Seric ** Call the mailer. 168294Seric ** The argument vector gets built, pipes through 'editfcn' 169294Seric ** are created as necessary, and we fork & exec as 170294Seric ** appropriate. In the parent, we call 'editfcn'. 171294Seric */ 172294Seric 173294Seric pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr); 174294Seric if (pvp == NULL) 175294Seric { 176294Seric usrerr("name too long"); 177294Seric return (-1); 178294Seric } 179294Seric rewind(stdin); 180294Seric 181294Seric /* create a pipe if we will need one */ 182294Seric if (editfcn != NULL && pipe(pvect) < 0) 183294Seric { 184294Seric syserr("pipe"); 185294Seric return (-1); 186294Seric } 1871504Smark # ifdef VFORK 1881504Smark pid = vfork(); 1891504Smark # else 190294Seric pid = fork(); 1911504Smark # endif 192294Seric if (pid < 0) 193294Seric { 194294Seric syserr("Cannot fork"); 195294Seric if (editfcn != NULL) 196294Seric { 197294Seric close(pvect[0]); 198294Seric close(pvect[1]); 199294Seric } 200294Seric return (-1); 201294Seric } 202294Seric else if (pid == 0) 203294Seric { 204294Seric /* child -- set up input & exec mailer */ 2051621Seric /* make diagnostic output be standard output */ 2061621Seric close(2); 2071621Seric dup(1); 208294Seric signal(SIGINT, SIG_IGN); 209294Seric if (editfcn != NULL) 210294Seric { 211294Seric close(0); 212294Seric if (dup(pvect[0]) < 0) 213294Seric { 214294Seric syserr("Cannot dup to zero!"); 2151619Seric _exit(EX_OSERR); 216294Seric } 217294Seric close(pvect[0]); 218294Seric close(pvect[1]); 219294Seric } 220294Seric if (!flagset(M_RESTR, m->m_flags)) 221294Seric setuid(getuid()); 222294Seric # ifdef LOG 223*2089Seric closelog(); 224294Seric # endif LOG 2251504Smark # ifndef VFORK 2261504Smark /* 2271504Smark * We have to be careful with vfork - we can't mung up the 2281504Smark * memory but we don't want the mailer to inherit any extra 2291504Smark * open files. Chances are the mailer won't 2301504Smark * care about an extra file, but then again you never know. 2311504Smark * Actually, we would like to close(fileno(pwf)), but it's 2321504Smark * declared static so we can't. But if we fclose(pwf), which 2331504Smark * is what endpwent does, it closes it in the parent too and 2341504Smark * the next getpwnam will be slower. If you have a weird mailer 2351504Smark * that chokes on the extra file you should do the endpwent(). 2361504Smark */ 237294Seric endpwent(); 2381504Smark # endif 239294Seric execv(m->m_mailer, pvp); 240294Seric /* syserr fails because log is closed */ 241294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 2421619Seric _exit(EX_UNAVAILABLE); 243294Seric } 244294Seric 245294Seric /* arrange to write out header message if error */ 246294Seric if (editfcn != NULL) 247294Seric { 248294Seric close(pvect[0]); 249294Seric signal(SIGPIPE, pipesig); 250294Seric mfile = fdopen(pvect[1], "w"); 251294Seric (*editfcn)(mfile); 252294Seric fclose(mfile); 253294Seric } 254294Seric 255294Seric /* 256294Seric ** Wait for child to die and report status. 257294Seric ** We should never get fatal errors (e.g., segmentation 258294Seric ** violation), so we report those specially. For other 259294Seric ** errors, we choose a status message (into statmsg), 260294Seric ** and if it represents an error, we print it. 261294Seric */ 262294Seric 263294Seric while ((i = wait(&st)) > 0 && i != pid) 264294Seric continue; 265294Seric if (i < 0) 266294Seric { 267294Seric syserr("wait"); 268294Seric return (-1); 269294Seric } 270294Seric if ((st & 0377) != 0) 271294Seric { 272294Seric syserr("%s: stat %o", pvp[0], st); 2731597Seric ExitStat = EX_UNAVAILABLE; 274294Seric return (-1); 275294Seric } 276294Seric i = (st >> 8) & 0377; 277294Seric giveresponse(i, FALSE, m); 278294Seric return (i); 279294Seric } 280294Seric /* 281294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 282294Seric ** 283294Seric ** Parameters: 284294Seric ** stat -- the status code from the mailer (high byte 285294Seric ** only; core dumps must have been taken care of 286294Seric ** already). 287294Seric ** force -- if set, force an error message output, even 288294Seric ** if the mailer seems to like to print its own 289294Seric ** messages. 290294Seric ** m -- the mailer descriptor for this mailer. 291294Seric ** 292294Seric ** Returns: 293294Seric ** none. 294294Seric ** 295294Seric ** Side Effects: 2961518Seric ** Errors may be incremented. 297294Seric ** ExitStat may be set. 298294Seric ** 299294Seric ** Called By: 300294Seric ** deliver 301294Seric */ 302294Seric 303294Seric giveresponse(stat, force, m) 304294Seric int stat; 305294Seric int force; 306294Seric register struct mailer *m; 307294Seric { 308294Seric register char *statmsg; 309294Seric extern char *SysExMsg[]; 310294Seric register int i; 311294Seric extern int N_SysEx; 3121624Seric extern long MsgSize; 3131624Seric char buf[30]; 314294Seric 315294Seric i = stat - EX__BASE; 316294Seric if (i < 0 || i > N_SysEx) 317294Seric statmsg = NULL; 318294Seric else 319294Seric statmsg = SysExMsg[i]; 320294Seric if (stat == 0) 321294Seric statmsg = "ok"; 322294Seric else 323294Seric { 3241518Seric Errors++; 325294Seric if (statmsg == NULL && m->m_badstat != 0) 326294Seric { 327294Seric stat = m->m_badstat; 328294Seric i = stat - EX__BASE; 329294Seric # ifdef DEBUG 330294Seric if (i < 0 || i >= N_SysEx) 331294Seric syserr("Bad m_badstat %d", stat); 332294Seric else 333294Seric # endif DEBUG 334294Seric statmsg = SysExMsg[i]; 335294Seric } 336294Seric if (statmsg == NULL) 337294Seric usrerr("unknown mailer response %d", stat); 338294Seric else if (force || !flagset(M_QUIET, m->m_flags)) 339294Seric usrerr("%s", statmsg); 340294Seric } 341294Seric 342294Seric /* 343294Seric ** Final cleanup. 344294Seric ** Log a record of the transaction. Compute the new 345294Seric ** ExitStat -- if we already had an error, stick with 346294Seric ** that. 347294Seric */ 348294Seric 3491624Seric if (statmsg == NULL) 3501624Seric { 3511624Seric sprintf(buf, "error %d", stat); 3521624Seric statmsg = buf; 3531624Seric } 3541624Seric 355294Seric # ifdef LOG 3561624Seric logmsg(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 357294Seric # endif LOG 3581389Seric setstat(stat); 359294Seric return (stat); 360294Seric } 361294Seric /* 362294Seric ** PUTHEADER -- insert the From header into some mail 363294Seric ** 364294Seric ** For mailers such as 'msgs' that want the header inserted 365294Seric ** into the mail, this edit filter inserts the From line and 3661824Seric ** then passes the rest of the message through. 367294Seric ** 368294Seric ** Parameters: 369294Seric ** fp -- the file pointer for the output. 370294Seric ** 371294Seric ** Returns: 372294Seric ** none 373294Seric ** 374294Seric ** Side Effects: 375294Seric ** Puts a "From" line in UNIX format, and then 376294Seric ** outputs the rest of the message. 377294Seric ** 378294Seric ** Called By: 379294Seric ** deliver 380294Seric */ 381294Seric 382294Seric putheader(fp) 383294Seric register FILE *fp; 384294Seric { 385294Seric char buf[MAXLINE + 1]; 386294Seric long tim; 387294Seric extern char *ctime(); 3881828Seric register char *p; 3891828Seric extern char *index(); 390294Seric 3911828Seric /* output the header part */ 3921828Seric fgets(buf, sizeof buf, stdin); 3931828Seric if (strncmp(buf, "From ", 5) != 0 || (p = index(&buf[5], ' ')) == NULL) 3941828Seric { 3951828Seric time(&tim); 3961828Seric fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); 397294Seric fputs(buf, fp); 3981828Seric } 3991828Seric else 4001828Seric fprintf(fp, "From %s %s", From.q_paddr, &p[1]); 4011828Seric 4021828Seric /* output the body */ 4031828Seric while (!ferror(fp) && fgets(buf, sizeof buf, stdin) != NULL) 4041828Seric fputs(buf, fp); 405294Seric if (ferror(fp)) 406294Seric { 407294Seric syserr("putheader: write error"); 408294Seric setstat(EX_IOERR); 409294Seric } 410294Seric } 411294Seric /* 412294Seric ** PIPESIG -- Handle broken pipe signals 413294Seric ** 414294Seric ** This just logs an error. 415294Seric ** 416294Seric ** Parameters: 417294Seric ** none 418294Seric ** 419294Seric ** Returns: 420294Seric ** none 421294Seric ** 422294Seric ** Side Effects: 423294Seric ** logs an error message. 424294Seric */ 425294Seric 426294Seric pipesig() 427294Seric { 428294Seric syserr("Broken pipe"); 4291621Seric signal(SIGPIPE, SIG_IGN); 430294Seric } 431294Seric /* 432294Seric ** SENDTO -- Designate a send list. 433294Seric ** 434294Seric ** The parameter is a comma-separated list of people to send to. 435294Seric ** This routine arranges to send to all of them. 436294Seric ** 437294Seric ** Parameters: 438294Seric ** list -- the send list. 439294Seric ** copyf -- the copy flag; passed to parse. 440294Seric ** 441294Seric ** Returns: 442294Seric ** none 443294Seric ** 444294Seric ** Side Effects: 445294Seric ** none. 446294Seric ** 447294Seric ** Called By: 448294Seric ** main 449294Seric ** alias 450294Seric */ 451294Seric 452294Seric sendto(list, copyf) 453294Seric char *list; 454294Seric int copyf; 455294Seric { 456294Seric register char *p; 457294Seric register char *q; 458294Seric register char c; 459294Seric addrq *a; 460294Seric extern addrq *parse(); 461294Seric bool more; 462294Seric 463294Seric /* more keeps track of what the previous delimiter was */ 464294Seric more = TRUE; 465294Seric for (p = list; more; ) 466294Seric { 467294Seric /* find the end of this address */ 468294Seric q = p; 469294Seric while ((c = *p++) != '\0' && c != ',' && c != '\n') 470294Seric continue; 471294Seric more = c != '\0'; 472294Seric *--p = '\0'; 473294Seric if (more) 474294Seric p++; 475294Seric 476294Seric /* parse the address */ 477294Seric if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) 478294Seric continue; 479294Seric 480294Seric /* arrange to send to this person */ 481294Seric recipient(a, &SendQ); 482294Seric } 483294Seric To = NULL; 484294Seric } 485294Seric /* 486294Seric ** RECIPIENT -- Designate a message recipient 487294Seric ** 488294Seric ** Saves the named person for future mailing. 489294Seric ** 490294Seric ** Designates a person as a recipient. This routine 491294Seric ** does the initial parsing, and checks to see if 492294Seric ** this person has already received the mail. 493294Seric ** It also supresses local network names and turns them into 494294Seric ** local names. 495294Seric ** 496294Seric ** Parameters: 497294Seric ** a -- the (preparsed) address header for the recipient. 498294Seric ** targetq -- the queue to add the name to. 499294Seric ** 500294Seric ** Returns: 501294Seric ** none. 502294Seric ** 503294Seric ** Side Effects: 504294Seric ** none. 505294Seric ** 506294Seric ** Called By: 507294Seric ** sendto 508294Seric ** main 509294Seric */ 510294Seric 511294Seric recipient(a, targetq) 512294Seric register addrq *a; 513294Seric addrq *targetq; 514294Seric { 515294Seric register addrq *q; 516294Seric register struct mailer *m; 517294Seric register char **pvp; 518294Seric extern char *xalloc(); 519294Seric extern bool forward(); 520294Seric extern int errno; 521294Seric extern bool sameaddr(); 522294Seric 523294Seric To = a->q_paddr; 524294Seric m = a->q_mailer; 525294Seric errno = 0; 526294Seric # ifdef DEBUG 527294Seric if (Debug) 528294Seric printf("recipient(%s)\n", To); 529294Seric # endif DEBUG 530294Seric 531294Seric /* 532294Seric ** Look up this person in the recipient list. If they 533294Seric ** are there already, return, otherwise continue. 534294Seric */ 535294Seric 536294Seric if (!ForceMail) 537294Seric { 538294Seric for (q = &SendQ; (q = nxtinq(q)) != NULL; ) 539294Seric if (sameaddr(q, a, FALSE)) 540294Seric { 541294Seric # ifdef DEBUG 542294Seric if (Debug) 543294Seric printf("(%s in SendQ)\n", a->q_paddr); 544294Seric # endif DEBUG 545294Seric return; 546294Seric } 547294Seric for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) 548294Seric if (sameaddr(q, a, FALSE)) 549294Seric { 550294Seric # ifdef DEBUG 551294Seric if (Debug) 552294Seric printf("(%s in AliasQ)\n", a->q_paddr); 553294Seric # endif DEBUG 554294Seric return; 555294Seric } 556294Seric } 557294Seric 558294Seric /* 559294Seric ** See if the user wants hir mail forwarded. 560294Seric ** `Forward' must do the forwarding recursively. 561294Seric */ 562294Seric 563294Seric if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) 564294Seric return; 565294Seric 566294Seric /* 567294Seric ** Put the user onto the target queue. 568294Seric */ 569294Seric 570294Seric if (targetq != NULL) 571294Seric { 572294Seric putonq(a, targetq); 573294Seric } 574294Seric 575294Seric return; 576294Seric } 577294Seric /* 578294Seric ** BUILDARGV -- Build an argument vector for a mail server. 579294Seric ** 580294Seric ** Using a template defined in config.c, an argv is built. 581294Seric ** The format of the template is already a vector. The 582294Seric ** items of this vector are copied, unless a dollar sign 583294Seric ** is encountered. In this case, the next character 584294Seric ** specifies something else to copy in. These can be 585294Seric ** $f The from address. 586294Seric ** $h The host. 587294Seric ** $u The user. 588294Seric ** $c The hop count. 589294Seric ** The vector is built in a local buffer. A pointer to 590294Seric ** the static argv is returned. 591294Seric ** 592294Seric ** Parameters: 593294Seric ** tmplt -- a template for an argument vector. 594294Seric ** flags -- the flags for this server. 595294Seric ** host -- the host name to send to. 596294Seric ** user -- the user name to send to. 597294Seric ** from -- the person this mail is from. 598294Seric ** 599294Seric ** Returns: 600294Seric ** A pointer to an argv. 601294Seric ** 602294Seric ** Side Effects: 603294Seric ** none 604294Seric ** 605294Seric ** WARNING: 606294Seric ** Since the argv is staticly allocated, any subsequent 607294Seric ** calls will clobber the old argv. 608294Seric ** 609294Seric ** Called By: 610294Seric ** deliver 611294Seric */ 612294Seric 613294Seric char ** 614294Seric buildargv(tmplt, flags, host, user, from) 615294Seric char **tmplt; 616294Seric int flags; 617294Seric char *host; 618294Seric char *user; 619294Seric char *from; 620294Seric { 621294Seric register char *p; 622294Seric register char *q; 623294Seric static char *pv[MAXPV+1]; 624294Seric char **pvp; 625294Seric char **mvp; 626294Seric static char buf[512]; 627294Seric register char *bp; 628294Seric char pbuf[30]; 629294Seric 630294Seric /* 631294Seric ** Do initial argv setup. 632294Seric ** Insert the mailer name. Notice that $x expansion is 633294Seric ** NOT done on the mailer name. Then, if the mailer has 634294Seric ** a picky -f flag, we insert it as appropriate. This 635294Seric ** code does not check for 'pv' overflow; this places a 636294Seric ** manifest lower limit of 4 for MAXPV. 637294Seric */ 638294Seric 639294Seric pvp = pv; 640294Seric bp = buf; 641294Seric 642294Seric *pvp++ = tmplt[0]; 643294Seric 644294Seric /* insert -f or -r flag as appropriate */ 645294Seric if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) 646294Seric { 647294Seric if (flagset(M_FOPT, flags)) 648294Seric *pvp++ = "-f"; 649294Seric else 650294Seric *pvp++ = "-r"; 651294Seric *pvp++ = From.q_paddr; 652294Seric } 653294Seric 654294Seric /* 655294Seric ** Build the rest of argv. 656294Seric ** For each prototype parameter, the prototype is 657294Seric ** scanned character at a time. If a dollar-sign is 658294Seric ** found, 'q' is set to the appropriate expansion, 659294Seric ** otherwise it is null. Then either the string 660294Seric ** pointed to by q, or the original character, is 661294Seric ** interpolated into the buffer. Buffer overflow is 662294Seric ** checked. 663294Seric */ 664294Seric 665294Seric for (mvp = tmplt; (p = *++mvp) != NULL; ) 666294Seric { 667294Seric if (pvp >= &pv[MAXPV]) 668294Seric { 669294Seric syserr("Too many parameters to %s", pv[0]); 670294Seric return (NULL); 671294Seric } 672294Seric *pvp++ = bp; 673294Seric for (; *p != '\0'; p++) 674294Seric { 675294Seric /* q will be the interpolated quantity */ 676294Seric q = NULL; 677294Seric if (*p == '$') 678294Seric { 679294Seric switch (*++p) 680294Seric { 681294Seric case 'f': /* from person */ 682294Seric q = from; 683294Seric break; 684294Seric 685294Seric case 'u': /* user */ 686294Seric q = user; 687294Seric break; 688294Seric 689294Seric case 'h': /* host */ 690294Seric q = host; 691294Seric break; 692294Seric 693294Seric case 'c': /* hop count */ 694294Seric sprintf(pbuf, "%d", HopCount); 695294Seric q = pbuf; 696294Seric break; 697294Seric } 698294Seric } 699294Seric 700294Seric /* 701294Seric ** Interpolate q or output one character 702294Seric ** Strip quote bits as we proceed..... 703294Seric */ 704294Seric 705294Seric if (q != NULL) 706294Seric { 707294Seric while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') 708294Seric continue; 709294Seric bp--; 710294Seric } 711294Seric else if (bp < &buf[sizeof buf - 1]) 712294Seric *bp++ = *p; 713294Seric } 714294Seric *bp++ = '\0'; 715294Seric if (bp >= &buf[sizeof buf - 1]) 716294Seric return (NULL); 717294Seric } 718294Seric *pvp = NULL; 719294Seric 720294Seric # ifdef DEBUG 721294Seric if (Debug) 722294Seric { 723294Seric printf("Interpolated argv is:\n"); 724294Seric for (mvp = pv; *mvp != NULL; mvp++) 725294Seric printf("\t%s\n", *mvp); 726294Seric } 727294Seric # endif DEBUG 728294Seric 729294Seric return (pv); 730294Seric } 731294Seric /* 732294Seric ** MAILFILE -- Send a message to a file. 733294Seric ** 734294Seric ** Parameters: 735294Seric ** filename -- the name of the file to send to. 736294Seric ** 737294Seric ** Returns: 738294Seric ** The exit code associated with the operation. 739294Seric ** 740294Seric ** Side Effects: 741294Seric ** none. 742294Seric ** 743294Seric ** Called By: 744294Seric ** deliver 745294Seric */ 746294Seric 747294Seric mailfile(filename) 748294Seric char *filename; 749294Seric { 750294Seric char buf[MAXLINE]; 751294Seric register FILE *f; 752294Seric auto long tim; 753294Seric extern char *ctime(); 754294Seric 755294Seric f = fopen(filename, "a"); 756294Seric if (f == NULL) 757294Seric return (EX_CANTCREAT); 758294Seric 759294Seric /* output the timestamp */ 760294Seric time(&tim); 761294Seric fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); 762294Seric rewind(stdin); 763294Seric while (fgets(buf, sizeof buf, stdin) != NULL) 764294Seric { 765294Seric fputs(buf, f); 766294Seric if (ferror(f)) 767294Seric { 768294Seric fclose(f); 769294Seric return (EX_IOERR); 770294Seric } 771294Seric } 772294Seric fputs("\n", f); 773294Seric fclose(f); 774294Seric return (EX_OK); 775294Seric } 776