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*405Seric static char SccsId[] = "@(#)deliver.c 1.3 07/25/80"; 10*405Seric 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 ** Requires: 45294Seric ** buildargv 46294Seric ** giveresponse 47294Seric ** fork (sys) 48294Seric ** rewind (sys) 49294Seric ** execv (sys) 50294Seric ** exit (sys) 51294Seric ** wait (sys) 52294Seric ** syserr 53294Seric ** getpwnam (sys) 54294Seric ** endpwent (sys) 55294Seric ** initlog 56294Seric ** flagset 57294Seric ** usrerr 58294Seric ** pipe (sys) 59294Seric ** close (sys) 60294Seric ** dup (sys) 61294Seric ** setuid (sys) 62294Seric ** getuid (sys) 63294Seric ** signal (sys) 64294Seric ** fdopen (sys[v7] or conf.c[v6]) 65294Seric ** fclose (sys) 66294Seric ** printf (sys) 67294Seric ** stripquotes 68294Seric ** mailfile 69294Seric ** index (sys) 70294Seric ** 71294Seric ** Called By: 72294Seric ** main 73294Seric ** savemail 74294Seric ** 75294Seric ** Files: 76294Seric ** standard input -- must be openned to the message to 77294Seric ** deliver. 78294Seric ** 79294Seric ** History: 80294Seric ** 3/5/80 -- modified rather extensively to change the 81294Seric ** internal form of addresses. 82294Seric ** 12/26/79 -- written. 83294Seric */ 84294Seric 85294Seric deliver(to, editfcn) 86294Seric addrq *to; 87294Seric int (*editfcn)(); 88294Seric { 89294Seric register struct mailer *m; 90294Seric char *host; 91294Seric char *user; 92294Seric extern struct passwd *getpwnam(); 93294Seric char **pvp; 94294Seric extern char **buildargv(); 95294Seric auto int st; 96294Seric register int i; 97294Seric register char *p; 98294Seric int pid; 99294Seric int pvect[2]; 100294Seric extern FILE *fdopen(); 101294Seric extern int errno; 102294Seric FILE *mfile; 103294Seric extern putheader(); 104294Seric extern pipesig(); 105294Seric 106294Seric /* 107294Seric ** Compute receiving mailer, host, and to addreses. 108294Seric ** Do some initialization first. To is the to address 109294Seric ** for error messages. 110294Seric */ 111294Seric 112294Seric To = to->q_paddr; 113294Seric m = to->q_mailer; 114294Seric user = to->q_user; 115294Seric host = to->q_host; 116294Seric Error = 0; 117294Seric errno = 0; 118294Seric # ifdef DEBUG 119294Seric if (Debug) 120294Seric printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); 121294Seric # endif DEBUG 122294Seric 123294Seric /* 124294Seric ** Remove quote bits from user/host. 125294Seric */ 126294Seric 127294Seric for (p = user; (*p++ &= 0177) != '\0'; ) 128294Seric continue; 129294Seric if (host != NULL) 130294Seric for (p = host; (*p++ &= 0177) != '\0'; ) 131294Seric continue; 132294Seric 133294Seric /* 134294Seric ** Strip quote bits from names if the mailer wants it. 135294Seric */ 136294Seric 137294Seric if (flagset(M_STRIPQ, m->m_flags)) 138294Seric { 139294Seric stripquotes(user); 140294Seric stripquotes(host); 141294Seric } 142294Seric 143294Seric /* 144294Seric ** See if this user name is "special". 145294Seric ** If the user is a program, diddle with the mailer spec. 146294Seric ** If the user name has a slash in it, assume that this 147294Seric ** is a file -- send it off without further ado. 148294Seric ** Note that this means that editfcn's will not 149294Seric ** be applied to the message. 150294Seric */ 151294Seric 152294Seric if (m == &Mailer[0]) 153294Seric { 154294Seric if (*user == '|') 155294Seric { 156294Seric user++; 157294Seric m = &Mailer[1]; 158294Seric } 159294Seric else 160294Seric { 161294Seric if (index(user, '/') != NULL) 162294Seric { 163294Seric i = mailfile(user); 164294Seric giveresponse(i, TRUE, m); 165294Seric return (i); 166294Seric } 167294Seric } 168294Seric } 169294Seric 170294Seric # ifdef BADMAIL 171294Seric /* 172294Seric ** If the mailer doesn't return the proper 173294Seric ** exit statuses, check here to see if the 174294Seric ** user exists so that we can give a pretty 175294Seric ** error message. 176294Seric */ 177294Seric 178294Seric if (m == &Mailer[0]) 179294Seric { 180294Seric if (getpwnam(user) == NULL) 181294Seric { 182294Seric giveresponse(EX_NOUSER, TRUE, m); 183294Seric return (EX_NOUSER); 184294Seric } 185294Seric } 186294Seric # endif BADMAIL 187294Seric 188294Seric /* 189294Seric ** If the mailer wants a From line, insert a new editfcn. 190294Seric */ 191294Seric 192294Seric if (flagset(M_HDR, m->m_flags) && editfcn == NULL) 193294Seric editfcn = putheader; 194294Seric 195294Seric /* 196294Seric ** Call the mailer. 197294Seric ** The argument vector gets built, pipes through 'editfcn' 198294Seric ** are created as necessary, and we fork & exec as 199294Seric ** appropriate. In the parent, we call 'editfcn'. 200294Seric */ 201294Seric 202294Seric pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr); 203294Seric if (pvp == NULL) 204294Seric { 205294Seric usrerr("name too long"); 206294Seric return (-1); 207294Seric } 208294Seric rewind(stdin); 209294Seric 210294Seric /* create a pipe if we will need one */ 211294Seric if (editfcn != NULL && pipe(pvect) < 0) 212294Seric { 213294Seric syserr("pipe"); 214294Seric return (-1); 215294Seric } 216294Seric pid = fork(); 217294Seric if (pid < 0) 218294Seric { 219294Seric syserr("Cannot fork"); 220294Seric if (editfcn != NULL) 221294Seric { 222294Seric close(pvect[0]); 223294Seric close(pvect[1]); 224294Seric } 225294Seric return (-1); 226294Seric } 227294Seric else if (pid == 0) 228294Seric { 229294Seric /* child -- set up input & exec mailer */ 230294Seric signal(SIGINT, SIG_IGN); 231294Seric if (editfcn != NULL) 232294Seric { 233294Seric close(0); 234294Seric if (dup(pvect[0]) < 0) 235294Seric { 236294Seric syserr("Cannot dup to zero!"); 237294Seric exit(EX_OSERR); 238294Seric } 239294Seric close(pvect[0]); 240294Seric close(pvect[1]); 241294Seric } 242294Seric if (!flagset(M_RESTR, m->m_flags)) 243294Seric setuid(getuid()); 244294Seric # ifdef LOG 245294Seric initlog(NULL, 0, LOG_CLOSE); 246294Seric # endif LOG 247294Seric endpwent(); 248294Seric execv(m->m_mailer, pvp); 249294Seric /* syserr fails because log is closed */ 250294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 251294Seric exit(EX_UNAVAIL); 252294Seric } 253294Seric 254294Seric /* arrange to write out header message if error */ 255294Seric if (editfcn != NULL) 256294Seric { 257294Seric close(pvect[0]); 258294Seric signal(SIGPIPE, pipesig); 259294Seric mfile = fdopen(pvect[1], "w"); 260294Seric (*editfcn)(mfile); 261294Seric fclose(mfile); 262294Seric } 263294Seric 264294Seric /* 265294Seric ** Wait for child to die and report status. 266294Seric ** We should never get fatal errors (e.g., segmentation 267294Seric ** violation), so we report those specially. For other 268294Seric ** errors, we choose a status message (into statmsg), 269294Seric ** and if it represents an error, we print it. 270294Seric */ 271294Seric 272294Seric while ((i = wait(&st)) > 0 && i != pid) 273294Seric continue; 274294Seric if (i < 0) 275294Seric { 276294Seric syserr("wait"); 277294Seric return (-1); 278294Seric } 279294Seric if ((st & 0377) != 0) 280294Seric { 281294Seric syserr("%s: stat %o", pvp[0], st); 282294Seric ExitStat = EX_UNAVAIL; 283294Seric return (-1); 284294Seric } 285294Seric i = (st >> 8) & 0377; 286294Seric giveresponse(i, FALSE, m); 287294Seric return (i); 288294Seric } 289294Seric /* 290294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 291294Seric ** 292294Seric ** Parameters: 293294Seric ** stat -- the status code from the mailer (high byte 294294Seric ** only; core dumps must have been taken care of 295294Seric ** already). 296294Seric ** force -- if set, force an error message output, even 297294Seric ** if the mailer seems to like to print its own 298294Seric ** messages. 299294Seric ** m -- the mailer descriptor for this mailer. 300294Seric ** 301294Seric ** Returns: 302294Seric ** none. 303294Seric ** 304294Seric ** Side Effects: 305294Seric ** Error may be set. 306294Seric ** ExitStat may be set. 307294Seric ** 308294Seric ** Requires: 309294Seric ** usrerr 310294Seric ** syserr 311294Seric ** flagset 312294Seric ** logmsg (sys) 313294Seric ** 314294Seric ** Called By: 315294Seric ** deliver 316294Seric ** 317294Seric ** History: 318294Seric ** 2/18/80 -- broken from deliver. 319294Seric */ 320294Seric 321294Seric giveresponse(stat, force, m) 322294Seric int stat; 323294Seric int force; 324294Seric register struct mailer *m; 325294Seric { 326294Seric register char *statmsg; 327294Seric extern char *SysExMsg[]; 328294Seric register int i; 329294Seric extern int N_SysEx; 330294Seric 331294Seric i = stat - EX__BASE; 332294Seric if (i < 0 || i > N_SysEx) 333294Seric statmsg = NULL; 334294Seric else 335294Seric statmsg = SysExMsg[i]; 336294Seric if (stat == 0) 337294Seric statmsg = "ok"; 338294Seric else 339294Seric { 340294Seric Error++; 341294Seric if (statmsg == NULL && m->m_badstat != 0) 342294Seric { 343294Seric stat = m->m_badstat; 344294Seric i = stat - EX__BASE; 345294Seric # ifdef DEBUG 346294Seric if (i < 0 || i >= N_SysEx) 347294Seric syserr("Bad m_badstat %d", stat); 348294Seric else 349294Seric # endif DEBUG 350294Seric statmsg = SysExMsg[i]; 351294Seric } 352294Seric if (statmsg == NULL) 353294Seric usrerr("unknown mailer response %d", stat); 354294Seric else if (force || !flagset(M_QUIET, m->m_flags)) 355294Seric usrerr("%s", statmsg); 356294Seric } 357294Seric 358294Seric /* 359294Seric ** Final cleanup. 360294Seric ** Log a record of the transaction. Compute the new 361294Seric ** ExitStat -- if we already had an error, stick with 362294Seric ** that. 363294Seric */ 364294Seric 365294Seric # ifdef LOG 366294Seric if (statmsg == NULL) 367294Seric logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat); 368294Seric else 369294Seric logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg); 370294Seric # endif LOG 371294Seric if (ExitStat == EX_OK) 372294Seric ExitStat = stat; 373294Seric return (stat); 374294Seric } 375294Seric /* 376294Seric ** PUTHEADER -- insert the From header into some mail 377294Seric ** 378294Seric ** For mailers such as 'msgs' that want the header inserted 379294Seric ** into the mail, this edit filter inserts the From line and 380294Seric ** then passes the rest of the message through. 381294Seric ** 382294Seric ** Parameters: 383294Seric ** fp -- the file pointer for the output. 384294Seric ** 385294Seric ** Returns: 386294Seric ** none 387294Seric ** 388294Seric ** Side Effects: 389294Seric ** Puts a "From" line in UNIX format, and then 390294Seric ** outputs the rest of the message. 391294Seric ** 392294Seric ** Requires: 393294Seric ** fprintf (sys) 394294Seric ** fgets (sys) 395294Seric ** fputs (sys) 396294Seric ** time (sys) 397294Seric ** ctime (sys) 398294Seric ** ferror (sys) 399294Seric ** syserr 400294Seric ** setstat 401294Seric ** 402294Seric ** Called By: 403294Seric ** deliver 404294Seric ** 405294Seric ** History: 406294Seric ** 1/8/80 -- written. 407294Seric */ 408294Seric 409294Seric putheader(fp) 410294Seric register FILE *fp; 411294Seric { 412294Seric char buf[MAXLINE + 1]; 413294Seric long tim; 414294Seric extern char *ctime(); 415294Seric 416294Seric time(&tim); 417294Seric fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); 418294Seric while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) 419294Seric fputs(buf, fp); 420294Seric if (ferror(fp)) 421294Seric { 422294Seric syserr("putheader: write error"); 423294Seric setstat(EX_IOERR); 424294Seric } 425294Seric } 426294Seric /* 427294Seric ** PIPESIG -- Handle broken pipe signals 428294Seric ** 429294Seric ** This just logs an error. 430294Seric ** 431294Seric ** Parameters: 432294Seric ** none 433294Seric ** 434294Seric ** Returns: 435294Seric ** none 436294Seric ** 437294Seric ** Side Effects: 438294Seric ** logs an error message. 439294Seric ** 440294Seric ** Requires: 441294Seric ** syserr 442294Seric ** 443294Seric ** History: 444294Seric ** 1/17/80 -- written. 445294Seric */ 446294Seric 447294Seric pipesig() 448294Seric { 449294Seric syserr("Broken pipe"); 450294Seric } 451294Seric /* 452294Seric ** SENDTO -- Designate a send list. 453294Seric ** 454294Seric ** The parameter is a comma-separated list of people to send to. 455294Seric ** This routine arranges to send to all of them. 456294Seric ** 457294Seric ** Parameters: 458294Seric ** list -- the send list. 459294Seric ** copyf -- the copy flag; passed to parse. 460294Seric ** 461294Seric ** Returns: 462294Seric ** none 463294Seric ** 464294Seric ** Side Effects: 465294Seric ** none. 466294Seric ** 467294Seric ** Requires: 468294Seric ** parse 469294Seric ** recipient 470294Seric ** 471294Seric ** Called By: 472294Seric ** main 473294Seric ** alias 474294Seric ** 475294Seric ** History: 476294Seric ** 1/11/80 -- written. 477294Seric */ 478294Seric 479294Seric sendto(list, copyf) 480294Seric char *list; 481294Seric int copyf; 482294Seric { 483294Seric register char *p; 484294Seric register char *q; 485294Seric register char c; 486294Seric addrq *a; 487294Seric extern addrq *parse(); 488294Seric bool more; 489294Seric 490294Seric /* more keeps track of what the previous delimiter was */ 491294Seric more = TRUE; 492294Seric for (p = list; more; ) 493294Seric { 494294Seric /* find the end of this address */ 495294Seric q = p; 496294Seric while ((c = *p++) != '\0' && c != ',' && c != '\n') 497294Seric continue; 498294Seric more = c != '\0'; 499294Seric *--p = '\0'; 500294Seric if (more) 501294Seric p++; 502294Seric 503294Seric /* parse the address */ 504294Seric if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) 505294Seric continue; 506294Seric 507294Seric /* arrange to send to this person */ 508294Seric recipient(a, &SendQ); 509294Seric } 510294Seric To = NULL; 511294Seric } 512294Seric /* 513294Seric ** RECIPIENT -- Designate a message recipient 514294Seric ** 515294Seric ** Saves the named person for future mailing. 516294Seric ** 517294Seric ** Designates a person as a recipient. This routine 518294Seric ** does the initial parsing, and checks to see if 519294Seric ** this person has already received the mail. 520294Seric ** It also supresses local network names and turns them into 521294Seric ** local names. 522294Seric ** 523294Seric ** Parameters: 524294Seric ** a -- the (preparsed) address header for the recipient. 525294Seric ** targetq -- the queue to add the name to. 526294Seric ** 527294Seric ** Returns: 528294Seric ** none. 529294Seric ** 530294Seric ** Side Effects: 531294Seric ** none. 532294Seric ** 533294Seric ** Requires: 534294Seric ** sameaddr 535294Seric ** parse 536294Seric ** forward 537294Seric ** printf (sys) 538294Seric ** strcmp (sys) 539294Seric ** nxtinq 540294Seric ** putonq 541294Seric ** 542294Seric ** Called By: 543294Seric ** sendto 544294Seric ** main 545294Seric ** 546294Seric ** History: 547294Seric ** 3/5/80 -- modified to know about new internal form 548294Seric ** for addresses. 549294Seric ** 12/31/79 -- written. 550294Seric */ 551294Seric 552294Seric recipient(a, targetq) 553294Seric register addrq *a; 554294Seric addrq *targetq; 555294Seric { 556294Seric register addrq *q; 557294Seric register struct mailer *m; 558294Seric register char **pvp; 559294Seric extern char *xalloc(); 560294Seric extern bool forward(); 561294Seric extern int errno; 562294Seric extern bool sameaddr(); 563294Seric 564294Seric To = a->q_paddr; 565294Seric m = a->q_mailer; 566294Seric errno = 0; 567294Seric # ifdef DEBUG 568294Seric if (Debug) 569294Seric printf("recipient(%s)\n", To); 570294Seric # endif DEBUG 571294Seric 572294Seric /* 573294Seric ** Don't go to the net if already on the target host. 574294Seric ** This is important on the berkeley network, since 575294Seric ** it get confused if we ask to send to ourselves. 576294Seric ** For nets like the ARPANET, we probably will have 577294Seric ** the local list set to NULL to simplify testing. 578294Seric ** The canonical representation of the name is also set 579294Seric ** to be just the local name so the duplicate letter 580294Seric ** suppression algorithm will work. 581294Seric */ 582294Seric 583294Seric if ((pvp = m->m_local) != NULL) 584294Seric { 585294Seric while (*pvp != NULL) 586294Seric { 587294Seric if (strcmp(*pvp++, a->q_host) == 0) 588294Seric { 589294Seric a->q_mailer = m = &Mailer[0]; 590294Seric break; 591294Seric } 592294Seric } 593294Seric } 594294Seric 595294Seric /* 596294Seric ** Look up this person in the recipient list. If they 597294Seric ** are there already, return, otherwise continue. 598294Seric */ 599294Seric 600294Seric if (!ForceMail) 601294Seric { 602294Seric for (q = &SendQ; (q = nxtinq(q)) != NULL; ) 603294Seric if (sameaddr(q, a, FALSE)) 604294Seric { 605294Seric # ifdef DEBUG 606294Seric if (Debug) 607294Seric printf("(%s in SendQ)\n", a->q_paddr); 608294Seric # endif DEBUG 609294Seric return; 610294Seric } 611294Seric for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) 612294Seric if (sameaddr(q, a, FALSE)) 613294Seric { 614294Seric # ifdef DEBUG 615294Seric if (Debug) 616294Seric printf("(%s in AliasQ)\n", a->q_paddr); 617294Seric # endif DEBUG 618294Seric return; 619294Seric } 620294Seric } 621294Seric 622294Seric /* 623294Seric ** See if the user wants hir mail forwarded. 624294Seric ** `Forward' must do the forwarding recursively. 625294Seric */ 626294Seric 627294Seric if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) 628294Seric return; 629294Seric 630294Seric /* 631294Seric ** Put the user onto the target queue. 632294Seric */ 633294Seric 634294Seric if (targetq != NULL) 635294Seric { 636294Seric putonq(a, targetq); 637294Seric } 638294Seric 639294Seric return; 640294Seric } 641294Seric /* 642294Seric ** BUILDARGV -- Build an argument vector for a mail server. 643294Seric ** 644294Seric ** Using a template defined in config.c, an argv is built. 645294Seric ** The format of the template is already a vector. The 646294Seric ** items of this vector are copied, unless a dollar sign 647294Seric ** is encountered. In this case, the next character 648294Seric ** specifies something else to copy in. These can be 649294Seric ** $f The from address. 650294Seric ** $h The host. 651294Seric ** $u The user. 652294Seric ** $c The hop count. 653294Seric ** The vector is built in a local buffer. A pointer to 654294Seric ** the static argv is returned. 655294Seric ** 656294Seric ** Parameters: 657294Seric ** tmplt -- a template for an argument vector. 658294Seric ** flags -- the flags for this server. 659294Seric ** host -- the host name to send to. 660294Seric ** user -- the user name to send to. 661294Seric ** from -- the person this mail is from. 662294Seric ** 663294Seric ** Returns: 664294Seric ** A pointer to an argv. 665294Seric ** 666294Seric ** Side Effects: 667294Seric ** none 668294Seric ** 669294Seric ** WARNING: 670294Seric ** Since the argv is staticly allocated, any subsequent 671294Seric ** calls will clobber the old argv. 672294Seric ** 673294Seric ** Requires: 674294Seric ** printf (sys) 675294Seric ** sprintf (sys) 676294Seric ** flagset 677294Seric ** syserr 678294Seric ** 679294Seric ** Called By: 680294Seric ** deliver 681294Seric ** 682294Seric ** History: 683294Seric ** 12/26/79 -- written. 684294Seric */ 685294Seric 686294Seric char ** 687294Seric buildargv(tmplt, flags, host, user, from) 688294Seric char **tmplt; 689294Seric int flags; 690294Seric char *host; 691294Seric char *user; 692294Seric char *from; 693294Seric { 694294Seric register char *p; 695294Seric register char *q; 696294Seric static char *pv[MAXPV+1]; 697294Seric char **pvp; 698294Seric char **mvp; 699294Seric static char buf[512]; 700294Seric register char *bp; 701294Seric char pbuf[30]; 702294Seric 703294Seric /* 704294Seric ** Do initial argv setup. 705294Seric ** Insert the mailer name. Notice that $x expansion is 706294Seric ** NOT done on the mailer name. Then, if the mailer has 707294Seric ** a picky -f flag, we insert it as appropriate. This 708294Seric ** code does not check for 'pv' overflow; this places a 709294Seric ** manifest lower limit of 4 for MAXPV. 710294Seric */ 711294Seric 712294Seric pvp = pv; 713294Seric bp = buf; 714294Seric 715294Seric *pvp++ = tmplt[0]; 716294Seric 717294Seric /* insert -f or -r flag as appropriate */ 718294Seric if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) 719294Seric { 720294Seric if (flagset(M_FOPT, flags)) 721294Seric *pvp++ = "-f"; 722294Seric else 723294Seric *pvp++ = "-r"; 724294Seric *pvp++ = From.q_paddr; 725294Seric } 726294Seric 727294Seric /* 728294Seric ** Build the rest of argv. 729294Seric ** For each prototype parameter, the prototype is 730294Seric ** scanned character at a time. If a dollar-sign is 731294Seric ** found, 'q' is set to the appropriate expansion, 732294Seric ** otherwise it is null. Then either the string 733294Seric ** pointed to by q, or the original character, is 734294Seric ** interpolated into the buffer. Buffer overflow is 735294Seric ** checked. 736294Seric */ 737294Seric 738294Seric for (mvp = tmplt; (p = *++mvp) != NULL; ) 739294Seric { 740294Seric if (pvp >= &pv[MAXPV]) 741294Seric { 742294Seric syserr("Too many parameters to %s", pv[0]); 743294Seric return (NULL); 744294Seric } 745294Seric *pvp++ = bp; 746294Seric for (; *p != '\0'; p++) 747294Seric { 748294Seric /* q will be the interpolated quantity */ 749294Seric q = NULL; 750294Seric if (*p == '$') 751294Seric { 752294Seric switch (*++p) 753294Seric { 754294Seric case 'f': /* from person */ 755294Seric q = from; 756294Seric break; 757294Seric 758294Seric case 'u': /* user */ 759294Seric q = user; 760294Seric break; 761294Seric 762294Seric case 'h': /* host */ 763294Seric q = host; 764294Seric break; 765294Seric 766294Seric case 'c': /* hop count */ 767294Seric sprintf(pbuf, "%d", HopCount); 768294Seric q = pbuf; 769294Seric break; 770294Seric } 771294Seric } 772294Seric 773294Seric /* 774294Seric ** Interpolate q or output one character 775294Seric ** Strip quote bits as we proceed..... 776294Seric */ 777294Seric 778294Seric if (q != NULL) 779294Seric { 780294Seric while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') 781294Seric continue; 782294Seric bp--; 783294Seric } 784294Seric else if (bp < &buf[sizeof buf - 1]) 785294Seric *bp++ = *p; 786294Seric } 787294Seric *bp++ = '\0'; 788294Seric if (bp >= &buf[sizeof buf - 1]) 789294Seric return (NULL); 790294Seric } 791294Seric *pvp = NULL; 792294Seric 793294Seric # ifdef DEBUG 794294Seric if (Debug) 795294Seric { 796294Seric printf("Interpolated argv is:\n"); 797294Seric for (mvp = pv; *mvp != NULL; mvp++) 798294Seric printf("\t%s\n", *mvp); 799294Seric } 800294Seric # endif DEBUG 801294Seric 802294Seric return (pv); 803294Seric } 804294Seric /* 805294Seric ** MAILFILE -- Send a message to a file. 806294Seric ** 807294Seric ** Parameters: 808294Seric ** filename -- the name of the file to send to. 809294Seric ** 810294Seric ** Returns: 811294Seric ** The exit code associated with the operation. 812294Seric ** 813294Seric ** Side Effects: 814294Seric ** none. 815294Seric ** 816294Seric ** Requires: 817294Seric ** fgets (sys) 818294Seric ** fputs (sys) 819294Seric ** fprintf (sys) 820294Seric ** fopen (sys) 821294Seric ** fclose (sys) 822294Seric ** ferror (sys) 823294Seric ** time (sys) 824294Seric ** ctime (sys) 825294Seric ** rewind (sys) 826294Seric ** 827294Seric ** Called By: 828294Seric ** deliver 829294Seric ** 830294Seric ** History: 831294Seric ** 3/5/80 -- written. 832294Seric */ 833294Seric 834294Seric mailfile(filename) 835294Seric char *filename; 836294Seric { 837294Seric char buf[MAXLINE]; 838294Seric register FILE *f; 839294Seric auto long tim; 840294Seric extern char *ctime(); 841294Seric 842294Seric f = fopen(filename, "a"); 843294Seric if (f == NULL) 844294Seric return (EX_CANTCREAT); 845294Seric 846294Seric /* output the timestamp */ 847294Seric time(&tim); 848294Seric fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); 849294Seric rewind(stdin); 850294Seric while (fgets(buf, sizeof buf, stdin) != NULL) 851294Seric { 852294Seric fputs(buf, f); 853294Seric if (ferror(f)) 854294Seric { 855294Seric fclose(f); 856294Seric return (EX_IOERR); 857294Seric } 858294Seric } 859294Seric fputs("\n", f); 860294Seric fclose(f); 861294Seric return (EX_OK); 862294Seric } 863