125a99e2eSeric # include <stdio.h> 225a99e2eSeric # include <pwd.h> 325a99e2eSeric # include <signal.h> 425a99e2eSeric # include "dlvrmail.h" 525a99e2eSeric # ifdef LOG 625a99e2eSeric # include <log.h> 725a99e2eSeric # endif LOG 825a99e2eSeric 9*243921eeSeric static char SccsId[] = "@(#)deliver.c 1.5 10/11/80"; 10259cace7Seric 1125a99e2eSeric /* 1225a99e2eSeric ** DELIVER -- Deliver a message to a particular address. 1325a99e2eSeric ** 1425a99e2eSeric ** Algorithm: 1525a99e2eSeric ** Compute receiving network (i.e., mailer), host, & user. 1625a99e2eSeric ** If local, see if this is really a program name. 1725a99e2eSeric ** Build argument for the mailer. 1825a99e2eSeric ** Create pipe through edit fcn if appropriate. 1925a99e2eSeric ** Fork. 2025a99e2eSeric ** Child: call mailer 2125a99e2eSeric ** Parent: call editfcn if specified. 2225a99e2eSeric ** Wait for mailer to finish. 2325a99e2eSeric ** Interpret exit status. 2425a99e2eSeric ** 2525a99e2eSeric ** Parameters: 2625a99e2eSeric ** to -- the address to deliver the message to. 2725a99e2eSeric ** editfcn -- if non-NULL, we want to call this function 2825a99e2eSeric ** to output the letter (instead of just out- 2925a99e2eSeric ** putting it raw). 3025a99e2eSeric ** 3125a99e2eSeric ** Returns: 3225a99e2eSeric ** zero -- successfully delivered. 3325a99e2eSeric ** else -- some failure, see ExitStat for more info. 3425a99e2eSeric ** 3525a99e2eSeric ** Side Effects: 3625a99e2eSeric ** The standard input is passed off to someone. 3725a99e2eSeric ** 3825a99e2eSeric ** WARNING: 3925a99e2eSeric ** The standard input is shared amongst all children, 4025a99e2eSeric ** including the file pointer. It is critical that the 4125a99e2eSeric ** parent waits for the child to finish before forking 4225a99e2eSeric ** another child. 4325a99e2eSeric ** 4425a99e2eSeric ** Called By: 4525a99e2eSeric ** main 4625a99e2eSeric ** savemail 4725a99e2eSeric ** 4825a99e2eSeric ** Files: 49a2ee7369Seric ** standard input -- must be opened to the message to 5025a99e2eSeric ** deliver. 5125a99e2eSeric */ 5225a99e2eSeric 5325a99e2eSeric deliver(to, editfcn) 5425a99e2eSeric addrq *to; 5525a99e2eSeric int (*editfcn)(); 5625a99e2eSeric { 5725a99e2eSeric register struct mailer *m; 5825a99e2eSeric char *host; 5925a99e2eSeric char *user; 6025a99e2eSeric extern struct passwd *getpwnam(); 6125a99e2eSeric char **pvp; 6225a99e2eSeric extern char **buildargv(); 6325a99e2eSeric auto int st; 6425a99e2eSeric register int i; 6525a99e2eSeric register char *p; 6625a99e2eSeric int pid; 6725a99e2eSeric int pvect[2]; 6825a99e2eSeric extern FILE *fdopen(); 6925a99e2eSeric extern int errno; 7025a99e2eSeric FILE *mfile; 7125a99e2eSeric extern putheader(); 7225a99e2eSeric extern pipesig(); 7325a99e2eSeric 7425a99e2eSeric /* 7525a99e2eSeric ** Compute receiving mailer, host, and to addreses. 7625a99e2eSeric ** Do some initialization first. To is the to address 7725a99e2eSeric ** for error messages. 7825a99e2eSeric */ 7925a99e2eSeric 8025a99e2eSeric To = to->q_paddr; 8125a99e2eSeric m = to->q_mailer; 8225a99e2eSeric user = to->q_user; 8325a99e2eSeric host = to->q_host; 8425a99e2eSeric Error = 0; 8525a99e2eSeric errno = 0; 8625a99e2eSeric # ifdef DEBUG 8725a99e2eSeric if (Debug) 8825a99e2eSeric printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); 8925a99e2eSeric # endif DEBUG 9025a99e2eSeric 9125a99e2eSeric /* 9225a99e2eSeric ** Remove quote bits from user/host. 9325a99e2eSeric */ 9425a99e2eSeric 9525a99e2eSeric for (p = user; (*p++ &= 0177) != '\0'; ) 9625a99e2eSeric continue; 9725a99e2eSeric if (host != NULL) 9825a99e2eSeric for (p = host; (*p++ &= 0177) != '\0'; ) 9925a99e2eSeric continue; 10025a99e2eSeric 10125a99e2eSeric /* 10225a99e2eSeric ** Strip quote bits from names if the mailer wants it. 10325a99e2eSeric */ 10425a99e2eSeric 10525a99e2eSeric if (flagset(M_STRIPQ, m->m_flags)) 10625a99e2eSeric { 10725a99e2eSeric stripquotes(user); 10825a99e2eSeric stripquotes(host); 10925a99e2eSeric } 11025a99e2eSeric 11125a99e2eSeric /* 11225a99e2eSeric ** See if this user name is "special". 11325a99e2eSeric ** If the user is a program, diddle with the mailer spec. 11425a99e2eSeric ** If the user name has a slash in it, assume that this 11525a99e2eSeric ** is a file -- send it off without further ado. 11625a99e2eSeric ** Note that this means that editfcn's will not 11725a99e2eSeric ** be applied to the message. 11825a99e2eSeric */ 11925a99e2eSeric 12025a99e2eSeric if (m == &Mailer[0]) 12125a99e2eSeric { 12225a99e2eSeric if (*user == '|') 12325a99e2eSeric { 12425a99e2eSeric user++; 12525a99e2eSeric m = &Mailer[1]; 12625a99e2eSeric } 12725a99e2eSeric else 12825a99e2eSeric { 12925a99e2eSeric if (index(user, '/') != NULL) 13025a99e2eSeric { 13125a99e2eSeric i = mailfile(user); 13225a99e2eSeric giveresponse(i, TRUE, m); 13325a99e2eSeric return (i); 13425a99e2eSeric } 13525a99e2eSeric } 13625a99e2eSeric } 13725a99e2eSeric 13825a99e2eSeric /* 139*243921eeSeric ** See if the user exists. 140*243921eeSeric ** Strictly, this is only needed to print a pretty 14125a99e2eSeric ** error message. 142*243921eeSeric ** 143*243921eeSeric ** >>>>>>>>>> This clause assumes that the local mailer 144*243921eeSeric ** >> NOTE >> cannot do any further aliasing; that 145*243921eeSeric ** >>>>>>>>>> function is subsumed by delivermail. 14625a99e2eSeric */ 14725a99e2eSeric 14825a99e2eSeric if (m == &Mailer[0]) 14925a99e2eSeric { 15025a99e2eSeric if (getpwnam(user) == NULL) 15125a99e2eSeric { 15225a99e2eSeric giveresponse(EX_NOUSER, TRUE, m); 15325a99e2eSeric return (EX_NOUSER); 15425a99e2eSeric } 15525a99e2eSeric } 15625a99e2eSeric 15725a99e2eSeric /* 15825a99e2eSeric ** If the mailer wants a From line, insert a new editfcn. 15925a99e2eSeric */ 16025a99e2eSeric 16125a99e2eSeric if (flagset(M_HDR, m->m_flags) && editfcn == NULL) 16225a99e2eSeric editfcn = putheader; 16325a99e2eSeric 16425a99e2eSeric /* 16525a99e2eSeric ** Call the mailer. 16625a99e2eSeric ** The argument vector gets built, pipes through 'editfcn' 16725a99e2eSeric ** are created as necessary, and we fork & exec as 16825a99e2eSeric ** appropriate. In the parent, we call 'editfcn'. 16925a99e2eSeric */ 17025a99e2eSeric 17125a99e2eSeric pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr); 17225a99e2eSeric if (pvp == NULL) 17325a99e2eSeric { 17425a99e2eSeric usrerr("name too long"); 17525a99e2eSeric return (-1); 17625a99e2eSeric } 17725a99e2eSeric rewind(stdin); 17825a99e2eSeric 17925a99e2eSeric /* create a pipe if we will need one */ 18025a99e2eSeric if (editfcn != NULL && pipe(pvect) < 0) 18125a99e2eSeric { 18225a99e2eSeric syserr("pipe"); 18325a99e2eSeric return (-1); 18425a99e2eSeric } 18525a99e2eSeric pid = fork(); 18625a99e2eSeric if (pid < 0) 18725a99e2eSeric { 18825a99e2eSeric syserr("Cannot fork"); 18925a99e2eSeric if (editfcn != NULL) 19025a99e2eSeric { 19125a99e2eSeric close(pvect[0]); 19225a99e2eSeric close(pvect[1]); 19325a99e2eSeric } 19425a99e2eSeric return (-1); 19525a99e2eSeric } 19625a99e2eSeric else if (pid == 0) 19725a99e2eSeric { 19825a99e2eSeric /* child -- set up input & exec mailer */ 19925a99e2eSeric signal(SIGINT, SIG_IGN); 20025a99e2eSeric if (editfcn != NULL) 20125a99e2eSeric { 20225a99e2eSeric close(0); 20325a99e2eSeric if (dup(pvect[0]) < 0) 20425a99e2eSeric { 20525a99e2eSeric syserr("Cannot dup to zero!"); 20625a99e2eSeric exit(EX_OSERR); 20725a99e2eSeric } 20825a99e2eSeric close(pvect[0]); 20925a99e2eSeric close(pvect[1]); 21025a99e2eSeric } 21125a99e2eSeric if (!flagset(M_RESTR, m->m_flags)) 21225a99e2eSeric setuid(getuid()); 21325a99e2eSeric # ifdef LOG 21425a99e2eSeric initlog(NULL, 0, LOG_CLOSE); 21525a99e2eSeric # endif LOG 21625a99e2eSeric endpwent(); 21725a99e2eSeric execv(m->m_mailer, pvp); 21825a99e2eSeric /* syserr fails because log is closed */ 21925a99e2eSeric /* syserr("Cannot exec %s", m->m_mailer); */ 22025a99e2eSeric exit(EX_UNAVAIL); 22125a99e2eSeric } 22225a99e2eSeric 22325a99e2eSeric /* arrange to write out header message if error */ 22425a99e2eSeric if (editfcn != NULL) 22525a99e2eSeric { 22625a99e2eSeric close(pvect[0]); 22725a99e2eSeric signal(SIGPIPE, pipesig); 22825a99e2eSeric mfile = fdopen(pvect[1], "w"); 22925a99e2eSeric (*editfcn)(mfile); 23025a99e2eSeric fclose(mfile); 23125a99e2eSeric } 23225a99e2eSeric 23325a99e2eSeric /* 23425a99e2eSeric ** Wait for child to die and report status. 23525a99e2eSeric ** We should never get fatal errors (e.g., segmentation 23625a99e2eSeric ** violation), so we report those specially. For other 23725a99e2eSeric ** errors, we choose a status message (into statmsg), 23825a99e2eSeric ** and if it represents an error, we print it. 23925a99e2eSeric */ 24025a99e2eSeric 24125a99e2eSeric while ((i = wait(&st)) > 0 && i != pid) 24225a99e2eSeric continue; 24325a99e2eSeric if (i < 0) 24425a99e2eSeric { 24525a99e2eSeric syserr("wait"); 24625a99e2eSeric return (-1); 24725a99e2eSeric } 24825a99e2eSeric if ((st & 0377) != 0) 24925a99e2eSeric { 25025a99e2eSeric syserr("%s: stat %o", pvp[0], st); 25125a99e2eSeric ExitStat = EX_UNAVAIL; 25225a99e2eSeric return (-1); 25325a99e2eSeric } 25425a99e2eSeric i = (st >> 8) & 0377; 25525a99e2eSeric giveresponse(i, FALSE, m); 25625a99e2eSeric return (i); 25725a99e2eSeric } 25825a99e2eSeric /* 25925a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 26025a99e2eSeric ** 26125a99e2eSeric ** Parameters: 26225a99e2eSeric ** stat -- the status code from the mailer (high byte 26325a99e2eSeric ** only; core dumps must have been taken care of 26425a99e2eSeric ** already). 26525a99e2eSeric ** force -- if set, force an error message output, even 26625a99e2eSeric ** if the mailer seems to like to print its own 26725a99e2eSeric ** messages. 26825a99e2eSeric ** m -- the mailer descriptor for this mailer. 26925a99e2eSeric ** 27025a99e2eSeric ** Returns: 27125a99e2eSeric ** none. 27225a99e2eSeric ** 27325a99e2eSeric ** Side Effects: 27425a99e2eSeric ** Error may be set. 27525a99e2eSeric ** ExitStat may be set. 27625a99e2eSeric ** 27725a99e2eSeric ** Called By: 27825a99e2eSeric ** deliver 27925a99e2eSeric */ 28025a99e2eSeric 28125a99e2eSeric giveresponse(stat, force, m) 28225a99e2eSeric int stat; 28325a99e2eSeric int force; 28425a99e2eSeric register struct mailer *m; 28525a99e2eSeric { 28625a99e2eSeric register char *statmsg; 28725a99e2eSeric extern char *SysExMsg[]; 28825a99e2eSeric register int i; 28925a99e2eSeric extern int N_SysEx; 29025a99e2eSeric 29125a99e2eSeric i = stat - EX__BASE; 29225a99e2eSeric if (i < 0 || i > N_SysEx) 29325a99e2eSeric statmsg = NULL; 29425a99e2eSeric else 29525a99e2eSeric statmsg = SysExMsg[i]; 29625a99e2eSeric if (stat == 0) 29725a99e2eSeric statmsg = "ok"; 29825a99e2eSeric else 29925a99e2eSeric { 30025a99e2eSeric Error++; 30125a99e2eSeric if (statmsg == NULL && m->m_badstat != 0) 30225a99e2eSeric { 30325a99e2eSeric stat = m->m_badstat; 30425a99e2eSeric i = stat - EX__BASE; 30525a99e2eSeric # ifdef DEBUG 30625a99e2eSeric if (i < 0 || i >= N_SysEx) 30725a99e2eSeric syserr("Bad m_badstat %d", stat); 30825a99e2eSeric else 30925a99e2eSeric # endif DEBUG 31025a99e2eSeric statmsg = SysExMsg[i]; 31125a99e2eSeric } 31225a99e2eSeric if (statmsg == NULL) 31325a99e2eSeric usrerr("unknown mailer response %d", stat); 31425a99e2eSeric else if (force || !flagset(M_QUIET, m->m_flags)) 31525a99e2eSeric usrerr("%s", statmsg); 31625a99e2eSeric } 31725a99e2eSeric 31825a99e2eSeric /* 31925a99e2eSeric ** Final cleanup. 32025a99e2eSeric ** Log a record of the transaction. Compute the new 32125a99e2eSeric ** ExitStat -- if we already had an error, stick with 32225a99e2eSeric ** that. 32325a99e2eSeric */ 32425a99e2eSeric 32525a99e2eSeric # ifdef LOG 32625a99e2eSeric if (statmsg == NULL) 32725a99e2eSeric logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat); 32825a99e2eSeric else 32925a99e2eSeric logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg); 33025a99e2eSeric # endif LOG 331*243921eeSeric setstat(stat); 33225a99e2eSeric return (stat); 33325a99e2eSeric } 33425a99e2eSeric /* 33525a99e2eSeric ** PUTHEADER -- insert the From header into some mail 33625a99e2eSeric ** 33725a99e2eSeric ** For mailers such as 'msgs' that want the header inserted 33825a99e2eSeric ** into the mail, this edit filter inserts the From line and 33925a99e2eSeric ** then passes the rest of the message through. 34025a99e2eSeric ** 34125a99e2eSeric ** Parameters: 34225a99e2eSeric ** fp -- the file pointer for the output. 34325a99e2eSeric ** 34425a99e2eSeric ** Returns: 34525a99e2eSeric ** none 34625a99e2eSeric ** 34725a99e2eSeric ** Side Effects: 34825a99e2eSeric ** Puts a "From" line in UNIX format, and then 34925a99e2eSeric ** outputs the rest of the message. 35025a99e2eSeric ** 35125a99e2eSeric ** Called By: 35225a99e2eSeric ** deliver 35325a99e2eSeric */ 35425a99e2eSeric 35525a99e2eSeric putheader(fp) 35625a99e2eSeric register FILE *fp; 35725a99e2eSeric { 35825a99e2eSeric char buf[MAXLINE + 1]; 35925a99e2eSeric long tim; 36025a99e2eSeric extern char *ctime(); 36125a99e2eSeric 36225a99e2eSeric time(&tim); 36325a99e2eSeric fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); 36425a99e2eSeric while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) 36525a99e2eSeric fputs(buf, fp); 36625a99e2eSeric if (ferror(fp)) 36725a99e2eSeric { 36825a99e2eSeric syserr("putheader: write error"); 36925a99e2eSeric setstat(EX_IOERR); 37025a99e2eSeric } 37125a99e2eSeric } 37225a99e2eSeric /* 37325a99e2eSeric ** PIPESIG -- Handle broken pipe signals 37425a99e2eSeric ** 37525a99e2eSeric ** This just logs an error. 37625a99e2eSeric ** 37725a99e2eSeric ** Parameters: 37825a99e2eSeric ** none 37925a99e2eSeric ** 38025a99e2eSeric ** Returns: 38125a99e2eSeric ** none 38225a99e2eSeric ** 38325a99e2eSeric ** Side Effects: 38425a99e2eSeric ** logs an error message. 38525a99e2eSeric */ 38625a99e2eSeric 38725a99e2eSeric pipesig() 38825a99e2eSeric { 38925a99e2eSeric syserr("Broken pipe"); 39025a99e2eSeric } 39125a99e2eSeric /* 39225a99e2eSeric ** SENDTO -- Designate a send list. 39325a99e2eSeric ** 39425a99e2eSeric ** The parameter is a comma-separated list of people to send to. 39525a99e2eSeric ** This routine arranges to send to all of them. 39625a99e2eSeric ** 39725a99e2eSeric ** Parameters: 39825a99e2eSeric ** list -- the send list. 39925a99e2eSeric ** copyf -- the copy flag; passed to parse. 40025a99e2eSeric ** 40125a99e2eSeric ** Returns: 40225a99e2eSeric ** none 40325a99e2eSeric ** 40425a99e2eSeric ** Side Effects: 40525a99e2eSeric ** none. 40625a99e2eSeric ** 40725a99e2eSeric ** Called By: 40825a99e2eSeric ** main 40925a99e2eSeric ** alias 41025a99e2eSeric */ 41125a99e2eSeric 41225a99e2eSeric sendto(list, copyf) 41325a99e2eSeric char *list; 41425a99e2eSeric int copyf; 41525a99e2eSeric { 41625a99e2eSeric register char *p; 41725a99e2eSeric register char *q; 41825a99e2eSeric register char c; 41925a99e2eSeric addrq *a; 42025a99e2eSeric extern addrq *parse(); 42125a99e2eSeric bool more; 42225a99e2eSeric 42325a99e2eSeric /* more keeps track of what the previous delimiter was */ 42425a99e2eSeric more = TRUE; 42525a99e2eSeric for (p = list; more; ) 42625a99e2eSeric { 42725a99e2eSeric /* find the end of this address */ 42825a99e2eSeric q = p; 42925a99e2eSeric while ((c = *p++) != '\0' && c != ',' && c != '\n') 43025a99e2eSeric continue; 43125a99e2eSeric more = c != '\0'; 43225a99e2eSeric *--p = '\0'; 43325a99e2eSeric if (more) 43425a99e2eSeric p++; 43525a99e2eSeric 43625a99e2eSeric /* parse the address */ 43725a99e2eSeric if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) 43825a99e2eSeric continue; 43925a99e2eSeric 44025a99e2eSeric /* arrange to send to this person */ 44125a99e2eSeric recipient(a, &SendQ); 44225a99e2eSeric } 44325a99e2eSeric To = NULL; 44425a99e2eSeric } 44525a99e2eSeric /* 44625a99e2eSeric ** RECIPIENT -- Designate a message recipient 44725a99e2eSeric ** 44825a99e2eSeric ** Saves the named person for future mailing. 44925a99e2eSeric ** 45025a99e2eSeric ** Designates a person as a recipient. This routine 45125a99e2eSeric ** does the initial parsing, and checks to see if 45225a99e2eSeric ** this person has already received the mail. 45325a99e2eSeric ** It also supresses local network names and turns them into 45425a99e2eSeric ** local names. 45525a99e2eSeric ** 45625a99e2eSeric ** Parameters: 45725a99e2eSeric ** a -- the (preparsed) address header for the recipient. 45825a99e2eSeric ** targetq -- the queue to add the name to. 45925a99e2eSeric ** 46025a99e2eSeric ** Returns: 46125a99e2eSeric ** none. 46225a99e2eSeric ** 46325a99e2eSeric ** Side Effects: 46425a99e2eSeric ** none. 46525a99e2eSeric ** 46625a99e2eSeric ** Called By: 46725a99e2eSeric ** sendto 46825a99e2eSeric ** main 46925a99e2eSeric */ 47025a99e2eSeric 47125a99e2eSeric recipient(a, targetq) 47225a99e2eSeric register addrq *a; 47325a99e2eSeric addrq *targetq; 47425a99e2eSeric { 47525a99e2eSeric register addrq *q; 47625a99e2eSeric register struct mailer *m; 47725a99e2eSeric register char **pvp; 47825a99e2eSeric extern char *xalloc(); 47925a99e2eSeric extern bool forward(); 48025a99e2eSeric extern int errno; 48125a99e2eSeric extern bool sameaddr(); 48225a99e2eSeric 48325a99e2eSeric To = a->q_paddr; 48425a99e2eSeric m = a->q_mailer; 48525a99e2eSeric errno = 0; 48625a99e2eSeric # ifdef DEBUG 48725a99e2eSeric if (Debug) 48825a99e2eSeric printf("recipient(%s)\n", To); 48925a99e2eSeric # endif DEBUG 49025a99e2eSeric 49125a99e2eSeric /* 49225a99e2eSeric ** Don't go to the net if already on the target host. 49325a99e2eSeric ** This is important on the berkeley network, since 49425a99e2eSeric ** it get confused if we ask to send to ourselves. 49525a99e2eSeric ** For nets like the ARPANET, we probably will have 49625a99e2eSeric ** the local list set to NULL to simplify testing. 49725a99e2eSeric ** The canonical representation of the name is also set 49825a99e2eSeric ** to be just the local name so the duplicate letter 49925a99e2eSeric ** suppression algorithm will work. 50025a99e2eSeric */ 50125a99e2eSeric 50225a99e2eSeric if ((pvp = m->m_local) != NULL) 50325a99e2eSeric { 50425a99e2eSeric while (*pvp != NULL) 50525a99e2eSeric { 50625a99e2eSeric if (strcmp(*pvp++, a->q_host) == 0) 50725a99e2eSeric { 50825a99e2eSeric a->q_mailer = m = &Mailer[0]; 50925a99e2eSeric break; 51025a99e2eSeric } 51125a99e2eSeric } 51225a99e2eSeric } 51325a99e2eSeric 51425a99e2eSeric /* 51525a99e2eSeric ** Look up this person in the recipient list. If they 51625a99e2eSeric ** are there already, return, otherwise continue. 51725a99e2eSeric */ 51825a99e2eSeric 51925a99e2eSeric if (!ForceMail) 52025a99e2eSeric { 52125a99e2eSeric for (q = &SendQ; (q = nxtinq(q)) != NULL; ) 52225a99e2eSeric if (sameaddr(q, a, FALSE)) 52325a99e2eSeric { 52425a99e2eSeric # ifdef DEBUG 52525a99e2eSeric if (Debug) 52625a99e2eSeric printf("(%s in SendQ)\n", a->q_paddr); 52725a99e2eSeric # endif DEBUG 52825a99e2eSeric return; 52925a99e2eSeric } 53025a99e2eSeric for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) 53125a99e2eSeric if (sameaddr(q, a, FALSE)) 53225a99e2eSeric { 53325a99e2eSeric # ifdef DEBUG 53425a99e2eSeric if (Debug) 53525a99e2eSeric printf("(%s in AliasQ)\n", a->q_paddr); 53625a99e2eSeric # endif DEBUG 53725a99e2eSeric return; 53825a99e2eSeric } 53925a99e2eSeric } 54025a99e2eSeric 54125a99e2eSeric /* 54225a99e2eSeric ** See if the user wants hir mail forwarded. 54325a99e2eSeric ** `Forward' must do the forwarding recursively. 54425a99e2eSeric */ 54525a99e2eSeric 54625a99e2eSeric if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) 54725a99e2eSeric return; 54825a99e2eSeric 54925a99e2eSeric /* 55025a99e2eSeric ** Put the user onto the target queue. 55125a99e2eSeric */ 55225a99e2eSeric 55325a99e2eSeric if (targetq != NULL) 55425a99e2eSeric { 55525a99e2eSeric putonq(a, targetq); 55625a99e2eSeric } 55725a99e2eSeric 55825a99e2eSeric return; 55925a99e2eSeric } 56025a99e2eSeric /* 56125a99e2eSeric ** BUILDARGV -- Build an argument vector for a mail server. 56225a99e2eSeric ** 56325a99e2eSeric ** Using a template defined in config.c, an argv is built. 56425a99e2eSeric ** The format of the template is already a vector. The 56525a99e2eSeric ** items of this vector are copied, unless a dollar sign 56625a99e2eSeric ** is encountered. In this case, the next character 56725a99e2eSeric ** specifies something else to copy in. These can be 56825a99e2eSeric ** $f The from address. 56925a99e2eSeric ** $h The host. 57025a99e2eSeric ** $u The user. 57125a99e2eSeric ** $c The hop count. 57225a99e2eSeric ** The vector is built in a local buffer. A pointer to 57325a99e2eSeric ** the static argv is returned. 57425a99e2eSeric ** 57525a99e2eSeric ** Parameters: 57625a99e2eSeric ** tmplt -- a template for an argument vector. 57725a99e2eSeric ** flags -- the flags for this server. 57825a99e2eSeric ** host -- the host name to send to. 57925a99e2eSeric ** user -- the user name to send to. 58025a99e2eSeric ** from -- the person this mail is from. 58125a99e2eSeric ** 58225a99e2eSeric ** Returns: 58325a99e2eSeric ** A pointer to an argv. 58425a99e2eSeric ** 58525a99e2eSeric ** Side Effects: 58625a99e2eSeric ** none 58725a99e2eSeric ** 58825a99e2eSeric ** WARNING: 58925a99e2eSeric ** Since the argv is staticly allocated, any subsequent 59025a99e2eSeric ** calls will clobber the old argv. 59125a99e2eSeric ** 59225a99e2eSeric ** Called By: 59325a99e2eSeric ** deliver 59425a99e2eSeric */ 59525a99e2eSeric 59625a99e2eSeric char ** 59725a99e2eSeric buildargv(tmplt, flags, host, user, from) 59825a99e2eSeric char **tmplt; 59925a99e2eSeric int flags; 60025a99e2eSeric char *host; 60125a99e2eSeric char *user; 60225a99e2eSeric char *from; 60325a99e2eSeric { 60425a99e2eSeric register char *p; 60525a99e2eSeric register char *q; 60625a99e2eSeric static char *pv[MAXPV+1]; 60725a99e2eSeric char **pvp; 60825a99e2eSeric char **mvp; 60925a99e2eSeric static char buf[512]; 61025a99e2eSeric register char *bp; 61125a99e2eSeric char pbuf[30]; 61225a99e2eSeric 61325a99e2eSeric /* 61425a99e2eSeric ** Do initial argv setup. 61525a99e2eSeric ** Insert the mailer name. Notice that $x expansion is 61625a99e2eSeric ** NOT done on the mailer name. Then, if the mailer has 61725a99e2eSeric ** a picky -f flag, we insert it as appropriate. This 61825a99e2eSeric ** code does not check for 'pv' overflow; this places a 61925a99e2eSeric ** manifest lower limit of 4 for MAXPV. 62025a99e2eSeric */ 62125a99e2eSeric 62225a99e2eSeric pvp = pv; 62325a99e2eSeric bp = buf; 62425a99e2eSeric 62525a99e2eSeric *pvp++ = tmplt[0]; 62625a99e2eSeric 62725a99e2eSeric /* insert -f or -r flag as appropriate */ 62825a99e2eSeric if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) 62925a99e2eSeric { 63025a99e2eSeric if (flagset(M_FOPT, flags)) 63125a99e2eSeric *pvp++ = "-f"; 63225a99e2eSeric else 63325a99e2eSeric *pvp++ = "-r"; 63425a99e2eSeric *pvp++ = From.q_paddr; 63525a99e2eSeric } 63625a99e2eSeric 63725a99e2eSeric /* 63825a99e2eSeric ** Build the rest of argv. 63925a99e2eSeric ** For each prototype parameter, the prototype is 64025a99e2eSeric ** scanned character at a time. If a dollar-sign is 64125a99e2eSeric ** found, 'q' is set to the appropriate expansion, 64225a99e2eSeric ** otherwise it is null. Then either the string 64325a99e2eSeric ** pointed to by q, or the original character, is 64425a99e2eSeric ** interpolated into the buffer. Buffer overflow is 64525a99e2eSeric ** checked. 64625a99e2eSeric */ 64725a99e2eSeric 64825a99e2eSeric for (mvp = tmplt; (p = *++mvp) != NULL; ) 64925a99e2eSeric { 65025a99e2eSeric if (pvp >= &pv[MAXPV]) 65125a99e2eSeric { 65225a99e2eSeric syserr("Too many parameters to %s", pv[0]); 65325a99e2eSeric return (NULL); 65425a99e2eSeric } 65525a99e2eSeric *pvp++ = bp; 65625a99e2eSeric for (; *p != '\0'; p++) 65725a99e2eSeric { 65825a99e2eSeric /* q will be the interpolated quantity */ 65925a99e2eSeric q = NULL; 66025a99e2eSeric if (*p == '$') 66125a99e2eSeric { 66225a99e2eSeric switch (*++p) 66325a99e2eSeric { 66425a99e2eSeric case 'f': /* from person */ 66525a99e2eSeric q = from; 66625a99e2eSeric break; 66725a99e2eSeric 66825a99e2eSeric case 'u': /* user */ 66925a99e2eSeric q = user; 67025a99e2eSeric break; 67125a99e2eSeric 67225a99e2eSeric case 'h': /* host */ 67325a99e2eSeric q = host; 67425a99e2eSeric break; 67525a99e2eSeric 67625a99e2eSeric case 'c': /* hop count */ 67725a99e2eSeric sprintf(pbuf, "%d", HopCount); 67825a99e2eSeric q = pbuf; 67925a99e2eSeric break; 68025a99e2eSeric } 68125a99e2eSeric } 68225a99e2eSeric 68325a99e2eSeric /* 68425a99e2eSeric ** Interpolate q or output one character 68525a99e2eSeric ** Strip quote bits as we proceed..... 68625a99e2eSeric */ 68725a99e2eSeric 68825a99e2eSeric if (q != NULL) 68925a99e2eSeric { 69025a99e2eSeric while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') 69125a99e2eSeric continue; 69225a99e2eSeric bp--; 69325a99e2eSeric } 69425a99e2eSeric else if (bp < &buf[sizeof buf - 1]) 69525a99e2eSeric *bp++ = *p; 69625a99e2eSeric } 69725a99e2eSeric *bp++ = '\0'; 69825a99e2eSeric if (bp >= &buf[sizeof buf - 1]) 69925a99e2eSeric return (NULL); 70025a99e2eSeric } 70125a99e2eSeric *pvp = NULL; 70225a99e2eSeric 70325a99e2eSeric # ifdef DEBUG 70425a99e2eSeric if (Debug) 70525a99e2eSeric { 70625a99e2eSeric printf("Interpolated argv is:\n"); 70725a99e2eSeric for (mvp = pv; *mvp != NULL; mvp++) 70825a99e2eSeric printf("\t%s\n", *mvp); 70925a99e2eSeric } 71025a99e2eSeric # endif DEBUG 71125a99e2eSeric 71225a99e2eSeric return (pv); 71325a99e2eSeric } 71425a99e2eSeric /* 71525a99e2eSeric ** MAILFILE -- Send a message to a file. 71625a99e2eSeric ** 71725a99e2eSeric ** Parameters: 71825a99e2eSeric ** filename -- the name of the file to send to. 71925a99e2eSeric ** 72025a99e2eSeric ** Returns: 72125a99e2eSeric ** The exit code associated with the operation. 72225a99e2eSeric ** 72325a99e2eSeric ** Side Effects: 72425a99e2eSeric ** none. 72525a99e2eSeric ** 72625a99e2eSeric ** Called By: 72725a99e2eSeric ** deliver 72825a99e2eSeric */ 72925a99e2eSeric 73025a99e2eSeric mailfile(filename) 73125a99e2eSeric char *filename; 73225a99e2eSeric { 73325a99e2eSeric char buf[MAXLINE]; 73425a99e2eSeric register FILE *f; 73525a99e2eSeric auto long tim; 73625a99e2eSeric extern char *ctime(); 73725a99e2eSeric 73825a99e2eSeric f = fopen(filename, "a"); 73925a99e2eSeric if (f == NULL) 74025a99e2eSeric return (EX_CANTCREAT); 74125a99e2eSeric 74225a99e2eSeric /* output the timestamp */ 74325a99e2eSeric time(&tim); 74425a99e2eSeric fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); 74525a99e2eSeric rewind(stdin); 74625a99e2eSeric while (fgets(buf, sizeof buf, stdin) != NULL) 74725a99e2eSeric { 74825a99e2eSeric fputs(buf, f); 74925a99e2eSeric if (ferror(f)) 75025a99e2eSeric { 75125a99e2eSeric fclose(f); 75225a99e2eSeric return (EX_IOERR); 75325a99e2eSeric } 75425a99e2eSeric } 75525a99e2eSeric fputs("\n", f); 75625a99e2eSeric fclose(f); 75725a99e2eSeric return (EX_OK); 75825a99e2eSeric } 759