FIDOGATE Part 4/6
Martin Junius
mj at dfv.rwth-aachen.de
Mon Jan 28 20:35:13 AEST 1991
---- 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.7 90/12/02 21:21:57 mj Exp $
X *
X * Miscancelleus functions, logging, sequence numberic etc.
X *
X * $Log: funcs.c,v $
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 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
#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 %T", (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 15826 -eq "$Wc_c" ||
echo 'funcs.c: original size 15826, 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.9 91/01/05 13:08:58 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.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 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
#include "fidogate.h"
X
X
X
#define PROGRAMNAME "rmail $Revision: 1.9 $"
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 at system):
X *
X * Local adress converting:
X * user at localhost.localdomain -> user
X * .uucp domain to bang converting:
X * user at system.uucp -> system!user
X * user at system -> system!user
X * Forward other messages to UUCP feed
X * user at system.domain -> uucpfeed!domain!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 at 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);
X if(len>5 && (!strcmp(p+len-5, ".uucp") || !strcmp(p+len-5, ".UUCP")))
X p[len - 5] = 0;
X else if(strchr(p, '.'))
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
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;
Node dummynode;
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;
char dummyname[100];
Node dummynode;
FILE *mailer;
static char buffer[BUFSIZ];
int stat_loc, pid;
char *from;
char *to;
static char tempname[64];
FILE *temp;
int in_header_flag;
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(parse_address(argv[cnt], dummyname, &dummynode) == NULL) {
X /*
X * No error from parse_address(), so this is
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 at system.domain to
X * UUCP bang address system!name.
X */
X debug(2, "Argument %d (receiver %d) in rmail: %s",
X rargc, rrec + 1, argv[cnt]);
X rargs[rargc++] = process_address(argv[cnt]);
/* rargs[rargc++] = strsave(argv[cnt]); /**/
X rrec++;
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(parse_address(to, dummyname, &dummynode) == NULL) {
X /*
X * No error from parse_address(), so this is
X * mail for FIDO.
X */
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 /*
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 at system.domain to
X * UUCP bang address system!name.
X */
X debug(2, "Argument %d (receiver %d) in rmail: %s",
X rargc, rrec + 1, to);
X rargs[rargc++] = process_address(to);
/* rargs[rargc++] = strsave(to); /**/
X rrec++;
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 13476 -eq "$Wc_c" ||
echo 'rmail.c: original size 13476, 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.2 90/12/09 18:35:27 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.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 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
#include "fidogate.h"
/*
#include <fcntl.h>
#include <sys/stat.h>
*/
X
X
#define PROGRAMNAME "fpack $Revision: 2.2 $"
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 log("Msg from %s to %s at %s", from, to, ascnode(msg_node));
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 10480 -eq "$Wc_c" ||
echo 'fpack.c: original size 10480, 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: mju at dfv.rwth-aachen.de
|_|_|_|_____| D-5100 Aachen Tel. (Voice) 0241-86931
More information about the Alt.sources
mailing list