home *** CD-ROM | disk | FTP | other *** search
- 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
-
-