125a99e2eSeric # include <stdio.h> 225a99e2eSeric # include <pwd.h> 325a99e2eSeric # include <signal.h> 4*6328bdf7Seric # include <ctype.h> 525a99e2eSeric # include "dlvrmail.h" 625a99e2eSeric # ifdef LOG 7e374fd72Seric # include <syslog.h> 825a99e2eSeric # endif LOG 925a99e2eSeric 10*6328bdf7Seric static char SccsId[] = "@(#)deliver.c 3.1 03/04/81"; 11259cace7Seric 1225a99e2eSeric /* 1325a99e2eSeric ** DELIVER -- Deliver a message to a particular address. 1425a99e2eSeric ** 1525a99e2eSeric ** Algorithm: 1625a99e2eSeric ** Compute receiving network (i.e., mailer), host, & user. 1725a99e2eSeric ** If local, see if this is really a program name. 1825a99e2eSeric ** Build argument for the mailer. 1925a99e2eSeric ** Create pipe through edit fcn if appropriate. 2025a99e2eSeric ** Fork. 2125a99e2eSeric ** Child: call mailer 2225a99e2eSeric ** Parent: call editfcn if specified. 2325a99e2eSeric ** Wait for mailer to finish. 2425a99e2eSeric ** Interpret exit status. 2525a99e2eSeric ** 2625a99e2eSeric ** Parameters: 2725a99e2eSeric ** to -- the address to deliver the message to. 2825a99e2eSeric ** editfcn -- if non-NULL, we want to call this function 2925a99e2eSeric ** to output the letter (instead of just out- 3025a99e2eSeric ** putting it raw). 3125a99e2eSeric ** 3225a99e2eSeric ** Returns: 3325a99e2eSeric ** zero -- successfully delivered. 3425a99e2eSeric ** else -- some failure, see ExitStat for more info. 3525a99e2eSeric ** 3625a99e2eSeric ** Side Effects: 3725a99e2eSeric ** The standard input is passed off to someone. 3825a99e2eSeric ** 3925a99e2eSeric ** WARNING: 4025a99e2eSeric ** The standard input is shared amongst all children, 4125a99e2eSeric ** including the file pointer. It is critical that the 4225a99e2eSeric ** parent waits for the child to finish before forking 4325a99e2eSeric ** another child. 4425a99e2eSeric ** 4525a99e2eSeric ** Called By: 4625a99e2eSeric ** main 4725a99e2eSeric ** savemail 4825a99e2eSeric ** 4925a99e2eSeric ** Files: 50a2ee7369Seric ** standard input -- must be opened to the message to 5125a99e2eSeric ** deliver. 5225a99e2eSeric */ 5325a99e2eSeric 5425a99e2eSeric deliver(to, editfcn) 5525a99e2eSeric addrq *to; 5625a99e2eSeric int (*editfcn)(); 5725a99e2eSeric { 5825a99e2eSeric register struct mailer *m; 5925a99e2eSeric char *host; 6025a99e2eSeric char *user; 6125a99e2eSeric extern struct passwd *getpwnam(); 6225a99e2eSeric char **pvp; 6325a99e2eSeric extern char **buildargv(); 6425a99e2eSeric auto int st; 6525a99e2eSeric register int i; 6625a99e2eSeric register char *p; 6725a99e2eSeric int pid; 6825a99e2eSeric int pvect[2]; 6925a99e2eSeric extern FILE *fdopen(); 7025a99e2eSeric extern int errno; 7125a99e2eSeric FILE *mfile; 72*6328bdf7Seric extern putmessage(); 7325a99e2eSeric extern pipesig(); 74b07ac16bSeric extern char *index(); 7525a99e2eSeric 7625a99e2eSeric /* 7725a99e2eSeric ** Compute receiving mailer, host, and to addreses. 7825a99e2eSeric ** Do some initialization first. To is the to address 7925a99e2eSeric ** for error messages. 8025a99e2eSeric */ 8125a99e2eSeric 8225a99e2eSeric To = to->q_paddr; 8325a99e2eSeric m = to->q_mailer; 8425a99e2eSeric user = to->q_user; 8525a99e2eSeric host = to->q_host; 86c1f9df2cSeric Errors = 0; 8725a99e2eSeric errno = 0; 8825a99e2eSeric # ifdef DEBUG 8925a99e2eSeric if (Debug) 9025a99e2eSeric printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); 9125a99e2eSeric # endif DEBUG 9225a99e2eSeric 9325a99e2eSeric /* 9425a99e2eSeric ** Remove quote bits from user/host. 9525a99e2eSeric */ 9625a99e2eSeric 9725a99e2eSeric for (p = user; (*p++ &= 0177) != '\0'; ) 9825a99e2eSeric continue; 9925a99e2eSeric if (host != NULL) 10025a99e2eSeric for (p = host; (*p++ &= 0177) != '\0'; ) 10125a99e2eSeric continue; 10225a99e2eSeric 10325a99e2eSeric /* 10425a99e2eSeric ** Strip quote bits from names if the mailer wants it. 10525a99e2eSeric */ 10625a99e2eSeric 10725a99e2eSeric if (flagset(M_STRIPQ, m->m_flags)) 10825a99e2eSeric { 10925a99e2eSeric stripquotes(user); 11025a99e2eSeric stripquotes(host); 11125a99e2eSeric } 11225a99e2eSeric 11325a99e2eSeric /* 11425a99e2eSeric ** See if this user name is "special". 11525a99e2eSeric ** If the user is a program, diddle with the mailer spec. 11625a99e2eSeric ** If the user name has a slash in it, assume that this 11725a99e2eSeric ** is a file -- send it off without further ado. 11825a99e2eSeric ** Note that this means that editfcn's will not 11925a99e2eSeric ** be applied to the message. 12025a99e2eSeric */ 12125a99e2eSeric 12225a99e2eSeric if (m == &Mailer[0]) 12325a99e2eSeric { 12425a99e2eSeric if (*user == '|') 12525a99e2eSeric { 12625a99e2eSeric user++; 12725a99e2eSeric m = &Mailer[1]; 12825a99e2eSeric } 12925a99e2eSeric else 13025a99e2eSeric { 13125a99e2eSeric if (index(user, '/') != NULL) 13225a99e2eSeric { 13325a99e2eSeric i = mailfile(user); 13425a99e2eSeric giveresponse(i, TRUE, m); 13525a99e2eSeric return (i); 13625a99e2eSeric } 13725a99e2eSeric } 13825a99e2eSeric } 13925a99e2eSeric 14025a99e2eSeric /* 141243921eeSeric ** See if the user exists. 142243921eeSeric ** Strictly, this is only needed to print a pretty 14325a99e2eSeric ** error message. 144243921eeSeric ** 145243921eeSeric ** >>>>>>>>>> This clause assumes that the local mailer 146243921eeSeric ** >> NOTE >> cannot do any further aliasing; that 147243921eeSeric ** >>>>>>>>>> function is subsumed by delivermail. 14825a99e2eSeric */ 14925a99e2eSeric 15025a99e2eSeric if (m == &Mailer[0]) 15125a99e2eSeric { 15225a99e2eSeric if (getpwnam(user) == NULL) 15325a99e2eSeric { 15425a99e2eSeric giveresponse(EX_NOUSER, TRUE, m); 15525a99e2eSeric return (EX_NOUSER); 15625a99e2eSeric } 15725a99e2eSeric } 15825a99e2eSeric 15925a99e2eSeric /* 16025a99e2eSeric ** Call the mailer. 161*6328bdf7Seric ** The argument vector gets built, pipes 16225a99e2eSeric ** are created as necessary, and we fork & exec as 163*6328bdf7Seric ** appropriate. 16425a99e2eSeric */ 16525a99e2eSeric 166*6328bdf7Seric pvp = buildargv(m, host, user, From.q_paddr); 16725a99e2eSeric if (pvp == NULL) 16825a99e2eSeric { 16925a99e2eSeric usrerr("name too long"); 17025a99e2eSeric return (-1); 17125a99e2eSeric } 17225a99e2eSeric rewind(stdin); 17325a99e2eSeric 174*6328bdf7Seric /* create a pipe to shove the mail through */ 175*6328bdf7Seric if (pipe(pvect) < 0) 17625a99e2eSeric { 17725a99e2eSeric syserr("pipe"); 17825a99e2eSeric return (-1); 17925a99e2eSeric } 180ea235328Smark # ifdef VFORK 181ea235328Smark pid = vfork(); 182ea235328Smark # else 18325a99e2eSeric pid = fork(); 184ea235328Smark # endif 18525a99e2eSeric if (pid < 0) 18625a99e2eSeric { 18725a99e2eSeric syserr("Cannot fork"); 18825a99e2eSeric close(pvect[0]); 18925a99e2eSeric close(pvect[1]); 19025a99e2eSeric return (-1); 19125a99e2eSeric } 19225a99e2eSeric else if (pid == 0) 19325a99e2eSeric { 19425a99e2eSeric /* child -- set up input & exec mailer */ 19503ab8e55Seric /* make diagnostic output be standard output */ 19603ab8e55Seric close(2); 19703ab8e55Seric dup(1); 19825a99e2eSeric signal(SIGINT, SIG_IGN); 19925a99e2eSeric close(0); 20025a99e2eSeric if (dup(pvect[0]) < 0) 20125a99e2eSeric { 20225a99e2eSeric syserr("Cannot dup to zero!"); 203a590b978Seric _exit(EX_OSERR); 20425a99e2eSeric } 20525a99e2eSeric close(pvect[0]); 20625a99e2eSeric close(pvect[1]); 20725a99e2eSeric if (!flagset(M_RESTR, m->m_flags)) 20825a99e2eSeric setuid(getuid()); 209e374fd72Seric # ifndef VFORK 210e374fd72Seric /* 211e374fd72Seric ** We have to be careful with vfork - we can't mung up the 212e374fd72Seric ** memory but we don't want the mailer to inherit any extra 213e374fd72Seric ** open files. Chances are the mailer won't 214e374fd72Seric ** care about an extra file, but then again you never know. 215e374fd72Seric ** Actually, we would like to close(fileno(pwf)), but it's 216e374fd72Seric ** declared static so we can't. But if we fclose(pwf), which 217e374fd72Seric ** is what endpwent does, it closes it in the parent too and 218e374fd72Seric ** the next getpwnam will be slower. If you have a weird 219e374fd72Seric ** mailer that chokes on the extra file you should do the 220e374fd72Seric ** endpwent(). 221e374fd72Seric ** 222e374fd72Seric ** Similar comments apply to log. However, openlog is 223e374fd72Seric ** clever enough to set the FIOCLEX mode on the file, 224e374fd72Seric ** so it will be closed automatically on the exec. 225e374fd72Seric */ 226e374fd72Seric 227e374fd72Seric endpwent(); 22825a99e2eSeric # ifdef LOG 229f9fe028fSeric closelog(); 23025a99e2eSeric # endif LOG 231e374fd72Seric # endif VFORK 23225a99e2eSeric execv(m->m_mailer, pvp); 23325a99e2eSeric /* syserr fails because log is closed */ 23425a99e2eSeric /* syserr("Cannot exec %s", m->m_mailer); */ 2352ac087dbSeric printf("Cannot exec %s\n", m->m_mailer); 2362ac087dbSeric fflush(stdout); 237a590b978Seric _exit(EX_UNAVAILABLE); 23825a99e2eSeric } 23925a99e2eSeric 240*6328bdf7Seric /* write out message to mailer */ 24125a99e2eSeric close(pvect[0]); 24225a99e2eSeric signal(SIGPIPE, pipesig); 24325a99e2eSeric mfile = fdopen(pvect[1], "w"); 244*6328bdf7Seric if (editfcn == NULL) 245*6328bdf7Seric editfcn = putmessage; 246*6328bdf7Seric (*editfcn)(mfile, m); 24725a99e2eSeric fclose(mfile); 24825a99e2eSeric 24925a99e2eSeric /* 25025a99e2eSeric ** Wait for child to die and report status. 25125a99e2eSeric ** We should never get fatal errors (e.g., segmentation 25225a99e2eSeric ** violation), so we report those specially. For other 25325a99e2eSeric ** errors, we choose a status message (into statmsg), 25425a99e2eSeric ** and if it represents an error, we print it. 25525a99e2eSeric */ 25625a99e2eSeric 25725a99e2eSeric while ((i = wait(&st)) > 0 && i != pid) 25825a99e2eSeric continue; 25925a99e2eSeric if (i < 0) 26025a99e2eSeric { 26125a99e2eSeric syserr("wait"); 26225a99e2eSeric return (-1); 26325a99e2eSeric } 26425a99e2eSeric if ((st & 0377) != 0) 26525a99e2eSeric { 26625a99e2eSeric syserr("%s: stat %o", pvp[0], st); 267df2792f7Seric ExitStat = EX_UNAVAILABLE; 26825a99e2eSeric return (-1); 26925a99e2eSeric } 27025a99e2eSeric i = (st >> 8) & 0377; 2712ac087dbSeric giveresponse(i, TRUE, m); 27225a99e2eSeric return (i); 27325a99e2eSeric } 27425a99e2eSeric /* 27525a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 27625a99e2eSeric ** 27725a99e2eSeric ** Parameters: 27825a99e2eSeric ** stat -- the status code from the mailer (high byte 27925a99e2eSeric ** only; core dumps must have been taken care of 28025a99e2eSeric ** already). 28125a99e2eSeric ** force -- if set, force an error message output, even 28225a99e2eSeric ** if the mailer seems to like to print its own 28325a99e2eSeric ** messages. 28425a99e2eSeric ** m -- the mailer descriptor for this mailer. 28525a99e2eSeric ** 28625a99e2eSeric ** Returns: 28725a99e2eSeric ** none. 28825a99e2eSeric ** 28925a99e2eSeric ** Side Effects: 290c1f9df2cSeric ** Errors may be incremented. 29125a99e2eSeric ** ExitStat may be set. 29225a99e2eSeric ** 29325a99e2eSeric ** Called By: 29425a99e2eSeric ** deliver 29525a99e2eSeric */ 29625a99e2eSeric 29725a99e2eSeric giveresponse(stat, force, m) 29825a99e2eSeric int stat; 29925a99e2eSeric int force; 30025a99e2eSeric register struct mailer *m; 30125a99e2eSeric { 30225a99e2eSeric register char *statmsg; 30325a99e2eSeric extern char *SysExMsg[]; 30425a99e2eSeric register int i; 30525a99e2eSeric extern int N_SysEx; 30629dd97a3Seric extern long MsgSize; 30729dd97a3Seric char buf[30]; 30825a99e2eSeric 30925a99e2eSeric i = stat - EX__BASE; 31025a99e2eSeric if (i < 0 || i > N_SysEx) 31125a99e2eSeric statmsg = NULL; 31225a99e2eSeric else 31325a99e2eSeric statmsg = SysExMsg[i]; 31425a99e2eSeric if (stat == 0) 31525a99e2eSeric statmsg = "ok"; 31625a99e2eSeric else 31725a99e2eSeric { 318c1f9df2cSeric Errors++; 31925a99e2eSeric if (statmsg == NULL && m->m_badstat != 0) 32025a99e2eSeric { 32125a99e2eSeric stat = m->m_badstat; 32225a99e2eSeric i = stat - EX__BASE; 32325a99e2eSeric # ifdef DEBUG 32425a99e2eSeric if (i < 0 || i >= N_SysEx) 32525a99e2eSeric syserr("Bad m_badstat %d", stat); 32625a99e2eSeric else 32725a99e2eSeric # endif DEBUG 32825a99e2eSeric statmsg = SysExMsg[i]; 32925a99e2eSeric } 33025a99e2eSeric if (statmsg == NULL) 33125a99e2eSeric usrerr("unknown mailer response %d", stat); 33225a99e2eSeric else if (force || !flagset(M_QUIET, m->m_flags)) 33325a99e2eSeric usrerr("%s", statmsg); 33425a99e2eSeric } 33525a99e2eSeric 33625a99e2eSeric /* 33725a99e2eSeric ** Final cleanup. 33825a99e2eSeric ** Log a record of the transaction. Compute the new 33925a99e2eSeric ** ExitStat -- if we already had an error, stick with 34025a99e2eSeric ** that. 34125a99e2eSeric */ 34225a99e2eSeric 34325a99e2eSeric if (statmsg == NULL) 34429dd97a3Seric { 34529dd97a3Seric sprintf(buf, "error %d", stat); 34629dd97a3Seric statmsg = buf; 34729dd97a3Seric } 34829dd97a3Seric 34929dd97a3Seric # ifdef LOG 350e374fd72Seric syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 35125a99e2eSeric # endif LOG 352243921eeSeric setstat(stat); 35325a99e2eSeric return (stat); 35425a99e2eSeric } 35525a99e2eSeric /* 356*6328bdf7Seric ** PUTMESSAGE -- output a message to the final mailer. 35725a99e2eSeric ** 358*6328bdf7Seric ** This routine takes care of recreating the header from the 359*6328bdf7Seric ** in-core copy, etc. 36025a99e2eSeric ** 36125a99e2eSeric ** Parameters: 362*6328bdf7Seric ** fp -- file to output onto. 363*6328bdf7Seric ** m -- a mailer descriptor. 36425a99e2eSeric ** 36525a99e2eSeric ** Returns: 366*6328bdf7Seric ** none. 36725a99e2eSeric ** 36825a99e2eSeric ** Side Effects: 369*6328bdf7Seric ** The message is written onto fp. 37025a99e2eSeric */ 37125a99e2eSeric 372*6328bdf7Seric putmessage(fp, m) 373*6328bdf7Seric FILE *fp; 374*6328bdf7Seric struct mailer *m; 37525a99e2eSeric { 376*6328bdf7Seric char buf[BUFSIZ]; 377*6328bdf7Seric register int i; 378*6328bdf7Seric HDR *h; 379b07ac16bSeric register char *p; 380*6328bdf7Seric extern char *arpadate(); 381*6328bdf7Seric extern char *hvalue(); 382*6328bdf7Seric bool anyheader = FALSE; 383*6328bdf7Seric extern char *translate(); 38425a99e2eSeric 385*6328bdf7Seric /* clear all "used" bits */ 386*6328bdf7Seric for (h = Header; h != NULL; h = h->h_link) 387*6328bdf7Seric h->h_flags &= ~H_USED; 388*6328bdf7Seric 389*6328bdf7Seric /* output date if needed by mailer */ 390*6328bdf7Seric p = hvalue("date"); 391*6328bdf7Seric if (flagset(M_NEEDDATE, m->m_flags) && p == NULL) 392*6328bdf7Seric p = arpadate(Date); 393*6328bdf7Seric if (p != NULL) 394b07ac16bSeric { 395*6328bdf7Seric fprintf(fp, "Date: %s\n", p); 396*6328bdf7Seric anyheader = TRUE; 397b07ac16bSeric } 398b07ac16bSeric 399*6328bdf7Seric /* output from line if needed by mailer */ 400*6328bdf7Seric p = hvalue("from"); 401*6328bdf7Seric if (flagset(M_NEEDFROM, m->m_flags) && p == NULL) 402*6328bdf7Seric { 403*6328bdf7Seric char frombuf[MAXLINE]; 404*6328bdf7Seric extern char *FullName; 405*6328bdf7Seric 406*6328bdf7Seric p = translate("$f", From.q_mailer, From.q_paddr, NULL, NULL); 407*6328bdf7Seric if (FullName != NULL) 408*6328bdf7Seric fprintf(fp, "From: %s <%s>\n", FullName, p); 409*6328bdf7Seric else 410*6328bdf7Seric fprintf(fp, "From: %s\n", p); 411*6328bdf7Seric free(p); 412*6328bdf7Seric anyheader = TRUE; 413*6328bdf7Seric } 414*6328bdf7Seric else if (p != NULL) 415*6328bdf7Seric { 416*6328bdf7Seric fprintf(fp, "From: %s\n", p); 417*6328bdf7Seric anyheader = TRUE; 418*6328bdf7Seric } 419*6328bdf7Seric 420*6328bdf7Seric /* output message-id field if needed */ 421*6328bdf7Seric p = hvalue("message-id"); 422*6328bdf7Seric if (flagset(M_MSGID, m->m_flags) && p == NULL) 423*6328bdf7Seric p = MsgId; 424*6328bdf7Seric if (p != NULL) 425*6328bdf7Seric { 426*6328bdf7Seric fprintf(fp, "Message-Id: %s\n", p); 427*6328bdf7Seric anyheader = TRUE; 428*6328bdf7Seric } 429*6328bdf7Seric 430*6328bdf7Seric /* output any other header lines */ 431*6328bdf7Seric for (h = Header; h != NULL; h = h->h_link) 432*6328bdf7Seric { 433*6328bdf7Seric if (flagset(H_USED, h->h_flags)) 434*6328bdf7Seric continue; 435*6328bdf7Seric fprintf(fp, "%s: %s\n", capitalize(h->h_field), h->h_value); 436*6328bdf7Seric h->h_flags |= H_USED; 437*6328bdf7Seric anyheader = TRUE; 438*6328bdf7Seric } 439*6328bdf7Seric 440*6328bdf7Seric if (anyheader) 441*6328bdf7Seric fprintf(fp, "\n"); 442*6328bdf7Seric 443*6328bdf7Seric /* output the body of the message */ 444*6328bdf7Seric while (!ferror(fp) && (i = read(0, buf, BUFSIZ)) > 0) 445*6328bdf7Seric fwrite(buf, 1, i, fp); 446*6328bdf7Seric 44725a99e2eSeric if (ferror(fp)) 44825a99e2eSeric { 449*6328bdf7Seric syserr("putmessage: write error"); 45025a99e2eSeric setstat(EX_IOERR); 45125a99e2eSeric } 45225a99e2eSeric } 45325a99e2eSeric /* 45425a99e2eSeric ** PIPESIG -- Handle broken pipe signals 45525a99e2eSeric ** 45625a99e2eSeric ** This just logs an error. 45725a99e2eSeric ** 45825a99e2eSeric ** Parameters: 45925a99e2eSeric ** none 46025a99e2eSeric ** 46125a99e2eSeric ** Returns: 46225a99e2eSeric ** none 46325a99e2eSeric ** 46425a99e2eSeric ** Side Effects: 46525a99e2eSeric ** logs an error message. 46625a99e2eSeric */ 46725a99e2eSeric 46825a99e2eSeric pipesig() 46925a99e2eSeric { 47025a99e2eSeric syserr("Broken pipe"); 47103ab8e55Seric signal(SIGPIPE, SIG_IGN); 47225a99e2eSeric } 47325a99e2eSeric /* 47425a99e2eSeric ** SENDTO -- Designate a send list. 47525a99e2eSeric ** 47625a99e2eSeric ** The parameter is a comma-separated list of people to send to. 47725a99e2eSeric ** This routine arranges to send to all of them. 47825a99e2eSeric ** 47925a99e2eSeric ** Parameters: 48025a99e2eSeric ** list -- the send list. 48125a99e2eSeric ** copyf -- the copy flag; passed to parse. 48225a99e2eSeric ** 48325a99e2eSeric ** Returns: 48425a99e2eSeric ** none 48525a99e2eSeric ** 48625a99e2eSeric ** Side Effects: 48725a99e2eSeric ** none. 48825a99e2eSeric ** 48925a99e2eSeric ** Called By: 49025a99e2eSeric ** main 49125a99e2eSeric ** alias 49225a99e2eSeric */ 49325a99e2eSeric 49425a99e2eSeric sendto(list, copyf) 49525a99e2eSeric char *list; 49625a99e2eSeric int copyf; 49725a99e2eSeric { 49825a99e2eSeric register char *p; 49925a99e2eSeric register char *q; 50025a99e2eSeric register char c; 50125a99e2eSeric addrq *a; 50225a99e2eSeric extern addrq *parse(); 50325a99e2eSeric bool more; 50425a99e2eSeric 50525a99e2eSeric /* more keeps track of what the previous delimiter was */ 50625a99e2eSeric more = TRUE; 50725a99e2eSeric for (p = list; more; ) 50825a99e2eSeric { 50925a99e2eSeric /* find the end of this address */ 51025a99e2eSeric q = p; 51125a99e2eSeric while ((c = *p++) != '\0' && c != ',' && c != '\n') 51225a99e2eSeric continue; 51325a99e2eSeric more = c != '\0'; 51425a99e2eSeric *--p = '\0'; 51525a99e2eSeric if (more) 51625a99e2eSeric p++; 51725a99e2eSeric 51825a99e2eSeric /* parse the address */ 51925a99e2eSeric if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) 52025a99e2eSeric continue; 52125a99e2eSeric 52225a99e2eSeric /* arrange to send to this person */ 52325a99e2eSeric recipient(a, &SendQ); 52425a99e2eSeric } 52525a99e2eSeric To = NULL; 52625a99e2eSeric } 52725a99e2eSeric /* 52825a99e2eSeric ** RECIPIENT -- Designate a message recipient 52925a99e2eSeric ** 53025a99e2eSeric ** Saves the named person for future mailing. 53125a99e2eSeric ** 53225a99e2eSeric ** Designates a person as a recipient. This routine 53325a99e2eSeric ** does the initial parsing, and checks to see if 53425a99e2eSeric ** this person has already received the mail. 53525a99e2eSeric ** It also supresses local network names and turns them into 53625a99e2eSeric ** local names. 53725a99e2eSeric ** 53825a99e2eSeric ** Parameters: 53925a99e2eSeric ** a -- the (preparsed) address header for the recipient. 54025a99e2eSeric ** targetq -- the queue to add the name to. 54125a99e2eSeric ** 54225a99e2eSeric ** Returns: 54325a99e2eSeric ** none. 54425a99e2eSeric ** 54525a99e2eSeric ** Side Effects: 54625a99e2eSeric ** none. 54725a99e2eSeric ** 54825a99e2eSeric ** Called By: 54925a99e2eSeric ** sendto 55025a99e2eSeric ** main 55125a99e2eSeric */ 55225a99e2eSeric 55325a99e2eSeric recipient(a, targetq) 55425a99e2eSeric register addrq *a; 55525a99e2eSeric addrq *targetq; 55625a99e2eSeric { 55725a99e2eSeric register addrq *q; 55825a99e2eSeric register struct mailer *m; 55925a99e2eSeric register char **pvp; 56025a99e2eSeric extern char *xalloc(); 56125a99e2eSeric extern bool forward(); 56225a99e2eSeric extern int errno; 56325a99e2eSeric extern bool sameaddr(); 56425a99e2eSeric 56525a99e2eSeric To = a->q_paddr; 56625a99e2eSeric m = a->q_mailer; 56725a99e2eSeric errno = 0; 56825a99e2eSeric # ifdef DEBUG 56925a99e2eSeric if (Debug) 57025a99e2eSeric printf("recipient(%s)\n", To); 57125a99e2eSeric # endif DEBUG 57225a99e2eSeric 57325a99e2eSeric /* 57425a99e2eSeric ** Look up this person in the recipient list. If they 57525a99e2eSeric ** are there already, return, otherwise continue. 57625a99e2eSeric */ 57725a99e2eSeric 57825a99e2eSeric if (!ForceMail) 57925a99e2eSeric { 58025a99e2eSeric for (q = &SendQ; (q = nxtinq(q)) != NULL; ) 58125a99e2eSeric if (sameaddr(q, a, FALSE)) 58225a99e2eSeric { 58325a99e2eSeric # ifdef DEBUG 58425a99e2eSeric if (Debug) 58525a99e2eSeric printf("(%s in SendQ)\n", a->q_paddr); 58625a99e2eSeric # endif DEBUG 58725a99e2eSeric return; 58825a99e2eSeric } 58925a99e2eSeric for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) 59025a99e2eSeric if (sameaddr(q, a, FALSE)) 59125a99e2eSeric { 59225a99e2eSeric # ifdef DEBUG 59325a99e2eSeric if (Debug) 59425a99e2eSeric printf("(%s in AliasQ)\n", a->q_paddr); 59525a99e2eSeric # endif DEBUG 59625a99e2eSeric return; 59725a99e2eSeric } 59825a99e2eSeric } 59925a99e2eSeric 60025a99e2eSeric /* 60125a99e2eSeric ** See if the user wants hir mail forwarded. 60225a99e2eSeric ** `Forward' must do the forwarding recursively. 60325a99e2eSeric */ 60425a99e2eSeric 60525a99e2eSeric if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) 60625a99e2eSeric return; 60725a99e2eSeric 60825a99e2eSeric /* 60925a99e2eSeric ** Put the user onto the target queue. 61025a99e2eSeric */ 61125a99e2eSeric 61225a99e2eSeric if (targetq != NULL) 61325a99e2eSeric { 61425a99e2eSeric putonq(a, targetq); 61525a99e2eSeric } 61625a99e2eSeric 61725a99e2eSeric return; 61825a99e2eSeric } 61925a99e2eSeric /* 62025a99e2eSeric ** BUILDARGV -- Build an argument vector for a mail server. 62125a99e2eSeric ** 62225a99e2eSeric ** Using a template defined in config.c, an argv is built. 62325a99e2eSeric ** The format of the template is already a vector. The 62425a99e2eSeric ** items of this vector are copied, unless a dollar sign 62525a99e2eSeric ** is encountered. In this case, the next character 62625a99e2eSeric ** specifies something else to copy in. These can be 62725a99e2eSeric ** $f The from address. 62825a99e2eSeric ** $h The host. 62925a99e2eSeric ** $u The user. 63025a99e2eSeric ** $c The hop count. 63125a99e2eSeric ** The vector is built in a local buffer. A pointer to 63225a99e2eSeric ** the static argv is returned. 63325a99e2eSeric ** 63425a99e2eSeric ** Parameters: 635*6328bdf7Seric ** m -- a pointer to the mailer descriptor. 63625a99e2eSeric ** host -- the host name to send to. 63725a99e2eSeric ** user -- the user name to send to. 63825a99e2eSeric ** from -- the person this mail is from. 63925a99e2eSeric ** 64025a99e2eSeric ** Returns: 64125a99e2eSeric ** A pointer to an argv. 64225a99e2eSeric ** 64325a99e2eSeric ** Side Effects: 64425a99e2eSeric ** none 64525a99e2eSeric ** 64625a99e2eSeric ** WARNING: 64725a99e2eSeric ** Since the argv is staticly allocated, any subsequent 64825a99e2eSeric ** calls will clobber the old argv. 64925a99e2eSeric ** 65025a99e2eSeric ** Called By: 65125a99e2eSeric ** deliver 65225a99e2eSeric */ 65325a99e2eSeric 65425a99e2eSeric char ** 655*6328bdf7Seric buildargv(m, host, user, from) 656*6328bdf7Seric struct mailer *m; 65725a99e2eSeric char *host; 65825a99e2eSeric char *user; 65925a99e2eSeric char *from; 66025a99e2eSeric { 66125a99e2eSeric register char *p; 66225a99e2eSeric register char *q; 66325a99e2eSeric static char *pv[MAXPV+1]; 66425a99e2eSeric char **pvp; 66525a99e2eSeric char **mvp; 66625a99e2eSeric static char buf[512]; 66725a99e2eSeric register char *bp; 668*6328bdf7Seric extern char *translate(); 66925a99e2eSeric 67025a99e2eSeric /* 67125a99e2eSeric ** Do initial argv setup. 67225a99e2eSeric ** Insert the mailer name. Notice that $x expansion is 67325a99e2eSeric ** NOT done on the mailer name. Then, if the mailer has 67425a99e2eSeric ** a picky -f flag, we insert it as appropriate. This 67525a99e2eSeric ** code does not check for 'pv' overflow; this places a 67625a99e2eSeric ** manifest lower limit of 4 for MAXPV. 67725a99e2eSeric */ 67825a99e2eSeric 67925a99e2eSeric pvp = pv; 68025a99e2eSeric bp = buf; 68125a99e2eSeric 682*6328bdf7Seric *pvp++ = m->m_argv[0]; 68325a99e2eSeric 68425a99e2eSeric /* insert -f or -r flag as appropriate */ 685*6328bdf7Seric if (flagset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 68625a99e2eSeric { 687*6328bdf7Seric if (flagset(M_FOPT, m->m_flags)) 68825a99e2eSeric *pvp++ = "-f"; 68925a99e2eSeric else 69025a99e2eSeric *pvp++ = "-r"; 691*6328bdf7Seric *pvp++ = translate(from, m, from, user, host); 69225a99e2eSeric } 69325a99e2eSeric 69425a99e2eSeric /* 69525a99e2eSeric ** Build the rest of argv. 69625a99e2eSeric ** For each prototype parameter, the prototype is 69725a99e2eSeric ** scanned character at a time. If a dollar-sign is 69825a99e2eSeric ** found, 'q' is set to the appropriate expansion, 69925a99e2eSeric ** otherwise it is null. Then either the string 70025a99e2eSeric ** pointed to by q, or the original character, is 70125a99e2eSeric ** interpolated into the buffer. Buffer overflow is 70225a99e2eSeric ** checked. 70325a99e2eSeric */ 70425a99e2eSeric 705*6328bdf7Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 70625a99e2eSeric { 70725a99e2eSeric if (pvp >= &pv[MAXPV]) 70825a99e2eSeric { 70925a99e2eSeric syserr("Too many parameters to %s", pv[0]); 71025a99e2eSeric return (NULL); 71125a99e2eSeric } 712*6328bdf7Seric *pvp++ = translate(p, m, from, user, host); 713*6328bdf7Seric } 714*6328bdf7Seric *pvp = NULL; 715*6328bdf7Seric 716*6328bdf7Seric # ifdef DEBUG 717*6328bdf7Seric if (Debug) 718*6328bdf7Seric { 719*6328bdf7Seric printf("Interpolated argv is:\n"); 720*6328bdf7Seric for (mvp = pv; *mvp != NULL; mvp++) 721*6328bdf7Seric printf("\t%s\n", *mvp); 722*6328bdf7Seric } 723*6328bdf7Seric # endif DEBUG 724*6328bdf7Seric 725*6328bdf7Seric return (pv); 726*6328bdf7Seric } 727*6328bdf7Seric /* 728*6328bdf7Seric ** TRANSLATE -- translate a string using $x escapes. 729*6328bdf7Seric ** 730*6328bdf7Seric ** Parameters: 731*6328bdf7Seric ** s -- string to translate. 732*6328bdf7Seric ** m -- pointer to mailer descriptor. 733*6328bdf7Seric ** 734*6328bdf7Seric ** Returns: 735*6328bdf7Seric ** pointer to translated string. 736*6328bdf7Seric ** 737*6328bdf7Seric ** Side Effects: 738*6328bdf7Seric ** none. 739*6328bdf7Seric */ 740*6328bdf7Seric 741*6328bdf7Seric char * 742*6328bdf7Seric translate(s, m, from, user, host) 743*6328bdf7Seric register char *s; 744*6328bdf7Seric struct mailer *m; 745*6328bdf7Seric char *from; 746*6328bdf7Seric char *user; 747*6328bdf7Seric char *host; 748*6328bdf7Seric { 749*6328bdf7Seric register char *q; 750*6328bdf7Seric char buf[MAXNAME]; 751*6328bdf7Seric register char *bp; 752*6328bdf7Seric char *stack = NULL; 753*6328bdf7Seric char pbuf[10]; 754*6328bdf7Seric extern char *newstr(); 755*6328bdf7Seric extern char *Macro[]; 756*6328bdf7Seric 757*6328bdf7Seric bp = buf; 758*6328bdf7Seric restart: 759*6328bdf7Seric 760*6328bdf7Seric # ifdef DEBUG 761*6328bdf7Seric if (Debug) 762*6328bdf7Seric printf("translate(%s)\n", s); 763*6328bdf7Seric # endif DEBUG 764*6328bdf7Seric for (; *s != '\0'; s++) 76525a99e2eSeric { 76625a99e2eSeric /* q will be the interpolated quantity */ 76725a99e2eSeric q = NULL; 768*6328bdf7Seric if (*s == '$') 76925a99e2eSeric { 770*6328bdf7Seric if (isupper(*++s)) 771*6328bdf7Seric q = Macro[*s - 'A']; 772*6328bdf7Seric else 773*6328bdf7Seric { 774*6328bdf7Seric switch (*s) 77525a99e2eSeric { 77625a99e2eSeric case 'f': /* from person */ 777*6328bdf7Seric if (stack == NULL && m != NULL) 778*6328bdf7Seric { 779*6328bdf7Seric stack = s; 780*6328bdf7Seric s = m->m_from; 781*6328bdf7Seric goto restart; 782*6328bdf7Seric } 78325a99e2eSeric q = from; 78425a99e2eSeric break; 78525a99e2eSeric 78625a99e2eSeric case 'u': /* user */ 78725a99e2eSeric q = user; 78825a99e2eSeric break; 78925a99e2eSeric 79025a99e2eSeric case 'h': /* host */ 79125a99e2eSeric q = host; 79225a99e2eSeric break; 79325a99e2eSeric 79425a99e2eSeric case 'c': /* hop count */ 79525a99e2eSeric sprintf(pbuf, "%d", HopCount); 79625a99e2eSeric q = pbuf; 79725a99e2eSeric break; 79825a99e2eSeric } 79925a99e2eSeric } 800*6328bdf7Seric } 80125a99e2eSeric 80225a99e2eSeric /* 80325a99e2eSeric ** Interpolate q or output one character 80425a99e2eSeric ** Strip quote bits as we proceed..... 80525a99e2eSeric */ 80625a99e2eSeric 80725a99e2eSeric if (q != NULL) 80825a99e2eSeric { 80925a99e2eSeric while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') 81025a99e2eSeric continue; 81125a99e2eSeric bp--; 81225a99e2eSeric } 81325a99e2eSeric else if (bp < &buf[sizeof buf - 1]) 814*6328bdf7Seric *bp++ = *s; 815*6328bdf7Seric } 816*6328bdf7Seric if (stack != NULL) 817*6328bdf7Seric { 818*6328bdf7Seric s = stack; 819*6328bdf7Seric s++; 820*6328bdf7Seric stack = NULL; 821*6328bdf7Seric goto restart; 82225a99e2eSeric } 82325a99e2eSeric *bp++ = '\0'; 82425a99e2eSeric if (bp >= &buf[sizeof buf - 1]) 82525a99e2eSeric return (NULL); 82625a99e2eSeric # ifdef DEBUG 82725a99e2eSeric if (Debug) 828*6328bdf7Seric printf("translate ==> '%s'\n", buf); 82925a99e2eSeric # endif DEBUG 830*6328bdf7Seric return (newstr(buf)); 83125a99e2eSeric } 83225a99e2eSeric /* 83325a99e2eSeric ** MAILFILE -- Send a message to a file. 83425a99e2eSeric ** 83525a99e2eSeric ** Parameters: 83625a99e2eSeric ** filename -- the name of the file to send to. 83725a99e2eSeric ** 83825a99e2eSeric ** Returns: 83925a99e2eSeric ** The exit code associated with the operation. 84025a99e2eSeric ** 84125a99e2eSeric ** Side Effects: 84225a99e2eSeric ** none. 84325a99e2eSeric ** 84425a99e2eSeric ** Called By: 84525a99e2eSeric ** deliver 84625a99e2eSeric */ 84725a99e2eSeric 84825a99e2eSeric mailfile(filename) 84925a99e2eSeric char *filename; 85025a99e2eSeric { 85125a99e2eSeric char buf[MAXLINE]; 85225a99e2eSeric register FILE *f; 85325a99e2eSeric auto long tim; 85425a99e2eSeric extern char *ctime(); 85525a99e2eSeric 85625a99e2eSeric f = fopen(filename, "a"); 85725a99e2eSeric if (f == NULL) 85825a99e2eSeric return (EX_CANTCREAT); 85925a99e2eSeric 86025a99e2eSeric /* output the timestamp */ 86125a99e2eSeric time(&tim); 86225a99e2eSeric fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); 86325a99e2eSeric rewind(stdin); 86425a99e2eSeric while (fgets(buf, sizeof buf, stdin) != NULL) 86525a99e2eSeric { 86625a99e2eSeric fputs(buf, f); 86725a99e2eSeric if (ferror(f)) 86825a99e2eSeric { 86925a99e2eSeric fclose(f); 87025a99e2eSeric return (EX_IOERR); 87125a99e2eSeric } 87225a99e2eSeric } 87325a99e2eSeric fputs("\n", f); 87425a99e2eSeric fclose(f); 87525a99e2eSeric return (EX_OK); 87625a99e2eSeric } 877