sampson@killer.UUCP (Steve Sampson) (05/08/88)
The last posting by Pete contained some bugs. The program was tested so far in slave mode. Still debugging master (connection problems). #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile README uucp.h uucico.c mail.c rmail.c uuxqt.c # Wrapped by sampson@killer on Sat May 7 21:42:47 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(1732 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# X# Makefile for Unix(tm) <-> UniFLEX(tm) Mail X# X# +O is for Optimize, +Q is for don't align on quad word boundry. X# X# You should be super-user when running this! X# X# This is for GIMIX Micro-20 68020 UniFLEX X# X XCFLAGS = +OQ X Xinstall: X move /usr/bin/mail /usr/bin/lmail X perms o-w u+rwx s+ /usr/bin/lmail X owner system /usr/bin/lmail X /etc/addusr uucp X crdir /gen/spooler/uucp X crdir /gen/spooler/uucp/.Log X owner uucp /gen/spooler/uucp /gen/spooler/uucp/.Log X move .Systems /gen/spooler/uucp X move .Devices /gen/spooler/uucp X move .Config /gen/spooler/uucp X owner uucp /gen/spooler/uucp/.Systems X owner uucp /gen/spooler/uucp/.Devices X owner uucp /gen/spooler/uucp/.Config X make uucico X make uuxqt X make mail X make rmail X# make strip X# make clean X echo "++\n++ Now edit the password file. Change the 'uucp' default\n" X echo "++ shell to 'uucico slave'\n++\n" X Xuucico: uucico.r X cc $(CFLAGS) uucico.r +o=/etc/uucico X owner uucp /etc/uucico X perms o-rwx u+rwx s+ /etc/uucico X Xuuxqt: uuxqt.r X cc $(CFLAGS) uuxqt.r +o=/etc/uuxqt X owner uucp /etc/uuxqt X perms o-rwx u+rwx s+ /etc/uuxqt X Xmail: mail.r X cc $(CFLAGS) mail.r +o=/usr/bin/mail X owner system /usr/bin/mail X perms o-w o+rx u+rwx /usr/bin/mail X Xrmail: rmail.r X cc $(CFLAGS) rmail.r +o=/usr/bin/rmail X owner uucp /usr/bin/rmail X perms o-w o+rx u+rwx s+ /usr/bin/rmail X X# X# Get rid of symbol table from binaries when debugging complete X# Xstrip: X strip /etc/uucico /etc/uuxqt /usr/bin/mail /usr/bin/rmail X X# X# Remove the object files from the work directory X# Xclean: X kill *.r X X# X# Dependencies X# Xuucico.r: uucico.c uucp.h Xuuxqt.r: uuxqt.c uucp.h Xmail.r: mail.c uucp.h Xrmail.r: rmail.c uucp.h X X# EOF X END_OF_Makefile echo shar: 1 control character may be missing from \"Makefile\" if test 1732 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(3781 characters\) sed "s/^X//" >README <<'END_OF_README' X X Unix to UniFLEX Mail Machine X Version 2.3, May 1988 X S. R. Sampson X X XThis archive of files is the basis for sending mail from a UniFLEX(tm) Xoperating system to the Unix(tm) operating system, using the uucp 'G' XProtocol. It is based on the DCP program by Richard Lamb as posted on XUsenet. X XThe files are: X XREADME This file Xuucp1.doc An information file on the G protocol Xuucp2.doc An information file on Unix UUCP XMakefile All encompassing build instructions Xuucp.h Header file for Operating System specifics Xmail.c Remote/Local mail front-end Xrmail.c Remote mail work file generator (simple bang mode) Xuucico.c G Protocol dialup machine Xuuxqt.c Work file execution machine X.Systems A sample dialing directory X.Devices A sample dialing port setup X.Config A sample configuration setup X X XI've been doing some minor testing on this code and would like others to Xplay around and improve it. It may be an useful start for other machines. X XPut the files in a source code directory and simply execute 'make'. XThis will almost completely build the mail machine. You will have to Xmanualy edit the /etc/log/password file to change the default shell to X'/etc/uucico'. Then run 'password uucp' and assign the account a password. XFollowing that, find a Unix machine to talk to and setup the .Config, X.Systems, and .Devices files for your serial ports. X XThe format for the .Devices file is: X X/dev/ttyxx Baudrate Type Status X XWhere: xx is the TTY number X Baudrate is the setting of the port X Type is MODEM or DIRECT X Status is FREE or USED X XYou initially create the file with everything FREE. I'm using a GMX Micro-20 Xand have it set up like so: X X/dev/tty03 1200 MODEM FREE X/dev/tty02 2400 DIRECT FREE X/dev/tty01 2400 DIRECT FREE X XThe format for the .Systems file is: X XMachine-Name Call-Time Baudrate Type Dialup-Sequence X XWher: Machine-name is 6 character significance X Call-Time is Any (Not implemented) X Baudrate is the machines (or your modems) maximum speed X Type is MODEM or DIRECT which is used when looking for a port X Dialup-Sequence is a send/receive sequence for logging on X XThe format for the .Config file is: X XUser-Name (The owner of the files (eg. 'uucp')) XMachine-Name (6 character significance (eg. 'test')) XError-Name (Who gets mail when problems are found (eg. 'root', 'system')) X X XThe uucp directory will contain all the work files to be sent and received. XThe log file will contain information written by the programs as they run. XThis information can be useful when debugging. Remember to purge this stuff Xwhen disk space starts filling up. X XThis UniFLEX version will automatically run in the slave mode upon login to Xthe uucp account. An example cron entry to run uucico in the master mode with Xa debug level 9 would look like so: X X0 * * * * /etc/uucico master 9 X XIf you have problems check on all permissions and ownership: X X/usr/bin/mail system rwxr-x X/usr/bin/lmail system rwxr-x SUID X/usr/bin/rmail uucp rwxr-x SUID X/etc/uucico uucp rwx--- SUID X/etc/uuxqt uucp rwx--- SUID X/gen/spooler/uucp uucp drwxr-x X/gen/spooler/uucp/.Log uucp drwx--- X/gen/spooler/uucp/.Systems uucp rw---- X/gen/spooler/uucp/.Devices uucp rw---- X/gen/spooler/uucp/.Config uucp rw---- X XSometimes the .Devices file may become corrupt. Make sure you view it for Xproblems such as no FREE device, or missplaced writes. X XTo send remote mail try something like: X Xmail myconnect!ihnp4!killer!sampson XThis is a test X[] <- Type a Control-D for EOF and mail will be spooled. X XWhere myconnect is the name of the Unix machine you dial up. X Xsampson@killer.UUCP ihnp4!killer!sampson XSteve Sampson, Box 45668 (AWACS), Tinker AFB, OK 73145 X X/* EOF */ X END_OF_README echo shar: 1 control character may be missing from \"README\" if test 3781 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f uucp.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"uucp.h\" else echo shar: Extracting \"uucp.h\" \(1045 characters\) sed "s/^X//" >uucp.h <<'END_OF_uucp.h' X/* X * uucp.h X * X * Header file for Unix(tm) to UniFLEX(tm) mail machine X */ X X/* X * Spool Directory X */ X X#define SPOOLDIR "/gen/spooler/uucp" X X/* X * Configuration file (in spooldir directory) format X * X * 1. user uucp X * 2. myname test X * 3. errorname system X */ X X#define CONFIG "/gen/spooler/uucp/.Config" X X/* X * Systems file (in spooldir directory) format X * X * 1. rmtname ihnp4 X * 2. cctime 2300-2359 X * 3. ttype MODEM X * 4. tspeed 2400 X * 5. loginseq xx gin: uucp\n sword: secret\n X */ X X#define SYSTEMS ".Systems" /* file with calling info */ X X/* X * Devices file (in spooldir directory) format X * X * 1. Name /dev/ttyxx X * 2. Max-Speed 75 - 19200 Baud X * 3. Type MODEM or DIRECT X * 4. Status USED or FREE X */ X X#define DEVICES ".Devices" /* file with terminal info */ X X X/* X * Error log files (relative to spooldir) X */ X X#define SYSLOG ".Log/uucico" /* error log file for uucico */ X#define XQTLOG ".Log/uuxqt" /* error log file for uuxqt */ X X/* EOF */ X END_OF_uucp.h echo shar: 1 control character may be missing from \"uucp.h\" if test 1045 -ne `wc -c <uucp.h`; then echo shar: \"uucp.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f uucico.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"uucico.c\" else echo shar: Extracting \"uucico.c\" \(41611 characters\) sed "s/^X//" >uucico.c <<'END_OF_uucico.c' X/* X * uucico.c X * X * Copy In - Copy Out 'G' Protocol X * X * 68020 UniFLEX(tm) Version 2.3, May 1988 X * X * Based on dcp.c Copyright (c) 1985, 1986, 1987 by Richard H. Lamb X * Changes are Public Domain by S. R. Sampson X * X * Called by 'cron', 'at', or 'uucp login'. X * X * Define DEBUG to prevent unlinking of C. files X */ X X/* Includes */ X X#include "uucp.h" X X#include <sys/signal.h> X#include <sys/sgtty.h> X#include <sys/modes.h> X#include <sys/dir.h> X#include <string.h> X#include <setjmp.h> X#include <errno.h> X#include <ctype.h> X#include <stdio.h> X#include <time.h> X#include <pwd.h> X X/* General purpose defines */ X X#define FALSE 0 X#define TRUE ~FALSE X X#define ERROR FALSE X#define OK TRUE X X#define MAXLINE 132 X#define MAXLOGTRY 4 X#define MSGTIME 20 X#define MAXTRY 5 X#define PKTTIME 10 X#define PKTSIZE 64 X#define PKTSIZ2 2 X#define HDRSIZE 6 X#define WNDSIZE 1 X#define DLE 16 X X/* Main Switching states */ X X#define INITIAL 000 X#define DEVICE 001 X#define LOGIN 002 X#define HANDSHAKE 003 X#define MASTER 004 X#define SLAVE 005 X#define END 006 X#define ABORT 007 X X/* Master/Slave states */ X X#define MS_INIT 020 X#define MS_SCANDIR 021 X#define MS_SEND 022 X#define MS_HANGUP 023 X#define MS_RECEIVE 024 X#define MS_ABORT 025 X#define MS_CHKWORK 026 X#define MS_END 027 X X/* Switching States */ X X#define SS_HEADER 030 X#define SS_DATA 031 X#define SS_EOF 032 X#define SS_END 033 X#define SS_ABORT 034 X X/* X * Control Packet Defines X * X * xxx name yyy X * X * 001 CLOSE n/a X * 002 RJ last correctly received sequence number X * 004 RR last correctly received sequence number X * 005 INITC window size X * 006 INITB data seqment size X * 007 INITA window size X */ X X#define DATA 000 /* The packet is data */ X#define CLOSE 001 /* CLOSE, Comunications complete */ X#define RJ 002 /* RJ Reject, detected an error */ X#define RR 004 /* RR Receiver ready, detected no errors */ X#define INITC 005 X#define INITB 006 X#define INITA 007 X X#define MODEM 000 /* TTY device types */ X#define DIRECT 001 X X/* Global Variables */ X Xstruct passwd *pw; X Xstruct { X int baudrate; X char *code; X} rates[] = { /* what I use the most */ X B300, "300", X B1200, "1200", X B2400, "2400", X B9600, "9600", X B19200, "19200", X 0, "" X}; X X#define DEFAULT_BAUD B1200 X Xstruct sgttyb NewSetting, X OldSetting; X Xlong Dpos; X XFILE *fd, X *fdC, X *log, X *input, X *output; X Xint type, X size, X pkrec, X pksent, X pknerr, X master, X debug_level; X Xchar InPacket[PKTSIZE], X OutPacket[PKTSIZE], X Filename[MAXLINE], X Cfilename[MAXNAMLEN+1], /* defined in dir.h */ X Loginseq[64], X Rmtname[8], X Device[16], X myname[8], X user[8], X speed[8]; X Xchar *rcverr[] = { X "Input Buffer Empty", X "Bad Header", X "Packet Timeout", X "Checksum Error", X "Wrong Packet Size" X}; X X/* Forward Declarations */ X Xunsigned checksum(); Xchar *mfgets(), *gtime(); Xjmp_buf env; X X/* X * Usage: X * uucico mode debug X * X * Where mode is 'master' or 'slave' X * And debug is an integer from 0 to 9 X * X * Defaults are slave mode and level 0 debug X */ X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X register int state; X X /* X * Read Configuration file X * X * The UniFLEX 2.3 C Compiler would not compile this X * correctly from an include file. X */ X X#undef CONFIG X#define CONFIG "/gen/spooler/uucp/.Config" X X if ((log = fopen(CONFIG, "r")) != (FILE *)NULL) { X mfgets(user, sizeof user, log); X mfgets(myname, sizeof myname, log); X fclose(log); X } X else X exit(1); X X /* X * Change to the spool directory X */ X X chdir(SPOOLDIR); X X /* X * Open the error log file X */ X X log = fopen(SYSLOG, "w"); X setbuf(log, (char *)NULL); /* log file should be unbuffered */ X X /* X * Setup defaults X */ X X master = FALSE; X debug_level = 0; X fd = fdC = (FILE *)NULL; X X /* X * Process the two command line arguments X * The first is "master" or "slave", the second X * is an integer debug level between 0 and 9. X */ X X if (argc > 1 && strcmp(argv[1], "master") == 0) X master = TRUE; X X if (argc > 2) { X debug_level = abs(atoi(argv[2])); X if (debug_level > 9) X debug_level = 9; X } X X state = INITIAL; X while (TRUE) { X switch(state) { X case INITIAL: X if (master) X state = GetSystem(); X else X state = HandShake(); X break; X case DEVICE: X state = GetTTY(); X if (state == ABORT) X fprintf(log,"Main(): No Device Available %s", X gtime()); X break; X case LOGIN: X state = Login(); X break; X case HANDSHAKE: X state = HandShake(); X break; X case MASTER: X state = Master(); X break; X case SLAVE: X state = Slave(); X break; X case END: X state = SendOO(); X } X X if (state == ABORT) X break; X } X X if (master) X CloseTTY(); X X fclose(log); X X /* go execute any transfered work files */ X X execl("/etc/uuxqt", "uuxqt", (char *)NULL); X} X X X/*------------------------- X * uucico Subroutines X *------------------------- X */ X XGetReply(string) Xregister char *string; X{ X register int i, len; X char c[MAXLINE]; X X len = strlen(string); X c[len--] = 0; X X while (strcmp(string, c) != 0) { X for (i = 0; i < len; i++) X c[i] = c[i+1]; X X if (ReadTTY(&c[i], 1, MSGTIME) == 0) { X fprintf(log,"GetReply(): Input timed out %s", gtime()); X fprintf(log," Wanted %s got %s\n", string, c); X return ERROR; X } X X toascii(c[i]); X } X X return OK; X} X X X/* X * mfgets (modified fgets) X * X * Same as fgets() only this version deletes '\n' X */ X Xchar *mfgets(s, n, iop) Xregister char *s; Xregister int n; Xregister FILE *iop; X{ X register int c; X register char *cs; X X cs = s; X while (--n > 0 && (c = getc(iop)) != EOF) { X if (c == 0x0D) { X *cs = '\0'; X break; X } X else X *cs++ = c; X } X X return((c == EOF && cs == s) ? (char *)NULL : s); X} X X Xchar *gtime() X{ X long value; X X time(&value); X return(ctime(&value)); X} X X XCheckName() X{ X register FILE *fdsys; X char line[MAXLINE], tmp[16]; X X if ((fdsys = fopen(SYSTEMS, "r")) == NULL) { X fprintf(log,"CheckName(): Can't open %s %s", SYSTEMS, gtime()); X return ERROR; X } X X while (mfgets(line, sizeof line, fdsys) != (char *)NULL) { X sscanf(line, "%s ", tmp); X X if (strncmp(Rmtname, tmp, 6) == 0) { X fclose(fdsys); X return OK; X } X } X X fclose(fdsys); X fprintf(log, "CheckName(): Unknown system %s attempted login %s", X Rmtname, gtime()); X return ERROR; X} X X XCheckTime(time) Xregister char *time; X{ X return OK; X} X X X/*------------------------------------------------- X * uucico High Level State Switching routines X *------------------------------------------------- X */ X XGetSystem() X{ X register FILE *fdsys; X char line[MAXLINE], ttype[8], cctime[16]; X X if ((fdsys = fopen(SYSTEMS, "r")) == NULL) { X fprintf(log,"GetSystem(): Can't open %s %s", SYSTEMS, gtime()); X return ABORT; X } X X do { X if (fgets(line, sizeof line, fdsys) == (char *)NULL) { X fclose(fdsys); X return ABORT; /* no more systems */ X } X X sscanf(line, "%s %s %s %s %s", X Rmtname, cctime, ttype, speed, Loginseq); X type = strcmp(ttype, "MODEM") ? DIRECT : MODEM; X } while ( !strcmp(cctime, "Slave") || !CheckTime(cctime) ); X X fclose(fdsys); X X return DEVICE; /* go get a device and login */ X} X X X/* X * Find the next device of the type and speed requested X * in the DEVICES file X */ X XGetTTY() X{ X register FILE *fdtty; X int Type, Used; X char line[MAXLINE], Types[8], Useds[8], Bauds[8]; X X if ((fdtty = fopen(DEVICES, "r+")) == (FILE *)NULL) { X fprintf(log,"GetTTY(): Can't open %s %s", DEVICES, gtime()); X return ABORT; X } X X do { X if (mfgets(line, sizeof line, fdtty) == (char *)NULL) { X fprintf(log,"GetTTY(): No devices available %s", X gtime()); X fclose(fdtty); X return ABORT; X } X X sscanf(line, "%s %s %s %s", Device, Bauds, Types, Useds); X Type = strcmp(Types, "MODEM") ? DIRECT : MODEM; X Used = strcmp(Useds, "FREE"); X } while (Type != type || strcmp(Bauds, speed) || Used); X X /* X * This is a hack until I figure out what I'm doing... X */ X X fseek(fdtty, -5L, 1); X Dpos = ftell(fdtty); /* Dpos is used in CloseTTY() */ X fputs("USED", fdtty); X fclose(fdtty); X X if (OpenTTY() == ERROR) X return ABORT; X X return LOGIN; X} X X XLogin() X{ X register int k, j, trys; X register char *last; X char buffer[MAXLINE]; X int flag; X X j = k = 0; X X /* X * First move everything to 'buffer', changing text X * newlines to binary X */ X X while(Loginseq[j] != '\0') { X if (Loginseq[j] == '\\' && Loginseq[j+1] == 'n') { X buffer[k++] = '\n'; X j += 2; X continue; X } X X buffer[k++] = Loginseq[j++]; X } X X buffer[k] = j = 0; X flag = TRUE; /* start by sending */ X X while (buffer[j]) { X k = j; X X while (buffer[k] != '-' && buffer[k] != '\0') X k++; X X if (buffer[k] == '\0') X buffer[k+1] = '\0'; X X buffer[k] = '\0'; X X if (flag) { X last = &buffer[j]; X WriteString(&buffer[j], FALSE); X flag = FALSE; X } else { X trys = 1; X while (GetReply(&buffer[j]) == ERROR) { X if (trys >= MAXLOGTRY) { X fprintf(log,"Login(): Failed login on remote %s", X gtime()); X return ABORT; X } X X /* try resending the last sequence */ X X trys++; X WriteString(last, FALSE); X } X X flag = TRUE; X } X X j = k + 1; X } X X return HANDSHAKE; X} X X XHandShake() X{ X char t1[16], t2[16]; X X if (master) { X if (ReadString(InPacket, MSGTIME) == 0) X return ABORT; X X if (strncmp(InPacket + 6, Rmtname, 6)) { X fprintf(log,"HandShake(): System name match error %s", X gtime()); X return ABORT; X } X X sprintf(OutPacket, "S%.6s", myname); X WriteString(OutPacket, TRUE); X X if (ReadString(InPacket, MSGTIME) == 0) X return ABORT; X X if (strncmp(InPacket + 1, "OK", 2)) { Xhserr1: fprintf(log,"HandShake(): Don't like name %s",gtime()); X return ABORT; X } X X if (ReadString(InPacket, MSGTIME) == 0) X return ABORT; X X if (InPacket[0] != 'P' && strchr(InPacket[1], 'g') == 0) { X WriteString("UN", TRUE); Xhserr2: fprintf(log,"HandShake(): G Protocol not available %s", X gtime()); X return ABORT; X } X X WriteString("Ug", TRUE); X return MASTER; X } else { X input = stdin; X output = stdout; X X SetTTY(fileno(input), 0); X SetTTY(fileno(output), 0); X X sprintf(OutPacket, "Shere=%.6s", myname); X WriteString(OutPacket, TRUE); X X if (ReadString(InPacket, MSGTIME) == 0) X return ABORT; X X sscanf(InPacket, "S%s %s %s", Rmtname, t1, t2); X sscanf(t2, "-x%d", &debug_level); X X if (CheckName() == ERROR) X goto hserr1; X X WriteString("ROK", TRUE); X WriteString("Pg", TRUE); X X if (ReadString(InPacket, MSGTIME) == 0) X return ABORT; X X if (strcmp(InPacket, "Ug") != 0) X goto hserr2; X X return SLAVE; X } X} X X XSendOO() X{ X register int i; X char msg[MAXLINE]; X X msg[1] = 0; X for (i = 0; ((msg[1] != 'O') && (i < MAXTRY)); i++) { X WriteString("OOOOOO", TRUE); X X if (ReadString(msg, MSGTIME) == 0) X break; X } X X if (i == MAXTRY) { X fprintf(log, "SendOO(): Can't \"Over and Out\" with %s %s", X Rmtname, gtime()); X return ABORT; X } X X WriteString("OOOOOO", TRUE); /* one last time for mama */ X X if (master) X return INITIAL; X else X return ABORT; X} X X X/*--------------------------------------------------- X * uucico Medium Level State Switching routines X *--------------------------------------------------- X */ X XMaster() X{ X register int state; X X state = MS_INIT; X X while (TRUE) { X switch (state) { X case MS_INIT: X state = SendInit(); X break; X case MS_SCANDIR: X state = ScanDirectory(); X break; X case MS_SEND: X state = Send(); X break; X case MS_HANGUP: X state = MasterHangup(); X break; X case MS_RECEIVE: X state = Receive(); X break; X case MS_ABORT: X return ABORT; X case MS_END: X return END; X } X } X} X X XSlave() X{ X register int state; X X state = MS_INIT; X X while (TRUE) { X switch (state) { X case MS_INIT: X state = RcvInit(); X break; X case MS_RECEIVE: X state = Receive(); X break; X case MS_CHKWORK: X state = CheckForWork(); X break; X case MS_HANGUP: X state = SlaveHangup(); X break; X case MS_SCANDIR: X state = ScanDirectory(); X break; X case MS_SEND: X state = Send(); X break; X case MS_ABORT: X return ABORT; X case MS_END: X return END; X } X } X} X X X/*------------------------------------------------ X * uucico Low Level State Switching routines X *------------------------------------------------ X */ X XSend() X{ X register int state; X X state = SS_HEADER; X X while (TRUE) { /* Do this as long as necessary */ X switch (state) { X case SS_HEADER: X if (fd != (FILE *)NULL) { X fprintf(log, X "Send(): File already open in SS_HEADER %s", X gtime()); X state = SS_ABORT; X } X else X state = SendFileHeader(); X break; X case SS_DATA: X state = SendData(); X break; X case SS_EOF: X state = SendEof(); X break; X case SS_END: X fclose(fdC); X#ifndef DEBUG X unlink(Cfilename); X#endif X fdC = (FILE *)NULL; X return MS_SCANDIR; X case SS_ABORT: X return MS_ABORT; X } X } X} X X XReceive() X{ X register int state; X X state = SS_HEADER; X X while (TRUE) { X switch (state) { X case SS_HEADER: X state = RcvFileHeader(); X break; X case SS_DATA: X state = RcvData(); X break; X case SS_ABORT: X return MS_ABORT; X case SS_END: X return MS_CHKWORK; X } X } X} X X XMasterHangup() X{ X int len; X X strcpy(OutPacket, "H"); X if (SendPacket(OutPacket, PKTSIZE, TRUE) == ERROR) X return ABORT; X X if (RcvPacket(InPacket, &len) == ERROR) X return ABORT; X X if (strncmp(InPacket, "HN", 2) != 0) X return MS_RECEIVE; X X return MS_END; X} X X XSlaveHangup() X{ X strcpy(OutPacket, "HY"); X SendPacket(OutPacket, PKTSIZE, 2); /* don't wait for Acknowledge */ X ClosePacket(); X X return MS_END; X} X X XGetFile(header) Xregister char *header; X{ X register int i; X char line[MAXLINE]; X X if (mfgets(line, sizeof line, fdC) == (char *)NULL) { X fprintf(log,"GetFile(): Unexpected End Of File %s", gtime()); X return ERROR; X } X X sscanf(&line[2], "%s ", Filename); X X for (i = 0; line[i]; i++) X if (strncmp(&line[i], "066", 3) == 0) X break; X X line[i+4] = '\0'; X strcpy(header, line); /* now contains the whole line up past 066x */ X X return OK; X} X X XCheckForWork() X{ X register int c; X X c = ScanDirectory(); X if (c == MS_ABORT) X return MS_ABORT; X X if (c == MS_SEND) { X strcpy(OutPacket, "HN"); X if (SendPacket(OutPacket, PKTSIZE, TRUE) == ERROR) X return MS_ABORT; X else X return MS_SEND; X } X else /* c == MS_END */ X return MS_HANGUP; X} X X XScanDirectory() X{ X register DIR *dir; X register struct direct *pdir; X X strcpy(Cfilename, "C."); X strncat(Cfilename, Rmtname, 6); X X if ((dir = opendir(SPOOLDIR)) == (DIR *)NULL) { X fprintf(log, "ScanDirectory(): Could not open %s %s", X SPOOLDIR, gtime()); X return MS_ABORT; X } X X while ((pdir = readdir(dir)) != (struct direct *)NULL) { X if (strncmp(pdir->d_name, Cfilename, MAXNAMLEN) == 0) { X strncpy(Cfilename, pdir->d_name,(int)(pdir->d_namlen)); X closedir(dir); X X if (fdC == (FILE *)NULL) { X if ((fdC = fopen(Cfilename, "r")) == (FILE *)NULL) { X fprintf(log, X "ScanDirectory(): Could not open %s %s", X Cfilename, gtime()); X return MS_ABORT; X } X } else { X fprintf(log, X "ScanDirectory(): File already open %s", X gtime()); X return MS_ABORT; X } X X return MS_SEND; X } X } X X closedir(dir); X return MS_END; X} X X X/*--------------------------------------------------- X * uucico G protocol High Level packet routines X *--------------------------------------------------- X */ X XSendInit() X{ X if (OpenPacket() == ERROR) X return MS_ABORT; X else X return MS_SEND; X} X X XRcvInit() X{ X if (OpenPacket() == ERROR) X return MS_ABORT; X else X return MS_RECEIVE; X} X X XSendFileHeader() X{ X int len; X char header[MAXLINE]; X X /* get next file from current work */ X X if (GetFile(header) == ERROR) X return SS_END; /* end sending session */ X X if ((fd = fopen(Filename, "r")) == NULL) { X fprintf(log, "SendFileHeader(): Can't open %s %s", Filename, X gtime()); X return SS_ABORT; X } X X /* X * Send the header X */ X X if (SendPacket(header, PKTSIZE, TRUE) == ERROR) X return SS_ABORT; X X /* X * Get the reply from remote X */ X X if (RcvPacket(InPacket, &len) == ERROR) X return SS_ABORT; X X /* X * Abort if remote doesn't say yes X */ X X if (strncmp(InPacket, "SY", 2) != 0) { X fprintf(log,"SendFileHeader(): Remote refused request %s", X gtime()); X return SS_ABORT; X } X X /* X * Scoop some poop X */ X X size = fread(OutPacket, sizeof(char), PKTSIZE, fd); X X /* X * Change to DATA state X */ X X return SS_DATA; X} X X XRcvFileHeader() X{ X int len; X char fromfile[MAXLINE]; X X if (RcvPacket(InPacket, &len) == ERROR) X return SS_ABORT; X X if (InPacket[0] == 'H') X return SS_END; X X sscanf(&InPacket[2], "%s %s ", fromfile, Filename); X X if ((fd = fopen(Filename, "w")) == (FILE *)NULL) { X fprintf(log, "RcvFileHeader(): Can't create %s %s", Filename, X gtime()); X strcpy(OutPacket, "SN4"); X if (SendPacket(OutPacket, PKTSIZE, TRUE) == ERROR) X return SS_ABORT; X else X return SS_HEADER; X } X X X strcpy(OutPacket, "SY"); X if (SendPacket(OutPacket, PKTSIZE, TRUE) == ERROR) X return SS_ABORT; X X /* X * Change to DATA state X */ X X return SS_DATA; X} X X XSendData() X{ X if (SendPacket(OutPacket, size, FALSE) == ERROR) X return SS_ABORT; X X /* Get data from file */ X X if ((size = fread(OutPacket, sizeof(char), PKTSIZE, fd)) < 1) X return SS_EOF; X X return SS_DATA; X} X X XSendEof() X{ X int len; X X OutPacket[0] = '\0'; X if (SendPacket(OutPacket, 0, FALSE) == ERROR) X return SS_ABORT; X X if (RcvPacket(InPacket, &len) == ERROR) X return SS_ABORT; /* rec CY or CN */ X X fclose(fd); X fd = (FILE *)NULL; X X if (strncmp(InPacket, "CY", 2) != 0) { X fprintf(log, "SendEof(): Rcvd %s expected CY %s", X InPacket, gtime()); X return SS_ABORT; X } X X return SS_HEADER; /* go get the next file to send */ X} X X XRcvData() X{ X int len; X X if (RcvPacket(InPacket, &len) == ERROR) X return SS_ABORT; X X if (len == 0) { X fclose(fd); X fd = (FILE *)NULL; X X strcpy(OutPacket, "CY"); X if (SendPacket(OutPacket, PKTSIZE, TRUE) == ERROR) X return SS_ABORT; X X return SS_HEADER; X } X X fwrite(InPacket, sizeof(char), len, fd); X X return SS_DATA; X} X X X/*----------------------------------------------------- X * uucico G protocol Medium Level packet routines X *----------------------------------------------------- X */ X XClosePacket() X{ X char tmp[PKTSIZE]; X X spack(CLOSE, 0, 0, 0, tmp); X spack(CLOSE, 0, 0, 0, tmp); X} X X X/* X * INITA - INITC Handshake X */ X XOpenPacket() X{ X register int i, j; X unsigned int npkrec, npksent, len; X char tmp[PKTSIZE]; X X pkrec = 0; X pksent = 1; X pknerr = 0; X X for (j = INITA; j >= INITC; j--) { X for (i = 0; i < MAXTRY; i++) { X spack(j, 0, 0, 0, tmp); X if (rpack(&npkrec, &npksent, &len, tmp) == j) X goto nextinit; X } X X fprintf(log,"OpenPacket(): Could not INIT Handshake %s", X gtime()); X return ERROR; Xnextinit:; X } X X return OK; X} X X XRcvPacket(data, len) Xregister char *data; Xregister int *len; X{ X register int i; X unsigned int npkrec, npksent, nlen, nakflg, val; X char tmp[PKTSIZE]; X X nakflg = FALSE; X X for (i = 0; i < MAXTRY; i++) { X switch (val = rpack(&npkrec, &npksent, &nlen, data)) { X case DATA: X pkrec = (pkrec + 1) % 8; X if (npksent != pkrec) X break; X X *len = nlen; X X if (nakflg) X spack(RJ, pkrec, 0, 0, tmp); X else X spack(RR, pkrec, 0, 0, tmp); X X return OK; X case CLOSE: X fprintf(log,"RcvPacket(): Rcvd CLOSE from remote %s", X gtime()); X return ERROR; X default: X nakflg = TRUE; X fprintf(log, X "RcvPacket(): rpack() returned %s %s", X rcverr[abs(val) - 1], gtime()); X } X } X X if (++pknerr >= MAXTRY) { X fprintf(log,"RcvPacket(): Too many packet errors %s", X gtime()); X return ERROR; X } X X return OK; X} X X X/* X * flg = 2 Just send the packet with no wait for ACK. X * flg = TRUE Zero out the unused part of the buffer (for "msg" pkts). X * flg = FALSE Normal data X */ X XSendPacket(data, len, flg) Xregister char *data; Xregister int len, flg; X{ X register int i; X unsigned int nlen, npkrec, npksent, val; X char tmp[PKTSIZE]; X X /* X * If Flag set then NULL fill to PKTSIZE X */ X X if (flg) X for (i = strlen(data); i < PKTSIZE; i++) X data[i] = '\0'; X X for (i = 0; i < MAXTRY; i++) { X spack(DATA, pkrec, pksent, len, data); X X if (flg == 2) X return OK; X X switch (val = rpack(&npkrec, &npksent, &nlen, tmp)) { X case RR: X case RJ: X if (npkrec != pksent) X break; /* Retry on wrong Packet Numbers */ X X pksent = (pksent + 1) % 8; X return OK; X case CLOSE: X fprintf(log,"SendPacket(): Rcvd CLOSE from remote %s", X gtime()); X return ERROR; X default: X fprintf(log,"SendPacket(): rpack() returned %s %s", rcverr[abs(val) - 1], gtime()); X } X } X X if (++pknerr >= MAXTRY) { X fprintf(log,"SendPacket(): Too many packet errors %s", X gtime()); X return ERROR; X } X X return OK; X} X X X/* X * Send a Packet X */ X Xspack(type, npkrec, npksent, len, packet) Xunsigned type, npkrec, npksent, len; Xchar *packet; X{ X unsigned int c, check, i; X char pkt[HDRSIZE]; X X if (len == 0) X *packet = '\0'; X X pkt[0] = DLE; X pkt[4] = (type << 3) & 0xFF; X type &= 0x07; X X switch (type) { X case CLOSE: X break; X case RR: X case RJ: X pkt[4] |= npkrec; X break; X case INITA: X case INITC: X pkt[4] |= WNDSIZE; /* window size */ X break; X case INITB: X pkt[4] |= 1; /* segment size (1 = 64) */ X break; X case DATA: X pkt[4] = (0x80 | (npksent << 3) | npkrec) & 0xFF; X X /* X * If packet length is less than 64 X * then first byte needs to indicate the X * difference. So shift everything right X * and put the difference in first byte X */ X X if (c = PKTSIZE - len) { X pkt[4] = (pkt[4] | 0x40) & 0xFF; X for (i = PKTSIZE - 1; i > 0; i--) X packet[i] = packet[i - 1]; X X packet[0] = c & 0xFF; X } X } X X if (type != DATA) { X pkt[1] = 9; /* control packet, size = 0 */ X check = pkt[4] & 0xFF; X } else { X pkt[1] = PKTSIZ2; /* data packet, size = 64 */ X check = checksum(packet, PKTSIZE) & 0xFFFF; X check = (check ^ (pkt[4] & 0xFF)) & 0xFFFF; X } X X check = (0xAAAA - check) & 0xFFFF; X pkt[2] = check & 0xFF; X pkt[3] = (check >> 8) & 0xFF; X pkt[5] = (pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4]) & 0xFF; X X WriteTTY(pkt, HDRSIZE); /* header is 6-bytes long */ X X if (pkt[1] != 9) X WriteTTY(packet, PKTSIZE); /* data is always 64 bytes long */ X} X X X/* X * Read Packet X * X * Returns: X * +n Okey-Dokey; X * -1 Input buffer empty; X * -2 Bad header; X * -3 Lost packet timeout; X * -4 Checksum error; X * -5 Wrong packet size X */ X Xrpack(npkrec, npksent, len, packet) Xregister unsigned int *npkrec, *npksent, *len; Xregister char *packet; X{ X register unsigned type, check, checkchk; X register int i; X char c, pkt[HDRSIZE]; X X c = 0; X while ((c & 0x7F) != DLE) X if (ReadTTY(&c, 1, PKTTIME) == 0) X return(-1); /* input buffer empty */ X X if (ReadTTY(&pkt[1], HDRSIZE - 1, PKTTIME) < (HDRSIZE - 1)) X return(-1); /* input buffer empty */ X X /* header is 6-bytes long */ X X if ((pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4] ^ pkt[5]) & 0xFF) X return(-2); /* bad header */ X X if ((pkt[1] & 0x7F) == 9) { /* control packet */ X *len = 0; X type = ((unsigned)pkt[4] >> 3) & 0x7F; X *npkrec = pkt[4] & 0x07; X *npksent = *packet = check = checkchk = 0; X } X else { /* data packet */ X if (pkt[1] != PKTSIZ2) X return(-5); /* can't handle other than size 64 */ X X type = DATA; X c = pkt[4] & 0x3F; X *npksent = ((unsigned)c >> 3) & 0x07; X *npkrec = c & 0x07; X X if (ReadTTY(packet, PKTSIZE, PKTTIME) < PKTSIZE) X return(-3); /* packet timeout */ X X /* 64 byte packets even if partial */ X X check = ((pkt[3] << 8) | (pkt[2] & 0xFF)) & 0xFFFF; X checkchk = checksum(packet, PKTSIZE) & 0xFFFF; X checkchk = 0xAAAA-(checkchk^((pkt[4] | 0x80) & 0xFF)) & 0xFFFF; X X if (checkchk != check) X return(-4); X X /* X * See if a "short" packet was received X * If so, delete the size difference in first byte X */ X X if (pkt[4] & 0x40) { X *len = PKTSIZE - *packet; X for (i = 0; i < *len; i++) X packet[i] = packet[i + 1]; X } X else X *len = PKTSIZE; X X packet[*len] = '\0'; X } X X return type; X} X X Xunsigned checksum(data, n) Xregister char *data; Xregister int n; X{ X register unsigned short t; X register short sum, x; X X sum = -1; X x = 0; X X do { X if (sum < 0) { X sum <<= 1; X sum++; X } X else X sum <<= 1; X X t = sum; X sum += (unsigned short)(*data++ & 0xFF); X x += sum ^ n; X X if ((unsigned short)sum <= t) X sum ^= x; X X } while (--n > 0); X X return (unsigned)sum; X} X X X/*-------------------------------------------------- X * uucico G protocol Low Level packet routines X *-------------------------------------------------- X */ X XWriteString(msg, syn) Xregister char *msg; Xregister int syn; X{ X if (syn) X WriteTTY("\020", 1); X X WriteTTY(msg, strlen(msg)); X X if (syn) X WriteTTY("", 1); X} X X XReadString(msg, seconds) Xregister char *msg; Xregister int seconds; X{ X register int i; X char c; X X do { X if (ReadTTY(&c, 1, seconds) == 0) { Xrperr: fprintf(log, "ReadString(): Input timed out %s", X gtime()); X return 0; X } X } while ((c = toascii(c)) != DLE); X X for (i = 0; i < MAXLINE && c ; i++) { X if (ReadTTY(&c, 1, seconds) == 0) X goto rperr; X X if ((c = toascii(c)) == '\n') X msg[i] = c = '\0'; X else X msg[i] = c; X } X X return(strlen(msg)); X} X X X/*------------------------------ X * uucico TTY I/O routines X *------------------------------ X */ X XReadTTY(data, len, seconds) Xregister char *data; Xregister int len, seconds; X{ X register int count; X int ClkInt(); X X if (setjmp(env)) X return 0; X X signal(SIGALRM, ClkInt); /* execute ClkInt() if alarm */ X alarm(seconds); /* goes off */ X X if ((count = fread(data, sizeof(char), len, input)) < 1) { X alarm(0); X return 0; X } X X alarm(0); X return count; X} X X XWriteTTY(data, len) Xregister char *data; Xregister int len; X{ X fwrite(data, sizeof(char), len, output); X} X X XClkInt() X{ X longjmp(env, 1); X} X X XOpenTTY() X{ X register int i, baud; X X i = 0; X baud = DEFAULT_BAUD; X X /* X * Check baud rate entry against table X * change 'baud' to new code X */ X X do { X if (strcmp(speed, rates[i].code) == 0) { X baud = rates[i].baudrate; X break; X } X } while (rates[++i].baudrate != 0); X X input = fopen(Device, "r"); X output = fopen(Device, "w"); X X if (input == NULL || output == NULL) { X fprintf(log, "OpenTTY(): Failure opening device %s %s", X Device, gtime()); X return ERROR; X } X X SetTTY(fileno(input), baud); X SetTTY(fileno(output), baud); X X return OK; X} X X XCloseTTY() X{ X register FILE *fdtty; X X stty(fileno(input), &OldSetting); X stty(fileno(output), &OldSetting); X X fclose(input); X fclose(output); X X if ((fdtty = fopen(DEVICES, "r+")) == (FILE *)NULL) { X fprintf(log, "CloseTTY(): Can't re-open %s %s", DEVICES, gtime()); X return; X } X X fseek(fdtty, Dpos, 0); /* Dpos is computed in GetTTY() */ X fputs("FREE", fdtty); X fclose(fdtty); X} X X XSetTTY(tty, baud) Xregister int tty, baud; X{ X gtty(tty, &OldSetting); /* get the TTY settings */ X gtty(tty, &NewSetting); /* copy old settings to new */ X X NewSetting.sg_speed = D8S1NONE; /* 8 Bits No Parity One Stop */ X NewSetting.sg_flag = RAW & ~ECHO; /* no echo and no processing */ X X if (baud) /* 0 Means Slave Mode */ X NewSetting.sg_prot = baud & 0x0F; /* slap in the given baud */ X X stty(tty, &NewSetting); /* set the TTY new settings */ X} X X/* EOF */ X END_OF_uucico.c echo shar: 1 control character may be missing from \"uucico.c\" if test 41611 -ne `wc -c <uucico.c`; then echo shar: \"uucico.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f mail.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"mail.c\" else echo shar: Extracting \"mail.c\" \(3462 characters\) sed "s/^X//" >mail.c <<'END_OF_mail.c' X/* X * mail.c X * X * UniFLEX(tm) Version 2.3, May 1988 X * Public Domain by S. R. Sampson X * X * This program checks for local or remote indication X * and sends mail using rmail or lmail. X */ X X/* Defines */ X X#define FALSE 0 X#define TRUE ~FALSE X X/* Includes */ X X#include "uucp.h" X X#include <string.h> X#include <stdio.h> X#include <errno.h> X#include <time.h> X#include <pwd.h> X X/* Globals */ X Xlong stamp; Xchar dfile[140], from[16], tmp[140]; Xint remote; X X/* The program */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X register FILE *fdfile; X register char *ptr; X struct passwd *name; X X if (argc == 1) { X execl("/usr/bin/lmail", "mail", (char *)NULL); X exit(-1); X } X X strcpy(dfile, "/tmp/msXXXXXX"); X mktemp(dfile); X X if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { X perror("mail 1"); X exit(-1); X } X X /* X * If address has a '!' character flag address as remote X * else local. X */ X X if ((ptr = strchr(argv[1], '!')) == (char *)NULL) X remote = FALSE; X else X remote = TRUE; X X /* X * Find out who we are and generate the required X * "From name date" line X */ X X if (remote) { X name = getpwuid(getuid()); X strcpy(from, name->pw_name); X endpwent(); X X time(&stamp); X sprintf(tmp, "From %s %s", from, ctime(&stamp)); X X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X } X X /* X * Copy stdin to a /tmp file X */ X X for (;;) { X if (fgets(tmp, sizeof tmp, stdin) == (char *)NULL) X break; X X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X } X X fflush(fdfile); X fclose(fdfile); X X if (remote) { X uufix(dfile); /* Change UniFLEX CR to Unix LF */ X sprintf(tmp, "rmail %s <%s >/dev/null", argv[1], dfile); X } else X sprintf(tmp, "lmail %s <%s >/dev/null", argv[1], dfile); X X if (system(tmp) != 0) { X fprintf(stderr, "mail: Fatal - Could not exec() mailer\n"); X exit(-1); X } X X#ifndef DEBUG X unlink(dfile); X#endif X} X X Xuufix(file) Xregister char *file; X{ X register FILE *fd, *temp; X register int scoop; X char name[32]; X X strcpy(name, "/tmp/uufixXXXXXX"); X mktemp(name); X X if ((fd = fopen(file, "r")) == (FILE *)NULL) { X fprintf(stderr, "mail: File '%s' not found\n", file); X exit(-1); X } X X if ((temp = fopen(name, "w")) == (FILE *)NULL) { X fprintf(stderr, "mail: Unable to open temp file '%s'\n", name); X exit(-1); X } X X while ((scoop = getc(fd)) != EOF) { X if (scoop == 0x0D) X putc(0x0A, temp); X else X putc(scoop, temp); X } X X fflush(temp); X fclose(temp); X fclose(fd); X X unlink(file); X link(name, file); X unlink(name); X} X X/* EOF */ X END_OF_mail.c echo shar: 1 control character may be missing from \"mail.c\" if test 3462 -ne `wc -c <mail.c`; then echo shar: \"mail.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f rmail.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"rmail.c\" else echo shar: Extracting \"rmail.c\" \(14828 characters\) sed "s/^X//" >rmail.c <<'END_OF_rmail.c' X/* X * rmail.c X * X * Mini Remote Mail Handler X * X * Version 2.3, Public Domain May 1988 X * X * This program is executed by either 'mail' or 'uuxqt'. X * X * The standard UniFLEX(tm) mail doesn't handle remote addresses X * so I made a new program called mail and renamed the old X * mail to lmail. Now if the new mail finds a remote address X * it calls rmail, else lmail. X * X * UniFLEX has a different End of Line convention than Unix X * does. Therefore rmail will need to fix the transfered X * files before sending to mail. X * X * Usage: X * rmail remotesystem!remoteuser myname (test myname) X * rmail remotesystem!remoteuser (.Config myname) X * rmail localuser X * X * Limitation: X * Will only do bang '!' addresses. X */ X X/* Defines */ X X#define FALSE 0 X#define TRUE ~FALSE X X/* Includes */ X X#include "uucp.h" X X#include <sys/modes.h> X#include <sys/dir.h> X#include <string.h> X#include <stdio.h> X#include <errno.h> X#include <time.h> X#include <pwd.h> X X/* Globals */ X Xextern char *tzname[2]; /* contains two strings CDT or CST */ Xextern int daylight; /* array index for above */ X Xstruct passwd *names; X Xlong stamp; Xint remote; Xchar bfile[32], cfile[32], dfile[32], xfile[32]; Xchar rmtname[16], rmtuser[128], myname[16], user[16]; Xchar datetime[48], ofrom[256], from[256], tmp[256], sys[32]; Xchar errorname[8], *p, *ptr, *mfgets(), *fgets(); X XFILE *fbfile, *fcfile, *fdfile; X X/* The program */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X if (argc < 2 || argc > 3) { X fprintf(stderr, "Usage: rmail [remote!]user [testname]\n"); X exit(-1); X } X X /* X * Read Configuration file X * X * The UniFLEX 2.3 C Compiler would not compile this X * correctly from an include file. X */ X X#undef CONFIG X#define CONFIG "/gen/spooler/uucp/.Config" X X if ((fcfile = fopen(CONFIG, "r")) != (FILE *)NULL) { X mfgets(user, sizeof user, fcfile); X mfgets(myname, sizeof myname, fcfile); X mfgets(errorname, sizeof errorname, fcfile); X fclose(fcfile); X } X else X exit(-1); X X if (argc == 3) /* useful for debuging */ X strcpy(myname, argv[2]); X X /* X * If address has a '!' character flag address as remote X * else local. X */ X X if ((ptr = strchr(argv[1], '!')) == (char *)NULL) X remote = FALSE; X else { X *ptr = '\0'; X remote = TRUE; X } X X /* X * Change file creation mask to rwx------ X */ X X umask(S_IOREAD | S_IOWRITE | S_IOEXEC); X X /* X * Change to working directory X */ X X chdir(SPOOLDIR); X X /* X * Calculate the time X */ X X time(&stamp); X strcpy(datetime, ctime(&stamp)); X datetime[strlen(datetime) - 1] = '\0'; X strcat(datetime, " "); X strcat(datetime, tzname[daylight]); /* add in CDT or CST */ X X /* X * See if this mail was generated locally X * or came from somewhere else. Local mail X * has a "From x y" header, remote has a X * "From x y remote from z" header. X */ X X strcpy(from, ""); X strcpy(ofrom, ""); X X fgets(tmp, sizeof tmp, stdin); /* get a line from stdin */ X X /* X * First line should be a From line. Our goal is to change from this: X * X * From a!b (date) remote from c X * X * To this: X * X * From c!a!b (date) remote from d X * X * Alternatively we may get a line from mail: X * X * From a (date) X * X * Now we must add on the machine name: X * X * From a (date) remote from b X * X * No 'from line' causes an error X */ X X if (strncmp(tmp, "From ", 5) != 0 && strncmp(tmp, ">From ", 6) != 0) { X strcpy(dfile, "/tmp/rmXXXXXX"); X mktemp(dfile); X X if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { X perror("rmail 1"); X exit(-1); X } X X /* write out old 'from' line */ X X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X X /* X * Copy file from stdin to the temporary file X */ X X for (;;) { X if (fgets(tmp, sizeof tmp, stdin) == (char *)NULL) X break; X X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X } X X fflush(fdfile); X fclose(fdfile); X X /* X * Send a letter to manager about this X */ X X SendMail("No From Line\012\012", TRUE); X exit(0); X } X X /* X * Get the (now) garbage "From" into sys X * and the remote address into ofrom X */ X X sscanf(tmp, "%s %s ", sys, ofrom); X p = tmp; X X /* X * Parse line to seek out "remote from" X */ X X for (;;) { X p = strchr(p + 1, 'r'); X if (p == NULL) { X X /* X * You get here after parsing to the end of the string X * and didn't find "remote from" text. The only other X * option is the basic "From" from mail. X */ X X break; X } X X if (strncmp(p, "remote from ", 12) == 0) X break; X } X X if (p == NULL) X strcat(from, ofrom); X else { X sscanf(p, "remote from %s", from); X strcat(from, "!"); X strcat(from, ofrom); X } X X if (remote) { X X /* spool a remote file */ X X strcpy(rmtname, argv[1]); X strcpy(rmtuser, ptr + 1); X X sprintf(dfile, "D.%.6sXXXXXX", myname); X mktemp(dfile); X X if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { X perror("rmail 2"); X exit(-1); X } X X sprintf(tmp, "From %s %s remote from %s\012", X from, datetime, myname); X X /* put out new from */ X X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X X sprintf(tmp, "Received: by %s on %s\012", myname, datetime); X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X X } else { X X /* set up a local file */ X X strcpy(dfile, "/tmp/rmXXXXXX"); X mktemp(dfile); X X if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { X perror("rmail 3"); X exit(-1); X } X X fwrite(">", sizeof(char), 1, fdfile); X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X } X X /* X * uuxqt and mail will call with: X * "rmail [remote!]user <D.xxx >/dev/null" X * X * Copy the stdin to the spool or /tmp file X */ X X for (;;) { X if (fgets(tmp, sizeof tmp, stdin) == (char *)NULL) X break; X X fwrite(tmp, sizeof(char), strlen(tmp), fdfile); X } X X if (!remote) { X fflush(fdfile); X fclose(fdfile); X X /* X * See if destination user name exists on this machine X */ X X names = getpwnam(argv[1]); X endpwent(); X X if (names == (struct passwd *)NULL) { X SendMail("Unknown User\012\012", FALSE); X exit(0); X } X else { X uufix(dfile); /* Change LF to CR */ X sprintf(tmp, "mail %s <%s", argv[1], dfile); X } X X if (system(tmp) != 0) X execerr(); X X#ifndef DEBUG X unlink(dfile); X#endif X } else { X fclose(fdfile); X X /* X * Now forward the mail, if user does not exist X * or the remote machine is not known X * then send mail to system manager and sender X * X * The senders name is now in the global from[] string X */ X X X /* X * See if we talk to requested remote machine X */ X X if (CheckLegalName(rmtname) == FALSE) { X SendMail("Unknown Machine\012\012", FALSE); X exit(0); X } X X /* make the spool files for uucico */ X X sprintf(bfile, "B.%.6sXXXXXX", rmtname); X mktemp(bfile); X X if ((fbfile = fopen(bfile, "w")) == (FILE *)NULL) { X perror("rmail 4"); X exit(-1); X } X X sprintf(tmp, "U %s %s\012F %s\012I %s\012C rmail %s\012", X user, myname, dfile, dfile, rmtuser); X fwrite(tmp, sizeof(char), strlen(tmp), fbfile); X X fclose(fbfile); X X sprintf(xfile, "X.%.6sXXXXXX", rmtname); X sprintf(cfile, "C.%.6sXXXXXX", myname); X mktemp(xfile); X mktemp(cfile); X X if ((fcfile = fopen(cfile, "w")) == (FILE *)NULL) { X perror("rmail 5"); X exit(-1); X } X X sprintf(tmp,"S %s %s %s - %s 0666\012S %s %s %s - %s 0666\012", X dfile, dfile, user, dfile, bfile, xfile, user, bfile); X fwrite(tmp, sizeof(char), strlen(tmp), fcfile); X X fclose(fcfile); X } X} X X Xexecerr() X{ X fprintf(stderr, "rmail: Fatal - Could not exec() mailer\n"); X exit(-1); X} X X X/* X * Send mail to system manager upon errors X * X * Mail is contained in a file referenced X * by Global variable 'dfile' X */ X XSendMail(str, mgronly) Xchar *str; Xint mgronly; X{ X strcpy(cfile, "/tmp/rmtXXXXXX"); X mktemp(cfile); X X fcfile = fopen(cfile, "w"); X fdfile = fopen(dfile, "r"); X X strcpy(tmp, "Subject: "); X strcat(tmp, str); X X fwrite(tmp, sizeof(char), strlen(tmp), fcfile); X X while (fgets(tmp, sizeof tmp, fdfile) != (char *)NULL) { X fwrite("> ", sizeof(char), 2, fcfile); X fwrite(tmp, sizeof(char), strlen(tmp), fcfile); X } X X fflush(fcfile); X fclose(fcfile); X fclose(fdfile); X X#ifndef DEBUG X unlink(dfile); X#endif X /* X * Return mail to system manager X * (and sender if mgronly == FALSE) X */ X X uufix(cfile); /* Change LF to CR */ X X if (!mgronly) { X sprintf(tmp, "mail %s <%s", from, cfile); X if (system(tmp) != 0) X execerr(); X } X X sprintf(tmp, "mail %s <%s", errorname, cfile); X X if (system(tmp) != 0) X execerr(); X X#ifndef DEBUG X unlink(cfile); X#endif X} X X X/* X * Check the machine name by reading the SYSTEMS file X * X * returns FALSE if not found, else TRUE X * X */ X XCheckLegalName(name) Xregister char *name; X{ X register FILE *fd; X char line[132], tmp[16]; X X if ((fd = fopen(SYSTEMS, "r")) == (FILE *)NULL) X return(FALSE); X X while (fgets(line, sizeof line, fd) != NULL) { X sscanf(line, "%s ", tmp); X X if (strncmp(name, tmp, 6) == 0) { X fclose(fd); X return(TRUE); X } X } X X fclose(fd); X X return(FALSE); X} X X X/* X * mfgets (modified fgets) X * X * Same as fgets() only this version deletes '\n' X */ X Xchar *mfgets(s, n, iop) Xregister char *s; Xregister int n; Xregister FILE *iop; X{ X register int c; X register char *cs; X X cs = s; X while (--n > 0 && (c = getc(iop)) != EOF) { X if (c == 0x0D) { X *cs = '\0'; X break; X } else X *cs++ = c; X } X X return((c == EOF && cs == s) ? (char *)NULL : s); X} X X X/* X * UniFLEX uses CR instead of LF (Just to be different I guess) X */ X Xchar *fgets(s, n, iop) Xregister char *s; Xregister int n; Xregister FILE *iop; X{ X register int c; X register char *cs; X X cs = s; X while (--n > 0 && (c = getc(iop)) != EOF) { X *cs++ = c; X if (c == 0x0A) X break; X } X X *cs = '\0'; X return((c == EOF && cs == s) ? (char *)NULL : s); X} X X X/* X * Change Unix LF to UniFLEX CR X */ X Xuufix(file) Xregister char *file; X{ X register FILE *fd, *temp; X register int scoop; X char name[32]; X X strcpy(name, "/tmp/uufixXXXXXX"); X mktemp(name); X X if ((fd = fopen(file, "r")) == (FILE *)NULL) { X fprintf(stderr, "rmail: File '%s' not found\n", file); X exit(-1); X } X X if ((temp = fopen(name, "w")) == (FILE *)NULL) { X fprintf(stderr,"rmail: Unable to open temp file '%s'\n", name); X exit(-1); X } X X while ((scoop = getc(fd)) != EOF) { X if (scoop == 0x0A) X putc(0x0D, temp); X else X putc(scoop, temp); X } X X fclose(temp); X fclose(fd); X X unlink(file); X link(name, file); X unlink(name); X} X X/* EOF */ X END_OF_rmail.c echo shar: 1 control character may be missing from \"rmail.c\" if test 14828 -ne `wc -c <rmail.c`; then echo shar: \"rmail.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f uuxqt.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"uuxqt.c\" else echo shar: Extracting \"uuxqt.c\" \(5910 characters\) sed "s/^X//" >uuxqt.c <<'END_OF_uuxqt.c' X/* X * uuxqt.c X * X * Command File Execute X * X * UniFLEX(tm) Version 2.3 May 1988 X * X * Based on dcp.c Copyright (c) 1985, 1986, 1987 by Richard H. Lamb X * Changes are Public Domain by S. R. Sampson X * X * This program searches for work files in the spool directory and X * executes them. Work files have a X. prefix. X * X * It is executed by 'uucico', 'cron', or 'at' X */ X X/* Includes */ X X#include "uucp.h" X X#include <sys/modes.h> X#include <sys/fcntl.h> X#include <sys/dir.h> /* defines MAXNAMLEN and directory stuff */ X#include <string.h> X#include <stdio.h> X#include <time.h> X#include <pwd.h> X X/* Defines */ X X#define MAXLINE 256 X X/* Globals */ X Xlong stamp; Xchar command[MAXLINE], input[MAXLINE], output[MAXLINE], line[MAXLINE]; Xchar Cfilename[MAXNAMLEN+1], filename[MAXNAMLEN+1], ltime[32]; Xchar systemname[16], username[16], user[16]; X X/* Forward Declarations */ X Xchar *mfgets(); X X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X register char *p; X register FILE *fdC, *log; X register DIR *dd; X register struct direct *dir; X struct passwd *pw; X int inull, onull; X X /* X * Read Configuration file X * X * The UniFLEX 2.3 C Compiler would not compile this X * correctly from an include file. X */ X X#undef CONFIG X#define CONFIG "/gen/spooler/uucp/.Config" X X if ((log = fopen(CONFIG, "r")) != (FILE *)NULL) { X mfgets(user, sizeof user, log); X fclose(log); X } X else X exit(1); X X /* X * Change to spool directory X */ X X chdir(SPOOLDIR); X X if ((dd = opendir(SPOOLDIR)) == (DIR *)NULL) X exit(1); X X while ((dir = readdir(dd)) != (struct direct *)NULL) { X if (strncmp(dir->d_name, "X.", 2) != 0) X continue; X X strncpy(Cfilename, dir->d_name, dir->d_namlen); X X if ((fdC = fopen(Cfilename, "r")) == (FILE *)NULL) X continue; X X inull = onull = TRUE; X X while (mfgets(line, sizeof line, fdC) != NULL) { X switch (line[0]) { X case 'C': X strcpy(command, &line[2]); X break; X X /* X * See if all required files are present X */ X X case 'F': X strcpy(filename, &line[2]); X p = filename; X X while ((*p != ' ') && *p) X p++; X X *p = '\0'; X X if (access(filename, 0) == -1) { X X /* X * All files not present, go check X * other work files and give up X * on this one till next time X */ X X goto not_ready; X } X X break; X X case 'I': X strcpy(input, &line[2]); X inull = FALSE; X break; X X case 'O': X strcpy(output, &line[2]); X onull = FALSE; X break; X X case 'U': X strcpy(username, &line[2]); X p = username; X X while ((*p != ' ') && *p) X p++; X X *p++ = '\0'; X strcpy(systemname, p); X break; X } X } X X if (inull) X strcpy(input, "/dev/null"); X X if (onull) X strcpy(output, "/dev/null"); X X sprintf(line,"%s <%s >%s", command, input, output); X X if ((log = fopen(XQTLOG, "a")) != (FILE *)NULL) { X time(&stamp); X strcpy(ltime, ctime(&stamp)); X ltime[strlen(ltime) - 1] = '\0'; X X fprintf(log, "%s %s %s %s\n", X ltime, systemname, username, line); X X fclose(log); X } X X if (system(line) != -1) { X#ifndef DEBUG X unlink(Cfilename); X X if (!inull) X unlink(input); X X if (!onull) X unlink(output); X#endif X } X Xnot_ready: fclose(fdC); X X } X X closedir(dd); X} X X X/* X * mfgets (modified fgets) X * X * Same as fgets() only this version deletes '\n' X */ X Xchar *mfgets(s, n, iop) Xregister char *s; Xregister int n; Xregister FILE *iop; X{ X register int c; X register char *cs; X X cs = s; X while (--n > 0 && (c = getc(iop)) != EOF) { X if (c == '\012') { X *cs = '\0'; X break; X } else X *cs++ = c; X } X X return((c == EOF && cs == s) ? (char *)NULL : s); X} X X/* EOF */ X END_OF_uuxqt.c echo shar: 1 control character may be missing from \"uuxqt.c\" if test 5910 -ne `wc -c <uuxqt.c`; then echo shar: \"uuxqt.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0 /*---------That is All (M.A.S.H.)---------------*/