FIDOGATE Part 5/6
Martin Junius
mj at dfv.rwth-aachen.de
Mon Jan 28 20:35:49 AEST 1991
---- 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.12 91/01/26 13:27:37 mj Exp $
X *
X * Unpack fido mail packets
X *
X * $Log: funpack.c,v $
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 at 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 at 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
X
X
#define PROGRAMNAME "funpack $Revision: 2.12 $"
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;
int acceptprivate = FALSE;
int trashprivate = FALSE;
X
/* Our net/node information */
Node this;
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(!strncmp(buffer, "From: ", 6)) {
X msgbody_rfc_from = strsaveline(buffer + 6);
/* compress_spaces(msgbody_rfc_from); */
X return(1);
X }
X if(!strncmp(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(!strncmp(buffer, "To: ", 4)) {
X msgbody_rfc_to = strsaveline(buffer + 4);
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
static Packet header;
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
#define NGFLAG_ACCEPT_PRIVATE 0
#define NGFLAG_COMMAND 1
#define NGFLAG_TRASH_PRIVATE 2
X
static char distribution[64];
static char *ngflags[] =
{"accept-private", "command", "trash-private", ""};
X
/* Like strtok but returns empty string instead of null if no more thigns
X found */
X
char *
estrtok(s, sep)
char *s, *sep;
{
X char *p;
X
X if (p = strtok(s, sep))
X return p;
X return "";
}
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
/* section(SECT_AREA_NG, config); /**/
X trashprivate = FALSE;
X acceptprivate = FALSE;
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 while (flag = strtok(NULL, SEPARATORS))
X switch (listscan(ngflags, flag)) {
X case NGFLAG_ACCEPT_PRIVATE:
X acceptprivate = TRUE;
X break;
X
X case NGFLAG_TRASH_PRIVATE:
X trashprivate = TRUE;
X break;
X
X case -1:
X default:
X log("Bad flag '%s' for newsgroup %s", flag, gr);
X break;
X }
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
/* Check if message is news-message (currenlty: if first line begins
X with AREA:). If area is found, we'll return name for that area,
X otherwise NULL. */
X
char *
news_msg(fp)
FILE *fp;
{
X FILE *config;
X long offset = ftell(fp);
X char *cp;
X static char area[64];
X
X if (ffgets(area, 64, 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 /* read date from packet */
X for (n = 0; n < 20; n++)
X if ((buffer[n] = getc(packet)) == 0)
X break;
X
X /*
X * Some message-packers do mistakes! Date should be 20 bytes but they start
X * name directly after null terminating 18-char date used in some systems.
X * Check if following char is null or not, and if not, put it back there as
X * it probably is first char in recipent name. This seems to be problem in
X * OMMM, but I'm not sure yet.
X *
X * Wed Nov 16 21:11:34 1988 Seems that the bug is in fsc001, as I constantly
X * keep receiving messages which 19 byte date?
X */
X
#ifdef FSC_IS_REALLY_CORRECT
X for (n++; n < 20; n++)
X if (c = getc(packet)) {
X ungetc(c, packet);
X }
#endif
X
X buffer[19] = 0;
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
/* Unpack packet and all files in it. Packet's header will be stripped
X off. For each message check if it is news-msg (First line begins
X with AREA:). If it is, send it to news-sender sfnews, otherwise
X send it to rmail. Address is given in to-field, or if it wont
X fit to it, in the first line of message. In later case to-field
X must be "Usenet". */
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 * 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 (acceptprivate || !(msg_attributes & ATTR_PRIVATE)))
X {
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 if (area) {
X debug(1, "Private message for area %s", area);
X if (trashprivate)
X goto error;
X }
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 if (area) {
X log("Skipping private echo for %s", msg_to);
X goto error; /* If private echo message, skip */
X }
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 log("Sending mail from %s at %s to %s", msg_from,
X ascnode(msg_orignode), 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 rfc_header_flag = check_rfc_header(buffer);
X }
X if(!strncmp(" * Origin:", buffer, 10)) {
X check_origin(buffer, &origin_node, origin_text);
X }
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 (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 * Output `From user ...' for mail
X */
X if(!area) {
X fprintf(out, "From %s %s remote from %s\n",
X msg_from,
X date("%a %h %d %T 19%y", (long *) 0),
X internode(packetnode) );
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/%s)\n",
X internode(*entry), PROGRAMNAME, entry->name);
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);
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, '('))
X fprintf(out, "To: %s\n", msgbody_rfc_to);
X else
X fprintf(out, "To: %s (%s)\n", msgbody_rfc_to, realto);
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
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 32138 -eq "$Wc_c" ||
echo 'funpack.c: original size 32138, 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: mju at dfv.rwth-aachen.de
|_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931
More information about the Alt.sources
mailing list