rsalz@uunet.uu.net (Rich Salz) (03/07/89)
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 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.