/* * k e r p o s s y s - KERMIT routines for P/OS * * Communications I/O package for KERMIT/POS using the * XK0: port. Uses the RSX/POS system services library * CX.OLB. Also contains user interface and message board * routines. * * By: * Bob Denny * Alisa Systems, Inc. * Pasadena, CA 91101 * 07-Jan-84 * * Modification history: * * 09-Jan-84 RBD Added ps_fil, ps_pmsg and ps_usage in an attempt * to make KERFIL.C more portable & access P/OS * menu-moron services. * 12-Jan-84 RBD Add ps_xfil to set up list of remote filespecs * to send to server for transmission back to us. * Decided to make up my own 'menu' ... too bad. * Required a lot of terminal fiddling! * 13-Jan-83 RBD Move terminal setup and restore into system * intialization and restore routines, so terminal * runs in our flavor all of the time. Also, * clear the screen on exit. */ #include #include #include #define DEBUGIT #define TRUE 1 #define FALSE 0 /* * We will use LUN 6 and EFN 6 for XK: QIO's * leaving room for 2 open files. */ #define COMM_DEVICE "XK:" /* XK0: is used by KERMIT */ #define COMM_UNIT 0 #define COMM_LUN 6 #define COMM_EFN 6 #define RBUF_SIZE 256 /* Local receive buffer size */ /* * Characteristics tables used by SF.GMC and * SF.SMC in saving, setting and restoring * the XK: port. */ /* * Symbolic array indexes to values */ #define ARC 1 #define BIN 3 #define EPA 5 #define FSZ 7 #define PAR 9 #define RSP 11 #define STB 13 #define XSP 15 #define EBC 17 #define MTP 19 static byte saved_chars[] = /* Saved XK: characteristics */ { TC_ARC, 0, TC_BIN, 0, TC_EPA, 0, TC_FSZ, 0, TC_PAR, 0, TC_RSP, 0, TC_STB, 0, TC_XSP, 0, TC_8BC, 0, XT_MTP, 0 }; static word savpar[] = {saved_chars, sizeof(saved_chars)}; static byte kermit_chars[] = /* KERMIT's XK: characteristics */ { TC_ARC, 1, /* Answer after 1 ring (remote) */ TC_BIN, 0, /* Enable ^S/^Q flow control */ TC_EPA, 1, /* (not used, even parity) */ TC_FSZ, 8, /* 8-bit character width */ TC_PAR, 0, /* No parity */ TC_RSP, 0, /* Rec baud rate (set at run time) */ TC_STB, 1, /* 1 stop bit */ TC_XSP, 0, /* Xmt baud rate (set at run time) */ TC_8BC, 1, /* Pass 8-bit characters */ XT_MTP, XTM_NO /* Hardwired line (no modem) */ }; static word setpar[] = /* QIO parameter list */ {kermit_chars, sizeof(kermit_chars)}; /* * Local storage & data for receiving */ static byte rbuf[RBUF_SIZE]; /* Receive buffer */ static byte *rbp = rbuf; /* Receive buffer scan pointer */ static word nchars = 0; /* Number of char's remaining */ static word rpar[6] = /* QIO parameters for read */ {0, 0, 0, 0, 0, 0}; static int iosb[2]; /* I/O status block */ /* * File selection menu data */ #define MAXCHOICE 40 /* Max choices from oldfil */ #define MAXSELECT 10 /* Max specify 10 remote files */ static char filspecs[MAXCHOICE][50]; /* Array of returned filespecs */ static char *filvec[MAXCHOICE]; /* Array of filespec pointers */ /* * Terminal characteristics control data & abort * AST stuff. */ static char *clrseq = "\033[1;1H\033[J"; /* Erase screen sequence */ extern int astsrv(); /* Declare our ^C AST service */ static word astpar[] = {0, 0 ,astsrv, 0, 0, 0}; static word aboarm = FALSE; /* TRUE = ^C aborts transfer */ static word was_esc; /* Remember original /[NO]ESCAPE */ static byte escchr[] = {TC_ESQ, 0}; static word escpar[] = {escchr, 2, 0, 0, 0, 0}; extern int $dsw; /* P/OS directive status */ extern int debug; /* Required KERFIL variables */ extern int remote; /* TRUE = we are in remote */ extern char **filelist; /* --> list of filespec strings */ extern int filecount; /* Number of filespecs left to do */ extern int aboflag; /* Transfer abort flag */ extern char *stdout; /* No need for */ /* * xk_set - Save current XK: settings and change them * to suit KERMIT. Also set up terminal for * our manual QIO'ing with escape sequence parsing. * * Exits after printing an error message if there is * some problem. */ xk_set(speed) word speed; /* Baud rate (numeric) */ { byte scode; /* * Assign and attach the port */ if(alunx(COMM_LUN, COMM_DEVICE, COMM_UNIT) != IS_SUC) xerr("Device assignment failed", $dsw); if(qiow(IO_ATT, COMM_LUN, COMM_EFN, iosb, 0, 0) != IS_SUC) xerr("Attach rejected", $dsw); if(iosb[0] != IS_SUC) xerr("Failed to attach port", iosb[0]); /* * Save current characteristics and set up * those required by KERMIT. No error checks * here ... */ qiow(SF_GMC, COMM_LUN, COMM_EFN, 0, 0, savpar); /* Save current chars */ #ifdef DEBUGIT if($dsw != IS_SUC) xerr("GMC rejected", $dsw); if(iosb[0] != IS_SUC) xerr("GMC failed", iosb[0]); #endif switch(speed) /* Translate speed to QIO code */ { case 300: scode = S_300; break; case 1200: scode = S_1200; break; case 2400: scode = S_2400; break; case 4800: scode = S_4800; break; case 9600: scode = S_9600; break; case 19200: scode = S_19_2; break; default: xerr("Bad baud rate"); } kermit_chars[RSP] = kermit_chars[XSP] = scode; /* Fill in new speed */ qiow(SF_SMC, COMM_LUN, COMM_EFN, iosb, 0, setpar); /* Set KERMIT's chars */ #ifdef DEBUGIT if($dsw != IS_SUC) xerr("SMC rejected", $dsw); if(iosb[0] != IS_SUC) xerr("SMC failed", iosb[0]); #endif /* * Finally, attach & set up the terminal for escape sequence * processing and ^C AST. The ^C (INTERRUPT-DO) will be used to * set the abort flag the first time, and the second time, it'll * abort the program itself. */ qiow(SF_GMC, 1, 1, 0, 0, escpar); /* Get current terminal setting */ if((was_esc = (word)escchr[1]) == 0) /* If not /ESCAPE */ { escchr[1] = 1; qiow(SF_SMC, 1, 1, 0, 0, escpar); /* SET TERM/ESCAPE */ } qiow(IO_DET, 1, 1, 0, 0, 0); /* Do I hafta? ... Just to */ qiow(IO_ATA|TF_ESQ, 1, 1, 0, 0, astpar); /* Ask for ^C & escape */ } /* * xk_rst - Flush, restore & detach XK: port, * clear screen & detach TI: */ xk_rst() { xk_flu(); /* Flush XK: input buffer */ qiow(SF_SMC, COMM_LUN, COMM_EFN, iosb, 0, savpar); /* Restore char's */ qiow(IO_DET, COMM_LUN, COMM_EFN, 0, 0, 0); /* Detach the line */ /* * Restore former setting of /[NO]ESCAPE */ if(!was_esc) { escchr[1] = 0; qiow(SF_SMC, 1, 1, 0, 0, escpar); } printf(clrseq); fflush(stdout); qiow(IO_DET, 1, 1, 0, 0, 0); /* Detach terminal */ } /* * xk_flu - Flush all input buffers */ static byte fluchr[] = {TC_TBF, 1}; static word flupar[] = {fluchr, sizeof(fluchr), 0, 0, 0, 0}; xk_flu() { rbp = rbuf; /* Flush local buffer */ nchars = 0; qiow(SF_SMC, COMM_LUN, COMM_EFN, 0, 0, flupar); /* Flush XK: buffer */ } /* * xk_wrt - Write a string of characters to XT: port * * No error checking ... */ static word wrtpar[] = {0, 0, 0, 0, 0, 0}; xk_wrt(buf, bytes) char *buf; /* Buffer address */ word bytes; /* Byte count */ { wrtpar[0] = buf; /* Set up parameters */ wrtpar[1] = bytes; qiow(IO_WLB, COMM_LUN, COMM_EFN, iosb, 0, wrtpar); } /* * xk_rch - Return a received character * * I find it amazing that this is so easy ... */ static word rlbpar[] = {rbuf, 0, 0, 0, 0, 0}; xk_rch(cp, timeout) char *cp; /* --> place to store character */ word timeout; /* Timeout value, seconds */ { again: if(nchars--) /* If char(s) remaining locally */ { *cp = *rbp++; /* Return one */ return(TRUE); /* Success */ } rbp = rbuf; /* Reset scan pointer */ rlbpar[1] = RBUF_SIZE; /* Get everything in XT: buffer */ rlbpar[2] = 0; /* (timeout=0) */ qiow(IO_RLB|TF_TMO, COMM_LUN, COMM_EFN, iosb, 0, rlbpar); if(nchars = iosb[1]) /* If we got something */ goto again; /* Go back and fetch a character */ rlbpar[1] = 1; /* Wait till a character arrives */ rlbpar[2] = 256 * timeout; /* Hang a timed-out read (sec) */ qiow(IO_RLB|TF_TMO, COMM_LUN, COMM_EFN, iosb, 0, rlbpar); if(nchars = iosb[1]) /* If we got something */ goto again; /* Go back and fetch a character */ return(FALSE); /* ERROR - Timed out */ } /* * xerr - Handle fatal initialization errors */ static xerr(msg, code) char *msg; word code; { char *fmt1, *fmt2; char mb[86]; fmt1 = "KERMIT/POS Initialization error:\n"; fmt2 = "%s Code = %d\n"; sprintf(mb, fmt2, msg, code); ps_pmsg(fmt1); ps_pmsg(mb); p$fatler(mb); } /* * ps_usage - Inform user of command line error & exit */ ps_usage() { char *m; m = "KERFIL command line error"; ps_pmsg(m); p$fatler(m); } /* * ps_pmsg - Print message to local user */ ps_pmsg(fmt, a1, a2, a3, a4, a5) char *fmt; { char msgbuf[86]; char *cp; if(remote) /* Do nothing if remote */ return; printf(fmt, a1, a2, a3, a4, a5); /* Display message */ printf("\n"); cp = sprintf(msgbuf, "Kermit: "); /* Format for message board */ sprintf(cp, fmt, a1, a2, a3, a4, a5); p$msgbrd(msgbuf, iosb); /* Write to message board */ #ifdef DEBUGIT if(iosb[0] < 0) printf("Message board send failed. stat[1] = %d\n", iosb[1]); #endif } /* * ps_gfil - Get a list of local filespecs from the user */ ps_gfil() { int nch; /* Returns with # chosen */ int stat[2]; register int i; for(i=0; i or a function key, passing back the function key * code in status ... */ static char fraseq[] = "\033[1;1H\033[J\033[7m\ Remote File Specification Selection Form\ \ \033[2;1H \033[2;79H \ \033[3;1H \033[3;79H \ \033[4;1H \033[4;79H \ \033[5;1H \033[5;79H \ \033[6;1H \033[6;79H \ \033[7;1H \033[7;79H \ \033[8;1H \033[8;79H \ \033[9;1H \033[9;79H \ \033[10;1H \033[10;79H \ \033[11;1H \033[11;79H \ \033[12;1H \033[12;79H \ \033[13;1H \033[13;79H \ \033[14;1H \033[14;79H \ \033[15;1H \033[15;79H \ \033[16;1H \033[16;79H \ \033[17;1H \033[17;79H \ \033[18;1H \033[18;79H \ \033[19;1H \033[19;79H \ \033[20;1H \ \033[0m\ \033[22;1HNOTE: File specs may contain wildcards as supported by remote system.\ \033[3;8HEnter up to 10 remote file specifications followed by RETURN\ \033[4;8Hthen press DO to start the transfer:"; static word frapar[] = {fraseq, sizeof(fraseq), 0, 0, 0, 0}; extern prscsi(); ps_xfil() { int stat[2]; int i; word len; char posseq[20]; /* Cursor positioning sequence */ for(i=0; i 0) i++; if((len == 0) || (stat[0] == 2 && (stat[1] == 9 || stat[1] == 10 || stat[1] == 16)) ) break; if(stat[0] == 2) /* Other F-key */ goto reptmnu; } /* * If MAIN SCREEN or EXIT pressed, exit from KERFIL. * Also exit if no files were selected. */ if((i == 0) || (stat[0] == 2 && (stat[1] == 9 || stat[1] == 10))) { xk_rst(); /* Reset comm port */ ps_pmsg("User stopped KERMIT or selected no files"); exits(EX$WAR); /* WARNING - no files transferred */ } /* * Complete by redirecting the file list and count */ filelist = filvec; filecount = i; } /* * Local routine for above function */ static char inpbuf[90]; static word inppar[] = {inpbuf, 80, 0, 0, 0, 0}; static get_line(buf, max, prompt, stat) char *buf; int max; char *prompt; int *stat; { word msgl; inppar[0] = buf; inppar[1] = max; inppar[3] = prompt; inppar[4] = strlen(prompt); qiow(IO_RPR, 1, 1, iosb, 0, inppar); if(iosb[0] == IS_CR) { buf[iosb[1]] = '\0'; stat[0] = 1; stat[1] = 13; return(iosb[1]); } else { call(prscsi, 4, stat, buf, &iosb[1], &msgl); buf[msgl-1] = '\0'; return(msgl - 1); } } /* * ps_arm - Display "in progress" screen and arm ^C transfer aborts. */ static char proform[] = "\033[1;1H\033[J\033#3 Transfer in progress\ \033[2;1H\033#4 Transfer in progress\ \033[4;8HPress \033[1mINTERRUPT-DO\033[0m to abort the transfer ...\ \033[6;1H========================================\ ========================================\ \033[22;1H========================================\ ========================================\ \033[24;8HThe above information is being logged on your message board.\ \033[7;21r\033[7;1H"; static word propar[] = {proform, sizeof(proform), 0, 0, 0, 0}; ps_arm(abofl) /* Enable user interrupts */ int *abofl; { qiow(IO_WLB, 1, 1, 0, 0, propar); /* Put up the form */ *abofl = FALSE; /* Clear the abort flag */ aboarm = TRUE; /* Tell AST to use 1st ^C */ return; } /* * ps_can - Cancel transfer abort mechanism. * * Reset screen. ^C now will gracefully exit task */ ps_can() { aboarm = aboflag = 0; /* Watch it! aboarm is decremented */ printf("%s\033[1;24r", clrseq); fflush(stdout); } /* * astsrv - Service ^C (INTERRUPT-DO) inputs * * If "armed" for transfer abort, the 1st INTERRUPT-DO sets a flag * which causes a synchronous abort of the file transfer currently * underway. If not, the first INTERRUPT-DO causes a fairly graceful * exit of the task. If not armed, one INTERRUPT-DO is enough to * cause task exit. */ extern char *fp; /* Open file pointer */ static astsrv() { astset(); /* Save environ. for AST */ if(aboarm-- > 0) /* If we were armed */ aboflag = TRUE; /* Set abort transfer flag */ else /* Real INTERRUPT-DO */ { qiow(IO_KIL, 1, 1, 0, 0, 0, 0); /* Kill terminal I/O */ qiow(IO_KIL, COMM_LUN, COMM_EFN, 0, 0, 0, 0); /* Kill XK: I/O */ fclose(fp); /* Close input file */ xk_rst(); /* Flush XK & restore I/O */ p$msgbrd("User aborted KERMIT.", iosb); p$fatler("User abort, INTERRUPT-DO entered."); } astx(1); /* Exit AST (remove 1 TDP) */ }