home *** CD-ROM | disk | FTP | other *** search
- From: mj@dfv.rwth-aachen.de (Martin Junius)
- Newsgroups: alt.sources
- Subject: FIDOGATE 03/06
- Message-ID: <mj.675078404@suntex>
- Date: 24 May 91 09:46:44 GMT
-
- ---- Cut Here and feed the following to sh ----
- #!/bin/sh
- # This is part 03 of a multipart archive
- # ============= rfmail.c ==============
- if test -f 'rfmail.c' -a X"$1" != X"-c"; then
- echo 'x - skipping rfmail.c (File already exists)'
- else
- echo 'x - extracting rfmail.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'rfmail.c' &&
- /*:ts=4*/
- /*****************************************************************************
- X * FIDOGATE --- Gateway software UNIX <-> FIDO
- X *
- X * $Id: rfmail.c,v 2.24 91/05/22 20:13:26 mj Exp $
- X *
- X * Read mail or news from standard input and put it into spool-directory.
- X * rfmail is called by the included version of rmail (mail receiver)
- X * and by relaynews from the CNews software.
- X *
- X * $Log: rfmail.c,v $
- X * Revision 2.24 91/05/22 20:13:26 mj
- X * Removed additional '\n' in log file entry.
- X *
- X * Revision 2.23 91/05/21 09:41:23 mj
- X * rfmail now split messages larger than MAXMSGSIZE into several parts.
- X *
- X * Revision 2.22 91/05/21 08:48:52 mj
- X * Moved log entry for NetMail to here.
- X *
- X * Revision 2.21 91/05/19 17:23:16 mj
- X * Some changes. (what?)
- X *
- X * Revision 2.20 91/05/07 23:58:59 mj
- X * Changed usage of function parse_address() due to new return type.
- X *
- X * Revision 2.19 91/03/29 18:13:07 mj
- X * No more chmod(600) for news articles.
- X *
- X * Revision 2.18 91/01/05 13:07:34 mj
- X * Improved generation of FIDO `^AREPLY', use `References:' or `In-Reply-To:'
- X * even if no `Message-ID:' present. Fixed function get_header().
- X *
- X * Revision 2.17 90/12/09 18:36:48 mj
- X * Support for new `X' header in intermediate file taken from RFC `X-Flags:'.
- X * Crash mail is now possible via `X-Flags: C'.
- X *
- X * Revision 2.16 90/12/09 17:35:13 mj
- X * Fixed a small bug in subject handling.
- X *
- X * Revision 2.15 90/12/02 21:22:25 mj
- X * Changed program header to mention both authors of the original
- X * software posted to alt.sources.
- X *
- X * Revision 2.14 90/12/01 17:49:49 mj
- X * Major new feature: rfmail is now able to handle news articles posted
- X * to several newsgroup. For each newsgroup in the Newsgroups header a
- X * seperate spool file for the corresponding FIDO EchoMail area is created.
- X *
- X * Revision 2.13 90/11/23 21:52:14 mj
- X * Changed date output to be compliant with FTS-0001: `DD MON YY HH:MM:SS',
- X * so QMail hopefully won't mess around with rfmail's dates any more.
- X *
- X * Revision 2.12 90/11/23 20:42:36 mj
- X * Output of ^AREPLY no longer depends on real versus fake net address.
- X *
- X * Revision 2.11 90/11/20 21:09:35 mj
- X * Added support for ^AINTL kludge.
- X *
- X * Revision 2.10 90/11/05 20:50:55 mj
- X * Changed my signature in all program headers.
- X *
- X * Revision 2.9 90/11/01 14:53:43 mj
- X * Take last message id from RFC822 Message-ID/References header.
- X *
- X * Revision 2.8 90/11/01 14:35:05 mj
- X * Enabled generation of ^AREPLY kludge.
- X *
- X * Revision 2.7 90/10/29 21:20:15 mj
- X * Enabled generation of ^AMSGID kludge.
- X *
- X * Revision 2.6 90/09/16 17:36:25 mj
- X * Some changes. (what?)
- X *
- X * Revision 2.5 90/09/15 14:22:54 mj
- X * Bug in newsgroup<->area conversion removed.
- X *
- X * Revision 2.4 90/09/13 21:58:38 mj
- X * Two major changes:
- X * Improved handling of user names in addresses and real names.
- X * Normally we use real name from header lines, but in case of
- X * special addressing via '%', e.g. "... % MAUS AC", we must use
- X * name in address, because "% ..." is not in real name.
- X * rfmail now handles news messages too. `-n' option implemented for
- X * this purpose. Look up newsgroup<->area conversion in Areas file
- X * and generate tear, origin, seen-by and path line. No more need
- X * for the rfnews program.
- X *
- X * Revision 2.3 90/09/08 18:49:03 mj
- X * Move strsaveline() to xalloc.c
- X *
- X * Revision 2.2 90/09/03 17:57:44 mj
- X * Some changes. Generation of ^AMSGID and ^AREPLY not active
- X * at this point.
- X *
- X * Revision 2.1 90/08/12 14:16:05 mj
- X * Added output of FIDO `^AMSGID:' and `^AREPLY:' kludges to the
- X * spool file for fpack. These lines are generated from RFC 822
- X * header lines `Message-ID:' and `References:'.
- X *
- X * Revision 2.0 90/08/12 11:58:33 mj
- X * Rewrote much of the code of rfmail.c: Parsing of header is now
- X * much cleaner, changed the names of some functions, introduced
- X * other ones. Sending of mail to more than one user now really
- X * works.
- X *
- X * Revision 1.6 90/08/09 19:18:05 mj
- X * `Comment-To:' header line no longer makes it's way into the FIDO
- X * message.
- X *
- X * Revision 1.5 90/07/29 18:12:23 mj
- X * Place real net/node in message header for FIDO netmail. Also
- X * a `^AFMPT x' kludge is generated in this case. Recipient of
- X * our mail now gets real address from message, which should
- X * make replying much easier.
- X *
- X * Revision 1.4 90/07/07 18:23:53 mj
- X * Support for point addressing and the IFNA `^ATOPT x' kludge
- X * added to rfmail.
- X *
- X * Revision 1.3 90/07/01 13:46:04 mj
- X * Removed all calls to alloca(). All unsave malloc()'s without
- X * checking the returned pointer are now done via xmalloc().
- X * Fixed a malloc() error in rmail.
- X *
- X * Revision 1.2 90/06/28 22:04:43 mj
- X * Much rework of the sources, no more hsu.h and other clean up.
- X * rmail improved, now handles special XENIX quirks.
- X *
- X * Revision 1.1 90/06/21 21:09:34 mj
- X * Everything seems to work, so this delta was made.
- X *
- X * Revision 1.0 90/06/19 18:33:19 mj
- X * Initial revision
- X *
- X *
- X *****************************************************************************
- X * This version hacked and maintained by:
- X * _____ _____
- X * | |___ | Martin Junius FIDO: 2:242/6.1 2:242/6.0
- X * | | | | | | Republikplatz 3 DOMAIN: mju@dfv.rwth-aachen.de
- X * |_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931
- X *
- X * Original version of these programs and files:
- X *
- X * Teemu Torma
- X * Heikki Suonsivu FIDO: 2:504/1 UUCP: ...!mcsun!santra!hsu
- X *
- X *****************************************************************************/
- X
- #include "fidogate.h"
- X
- #include <varargs.h>
- #include <pwd.h>
- X
- X
- X
- #define PROGRAMNAME "rfmail $Revision: 2.24 $"
- X
- #define ORIGIN "Link to news/mail at hippo.uucp"
- X
- /*
- X * Max. message size for FIDO. Due to some more brain damage in FIDONET
- X * programs we have to split larger messages into several smaller ones.
- X * QMail moved messages larger than 16K to the BADMSG directory. We use
- X * 15000 bytes as the max. message size, this leaves enough room for
- X * header and other things.
- X */
- #define MAXMSGSIZE 15000
- X
- X
- X
- extern struct passwd *getpwuid();
- extern int getopt();
- extern char *optarg;
- extern int optind;
- extern void exit();
- extern char *spoolfile(), *basename();
- extern char *regex();
- extern time_t time();
- extern FILE *popen();
- X
- X
- /* Verbosity */
- int verbose = INIT_VERBOSE;
- X
- /* Private mail (default) */
- bool private = TRUE;
- X
- /* News-article */
- int newsmode = FALSE;
- X
- /* Our net/node information */
- Node this;
- X
- /*
- X * Global array to save message header
- X */
- #define MAXHEADERS 50
- X
- char *headers[MAXHEADERS];
- X
- X
- X
- /*
- X * get_header() --- Get specific message header from headers[]
- X *
- X * Example:
- X * To: mj@hippo.uucp (Martin Junius)
- X * Use:
- X * get_header("To") -> "mj@hippo.uucp (Martin Junius)"
- X */
- X
- char *get_header(name)
- char *name;
- {
- register int i, len;
- X
- X len = strlen(name);
- X for(i=0; i<MAXHEADERS && headers[i]; i++)
- X if(!strncmp(headers[i], name, len) && headers[i][len]==':')
- X return(headers[i] + strlen(name) + 2); /* +2 for ": " */
- X return(NULL);
- }
- X
- X
- X
- /*
- X * Extract address/name from `From:', `Reply-To:' or `To:' field.
- X * Understood formats:
- X * full name <address>
- X * address (full name)
- X * address
- X */
- X
- void get_address(field, address)
- char *field, *address;
- {
- register char *cp, *np;
- X
- X if ((cp = strchr(field, '(')) && strchr(cp + 1, ')')) {
- X /* format is 'address (full name)' */
- X for (np = field; np < cp - 1; np++)
- X *address++ = *np;
- X *address = 0;
- X }
- X else if ((cp = strchr(field, '<')) && (np = strchr(cp + 1, '>'))) {
- X /* format is 'full name <address>' */
- X cp++;
- X while (cp < np)
- X *address++ = *cp++;
- X *address = 0;
- X }
- X else
- X /* line contains only address */
- X strcpy(address, field);
- }
- X
- void get_name(field, name)
- char *field;
- char *name;
- {
- register char *cp, *np;
- X
- X if ((cp = strchr(field, '(')) && (np = strchr(cp + 1, ')'))) {
- X /* format is 'address (full name)' */
- X for(cp++; *cp && cp<np; cp++)
- X *name++ = *cp;
- X *name= 0;
- X }
- X else if ((cp = strchr(field, '<')) && (np = strchr(cp + 1, '>'))) {
- X /* format is 'full name <address>' */
- X for(cp=field; *cp && *cp!='<' && *(cp+1)!='<'; cp++)
- X *name++ = *cp;
- X *name = 0;
- X }
- X else
- X /* line contains only address */
- X *name = 0;
- }
- X
- X
- X
- /*
- X * Get return address for returning undeliverable mail to sender.
- X * Extract it from Reply-To: or From: fields.
- X */
- X
- void
- get_return_address(address)
- char *address;
- {
- char buffer[BUFSIZ];
- char *field;
- X
- X *address = 0;
- X
- X /* check is there is Reply-To: field */
- X if(field = get_header("Reply-To")) {
- X get_address(field, address);
- X return;
- X }
- X
- X /* no Reply-To:, check for From: */
- X if(field = get_header("From")) {
- X get_address(field, address);
- X return;
- X }
- X
- X /* not found, send it to root */
- X strcpy(address, "root");
- }
- X
- X
- X
- /*
- X * Open stream associated with programs standard input. Program is invoked
- X * with given argument list. Popen(3S) would invoke mailer thru sh(1),
- X * so this uses less memory and is faster.
- X */
- X
- FILE *open_mailer(program, args, pid)
- char *program, **args;
- int *pid;
- {
- FILE *fp;
- int fd[2];
- X
- X /* create pipe */
- X if (pipe(fd) == -1) {
- X perror("rfmail: pipe");
- X exit(EX_OSERR);
- X }
- X
- X switch (*pid = fork()) {
- X case -1: /* Error */
- X perror("rfmail: fork failed");
- X exit(EX_OSERR);
- X case 0: /* Child */
- X (void) close(0);
- X if (dup(fd[0]) == 0) {
- X (void) close(fd[0]);
- X (void) close(fd[1]);
- X (void) execvp(program, args);
- X perror(program);
- X }
- X else
- X perror("rfmail: dup");
- X exit(EX_OSERR);
- X default: /* Parent */
- X (void) close(fd[0]);
- X if ((fp = fdopen(fd[1], "w")) == NULL) {
- X perror("rfmail: fdopen");
- X exit(EX_OSERR);
- X }
- X }
- X return fp;
- }
- X
- X
- X
- /*
- X * In case of error send mail back to sender.
- X * First argument is file pointer for mail file, the following
- X * are format string and args for printf().
- X */
- X
- /**VARARGS**/
- void sendback(va_alist)
- va_dcl
- {
- va_list args;
- FILE *mail;
- char *fmt;
- X
- #ifdef RETURN_FAILED_MAIL
- FILE *mailer;
- char to[128];
- char *argv[3];
- int pid;
- char buffer[BUFSIZ];
- int i;
- #endif /* RETURN_FAILED_MAIL */
- X
- X va_start(args);
- X mail = va_arg(args, FILE *);
- X fmt = va_arg(args, char *);
- X
- #ifdef RETURN_FAILED_MAIL
- X get_return_address(to);
- X log("Mail failed, return to %s", to);
- X
- X argv[0] = RMAIL;
- X argv[1] = to;
- X argv[2] = NULL;
- X mailer = open_mailer(RMAIL, argv, &pid);
- X if(!mailer) {
- X log("$Unable to invoke mailer for returned mail");
- X va_end(args);
- X return;
- X }
- X
- X /* print correct header for mailer */
- X fprintf(mailer, "From rfmail %s\n", date("%a %h %d %T 19%y", (long *) 0));
- X fprintf(mailer, "Received: by %s (%s/%s)\n",
- X internode(this), PROGRAMNAME, this.name);
- X fprintf(mailer, "\tid AA%05d; %s\n", getpid(),
- X date("%a, %d %h %y %T %o (%z)", (long *) 0));
- X fprintf(mailer, "Date: %s\n", date("%a, %d %h %y %T %o", (long *) 0));
- X fprintf(mailer, "From: Gateway to FIDONet <%s@%s>\n",
- X "rfmail", internode(this));
- X fprintf(mailer, "Subject: Returned mail: Unable to deliver mail to FIDONet\n");
- X fprintf(mailer, "Message-Id: <%s.AA%05d@%s>\n",
- X date("%y%m%q%H%M", (long *) 0), getpid(),
- X internode(this));
- X fprintf(mailer, "To: %s\n", to);
- X fprintf(mailer, "\n");
- X fprintf(mailer, " ----- Transcript of session follows -----\n");
- X vfprintf(mailer, fmt, args);
- X fprintf(mailer, "\n\n");
- X fprintf(mailer, " ----- Unsent message follows -----\n");
- X
- X /* Copy removed header line */
- X for(i=0; i<MAXHEADERS && headers[i]; i++)
- X fprintf(mailer, "%s\n", headers[i]);
- X fprintf(mailer, "\n");
- X
- X /* now copy the message to mailer */
- X rewind(mail);
- X while (fgets(buffer, BUFSIZ, mail))
- X fputs(buffer, mailer);
- X
- X /* mail is now sent, close mailer */
- X fclose(mailer);
- X
- #else /**!RETURN_FAILED_MAIL**/
- X mail = va_arg(args, FILE*);
- X fmt = va_arg(args, char *);
- X
- X vfprintf(stderr, fmt, args);
- #endif /* not RETURN_FAILED_MAIL */
- X
- X va_end(args);
- }
- X
- X
- X
- /* Check that net/node exists and mail can be send to there (ie. it
- X is not down or in hold). Also be will replace name with sysop's name,
- X if mail is for sysop (note that alias will override this sysop-name).
- X Mail will be send back to sender, if this checking fails. */
- X
- int
- valid_netnode(name, node, mail)
- X char *name;
- X Node node;
- X FILE *mail;
- {
- #ifdef NODELIST_SUPPORT
- X Node *entry;
- X
- X if (entry = node_entry(node))
- X switch (entry->type)
- X {
- X case HOLD:
- X /* node is in hold */
- X sendback(mail, "Node %s is in hold", ascnode(node));
- X return EX_NOHOST;
- X case DOWN:
- X /* node is down */
- X sendback(mail, "Node %s is currently down", ascnode(node));
- X return EX_NOHOST;
- X default:
- X /* everything was fine */
- X if (!strcmp(name, "sysop") || !strcmp(name, "Sysop"))
- X (void) strcpy(name, entry->sysop);
- X return EX_OK;
- X }
- X
- X /* we didn't find node */
- X sendback(mail, "Node %s does not exist", ascnode(node));
- X return EX_NOHOST;
- #else
- X return EX_OK;
- #endif
- }
- X
- X
- X
- /*
- X * Return sender of mail. Figure it out from From: field or from
- X * our uid if it's not administrative uid (e.g. uucp or nuucp).
- X * If not there, try $HOME/.fullname, then
- X * $HOME/.realname, then
- X * environment string NAME.
- X * If neither method works, return NULL.
- X * If $HOME is not defined, skip both .fullname and .realname
- X */
- X
- char *mail_sender()
- {
- struct passwd *pwd;
- static char name[36];
- char buffer[BUFSIZ];
- register char *cp, *np;
- register int cnt;
- Node dummynode;
- FILE *fp;
- char *from;
- X
- X name[35] = 0;
- X buffer[0] = 0;
- X
- X if(from = get_header("From"))
- X strcpy(buffer, from);
- X
- X if(*buffer) {
- X debug(2, "Checking From: field");
- X /*
- X * Parse the name out from From: field. there are basically
- X * two kinds of formats: 'User Name <address>' or
- X * 'address (User Name)'. We'll try to figure it out
- X * which format sender uses.
- X */
- X if ((cp = strchr(buffer, '<')) && (np = strchr(cp, '>'))) {
- X /* Format is 'From: Name <address>' */
- X for(np = buffer,
- X cnt = 0; np < cp - 1 && cnt < 35;
- X np++, cnt++)
- X name[cnt] = *np;
- X name[cnt] = 0;
- X debug(2, "Got name %s, fmt name <address>", name);
- X }
- X else if ((cp = strchr(buffer, '(')) && (np = strchr(cp, ')'))) {
- X /* Format is 'From: address (Name)' */
- X for (cnt = 0, cp++; cp < np && cnt < 35; cp++, cnt++)
- X name[cnt] = *cp;
- X name[cnt] = 0;
- X debug(2, "Got name %s, fmt address (name)", name);
- X }
- X else {
- X debug(5, "Could no find realname in <> or ()");
- X /* Try parse it with parse_address */
- X if (parse_address(buffer, name, &dummynode)) {
- X (void) strncpy(name, buffer, 35);
- X name[35] = 0;
- X debug(2, "No format in From: line, name %s", name);
- X }
- X else {
- X name[35] = 0;
- X debug(2, "Name %s parsed from address", name);
- X }
- X }
- X return name;
- X }
- X
- X /* hmm.. no From: field in mail. let's try to figure this problem
- X out some other way. If our uid is some user's uid, we'll use
- X that uid to show user's name, otherwise we'll return NULL. */
- X
- X if (getuid() >= USERUID && (pwd = getpwuid( (int) getuid())))
- X {
- X /* There are two commonly used gecos-formats: So called USG
- X format used by System III and System V machines and BSD
- X format used by BSD machines. In USG format name is
- X sandwitched between '-' and '(' characters and in BSD
- X format name is first this in gecos-field up to first comma
- X in it. In many machines there's only name in gecos. */
- X
- X if ((cp = strchr(pwd->pw_gecos, '-')) && (np = strchr(cp, '(')))
- X {
- X /* USG format 'stuff-name(stuff)' */
- X for (cnt = 0, cp++; cnt < 35 && cp < np; cp++, cnt++)
- X name[cnt] = *cp;
- X name[cnt] = 0;
- X debug(3, "Got name from USG fmt, name %s", name);
- X }
- X else
- X if (cp = strchr(pwd->pw_gecos, ','))
- X {
- X /* BSD format 'name,stuff...' */
- X for (cp = buffer, cnt = 0; cnt < 35 && *cp != ','; cp++, cnt++)
- X name[cnt] = *cp;
- X name[cnt] = 0;
- X debug(3, "Got name from BSD format, name %s", name);
- X }
- X else
- X if (*pwd->pw_gecos)
- X {
- X /* non-empty gecos, assume that there's only name */
- X (void) strncpy(name, pwd->pw_gecos, 35);
- X name[35] = 0;
- X debug(3, "No fmt in gecos, name %s", name);
- X }
- X else
- X {
- X /* Lazy administrator or user who want's to be anonymous
- X (or this is some administrative uid with no explanation
- X which)... We'll use only the username. */
- X
- X (void) strncpy(name, pwd->pw_name, 35);
- X /* never heard over 35 char usernames???? I haven't but... */
- X name[35] = 0;
- X debug(3, "No gecos, name = %s");
- X }
- X return name;
- X }
- X
- X *buffer = 0;
- X if (cp = getenv("HOME"))
- X {
- X debug(5, "Try .fullname");
- X if (fp = fopen(sprintfs("%s/%s", cp, ".fullname"), "r"))
- X {
- X if (!fgets(buffer, BUFSIZ, fp)) *buffer = 0;
- X fclose(fp);
- X strncpy(name, buffer, 35);
- X if (!strempty(name))
- X {
- X strclean(name);
- X debug(2, "Got name %s from .fullname", name);
- X return name;
- X }
- X else
- X debug(1, "Empty name '%s' in .fullname", name);
- X }
- X debug(5, "Try .realname");
- X if (fp = fopen(sprintfs("%s/%s", cp, ".realname"), "r"))
- X {
- X if (!fgets(buffer, BUFSIZ, fp)) *buffer = 0;
- X fclose(fp);
- X strncpy(name, buffer, 35);
- X if (!strempty(name))
- X {
- X strclean(name);
- X debug(2, "Got name %s from .realname", name);
- X return name;
- X }
- X else
- X debug(1, "Empty name '%s' in .realname", name);
- X }
- X }
- X
- X if (cp = getenv("NAME"))
- X {
- X debug(5, "Name defined, use it");
- X strncpy(name, buffer, 35);
- X if (!strempty(name))
- X {
- X strclean(name);
- X debug(2, "Got name %s from environment NAME", name);
- X return name;
- X }
- X }
- X
- X debug(2, "No name, uid = %d", getuid());
- X
- X return (char *) 0;
- }
- X
- X
- X
- /* Get net/node information from info. If zone, net, or point are missing,
- X they will be returned as -1TRUE is returned, if
- X everything went fine, otherwise FALSE. */
- X
- bool
- getnode(info, node)
- X char *info;
- X Node *node;
- {
- X /* Extract zone information */
- X if (strchr(info, ':'))
- X {
- X for (node->zone = 0; *info != ':'; info++)
- X if (isdigit(*info))
- X node->zone = node->zone * 10 + *info - '0';
- X else
- X {
- X debug(1, "Invalid character in zone '%c' %02x", *info, *info);
- X return FALSE;
- X }
- X info++;
- X }
- X else
- X node->zone = -1;
- X
- X /* Extract net information if net is present, otherwise
- X set net to -1. */
- X
- X if (strchr(info, '/'))
- X {
- X for (node->net = 0; *info != '/'; info++)
- X if (isdigit(*info))
- X node->net = node->net * 10 + *info - '0';
- X else
- X {
- X debug(1, "Invalid character in net '%c' %02x", *info, *info);
- X return FALSE;
- X }
- X info++;
- X }
- X else
- X node->net = -1;
- X
- X /* Exract node information, set to -1 if empty. */
- X
- X if (*info)
- X for (node->node = 0; *info && *info != '.'; info++)
- X if (isdigit(*info))
- X node->node = node->node * 10 + *info - '0';
- X else
- X {
- X debug(1, "Invalid characer in node '%c' %02x", *info, *info);
- X return FALSE;
- X }
- X else
- X node->node = -1;
- X
- X /* Exract point information, set to -1 if empty. */
- X
- X if (*info)
- X for (node->point = 0; *info; info++)
- X if (isdigit(*info))
- X node->point = node->point * 10 + *info - '0';
- X else
- X {
- X debug(1, "Invalid characer in node '%c' %02x", *info, *info);
- X return FALSE;
- X }
- X else
- X node->point = -1;
- X
- X debug(2, "Got alias %s", ascnode(*node));
- X return TRUE;
- }
- X
- /* Compare receiver and user in aliasfile. Each line in aliasfile contains
- X alias, optional net/node information separated by commas zero or
- X more times, white space(s) and rest of the line literally to whom
- X mail should be send. Net and node information is format 'net/node'.
- X if net is omitted then every net is counted, if node is omitted,
- X then all nodes in that net. If net is omitted, slash may be left off.
- X
- X E.g following are valid aliases:
- X
- X tot,504/ Teemu Torma
- X foo Foo Bar
- X sysop,504/1,504/9 System Operator */
- X
- bool aliascmp(alias, to, node)
- char *alias, *to;
- Node *node;
- {
- char buffer[BUFSIZ];
- char *cp;
- Node anode;
- X
- X while (*alias && *alias != ',' && !isspace(*alias) && *to)
- X if (*alias++ != *to++)
- X return FALSE;
- X
- X if(*to)
- X return FALSE;
- X
- X if (isspace(*alias)) /* match */
- X return TRUE;
- X
- X if (*alias == ',') {
- X /* copy alias to buffer and terminate the it after first space */
- X strcpy(buffer, alias + 1);
- X for (cp = buffer; *cp; cp++)
- X if (isspace(*cp)) {
- X *cp = 0;
- X break;
- X }
- X
- X /* get net/node information from buffer one at the time */
- X for (cp = strtok(buffer, ","); cp; cp = strtok((char *) 0, ",")) {
- X debug(2, "Got node '%s'", cp);
- X if (getnode(cp, &anode)) {
- X if ((anode.zone == -1 || anode.zone == node->zone ) &&
- X (anode.net == -1 || anode.net == node->net ) &&
- X (anode.node == -1 || anode.node == node->node ) &&
- X (anode.point == -1 || anode.point == node->point) )
- X return TRUE;
- X }
- X else
- X return FALSE;
- X }
- X }
- X else
- X debug(1, "Invalid alias, %c is not ',' or white space", *alias);
- X
- X return FALSE;
- }
- X
- X
- X
- /* Return receiver's name. If name is aliased, return it, otherwise
- X return receiver's name. */
- X
- char *receiver(to, node)
- char *to;
- Node *node;
- {
- static char name[36];
- char buffer[BUFSIZ];
- register int cnt;
- register char *cp;
- FILE *fp;
- int i, c, convert_flag;
- X
- X debug(3, "Name for alias checking: %s", to);
- X
- X if (fp = fopen(ALIAS, "r")) {
- X while (fgets(buffer, BUFSIZ, fp)) {
- X buffer[strlen(buffer) - 1] = 0;
- X if (*buffer != '#')
- X debug(3, "Checking for alias %s", buffer);
- X if (*buffer != '#' && aliascmp(buffer, to, node)) {
- X /* match, save the alias. */
- X for (cp = buffer; *cp && !isspace(*cp); cp++)
- X /* skip alias itself */;
- X while (isspace(*cp))
- X cp++;
- X if (*cp) {
- X for (cnt = 0; *cp && cnt < 35; cnt++, cp++)
- X name[cnt] = *cp;
- X name[cnt] = 0;
- X debug(2, "Got alias %s", name);
- X fclose(fp);
- X return name;
- X }
- X else
- X debug(1, "Missing alias");
- X }
- X }
- X fclose(fp);
- X }
- X else
- X log("$Unable to open aliasfile %s", ALIAS);
- X
- X /*
- X * Alias not found. Return the the original receiver with all
- X * '_' characters replaced by space and all words capitalized.
- X */
- X convert_flag = isupper(*to) ? -1 : 1;
- X for(i=0; *to && i<35; i++, to++) {
- X c = *to;
- X switch(c) {
- X case '_':
- X name[i] = ' ';
- X if(!convert_flag)
- X convert_flag = 1;
- X break;
- X case '%':
- X if(convert_flag != -1)
- X convert_flag = 2;
- X /**Fall thru**/
- X default:
- X if(convert_flag > 0) {
- X name[i] = islower(c) ? toupper(c) : c;
- X if(convert_flag == 1)
- X convert_flag = 0;
- X }
- X else
- X name[i] = c;
- X break;
- X }
- X }
- X name[i] = 0;
- X
- X debug(2, "No alias, name %s", name);
- X return name;
- }
- X
- X
- X
- /*
- X * Return from field for FIDO message.
- X * Alias checking is done via receiver().
- X */
- X
- char *mail_receiver(address, node)
- char *address;
- Node *node;
- {
- char *cp;
- int found = 0;
- char name[36];
- char realname[36];
- char addr[128];
- char *to;
- Node dummy;
- X
- X realname[0] = 0;
- X
- X if(address) {
- X /*
- X * Address is argument
- X */
- X debug(2, "Address to parse: %s", address);
- X if(parse_address(address, name, node)) {
- X log("Parse of address %s failed", address);
- X return NULL;
- X }
- X }
- X else {
- X /*
- X * Address is echo feed
- X */
- X node->zone = MY_ZONE;
- X node->net = ECHOFEED_NET;
- X node->node = ECHOFEED_NODE;
- X node->point = 0;
- X strcpy(name, "All");
- X }
- X
- X /*
- X * Try to look up a better real name in header fields
- X *
- X * Standard RFC822 header line
- X */
- X if(to = get_header("To")) {
- X debug(2, "Checking To: field");
- X get_address(to, addr);
- X if(!address || !strcmp(address, addr)) {
- X get_name(to, realname);
- X found = 1;
- X }
- X }
- X
- X /*
- X * User-defined header line for gateway software
- X * (can be patched into news reader)
- X */
- X if(!found && (to = get_header("Comment-To"))) {
- X debug(2, "Checking Comment-To: field");
- X get_address(to, addr);
- X if(!address || !strcmp(address, addr)) {
- X get_name(to, realname);
- X found = 1;
- X }
- X }
- X
- X /*
- X * Header generated by nn's `r' command
- X */
- X if(!found && (to = get_header("Orig-To"))) {
- X debug(2, "Checking Orig-To: field");
- X get_address(to, addr);
- X if(!address || !strcmp(address, addr)) {
- X get_name(to, realname);
- X found = 1;
- X }
- X }
- X
- X /*
- X * News message: get name from address taken out of header line
- X */
- X if(found && !address)
- X parse_address(addr, name, &dummy);
- X
- X /*
- X * Use real name from header line, if no special addressing with '%'
- X */
- X if(found && !strchr(name, '%') && *realname)
- X strcpy(name, realname);
- X
- X return receiver(name, node);
- }
- X
- X
- X
- /*
- X * Get date field for FIDO message. Look for `Date:' header or use
- X * current time.
- X */
- X
- char *fido_date()
- {
- time_t timevar;
- struct tm *localtime();
- struct tm *mtime;
- static char timebuf[20];
- /* literal months */
- static char *months[] = {
- X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- X (char *) 0,
- };
- /* Literal weekdays */
- static char *wkdays[] = {
- X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", (char *) 0,
- };
- char *header_date;
- X
- X if(header_date = get_header("Date")) {
- X /* try to extract date and other information from it */
- X debug(2, "Found date: '%s'", header_date);
- X timevar = getdate(header_date, NULL);
- X }
- X else
- X timevar = time(0);
- X
- X debug(2, "timevar %ld", timevar);
- X mtime = localtime(&timevar);
- X /* Save date in FTS-0001 format ! */
- X sprintf(timebuf, "%02d %3s %02d %02d:%02d:%02d",
- X mtime->tm_mday, months[mtime->tm_mon], mtime->tm_year,
- X mtime->tm_hour, mtime->tm_min, mtime->tm_sec );
- X debug(1, "Returning %s", timebuf);
- X return timebuf;
- }
- X
- X
- X
- char *estrtok(s, sep)
- char *s, *sep;
- {
- X char *p;
- X
- X if (p = strtok(s, sep))
- X return p;
- X return "";
- }
- X
- X
- X
- /*
- X * Output mail/news messages into spool file(s) for fpack
- X */
- X
- #define NGROUPS 10
- #define NFIDO 6
- X
- #define FIDO_NODE 0
- #define FIDO_TO 1
- #define FIDO_FROM 2
- #define FIDO_SUBJECT 3
- #define FIDO_DATE 4
- #define FIDO_FLAGS 5
- X
- int send_mail(fp, to, split)
- FILE *fp; /* Temporary file message body */
- char *to; /* Adress to send to (news = NULL) */
- int split; /* Split message into several parts */
- {
- char buffer[BUFSIZ];
- char groups[BUFSIZ];
- char *group[NGROUPS];
- Node node;
- char *p;
- char *fido_header[NFIDO];
- char *area;
- char *newsgroup;
- FILE *fpareas;
- int status;
- int i;
- X
- X if(to)
- X debug(1, "Sending mail to %s", to);
- X else
- X debug(1, "Sending news");
- X
- X /*
- X * Get to/from/node/subject/date
- X */
- X fido_header[FIDO_TO] = mail_receiver(to, &node);
- X if(!fido_header[FIDO_TO]) {
- X sendback(fp, "Illegal address %s", to);
- X return(EX_NOHOST);
- X }
- X
- X fido_header[FIDO_FROM] = mail_sender();
- X if(!fido_header[FIDO_FROM])
- X fido_header[FIDO_FROM] = "Gateway to FIDONET";
- X
- X fido_header[FIDO_NODE] = ascnode(node);
- X
- X fido_header[FIDO_SUBJECT] = get_header("Subject");
- X if(!fido_header[FIDO_SUBJECT])
- X fido_header[FIDO_SUBJECT] = "Mail from Gateway to FIDONET";
- X
- X fido_header[FIDO_DATE] = fido_date();
- X
- X fido_header[FIDO_FLAGS] = get_header("X-Flags");
- X if(!fido_header[FIDO_FLAGS])
- X fido_header[FIDO_FLAGS] = "";
- X
- X debug(2, "FIDO Node: %s", fido_header[FIDO_NODE]);
- X debug(2, "FIDO To: %s", fido_header[FIDO_TO]);
- X debug(2, "FIDO From: %s", fido_header[FIDO_FROM]);
- X debug(2, "FIDO Subject: %s", fido_header[FIDO_SUBJECT]);
- X debug(2, "FIDO Date: %s", fido_header[FIDO_DATE]);
- X debug(2, "FIDO Flags: %s", fido_header[FIDO_DATE]);
- X
- X if(newsmode) {
- X /*
- X * News message: get newsgroups and convert to FIDO areas
- X */
- X p = get_header("Newsgroups");
- X if(!p) {
- X sendback(fp, "No Newsgroups header in news message");
- X return(EX_DATAERR);
- X }
- X strcpy(groups, p);
- X debug(3, "Newsgroups '%s'", groups);
- X
- X for(i=0, p=strtok(groups, ","); p && i<NGROUPS; p=strtok(NULL, ","), i++)
- X group[i] = p;
- X for(; i<NGROUPS; i++)
- X group[i] = NULL;
- X
- X fpareas = pfopen(LIBDIR, "Areas", "r");
- X if(!fpareas) {
- X log("$Can't open areas file");
- X sendback(fp, "Internal error: can't open file");
- X return(EX_IOERR);
- X }
- X
- X for(i=0; i<NGROUPS && group[i]; i++) {
- X p = group[i];
- X debug(3, "Look up newsgroup %s", p);
- X rewind(fpareas);
- X while(getcl(buffer, BUFSIZ, fpareas)) {
- X area = estrtok(buffer, " \t");
- X newsgroup = estrtok(NULL, " \t");
- X debug(4, "Checking newsgroup %s", newsgroup);
- X if(!strcmp(newsgroup, p)) { /* Found */
- X debug(4, "Found area %s", area);
- X break;
- X }
- X area = NULL;
- X }
- #if 0
- X if(!area) {
- X log("No EchoMail area found for newsgroup '%s'", p);
- /* area = "JUNK"; /**/
- X }
- #endif
- X if(area) {
- X debug(3, "Sending message to area '%s'", area);
- X status = send_message(fp, node, fido_header, area, split);
- X if(status)
- X return(status);
- X }
- X }
- X }
- X else {
- X /*
- X * NetMail message
- X */
- X p = get_header("From");
- X log("%s -> %s @ %s", p ? p : fido_header[FIDO_FROM],
- X fido_header[FIDO_TO], fido_header[FIDO_NODE] );
- X return(send_message(fp, node, fido_header, NULL, split));
- X }
- X
- X return EX_OK;
- }
- X
- X
- int send_message(fp, node, fido_header, area, split)
- FILE *fp;
- Node node;
- char *fido_header[];
- char *area;
- int split;
- {
- char buffer[BUFSIZ];
- FILE *sf;
- char *sfile;
- char *header;
- int part = 1;
- long size;
- X
- X rewind(fp);
- X
- X /*
- X * Open spool file for output
- X */
- again:
- X sf = fopen(sfile = spoolfile("M."), "w");
- X if(!sf) {
- X log("$Unable to open spoolfile %s", sfile);
- X return(EX_CANTCREAT);
- X }
- X
- X /* set correct permissions for spoolfile and lock it */
- X if(private)
- X chmod(sfile, 0600);
- X lock(fileno(sf));
- X
- X /*
- X * Header for fpack
- X * N destination node
- X * T destination name
- X * F from name
- X * S subject
- X * D date
- X * X flags (P=private, C=crash)
- X */
- X fprintf(sf, "N %s\n", fido_header[FIDO_NODE]);
- X fprintf(sf, "T %s\n", fido_header[FIDO_TO]);
- X fprintf(sf, "F %s\n", fido_header[FIDO_FROM]);
- X if(split)
- X fprintf(sf, "S %c: %s\n", part + '@', fido_header[FIDO_SUBJECT]);
- X else
- X fprintf(sf, "S %s\n", fido_header[FIDO_SUBJECT]);
- X fprintf(sf, "D %s\n", fido_header[FIDO_DATE]);
- X fprintf(sf, "X %s%s\n", private ? "P" : "", fido_header[FIDO_FLAGS]);
- X fprintf(sf, "\n");
- X
- X
- X if(newsmode) {
- X /*
- X * Add AREA:... line for echo mail
- X */
- X fprintf(sf, "AREA:%s\n", area);
- X }
- X else {
- X /*
- X * Add IFNA kludges for zone/point addressing
- X */
- X if(private && (node.zone != MY_ZONE))
- X fprintf(sf, "\001INTL %s %s\n", ascnoden(node), ascnoden(this));
- X if(private && REAL_POINT)
- X fprintf(sf, "\001FMPT %d\n", REAL_POINT);
- X if(node.point)
- X fprintf(sf, "\001TOPT %d\n", node.point);
- X }
- X
- X /*
- X * Add kludge for MSGID / REPLY
- X */
- X if(header = get_header("Message-ID")) {
- X if(print_msgid(sf, "MSGID", header))
- X print_local_msgid(sf);
- X if(header = get_header("References"))
- X print_msgid(sf, "REPLY", header);
- X else if(header = get_header("In-Reply-To"))
- X print_msgid(sf, "REPLY", header);
- X }
- X else {
- X print_local_msgid(sf);
- X if(header = get_header("In-Reply-To"))
- X print_msgid(sf, "REPLY", header);
- X }
- X
- X /*
- X * Add some header lines
- X */
- X if(header = get_header("From"))
- X fprintf(sf, "From: %s\n", header);
- X if(header = get_header("Reply-To"))
- X fprintf(sf, "Reply-To: %s\n", header);
- X if(header = get_header("To"))
- X fprintf(sf, "To: %s\n", header);
- X if(header = get_header("Cc"))
- X fprintf(sf, "Cc: %s\n", header);
- X if(header = get_header("Newsgroups"))
- X if(strchr(header, ',')) /* Posted to multiple groups */
- X fprintf(sf, "Newsgroups: %s\n", header);
- X fprintf(sf, "\n");
- X
- X /*
- X * Add line indicating splitted message
- X */
- X if(split)
- X fprintf(sf, " * Large message splitted by rfmail: part %02d/%02d\n\n",
- X part, split );
- X
- X /*
- X * Copy mail file
- X */
- X size = 0;
- X debug(3, "Copying mail");
- X while(fgets(buffer, BUFSIZ, fp)) {
- X fputs(buffer, sf);
- X size += strlen(buffer) + 1;
- X if(size > MAXMSGSIZE) {
- X if(newsmode)
- X print_origin(sf);
- X fclose(sf);
- X part++;
- X goto again;
- X }
- X }
- X
- X /*
- X * If message is for echo mail (-n flag) then add
- X * tear, origin, seen-by and path line.
- X */
- X if(newsmode)
- X print_origin(sf);
- X
- X /*
- X * Done
- X */
- X fclose(sf);
- X return EX_OK;
- }
- X
- X
- X
- /*
- X * Generate origin, seen-by and path line
- X */
- X
- int print_origin(fp)
- FILE *fp;
- {
- X fprintf(fp, "\n--- %s\n", PROGRAMNAME);
- X fprintf(fp, " * Origin: %s (%d:%d/%d.%d)\n", ORIGIN,
- X REAL_ZONE, REAL_NET, REAL_NODE, REAL_POINT);
- X fprintf(fp, "SEEN-BY: %d/%d ", MY_NET, MY_NODE);
- X if(ECHOFEED_NET != MY_NET)
- X fprintf(fp, "%d/", ECHOFEED_NET);
- X fprintf(fp,"%d\n", ECHOFEED_NODE);
- X fprintf(fp, "\001PATH: %d/%d\n", MY_NET, MY_NODE);
- }
- X
- X
- X
- /*
- X * Generate new FIDO kludge: `^AMSGID:' and `^AREPLY:'
- X */
- X
- int print_msgid(fp, name, message_id)
- FILE *fp;
- char *name;
- char *message_id;
- {
- char *id, *host, *p;
- char *savep;
- Node node;
- long atol();
- X
- X savep = message_id = strsave(message_id);
- X /*
- X * Format of message_id is "<identification@host.domain> ..."
- X * We want the the last one in the chain, which is the message id
- X * of the article replied to.
- X */
- X message_id = strrchr(message_id, '<');
- X if(!message_id)
- X goto error;
- X id = message_id+1;
- X host = strchr(message_id, '@');
- X if(!host)
- X goto error;
- X *host++ = 0;
- X p = strchr(host, '>');
- X if(!p)
- X goto error;
- X *p = 0;
- X
- X /*
- X * First let's test id. If it is entirely numeric, we can use
- X * it for the 32-bit number in ^AMSGID, else give up.
- X */
- X for(p=id; *p; p++)
- X if(!isdigit(*p))
- X goto error;
- X
- X /*
- X * Try to interprete host as a FIDO node. If this succeedes
- X * print out host as <zone>:<net>/<node>[.<point>], else
- X * print host as we got it from message_id.
- X */
- X if(!parseinternode(host, &node))
- X host = ascnode(node);
- X fprintf(fp, "\001%s: %s %08lx\n", name, host, atol(id));
- X
- X free(savep);
- X return(0);
- X
- error:
- X free(savep);
- X return(-1);
- }
- X
- X
- X
- /*
- X * Generate local `^AMSGID:' if none is found in message header
- X */
- X
- print_local_msgid(fp)
- FILE *fp;
- {
- long msgid;
- X
- X msgid = sequencer(MSGIDSEQ);
- X fprintf(fp, "\001MSGID: %s %08lx\n", ascnode(this), msgid);
- }
- X
- X
- X
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int cnt, c;
- FILE *mail;
- char buffer[BUFSIZ], tmpfile[L_tmpnam];
- int status = EX_OK;
- char *error;
- Node *node, mynode;
- int header_count;
- long size;
- int split;
- X
- X newsmode = FALSE;
- X
- X while ((c = getopt(argc, argv, "npvV:")) != EOF)
- X switch (c) {
- X case 'n':
- X /* Set news-mode */
- X newsmode = TRUE;
- X private = FALSE;
- X break;
- X case 'v':
- X /* set more verbosity */
- X verbose++;
- X break;
- X case 'V':
- X verbose = atoi(optarg);
- X break;
- X case 'p':
- X /* this is not private message */
- X private = FALSE;
- X break;
- X default:
- X fprintf(stderr, "%s\n\n", PROGRAMNAME);
- X fprintf(stderr, "usage: rfmail [-npv] [-V verbose_level] user ...\n\n");
- X exit(EX_USAGE);
- X break;
- X }
- X
- X /*
- X * Create temp file for saving standard input and open it
- X */
- X tmpnam(tmpfile);
- X if((mail = fopen(tmpfile, "w+")) == NULL) {
- X log("$Can not open %s for writing", tmpfile);
- X exit(EX_CANTCREAT);
- X }
- X /* protect mail file */
- X chmod(tmpfile, 0600);
- X
- X /*
- X * Read headers from stdin
- X */
- X header_count = 0;
- X while(fgets(buffer, BUFSIZ, stdin)) {
- X if(*buffer == '\n') /* End of header lines */
- X break;
- X if(header_count < MAXHEADERS)
- X headers[header_count++] = strsaveline(buffer);
- X }
- X
- X /*
- X * Copy remainder of stdin to temporary file and count size
- X */
- X size = 0;
- X while(fgets(buffer, BUFSIZ, stdin)) {
- X fputs(buffer, mail);
- X size += strlen(buffer) + 1; /* `+1' for additional CR */
- X }
- X split = size>MAXMSGSIZE ? size/MAXMSGSIZE + 1 : 0;
- X debug(3, "Message body size %ld", size);
- X if(split)
- X debug(3, "Must split message, %d parts", split);
- X
- #ifdef NODELIST_SUPPORT
- X /* update nodelist-index if needed */
- X if (error = update_index()) {
- X /* there was error while updating nodelist-index */
- X if (*error == '$')
- X sendback(mail, "%s: %s", error + 1, strerror(errno));
- X else
- X sendback(mail, "%s", error);
- X exit(EX_SOFTWARE);
- X }
- #endif
- X
- X mynode.zone = REAL_ZONE;
- X mynode.net = REAL_NET;
- X mynode.node = REAL_NODE;
- X mynode.point = REAL_POINT;
- X strcpy(mynode.name, MY_NAME);
- X
- #ifdef NODELIST_SUPPORT
- X if ((node = node_entry(mynode)) == NULL) {
- X (void) fprintf(stderr, "Unable to this node from nodelist\n");
- X log("No %s in nodelist", ascnode(mynode));
- X exit(EX_SOFTWARE);
- X }
- #else
- X node = &mynode;
- #endif
- X this = *node;
- X
- X
- X rewind(mail);
- X
- X if(newsmode)
- X /*
- X * Send mail to echo feed for news messages
- X */
- X status = send_mail(mail, NULL, split);
- X else
- X /*
- X * Send mail to addresses from command line args
- X */
- X for(cnt = optind; cnt < argc; cnt++)
- X if((status = send_mail(mail, argv[cnt], split)) != EX_OK)
- X break;
- X
- X /* remove temporary file */
- X fclose(mail);
- X unlink(tmpfile);
- X
- X exit(status);
- }
- SHAR_EOF
- chmod 0644 rfmail.c ||
- echo 'restore of rfmail.c failed'
- Wc_c="`wc -c < 'rfmail.c'`"
- test 36748 -eq "$Wc_c" ||
- echo 'rfmail.c: original size 36748, current size' "$Wc_c"
- fi
- true || echo 'restore of funcs.c failed'
- echo End of part 3, continue with part 4
- exit 0
-
- --
- _____ _____
- | |___ | Martin Junius FIDO: 2:242/6.1 2:242/6.0
- | | | | | | Republikplatz 3 DOMAIN: mj@dfv.rwth-aachen.de
- |_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931
-