home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- #ifndef lint
- char copyright[] =
- "@(#) Copyright (c) 1988 Regents of the University of California.\n\
- All rights reserved.\n";
- #endif /* not lint */
-
- #ifndef lint
- static char sccsid[] = "@(#)arpa.c 5.4 (Berkeley) 6/1/90";
- #endif /* not lint */
-
- # include <stdio.h>
- # include <ctype.h>
- # include <signal.h>
- # include <sysexits.h>
- # include <whoami.h>
- # include <useful.h>
-
- char Version[] = "@(#)Arpa-mailer version 5.4 of 6/1/90";
-
- # define void int
-
- /*
- ** ARPA MAILER -- Queue ARPANET mail for eventual delivery
- **
- ** The standard input is stuck away in the outgoing arpanet
- ** mail queue for delivery by the true arpanet mailer.
- **
- ** CUSTOMIZED FOR THE C/70
- **
- ** Usage:
- ** /usr/lib/mailers/arpa from host user
- **
- ** Positional Parameters:
- ** from -- the person sending the mail.
- ** host -- the host to send the mail to.
- ** user -- the user to send the mail to.
- **
- ** Flags:
- ** -T -- debug flag.
- **
- ** Files:
- ** /usr/spool/netmail/* -- the queue file.
- **
- ** Return Codes:
- ** 0 -- all messages successfully mailed.
- ** 2 -- user or host unknown.
- ** 3 -- service unavailable, probably temporary
- ** file system condition.
- ** 4 -- syntax error in address.
- **
- ** Compilation Flags:
- ** SPOOLDIR -- the spool directory
- **
- ** Compilation Instructions:
- ** cc -n -O -s arpa-mailer.c -o arpa-mailer -lX
- ** chmod 755 arpa-mailer
- ** mv arpa-mailer /usr/lib/mailers/arpa
- **
- ** Author:
- ** Eric Allman, UCB/INGRES (eric@berkeley)
- */
-
- # ifdef C70
- # define SPOOLDIR "/usr/netmail"
- # else
- # define SPOOLDIR "/usr/spool/netmail"
- # endif
-
-
-
-
- char *From; /* person sending this mail */
- char *To; /* current "To:" person */
- int State; /* the current state (for exit codes) */
- # ifdef DEBUG
- bool Tflag; /* -T given */
- # endif DEBUG
- char FromHost[200]; /* string to prepend to addresses */
- /*
- ** MAIN -- Main program for arpa mailer
- **
- ** Processes arguments, and calls sendmail successively on
- ** the To: list.
- **
- ** Algorithm:
- ** Scan for debug flag.
- ** Catch interrupt signals.
- ** Collect input file name and from person.
- ** If more than one person in the to list, and
- ** if the input file is not a real file,
- ** collect input into a temp file.
- ** For each person in the to list
- ** Send to that person.
- **
- ** Parameters:
- ** argc
- ** argv -- as usual
- **
- ** Returns:
- ** via exit
- **
- ** Side Effects:
- ** Mail gets sent.
- **
- ** Author:
- ** Eric Allman UCB/INGRES.
- */
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- register int i;
- register char *p;
- register int ifd;
- char buf[512];
- extern int done();
- extern char *locv();
- register char *q;
- char *lastmark;
-
- State = 3;
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- (void) signal(SIGINT, done);
-
- /* process flags */
- argv[argc] = 0;
- # ifdef DEBUG
- if (strcmp(argv[1], "-T") == 0)
- {
- Tflag++;
- argv++;
- argc--;
- printf("%s\n", Version);
- }
- # endif DEBUG
-
- if (argc != 4)
- {
- rexit(EX_SOFTWARE);
- }
-
- /* decode parameters */
- From = argv[1];
- lastmark = &FromHost[-1];
- for (p = From, q = FromHost; (*q = *p) != '\0'; p++, q++)
- {
- if (*p == ':')
- *q = *p = '.';
- if (*q == '.' || *q == '!' || *q == '@')
- lastmark = q;
- }
- lastmark[1] = '\0';
-
- /* start sending mail */
- State = sendmail(argv[2], argv[3]);
-
- /* all done, clean up */
- done();
- }
- /*
- ** DONE -- Finish up, remove temp files, etc.
- **
- ** This does basic cleanup on interrupt, error, or
- ** normal termination. It uses "State" to tell which
- ** is happening.
- **
- ** Parameters:
- ** none
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** Exit(State).
- */
-
- done()
- {
- rexit(State);
- }
-
- /*
- ** REXIT -- exit, reporting error code if -T given
- **
- ** Parameters:
- ** e -- error code to exit with; see sysexits.h
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** Exit(e).
- */
- rexit(e)
- {
-
- # ifdef DEBUG
- if (Tflag)
- fprintf(stderr, "arpa-mail: return code %d\n", e);
- # endif
- exit(e);
- }
- /*
- ** SENDMAIL -- Queue up mail for the arpanet mailer.
- **
- ** The mail is inserted with proper headers into the
- ** arpanet queue directory.
- **
- ** Algorithm:
- ** decode "to" address
- ** if error, exit.
- ** create a spool file name.
- ** output the header information to spool file,
- ** separate names in To:, CC: fields with commas.
- ** copy the mail to the spool file.
- **
- ** Parameters:
- ** host -- the host to send to.
- ** user -- the user to send to.
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** the mail is copied into a file in the network
- ** queue directory (/usr/spool/netmail).
- */
-
- sendmail(host, user)
- char *host;
- char *user;
- {
- char spoolfile[50]; /* gets the spool file name */
- register int i;
- register char *p;
- static int callnum; /* for the final letter on spoolfile */
- char buf[512];
- register FILE *sfp; /* spool file */
- register int c;
- extern char *matchhdr();
-
- /* verify that the host exists */
- (void) strcpy(buf, "/dev/net/");
- (void) strcat(buf, host);
- # ifndef C70
- #ifdef DEBUG
- if (!Tflag)
- #endif DEBUG
- if (host[0] == '\0' || access(buf, 0) < 0)
- return (EX_NOHOST);
- # endif C70
-
- /*
- ** Create spool file name.
- ** Format is "username000nnX", where username is
- ** padded on the right with zeros and nn (the process
- ** id) is padded on the left with zeros; X is a unique
- ** sequence character.
- */
-
- # ifdef DEBUG
- if (Tflag)
- (void) strcpy(spoolfile, "arpa.out");
- else
- # endif DEBUG
- (void) sprintf(spoolfile, "%s/arpamail%05d%c", SPOOLDIR, getpid(), 'a' + callnum++);
-
- /* create spool file */
- sfp = fopen(spoolfile, "w");
- if (sfp == NULL)
- {
- spoolerr:
- return (EX_OSERR);
- }
- # ifdef DEBUG
- if (!Tflag)
- # endif DEBUG
- (void) chmod(spoolfile, 0400);
-
- /*
- ** Output mailer control lines.
- ** These lines are as follows:
- ** /dev/net/<hostname> {target host}
- ** user-name {at target host}
- ** /mnt/eric {pathname of sender; not used}
- ** eric {name of user who is sending}
- ** These are different (but close) on the C/70.
- */
-
- # ifdef C70
- fputs(host, sfp);
- fputs(":", sfp);
- fputs(user, sfp);
- fputs(":", sfp);
- fputs(From, sfp);
- fputs(":\n", sfp);
- # else
- fputs(buf, sfp);
- fputs("\n", sfp);
- fputs(user, sfp);
- fputs("\n\n", sfp);
- fputs(From, sfp);
- fputs("\n", sfp);
- # endif
-
- /*
- ** Output the mail
- ** Check the first line for the date. If not found,
- ** assume the message is not in arpanet standard format
- ** and output a "Date:" and "From:" header.
- */
-
- if (fgets(buf, sizeof buf, stdin) == NULL)
- {
- /* no message */
- (void) unlink(spoolfile);
- return (EX_OK);
- }
- if (strncmp("From ", buf, 5) == 0)
- {
- /* strip Unix "From" line */
- /* should save the date here */
- (void) fgets(buf, sizeof buf, stdin);
- }
- while (matchhdr(buf, "mail-from") != NULL ||
- matchhdr(buf, "sender-path") != NULL ||
- matchhdr(buf, "received") != NULL ||
- matchhdr(buf, "via") != NULL)
- {
- fputs(buf, sfp);
- (void) fgets(buf, sizeof buf, stdin);
- }
- if (matchhdr(buf, "date") == NULL)
- putdate(sfp);
- else
- {
- fputs(buf, sfp);
- (void) fgets(buf, sizeof buf, stdin);
- }
- if (matchhdr(buf, "from") == NULL)
- putfrom(sfp);
- else
- {
- /* hack to support sendmail -- for a while */
- if (index(buf, '@') == NULL)
- putfrom(sfp);
- else
- fputs(buf, sfp);
- (void) fgets(buf, sizeof buf, stdin);
- }
- if (!ishdr(buf))
- {
- if (buf[0] != '\n')
- putc('\n', sfp);
- goto hdrdone;
- }
-
- /*
- ** At this point, we have a message with REAL headers.
- ** We look at each head line and insert commas if it
- ** is a To: or Cc: field.
- */
-
- do
- {
- if (!ishdr(buf))
- break;
- if (!matchhdr(buf, "to") && !matchhdr(buf, "cc"))
- {
- fputs(buf, sfp);
- continue;
- }
- /* gotcha! */
- fixaddr(buf, 1, sfp);
- while (isspace(c = peekc(stdin)) && c != '\n')
- {
- (void) fgets(buf, BUFSIZ, stdin);
- fixaddr(buf, 0, sfp);
- }
- } while (fgets(buf, BUFSIZ, stdin) != NULL);
-
- hdrdone:
- /* output the rest of the header & the body of the letter */
- do
- {
- fputs(buf, sfp);
- if (ferror(sfp))
- goto spoolerr;
- } while (fgets(buf, sizeof buf, stdin) != NULL);
-
- /* all done! */
- (void) fclose(sfp);
- return (EX_OK);
- }
- /*
- ** FIXADDR -- Output header line with needed commas.
- **
- ** Parameters:
- ** buf -- header line
- ** first -- true if this is not a continuation
- **
- ** Returns:
- ** none
- **
- ** Side effects:
- ** The contents of buf is copied onto the spool file with
- ** with the right commas interlaced
- **
- ** Called by:
- ** sendmail
- */
-
- fixaddr(buf, first, spf)
- char buf[];
- register FILE *spf;
- {
- register char *cp;
- register int c;
- char word[BUFSIZ], word2[BUFSIZ];
- char *gword();
- static char wsep[] = ", ";
-
- cp = buf;
- if (first)
- {
- while (*cp != ':' && *cp)
- putc(*cp++, spf);
- if (*cp == ':')
- {
- fputs(": ", spf);
- cp++;
- }
- }
- else
- while (*cp && isspace(*cp))
- putc(*cp++, spf);
- cp = gword(word, cp);
- if (strlen(word) == 0)
- {
- putc('\n', spf);
- goto test;
- }
- for (;;)
- {
- cp = gword(word2, cp);
- if (strlen(word2) == 0)
- {
- putaddr(word, spf);
- break;
- }
- if (strcmp(word2, "%") == 0)
- word2[0] = '@';
- if (strcmp(word2, "@") && strcmp(word2, "at"))
- {
- putaddr(word, spf);
- fputs(wsep, spf);
- (void) strcpy(word, word2);
- continue;
- }
- fputs(word, spf);
- if (word2[0] == '@')
- putc('@', spf);
- else
- fputs(" at ", spf);
- cp = gword(word, cp);
- fputs(word, spf);
- cp = gword(word, cp);
- if (strlen(word))
- fputs(wsep, spf);
- }
-
- test:
- c = peekc(stdin);
- if (isspace(c) && c != '\n')
- fputs(",\n", spf);
- else
- putc('\n', spf);
- }
- /*
- ** PUTADDR -- output address onto file
- **
- ** Putaddr prepends the network header onto the address
- ** unless one already exists.
- **
- ** Parameters:
- ** name -- the name to output.
- ** fp -- the file to put it on.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** name is put onto fp.
- */
-
- putaddr(name, fp)
- char *name;
- FILE *fp;
- {
- register char *p;
-
- if (strlen(name) == 0)
- return;
- for (p = name; *p != '\0' && *p != ':' && *p != '.' && *p != '@' &&
- *p != '!' && *p != '^'; p++)
- continue;
- if (*p == ':')
- *p = '.';
- else if (*p == '\0')
- fputs(FromHost, fp);
- fputs(name, fp);
- if (*p != '@')
- fputs("@Berkeley", fp);
- }
- /*
- ** PEEKC -- peek at next character in input file
- **
- ** Parameters:
- ** fp -- stdio file buffer
- **
- ** Returns:
- ** the next character in the input or EOF
- **
- ** Side effects:
- ** None.
- */
- peekc(fp)
- register FILE *fp;
- {
- register int c;
-
- c = getc(fp);
- (void) ungetc(c, fp);
- return(c);
- }
-
- /*
- ** GWORD -- get the next liberal word from a string
- **
- ** Parameters:
- ** buf -- place to put scanned word
- ** p -- place to start looking for word
- **
- ** Returns:
- ** updated value of p or 0 if no more left after this
- **
- ** Side effects:
- ** buf gets the liberal word scanned.
- ** buf will be length 0 if there is no more input,
- ** or if p was passed as 0
- */
- char *
- gword(buf, p)
- char buf[];
- register char *p;
- {
- register char *sp, *dp;
- int atfound = 0; /* weither or not a '@' found in the scan */
-
- (void) strcpy(buf, "");
- if (p == 0)
- return(0);
- sp = p;
- while (*sp && (isspace(*sp) || *sp == ','))
- sp++;
- dp = buf;
- if (*sp != '%' && *sp != '@')
- {
- while (*sp && !isspace(*sp) && *sp != ',' )
- {
- if ( *sp == '@' || *sp == '%' )
- atfound++;
- *dp++ = *sp++;
- }
- if ( atfound )
- {
- dp--;
- while ( *dp != '@' && *dp != '%' )
- dp--,sp--;
- sp--;
- }
-
- }
- else
- *dp++ = *sp++;
- *dp = 0;
- if (*sp == 0)
- return(0);
- return(sp);
- }
- /*
- ** ISHDR -- see if the passed line is a ARPA style header line
- **
- ** Parameters:
- ** buf -- header line
- **
- ** Returns:
- ** non-zero if the line is a header line, else zero
- **
- ** Side effects:
- ** none
- **
- ** Called by:
- ** sendmail
- */
- ishdr(buf)
- char buf[];
- {
- register char *p;
-
- p = buf;
-
- /* check for continuation lines */
- if (isspace(*p))
- return (1);
- else
- {
- while (*p != ':' && !isspace(*p))
- p++;
- while (isspace(*p))
- p++;
- if (*p != ':')
- p = 0;
- }
- return(p != 0);
- }
- /*
- ** PUTDATE -- Put the date field into the message.
- **
- ** Parameters:
- ** fp -- file to put it onto.
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** output onto fp.
- */
-
- putdate(fp)
- register FILE *fp;
- {
- extern char *arpadate();
-
- fputs("Date: ", fp);
- fputs(arpadate(NULL), fp);
- fputs("\n", fp);
- }
- /*
- ** PUTFROM -- Put the from field into the message.
- **
- ** Parameters:
- ** fp -- file to put it onto.
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** output onto fp.
- */
-
- putfrom(fp)
- register FILE *fp;
- {
-
- fputs("From: ", fp);
- fputs(From, fp);
- fputs("@Berkeley\n", fp);
- }
-