home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume18
/
fnet
/
part02
< prev
next >
Wrap
Text File
|
1989-03-05
|
61KB
|
2,249 lines
Subject: v18i003: Fido/Usenet gateway, Part02/05
Newsgroups: comp.sources.unix
Sender: sources
Approved: rsalz@uunet.UU.NET
Submitted-by: Heikki Suonsivu <hsu@santra.hut.fi>
Posting-number: Volume 18, Issue 3
Archive-name: fnet/part02
#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file rfmail.c continued
#
CurArch=2
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file rfmail.c"
sed 's/^X//' << 'SHAR_EOF' >> rfmail.c
X}
X
X/* Get return address from mail. Extract it from Reply-To: or From: fields. */
X
Xvoid
Xget_return_address(mail, address)
X FILE *mail;
X char *address;
X{
X char buffer[BUFSIZ];
X
X *address = 0;
X
X /* check is there is Reply-To: field */
X (void) rewind(mail);
X while (fgets(buffer, BUFSIZ, mail) && *buffer != '\n')
X if (!strncmp(buffer, "Reply-To: ", 10))
X {
X get_address(buffer + 10, address);
X return;
X }
X
X /* no Reply-To:, check for From: */
X (void) rewind(mail);
X while (fgets(buffer, BUFSIZ, mail) && *buffer != '\n')
X if (!strncmp(buffer, "From: ", 6))
X {
X get_address(buffer + 6, address);
X return;
X }
X
X /* not found, send it to uucp */
X (void) strcpy(address, "uucp");
X}
X
X/* Send mail back to sender. If Reply-To: of From:-field is present,
X we'll use address specified in that, otherwise we will not return
X mail (it also should be able to parse From_ fields). First argument
X is file containing this mail, others are for vprintf(3S) to be used
X as transcript. */
X
X/* VARARGS */
Xvoid
Xsendback(va_alist)
X va_dcl
X{
X va_list args;
X FILE *mail;
X
X#ifdef RETURN_FAILED_MAIL
X FILE *mailer;
X char *fmt, buffer[BUFSIZ];
X char to[128];
X#endif /* RETURN_FAILED_MAIL */
X
X va_start(args);
X mail = va_arg(args, FILE *);
X fmt = va_arg(args, char *);
X
X#ifdef RETURN_FAILED_MAIL
X get_return_address(mail, to);
X log("Mail failed, return to %s", to);
X
X /* generate shell command and open it */
X (void) sprintf(buffer, "exec %s %s", RMAIL, to);
X if (mailer = popen(buffer, "w"))
X {
X /* print correct header for mailer */
X (void) fprintf(mailer, "From %d!MAILER-DAEMON %s remote from %d\n",
X this.node, date("%a %h %d %T 19%y", (long *) 0),
X this.net);
X (void) fprintf(mailer, "Received: by %s (%s/%s)\n",
X internode(this), PROGRAMNAME, this.name);
X (void) fprintf(mailer, "\tid AA%05d; %s\n", getpid(),
X date("%a, %d %h %y %T %o (%z)", (long *) 0));
X (void) fprintf(mailer, "Date: %s\n", date("%a, %d %h %y %T %o",
X (long *) 0));
X (void) fprintf(mailer, "From: FidoNet Mail <%s@%s>\n",
X "MAILER-DAEMON", internode(this));
X (void) fprintf(mailer, "Subject: Returned mail: %s\n",
X "Unable to deliver mail to FidoNet");
X (void) fprintf(mailer, "Message-Id: <%s.AA%05d@%s>\n",
X date("%y%m%q%H%M", (long *) 0), getpid(),
X internode(this));
X (void) fprintf(mailer, "To: %s\n", to);
X (void) fprintf(mailer, "\n");
X (void) fprintf(mailer, " ----- Transcript of session follows -----\n");
X (void) vfprintf(mailer, fmt, args);
X (void) fprintf(mailer, "\n\n");
X (void) fprintf(mailer, " ----- Unsent message follows -----\n");
X
X /* now copy the message to mailer */
X (void) rewind(mail);
X while (fgets(buffer, BUFSIZ, mail))
X (void) fputs(buffer, mailer);
X
X /* mail is now sent, close mailer */
X (void) pclose(mailer);
X }
X else
X log("$Unable to invoke mailer for returned mail");
X#else /* not RETURN_FAILED_MAIL */
X /* get dummy mail-file pointer */
X mail = va_arg(args, FILE*);
X fmt = va_arg(args, char *);
X
X /* just print error to stderr, sendmail will return mail to sender
X due to non-zero exit code. */
X (void) vfprintf(stderr, fmt, args);
X#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
Xint
Xvalid_netnode(name, node, mail)
X char *name;
X Node node;
X FILE *mail;
X{
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;
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
Xchar *
Xsender(mail, field)
X FILE *mail;
X char *field;
X{
X struct passwd *pwd;
X static char name[36];
X char buffer[BUFSIZ];
X register char *cp, *np;
X register int cnt;
X Node dummynode;
X FILE *fp;
X
X name[35] = 0;
X (void) rewind(mail);
X while (fgets(buffer, BUFSIZ, mail))
X {
X buffer[strlen(buffer) - 1] = 0; /* strip newline */
X if (!strncmp(buffer, field, strlen(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 {
X /* Format is 'From: Name <address>' */
X for (np = buffer + strlen(field),
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
X if ((cp = strchr(buffer, '(')) && (np = strchr(cp, ')')))
X {
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 {
X debug(5, "Could no find realname in <> or ()");
X /* Try parse it with parse_address */
X if (parse_address(buffer + strlen(field), name, &dummynode))
X {
X (void) strncpy(name, buffer + strlen(field), 35);
X name[35] = 0;
X debug(2, "No format in %s, name %s", field, name);
X }
X else
X {
X name[35] = 0;
X debug(2, "Name %s parsed from address", name);
X }
X }
X return name;
X }
X }
X
X /* If not searching for sender, don't try to use uid */
X
X if (strcmp(field, "From: ")) return NULL;
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 /* Found nothing reasonable. we could put there path, but it's quite
X complicated to parse it and it's quite often more than 35 characters
X and partial paths are not very informative. Reader can figure
X it out by himself (or herself) and tell sender to use mailer... */
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
Xbool
Xgetnode(info, node)
X char *info;
X Node *node;
X{
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}
X
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
Xbool
Xaliascmp(alias, to, node)
X char *alias, *to;
X Node node;
X{
X char buffer[BUFSIZ];
X char *cp;
X Node anode;
X
X while (*alias && *alias != ',' && !isspace(*alias) && *to)
X if (*alias++ != *to++)
X return False;
X
X if (isspace(*alias)) /* match */
X return True;
X
X if (*alias == ',')
X {
X /* copy alias to buffer and terminate the it after first space */
X (void) strcpy(buffer, alias + 1);
X for (cp = buffer; *cp; cp++)
X if (isspace(*cp))
X {
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 {
X debug(2, "Got node '%s'", cp);
X if (getnode(cp, &anode))
X {
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
Xchar *
Xreceiver(to, node)
X char *to;
X Node node;
X{
X static char name[36];
X char buffer[BUFSIZ];
X register int cnt;
X register char *cp;
X FILE *fp;
X
X if (fp = fopen(ALIAS, "r"))
X {
X while (fgets(buffer, BUFSIZ, fp))
X {
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 {
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 {
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 return name;
X }
X else
X debug(1, "Missing alias");
X }
X }
X (void) fclose(fp);
X }
X else
X log("$Unable to open aliasfile %s", ALIAS);
X
X /* Alias not found. Return the the original receiver with all
X _-characters replaced by space and all words calitalized. */
X
X for (cp = NULL, cnt = 0; *to && cnt < 35; cnt++, cp = to++)
X {
X if (*to == '_')
X name[cnt] = ' ';
X else
X if (!cp || *cp == '_' || *to == ' ')
X name[cnt] = toupper(*to);
X else
X name[cnt] = tolower(*to);
X }
X name[cnt] = 0;
X debug(2, "No alias, name %s", name);
X return name;
X}
X
X/* Return receiver's name, took Comment-To: field. If not found,
X call receiver() and return what it returns */
X
Xchar *newsreceiver(fp, to, node)
X FILE *fp;
X char *to;
X Node node;
X{
X char *cp;
X
X debug(2, "Checking To: field");
X if (cp = sender(fp, "To: "))
X {
X debug(1, "Got recipent %s from To: field", cp);
X strcpy(to, cp);
X }
X else
X {
X debug(2, "Checking Comment-To: field");
X if (cp = sender(fp, "Comment-To: "))
X {
X debug(1, "Got recipent %s from Comment-To field", cp);
X strcpy(to, cp);
X }
X }
X
X return receiver(to, node);
X}
X
X/* Get date from mail. Look for Date: field, if present and time is in
X correct format (same than ARPA-net mail uses), it will be used, otherwise
X current time will be taken. */
X
Xchar *
Xlgetdate(fp)
X FILE *fp;
X{
X time_t timevar;
X struct tm *localtime();
X struct tm *mtime;
X static char timebuf[20];
X char buffer[BUFSIZ];
X /* literal months */
X static char *months[] = {
X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
X (char *) 0,
X };
X /* Literal weekdays */
X static char *wkdays[] = {
X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", (char *) 0,
X };
X
X (void) rewind(fp);
X while (fgets(buffer, BUFSIZ, fp))
X /* did we find Date: */
X if (!strncmp(buffer, "Date: ", 6))
X {
X buffer[strlen(buffer) - 1] = '\0';
X /* try to extract date and other information from it */
X debug(2, "Found date: '%s'", buffer + 6);
X#ifdef OLD_VERSION
X if (sscanf(buffer + 6, "%3s, %2d %3s %2d %2d:%2d:%*2d %*s",
X wday, &mday, month, &year, &hour, &min) == 6)
X {
X debug(2, "Correct date format");
X /* save date in SEAdog format */
X (void) sprintf(timebuf, "%3s %2d %3s %2d %02d:%02d",
X wday, mday, month, year, hour, min);
X return timebuf;
X }
X#else
X timevar = getdate(buffer + 6, (struct timeb *) NULL);
X debug(2, "timevar %ld", timevar);
X mtime = localtime(&timevar);
X /* Save date in SEAdog format */
X (void) sprintf(timebuf, "%3s %2d %3s %2d %02d:%02d",
X wkdays[mtime->tm_wday], mtime->tm_mday,
X months[mtime->tm_mon], mtime->tm_year,
X mtime->tm_hour, mtime->tm_min);
X debug(1, "Returning %s", timebuf);
X return timebuf;
X#endif
X }
X
X (void) rewind(fp);
X debug(2, "No Date: field in mail");
X
X /* we did not found Date: field, let's use current time */
X return date("%a %d %h %y %T", (long *) NULL);
X}
X
X/* Send mail from filepoiner fp to user to. To is in format of
X net!node!receiver, where net and node are destnation and
X receiver is receivers name in which blankos are replaces by
X _-characters or alias. */
X
Xint
Xsendmail(fp, to)
X FILE *fp;
X char *to;
X{
X char buffer[BUFSIZ], *cp;
X FILE *sf;
X char *sfile;
X char hostname[10];
X Node node;
X char name[36];
X int status, nodate, nosubject, nofrom;
X
X (void) gethostname(hostname, 10);
X
X /* get receiver and net/node */
X if (cp = parse_address(to, name, &node))
X {
X sendback(fp, "Parse failed: %s", cp);
X return EX_NOHOST;
X }
X
X debug(1, "Sending mail to %s at %s", name, ascnode(node));
X
X if ((status = valid_netnode(name, node, fp)) != EX_OK)
X return status;
X
X debug(1, "Netnode ok, opening spool file");
X
X if (sf = fopen(sfile = spoolfile("M."), "w"))
X {
X /* set correct permissions for spoolfile and lock it */
X (void) chmod(sfile, 0600);
X (void) lock(fileno(sf));
X
X debug(1, "chmod and lock ok");
X
X /* save net and node information */
X (void) fprintf(sf, "N %s\n", ascnode(node));
X
X /* save receiver. If using newsreceiver seem to cause
X trouble, use normal receiver if not in news mode */
X
X (void) fprintf(sf, "T %s\n", newsreceiver(fp, name, node));
X
X /* save sender ... */
X debug(10, "Trying to find sender (From)");
X (void) fprintf(sf, "F %s\n", (cp = sender(fp, "From: ")) ?
X cp : "Usenet");
X
X /* try to find subject ... */
X (void) rewind(fp);
X while (fgets(buffer, BUFSIZ, fp))
X if (!strncmp("Subject: ", buffer, 9))
X {
X (void) fprintf(sf, "S %s", buffer + 9);
X buffer[strlen(buffer) - 1] = 0;
X debug(2, "Subject: %s", buffer + 9);
X break;
X }
X
X if (feof(fp))
X /* we didn't find subject.. */
X (void) fprintf(sf, "S Mail from Usenet\n");
X
X /* save date */
X (void) fprintf(sf, "D %s\n", lgetdate(fp));
X
X /* if not public, mark that message is private */
X if (!public)
X (void) fprintf(sf, "P \n");
X
X /* done with header information, now we'll copy the hole mail
X after the header */
X
X (void) putc('\n', sf);
X
X debug(2, "Copying mail");
X
X /* Now copy mail, also add Received field to mail */
X (void) rewind(fp);
X while (fgets(buffer, BUFSIZ, fp) && (!strncmp(buffer, "From ", 5) ||
X !strncmp(buffer, ">From ", 6) ||
X !strncmp(buffer, "AREA:", 5)))
X (void) fputs(buffer, sf);
X
X (void) fprintf(sf, "Received: from %s%s by %s (%s%s/%s)\n",
X hostname, DOMAIN, internode(this), "rfmail",
X version, this.name);
X (void) fprintf(sf, "\tid AA%05d; %s\n", getpid(),
X date("%a, %d %h %y %T %o (%z)", (long *) NULL));
X
X /* Copy header. Try to avoid duplicating headers already in
X fidonet header. Only first occurence of header is processed,
X others will be ignored. Header is considered to end at first
X empty line. */
X
X nodate = TRUE;
X nosubject = TRUE;
X nofrom = TRUE;
X do {
X
X /* Date is in mail header, so skip header Date: */
X if (nodate)
X if (!strncmp(buffer, "Date:", 5))
X {
X nodate = FALSE;
X continue;
X }
X
X /* Print subject only if it doesnt fit in fidonet header correctly */
X if (nosubject)
X if (!strncmp(buffer, "Subject:", 8))
X {
X if (strlen(buffer + 8) > 72)
X fputs(buffer, sf);
X nosubject = FALSE;
X continue;
X }
X
X /* Print From field only if it doesn't fit in fidonet header */
X if (nofrom)
X if (!strncmp(buffer, "From:", 5))
X {
X if (strlen(buffer + 5) > 36)
X fputs(buffer, sf);
X nofrom = FALSE;
X continue;
X }
X
X fputs(buffer, sf);
X } while (fgets(buffer, BUFSIZ, fp));
X
X /* done. */
X (void) fclose(sf);
X return EX_OK;
X }
X else
X {
X log("$Unable to open spoolfile");
X return EX_CANTCREAT;
X }
X /* NOTREACHED */
X}
X
X/*ARGSUSED*/
Xint
Xmain(argc, argv, envp)
X int argc;
X char **argv, **envp;
X{
X int cnt, c;
X FILE *mail;
X char buffer[BUFSIZ], tmpf[L_tmpnam];
X int status = EX_OK;
X char *error;
X Node *node, mynode;
X
X newsmode = FALSE;
X while ((c = getopt(argc, argv, "npvV:")) != EOF)
X switch (c)
X {
X case 'n':
X /* Set news-mode */
X newsmode = TRUE;
X break;
X case 'v':
X /* set more verbosity */
X verbose++;
X break;
X case 'V':
X /* allow version on command line only if test version. */
X if (*version != '%' || version[1] != 'I' || version[2] != '%')
X version = optarg;
X /* NOTE: Comparison cannot be with strcmp, because SCCS would also
X change that comparison string. */
X break;
X case 'p':
X /* this is not private message */
X public = True;
X break;
X default:
X (void) fprintf(stderr, "See manual page.\n", *argv);
X exit(EX_USAGE);
X }
X
X /* create name of temporary mail-message */
X (void) strcpy(tmpf, P_tmpdir);
X (void) strcat(tmpf, mktemp("rfm.XXXXXX"));
X
X /* open mail-temp */
X if (mail = fopen(tmpf, "w+"))
X {
X /* protect mail file */
X (void) chmod(tmpf, 0600);
X
X /* copy mail to temp-file */
X while (fgets(buffer, BUFSIZ, stdin))
X (void) fputs(buffer, mail);
X
X /* update nodelist-index if needed */
X if (error = update_index())
X {
X /* there was error while updating nodelist-index */
X if (*error == '$')
X sendback(mail, "%s: %s", error + 1, sys_errlist[errno]);
X else
X sendback(mail, "%s", error);
X exit(EX_SOFTWARE);
X }
X
X mynode.zone = MY_ZONE;
X mynode.net = MY_NET;
X mynode.node = MY_NODE;
X mynode.point = MY_POINT;
X if ((node = node_entry(mynode)) == NULL)
X {
X (void) fprintf(stderr, "Unable to this node from nodelist\n");
X log("No %s in nodelist", ascnode(mynode));
X exit(EX_SOFTWARE);
X }
X this = *node;
X
X
X /* send mail to all user's */
X for (rewind(mail), cnt = optind; cnt < argc; rewind(mail), cnt++)
X /* send mail */
X if ((status = sendmail(mail, argv[cnt])) != EX_OK)
X break;
X
X /* remove temporary file */
X (void) fclose(mail);
X (void) unlink(tmpf);
X }
X else
X {
X /* opening tmp-file failed, we can't even send mail back */
X log("$Can not open %s for writing", tmpf);
X exit(EX_CANTCREAT);
X }
X
X exit(status);
X /*NOTREACHED*/
X}
SHAR_EOF
echo "File rfmail.c is complete"
chmod 0644 rfmail.c || echo "restore of rfmail.c fails"
echo "x - extracting funcs.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > funcs.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Miscancelleus functions, logging, sequence numberic etc.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X/* LINTLIBRARY */
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <varargs.h>
X#include <unistd.h>
X#include <sys/types.h>
X#include <time.h>
X#include <sys/utsname.h>
X#include <errno.h>
X#include "hsu.h"
X#include "config.h"
X#include "fnet.h"
X#include "sysexits.h"
X#include "nodelist.h"
X#include "shuffle.h"
X
X#define labs(n) (((n) < 0l) ? (-(n)) : (n))
X
Xextern void exit(), perror();
Xextern long atol();
Xextern time_t time();
Xextern int errno;
Xextern char *sys_errlist[];
X
XFILE *logfp = NULL;
X
X/* Lock file descriptor up to the end. If yur system doesn't have lockf()
X (also known as locking()), or other region or file locking function
X or system call, this should be done with lock-files. */
X
Xint
Xlock(fd)
X int fd;
X{
X#ifdef LOCK_LOCKF
X return lockf(fd, F_LOCK, 0l);
X#else
X return locking(fd, F_LOCK, 0l);
X#endif
X}
X
X/* Unlock file descriptor up to the end. Routine which calls this should
X first seek to original position. */
X
Xint
Xunlock(fd)
X int fd;
X{
X#ifdef LOCK_LOCKF
X return lockf(fd, F_ULOCK, 0l);
X#else
X return locking(fd, F_ULOCK, 0l);
X#endif
X}
X
X/* Return ascii-date in specified format. If format string is null, return
X date as date(1) returns it. Format is same than date(1) has, in addition
X %z, which means timezone name. Clock is the time to convert, if NULL,
X we'll use current time. */
X
Xchar *
Xdate(fmt, clock)
X char *fmt;
X time_t *clock;
X{
X /* names for weekdays */
X static char *weekdays[] = {
X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
X };
X
X /* names for months */
X static char *months[] = {
X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
X };
X
X static char buffer[80];
X char *bp = buffer;
X time_t _clock;
X struct tm *tm;
X
X if (!clock)
X _clock = time((long *) 0);
X tm = localtime(clock ? clock : &_clock);
X
X /* if no format string, this is default */
X if (!fmt)
X fmt = "%a %h %d %T %z 19%y";
X
X for (*bp = 0; *fmt; fmt++)
X switch (*fmt)
X {
X case '%':
X switch (*++fmt)
X {
X /* newline */
X case 'n':
X *bp++ = '\n';
X break;
X /* tabulator */
X case 't':
X *bp++ = '\t';
X break;
X /* month number 1-12 */
X case 'm':
X (void) sprintf(bp, "%02d", tm->tm_mon + 1);
X while (*bp)
X bp++;
X break;
X /* day of month 1-31 */
X case 'd':
X (void) sprintf(bp, "%2d", tm->tm_mday);
X while (*bp)
X bp++;
X break;
X case 'q':
X (void) sprintf(bp, "%02d", tm->tm_mday);
X while (*bp)
X bp++;
X break;
X /* year 00-99 */
X case 'y':
X (void) sprintf(bp, "%02d", tm->tm_year);
X while (*bp)
X bp++;
X break;
X /* date in format YY/MM/DD */
X case 'D':
X (void) sprintf(bp, "%02d/%02d/%02d", tm->tm_year,
X tm->tm_mon + 1, tm->tm_mday);
X while (*bp)
X bp++;
X break;
X /* hour 0-23 */
X case 'H':
X (void) sprintf(bp, "%02d", tm->tm_hour);
X while (*bp)
X bp++;
X break;
X /* minutes 0-59 */
X case 'M':
X (void) sprintf(bp, "%02d", tm->tm_min);
X while (*bp)
X bp++;
X break;
X /* seconds 0-59 */
X case 'S':
X (void) sprintf(bp, "%02d", tm->tm_sec);
X while (*bp)
X bp++;
X break;
X /* time in format HH:MM:SS */
X case 'T':
X (void) sprintf(bp, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
X tm->tm_sec);
X while (*bp)
X bp++;
X break;
X /* day of year 1-356 */
X case 'j':
X (void) sprintf(bp, "%03d", tm->tm_yday + 1);
X while (*bp)
X bp++;
X break;
X /* weekday 0-6 */
X case 'w':
X (void) sprintf(bp, "%d", tm->tm_wday);
X while (*bp)
X bp++;
X break;
X /* name of weekday 'Mon', 'Tue', ... , 'Sun' */
X case 'a':
X (void) strcpy(bp, weekdays[tm->tm_wday]);
X while (*bp)
X bp++;
X break;
X /* name of month 'Jan', 'Feb', ... , 'Dec' */
X case 'h':
X (void) strcpy(bp, months[tm->tm_mon]);
X while (*bp)
X bp++;
X break;
X /* name of timezone, e.g. EST */
X case 'z':
X (void) strcpy(bp, *tzname);
X while (*bp)
X bp++;
X break;
X /* numeric time zone, e.g. +0200 */
X case 'o':
X (void) sprintf(bp, "%c%02ld%02ld", (timezone <= 0l) ? '+' : '-',
X (labs(timezone) / (60l * 60l)),
X (labs(timezone) % (60l * 60l)));
X while (*bp)
X bp++;
X break;
X case 'l':
X /* military time zone, Z = UT, A = -1, M = -12, (J not used),
X N = +1, Y = +12.. */
X *bp = (timezone == 0l) ? 'Z' : ((int) (labs(timezone) /
X (60l * 60l)) +
X ((timezone < 0l) ? 'M' : '@'));
X if (timezone > 0l && *bp >= 'J')
X (*bp)++;
X *++bp = 0;
X break;
X default:
X *bp++ = *fmt;
X break;
X }
X break;
X default:
X *bp++ = *fmt;
X break;
X }
X
X *bp = 0;
X return buffer;
X}
X
X/* Log to logfile. If logfile is not open, open it.
X
X If first character in format string is '$', print also errno. If external
X variable verbose is set, logging will be done also to stderr. */
X
X/* VARARGS */
Xvoid
Xlog(va_alist)
X va_dcl
X{
X va_list args;
X char *fmt;
X int eno = errno;
X
X va_start(args);
X
X fmt = va_arg(args, char *);
X
X if (!logfp)
X if ((logfp = fopen(LOGFILE, "a")) == NULL)
X {
X perror("Cannot open log file");
X return;
X }
X
X (void) fprintf(logfp, "%s: ", date("%a, %d %h %y %T %o", (long *) 0));
X (void) vfprintf(logfp, *fmt == '$' ? fmt + 1 : fmt, args);
X if (*fmt == '$')
X (void) fprintf(logfp, " errno = %d (%s)\n", eno, sys_errlist[eno]);
X else
X (void) fprintf(logfp, "\n");
X (void) fflush(logfp);
X
X /* if verbose is set, print also to stderr */
X if (verbose)
X {
X (void) vfprintf(stderr, fmt + (*fmt == '$'), args);
X if (*fmt == '$')
X (void) fprintf(stderr, " errno = %d (%s)\n", eno,
X sys_errlist[eno]);
X else
X (void) fprintf(stderr, "\n");
X (void) fflush(stderr);
X }
X
X va_end(args);
X}
X
X/* Debug output. First argument should be number, rest are used arguments
X for vfprintf(3S). If external variable verbose has equal or greater
X value than first number, vfprintf(3S) will be used to print other
X arguments to stderr. */
X
X/* VARARGS */
Xvoid
Xdebug(va_alist)
X va_dcl
X{
X va_list args;
X char *fmt;
X int debug_level;
X
X va_start(args);
X
X debug_level = va_arg(args, int);
X fmt = va_arg(args, char *);
X
X if (debug_level <= verbose)
X {
X if (*fmt != '>' && *fmt != '<')
X (void) fprintf(stderr, "\n%ld: ", time( (long *) NULL));
X (void) vfprintf(stderr, fmt, args);
X }
X
X va_end(args);
X}
X
X/* Get next job number. New sequemnt number will be taken from file
X LIBDIR/seq, which is in ascii-format and new number will be saved
X back there. */
X
Xlong
Xjob_number()
X{
X char seqfile[128], buffer[14];
X FILE *fp;
X long seqn = 0;
X
X (void) sprintf(seqfile, "%s/seq", LIBDIR);
X if (fp = fopen(seqfile, "r+"))
X {
X (void) lock(fileno(fp));
X if (fgets(buffer, 14, fp))
X seqn = atol(buffer);
X seqn++;
X (void) rewind(fp);
X (void) fprintf(fp, "%ld\n", seqn);
X (void) unlock(fileno(fp));
X (void) fclose(fp);
X }
X else
X {
X log("$Can not open seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X return seqn;
X}
X
X/* General sequencer */
X
Xlong
Xsequencer(filename)
X char *filename;
X{
X char seqfile[128], buffer[14];
X FILE *fp;
X long seqn = 0;
X
X (void) sprintf(seqfile, "%s", filename);
X if ((fp = fopen(seqfile, "r+")) == NULL)
X {
X if (errno == ENOENT)
X {
X if ((fp = fopen(seqfile, "w+")) == NULL)
X {
X log("$Can not create seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X fputs("1", fp);
X fclose(fp);
X if ((fp = fopen(seqfile, "r+")) == NULL)
X {
X log("$Can not open new seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X }
X else
X {
X log("$Can not open seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X }
X
X (void) lock(fileno(fp));
X if (fgets(buffer, 14, fp))
X seqn = atol(buffer);
X else
X seqn = 0; /* This can theoretically fail */
X
X seqn++;
X (void) rewind(fp);
X (void) fprintf(fp, "%ld\n", seqn);
X (void) unlock(fileno(fp));
X (void) fclose(fp);
X return seqn;
X}
X
X/* Returns current last sequence number */
Xlong
Xgetsequencer(filename)
X char *filename;
X{
X char seqfile[128], buffer[14];
X FILE *fp;
X long seqn = 0;
X
X (void) sprintf(seqfile, "%s", filename);
X if ((fp = fopen(seqfile, "r+")) == NULL)
X {
X if (errno == ENOENT)
X {
X if ((fp = fopen(seqfile, "w+")) == NULL)
X {
X log("$Can not create seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X fputs("1", fp);
X fclose(fp);
X if ((fp = fopen(seqfile, "r+")) == NULL)
X {
X log("$Can not open new seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X }
X else
X {
X log("$Can not open seq-file %s", seqfile);
X exit(EX_OSFILE);
X }
X }
X
X (void) lock(fileno(fp));
X if (fgets(buffer, 14, fp))
X seqn = atol(buffer);
X else
X seqn = 0; /* This can theoretically fail */
X
X (void) unlock(fileno(fp));
X (void) fclose(fp);
X return seqn;
X}
X
X/* Get full pathname for spoolfile with new job number. File is in
X spool directory and contains prefix followed by four digit
X job number. */
X
Xchar *
Xspoolfile(prefix)
X char *prefix;
X{
X static char file[BUFLEN];
X
X (void) sprintf(file, "%s/%s%08ld", SPOOL, prefix, job_number());
X return file;
X}
X
X/* Return basename of s */
X
Xchar *
Xbasename(s)
X register char *s;
X{
X register char *p = s;
X
X while (*s)
X if (*s++ == '/')
X p = s;
X return p;
X}
X
X/* Open file with directory name and filename. */
X
XFILE *
Xpfopen(dir, name, mode)
X char *dir, *name, *mode;
X{
X char filename[128];
X
X (void) strcpy(filename, dir);
X (void) strcat(filename, "/");
X (void) strcat(filename, name);
X
X return fopen(filename, mode);
X}
X
Xchar *baseit(n)
X long n;
X{
X static char tab[] =
X "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
X int count = 0;
X
X SHUFFLEBUFFERS;
X
X while (n)
X {
X tcharp[count] = tab[n % strlen(tab)];
X n = n / strlen(tab);
X count++;
X }
X
X tcharp[count] = 0;
X return tcharp;
X}
X
X/* Create packet name for node given */
X
Xsprintpacketname(s, node)
X char *s;
X Node node;
X{
X sprintf(s, "%s%s.%s.%s", node.point ?
X sprintfs("%s.", baseit( (long) node.point)) : "",
X baseit( (long) node.node), baseit( (long) node.net),
X baseit( (long) node.zone));
X}
X
X/* Create packet name for inbound xx.xx.xx.xx.num. If point
X number is 0, don't include it. All numbers are in ~63-base to squeeze
X them to as small space as possible. It could be more sensible solution
X to make them directory trees but I would need more time for that. This
X trick makes finding packets difficult.
X */
X
Xsprintipacketname(s, node)
X char *s;
X Node node;
X{
X sprintf(s, "%s%s.%s.%s.%s", node.point ?
X sprintfs("%s.", baseit( (long) node.point)) : "",
X baseit( (long) node.node), baseit( (long) node.net),
X baseit( (long) node.zone), baseit(sequencer(IPACKETSEQUENCE)));
X}
X
X/* Get line from config file. If *-character is in first column, report
X EOF, and otherwise return line with comments stripped. This causes
X effect, that each section in configuration file looks like it's own
X file. Arguments and return value are the same than with fgets(3S). */
X
Xchar *
Xgetcl(buffer, len, fp)
X char *buffer;
X int len;
X FILE *fp;
X{
X char *cp;
X
X while (fgets(buffer, len, fp))
X {
X buffer[strlen(buffer) - 1] = 0;
X if (*buffer == '*')
X return (char *) NULL;
X /* everything after #-sign is comment */
X if (cp = strchr(buffer, '#'))
X *cp = 0;
X /* if there's something left, return it */
X if (*buffer)
X return buffer;
X }
X return (char *) NULL;
X}
X
X/* Scan config file to specified section. This mechanism is not very
X effective, but otherwise it would get too complicated. */
X
Xvoid
Xsection(number, config)
X int number;
X FILE *config;
X{
X char buffer[BUFLEN];
X
X (void) rewind(config);
X while (--number)
X while (getcl(buffer, BUFLEN, config))
X /* skip section */;
X}
X
X/* Get header field from file. */
X
X#define MAX_HEADER_LEN 256
X
Xchar *mheader(fp, headername)
X FILE *fp;
X char *headername;
X{
X static char header[MAX_HEADER_LEN];
X long position;
X
X position = ftell(fp);
X
X rewind(fp);
X
X /* Blank line terminates also, there shouldn't be any headers
X after it any more */
X
X while (fgets(header, MAX_HEADER_LEN, fp) && *header != '\n')
X if (!strncmp(header, headername, strlen(headername)))
X {
X /* Remove \n at end */
X header[strlen(header) - 1] = 0;
X fseek(fp, position, 0);
X return header + strlen(headername);
X }
X
X /* Not found, return empty string */
X
X fseek(fp, position, 0);
X return "";
X}
X
X
X
SHAR_EOF
chmod 0644 funcs.c || echo "restore of funcs.c fails"
echo "x - extracting rfnews.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rfnews.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Spool Usenet news articles to fidonet. Currently there is no news-system
X in fido, it's done by software after and before mail-slots. Echomail
X is most popular one, and this program does about the same thing:
X it sends news-articles as fido-mail containing suitable information
X for echomail. Echomail relies on normal fido-mail, we send news thru
X rfmail, because this mechanism requires nothing different from normal
X mail.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <sys/types.h>
X#include "hsu.h"
X#include "config.h"
X#include "fnet.h"
X#include "fnews.h"
X#include "nodelist.h"
X
Xextern void exit();
Xextern void perror();
X
Xint verbose = INIT_VERBOSE;
X
X/* Get header field. Rewind header file and scan forward until we find
X desired field. Not effective, but... Return NULL if field not found. */
X
Xchar *
Xget_field(field, hdr)
X char *field;
X FILE *hdr;
X{
X static char buffer[BUFLEN];
X int conditional = FALSE;
X char *p;
X
X if (*field == '?')
X {
X conditional = TRUE;
X for (p = field; *p = *(p + 1); p++);
X }
X
X (void) rewind(hdr);
X while (fgets(buffer, BUFLEN, hdr))
X if (!strncmp(field, buffer, strlen(field)))
X {
X if (conditional)
X {
X /* Note: <= is ok, because there is one blank after header which
X wouldn't be included in Fidonet message header */
X if (!strncmp(field, "Subject:", 8))
X if (strlen(buffer + 8) <= 72) return NULL;
X if (!strncmp(field, "From:", 5))
X if (strlen(buffer + 5) <= 36) return NULL;
X if (!strncmp(field, "Reply-To:", 9))
X if (strlen(buffer + 9) <= 36) return NULL;
X if (!strncmp(field, "To:", 3))
X if (strlen(buffer + 3) <= 36) return NULL;
X }
X
X buffer[strlen(buffer) - 1] = 0;
X return buffer + strlen(field);
X }
X
X return (char *) NULL;
X}
X
X/* Open stream which is associated with fido-mailers starndard input.
X We could use also popen(3S), but it invokes also sh(1) which slows
X down opening and gets more memory. This routine exists if something
X goes wrong, because this is quite essential part of program and
X we can not continue without mailer. */
X
XFILE *
Xopen_mailer(to)
X char *to;
X{
X FILE *fp;
X int fd[2];
X char mailer[128];
X
X (void) sprintf(mailer, "%s/rfmail", LIBDIR);
X
X /* create pipe */
X if (pipe(fd) == -1)
X {
X perror("rfnews: pipe");
X exit(1);
X }
X
X switch (fork())
X {
X case -1:
X perror("rfnews: fork failed");
X exit(1);
X case 0:
X (void) close(0);
X /* duplicate pipe and close now unused fd's */
X if (dup(fd[0]) == 0)
X {
X (void) close(fd[0]);
X (void) close(fd[1]);
X (void) execlp(mailer, "rfmail", "-p", to, (char *) NULL);
X perror(mailer);
X }
X else
X perror("rfnews: dup");
X exit(0);
X default:
X (void) close(fd[0]);
X /* open the other end of pipe as buffered */
X if ((fp = fdopen(fd[1], "w")) == NULL)
X {
X perror("rfnews: fdopen");
X exit(1);
X }
X }
X return fp;
X}
X
X/* Save news header for future processing and return file pointer to it. */
X
XFILE *
Xsave_hdr()
X{
X char buffer[BUFLEN];
X FILE *hdr = tmpfile();
X
X while (fgets(buffer, BUFLEN, stdin) && *buffer != '\n')
X (void) fputs(buffer, hdr);
X return hdr;
X}
X
X/* Open rfmail. Send mail to net/node in config file, receiver will be
X All, because Usenet News articles don't have To: field. Net/node
X exraction is not very reliable of there's something wrong in
X configuration file. */
X
XFILE *
Xinvoke_rfmail(config)
X FILE *config;
X{
X char buffer[BUFLEN], *cp;
X int net, node;
X
X section(SECT_NETNODE, config);
X if (getcl(buffer, BUFLEN, config))
X {
X /* get net number */
X for (cp = buffer, net = 0; *cp && isdigit(*cp) && *cp != '/'; cp++)
X net = net * 10 + *cp - '0';
X debug(1, "Got net %d from config file", net);
X if (*cp)
X {
X /* get node number */
X for (cp++, node = 0; *cp && isdigit(*cp); cp++)
X node = node * 10 + *cp - '0';
X debug(1, "Got node %d from config file", node);
X }
X else
X {
X log("Missing node in config file");
X exit(1);
X }
X (void) sprintf(buffer, "All@%d.%d.FidoNet", node, net);
X return open_mailer(buffer);
X }
X else
X {
X log("Missing net/node in config file");
X exit(1);
X }
X /* NOTREACHED */
X}
X
X/* Try to get area for some of the newsgroups in newsgroup list. Method
X is not very sophisticated, but it should work. */
X
Xchar *
Xget_area(config, groups)
X FILE *config;
X char *groups;
X{
X static char conv[BUFLEN];
X char buffer[BUFLEN];
X char *cp, *gr, *area;
X
X debug(2, "Checking grouplist '%s'", groups);
X
X section(SECT_NG_AREA, config);
X while (getcl(conv, BUFLEN, config))
X {
X for (cp = conv; !isspace(*cp); cp++)
X /* find the end of newsgroup name */;
X if (isspace(*cp))
X {
X *cp++ = 0;
X (void) strcpy(buffer, groups);
X debug(3, "Config line '%s'", conv);
X /* get group by group from newsgroup-list */
X for (gr = strtok(buffer, " ,"); gr; gr = strtok((char *) NULL, " ,"))
X {
X debug(3, "Comparing '%s' and '%s'", gr, conv);
X if (!strcmp(gr, conv))
X {
X while (isspace(*cp))
X cp++;
X area = cp;
X while (*cp && !isspace(*cp))
X cp++;
X *cp = 0;
X debug(3, "Match, return area '%s'", area);
X return area;
X }
X }
X debug(3, "No match");
X }
X else
X log("Invalid line in config: '%s'", conv);
X }
X log("No area found for any group in '%s'", groups);
X return (char *) NULL;
X}
X
X/* Do actual processing of article. This will copy article, get newsgoroups
X and save them and then send all rest of article. */
X
X/* ARGSUSED */
Xint
Xmain(argc, argv, envp)
X int argc;
X char **argv, **envp;
X{
X FILE *config, *rfmail, *hdr;
X char buffer[BUFLEN], seenbys[BUFLEN];
X int c;
X char *cp, *errorstr;
X
X /* get options */
X while ((c = getopt(argc, argv, "v")) != EOF)
X switch (c)
X {
X case 'v':
X verbose++;
X break;
X default:
X (void) fprintf(stderr, "Usage: %s [-v]\n", *argv);
X exit(1);
X }
X
X /* try to update nodelist-index */
X if (errorstr = update_index())
X {
X if (*errorstr == '$')
X log("$Cannot update nodelist-index: %s", errorstr + 1);
X else
X log("Cannot update nodelist-index: %s", errorstr);
X exit(EX_OSERR);
X }
X
X /* try to open config file */
X if ((config = pfopen(LIBDIR, "fnews.cf", "r")) == NULL)
X {
X log("$Unable to open config file");
X exit(1);
X }
X
X /* open rfmail to send news */
X rfmail = invoke_rfmail(config);
X
X /* save news header */
X hdr = save_hdr();
X
X /* try to get area to which this article is going */
X if (cp = get_field("Newsgroups: ", hdr))
X if (cp = get_area(config, cp))
X {
X (void) fprintf(rfmail, "AREA:%s\n", cp);
X debug(2, "send area %s", cp);
X }
X else
X {
X log("Unable to get area");
X#ifdef JUNK_AREA
X (void) fprintf(rfmail, "AREA:\n", JUNK_AREA);
X log("Sending article to area %s", JUNK_AREA);
X#else
X exit(1);
X#endif
X }
X else
X {
X log("Missing Newsgroups: line in article");
X exit(1);
X }
X
X /* now send news header */
X section(SECT_HEADERS, config);
X while (getcl(buffer, BUFLEN, config))
X if (cp = get_field(buffer, hdr))
X (void) fprintf(rfmail,"%s%s\n", buffer, cp);
X (void) putc('\n', rfmail);
X
X /* send rest of the article */
X while (fgets(buffer, BUFLEN, stdin))
X (void) fputs(buffer, rfmail);
X
X /* send last information */
X fprintf(rfmail, "--- %s\n", PROGRAMNAME);
X section(SECT_ENDMSG, config);
X if (!getcl(buffer, BUFLEN, config))
X strcpy(buffer, "No Origin");
X else if (!getcl(seenbys, BUFLEN, config))
X *seenbys = 0;
X
X (void) fprintf(rfmail, " * Origin: %s (%d:%d/%d.%d)\n", buffer,
X MY_ZONE, MY_NET, MY_NODE, MY_POINT);
X fprintf(rfmail, "SEEN-BY: %s \n", seenbys);
X fprintf(rfmail, "\001PATH: %d/%d \n", MY_NET, MY_NODE);
X
X /* I think that that was all... */
X (void) fclose(rfmail);
X (void) wait((int *) NULL);
X
X exit(0);
X /* NOTREACHED */
X}
SHAR_EOF
chmod 0644 rfnews.c || echo "restore of rfnews.c fails"
echo "x - extracting rmail.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rmail.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Replacement for rmail. This looks out, if destination system
X name is numeric, and if it is, feeds mail to fidonet mail
X server. If systemname is not numeric, this executes real rmail.
X If this site is not fidonet gateway, define GATEWAY in rmail.h
X to path to that host.
X
X This is just a temporary replacement, MUCH MORE better is to use
X sendmail for gatewaying or smail 2.3 version that also can invoke
X other mailer.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include "hsu.h"
X#include "rmail.h"
X#include "config.h"
X#include "sysexits.h"
X#include "nodelist.h"
X#include "fnet.h"
X
Xextern char *malloc();
Xextern void exit();
Xextern void perror();
Xextern char *regex();
X
X/* verbosity */
Xint verbose = INIT_VERBOSE;
X
X#ifndef GATEWAY
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
XFILE *
Xopen_mailer(program, args, pid)
X char *program, **args;
X int *pid;
X{
X FILE *fp;
X int fd[2];
X
X /* create pipe */
X if (pipe(fd) == -1)
X {
X perror("rmail: pipe");
X exit(EX_OSERR);
X }
X
X switch (*pid = fork())
X {
X case -1:
X perror("rmail: fork failed");
X exit(EX_OSERR);
X case 0:
X (void) close(0);
X if (dup(fd[0]) == 0)
X {
X (void) close(fd[0]);
X (void) close(fd[1]);
X (void) execvp(program, args);
X perror(program);
X }
X else
X perror("rmail: dup");
X exit(EX_OSERR);
X default:
X (void) close(fd[0]);
X if ((fp = fdopen(fd[1], "w")) == NULL)
X {
X perror("rmail: fdopen");
X exit(EX_OSERR);
X }
X }
X return fp;
X}
X
X#endif
X
X
X/* ARGSUSED */
Xint
Xmain(argc, argv, envp)
X int argc;
X char **argv, **envp;
X{
X int cnt;
X
X#ifdef GATEWAY
X
X char *path;
X
X#else
X
X char **rargs = marray(argc + 1), **fargs = marray(argc + 1);
X int rrec = 0, frec = 0, rargc = 1, fargc = 1;
X int status = EX_OK;
X char dummyname[100];
X Node dummynode;
X
X#endif
X
X#ifdef GATEWAY
X
X /* If GATEWAY is defined, send all mail going to fidonet to there.
X If domain .FidoNet is known by other mahcines, routing is not
X really problem and this rmail is not needed elsewhere than in
X real gateway if there's no sendmail or other intelligent system
X in use. */
X
X for (cnt = 1; cnt < argc; cnt++)
X if (parse_address(argv[cnt], dummyname, &dummynet, &dummynode) == NULL)
X {
X#ifdef DEBUG
X (void) printf("Routing %s to %s.\n", argv[cnt], GATEWAY);
X#endif
X path = malloc((unsigned) (strlen(GATEWAY) +
X strlen(argv[cnt]) + 2));
X (void) strcpy(path, GATEWAY);
X (void) strcat(path, "!");
X argv[cnt] = strcat(path, argv[cnt]);
X }
X
X (void) execvp(RMAIL, argv);
X perror(RMAIL);
X
X#else
X
X *rargs = RMAIL;
X *fargs = FIDOMAILER;
X
X /* Scan thru receiver list and put all receivers in fidonet in fido-
X mailer's receiver-list and all others in real rmails one. No
X options can be passed to fidomailer thru this, because it would
X be too difficult to determine which one goes to which one and
X there might be same options also. Somehow it's good that fidomailer
X is well hidden under this... */
X
X for (cnt = 1; cnt < argc; cnt++)
X if (*argv[cnt] == '-')
X rargs[rargc++] = strsave(argv[cnt]);
X else
X {
X if (parse_address(argv[cnt], dummyname, &dummynode) == NULL)
X {
X#ifdef DEBUG
X (void) printf("Argument %d (receiver %d) in fidomailer: %s\n",
X fargc, frec + 1, argv[cnt]);
X#endif
X fargs[fargc++] = strsave(argv[cnt]);
X frec++;
X }
X else
X {
X#ifdef DEBUG
X (void) printf("Argument %d (receiver %d) in rmail: %s\n",
X rargc, rrec + 1, argv[cnt]);
X#endif
X rargs[rargc++] = strsave(argv[cnt]);
X rrec++;
X }
X }
X
X /* NULL terminate arument lists */
X rargs[rargc] = NULL;
X fargs[fargc] = NULL;
X
X /* If there is mail only to rmail or fidomail, execute that mailer
X with our original argument list. */
X
X if (!frec)
X {
X#ifdef DEBUG
X (void) printf("No mail to fidonet, executing %s\n", RMAIL);
X#endif
X (void) execvp(RMAIL, argv);
X perror(RMAIL);
X exit(1);
X }
X else
X if (!rrec)
X {
X#ifdef DEBUG
X (void) printf("No mail to UUCP, executing %s\n", FIDOMAILER);
X#endif
X (void) execvp(FIDOMAILER, argv);
X perror(FIDOMAILER);
X exit(1);
X }
X else
X {
X
X /* There's mail to both fidonet and usenet. We'll have to open
X both mailers and feed this letter to them at the same time.
X This is quite risky: If one of the mailer's exits for any
X reason, we will get SIGPIPE and we'll fall down.... if that
X happens, the other mailer got incomplete letter. */
X
X int rmail_pid, fmail_pid;
X register FILE *rmail = open_mailer(RMAIL, rargs, &rmail_pid);
X register FILE *fmail = open_mailer(FIDOMAILER, fargs, &fmail_pid);
X char buffer[BUFSIZ];
X int stat_loc, pid;
X
X#ifdef DEBUG
X (void) printf("Mail both to fidonet and UUCP\n");
X#endif
X while (fgets(buffer, BUFSIZ, stdin))
X {
X (void) fputs(buffer, rmail);
X (void) fputs(buffer, fmail);
X }
X (void) fclose(rmail);
X (void) fclose(fmail);
X
X /* We should wait for both mailers to exit and check their exit
X statuses. Then we should decide which one we'll should return,
X in this case let's return status from rmail, if other than
X EX_OK, otherwise from fidomail. */
X
X while ((pid = wait(&stat_loc)) != -1)
X if (pid == rmail_pid)
X {
X if ((stat_loc & 0377) == 0)
X status = stat_loc >> 8;
X }
X else
X if (pid == fmail_pid)
X {
X if ((stat_loc & 0377) == 0 && status == EX_OK)
X status = stat_loc >> 8;
X }
X }
X#endif
X
X exit(status);
X /* NOTREACHED */
X}
SHAR_EOF
chmod 0644 rmail.c || echo "restore of rmail.c fails"
echo "x - extracting fpack.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > fpack.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Create and update fidomail packets. Read mail messages from
X spool directory and append them to packet. If packet doesn't
X exist already, it will be created. Packet name in P.point.node.net.zone.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <errno.h>
X#include <string.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <time.h>
X#include <sys/stat.h>
X#include <dirent.h>
X#include "hsu.h"
X#include "config.h"
X#include "fnet.h"
X#include "fpack.h"
X#include "nodelist.h"
X
Xextern time_t time();
Xextern int getopt();
Xextern int optind;
Xextern char *optarg;
Xextern uint sleep();
Xextern void exit();
Xextern void swab();
X
XNode node;
Xint verbose = INIT_VERBOSE;
X
X/* Return True if string is numeric. */
X
Xbool
Xnumeric(s)
X register char *s;
X{
X while (*s)
X if (!isdigit(*s++))
X return False;
X return True;
X}
X
X/* Return argument as 16 bit interger to msdos */
X
XINT16
Xint16(value)
X int value;
X{
X INT16 msint, mval = (INT16) value;
X
X#ifdef SWAB_BYTES
X swab((char *) &mval, (char *) &msint, 2);
X#else
X msint = mval;
X#endif
X return msint;
X}
X
X/* Put string to file in null-terminated format. */
X
Xvoid
Xput_string(fp, s)
X FILE *fp;
X char *s;
X{
X while (*s)
X {
X (void) putc(*s, fp);
X s++;
X }
X (void) putc(0, fp);
X}
X
X/* Return date in ascii string that is in fido-format, ie.
X dd mmm yy hh:mm:ss, like 24 Jan 87 06:24:27 */
X
Xchar
X*fido_date(clock)
X time_t clock;
X{
X struct tm *tm;
X static char date[20];
X
X /* Literal months */
X static char *months[] = {
X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
X };
X
X tm = localtime(&clock);
X (void) sprintf(date, "%02d %3s %02d %02d:%02d:%02d", tm->tm_mday,
X months[tm->tm_mon], tm->tm_year, tm->tm_hour,
X tm->tm_min, tm->tm_sec);
X return date;
X}
X
X/* Write int to file in msdos interger format */
X
Xint
Xwrite_int(fp, value)
X FILE *fp;
X int value;
X{
X INT16 msint = int16(value);
X
X return fwrite((char *) &msint, sizeof(INT16), 1, fp);
X}
X
X/* Write fido msg header for mailfile. Mailfile contains first headers
X terminated by empty line, after that comes message text.
X Header consists of one letter id followed by arguments if any.
X
X Id-letters:
X N - fidonet address information of message, e.g. N 2:504/8.0.
X T - to whom message is to, e.g. T Teemu Torma.
X F - from whom message is from, e.g. F Foo Bar.
X S - subject of message, e.g S How are you?.
X P - indicates that message is private. (Here is little conflict:
X rfmail uses option -p to indicate that mail to public and here
X P means that mail is private. Maybe this P should mean that
SHAR_EOF
echo "End of part 2"
echo "File fpack.c is continued in part 3"
echo "3" > s2_seq_.tmp
exit 0