pete@wlbr.EATON.COM (Pete Lyall) (04/19/88)
For those that are interested in the OS9/UUCP porting project (which is as yet, loosely defined), here is the code we will likely be starting with. This particular group of files was ported to UNIFlex (a 680x0 unix clone) by Steve Sampson. Bob Santy has expressed an interest to commence work on the port, but is currently changing jobs. I'll be happy to gateway any requests or information. There are also two doc files that will be included in another posting. They are somewhat general in that they pertain more to protocol innards that the actual system operation. ============================== Cut Here ============================ #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # README # uucp.h # mail.c # rmail.c # uucico.c # uuxqt.c # This archive created: Mon Apr 18 11:13:13 1988 export PATH; PATH=/bin:$PATH if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # Makefile for Unix(tm) <-> UniFLEX(tm) Mail # # +O is for Optimize, +Q is for don't align on quad word boundry. # # You should be super-user when running this! # # This is for GIMIX Micro-20 68020 UniFLEX # CFLAGS = +OQ install: move /usr/bin/mail /usr/bin/lmail perms o-w u+rwx s+ /usr/bin/lmail owner system /usr/bin/lmail /etc/addusr uucp mkdir /gen/spooler/uucp mkdir /gen/spooler/uucp/.Log owner uucp /gen/spooler/uucp /gen/spooler/uucp/.Log move .Systems /gen/spooler/uucp move .Devices /gen/spooler/uucp move .Config /gen/spooler/uucp owner uucp /gen/spooler/uucp/.Systems owner uucp /gen/spooler/uucp/.Devices owner uucp /gen/spooler/uucp/.Config make uucico make uuxqt make mail make rmail make strip # make clean echo "++\n++ Now edit the password file. Change the 'uucp' default\n" echo "++ shell to 'uucico slave'\n++\n" uucico: uucico.r cc $(CFLAGS) uucico.r +o=/etc/uucico owner uucp /etc/uucico perms o-rwx u+rwx s+ /etc/uucico uuxqt: uuxqt.r cc $(CFLAGS) uuxqt.r +o=/etc/uuxqt owner uucp /etc/uuxqt perms o-rwx u+rwx s+ /etc/uuxqt mail: mail.r cc $(CFLAGS) mail.r +o=/usr/bin/mail owner system /usr/bin/mail perms o-w o+rx u+rwx /usr/bin/mail rmail: rmail.r cc $(CFLAGS) rmail.r +o=/usr/bin/rmail owner uucp /usr/bin/rmail perms o-w o+rx u+rwx s+ /usr/bin/rmail # # Get rid of symbol table from binaries when debugging complete # strip: strip /etc/uucico /etc/uuxqt /usr/bin/mail /usr/bin/rmail # # Remove the object files from the work directory # clean: kill *.r # # Dependencies # uucico.r: uucico.c uucp.h uuxqt.r: uuxqt.c uucp.h mail.r: mail.c uucp.h rmail.r: rmail.c uucp.h # EOF SHAR_EOF fi # end of overwriting check if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' Unix to UniFLEX Mail Machine Version 2.1, March 1988 S. R. Sampson This archive of files is the basis for sending mail from a UniFLEX(tm) operating system to the Unix(tm) operating system, using the uucp 'G' Protocol. It is based on the DCP program by Richard Lamb as posted on Usenet. The files are: README This file Makefile All encompassing build instructions uucp.h Header file for Operating System specifics mail.c Remote/Local mail front-end rmail.c Remote mail work file generator (simple bang mode) uucico.c G Protocol dialup machine uuxqt.c Work file execution machine .Systems A sample dialing directory .Devices A sample dialing port setup .Config A sample configuration setup I've been doing some minor testing on this code and would like others to play around and improve it. It may be an useful start for other machines. Put the files in a source code directory and simply execute 'make'. This will almost completely build the mail machine. You will have to manualy edit the /etc/log/password file to change the default shell to '/etc/uucico'. Then run 'password uucp' and assign the account a password. Following that, find a Unix machine to talk to and setup the .Config, .Systems, and .Devices files for your serial ports. The format for the .Devices file is: /dev/ttyxx Baudrate Type Status Where: xx is the TTY number Baudrate is the setting of the port Type is MODEM or DIRECT Status is FREE or USED You initially create the file with everything FREE. I'm using a GMX Micro-20 and have it set up like so: /dev/tty03 1200 MODEM FREE /dev/tty02 2400 DIRECT FREE /dev/tty01 2400 DIRECT FREE The format for the .Systems file is: Machine-Name Call-Time Baudrate Type Dialup-Sequence Wher: Machine-name is 6 character significance Call-Time is Any (Not implemented) Baudrate is the machines (or your modems) maximum speed Type is MODEM or DIRECT which is used when looking for a port Dialup-Sequence is a send/receive sequence for logging on The format for the .Config file is: User-Name (The owner of the files (eg. 'uucp')) Machine-Name (6 character significance (eg. 'test')) Error-Name (Who gets mail when problems are found (eg. 'root', 'system')) The uucp directory will contain all the work files to be sent and received. The log file will contain information written by the programs as they run. This information can be useful when debugging. Remember to purge this stuff when disk space starts filling up. This UniFLEX version will automatically run in the slave mode upon login to the uucp account. An example cron entry to run uucico in the master mode with a debug level 9 would look like so: 0 * * * * /etc/uucico master 9 If you have problems check on all permissions and ownership: /usr/bin/mail system rwxr-x /usr/bin/lmail system rwxr-x SUID /usr/bin/rmail uucp rwxr-x SUID /etc/uucico uucp rwx--- SUID /etc/uuxqt uucp rwx--- SUID /gen/spooler/uucp uucp drwxr-x /gen/spooler/uucp/.Log uucp drwx--- /gen/spooler/uucp/.Systems uucp rw---- /gen/spooler/uucp/.Devices uucp rw---- /gen/spooler/uucp/.Config uucp rw---- Sometimes the .Devices file may become corrupt. Make sure you view it for problems such as no FREE device, or missplaced writes. To send remote mail: mail myconnect!ihnp4!killer!sampson This is a test [] <- Type a Control-D for EOF and mail will be spooled. sampson@killer.UUCP ihnp4!killer!sampson Steve Sampson, Box 45668, Tinker AFB, OK 73145 /* EOF */ SHAR_EOF fi # end of overwriting check if test -f 'uucp.h' then echo shar: will not over-write existing file "'uucp.h'" else cat << \SHAR_EOF > 'uucp.h' /* * uucp.h * * Header file for Unix(tm) to UniFLEX(tm) mail machine */ /* * Spool Directory */ #define SPOOLDIR "/gen/spooler/uucp" /* * Configuration file (in spooldir directory) format * * 1. user uucp * 2. myname test * 3. errorname system */ #define CONFIG "/gen/spooler/uucp/.Config" /* * Systems file (in spooldir directory) format * * 1. rmtname ihnp4 * 2. cctime 2300-2359 * 3. ttype MODEM * 4. tspeed 2400 * 5. loginseq /n/n:gin:uucp\n:sword:secret\n */ #define SYSTEMS ".Systems" /* file with calling info */ /* * Devices file (in spooldir directory) format * * 1. Name /dev/ttyxx * 2. Max-Speed 75 - 19200 Baud * 3. Type MODEM or DIRECT * 4. Status USED or FREE */ #define DEVICES ".Devices" /* file with terminal info */ /* * Error log files (relative to spooldir) */ #define SYSLOG ".Log/uucico" /* error log file for uucico */ #define XQTLOG ".Log/uuxqt" /* error log file for uuxqt */ /* EOF */ SHAR_EOF fi # end of overwriting check if test -f 'mail.c' then echo shar: will not over-write existing file "'mail.c'" else cat << \SHAR_EOF > 'mail.c' /* * mail.c * * UniFLEX(tm) Version 2.1 * Public Domain, March 1988 by S. R. Sampson * * This program checks for local or remote indication * and sends mail using rmail or lmail. * */ /* Defines */ #define FALSE 0 #define TRUE ~FALSE /* Includes */ #include "uucp.h" #include <string.h> #include <stdio.h> #include <errno.h> #include <time.h> #include <pwd.h> /* Globals */ long stamp; char dfile[140], from[16], tmp[140]; int remote; /* The program */ main(argc, argv) int argc; char *argv[]; { register FILE *fdfile; register char *ptr; struct passwd *name; if (argc == 1) { execl("/usr/bin/lmail", "mail", (char *)NULL); exit(-1); } strcpy(dfile, "/tmp/msXXXXXX"); mktemp(dfile); if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { perror("mail 1"); exit(-1); } /* * If address has a '!' character flag address as remote * else local. */ if ((ptr = strchr(argv[1], '!')) == (char *)NULL) remote = FALSE; else remote = TRUE; /* * Find out who we are and generate the required * "From name date" line */ if (remote) { name = getpwuid(getuid()); strcpy(from, name->pw_name); endpwent(); time(&stamp); sprintf(tmp, "From %s %s", from, ctime(&stamp)); fwrite(tmp, sizeof(char), strlen(tmp), fdfile); } /* * Copy stdin to a /tmp file */ for (;;) { if (fgets(tmp, sizeof tmp, stdin) == (char *)NULL) break; fwrite(tmp, sizeof(char), strlen(tmp), fdfile); } fflush(fdfile); fclose(fdfile); if (remote) { uufix(dfile); /* Change UniFLEX CR to Unix LF */ sprintf(tmp, "rmail %s <%s >/dev/null", argv[1], dfile); } else sprintf(tmp, "lmail %s <%s >/dev/null", argv[1], dfile); if (system(tmp) != 0) { fprintf(stderr, "mail: Fatal - Could not exec() mailer\n"); exit(-1); } #ifndef DEBUG unlink(dfile); #endif } uufix(file) register char *file; { register FILE *fd, *temp; register int scoop; char name[32]; strcpy(name, "/tmp/uufixXXXXXX"); mktemp(name); if ((fd = fopen(file, "r")) == (FILE *)NULL) { fprintf(stderr, "mail: File '%s' not found\n", file); exit(-1); } if ((temp = fopen(name, "w")) == (FILE *)NULL) { fprintf(stderr, "mail: Unable to open temp file '%s'\n", name); exit(-1); } while ((scoop = getc(fd)) != EOF) { if (scoop == 0x0D) putc(0x0A, temp); else putc(scoop, temp); } fflush(temp); fclose(temp); fclose(fd); unlink(file); link(name, file); unlink(name); } /* EOF */ SHAR_EOF fi # end of overwriting check if test -f 'rmail.c' then echo shar: will not over-write existing file "'rmail.c'" else cat << \SHAR_EOF > 'rmail.c' /* * rmail.c * * Mini Remote Mail Handler * * Version 2.1, Public Domain (p) March 1988 * * This program is executed by either 'mail' or 'uuxqt'. * * The standard UniFLEX(tm) mail doesn't handle remote addresses * so I made a new program called mail and renamed the old * mail to lmail. Now if the new mail finds a remote address * it calls rmail, else lmail. * * UniFLEX has a different End of Line convention than Unix * does. Therefore rmail will need to fix the transfered * files before sending to mail. * * Usage: * rmail remotesystem!remoteuser myname (test myname) * rmail remotesystem!remoteuser (.Config myname) * rmail localuser * * Limitation: * Will only do bang '!' addresses. */ /* Defines */ #define FALSE 0 #define TRUE ~FALSE /* Includes */ #include "uucp.h" #include <sys/modes.h> #include <sys/dir.h> #include <string.h> #include <stdio.h> #include <errno.h> #include <time.h> #include <pwd.h> /* Globals */ extern char *tzname[2]; /* contains two strings CDT or CST */ extern int daylight; /* array index for above */ struct passwd *names; long stamp; int remote; char bfile[32], cfile[32], dfile[32], xfile[32]; char rmtname[16], rmtuser[128], myname[16], user[16]; char datetime[48], ofrom[256], from[256], tmp[256], sys[32]; char errorname[8], *p, *ptr, *mfgets(), *fgets(); FILE *fbfile, *fcfile, *fdfile; /* The program */ main(argc, argv) int argc; char *argv[]; { if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: rmail [remote!]user [testname]\n"); exit(-1); } /* * Read Configuration file * * The UniFLEX 2.3 C Compiler would not compile this * correctly from an include file. */ #undef CONFIG #define CONFIG "/gen/spooler/uucp/.Config" if ((fcfile = fopen(CONFIG, "r")) != (FILE *)NULL) { mfgets(user, sizeof user, fcfile); mfgets(myname, sizeof myname, fcfile); mfgets(errorname, sizeof errorname, fcfile); fclose(fcfile); } else exit(-1); if (argc == 3) /* useful for debuging */ strcpy(myname, argv[2]); /* * If address has a '!' character flag address as remote * else local. */ if ((ptr = strchr(argv[1], '!')) == (char *)NULL) remote = FALSE; else { *ptr = '\0'; remote = TRUE; } /* * Change file creation mask to rwx------ */ umask(S_IOREAD | S_IOWRITE | S_IOEXEC); /* * Change to working directory */ chdir(SPOOLDIR); /* * Calculate the time */ time(&stamp); strcpy(datetime, ctime(&stamp)); datetime[strlen(datetime) - 1] = '\0'; strcat(datetime, " "); strcat(datetime, tzname[daylight]); /* add in CDT or CST */ /* * See if this mail was generated locally * or came from somewhere else. Local mail * has a "From x y" header, remote has a * "From x y remote from z" header. */ strcpy(from, ""); strcpy(ofrom, ""); fgets(tmp, sizeof tmp, stdin); /* get a line from stdin */ /* * First line should be a From line. Our goal is to change from this: * * From a!b (date) remote from c * * To this: * * From c!a!b (date) remote from d * * Alternatively we may get a line from mail: * * From a (date) * * Now we must add on the machine name: * * From a (date) remote from b * * No 'from line' causes an error */ if (strncmp(tmp, "From ", 5) != 0 && strncmp(tmp, ">From ", 6) != 0) { strcpy(dfile, "/tmp/rmXXXXXX"); mktemp(dfile); if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { perror("rmail 1"); exit(-1); } /* write out old 'from' line */ fwrite(tmp, sizeof(char), strlen(tmp), fdfile); /* * Copy file from stdin to the temporary file */ for (;;) { if (fgets(tmp, sizeof tmp, stdin) == (char *)NULL) break; fwrite(tmp, sizeof(char), strlen(tmp), fdfile); } fflush(fdfile); fclose(fdfile); uufix(dfile); /* change LF to required EOL */ /* * Send a letter to manager about this */ SendMail("No From Line\012\012", TRUE); exit(0); } /* * Get the (now) garbage "From" into sys * and the remote address into ofrom */ sscanf(tmp, "%s %s ", sys, ofrom); p = tmp; /* * Parse line to seek out "remote from" */ for (;;) { p = strchr(p + 1, 'r'); if (p == NULL) { /* * You get here after parsing to the end of the string * and didn't find "remote from" text. The only other * option is the basic "From" from mail. */ break; } if (strncmp(p, "remote from ", 12) == 0) break; } if (p == NULL) strcat(from, ofrom); else { sscanf(p, "remote from %s", from); strcat(from, "!"); strcat(from, ofrom); } if (remote) { /* spool a remote file */ strcpy(rmtname, argv[1]); strcpy(rmtuser, ptr + 1); sprintf(dfile, "D.%.6sXXXXXX", myname); mktemp(dfile); if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { perror("rmail 2"); exit(-1); } sprintf(tmp, "From %s %s remote from %s\012", from, datetime, myname); /* put out new from */ fwrite(tmp, sizeof(char), strlen(tmp), fdfile); sprintf(tmp, "Received: by %s on %s\012", myname, datetime); fwrite(tmp, sizeof(char), strlen(tmp), fdfile); } else { /* set up a local file */ strcpy(dfile, "/tmp/rmXXXXXX"); mktemp(dfile); if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) { perror("rmail 3"); exit(-1); } fwrite(">", sizeof(char), 1, fdfile); fwrite(tmp, sizeof(char), strlen(tmp), fdfile); } /* * uuxqt and mail will call with: * "rmail [remote!]user <D.xxx >/dev/null" * * Copy the stdin to the spool or /tmp file */ for (;;) { if (fgets(tmp, sizeof tmp, stdin) == (char *)NULL) break; fwrite(tmp, sizeof(char), strlen(tmp), fdfile); } if (!remote) { fflush(fdfile); fclose(fdfile); uufix(dfile); /* * See if destination user name exists on this machine */ names = getpwnam(argv[1]); endpwent(); if (names == (struct passwd *)NULL) { SendMail("Unknown User\012\012", FALSE); exit(0); } else sprintf(tmp, "mail %s <%s", argv[1], dfile); if (system(tmp) != 0) execerr(); #ifndef DEBUG unlink(dfile); #endif } else { fclose(fdfile); /* * Now forward the mail, if user does not exist * or the remote machine is not known * then send mail to system manager and sender * * The senders name is now in the global from[] string */ /* * See if we talk to requested remote machine */ if (CheckLegalName(rmtname) == FALSE) { SendMail("Unknown Machine\012\012", FALSE); exit(0); } /* make the spool files for uucico */ sprintf(bfile, "B.%.6sXXXXXX", rmtname); mktemp(bfile); if ((fbfile = fopen(bfile, "w")) == (FILE *)NULL) { perror("rmail 4"); exit(-1); } sprintf(tmp, "U %s %s\012F %s\012I %s\012C rmail %s\012", user, myname, dfile, dfile, rmtuser); fwrite(tmp, sizeof(char), strlen(tmp), fbfile); fclose(fbfile); sprintf(xfile, "X.%.6sXXXXXX", rmtname); sprintf(cfile, "C.%.6sXXXXXX", myname); mktemp(xfile); mktemp(cfile); if ((fcfile = fopen(cfile, "w")) == (FILE *)NULL) { perror("rmail 5"); exit(-1); } sprintf(tmp,"S %s %s %s - %s 0666\012S %s %s %s - %s 0666\012", dfile, dfile, user, dfile, bfile, xfile, user, bfile); fwrite(tmp, sizeof(char), strlen(tmp), fcfile); fclose(fcfile); } } execerr() { fprintf(stderr, "rmail: Fatal - Could not exec() mailer\n"); exit(-1); } /* * Send mail to system manager upon errors * * Mail is contained in a file referenced * by Global variable 'dfile' */ SendMail(str, mgronly) char *str; int mgronly; { strcpy(cfile, "/tmp/rmtXXXXXX"); mktemp(cfile); fcfile = fopen(cfile, "w"); fdfile = fopen(dfile, "r"); strcpy(tmp, "Subject: "); strcat(tmp, str); fwrite(tmp, sizeof(char), strlen(tmp), fcfile); while (feets(tmp, sizeof tmp, fdfile) != (char *)NULL) { fwrite("> ", sizeof(char), 2, fcfile); fwrite(tmp, sizeof(char), strlen(tmp), fcfile); } fclose(fcfile); fclose(fdfile); #ifndef DEBUG unlink(dfile); #endif /* * Return mail to system manager * (and sender if mgronly == FALSE) */ if (!mgronly) { sprintf(tmp, "mail %s <%s", from, cfile); if (system(tmp) != 0) execerr(); } sprintf(tmp, "mail %s <%s", errorname, cfile); if (system(tmp) != 0) execerr(); #ifndef DEBUG unlink(cfile); #endif } /* * Check the machine name by reading the SYSTEMS file * * returns FALSE if not found, else TRUE * */ CheckLegalName(name) register char *name; { register FILE *fd; char line[256], tmp[16]; if ((fd = fopen(SYSTEMS, "r")) == NULL) return(FALSE); while (fgets(line, sizeof line, fd) != NULL) { sscanf(line, "%s ", tmp); if (strncmp(name, tmp, 6) == 0) { fclose(fd); return(TRUE); } } fclose(fd); return(FALSE); } /* * mfgets (modified fgets) * * Same as fgets() only this version deletes '\n' */ char *mfgets(s, n, iop) register char *s; register int n; register FILE *iop; { register int c; register char *cs; cs = s; while (--n > 0 && (c = getc(iop)) != EOF) { if (c == 0x0D) { *cs = '\0'; break; } else *cs++ = c; } return((c == EOF && cs == s) ? (char *)NULL : s); } /* * UniFLEX uses CR instead of LF (Just to be different I guess) */ char *fgets(s, n, iop) register char *s; register int n; register FILE *iop; { register int c; register char *cs; cs = s; while (--n > 0 && (c = getc(iop)) != EOF) { *cs++ = c; if (c == 0x0A) break; } *cs = '\0'; return((c == EOF && cs == s) ? (char *)NULL : s); } /* * Change Unix LF to UniFLEX CR */ uufix(file) register char *file; { register FILE *fd, *temp; register int scoop; char name[32]; strcpy(name, "/tmp/uufixXXXXXX"); mktemp(name); if ((fd = fopen(file, "r")) == (FILE *)NULL) { fprintf(stderr, "rmail: File '%s' not found\n", file); exit(-1); } if ((temp = fopen(name, "w")) == (FILE *)NULL) { fprintf(stderr,"rmail: Unable to open temp file '%s'\n", name); exit(-1); } while ((scoop = getc(fd)) != EOF) { if (scoop == 0x0A) putc(0x0D, temp); else putc(scoop, temp); } fclose(temp); fclose(fd); unlink(file); link(name, file); unlink(name); } /* EOF */ SHAR_EOF fi # end of overwriting check if test -f 'uucico.c' then echo shar: will not over-write existing file "'uucico.c'" else cat << \SHAR_EOF > 'uucico.c' /* * uucico.c * * Copy In - Copy Out 'G' Protocol * * 68020 UniFLEX(tm) Version 2.1 * * Based on dcp.c Copyright (c) 1985, 1986, 1987 by Richard H. Lamb * Changes are Public Domain (p) March 1988 by S. R. Sampson * * Called by 'cron', 'at', or 'uucp login'. * * Define DEBUG to prevent unlinking of C. files */ /* Includes */ #include "uucp.h" #include <sys/signal.h> #include <sys/sgtty.h> #include <sys/modes.h> #include <sys/dir.h> #include <string.h> #include <setjmp.h> #include <errno.h> #include <ctype.h> #include <stdio.h> #include <time.h> #include <pwd.h> /* General purpose defines */ #define FALSE 0 #define TRUE ~FALSE #define ERROR FALSE #define OK TRUE #define MAXLINE 132 #define MAXLOGTRY 4 #define MSGTIME 25 #define MAXTRY 5 #define PKTTIME 10 #define PKTSIZE 64 #define PKTSIZ2 2 #define HDRSIZE 6 #define WNDSIZE 3 #define DLE 16 /* Main Switching states */ #define INITIAL 000 #define DEVICE 001 #define LOGIN 002 #define HANDSHAKE 003 #define MASTER 004 #define SLAVE 005 #define HANGUP 006 #define END 007 #define ABORT 010 /* Master/Slave states */ #define MS_INIT 020 #define MS_SCANDIR 021 #define MS_SEND 022 #define MS_HANGUP 023 #define MS_RECEIVE 024 #define MS_ABORT 025 #define MS_CHKWORK 026 #define MS_END 027 /* Switching States */ #define SS_HEADER 030 #define SS_DATA 031 #define SS_EOF 032 #define SS_END 033 #define SS_ABORT 034 /* * Control Packet Defines * * xxx name yyy * * 001 CLOSE n/a * 002 RJ last correctly received sequence number * 004 RR last correctly received sequence number * 005 INITC window size * 006 INITB data seqment size * 007 INITA window size */ #define DATA 000 /* The packet is data */ #define CLOSE 001 /* CLOSE, Comunications complete */ #define RJ 002 /* RJ Reject, detected an error */ #define RR 004 /* RR Receiver ready, detected no errors */ #define INITC 005 #define INITB 006 #define INITA 007 #define MODEM 000 /* TTY device types */ #define DIRECT 001 /* Global Variables */ struct passwd *pw; struct { int baudrate; char *code; } rates[] = { /* what I use the most */ B300, "300", B1200, "1200", B2400, "2400", B9600, "9600", B19200, "19200", 0, "" }; #define DEFAULT_BAUD B1200 struct sgttyb NewSetting, OldSetting; long Dpos; FILE *fd, *fdC, *log, *input, *output; int type, size, pkrec, pksent, pknerr, master, debug_level; char InPacket[PKTSIZE], OutPacket[PKTSIZE], Filename[MAXLINE], Cfilename[MAXNAMLEN+1], /* defined in dir.h */ Loginseq[64], Rmtname[8], Device[16], myname[8], user[8], speed[8]; char *rcverr[] = { "", "Input Buffer Empty", "Bad Header", "Packet Timeout", "Checksum Error", "Wrong Packet Size" }; /* Forward Declarations */ unsigned checksum(); char *mfgets(), *gtime(); jmp_buf env; /* * Usage: * uucico mode debug * * Where mode is 'master' or 'slave' * And debug is an integer from 0 to 9 * * Defaults are slave mode and level 0 debug * */ main(argc, argv) int argc; char **argv; { register int state; /* * Read Configuration file * * The UniFLEX 2.3 C Compiler would not compile this * correctly from an include file. */ #undef CONFIG #define CONFIG "/gen/spooler/uucp/.Config" if ((log = fopen(CONFIG, "r")) != (FILE *)NULL) { mfgets(user, sizeof user, log); mfgets(myname, sizeof myname, log); fclose(log); } else exit(1); /* * Open the error log file */ log = fopen(SYSLOG, "a"); setbuf(log, (char *)NULL); /* log file should be unbuffered */ /* * Setup defaults */ master = FALSE; debug_level = 0; fd = fdC = (FILE *)NULL; /* * Change to the spool directory */ chdir(SPOOLDIR); /* * Process the two command line arguments * The first is "master" or "slave", the second * is an integer debug level between 0 and 9. */ if (argc > 1 && strcmp(argv[1], "master") == 0) master = TRUE; if (argc > 2) { debug_level = abs(atoi(argv[2])); if (debug_level > 9) debug_level = 9; } state = INITIAL; while (TRUE) { switch(state) { case INITIAL: if (master) state = GetSystem(); else state = HandShake(); break; case DEVICE: state = GetTTY(); if (state == ABORT) fprintf(log,"Main(): No Device Available %s", gtime()); break; case LOGIN: state = Login(); break; case HANDSHAKE: state = HandShake(); break; case MASTER: state = Master(); break; case SLAVE: state = Slave(); break; case HANGUP: state = MasterHangup(); break; case END: state = SendOO(); } if (state == ABORT) break; } CloseTTY(); fclose(log); /* go execute any transfered work files */ execl("/etc/uuxqt", "uuxqt", (char *)NULL); } /*------------------------- * uucico Subroutines *------------------------- */ GetString(string) register char *string; { register int i, len; char c[MAXLINE]; len = strlen(string); c[len--] = 0; while (strcmp(string, c) != 0) { for (i = 0; i < len; i++) c[i] = c[i+1]; if (ReadTTY(&c[i], 1, PKTTIME) == 0) { fprintf(log,"GetString(): Input timed out %s", gtime()); fprintf(log," Wanted %s got %s\n", string, c); return ERROR; } toascii(c[i]); } return OK; } /* * mfgets (modified fgets) * * Same as fgets() only this version deletes '\n' */ char *mfgets(s, n, iop) register char *s; register int n; register FILE *iop; { register int c; register char *cs; cs = s; while (--n > 0 && (c = getc(iop)) != EOF) { if (c == 0x0D) { *cs = '\0'; break; } else *cs++ = c; } return((c == EOF && cs == s) ? (char *)NULL : s); } char *gtime() { long value; time(&value); return(ctime(&value)); } CheckName() { register FILE *fdsys; char line[MAXLINE], tmp[16]; if ((fdsys = fopen(SYSTEMS, "r")) == NULL) { fprintf(log,"CheckName(): Can't open %s %s", SYSTEMS, gtime()); return ERROR; } while (mfgets(line, sizeof line, fdsys) != (char *)NULL) { sscanf(line, "%s ", tmp); if (strncmp(Rmtname, tmp, 6) == 0) { fclose(fdsys); return OK; } } fclose(fdsys); fprintf(log, "CheckName(): Unknown system %s attempted login %s", Rmtname, gtime()); return ERROR; } CheckTime(time) register char *time; { return OK; } /*------------------------------------------------- * uucico High Level State Switching routines *------------------------------------------------- */ GetSystem() { register FILE *fdsys; char line[MAXLINE], ttype[8], cctime[16]; if ((fdsys = fopen(SYSTEMS, "r")) == NULL) { fprintf(log,"GetSystem(): Can't open %s %s", SYSTEMS, gtime()); return ABORT; } do { if (mfgets(line, sizeof line, fdsys) == (char *)NULL) { fclose(fdsys); return ABORT; /* no more systems */ } sscanf(line, "%s %s %s %s %s", Rmtname, cctime, ttype, speed, Loginseq); type = strcmp(ttype, "MODEM") ? DIRECT : MODEM; } while ( !strcmp(cctime, "Slave") || !CheckTime(cctime) ); fclose(fdsys); return DEVICE; /* go get a device and login */ } /* * Find the next device of the type and speed requested * in the DEVICES file */ GetTTY() { register FILE *fdtty; int Type, Used; char line[MAXLINE], Types[8], Useds[8], Bauds[8]; if ((fdtty = fopen(DEVICES, "r+")) == (FILE *)NULL) { fprintf(log,"GetTTY(): Can't open %s %s", DEVICES, gtime()); return ABORT; } do { if (mfgets(line, sizeof line, fdtty) == (char *)NULL) { fprintf(log,"GetTTY(): No devices available %s", gtime()); fclose(fdtty); return ABORT; } sscanf(line, "%s %s %s %s", Device, Bauds, Types, Useds); Type = strcmp(Types, "MODEM") ? DIRECT : MODEM; Used = strcmp(Useds, "FREE"); } while (Type != type || strcmp(Bauds, speed) || Used); fseek(fdtty, -5L, 1); Dpos = ftell(fdtty); /* Dpos is used in CloseTTY() */ fputs("USED", fdtty); fclose(fdtty); if (OpenTTY() == ERROR) return ABORT; return LOGIN; } Login() { register int k, j, trys; register char *last; char buffer[MAXLINE]; int flag; j = k = 0; /* * First move everything to 'buffer', changing text * newlines to binary */ while(Loginseq[j] != '\0') { if (Loginseq[j] == '\\' && Loginseq[j+1] == 'n') { buffer[k++] = '\n'; j += 2; continue; } buffer[k++] = Loginseq[j++]; } buffer[k] = j = 0; flag = TRUE; /* start by sending */ while (buffer[j]) { k = j; while (buffer[k] != '-' && buffer[k] != '\0') k++; if (buffer[k] == '\0') buffer[k+1] = '\0'; buffer[k] = '\0'; if (flag) { last = &buffer[j]; WritePacket(&buffer[j], FALSE); flag = FALSE; } else { trys = 1; while (GetString(&buffer[j]) == ERROR) { if (trys >= MAXLOGTRY) { fprintf(log,"Login(): Failed login on remote %s", gtime()); return ABORT; } /* try resending the last sequence */ trys++; WritePacket(last, FALSE); } flag = TRUE; } j = k + 1; } return HANDSHAKE; } HandShake() { char t1[16], t2[16]; if (master) { if (ReadPacket(InPacket, MSGTIME) == 0) return ABORT; if (strncmp(InPacket + 6, Rmtname, 6)) { fprintf(log,"HandShake(): System name match error %s", gtime()); return ABORT; } sprintf(OutPacket, "S%.6s", myname); WritePacket(OutPacket, TRUE); if (ReadPacket(InPacket, MSGTIME) == 0) return ABORT; if (strncmp(InPacket + 1, "OK", 2)) { fprintf(log,"HandShake(): Remote doesn't like name %s", gtime()); return ABORT; } if (ReadPacket(InPacket, MSGTIME) == 0) return ABORT; if (InPacket[0] != 'P' && strchr(InPacket[1], 'g') == 0) { WritePacket("UN", TRUE); hserr: fprintf(log,"HandShake(): G Protocol not available %s", gtime()); return ABORT; } WritePacket("Ug", TRUE); return MASTER; } else { sprintf(OutPacket, "Shere=%.6s", myname); WritePacket(OutPacket, TRUE); if (ReadPacket(InPacket, MSGTIME) == 0) return ABORT; sscanf(InPacket, "S%s %s %s", Rmtname, t1, t2); sscanf(t2, "-x%d", &debug_level); if (CheckName()) return ABORT; WritePacket("ROK", TRUE); WritePacket("Pg", TRUE); if (ReadPacket(InPacket, MSGTIME) == 0) return ABORT; if (strcmp(InPacket, "Ug") != 0) goto hserr; return SLAVE; } } MasterHangup() { int len; if (SendPacket("H", 0, TRUE) == ERROR) return ABORT; if (ReceivePacket(InPacket, &len) == ERROR) return ABORT; if (strncmp(InPacket, "HN", 2) != 0) return SLAVE; return END; } /*--------------------------------------------------- * uucico Medium Level State Switching routines *--------------------------------------------------- */ Master() { register int state; state = MS_INIT; while (TRUE) { switch (state) { case MS_INIT: state = SendInit(); break; case MS_SCANDIR: state = ScanDirectory(); break; case MS_SEND: state = Send(); break; case MS_HANGUP: state = MasterHangup(); break; case MS_RECEIVE: state = Receive(); break; case MS_ABORT: return ABORT; } } } Slave() { register int state; state = MS_INIT; while (TRUE) { switch (state) { case MS_INIT: state = ReceiveInit(); break; case MS_RECEIVE: state = Receive(); break; case MS_CHKWORK: state = CheckForWork(); break; case MS_SCANDIR: state = ScanDirectory(); break; case MS_SEND: state = Send(); break; case MS_HANGUP: state = SlaveHangup(); break; case MS_ABORT: return ABORT; } } } /*------------------------------------------------ * uucico Low Level State Switching routines *------------------------------------------------ */ Send() { register int state; state = SS_HEADER; while (TRUE) { /* Do this as long as necessary */ switch (state) { case SS_HEADER: if (fd != (FILE *)NULL) { fprintf(log,"Send(): File already open in SS_HEADER %s", gtime()); state = SS_ABORT; } else state = SendFileHeader(); break; case SS_DATA: state = SendData(); break; case SS_EOF: state = SendEof(); break; case SS_END: fclose(fdC); #ifndef DEBUG unlink(Cfilename); #endif fdC = (FILE *)NULL; return MS_SCANDIR; case SS_ABORT: return MS_ABORT; } } } Receive() { register int state; state = SS_HEADER; while (TRUE) { switch (state) { case SS_HEADER: state = ReceiveFileHeader(); break; case SS_DATA: state = ReceiveData(); break; case SS_ABORT: return MS_ABORT; case SS_END: return MS_CHKWORK; } } } SendOO() { register int i; char msg[MAXLINE]; msg[1] = 0; for (i = 0; ((msg[1] != 'O') && (i < MAXTRY)); i++) { WritePacket("OOOOOO", TRUE); if (ReadPacket(msg, MSGTIME) == 0) break; } if (i == MAXTRY) fprintf(log, "SendOO(): Can't \"Over and Out\" with %s %s", Rmtname, gtime()); WritePacket("OOOOOO", TRUE); /* one last time for mama */ if (master) return INITIAL; else return ABORT; } SlaveHangup() { SendPacket("HY", 0, 2); /* don't wait for Acknowledge */ ClosePacket(); return END; } GetFile(header) register char *header; { register int i; char line[MAXLINE]; if (mfgets(line, sizeof line, fdC) == (char *)NULL) { fprintf(log,"GetFile(): Unexpected End Of File %s", gtime()); return ERROR; } sscanf(&line[2], "%s ", Filename); for (i = 0; line[i]; i++) if (strncmp(&line[i], "0666", 4) == 0) break; line[i+4] = '\0'; strcpy(header, line); /* now contains the whole line up past 0666 */ return OK; } CheckForWork() { register int c; c = ScanDirectory(); if (c == MS_ABORT) return MS_ABORT; if (c == MS_SEND) if (SendPacket("HN", 0, TRUE) == ERROR) return MS_ABORT; return MS_SEND; } ScanDirectory() { register DIR *dir; register struct direct *pdir; strcpy(Cfilename, "C."); strncat(Cfilename, Rmtname, 6); if ((dir = opendir(SPOOLDIR)) == (DIR *)NULL) { fprintf(log, "ScanDirectory(): Could not open %s %s", SPOOLDIR, gtime()); return MS_ABORT; } while ((pdir = readdir(dir)) != (struct direct *)NULL) { if (strncmp(pdir->d_name, Cfilename, MAXNAMLEN) == 0) { strncpy(Cfilename, pdir->d_name, (int)(pdir->d_namlen)); closedir(dir); if (fdC == (FILE *)NULL) { if ((fdC = fopen(Cfilename, "r")) == (FILE *)NULL) { fprintf(log,"ScanDirectory(): Could not open %s %s", Cfilename, gtime()); return MS_ABORT; } } return MS_SEND; } } closedir(dir); return MS_END; } /*--------------------------------------------------- * uucico G protocol High Level packet routines *--------------------------------------------------- */ SendInit() { if (OpenPacket() == ERROR) return MS_ABORT; return MS_SEND; } ReceiveInit() { if (OpenPacket() == ERROR) return MS_ABORT; return MS_RECEIVE; } SendFileHeader() { int len; char header[MAXLINE]; /* get next file from current work */ if (GetFile(header) == ERROR) return SS_END; /* end sending session */ if ((fd = fopen(Filename, "r")) == NULL) { fprintf(log, "SendFileHeader(): Can't open %s %s", Filename, gtime()); return SS_ABORT; } /* * Send the header */ if (SendPacket(header, 0, TRUE) == ERROR) return SS_ABORT; /* * Get the reply from remote */ if (ReceivePacket(InPacket, &len) == ERROR) return SS_ABORT; /* * Abort if remote doesn't say yes */ if (strncmp(InPacket, "SY", 2) != 0) { fprintf(log,"SendFileHeader(): Remote refused request %s", gtime()); return SS_ABORT; } /* * Scoop some poop */ size = fread(OutPacket, sizeof(char), PKTSIZE, fd); /* * Change to DATA state */ return SS_DATA; } ReceiveFileHeader() { int len; char fromfile[MAXLINE]; if (ReceivePacket(InPacket, &len) == ERROR) return SS_ABORT; if (strncmp(InPacket, "H", 1) == 0) return SS_END; sscanf(&InPacket[2], "%s %s ", fromfile, Filename); if ((fd = fopen(Filename, "w")) == NULL) { fprintf(log, "ReceiveFileHeader(): Can't create %s %s", Filename, gtime()); return SS_ABORT; } if (SendPacket("SY", 0, TRUE) == ERROR) return SS_ABORT; /* * Change to DATA state */ return SS_DATA; } SendData() { if (SendPacket(OutPacket, size, FALSE) == ERROR) return SS_ABORT; /* Get data from file */ if ((size = fread(OutPacket, sizeof(char), PKTSIZE, fd)) == 0) return SS_EOF; return SS_DATA; } SendEof() { int len; if (SendPacket("", 0, FALSE) == ERROR) return SS_ABORT; if (ReceivePacket(InPacket, &len) == ERROR) return SS_ABORT; /* rec CY or CN */ if (strncmp(InPacket, "CY", 2)) { fprintf(log, "SendEof(): Received %s expected CY %s", InPacket, gtime()); return SS_ABORT; } fclose(fd); fd = (FILE *)NULL; return SS_HEADER; /* go get the next file to send */ } ReceiveData() { int len; if (ReceivePacket(InPacket, &len) == ERROR) return SS_ABORT; if (len == 0) { fclose(fd); if (SendPacket("CY", 0, TRUE) == ERROR) return SS_ABORT; return SS_HEADER; } fwrite(InPacket, sizeof(char), len, fd); return SS_DATA; } /*----------------------------------------------------- * uucico G protocol Medium Level packet routines *----------------------------------------------------- */ ClosePacket() { char tmp[PKTSIZE]; spack(CLOSE, 0, 0, 0, tmp); spack(CLOSE, 0, 0, 0, tmp); } /* * INITA - INITC Handshake */ OpenPacket() { register int i, j; int npkrec, npksent, len; char tmp[PKTSIZE]; pkrec = 0; pksent = 1; pknerr = 0; for (j = INITA; j >= INITC; j--) { for (i = 0; i < MAXTRY; i++) { spack(j, 0, 0, 0, tmp); if (rpack(&npkrec, &npksent, &len, tmp) == j) goto nextinit; } fprintf(log,"OpenPacket(): Could not INIT Handshake %s", gtime()); return ERROR; nextinit:; } return OK; } ReceivePacket(data, len) register char *data; register int *len; { register int i, val; int npkrec, npksent, nlen, nakflg; char tmp[PKTSIZE]; nakflg = FALSE; for (i = 0; i < MAXTRY; i++) { switch (val = rpack(&npkrec, &npksent, &nlen, data)) { case DATA: if (npksent != ((pkrec + 1) % 8)) break; pkrec = (pkrec + 1) % 8; *len = nlen; if (nakflg) spack(RJ, pkrec, 0, 0, tmp); else spack(RR, pkrec, 0, 0, tmp); return OK; case CLOSE: fprintf(log,"ReceivePacket(): Received CLOSE from remote %s", gtime()); return ERROR; default: fprintf(log,"ReceivePacket(): rpack() returned %s %s", rcverr[abs(val)], gtime()); nakflg = TRUE; break; } } if (++pknerr >= MAXTRY) { fprintf(log,"ReceivePacket(): Too many packet errors %s", gtime()); return ERROR; } return OK; } /* * flg = 2 Just send the packet with no wait for ACK. * flg = TRUE Zero out the unused part of the buffer (for "msg" pkts). * flg = FALSE Normal data */ SendPacket(data, len, flg) register char *data; register int len, flg; { register int i, val; int nlen, npkrec, npksent; char tmp[PKTSIZE]; if (flg) { len = PKTSIZE; for (i = strlen(data); i < PKTSIZE; i++) data[i] = '\0'; } for (i = 0; i < MAXTRY; i++) { spack(DATA, pkrec, pksent, len, data); if (flg == 2) return OK; switch (val = rpack(&npkrec, &npksent, &nlen, tmp)) { case RR: case RJ: if (npkrec != pksent) break; /* Retry on wrong Packet Numbers */ pksent = (pksent + 1) % 8; return OK; case CLOSE: fprintf(log,"SendPacket(): Received CLOSE from remote %s", gtime()); return ERROR; default: fprintf(log,"SendPacket(): rpack() returned %s %s", rcverr[abs(val)], gtime()); } } if (++pknerr >= MAXTRY) { fprintf(log,"SendPacket(): Too many packet errors %s", gtime()); return ERROR; } return OK; } /* * Send a Packet */ spack(type, npkrec, npksent, len, packet) int type, npkrec, npksent, len; char *packet; { unsigned int check, i; char c, pkt[HDRSIZE]; if (len == 0) *packet = 0; pkt[0] = DLE; pkt[4] = type << 3; switch (type) { case CLOSE: break; case RR: case RJ: pkt[4] |= npkrec; break; case INITA: case INITC: pkt[4] |= WNDSIZE; /* window size */ break; case INITB: pkt[4] |= 1; /* segment size (1 = 64) */ break; case DATA: pkt[4] = 0x80 | (npksent << 3) | npkrec; /* * If packet length is less than 64 * then first byte needs to indicate the * difference. So shift everything right * and put the difference in first byte */ if (c = PKTSIZE - len) { pkt[4] |= 0x40; /* "short" data packet */ for (i = PKTSIZE - 1; i > 0; i--) packet[i] = packet[i - 1]; packet[0] = c; } } if (type != DATA) { pkt[1] = 9; /* control packet, size = 0 */ check = (unsigned)pkt[4]; } else { pkt[1] = PKTSIZ2; /* data packet, size = 64 */ check = checksum(packet, PKTSIZE); check = (check ^ (unsigned)pkt[4]); } check = (unsigned)0xAAAA - check; pkt[2] = check & 0xFF; pkt[3] = check >> 8; pkt[5] = (pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4]); WriteTTY(pkt, HDRSIZE); /* header is 6-bytes long */ if (pkt[1] != 9) WriteTTY(packet, PKTSIZE); /* data is always 64 bytes long */ } /* * Read Packet * * Returns: * +n Okey-Dokey; * -1 Input buffer empty; * -2 Bad header; * -3 Lost packet timeout; * -4 Checksum error; * -5 Wrong packet size */ rpack(npkrec, npksent, len, packet) register int *npkrec, *npksent, *len; register char *packet; { register unsigned type, check, checkchk; register int i; char c, pkt[HDRSIZE]; c = 0; while ((c & 0x7F) != DLE) if (ReadTTY(&c, 1, PKTTIME) < 1) return(-1); /* input buffer empty */ if (ReadTTY(&pkt[1], HDRSIZE - 1, PKTTIME) < (HDRSIZE - 1)) return(-1); /* input buffer empty */ /* header is 6-bytes long */ if (pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4] ^ pkt[5]) return(-2); /* bad header */ if ((pkt[1] & 0x7F) == 9) { /* control packet */ *len = 0; type = (unsigned)pkt[4] >> 3; *npkrec = (int)(pkt[4] & 0x07); *npksent = *packet = check = checkchk = 0; } else { /* data packet */ if ((pkt[1] & 0x7F) != PKTSIZ2) return(-5); /* can't handle other than size 64 */ type = DATA; c = pkt[4] & 0x3F; *npksent = (unsigned)c >> 3; *npkrec = (int)(c & 0x07); if (ReadTTY(packet, PKTSIZE, PKTTIME) < PKTSIZE) return(-3); /* packet timeout */ /* 64 byte packets even if partial */ check = ((unsigned)pkt[3] << 8) | (unsigned)pkt[2]; checkchk = checksum(packet, PKTSIZE); checkchk = (unsigned)0xAAAA-(checkchk^((unsigned)pkt[4]|0x80)); if (checkchk != check) return(-4); /* * See if a "short" packet was received * If so, delete the size difference in first byte */ *len = PKTSIZE; if (pkt[4] & 0x40) { *len -= *packet; for (i = 0; i < *len; i++) packet[i] = packet[i + 1]; } packet[*len] = 0; } return type; } unsigned checksum(data, n) register char *data; register int n; { register int sum, x; register unsigned t; sum = -1; x = 0; do { if (sum < 0) { sum <<= 1; sum++; } else sum <<= 1; t = sum; sum += (unsigned)*data++; x += sum ^ n; if ((unsigned)sum < t) sum ^= x; } while (--n > 0); return sum; } /*-------------------------------------------------- * uucico G protocol Low Level packet routines *-------------------------------------------------- */ WritePacket(msg, syn) register char *msg; register int syn; { if (syn) WriteTTY("\020", 1); WriteTTY(msg, strlen(msg)); if (syn) WriteTTY("", 1); } ReadPacket(msg, seconds) register char *msg; register int seconds; { register int i; char c; do { if (ReadTTY(&c, 1, seconds) == 0) { rperr: fprintf(log, "ReadPacket(): Input timed out %s", gtime()); return 0; } } while ((c = toascii(c)) != '\020'); dor (i = 0; i < MAXLINE && c ; i++) { if (ReadTTY(&c, 1, seconds) == 0) goto rperr; if ((c = toascii(c)) == '\n') msg[i] = c = '\0'; else msg[i] = c; } return(strlen(msg)); } /*------------------------------ * uucico TTY I/O routines *------------------------------ */ ReadTTY(data, len, seconds) register char *data; register int len, seconds; { register int count; int ClkInt(); if (setjmp(env)) return 0; signal(SIGALRM, ClkInt); /* execute ClkInt() if alarm */ alarm(seconds); /* goes off */ if ((count = fread(data, sizeof(char), len, input)) < 1) { alarm(0); return 0; } alarm(0); return count; } WriteTTY(data, len) register char *data; register int len; { fwrite(data, sizeof(char), len, output); } ClkInt() { longjmp(env, 1); } OpenTTY() { register int i, baud; i = 0; baud = DEFAULT_BAUD; /* * Check baud rate entry against table * change 'baud' to new code */ do { if (strcmp(speed, rates[i].code) == 0) { baud = rates[i].baudrate; break; } } while (rates[++i].baudrate != 0); input = fopen(Device, "r"); output = fopen(Device, "w"); if (input == NULL || output == NULL) { fprintf(log, "OpenTTY(): Failure opening device %s %s", Device, gtime()); return ERROR; } SetTTY(fileno(input), baud); SetTTY(fileno(output), baud); return OK; } CloseTTY() { register FILE *fdtty; stty(fileno(input), &OldSetting); stty(fileno(output), &OldSetting); fclose(input); fclose(output); if ((fdtty = fopen(DEVICES, "r+")) == (FILE *)NULL) { fprintf(log, "CloseTTY(): Can't re-open %s %s", DEVICES, gtime()); return; } fseek(fdtty, Dpos, 0); /* Dpos is computed in GetTTY() */ fputs("FREE", fdtty); fclose(fdtty); } SetTTY(tty, baud) register int tty, baud; { gtty(tty, &OldSetting); /* get the TTY settings */ gtty(tty, &NewSetting); /* copy old settings to new */ NewSetting.sg_speed = D8S1NONE; /* 8 Bits No Parity One Stop */ NewSetting.sg_flag = RAW & ~ECHO; /* no echo and no processing */ NewSetting.sg_prot = baud; /* slap in the given baud */ stty(tty, &NewSetting); /* set the TTY new settings */ } /* EOF */ SHAR_EOF fi # end of overwriting check if test -f 'uuxqt.c' then echo shar: will not over-write existing file "'uuxqt.c'" else cat << \SHAR_EOF > 'uuxqt.c' /* * uuxqt.c * * Command File Execute * * UniFLEX(tm) Version 2.1 * * Based on dcp.c Copyright (c) 1985, 1986, 1987 by Richard H. Lamb * Changes are Public Domain (p) March 1988 by S. R. Sampson * * This program searches for work files in the spool directory and * executes them. Work files have a X. prefix. * * It is executed by 'uucico', 'cron', or 'at' */ /* Includes */ #include "uucp.h" #include <sys/modes.h> #include <sys/fcntl.h> #include <sys/dir.h> /* defines MAXNAMLEN and directory stuff */ #include <string.h> #include <stdio.h> #include <time.h> #include <pwd.h> /* Defines */ #define MAXLINE 256 #define ERROR -1 /* Globals */ long stamp; char command[MAXLINE], input[MAXLINE], output[MAXLINE], line[MAXLINE]; char Cfilename[MAXNAMLEN+1], filename[MAXNAMLEN+1], ltime[32]; char systemname[16], username[16], user[16]; /* Forward Declarations */ char *mfgets(); main(argc, argv) int argc; char **argv; { register char *p; register FILE *fdC, *log; register DIR *dd; register struct direct *dir; struct passwd *pw; int inull, onull; /* * Read Configuration file * * The UniFLEX 2.3 C Compiler would not compile this * correctly from an include file. */ #undef CONFIG #define CONFIG "/gen/spooler/uucp/.Config" if ((log = fopen(CONFIG, "r")) != (FILE *)NULL) { mfgets(user, sizeof user, log); fclose(log); } else exit(1); /* * Change to spool directory */ chdir(SPOOLDIR); id ((dd = opendir(SPOOLDIR)) == (DIR *)NULL) exit(1); while ((dir = readdir(dd)) != (struct direct *)NULL) { if (strncmp(dir->d_name, "X.", 2) != 0) continue; strncpy(Cfilename, dir->d_name, dir->d_namlen); if ((fdC = fopen(Cfilename, "r")) == ERROR) continue; inull = onull = TRUE; while (mfgets(line, sizeof line, fdC) != NULL) { switch (line[0]) { case 'C': strcpy(command, &line[2]); break; /* * See if all required files are present */ case 'F': strcpy(filename, &line[2]); p = filename; while ((*p != ' ') && *p) p++; *p = '\0'; if (access(filename, 1) == ERROR) { /* * All files not present, go check * other work files and give up * on this one till next time */ goto not_ready; } break; case 'I': strcpy(input, &line[2]); inull = FALSE; break; case 'O': strcpy(output, &line[2]); onull = FALSE; break; case 'U': strcpy(username, &line[2]); p = username; while ((*p != ' ') && *p) p++; *p++ = '\0'; strcpy(systemname, p); break; default: break; } } if (inull) strcpy(input, "/dev/null"); if (onull) strcpy(output, "/dev/null"); sprintf(line,"%s <%s >%s", command, input, output); if ((log = fopen(XQTLOG, "a")) != ERROR) { time(&stamp); strcpy(ltime, ctime(&stamp)); ltime[strlen(ltime) - 1] = '\0'; fprintf(log, "%s %s %s %s\n", ltime, systemname, username, line); fclose(log); } if (system(line) != ERROR) { #ifndef DEBUG unlink(Cfilename); if (!inull) unlink(input); if (!onull) unlink(output); #endif } not_ready: fclose(fdC); } closedir(dd); } /* * mfgets (modified fgets) * * Same as fgets() only this version deletes '\n' */ char *mfgets(s, n, iop) register char *s; register int n; register FILE *iop; { register int c; register char *cs; cs = s; while (--n > 0 && (c = getc(iop)) != EOF) { if (c == '\n') { *cs = '\0'; break; } else *cs++ = c; } return((c == EOF && cs == s) ? (char *)NULL : s); } /* EOF */ SHAR_EOF fi # end of overwriting check # End of shell archive exit 0 -- Pete Lyall (OS9 Users Group VP)| DELPHI: OS9UGVP | Eaton Corp.(818)-706-5693 Compuserve: 76703,4230 (OS9 Sysop) OS9 (home): (805)-985-0632 (24hr./1200 baud) Internet: pete@wlbr.eaton.com UUCP: {ihnp4,scgvax,jplgodo,voder}!wlbr!pete