home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / msdos / graphics / tty.arc / TTY.C
C/C++ Source or Header  |  1987-11-01  |  24KB  |  1,126 lines

  1. /*
  2.  *    TTY.C        A quick general purpose terminal program.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <osbind.h>
  7. #ifdef dLibs
  8. #include <time.h>
  9. #endif
  10.  
  11. #define    ident    "TTY v0.71\033v\r\n"
  12.  
  13. #define    ABORT    (-3)
  14. #define    CANCEL    (-2)
  15.  
  16. #define    AUX    1
  17. #define    CON    2
  18.  
  19. #define    SOH    0x01
  20. #define    STX    0x02
  21. #define    EOT    0x04
  22. #define    ACK    0x06
  23. #define    NAK    0x15
  24. #define    CAN    0x18
  25. #define    CEE    0x43
  26.  
  27. #define    KEY_UNDO    0x6100        /* [undo]    */
  28. #define    KEY_HELP    0x6200        /* [help]    */
  29. #define    KEY_INS        0x5200        /* [insert]    */
  30. #define    KEY_CLR        0x4700        /* [clr/home]    */
  31. #define    KEY_CR        0x1C0D        /* [return]    */
  32. #define    KEY_LF        0x720D        /* [enter]    */
  33. #define    KEY_BS        0x0E08        /* [backspace]    */
  34. #define    KEY_DEL        0x537F        /* [delete]    */
  35. #define    KEY_BRK        0x2E03        /* [control][C]    */
  36. #define    KEY_F1        0x3B00        /* [f1]        */
  37. #define    KEY_F2        0x3C00        /* [f2]        */
  38. #define    KEY_F3        0x3D00        /* [f3]        */
  39. #define    KEY_F4        0x3E00        /* [f4]        */
  40. #define    KEY_F5        0x3F00        /* [f5]        */
  41. #define    KEY_F6        0x4000        /* [f6]        */
  42. #define    KEY_F7        0x4100        /* [f7]        */
  43. #define    KEY_F8        0x4200        /* [f8]        */
  44. #define    KEY_F9        0x4300        /* [f9]        */
  45. #define    KEY_F10        0x4400        /* [f10]    */
  46. #define    ALT_C        0x2E00        /* [alt][C]    */
  47. #define    ALT_A        0x1E00        /* [alt][A]    */
  48. #define    ALT_DASH    0x8200        /* [alt][-]    */
  49. #define    ALT_V        0x2F00        /* [alt][V]    */
  50. #define    ALT_T        0x1400        /* [alt][T]    */
  51. #define    ALT_E        0x1200        /* [alt][E]    */
  52. #define    ALT_F        0x2100        /* [alt][F]    */
  53. #define    ALT_R        0x1300        /* [alt][R]    */
  54. #define    ALT_S        0x1F00        /* [alt][S]    */
  55. #define    ALT_B        0x3000        /* [alt][B]    */
  56. #define    ALT_0        0x8100        /* [alt][0]    */
  57. #define    ALT_H        0x2300        /* [alt][H]    */
  58. #define    ALT_X        0x2D00        /* [alt][X]    */
  59. #define    ALT_G        0x2200        /* [alt][G]    */
  60.  
  61. #define    ECODES    3        /* line echo settings (aka duplex) */
  62. #define    FULLDUP    0        /*    no echo            */
  63. #define    HALFDUP    1        /*    local echo        */
  64. #define    HOSTMOD    2        /*    local & remote echo    */
  65.  
  66. #define    XCODES    4        /* # of file xfer modes */
  67. #define    ASCII    0
  68. #define    XMODEM    1
  69. #define    XMODEMC    2
  70. #define    YMODEM    3
  71.  
  72. #define    BCODES    5        /* # of baud rate settings */
  73. #define    B300    0
  74. #define    B1200    1
  75. #define    B2400    2
  76. #define    B4800    3
  77. #define    B9600    4
  78.  
  79. #define    HSIZ    (1<<11)        /* history size (2K) */
  80. #define    HMASK    (HSIZ-1)
  81.  
  82. int    cd;            /* current state of carrier */
  83. BYTE    hist[HSIZ];        /* history buffer */
  84. int    hp = 0;            /* history position index */
  85. BYTE    data[1200];        /* general purpose data buffer */
  86. int    crcmode, kmode, ybatch;    /* file transfer mode settings */
  87. int    pktnum;            /* file transfer packet counter */
  88. int    noise;            /* line noise analysis value */
  89. handle    capture = 0;        /* ascii capture file handle */
  90. int    crtocrlf = FALSE;    /* convert <cr> --> <cr>+<lf> */
  91. int    echo = FULLDUP;        /* echo mode (duplex) */
  92. char    *ename[ECODES] =    /* echo mode names */
  93.     {"full duplex", "half duplex", "host mode"};
  94. int    xfer = XMODEMC;        /* file xfer mode */
  95. char    *xname[XCODES] =    /* xfer mode names */
  96.     {"ascii", "xmodem", "xmodem-crc", "ymodem"};
  97. int    bcode = B300;        /* baud code (not set on entry) */
  98. int    brate[BCODES] =        /* baud rate values */
  99.     {9, 7, 4, 2, 1};
  100. char    *bname[BCODES] =    /* baud code names */
  101.     {"300", "1200", "2400", "4800", "9600"};
  102. int    literal = FALSE;    /* literal mode flag */
  103. int    debug = FALSE;        /* debugging mode flag */
  104.  
  105. struct iorec {
  106.     char    *iobuf;            /* pointer to buffer */
  107.     int    iobufsiz;        /* size of buffer */
  108.     int    iobufhd;        /* head pointer */
  109.     int    iobuftl;        /* tail pointer */
  110.     int    iobuflo;        /* low water mark */
  111.     int    iobufhi;        /* high water mark */
  112. };
  113.  
  114. typedef struct {
  115.     struct iorec in;            /*  0 Input buffer        */
  116.     struct iorec out;            /* 14 Output buffer        */
  117.     char    rsr_status;        /* 28 MFP(0x1C) Receiver status    */
  118.     char    tsr_status;        /* 29 MFP(0x1D) Transmit status    */
  119.     char    xoff_sent;        /* 30 TRUE if we sent XOFF    */
  120.     char    xoff_received;        /* 31 TRUE if we got XOFF    */
  121.     char    mode;            /* 32 Bit 0 XON, Bit 1 RTS mode    */
  122.     char    filler;            /* 33 Unused            */
  123. } IOREC;
  124.  
  125. #define    IBUFSIZ    1200
  126. #define    OBUFSIZ    2
  127.  
  128. char    st_ibuf[IBUFSIZ];    /* our own input buffer        */
  129. char    st_obuf[OBUFSIZ];    /* and our own output buffer    */
  130.  
  131. IOREC    *st_sysr;        /* ptr to system rs232 record    */
  132. IOREC    st_savr;        /* to save system rs232 record    */
  133.  
  134. IOREC    st_myiorec = {        /* my own i/o record */
  135.      st_ibuf, IBUFSIZ, 0, 0, (IBUFSIZ/4), (3*(IBUFSIZ/4)),
  136.      st_obuf, OBUFSIZ, 0, 0, 0, 1,
  137.      0, 0, 0, 0
  138. };
  139.  
  140. #ifndef dLibs
  141. int strncmp(str1, str2, limit)
  142. register char *str1;
  143. register char *str2;
  144. register int limit;
  145. /*
  146.  *    Compare strings as with strcmp(), but limit comparison to the
  147.  *    first <limit> characters.
  148.  */
  149. {
  150.     for(; ((--limit) && (*str1 == *str2)); ++str1, ++str2)
  151.         if(*str1 == '\0')
  152.             return(0);
  153.     return(*str1 - *str2);
  154. }
  155.  
  156. /*
  157.  * start_timer & time_since
  158.  *
  159.  * Use 200Hz system clock for an elapsed time function. -Dal
  160.  */
  161. long start_timer(timer)
  162. long *timer;
  163. {
  164.     asm("    clr.l    -(sp)        ");
  165.     asm("    move.w    #$20,-(sp)    ");
  166.     asm("    trap    #1        ");    /* enter supervisor mode */
  167.     asm("    addq.l    #6,sp        ");
  168.     asm("    move.l    $4BA,-(sp)    ");    /* save system clock value */
  169.     asm("    move.l    d0,-(sp)    ");
  170.     asm("    move.w    #$20,-(sp)    ");
  171.     asm("    trap    #1        ");    /* exit supervisor mode */
  172.     asm("    addq.l    #6,sp        ");
  173.     asm("    move.l    (sp)+,d0    ");
  174.     asm("    move.l    $8(a6),a0    ");    /* grab pointer to timer */
  175.     asm("    move.l    d0,(a0)        ");    /* return clock value */
  176. }
  177.  
  178. long time_since(timer)
  179. long *timer;
  180. {
  181.     asm("    clr.l    -(sp)        ");
  182.     asm("    move.w    #$20,-(sp)    ");
  183.     asm("    trap    #1        ");    /* enter supervisor mode */
  184.     asm("    addq.l    #6,sp        ");
  185.     asm("    move.l    $4BA,-(sp)    ");    /* save system clock value */
  186.     asm("    move.l    d0,-(sp)    ");
  187.     asm("    move.w    #$20,-(sp)    ");
  188.     asm("    trap    #1        ");    /* exit supervisor mode */
  189.     asm("    addq.l    #6,sp        ");
  190.     asm("    move.l    (sp)+,d0    ");
  191.     asm("    move.l    $8(a6),a0    ");    /* grab pointer to timer */
  192.     asm("    sub.l    (a0),d0        ");    /* return elapsed time */
  193. }
  194. #endif
  195.  
  196. msleep(n)            /* do nothing for n-100ths of a second */
  197. register int n;
  198. {
  199.     long t;
  200.  
  201.     n <<= 1;        /* multiply by 2 to get 200Hz ticks */
  202.     start_timer(&t);
  203.     while(time_since(&t) < n)
  204.         ;
  205. }
  206.  
  207. rs232cd()            /* state of rs232 carrier detect line */
  208. {
  209.     register long ssp;
  210.     register int *mfp, status;
  211.  
  212.     mfp = ((int *) 0xFFFFFA00L);        /* base address of MFP */
  213.     ssp = Super(0L);            /* enter supervisor mode */
  214.     status = *mfp;                /* get MFP status */
  215.     Super(ssp);                /* return to user mode */
  216.     return(!(status & 0x0002));        /* check for carrier */
  217. }
  218.  
  219. snd_brk()            /* send a BREAK to the rs232 port */
  220. {
  221.     register long ssp;
  222.     register char *tsr;
  223.  
  224.     tsr = ((char *) 0xFFFFFA2DL);        /* address of tsr */
  225.     ssp = Super(0L);            /* enter supervisor mode */
  226.     *tsr = 0x09;                /* turn break on */
  227.     Super(ssp);                /* return to user mode */
  228.     msleep(30);                /* 0.3 second BREAK */
  229.     ssp = Super(0L);            /* enter supervisor mode */
  230.     *tsr = 0x01;                /* turn break off */
  231.     Super(ssp);                /* return to user mode */
  232. }
  233.  
  234. hangup()            /* drop carrier by droppping DTR to modem */
  235. {
  236.     Ongibit(0x10);                /* kill DTR */
  237.     msleep(50);                /* wait 1/2 a second */
  238.     Offgibit(0xEF);                /* restore DTR */
  239. }
  240.  
  241. /*
  242.  * Buffered file input functions
  243.  */
  244. #define    Bsiz    1024        /* block read size */
  245. #define    Fsiz    (2*Bsiz)+256    /* buffer size */
  246. BYTE    Fbuf[Fsiz];        /* file character buffer */
  247. BYTE    *Fp = &Fbuf[Fsiz];    /* next character to output from Fbuf[] */
  248. int    Fcnt = 0;        /* number of characters in Fbuf[] */
  249. handle    Fh;            /* file handle for buffered file */
  250.  
  251. Finit(fname)
  252. char *fname;
  253. {
  254.     Fp = &Fbuf[Fsiz];
  255.     Fcnt = 0;
  256.     return(Fh = Fopen(fname, 0));
  257. }
  258.  
  259. Fgetc()            /* get a character from file */
  260. {
  261.     register int n;
  262.  
  263.     if(Fcnt <= 0) {
  264.         Fp -= Bsiz;
  265.         if((n = Fread(Fh, ((long) Bsiz), Fp)) < 0)
  266.             Bconws(CON, "<read error>\r\n");
  267.         if(n <= 0)
  268.             return(EOF);
  269.         Fcnt += n;
  270.     }
  271.     --Fcnt;
  272.     return(*Fp++);        /* MUST & with 0xFF if not UNSIGNED */
  273. }
  274.  
  275. Fgetn(buf, n)        /* get 'n' characters from file */
  276. register char *buf;
  277. register int n;
  278. {
  279.     register int c, m;
  280.  
  281.     m = n;
  282.     while(n--) {
  283.         if((c = Fgetc()) == EOF) {
  284.             m -= (++n);
  285.             while(n--)
  286.                 *buf++ = '\0';
  287.             break;
  288.         }
  289.         *buf++ = c;
  290.     }
  291.     return(m);
  292. }
  293.  
  294. Fungetn(buf, n)
  295. register char *buf;
  296. register int n;
  297. {
  298.     register char *p;
  299.  
  300.     Fcnt += n;
  301.     Fp -= n;
  302.     for(p=Fp; n--; *p++ = *buf++)
  303.         ;
  304. }
  305.  
  306. /*
  307.  * Extra i/o functions including AUX: input with timeout
  308.  */
  309. openaux()        /* set up our own rs232 input and output buffers */
  310. {
  311.     while(Bconstat(AUX))        /* flush existing buffer */
  312.         Bconin(AUX);
  313.     st_sysr = (IOREC *)Iorec(0);
  314.     st_savr = *st_sysr;        /* Save system buffer    */
  315.     *st_sysr = st_myiorec;        /* Set my io buffer    */
  316. }
  317.  
  318. closeaux()        /* restore system i/o buffer */
  319. {
  320.     *st_sysr = st_savr;
  321. }
  322.  
  323. int un_kb = '\0';        /* ungotten keyboard character */
  324.  
  325. #define    ungetkb(c)    un_kb=(c)
  326.  
  327. kbready()
  328. {
  329.     return(un_kb || Bconstat(CON));
  330. }
  331.  
  332. getkb()
  333. {
  334.     register long n;
  335.     register int c;
  336.  
  337.     if(un_kb) {
  338.         c = un_kb;
  339.         un_kb = '\0';
  340.         return(c);
  341.     }
  342.     n = Bconin(CON);
  343.     return((0x00FF & n) | (0xFF00 & (n>>8)));
  344. }
  345.  
  346. checkabort()            /* check for abort conditions */
  347. {
  348.     return(!rs232cd() || (Bconstat(CON) && (getkb() == KEY_UNDO)));
  349. }
  350.  
  351. #define    RDLNMAX    128
  352.  
  353. char *getln()            /* Get input line from console thru OS */
  354. {
  355.     static char rdlnbuf[RDLNMAX+4];
  356.     register char *cp=rdlnbuf;
  357.     register int c, i=0;
  358.  
  359.     for(;;) {
  360.         c = getkb();
  361.         if(c == KEY_UNDO) {
  362.             *(cp = rdlnbuf) = '\0';
  363.             i=0;
  364.             break;
  365.         }
  366.         else if((c == KEY_CR) || (c == KEY_LF)) {
  367.             *cp = '\0';
  368.             break;
  369.         }
  370.         else if((c == KEY_BS) || (c == KEY_DEL)) {
  371.             if(cp != rdlnbuf) {
  372.                 --cp;
  373.                 Bconws(CON, "\b \b");
  374.                 --i;
  375.             }
  376.             else
  377.                 Bconout(CON, 0x07);
  378.         }
  379.         else if((c >= ' ') && (i < RDLNMAX)) {
  380.             Bconout(CON, (*cp++ = c));
  381.             ++i;
  382.         }
  383.         else
  384.             Bconout(CON, 0x07);
  385.     }
  386.     return(rdlnbuf);
  387. }
  388.  
  389. char *prompt(p)            /* prompt for console input */
  390. char *p;
  391. {
  392.     Bconws(CON, p);
  393.     p = getln();
  394.     Bconws(CON, "\r\n");
  395.     return(p);
  396. }
  397.  
  398. int un_aux = '\0';        /* ungotten AUX: character */
  399. int can_flg = FALSE;        /* CAN character received */
  400.  
  401. #define    ungetaux(c)    un_aux=(c)
  402.  
  403. auxready()
  404. {
  405.     return(un_aux || Bconstat(AUX));
  406. }
  407.  
  408. getaux(limit)            /* get a character from AUX: w/ timeout */
  409. int limit;
  410. {
  411.     long t;
  412.     register long tt;
  413.     register int c;
  414.  
  415.     tt = ((long) (limit * 200));
  416.     if(un_aux) {
  417.         c = un_aux;
  418.         un_aux = '\0';
  419.         return(c);
  420.     }
  421.     start_timer(&t);
  422.     while(!Bconstat(AUX)) {
  423.         if(checkabort()) {
  424.             cancel();
  425.             return(ABORT);
  426.         }
  427.         if(time_since(&t) > tt)
  428.             return(ERROR);
  429.     }
  430.     c = (0xFF & Bconin(AUX));
  431.     if(c == CAN) {
  432.         if((can_flg = !can_flg) == FALSE)
  433.             return(CANCEL);
  434.     }
  435.     else
  436.         can_flg = FALSE;
  437.     return(c);
  438. }
  439.  
  440. int getsnaux(s, n)        /* get 'n' characters from AUX: */
  441. register char *s;
  442. register int n;
  443. {
  444.     register int c;
  445.  
  446.     while(n--) {
  447.         switch(c = getaux(1)) {
  448.             case ERROR:
  449.             case ABORT:
  450.                 return(c);
  451.             case CANCEL:
  452.                 c = CAN;    /* FALL THRU! */
  453.             default:
  454.                 *s++ = c;
  455.         }
  456.     }
  457.     *s = '\0';
  458.     return(TRUE);
  459. }
  460.  
  461. putaux(c)
  462. int c;
  463. {
  464.     Bconout(AUX, (c & 0xFF));
  465. }
  466.  
  467. putsnaux(s, n)            /* send 'n' characters to AUX: */
  468. register char *s;
  469. register int n;
  470. {
  471.     register int c;
  472.  
  473.     while(n--) {
  474.         if(auxready()) {
  475.             c = getaux(0);
  476.             if((c < 0) || (c == NAK))
  477.                 return(ungetaux(c));
  478.         }
  479.         putaux(*s++);
  480.     }
  481. }
  482.  
  483. purge()
  484. {
  485.     register int c;
  486.  
  487.     while((c = getaux(1)) >= 0)    /* wait for timeout or cancel */
  488.         ;
  489.     return(c);
  490. }
  491.  
  492. cancel()
  493. {
  494.     register int i;
  495.  
  496.     purge();
  497.     for(i=0;i<3;++i)
  498.         putaux(CAN);
  499.     for(i=0;i<3;++i)
  500.         putaux('\b');
  501.     if(debug) Bconws(CON, "<cancel>\r\n");
  502.     return(CANCEL);
  503. }
  504.  
  505. /*
  506.  * This function calculates the CRC used by the XMODEM/CRC Protocol
  507.  * The first argument is a pointer to the message block.
  508.  * The second argument is the number of bytes in the message block.
  509.  * The function returns an integer which contains the CRC.
  510.  * The low order 16 bits are the coefficients of the CRC.
  511.  */
  512. int calcrc(ptr, count)
  513. register char *ptr;
  514. register int count;
  515. {
  516.     register int crc = 0, i;
  517.  
  518.     while(--count >= 0) {
  519.         crc = crc ^ (int)*ptr++ << 8;
  520.         for(i=0; i<8; ++i)
  521.             if(crc & 0x8000)
  522.                 crc = crc << 1 ^ 0x1021;
  523.             else
  524.                 crc = crc << 1;
  525.         }
  526.     return(crc & 0xFFFF);
  527. }
  528.  
  529. int calchk(ptr, count)
  530. register char *ptr;
  531. register int count;
  532. {
  533.     register int sum = 0;
  534.  
  535.     while(--count >= 0)
  536.         sum += *ptr++;
  537.     return(sum & 0x00FF);
  538. }
  539.  
  540. mode_init()            /* initialize xfer mode settings from config */
  541. {
  542.     crcmode = (xfer >= XMODEMC);
  543.     kmode = (xfer >= YMODEM);
  544.     ybatch = (xfer == YMODEM) && (FALSE);    /* <-- check for wildcards */
  545. }
  546.  
  547. pkt_sync(limit)
  548. int limit;
  549. {
  550.     register int c;
  551.  
  552.      kmode = FALSE;
  553.     while(rs232cd()) {
  554.         switch(c = getaux(limit)) {
  555.             case ERROR:
  556.             case CANCEL:
  557.             case ABORT:
  558.                 return(c);
  559.             case STX:
  560.                 kmode = TRUE;        /* FALL THRU... */
  561.             case SOH:
  562.                 return(TRUE);
  563.             case EOT:
  564.                 return(FALSE);
  565.         }
  566.     }
  567.     return(ERROR);
  568. }
  569.  
  570. rcv_init()
  571. {
  572.     register int i, j;
  573.  
  574.     pktnum = 1;
  575.     mode_init();
  576.     if(crcmode) {
  577.         i = 3;
  578.         while(i--) {
  579.             putaux(CEE);
  580.             Bconout(CON, 'c');
  581.             j = pkt_sync(5);
  582.             if(j != ERROR)
  583.                 return(j);
  584.         }
  585.         crcmode = FALSE;
  586.     }
  587.     i = 9;
  588.     while(i--) {
  589.         putaux(NAK);
  590.         Bconout(CON, '.');
  591.         j = pkt_sync(5);
  592.         if(j != ERROR)
  593.             return(j);
  594.     }
  595.     if(debug) Bconws(CON, "<init failed>\r\n");
  596.     return(ERROR);
  597. }
  598.  
  599. rcv_pkt()
  600. {
  601.     register int i, j, k = 0;
  602.  
  603.     while(++k < 6) {
  604.         if((j = pkt_sync(10)) != TRUE)
  605.             return(j);
  606.         i = (kmode ? 1024 : 128);
  607.         j = getsnaux(data, (i+3+crcmode));
  608.         if(j == ERROR) {        /* receiver timeout */
  609.             if(debug) Bconws(CON, "[timeout]");
  610.             goto RETRY;
  611.         }
  612.         if((pktnum==1) && (data[0]==0) && (data[1]==0xFF)) {
  613.             /* Ymodem-batch header */
  614.             crcmode = TRUE;
  615.             ybatch = TRUE;
  616.             Bconout(CON, '*');
  617.             putaux(ACK);
  618.             putaux(CEE);
  619.             return(rcv_pkt());    /* recurse... */
  620.         }
  621.         if(data[0] != ~data[1]) {    /* parity error */
  622.             if(debug) Bconws(CON, "[parity error]");
  623.             goto RETRY;
  624.         }
  625.         if(data[0] == (pktnum - 1)) {    /* duplicate packet */
  626.             if(debug) Bconws(CON, "[duplicate packet]");
  627.             putaux(ACK);
  628.             return(rcv_pkt());    /* recurse... */
  629.         }
  630.         if(data[0] != pktnum) {        /* sequence error, CANCEL! */
  631.             if(debug) Bconws(CON, "[sequence error]");
  632.             return(cancel());
  633.         }
  634.         if(crcmode) {
  635.             j = calcrc(data+2, i);
  636.             i = *((int *) (data+i+2));
  637.         }
  638.         else {
  639.             j = calchk(data+2, i);
  640.             i = ((int) (0xFF & data[i+2]));
  641.         }
  642.         if(i == j) {
  643.             if(++pktnum > 255)
  644.                 pktnum = 0;
  645.             Bconout(CON, '+');
  646.             putaux(ACK);
  647.             return(TRUE);
  648.         }
  649.         if(debug) Bconws(CON, crcmode?"[crc error]":"[chksum error]");
  650. RETRY:        purge();
  651.         Bconout(CON, '-');
  652.         putaux(NAK);
  653.     }
  654.     if(debug) Bconws(CON, "[retry error]");
  655.     return(cancel());
  656. }
  657.  
  658. rcv_file()
  659. {
  660.     register int f, j;
  661.     register char *p;
  662.  
  663.     if(!rs232cd()) {
  664.         Bconws(CON, "You're not on-line.\r\n");
  665.         return(FALSE);
  666.     }
  667.     if(xfer == ASCII) {
  668.         Bconws(CON, "Use text capture for ASCII receive.\r\n");
  669.         return(TRUE);
  670.     }
  671.     p = prompt("\r\nReceive file: ");    /* prompt for file name */
  672.     if(!(*p))
  673.         return(FALSE);
  674.     if((f = Fcreate(p, 0)) < 0) {
  675.         Bconws(CON, "\007<file error>\r\n");
  676.         return(ERROR);
  677.     }
  678.     if((j = rcv_init()) != TRUE)
  679.         return(j);
  680.     ungetaux(kmode ? STX : SOH);
  681.     if(debug) Bconws(CON, (crcmode?"<crc mode>":"<chksum mode>"));
  682.     while((j = rcv_pkt()) == TRUE) {
  683.         if(Fwrite(f, (kmode ? 1024L : 128L), data+2) < 0)
  684.             return(cancel());
  685.     }
  686.     Fclose(f);
  687.     if(ybatch) {        /* clean up after ymodem batch xfer */
  688.         msleep(50);
  689.         cancel();
  690.     }
  691.     if(j == FALSE) {
  692.         putaux(ACK);
  693.         if(debug) Bconws(CON, "<file rcvd>");
  694.         Bconws(CON, "\r\n");
  695.         return(TRUE);
  696.     }
  697.     else
  698.         return(j);
  699. }
  700.  
  701. snd_init()
  702. {
  703.     register int c;
  704.  
  705.     if(xfer == ASCII)
  706.         return(TRUE);
  707.     pktnum = 1;
  708.     noise = 7;
  709.     mode_init();
  710.     while(Bconstat(AUX))
  711.         Bconin(AUX);
  712.     for(;;) {
  713.         switch(c = getaux(30)) {
  714.             case ERROR:
  715.             case CANCEL:
  716.             case ABORT:
  717.                 return(c);
  718.             case CEE:
  719.             case NAK:
  720.                 Bconout(CON, ((c == CEE) ? 'c' : '.'));
  721.                 if(!(crcmode = (c == CEE)))
  722.                     kmode = FALSE;
  723.                 if(debug) Bconws(CON, 
  724.                         (crcmode?"<crc mode>":
  725.                              "<chksum mode>"));
  726.                 return(TRUE);
  727.         }
  728.     }
  729. }
  730.  
  731. snd_pkt()
  732. {
  733.     register int n, i, j, k = 0;
  734.     register char *p;
  735.  
  736.     if(xfer == ASCII) {
  737.         switch(i = Fgetc()) {
  738.             case EOF:
  739.                 return(FALSE);
  740.             case '\r':
  741.                 putaux('\r');
  742.                 if(crtocrlf)
  743.                     putaux('\n');
  744.                 msleep(10);        /* FALL THRU.. */
  745.             case '\n':
  746.                 break;
  747.             default:
  748.                 putaux(i);
  749.         }
  750.         while((i = getaux(0)) >= 0)
  751.             Bconout(CON, (i & 0x7F));
  752.         return((i == ERROR) ? TRUE : i);
  753.     }
  754.     while(++k < 6) {
  755.         data[0] = (pktnum & 0xFF);
  756.         data[1] = ((~pktnum) & 0xFF);
  757.         i = (kmode ? 1024 : 128);
  758.         p = data+2;
  759.         if((n = Fgetn(p, i)) == 0)    /* empty packet == EOF */
  760.             return(FALSE);
  761.         if(kmode && (n < 1024)) {    /* send last packets as 128 */
  762.             Fungetn(p, n);
  763.             kmode = FALSE;
  764.             n = Fgetn(p, (i = 128));
  765.         }
  766.         if(crcmode) {
  767.             j = calcrc(p, i);
  768.             *((int *) (p+i)) = j;
  769.         }
  770.         else
  771.             *(p+i) = calchk(p, i);
  772.         putaux(kmode ? STX : SOH);
  773.         putsnaux(data, i+3+crcmode);
  774.         do {
  775.             switch(j = getaux(15)) {
  776.                 case CANCEL:
  777.                 case ABORT:
  778.                     return(j);
  779.                 case ACK:
  780.                     ++noise;
  781.                     if(++pktnum > 255)
  782.                         pktnum = 0;
  783.                     Bconout(CON, '+');
  784.                     return(n == i);    /* short pkt == EOF */
  785.                 case ERROR:
  786.                     j = NAK;
  787.                     break;
  788.             }
  789.         } while(j != NAK);
  790.         Fungetn(p, n);
  791.         Bconout(CON, '-');
  792.         if(kmode && ((noise -= 8) < 0)) {    /* if too noisy.. */
  793.             if(debug) Bconws(CON, "<downshift>");
  794.             kmode = FALSE;
  795.         }
  796.     }
  797.     return(cancel());
  798. }
  799.  
  800. snd_file()
  801. {
  802.     register int i, j;
  803.     register char *p;
  804.  
  805.     if(!rs232cd()) {
  806.         Bconws(CON, "You're not on-line.\r\n");
  807.         return(FALSE);
  808.     }
  809.     p = prompt("\r\nSend file: ");        /* prompt for file name */
  810.     if(!(*p))
  811.         return(FALSE);
  812.     if(Finit(p) < 0) {
  813.         Bconws(CON, "\007<file error>\r\n");
  814.         return(ERROR);
  815.     }
  816.     if((j = snd_init()) != TRUE)
  817.         return(j);
  818.     while((j = snd_pkt()) == TRUE)
  819.         ;
  820.     Fclose(Fh);
  821.     if(xfer == ASCII)
  822.         return(j == FALSE);
  823.     if(j == FALSE) {
  824.         i = NAK;
  825.         do {
  826.             if(i == NAK)
  827.                 putaux(EOT);
  828.             i = getaux(10);
  829.             if(i < 0)
  830.                 return(i);
  831.         } while(i != ACK);
  832.         if(debug) Bconws(CON, "<file sent>");
  833.         Bconws(CON, "\r\n");
  834.         return(TRUE);
  835.     }
  836.     else
  837.         return(j);
  838. }
  839.  
  840. start_capture()
  841. {
  842.     register char *p;
  843.  
  844.     if(*(p = prompt("\r\nCapture file: ")) == '\0')
  845.         return(FALSE);
  846.     if((capture = Fcreate(p, 0)) < 0) {
  847.         capture = 0;
  848.         Bconws(CON, "\007<file error>\r\n");
  849.         return(FALSE);
  850.     }
  851. }
  852.  
  853. putcap(c)
  854. char c;
  855. {
  856.     if(Fwrite(capture, 1L, &c) != 1L) {
  857.         capture = 0;
  858.         Bconws(CON, "\007<write error>\r\n");
  859.         return(FALSE);
  860.     }
  861. }
  862.  
  863. do_grab()
  864. {
  865.     register int h, i, j;
  866.  
  867.     if((h = Fopen("GRAB.TXT", 2)) < 0) {
  868.         if((h = Fcreate("GRAB.TXT", 0)) < 0) {
  869.             Bconws(CON, "\007<can't create grab file>\r\n");
  870.             return(FALSE);
  871.         }
  872.     }
  873.     else
  874.         Fseek(h, 0L, 2);
  875.     if(Fwrite(h, 8L, "\r\n----\r\n") != 8L) {
  876.         Bconws(CON, "\007<write error>\r\n");
  877.         return(FALSE);
  878.     }
  879.     i = HSIZ - hp;
  880.     j = hp;
  881.     if(i > 0)
  882.         if(Fwrite(h, ((long) i), &hist[j]) <= 0) {
  883.             Bconws(CON, "\007<write error>\r\n");
  884.             return(FALSE);
  885.         }
  886.     if(j > 0)
  887.         if(Fwrite(h, ((long) j), hist) <= 0) {
  888.             Bconws(CON, "\007<write error>\r\n");
  889.             return(FALSE);
  890.         }
  891.     Fclose(h);
  892.     return(TRUE);
  893. }
  894.  
  895. do_help()
  896. {
  897.     Bconws(CON, "\r\n");
  898.     Bconws(CON, "[Alt][C]    Shell Command    [F1]\r\n");
  899.     Bconws(CON, "[Alt][A]    Ascii Capture    [F2]\r\n");
  900.     Bconws(CON, "[Alt][-]    Debug mode    [F3]\r\n");
  901.     Bconws(CON, "[Alt][V]    Literal mode    [F4]\r\n");
  902.     Bconws(CON, "[Alt][T]    CR -> CR+LF    [F5]\r\n");
  903.     Bconws(CON, "[Alt][E]    Echo mode    [F6]\r\n");
  904.     Bconws(CON, "[Alt][F]    File Xfer Mode    [F7]\r\n");
  905.     Bconws(CON, "[Alt][R]    Receive File    [F8]\r\n");
  906.     Bconws(CON, "[Alt][S]    Send File    [F9]\r\n");
  907.     Bconws(CON, "[Alt][B]    Baud Rate    [F10]\r\n");
  908.     Bconws(CON, "[Alt][0]    Send BREAK    [INS]\r\n");
  909.     Bconws(CON, "[Alt][H]    Drop Carrier    [CLR]\r\n");
  910.     Bconws(CON, "[Alt][X]    Exit TTY    [UNDO]\r\n");
  911.     Bconws(CON, "[Alt][G]    Grab history    \r\n");
  912. }
  913.  
  914. char *hexchr(c)
  915. {
  916.     static char hexout[5];
  917.     static char hexdigit[] = "0123456789ABCDEF";
  918.  
  919.     hexout[4] = '\0';
  920.     hexout[3] = hexdigit[c&0xF];
  921.     c >>= 4;
  922.     hexout[2] = hexdigit[c&0xF];
  923.     hexout[1] = 'x';
  924.     hexout[0] = '\\';
  925.     return(hexout);
  926. }
  927.  
  928. extern    long    _base;        /* our base-page pointer */
  929.  
  930. do_shell()
  931. {
  932.     register char *p, *ssp, (*shell)();
  933.     register long rv = 0L;
  934.  
  935.     /* get _shell_p value */
  936.     ssp = Super(0L);
  937.     shell = *((long *) 0x4F6L);
  938.     Super(ssp);
  939.  
  940.     /* validate _shell_p */
  941.     if(shell == 0L) {
  942.         Bconws(CON, "\r\nNo shell available.\r\n");
  943.         return(ERROR);
  944.     }
  945.     if((((long) shell) > ((long) _base)) || !(strncmp(shell, "PATH", 4))) {
  946.         Bconws(CON, "\r\nBad shell pointer.\r\n");
  947.         return(ERROR);
  948.     }
  949.  
  950.     /* execute the command */
  951.     if(*(p = prompt("\r\nShell Command: ")))
  952.         rv = (*shell)(p);
  953.     return((int) rv);
  954. }
  955.  
  956. main()
  957. {
  958.     register int c;
  959.  
  960.     Bconws(CON, ident);
  961.     openaux();
  962.     for(c = 0; c < HSIZ; hist[c++] = '\0')        /* zero history */
  963.         ;
  964. #ifdef NEVER
  965.     cd = !rs232cd();
  966. #endif
  967.     for(;;) {
  968.         if(kbready()) {
  969.             switch(c = getkb()) {
  970.                 case KEY_UNDO:        /* exit */
  971.                 case ALT_X:
  972.                     Bconws(CON, "\r\nExit TTY? ");
  973.                     c = (getkb() & 0xFF);
  974.                     Bconout(CON, c);
  975.                     Bconws(CON, "\r\n");
  976.                     if((c == 'y') || (c == 'Y'))
  977.                         punt(0);
  978.                     break;
  979.                 case KEY_INS:        /* break */
  980.                 case ALT_0:
  981.                     snd_brk();
  982.                     break;
  983.                 case KEY_CLR:        /* hangup */
  984.                 case ALT_H:
  985.                     hangup();
  986.                     break;
  987.                 case KEY_F1:        /* shell escape */
  988.                 case ALT_C:
  989.                     do_shell();
  990.                     break;
  991.                 case KEY_F2:        /* ascii capture */
  992.                 case ALT_A:
  993.                     if(capture) {
  994.                         Fclose(capture);
  995.                         capture = 0;
  996.                         Bconws(CON,
  997.                             "[capture off]\r\n");
  998.                     }
  999.                     else if(start_capture()) {
  1000.                         Bconws(CON,
  1001.                             "[capture on]\r\n");
  1002.                     }
  1003.                     break;
  1004.                 case KEY_F3:        /* debug toggle */
  1005.                 case ALT_DASH:
  1006.                     Bconws(CON, ((debug = !debug) ?
  1007.                         "\r\n[DEBUG ON]\r\n" :
  1008.                         "\r\n[DEBUG OFF]\r\n"));
  1009.                     break;
  1010.                 case KEY_F4:        /* literal toggle */
  1011.                 case ALT_V:
  1012.                     Bconws(CON, ((literal = !literal) ?
  1013.                         "\r\n[literal on]\r\n" :
  1014.                         "\r\n[literal off]\r\n"));
  1015.                     break;
  1016.                 case KEY_F5:        /* cr -> cr+lf */
  1017.                 case ALT_T:
  1018.                     crtocrlf = !crtocrlf;
  1019.                     Bconws(CON, crtocrlf?
  1020.                         "[cr->cr+lf]" : "[cr->cr]");
  1021.                     Bconws(CON, "\r\n");
  1022.                     break;
  1023.                 case KEY_F6:        /* duplex/echo modes */
  1024.                 case ALT_E:
  1025.                     echo = ((echo + 1) % ECODES);
  1026.                     Bconout(CON, '[');
  1027.                     Bconws(CON, ename[echo]);
  1028.                     Bconws(CON, "]\r\n");
  1029.                     break;
  1030.                 case KEY_F7:        /* file xfer modes */
  1031.                 case ALT_F:
  1032.                     xfer = ((xfer + 1) % XCODES);
  1033.                     Bconout(CON, '[');
  1034.                     Bconws(CON, xname[xfer]);
  1035.                     Bconws(CON, "]\r\n");
  1036.                     break;
  1037.                 case KEY_F8:        /* receive file */
  1038.                 case ALT_R:
  1039.                     if(rcv_file() != TRUE)
  1040.                      Bconws(CON, "\r\n<rcv failed>\r\n");
  1041.                     break;
  1042.                 case KEY_F9:        /* send file */
  1043.                 case ALT_S:
  1044.                     if(snd_file() != TRUE)
  1045.                      Bconws(CON, "\r\n<send failed>\r\n");
  1046.                     break;
  1047.                 case KEY_F10:        /* change baud rate */
  1048.                 case ALT_B:
  1049.                     bcode = ((bcode + 1) % BCODES);
  1050.                     Rsconf(brate[bcode],0,-1,-1,-1,-1);
  1051.                     Bconout(CON, '[');
  1052.                     Bconws(CON, bname[bcode]);
  1053.                     Bconws(CON, "]\r\n");
  1054.                     break;
  1055.                 case ALT_G:        /* grab history */
  1056.                     if(do_grab())
  1057.                         Bconws(CON, "<grabbed>\r\n");
  1058.                     break;
  1059.                 case KEY_HELP:        /* help info */
  1060.                     do_help();
  1061.                     break;
  1062.                 default:
  1063.                     c &= 0xFF;
  1064.                     putaux(c);
  1065.                     if(echo >= HALFDUP) {
  1066.                         Bconout(CON, c);
  1067.                         hist[hp++] = c;
  1068.                         hp &= HMASK;
  1069.                         if(capture)
  1070.                             putcap(c);
  1071.                     }
  1072.                     if(crtocrlf && (c == '\r'))
  1073.                         ungetkb('\n');
  1074.                     break;
  1075.             }
  1076.         }
  1077.         if(auxready()) {
  1078.             if(un_aux) {
  1079.                 c = (un_aux & 0xFF);
  1080.                 un_aux = '\0';
  1081.             }
  1082.             else
  1083.                 c = (Bconin(AUX) & 0x7F);
  1084.             if(literal && (c < ' '))
  1085.                 Bconws(CON, hexchr(c));
  1086.             else
  1087.                 Bconout(CON, c);
  1088.             hist[hp++] = c;
  1089.             hp &= HMASK;
  1090.             if(capture)
  1091.                 putcap(c);
  1092.             if(echo == HOSTMOD)
  1093.                 putaux(c);
  1094.             if(crtocrlf && (c == '\r'))
  1095.                 ungetaux('\n');
  1096.         }
  1097. #ifdef NEVER
  1098.         if (cd != rs232cd())
  1099.             Bconws(CON, ((cd = rs232cd()) ?
  1100.                 "\r\n[CARRIER]\r\n" :
  1101.                 "\r\n[NO CARRIER]\r\n"));
  1102. #endif
  1103.     }
  1104. }
  1105.  
  1106. Bconws(dev, s)
  1107. register int dev;
  1108. register char *s;
  1109. {
  1110.     while(*s)
  1111.         Bconout(dev, *s++);
  1112. }
  1113.  
  1114. punt(errcode)
  1115. int errcode;
  1116. {
  1117.     closeaux();
  1118.     exit(errcode);
  1119. }
  1120.  
  1121. #ifdef dLibs
  1122. _initargs()        /* dummy function to avoid command line processing */
  1123. {
  1124. }
  1125. #endif