home *** CD-ROM | disk | FTP | other *** search
- From: mj@dfv.rwth-aachen.de (Martin Junius)
- Newsgroups: alt.sources
- Subject: FIDOGATE 05/06
- Message-ID: <mj.675078508@suntex>
- Date: 24 May 91 09:48:28 GMT
-
- ---- Cut Here and feed the following to sh ----
- #!/bin/sh
- # This is part 05 of a multipart archive
- # ============= funpack.c ==============
- if test -f 'funpack.c' -a X"$1" != X"-c"; then
- echo 'x - skipping funpack.c (File already exists)'
- else
- echo 'x - extracting funpack.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'funpack.c' &&
- /*:ts=4*/
- /*****************************************************************************
- X * FIDOGATE --- Gateway software UNIX <-> FIDO
- X *
- X * $Id: funpack.c,v 2.18 91/05/21 09:40:54 mj Exp $
- X *
- X * Unpack fido mail packets
- X *
- X * $Log: funpack.c,v $
- X * Revision 2.18 91/05/21 09:40:54 mj
- X * Changed log entry for NetMail messages.
- X *
- X * Revision 2.17 91/05/21 08:48:20 mj
- X * Fixed a small bug in bouncing mail.
- X *
- X * Revision 2.16 91/05/19 17:21:58 mj
- X * More clean-up of the source code. Mail to unknown local user is bounced.
- X *
- X * Revision 2.15 91/04/28 21:39:03 mj
- X * Changed address in `From_' line from packet origin node to message
- X * origin node. Less verbose `Received:' header.
- X *
- X * Revision 2.14 91/03/29 18:11:13 mj
- X * Names `UUCP' and `GATEWAY' aren't added to output To: adress. Log of
- X * personal mail improved. RFC headers at start of FIDO message are not
- X * included in output.
- X *
- X * Revision 2.13 91/01/28 19:33:07 mj
- X * Generated `Errors-To:' header for mail addressed from FIDO.
- X * `SEEN-BY' and tear lines are removed from output message.
- X *
- X * Revision 2.12 91/01/26 13:27:37 mj
- X * Changed generation of `Path' header to include FIDO address of gateway.
- X *
- X * Revision 2.11 90/12/09 17:34:26 mj
- X * Recognize `To:' header at start of message.
- X *
- X * Revision 2.10 90/12/02 21:22:02 mj
- X * Changed program header to mention both authors of the original
- X * software posted to alt.sources.
- X *
- X * Revision 2.9 90/11/23 20:41:10 mj
- X * Changed locally generated message ids to <funpackNNN@fN.nN.zN.fidonet.org>,
- X * corrected line breaking in ffgets().
- X *
- X * Revision 2.8 90/11/20 21:08:44 mj
- X * Added support for ^AINTL kludge.
- X *
- X * Revision 2.7 90/11/05 20:50:14 mj
- X * Changed my signature in all program headers.
- X *
- X * Revision 2.6 90/11/04 14:14:48 mj
- X * A small change in line wrapping: no more line wrapping at punctuation
- X * characters.
- X *
- X * Revision 2.5 90/11/01 14:33:56 mj
- X * Convert FIDO ^AMSGID and ^AREPLY kludges to RFC822 Message-ID and
- X * References headers.
- X *
- X * Revision 2.4 90/10/29 21:19:37 mj
- X * Ignore case when checking for name alias.
- X *
- X * Revision 2.3 90/09/16 17:35:49 mj
- X * Also look for "UUCPFROM:" in first lines of message body.
- X *
- X * Revision 2.2 90/09/09 10:54:37 mj
- X * Fixed a bug in handling of `ReplyTo:' in FIDO message body. Spaces
- X * in such an address are now striped off.
- X *
- X * Revision 2.1 90/09/08 18:46:32 mj
- X * Changed some code for getting real names out of FIDO from and to header
- X * fields. (Ignore things after "%" or "Of")
- X * Now we look for RFC822 like header lines at the beginning of the
- X * message body and use them for the `From:' and `To:' field.
- X *
- X * Revision 2.0 90/09/03 17:54:23 mj
- X * Rewrote much of the code inside this module.
- X * There are now hooks, where support for most of
- X * the FIDO ^A kludges (e.g. ^AMSGID) can be installed.
- X * Function stripbad() from nodelist.c moved to
- X * funpack.c
- X *
- X * Revision 1.7 90/08/12 11:56:54 mj
- X * Some changes. (what?)
- X *
- X * Revision 1.6 90/07/23 12:58:26 mj
- X * The FIDO `^AFMPT x' kludge is now recognized by funpack and
- X * inserted as the point address in the `From: ...' line.
- X *
- X * Revision 1.5 90/07/15 10:26:11 mj
- X * Messages for mail: M.xxxx.TO is not used any more. frecv now
- X * looks for `To: ...' line is mail file M.xxxx.
- X * Messages for news: Address from origin line is only substituted
- X * in header `From: ...' line, all others are left unchanged.
- X *
- X * Revision 1.4 90/07/01 15:20:18 mj
- X * Fixed some bugs in funpack caused by the removal of alloca().
- X * No more core dumps, but heaven knows, why it works now. Strange.
- X *
- X * Revision 1.3 90/07/01 13:45:50 mj
- X * Removed all calls to alloca(). All unsave malloc()'s without
- X * checking the returned pointer are now done via xmalloc().
- X * Fixed a malloc() error in rmail.
- X *
- X * Revision 1.2 90/06/28 22:04:19 mj
- X * Much rework of the sources, no more hsu.h and other clean up.
- X * rmail improved, now handles special XENIX quirks.
- X *
- X * Revision 1.1 90/06/21 21:09:19 mj
- X * Everything seems to work, so this delta was made.
- X *
- X * Revision 1.0 90/06/19 18:32:29 mj
- X * Initial revision
- X *
- X *
- X *****************************************************************************
- X * This version hacked and maintained by:
- X * _____ _____
- X * | |___ | Martin Junius FIDO: 2:242/6.1 2:242/6.0
- X * | | | | | | Republikplatz 3 DOMAIN: mju@dfv.rwth-aachen.de
- X * |_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931
- X *
- X * Original version of these programs and files:
- X *
- X * Teemu Torma
- X * Heikki Suonsivu FIDO: 2:504/1 UUCP: ...!mcsun!santra!hsu
- X *
- X *****************************************************************************/
- X
- /*
- X * Fido mail packets in SPOOL/in are processed and splitted into
- X * single messages for either news
- X * N.xxxx
- X * or mail
- X * M.xxxx
- X * in directory SPOOL/unpacked.
- X *
- X */
- X
- #include "fidogate.h"
- X
- #include <pwd.h>
- X
- X
- X
- #define PROGRAMNAME "funpack $Revision: 2.18 $"
- X
- X
- X
- #define SEPARATORS " ,;\015\012\011"
- #define WHITESPACE " \015\012\011"
- X
- X
- X
- extern time_t time();
- extern char *tzname[];
- extern int getopt();
- extern int optind;
- extern char *optarg;
- extern void exit(), perror();
- extern time_t dateconv();
- extern void swab();
- X
- X
- int verbose = INIT_VERBOSE;
- X
- /* Our net/node information */
- Node this;
- X
- /* News distribution for FIDO area */
- char distribution[64];
- X
- /* FIDO mail packet header */
- Packet header;
- X
- X
- /*
- X * For recognizing `^AINTL', `^AFMPT x', `^AMSGID ...' and `^AREPLY ...'
- X */
- #define SAVEBUFSIZ 256
- X
- static int msgbody_fmpt = 0;
- static char msgbody_msgid[SAVEBUFSIZ];
- static char msgbody_reply[SAVEBUFSIZ];
- static char msgbody_intl[SAVEBUFSIZ];
- X
- X
- /*
- X * For grabbing addresses from RFC822 header lines at start of message
- X */
- X
- static char *msgbody_rfc_from;
- static char *msgbody_rfc_to;
- X
- X
- X
- /*
- X * check_origin() --- Analyse ` * Origin: ...' line in FIDO message
- X * body and parse address in ()s into Node structure
- X *
- X * Origin line is checked for the rightmost occurence of
- X * ([text] z:n/n.p). If origin line get splitted across
- X * two lines you're out of luck.
- X */
- X
- check_origin(buffer, node, text)
- char *buffer;
- Node *node;
- char *text;
- {
- char *left, *right;
- char *buf;
- X
- X if(!strncmp(" * Origin:", buffer, 10)) {
- X debug(3, "Checking origin line for FIDO address");
- X buf = strsave(buffer);
- X right = strrchr(buf, ')');
- X if(!right) {
- X free(buf);
- X return(FALSE);
- X }
- X left = strrchr(buf, '(');
- X if(!left) {
- X free(buf);
- X return(FALSE);
- X }
- X *right = 0;
- X *left++ = 0;
- X /*
- X * Copy info text for Organization: header
- X */
- X strcpy(text, buf + strlen(" * Origin: "));
- X /*
- X * Parse node info
- X */
- X if(parsefnetaddress(left, node)) {
- X /* Not a valid FIDO address */
- X debug(3, "Could not parse %s", left);
- X node->zone = node->net = node->node = node->point = -1;
- X free(buf);
- X return(FALSE);
- X }
- X else {
- X /* Valid FIDO address */
- X debug(3, "Parsed %s to %s", left, ascnode(*node));
- X }
- X free(buf);
- X return(TRUE);
- X }
- X return(FALSE);
- }
- X
- X
- X
- /*
- X * check_ctrl_a() --- Check for various ^A kludges
- X */
- X
- check_ctrl_a(buffer)
- char *buffer;
- {
- register char *p;
- X
- X /*
- X * Look for `^AINTL ...'
- X */
- X if(!strncmp(buffer, "^AINTL", 6)) {
- X buffer += 6;
- X while(*buffer==':' || *buffer==' ')
- X buffer++;
- X strcpy(msgbody_intl, buffer);
- X }
- X
- X /*
- X * Look for `^AFMPT x'
- X */
- X if(!strncmp(buffer, "^AFMPT", 6)) {
- X for(p=buffer+6; *p && !isdigit(*p); p++);
- X if(*p)
- X msgbody_fmpt = atoi(p);
- X }
- X
- X /*
- X * Look for `^AMSGID ...'
- X */
- X if(!strncmp(buffer, "^AMSGID: ", 9))
- X strcpy(msgbody_msgid, buffer+9);
- X
- X /*
- X * Look for `^AREPLY ...'
- X */
- X if(!strncmp(buffer, "^AREPLY: ", 9))
- X strcpy(msgbody_reply, buffer+9);
- X
- }
- X
- X
- X
- /*
- X * check_rfc_header() --- Check for RFC822 like header lines at
- X * the beginning of the FIDO message body
- X */
- X
- int check_rfc_header(buffer)
- char *buffer;
- {
- X if(!strnicmp(buffer, "From: ", 6)) {
- X msgbody_rfc_from = strsaveline(buffer + 6);
- /* compress_spaces(msgbody_rfc_from); */
- X return(1);
- X }
- X if(!strnicmp(buffer, "Reply-To: ", 10)) {
- X msgbody_rfc_from = strsaveline(buffer + 10);
- X compress_spaces(msgbody_rfc_from);
- X return(1);
- X }
- X if(!strncmp(buffer, "UUCPFROM:", 9)) {
- X msgbody_rfc_from = strsaveline(buffer + 9);
- /* compress_spaces(msgbody_rfc_from); */
- X return(1);
- X }
- X if(!strnicmp(buffer, "To: ", 4)) {
- X msgbody_rfc_to = strsaveline(buffer + 4);
- X return(1);
- X }
- X if(!strnicmp(buffer, "To:", 3)) {
- X msgbody_rfc_to = strsaveline(buffer + 3);
- X return(1);
- X }
- X return(0);
- }
- X
- X
- X
- /*
- X * compress_spaces() --- Strip spaces out of string
- X */
- X
- compress_spaces(string)
- char *string;
- {
- char *p;
- X
- X for(p=string; *p; p++)
- X if(*p != ' ')
- X *string++ = *p;
- X *string = 0;
- }
- X
- X
- X
- /*
- X * Generate RFC822 message-id from FIDO ^AMSGID/REPLY kludge
- X */
- X
- int generate_msgid(fp, header, msgid)
- FILE *fp;
- char *header, *msgid;
- {
- char *system;
- char *id;
- Node idnode;
- long idnumber, xtol();
- X
- X /*
- X * Seperate system string
- X */
- X for(system=msgid; *msgid && !isspace(*msgid); msgid++);
- X if(!*msgid)
- X return(-1);
- X *msgid++ = 0;
- X /*
- X * Seperate id string
- X */
- X for(; *msgid && isspace(*msgid); msgid++);
- X if(!*msgid)
- X return(-1);
- X for(id=msgid; *msgid && isxdigit(*msgid); msgid++);
- X *msgid = 0;
- X
- X /*
- X * Try to interprete system as FIDO node
- X */
- X if(!parsefnetaddress(system, &idnode))
- X system = internode(idnode);
- X else
- X stripbad(system);
- X /*
- X * Convert hex id to decimal
- X */
- X idnumber = xtol(id);
- X
- X /*
- X * Output RFC822 style message id
- X */
- X fprintf(fp, "%s <%lu@%s>\n", header, idnumber, system);
- X
- X return(0);
- }
- X
- X
- X
- /*
- X * Replacement for fgets(3S) to understand cr's generated by Fido
- X * and 'soft' cr's generated by SEAdog.
- X * ie. 0 is got from file.
- X */
- X
- static char *
- ffgets(buffer, maxlen, fp)
- char *buffer;
- int maxlen;
- FILE *fp;
- {
- X register int c, ch, index;
- X register char *cp;
- X static char wordsave[BUFSIZ];
- X
- X /* TRUE if last line was origin line without valid node */
- X static int last_line_was_origin = FALSE;
- X
- X /* TRUE if last character caused line wrap */
- X static int last_char_wrapped = FALSE;
- X Node node;
- X
- X /* There might be wrapped word lying around */
- X if (*wordsave) {
- X strcpy(buffer, wordsave);
- X strsclean(buffer);
- X debug(20, "Picked up word '%s'", buffer);
- X *wordsave = 0;
- X }
- X else
- X *buffer = 0;
- X
- X cp = buffer + strlen(buffer);
- X
- X while (--maxlen > 0 && (c = getc(fp)) != EOF && c) {
- X /* Hard carriage return */
- X
- X if (c == '\r')
- X c = '\n';
- X else if (c == '\n' || c == 0x8d) {
- X /* Forget about these ! */
- X continue;
- X }
- X else if(c < ' ') {
- X /*
- X * Substitute control chars with '^X'
- X */
- X if(c != '\t') {
- X *cp++ = '^';
- X c = c + '@';
- X }
- X }
- X else if(c & 0x80) {
- X /*
- X * Convert IBM umlaut chars and others above 0x80
- X */
- X switch(c) {
- X case 132:
- X *cp++ = 'a'; c = 'e'; break;
- X case 148:
- X *cp++ = 'o'; c = 'e'; break;
- X case 129:
- X *cp++ = 'u'; c = 'e'; break;
- X case 142:
- X *cp++ = 'A'; c = 'e'; break;
- X case 153:
- X *cp++ = 'O'; c = 'e'; break;
- X case 154:
- X *cp++ = 'U'; c = 'e'; break;
- X case 225: case 158:
- X *cp++ = 's'; c = 's'; break;
- X default:
- X c = '*'; break;
- X }
- X }
- X
- X /*
- X * If last character caused line wrap, and we now got another linefeed,
- X * skip this linefeed to avoid unneeded empty lines.
- X */
- X if (last_char_wrapped) {
- X if (c == '\n') {
- X last_char_wrapped = FALSE;
- X continue;
- X }
- X
- X if (isspace(c) && strempty(buffer))
- X continue;
- X }
- X
- X *cp++ = c;
- X
- X if (c == '\n')
- X break;
- X
- X *cp = 0;
- X
- X /*
- X * Try to wrap if line is too long and it is not a seen-by, origin or
- X * path line.
- X */
- X if (strlen(buffer) >= MAX_LINELEN &&
- X strncmp(" * Origin:", buffer, 10) &&
- X strncmp("SEEN-BY:", buffer, 8) &&
- X strncmp("^A", buffer, 2) &&
- X strncmp("FSC-Control:", buffer, 12)) { /* - 1 for \n */
- X last_char_wrapped = TRUE;
- X
- X /* Search for place to cut */
- X for (index = strlen(buffer) - 1; index >= 0; index--) {
- X c = buffer[index];
- X if (index <= MAX_LINELEN / 3) {
- X /* Too long, cut. */
- X *cp++ = c = '\n';
- X goto collected;
- X }
- X
- X if (isspace(c)) {
- X /* Wrap here! */
- X cp = buffer + index + 1; /* Punctuation left on this
- X * line */
- X strcpy(wordsave, cp);
- X debug(20, "saving word '%s'", wordsave);
- X *cp++ = c = '\n';
- X goto collected;
- X }
- X }
- X }
- X
- X last_char_wrapped = FALSE;
- X }
- X
- X collected:
- X
- X /* if we got nul, put it back if occurred in the middle of line */
- X if (!c && cp != buffer)
- X (void) ungetc(0, fp);
- X
- X *cp = 0; /* Cut it here */
- X
- X
- X out:
- X return ((!c || c == EOF) && cp == buffer) ? (char *) 0 : buffer;
- }
- X
- X
- X
- /*
- X * Read FIDO message header from input file
- X */
- X
- read_header(fp)
- FILE *fp;
- {
- X header.orig_node = read_int(fp);
- X header.dest_node = read_int(fp);
- X header.year = read_int(fp);
- X header.month = read_int(fp);
- X header.day = read_int(fp);
- X header.hour = read_int(fp);
- X header.minute = read_int(fp);
- X header.second = read_int(fp);
- X header.rate = read_int(fp);
- X header.ver = read_int(fp);
- X header.orig_net = read_int(fp);
- X header.dest_net = read_int(fp);
- X header.product = getc(fp);
- X header.x1 = getc(fp);
- X fread(header.pwd_kludge, 8, 1, fp);
- X header.orig_zone = read_int(fp);
- X if (header.orig_zone == 0)
- X header.orig_zone = MY_ZONE;
- X header.dest_zone = read_int(fp);
- X if (header.dest_zone == 0)
- X header.dest_zone = MY_ZONE;
- X fread(header.B_fill2, 16, 1, fp);
- X fread((char *) &header.B_fill3, 4, 1, fp);
- X return(ferror(fp) || feof(fp));
- }
- X
- X
- X
- /*
- X * Read 16-bit integer in 80x86 format, i.e. low byte first,
- X * then high byte. Machine independent function.
- X */
- X
- int read_int(fp)
- FILE *fp;
- {
- register int c;
- register int val;
- X
- X if((c = getc(fp)) == EOF) {
- X log("$Can't read file (EOF)");
- X return(0);
- X }
- X val = c;
- X if((c = getc(fp)) == EOF) {
- X log("$Can't read file (EOF)");
- X return(0);
- X }
- X val |= c << 8;
- X return(val);
- }
- X
- X
- X
- /* Read null-terminated string from file. Ensure that buffer is also
- X null-terminated. Remove possible \n:s from end, they are generated by
- X some buggy mailers. */
- X
- void
- get_string(buffer, fp, nbytes)
- char *buffer;
- FILE *fp;
- int nbytes;
- {
- X register int n;
- X char *p;
- X
- X debug(8, "get string start %ld", ftell(fp));
- X
- X for (n = 0, *buffer = 0; n < nbytes; n++)
- X if ((buffer[n] = getc(fp)) == 0)
- X break;
- X else
- X debug(8, "<%d %c>", buffer[n], buffer[n]);
- X
- X /* If still more chars in buffer, skip them until null char found */
- X if (n >= nbytes) {
- X debug(8, "Skipping rest");
- X while (getc(fp)) ;
- X }
- X
- X buffer[nbytes] = 0;
- X
- X /* Remove \n from end if its there, its a bug */
- X if (p = strchr(buffer, '\n'))
- X *p = 0;
- X
- X debug(8, "Getstring at %ld %s", ftell(fp), buffer);
- }
- X
- X
- X
- /*
- X * Like strtok but returns empty string instead of null if no more thigns
- X * found
- X */
- X
- char *
- estrtok(s, sep)
- char *s, *sep;
- {
- X char *p;
- X
- X if (p = strtok(s, sep))
- X return p;
- X return "";
- }
- X
- X
- X
- /*
- X * Get matching newsgroup for FIDO area from `AREAS' file
- X */
- X
- char *get_ng(config, echo, distrib)
- FILE *config;
- char *echo, *distrib;
- {
- static char conv[BUFLEN];
- char *gr, *flag;
- X
- X debug(2, "Checking echolist '%s'", echo);
- X
- X while (getcl(conv, BUFLEN, config)) {
- X debug(3, "Config line '%s'", conv);
- X
- X gr = estrtok(conv, SEPARATORS);
- X if (!strcmp(gr, echo)) {
- X /* Matched, take distribution and return newsgroup */
- X
- X gr = estrtok(NULL, SEPARATORS);
- X strcpy(distrib, estrtok(NULL, SEPARATORS));
- X
- X debug(3, "Match, return newsgroup '%s', distribution %s",
- X gr, distrib);
- X return gr;
- X }
- X }
- X log("No newsgroup for '%s' found, return junk, distribution local", echo);
- X strcpy(distrib, "local");
- X return "junk";
- }
- X
- X
- X
- /*
- X * Test for news article by reading first line. If it starts with `AREA:'
- X * this is FIDO EchoMail. Returns matching newsgroup name or NULL.
- X */
- X
- char *news_msg(fp)
- FILE *fp;
- {
- FILE *config;
- long offset = ftell(fp);
- char *cp;
- static char area[128];
- X
- X if (ffgets(area, 128, fp) && !strncmp(area, "AREA:", 5)) {
- X /* this is echomail-message */
- X area[strlen(area) - 1] = 0;
- X
- X /* strip possible spaces */
- X for (cp = area + 5; *cp && isspace(*cp); cp++) ;
- X
- X if ((config = pfopen(LIBDIR, "Areas", "r")) == NULL) {
- X log("$Unable to open areas file");
- X exit(1);
- X }
- X
- X strcpy(cp, get_ng(config, cp, distribution));
- X fclose(config);
- X
- X /* return converted area-name */
- X return cp;
- X }
- X else {
- X /* this is not echomail message, seek back */
- X (void) fseek(fp, offset, 0);
- X return (char *) 0;
- X }
- X /* NOTREACHED */
- }
- X
- X
- X
- /*
- X * Return date of message in UNIX format (secs after the epoche)
- X *
- X * Understood formats: see getdate.y
- X */
- X
- time_t lgetdate(packet)
- FILE *packet;
- {
- char buffer[20];
- int c;
- time_t timevar;
- int n;
- X
- X /*
- X * Some FIDO message packers do it wrong! Regarding FTS-0001, the
- X * message date is a fixed 20 bytes long string. But some programs,
- X * e.g. QMail under certain circumstances, produce 19 bytes dates.
- X */
- X /* read date from packet */
- X for (n = 0; n < 20; n++)
- X if ((buffer[n] = getc(packet)) == 0)
- X break;
- X buffer[19] = 0;
- X
- X debug(8, "Getdate %s at %ld", buffer, ftell(packet));
- X
- X /* try to get date */
- X timevar = getdate(buffer, NULL);
- X return timevar;
- }
- X
- X
- X
- /* Search alias name which matches with fidonet name, return NULL
- X if no alias specified. */
- X
- char *
- get_alias(name)
- char *name;
- {
- X char buffer[BUFSIZ];
- X char *cp;
- X FILE *fp;
- X static char unixname[BUFSIZ], fidoname[BUFSIZ];
- X
- X if (fp = fopen(ALIAS, "r")) {
- X while (fgets(buffer, BUFSIZ, fp)) {
- X buffer[strlen(buffer) - 1] = 0;
- X if (*buffer != '#') {
- X if ((cp = strchr(buffer, ' ')) ?
- X cp : (cp = strchr(buffer, '\t'))) {
- X *cp = 0; /* Break unixname out */
- X strcpy(unixname, buffer); /* And save it */
- X debug(8, "Unix name %s", unixname);
- X }
- X else {
- X /* No space or tab found, probably bad line */
- X debug(1, "Bad alias line %s", buffer);
- X continue;
- X }
- X
- X /* Search for name start, there may be space between */
- X cp++;
- X while (*cp && isspace(*cp))
- X cp++;
- X if (!*cp) {
- X debug(1, "Bad alias line %s", buffer);
- X continue;
- X }
- X
- X strcpy(fidoname, cp); /* Save fidonet name */
- X debug(8, "Fidoname %s", fidoname);
- X
- X if (!stricmp(fidoname, name)) {
- X fclose(fp);
- X
- X /* There may be node specs after name, null them out */
- X if (cp = strchr(unixname, ','))
- X *cp = 0;
- X
- X debug(8, "Fidoname %s matched with %s, return %s",
- X fidoname, name, unixname);
- X return unixname;
- X }
- X }
- X }
- X }
- X
- X fclose(fp);
- X return NULL;
- }
- X
- X
- X
- /*
- X * Strip bad chars from FIDO names, i.e. chars not allowed in
- X * RFC822 `atoms'. One execption is ' ' (space), which is converted
- X * to '_' later on.
- X */
- X
- stripbad(name)
- char *name;
- {
- char *d;
- X
- X for(d=name; *d; d++)
- X if( !iscntrl(*d) && !strchr("()<>@,;:\\\"[]", *d) )
- X *name++ = *d;
- X *name = 0;
- }
- X
- X
- X
- /*
- X * Capitalize string
- X */
- X
- char *strcap(s)
- char *s;
- {
- X if(!s || !*s)
- X return(s);
- X if(islower(*s))
- X *s = toupper(*s);
- X for(s++; *s; s++)
- X if(isupper(*s))
- X *s = tolower(*s);
- X return(s);
- }
- X
- X
- X
- /*
- X * Convert name in FIDO from or to field to real name
- X * for use in () in RFC822 header. Everything after
- X * `%' or `Of' is thrown away. The result is capitalized.
- X */
- X
- realname_convert(name, realname)
- char *name;
- char *realname;
- {
- char *p, *string;
- int cat_flag = 0;
- X
- X string = strsave(name);
- X *realname = 0;
- X for(p=strtok(string, " \t"); p; p=strtok(NULL, " \t")) {
- X if(!strcmp(p, "%") || !strcmp(p, "of") || !strcmp(p, "Of") ||
- X !strcmp(p, "-") )
- X break;
- X strcap(p);
- X if(cat_flag)
- X strcat(realname, " ");
- X strcat(realname, p);
- X cat_flag = 1;
- X }
- X free(string);
- }
- X
- X
- X
- /*
- X * Unpack FIDO mail packet. Each message header und some information in
- X * the message body (^A kludges and some RFC like lines) ist converted
- X * to an RFC compatible message header. If the first line of the message
- X * starts with `AREA:' then message is processed as a news article, else
- X * as a mail message.
- X */
- X
- void unpack(packet, packetnode)
- FILE *packet;
- Node packetnode;
- {
- /*
- X * Variables for header info
- X */
- Node msg_orignode, msg_destnode; /* Origin/destination address */
- int msg_attributes; /* Attributes of message (priv. etc.) */
- time_t msg_date; /* Date of message */
- char msg_to[36]; /* To name */
- char msg_from[36]; /* From name */
- char msg_subject[72]; /* Subject */
- /*
- X * Variables for info from FIDO kludges
- X */
- Node origin_node; /* Address in origin line */
- char origin_text[128]; /* Organization taken from * Origin */
- X
- int lines; /* Lines in message body */
- X
- char *area; /* Area / newsgroup (NULL = mail) */
- char *p;
- int count, messagetype;
- char realto[40], realfrom[40];
- char searchto[36];
- char buffer[BUFSIZ];
- int c;
- Node *entry, mynode;
- Node node;
- char hostname[10];
- long msgid; /* Msg id from sequence file */
- char out_name[128]; /* Name for output msg */
- char mail_to[128]; /* Addressee of mail */
- FILE *outtmp, *out;
- int rfc_header_flag;
- X
- X
- #ifdef NODELIST_SUPPORT
- X /* get node-entry fo packet-sender */
- X if (node_entry(packetnode) == NULL) {
- X log("Unknown packet sender: %s", ascnode(packetnode));
- X return;
- X }
- #endif
- X
- X mynode.zone = MY_ZONE;
- X mynode.net = MY_NET;
- X mynode.node = MY_NODE;
- X mynode.point = MY_POINT;
- X strcpy(mynode.name, MY_NAME);
- X
- #ifdef NODELIST_SUPPORT
- X if ((entry = node_entry(mynode)) == NULL) {
- X log("Unable to find this net/node from nodelist");
- X return;
- X }
- #else
- X entry = &mynode;
- #endif
- X
- X /* get our uucp-nodename */
- X if (gethostname(hostname, 10) == -1) {
- X log("Unable to get hostname");
- X return;
- X }
- X
- X while ((messagetype = read_int(packet)) == MSGTYPE) {
- X /*
- X * Clear stuff set by parsing message body
- X */
- X origin_node.zone = -1;
- X origin_text[0] = 0;
- X msgbody_fmpt = 0;
- X msgbody_msgid[0] = 0;
- X msgbody_reply[0] = 0;
- X msgbody_intl[0] = 0;
- X if(msgbody_rfc_from) {
- X free(msgbody_rfc_from);
- X msgbody_rfc_from = NULL;
- X }
- X if(msgbody_rfc_to) {
- X free(msgbody_rfc_to);
- X msgbody_rfc_to = NULL;
- X }
- X lines = 1;
- X
- X /*
- X * Initialize some stuff
- X */
- X msg_orignode.zone = packetnode.zone;
- X msg_orignode.point = packetnode.point;
- X msg_destnode.zone = packetnode.zone;
- X msg_destnode.point = packetnode.point;
- X
- X /*
- X * Read FIDO message header and save information
- X */
- X /***** Origin/destination node *****/
- X msg_orignode.node = read_int(packet);
- X msg_destnode.node = read_int(packet);
- X /***** Origin/destination net *****/
- X msg_orignode.net = read_int(packet);
- X msg_destnode.net = read_int(packet);
- X debug(2, "Origin: %s", ascnode(msg_orignode));
- X debug(2, "Destination: %s", ascnode(msg_destnode));
- X /***** Message attributes *****/
- X msg_attributes = read_int(packet);
- X /***** Cost (thrown away) *****/
- X read_int(packet);
- X /***** Date *****/
- X msg_date = lgetdate(packet);
- X /***** To name *****/
- X get_string(msg_to, packet, 35);
- X debug(2, "To: %s", msg_to);
- X /***** From name *****/
- X get_string(msg_from, packet, 35);
- X debug(2, "From: %s", msg_from);
- X /***** Subject *****/
- X get_string(msg_subject, packet, 71);
- X /* Remove trailing blanks */
- X for(count = strlen(msg_subject) - 1;
- X count >= 0 && isspace(msg_subject[count]);
- X count-- )
- X msg_subject[count] = 0;
- X if (!*msg_subject)
- X strcpy(msg_subject, "(no subject)");
- X debug(2, "Subject: %s", msg_subject);
- X
- X /*
- X * Check that message is addressed to this node
- X */
- X if(!samenode(msg_destnode, mynode)) {
- X log("Msg from %s to %s at %s: wrong node address",
- X msg_from, msg_to, ascnode(msg_destnode));
- X goto error;
- X }
- X
- X /*
- X * Strip bad chars from header fields
- X */
- X stripbad(msg_from);
- X stripbad(msg_to);
- X strcpy(searchto, msg_to);
- X /*
- X * Convert to real names for use in ()
- X */
- X realname_convert(msg_from, realfrom);
- X realname_convert(msg_to, realto);
- X /*
- X * We don't want `UUCP' and `GATEWAY' as names
- X */
- X if(!stricmp(realto, "UUCP"))
- X *realto = 0;
- X if(!stricmp(realto, "GATEWAY"))
- X *realto = 0;
- X /*
- X * Convert spaces to `_'
- X */
- X for(p=msg_from; *p; p++)
- X *p = *p==' ' ? '_' : *p;
- X for(p=msg_to; *p; p++)
- X *p = *p==' ' ? '_' : *p;
- X
- X /*
- X * Get next message-id
- X */
- X msgid = sequencer(IDSEQUENCE);
- X
- X /*
- X * Check for mail or news.
- X * Read first line from FIDO message body. If it starts with
- X * `AREA:...' then it is news, else it is mail. area is newsgroup
- X * name or NULL for mail.
- X */
- X if(area = news_msg(packet)) {
- X /*
- X * This is a news article.
- X */
- X debug(1, "Message is news-article");
- X sprintf(out_name, "%s/unpacked/N.%ld", SPOOL, msgid);
- X }
- X else {
- X /*
- X * This is personal mail
- X */
- X debug(1, "Message is for mail");
- X sprintf(out_name, "%s/unpacked/M.%ld", SPOOL, msgid);
- X
- X debug(8, "Searching alias for %s", searchto);
- X if (p = get_alias(searchto)) {
- X (void) strcpy(buffer, p);
- X debug(8, "Got alias %s", buffer);
- X }
- X else {
- X (void) strcpy(buffer, msg_to);
- X debug(8, "No alias, using %s", buffer);
- X }
- X
- X for(p=buffer; *p; p++)
- X *p = isupper(*p) ? tolower(*p) : *p;
- X
- X strcpy(mail_to, buffer);
- X
- X area = NULL;
- X }
- X
- X /*
- X * Create files
- X */
- X outtmp = tmpfile();
- X if(!outtmp) {
- X log("$Can't create temp file");
- X goto error;
- X }
- X out = fopen(out_name, "w");
- X if(!out) {
- X log("$Can't create output file %s", out_name);
- X fclose(outtmp);
- X goto error;
- X }
- X
- X /*
- X * Read entire FIDO message body and write it
- X * to temporary file for later use. (Must read
- X * message body first `cause we need some information
- X * from it.)
- X * Some special treatment for origin line and ^A
- X * kludges is done.
- X */
- X rfc_header_flag = 1;
- X while(ffgets(buffer, BUFSIZ, packet)) {
- X if(!strncmp(buffer, "^A", 2)) {
- X check_ctrl_a(buffer);
- X continue;
- X }
- X else if(rfc_header_flag) {
- X if(rfc_header_flag = check_rfc_header(buffer))
- X continue;
- X }
- X if(!strncmp(" * Origin:", buffer, 10)) {
- X check_origin(buffer, &origin_node, origin_text);
- X continue;
- X }
- X if(!strncmp("SEEN-BY:", buffer, 8) ||
- X !strncmp("--- ", buffer, 4) )
- X continue;
- X lines++;
- X fputs(buffer, outtmp);
- X }
- X
- X /*
- X * Construct real from address, using information from
- X * header, origin line and ^A kludges.
- X */
- X if(area && origin_node.zone != -1) {
- X debug(1, "Using address from ` * Origin: ...'");
- X msg_orignode = origin_node;
- X }
- X else {
- X debug(1, "Using address in message header");
- X }
- X if(*msgbody_intl) {
- X p = strtok(msgbody_intl, " \n"); /* Destination */
- X p = strtok(NULL , " \n"); /* Source */
- X if(p)
- X if(!parsefnetaddress(p, &node)) {
- X debug(1, "Using address from ^AINTL");
- X msg_orignode = node;
- X }
- X }
- X if(msgbody_fmpt) {
- X debug(1, "Point address %d", msgbody_fmpt);
- X msg_orignode.point = msgbody_fmpt;
- X }
- X debug(1, "New from address %s", ascnode(msg_orignode));
- X
- X /*
- X * Check mail messages' user name
- X */
- X if(!area && !msgbody_rfc_to) {
- X /*
- X * If mail_to is a local user name, check for existence.
- X * If user does not exist, bounce message.
- X */
- X struct passwd *pw, *getpwnam();
- X
- X pw = getpwnam(mail_to);
- X if(!pw) { /* Doesn't exist -> bounce */
- X fprintf(out, "From funpack %s\n",
- X date("%a %h %d %T 19%y", NULL) );
- X fprintf(out, "Date: %s\n", date("%a, %d %h %y %T %o", NULL));
- X fprintf(out, "From: Gateway to FIDONet <%s@%s>\n",
- X "rfmail", internode(this) );
- X fprintf(out, "Subject: Returned mail: user unknown\n");
- X fprintf(out, "Message-Id: <%s.AA%05d@%s>\n",
- X date("%y%m%q%H%M", (long *) 0), getpid(),
- X internode(this) );
- X fprintf(out, "To: %s@%s\n", msg_from, internode(msg_orignode));
- X fprintf(out, "\n ----- Transcript of session follows -----\n");
- X fprintf(out, "User %s is unknown at %s%s.\n\n",
- X mail_to, MY_HOSTNAME, MY_DOMAIN );
- X fprintf(out, "If you want to send mail to a user on the Internet/Usenet/DNet/EUNET\n");
- X fprintf(out, "via this gateway, your message must start with a `To:' line containing\n");
- X fprintf(out, "the address, e.g.\n");
- X fprintf(out, " To: mj@dfv.rwth-aachen.de\n\n");
- X fprintf(out, " ----- Unsent message follows -----\n");
- X
- X log("Mail from %s at %s to %s bounced", msg_from,
- X ascnode(msg_orignode), mail_to );
- X
- X goto output_msgbody;
- X }
- X }
- X
- X /*
- X * Output `From user ...' for mail
- X */
- X if(!area) {
- X fprintf(out, "From %s %s remote from %s\n",
- X msg_from, date("%a %h %d %T 19%y", NULL),
- X internode(msg_orignode) );
- X /* Log it */
- X log("%s @ %s -> %s", msg_from, ascnode(msg_orignode),
- X msgbody_rfc_to ? msgbody_rfc_to : mail_to );
- X }
- X
- X /*
- X * Output RFC822 header for mail/news
- X */
- X if(area)
- X fprintf(out, "Path: %s!%s!%s\n",
- X internode(this), internode(msg_orignode), msg_from);
- X else {
- X fprintf(out, "Received: by %s (%s)\n",
- X internode(*entry), PROGRAMNAME);
- X fprintf(out, "\tid AA%05d; %s\n",
- X getpid(), date("%a, %d %h %y %T %o (%z)", (long *) 0));
- X }
- X fprintf(out, "Date: %s\n", date("%a, %d %h %y %T %o", &msg_date));
- X if(msgbody_rfc_from) {
- X if(strchr(msgbody_rfc_from, '('))
- X fprintf(out, "From: %s\n", msgbody_rfc_from);
- X else
- X fprintf(out, "From: %s (%s)\n", msgbody_rfc_from, realfrom);
- X }
- X else
- X fprintf(out, "From: %s@%s (%s)\n", msg_from, internode(msg_orignode),
- X realfrom);
- #ifdef LOCAL_REPLY_TO
- X fprintf(out, "Reply-To: %s%%%s@%s%s (%s)\n", msg_from,
- X internodex(msg_orignode), MY_HOSTNAME, MY_DOMAIN, realfrom );
- #endif
- X fprintf(out, "Subject: %s\n", msg_subject);
- X if(!*msgbody_msgid ||
- X generate_msgid(out, "Message-ID:", msgbody_msgid) )
- X fprintf(out, "Message-ID: <funpack%lu@%s>\n", msgid, internode(*entry));
- X if(*msgbody_reply)
- X generate_msgid(out, "References:", msgbody_reply);
- X
- X if (area) {
- X /*
- X * News special
- X */
- X fprintf(out, "Newsgroups: %s\n", area);
- X if(*distribution)
- X fprintf(out, "Distribution: %s\n", distribution);
- X /***** This is a *USER DEFINED* header, not in RFC822 !!! *****/
- X fprintf(out, "Comment-To: %s@%s (%s)\n", msg_to,
- X internode(msg_destnode), realto);
- X }
- X else {
- X /*
- X * Mail special
- X */
- X if(msgbody_rfc_to) {
- X if(strchr(msgbody_rfc_to, '(') || !*realto)
- X fprintf(out, "To: %s\n", msgbody_rfc_to);
- X else
- X fprintf(out, "To: %s (%s)\n", msgbody_rfc_to, realto);
- X /* Bounced messages will be sent to ... */
- #ifdef ERRORS_TO
- X fprintf(out, "Errors-To: %s\n", ERRORS_TO);
- #endif
- X }
- X else
- X fprintf(out, "To: %s\n", mail_to);
- X }
- X /*
- X * Some more headers ...
- X */
- X if(*origin_text)
- X fprintf(out, "Organization: %s\n", origin_text);
- X fprintf(out, "Lines: %d\n", lines);
- X
- X /*
- X * Append message body in temporary file to message
- X */
- X fprintf(out, "\n");
- X
- output_msgbody:
- X rewind(outtmp);
- X while(fgets(buffer, BUFSIZ, outtmp))
- X fputs(buffer, out);
- X
- X /*
- X * Dome with this message.
- X */
- X fclose(outtmp);
- X fclose(out);
- X debug(1, "Done with message");
- X continue;
- X
- X /*
- X * In case of error skip text of message
- X */
- error:
- X while((c = getc(packet)) && c != EOF);
- X }
- X
- X if (messagetype != MSGTYPE && messagetype != EOF && messagetype != 0)
- X log("Strange ending: %d", messagetype);
- X
- X debug(1, "Done with packet");
- }
- X
- X
- X
- main(argc, argv)
- int argc;
- char *argv[];
- {
- struct dirent *dir;
- DIR *dp;
- int c;
- FILE *packet;
- char files[BUFLEN];
- Node node;
- bool nocheck = FALSE;
- char *error, *p;
- Node packetnode;
- X
- X node.zone = -1;
- X while ((c = getopt(argc, argv, "if:vV:")) != EOF)
- X switch (c) {
- X case 'i':
- X nocheck = TRUE;
- X break;
- X case 'v':
- X verbose++;
- X break;
- X case 'V':
- X verbose = atoi(optarg);
- X break;
- X case 'f':
- X if (parsefnetaddress(optarg, &node))
- X exit(1);
- X break;
- X default:
- X fprintf(stderr, "%s\n\n", PROGRAMNAME);
- X fprintf(stderr, "usage: funpack [-iv] [-V verbose_level] [-f Z:N/F.P]\n\n");
- X exit(EX_USAGE);
- X break;
- X }
- X
- X this.zone = MY_ZONE;
- X this.net = MY_NET;
- X this.node = MY_NODE;
- X this.point = MY_POINT;
- X strcpy(this.name, MY_NAME);
- X
- X /* create name for unpacking */
- X if (node.zone == -1)
- X (void) strcpy(files, "");
- X else {
- X sprintipacketname(files, node);
- X /* Cut sequence number off */
- X if (p = strrchr(files, "."))
- X *p = 0;
- X }
- X
- X debug(2, "Unpacking packets beginning with %s", files);
- X
- X /* try to update nodelist-index */
- #ifdef NODELIST_SUPPORT
- X if (error = update_index()) {
- X if (*error == '$')
- X log("$Cannot update nodelist-index: %s", error + 1);
- X else
- X log("Cannot update nodelist-index: %s", error);
- X exit(EX_OSERR);
- X }
- #endif
- X if (chdir(sprintfs("%s/in", SPOOL)) == -1) {
- X log("$Cannot chdir to %s/in", SPOOL);
- X exit(EX_OSERR);
- X };
- X if (dp = opendir(".")) {
- X while (dir = readdir(dp))
- X if (!strncmp(dir->d_name, files, strlen(files)) && *dir->d_name != '.') {
- X
- X /* this packet is right */
- X debug(1, "Unpacking %s", dir->d_name);
- X
- X /* open packet */
- X if (packet = fopen(dir->d_name, "r")) {
- X if (read_header(packet)) {
- X if (feof(packet))
- X log("Missing packet header");
- X else
- X log("$Error reading header");
- X }
- X else {
- X packetnode.zone = header.orig_zone;
- X packetnode.net = header.orig_net;
- X packetnode.node = header.orig_node;
- X packetnode.point = 0;
- X debug(1, "Packet from %s", ascnode(packetnode));
- X debug(1, "Time %02d:%02d:%02d %d.%d.%d",
- X header.hour, header.minute, header.second,
- X header.day, header.month+1, header.year );
- X debug(1, "Max baud rate %d, version %d, product %d, x %d",
- X header.rate, header.ver, header.product, header.x1);
- X debug(1, "Pwd \"%s\"", header.pwd_kludge);
- X }
- X
- X if (nocheck || ((header.dest_zone == MY_ZONE ||
- X header.dest_zone == 0) &&
- X header.dest_node == MY_NODE &&
- X header.dest_net == MY_NET))
- X unpack(packet, packetnode);
- X else
- X log("Packet is to %d:%d/%d",
- X header.dest_zone,
- X header.dest_net,
- X header.dest_node);
- X (void) fclose(packet);
- X
- X if (unlink(dir->d_name))
- X log("$Could not unlink packet %s", dir->d_name);
- X }
- X else
- X log("$Unable open packet %s", dir->d_name);
- X }
- X (void) closedir(dp);
- X }
- X else {
- X log("$Unable to open spool directory");
- X exit(EX_OSERR);
- X }
- X exit(EX_OK);
- X /* NOTREACHED */
- }
- SHAR_EOF
- chmod 0644 funpack.c ||
- echo 'restore of funpack.c failed'
- Wc_c="`wc -c < 'funpack.c'`"
- test 33958 -eq "$Wc_c" ||
- echo 'funpack.c: original size 33958, current size' "$Wc_c"
- fi
- true || echo 'restore of nodelist.c failed'
- echo End of part 5, continue with part 6
- exit 0
-
- --
- _____ _____
- | |___ | Martin Junius FIDO: 2:242/6.1 2:242/6.0
- | | | | | | Republikplatz 3 DOMAIN: mj@dfv.rwth-aachen.de
- |_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931
-