mj@dfv.rwth-aachen.de (Martin Junius) (05/24/91)
---- Cut Here and feed the following to sh ---- #!/bin/sh # This is part 04 of a multipart archive # ============= funcs.c ============== if test -f 'funcs.c' -a X"$1" != X"-c"; then echo 'x - skipping funcs.c (File already exists)' else echo 'x - extracting funcs.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'funcs.c' && /*:ts=4*/ /***************************************************************************** X * FIDOGATE --- Gateway software UNIX <-> FIDO X * X * $Id: funcs.c,v 1.8 91/05/21 08:48:10 mj Exp $ X * X * Miscancelleus functions, logging, sequence numberic etc. X * X * $Log: funcs.c,v $ X * Revision 1.8 91/05/21 08:48:10 mj X * Less verbose log(). X * X * Revision 1.7 90/12/02 21:21:57 mj X * Changed program header to mention both authors of the original X * software posted to alt.sources. X * X * Revision 1.6 90/11/05 20:49:53 mj X * Changed my signature in all program headers. X * X * Revision 1.5 90/11/01 14:33:39 mj X * Added function xtol() X * X * Revision 1.4 90/10/29 21:19:14 mj X * Added functions strnicmp() and stricmp(). X * X * Revision 1.3 90/09/08 18:45:54 mj X * Some changes. X * X * Revision 1.2 90/08/12 14:14:09 mj X * Removed unused code. X * X * Revision 1.1 90/06/28 22:04:15 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.0 90/06/21 19:01:04 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 #include "fidogate.h" X #include <varargs.h> #include <unistd.h> X #include "shuffle.h" X X /* X * We supply our own version of the toupper()/tolower() X * macros, because the exact behaviour of those in X * <ctype.h> varies among systems. X */ X #undef _toupper #undef _tolower #undef toupper #undef tolower X #define _toupper(c) ((c)-'a'+'A') #define _tolower(c) ((c)-'A'+'a') #define toupper(c) (islower(c) ? _toupper(c) : (c)) #define tolower(c) (isupper(c) ? _tolower(c) : (c)) X X X #define labs(n) (((n) < 0l) ? (-(n)) : (n)) X extern void exit(), perror(); extern long atol(); extern time_t time(); X X /***** strnicmp() --- compare n chars of strings ignoring case ***************/ X int strnicmp(sa, sb, len) register char *sa, *sb; int len; { X while(len--) X if(tolower(*sa) == tolower(*sb)) { X sa++; X sb++; X } X else if(tolower(*sa) < tolower(*sb)) X return(-1); X else X return(1); X return(0); } X X X /***** stricmp() --- compare strings ignoring case ***************************/ X int stricmp(sa, sb) register char *sa, *sb; { X while(tolower(*sa) == tolower(*sb)) { X if(!*sa) X return(0); X sa++; X sb++; X } X return(tolower(*sa) - tolower(*sb)); } X X X /***** xtol() --- convert hex string to long *********************************/ X long xtol(s) char *s; { long val = 0; int n; X X while(*s) { X n = toupper(*s) - (isalpha(*s) ? 'A'-10 : '0'); X val = val*16 + n; X s++; X } X return(val); } X X X FILE *logfp = NULL; X /* Lock file descriptor up to the end. If yur system doesn't have lockf() X (also known as locking()), or other region or file locking function X or system call, this should be done with lock-files. */ X int lock(fd) X int fd; { #ifdef LOCK_LOCKF X return lockf(fd, F_LOCK, 0l); #else X return locking(fd, F_LOCK, 0l); #endif } X /* Unlock file descriptor up to the end. Routine which calls this should X first seek to original position. */ X int unlock(fd) X int fd; { #ifdef LOCK_LOCKF X return lockf(fd, F_ULOCK, 0l); #else X return locking(fd, F_ULOCK, 0l); #endif } X /* Return ascii-date in specified format. If format string is null, return X date as date(1) returns it. Format is same than date(1) has, in addition X %z, which means timezone name. Clock is the time to convert, if NULL, X we'll use current time. */ X char * date(fmt, clock) X char *fmt; X time_t *clock; { X /* names for weekdays */ X static char *weekdays[] = { X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", X }; X X /* names for months */ X static char *months[] = { X "Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", X }; X X static char buffer[80]; X char *bp = buffer; X time_t _clock; X struct tm *tm; X X if (!clock) X _clock = time((long *) 0); X tm = localtime(clock ? clock : &_clock); X X /* if no format string, this is default */ X if (!fmt) X fmt = "%a %h %d %T %z 19%y"; X X for (*bp = 0; *fmt; fmt++) X switch (*fmt) X { X case '%': X switch (*++fmt) X { X /* newline */ X case 'n': X *bp++ = '\n'; X break; X /* tabulator */ X case 't': X *bp++ = '\t'; X break; X /* month number 1-12 */ X case 'm': X (void) sprintf(bp, "%02d", tm->tm_mon + 1); X while (*bp) X bp++; X break; X /* day of month 1-31 */ X case 'd': X (void) sprintf(bp, "%2d", tm->tm_mday); X while (*bp) X bp++; X break; X case 'q': X (void) sprintf(bp, "%02d", tm->tm_mday); X while (*bp) X bp++; X break; X /* year 00-99 */ X case 'y': X (void) sprintf(bp, "%02d", tm->tm_year); X while (*bp) X bp++; X break; X /* date in format YY/MM/DD */ X case 'D': X (void) sprintf(bp, "%02d/%02d/%02d", tm->tm_year, X tm->tm_mon + 1, tm->tm_mday); X while (*bp) X bp++; X break; X /* hour 0-23 */ X case 'H': X (void) sprintf(bp, "%02d", tm->tm_hour); X while (*bp) X bp++; X break; X /* minutes 0-59 */ X case 'M': X (void) sprintf(bp, "%02d", tm->tm_min); X while (*bp) X bp++; X break; X /* seconds 0-59 */ X case 'S': X (void) sprintf(bp, "%02d", tm->tm_sec); X while (*bp) X bp++; X break; X /* time in format HH:MM:SS */ X case 'T': X (void) sprintf(bp, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, X tm->tm_sec); X while (*bp) X bp++; X break; X /* day of year 1-356 */ X case 'j': X (void) sprintf(bp, "%03d", tm->tm_yday + 1); X while (*bp) X bp++; X break; X /* weekday 0-6 */ X case 'w': X (void) sprintf(bp, "%d", tm->tm_wday); X while (*bp) X bp++; X break; X /* name of weekday 'Mon', 'Tue', ... , 'Sun' */ X case 'a': X (void) strcpy(bp, weekdays[tm->tm_wday]); X while (*bp) X bp++; X break; X /* name of month 'Jan', 'Feb', ... , 'Dec' */ X case 'h': X (void) strcpy(bp, months[tm->tm_mon]); X while (*bp) X bp++; X break; X /* name of timezone, e.g. EST */ X case 'z': X (void) strcpy(bp, *tzname); X while (*bp) X bp++; X break; X /* numeric time zone, e.g. +0200 */ X case 'o': X (void) sprintf(bp, "%c%02ld%02ld", (timezone <= 0l) ? '+' : '-', X (labs(timezone) / (60l * 60l)), X (labs(timezone) % (60l * 60l))); X while (*bp) X bp++; X break; X case 'l': X /* military time zone, Z = UT, A = -1, M = -12, (J not used), X N = +1, Y = +12.. */ X *bp = (timezone == 0l) ? 'Z' : ((int) (labs(timezone) / X (60l * 60l)) + X ((timezone < 0l) ? 'M' : '@')); X if (timezone > 0l && *bp >= 'J') X (*bp)++; X *++bp = 0; X break; X default: X *bp++ = *fmt; X break; X } X break; X default: X *bp++ = *fmt; X break; X } X X *bp = 0; X return buffer; } X X X /* X * strerror() --- get string from sys_errlist[] X */ X char * strerror(errnum) int errnum; { extern int sys_nerr; extern char *sys_errlist[]; X X if (errnum > 0 && errnum < sys_nerr) X return sys_errlist[errnum]; X return ""; } X X X /* X * Log to logfile. If logfile is not open, open it. X * X * If first character in format string is '$', print also errno. If external X * variable verbose is set, logging will be done also to stderr. X */ X /**VARARGS**/ void log(va_alist) va_dcl { va_list args; char *fmt; X X va_start(args); X X fmt = va_arg(args, char *); X X if(!logfp) X if ((logfp = fopen(LOGFILE, "a")) == NULL) { X perror("Cannot open log file"); X return; X } X X (void) fprintf(logfp, "%s: ", date("%d %h %y %H:%M", (long *) 0)); X (void) vfprintf(logfp, *fmt == '$' ? fmt + 1 : fmt, args); X if (*fmt == '$') X (void) fprintf(logfp, "\n\t\terrno = %d (%s)\n", errno, strerror(errno)); X else X (void) fprintf(logfp, "\n"); X (void) fflush(logfp); X X /* X * if verbose is set, print also to stderr (without date) X */ X if (verbose) { X (void) vfprintf(stderr, *fmt == '$' ? fmt + 1 : fmt, args); X if (*fmt == '$') X (void) fprintf(stderr, "\n\t\terrno = %d (%s)\n", errno, strerror(errno)); X else X (void) fprintf(stderr, "\n"); X (void) fflush(stderr); X } X X va_end(args); } X X X /* X * Debug output. First argument should be number, rest are used arguments X * for vfprintf(3S). If external variable verbose has equal or greater X * value than first number, vfprintf(3S) will be used to print other X * arguments to stderr. X */ X /**VARARGS**/ void debug(va_alist) va_dcl { va_list args; char *fmt; int debug_level; X X va_start(args); X X debug_level = va_arg(args, int); X fmt = va_arg(args, char *); X X if (debug_level <= verbose) { X if (*fmt != '>' && *fmt != '<') X (void) vfprintf(stderr, fmt, args); X (void) fprintf(stderr, "\n"); X } X X va_end(args); } X X X /* Get next job number. New sequemnt number will be taken from file X LIBDIR/seq, which is in ascii-format and new number will be saved X back there. */ X long job_number() { X return sequencer(JOBSEQ); } X /* General sequencer */ X long sequencer(filename) X char *filename; { X char seqfile[128], buffer[14]; X FILE *fp; X long seqn = 0; X X (void) sprintf(seqfile, "%s", filename); X if ((fp = fopen(seqfile, "r+")) == NULL) X { X if (errno == ENOENT) X { X if ((fp = fopen(seqfile, "w+")) == NULL) X { X log("$Can not create seq-file %s", seqfile); X exit(EX_OSFILE); X } X fputs("1", fp); X fclose(fp); X if ((fp = fopen(seqfile, "r+")) == NULL) X { X log("$Can not open new seq-file %s", seqfile); X exit(EX_OSFILE); X } X } X else X { X log("$Can not open seq-file %s", seqfile); X exit(EX_OSFILE); X } X } X X (void) lock(fileno(fp)); X if (fgets(buffer, 14, fp)) X seqn = atol(buffer); X else X seqn = 0; /* This can theoretically fail */ X X seqn++; X (void) rewind(fp); X (void) fprintf(fp, "%ld\n", seqn); X (void) unlock(fileno(fp)); X (void) fclose(fp); X return seqn; } X /* Returns current last sequence number */ long getsequencer(filename) X char *filename; { X char seqfile[128], buffer[14]; X FILE *fp; X long seqn = 0; X X (void) sprintf(seqfile, "%s", filename); X if ((fp = fopen(seqfile, "r+")) == NULL) X { X if (errno == ENOENT) X { X if ((fp = fopen(seqfile, "w+")) == NULL) X { X log("$Can not create seq-file %s", seqfile); X exit(EX_OSFILE); X } X fputs("1", fp); X fclose(fp); X if ((fp = fopen(seqfile, "r+")) == NULL) X { X log("$Can not open new seq-file %s", seqfile); X exit(EX_OSFILE); X } X } X else X { X log("$Can not open seq-file %s", seqfile); X exit(EX_OSFILE); X } X } X X (void) lock(fileno(fp)); X if (fgets(buffer, 14, fp)) X seqn = atol(buffer); X else X seqn = 0; /* This can theoretically fail */ X X (void) unlock(fileno(fp)); X (void) fclose(fp); X return seqn; } X /* Get full pathname for spoolfile with new job number. File is in X spool directory and contains prefix followed by four digit X job number. */ X char * spoolfile(prefix) X char *prefix; { X static char file[BUFLEN]; X X (void) sprintf(file, "%s/%s%08ld", SPOOL, prefix, job_number()); X return file; } X /* Return basename of s */ X char * basename(s) X register char *s; { X register char *p = s; X X while (*s) X if (*s++ == '/') X p = s; X return p; } X /* Open file with directory name and filename. */ X FILE * pfopen(dir, name, mode) X char *dir, *name, *mode; { X char filename[128]; X X (void) strcpy(filename, dir); X (void) strcat(filename, "/"); X (void) strcat(filename, name); X X return fopen(filename, mode); } X char *baseit(n) X long n; { X static char tab[] = X "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; X int count = 0; X X SHUFFLEBUFFERS; X X while (n) X { X tcharp[count] = tab[n % strlen(tab)]; X n = n / strlen(tab); X count++; X } X X tcharp[count] = 0; X return tcharp; } X /* Create packet name for node given */ X sprintpacketname(s, node) X char *s; X Node node; { X sprintf(s, "%s%s.%s.%s", node.point ? X sprintfs("%s.", baseit( (long) node.point)) : "", X baseit( (long) node.node), baseit( (long) node.net), X baseit( (long) node.zone)); } X /* Create packet name for inbound xx.xx.xx.xx.num. If point X number is 0, don't include it. All numbers are in ~63-base to squeeze X them to as small space as possible. It could be more sensible solution X to make them directory trees but I would need more time for that. This X trick makes finding packets difficult. X */ X sprintipacketname(s, node) X char *s; X Node node; { X sprintf(s, "%s%s.%s.%s.%s", node.point ? X sprintfs("%s.", baseit( (long) node.point)) : "", X baseit( (long) node.node), baseit( (long) node.net), X baseit( (long) node.zone), baseit(sequencer(IPACKETSEQUENCE))); } X X X /* X * Get line from config file. If *-character is in first column, report X * EOF, and otherwise return line with comments stripped. This causes X * effect, that each section in configuration file looks like it's own X * file. Arguments and return value are the same than with fgets(3S). X */ X char * getcl(buffer, len, fp) char *buffer; int len; FILE *fp; { char *cp; X X while (fgets(buffer, len, fp)) { X buffer[strlen(buffer) - 1] = 0; X if (*buffer == '*') X return (char *) NULL; X /* everything after #-sign is comment */ X if (cp = strchr(buffer, '#')) X *cp = 0; X /* if there's something left, return it */ X if (*buffer) X return buffer; X } X return (char *) NULL; } X X X /* Scan config file to specified section. This mechanism is not very X effective, but otherwise it would get too complicated. */ X void section(number, config) X int number; X FILE *config; { X char buffer[BUFLEN]; X X (void) rewind(config); X while (--number) X while (getcl(buffer, BUFLEN, config)) X /* skip section */; } X /* Get header field from file. */ X #define MAX_HEADER_LEN 256 X char *mheader(fp, headername) X FILE *fp; X char *headername; { X static char header[MAX_HEADER_LEN]; X long position; X X position = ftell(fp); X X rewind(fp); X X /* Blank line terminates also, there shouldn't be any headers X after it any more */ X X while (fgets(header, MAX_HEADER_LEN, fp) && *header != '\n') X if (!strncmp(header, headername, strlen(headername))) X { X /* Remove \n at end */ X header[strlen(header) - 1] = 0; X fseek(fp, position, 0); X return header + strlen(headername); X } X X /* Not found, return empty string */ X X fseek(fp, position, 0); X return ""; } SHAR_EOF chmod 0644 funcs.c || echo 'restore of funcs.c failed' Wc_c="`wc -c < 'funcs.c'`" test 15896 -eq "$Wc_c" || echo 'funcs.c: original size 15896, current size' "$Wc_c" fi # ============= rmail.c ============== if test -f 'rmail.c' -a X"$1" != X"-c"; then echo 'x - skipping rmail.c (File already exists)' else echo 'x - extracting rmail.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'rmail.c' && /*:ts=4*/ /***************************************************************************** X * FIDOGATE --- Gateway software UNIX <-> FIDO X * X * $Id: rmail.c,v 1.12 91/05/07 23:59:33 mj Exp $ X * X * Replacement for rmail. X * This program performs two functions: X * - it checks for mail addressed to the FIDO domain (.fidonet.org) X * and passes these messages to rfmail X * - It does some rudimentary transforming for domain style addresses X * X * This is just a small hack. For real mail processing use X * sendmail or smail, which are much better at those things. X * X * $Log: rmail.c,v $ X * Revision 1.12 91/05/07 23:59:33 mj X * Uses new function isfido() to determine wheter address is for FIDO or X * not. Also supports rerouting of UUCP bang addresses to UUCP feed. X * X * Revision 1.11 91/04/28 21:40:55 mj X * Reroute mail to .uucp also via UUCPFEED. X * X * Revision 1.10 91/03/29 18:13:50 mj X * Improved routing for new Reply-To: adresses. X * X * Revision 1.9 91/01/05 13:08:58 mj X * Recognize MY_HOSTNAME.MY_DOMAIN as local address. X * X * Revision 1.8 90/12/09 17:35:50 mj X * Readdress mail to UUCPFEED. Removed unnessary `GATEWAY' code. X * X * Revision 1.7 90/12/02 21:22:32 mj X * Changed program header to mention both authors of the original X * software posted to alt.sources. X * X * Revision 1.6 90/11/05 20:51:06 mj X * Changed my signature in all program headers. X * X * Revision 1.5 90/07/11 17:57:50 mj X * Removed an obscure bug while feeding letter to mail receiving X * process. Once in a while the result was garbage. The cause was X * that the temporary file was opened by both the parent and the X * child process. Even if the child never ever does something to X * this file, this seems to confuse the operating system. X * X * Revision 1.4 90/07/07 17:54:47 mj X * Improved version. Now rmail is able to get destination address X * from message header, `To: ...' line. This has been implemented X * to make rmail work with nn, 'cause this news reader doesn't pass X * the address as a command line argument to rmail. X * X * Revision 1.3 90/07/01 15:20:37 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.2 90/07/01 13:46:12 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.1 90/06/28 22:04:56 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.0 90/06/19 18:34:10 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 #include "fidogate.h" X X X #define PROGRAMNAME "rmail $Revision: 1.12 $" X X X /* X * This is special to XENIX: X * On XENIX, one can't use rmail for sending mail, 'cause this X * program doesn't generate a correct `From user ...' line for X * locally created mail. One has to execute /usr/lib/mail/execmail X * instead. But execmail *always* generates it's own `From ...' X * line, even if there is already one in the mail. So for mail X * of remote origin, e.g. those messages created by funpack, one X * must instruct execmail to handle this right. This can be done X * with the `-f' flags of execmail, whose argument replaces user X * in `From user ...' line. X */ #ifdef M_XENIX # define EXECMAIL /* Use -f from, if neccessary */ # undef RECVMAIL # define RECVMAIL "/usr/lib/mail/execmail" /* Force use of execmail */ #endif X X X /* verbosity */ /* int verbose = 3; /**/ int verbose = INIT_VERBOSE; /**/ X X X /* X * For domain type addresses (name@system): X * X * Local adress converting: X * user@localhost.localdomain -> user X * [.uucp domain to bang converting: ] X * [ user@system.uucp -> system!user ] disabled X * [ user@system -> system!user ] X * Forward other messages to UUCP feed X * user@system.domain -> uucpfeed!domain!user X * UUCP rerouting via UUCP feed X * system!user -> uucpfeed!system!user X */ X char *process_address(addr) char *addr; { static char hostname[256]; static char address[256]; static char newaddress[256]; char *p; int len; int not_uucp = FALSE; X X gethostname(hostname, 20); X strcpy(address, addr); X debug(3, "Address to process: %s", addr); X X if(p = strchr(address, '@')) { X /* X * Domain address: name@system.domain X * X * Isolate user name, p points to system.domain X */ X *p++ = 0; X /* X * Remove suffix ".uucp" X */ X len = strlen(p); #if 0 X if(len>5 && (!strcmp(p+len-5, ".uucp") || !strcmp(p+len-5, ".UUCP"))) X p[len - 5] = 0; X else if(strchr(p, '.')) #endif X not_uucp = TRUE; X /* X * If addressed to our hostname or full domain name, X * just send to user name X */ X if(!strcmp(p, hostname)) X *p = 0; X else { X strcat(hostname, MY_DOMAIN); X if(!strcmp(p, hostname)) X *p = 0; X } X /* X * Construct converted address X */ X if(!*p) /* Local address */ X strcpy(newaddress, address); X else if(not_uucp) /* Address domain via UUCPFEED */ X sprintf(newaddress, "%s!%s!%s", UUCPFEED, p, address); X else /* UUCP address */ X sprintf(newaddress, "%s!%s", p, address); X debug(2, "Renamed %s to %s", addr, newaddress); X return strsave(newaddress); X } X else if(strchr(address, '!')) { X /* X * Bang address: system!user X */ X sprintf(newaddress, "%s!%s", UUCPFEED, address); X return strsave(newaddress); X } X else X return strsave(address); } X X X /* X * Get name from `From user ...' line. X * Understood format of From line is: X * `From USER day mon dd hh:mm:ss [zone] yyyy [remote from SYSTEM]' X * Destroys contents of buf! X */ X char *get_from_name(buf) char *buf; { char *name, *system; static char from[64]; X X name = "anonymous"; /* Defaults */ X system = ""; X X buf += 5; /* Skip `From ' */ X if(*buf) { X name = buf; X while(*buf && *buf!=' ' && *buf!='\t') X buf++; X if(*buf) { X *buf++ = 0; X /* Scan for `remote from ' */ X while(strlen(buf) >= 12) /* 12 = strlen("remote from") */ X if(!strncmp(buf, "remote from ", 12)) { /* gefunden! */ X buf += 12; X system = buf; X while(*buf && *buf!=' ' && *buf!='\t' && *buf!='\n') X buf++; X *buf = 0; X break; X } X else X buf++; X } X } X X if(*system) { X strcpy(from, system); X strcat(from, "!"); X } X else X *from = 0; X strcat(from, name); X X return(from); } X X X /* X * get_to_name() --- Get destination address from `To: ...' line X */ X char *get_to_name(buffer) char *buffer; { register char *cp, *np; register int cnt; static char to[64]; X X buffer += strlen("To: "); X *to = 0; X X /* X * Parse the name from `To: ...' line. There are basically X * two formats: X * `User Name <address>' or X * `address (User Name)' X * We'll try to figure it out which format sender uses. X */ X if ((cp = strchr(buffer, '<')) && (np = strchr(cp, '>'))) { X /* X * Format is 'From: Name <address>' X */ X for(np=cp+1, cnt=0; *np && *np!='>'; np++, cnt++) X to[cnt] = *np; X to[cnt] = 0; X } X else if ((cp = strchr(buffer, '(')) && (np = strchr(cp, ')'))) { X /* X * Format is 'From: address (Name)' X */ X for(np=buffer, cnt=0; *np && *np!='(' && !isspace(*np); np++, cnt++) X to[cnt] = *np; X to[cnt] = 0; X } X else { X /* X * Not a recognized format, just copy X */ X strncpy(to, buffer, 64); X to[63] = 0; X cnt = strlen(to); X if(to[cnt - 1] == '\n') X to[cnt - 1] = 0; X } X X return( *to ? to : NULL); } X X X /* X * Open stream associated with programs standard input. Program is invoked X * with given argument list. Popen(3S) would invoke mailer thru sh(1), X * so this uses less memory and is faster. X */ X FILE * open_mailer(program, args, pid) char *program, **args; int *pid; { FILE *fp; int fd[2]; X X /* create pipe */ X if (pipe(fd) == -1) { X perror("rmail: pipe"); X exit(EX_OSERR); X } X X switch (*pid = fork()) { X case -1: /* Error */ X perror("rmail: fork failed"); X exit(EX_OSERR); X case 0: /* Child */ X (void) close(0); X if (dup(fd[0]) == 0) { X (void) close(fd[0]); X (void) close(fd[1]); X (void) execvp(program, args); X perror(program); X } X else X perror("rmail: dup"); X exit(EX_OSERR); X default: /* Parent */ X (void) close(fd[0]); X if ((fp = fdopen(fd[1], "w")) == NULL) { X perror("rmail: fdopen"); X exit(EX_OSERR); X } X } X return fp; } X X X int main(argc, argv) int argc; char *argv[]; { int cnt; char **rargs, **fargs; int rrec = 0, frec = 0, rargc = 1, fargc = 1; int status = EX_OK; FILE *mailer; static char buffer[BUFSIZ]; int stat_loc, pid; char *from; char *to; static char tempname[64]; FILE *temp; int in_header_flag; char *addr; X X /* X * Allocate memory for argument lists of RECVMAIL and RFMAIL. X * 2 extra pointers are needed, 'cause we eventually insert X * `-f user' for XENIX execmail. 1 more extra pointer for X * address from `To: ...' line. X */ X rargs = (char **)xmalloc( (argc + 4) * sizeof(char *) ); X fargs = (char **)xmalloc( (argc + 4) * sizeof(char *) ); X X rargs[0] = RECVMAIL; X fargs[0] = RFMAIL; X X /* X * Scan thru receiver list and put all receivers in fidonet in fido- X * mailer's receiver-list and all others in real rmails one. No X * options can be passed to fidomailer thru this, because it would X * be too difficult to determine which one goes to which one and X * there might be same options also. Somehow it's good that fidomailer X * is well hidden under this... X */ X for (cnt = 1; cnt < argc; cnt++) X if (*argv[cnt] == '-') X rargs[rargc++] = strsave(argv[cnt]); X else { X if(isfido(argv[cnt])) { X /* X * Mail for FIDO. X */ X debug(2, "Argument %d (receiver %d) in fidomailer: %s", X fargc, frec + 1, argv[cnt]); X fargs[fargc++] = strsave(argv[cnt]); X frec++; X } X else { X /* X * Not a valid FIDO address, so this must be for UUCP. X * In this case process address further to convert X * internet domain address name@system.domain to X * UUCP bang address system!name. X * Beware: result of process_address() may be a FIDO X * address again, so another check is necessary. X */ X addr = process_address(argv[cnt]); X if(isfido(addr)) { X debug(2, "Argument %d (receiver %d) in fidomailer: %s", X fargc, frec + 1, addr); X fargs[fargc++] = addr; X frec++; X } X else { X debug(2, "Argument %d (receiver %d) in rmail: %s", X rargc, rrec + 1, addr); X rargs[rargc++] = addr; X rrec++; X } X } X } X X /* X * Open temporary file and copy mail from stdin to there X */ X tmpnam(tempname); X temp = fopen(tempname, "w"); X if(!temp) { X log("$Can't create temporary file %s", tempname); X exit(1); X } X *buffer = 0; X from = to = NULL; X in_header_flag = TRUE; #ifdef EXECMAIL X /* X * Look form `From user ...' line X */ X *buffer = 0; X fgets(buffer, BUFSIZ, stdin); X if(!strncmp(buffer, "From ", 5)) { X from = get_from_name(buffer); X debug(3, "from = %s", from); X *buffer = 0; X } X else { X from = NULL; X goto test_header; X } #endif X while(fgets(buffer, BUFSIZ, stdin)) { test_header: X if(in_header_flag) { X if(*buffer == '\n') X in_header_flag = FALSE; X else if(!strncmp(buffer, "To: ", 4)) { X to = get_to_name(buffer); X debug(3, "to = %s", to); X } X } X fputs(buffer, temp); X } X fclose(temp); X X /* X * If no address on command line, then use the one from X * get_to_name() X */ X if(!frec && !rrec && to) { X if(isfido(to)) { X debug(2, "Argument %d (receiver %d) in fidomailer: %s", X fargc, frec + 1, to); X fargs[fargc++] = strsave(to); X frec++; X } X else { X addr = process_address(to); X if(isfido(addr)) { X debug(2, "Argument %d (receiver %d) in fidomailer: %s", X fargc, frec + 1, addr); X fargs[fargc++] = addr; X frec++; X } X else { X debug(2, "Argument %d (receiver %d) in rmail: %s", X rargc, rrec + 1, addr); X rargs[rargc++] = addr; X rrec++; X } X } X } X X /* X * NULL terminate arument lists X */ X rargs[rargc] = NULL; X fargs[fargc] = NULL; X X X if (rrec) { X /* X * Mail to UUCP, use rmail (or XENIX special: execmail) X */ X debug(1, "Mail to UUCP, executing %s", RECVMAIL); #ifdef EXECMAIL X /* X * Insert `-f FROM' into argument list of execmail (rargs[]) X */ X if(from) { X for(cnt=rargc; cnt>=1; cnt--) X rargs[cnt + 2] = rargs[cnt]; X rargs[1] = "-f"; X rargs[2] = from; X rargc += 2; X } #endif /**EXECMAIL**/ X /* X * Open mailer and feed letter to it X */ X mailer = open_mailer(RECVMAIL, rargs, &pid); X temp = fopen(tempname, "r"); X if(!temp) { X log("$Can't open %s again", tempname); X unlink(tempname); X exit(1); X } X while (fgets(buffer, BUFSIZ, temp)) X fputs(buffer, mailer); X fclose(mailer); X /* X * Wait for rmail to exit X */ X wait(&stat_loc); X if(!status) X status = (stat_loc & 0xff) == 0 ? (stat_loc >> 8) & 0xff : 1; X } X X if (frec) { X /* X * Mail to FIDO, use rfmail X */ X debug(1, "Mail to FIDO, executing %s", RFMAIL); X /* X * Open mailer and feed letter to it X */ X mailer = open_mailer(RFMAIL, fargs, &pid); X temp = fopen(tempname, "r"); X if(!temp) { X log("$Can't open %s again", tempname); X unlink(tempname); X exit(1); X } X while (fgets(buffer, BUFSIZ, temp)) X fputs(buffer, mailer); X fclose(mailer); X /* X * Wait for rfmail to exit X */ X wait(&stat_loc); X if(!status) X status = (stat_loc & 0xff) == 0 ? (stat_loc >> 8) & 0xff : 1; X } X X /* X * Remove temporary file X */ X unlink(tempname); X X exit(status); } SHAR_EOF chmod 0644 rmail.c || echo 'restore of rmail.c failed' Wc_c="`wc -c < 'rmail.c'`" test 14095 -eq "$Wc_c" || echo 'rmail.c: original size 14095, current size' "$Wc_c" fi # ============= fpack.c ============== if test -f 'fpack.c' -a X"$1" != X"-c"; then echo 'x - skipping fpack.c (File already exists)' else echo 'x - extracting fpack.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'fpack.c' && /*:ts=4*/ /***************************************************************************** X * FIDOGATE --- Gateway software UNIX <-> FIDO X * X * $Id: fpack.c,v 2.4 91/05/21 08:47:41 mj Exp $ X * X * Create and update fidomail packets. Read mail messages from X * spool directory and append them to packet. If packet doesn't X * exist already, it will be created. X * X * $Log: fpack.c,v $ X * Revision 2.4 91/05/21 08:47:41 mj X * Moved log entry for NetMail to rfmail. X * X * Revision 2.3 91/03/29 18:10:14 mj X * No log entries for news. X * X * Revision 2.2 90/12/09 18:35:27 mj X * Rewrote some more code. Now support `X' header line and crash mail. X * X * Revision 2.1 90/12/02 21:21:53 mj X * Changed program header to mention both authors of the original X * software posted to alt.sources. X * X * Revision 2.0 90/11/23 21:49:24 mj X * Major rewrite of fpack started: no more ugly messing around with X * byte order, use machine independent function write_int() instead. X * Removed some functions and macros. X * X * Revision 1.3 90/11/05 20:49:38 mj X * Changed my signature in all program headers. X * X * Revision 1.2 90/07/29 18:10:52 mj X * Place real net/node in message header for FIDO netmail. Also X * a `^AFMPT x' kludge is generated in this case. Recipient of X * our mail now gets real address from message, which should X * make replying much easier. X * X * Revision 1.1 90/06/28 22:04:07 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.0 90/06/19 18:32:01 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 #include "fidogate.h" /* #include <fcntl.h> #include <sys/stat.h> */ X X #define PROGRAMNAME "fpack $Revision: 2.4 $" X X X extern time_t time(); extern int getopt(); extern int optind; extern char *optarg; extern unsigned sleep(); extern void exit(); extern void swab(); X Node node; int verbose = INIT_VERBOSE; X X X /* X * Put string to file in null-terminated format. X */ X int put_string(fp, s) FILE *fp; char *s; { X while (*s) { X putc(*s, fp); X s++; X } X putc(0, fp); } X X X /* X * Write 16-bit integer in 80x86 format, i.e. low byte first, X * then high byte. Machine independent function. X */ X int write_int(value, fp) int value; FILE *fp; { X putc(value & 0xff, fp); X putc((value >> 8) & 0xff, fp); } X X /* X * Copy n-char String, force trailing `\0' X */ X char *strncpy0(d, s, n) char *d, *s; int n; { char *p; X X p = strncpy(d, s, n); X d[n - 1] = 0; X return(p); } X X X /* X * Write FIDO message header to mail packet. Information is taken X * from input message header: X * X * N node Address to send to X * T name Name of recipient X * F name Name of sender X * S subject Subject of message X * D date Date of message (FTS-0001 format) X * X flags Message flags: P=private, C=crash X */ X int write_hdr(source, packet) FILE *source, *packet; { int private_flag = FALSE; char buffer[BUFSIZ]; char from[SIZE_FROM], X to[SIZE_TO], X subject[SIZE_SUBJECT], X date[SIZE_DATE]; Node msg_node; int attr = 0; char *p; X X msg_node.zone = msg_node.net = msg_node.node = msg_node.point = -1; X X /* clean up from, to and subject */ X *from = 0; X *to = 0; X *subject = 0; X *date = 0; X X while (fgets(buffer, BUFSIZ, source) && *buffer != '\n') { X buffer[strlen(buffer) - 1] = 0; /* strip newline */ X switch(*buffer) { X case 'N': X if (parsefnetaddress(buffer, &msg_node)) { X log("Invalid destination: %s", buffer); X return FALSE; X } X break; X case 'F': X strncpy0(from, buffer + 2, SIZE_FROM); X break; X case 'T': X strncpy0(to, buffer + 2, SIZE_TO); X break; X case 'S': X strncpy0(subject, buffer + 2, SIZE_SUBJECT); X break; X case 'D': X strncpy0(date, buffer + 2, SIZE_DATE); X break; X case 'P': /* Old `private' header */ X attr |= ATTR_PRIVATE; X private_flag = TRUE; X break; X case 'X': /* New flags header */ X for(p=buffer+2; *p; p++) X switch(*p) { X case 'P': X attr |= ATTR_PRIVATE; X private_flag = TRUE; X break; X case 'C': X attr |= ATTR_CRASH; X break; X } X break; X } X } X X /* Save all header values */ X write_int(MSGTYPE, packet); /* save msg type */ X write_int(private_flag ? REAL_NODE : MY_NODE, packet);/* save our node */ X write_int(msg_node.node, packet); /* save messages node */ X write_int(private_flag ? REAL_NET : MY_NET, packet);/* save our net */ X write_int(msg_node.net, packet); /* save messages net */ X write_int(attr, packet); /* save attributes */ X write_int(0, packet); /* cost, not used by us */ X put_string(packet, date); /* save time of mail */ X put_string(packet, to); /* save receiver */ X put_string(packet, from); /* save sender */ X put_string(packet, subject); /* save subject */ X X /* done with this header */ X return TRUE; } X X X /* X * Write packet header for new packet. X */ X int write_pkthdr(packet) FILE *packet; { Packet header; int count; struct tm *tm; time_t clock = time((long *) 0); X X tm = localtime(&clock); X X /* create packet structure */ X header.orig_node = MY_NODE; X header.dest_node = node.node; X header.orig_net = MY_NET; X header.dest_net = node.net; X X /* save time for header (why all these fields?) */ X header.year = tm->tm_year + 1900; X header.month = tm->tm_mon; X header.day = tm->tm_mday; X header.hour = tm->tm_hour + 1; X header.minute = tm->tm_min; X header.second = tm->tm_sec; X X header.rate = MAXBAUD; X header.ver = HDRVER; X header.product = 0; X header.x1 = 0; #ifdef FIDO_V11w X for(count = 0; count < 16; count++) X header.fill[count] = 0; #else X for(count = 0; count < 8; count++) X header.pwd_kludge[count] = 0; X header.orig_zone = MY_ZONE; X header.dest_zone = node.zone; X for (count = 0; count < 16; count++) X header.B_fill2[count] = 0; X header.B_fill3 = 0; #endif X /* write header to file */ X write_int(header.orig_node, packet); X write_int(header.dest_node, packet); X write_int(header.year , packet); X write_int(header.month , packet); X write_int(header.day , packet); X write_int(header.hour , packet); X write_int(header.minute , packet); X write_int(header.second , packet); X write_int(header.rate , packet); X write_int(header.ver , packet); X write_int(header.orig_net , packet); X write_int(header.dest_net , packet); X putc( header.product , packet); X putc( header.x1 , packet); X for(count = 0; count < 8; count++) X putc(header.pwd_kludge[count], packet); X write_int(header.orig_zone, packet); X write_int(header.dest_zone, packet); X for(count = 0; count < 16; count++) X putc(header.B_fill2[count], packet); X for(count = 0; count < 4; count++) X putc(header.B_fill3 << (8 * count), packet); /* pc long = 4 bytes! */ X X if(ferror(packet) || feof(packet)) { X log("$Write error on packet header"); X return FALSE; X } X X debug(1, "New packet created"); X X return TRUE; } X X X int main(argc, argv) int argc; char *argv[]; { DIR *dp; struct dirent *dir; FILE *msg, *packet; char packet_name[16]; int c; Node np; char *error; X X node.net = node.zone = -1; X X /* get options */ X while ((c = getopt(argc, argv, "vf:")) != EOF) X switch (c) { X case 'f': X if (parsefnetaddress(optarg, &np)) exit(1); X node = np; X break; X case 'v': X verbose++; X break; X default: X fprintf(stderr, "%s\n\n", PROGRAMNAME); X fprintf(stderr, "Usage: fpack [-v] [-f Z:N/N.P]\n\n"); X exit(EX_USAGE); X } X X /* make sure that we got net/node */ X if (node.net == -1 || node.node == -1) { X node.zone = REM_ZONE; X node.net = REM_NET; X node.node = REM_NODE; X node.point = REM_POINT; X strcpy(node.name, REM_NAME); X } X #if 0 X /* try to update nodelist-index */ X if (error = update_index()) X { 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 X /* goto spool directory, everything exiting happens there... */ X if (chdir(SPOOL) == -1) { X log("$Can't chdir to %s", SPOOL); X exit(1); X } X #if 0 X /* create packet name */ X sprintpacketname(packet_name, node); #else X /* MSDOS compatible packet names */ X sprintf(packet_name, "%04x%04x.out", node.net, node.node); #endif X X if (access(sprintfs("out/%s", packet_name), 0) == 0) { X debug(1, "Packet out/%s exists, append to it", packet_name); X if ((packet = fopen(sprintfs("out/%s", packet_name), "r+")) == NULL) { X log("$Can't open out/%s for update", packet_name); X exit(1); X } X fseek(packet, -2L, 2); X } X else { X debug(1, "New packet out/%s", packet_name); X if ((packet = fopen(sprintfs("out/%s", packet_name), "w")) == NULL) { X log("$Can't open out/%s for writing", packet_name); X exit(1); X } X /* protect packet from users...*/ X chmod(sprintfs("out/%s", packet_name), 0600); X /* write packet-header, if it fails, exit */ X if (!write_pkthdr(packet)) { X unlink(sprintfs("out/%s", packet_name)); X exit(1); X } X } X X /* lock packet, wait if it's alredy locked */ X while (lock(fileno(packet)) == -1 && errno == EAGAIN) X sleep(5); X X /* open spool directory */ X dp = opendir("."); X if(!dp) { X log("$Can't open spool directory %s", SPOOL); X exit(1); X } X while (dir = readdir(dp)) { X /* check that file is for us */ X if(dir->d_name[0]=='M' && dir->d_name[1]=='.') { X msg = fopen(dir->d_name, "r"); X if(!msg) { X log("$Can't open mail %s for reading", dir->d_name); X continue; X } X debug(1, "Adding mailfile %s", dir->d_name); X X /* save header */ X if(write_hdr(msg, packet)) { X /* copy mail text, replace newlines with <cr> <lf> */ X while ((c = getc(msg)) && c != EOF) { X if (c == '\n') X putc('\r', packet); X putc(c, packet); X } X /* null-terminate msg text */ X putc(0, packet); X } X fclose(msg); X if(unlink(dir->d_name) == -1) X log("$Unable to unlink %s", dir->d_name); X } X } X closedir(dp); X X /* msg type 0 indicates end of packet */ X write_int(0, packet); X X fclose(packet); X X exit(0); } SHAR_EOF chmod 0644 fpack.c || echo 'restore of fpack.c failed' Wc_c="`wc -c < 'fpack.c'`" test 10575 -eq "$Wc_c" || echo 'fpack.c: original size 10575, current size' "$Wc_c" fi true || echo 'restore of funpack.c failed' echo End of part 4, continue with part 5 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