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