/* * S O F T W I R E * * Softwire is a virtual terminal program which exploits the RSX11-M * terminal driver. The program executes under RSX11M and RSX11M+. * Softwire has been extensively tested running under RSX11M using * a 1200 baud line on a heavily loaded PDP-11/44. Characters are seldom * lost when run at a slightly higher priority than text editors. It requires * about 25% (a guess) of the CPU during receival of data. Other operations * use little CPU time. Since Softwire sends XON-XOFF when it detects * typeahead buffer overrun it can handle 9600 baud lines on RSX11M+ using * a tyepahead buffer size of 255. Effective throughput is somewhat lower. * Sow has successfully been used to communicate with RSX, UNIX, CMS, and * CPM. If Softwire is using a multiplexor which allows settable speeds * (e.g., DH, DZ) it can successfully send a break character and supports * setting the speed of the remote port. This is useful when communicating * with autobauding, autodialing modems. Also, the remote port is disonnected * by default when the port is set remote. This enforces automatic logoff when * the remote system (or modem) inspects DSR on the RS-232 interface. */ /* * Installation notes: * * SOW communicates with SW:. This pseudo device should be assigned * globally for 1 device or locally via command files if SOW is to * be used with several devices. Intsall SOW at a high enough * priority to aviod loosing characters. Installed at a slightly * higher proiority than interactive tasks is usually suffcient. * * Build file: * * XCC -a SOFTWIRE * TKB * SOFTWIRE/CP/PR:0/-IP=SOFTWIRE,[1,1]CX/LB,C/LB * / * UNITS=12 * TASK=...SOW * // */ #ifdef DOCUMENTATION title sow Softwire Terminal Emulator index terminal emulator synopsis sow [-options] [-SPEED] description Softwire allows a person using a terminal to connect to another computer port. This port may be a terminal, a modem, a wire to another computer, etc. Softwire sends all characters typed by the user to the other port. Characters arriving from the other port are sent to the user's terminal. Thus the computer on which Softwire is executing becomes transparent. Softwire also supports transmission of files to and from the other port. The following options may be used when invoking Softwire: .lm +8 .s.i -8;-SPEED Set the speed of the remote port. .s.i -8;-d Do not hang up remote port on termination of Softwire. .s.i -8;-x Do not use XON/XOFF (ctrl-q/ctrl-s) protocol. .s.lm -8 These options are usually selected because of the characteristics of the remote port. All options have the defaults discussed below. .lm +8 .s.i -8;-SPEED (Set remote port baudrate) .s If the -SPEED option is specified then the speed of the remote port is set upon execution of the program. Note that the speed specified must be supported by the hardware. SPEED is specified as the baudrate of the remote port. If -SPEED is not specified the speed of the line as set by MCR is used by default. .s example: SOW -300 .s.i -8;-d (Do not disconnect) .s SOW attempts to hang up remote lines by setting the Data Set Ready signal line low upon exit. Specifying -d in the command line prevents this. This may be useful when it is neccessary to exit SOW for a period of time then re-connect to the remote line. .s example: SOW -d .s.i -8;x (No xon/xoff) .s Normally SOW will transmit a ctrl-s to the remote port when characters are arriving too fast for it to process and will transmit a ctrl-q when it has caught up. Specifying -x on the command line will disable this process. This may be necessary when the remote port is connected to an IBM machine, modem, etc. Be careful to use -x only when necessary as this may cause characters to be lost during receival. .s example: SOW -x .s .lm -8 During execution is may be necessary to have SOW perform special functions called commands. These commands are recognized by SOW when the first character on a line is a tilde (~). The following commands are supported by SOW. .lm +8 .s.i -8;~. End SOW. .s.i -8;~> Re-open the last receive file for append. .s.i -8;~< Send a file to the remote port. .s.i -8;~# Send a break to the remote port. .s.i -8;~! Issue an MCR command. .s.i -8;~a Abort transmission of a file. .s.i -8;~c Close the file being received. .s.i -8;~d Toggle the disconnect (-d) status. .s.i -8;~f Open a receive file (do not append). .s.i -8;~x Toggle the XON/XOFF (-x) status. .s.lm -8 .lm +8 Commands are recognized when the first character on a line is a tilde (~) and the next character is a recognizable command. For example, hitting the return key, followed by ~. will stop execuiton of SOW. .s.i -8;~. (End SOW) .s Typing ~. first on a line resets the remote and local terminal to the original configuration. If the port is set remote (MCR SET /REMOTE=RT0:) the port will be hung-up. (I.e., IO.HNG qio is issued. See RSX-11M I/O DEVICE DRIVERS REFERENCE MANUAL). Hanging up can be overridden with the -d option or the ~d command. .s.i -8;~> (Open a file for receive) .s Typing ~> instructs SOW to put all characters received from the remote port into a file. A file name will be prompted for if no file has previously been used to recieive characters. Otherwise, the last receive file used is re-opened and received chracters are appended to the end of that file. Note that a different file can be opened with the ~f command below. .s.i -8;~< (Transmit a file to the remote port) .s Typing ~< causes SOW to prompt for a file name. If the file is opened successfully it is transmitted to the remote port. .s.i -8;~! (Issue an MCR command) .s Typing ~! causes SOW to prompt for a command and pass that command to MCR. .s.i -8;~# (Send a break to the remote port) .s Typing ~# instructs SOW to send a break to the remote port. This is useful on systems which require a break key. (E.g., IBM's CMS). .s.i -8;~a (Abort transmission of a file) .s If a file is being transmitted to the remote port with ~< then typing ~a causes that transmission to be aborted. .s.i -8;~c (Close receive file) .s Typing ~c closes a receive file opended by ~> or ~f. Any character arriving from the remote port will only be sent to the local terminal. .s.i -8;~d (Toggle disconnect) .s Typing ~d toggles the state of the disconnect option. For example, if SOW was invoked without the -d option (automatic disconnect) and ~d is typed then the remote line will not be disconnected on exit of SOW. This is useful if it is necessary to leave SOW to execute a transmission program such as KERMIT then return to SOW without having the line disconnected. .s.i -8;~f (Start a new receive file) .s Typing ~f will instructs SOW to prompt for a new receive file name and open that file. This may be useful when transmitting multiple files from the removte system while preserving the original name. If a receive file is already open it will be closed. .s.i -8;~x (Toggle XON/XOFF status) .s Typing ~x toggles whether or not to transmit ctrl-s and ctrl-q when SOW detects it is falling behind when recieving data. For example, if SOW was invoked with the -x opion then protocol can be activated bo ~x. This is useful when conversing with modems which do not allow control characters then activating the protocol when a connection to a remote computer is established. .s Note that typing ~~? first on a line where ? is any character results in ~? being transmitted to the remote port. This facilitates talking through several Softwires. E.g., ~~~f opens a file on the third machine. hints Set the remote system to not echo characters and to use XON/XOFF (tandem mode in UNIX) when transmitting a file. This reduces overhead and avoids lost data at the remote end. Invoke SOW then set your terminal to the correct parity when talking to CMS. diagnostics Diagnostic messages should be self-explanatory bugs XON/XOFF is not used when transmitting files to a remote port since sending a ctrl-s to most computers which are echoing characters tends to upset them. Therefore, echoed text may appear to have lost characters when they have arrived at the remote system. SOW maitains the parity of the terminal during passthrough. Not enough attention has been paid to sending ctrl-s, ctrl-q in the proper parity. #endif /* * If you are running RSX11M leave the following commented out. If you * are running RSX11M+ uncomment the following. */ /* #define RSX11M+ */ /* * If you are running RSX11M+ with kernel data space uncomment the following. * If you are running RXX11M+ without kernel data space or RSX11M leave * it commented. */ /* #define KSPACE */ #include #include #include #include #include /* * The following is a list of parameters you may want to change */ #define RBUFSZ 1000 /* Size of circular remote buffer */ #define LBUFSZ 200 /* Size of circular local buffer */ /* * When THIWAT or more characters are in the type-ahead buffer * a ctrl-s is sent to the remote. */ #define THIWAT 18 /* * When RHIWAT or more characters are in the circular remote buffer * a ctrl-s is sent to the remote. (Keep small enough that ctrl-s works * in a timely fashion). */ #define RHIWAT 100 /* * Define states of input parser */ #define ANYCH 0 /* Any old character has been found */ #define RETRN 1 /* A carriage return has been found */ #define TILDE 2 /* A ~ has been found */ /* * Change the following at your own risk */ #define LQIOEF 4 /* Event flag for local qiow */ #define RQIOEF 5 /* Event flag for remote qiow */ #define WAITEF 6 /* Wait for remote input */ #define EQIOEF 7 /* Event flag for express remote qiow */ #define NUMWT 6 /* Number of input characters before a timed read */ #define WTLENG 15 /* Number of clock ticks to wait before local write */ #define CTRLQ 021 /* ctrl-q character */ #define CTRLS 023 /* ctrl-s character */ #define NUMNUL 2 /* The number of nulls to send for a break */ /* * The following are included here because they were left out of qiottdrv.h * somehow. */ #define TC_TBS 64 #define TC_TBM 65 char rbuff[RBUFSZ]; /* Remote input circular buffer */ char *rfc = rbuff; /* First character in remote buffer */ char *rlc = rbuff; /* Last character in remote buffer */ char lbuff[LBUFSZ]; /* Local input circular buffer */ char *lfc = lbuff; /* First character in local buffer */ char *llc = lbuff; /* Last character in local buffer */ unsigned nremt; /* Number of remote characters since last local char */ int pctrls; /* Number of ctrl-s send by this program */ int uctrls = FALSE; /* True if ctrl-s sent to remote by user */ unsigned speed; /* Speed from arg list (else 0) */ int xof = TRUE; /* Rremote can handle ctrl-q ctrl-s protocol */ int xofsave; /* Save of above state during transmission */ FILE *rfp; /* Receive file pointer */ FILE *xfp; /* Transmit file pointer */ FILE *lfp; /* Local terminal pointer for raw io */ FILE *tfp; /* Remote terminal pointer */ int loclun; /* Lun of local terminal */ int remlun; /* Lun of remote terminal */ char rname[22]; /* Name of recieve file */ char rmode[2]; /* Fopen mode of receive file */ int rop = FALSE; /* True if receive file open */ char xname[22]; /* Name of file being transmitted */ int transp = FALSE; /* True if recieve all (raw) characters */ int disc = TRUE; /* If true then disconnect remote at exit of program */ int p[6]; /* Parameter block for qio */ char nulls[NUMNUL]; /* That many nulls */ struct iosb { /* I/O status block */ char stat; char term; int count; } io; /* * Define a template for get/set multiple characteristics */ struct gets { char name; char val; }; /* * The following structure contains the operating characteristics of * the local terminal. */ struct gets lset[] = { {TC_ACR, 0}, {TC_BIN, 1}, {TC_FDX, 1}, {TC_RAT, 1}, {TC_SMR, 1}, {TC_WID, 255} }; /* * The following structure is used to save the characteristics of the local * terminal so they may be restored on exit of this program */ struct gets lsave[sizeof(lset)/sizeof(lset[0])]; /* * The following structure contains the operating characteristics of * the remote terminal. Refer to the rsx11m i/o dirvers reference * manual for details. */ struct gets rset[] = { {TC_ACR, 0}, {TC_BIN, 1}, /* Turned off during file xmit */ {TC_8BC, 1}, /* In effect when above off */ {TC_CTS, 0}, {TC_FDX, 1}, {TC_NBR, 1}, {TC_NEC, 1}, {TC_SLV, 1}, {TC_SMR, 1}, #ifdef RSX11M+ {TC_TBM, 0}, #endif #ifdef KSPACE {TC_TBS, 255}, #endif #ifndef RSX11M+ {TC_RAT, 1}, #endif {TC_WID, 255} }; /* * The following structure is used to save the characteristics of the remote * terminal so they may be restored on exit of this program */ struct gets rsave[sizeof(rset)/sizeof(rset[0])]; char rxspeed, rrspeed; /* Save remote xmit & receive speeds */ main(argc, argv) int argc; char *argv[]; { register char *prm; register c, i; for(i=1; i= '1' && *prm <= '9') { setspe(prm); continue; } while (c = *prm++) switch (c) { /* * do not setd ctrl-s, ctrl-q */ case 'x': case 'X': xof = FALSE; prm++; break; /* * Write data "as is" to receive file. */ case 't': case 'T': transp = TRUE; break; /* * Don't disconnect phone on exit */ case 'd': case 'D': disc = FALSE; break; default: usage(); } } } setup(); /* * Wait for remote input (Note: end of program in lproc) */ for(;;) { wtse(WAITEF); /* * Process all arrived characters until no more */ do { clef(WAITEF); if(lfc != llc) /* Do local first */ lproc(); if(rfc != rlc) rproc(); } while (lfc != llc || rfc != rlc); /* * Secd ctrl-q if ctrl-s has been sent to remote */ if(pctrls) { pctrls = 0; /* * If user has send ctrl-s then wait for his ctrl-q */ if(!uctrls) wrexp(CTRLQ); } /* * Transmit file to remote */ if(xname[0] != NULL) xmit(); } } /* * Set speed of remote line to that passed in argument list. */ setspe(s) char *s; { register i; i = atoi(s); switch(i) { case 110: speed = S_110; break; case 300: speed = S_300; break; case 1200: speed = S_1200; break; case 2400: speed = S_2400; break; case 4800: speed = S_4800; break; case 9600: speed = S_9600; break; default: fprintf(stderr, "SOW> Bad speed\n"); exit(); } } /* * Process a character from the local keyboard. If this is a \r~... * sequence then process. Else pass char to remote tty. */ int state = RETRN; /* The current state of input (start = \r) */ lproc() { register c, ch; while(lfc != llc) { c = *lfc++; /* Get character as is */ if (lfc == lbuff+LBUFSZ) lfc = lbuff; ch = c&0177; /* Strip parity */ /* * Handle users ctrl-s, ctrl-q */ if(ch == CTRLS) { wraw(c); /* o.k to send more than 1 */ uctrls = TRUE; break; } else if(ch == CTRLQ) { uctrls = FALSE; if(pctrls == 0) wraw(c); break; } /* * Look for \r~. */ switch(state) { case ANYCH: if(ch == '\r') state = RETRN; wraw(c); break; case RETRN: if(ch == '~') state = TILDE; else { wraw(c); if(ch == '\r') state = RETRN; else state = ANYCH; } break; case TILDE: state = RETRN; /* May be overridden */ switch(ch) { case '.': fini(); break; case '>': if(rop) fprintf(stderr,"SOW> %s already open\r\n\n", rname); else { ropen(); state = RETRN; } break; case '<': topen(); state = RETRN; break; case '!': cmnd(); state = RETRN; break; case '#': sndbrk(); state = RETRN; break; case 'a': case 'A': fprintf(stderr, "SOW> Transmission of %s aborted\r\n\n", xname); tclose(); break; case 'c': case 'C': if(rop) { fclose(rfp); fprintf(stderr, "SOW> File %s closed\r\n\n", rname); rop = FALSE; } else fprintf(stderr, "SOW> No file open\r\n\n"); break; case 'd': case 'D': if(disc == TRUE) { disc = FALSE; fprintf(stderr, "SOW> No disconnect\r\n\n"); } else { disc = TRUE; fprintf(stderr, "SOW> Disconnect \r\n\n"); } break; case 'f': case 'F': if(rop) fclose(rfp); rname[0] = NULL; ropen(); break; case 'x': case 'X': if(xof == TRUE) { xof = FALSE; fprintf(stderr, "SOW> No xon/xoff\r\n\n"); } else { xof = TRUE; fprintf(stderr, "SOW> Xon/xoff\r\n\n"); } break; case '~': wraw(c); state = ANYCH; break; default: wraw('~'); wraw(c); /* * Don't force \r\r search */ if(ch != '\r') state = ANYCH; break; } break; } } fflush(tfp); } /* * Routine to process characters in remote circular buffer */ rproc() { register i; register num; /* * If characters are streaming in then wait for a few to accumulate * before writing them to terminal. */ if (nremt >= NUMWT) { mrkt(LQIOEF, WTLENG, 1, 0); wtse(LQIOEF); } num = rlc-rfc; /* Get number of bytes */ if(num < 0) num = rbuff+RBUFSZ-rfc; /* * Write characters to receive file if open */ if(rop) rput(rfc, num); /* * Write characters to local terminal */ fput(rfc, num, lfp); fflush(lfp); rfc += num; if(rfc == rbuff+RBUFSZ) rfc = rbuff; } /* * Write characters to recieve file */ rput(s, num) char *s; /* Pointer to character string */ int num; /* Number of characters */ { register i, ch; /* * If trnasparent mode write all characters, else try * to filter. */ for(i=0; i Remote Write Error, DSW = %o\n", i); } /* * Transmit a file to the remote terminal */ xmit() { register num; register char c; num = 0; /* limit on how may at one time */ while((c=getc(xfp)) != EOF) { if(c == '\n') { putc('\r', tfp); fflush(tfp); setf(WAITEF); /* Check things elsewhere */ return; } else { putc(c, tfp); num++; if(num > RHIWAT/2) { fflush(tfp); setf(WAITEF); return; } } } /* * Transmission done, clean up */ tclose(); fprintf(stderr, "\r\n\nSOW> Transmission of %s Finished\r\n\n", xname); } /* * Local ast to put input characters in Local cirular buff & notify waiter. */ locast() { register num; astset(); *llc++ = gtdp(0) ; if(llc == lbuff+LBUFSZ) llc = lbuff; nremt = 0; /* Set timer low */ setf(WAITEF); /* Wake up main */ astx(1); /* Remove character, terminal number off stack */ } /* * Remote ast to put input characters in remote cirular buff & notify waiter. */ remast() { register num; astset(); *rlc++ = gtdp(0); if(rlc == rbuff+RBUFSZ) rlc = rbuff; nremt++; /* * If too many characters in typeahead or in circular buffer send ctrl-s */ if(xof) { if(pctrls < 5) { num = rgetval(TC_TBF); if(num >= THIWAT) { wrexp(CTRLS); pctrls++; } if((num = rlc-rfc) < 0) num += RBUFSZ; /* Number chars in circ buff */ if(num > RHIWAT) { wrexp(CTRLS); pctrls ++; } } } setf(WAITEF); /* Wake up main */ astx(1); /* Remove character, terminal number off stack */ } /* * Open a receive file */ ropen() { /* * If no file name then get one */ if(rname[0] == NULL) { lrest(); /* Put local term to sane state */ printf("SOW> Enter receive file name:\n"); if(gets(rname) == NULL) { lsetup(); /* Term back to transparent mode */ return; /* CTRL-Z instead of name */ } lsetup(); strcpy(rmode, "w"); /* open new file */ } else strcpy(rmode, "a"); rfp = fopen(rname, rmode); if (rfp == NULL) { fprintf(stderr, "SOW> Cannot open %s\r\n", rname); rname[0] = NULL; return; } fprintf(stderr, "SOW> File %s opened\r\n\n", rname); rop = TRUE; } /* * Open a transmit file */ topen() { if(xname[0] != NULL) { fprintf(stderr, "SOW> File %s being transmitted\r\n\n", xname); return; } lrest(); /* Terminal in sane state for prompt */ printf("SOW> Enter transmit file name:\n"); if(gets(xname) == NULL) { lsetup(); /* Term back to transparent mode */ return; /* CTRL-Z instead of name */ } lsetup(); xfp = fopen(xname, "r"); if (xfp == NULL) { fprintf(stderr, "SOW> Cannot open %s\r\n\n", xname); xname[0] = NULL; return; } /* * File open, initialize for transmission */ xofsave = xof; /* Save xof state */ xof = FALSE; /* Don't do xof during transmission */ rsetval(TC_BIN, 0); /* Turn on xon/xoff processing */ } /* * End of transmission */ tclose() { putc('\n', tfp); fflush(tfp); /* Send any unsent characters */ fclose(xfp); xof = xofsave; xname[0] = NULL; rsetval(TC_BIN, 1); /* Turn off xon/xoff */ } /* * Spawn an mcr command */ cmnd() { char cmdlin[100]; /* Buffer for command line */ char name[6]; /* For rad50 conversion */ register i; lrest(); /* Terminal in sane state for prompt */ printf("SOW> Enter command:\n"); if(gets(cmdlin) == NULL) { lsetup(); /* Term back to transparent mode */ return; /* CTRL-Z instead of name */ } else if(cmdlin[0] == NULL) { lsetup(); return; } locdet(); /* Detatch local terminal */ remdet(); /* Detatch remote terminal */ ascr50(6, "mcr...", name); if((i=spwn(name, 0, LQIOEF, 0, 0, cmdlin, strlen(cmdlin))) != IS_SUC) fprintf(stderr, "SOW> Cannot spawn %s: %d\n", cmdlin, i); wtse(LQIOEF); /* Wait for task to exit */ remata(); /* Reattach remote terminal */ fprintf(stderr, "SOW> Done\n\n"); locata(); /* Reattach local terminal */ lsetup(); /* Reset terminal */ } /* * Send a break by setting the speed down then sending nulls */ struct gets brk[] = {TC_XSP,S_50}; /* Set speed to 50 baud */ sndbrk() { register i; int savsp; /* * Save speed for restore */ if((savsp = rgetval(TC_XSP)) < 0) { fprintf(stderr, "Can't get remote speed\n"); return; } /* * Set remote xmitter speed down */ if(rsetval(TC_XSP, S_50) < 0) { fprintf(stderr, "SOW> Can't send break\n"); return; } p[0] = nulls; p[1] = NUMNUL; p[3] = 0; if((i = qiow(IO_CCO, remlun, RQIOEF, 0, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Remote Write Error, DSW = %o\n", i); /* * Resetet remote xmitter speed */ if(rsetval(TC_XSP, savsp) < 0) fprintf(stderr, "SOW> Can't restore remote speed\n"); } /* * Get the charactersitic from the TTY driver. Note: this routine returns * a positive value for status success. Otherwise, returns the (negative) * error. */ rgetval(ch) int ch; /* Characteristic to be gotten */ { int i; struct gets gmc; /* get single charistic */ gmc.name = ch; p[0] = &gmc; p[1] = sizeof(gmc); if((i = qiow(SF_GMC, remlun, RQIOEF, &io, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Get Characteristics Error, DSW = %o\n", i); if(io.stat != IS_SUC) return(io.stat); /* * status ok, return (positive) value */ return(gmc.val); } /* * Set the characteristic of the remote port. */ rsetval(ch, val) int ch; /* Characteristic to be set */ int val; /* Value of characteristic */ { int i; struct gets smc; /* set single charistic */ smc.name = ch; smc.val = val; p[0] = &smc; p[1] = sizeof(smc); if((i = qiow(SF_SMC, remlun, RQIOEF, &io, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Set Characteristics Error, DSW = %o\n", i); if(io.stat != IS_SUC) return(io.stat); /* * status ok, return (positive) value */ return(smc.val); } /* * Save current status of both remote and local terminal and set up * as in rset, lset. */ setup() { register i; extern busy(); /* * Open a path to the local terminal for "raw" io */ lfp = fopen("TI:", "wn"); if (lfp == NULL) { fprintf(stderr, "SOW> Cannot open terminal TI:\n"); exit(); } /* * Open a path to the remote terminal */ tfp = fopen("SW:", "rn"); if (tfp == NULL) { fprintf(stderr, "SOW> Cannot open remote path SW:\n"); exit(); } /* * Attach remote terminal, if timeout occurs assume alredy attached */ remlun = fileno(tfp); /* Lun for remote qio's */ mrkt(0, 3, 2, busy); /* Set up timer */ remata(); /* Attach remote terminal */ cmkt(0, busy); /* Cancel timer */ /* * Get remote terminal characteristics */ copy(rsave, rset, sizeof(rsave)); p[0] = &rsave; p[1] = sizeof(rsave); if((i = qiow(SF_GMC, remlun, RQIOEF, &io, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Remote GMC Error, DSW = %d\n",i); if(io.stat != IS_SUC) fprintf(stderr, "SOW> Remote GMC Error, offset = %d\n", io.count); /* * Save and set speed of remote terminal */ if(speed != 0) { rrspeed = rgetval(TC_RSP); rxspeed = rgetval(TC_XSP); if(rsetval(TC_RSP, speed) < 0 || rsetva(TC_XSP, speed) < 0) { fprintf(stderr, "SOW> Can't set remote speed\n"); exit(-1); } } /* * Set proper characteristics of remote terminal */ for(i=0; i<(sizeof(rset)/sizeof(rset[0])); i++) rsetval(rset[i].name, rset[i].val); /* * Get local terminal characteristics */ loclun = fileno(stderr); /* Lun for local qio's */ copy(lsave, lset, sizeof(lsave)); p[0] = &lsave; p[1] = sizeof(lsave); if((i = qiow(SF_GMC, loclun, LQIOEF, &io, 0, p)) != IS_SUC) { fprintf(stderr, "SOW> Local GMC Error, DSW = %d\n", i); exit(); } if(io.stat != IS_SUC) { fprintf(stderr, "SOW> Local GMC Error, offset = %d\n", io.count); exit(); } lsetup(); /* Set up local terminal */ locata(); /* Attach local terminal */ } /* * Attatch local terminal */ locata() { register i; p[0] = locast; p[1] = 0; p[2] = 0; if((i = qiow(IO_ATA, loclun, LQIOEF, 0, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Local Attach Error, DSW = %o\n", i); } /* * Detatch local terminal */ locdet() { register i; if((i = qiow(IO_DET, loclun, LQIOEF, 0, 0, 0)) != IS_SUC) fprintf(stderr, "SOW> Local Detatch Error, DSW = %o\n", i); } /* * Attach remote terminal */ remata() { register i; p[0] = remast; p[1] = 0; p[2] = 0; if((i = qiow(IO_ATA, remlun, RQIOEF, 0, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Remote Attach Error, DSW = %d\n", i); } /* * Detatch remote terminal */ remdet() { register i; if((i = qiow(IO_DET, remlun, RQIOEF, 0, 0, 0)) != IS_SUC) fprintf(stderr, "SOW> Remote Detatch Error, DSW = %o\n", i); } /* * Restore terminals to original state, clean up, and exit. */ fini() { register i; if(rop) fclose(rfp); if(xname[0] != NULL) fclose(xfp); lrest(); /* Restore local teminal characteristics */ locdet(); /* Detatch local terminal */ /* * Restore remote terminal to proper config */ for(i=0; i<(sizeof(rsave)/sizeof(rsave[0])); i++) rsetval(rsave[i].name, rsave[i].val); /* * Restore remote terminal speed if set */ if(speed != 0) if(rsetval(TC_RSP, rrspeed) < 0 || rsetva(TC_XSP, rxspeed) < 0) fprintf(stderr, "SOW> Can't reset remote speed\n"); /* * Disconnect the line if this is a dial-up line */ if(disc) if(rgetval(TC_DLU)) if((i = qiow(IO_HNG, remlun, RQIOEF, &io, 0, p)) == IS_SUC) fprintf(stderr, "\nSOW> DISCONNECT\n"); else fprintf(stderr, "SOW> Disconnect error, DSW = %o\n", i); remdet(); /* Detatch remote terminal */ fprintf(stderr, "\nSOW> DID YOU REMEMBER TO LOGOFF?\n"); exit(); } /* * Set proper characteristics of local terminal */ lsetup() { register i; p[0] = &lset; p[1] = sizeof(lset); if((i = qiow(SF_SMC, loclun, LQIOEF, &io, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Local SMC Error, DSW = %d\n", i); if(io.stat != IS_SUC) fprintf(stderr, "SOW> Local SMC Error, offset = %d\n", io.count); } /* * If line doesn't open in 3 seconds then assume in use by someone else */ busy() { astset(); qiow(IO_KIL, remlun, RQIOEF, 0, 0, 0); /* Kill the attach */ fprintf(stderr, "*** Remote port in use, try again later ***\n"); exit(); } /* * Restore local terminal to original state */ lrest() { register i; /* * Restore local terminal to proper config */ p[0] = &lsave; p[1] = sizeof(lsave); if((i = qiow(SF_SMC, loclun, LQIOEF, &io, 0, p)) != IS_SUC) fprintf(stderr, "SOW> Local SMC Error, DSW = %o\n", i); if(io.stat != IS_SUC) fprintf(stderr, "SOW> Local SMC Error, offset = %d\n", io.count); } usage() { fprintf(stderr,"Use: SOW [-speed] [-dx]\n\n"); fprintf(stderr," -speed is the speed of the remote line\n"); fprintf(stderr," -d Do not disconnect line on exit of program\n"); fprintf(stderr," -x Specifies the remote cannot handle CTRL-Q"); fprintf(stderr," CTRL-S protocol\n\n"); fprintf(stderr,"Example: SOW -1200 -dx\n"); exit(); }