1*294Seric # include <stdio.h> 2*294Seric # include <pwd.h> 3*294Seric # include <signal.h> 4*294Seric # include "dlvrmail.h" 5*294Seric # ifdef LOG 6*294Seric # include <log.h> 7*294Seric # endif LOG 8*294Seric 9*294Seric /* 10*294Seric ** DELIVER -- Deliver a message to a particular address. 11*294Seric ** 12*294Seric ** Algorithm: 13*294Seric ** Compute receiving network (i.e., mailer), host, & user. 14*294Seric ** If local, see if this is really a program name. 15*294Seric ** Build argument for the mailer. 16*294Seric ** Create pipe through edit fcn if appropriate. 17*294Seric ** Fork. 18*294Seric ** Child: call mailer 19*294Seric ** Parent: call editfcn if specified. 20*294Seric ** Wait for mailer to finish. 21*294Seric ** Interpret exit status. 22*294Seric ** 23*294Seric ** Parameters: 24*294Seric ** to -- the address to deliver the message to. 25*294Seric ** editfcn -- if non-NULL, we want to call this function 26*294Seric ** to output the letter (instead of just out- 27*294Seric ** putting it raw). 28*294Seric ** 29*294Seric ** Returns: 30*294Seric ** zero -- successfully delivered. 31*294Seric ** else -- some failure, see ExitStat for more info. 32*294Seric ** 33*294Seric ** Side Effects: 34*294Seric ** The standard input is passed off to someone. 35*294Seric ** 36*294Seric ** WARNING: 37*294Seric ** The standard input is shared amongst all children, 38*294Seric ** including the file pointer. It is critical that the 39*294Seric ** parent waits for the child to finish before forking 40*294Seric ** another child. 41*294Seric ** 42*294Seric ** Requires: 43*294Seric ** buildargv 44*294Seric ** giveresponse 45*294Seric ** fork (sys) 46*294Seric ** rewind (sys) 47*294Seric ** execv (sys) 48*294Seric ** exit (sys) 49*294Seric ** wait (sys) 50*294Seric ** syserr 51*294Seric ** getpwnam (sys) 52*294Seric ** endpwent (sys) 53*294Seric ** initlog 54*294Seric ** flagset 55*294Seric ** usrerr 56*294Seric ** pipe (sys) 57*294Seric ** close (sys) 58*294Seric ** dup (sys) 59*294Seric ** setuid (sys) 60*294Seric ** getuid (sys) 61*294Seric ** signal (sys) 62*294Seric ** fdopen (sys[v7] or conf.c[v6]) 63*294Seric ** fclose (sys) 64*294Seric ** printf (sys) 65*294Seric ** stripquotes 66*294Seric ** mailfile 67*294Seric ** index (sys) 68*294Seric ** 69*294Seric ** Called By: 70*294Seric ** main 71*294Seric ** savemail 72*294Seric ** 73*294Seric ** Files: 74*294Seric ** standard input -- must be openned to the message to 75*294Seric ** deliver. 76*294Seric ** 77*294Seric ** History: 78*294Seric ** 3/5/80 -- modified rather extensively to change the 79*294Seric ** internal form of addresses. 80*294Seric ** 12/26/79 -- written. 81*294Seric */ 82*294Seric 83*294Seric deliver(to, editfcn) 84*294Seric addrq *to; 85*294Seric int (*editfcn)(); 86*294Seric { 87*294Seric register struct mailer *m; 88*294Seric char *host; 89*294Seric char *user; 90*294Seric extern struct passwd *getpwnam(); 91*294Seric char **pvp; 92*294Seric extern char **buildargv(); 93*294Seric auto int st; 94*294Seric register int i; 95*294Seric register char *p; 96*294Seric int pid; 97*294Seric int pvect[2]; 98*294Seric extern FILE *fdopen(); 99*294Seric extern int errno; 100*294Seric FILE *mfile; 101*294Seric extern putheader(); 102*294Seric extern pipesig(); 103*294Seric 104*294Seric /* 105*294Seric ** Compute receiving mailer, host, and to addreses. 106*294Seric ** Do some initialization first. To is the to address 107*294Seric ** for error messages. 108*294Seric */ 109*294Seric 110*294Seric To = to->q_paddr; 111*294Seric m = to->q_mailer; 112*294Seric user = to->q_user; 113*294Seric host = to->q_host; 114*294Seric Error = 0; 115*294Seric errno = 0; 116*294Seric # ifdef DEBUG 117*294Seric if (Debug) 118*294Seric printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); 119*294Seric # endif DEBUG 120*294Seric 121*294Seric /* 122*294Seric ** Remove quote bits from user/host. 123*294Seric */ 124*294Seric 125*294Seric for (p = user; (*p++ &= 0177) != '\0'; ) 126*294Seric continue; 127*294Seric if (host != NULL) 128*294Seric for (p = host; (*p++ &= 0177) != '\0'; ) 129*294Seric continue; 130*294Seric 131*294Seric /* 132*294Seric ** Strip quote bits from names if the mailer wants it. 133*294Seric */ 134*294Seric 135*294Seric if (flagset(M_STRIPQ, m->m_flags)) 136*294Seric { 137*294Seric stripquotes(user); 138*294Seric stripquotes(host); 139*294Seric } 140*294Seric 141*294Seric /* 142*294Seric ** See if this user name is "special". 143*294Seric ** If the user is a program, diddle with the mailer spec. 144*294Seric ** If the user name has a slash in it, assume that this 145*294Seric ** is a file -- send it off without further ado. 146*294Seric ** Note that this means that editfcn's will not 147*294Seric ** be applied to the message. 148*294Seric */ 149*294Seric 150*294Seric if (m == &Mailer[0]) 151*294Seric { 152*294Seric if (*user == '|') 153*294Seric { 154*294Seric user++; 155*294Seric m = &Mailer[1]; 156*294Seric } 157*294Seric else 158*294Seric { 159*294Seric if (index(user, '/') != NULL) 160*294Seric { 161*294Seric i = mailfile(user); 162*294Seric giveresponse(i, TRUE, m); 163*294Seric return (i); 164*294Seric } 165*294Seric } 166*294Seric } 167*294Seric 168*294Seric # ifdef BADMAIL 169*294Seric /* 170*294Seric ** If the mailer doesn't return the proper 171*294Seric ** exit statuses, check here to see if the 172*294Seric ** user exists so that we can give a pretty 173*294Seric ** error message. 174*294Seric */ 175*294Seric 176*294Seric if (m == &Mailer[0]) 177*294Seric { 178*294Seric if (getpwnam(user) == NULL) 179*294Seric { 180*294Seric giveresponse(EX_NOUSER, TRUE, m); 181*294Seric return (EX_NOUSER); 182*294Seric } 183*294Seric } 184*294Seric # endif BADMAIL 185*294Seric 186*294Seric /* 187*294Seric ** If the mailer wants a From line, insert a new editfcn. 188*294Seric */ 189*294Seric 190*294Seric if (flagset(M_HDR, m->m_flags) && editfcn == NULL) 191*294Seric editfcn = putheader; 192*294Seric 193*294Seric /* 194*294Seric ** Call the mailer. 195*294Seric ** The argument vector gets built, pipes through 'editfcn' 196*294Seric ** are created as necessary, and we fork & exec as 197*294Seric ** appropriate. In the parent, we call 'editfcn'. 198*294Seric */ 199*294Seric 200*294Seric pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr); 201*294Seric if (pvp == NULL) 202*294Seric { 203*294Seric usrerr("name too long"); 204*294Seric return (-1); 205*294Seric } 206*294Seric rewind(stdin); 207*294Seric 208*294Seric /* create a pipe if we will need one */ 209*294Seric if (editfcn != NULL && pipe(pvect) < 0) 210*294Seric { 211*294Seric syserr("pipe"); 212*294Seric return (-1); 213*294Seric } 214*294Seric pid = fork(); 215*294Seric if (pid < 0) 216*294Seric { 217*294Seric syserr("Cannot fork"); 218*294Seric if (editfcn != NULL) 219*294Seric { 220*294Seric close(pvect[0]); 221*294Seric close(pvect[1]); 222*294Seric } 223*294Seric return (-1); 224*294Seric } 225*294Seric else if (pid == 0) 226*294Seric { 227*294Seric /* child -- set up input & exec mailer */ 228*294Seric signal(SIGINT, SIG_IGN); 229*294Seric if (editfcn != NULL) 230*294Seric { 231*294Seric close(0); 232*294Seric if (dup(pvect[0]) < 0) 233*294Seric { 234*294Seric syserr("Cannot dup to zero!"); 235*294Seric exit(EX_OSERR); 236*294Seric } 237*294Seric close(pvect[0]); 238*294Seric close(pvect[1]); 239*294Seric } 240*294Seric if (!flagset(M_RESTR, m->m_flags)) 241*294Seric setuid(getuid()); 242*294Seric # ifdef LOG 243*294Seric initlog(NULL, 0, LOG_CLOSE); 244*294Seric # endif LOG 245*294Seric endpwent(); 246*294Seric execv(m->m_mailer, pvp); 247*294Seric /* syserr fails because log is closed */ 248*294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 249*294Seric exit(EX_UNAVAIL); 250*294Seric } 251*294Seric 252*294Seric /* arrange to write out header message if error */ 253*294Seric if (editfcn != NULL) 254*294Seric { 255*294Seric close(pvect[0]); 256*294Seric signal(SIGPIPE, pipesig); 257*294Seric mfile = fdopen(pvect[1], "w"); 258*294Seric (*editfcn)(mfile); 259*294Seric fclose(mfile); 260*294Seric } 261*294Seric 262*294Seric /* 263*294Seric ** Wait for child to die and report status. 264*294Seric ** We should never get fatal errors (e.g., segmentation 265*294Seric ** violation), so we report those specially. For other 266*294Seric ** errors, we choose a status message (into statmsg), 267*294Seric ** and if it represents an error, we print it. 268*294Seric */ 269*294Seric 270*294Seric while ((i = wait(&st)) > 0 && i != pid) 271*294Seric continue; 272*294Seric if (i < 0) 273*294Seric { 274*294Seric syserr("wait"); 275*294Seric return (-1); 276*294Seric } 277*294Seric if ((st & 0377) != 0) 278*294Seric { 279*294Seric syserr("%s: stat %o", pvp[0], st); 280*294Seric ExitStat = EX_UNAVAIL; 281*294Seric return (-1); 282*294Seric } 283*294Seric i = (st >> 8) & 0377; 284*294Seric giveresponse(i, FALSE, m); 285*294Seric return (i); 286*294Seric } 287*294Seric /* 288*294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 289*294Seric ** 290*294Seric ** Parameters: 291*294Seric ** stat -- the status code from the mailer (high byte 292*294Seric ** only; core dumps must have been taken care of 293*294Seric ** already). 294*294Seric ** force -- if set, force an error message output, even 295*294Seric ** if the mailer seems to like to print its own 296*294Seric ** messages. 297*294Seric ** m -- the mailer descriptor for this mailer. 298*294Seric ** 299*294Seric ** Returns: 300*294Seric ** none. 301*294Seric ** 302*294Seric ** Side Effects: 303*294Seric ** Error may be set. 304*294Seric ** ExitStat may be set. 305*294Seric ** 306*294Seric ** Requires: 307*294Seric ** usrerr 308*294Seric ** syserr 309*294Seric ** flagset 310*294Seric ** logmsg (sys) 311*294Seric ** 312*294Seric ** Called By: 313*294Seric ** deliver 314*294Seric ** 315*294Seric ** History: 316*294Seric ** 2/18/80 -- broken from deliver. 317*294Seric */ 318*294Seric 319*294Seric giveresponse(stat, force, m) 320*294Seric int stat; 321*294Seric int force; 322*294Seric register struct mailer *m; 323*294Seric { 324*294Seric register char *statmsg; 325*294Seric extern char *SysExMsg[]; 326*294Seric register int i; 327*294Seric extern int N_SysEx; 328*294Seric 329*294Seric i = stat - EX__BASE; 330*294Seric if (i < 0 || i > N_SysEx) 331*294Seric statmsg = NULL; 332*294Seric else 333*294Seric statmsg = SysExMsg[i]; 334*294Seric if (stat == 0) 335*294Seric statmsg = "ok"; 336*294Seric else 337*294Seric { 338*294Seric Error++; 339*294Seric if (statmsg == NULL && m->m_badstat != 0) 340*294Seric { 341*294Seric stat = m->m_badstat; 342*294Seric i = stat - EX__BASE; 343*294Seric # ifdef DEBUG 344*294Seric if (i < 0 || i >= N_SysEx) 345*294Seric syserr("Bad m_badstat %d", stat); 346*294Seric else 347*294Seric # endif DEBUG 348*294Seric statmsg = SysExMsg[i]; 349*294Seric } 350*294Seric if (statmsg == NULL) 351*294Seric usrerr("unknown mailer response %d", stat); 352*294Seric else if (force || !flagset(M_QUIET, m->m_flags)) 353*294Seric usrerr("%s", statmsg); 354*294Seric } 355*294Seric 356*294Seric /* 357*294Seric ** Final cleanup. 358*294Seric ** Log a record of the transaction. Compute the new 359*294Seric ** ExitStat -- if we already had an error, stick with 360*294Seric ** that. 361*294Seric */ 362*294Seric 363*294Seric # ifdef LOG 364*294Seric if (statmsg == NULL) 365*294Seric logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat); 366*294Seric else 367*294Seric logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg); 368*294Seric # endif LOG 369*294Seric if (ExitStat == EX_OK) 370*294Seric ExitStat = stat; 371*294Seric return (stat); 372*294Seric } 373*294Seric /* 374*294Seric ** PUTHEADER -- insert the From header into some mail 375*294Seric ** 376*294Seric ** For mailers such as 'msgs' that want the header inserted 377*294Seric ** into the mail, this edit filter inserts the From line and 378*294Seric ** then passes the rest of the message through. 379*294Seric ** 380*294Seric ** Parameters: 381*294Seric ** fp -- the file pointer for the output. 382*294Seric ** 383*294Seric ** Returns: 384*294Seric ** none 385*294Seric ** 386*294Seric ** Side Effects: 387*294Seric ** Puts a "From" line in UNIX format, and then 388*294Seric ** outputs the rest of the message. 389*294Seric ** 390*294Seric ** Requires: 391*294Seric ** fprintf (sys) 392*294Seric ** fgets (sys) 393*294Seric ** fputs (sys) 394*294Seric ** time (sys) 395*294Seric ** ctime (sys) 396*294Seric ** ferror (sys) 397*294Seric ** syserr 398*294Seric ** setstat 399*294Seric ** 400*294Seric ** Called By: 401*294Seric ** deliver 402*294Seric ** 403*294Seric ** History: 404*294Seric ** 1/8/80 -- written. 405*294Seric */ 406*294Seric 407*294Seric putheader(fp) 408*294Seric register FILE *fp; 409*294Seric { 410*294Seric char buf[MAXLINE + 1]; 411*294Seric long tim; 412*294Seric extern char *ctime(); 413*294Seric 414*294Seric time(&tim); 415*294Seric fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); 416*294Seric while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) 417*294Seric fputs(buf, fp); 418*294Seric if (ferror(fp)) 419*294Seric { 420*294Seric syserr("putheader: write error"); 421*294Seric setstat(EX_IOERR); 422*294Seric } 423*294Seric } 424*294Seric /* 425*294Seric ** PIPESIG -- Handle broken pipe signals 426*294Seric ** 427*294Seric ** This just logs an error. 428*294Seric ** 429*294Seric ** Parameters: 430*294Seric ** none 431*294Seric ** 432*294Seric ** Returns: 433*294Seric ** none 434*294Seric ** 435*294Seric ** Side Effects: 436*294Seric ** logs an error message. 437*294Seric ** 438*294Seric ** Requires: 439*294Seric ** syserr 440*294Seric ** 441*294Seric ** History: 442*294Seric ** 1/17/80 -- written. 443*294Seric */ 444*294Seric 445*294Seric pipesig() 446*294Seric { 447*294Seric syserr("Broken pipe"); 448*294Seric } 449*294Seric /* 450*294Seric ** SENDTO -- Designate a send list. 451*294Seric ** 452*294Seric ** The parameter is a comma-separated list of people to send to. 453*294Seric ** This routine arranges to send to all of them. 454*294Seric ** 455*294Seric ** Parameters: 456*294Seric ** list -- the send list. 457*294Seric ** copyf -- the copy flag; passed to parse. 458*294Seric ** 459*294Seric ** Returns: 460*294Seric ** none 461*294Seric ** 462*294Seric ** Side Effects: 463*294Seric ** none. 464*294Seric ** 465*294Seric ** Requires: 466*294Seric ** parse 467*294Seric ** recipient 468*294Seric ** 469*294Seric ** Called By: 470*294Seric ** main 471*294Seric ** alias 472*294Seric ** 473*294Seric ** History: 474*294Seric ** 1/11/80 -- written. 475*294Seric */ 476*294Seric 477*294Seric sendto(list, copyf) 478*294Seric char *list; 479*294Seric int copyf; 480*294Seric { 481*294Seric register char *p; 482*294Seric register char *q; 483*294Seric register char c; 484*294Seric addrq *a; 485*294Seric extern addrq *parse(); 486*294Seric bool more; 487*294Seric 488*294Seric /* more keeps track of what the previous delimiter was */ 489*294Seric more = TRUE; 490*294Seric for (p = list; more; ) 491*294Seric { 492*294Seric /* find the end of this address */ 493*294Seric q = p; 494*294Seric while ((c = *p++) != '\0' && c != ',' && c != '\n') 495*294Seric continue; 496*294Seric more = c != '\0'; 497*294Seric *--p = '\0'; 498*294Seric if (more) 499*294Seric p++; 500*294Seric 501*294Seric /* parse the address */ 502*294Seric if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) 503*294Seric continue; 504*294Seric 505*294Seric /* arrange to send to this person */ 506*294Seric recipient(a, &SendQ); 507*294Seric } 508*294Seric To = NULL; 509*294Seric } 510*294Seric /* 511*294Seric ** RECIPIENT -- Designate a message recipient 512*294Seric ** 513*294Seric ** Saves the named person for future mailing. 514*294Seric ** 515*294Seric ** Designates a person as a recipient. This routine 516*294Seric ** does the initial parsing, and checks to see if 517*294Seric ** this person has already received the mail. 518*294Seric ** It also supresses local network names and turns them into 519*294Seric ** local names. 520*294Seric ** 521*294Seric ** Parameters: 522*294Seric ** a -- the (preparsed) address header for the recipient. 523*294Seric ** targetq -- the queue to add the name to. 524*294Seric ** 525*294Seric ** Returns: 526*294Seric ** none. 527*294Seric ** 528*294Seric ** Side Effects: 529*294Seric ** none. 530*294Seric ** 531*294Seric ** Requires: 532*294Seric ** sameaddr 533*294Seric ** parse 534*294Seric ** forward 535*294Seric ** printf (sys) 536*294Seric ** strcmp (sys) 537*294Seric ** nxtinq 538*294Seric ** putonq 539*294Seric ** 540*294Seric ** Called By: 541*294Seric ** sendto 542*294Seric ** main 543*294Seric ** 544*294Seric ** History: 545*294Seric ** 3/5/80 -- modified to know about new internal form 546*294Seric ** for addresses. 547*294Seric ** 12/31/79 -- written. 548*294Seric */ 549*294Seric 550*294Seric recipient(a, targetq) 551*294Seric register addrq *a; 552*294Seric addrq *targetq; 553*294Seric { 554*294Seric register addrq *q; 555*294Seric register struct mailer *m; 556*294Seric register char **pvp; 557*294Seric extern char *xalloc(); 558*294Seric extern bool forward(); 559*294Seric extern int errno; 560*294Seric extern bool sameaddr(); 561*294Seric 562*294Seric To = a->q_paddr; 563*294Seric m = a->q_mailer; 564*294Seric errno = 0; 565*294Seric # ifdef DEBUG 566*294Seric if (Debug) 567*294Seric printf("recipient(%s)\n", To); 568*294Seric # endif DEBUG 569*294Seric 570*294Seric /* 571*294Seric ** Don't go to the net if already on the target host. 572*294Seric ** This is important on the berkeley network, since 573*294Seric ** it get confused if we ask to send to ourselves. 574*294Seric ** For nets like the ARPANET, we probably will have 575*294Seric ** the local list set to NULL to simplify testing. 576*294Seric ** The canonical representation of the name is also set 577*294Seric ** to be just the local name so the duplicate letter 578*294Seric ** suppression algorithm will work. 579*294Seric */ 580*294Seric 581*294Seric if ((pvp = m->m_local) != NULL) 582*294Seric { 583*294Seric while (*pvp != NULL) 584*294Seric { 585*294Seric if (strcmp(*pvp++, a->q_host) == 0) 586*294Seric { 587*294Seric a->q_mailer = m = &Mailer[0]; 588*294Seric break; 589*294Seric } 590*294Seric } 591*294Seric } 592*294Seric 593*294Seric /* 594*294Seric ** Look up this person in the recipient list. If they 595*294Seric ** are there already, return, otherwise continue. 596*294Seric */ 597*294Seric 598*294Seric if (!ForceMail) 599*294Seric { 600*294Seric for (q = &SendQ; (q = nxtinq(q)) != NULL; ) 601*294Seric if (sameaddr(q, a, FALSE)) 602*294Seric { 603*294Seric # ifdef DEBUG 604*294Seric if (Debug) 605*294Seric printf("(%s in SendQ)\n", a->q_paddr); 606*294Seric # endif DEBUG 607*294Seric return; 608*294Seric } 609*294Seric for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) 610*294Seric if (sameaddr(q, a, FALSE)) 611*294Seric { 612*294Seric # ifdef DEBUG 613*294Seric if (Debug) 614*294Seric printf("(%s in AliasQ)\n", a->q_paddr); 615*294Seric # endif DEBUG 616*294Seric return; 617*294Seric } 618*294Seric } 619*294Seric 620*294Seric /* 621*294Seric ** See if the user wants hir mail forwarded. 622*294Seric ** `Forward' must do the forwarding recursively. 623*294Seric */ 624*294Seric 625*294Seric if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) 626*294Seric return; 627*294Seric 628*294Seric /* 629*294Seric ** Put the user onto the target queue. 630*294Seric */ 631*294Seric 632*294Seric if (targetq != NULL) 633*294Seric { 634*294Seric putonq(a, targetq); 635*294Seric } 636*294Seric 637*294Seric return; 638*294Seric } 639*294Seric /* 640*294Seric ** BUILDARGV -- Build an argument vector for a mail server. 641*294Seric ** 642*294Seric ** Using a template defined in config.c, an argv is built. 643*294Seric ** The format of the template is already a vector. The 644*294Seric ** items of this vector are copied, unless a dollar sign 645*294Seric ** is encountered. In this case, the next character 646*294Seric ** specifies something else to copy in. These can be 647*294Seric ** $f The from address. 648*294Seric ** $h The host. 649*294Seric ** $u The user. 650*294Seric ** $c The hop count. 651*294Seric ** The vector is built in a local buffer. A pointer to 652*294Seric ** the static argv is returned. 653*294Seric ** 654*294Seric ** Parameters: 655*294Seric ** tmplt -- a template for an argument vector. 656*294Seric ** flags -- the flags for this server. 657*294Seric ** host -- the host name to send to. 658*294Seric ** user -- the user name to send to. 659*294Seric ** from -- the person this mail is from. 660*294Seric ** 661*294Seric ** Returns: 662*294Seric ** A pointer to an argv. 663*294Seric ** 664*294Seric ** Side Effects: 665*294Seric ** none 666*294Seric ** 667*294Seric ** WARNING: 668*294Seric ** Since the argv is staticly allocated, any subsequent 669*294Seric ** calls will clobber the old argv. 670*294Seric ** 671*294Seric ** Requires: 672*294Seric ** printf (sys) 673*294Seric ** sprintf (sys) 674*294Seric ** flagset 675*294Seric ** syserr 676*294Seric ** 677*294Seric ** Called By: 678*294Seric ** deliver 679*294Seric ** 680*294Seric ** History: 681*294Seric ** 12/26/79 -- written. 682*294Seric */ 683*294Seric 684*294Seric char ** 685*294Seric buildargv(tmplt, flags, host, user, from) 686*294Seric char **tmplt; 687*294Seric int flags; 688*294Seric char *host; 689*294Seric char *user; 690*294Seric char *from; 691*294Seric { 692*294Seric register char *p; 693*294Seric register char *q; 694*294Seric static char *pv[MAXPV+1]; 695*294Seric char **pvp; 696*294Seric char **mvp; 697*294Seric static char buf[512]; 698*294Seric register char *bp; 699*294Seric char pbuf[30]; 700*294Seric 701*294Seric /* 702*294Seric ** Do initial argv setup. 703*294Seric ** Insert the mailer name. Notice that $x expansion is 704*294Seric ** NOT done on the mailer name. Then, if the mailer has 705*294Seric ** a picky -f flag, we insert it as appropriate. This 706*294Seric ** code does not check for 'pv' overflow; this places a 707*294Seric ** manifest lower limit of 4 for MAXPV. 708*294Seric */ 709*294Seric 710*294Seric pvp = pv; 711*294Seric bp = buf; 712*294Seric 713*294Seric *pvp++ = tmplt[0]; 714*294Seric 715*294Seric /* insert -f or -r flag as appropriate */ 716*294Seric if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) 717*294Seric { 718*294Seric if (flagset(M_FOPT, flags)) 719*294Seric *pvp++ = "-f"; 720*294Seric else 721*294Seric *pvp++ = "-r"; 722*294Seric *pvp++ = From.q_paddr; 723*294Seric } 724*294Seric 725*294Seric /* 726*294Seric ** Build the rest of argv. 727*294Seric ** For each prototype parameter, the prototype is 728*294Seric ** scanned character at a time. If a dollar-sign is 729*294Seric ** found, 'q' is set to the appropriate expansion, 730*294Seric ** otherwise it is null. Then either the string 731*294Seric ** pointed to by q, or the original character, is 732*294Seric ** interpolated into the buffer. Buffer overflow is 733*294Seric ** checked. 734*294Seric */ 735*294Seric 736*294Seric for (mvp = tmplt; (p = *++mvp) != NULL; ) 737*294Seric { 738*294Seric if (pvp >= &pv[MAXPV]) 739*294Seric { 740*294Seric syserr("Too many parameters to %s", pv[0]); 741*294Seric return (NULL); 742*294Seric } 743*294Seric *pvp++ = bp; 744*294Seric for (; *p != '\0'; p++) 745*294Seric { 746*294Seric /* q will be the interpolated quantity */ 747*294Seric q = NULL; 748*294Seric if (*p == '$') 749*294Seric { 750*294Seric switch (*++p) 751*294Seric { 752*294Seric case 'f': /* from person */ 753*294Seric q = from; 754*294Seric break; 755*294Seric 756*294Seric case 'u': /* user */ 757*294Seric q = user; 758*294Seric break; 759*294Seric 760*294Seric case 'h': /* host */ 761*294Seric q = host; 762*294Seric break; 763*294Seric 764*294Seric case 'c': /* hop count */ 765*294Seric sprintf(pbuf, "%d", HopCount); 766*294Seric q = pbuf; 767*294Seric break; 768*294Seric } 769*294Seric } 770*294Seric 771*294Seric /* 772*294Seric ** Interpolate q or output one character 773*294Seric ** Strip quote bits as we proceed..... 774*294Seric */ 775*294Seric 776*294Seric if (q != NULL) 777*294Seric { 778*294Seric while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') 779*294Seric continue; 780*294Seric bp--; 781*294Seric if (q[-2] == '"') 782*294Seric bp--; 783*294Seric } 784*294Seric else if (bp < &buf[sizeof buf - 1]) 785*294Seric *bp++ = *p; 786*294Seric } 787*294Seric *bp++ = '\0'; 788*294Seric if (bp >= &buf[sizeof buf - 1]) 789*294Seric return (NULL); 790*294Seric } 791*294Seric *pvp = NULL; 792*294Seric 793*294Seric # ifdef DEBUG 794*294Seric if (Debug) 795*294Seric { 796*294Seric printf("Interpolated argv is:\n"); 797*294Seric for (mvp = pv; *mvp != NULL; mvp++) 798*294Seric printf("\t%s\n", *mvp); 799*294Seric } 800*294Seric # endif DEBUG 801*294Seric 802*294Seric return (pv); 803*294Seric } 804*294Seric /* 805*294Seric ** MAILFILE -- Send a message to a file. 806*294Seric ** 807*294Seric ** Parameters: 808*294Seric ** filename -- the name of the file to send to. 809*294Seric ** 810*294Seric ** Returns: 811*294Seric ** The exit code associated with the operation. 812*294Seric ** 813*294Seric ** Side Effects: 814*294Seric ** none. 815*294Seric ** 816*294Seric ** Requires: 817*294Seric ** fgets (sys) 818*294Seric ** fputs (sys) 819*294Seric ** fprintf (sys) 820*294Seric ** fopen (sys) 821*294Seric ** fclose (sys) 822*294Seric ** ferror (sys) 823*294Seric ** time (sys) 824*294Seric ** ctime (sys) 825*294Seric ** rewind (sys) 826*294Seric ** 827*294Seric ** Called By: 828*294Seric ** deliver 829*294Seric ** 830*294Seric ** History: 831*294Seric ** 3/5/80 -- written. 832*294Seric */ 833*294Seric 834*294Seric mailfile(filename) 835*294Seric char *filename; 836*294Seric { 837*294Seric char buf[MAXLINE]; 838*294Seric register FILE *f; 839*294Seric auto long tim; 840*294Seric extern char *ctime(); 841*294Seric 842*294Seric f = fopen(filename, "a"); 843*294Seric if (f == NULL) 844*294Seric return (EX_CANTCREAT); 845*294Seric 846*294Seric /* output the timestamp */ 847*294Seric time(&tim); 848*294Seric fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); 849*294Seric rewind(stdin); 850*294Seric while (fgets(buf, sizeof buf, stdin) != NULL) 851*294Seric { 852*294Seric fputs(buf, f); 853*294Seric if (ferror(f)) 854*294Seric { 855*294Seric fclose(f); 856*294Seric return (EX_IOERR); 857*294Seric } 858*294Seric } 859*294Seric fputs("\n", f); 860*294Seric fclose(f); 861*294Seric return (EX_OK); 862*294Seric } 863