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*03ab8e55Seric static char SccsId[] = "@(#)deliver.c 1.10 10/27/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; 84c1f9df2cSeric Errors = 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 /* 139243921eeSeric ** See if the user exists. 140243921eeSeric ** Strictly, this is only needed to print a pretty 14125a99e2eSeric ** error message. 142243921eeSeric ** 143243921eeSeric ** >>>>>>>>>> This clause assumes that the local mailer 144243921eeSeric ** >> NOTE >> cannot do any further aliasing; that 145243921eeSeric ** >>>>>>>>>> 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 } 185ea235328Smark # ifdef VFORK 186ea235328Smark pid = vfork(); 187ea235328Smark # else 18825a99e2eSeric pid = fork(); 189ea235328Smark # endif 19025a99e2eSeric if (pid < 0) 19125a99e2eSeric { 19225a99e2eSeric syserr("Cannot fork"); 19325a99e2eSeric if (editfcn != NULL) 19425a99e2eSeric { 19525a99e2eSeric close(pvect[0]); 19625a99e2eSeric close(pvect[1]); 19725a99e2eSeric } 19825a99e2eSeric return (-1); 19925a99e2eSeric } 20025a99e2eSeric else if (pid == 0) 20125a99e2eSeric { 20225a99e2eSeric /* child -- set up input & exec mailer */ 203*03ab8e55Seric /* make diagnostic output be standard output */ 204*03ab8e55Seric close(2); 205*03ab8e55Seric dup(1); 20625a99e2eSeric signal(SIGINT, SIG_IGN); 20725a99e2eSeric if (editfcn != NULL) 20825a99e2eSeric { 20925a99e2eSeric close(0); 21025a99e2eSeric if (dup(pvect[0]) < 0) 21125a99e2eSeric { 21225a99e2eSeric syserr("Cannot dup to zero!"); 213a590b978Seric _exit(EX_OSERR); 21425a99e2eSeric } 21525a99e2eSeric close(pvect[0]); 21625a99e2eSeric close(pvect[1]); 21725a99e2eSeric } 21825a99e2eSeric if (!flagset(M_RESTR, m->m_flags)) 21925a99e2eSeric setuid(getuid()); 22025a99e2eSeric # ifdef LOG 22125a99e2eSeric initlog(NULL, 0, LOG_CLOSE); 22225a99e2eSeric # endif LOG 223ea235328Smark # ifndef VFORK 224ea235328Smark /* 225ea235328Smark * We have to be careful with vfork - we can't mung up the 226ea235328Smark * memory but we don't want the mailer to inherit any extra 227ea235328Smark * open files. Chances are the mailer won't 228ea235328Smark * care about an extra file, but then again you never know. 229ea235328Smark * Actually, we would like to close(fileno(pwf)), but it's 230ea235328Smark * declared static so we can't. But if we fclose(pwf), which 231ea235328Smark * is what endpwent does, it closes it in the parent too and 232ea235328Smark * the next getpwnam will be slower. If you have a weird mailer 233ea235328Smark * that chokes on the extra file you should do the endpwent(). 234ea235328Smark */ 23525a99e2eSeric endpwent(); 236ea235328Smark # endif 23725a99e2eSeric execv(m->m_mailer, pvp); 23825a99e2eSeric /* syserr fails because log is closed */ 23925a99e2eSeric /* syserr("Cannot exec %s", m->m_mailer); */ 240a590b978Seric _exit(EX_UNAVAILABLE); 24125a99e2eSeric } 24225a99e2eSeric 24325a99e2eSeric /* arrange to write out header message if error */ 24425a99e2eSeric if (editfcn != NULL) 24525a99e2eSeric { 24625a99e2eSeric close(pvect[0]); 24725a99e2eSeric signal(SIGPIPE, pipesig); 24825a99e2eSeric mfile = fdopen(pvect[1], "w"); 24925a99e2eSeric (*editfcn)(mfile); 25025a99e2eSeric fclose(mfile); 25125a99e2eSeric } 25225a99e2eSeric 25325a99e2eSeric /* 25425a99e2eSeric ** Wait for child to die and report status. 25525a99e2eSeric ** We should never get fatal errors (e.g., segmentation 25625a99e2eSeric ** violation), so we report those specially. For other 25725a99e2eSeric ** errors, we choose a status message (into statmsg), 25825a99e2eSeric ** and if it represents an error, we print it. 25925a99e2eSeric */ 26025a99e2eSeric 26125a99e2eSeric while ((i = wait(&st)) > 0 && i != pid) 26225a99e2eSeric continue; 26325a99e2eSeric if (i < 0) 26425a99e2eSeric { 26525a99e2eSeric syserr("wait"); 26625a99e2eSeric return (-1); 26725a99e2eSeric } 26825a99e2eSeric if ((st & 0377) != 0) 26925a99e2eSeric { 27025a99e2eSeric syserr("%s: stat %o", pvp[0], st); 271df2792f7Seric ExitStat = EX_UNAVAILABLE; 27225a99e2eSeric return (-1); 27325a99e2eSeric } 27425a99e2eSeric i = (st >> 8) & 0377; 27525a99e2eSeric giveresponse(i, FALSE, m); 27625a99e2eSeric return (i); 27725a99e2eSeric } 27825a99e2eSeric /* 27925a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 28025a99e2eSeric ** 28125a99e2eSeric ** Parameters: 28225a99e2eSeric ** stat -- the status code from the mailer (high byte 28325a99e2eSeric ** only; core dumps must have been taken care of 28425a99e2eSeric ** already). 28525a99e2eSeric ** force -- if set, force an error message output, even 28625a99e2eSeric ** if the mailer seems to like to print its own 28725a99e2eSeric ** messages. 28825a99e2eSeric ** m -- the mailer descriptor for this mailer. 28925a99e2eSeric ** 29025a99e2eSeric ** Returns: 29125a99e2eSeric ** none. 29225a99e2eSeric ** 29325a99e2eSeric ** Side Effects: 294c1f9df2cSeric ** Errors may be incremented. 29525a99e2eSeric ** ExitStat may be set. 29625a99e2eSeric ** 29725a99e2eSeric ** Called By: 29825a99e2eSeric ** deliver 29925a99e2eSeric */ 30025a99e2eSeric 30125a99e2eSeric giveresponse(stat, force, m) 30225a99e2eSeric int stat; 30325a99e2eSeric int force; 30425a99e2eSeric register struct mailer *m; 30525a99e2eSeric { 30625a99e2eSeric register char *statmsg; 30725a99e2eSeric extern char *SysExMsg[]; 30825a99e2eSeric register int i; 30925a99e2eSeric extern int N_SysEx; 31025a99e2eSeric 31125a99e2eSeric i = stat - EX__BASE; 31225a99e2eSeric if (i < 0 || i > N_SysEx) 31325a99e2eSeric statmsg = NULL; 31425a99e2eSeric else 31525a99e2eSeric statmsg = SysExMsg[i]; 31625a99e2eSeric if (stat == 0) 31725a99e2eSeric statmsg = "ok"; 31825a99e2eSeric else 31925a99e2eSeric { 320c1f9df2cSeric Errors++; 32125a99e2eSeric if (statmsg == NULL && m->m_badstat != 0) 32225a99e2eSeric { 32325a99e2eSeric stat = m->m_badstat; 32425a99e2eSeric i = stat - EX__BASE; 32525a99e2eSeric # ifdef DEBUG 32625a99e2eSeric if (i < 0 || i >= N_SysEx) 32725a99e2eSeric syserr("Bad m_badstat %d", stat); 32825a99e2eSeric else 32925a99e2eSeric # endif DEBUG 33025a99e2eSeric statmsg = SysExMsg[i]; 33125a99e2eSeric } 33225a99e2eSeric if (statmsg == NULL) 33325a99e2eSeric usrerr("unknown mailer response %d", stat); 33425a99e2eSeric else if (force || !flagset(M_QUIET, m->m_flags)) 33525a99e2eSeric usrerr("%s", statmsg); 33625a99e2eSeric } 33725a99e2eSeric 33825a99e2eSeric /* 33925a99e2eSeric ** Final cleanup. 34025a99e2eSeric ** Log a record of the transaction. Compute the new 34125a99e2eSeric ** ExitStat -- if we already had an error, stick with 34225a99e2eSeric ** that. 34325a99e2eSeric */ 34425a99e2eSeric 34525a99e2eSeric # ifdef LOG 34625a99e2eSeric if (statmsg == NULL) 34725a99e2eSeric logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat); 34825a99e2eSeric else 34925a99e2eSeric logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg); 35025a99e2eSeric # endif LOG 351243921eeSeric setstat(stat); 35225a99e2eSeric return (stat); 35325a99e2eSeric } 35425a99e2eSeric /* 35525a99e2eSeric ** PUTHEADER -- insert the From header into some mail 35625a99e2eSeric ** 35725a99e2eSeric ** For mailers such as 'msgs' that want the header inserted 35825a99e2eSeric ** into the mail, this edit filter inserts the From line and 35925a99e2eSeric ** then passes the rest of the message through. 36025a99e2eSeric ** 36125a99e2eSeric ** Parameters: 36225a99e2eSeric ** fp -- the file pointer for the output. 36325a99e2eSeric ** 36425a99e2eSeric ** Returns: 36525a99e2eSeric ** none 36625a99e2eSeric ** 36725a99e2eSeric ** Side Effects: 36825a99e2eSeric ** Puts a "From" line in UNIX format, and then 36925a99e2eSeric ** outputs the rest of the message. 37025a99e2eSeric ** 37125a99e2eSeric ** Called By: 37225a99e2eSeric ** deliver 37325a99e2eSeric */ 37425a99e2eSeric 37525a99e2eSeric putheader(fp) 37625a99e2eSeric register FILE *fp; 37725a99e2eSeric { 37825a99e2eSeric char buf[MAXLINE + 1]; 37925a99e2eSeric long tim; 38025a99e2eSeric extern char *ctime(); 38125a99e2eSeric 38225a99e2eSeric time(&tim); 38325a99e2eSeric fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); 38425a99e2eSeric while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) 38525a99e2eSeric fputs(buf, fp); 38625a99e2eSeric if (ferror(fp)) 38725a99e2eSeric { 38825a99e2eSeric syserr("putheader: write error"); 38925a99e2eSeric setstat(EX_IOERR); 39025a99e2eSeric } 39125a99e2eSeric } 39225a99e2eSeric /* 39325a99e2eSeric ** PIPESIG -- Handle broken pipe signals 39425a99e2eSeric ** 39525a99e2eSeric ** This just logs an error. 39625a99e2eSeric ** 39725a99e2eSeric ** Parameters: 39825a99e2eSeric ** none 39925a99e2eSeric ** 40025a99e2eSeric ** Returns: 40125a99e2eSeric ** none 40225a99e2eSeric ** 40325a99e2eSeric ** Side Effects: 40425a99e2eSeric ** logs an error message. 40525a99e2eSeric */ 40625a99e2eSeric 40725a99e2eSeric pipesig() 40825a99e2eSeric { 40925a99e2eSeric syserr("Broken pipe"); 410*03ab8e55Seric signal(SIGPIPE, SIG_IGN); 41125a99e2eSeric } 41225a99e2eSeric /* 41325a99e2eSeric ** SENDTO -- Designate a send list. 41425a99e2eSeric ** 41525a99e2eSeric ** The parameter is a comma-separated list of people to send to. 41625a99e2eSeric ** This routine arranges to send to all of them. 41725a99e2eSeric ** 41825a99e2eSeric ** Parameters: 41925a99e2eSeric ** list -- the send list. 42025a99e2eSeric ** copyf -- the copy flag; passed to parse. 42125a99e2eSeric ** 42225a99e2eSeric ** Returns: 42325a99e2eSeric ** none 42425a99e2eSeric ** 42525a99e2eSeric ** Side Effects: 42625a99e2eSeric ** none. 42725a99e2eSeric ** 42825a99e2eSeric ** Called By: 42925a99e2eSeric ** main 43025a99e2eSeric ** alias 43125a99e2eSeric */ 43225a99e2eSeric 43325a99e2eSeric sendto(list, copyf) 43425a99e2eSeric char *list; 43525a99e2eSeric int copyf; 43625a99e2eSeric { 43725a99e2eSeric register char *p; 43825a99e2eSeric register char *q; 43925a99e2eSeric register char c; 44025a99e2eSeric addrq *a; 44125a99e2eSeric extern addrq *parse(); 44225a99e2eSeric bool more; 44325a99e2eSeric 44425a99e2eSeric /* more keeps track of what the previous delimiter was */ 44525a99e2eSeric more = TRUE; 44625a99e2eSeric for (p = list; more; ) 44725a99e2eSeric { 44825a99e2eSeric /* find the end of this address */ 44925a99e2eSeric q = p; 45025a99e2eSeric while ((c = *p++) != '\0' && c != ',' && c != '\n') 45125a99e2eSeric continue; 45225a99e2eSeric more = c != '\0'; 45325a99e2eSeric *--p = '\0'; 45425a99e2eSeric if (more) 45525a99e2eSeric p++; 45625a99e2eSeric 45725a99e2eSeric /* parse the address */ 45825a99e2eSeric if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) 45925a99e2eSeric continue; 46025a99e2eSeric 46125a99e2eSeric /* arrange to send to this person */ 46225a99e2eSeric recipient(a, &SendQ); 46325a99e2eSeric } 46425a99e2eSeric To = NULL; 46525a99e2eSeric } 46625a99e2eSeric /* 46725a99e2eSeric ** RECIPIENT -- Designate a message recipient 46825a99e2eSeric ** 46925a99e2eSeric ** Saves the named person for future mailing. 47025a99e2eSeric ** 47125a99e2eSeric ** Designates a person as a recipient. This routine 47225a99e2eSeric ** does the initial parsing, and checks to see if 47325a99e2eSeric ** this person has already received the mail. 47425a99e2eSeric ** It also supresses local network names and turns them into 47525a99e2eSeric ** local names. 47625a99e2eSeric ** 47725a99e2eSeric ** Parameters: 47825a99e2eSeric ** a -- the (preparsed) address header for the recipient. 47925a99e2eSeric ** targetq -- the queue to add the name to. 48025a99e2eSeric ** 48125a99e2eSeric ** Returns: 48225a99e2eSeric ** none. 48325a99e2eSeric ** 48425a99e2eSeric ** Side Effects: 48525a99e2eSeric ** none. 48625a99e2eSeric ** 48725a99e2eSeric ** Called By: 48825a99e2eSeric ** sendto 48925a99e2eSeric ** main 49025a99e2eSeric */ 49125a99e2eSeric 49225a99e2eSeric recipient(a, targetq) 49325a99e2eSeric register addrq *a; 49425a99e2eSeric addrq *targetq; 49525a99e2eSeric { 49625a99e2eSeric register addrq *q; 49725a99e2eSeric register struct mailer *m; 49825a99e2eSeric register char **pvp; 49925a99e2eSeric extern char *xalloc(); 50025a99e2eSeric extern bool forward(); 50125a99e2eSeric extern int errno; 50225a99e2eSeric extern bool sameaddr(); 50325a99e2eSeric 50425a99e2eSeric To = a->q_paddr; 50525a99e2eSeric m = a->q_mailer; 50625a99e2eSeric errno = 0; 50725a99e2eSeric # ifdef DEBUG 50825a99e2eSeric if (Debug) 50925a99e2eSeric printf("recipient(%s)\n", To); 51025a99e2eSeric # endif DEBUG 51125a99e2eSeric 51225a99e2eSeric /* 51325a99e2eSeric ** Look up this person in the recipient list. If they 51425a99e2eSeric ** are there already, return, otherwise continue. 51525a99e2eSeric */ 51625a99e2eSeric 51725a99e2eSeric if (!ForceMail) 51825a99e2eSeric { 51925a99e2eSeric for (q = &SendQ; (q = nxtinq(q)) != NULL; ) 52025a99e2eSeric if (sameaddr(q, a, FALSE)) 52125a99e2eSeric { 52225a99e2eSeric # ifdef DEBUG 52325a99e2eSeric if (Debug) 52425a99e2eSeric printf("(%s in SendQ)\n", a->q_paddr); 52525a99e2eSeric # endif DEBUG 52625a99e2eSeric return; 52725a99e2eSeric } 52825a99e2eSeric for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) 52925a99e2eSeric if (sameaddr(q, a, FALSE)) 53025a99e2eSeric { 53125a99e2eSeric # ifdef DEBUG 53225a99e2eSeric if (Debug) 53325a99e2eSeric printf("(%s in AliasQ)\n", a->q_paddr); 53425a99e2eSeric # endif DEBUG 53525a99e2eSeric return; 53625a99e2eSeric } 53725a99e2eSeric } 53825a99e2eSeric 53925a99e2eSeric /* 54025a99e2eSeric ** See if the user wants hir mail forwarded. 54125a99e2eSeric ** `Forward' must do the forwarding recursively. 54225a99e2eSeric */ 54325a99e2eSeric 54425a99e2eSeric if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) 54525a99e2eSeric return; 54625a99e2eSeric 54725a99e2eSeric /* 54825a99e2eSeric ** Put the user onto the target queue. 54925a99e2eSeric */ 55025a99e2eSeric 55125a99e2eSeric if (targetq != NULL) 55225a99e2eSeric { 55325a99e2eSeric putonq(a, targetq); 55425a99e2eSeric } 55525a99e2eSeric 55625a99e2eSeric return; 55725a99e2eSeric } 55825a99e2eSeric /* 55925a99e2eSeric ** BUILDARGV -- Build an argument vector for a mail server. 56025a99e2eSeric ** 56125a99e2eSeric ** Using a template defined in config.c, an argv is built. 56225a99e2eSeric ** The format of the template is already a vector. The 56325a99e2eSeric ** items of this vector are copied, unless a dollar sign 56425a99e2eSeric ** is encountered. In this case, the next character 56525a99e2eSeric ** specifies something else to copy in. These can be 56625a99e2eSeric ** $f The from address. 56725a99e2eSeric ** $h The host. 56825a99e2eSeric ** $u The user. 56925a99e2eSeric ** $c The hop count. 57025a99e2eSeric ** The vector is built in a local buffer. A pointer to 57125a99e2eSeric ** the static argv is returned. 57225a99e2eSeric ** 57325a99e2eSeric ** Parameters: 57425a99e2eSeric ** tmplt -- a template for an argument vector. 57525a99e2eSeric ** flags -- the flags for this server. 57625a99e2eSeric ** host -- the host name to send to. 57725a99e2eSeric ** user -- the user name to send to. 57825a99e2eSeric ** from -- the person this mail is from. 57925a99e2eSeric ** 58025a99e2eSeric ** Returns: 58125a99e2eSeric ** A pointer to an argv. 58225a99e2eSeric ** 58325a99e2eSeric ** Side Effects: 58425a99e2eSeric ** none 58525a99e2eSeric ** 58625a99e2eSeric ** WARNING: 58725a99e2eSeric ** Since the argv is staticly allocated, any subsequent 58825a99e2eSeric ** calls will clobber the old argv. 58925a99e2eSeric ** 59025a99e2eSeric ** Called By: 59125a99e2eSeric ** deliver 59225a99e2eSeric */ 59325a99e2eSeric 59425a99e2eSeric char ** 59525a99e2eSeric buildargv(tmplt, flags, host, user, from) 59625a99e2eSeric char **tmplt; 59725a99e2eSeric int flags; 59825a99e2eSeric char *host; 59925a99e2eSeric char *user; 60025a99e2eSeric char *from; 60125a99e2eSeric { 60225a99e2eSeric register char *p; 60325a99e2eSeric register char *q; 60425a99e2eSeric static char *pv[MAXPV+1]; 60525a99e2eSeric char **pvp; 60625a99e2eSeric char **mvp; 60725a99e2eSeric static char buf[512]; 60825a99e2eSeric register char *bp; 60925a99e2eSeric char pbuf[30]; 61025a99e2eSeric 61125a99e2eSeric /* 61225a99e2eSeric ** Do initial argv setup. 61325a99e2eSeric ** Insert the mailer name. Notice that $x expansion is 61425a99e2eSeric ** NOT done on the mailer name. Then, if the mailer has 61525a99e2eSeric ** a picky -f flag, we insert it as appropriate. This 61625a99e2eSeric ** code does not check for 'pv' overflow; this places a 61725a99e2eSeric ** manifest lower limit of 4 for MAXPV. 61825a99e2eSeric */ 61925a99e2eSeric 62025a99e2eSeric pvp = pv; 62125a99e2eSeric bp = buf; 62225a99e2eSeric 62325a99e2eSeric *pvp++ = tmplt[0]; 62425a99e2eSeric 62525a99e2eSeric /* insert -f or -r flag as appropriate */ 62625a99e2eSeric if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) 62725a99e2eSeric { 62825a99e2eSeric if (flagset(M_FOPT, flags)) 62925a99e2eSeric *pvp++ = "-f"; 63025a99e2eSeric else 63125a99e2eSeric *pvp++ = "-r"; 63225a99e2eSeric *pvp++ = From.q_paddr; 63325a99e2eSeric } 63425a99e2eSeric 63525a99e2eSeric /* 63625a99e2eSeric ** Build the rest of argv. 63725a99e2eSeric ** For each prototype parameter, the prototype is 63825a99e2eSeric ** scanned character at a time. If a dollar-sign is 63925a99e2eSeric ** found, 'q' is set to the appropriate expansion, 64025a99e2eSeric ** otherwise it is null. Then either the string 64125a99e2eSeric ** pointed to by q, or the original character, is 64225a99e2eSeric ** interpolated into the buffer. Buffer overflow is 64325a99e2eSeric ** checked. 64425a99e2eSeric */ 64525a99e2eSeric 64625a99e2eSeric for (mvp = tmplt; (p = *++mvp) != NULL; ) 64725a99e2eSeric { 64825a99e2eSeric if (pvp >= &pv[MAXPV]) 64925a99e2eSeric { 65025a99e2eSeric syserr("Too many parameters to %s", pv[0]); 65125a99e2eSeric return (NULL); 65225a99e2eSeric } 65325a99e2eSeric *pvp++ = bp; 65425a99e2eSeric for (; *p != '\0'; p++) 65525a99e2eSeric { 65625a99e2eSeric /* q will be the interpolated quantity */ 65725a99e2eSeric q = NULL; 65825a99e2eSeric if (*p == '$') 65925a99e2eSeric { 66025a99e2eSeric switch (*++p) 66125a99e2eSeric { 66225a99e2eSeric case 'f': /* from person */ 66325a99e2eSeric q = from; 66425a99e2eSeric break; 66525a99e2eSeric 66625a99e2eSeric case 'u': /* user */ 66725a99e2eSeric q = user; 66825a99e2eSeric break; 66925a99e2eSeric 67025a99e2eSeric case 'h': /* host */ 67125a99e2eSeric q = host; 67225a99e2eSeric break; 67325a99e2eSeric 67425a99e2eSeric case 'c': /* hop count */ 67525a99e2eSeric sprintf(pbuf, "%d", HopCount); 67625a99e2eSeric q = pbuf; 67725a99e2eSeric break; 67825a99e2eSeric } 67925a99e2eSeric } 68025a99e2eSeric 68125a99e2eSeric /* 68225a99e2eSeric ** Interpolate q or output one character 68325a99e2eSeric ** Strip quote bits as we proceed..... 68425a99e2eSeric */ 68525a99e2eSeric 68625a99e2eSeric if (q != NULL) 68725a99e2eSeric { 68825a99e2eSeric while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') 68925a99e2eSeric continue; 69025a99e2eSeric bp--; 69125a99e2eSeric } 69225a99e2eSeric else if (bp < &buf[sizeof buf - 1]) 69325a99e2eSeric *bp++ = *p; 69425a99e2eSeric } 69525a99e2eSeric *bp++ = '\0'; 69625a99e2eSeric if (bp >= &buf[sizeof buf - 1]) 69725a99e2eSeric return (NULL); 69825a99e2eSeric } 69925a99e2eSeric *pvp = NULL; 70025a99e2eSeric 70125a99e2eSeric # ifdef DEBUG 70225a99e2eSeric if (Debug) 70325a99e2eSeric { 70425a99e2eSeric printf("Interpolated argv is:\n"); 70525a99e2eSeric for (mvp = pv; *mvp != NULL; mvp++) 70625a99e2eSeric printf("\t%s\n", *mvp); 70725a99e2eSeric } 70825a99e2eSeric # endif DEBUG 70925a99e2eSeric 71025a99e2eSeric return (pv); 71125a99e2eSeric } 71225a99e2eSeric /* 71325a99e2eSeric ** MAILFILE -- Send a message to a file. 71425a99e2eSeric ** 71525a99e2eSeric ** Parameters: 71625a99e2eSeric ** filename -- the name of the file to send to. 71725a99e2eSeric ** 71825a99e2eSeric ** Returns: 71925a99e2eSeric ** The exit code associated with the operation. 72025a99e2eSeric ** 72125a99e2eSeric ** Side Effects: 72225a99e2eSeric ** none. 72325a99e2eSeric ** 72425a99e2eSeric ** Called By: 72525a99e2eSeric ** deliver 72625a99e2eSeric */ 72725a99e2eSeric 72825a99e2eSeric mailfile(filename) 72925a99e2eSeric char *filename; 73025a99e2eSeric { 73125a99e2eSeric char buf[MAXLINE]; 73225a99e2eSeric register FILE *f; 73325a99e2eSeric auto long tim; 73425a99e2eSeric extern char *ctime(); 73525a99e2eSeric 73625a99e2eSeric f = fopen(filename, "a"); 73725a99e2eSeric if (f == NULL) 73825a99e2eSeric return (EX_CANTCREAT); 73925a99e2eSeric 74025a99e2eSeric /* output the timestamp */ 74125a99e2eSeric time(&tim); 74225a99e2eSeric fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); 74325a99e2eSeric rewind(stdin); 74425a99e2eSeric while (fgets(buf, sizeof buf, stdin) != NULL) 74525a99e2eSeric { 74625a99e2eSeric fputs(buf, f); 74725a99e2eSeric if (ferror(f)) 74825a99e2eSeric { 74925a99e2eSeric fclose(f); 75025a99e2eSeric return (EX_IOERR); 75125a99e2eSeric } 75225a99e2eSeric } 75325a99e2eSeric fputs("\n", f); 75425a99e2eSeric fclose(f); 75525a99e2eSeric return (EX_OK); 75625a99e2eSeric } 757