Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (06/28/90)
Submitted-by: Matt Dillon <@uunet.uu.net:overload!dillon>
Posting-number: Volume 90, Issue 189
Archive-name: unix/uucp-1.06d/part11
#!/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 archive 11 (of 12)."
# Contents: uucp2/src/uucico/uucico.c
# Wrapped by tadguy@xanth on Thu Jun 28 08:21:37 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'uucp2/src/uucico/uucico.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'uucp2/src/uucico/uucico.c'\"
else
echo shar: Extracting \"'uucp2/src/uucico/uucico.c'\" \(33705 characters\)
sed "s/^X//" >'uucp2/src/uucico/uucico.c' <<'END_OF_FILE'
X
X/*
X * UUCICO.C
X *
X * $Header: Beta:src/uucp/src/uucico/RCS/uucico.c,v 1.1 90/02/02 11:56:01 dillon Exp Locker: dillon $
X *
X * (C) Copyright 1987 by John Gilmore.
X * Copying and use of this program are controlled by the terms of the Free
X * Software Foundation's GNU Emacs General Public License.
X *
X * Derived from:
X * i[$]uuslave.c 1.7 08/12/85 14:04:20
X * which came from the ACGNJ BBS system at +1 201 753 9758. Original
X * author unknown.
X *
X * Ported to Amiga by William Loftus
X * Amiga Changes Copyright 1988 by William Loftus. All rights reserved.
X * Additional Major Changes (c)Copyright 1989 by Matthew Dillon, All rights reserved
X *
X * 14-Oct-89, moved modem_init() to before poll_sys.
X *
X * -r option (-r1 does a call out to all systems we have mail for)
X * -D[EVICE] dev sets serial device name (automatic from Getty)
X * -U[NIT] unit sets unit name (automatic from Getty)
X * -h0 Ignore CD (carrier detect)
X * -7
X */
X
X
X#include "includes.h" /* System include files, system dependent */
X#include "uucp.h" /* Uucp definitions and parameters */
X#include <log.h>
X#include "version.h"
X
XPrototype int getname(int);
XPrototype int get_proto(void);
XPrototype int instr(char *, int);
XPrototype int twrite(const char *, int);
XPrototype void xlat_str(char *, char *);
XPrototype int read_ctl(void);
XPrototype int do_outbound(void);
XPrototype int call_system(char *, int);
XPrototype int call_sysline(char *);
XPrototype int do_session(int);
XPrototype int top_level(int);
XPrototype int do_one_slave(void);
XPrototype int do_one_master(void);
XPrototype int yesno(char, int, int);
XPrototype int host_send_file(char *);
XPrototype int host_receive_file(char *);
XPrototype int local_send_file(char *, int *);
XPrototype int local_receive_file(void);
XPrototype int receive_file(FILE *, char *, char *, char *, int);
XPrototype int send_file(FILE *);
X
X#define MAX_FLAGS 40
X
Xextern int errno;
X
XIDENT(".10");
X
Xstatic char *Copyright = COPYRIGHT;
X
Xchar ttynam[NAMESIZE], /* Name of tty we use as serial port */
X srcnam[NAMESIZE], /* Source file name */
X dstnam[NAMESIZE], /* Dest file name */
X who[NAMESIZE] = "-", /* Who sent the file */
X flags[MAX_FLAGS], /* Flags from file xfer cmd */
X temp[NAMESIZE]; /* Temp file name */
X
Xint ourpid = 0, /* Our process ID */
X ignore_time_restrictions = 0, /* Call out even if L.sys sez no */
X mode; /* File mode from file xfer cmd */
X
Xchar host_name[MAX_HOST] = "AmigaUUCP"; /* Other guy's host name */
Xchar our_name[MAX_HOST]; /* Our uucp hostname, set from usenet.ctl */
Xchar path[128];
Xint debug = -1; /* -1 indicates not set by command line or ctl file */
Xint f_wait = 0; /* wait for a call (-w) or calls (-w -e) after outbnd */
Xint loop = 0; /* Loop accepting logins if tty name specified */
Xint curtemp = 0;
Xint Overide = 0; /* overide modem protocol */
Xint Getty = 0; /* -Getty initiated */
Xint IgnoreCD= 0; /* xgetc() should ignore carrier? */
Xint OurNameOv= 0;
Xint WindowOne= 0;
Xint SevenWire= 0;
Xint XDebug = 0; /* do not pass debug parameter to remote */
X
X#define MAX_STRING 200 /* Max length string to send/expect */
X
X#define MSGO2IDX 7
X
X/* We print these prompts */
X
Xchar msgo0[] = "login: ";
Xchar msgo1[] = "Password:";
Xchar msgo2[10+MAX_HOST] = { "\20Shere" }; /* NO = */
Xchar msgo3[] = "\20ROK\0";
Xchar msgo3a[]= "\20P";
Xchar msgo3b[]= "\20Pg\0";
Xchar msgo4[] = "\20OOOOOOO\0";
X
X/* We expect to receive these strings */
X
Xchar msgi0[] = "uucp\r";
Xchar msgi1[] = "s8000\r";
X/* char msgi2[] = "\20S*\0"; We now scan it specially FIXME */
Xchar msgi3[] = "\20Ug\0";
Xchar msgi4[] = "OOOOOO";
X
X/*
X * Protocol switch data structure
X */
X
X#define turnon gturnon
X#define rdmsg grdmsg
X#define wrmsg gwrmsg
X#define rddata grddata
X#define wrdata gwrdata
X#define turnoff gturnoff
X
Xint
Xgetname(isshere)
Xint isshere;
X{
X int data, count = 0;
X static char msgi[MAX_STRING+SLOP]; /* Incoming trash buffer */
X
X /* Read data until null character */
X
X while ((data = xgetc(BYTE_TO)) != EOF) {
X data &= 0x7F;
X if (data == 020)
X break;
X }
X if (data == EOF)
X return FAIL;
X
X while ((data = xgetc(BYTE_TO)) != EOF && (data & 0x7F)) {
X data &= 0x7F;
X if (count == 0 && data != 'S')
X continue;
X if (count > sizeof(msgi) - 2)
X continue;
X msgi[count++] = (char)data;
X }
X msgi[count] = 0;
X
X if (debug > 8)
X printf("GETNAME MSG (%d): %s\n", count, msgi);
X
X if (msgi[0] != 'S')
X return FAIL;
X if (isshere) {
X for (count = 1; msgi[count] && msgi[count] != '='; ++count);
X if (msgi[count] == '=')
X ++count;
X } else {
X count = 1;
X }
X if (msgi[count]) {
X if (debug > 8)
X printf("Compare host names: '%s' '%s'\n", host_name, msgi + count);
X strcpy (host_name, msgi + count);
X }
X strtok(host_name, " \t"); /* put \0 after hostname */
X if (debug > 8)
X printf("Hostname is '%s'\n", host_name);
X return SUCCESS;
X}
X
X/*
X * get_proto() checks the list of protos given by the foriegn machine
X * checking for 'g' (which is the only proto we have). Use only in master
X * mode.
X */
X
Xint
Xget_proto()
X{
X int data;
X
X while ((data = xgetc(BYTE_TO)) != EOF) {
X data &= 0x7F;
X if (data == 0)
X break;
X if (data == 'g')
X return(SUCCESS);
X }
X return FAIL;
X}
X
X/*
X * Medium level input routine.
X *
X * Look for an input string for the send-expect sequence.
X * Return 0 for matching string, 1 for timeout before we found it.
X * FIXME: we only time out if the other end stops sending. If it
X * keeps sending, we keep listening forever.
X */
X
Xinstr(s, n)
Xchar *s;
Xint n;
X{
X int data,count,j;
X int i;
X static char msgi[512]; /* Incoming trash buffer */
X
X count = 0;
X
X if (debug > 8) {
X printf("Expecting ");
X for (i = 0; i < n; i++)
X printc(s[i]);
X printf("\n");
X }
X
X while ((data = xgetc(BYTE_TO)) != EOF) {
X msgi[count++] = (char)data & 0x7F;
X
X if (count == sizeof(msgi)) { /* throw away first half */
X count = sizeof(msgi) / 2;
X bcopy(msgi + sizeof(msgi) / 2, msgi, sizeof(msgi) / 2);
X }
X
X if (count >= n) {
X for (i = n - 1, j = count - 1; i >= 0; i--, j--) {
X if (*(s+i) != msgi[j])
X break;
X }
X if (i < 0) {
X if (debug > 8)
X printf("\n");
X return(0);
X }
X }
X }
X
X if (debug > 8)
X printf("\n");
X msgi[count] = (char)0;
X return(1);
X}
X
X/*
X * Debugging hack for stuff written to the modem.
X */
X
Xint
Xtwrite(s, n)
Xconst char *s;
Xint n;
X{
X int i;
X
X if (debug > 8) {
X printf("Wrote: ");
X for (i = 0; i < n; i++)
X printc(s[i]);
X printf("\n");
X }
X return xwrite(s, n);
X}
X
X/*
X * MAIN ROUTINE.
X *
X * This is called at program startup. It parses the arguments to the
X * program (if any) and sets up to receive a call on the modem.
X *
X * If there are no arguments, we assume the caller is already on standard
X * input, waiting to do uucp protocols (past the login prompt), and we
X * just handle one caller.
X *
X * If there is an argument, it is the name of the tty device where we
X * should listen for multiple callers and handle login and password.
X */
X
Xvoid
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X int i;
X char *poll_sys = (char *)NULL; /* System name to poll, or none */
X short rmode = 0; /* 1 = master, 0 = slave */
X
X LogProgram = "uucico";
X LogHost = host_name;
X LogWho = who;
X
X onbreak(sigint);
X
X /* FIXME, use getopt */
X /* scan command line arguments, kinda kludgy but it works */
X
X for (i = 1; i < argc; ++i) {
X if (argv[i][0] != '-') {
X printf("uucico: warning, extra args ignored: %s\n", argv[i]);
X break;
X }
X switch (argv[i][1]) {
X case 'N':
X strcpy(our_name, argv[i] + 2);
X OurNameOv = 1;
X break;
X case 'D': /* Serial Device */
X {
X extern char *DeviceName;
X DeviceName = argv[++i];
X }
X break;
X case 'U': /* Serial Unit */
X {
X extern long DeviceUnit;
X DeviceUnit = atoi(argv[++i]);
X }
X break;
X case 'g':
X case 'G':
X Getty = 1;
X break;
X case 'h':
X IgnoreCD = atoi(argv[i] + 2);
X break;
X case 'w':
X ++f_wait;
X break;
X case 'r':
X rmode = atoi(&argv[i][2]);
X break;
X case 'X':
X XDebug = 1;
X case 'x':
X debug = atoi(&argv[i][2]);
X LogLevel = debug;
X LogToStdout = 1;
X printf("uucico: debug level set to %d\n", debug);
X break;
X case 'o':
X Overide = 1;
X break;
X case 'n':
X WindowOne = 1; /* force windowing mode to size=1 */
X break;
X case 'S':
X ignore_time_restrictions++;
X case 's':
X poll_sys = &argv[i][2];
X break;
X case 'e':
X ++loop;
X break;
X /* Is -t needed for MSDOS? Why? -- hoptoad!gnu */
X case 't':
X curtemp++;
X printf("uucico: using ~uutemp.$$$ for temp file\n");
X break;
X case '7':
X SevenWire = 1;
X break;
X default:
X printf("uucico: warning, bad flag %s\n", argv[i]);
X break;
X }
X }
X
X /* If argument provided, use it as name of comm port */
X
X /* FIXME, this needs some thought. */
X
X getcwd(path,128);
X if (chdir(GetConfigDir(UUSPOOL))) {
X perror("Can't chdir to Spool directory");
X exit(2);
X }
X
X read_ctl();
X
X /*
X * If running via getty/login, our debug stdout had better
X * go to a file, not to the usual stdout!
X */
X
X if (debug > 0 && Getty) {
X freopen("T:uuslave.log", "a", stdout);
X }
X
X /*setvbuf(stdout, NULL, _IOLBF, 0);*/
X
X /* Timestamp the long debug log */
X
X if (debug > 0) {
X long clock;
X
X time(&clock);
X printf("\014\nuuslave log on tty '%s' starting %s\n",
X ttynam, ctime(&clock));
X }
X
X /* Log our presence so we humans reading the logs can find the
X entries created by uuslave. */
X
X ulog(-1, "Startup %s", VERSION);
X
X amiga_setup();
X
X modem_init();
X
X if (poll_sys) {
X if (*poll_sys == '\0')
X poll_sys = (char *)NULL;
X call_system(poll_sys, rmode);
X if (!f_wait)
X goto end;
X } else {
X if (rmode) {
X do_outbound();
X if (!f_wait)
X goto end;
X }
X }
X
X do {
X /*
X * Set up serial channel, wait for incoming call.
X */
X DEBUG(0, "\nRestarting\n", 0);
X
X if (Getty == 0 && Overide == 0)
X openline();
X
X do_session(Getty);
X
X hangup();
X DEBUG(0, "\nEnd of call\n", 0);
X } while (loop && !Getty);
X
Xend:
X cleanup();
X}
X
X/*
X * translate embedded escape characters
X */
X
Xvoid
Xxlat_str(msg, out)
Xchar *msg;
Xchar *out;
X{
X int i = 0;
X int cr = 1;
X /*int j = 0;*/
X
X while (msg[i]) {
X if (msg[i] == '\\') {
X switch (msg[++i]) {
X case 'r': /* carriage return */
X twrite("\r", 1);
X /*out[j++] = 0x0d;*/
X break;
X case 'n': /* line feed */
X twrite("\n", 1);
X /*out[j++] = 0x0a;*/
X break;
X case '\\': /* back slash */
X twrite("\\", 1);
X /*out[j++] = '\\';*/
X break;
X case 't': /* tab */
X twrite("\t", 1);
X /*out[j++] = '\t';*/
X break;
X case 'b':
X SendBreak();
X break;
X case 'd': /* delay */
X Delay(180);
X break;
X case 's': /* space */
X twrite(" ", 1);
X /*out[j++] = ' ';*/
X break;
X case 'c': /* no CR at end */
X cr = 0;
X break;
X default: /* don't know so skip it */
X break;
X }
X ++i;
X } else {
X twrite(msg + i, 1);
X ++i;
X /*out[j++] = msg[i++];*/
X }
X }
X if (cr) {
X twrite("\r", 1);
X /*out[j++] = 0x0d;*/
X }
X /*out[j] = '\0';*/
X}
X
X/*
X * Read the control file and grab a few parameters.
X */
X
Xint
Xread_ctl()
X{
X char *nodename = FindConfig(NODENAME);
X char *debugstr = FindConfig(DEBUGNAME);
X
X if (nodename && OurNameOv == 0)
X strcpy(our_name, nodename);
X if (debugstr && debug < 0)
X debug = atoi(debugstr);
X return (1);
X}
X
X/*
X * Search spool queues for work, call the systems we need to call.
X */
X
Xint
Xdo_outbound()
X{
X return call_system((char *)NULL, 1);
X}
X
X/*
X * Call a specific system, or all systems that have work pending.
X */
X
Xint
Xcall_system(sys, ifworkpend)
Xchar *sys;
X{
X FILE *lsys;
X static char buf[MAX_LSYS];
X static char sysnam[MAX_HOST];
X static char prev_name[MAX_HOST];
X int called = FAIL;
X
X /*
X * Unix uucico just reads the directory, and calls the systems
X * in the order of the files in the directory. We want more
X * control than that, though I'm not sure that L.sys order is
X * best either. For example, in the first call after 11PM,
X * I'd like to call the sites that haven't been callable before
X * 11PM first, and finish up with the ones I've been able to call
X * all day. FIXME.
X */
X
X if (! (lsys = fopen(MakeConfigPath(UULIB, "L.sys"), "r"))) {
X DEBUG(0, "uucico: can't open L.sys, errno %d\n", errno);
X return 0;
X }
X sysnam[0] = '\0'; /* Initially, no previous sys */
X
X /* Once per system in L.sys... */
X /* FIXME, handle continuation lines (trailing "\") */
X
X while (fgets(buf, sizeof buf, lsys)) {
X if (buf[0] == '#' || buf[0] == '\n')
X continue;
X
X /*
X * Grab the system name. If same as previous, and
X * the previous call worked, skip it.
X */
X
X strcpy(prev_name, sysnam);
X (void) sscanf(buf, "%s", sysnam);
X if (!strcmp(sysnam, prev_name)) {
X if (called == SUCCESS)
X continue;
X }
X
X /*
X * If a system name was specified, skip til we find it
X * If none was specified, only call if there is work.
X */
X
X if (sys) {
X if (strcmp(sys, sysnam) != 0)
X continue;
X if (ifworkpend && !work_scan(sysnam)) {
X ulog(-1, "No work for system %s", sysnam);
X called = SUCCESS;
X continue;
X }
X } else {
X DEBUG(3,"searching for outbound to %s\n", sysnam);
X if (!work_scan(sysnam)) {
X DEBUG(3,"no work for %s\n", sysnam);
X called = SUCCESS; /* Don't try further */
X continue;
X }
X DEBUG(2, "uucico: found work for %s\n", sysnam);
X }
X
X called = call_sysline(buf);
X
X if (called == SUCCESS && sys)
X break;
X }
X
X fclose(lsys);
X if (called == FAIL && sys)
X DEBUG(0, "Could not call system %s\n", sys);
X return 0;
X}
X
X/*
X * Call out to a system, given its L.sys line.
X */
X
Xint
Xcall_sysline(lsysline)
Xchar *lsysline;
X{
X static char tempname[MAX_HOST + 30 + SLOP];
X static char strbuf[MAX_STRING+SLOP];
X char *sysnam,
X *times,
X *acu,
X *sbaud,
X *telno,
X *send,
X *expct;
X int baud;
X
X who[0] = '-'; who[1] = '\0'; /* No user now (for logit) */
X
X /* FIXME, use the values it is ignoring here */
X
X sysnam = strtok(lsysline, " \t");
X times = strtok(NULL, " \t"); /* Time */
X acu = strtok(NULL, " \t"); /* ACU */
X sbaud = strtok(NULL, " \t"); /* Baud */
X telno = strtok(NULL," \t"); /* phone*/
X
X strcpy(host_name, sysnam);
X
X if (ignore_time_restrictions == 0) {
X if (CheckTimeRestrictions(times) == FAIL) {
X ulog(-1, "Wrong Time To Call %s", sysnam);
X return(FAIL);
X }
X }
X
X baud = atoi(sbaud);
X
X /* FIX ME, acu not implemented ? */
X DEBUG(4, "Opening outgoing line %s\n", acu);
X if (openout(acu, baud) != SUCCESS)
X return FAIL;
X
X if (Overide == 0) {
X if (dial_nbr(telno)) {
X ulog(-1, "FAILED call to %s", host_name);
X return FAIL;
X }
X }
X
X /* FIXME, log tty, baud rate, ... */
X ulog(-1, "DIALED %s", host_name);
X
X /*
X * Process send-expect strings.
X * FIXME, deal with "-", BREAK, etc.
X */
X
X while (send = (char*)strtok((char *)NULL, " \t")) {
X if (send[0] != '"' || send[1] != '"' || send[2] != '\0') {
X if (instr(send, strlen(send)))
X goto bort1;
X }
X
X if (expct = (char*)strtok((char *)NULL, " \t")) {
X /* FIXME secondary strings, e.g. ogin:-EOT-ogin: */
X xlat_str(expct, strbuf);
X
X /*twrite(strbuf, strlen(strbuf));*/
X }
X }
X
X /*
X * FIXME, there should be a way to detect login/passwd
X * failure here and keep doing the script rather than
X * continuing to expect Shere at another login: prompt.
X */
X
X ulog(-1, "SUCCEEDED call to %s", host_name);
X
X
X if (getname(1)) /* get name */
X goto bort1;
X /* send response */
X sprintf(tempname, "\20S%s -Q0 -x%d\0", our_name, (XDebug) ? 0 : debug);
X twrite(tempname, strlen(tempname)+1); /* Including null */
X
X /* wait for ok message, wait for protocol request
X * send protocol 'g' response */
X /* FIXME, we don't actually wait for the ROK message, since
X * it is immediately followed by the Pprotos message. We
X * currently just look for a Pg message. This needs work.
X * FIXME, WE CAN'T TALK TO SITES THAT SUPPORT more than 'g'.
X */
X
X if (instr(msgo3a, sizeof(msgo3a)-1)) {
X if (!get_proto())
X goto bort1;
X }
X
X
X twrite( msgi3, sizeof(msgi3)-1);
X
X ResetGIO(); /* reset GIO protocol */
X
X if (turnon(1))
X goto bort1;
X
X ulog(-1, "OK Startup");
X
X top_level(1);
X hangup();
X return SUCCESS;
X
Xbort1:
X hangup();
X return FAIL;
X}
X
X/* Handle a single uucp [slave] login session */
X
Xint
Xdo_session(ontheline)
Xint ontheline;
X{
X if (ontheline == 0) {
X /* output login request, verify uucp */
X twrite(msgo0,sizeof(msgo0)-1);
X if (instr(msgi0,sizeof(msgi0)-1)) {
X printf("uucico: invalid login name\n");
X goto bort;
X }
X
X /* output password request, verify s8000 */
X twrite(msgo1,sizeof(msgo1)-1);
X if (instr(msgi1,sizeof(msgi1)-1)) {
X printf("uucico: invalid password\n");
X goto bort;
X }
X
X printf("uucico: correct login\n");
X }
X
X /*
X * send Shere=<myhost>
X *
X * Apparently mac UUCP has a bug that only allows 7
X * char host names, and it fails if it gets shere=<myhost>
X * where <myhost> is > 7 chars.
X */
X
X /*strcpy(msgo2 + MSGO2IDX, our_name);*/
X twrite(msgo2,strlen(msgo2)+1);
X
X /*
X * get \020S<host> -Qn n (??)
X */
X
X if (getname(0))
X goto bort;
X
X /* output ok message, output protocol request, wait for response */
X
X twrite(msgo3,sizeof(msgo3)-1);
X
X /* FIXME, make the protocol list here, and use it */
X twrite(msgo3b,sizeof(msgo3b)-1);
X if (instr(msgi3,sizeof(msgi3)-1))
X goto bort;
X
X ResetGIO(); /* reset GIO protocol */
X
X if (turnon(0))
X goto bort;
X
X ulog(-1, "OK Startup");
X top_level(0);
X
Xbort:
X if (debug > 0)
X printf("uucico: call complete\n");
X return (1);
X}
X
X/*
X * Handle transactions "at top level", as Unix uucp's debug log says.
X *
X * As master, we scan our queues for work and send requests to the
X * other side. When done, we send a hangup request and switch to slave mode.
X *
X * As slave, we accept requests from the other side; when it is done,
X * it sends a hangup request, and we switch to master mode, if we have
X * any work queued up for that system.
X *
X * This repeats as long as either side has work to do. When all the
X * queued work is done, we agree to hang up, terminate the packet protocol,
X * and return to the caller. (We still haven't hung up the phone line yet.)
X *
X * A curious feature of the hangup protocol is that it is not a simple
X * question-answer. The master says "H", asking about hangup. The
X * slave responds "HY" saying OK. The master then says "HY" also,
X * then both of them hang up. Maybe this is to make sure the first HY
X * got ack'ed? Anyway, an "H" is reported as HANGUP and an "HY" as
X * HANGNOW. After we send an HY, we go back to listening for commands;
X * if the master sends something other than HY, we'll do it.
X */
X
X#define HANGUP 2 /* Signal to switch master/slave roles */
X#define HANGNOW 3 /* Signal to hang up now */
X#define COPYFAIL 4 /* File copy failed */
X
Xint
Xtop_level(master_mode)
Xint master_mode;
X{
X static char buf[MAXMSGLEN]; /* For hangup responses */
X
X
X if (master_mode) {
X (void) work_scan(host_name); /* Kick off queue scan */
X goto master;
X }
X
X for (;;) {
X slave: /* SLAVE SIDE */
X for (;;) {
X DEBUG(4, "*** TOP *** - slave\n", 0);
X switch (do_one_slave()) {
X case SUCCESS:
X break;
X case FAIL:
X return FAIL;
X case HANGUP:
X if (work_scan(host_name)) {
X if (wrmsg("HN"))
X return FAIL;
X goto master;
X } else {
X if (wrmsg("HY"))
X return FAIL;
X break; /* go to master mode */
X }
X case HANGNOW:
X goto quit;
X }
X }
X master: /* MASTER SIDE */
X for (;;) {
X DEBUG(4, "*** TOP *** - master\n", 0);
X switch (do_one_master()) {
X case SUCCESS:
X break;
X case FAIL:
X return FAIL;
X case HANGUP:
X /* We wrote an H command, what's the resp? */
X if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
X return FAIL;
X }
X if (buf[0] != 'H')
X return FAIL;
X if (buf[1] == 'N')
X goto slave;
X else {
X /* Write the final HY */
X if (wrmsg("HY"))
X return FAIL;
X goto quit;
X }
X }
X }
X }
X
Xquit:
X /* Shut down the packet protocol */
X
X turnoff();
X
X /* Write the closing sequence */
X
X twrite(msgo4, sizeof(msgo4)-1);
X (void) instr(msgi4, sizeof(msgi4)-1);
X
X twrite(msgo4, sizeof(msgo4)-1);
X
X strcpy(who, "-");
X ulog(-1, "OK Conversation complete");
X
X return SUCCESS; /* Go byebye */
X}
X
X/*
X * We are slave; get a command from the other side and execute it.
X *
X * Result is SUCCESS, FAIL, HANGUP, or HANGNOW.
X */
X
Xint
Xdo_one_slave()
X{
X static char msg[MAXMSGLEN]; /* Master's message to us */
X
X /* Get master's command */
X if (rdmsg(msg, MAXMSGLEN) != SUCCESS)
X return FAIL;
X
X /* Print it for easy debugging */
X DEBUG(5,"\nCommand: %s\n\n", msg);
X
X switch (msg[0]) {
X case 'S':
X if (msg[1] != ' ')
X break;
X return host_send_file(msg);
X case 'R':
X if (msg[1] != ' ')
X break;
X return host_receive_file(msg);
X case 'X':
X /*
X * Cause uuxqt to run (on certain files?)
X * See Protocol.doc for sketchy details.
X */
X break;
X case 'H':
X if (msg[1] == '\0') return HANGUP;
X if (msg[1] == 'Y') return HANGNOW;
X if (msg[1] == 'N') return SUCCESS; /* Ignore HN to slave */
X break;
X }
X
X /* Unrecognized packet from the other end */
X
X DEBUG(0, "Bad control packet refused: %s\n", msg);
X if (yesno(msg[0], 0, 0)) /* FIXME: return error code */
X return FAIL;
X return SUCCESS;
X}
X
X/*
X * Do one piece of work as master.
X *
X * FIXME: we don't handle the flags, e.g. -c, properly!
X *
X * Now only dequeues queue file if all transfers were successful.
X */
X
Xint
Xdo_one_master()
X{
X FILE *fd;
X char *sname;
X char cmnd[1]; /* Command character */
X static char buf[256];
X int fail = SUCCESS;
X int failaccum = 0;
X int num;
X int delmeflag;
X static char notify[NAMESIZE]; /* A bit large...FIXME */
X char *delList[16]; /* delete files list */
X short di = 0;
X
X /* FIXME: do the notify stuff */
X
X sname = work_next();
X if (!sname) {
X /* No more work, time to hang up. */
X if (wrmsg("H"))
X return FAIL;
X return HANGUP;
X }
X
X DEBUG(2, "Request file %s\n", sname);
X
X LockFile(sname);
X
X fd = fopen(sname, "r");
X if (fd == NULL) {
X UnLockFile(sname);
X DEBUG(0, "uucico: couldn't open %s\n", sname);
X return SUCCESS;
X }
X
X while (fgets(buf, sizeof buf, fd)) {
X DEBUG(3, "Queued request: %s", buf);
X
X if (buf[1] != ' ')
X goto badnum;
X
X num = sscanf(buf, "%s %s %s %s %s %s %o\n",
X cmnd, srcnam, dstnam, who, flags, temp, &mode, notify
X );
X
X switch (cmnd[0]) {
X case 'S':
X if (num < 7 || num > 8)
X goto badnum;
X fail = local_send_file(buf, &delmeflag);
X if (delmeflag) {
X if (di == sizeof(delList)/sizeof(delList[0])) {
X ulog(-1, "Too many source files in Cmd file! %s", sname);
X } else {
X delList[di] = malloc(strlen(temp) + 1);
X strcpy(delList[di], temp);
X ++di;
X }
X }
X break;
X case 'R':
X if (num != 5) {
X if (debug > 7)
X printf("Invalid scanf %d/5 :%s:%s:%s\n", num, cmnd, srcnam, dstnam);
X goto badnum;
X }
X fail = local_receive_file();
X break;
X default:
X badnum:
X DEBUG(0, "Unknown/invalid queued request: %s\n", buf);
X ++fail;
X break;
X }
X if (fail != SUCCESS)
X ++failaccum;
X
X /* FIXME, what does uucp do if one of N xfers fails? */
X
X if (fail == FAIL) {
X ulog(-1, "Error in work file %s", sname);
X ulog(-1, "Bad line is: %s", buf);
X }
X }
X fclose(fd);
X
X /*
X * If we successfuly copied everything zap the queue file
X * and any local data files...
X */
X
X if (failaccum == 0) {
X while (di) {
X --di;
X remove(delList[di]);
X free(delList[di]);
X }
X fail = remove(sname);
X UnLockFile(sname);
X if (fail != 0) {
X ulog(-1, "Unable to remove work file %s", sname);
X DEBUG(0, "Can't remove, errno %d\n", errno);
X } else {
X DEBUG(4, "Removed work file %s\n", sname);
X }
X } else {
X UnLockFile(sname);
X }
X return SUCCESS;
X}
X
X/* Send a "yes or no" packet with character 'c'. */
X
Xint
Xyesno(c, true, err)
Xchar c;
Xint true;
Xint err;
X{
X char buf[21];
X
X buf[0] = c;
X buf[1] = true? 'Y': 'N';
X buf[2] = 0;
X if (err && !true)
X sprintf(buf+2,"%d", err);
X
X return wrmsg(buf);
X}
X
X/*
X * SLAVE MODE, Master wishes to send a file to us
X *
X * SECURITY: If file is not in list of allowed directories
X * disallow transfer. UUSPOOL: is always in the
X * list.
X *
X * If file is for UUSPOOL: (the current dir), disallow "C." files
X * NOTE: success return and file redirected to T: as this can
X * occur only if somebody purposefully is trying to break us.
X *
X * Return 0 = success
X */
X
Xint
Xhost_send_file(msg)
Xchar *msg;
X{
X FILE *fddsk; /* Disk file pointer */
X char cmnd[1]; /* Command character */
X int r;
X int nor = 0;
X
X sscanf(msg,"%s %s %s %s %s %s %o",
X cmnd, srcnam, dstnam, who, flags, temp, &mode);
X
X ulog(-1, "REQUESTED %s", msg);
X munge_filename(dstnam, dstnam); /* Translate to local name */
X strcpy (temp, TmpFileName(dstnam)); /* Create a handy temp file */
X
X if (SecurityDisallow(dstnam, 'w')) {
X ulog(-1, "REQUEST FAILED -- SECURITY");
X if (yesno('S', 0, 4))
X return FAIL;
X return SUCCESS;
X }
X if (SecurityDisallow(dstnam, 'c') > 0) {
X ulog(-1, "REQUEST FAILED -- SECURITY, REMOTE TRIED TO SEND");
X ulog(-1, "US A COMMAND FILE: %s, FILE COPIED TO T:Bad-Cmd", dstnam);
X strcpy(dstnam, "T:Bad-Cmd");
X nor = 1;
X }
X
X /* FIXME: deal with file modes now that we fopen. */
X
X LockFile(temp);
X
X fddsk = fopen(temp, "wb" /*, mode|0600 */);
X if (fddsk == NULL) {
X UnLockFile(temp);
X /* Can't open file -- send error response */
X if (debug > 0) {
X printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
X temp,
X dstnam,
X errno
X );
X }
X ulog(-1, "REQUEST FAILED -- TEMP FILE");
X if (yesno('S', 0, 4))
X return FAIL;
X return SUCCESS;
X }
X
X /* FIXME: Are the above permissions right?? */
X /* FIXME: Should we create directories for the file? */
X
X if (yesno('S',1, 0)) { /* Say yes */
X fclose(fddsk);
X unlink(temp);
X UnLockFile(temp);
X return 1;
X }
X r = receive_file(fddsk, temp, dstnam, srcnam, nor);
X UnLockFile(temp);
X return(r);
X}
X
X/*
X * SLAVE MODE, Master wants us to send a file to it
X *
X * SECURITY: If file is not in list of allowed directories
X * disallow transfer. UUSPOOL: is always in the
X * list.
X *
X * 0 = sucess
X */
X
Xint
Xhost_receive_file(msg)
Xchar *msg;
X{
X FILE *fddsk; /* Disk file descriptor */
X int x;
X char cmnd[1]; /* Command character */
X
X ulog(-1, "REQUESTED %s", msg);
X
X sscanf(msg,"%s %s %s",cmnd,srcnam,dstnam);
X munge_filename(srcnam, temp);
X
X if (SecurityDisallow(temp, 'r')) {
X ulog(-1, "COPY FAILED -- SECURITY");
X if (yesno('S', 0, 4))
X return FAIL;
X return SUCCESS;
X }
X
X fddsk = fopen(temp, "rb"); /* Try to open the file */
X if (fddsk == NULL) {
X /* File didn't open, sigh. */
X if (debug > 0) {
X printf("Cannot open file %s (%s) for reading, errno=%d\n",
X temp, srcnam, errno
X );
X }
X ulog(-1, "DENIED CAN'T OPEN %s", temp);
X if (yesno('R', 0, 2))
X return 1;
X return 0;
X }
X
X if (yesno('R',1, 0)) { /* Say yes */
X fclose(fddsk);
X return 1;
X }
X
X x = send_file(fddsk);
X
X switch (x) {
X default:
X return x;
X case COPYFAIL:
X /* We don't care if the copy failed, since the master
X asked for the file and knows the result. */
X return SUCCESS;
X }
X return 1;
X}
X
X/*
X * MASTER MODE, We want to send a file.
X *
X * Return FAIL, SUCCESS, or COPYFAIL.
X *
X * SUCCESS is returned either if the file was not found locally (local
X * error, and the queued transfer should be flushed) or if it was moved
X * successfully. COPYFAIL indicates that the queued transfer should be
X * left queued, and later retried. FIXME, there are several failure points
X * in the transaction (see Protocol.doc) and we need finer control here.
X */
X
Xint
Xlocal_send_file(workstr, delmeflag)
Xchar *workstr;
Xint *delmeflag;
X{
X static char buf[MAXMSGLEN]; /* Used for both xmit and receive */
X FILE *fddsk; /* Disk file descriptor */
X int res; /* Result and file removal status */
X
X *delmeflag = 0;
X
X /* WHY are temp and srcnam switched? FIXME! And no notify? */
X
X sprintf(buf,"S %s %s %s %s %s 0%o %s",
X temp, dstnam, who, flags, srcnam, mode, who
X );
X
X ulog(-1, "REQUEST %s", buf);
X
X if (strchr(flags, 'c')) {
X munge_filename(srcnam, temp);
X } else {
X munge_filename(temp, temp);
X }
X LockFile(temp);
X fddsk = fopen(temp, "rb");
X if (fddsk == NULL) {
X UnLockFile(temp);
X /* FIXME -- handle queued request for nonexistent file */
X if (debug > 0)
X printf("Can't open file %s (%s), errno=%d\n",
X temp,
X srcnam,
X errno
X );
X ulog(-1, "NOT FOUND %s", temp);
X /* return COPYFAIL;*/
X return SUCCESS; /* assume file previously sent */
X }
X
X /* Tell the other side we want to send this file */
X
X if (wrmsg(buf) != SUCCESS) {
X DEBUG(0, "problem sending request\n", 0);
X fclose(fddsk);
X UnLockFile(temp);
X return FAIL;
X }
X
X /* See what they have to say about it */
X
X if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
X fclose(fddsk);
X UnLockFile(temp);
X return FAIL;
X }
X if ((buf[0] != 'S') || (buf[1] != 'Y')) {
X ulog(-1, "REQUEST DENIED %s", buf);
X fclose(fddsk);
X UnLockFile(temp);
X return FAIL;
X }
X res = send_file(fddsk); /* FAIL, SUCCESS, or COPYFAIL */
X
X /* Delete the source file if it was just a copy */
X
X if (res != SUCCESS) {
X UnLockFile(temp);
X return res;
X }
X if (strchr(flags, 'c')) { /* If copied direct from source */
X UnLockFile(temp);
X return res; /* ...just return. */
X }
X *delmeflag = 1;
X UnLockFile(temp);
X
X return res;
X}
X
X/*
X * MASTER MODE, We wish to receive a specific file so we ask for it
X *
X * Return 0 = success
X */
X
Xint
Xlocal_receive_file()
X{
X static char buf[MAXMSGLEN];
X FILE *fddsk; /* Disk file pointer */
X int r;
X
X /* FIXME, test dest file access before we ask for it. */
X
X sprintf(buf,"R %s %s %s %s %s 0%o %s",
X srcnam, dstnam, who, flags, temp, mode, who
X );
X
X munge_filename(dstnam, dstnam); /* tlate to local name */
X strcpy (temp, TmpFileName(dstnam)); /* Create a handy temp file */
X
X /* FIXME: deal with file modes now that we fopen. */
X /* FIXME: Are the above permissions right?? */
X /* FIXME: Should we create directories for the file? */
X
X LockFile(temp);
X fddsk = fopen(temp, "wb" /*, mode|060 */);
X
X if (fddsk == NULL) {
X UnLockFile(temp);
X /* Can't open temp file -- send error response */
X if (debug > 0) {
X printf("Cannot open temp file %s (%s) for writing, errno=%d\n",
X temp,
X dstnam,
X errno
X );
X }
X ulog(-1, "REQUEST FAILED -- TEMPFILE");
X return FAIL;
X }
X
X ulog(-1, "REQUEST %s", buf);
X if (wrmsg(buf) != SUCCESS) {
X fclose(fddsk);
X UnLockFile(temp);
X printf("uucico: problem sending request\n");
X return FAIL;
X }
X
X /* See what the other side has to say about it */
X
X if (rdmsg(buf, MAXMSGLEN) != SUCCESS) {
X fclose(fddsk);
X UnLockFile(temp);
X return FAIL;
X }
X if ((buf[0] != 'R') || (buf[1] != 'Y')) {
X ulog(-1, "REQUEST DENIED %s", buf);
X fclose(fddsk);
X UnLockFile(temp);
X return SUCCESS; /* FIXME, should do something more here */
X }
X
X r = receive_file(fddsk, temp, dstnam, srcnam, 0);
X UnLockFile(temp);
X return(r);
X}
X
X/*
X * General receive file
X */
X
Xint
Xreceive_file(fddsk, temp, dstnam, srcnam, norename)
XFILE *fddsk;
Xchar *temp, *dstnam, *srcnam;
X{
X int status;
X int error = 0; /* No errors so far */
X
X if (rddata(fddsk) != SUCCESS)
X error++;
X status = fclose(fddsk); /* Make sure the data got here */
X if (status != 0) {
X error++;
X DEBUG(0, "fclose errno=%d\n", errno);
X }
X
X /*
X * Move the file from its temp location to its real location,
X * This needs to be able to copy a file if a simple rename
X * does not suffice. Should create directories if necesary.
X * should use source ]name if target is a directory (i.e. no
X * target source name
X */
X
X unlink(dstnam);
X
X if (norename) /* for security redirect */
X status = 0;
X else
X status = rename(temp, dstnam);
X
X if (status != 0) {
X error++;
X if (debug > 0) {
X printf("Cannot rename file %s to %s, errno=%d\n",
X temp, dstnam, errno);
X }
X }
X
X ulog(-1, "COPY %s", error ? "FAILED": "SUCCEEDED");
X
X if (yesno('C', error == 0, 5)) /* Send yes or no */
X return FAIL;
X
X return SUCCESS;
X}
X
X/*
X * general file send routine
X * Return SUCCESS, FAIL, or COPYFAIL.
X */
X
Xint
Xsend_file(fddsk)
XFILE *fddsk; /* Disk file pointer */
X{
X static char ansbuf[MAXMSGLEN];
X
X if (wrdata(fddsk) != SUCCESS) {
X fclose(fddsk);
X return COPYFAIL;
X }
X fclose(fddsk);
X
X /* Await the "CY" or "CNddd" packet, and toss it. */
X
X while (1) {
X if (rdmsg(ansbuf, MAXMSGLEN) != SUCCESS)
X return COPYFAIL;
X if (ansbuf[0] != 'C') {
X DEBUG(0,"\nDidn't get 'CY' or 'CN', got %s\n", ansbuf);
X /* and loop looking for C message */
X } else if (ansbuf[1] == 'Y') {
X ulog(-1, "REQUESTED %s", ansbuf);
X return SUCCESS;
X } else {
X ulog(-1, "COPY FAILED %s", ansbuf);
X return COPYFAIL;
X }
X }
X return COPYFAIL;
X}
X
END_OF_FILE
if test 33705 -ne `wc -c <'uucp2/src/uucico/uucico.c'`; then
echo shar: \"'uucp2/src/uucico/uucico.c'\" unpacked with wrong size!
fi
# end of 'uucp2/src/uucico/uucico.c'
fi
echo shar: End of archive 11 \(of 12\).
cp /dev/null ark11isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 12 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.