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