/* ** QBTTL is a complete, if somewhat limited, terminal emulation ** program designed to demonstrate the use of the LiteComm(tm) ** ToolBox. The executable version is included so that you can ** try it out while viewing the code. To successfully create a ** new version of QBTTL, you must have the XMODEM and WXMODEM engines ** which are provided as part of your registration package. The ** QUICKB functionality is derived from public domain code, and adapted ** by Information Technology for use with LiteComm. ** Also note that the windowing parts of the program are based upon ** CXL, a shareware product of Innovative Data Concepts. ** You must have this product and be a LiteComm registrant to successfully ** compile a new version of QBTTL. ** ** While non-registered users cannot create a new version of QBTTL, as-is ** we have provided the source as part of the distribution package to ** help you in your understanding of the way in which the LiteComm ** Communications ToolBox can be used. ** ** QBTTL functions as a vidtex terminal when used in conjuction with ** CompuServe. In addition, it will run on any communications port from ** 1 thru 4, defaulting to port 2 (COM2). To execute QBTTL on other than ** COM2, specify ** QBTTL n ** where n is a number from 1 to 4. ** ** Please note also that, to send a Ctrl-C, you must use the Alt-C keys ** ** Information Technology, Ltd. */ #include "litecomm.h" #include "lcproto.h" #include "lcpxm.h" #include "lczm.h" #include "cxlkey.h" #include "cxlstr.h" #include "cxlwin.h" #include #ifdef __TURBOC__ #include #include #include #include #include #include #include #endif #ifdef M_I86 #include #include #include #include #include #include #include #include #include #include #endif #ifdef __TURBOC__ unsigned _stklen = 16384; #endif #define CTRLX 0x18 #define ESC 0x1b #define ENQ 0x05 int nocbrk(); void selproto(void); void terminal(void); void chgcomm(void); void procesc(void); void moveleft(void); void moveright(void); void moveup(void); void movedn(void); void show_modem(unsigned char); void simtab(); void setcursorpos(void); void send(void); void recv(void); void xupload(void); void xdnload(void); void wupload(void); void wdnload(void); void yzupload(void); void yzdnload(void); int kb_abort(void); /* ** Comm parameters - human-readable form */ int baud = 2400; char parity = 'N'; int data = 8; int stop = 1; /* ** Comm parameters - Litecomm form */ unsigned pbaud = 2400; unsigned pparity = NPARITY; unsigned pbits = BIT8; unsigned pstop = STOP1; unsigned protocol = XMODEM; unsigned port = 1; int xmode = 0; /* xmodem type */ int yxmode = 0; /* use small blocks */ int halfd = 0; /* half-duplex */ int hostm = 0; /* host mode */ int ctlc_hit = FALSE; char MODEMSET0[] = "ATZ\r"; char MODEMSET1[] = "ATT E0\r"; char MODEMSET2[] = "ATC1 V0 X1 S0=1 M1\r"; /* ** protocol control block pointer - Rev 6 form */ PROTO *p; WINDOW mwin; /* for CXL */ WINDOW swin; int mbd; int mbg; int msay; int mact; int mnact; int mtitle; int sbd; int sbg; int ssay; int sact; int snact; int stitle; char strbuf[80]; /* for sprintf usage */ void main(argc, argv) int argc; char *argv[]; { int opt; #ifdef M_I86 signal(SIGINT, nocbrk); /* set Ctrl-Break handler */ #endif #ifdef __TURBOC__ ctrlbrk(nocbrk); #endif /* ** check for a port parameter */ if (argc > 1) { port = atoi(argv[1]); if ((port < 1) || (port > 4)) { puts("Invalid Port Specified\n"); exit(4); } } /* ** establish windowing environment */ if ((mwin=wopen(0,0,23,79,5,(WHITE | _BLACK), (WHITE | _BLACK))) == 0) wperror("mwin:Not Enough Memory"); if ((swin=wopen(24,0,24,79,5,(BLACK | _LGREY), (BLACK | _LGREY))) == 0) wperror("swin:Not Enough Memory"); wactiv(mwin); /* ** set-up the comm port */ if (comm_opn(port,2400,NPARITY,BIT8,STOP1,2048,2048,FALSE) == -1) { wperror("Can't open port"); abort(); } /* ** allocate the protocol control block */ if ((p = lcp_alloc(port)) == NULL) { wperror("Cant make proto control block"); abort(); } lcp_abort = kb_abort; while (1) { wclear(); wputs("-- MAIN MENU --\n"); wputs("T - enter Terminal mode\n"); wputs(" Alt-X leaves terminal mode\n"); wprintf("H - toggle Host mode (now %s)\n",hostm ? "ON":"OFF"); wprintf("G - toGgle half-duplex mode (now %s)\n",halfd ? "ON":"OFF"); wprintf("C - change Comm parameters (now %d,%c,%d,%d)\n", baud,parity,data,stop); wputs("P - Select protocol, currently "); switch(protocol) { case XMODEM: wputs("XModem\n"); break; case XMODEM1K: wputs("1K XModem\n"); break; case WXMODEM: wputs("Windowed XModem\n"); break; case YMODEM: wputs("YModem\n"); break; case ZMODEM: wputs("ZModem\n"); break; } wputs("S - Send a file\n"); wputs("R - Receive a file\n"); wputs("Q - Quit\n\n"); opt = getchf("THGPSRCQ", 0); opt = toupper(opt); switch (opt) { case 'T': terminal(); break; case 'H': if (hostm) hostm = 0; else { hostm = 1; halfd = 0; } break; case 'G': if (halfd) halfd = 0; else { halfd = 1; hostm = 0; } break; case 'P': selproto(); break; case 'S': send(); break; case 'R': recv(); break; case 'C': chgcomm(); break; } if (opt == 'Q') break; /* shut down time */ } /* while (1) */ comm_close(port,FALSE); wcloseall(); lcp_free(p); /* release proto control */ exit(0); } /* main */ int nocbrk() { #ifdef M_I86 signal(SIGINT, SIG_IGN); /* set Ctrl-Break handler */ #endif ctlc_hit = TRUE; #ifdef M_I86 signal(SIGINT, nocbrk); /* set Ctrl-Break handler */ #endif return(TRUE); } void terminal() { int ch; int row, col; wclear(); while (1) { if ((ch = lc_get(port)) != -1) switch (ch & 0x7f) { case DLE: bp_DLE(); wopen(6,25,10,50,1,(WHITE|_BLACK),(WHITE|_BLACK)); wtitle("CIS RECEIVE FILE", TCENTER, (BLACK|_LGREY)); wclose(); break; case ENQ: bp_ENQ(); break; case ESC: procesc(); break; default: if (pparity != NPARITY) ch &= 0x7f; /* strip parity */ wputc(ch); if (hostm) { lc_put(port,ch); /* echo back */ if (ch == '\n') /* was it return */ { lc_put(port,'\n'); /* echo lf as well */ wputc('\n'); } } } show_modem (lc_mstat(port)); if (kbmhit()) /* anything typed ? */ { ch = getxch(); /* get input */ if (ch == 0x2d00) /* ALT-X */ return; if (ch == 0x2e00) /* ALT-X */ ch = 0x2e03; lc_put(port,ch & 0x007f); /* xmit the char */ if (hostm || halfd) /* local echo needed ? */ { wputc(ch); if (ch == '\n') /* was it CR */ { wputc('\n'); /* add LF */ if (hostm) lc_put(port, '\n'); /* and send LF in host mode */ } } } } /* while */ } void procesc() { int ch; ch = lc_getw(port); /* wait for actual command */ switch (ch & 0x7f) { case 'A': moveup(); break; case 'B': movedn(); break; case 'C': moveright(); break; case 'D': moveleft(); break; case 'H': wgotoxy(0,0); break; case 'I': bp_ESC_I(); break; case 'J': wclreos(); break; case 'K': wclreol(); break; case 'j': wclear(); break; case 'Y': setcursorpos(); break; } } /* procesc */ void selproto() { int opt; wclear(); wputs("-- SELECT PROTOCOL --\n"); wputs("1 - XMODEM\n"); wputs("2 - 1K XMODEM\n"); wputs("3 - Windowed XMODEM\n"); wputs("4 - YMODEM\n"); wputs("5 - ZMODEM\n"); opt = getchf("12345", 0); switch (opt) { case '1': protocol = XMODEM; break; case '2': protocol = XMODEM1K; break; case '3': protocol = WXMODEM; break; case '4': protocol = YMODEM; break; case '5': protocol = ZMODEM; break; } } void show_modem(unsigned char mdmstat) { if ((mdmstat & 0x0f)) /* any status change ? */ { wwprints(swin, 0, 2, (BLACK|_LGREY), " "); if (mdmstat & CTS) wwprints(swin, 0, 2, (BLACK|_LGREY), "CTS"); if (mdmstat & DSR) wwprints(swin, 0, 8, (BLACK|_LGREY), "DSR"); if (mdmstat & DCD) wwprints(swin, 0, 14, (BLACK|_LGREY), "DCD"); if (mdmstat & RI) wwprints(swin, 0, 20, (BLACK|_LGREY), "RI"); } } /* show_modem */ void setcursorpos() { int ch; int x; int y; while((ch = lc_get(port)) == -1) ; y = (ch & 0x7f) - 32; while((ch = lc_get(port)) == -1) ; x = (ch & 0x7f) - 32; wgotoxy(y, x); } struct text_info { int wintop, winbottom, winleft, winright, curx, cury; }; void gettextinfo(r) struct text_info *r; { struct _wrec_t *tmp; /* pointer to active window */ tmp = _winfo.active; r->wintop = tmp->srow; r->winleft = tmp->scol; r->winbottom = tmp->erow; r->winright = tmp->ecol; wreadcur(&(r->cury), &(r->curx)); } void moveleft() { int scurx, scury; struct text_info r; gettextinfo(&r); scurx = r.curx; scury = r.cury; scurx--; /* decrement x position */ if (scurx < r.winleft) { scury--; scurx = r.winright; if (scury < r.wintop); scury = r.winbottom; } wgotoxy(scury, scurx); } /* moveleft */ void moveright() { int scurx, scury; struct text_info r; gettextinfo(&r); scurx = r.curx; scury = r.cury; scurx++; /* decrement x position */ if (scurx > r.winright) { scury++; scurx = r.winleft; if (scury > r.winbottom); scury = r.wintop; } wgotoxy(scury, scurx); } /* moveright */ void moveup() { int scury; struct text_info r; gettextinfo(&r); scury = r.cury; scury = r.cury - 1; if (scury < r.wintop) scury = r.winbottom; wgotoxy(scury, r.curx); } /* moveup */ void movedn() { int scury; struct text_info r; gettextinfo(&r); scury = r.cury; scury = r.cury + 1; if (scury > r.winbottom) scury = r.wintop; wgotoxy(scury, r.curx); } void simtab() { int scurx, scury; struct text_info r; gettextinfo(&r); scurx = r.curx; scury = r.cury; do scurx++; /* bump x position */ while (scurx % 9); if (scurx > r.winright) { scury++; scurx = r.winleft; if (scury > r.winbottom); { wgotoxy(r.winbottom, r.winright); wputc('\n'); return; } } wgotoxy(scury, scurx); } /* simtab */ void chgcomm() { int opt; unsigned sbaud; unsigned sparity; unsigned sbits; unsigned sstop; int hbaud; char hparity; int hdata; int hstop; /* ** get current default settings */ sbaud = pbaud; sparity = pparity; sbits = pbits; sstop = pstop; hbaud = baud; hparity = parity; hdata = data; hstop = stop; while (1) { wclear(); wputs("-- COMM PARAMETERS --\n"); wprintf(" (Presently %d,%c,%d,%d)\n", hbaud,hparity,hdata,hstop); wputs("B - change Baud Rate\n"); wputs("P - change Parity\n"); wputs("D - change Data bits\n"); wputs("S - change Stop bits\n\n"); wputs("A - Abandon Changes\n"); wputs("Q - Quit to Main Menu\n\n"); opt = getxch() & 0x007f; opt = toupper(opt); switch (opt) { case 'A': return; case 'Q': pbaud = sbaud; /* reset the globals */ pparity = sparity; pbits = sbits; pstop = sstop; baud = hbaud; parity = hparity; data = hdata; stop = hstop; comm_setup(port,pbaud,pparity,pbits,pstop); return; case 'B': wputs("1 - 110, 2 - 300, 3 - 600, 4 - 1200, 5 - 2400\n"); wputs("6 - 4800, 7 - 9600, 8 - 19200\n"); opt = getxch() & 0x007f; switch (opt) { case '1': hbaud = 110; sbaud = 110; break; case '2': hbaud = 300; sbaud = 300; break; case '3': hbaud = 600; sbaud = 600; break; case '4': hbaud = 1200; sbaud = 1200; break; case '5': hbaud = 2400; sbaud = 2400; break; case '6': hbaud = 4800; sbaud = 4800; break; case '7': hbaud = 9600; sbaud = 9600; break; case '8': hbaud = 19200; sbaud = 19200; break; case '9': hbaud = 38400; sbaud = 38400; break; } break; case 'P': wputs("1 - NONE, 2 - EVEN, 3 - ODD, 4 - MARK, 5 - SPACE\n"); opt = getxch() & 0x007f; switch (opt) { case '1': hparity = 'N'; sparity = NPARITY; break; case '2': hparity = 'E'; sparity = EPARITY; break; case '3': hparity = 'O'; sparity = OPARITY; break; case '4': hparity = 'M'; sparity = MPARITY; break; case '5': hparity = 'S'; sparity = SPARITY; break; } break; case 'D': wputs("Number of Data Bits (5, 6, 7, 8)\n"); opt = getxch() & 0x007f; switch (opt) { case '5': hdata = 5; sbits = BIT5; break; case '6': hdata = 6; sbits = BIT6; break; case '7': hdata = 7; sbits = BIT7; break; case '8': hdata = 8; sbits = BIT8; break; } break; case 'S': wputs("Number of Stop Bits (1, 2)\n"); opt = getxch() & 0x007f; switch (opt) { case '1': hstop = 1; sstop = STOP1; break; case '2': hstop = 2; sstop = STOP2; break; } break; } } } void send() { wopen(6,25,10,50,1,(WHITE|_BLACK),(WHITE|_BLACK)); wtitle("SEND A FILE", TCENTER, (BLACK|_LGREY)); lcp_setproto(p, protocol, TRUE); switch (protocol) { case XMODEM: case XMODEM1K: xupload(); break; case WXMODEM: wupload(); break; case YMODEM: case ZMODEM: yzupload(); break; } wclose(); } void recv() { wopen(6,25,10,50,1,(WHITE|_BLACK),(WHITE|_BLACK)); wtitle("RECEIVE A FILE", TCENTER, (BLACK|_LGREY)); lcp_setproto(p, protocol, TRUE); switch (protocol) { case XMODEM: case XMODEM1K: xdnload(); break; case WXMODEM: wdnload(); break; case YMODEM: case ZMODEM: yzdnload(); break; } wclose(); } void getfname(fname) char *fname; { wclear(); wputs("File Name: "); wgetns(fname, 13); cputs("\n"); } void getpname(fname) char *fname; { wclear(); wputs("Storage Path: "); wgetns(fname, 13); cputs("\n"); } void xupload(void) { char fname[81]; int fd; unsigned char *bpos; int toread; int tosend; unsigned char hdshk; int hmode; int result; getfname(fname); ctlc_hit = FALSE; if (ctlc_hit == TRUE) { ctlc_hit = FALSE; return; } if (strblank(fname)) return; strbtrim(fname); if ((fd = open(fname, (O_RDONLY|O_BINARY))) == -1) { wperror("Unable to open the file"); return; } /* ** the file has been opened successfully...now switch the ** comport mode to 8 bits for xmodem protocol */ if (comm_setup(port,pbaud,NPARITY,BIT8,pstop) == ERR) { wperror("Unable to switch line mode"); return; } /* ** begin file transmission to receiver - ** in receiver's specified mode */ if(protocol == XMODEM1K) toread = 1024; else toread = 128; while (TRUE) { memset(p->buff, 0x1a, 1024); /* clear buff, short rec */ if ((tosend = read(fd, p->buff, 1024)) < 1) /* EOF or Error */ { lcxteot(p); /* send end of file */ wperror("End of Transmission"); break; } bpos = p->buff; while (TRUE) { if (tosend <= 0) break; /* block sent completely */ if (protocol == XMODEM1K) if (tosend != toread) /* short block */ { toread = 128; /* sending short */ p->protocol = XMODEM; } result = lcpxmsnd(p); switch(result) /* what action to take ? */ { case SUCCESS: wgotoxy(1,1); wclreol(); wprintf("Sent record: %d",(p->rec-1)); tosend -= toread; bpos += toread; break; case CAN: wperror("Cancel Received"); break; case RETRIES: sprintf(strbuf, "Too Many tries...Rec %d",(p->rec-1)); wperror(strbuf); break; default: wperror("Fatal transmission error"); break; } if (result != SUCCESS) break; } /* inner while */ if (result != SUCCESS) break; } /* while TRUE */ comm_setup(port,pbaud,pparity,pbits,pstop); close(fd); /* close down the file */ } void xdnload(void) { char fname[81]; int fd; int result; ctlc_hit = FALSE; getfname(fname); if (ctlc_hit == TRUE) { ctlc_hit = FALSE; return; } if (strblank(fname)) return; strbtrim(fname); if ((fd = open(fname, (O_WRONLY|O_CREAT|O_TRUNC|O_BINARY),(S_IREAD|S_IWRITE))) == -1) { wperror("Unable to open the file"); return; } /* ** the file has been opened successfully...now switch the ** comport mode to 8 bits for xmodem protocol */ if (comm_setup(port,pbaud,NPARITY,BIT8,pstop) == ERR) { wperror("Unable to switch line mode"); return; } /* ** setup conditions for XMODEM receive */ while (TRUE) { while ((result = lcpxmrec(p)) == SUCCESS) { write(fd, p->buff, p->rbsize); /* dump the block */ wgotoxy(1,1); wclreol(); wprintf("Received record: %d",(p->rec-1)); } switch(result) /* unusual conditions */ { case DUPSEQ: wgotoxy(1,1); wclreol(); wputs("Duplicate record seq"); break; case CAN: wperror("Cancelled by host"); break; case EOT: wperror("Normal Termination"); break; case TOUT: wperror("SOH timeout"); break; case RETRIES: sprintf(strbuf, "Too Many tries...Rec %d",(p->rec-1)); wperror(strbuf); break; default: wperror("Fatal transmission error"); break; } if ((result != SUCCESS) && (result != DUPSEQ)) break; } /* while TRUE */ comm_setup(port,pbaud,pparity,pbits,pstop); close(fd); /* close down the file */ } void wupload(void) { char fname[81]; int fd; int hmode; int result; int nrec; /* returned record */ ctlc_hit = FALSE; getfname(fname); if (ctlc_hit == TRUE) { ctlc_hit = FALSE; return; } if (strblank(fname)) return; strbtrim(fname); if ((fd = open(fname,(O_RDONLY|O_BINARY))) == -1) { wperror("Unable to open the file"); return; } /* ** the file has been opened successfully...now switch the ** comport mode to 8 bits for xmodem protocol */ if (comm_setup(port,pbaud,NPARITY,BIT8,pstop) == ERR) { wperror("Unable to switch line mode"); return; } lc_xoff(port,TRUE); /* turn on auto xon-xoff */ /* ** begin file transmission to receiver - ** in receiver's specified mode */ while (TRUE) { memset(p->buff, 0x1a, 128); /* clear buff, short rec */ if (read(fd, p->buff, 128) < 1) /* EOF or Error */ nrec = -1; /* defines End of File */ else nrec = 0; result = lcpwxsnd(p, &nrec); switch(result) /* what action to take ? */ { case SUCCESS: if (nrec == -1) /* EOF confirmed */ wperror("End of Transmission"); else { wgotoxy(1,1); wclreol(); wprintf("Sent record: %d",p->rec); } break; case CAN: wperror("Cancel Received"); break; case RETRIES: sprintf(strbuf, "Too Many tries...Rec %d",p->rec); wperror(strbuf); break; case RESEND: /* must reset file position */ lseek(fd, (long)(nrec * 128), SEEK_SET); break; default: wperror("Fatal transmission error"); break; } if (result == RESEND) continue; if (result == SUCCESS) if (nrec == -1) /* was EOF signalled */ break; else continue; break; /* some other error */ } /* while TRUE */ lc_xoff(port, FALSE); /* turn off auto xon/xoff */ comm_setup(port,pbaud,pparity,pbits,pstop); close(fd); /* close down the file */ } void wdnload(void) { char fname[81]; int fd; int result; ctlc_hit = FALSE; getfname(fname); if (ctlc_hit == TRUE) { ctlc_hit = FALSE; return; } if (strblank(fname)) return; strbtrim(fname); if ((fd = open(fname, (O_WRONLY|O_CREAT|O_TRUNC|O_BINARY),(S_IREAD|S_IWRITE))) == -1) { wperror("Unable to open the file"); return; } /* ** the file has been opened successfully...now switch the ** comport mode to 8 bits for xmodem protocol */ if (comm_setup(port,pbaud,NPARITY,BIT8,pstop) == ERR) { wperror("Unable to switch line mode"); return; } /* ** setup conditions for WXMODEM receive */ while (TRUE) { while ((result = lcpwxrec(p)) == SUCCESS) { write(fd, p->buff, 128); /* dump the block */ wgotoxy(1,1); wclreol(); wprintf("Received record: %d", p->rec-1); } switch(result) /* unusual conditions */ { case DUPSEQ: wgotoxy(1,1); wclreol(); wputs("Duplicate record seq"); break; case CAN: wperror("Cancelled by host"); break; case EOT: wperror("Normal Termination"); break; case TOUT: wperror("SOH timeout"); break; case RETRIES: sprintf(strbuf, "Too Many tries...Rec %d",(p->rec-1)); wperror(strbuf); break; default: wperror("Fatal transmission error"); break; } if ((result != SUCCESS) && (result != DUPSEQ)) break; } /* while TRUE */ comm_setup(port,pbaud,pparity,pbits,pstop); close(fd); /* close down the file */ } void yzupload(void) { char fname[81]; int result; int i; int j; int nrec; /* returned record */ unsigned char *filelist[33]; #ifdef __TURBOC__ struct ffblk fi; #else struct find_t fi; #endif ctlc_hit = FALSE; getfname(fname); if (ctlc_hit == TRUE) { ctlc_hit = FALSE; return; } if (strblank(fname)) return; strbtrim(fname); i = 0; #ifdef __TURBOC__ result = findfirst(fname, &fi,0); while ((result != -1) && (i < 32)) #else result = _dos_findfirst(fname, 0, &fi); while ((result == 0) && (i < 32)) #endif { #ifdef __TURBOC__ filelist[i] = strdup(fi.ff_name); #else filelist[i] = strdup(fi.name); #endif if (filelist[i] == NULL) { for (j = 0; j < i; j++) free(filelist[j]); return; } i++; #ifdef __TURBOC__ result = findnext(&fi); #else result = _dos_findnext(&fi); #endif } filelist[i] = strdup(""); /* null name terminates list */ /* now switch the ** comport mode to 8 bits for xmodem protocol */ if (comm_setup(port,pbaud,NPARITY,BIT8,pstop) == ERR) { wperror("Unable to switch line mode"); for (j = 0; j < i; j++) free(filelist[j]); return; } /* ** begin file transmission to receiver - ** in receiver's specified mode */ if (protocol == YMODEM) lcym_send(p, (unsigned char**) filelist); /* go do it */ else lczm_send(p, (long) pbaud, (unsigned char **) filelist); comm_setup(port,pbaud,pparity,pbits,pstop); /* reset params */ for (j = 0; j < i; j++) free(filelist[j]); } void yzdnload(void) { char fname[81]; int result; ctlc_hit = FALSE; getpname(fname); if (ctlc_hit == TRUE) { ctlc_hit = FALSE; return; } if (strblank(fname)) return; strbtrim(fname); /* ** the file has been opened successfully...now switch the ** comport mode to 8 bits for xmodem protocol */ if (comm_setup(port,pbaud,NPARITY,BIT8,pstop) == ERR) { wperror("Unable to switch line mode"); return; } /* ** process the download */ if (protocol == YMODEM) lcym_recv(p, fname); else lczm_recv(p, pbaud, fname); comm_setup(port,pbaud,pparity,pbits,pstop); } int kb_abort(void) { char ch; if (kbmhit()) { ch = getxch(); if (ch == 0x1b) /* escape ? */ return(TRUE); } return (FALSE); }