home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------*/
- /* d c p . c */
- /* */
- /* Main routines for UUCICO */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* Changes Copyright (c) 1989-1993 by Kendra Electronic */
- /* Wonderworks. */
- /* */
- /* All rights reserved except those explicitly granted by the */
- /* UUPC/extended license agreement. */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* Copyright (c) Richard H. Lamb 1985, 1986, 1987 */
- /* Changes Copyright (c) Stuart Lynne 1987 */
- /*--------------------------------------------------------------------*/
-
- /*
- * $Id: dcp.c 1.20 1993/10/03 20:37:34 ahd Exp $
- *
- * $Log: dcp.c $
- * Revision 1.20 1993/10/03 20:37:34 ahd
- * Don't attempt to suspend port if using network protocol suite
- *
- * Revision 1.19 1993/09/30 03:06:28 ahd
- * Move suspend signal handler into suspend2
- *
- * Revision 1.18 1993/09/29 13:18:06 ahd
- * Don't call suspend handler under DOS Turbo C++ (not impletemented, anyway)
- *
- * Revision 1.17 1993/09/29 04:52:03 ahd
- * Suspend port by port name, not modem file name
- *
- * Revision 1.16 1993/09/27 00:48:43 ahd
- * Control UUCICO in passive mode by K. Rommel
- *
- * Revision 1.15 1993/09/20 04:46:34 ahd
- * OS/2 2.x support (BC++ 1.0 support)
- * TCP/IP support from Dave Watt
- * 't' protocol support
- *
- * Revision 1.14 1993/08/02 03:24:59 ahd
- * Further changes in support of Robert Denny's Windows 3.x support
- *
- * Revision 1.13 1993/07/31 16:26:01 ahd
- * Changes in support of Robert Denny's Windows support
- *
- * Revision 1.12 1993/07/22 23:22:27 ahd
- * First pass at changes for Robert Denny's Windows 3.1 support
- *
- * Revision 1.11 1993/05/30 00:01:47 ahd
- * Allow tracing connection via UUCICO -t flag
- *
- * Revision 1.10 1993/04/11 00:35:46 ahd
- * Global edits for year, TEXT, etc.
- *
- * Revision 1.9 1993/04/05 04:32:19 ahd
- * Allow unique send and receive packet sizes
- *
- * Revision 1.8 1993/01/23 19:08:09 ahd
- * Don't update host status at sysend() if hostp is not initialized
- *
- * Revision 1.7 1992/12/18 12:05:57 ahd
- * Suppress duplicate machine state messages to improve OS/2 scrolling
- *
- * Revision 1.6 1992/12/01 04:37:03 ahd
- * Add standard comment block for header
- *
- * Revision 1.5 1992/11/28 19:51:16 ahd
- * If in multitask mode, only open syslog on demand basis
- *
- * Revision 1.4 1992/11/22 21:30:55 ahd
- * Do not bother to strdup() string arguments
- *
- * 25Aug87 - Added a version number - Jal
- * 25Aug87 - Return 0 if contact made with host, or 5 otherwise.
- * 04Sep87 - Bug causing premature sysend() fixed. - Randall Jessup
- * 13May89 - Add date to version message - Drew Derbyshire
- * 17May89 - Add '-u' (until) option for login processing
- * 01 Oct 89 Add missing function prototypes
- * 28 Nov 89 Add parse of incoming user id for From record
- * 18 Mar 90 Change checktime() calls to Microsoft C 5.1
- */
-
- /*--------------------------------------------------------------------*/
- /* This program implements a uucico type file transfer and remote */
- /* execution protocol. */
- /* */
- /* Usage: UUCICO [-s sys] */
- /* [-r 0|1] */
- /* [-x debug] */
- /* [-d hhmm] */
- /* [-m modem] */
- /* [-l logfile] */
- /* [-x debuglevel] */
- /* [-w userid] */
- /* [-z bps] */
- /* [-t] */
- /* */
- /* e.g. */
- /* */
- /* UUCICO [-x n] -r 0 [-d hhmm] client mode, wait for an incoming */
- /* call for 'hhmm'. */
- /* UUCICO [-x n] -s HOST call the host "HOST". */
- /* UUCICO [-x n] -s all call all known hosts in the systems */
- /* file. */
- /* UUCICO [-x n] -s any call any host we have work queued for. */
- /* UUCICO [-x n] same as the above. */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* System include files */
- /*--------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <limits.h>
- #include <time.h>
-
- #ifdef _Windows
- #include <Windows.h>
- #endif
-
- /*--------------------------------------------------------------------*/
- /* UUPC/extended prototypes */
- /*--------------------------------------------------------------------*/
-
- #include "lib.h"
- #include "arpadate.h"
- #include "catcher.h"
- #include "checktim.h"
- #include "dcp.h"
- #include "dcplib.h"
- #include "dcpstats.h"
- #include "dcpsys.h"
- #include "dcpxfer.h"
- #include "expath.h"
- #include "getopt.h"
- #include "hlib.h"
- #include "hostable.h"
- #include "hostatus.h"
- #include "lock.h"
- #include "logger.h"
- #include "modem.h"
- #include "security.h"
- #include "ssleep.h"
- #include "suspend.h"
- #include "commlib.h"
-
- #if defined(_Windows)
- #include "winutil.h"
- #endif
-
-
- /*--------------------------------------------------------------------*/
- /* Define passive and active polling modes; passive is */
- /* sometimes refered to as "slave", "active" as master. Since */
- /* the roles can actually switch during processing, we avoid */
- /* the terms here */
- /*--------------------------------------------------------------------*/
-
- typedef enum {
- POLL_PASSIVE = 0, /* We answer the telephone */
- POLL_ACTIVE = 1 /* We call out to another host */
- } POLL_MODE ;
-
- /*--------------------------------------------------------------------*/
- /* Global variables */
- /*--------------------------------------------------------------------*/
-
- size_t s_pktsize; /* send packet size for protocol */
- size_t r_pktsize; /* receive packet size for protocol */
-
- FILE *xfer_stream = NULL; /* stream for file being handled */
- boolean callnow = FALSE; /* TRUE = ignore time in L.SYS */
- FILE *fwork = NULL, *fsys= NULL ;
- FILE *syslog = NULL;
- char workfile[FILENAME_MAX]; /* name of current workfile */
- char *Rmtname = nil(char); /* system we want to call */
- char rmtname[20]; /* system we end up talking to */
- struct HostTable *hostp;
- struct HostStats remote_stats; /* host status, as defined by hostatus */
-
- static boolean dialed = FALSE;/* True = We attempted a phone call */
-
- currentfile();
-
- /*--------------------------------------------------------------------*/
- /* Local function prototypes */
- /*--------------------------------------------------------------------*/
-
- static CONN_STATE process( const POLL_MODE poll_mode, const char callgrade );
-
- /*--------------------------------------------------------------------*/
- /* d c p m a i n */
- /* */
- /* main program for DCP, called by uuhost */
- /*--------------------------------------------------------------------*/
-
- int dcpmain(int argc, char *argv[])
- {
-
- char *logfile_name = NULL;
- boolean Contacted = FALSE;
-
- int option;
- int poll_mode = POLL_ACTIVE; /* Default = dial out to system */
- time_t exit_time = LONG_MAX;
-
- char recvgrade = ALL_GRADES;
- boolean override_grade = FALSE;
- char sendgrade = ALL_GRADES;
-
- char *hotuser = NULL;
- BPS hotbaud = 0;
-
- fwork = nil(FILE);
-
- /*--------------------------------------------------------------------*/
- /* Process our options */
- /*--------------------------------------------------------------------*/
-
- while ((option = getopt(argc, argv, "d:g:m:l:r:s:tw:x:z:n?")) != EOF)
- switch (option)
- {
-
- case 'd':
- exit_time = atoi( optarg );
- exit_time = time(NULL) + hhmm2sec(exit_time);
- poll_mode = 0; // Implies passive polling
- break;
-
- case 'g':
- if (strlen(optarg) == 1 )
- recvgrade = *optarg;
- else {
- recvgrade = checktime( optarg );
- /* Get restriction for this hour */
- if ( ! recvgrade ) /* If no class, use the default */
- recvgrade = ALL_GRADES;
- }
- override_grade = TRUE;
- break;
-
- case 'm': /* Override in modem name */
- E_inmodem = optarg;
- poll_mode = 0; /* Presume passive polling */
- break;
-
- case 'l': /* Log file name */
- logfile_name = optarg;
- break;
-
- case 'n':
- callnow = TRUE;
- break;
-
- case 'r':
- poll_mode = atoi(optarg);
- break;
-
- case 's':
- Rmtname = optarg;
- break;
-
- case 't':
- traceEnabled = TRUE;
- break;
-
- case 'x':
- debuglevel = atoi(optarg);
- break;
-
- case 'z':
- hotbaud = atoi(optarg);
- break;
-
- case 'w':
- poll_mode = 0; /* Presume passive polling */
- hotuser = optarg;
- break;
-
- case '?':
- puts("\nUsage:\tuucico\t"
- "[-s [all | any | sys]] [-r 1|0] [-x debug] [-d hhmm]\n"
- "\t\t[-n] [-t] [-w user] [-l logfile] [-m modem] [-z bps]");
- return 4;
- }
-
- /*--------------------------------------------------------------------*/
- /* Abort if any options were left over */
- /*--------------------------------------------------------------------*/
-
- if (optind != argc) {
- puts("Extra parameter(s) at end.");
- return 4;
- }
-
- if (Rmtname == nil(char))
- Rmtname = "any";
-
- /*--------------------------------------------------------------------*/
- /* Initialize logging and the name of the systems file */
- /*--------------------------------------------------------------------*/
-
- openlog( logfile_name );
-
- if (bflag[F_SYSLOG] && ! bflag[F_MULTITASK])
- {
- syslog = FOPEN(SYSLOG, "a",TEXT_MODE);
- if ((syslog == nil(FILE)) || setvbuf( syslog, NULL, _IONBF, 0))
- {
- printerr( SYSLOG );
- panic();
- }
- }
-
- if ( terminate_processing )
- return 100;
-
- /*--------------------------------------------------------------------*/
- /* Initialize security */
- /*--------------------------------------------------------------------*/
-
- if ( !LoadSecurity())
- {
- printmsg(0,"Unable to initialize security, see previous message");
- panic();
- }
-
- if ( terminate_processing )
- return 100;
-
- #if defined(_Windows)
- atexit(CloseEasyWin); // Auto-close EasyWin window on exit
- #endif
-
- atexit( shutDown ); /* Insure port is closed by panic() */
- remote_stats.save_hstatus = nocall;
- /* Known state for automatic status
- update */
-
- /*--------------------------------------------------------------------*/
- /* Begin main processing loop */
- /*--------------------------------------------------------------------*/
-
- if (poll_mode == POLL_ACTIVE) {
-
- CONN_STATE m_state = CONN_INITSTAT;
- CONN_STATE old_state = CONN_EXIT;
-
- printmsg(2, "calling \"%s\", debug=%d", Rmtname, debuglevel);
-
- if ((fsys = FOPEN(E_systems, "r",TEXT_MODE)) == nil(FILE))
- {
- printerr(E_systems);
- panic();
- }
-
- setvbuf( fsys, NULL, _IONBF, 0);
-
- while (m_state != CONN_EXIT )
- {
- printmsg(old_state == m_state ? 10 : 4 ,
- "M state = %c", m_state);
- old_state = m_state;
-
- if (bflag[F_MULTITASK] &&
- (hostp != NULL ) &&
- (remote_stats.save_hstatus != hostp->hstatus ))
- {
- dcupdate();
- remote_stats.save_hstatus = hostp->hstatus;
- }
-
- switch (m_state)
- {
- case CONN_INITSTAT:
- HostStatus();
- m_state = CONN_INITIALIZE;
- break;
-
- case CONN_INITIALIZE:
- hostp = NULL;
-
- if ( locked )
- UnlockSystem();
-
- m_state = getsystem(recvgrade);
- if ( hostp != NULL )
- remote_stats.save_hstatus = hostp->hstatus;
- break;
-
- case CONN_CHECKTIME:
- sendgrade = checktime(flds[FLD_CCTIME]);
-
- if ( (override_grade && sendgrade) || callnow )
- sendgrade = recvgrade;
-
- if ( !CallWindow( sendgrade ))
- m_state = CONN_INITIALIZE;
- else if ( LockSystem( hostp->hostname , B_UUCICO))
- {
- dialed = TRUE;
- time(&hostp->hstats->ltime);
- /* Save time of last attempt to call */
- hostp->hstatus = autodial;
- m_state = CONN_MODEM;
- }
- else
- m_state = CONN_INITIALIZE;
-
- break;
-
- case CONN_MODEM:
- if (getmodem(flds[FLD_TYPE]))
- m_state = CONN_DIALOUT;
- else {
- hostp->hstatus = invalid_device;
- m_state = CONN_INITIALIZE;
- }
- break;
-
- case CONN_DIALOUT:
-
- if ( !IsNetwork() && suspend_other(TRUE, M_device ) < 0 )
- {
- hostp->hstatus = nodevice;
- m_state = CONN_INITIALIZE; // Try next system
- }
- else
- m_state = callup( );
- break;
-
- case CONN_PROTOCOL:
- m_state = startup_server( (char)
- (bflag[F_SYMMETRICGRADES] ?
- sendgrade : recvgrade) );
- break;
-
- case CONN_SERVER:
- m_state = process( poll_mode, recvgrade );
- Contacted = TRUE;
- break;
-
- case CONN_TERMINATE:
- m_state = sysend();
- if ( hostp != NULL )
- {
- if (hostp->hstatus == inprogress)
- hostp->hstatus = call_failed;
- dcstats();
- }
- break;
-
- case CONN_DROPLINE:
- shutDown();
- UnlockSystem();
- suspend_other(FALSE, M_device);
- m_state = CONN_INITIALIZE;
- break;
-
- case CONN_EXIT:
- break;
-
- default:
- printmsg(0,"dcpmain: Unknown master state = %c",m_state );
- panic();
- break;
- } /* switch */
-
- if ( terminate_processing )
- m_state = CONN_EXIT;
-
- } /* while */
-
- fclose(fsys);
-
- }
- else { /* client mode */
-
- CONN_STATE s_state = CONN_INITIALIZE;
- CONN_STATE old_state = CONN_EXIT;
-
- if (!getmodem(E_inmodem)) /* Initialize modem configuration */
- panic(); /* Avoid loop if bad modem name */
-
- if ( ! IsNetwork() )
- suspend_init(M_device);
-
- while (s_state != CONN_EXIT )
- {
- printmsg(s_state == old_state ? 10 : 4 ,
- "S state = %c", s_state);
- old_state = s_state;
-
- if (bflag[F_MULTITASK] &&
- (hostp != NULL ) &&
- (remote_stats.save_hstatus != hostp->hstatus ))
- {
- printmsg(2, "Updating status for host %s, status %d",
- hostp->hostname ,
- (int) hostp->hstatus );
- dcupdate();
- remote_stats.save_hstatus = hostp->hstatus;
- }
-
- switch (s_state) {
- case CONN_INITIALIZE:
- if ( hotuser == NULL )
- s_state = CONN_ANSWER;
- else
- s_state = CONN_HOTMODEM;
- break;
-
- case CONN_WAIT:
- #if !defined(__TURBOC__) || defined(BIT32ENV)
- s_state = suspend_wait();
- #else
- panic(); // Why are we here?!
- #endif
- break;
-
- case CONN_ANSWER:
- s_state = callin( exit_time );
- break;
-
- case CONN_HOTMODEM:
- s_state = callhot( hotbaud );
- break;
-
- case CONN_HOTLOGIN:
- if ( loginbypass( hotuser ) )
- s_state = CONN_INITSTAT;
- else
- s_state = CONN_DROPLINE;
- break;
-
- case CONN_LOGIN:
- if ( login( ) )
- s_state = CONN_INITSTAT;
- else
- s_state = CONN_DROPLINE;
- break;
-
- case CONN_INITSTAT:
- HostStatus();
- s_state = CONN_PROTOCOL;
- break;
-
- case CONN_PROTOCOL:
- s_state = startup_client(&sendgrade);
- break;
-
- case CONN_CLIENT:
- Contacted = TRUE;
- s_state = process( poll_mode, sendgrade );
- break;
-
- case CONN_TERMINATE:
- s_state = sysend();
- if ( hostp != NULL )
- dcstats();
- break;
-
- case CONN_DROPLINE:
- shutDown();
- if ( locked ) /* Cause could get here w/o
- locking */
- UnlockSystem();
- s_state = CONN_EXIT;
- break;
-
- case CONN_EXIT:
- break;
-
- default:
- printmsg(0,"dcpmain: Unknown slave state = %c",s_state );
- panic();
- break;
- } /* switch */
-
- if ( terminate_processing )
- s_state = CONN_EXIT;
-
- } /* while */
- } /* else */
-
- /*--------------------------------------------------------------------*/
- /* Report our results */
- /*--------------------------------------------------------------------*/
-
- if (!Contacted && (poll_mode == POLL_ACTIVE))
- {
- if (dialed)
- printmsg(0, "Could not connect to remote system.");
- else
- printmsg(0,
- "No work for requested system or wrong time to call.");
- }
-
- dcupdate();
-
- if (bflag[F_SYSLOG] && ! bflag[F_MULTITASK])
- fclose(syslog);
-
- return terminate_processing ? 100 : (Contacted ? 0 : 5);
-
- } /*dcpmain*/
-
-
- /*--------------------------------------------------------------------*/
- /* p r o c e s s */
- /* */
- /* The procotol state machine */
- /*--------------------------------------------------------------------*/
-
- static CONN_STATE process( const POLL_MODE poll_mode, const char callgrade )
- {
- boolean master = ( poll_mode == POLL_ACTIVE );
- boolean aborted = FALSE;
- XFER_STATE state = master ? XFER_SENDINIT : XFER_RECVINIT;
- XFER_STATE old_state = XFER_EXIT;
- /* Initialized to any state but the
- original value of "state" */
- XFER_STATE save_state = XFER_EXIT;
-
- /*--------------------------------------------------------------------*/
- /* Yea old state machine for the high level file transfer procotol */
- /*--------------------------------------------------------------------*/
-
- while( state != XFER_EXIT )
- {
- printmsg(state == old_state ? 14 : 4 ,
- "process: Machine state is = %c", state );
- old_state = state;
-
- if ( terminate_processing != aborted )
- {
- aborted = terminate_processing;
- state = XFER_ABORT;
- }
-
- switch( state )
- {
-
- case XFER_SENDINIT: /* Initialize outgoing protocol */
- state = sinit();
- break;
-
- case XFER_RECVINIT: /* Initialize Receive protocol */
- state = rinit();
- break;
-
- case XFER_MASTER: /* Begin master mode */
- master = TRUE;
- state = XFER_NEXTJOB;
- break;
-
- case XFER_SLAVE: /* Begin slave mode */
- master = FALSE;
- state = XFER_RECVHDR;
- break;
-
- case XFER_NEXTJOB: /* Look for work in local queue */
- state = scandir( rmtname, callgrade );
- break;
-
- case XFER_REQUEST: /* Process next file in current job
- in queue */
- state = newrequest();
- break;
-
- case XFER_PUTFILE: /* Got local tranmit request */
- state = ssfile();
- break;
-
- case XFER_GETFILE: /* Got local tranmit request */
- state = srfile();
- break;
-
- case XFER_SENDDATA: /* Remote accepted our work, send data */
- state = sdata();
- break;
-
- case XFER_SENDEOF: /* File xfer complete, send EOF */
- state = seof( master );
- break;
-
- case XFER_FILEDONE: /* Receive or transmit is complete */
- state = master ? XFER_REQUEST : XFER_RECVHDR;
- break;
-
- case XFER_NOLOCAL: /* No local work, remote have any? */
- state = sbreak();
- break;
-
- case XFER_NOREMOTE: /* No remote work, local have any? */
- state = schkdir( poll_mode == POLL_ACTIVE, callgrade );
- break;
-
- case XFER_RECVHDR: /* Receive header from other host */
- state = rheader();
- break;
-
- case XFER_TAKEFILE: /* Set up to receive remote requested
- file transfer */
- state = rrfile();
- break;
-
- case XFER_GIVEFILE: /* Set up to transmit remote
- requuest file transfer */
- state = rsfile();
- break;
-
- case XFER_RECVDATA: /* Receive file data from other host */
- state = rdata();
- break;
-
- case XFER_RECVEOF:
- state = reof();
- break;
-
- case XFER_LOST: /* Lost the other host, flame out */
- printmsg(0,"process: Connection lost to %s, "
- "previous system state = %c",
- rmtname, save_state );
- hostp->hstatus = call_failed;
- state = XFER_EXIT;
- break;
-
- case XFER_ABORT: /* Internal error, flame out */
- printmsg(0,"process: Aborting connection to %s, "
- "previous system state = %c",
- rmtname, save_state );
- hostp->hstatus = call_failed;
- state = XFER_ENDP;
- break;
-
- case XFER_ENDP: /* Terminate the protocol */
- state = endp();
- break;
-
- default:
- printmsg(0,"process: Unknown state = %c, "
- "previous system state = %c",
- state, save_state );
- state = XFER_ABORT;
- break;
- } /* switch */
-
- save_state = old_state; /* Used only if we abort */
-
- } /* while( state != XFER_EXIT ) */
-
- /*--------------------------------------------------------------------*/
- /* Protocol is complete, terminate the connection */
- /*--------------------------------------------------------------------*/
-
- return CONN_TERMINATE;
-
- } /* process */
-