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.