mj@dfv.rwth-aachen.de (Martin Junius) (01/28/91)
---- 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@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 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@dfv.rwth-aachen.de |_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931