[comp.sources.amiga] v90i189: UUCP 1.06D - UNIX compatible uucp/news/mail system, Part11/12

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.