home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume18
/
fnet
/
part03
< prev
next >
Wrap
Text File
|
1989-03-05
|
62KB
|
2,360 lines
Subject: v18i004: Fido/Usenet gateway, Part03/05
Newsgroups: comp.sources.unix
Sender: sources
Approved: rsalz@uunet.UU.NET
Submitted-by: Heikki Suonsivu <hsu@santra.hut.fi>
Posting-number: Volume 18, Issue 4
Archive-name: fnet/part03
#!/bin/sh
# this is part 3 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file fpack.c continued
#
CurArch=3
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file fpack.c"
sed 's/^X//' << 'SHAR_EOF' >> fpack.c
X mail is public and default is private).
X
X All letters having arguments have only on space after them, and all
X rest of the line is considered to be that argument. */
X
Xbool
Xwrite_hdr(source, packet)
X FILE *source, *packet;
X{
X char buffer[BUFSIZ];
X char from[36], to[36], subject[72], date[20];
X Node msg_node;
X int attr = 0;
X struct stat stbuf;
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 {
X buffer[strlen(buffer) - 1] = 0; /* strip newline */
X switch (*buffer)
X {
X case 'N':
X if (parsefnetaddress(buffer, &msg_node))
X {
X log("Invalid destination: %s", buffer);
X return False;
X }
X break;
X case 'F':
X (void) strncpy(from, buffer + 2, 35);
X from[35] = 0;
X break;
X case 'T':
X (void) strncpy(to, buffer + 2, 35);
X to[35] = 0;
X break;
X case 'S':
X (void) strncpy(subject, buffer + 2, 71);
X subject[71] = 0;
X break;
X case 'D':
X (void) strncpy(date, buffer + 2, 19);
X date[19] = 0;
X break;
X case 'P':
X attr |= ATTR_PRIVATE;
X break;
X }
X }
X
X /* check if net/node was missing */
X if (msg_node.net == -1 || msg_node.node == -1)
X {
X log("Message with no destination");
X return False;
X }
X
X /* we must have also receiver */
X if (!*to)
X {
X log("Missing receiver in mail header");
X return False;
X }
X
X /* if from is missing, we'll improvise...*/
X if (!*from)
X {
X log("Missing from is header");
X (void) strcpy(from, "Usenet");
X }
X
X /* if subject is missing, let's put there something */
X if (!*subject)
X {
X log("Missing subject in header");
X (void) strcpy(subject, "Mail from Usenet");
X }
X
X /* if date is missing, put there current date */
X if (!*date)
X {
X log("Missing date in header");
X (void) strcpy(date, fido_date(time((long *) 0)));
X }
X
X /* save all header values */
X (void) write_int(packet, MSGTYPE); /* save msg type */
X (void) write_int(packet, MY_NODE); /* save our node */
X (void) write_int(packet, msg_node.node); /* save messages node */
X (void) write_int(packet, MY_NET); /* save our net */
X (void) write_int(packet, msg_node.net); /* save messages net */
X (void) write_int(packet, attr); /* save attributes */
X (void) write_int(packet, 0); /* 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 /* get status of mailfile and log this message */
X if (fstat(fileno(source), &stbuf) == -1)
X log("Unable to get stat of msg");
X
X log("Msg from %s to %s at %s packetized (%ld chars)", from, to,
X ascnode(msg_node), stbuf.st_size - ftell(source));
X
X /* done with this header */
X return True;
X}
X
X/* Write packet header for new packet.
X
X Tue Oct 11 04:01:49 1988
X Changed fwrite to write-ints and so on, as there is too many problems
X with int and specially long alignment on different architectures. This
X should be more portable!
X (two extra bytes added for long alignment caused confmail to find
X message type to be 0 and so it just forgot about that packet thinking
X that it was in the end!)
X */
X
Xbool
Xwrite_pkthdr(packet)
X FILE *packet;
X{
X Packet header;
X int count;
X struct tm *tm;
X time_t clock = time((long *) 0);
X
X tm = localtime(&clock);
X
X /* create packet structure */
X header.orig_node = int16(MY_NODE);
X header.dest_node = int16(node.node);
X header.orig_net = int16(MY_NET);
X header.dest_net = int16(node.net);
X
X /* save time for header (why all these fields?) */
X header.year = int16(tm->tm_year + 1900);
X header.month = int16(tm->tm_mon);
X header.day = int16(tm->tm_mday);
X header.hour = int16(tm->tm_hour + 1);
X header.minute = int16(tm->tm_min);
X header.second = int16(tm->tm_sec);
X
X header.rate = int16(MAXBAUD);
X header.ver = int16(HDRVER);
X header.product = 0;
X header.x1 = 0;
X#ifdef FIDO_V11w
X for (count = 0; count < 16; count++) header.fill[count] = 0;
X#else
X for (count = 0; count < 8; count++) header.pwd_kludge[count] = 0;
X header.orig_zone = int16(MY_ZONE);
X header.dest_zone = int16(node.zone);
X for (count = 0; count < 16; count++) header.B_fill2[count] = 0;
X header.B_fill3 = 0;
X#endif
X /* write header to file */
X FPUTINT16(header.orig_node, packet);
X FPUTINT16(header.dest_node, packet);
X FPUTINT16(header.year, packet);
X FPUTINT16(header.month, packet);
X FPUTINT16(header.day, packet);
X FPUTINT16(header.hour, packet);
X FPUTINT16(header.minute, packet);
X FPUTINT16(header.second, packet);
X FPUTINT16(header.rate, packet);
X FPUTINT16(header.ver, packet);
X FPUTINT16(header.orig_net, packet);
X FPUTINT16(header.dest_net, packet);
X putc(header.product, packet);
X putc(header.x1, packet);
X for (count = 0; count < 8; count++) putc(header.pwd_kludge[count], packet);
X FPUTINT16(header.orig_zone, packet);
X FPUTINT16(header.dest_zone, packet);
X for (count = 0; count < 16; count++) 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 (ferr(packet))
X {
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/*ARGSUSED*/
Xint
Xmain(argc, argv, envp)
X int argc;
X char **argv, **envp;
X{
X DIR *dp;
X struct dirent *dir;
X FILE *msg, *packet;
X char packet_name[16];
X int c;
X Node np;
X char *error;
X
X /* get options */
X while ((c = getopt(argc, argv, "vf:")) != EOF)
X switch (c)
X {
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 (void) fprintf(stderr, "Usage: %s [-v] -f fidonet_address\n", *argv);
X exit(1);
X }
X
X /* make sure that we got net/node */
X if (node.net == -1 || node.node == -1)
X {
X log("Missing fidonet node in command line");
X exit(1);
X }
X
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 }
X
X /* goto spool directory, everything exiting happens there... */
X if (chdir(SPOOL) == -1)
X {
X log("$Can not chdir to %s", SPOOL);
X exit(1);
X }
X
X /* create packet name */
X sprintpacketname(packet_name, node);
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 {
X log("$Can not open out/%s for update", packet_name);
X exit(1);
X }
X (void) 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 {
X log("$Can not open packet out/%s for writing", packet_name);
X exit(1);
X }
X
X /* protect packet from users...*/
X (void) chmod(sprintfs("out/%s", packet_name), 0600);
X
X /* write packet-header, if it fails, exit */
X if (!write_pkthdr(packet))
X {
X (void) 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 (void) sleep((unsigned) 1);
X
X /* open spool directory */
X if (dp = opendir("."))
X {
X while (dir = readdir(dp))
X {
X /* check that file is for us */
X if (*dir->d_name == 'M' && dir->d_name[1] == '.')
X {
X if (msg = fopen(dir->d_name, "r"))
X {
X debug(1, "Adding mailfile %s", dir->d_name);
X
X /* save header */
X if (write_hdr(msg, packet))
X {
X /* copy mail text, replace newlines with <cr> <lf> */
X while ((c = getc(msg)) && c != EOF)
X {
X if (c == '\n')
X (void) putc('\r', packet);
X (void) putc(c, packet);
X }
X /* null-terminate msg text */
X (void) putc(0, packet);
X }
X (void) fclose(msg);
X if (unlink(dir->d_name) == -1)
X log("$Unable to unlink %s", dir->d_name);
X }
X else
X log("$Can not open mail %s for reading", dir->d_name);
X }
X }
X (void) closedir(dp);
X }
X else
X {
X log("$Can not open spool directory %s", SPOOL);
X exit(1);
X }
X
X /* msg type 0 indicates end of packet */
X (void) write_int(packet, 0);
X
X (void) fclose(packet);
X
X exit(0);
X /* NOTREACHED */
X}
X
X
SHAR_EOF
echo "File fpack.c is complete"
chmod 0644 fpack.c || echo "restore of fpack.c fails"
echo "x - extracting funpack.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > funpack.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Unpaketize fido-mail packets and send mail to reciver or send it to
X news-server.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <sys/types.h>
X#include <varargs.h>
X#include <time.h>
X#include <dirent.h>
X#include "hsu.h"
X#include "config.h"
X#include "fnet.h"
X#include "fpack.h"
X#include "nodelist.h"
X#include "sysexits.h"
X#include "fnews.h"
X
X#define MAXARGS (32) /* maximum number of arguments */
X
Xextern time_t time();
Xextern char *tzname[];
Xextern int getopt();
Xextern int optind;
Xextern char *optarg;
Xextern void exit(), perror(), free();
Xextern char *malloc();
Xextern time_t dateconv();
Xextern void swab();
X
Xint verbose = INIT_VERBOSE;
Xint newsmode = FALSE;
Xint acceptprivate = FALSE;
Xint trashprivate = FALSE;
X
X#ifdef SCCS
Xchar *version = "%I%";
X#else
Xchar *version = PROGRAMNAME;
X#endif
X
X/* Test if string is totally numeric. */
X
Xbool
Xnumeric(s)
X register char *s;
X{
X while (*s)
X if (!isdigit(*s++))
X return False;
X return True;
X}
X
X/* Return msdos interger as machine integer */
X
Xint
Xint16(msint)
X INT16 msint;
X{
X static INT16 value;
X
X#ifdef SWAB_BYTES
X swab((char *) &msint, (char *) &value, 2);
X#else
X value = msint;
X#endif
X return (int) value;
X}
X
Xstatic FILE *badtemp = NULL;
X
X/*VARARGS2*/
Xtprintf(fp, fmt, va_alist)
X FILE *fp;
X char *fmt;
X{
X char buffer[BUFSIZ];
X va_list pvar;
X
X va_start(pvar);
X vsprintf(buffer, fmt, pvar);
X fputs(buffer, fp);
X if (badtemp) fputs(buffer, badtemp);
X va_end(pvar);
X}
X
Xtputs(buffer, fp)
X char *buffer;
X FILE *fp;
X{
X fputs(buffer, fp);
X if (badtemp) fputs(buffer, badtemp);
X}
X
X#define tputc(c, fp) putc(c, fp); if (badtemp) putc(c, badtemp);
X
X/* Replacement for fgets(3S) to understand cr's generated by Fido
X and 'soft' cr's generated by SEAdog. It return EOF if text is over,
X ie. 0 is got from file.
X
X Sat Oct 1 10:15:46 1988
X Must notice cr without linefeed, as confmail seems to send
X strange ids without lf.
X
X Mon Oct 3 01:51:01 1988
X Notice * Origin header and extract node from it. Useless time consumer
X when looking for mail.
X */
X
Xstatic char *
Xffgets(buffer, maxlen, fp)
X char *buffer;
X int maxlen;
X FILE *fp;
X{
X register int c, ch, index;
X register char *cp;
X char buf[BUFSIZ];
X static char wordsave[BUFSIZ];
X /* TRUE if last line was origin line without valid node */
X static int last_line_was_origin = FALSE;
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 {
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 {
X /* Hard carriage return */
X
X if (c == '\r')
X c = '\n';
X else if (c == '\n' || c == 0x8d || c == '\215')
X {
X /* Forget about these ! */
X continue;
X }
X else
X if (c == '\001')
X {
X /* Kludge. Stupid idea to put control chars to messages,
X but thats the way it is, replace with something which
X doesn't make programs expecting ascii mad */
X strncpy(cp, "FSC-Control:", 12);
X cp += 12;
X c = ' ';
X }
X
X /* If last character caused line wrap, and we now got another
X linefeed, skip this linefeed to avoid unneeded empty lines. */
X
X if (last_char_wrapped)
X {
X if (c == '\n')
X {
X last_char_wrapped = FALSE;
X continue;
X }
X
X if (isspace(c) && strempty(buffer)) continue;
X }
X
X *cp++ = c;
X
X if (c == '\n')
X break;
X
X *cp = 0;
X
X /* Try to wrap if line is too long and it is not a seen-by, origin
X or path line. */
X if (strlen(buffer) >= MAX_LINELEN - 1 &&
X strncmp(" * Origin:", buffer, 10) &&
X strncmp("SEEN-BY:", buffer, 8) &&
X strncmp("FSC-Control:", buffer, 12)) /* - 1 for \n */
X {
X last_char_wrapped = TRUE;
X
X /* Search for place to cut */
X for (index = strlen(buffer) - 1; index >= 0; index--)
X {
X c = buffer[index];
X if (index <= MAX_LINELEN / 3)
X {
X /* Too long, cut. */
X *cp++ = c = '\n';
X goto collected;
X }
X
X /* Note: [\]{|}@` are not considered punctuation because
X they are used in some countries for national characters. */
X if (isspace(c) || (ispunct(c) && !strchr("[\\]{|}@`", c)))
X {
X /* Wrap here! */
X cp = buffer + index + 1; /* Punctuation left on this 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 /* This is really nasty part: Try to work out reply-to path from
X origin for those people who don't have node in nodelist.
X This should handle both situations where origin line is split by
X some stupid mailer, or because origin line was too long (sysops,
X please don't use long system identifiers, it causes lots of trouble!).
X It checks that line doesn't start with SEEN-BY: or FSC-Control as
X those things generally follow origin lines. */
X
X if (!strncmp(" * Origin:", buffer, 10) || last_line_was_origin) {
X char *left, *right;
X
X if (last_line_was_origin)
X {
X last_line_was_origin = FALSE;
X /* If its seen-by or control, it probably isn't continuation! */
X if (!strncmp("SEEN-BY:", buffer, 8) ||
X !strncmp("FSC-Control:", buffer, 12))
X goto out;
X }
X else
X last_line_was_origin = TRUE;
X
X strcpy(buf, buffer);
X right = buf;
X
X for (;;)
X {
X if ((left = strchr(right, '(')) && (right = strchr(left + 1, ')')))
X {
X *right = 0;
X if (parsefnetaddress(++left, &node))
X {
X debug(1, "Could not parse %s", left);
X }
X else
X {
X memcpy( (char *) &originnode, (char *) &node, sizeof(Node));
X debug(1, "Parsed %s to %d:%d/%d.%d", left, originnode.zone,
X originnode.net, originnode.node, originnode.point);
X }
X left = ++right;
X }
X else
X break;
X }
X }
X
X out:
X return ((!c || c == EOF) && cp == buffer) ? (char *) 0 : buffer;
X}
X
X/* Execute sender of fido-message. Argument will be program name, anrgument
X for that and pid to return. If command is not empty, use it instead
X of given program and build parameter table. */
X
Xstatic char command[64];
X
XFILE *
Xopen_sender(program, args, pid)
X char *program, **args;
X int *pid;
X{
X FILE *fp;
X int fd[2], count = 0;
X char *p, *realargs[MAXARGS];
X char *cmd, *realprogram;
X
X cmd = alloca(strlen(command) + 1);
X strcpy(cmd, command);
X
X if (*cmd)
X {
X while (p = strtok(cmd, SEPARATORS))
X {
X realargs[count++] = p;
X cmd = NULL; /* For strtok */
X }
X
X realargs[count++] = NULL;
X realprogram = *realargs;
X
X if (realprogram)
X {
X program = realprogram;
X args = realargs;
X }
X }
X
X if (pipe(fd) == -1)
X {
X perror("funpack: pipe");
X return (FILE *) 0;
X }
X
X switch (*pid = fork())
X {
X case -1:
X perror("funpack: fork failed");
X return (FILE *) 0;
X case 0:
X (void) close(0);
X if (dup(fd[0]) == 0)
X {
X (void) close(fd[0]);
X (void) close(fd[1]);
X if (args)
X (void) execvp(program, args);
X else
X (void) execlp(program, basename(program), (char *) 0);
X perror(program);
X }
X else
X perror("funpack: dup");
X exit(EX_OSERR);
X default:
X (void) close(fd[0]);
X if ((fp = fdopen(fd[1], "w")) == NULL)
X {
X perror("funpack: fdopen");
X return (FILE *) 0;
X }
X }
X return fp;
X}
X
Xstatic Packet header;
X
Xread_header(fp)
X FILE *fp;
X{
X FGETINT16(header.orig_node, fp);
X FGETINT16(header.dest_node, fp);
X FGETINT16(header.year, fp);
X FGETINT16(header.month, fp);
X FGETINT16(header.day, fp);
X FGETINT16(header.hour, fp);
X FGETINT16(header.minute, fp);
X FGETINT16(header.second, fp);
X FGETINT16(header.rate, fp);
X FGETINT16(header.ver, fp);
X FGETINT16(header.orig_net, fp);
X FGETINT16(header.dest_net, fp);
X header.product = getc(fp);
X header.x1 = getc(fp);
X FREAD(header.pwd_kludge, 8, 1, fp);
X FGETINT16(header.orig_zone, fp);
X if (header.orig_zone == 0) header.orig_zone = int16(MY_ZONE);
X FGETINT16(header.dest_zone, fp);
X if (header.dest_zone == 0) header.dest_zone = int16(MY_ZONE);
X FREAD(header.B_fill2, 16, 1, fp);
X FREAD( (char *) &header.B_fill3, 4, 1, fp);
X return ferr(fp);
X}
X
X/* Return int from file. Int in file is supposed to be 16 bit ms-dos
X integer. */
X
Xint
Xread_int(fp)
X FILE *fp;
X{
X static INT16 value;
X
X if (fread((char *) &value, 2, 1, fp) != 1)
X {
X if (ferr(fp))
X log("Cannot read file, errno %d : %s", errno, sys_errlist[errno]);
X
X value = 0;
X }
X
X debug(8, "< %02x(%ld)", int16(value), ftell(fp));
X return int16(value);
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
Xvoid
Xget_string(buffer, fp, nbytes)
X char *buffer;
X FILE *fp;
X int nbytes;
X{
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 {
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')) *p = 0;
X
X debug(8, "Getstring at %ld %s", ftell(fp), buffer);
X}
X
X#define NGFLAG_ACCEPT_PRIVATE 0
X#define NGFLAG_COMMAND 1
X#define NGFLAG_TRASH_PRIVATE 2
X
Xstatic char distribution[64];
Xstatic char *ngflags[] = { "accept-private", "command", "trash-private", "" };
X
X/* Like strtok but returns empty string instead of null if no more thigns
X found */
X
Xchar *estrtok(s, sep)
X char *s, *sep;
X{
X char *p;
X
X if (p = strtok(s, sep)) return p;
X return "";
X}
X
Xchar *
Xget_ng(config, echo, distrib)
X FILE *config;
X char *echo, *distrib;
X{
X static char conv[BUFLEN];
X char *gr, *flag;
X
X debug(2, "Checking echolist '%s'", echo);
X
X *command = 0;
X section(SECT_AREA_NG, config);
X trashprivate = FALSE;
X acceptprivate = FALSE;
X while (getcl(conv, BUFLEN, config))
X {
X debug(3, "Config line '%s'", conv);
X
X gr = estrtok(conv, SEPARATORS);
X if (!strcmp(gr, echo))
X {
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 {
X case NGFLAG_ACCEPT_PRIVATE:
X acceptprivate = TRUE;
X break;
X
X case NGFLAG_COMMAND:
X /* Fails if fnews.cf has DEL char in it, but thats
X mostly a philosophical question. */
X strcpy(command, estrtok(NULL, "\377"));
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}
X
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
Xchar *
Xnews_msg(fp)
X FILE *fp;
X{
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 {
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, "fnews.cf", "r")) == NULL)
X {
X log("$Unable to open config 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 {
X /* this is not echomail message, seek back */
X (void) fseek(fp, offset, 0);
X return (char *) 0;
X }
X /* NOTREACHED */
X}
X
X/* Return date of message. Date will be read and converted to one
X long-interger as normal Unix-time will be.
X
X Both SEAdog and Fido date formats are understood.
X SEAgod: Mon 1 Jan 86 02:34
X Fido: 01 Jan 86 02:34:56 */
X
Xtime_t
Xlgetdate(packet)
X FILE *packet;
X{
X char buffer[20];
X int c;
X time_t timevar;
X int n;
X
X /* read date from packet */
X for (n = 0; n < 20; n++)
X if ((buffer[n] = getc(packet)) == NULL) break;
X
X /* Some message-packers do mistakes! Date should be 20 bytes but
X they start name directly after null terminating 18-char date
X used in some systems. Check if following char is null or not,
X and if not, put it back there as it probably is first char in
X recipent name. This seems to be problem in OMMM, but I'm not
X sure yet.
X
X Wed Nov 16 21:11:34 1988 Seems that the bug is in fsc001, as
X I constantly keep receiving messages which 19 byte date?
X */
X
X#ifdef FSC_IS_REALLY_CORRECT
X for (n++; n < 20; n++)
X if (c = getc(packet))
X {
X ungetc(c, packet);
X }
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, (struct timeb *) NULL);
X return timevar;
X}
X
X/* Remove 'of net/node' from name. Number will be saved
X for later use and used as reply-to address, as I think most users use
X it as their home system or if they are sysops, as their node. */
X
Xsearch_node(from, node)
X char *from;
X Node *node;
X{
X char *s, *p, *of;
X Node tempnode;
X
X s = alloca(strlen(from) + 1);
X strcpy(s, from);
X
X p = strtok(s, WHITESPACE);
X while (p)
X {
X if (!stricmp(p, "of"))
X {
X of = p;
X /* Skip possible multiple 'of's */
X for (; (p = strtok(NULL, WHITESPACE)) && !stricmp(p, "of"););
X /* Of and something else follows, try to parse */
X if (p)
X {
X if (!parsefnetaddress(p, &tempnode))
X {
X if (node) *node = tempnode;
X /* Of net/node should be the last string */
X if ((p = strtok(NULL, WHITESPACE)) == NULL)
X {
X /* Remove 'of ...' from name */
X *(from + (int) (of - s)) = 0;
X strclean(from);
X return; /* Found it */
X }
X else
X continue; /* Something follows, try again */
X }
X }
X else
X return; /* no more stuff */
X }
X p = strtok(NULL, WHITESPACE);
X }
X return;
X}
X
X/* Remove userids from names, like "James Smith (SMITH)" will become
X "James Smith". Simple algorithm now, but its enough. Scandinvian
X chars are translated to a and o, and other special chars are
X removed. */
X
Xremove_id(name)
X char *name;
X{
X char *p, *cp;
X
X if (p = strchr(name, '(')) {
X while (*p != ')' && *p)
X for (cp = p; *cp = *(cp + 1); cp++); /* Remove one char */
X
X if (*p == ')')
X for (cp = p; *cp = *(cp + 1); cp++); /* Remove last ) */
X }
X
X /* Remove blanks from the end */
X while (strlen(name) && isspace(name[strlen(name) - 1]))
X name[strlen(name) - 1] = 0;
X (void) ascii_convert(name);
X fine_convert(name);
X stripbad(name);
X}
X
X/* Search alias name which matches with fidonet name, return NULL
X if no alias specified. */
X
Xchar *get_alias(name)
X char *name;
X{
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 {
X while (fgets(buffer, BUFSIZ, fp))
X {
X buffer[strlen(buffer) - 1] = 0;
X if (*buffer != '#')
X {
X if ((cp = strchr(buffer, ' ')) ?
X cp : (cp = strchr(buffer, '\t')))
X {
X *cp = 0; /* Break unixname out */
X strcpy(unixname, buffer); /* And save it */
X debug(8, "Unix name %s", unixname);
X }
X else
X {
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)) cp++;
X if (!*cp)
X {
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 {
X fclose(fp);
X
X /* There may be node specs after name, null them out */
X if (cp = strchr(unixname, ',')) *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/* Save bad article from file given to bad directory */
X
Xsavebad(fp)
X FILE *fp;
X{
X char *fname, buffer[BUFSIZ];
X FILE *badfile;
X
X log("Saving bad article/mail to %s",
X fname = sprintfs("%s/bad%ld", BADARTICLES, sequencer(BADSEQ)));
X if (badfile = fopen(fname, "w+"))
X {
X rewind(fp);
X while (fgets(buffer, BUFSIZ, fp))
X fputs(buffer, badfile);
X }
X else
X {
X log("$Could not open bad article file");
X return -1;
X }
X fclose(badfile);
X return 0;
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
Xvoid
Xunpack(packet, packetnode)
X FILE *packet;
X Node packetnode;
X{
X int count, attributes, messagetype;
X char to[36], from[36], realto[40], realfrom[40], subject[72];
X char badname[BUFSIZ];
X char *args[MAXARGS];
X char buffer[BUFSIZ], *cp, *p;
X FILE *sender, *newssender;
X int n, pid, stat_loc, c;
X Node *entry, mynode, orignode, destnode, fromnode;
X char hostname[10];
X time_t msg_date;
X char *area;
X
X /* get node-entry fo packet-sender */
X if (node_entry(packetnode) == NULL)
X {
X log("Unknown packet sender: %s", ascnode(packetnode));
X return;
X }
X
X mynode.zone = MY_ZONE;
X mynode.net = MY_NET;
X mynode.node = MY_NODE;
X mynode.point = MY_POINT;
X
X if ((entry = node_entry(mynode)) == NULL)
X {
X log("Unable to find this net/node from nodelist");
X return;
X }
X
X /* get our uucp-nodename */
X if (gethostname(hostname, 10) == -1)
X {
X log("$Unable to get hostname");
X return;
X }
X
X while ((messagetype = read_int(packet)) == MSGTYPE)
X {
X *args = NULL;
X originnode.zone = -1;
X fromnode.zone = -1;
X orignode.zone = packetnode.zone; /* Orignode zone and point are not */
X orignode.point = packetnode.point; /* included in messages. */
X destnode.zone = packetnode.zone;
X destnode.point = packetnode.point;
X
X /* get nodes information about message */
X orignode.node = read_int(packet);
X destnode.node = read_int(packet);
X
X /* get nodes from message */
X orignode.net = read_int(packet);
X destnode.net = read_int(packet);
X
X debug(2, "Original net/node = %s", ascnode(orignode));
X debug(2, "Destination net/node = %s", ascnode(destnode));
X
X /* we're not interested about attributes currenty */
X attributes = read_int(packet);
X
X /* through away cost */
X (void) read_int(packet);
X
X /* get date */
X msg_date = lgetdate(packet);
X
X /* get receiver of message */
X get_string(to, packet, 35);
X search_node(to, (Node *) NULL);
X remove_id(to);
X debug(2, "Msg is to '%s'", to);
X
X /* get sender of message */
X get_string(from, packet, 35);
X search_node(from, &fromnode);
X remove_id(from);
X debug(2, "Msg is from '%s'", from);
X
X /* get subject */
X get_string(subject, packet, 71);
X
X /* Remove trailing blanks */
X for (count = strlen(subject) - 1; count >= 0 && isspace(subject[count]);
X count--) subject[count] = 0;
X
X /* News expects some kind of subject and ignores the message
X without one? */
X if (!*subject) strcpy(subject, "No subject");
X
X debug(2, "Subject is '%s'", subject);
X
X /* check that message is to this node */
X if (!samenode(destnode, mynode))
X {
X log("Msg from %s to %s at %s: wrong node address",
X from, to, ascnode(destnode));
X goto error;
X }
X
X /* check if this is news-message. Private messages will not
X be forwarded to readnews, they go to mail, if received is
X known, otherwise they will be thrown away. Exception are
X conferences which are marked accept-private. */
X newsmode = FALSE;
X if ((area = news_msg(packet)) &&
X (acceptprivate || !(attributes & ATTR_PRIVATE)))
X {
X /* This is news-artcile. Open sendfidonews and give area name as
X argument to it. Input of sfnews will be just like input
X of mail. */
X
X debug(1, "Message is news-article");
X newsmode = TRUE;
X
X /* create args for sender */
X *args = strsave(RNEWS);
X#ifdef NEEDED
X args[1] = strsave(area);
X args[2] = NULL;
X#else
X args[1] = NULL;
X#endif
X /* open sender */
X if (!(sender = tmpfile()))
X {
X log("Can not create temp file, errno %d: %s",
X errno, sys_errlist[errno]);
X goto error;
X }
X
X if ((newssender = open_sender(*args, args, &pid)) == NULL)
X {
X log("Can not execute %s", *args);
X goto error;
X }
X
X badtemp = NULL; /* tmp file for news messages will be
X created later. */
X }
X else
X {
X debug(1, "Message is for mail");
X if (area)
X {
X debug(1, "Private message for area %s", area);
X if (trashprivate) goto error;
X }
X
X /* If message receiver is Usenet, then receiver of mail will
X be at first-line of message separated by commands/spaces.
X If receiver is not usenet, mail will be sent to normal
X receiver, but in this case all charactes will be converted
X to lower case (Fido changes them, you know). */
X
X if (!strcmp(to, "Usenet"))
X {
X if (ffgets(buffer, BUFSIZ, packet) == NULL)
X {
X log("Missing receiver in msg from %s at %s", from,
X ascnode(orignode));
X goto error;
X }
X buffer[strlen(buffer) - 1] = 0;
X }
X else
X {
X debug(8, "Searching alias for %s", to);
X if (p = get_alias(to))
X {
X (void) strcpy(buffer, p);
X debug(8, "Got alias %s", buffer);
X }
X else
X {
X if (area)
X {
X log("Skipping private echo for %s", to);
X goto error; /* If private echo message, skip */
X }
X (void) strcpy(buffer, to);
X debug(8, "No alias, using %s", buffer);
X }
X
X for (n = 0; buffer[n]; n++)
X buffer[n] = tolower(buffer[n]);
X }
X
X *args = strsave(basename(RMAIL));
X for (n = 1, cp = strtok(buffer, ", \t"); cp && n < MAXARGS;
X cp = strtok((char *) 0, ", \t"), n++)
X args[n] = strsave(cp);
X args[n] = NULL;
X
X for (n = 1; args[n]; n++)
X log("Sending mail from %s at %s to %s", from, ascnode(orignode),
X args[n]);
X
X /* open rmail for sending message */
X if ((sender = open_sender(RMAIL, args, &pid)) == NULL)
X {
X log("Can not execute %s", RMAIL);
X goto error;
X }
X
X if (badtemp)
X fclose(badtemp);
X
X if ((badtemp =
X fopen(strcpy(badname, mktemp("/tmp/funpXXXXXX")), "w+"))
X == NULL)
X {
X log("$Cannot open tmp file %s", badname);
X goto error;
X }
X
X area = NULL;
X
X }
X
X /* Save real names for further use. Blanks included, */
X if (strchr(from, ' '))
X {
X strcpy(realfrom, " (");
X strcat(realfrom, from);
X strcat(realfrom, ")");
X }
X else
X *realfrom = 0;
X
X if (strchr(to, ' '))
X {
X strcpy(realto, " (");
X strcat(realto, to);
X strcat(realto, ")");
X }
X else
X *realto = 0;
X
X /* change all spaces in name to _'s */
X for (n = 0; from[n]; n++)
X if (from[n] == ' ') from[n] = '_';
X /* Same for to field */
X for (n = 0; to[n]; n++)
X if (to[n] == ' ') to[n] = '_';
X
X /* set From_ line */
X (void) tprintf(sender, "From %d!%s %s remote from %d\n", orignode.node,
X from, date("%a %h %d %T 19%y", (long *) 0), orignode.net);
X
X /* Now generate valid RFC 822 header for mail. Some fields may
X be different, in all places there may be comments between (
X and )-charactes. */
X
X /* This is imporant for news articles, as without this inews
X tries to post it back. This is a bit complicated, as we cannot
X put fidonet path here? Hmm... why not, I have to check this out! */
X (void) tprintf(sender, "Path: %s!%s\n", RECEIVE_PATH, from);
X
X /* print Received: field */
X (void) tprintf(sender, "Received: by %s (funpack%s/%s)\n",
X internode(*entry), version, entry->name);
X (void) tprintf(sender, "\tid AA%05d; %s\n",
X getpid(), date("%a, %d %h %y %T %o (%z)", (long *) 0));
X
X /* print Date: field */
X (void) tprintf(sender, "Date: %s\n", date("%a, %d %h %y %T %o",
X &msg_date));
X
X /* print From: field */
X (void) tprintf(sender, "From: %s@%s%s\n", from, internode(orignode),
X realfrom);
X
X /* print Subject: field */
X (void) tprintf(sender, "Subject: %s\n", subject);
X
X /* print Message-Id: field */
X (void) tprintf(sender, "Message-Id: <%s.AA%ld@%s>\n",
X date("%y%m%q%H%M", (long *) 0), sequencer(IDSEQUENCE),
X internode(*entry));
X
X if (area)
X {
X (void) tprintf(sender, "Newsgroups: %s\n", area);
X if (strlen(distribution))
X (void) tprintf(sender, "Distribution: %s\n", distribution);
X
X /* print Reply-To: field */
X /* Note: This is not accurate yet, as * Origin can change
X address to other node */
X (void) tprintf(sender, "Reply-To: %s@%s%s\n",
X from, internode(destnode), realfrom);
X }
X else
X {
X /* print To: field */
X (void) tprintf(sender, "To: ");
X for (n = 1; args[n]; n++)
X {
X (void) tprintf(sender, "%s", args[n]);
X if (args[n + 1])
X (void) tprintf(sender, ", ");
X }
X tprintf(sender, "\n");
X
X /* print Reply-To: field */
X (void) tprintf(sender, "Reply-To: %s@%s%s\n",
X from, internode(orignode), realfrom);
X }
X
X /* done with header, now send message text */
X
X tprintf(sender, "\n");
X while (ffgets(buffer, BUFSIZ, packet))
X (void) tputs(buffer, sender);
X
X /* News messages are a little bit more compilicated. News
X article has been saved in temp file, and now we need to
X read it through, replace Reply-To with correct return address
X taken from origin row, nodelist, or if not found, echo feed.
X Then really send mail to newssender. */
X
X if (area)
X {
X debug(1, "Reading back news article");
X rewind(sender);
X
X if (badtemp)
X fclose(badtemp);
X
X if ((badtemp =
X fopen(strcpy(badname, mktemp("/tmp/funpXXXXXX")), "w+"))
X == NULL)
X {
X log("$Cannot open tmp file %s", badname);
X goto error;
X }
X
X while (fgets(buffer, BUFSIZ, sender))
X {
X if (!strncmp(buffer, "Reply-To:", 9))
X {
X if (search_name(from))
X {
X debug(1, "%s is not a sysop, try his name", from);
X if (fromnode.zone != -1)
X originnode = fromnode;
X else
X {
X debug(1, "No node in his name, try * Origin", from);
X if (originnode.zone == -1)
X {
X debug(1, "No * Origin, replace with echo feed");
X originnode = orignode;
X }
X else
X debug(2, "Origin %s", ascnode(originnode));
X }
X }
X
X (void) tprintf(newssender, "Reply-To: %s@%s%s\n",
X from, internode(originnode), realfrom);
X
X /* Set Comment-To field */
X if (search_name(to))
X {
X debug(1, "%s is not a sysop, try * Origin", to);
X if (originnode.zone == -1)
X {
X debug(1, "No * Origin, replace with echo feed");
X originnode = orignode;
X }
X else
X debug(2, "Origin %s", ascnode(originnode));
X }
X
X (void) tprintf(newssender, "Comment-To: %s@%s%s\n", to,
X internode(originnode), realto);
X }
X else
X (void) tputs(buffer, newssender);
X }
X fclose(newssender); /* sender will vanish when its closed! */
X }
X
X /* done with this msg, wait process to finish */
X (void) fclose(sender);
X while ((n = wait(&stat_loc)) != pid && n != -1);
X
X debug(2, "Wait status: %o", stat_loc);
X if (stat_loc)
X savebad(badtemp);
X
X fclose(badtemp);
X unlink(badname);
X
X debug(1, "Done with message");
X
X /* free argument-list */
X for (n = 0; args[n]; n++)
X free(args[n]);
X continue;
X
X /* in the case of error skip text of message */
X error:
X while ((c = getc(packet)) && c != EOF);
X
X /* free argument-list */
X for (n = 0; args[n]; n++)
X free(args[n]);
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/* ARGSUSED */
Xint
Xmain(argc, argv, envp)
X int argc;
X char **argv, **envp;
X{
X struct dirent *dir;
X DIR *dp;
X int c;
X FILE *packet;
X char files[BUFLEN];
X Node node;
X bool nocheck = False;
X char *error, *p;
X Node packetnode;
X
X node.zone = -1;
X while ((c = getopt(argc, argv, "if:vV:")) != EOF)
X switch (c)
X {
X case 'V':
X version = optarg;
X break;
X case 'i':
X nocheck = True;
X break;
X case 'v':
X verbose++;
X break;
X case 'f':
X if (parsefnetaddress(optarg, &node)) exit(1);
X break;
X default:
X fprintf(stderr,
X "Usage: %s [-v] [-f [[<zone>:]<net>/]<node>[.<point>]]\n",
X *argv);
X exit(EX_USAGE);
X }
X
X /* create name for unpacking */
X if (node.zone == -1)
X (void) strcpy(files, "");
X else
X {
X sprintipacketname(files, node);
X /* Cut sequence number off */
X if (p = strrchr(files, ".")) *p = 0;
X }
X
X debug(2, "Unpacking packets beginning with %s", files);
X
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 }
X
X if (chdir(sprintfs("%s/in", SPOOL)) == -1)
X {
X log("$Cannot chdir to %s/in", SPOOL);
X exit(EX_OSERR);
X };
X
X if (dp = opendir("."))
X {
X while (dir = readdir(dp))
X if (!strncmp(dir->d_name, files, strlen(files)) && *dir->d_name != '.')
X {
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 {
X if (read_header(packet))
X {
X if (feof(packet))
X log("Missing packet header");
X else
X log("Error reading header, errno %d : %s",
X errno, sys_errlist[errno]);
X }
X else
X {
X packetnode.zone = int16(header.orig_zone);
X packetnode.net = int16(header.orig_net);
X packetnode.node = int16(header.orig_node);
X packetnode.point = 0; /* no points in fidonet header? */
X debug(1, "Packet from %s", ascnode(packetnode));
X debug(1, "Time %02d:%02d:%02d %d.%d.%d",
X int16(header.hour),
X int16(header.minute), int16(header.second),
X int16(header.day), int16(header.month),
X int16(header.year));
X debug(1, "Max baud rate %d, version %d, product %d, x %d",
X int16(header.rate), int16(header.ver),
X header.product, header.x1);
X debug(1, "Pwd \"%s\"", header.pwd_kludge);
X }
X
X if (nocheck || ((int16(header.dest_zone) == MY_ZONE ||
X int16(header.dest_zone) == 0) &&
X int16(header.dest_node) == MY_NODE &&
X int16(header.dest_net) == MY_NET))
X unpack(packet, packetnode);
X else
X log("Packet is to %d:%d/%d",
X int16(header.dest_zone),
X int16(header.dest_net),
X int16(header.dest_node));
X (void) fclose(packet);
X
X /* Move packet to unpacked directory. */
X if (link(dir->d_name,
X sprintfs("%s/%s", UNPACKED_DIR, dir->d_name)))
X log("$Could not link packet %s", dir->d_name);
X else
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 {
X log("$Unable to open spool directory");
X exit(EX_OSERR);
X }
X exit(EX_OK);
X /* NOTREACHED */
X}
SHAR_EOF
chmod 0644 funpack.c || echo "restore of funpack.c fails"
echo "x - extracting fcall.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > fcall.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Dial to host-fido for mail.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <signal.h>
X#include <termio.h>
X#include <dial.h>
X#include <sys/types.h>
X#include <dirent.h>
X#include <time.h>
X#include "hsu.h"
X#include "config.h"
X#include "fnet.h"
X#include "fio.h"
X#include "nodelist.h"
X
Xextern unsigned sleep();
Xextern void exit();
Xextern int getopt();
Xextern int optind;
Xextern char *optarg;
X
Xint line = -1;
Xint verbose = INIT_VERBOSE;
X
X/* Macros to check timeout */
X
X#define SetStart() (stime = time((long *) 0))
X#define Timeout(t) (time((long *) 0) - stime > (t))
X
X/* States for session sender. */
X
X#define SendInit (0)
X#define WaitCxD (1)
X#define WhackCRs (2)
X#define WaitClear (3)
X#define SendMail (4)
X#define CheckMail (5)
X#define SendFiles (6)
X#define CheckFiles (7)
X#define TryPickup (8)
X
X/* States for session receiver. */
X
X#define WaitTsync (9)
X#define RecMail (10)
X#define XRecEnd (11)
X#define RecFiles (12)
X#define ChkFiles (13)
X#define AllowPickup (14)
X
X/* States to break up the loops */
X
X#define Error (-1)
X#define Done (-2)
X
X/* For debugging */
X
Xstatic char devicebuffer[100];
XCALL call; /* call structure for dial(3) */
X
X/* Show dialer's error code as message */
X
Xvoid
Xlog_dialerr(code)
X int code;
X{
X switch (code)
X {
X case INTRPT:
X log("Interrupt occured during dialing");
X break;
X case D_HUNG:
X log("Dialer hung (no return from write)");
X break;
X case NO_ANS:
X log("No answer");
X break;
X case ILL_BD:
X log("Illegal baud-rate");
X break;
X case A_PROB:
X log("Acu problem (open() failure)");
X break;
X case L_PROB:
X log("Line problem (open() failure)");
X break;
X case NO_Ldv:
X log("Can't open LDEVS file");
X break;
X case DV_NT_A:
X log("Requested device not available");
X break;
X case DV_NT_K:
X log("Requested device %s, line %s telno %s speed %d baud %d, not known",
X call.device, call.line, call.telno, call.speed, call.baud);
X break;
X case NO_BD_A:
X log("No device available at requested baud");
X break;
X case NO_BD_K:
X log("No device known at requested baud");
X break;
X case DV_NT_E:
X log("Requested speed does not match");
X break;
X default:
X log("Dial error %d", code);
X }
X}
X
X/* Trapper for signals to quit gracefully. Be must do undial to get lock-
X file removed */
X
Xint
Xquit(sig)
X int sig;
X{
X (void) signal(SIGINT, SIG_IGN);
X (void) signal(SIGQUIT, SIG_IGN);
X (void) signal(SIGTERM, SIG_IGN);
X (void) signal(SIGHUP, SIG_IGN);
X
X if (line >= 0)
X undial(line);
X if (sig >= 0)
X log("Caught signal %d", sig);
X exit(1);
X /* NOTREACHED */
X}
X
X/* Send files in batch protocol */
X
Xbool
Xsendfiles()
X{
X/* if (batchsend("fio.h")) */
X return batchsend((char *) 0);
X/* else return 0; */
X}
X
Xbool recfiles()
X{
X return batchrec((char *) 0);
X}
X
X/* ARGSUSED */
Xint
Xmain(argc, argv, envp)
X int argc;
X char **argv, **envp;
X{
X struct termio tio; /* terminal state */
X int c;
X time_t stime;
X int retry_time = 0, no_retrys = 0, wait_line = 0;
X int state = SendInit, receive_retrys = MAX_SEND_RETRIES;
X bool ok, pickup = False;
X Node *node, tnode;
X char phonenumber[100];
X char packetname[100], ipacketname[100];
X char *error, *p;
X
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 }
X
X if (chdir(SPOOL) < 0)
X {
X log("$Can not chdir to %s", SPOOL);
X exit(1);
X }
X
X strcpy(packetname, "packet.out");
X strcpy(ipacketname, "packet.junk");
X
X call.attr = &tio;
X call.baud = 0;
X call.speed = 0;
X call.line = NULL;
X call.telno = NULL;
X call.modem = 0;
X call.device = devicebuffer;
X call.dev_len = sizeof(devicebuffer);
X
X tio.c_iflag = IGNPAR | IGNBRK;
X tio.c_oflag = 0;
X tio.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
X tio.c_lflag = NOFLSH;
X tio.c_cc[VMIN] = 1;
X tio.c_cc[VTIME] = 0;
X
X if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGINT, quit);
X if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X (void) signal(SIGTERM, quit);
X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X (void) signal(SIGQUIT, quit);
X if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
X (void) signal(SIGHUP, quit);
X
X while ((c = getopt(argc, argv, "vmdp:l:b:s:r:n:w:f:")) != EOF)
X switch (c)
X {
X case 'd':
X pickup = True;
X break;
X case 'p':
X call.telno = optarg;
X break;
X case 'v':
X verbose++;
X break;
X case 'l':
X call.line = optarg;
X break;
X case 'b':
X call.baud = atoi(optarg);
X break;
X case 's':
X call.speed = atoi(optarg);
X break;
X case 'r':
X retry_time = atoi(optarg);
X break;
X case 'n':
X no_retrys = atoi(optarg);
X break;
X case 'w':
X wait_line = atoi(optarg);
X break;
X case 'm':
X call.modem = 1;
X break;
X case 'f':
X
X /* Fidonet address to call */
X
X if (parsefnetaddress(optarg, &tnode)) exit(1);
X if (!(node = node_entry(tnode))) {
X log("Could not get node information");
X exit(1);
X }
X
X /* Use either maximum speed set or maximum speed of fido system */
X
X if (node->speed > MAXBAUD) {
X if (!call.baud) {
X call.baud = call.speed = MAXBAUD;
X }
X } else {
X call.baud = call.speed = node->speed;
X }
X if (call.baud < MINBAUD) call.baud = call.speed = MINBAUD;
X
X /* Translate phone number from nodelist, if not set */
X
X if (!call.telno) {
X dial_translation(phonenumber, node->phone);
X call.telno = phonenumber;
X }
X
X sprintpacketname(packetname, *node);
X sprintipacketname(ipacketname, *node);
X break;
X
X default:
X log("Illegal option for fcall");
X exit(1);
X }
X
X while (state >= SendInit && state < AllowPickup)
X switch (state)
X {
X case SendInit:
X if (call.telno)
X log("Dialing to %s", call.telno);
X line = dial(call);
X state = WaitCxD;
X break;
X case WaitCxD:
X if (line == NO_ANS && retry_time)
X if (--no_retrys < 0)
X {
X log("Too many retries in call");
X state = Error;
X }
X else
X {
X log("No answer, redial in %d seconds", retry_time);
X (void) sleep((unsigned) retry_time);
X state = SendInit;
X }
X else
X if ((line == DV_NT_A || line == NO_BD_A) && wait_line)
X {
X log("No free lines, waiting %d seconds", wait_line);
X (void) sleep((unsigned) wait_line);
X }
X else {
X if (line >= 0)
X {
X log("Call succeeded");
X state = WhackCRs;
X debug(1, "Wait %d seconds before start", PREWAIT);
X (void) sleep((unsigned) PREWAIT);
X }
X else
X {
X log_dialerr(line);
X log("Dial failed");
X state = Error;
X }
X }
X break;
X case WhackCRs:
X SetStart();
X while (state == WhackCRs)
X if (Timeout(30))
X {
X log("No response");
X state = Error;
X }
X else if (readline(1) == '\r')
X {
X debug(1, "Got CR, wait 1 second");
X (void) sleep((unsigned) 1);
X state = WaitClear;
X }
X else
X {
X debug(2, "Sending <sp><cr>");
X sendline(' ');
X sendline('\r');
X }
X break;
X case WaitTsync:
X SetStart();
X while (state == WaitTsync)
X if (Timeout(60))
X {
X log("Garbage, no Tsync, Call ok (?)");
X state = AllowPickup;
X }
X else if ((c = readline(1)) == TSYNCH)
X {
X debug(1, "Received TSYNCH");
X state = RecMail;
X }
X else if (c == ENQ)
X {
X debug(1, "Got ENQ, nothing to pick up");
X state = AllowPickup;
X }
X break;
X case RecMail:
X ok = xtrec(sprintfs("in/%s", ipacketname), False);
X state = XRecEnd;
X break;
X case XRecEnd:
X if (ok)
X {
X log("Mail received successfully");
X
X /* Flush input */
X
X (void) sleep((unsigned) 1);
X
X SetStart();
X while (state == XRecEnd)
X if (Timeout(60))
X {
X log("Garbage on line");
X state = Error;
X break;
X }
X else if (readline(1) == TIMEOUT)
X {
X debug(1, "Line is clear, rec files");
X state = RecFiles;
X }
X }
X else
X {
X log("Receiving mail failed or nothing to receive");
X log("Moving received packet in/%s to %s", ipacketname,
X p = sprintfs("%s/%s", BADARTICLES, ipacketname));
X if (link(sprintfs("in/%s", ipacketname), p))
X log("$Could not link packet in/%s", ipacketname);
X else
X if (unlink(sprintfs("in/%s", ipacketname)))
X log("$Could not unlink packet in/%s", ipacketname);
X
X state = Error;
X }
X break;
X case RecFiles:
X ok = recfiles();
X state = ChkFiles;
X break;
X case ChkFiles:
X if (ok)
X {
X log("Files received succesfully");
X (void) sleep((unsigned) 2);
X state = AllowPickup;
X }
X else
X {
X log("Files not received ok");
X state = Error;
X }
X break;
X case WaitClear:
X SetStart();
X while (state == WaitClear)
X if (Timeout(60))
X {
X log("Garbage on line");
X state = Error;
X break;
X }
X else if (readline(WAITCLEAR) == TIMEOUT)
X {
X debug(1, "Line is clear, send TSYNCH");
X sendline(TSYNCH);
X clear_input();
X state = SendMail;
X }
X break;
X case SendMail:
X ok = xtsend(sprintfs("out/%s", packetname), False);
X if (!ok && receive_retrys--)
X state = WaitClear;
X else
X state = CheckMail;
X
X break;
X case CheckMail:
X if (ok)
X {
X log("Mail sent successfully");
X log("Moving mail packet out/%s to %s", packetname,
X p = sprintfs("%s/%s.%s", SENTBUNDLE_DIR, packetname,
X baseit(sequencer(OPACKETSEQUENCE))));
X if (link(sprintfs("out/%s", packetname), p))
X log("$Could not link packet out/%s", packetname);
X else
X if (unlink(sprintfs("out/%s", packetname)))
X log("$Could not unlink packet out/%s",packetname);
X
X sequencer(OPACKETSEQUENCE);
X state = SendFiles;
X }
X else
X {
X log("Mail send failed");
X state = Error;
X }
X break;
X case SendFiles:
X ok = sendfiles();
X state = CheckFiles;
X break;
X case CheckFiles:
X if (ok)
X {
X log("Files sent successfully");
X state = TryPickup;
X }
X else
X {
X log("Files not send ok");
X state = Error;
X }
X break;
X case TryPickup:
X log("Send successful");
X if (pickup)
X {
X log("Starting mail pickup");
X state = WaitTsync;
X }
X else
X state = Done;
X break;
X }
X
X if (state == Error) {
X log("Conversation failed");
X } else {
X log("Conversation complete");
X }
X
X if (line >= 0) {
X (void) sleep((unsigned) 5);
X undial(line);
X }
X exit(0);
X /* NOTREACHED */
X}
SHAR_EOF
chmod 0644 fcall.c || echo "restore of fcall.c fails"
echo "x - extracting fio.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > fio.c &&
X#ifndef lint
Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%";
X#endif
X
X/* Routines for io for fidonet software.
X
X @(#)Copyright (c) 1987 by Teemu Torma
X
X Permission is given to distribute this program and alter this code as
X needed to adapt it to forign systems provided that this header is
X included and that the original author's name is preserved. */
X
X#include <stdio.h>
X#include <signal.h>
X#include <termio.h>
X#include <sys/types.h>
X#include "fnet.h"
X#include "fio.h"
X
X/* number of characters in input buffer */
Xint nchars = 0;
X
X#ifdef DEBUG
X/* This is for protocol debugging logs */
X#define DEBUG_STATE_READ 1
X#define DEBUG_STATE_WRITE 2
X#endif
X
X/* Signal trapper for readline. */
X
Xstatic int
Xtrap(sig)
X int sig;
X{
X (void) signal(sig, trap);
X return 0;
X}
X
X/* Read one character from line. We will do buffering up to BUFBIZ
X characters. TIMEOUT will be returned it readline timeouts */
X
Xint
Xreadline(timeout)
X int timeout;
X{
X int c;
X static unsigned char buffer[BUFSIZ];
X static int pos = 0;
X void (*alrm)();
X
X if (pos < nchars)
X /* there are characters in buffer */
X c = buffer[pos++];
X else
X {
X /* trap alarm signals and set timeout value */
X alrm = signal(SIGALRM, trap);
X (void) alarm((unsigned) timeout);
X
X /* read characters */
X nchars = read(line, (char *) buffer, BUFSIZ);
X#ifdef NEEDED
X if (!receiving_data) debug(10, "Read returned %d", nchars);
X#endif
X
X /* turn off alarm and return function value */
X (void) alarm((unsigned) 0);
X (void) signal(SIGALRM, alrm);
X
X /* if we got characters return first of them, otherwise return
X TIMEOUT */
X
X if (nchars <= 0)
X c = TIMEOUT;
X else
X {
X c = buffer[pos = 0];
X pos++;
X }
X }
X
X if (!receiving_data) debug(8, "< %02x", c);
X return c;
X}
X
X/* Flush line. Both terminal buffers and input buffer of readline will
X be flushed */
X
Xvoid
Xflush()
X{
X (void) ioctl(line, TCFLSH, 0);
X nchars = 0;
X}
X
X/* Send character c to line. This also clears readline's input buffer
X but not terminal buffers because it might takes too much time.
X Tue Nov 8 13:49:27 1988
X No more clearing buffer, as I try to make it sealink compatible.
X */
X
Xvoid
Xsendline(c)
X int c;
X{
X unsigned char cc = (c & 0377);
X
X debug(8, "> %02x", cc);
X (void) write(line, (char *) &cc, 1);
X#ifdef NO_SEALINK
X nchars = 0;
X#endif
X}
X
Xclear_input()
SHAR_EOF
echo "End of part 3"
echo "File fio.c is continued in part 4"
echo "4" > s2_seq_.tmp
exit 0