home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 14 / CD_ASCQ_14_0694.iso / maj / 4151 / smalterm.c < prev    next >
C/C++ Source or Header  |  1994-03-22  |  37KB  |  1,079 lines

  1.  
  2. /** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3. *      S M A L T E R M  --  D e m o   D r i v e r   f o r   M C o m m 5     *
  4. *                          A s y n c   R o u t i n e s                      *
  5. *                                                                           *
  6. *              Mike Dumdei, 6 Holly Lane, Texarkana TX 75503                *
  7. *                  North East Texas DataLink, 903 838-6713                  *
  8. *                                                                           *
  9. *               (Link with comm_s.lib for external functions)               *
  10. *               cl smalterm.c /link comm_s          (Microsoft C)           *
  11. *               tcc smalterm.c comm_s.lib           (Turbo C)               *
  12. *               ztc -b smalterm.c comm_s.lib        (Zortech C)             *
  13. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/
  14. #include <stdio.h>
  15. #include <fcntl.h>
  16. #if !defined(__TURBOC__)
  17.     #include <sys\types.h>
  18. #endif
  19. #include <sys\stat.h>
  20. #include <io.h>
  21. #include <stdlib.h>
  22. #include <conio.h>
  23. #include <ctype.h>
  24. #include <string.h>
  25. #include <process.h>
  26. #include <stdarg.h>
  27. #if defined(__ZTC__)
  28.   #define   MSDOS           1
  29.   #define   stricmp         strcmpl
  30. #endif
  31. #include <dos.h>
  32. #include <bios.h>
  33.  
  34. #include "comm.h"                            /* header for async functions */
  35. #include "ansidrv.h"                   /* header for ANSI display routines */
  36. #define KEY_INT
  37. #include "keys.h"                                 /* key definition header */
  38. #if defined(RED)
  39.     #undef RED
  40. #endif
  41. #include "colors.h"                  /* vid mode & color definition header */
  42. #include "extra.h"                               /* extra functions header */
  43.  
  44. #if defined (__TURBOC__)                                        /* Turbo C */
  45.   #define   NO_FILES(x)     findfirst((x), &findbuf, 0)
  46.   #define   find_t          ffblk
  47.   #define   KBHIT           bioskey(1)
  48.   #define   KBREAD          bioskey(0)
  49.   #include  <dir.h>
  50. #else                                            /* Microsoft C, Zortech C */
  51.   #include  <direct.h>
  52.   #define   NO_FILES(x)     _dos_findfirst((x), _A_NORMAL, &findbuf)
  53.   #define   KBHIT           _bios_keybrd(_KEYBRD_READY)
  54.   #define   KBREAD          _bios_keybrd(_KEYBRD_READ)
  55. #endif
  56.  
  57. #define POP         0
  58. #define PUSH        1              /* used in screen save/restore function */
  59. #define RXBUFSZ     4096                            /* rx ring buffer size */
  60. #define TXBUFSZ     1050                            /* tx ring buffer size */
  61. #define LOST_CARRIER -1
  62. #define NO_INPUT     -1
  63. #define ESC_PRESSED  -2
  64. #define TIMED_OUT    -3
  65.  
  66. #define TRUE          1
  67. #define FALSE         0
  68. #define REG     register
  69.  
  70. typedef unsigned char uchar;
  71. typedef unsigned long ulong;
  72. typedef unsigned int uint;
  73.  
  74.  
  75. /*      f u n c t i o n   d e c l a r a t i o n s     */
  76. extern int main(int argc,char * *argv);
  77. static int proc_keypress(int ch);
  78. static int proc_rxch(int ch);
  79. static int proc_fkey(int keycd);
  80. static int watch_cd(void );
  81. static int rcls(void);
  82. static int toggle_log(void );
  83. static int toggle_echo(void );
  84. static int toggle_lfs(void );
  85. static int toggle_dtr(void );
  86. static int dial_nbr(void );
  87. static int shell_to_dos(void );
  88. static int host_mode(void );
  89. static int shell_remote(void );
  90. static int run_batch(int keycd);
  91. static int exit_term(void );
  92. static int do_help(void );
  93. static int async_tx_str(char *str);
  94. static int async_tx_echo(char *str);
  95. static int screen_pushpop(int flag);
  96. static int chg_parms(void );
  97. static int rx_timeout(int Tenths);
  98. static int waitfor(char *str, int ticks);
  99. static int waitforOK(int ticks );
  100. static int prompt(char *kbuf,char *promptmsg,int maxchars);
  101. static int comprompt(char *kbuf,char *promptmsg,int maxchars);
  102. static int hang_up(void );
  103.  
  104. /*      g l o b a l   v a r i a b l e s     */
  105.  
  106. ASYNC   *port;                               /* pointer to async structure */
  107.  /* default to COM1 */
  108. char    com_str[5] = "COM1";           /* text for port ("COM1" or "COM2") */
  109. int     IOadrs = 0x3f8;                      /* comm port base I/O address */
  110. char    irqm = IRQ4;                         /* mask for selected IRQ line */
  111. char    vctrn = VCTR4;                        /* comm interrupt vector nbr */
  112.  
  113. FILE    *logfil = NULL;                                 /* log file handle */
  114. char    dialstr[40];                           /* dial string storage area */
  115. int     ChkgKbd = 1;              /* watch for ESC during rcv with timeout */
  116. int     ChkgCarrier = 0;        /* monitor carrier during rcv with timeout */
  117. char    buf[200];                                    /* gen purpose buffer */
  118. int     lfs = 0, echo = 0, dtr = 1, autoans = 0;          /* various flags */
  119. struct find_t findbuf;                        /* struct for NO_FILES macro */
  120. int     cyn, hred, grn, hgrn, wht, hblu;           /* text color variables */
  121. int     hostcnt = 0;                        /* toggle to host mode counter */
  122.  
  123. /*
  124.             * * * *    M A I N    * * * *
  125. */
  126. main(int argc, char **argv)
  127. {
  128.     static char params[10] = "1200N81";              /* default parameters */
  129.     char        buf[100];
  130.     int         got_port = FALSE;
  131.     unsigned    i, ch;
  132.  
  133.     initvid();                                /* initialize video routines */
  134.     if (v_mode == CO80)
  135.     {
  136.         cyn = CYN, hred = H_RED, grn = GRN, hgrn = H_GRN,
  137.         wht = WHT, hblu = H_BLU;
  138.     }
  139.     else
  140.     {
  141.         cyn = WHT, hred = H_WHT, grn = WHT, hgrn = H_WHT,
  142.         wht = WHT, hblu = H_WHT;
  143.     }
  144.     v_color = cyn;
  145.     cls();                                             /* clear the screen */
  146.  
  147.     /*  D I S P L A Y   S I G N O N  */
  148.     v_color = hred;
  149.     d_str("SMALTERM - Sample driver for MCOMM5 comm routines\n");
  150.     v_color = grn;
  151.     d_str("    Mike Dumdei, 6 Holly Lane, Texarkana TX 75503\n");
  152.     d_str("    North East Texas DataLink   903 838-6713\n");
  153.     v_color = hred;
  154.     d_str("Usage: smalterm {COM1 | COM2} {param str EX: 2400N81}\n\n");
  155.     v_color = cyn;
  156.  
  157.     /*  P R O C E S S   C O M M A N D   L I N E   A R G S  */
  158.     for (i = 1; i < 3; i++)        /* do it twice so args can be any order */
  159.     {                              /*  or have one arg and not the other   */
  160.         if (argc > i)
  161.         {
  162.             if (!got_port && !stricmp(argv[i], "COM1"))
  163.                 got_port = TRUE;
  164.             else if (!got_port && !stricmp(argv[i], "COM2"))
  165.             {
  166.                 got_port = TRUE, strcpy(com_str, "COM2");
  167.                 IOadrs = 0x2f8, irqm = IRQ3, vctrn = VCTR3;
  168.             }
  169.             else if (strlen(argv[i]) < 9)   /* assume a valid param string */
  170.                 strcpy(params, argv[i]);
  171.         }
  172.     }
  173.  
  174.     /*  O P E N   T H E   C O M M   P O R T  */
  175.     port = malloc(sizeof(ASYNC));
  176.     AllocRingBuffer(port, RXBUFSZ, TXBUFSZ, 1);    /* alloc FAR ring bufrs */
  177.     if ((ch = async_open(port, IOadrs, irqm, vctrn, params)) != 0)
  178.     {
  179.         /* couldn't open the port code */
  180.         strsum(buf, "SMALTERM: Couldn't open ", com_str, " using ",
  181.               params, " for parameters -- ABORTING\n\n", NULL);
  182.         d_str(buf);
  183.         strsum(buf, "Error code = ", itoa(ch, &buf[50], 10), "\n\n", NULL);
  184.         d_str(buf);
  185.         exit(ch);
  186.     }
  187.  
  188.     /* opened OK code */
  189.  
  190.     d_str(strsum(buf, "SMALTERM: ", com_str, " -- PORT OPENED\n\n", NULL));
  191.     d_str("Press F1 for HELP screen\n");           /* tell how to get help */
  192.     /* display status line */
  193.     SETWND(0, 0, 23, 79);                           /* set the window size */
  194.     d_strnat(24, 0, '═', cyn, 80);                          /* paint a bar */
  195.     d_msgat(24, 60, hgrn, strupr(com_str));                /* display port */
  196.     d_msgat(24, 65, hgrn, strupr(params));               /* display params */
  197.     d_msgat(24, 10, hgrn, "DTR");                           /* DTR is high */
  198.     *dialstr = '\0';                              /* clear out dial string */
  199.     tickhookset(1);        /* enable 'ticker' variable for timer functions */
  200.     if (!async_carrier(port))
  201.     {
  202.         async_tx_str("ATE1V1\r");                       /* reset the modem */
  203.         waitforOK(9);
  204.     }
  205.     /*
  206.         T H I S   I S   T H E   M A I N   I N G R E D I E N T
  207.     */
  208.     while (1)
  209.     {
  210.         /* turn off auto answer if enabled by Host mode */
  211.         if (autoans && !async_carrier(port))
  212.         {
  213.             DELAY_TENTHS(2);
  214.             async_tx_str("ATS0=0\r");
  215.             waitforOK(9);
  216.             autoans = 0;
  217.         }
  218.          /* check the keyboard */
  219.         if (KBHIT)
  220.             proc_keypress(KBREAD);
  221.          /* check the serial port */
  222.         if (async_rxcnt(port))
  223.             proc_rxch(async_rx(port));
  224.  
  225.     }
  226. }
  227.  
  228. int proc_rxch(int ch)
  229. {
  230.     REG int ch2;
  231.  
  232.     ch2 = ch & 0xff;
  233.  
  234.     if (ch2 == '\r' && lfs)
  235.         ch2 = '\n';              /* translate to nl if supplying lin feeds */
  236.     if (ch2 != '~')
  237.         hostcnt = 0;
  238.     else
  239.     {
  240.         if (++hostcnt >= 10)               /* ten ~'s puts it in host mode */
  241.         {
  242.             host_mode();
  243.             hostcnt = 0;
  244.             return (ch);
  245.         }
  246.     }
  247.     d_ch((char)ch2);     /* dsply if got one -- 'd_ch' supports ANSI codes */
  248.     if (logfil && !v_ansiseq)
  249.         fputc(ch2, logfil);               /* write char to logfile if open */
  250.     return (ch);
  251. }
  252.  
  253. /*
  254.         p r o c e s s   k e y p r e s s
  255. */
  256. int proc_keypress(REG int ch)
  257. {
  258.     REG int ch2;
  259.  
  260.     if ((ch2 = ch & 0xff) == 0)
  261.         proc_fkey(ch);                  /* process if extended key pressed */
  262.     else
  263.     {
  264.     async_tx(port, (char)ch2);                          /* send ch to port */
  265.         if (echo && ch != X_ESC)
  266.         {
  267.             if (ch2 == '\r' && lfs)
  268.                 ch2 = '\n';                  /* make it a nl if adding lfs */
  269.         d_ch((char)ch2);                               /* display the char */
  270.             if (logfil && !v_ansiseq)
  271.                 fputc(ch2, logfil);            /* write to logfile if open */
  272.         }
  273.     }
  274.     return (ch);
  275. }
  276.  
  277. /*
  278.         p r o c e s s   e x t e n d e d   k e y s
  279. */
  280. int     proc_fkey(REG int keycd)
  281. {
  282.     static struct
  283.     {
  284.     int jval;
  285.     int (*fun)();
  286.     } *f, funtbl[] = {
  287.         { ALT_C, rcls },            { ALT_E, toggle_echo },
  288.         { ALT_X, exit_term },       { ALT_S, shell_to_dos },
  289.         { ALT_D, dial_nbr },        { PGUP, run_batch },
  290.         { PGDN, run_batch },        { ALT_H, hang_up },
  291.         { ALT_L, toggle_lfs},       { F2, toggle_log },
  292.         { F10, host_mode },         { ALT_P, chg_parms },
  293.         { F9, watch_cd },    { 0, NULL }             };
  294.  
  295.     if (keycd == F1)
  296.         keycd = do_help();         /* do a help screen first if F1 pressed */
  297.     for (f = funtbl; f->jval != keycd && f->jval; f++)
  298.         ;                                       /* lookup function for key */
  299.     if (f->jval)
  300.         return ((f->fun)(keycd));/* execute it if found & return exit code */
  301.     else
  302.         return (0);                      /* else do nothing and return a 0 */
  303. }
  304.  
  305. /*
  306.         w a t c h   c a r r i e r  d e t e c t
  307. */
  308. int     watch_cd(void)
  309. {
  310.     return(watchdogset(1, port->ComBase));
  311. }
  312.  
  313. /*
  314.         r e s e t   c o l o r,   c l e a r   s c r e e n
  315. */
  316. int     rcls(void)
  317. {
  318.     v_color = cyn;
  319.     cls();
  320.     return 0;
  321. }
  322.  
  323. /*
  324.         t o g g l e   l o g   f i l e
  325. */
  326. int     toggle_log(void)
  327. {
  328.     if (logfil == NULL)
  329.     {
  330.         if (NULL != (logfil = fopen("smalterm.log", "ab")))
  331.             d_msgat(24, 25, hgrn, "LOG");              /* LOG file is open */
  332.     }
  333.     else
  334.     {
  335.         fclose(logfil);
  336.         logfil = NULL;
  337.         d_msgat(24, 25, cyn, "═══");                   /* LOG file is open */
  338.     }
  339.     return 0;
  340. }
  341.  
  342. /*
  343.         t o g g l e   e c h o    f u n c t i o n
  344. */
  345. int     toggle_echo(void)
  346. {
  347.     if (echo ^= 1)                                          /* toggle flag */
  348.         d_msgat(24, 15, hgrn, "ECHO");                       /* ECHO is on */
  349.     else
  350.         d_msgat(24, 15, cyn, "════");                       /* ECHO is off */
  351.     return 0;
  352. }
  353.  
  354. /*
  355.         t o g g l e   l f ' s    f u n c t i o n
  356. */
  357. int     toggle_lfs(void)
  358. {
  359.     if (lfs ^= 1)                                           /* toggle flag */
  360.         d_msgat(24, 21, hgrn , "LF");                       /* LF's are on */
  361.     else
  362.         d_msgat(24, 21, cyn, "══");                        /* LF's are off */
  363.     return 0;
  364. }
  365.  
  366. /*
  367.         t o g g l e   d t r    f u n c t i o n
  368. */
  369. int     toggle_dtr(void)
  370. {
  371.     async_dtr(port, (dtr ^= 1));                             /* toggle DTR */
  372.     if (dtr)
  373.         d_msgat(24, 10, hgrn, "DTR");                       /* DTR is high */
  374.     else
  375.         d_msgat(24, 10, (hred | BLNK), "DTR");               /* DTR is low */
  376.     return 0;
  377. }
  378.  
  379. /*
  380.         d i a l   a   n u m b e r
  381. */
  382. int     dial_nbr(void)
  383. {
  384.     char    lbuf[25];
  385.     static char dmsg[] = "Enter number (proceed with P if pulse dial) ->";
  386.  
  387.     /* input a phone number */
  388.     if (prompt(lbuf, dmsg, 24))                        /* input the number */
  389.         return 0;
  390.     if (*lbuf == 'p' || *lbuf == 'P')
  391.         strsum(dialstr, "ATDP", &lbuf[1], "\r", NULL);
  392.     else                                          /* build the dial string */
  393.         strsum(dialstr, "ATDT", lbuf, "\r", NULL);
  394.     async_tx_str(dialstr);                              /* dial the number */
  395.     return 0;
  396. }
  397.  
  398. /*
  399.         s h e l l   t o   D O S   f u n c t i o n
  400. */
  401. int     shell_to_dos(void)
  402. {
  403.     char    savdcolr, lbuf[2];
  404.     char    cmdcom[60];
  405.  
  406.     if (screen_pushpop(PUSH))                       /* save current screen */
  407.     {
  408.         cls();
  409.         savdcolr = v_color, v_color = hred;
  410.         *cmdcom = '\0';
  411.         strcpy(cmdcom, getenv("COMSPEC"));
  412.         if (!*cmdcom)
  413.             strcpy(cmdcom, "COMMAND.COM");
  414.         d_str("Type EXIT to return to SMALTERM."); /* tell how to get back */
  415.         v_color = savdcolr;
  416.         spawnlp(P_WAIT, cmdcom, cmdcom, NULL);        /* spawn COMMAND.COM */
  417.         screen_pushpop(POP);     /* fix up screen & ANSI sequence variable */
  418.     }
  419.     else
  420.         prompt(lbuf, "Not enough memory, Press ENTER to continue\a", 0);
  421.     screen_pushpop(POP);         /* fix up screen & ANSI sequence variable */
  422.     return 0;
  423. }
  424.  
  425. /*
  426.         h o s t   m o d e
  427. */
  428. int     host_mode(void)
  429. {
  430.     long    rto;
  431.     char    i, lbuf[62], ch = '\0';
  432.     int     savdcolr;
  433.  
  434.     static char menu[] =
  435. "\r\n\r\nU)pload    D)ownload    S)hell to DOS    P)age operator    H)ang up\
  436. \r\n      Enter selection ---> ";
  437.  
  438.     static char zmrcvmsg[] =
  439. "u\r\n\r\nReady to receive files using Zmodem, start your upload\r\n";
  440.  
  441.     static char zmsndmsg1[] =
  442. "d\r\n\r\nEnter the filename(s) you wish to download at the prompt, one file\r\n\
  443. per prompt.  Wild cards are accepted.  Press ENTER when all files have\r\n\
  444. been entered or press ESC to abort the transfer.\r\n";
  445.  
  446.     static char zmsndmsg2[] =
  447. "\r\nReady to transmit files using Zmodem, start your download\r\n";
  448.  
  449.     static char pagemsg[] =
  450. "p\r\n\r\nPaging remote, press ESC if no answer\r\n";
  451.     
  452.     d_str("\nHost mode activated, Press ESC to exit Host,\n");
  453.     d_str("Press the space bar to chat\n");
  454.     async_txflush(port);
  455.     async_rxflush(port);                             /* clean out the port */
  456.     if (lfs)
  457.         toggle_lfs();
  458.     if (echo)
  459.         toggle_echo();
  460.     while (ch != ESC && ch != ' ')
  461.     {
  462.         if (!async_carrier(port))
  463.         {
  464.             DELAY_TENTHS(2);
  465.             async_tx_str("ATS0=1\r");         /* set modem for auto answer */
  466.             waitforOK(9);                             /* throw away the OK */
  467.             autoans = 1;       /* set flag showing AA enabled by Host mode */
  468.             d_str("\r\nAwaiting caller\r\n");
  469.             while (1)         /* loop till carrier detected or ESC pressed */
  470.             {
  471.                 if (KBHIT && ((ch = KBREAD) == ESC))
  472.                     break;    
  473.                 if (async_carrier(port))
  474.                 {
  475.                     DELAY_TENTHS(5);/* half sec delay to let things settle */
  476.                     async_rxflush(port);             /* clean out the port */
  477.                     async_tx_echo("Welcome to Smalterm Host\r\n");
  478.                     break;
  479.                 }
  480.             }
  481.         }
  482.         if (async_carrier(port))
  483.             async_tx_echo(menu);
  484.         while (async_carrier(port) && ch != ESC && ch != ' ')
  485.         {
  486.             if (KBHIT)
  487.             {
  488.                 switch (ch = KBREAD)
  489.                 {
  490.                   case ESC:
  491.                     hang_up();                        /* hang up on caller */
  492.                     d_str("\r\nCaller aborted");
  493.                     continue;                         /* break out of loop */
  494.                   case ' ':
  495.                     async_tx_echo("\r\nEntering chat mode\r\nHello\r\n");
  496.                     toggle_lfs();
  497.                     toggle_echo();
  498.                     continue;
  499.                 }
  500.             }
  501.             switch (async_rx(port) & 0xff)
  502.             {
  503.               case 'u':
  504.               case 'U':
  505.                 async_tx_echo(zmrcvmsg);
  506.                 while (!async_stat(port, B_TXEMPTY | B_CD))
  507.                     ;
  508.                 DELAY_TENTHS(2);
  509.                 if (!async_carrier(port))
  510.                     break;
  511.                 if (screen_pushpop(PUSH))           /* save current screen */
  512.                 {
  513.                     cls();
  514.                     savdcolr = v_color, v_color = hred;
  515.                     d_str("Remote is uploading ...");
  516.                     v_color = savdcolr;
  517.                     system("RCV.BAT");                /* receive the files */
  518.                 }
  519.                 screen_pushpop(POP);                 /* restore the screen */
  520.                 DELAY_TENTHS(2);
  521.                 break;
  522.               case 'd':
  523.               case 'D':
  524.                 async_tx_echo(zmsndmsg1);
  525.                 while (!async_stat(port, B_TXEMPTY | B_CD))
  526.                     ;
  527.                 strcpy(buf, "SND.BAT");
  528.                 i = '0';
  529.                 while(++i < '9' && async_carrier(port))
  530.                 {
  531.                     strcpy(lbuf, "\r\nEnter filename #  : ");
  532.                     lbuf[18] = i;
  533.                     comprompt(lbuf, lbuf, 60);
  534.                     if (!*lbuf || *lbuf == ESC)
  535.                         break;
  536.                     if (NO_FILES(lbuf))
  537.                     {
  538.                         async_tx_echo("\r\nFile not found");
  539.                         --i;
  540.                         continue;
  541.                     }
  542.                     if (strlen(buf) + strlen(lbuf) > 125)
  543.                     {
  544.                         async_tx_echo("\r\nFile buffer full");
  545.                         continue;
  546.                     }
  547.                     strcat(buf, " ");
  548.                     strcat(buf, lbuf);
  549.                 }
  550.                 if (*lbuf == ESC || !async_carrier(port))
  551.                     break;
  552.                 async_tx_echo(zmsndmsg2);
  553.                 while (!async_stat(port, B_TXEMPTY | B_CD))
  554.                     ;
  555.                 DELAY_TENTHS(2);
  556.                 if (screen_pushpop(PUSH))           /* save current screen */
  557.                 {
  558.                     cls();
  559.                     savdcolr = v_color, v_color = hred;
  560.                     d_str("Remote is downloading ...");
  561.                     v_color = savdcolr;
  562.                     system(buf);                         /* send the files */
  563.                 }
  564.                 screen_pushpop(POP);                 /* restore the screen */
  565.                 break;
  566.               case 's':
  567.               case 'S':
  568.                 async_tx_echo("s\r\n");
  569.                 watchdogset(1, port->ComBase);          /* enable watchdog */
  570.                 shell_remote();                         /* do remote shell */
  571.                 watchdogset(0, 0);                     /* disable watchdog */
  572.                 break;
  573.               case 'p':
  574.               case 'P':
  575.                 ch = '\0';
  576.                 async_tx_echo(pagemsg);
  577.                 d_str("\a\a\a");
  578.                 SET_TO_SECS(rto, 15);
  579.                 while (async_carrier(port) && async_rx(port) != ESC
  580.                   && (!KBHIT || (ch = KBREAD) != ' '))
  581.                 {
  582.                     if (timed_out(&rto))
  583.                     {
  584.                         d_str("\a\a\a");
  585.                         SET_TO_SECS(rto, 15);
  586.                     }
  587.                 }
  588.                 if (ch == ' ')
  589.                 {
  590.                     async_tx_echo("\r\nEntering chat mode\r\nHello\r\n");
  591.                     toggle_lfs();
  592.                     toggle_echo();
  593.                     continue;
  594.                 }
  595.                 break;
  596.               case 'h':
  597.               case 'H':
  598.                 async_tx_echo(
  599.                   "h\r\nSmalterm Host going offline ...\r\n");
  600.                 while (!async_stat(port, B_TXEMPTY))
  601.                     ;
  602.                 hang_up();
  603.                 d_str("\r\nCaller offline");
  604.                 continue;                             /* break out of loop */
  605.               default:
  606.                 continue;                                /* skips the menu */
  607.             }
  608.             async_tx_echo(menu);
  609.         }
  610.     }
  611.     return 0;
  612. }
  613.  
  614.  
  615. /*
  616.         r e m o t e   s h e l l   t o   D O S   f u n c t i o n
  617. */
  618. int     shell_remote(void)
  619. {
  620.     char    savdcolr, lbuf[2];
  621.     char    cmdcom[60];
  622.     int      x, inhdl, outhdl, errhdl;
  623.  
  624.     if (screen_pushpop(PUSH))                       /* save current screen */
  625.     {
  626.         cls();
  627.         savdcolr = v_color, v_color = hred;
  628.         *cmdcom = '\0';
  629.         strcpy(cmdcom, getenv("COMSPEC"));
  630.         if (!*cmdcom)
  631.             strcpy(cmdcom, "COMMAND.COM");
  632.         d_str("Executing remote shell to DOS ...");
  633.         v_color = savdcolr;
  634.         async_txflush(port);
  635.         async_tx_str("\r\nShelling to DOS, Type EXIT when finished.\r\n");
  636.         while (!async_stat(port, B_TXEMPTY))
  637.             ;                             /* wait for message to get there */
  638.         DELAY_TENTHS(1);                         /* wait a little bit more */
  639.         async_stop(port);                       /* let go of the comm port */
  640.  
  641.         /* make stdin, stdout, & stderr refer to com port */
  642.         x = open(com_str, O_RDWR | O_BINARY);
  643.         inhdl = dup(0);
  644.         outhdl = dup(1);
  645.         errhdl = dup(2);
  646.         dup2(x, 0);
  647.         dup2(x, 1);
  648.         dup2(x, 2);
  649.  
  650.         spawnlp(P_WAIT, cmdcom, cmdcom, NULL);        /* spawn COMMAND.COM */
  651.  
  652.         /* restore stdin, stdout, & stderr */
  653.         close(x);
  654.         dup2(inhdl, 0);
  655.         close(inhdl);
  656.         dup2(outhdl, 1);
  657.         close(outhdl);
  658.         dup2(errhdl, 2);
  659.         close(errhdl);
  660.  
  661.         async_restart(port);                      /* re-init the comm port */
  662.     }
  663.     else
  664.         prompt(lbuf, "Not enough memory, Press ENTER to continue\a", 0);
  665.     screen_pushpop(POP);         /* fix up screen & ANSI sequence variable */
  666.     return 0;
  667. }
  668.  
  669. /*
  670.         r u n   b a t c h   f i l e
  671. */
  672. int     run_batch(int keycd)
  673. {
  674.     REG     char *p1;
  675.     char    savdcolr;
  676.     char    b_buf[60];
  677.  
  678.     /* get batch name and parameters */
  679.     p1 = b_buf;
  680.     strcpy (p1, (keycd == PGUP) ? "SND.BAT " : "RCV.BAT ");
  681.     p1 += strlen(p1);
  682.     if (prompt(p1, "Enter batch parameters ->", 50) == ESC_PRESSED)
  683.         return 0;
  684.     if (screen_pushpop(PUSH))                       /* save current screen */
  685.     {
  686.         cls();
  687.         savdcolr = v_color, v_color = hred;
  688.         d_str(strsum(buf, "Executing: ", b_buf, "\n\n", NULL));
  689.         v_color = savdcolr;
  690.         system(b_buf);                               /* run the batch file */
  691.     }
  692.     else
  693.         prompt(b_buf, "Not enough memory, Press ENTER to continue\a", 0);
  694.     screen_pushpop(POP);         /* fix up screen & ANSI sequence variable */
  695.     d_str("\a\a\a\a");                                  /* signal finished */
  696.     return 0;
  697. }
  698.  
  699. /*
  700.         e x i t   f o r   g o o d   f u n c t i o n
  701. */
  702. int     exit_term(void)
  703. {
  704.     char    lbuf[2];
  705.  
  706.     switch (prompt(lbuf, "Exit SmalTerm (Y, n)?", 1))
  707.     {
  708.       case ESC_PRESSED:
  709.         return 0;
  710.       case NO_INPUT:
  711.         break;
  712.       default:
  713.         if (*lbuf != 'Y' && *lbuf != 'y')
  714.             return 0;
  715.     }
  716.     tickhookset(0);                    /* disable the TIMER interrupt hook */
  717.     async_close(port);                                   /* close the port */
  718.     SETWND(0, 0, 24, 79);
  719.     cls();                                             /* clear the screen */
  720.     exit (0);                                               /* back to DOS */
  721. }
  722.  
  723.  
  724. /*
  725.         h e l p    f u n c t i o n
  726. */
  727. int     do_help()
  728. {
  729.     /* not the best way to do video but shows ANSI  */
  730.     /*  capabilities of ANSI8MSC display functions  */
  731.     static char *help_scrn[] =
  732.     {
  733. "\33[1;1H\33[0;1;37;40m┌──   \33[31mSmalTerm HELP  [F1]   \33[37m─────────────────────────────────┐\n",
  734. "│\33[60C│\n",
  735. "│  \33[0;32mALT-C:  \33[36mClear the screen\33[8C\33[32mPGUP :  \33[36mExecute SND.BAT   \33[1;37m│\n",
  736. "│  \33[0;32mALT-D:  \33[36mDial a number\33[11C\33[32mPGDN :  \33[36mExecute RCV.BAT   \33[1;37m│\n",
  737. "│  \33[0;32mALT-E:  \33[36mToggle echo\33[15C\33[32mF2 :  \33[36mToggle log file   \33[1;37m│\n",
  738. "│  \33[0;32mALT-H:  \33[36mHang Up\33[19C\33[32mF9 :  \33[36mEnable watchdog   \33[1;37m│\n",
  739. "│  \33[0;32mALT-L:  \33[36mToggle line feeds\33[8C\33[32mF10 :  \33[36mEnable host mode  \33[1;37m│\n",
  740. "│  \33[0;32mALT-P:  \33[36mChange parameters\33[33C\33[1;37m│\n",
  741. "│  \33[0;32mALT-S:  \33[36mShell to DOS\33[12C\33[32mALT-X:  \33[36mExit to DOS\33[7C\33[1;37m│\n",
  742. "├────────────────────────────────────────────────────────────┤\n",
  743. "│  \33[0;37mDemo comm program written using MCOMM5 async routines,    \33[1;37m│\n",
  744. "│  \33[0;37mANSI_xxC video routines, and EXTRA functions.\33[13C\33[1;37m│\n",
  745. "│   \33[0;37mMike Dumdei, 6 Holly Lane, Texarkana TX 75503\33[12C\33[1;37m│\n",
  746. "│   \33[0;37mSplit Up the Middle BBS  ----  (903) 838-6713\33[12C\33[1;37m│\n",
  747. "└────────────────────────────────────────────────────────────┘\33[0;36m",
  748. NULL
  749.     };
  750.     register char **p1;
  751.     char    *lbuf = 0;
  752.     int     rval = 0, x;
  753.  
  754.     x = v_ansiseq, v_ansiseq = 0;    /* in case an ANSI seq is in progress */
  755.     if ((lbuf = malloc(SCRBUF(15, 62))) != NULL)/* malloc buf to save scrn */
  756.     {
  757.         pu_scrnd(3, 9, 15, 62, lbuf);            /* push area used by HELP */
  758.         SETWND(3, 9, 17, 70);
  759.         cls();
  760.         v_scrlm = 0;   /* don't want to scroll when at the btm of the wind */
  761.     }
  762.     for (p1 = help_scrn; *p1; p1++)  /* display the ANSI style help screen */
  763.         d_str(*p1);
  764.     rval = KBREAD;                                   /* return key pressed */
  765.     if (lbuf)
  766.     {
  767.         SETWND(0, 0, 23, 79);                     /* reset the window size */
  768.         v_scrlm = 1;                              /* reset the scroll mode */
  769.         po_scrnd(lbuf);                                  /* restore screen */
  770.         free(lbuf);                                      /* release memory */
  771.     }
  772.     v_ansiseq = x;                                  /* restore ANSI status */
  773.     return (rval);               /* return extended key if pressed, else 0 */
  774. }
  775.  
  776. /*
  777.         a s y n c _ t x _ s t r   f u n c t i o n
  778. */
  779. int     async_tx_str(char *str)
  780. {
  781.     return(async_txblk(port, str, strlen(str)));
  782. }
  783.  
  784. /*
  785.         a s y n c _ t x _ e c h o   f u n c t i o n
  786. */
  787. int     async_tx_echo(register char *str)
  788. {
  789.  
  790.     while (*str && async_carrier(port))
  791.     {
  792.         d_ch(*str);
  793.         async_tx(port, *str++);
  794.         while (!async_stat(port, B_TXEMPTY | B_CD))
  795.             ;
  796.     }
  797.     return 0;
  798. }
  799.  
  800.  
  801. /*
  802.         s c r e e n   s a v e / r e s t o r e   f u n c t i o n
  803. */
  804. int     screen_pushpop(int flag)
  805. {
  806.     static char *savscrn = NULL;
  807.     static ulong   savdwndsz;
  808.     static int     x;
  809.  
  810.     if (flag == PUSH)
  811.     {
  812.         x = v_ansiseq, v_ansiseq = 0;/* in case an ANSI seq is in progress */
  813.     if ((savscrn = malloc(SCRBUF(25, 80))) != NULL)
  814.         {
  815.             savdwndsz = v_wndsz;
  816.             SETWND(0, 0, 24, 79);         /* reset window to entire screen */
  817.             pu_scrnd(0, 0, 25, 80, savscrn);/* save current screen in bufr */
  818.             return (1);                                  /* return success */
  819.         }
  820.         else
  821.             return (0);                                   /* return failed */
  822.     }
  823.     else
  824.     {
  825.         v_ansiseq = x;                              /* restore ANSI status */
  826.         if (savscrn != NULL)
  827.         {
  828.             po_scrnd(savscrn);                /* restore the pushed screen */
  829.             free(savscrn);                 /* release screen buffer memory */
  830.             savscrn = NULL;
  831.             v_wndsz = savdwndsz;                  /* reset the screen size */
  832.             return (1);                                  /* return success */
  833.         }
  834.         else
  835.             return (0);                 /* return failed if nothing pushed */
  836.     }
  837. }
  838.  
  839. /*
  840.         c h a n g e   p a r a m e t e r s
  841. */
  842. int     chg_parms(void)
  843. {
  844.     char    lbuf[12];
  845.  
  846.     /* get new parmameters */
  847.     if (prompt(lbuf, "Enter parameters (Ex: 1200N81) ->", 10))
  848.         return 0;
  849.     if (async_setbpds(port, lbuf) == 0)               /* change parameters */
  850.     {
  851.         d_nchat(24, 65, '═', cyn, 10, HORZ);
  852.         d_msgat(24, 65, hgrn, strupr(lbuf));             /* display params */
  853.     }
  854.     else
  855.         prompt(lbuf, "Invalid parameters, Press ENTER to continue\a", 0);
  856.     return 0;
  857. }
  858.  
  859. /*
  860.         r e c e i v e   w i t h   t i m e o u t
  861.             Gets a char from the async port 'port'.  Times out after so many
  862.             tenths of a second.
  863. */
  864. int     rx_timeout(int Tenths)
  865. {
  866.     uint StatChar;
  867.     long rto;
  868.  
  869.     /* if char is in buffer return it with no kbd or timeout chks */
  870.     if (!(B_RXEMPTY & (StatChar = async_rx(port))))
  871.         return (StatChar & 0xff);
  872.  
  873.     /* if no char in rxbufr, set up timeout val & wait for char or timeout */
  874.     SET_TO_TENTHS(rto, Tenths);
  875.     while (1)
  876.     {
  877.         if (!(B_RXEMPTY & (StatChar = async_rx(port))))
  878.             return (StatChar & 0xff);     /* return with char if one ready */
  879.         if (ChkgCarrier && (B_CD & StatChar))
  880.             return (LOST_CARRIER);               /* ret if carrier dropped */
  881.         if (ChkgKbd && KBHIT && (char)KBREAD == ESC)
  882.             return (ESC_PRESSED);     /* ret if watching Kbd & ESC pressed */
  883.         if (timed_out(&rto))
  884.             return (TIMED_OUT);                  /* ret if ran out of time */
  885.     }
  886. }
  887.  
  888. /*
  889.         w a i t   f o r   m o d e m   t o   s e n d   O K
  890. */
  891. int     waitforOK(int ticks)
  892. {
  893.     char lbuf[2];
  894.  
  895.     if (waitfor("OK", ticks))
  896.         prompt(lbuf, "Modem does not respond,  Press ENTER to continue\a", 0);
  897.     return 0;
  898. }
  899.  
  900. /*
  901.         w a i t f o r   f u n c t i o n
  902. */
  903. int     waitfor(char *str, int ticks)
  904. {
  905.     REG char *p1, *lbuf;
  906.     long    to;
  907.     char    ch, *end;
  908.     int     matchlen;
  909.  
  910.     if ((matchlen = strlen(str)) == 0)
  911.         return (0);
  912.     set_timeout(&to, ticks);
  913.     lbuf = calloc(matchlen + 1, 1);
  914.     p1 = lbuf - 1;
  915.     end = p1 + matchlen;
  916.     while (1)
  917.     {
  918.         if (timed_out(&to))
  919.         {
  920.             free(lbuf);
  921.             return (TIMED_OUT);
  922.         }
  923.         if (KBHIT && proc_keypress(KBREAD) == X_ESC)
  924.         {
  925.             free(lbuf);
  926.             return (ESC_PRESSED);
  927.         }
  928.         if (!async_rxcnt(port))
  929.             continue;
  930.         ch = (char)proc_rxch(async_rx(port));
  931.         if (p1 != end)
  932.         {
  933.             *++p1 = ch;
  934.             if (p1 != end)
  935.                 continue;
  936.         }
  937.         else
  938.         {
  939.             memmove(lbuf, &lbuf[1], matchlen);
  940.             *p1 = ch;
  941.         }
  942.         if (*lbuf == *str && !memicmp(lbuf, str, matchlen))
  943.         {
  944.             free(lbuf);
  945.             return (0);
  946.         }
  947.     }
  948. }
  949.  
  950. /*
  951.         p r o m p t   f o r   k e y b o a r d   i n p u t
  952. */
  953. int     prompt(char *kbuf, char *promptmsg, int maxchars)
  954. {
  955.     REG     char *p1;
  956.     char    ch = 0, *scrnbuf, *endkbuf;
  957.     int     i, x, y, boxtop, boxlft, boxlen;
  958.  
  959.     x = v_ansiseq, v_ansiseq = 0;                /* save ANSI seq variable */
  960.     y = v_color, v_color = hblu;                   /* set the color to use */
  961.     boxlen = strlen(promptmsg) + maxchars + 6;
  962.     boxlft = (80 - boxlen) / 2;
  963.     boxtop = (v_btm - 5) / 2;                  /* calculate box dimensions */
  964.     scrnbuf = malloc(SCRBUF(5, boxlen));
  965.     pu_scrnd(boxtop, boxlft, 5, boxlen, scrnbuf);  /* save the screen area */
  966.     for (i = 1; i < 4; i++)
  967.         d_nchat(boxtop + i, boxlft + 1, ' ', wht, boxlen - 2, HORZ);
  968.     d_chat(boxtop, boxlft, '╔');
  969.     d_nchat(boxtop, boxlft + 1, '═', hblu, boxlen - 2, HORZ);
  970.     d_chat(boxtop, boxlft + boxlen - 1, '╗');
  971.     d_nchat(boxtop + 1, boxlft, '║', hblu, 3, VERT);
  972.     d_chat(boxtop + 4, boxlft, '╚');
  973.     d_nchat(boxtop + 4, boxlft + 1, '═', hblu, boxlen - 2, HORZ);
  974.     d_chat(boxtop + 4, boxlft + boxlen - 1, '╝');            /* draw a box */
  975.     d_nchat(boxtop + 1, boxlft + boxlen - 1, '║', hblu, 3, VERT);
  976.     d_msgat(boxtop + 2, boxlft + 3, hred, promptmsg);
  977.     loc(boxtop + 2, boxlft + strlen(promptmsg) + 4); /* display the prompt */
  978.     v_color = wht;
  979.     for (p1 = kbuf, endkbuf = p1 + maxchars; ch != '\r' && ch != ESC;)
  980.     {
  981.         ch = KBREAD & 0xff;                                  /* get a char */
  982.         if (ch != '\r' && ch != ESC)
  983.         {
  984.             if (ch == '\b')
  985.             {
  986.                 if (p1 > kbuf)                 /* backspace key processing */
  987.                     --p1, d_ch(ch);
  988.                 continue;
  989.             }
  990.             else if (p1 != endkbuf && isprint(ch))
  991.             {
  992.                 d_ch(ch), *p1++ = ch;                /* put char in buffer */
  993.                 continue;
  994.             }
  995.             d_ch('\a');               /* beep if max chars already entered */
  996.         }
  997.         *p1 = '\0';                                /* terminate the buffer */
  998.     }
  999.     po_scrnd(scrnbuf);
  1000.     free(scrnbuf);
  1001.     v_ansiseq = x, v_color = y;              /* restore screen & variables */
  1002.     if (ch == ESC)
  1003.         return (ESC_PRESSED);                /* return this if ESCaped out */
  1004.     if (p1 == kbuf)
  1005.         return (NO_INPUT);                     /* return val if ENTER only */
  1006.     return (0);                            /* return val if got some input */
  1007. }
  1008.  
  1009. /*
  1010.         r e m o t e   p r o m p t   f u n c t i o n
  1011. */
  1012. int     comprompt(char *kbuf, char *promptmsg, int maxchars)
  1013. {
  1014.     REG     char *p1;
  1015.     char    ch = 0, *endkbuf;
  1016.  
  1017.     async_tx_echo(promptmsg);
  1018.     for (p1 = kbuf, endkbuf = p1 + maxchars; ch != '\r' && ch != ESC;)
  1019.     {
  1020.         if (KBHIT && (KBREAD == X_ESC) || !async_carrier(port))
  1021.             ch = ESC;                       /* ck for local operator abort */
  1022.         else
  1023.             ch = async_rx(port);
  1024.         if (!ch)                             /* get a char from the remote */
  1025.             continue;
  1026.         if (ch != '\r' && ch != ESC)
  1027.         {
  1028.             if (ch == '\b')
  1029.             {
  1030.                 if (p1 > kbuf)                 /* backspace key processing */
  1031.                     --p1, d_ch(ch), async_tx(port, ch);
  1032.                 continue;
  1033.             }
  1034.             else if (p1 != endkbuf && isprint(ch))
  1035.             {
  1036.                 d_ch(ch), async_tx(port, ch), *p1++ = ch; /* put ch in bfr */
  1037.                 continue;
  1038.             }
  1039.             async_tx(port, '\a');     /* beep if max chars already entered */
  1040.         }
  1041.         *p1 = '\0';                                /* terminate the buffer */
  1042.     }
  1043.     if (ch == ESC)
  1044.         return (*kbuf = ESC);
  1045.     if (p1 == kbuf)
  1046.         return (*kbuf = '\0');                 /* return val if ENTER only */
  1047.     return (p1 - kbuf);
  1048. }
  1049.  
  1050. /*
  1051.         h a n g   u p   t h e   p h o n e
  1052. */
  1053. int     hang_up(void)
  1054. {
  1055.     long rto;
  1056.  
  1057.     if (dtr)
  1058.         toggle_dtr();
  1059.     async_txflush(port);
  1060.     async_rxflush(port);
  1061.     SET_TO_TENTHS(rto, 3);
  1062.     while (!timed_out(&rto))
  1063.     {
  1064.         if (!async_carrier(port))
  1065.         {
  1066.             toggle_dtr();
  1067.             return 0;
  1068.         }
  1069.     }
  1070.     toggle_dtr();
  1071.     DELAY_TENTHS(11);
  1072.     async_tx_str("+++");
  1073.     DELAY_TENTHS(13);
  1074.     async_tx_str("ATH0\r");
  1075.     waitforOK(24);
  1076.     return 0;
  1077. }
  1078.  
  1079.