/* * @(#)uuslave.c Version hoptoad-1.21 87/08/14 * * (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. */ char version[] = "Version Amiga-0.30 BETA"; #include "includes.h" /* System include files, system dependent */ #include "uucp.h" /* Uucp definitions and parameters */ #include "sysdep.h" /* System dependent parts of gnuucp */ #include "modem.h" /* Modem commands */ int sigint(); void modem_init(); void cleanup(); #define MAX_FLAGS 40 #ifndef LOG #define logit(one, two) /* Nothing */ #else void logit(); #endif extern int errno; 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 logfd, /* file desc of uucp logfile */ 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"; /* Other guy's host name */ char our_name[MAX_HOST]; /* Our uucp hostname, set from usenet.ctl */ char spool_dir[128]; char path[128]; int debug = -1; /* -1 indicates not set by command line or ctl file */ int f_wait = 0; /* FIXME, unreferenced now */ int loop = 1; /* Loop accepting logins if tty name specified */ int curtemp = 0; #define MAX_STRING 200 /* Max length string to send/expect */ /* We print these prompts */ char msgo0[] = "login: "; char msgo1[] = "Password:"; char msgo2[] = "\20Shere\0"; 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"; #define SPOOLDIR "UUCP:SPOOL" /* * Protocol switch data structure */ extern int gturnon(), grdmsg(), gwrmsg(), grddata(), gwrdata(), gturnoff(); #define turnon gturnon #define rdmsg grdmsg #define wrmsg gwrmsg #define rddata grddata #define wrdata gwrdata #define turnoff gturnoff /* * FIXME, comment this, make formatting match, etc. * get the calling hosts name from his response to Shere= * Result is in global variable host_name. */ int getname() { int data, count = 0; char msgi[MAX_STRING+SLOP]; /* Incoming trash buffer */ /* Read data until null character */ while ( ((data = xgetc()) != EOF) && (data != 0x00)) msgi[count++] = (char)data & 0x7F; if (msgi[0] = 'S') { strcpy (host_name, strtok(msgi, "\20S ")); return SUCCESS; } return FAIL; } /* 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()) != EOF) && (data != 0x00)) { if ((char)data == 'g') { return SUCCESS; /* System we are talking to has 'g' */ } } 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; /* FIXME, msgi is WAY too small to handle a large /etc/motd! */ static char msgi[512]; /* Incoming trash buffer */ count = 0; if (debug > 8) { printf("Expecting "); for (i = 0; i < n; i++) printf("%02x%c ",s[i] & 0xFF, isprint(s[i])? s[i]: ' '); printf("\nR "); } while ((data = xgetc()) != EOF) { msgi[count++] = (char)data & 0x7F; if (debug > 8) { printf("%02x%c ",msgi[count-1], isprint(msgi[count-1])? msgi[count-1]: ' '); } if (count == 512) { logit("OVERRAN message buffer\n"); sigint(); } 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) char *s; int n; { int i; if (debug > 8) { printf("Wrote: "); for (i = 0; i < n; i++) printf("%02x%c ",s[i] & 0xFF, isprint(s[i])? s[i]: ' '); printf("\n"); } return xwrite(s, n); } void create_lock() { FILE *fd; if (access(LOCK_FILE,0) != -1) { printf("UUCP is locked.\n"); exit(2); } if (!(fd = fopen(LOCK_FILE, "w"))) { printf("UUCP can't be locked.\n"); exit(3); } fclose(fd); } void destroy_lock() { if (unlink(LOCK_FILE)) { printf("Couldn't remove lock.\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 ontheline = 0; /* for amiga */ int i; char *poll_sys = (char *)NULL; /* System name to poll, or none */ signal(SIGINT,sigint); /* Allow the user to break */ create_lock(); /* FIXME, use getopt */ /* scan command line arguments, kinda kludgy but it works */ for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; switch (argv[i][1]) { case 'w': f_wait++; printf("uucico: will wait for call after outbound\n"); break; case 'x': debug = atoi(&argv[i][2]); printf("uucico: debug level set to %d\n", debug); break; case 'S': ignore_time_restrictions++; case 's': poll_sys = &argv[i][2]; ontheline = 0; break; case 'e': loop++; printf("uucico: endless loop mode\n"); break; /* Is -t needed for MSDOS? Why? -- hoptoad!gnu */ case 't': curtemp++; printf("uucico: using ~uutemp.$$$ for temp file\n"); break; } } /* If argument provided, use it as name of comm port */ /* FIXME, this needs some thought. */ if (!ontheline) { getcwd(path,128); if (chdir(SPOOLDIR)) { perror("Can't chdir to Spool directory"); destroy_lock(); exit(2); } } read_ctl(); /* Read control file FIXME */ /* * If running via getty/login, our debug stdout had better * go to a file, not to the usual stdout! */ if (debug > 0 && ontheline) { freopen("uuslave.log", "a", stdout); } setbuf(stdout, (char *)NULL); /* Unbuffered debug output */ /* 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. */ logit("Amiga", version); amiga_setup(); if (poll_sys) { if (*poll_sys == '\0') poll_sys = (char *)NULL; call_system(poll_sys); if (!f_wait) goto end; } modem_init(); do { /* * Set up serial channel, wait for incoming call. */ DEBUG(0, "\nRestarting\n", 0); openline(); do_session(ontheline); hangup(); DEBUG(0, "\nEnd of call\n", 0); } while (loop && !ontheline); end: cleanup(); destroy_lock(); } /* * translate embedded escape characters * */ void xlat_str(msg, out) char *msg; char *out; { int i = 0, cr = 1, j = 0; while (msg[i]) { if (msg[i] == '\\') { switch (msg[++i]) { case 'r': /* carriage return */ out[j++] = 0x0d; break; case 'n': /* line feed */ out[j++] = 0x0a; break; case '\\': /* back slash */ out[j++] = '\\'; break; case 't': /* tab */ out[j++] = '\t'; break; case 'd': /* delay */ Delay(180); break; case 's': /* space */ out[j++] = ' '; break; case 'c': /* no CR at end */ cr = 0; break; default: /* don't know so skip it */ break; } i++; } else out[j++] = msg[i++]; } if (cr) out[j++] = 0x0d; out[j] = '\0'; } /* * Read the control file and grab a few parameters. */ read_ctl() { FILE *fd; char buf[MAX_CTLLINE]; if (! (fd = fopen("UUCP:lib/config", "r"))) { printf("Can't Find config file"); chdir(path); destroy_lock(); exit(3); } /* find path to inbound news */ spool_dir[0] = '\0'; while (NULL != fgets(buf, sizeof buf, fd)) { if (strncmp(buf, "Spool", 5) == 0) strcpy(spool_dir, strtok(&buf[6], CTL_DELIM) ); else if (strncmp(buf, "NodeName", 8) == 0) strcpy(our_name, strtok(&buf[9], CTL_DELIM) ) ; else if (strncmp(buf, "Debug", 5) == 0) if (debug < 0) debug = atoi(strtok(&buf[6], CTL_DELIM)); } fclose(fd); return (1); } /* * Search spool queues for work, call the systems we need to call. */ do_outbound() { return call_system((char *)NULL); } /* * Call a specific system, or all systems that have work pending. */ call_system(sys) char *sys; { FILE *lsys; char buf[MAX_LSYS]; char sysnam[MAX_HOST]; 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("uucp:lib/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] == '#') 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 (0 != strcmp(sys, sysnam)) 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. */ call_sysline(lsysline) char *lsysline; { char tempname[MAX_HOST + 30 + SLOP], *sysnam, *times, *acu, *sbaud, *telno, *send, *expct; char logbuf[MAX_HOST+30+SLOP]; char strbuf[MAX_STRING+SLOP]; int baud; who[0] = '-'; who[1] = '\0'; /* No user now (for logit) */ /* FIXME, use the values it is ignoring here */ sysnam = (char*)strtok(lsysline, " "); times = (char*)strtok((char *)NULL, " "); /* Time */ acu = (char*)strtok((char *)NULL, " "); /* ACU */ sbaud = (char*)strtok((char *)NULL, " "); /* Baud */ telno = (char*)strtok((char *)NULL," "); /* phone */ strcpy(host_name, sysnam); if ((!ignore_time_restrictions) && (strcmp(times,"Any"))) { /* FIXME, check the time parameter and return FAIL if * it does not allow calls now. Meanwhile, bounce * all calls unless -S is specified. */ logit("WRONG TIME TO CALL", sysnam); return FAIL; } baud = atoi(sbaud); /* FIXME, this needs work for the ACU parameter */ /* Currently depends on symlink from /usr/spool/uucp/ACU !! */ DEBUG(4, "Opening outgoing line %s\n", acu); if (openout(acu, baud) != SUCCESS) return FAIL; sprintf(logbuf, "call to %s", host_name); if (dial_nbr(telno)) { logit("FAILED", logbuf); return FAIL; } /* FIXME, log tty, baud rate, ... */ logit("DIALED", host_name); /* * Process send-expect strings. * FIXME, deal with "-", BREAK, etc. */ while (send = (char*)strtok((char *)NULL, " ")) { if (send[0] != '"' || send[1] != '"' || send[2] != '\0') if (instr(send, strlen(send))) goto bort1; if (expct = (char*)strtok((char *)NULL, " ")) { /* FIXME secondary strings, e.g. ogin:-EOT-ogin: */ /* This puts delays in the wrong place, FIXME */ 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. */ logit("SUCCEEDED", logbuf); /* wait for Shere message, send response */ /* FIXME, grab hostname and check it if provided? */ sprintf(tempname, "\20Shere"); if (instr(tempname, strlen(tempname))) goto bort1; sprintf(tempname, "\20S%s -Q0 -x%d\0", our_name, 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); if (turnon(1)) goto bort1; logit("OK", "startup"); top_level(1); hangup(); return SUCCESS; bort1: hangup(); return FAIL; } /* Handle a single uucp [slave] login session */ do_session(ontheline) int ontheline; { if (!ontheline) { /* 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"); } /* output here message, wait for response */ twrite(msgo2,sizeof(msgo2)-1); /* FIXME, handle this kludge */ /* if (instr(msgi2,sizeof(msgi2)-1)) */ if (getname()) 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; if (turnon(0)) goto bort; logit("OK", "startup"); top_level(0); bort: 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; { char buf[MAXMSGLEN]; /* For hangup responses */ if (master_mode) { (void) work_scan(host_name); /* Kick off queue scan */ goto master; } for (;;) { /* Slave side */ slave: 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('H', "N")) return FAIL; goto master; } else { if (wrmsg('H', "Y")) return FAIL; break; } case HANGNOW: goto quit; } } /* Master side */ master: 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) != SUCCESS) return FAIL; if (buf[0] != 'H') return FAIL; if (buf[1] == 'N') goto slave; else { /* Write the final HY */ if (wrmsg('H', "Y")) 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); logit("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() { char msg[MAXMSGLEN]; /* Master's message to us */ /* Get master's command */ if (rdmsg(msg) != 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! */ int do_one_master() { FILE *fd; char *sname; char cmnd[1]; /* Command character */ char buf[256]; int fail; int num; char notify[NAMESIZE]; /* A bit large...FIXME */ /* 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); fd = fopen(sname, "r"); if (fd == NULL) { 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); break; case 'R': if (num != 5) goto badnum; fail = local_receive_file(buf); break; default: badnum: DEBUG(0, "Unknown/invalid queued request: %s\n", buf); fail++; break; } /* FIXME, what does uucp do if one of N xfers fails? */ if (fail == FAIL) { logit("ERROR IN WORK FILE", sname); logit("BAD LINE IS", buf); } } fclose(fd); /* Zap the queue file, if file was copied successfully, or */ /* if it was a complete success, but not if it was a COPY_FAIL */ if (fail != COPYFAIL) { fail = remove(sname); if (fail != 0) { logit("CAN'T REMOVE WORK FILE", sname); DEBUG(0, "Can't remove, errno %d\n", errno); } else { DEBUG(4, "Removed work file %s\n", 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[20]; buf[0] = true? 'Y': 'N'; buf[1] = 0; if (err && !true) sprintf(buf+1,"%d", err); return wrmsg(c, buf); } /* * Master wishes to send a file to us -- we receive it. * Return 1 to abort the call, 0 to continue. */ int host_send_file(msg) char *msg; { FILE *fddsk; /* Disk file pointer */ char cmnd[1]; /* Command character */ sscanf(msg,"%s %s %s %s %s %s %o", cmnd, srcnam, dstnam, who, flags, temp, &mode); logit("REQUESTED", msg); strcpy (dstnam, munge_filename(dstnam)); /* Translate to local name */ strcpy (temp, temp_filename(dstnam)); /* Create a handy temp file */ /* FIXME: deal with file modes now that we fopen. */ fddsk = fopen(temp, "wb" /*, mode|0600 */); if (fddsk == NULL) { /* 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); } logit("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 */ return 1; return receive_file(fddsk, temp, dstnam, srcnam); } /* * Master wants to Recieve a file from us -- we send it. * Return 1 to abort the call, 0 to continue. */ host_receive_file(msg) char *msg; { FILE *fddsk; /* Disk file descriptor */ int x; char cmnd[1]; /* Command character */ logit("REQUESTED", msg); sscanf(msg,"%s %s %s",cmnd,srcnam,dstnam); strcpy (temp, munge_filename(srcnam)); 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); } logit("DENIED", "CAN'T OPEN"); if (yesno('R', 0, 2)) return 1; return 0; } if (yesno('R',1, 0)) /* Say yes */ 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; } /* * We, as master, 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) char *workstr; { char buf[MAXMSGLEN]; /* Used for both xmit and receive */ FILE *fddsk; /* Disk file descriptor */ int res, status; /* Result and file removal status */ /* 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); logit("REQUEST", buf); if (strchr(flags, 'c')) { strcpy(temp, munge_filename(srcnam)); } else { strcpy(temp, munge_filename(temp)); } fddsk = fopen(temp, "rb"); if (fddsk == NULL) { /* FIXME -- handle queued request for nonexistent file */ if (debug > 0) printf("Can't open file %s (%s), errno=%d\n", temp, srcnam, errno); logit("NOT FOUND", temp); return COPYFAIL; /* FIXME caller won't deal with this */ } /* Tell the other side we want to send this file */ if (wrmsg('S', buf+1) != SUCCESS) { DEBUG(0, "problem sending request\n", 0); return FAIL; } /* See what they have to say about it */ if (rdmsg(buf) != SUCCESS) return FAIL; if ((buf[0] != 'S') || (buf[1] != 'Y')) { logit("REQUEST DENIED", buf); return FAIL; } res = send_file(fddsk); /* FAIL, SUCCESS, or COPYFAIL */ /* Delete the source file if it was just a copy */ if (res != SUCCESS) return res; if (strchr(flags, 'c')) /* If copied direct from source */ return res; /* ...just return. */ status = remove(temp); /* Delete uucp's copy of the file */ if (status != 0) { logit("CAN'T REMOVE SENT FILE", temp); DEBUG(0, "Can't remove, errno %d\n", errno); } else { DEBUG(4, "Removed sent file %s\n", temp); } return res; } /* * We want to Receive a file -- so we ask for it. * Return 1 to abort the call, 0 to continue. */ int local_receive_file() { char buf[MAXMSGLEN]; FILE *fddsk; /* Disk file pointer */ /* 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); strcpy (dstnam, munge_filename(dstnam)); /* Translate to local name */ strcpy (temp, temp_filename(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? */ fddsk = fopen(temp, "wb" /*, mode|060 */); if (fddsk == NULL) { /* 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); } logit("REQUEST", "FAILED -- TEMPFILE"); return FAIL; } logit("REQUEST", buf); if (wrmsg('R', buf+1) != SUCCESS) { printf("uucico: problem sending request\n"); return FAIL; } /* See what the other side has to say about it */ if (rdmsg(buf) != SUCCESS) return FAIL; if ((buf[0] != 'R') || (buf[1] != 'Y')) { logit("REQUEST DENIED", buf); return SUCCESS; /* FIXME, should do something more here */ } return receive_file(fddsk, temp, dstnam, srcnam); /* FIXME - We should deal with files that didn't get there */ } /* general file receive routine */ int receive_file(fddsk, temp, dstnam, srcnam) FILE *fddsk; /* Disk file pointer */ 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 loc */ /* FIXME: This needs to be able to copy the file, if a simple rename does not suffice. */ /* FIXME: should create directories if necessary, e.g. D. or subdirs of /usr/spool/uucppublic. */ /* FIXME: should use source name if target is a directory e.g. ~/ */ status = rename(temp, dstnam); if (status != 0) { error++; if (debug > 0) { printf("Cannot rename file %s to %s, errno=%d\n", temp, dstnam, errno); } } logit("COPY", 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 */ { char ansbuf[MAXMSGLEN]; if (wrdata(fddsk) != SUCCESS) return COPYFAIL; (void) fclose(fddsk); /* Await the "CY" or "CNddd" packet, and toss it. */ while (1) { if (rdmsg(ansbuf) != 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') { logit("REQUESTED", ansbuf); return SUCCESS; } else { logit("COPY FAILED", ansbuf); return COPYFAIL; } } return COPYFAIL; } #ifdef LOG /* * Log file writing subroutine. * * Makes incredibly ugly log entries that look *just like* Unix uucp's * incredibly ugly log entries. * * Once we don't care about compatability, we should do this much better. */ void logit(one, two) char *one, *two; { char logbuf[(NAMESIZE*4)+SLOP+50]; /* Temp buffer for logs */ long clock; struct tm *ut; int len; if (0 > (logfd = open("LOGFILE", O_CREAT|O_WRONLY|O_APPEND, 0644))) { perror("Can't open LOGFILE"); chdir(path); destroy_lock(); exit(2); } (void) time(&clock); ut = localtime(&clock); sprintf(logbuf, "%s %s (%d/%d-%d:%02d:%02d-%d) %s (%s)\n", who, host_name, ut->tm_mon+1, ut->tm_mday, ut->tm_hour, ut->tm_min, ut->tm_sec, ourpid, one, two); DEBUG(0, "%s", logbuf); len = strlen(logbuf); if (len != write(logfd, logbuf, len)) { if (debug > 0) { printf("Can't log to logfd, terminating!\n"); perror("LOGFILE"); } sigint(); /* Terminate if we can't log */ } close(logfd); logfd = 0; } #endif