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