home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / Mgr / mgrterm.zoo / mgrterm.c next >
C/C++ Source or Header  |  1991-04-04  |  19KB  |  929 lines

  1. /*
  2.  * mgrterm - a terminal emulator for MiNT/mgr
  3.  * term loop based on a very simple term emu by
  4.  *       david@doe.utoronto.ca (David Megginson)
  5.  *
  6.  *    ++jrb    bammi@cadence.com
  7.  */
  8.  
  9. /*
  10.  * Menus:
  11.  *
  12.  *    Main Menu        Baud    Dial    FlowControl
  13.  *    ---------         ----    ----    -----------
  14.  *    Suspend        19200   ph#1    None
  15.  *    Baud =>         9600    ..     Rts/Cts
  16.  *    Dial =>         2400        Xon/Xoff
  17.  *    ToggleDuplex     1200    ..    Both
  18.  *    FlowControl =>      300   ph#n
  19.  *    StuffTermcap
  20.  *    Shell
  21.  *    Status
  22.  *    =============
  23.  *    Quit
  24.  *
  25.  */
  26.  
  27. /* Whitepages
  28.  *    the whitepages file may either be specified
  29.  *     - on the command line
  30.  *     - via the WHITEPAGES environment variable
  31.  *     - otherwise the default below is used if it exists
  32.  *     - if no white pages exits, the menu entry will contain a dummy.
  33.  * The dial pull right menu is paged, 15 entries/page.
  34.  *
  35.  * The whitepages files can contain
  36.  *    - comments lines - begining with '#'
  37.  *    - blank lines
  38.  *    - entries
  39.  * a whitepages entry is for the form (max length of an entry == 132)
  40.  * name : [baud] : [dial string]
  41.  *
  42.  * the name is the key. only enough characters to make the search
  43.  * unambigious need be specified. imbedded blanks are significant.
  44.  * leading and trailing one are ignored. case is significant.
  45.  *
  46.  * if no baud is specified, then the present baud rate is not changed,
  47.  * otherwise the baud rate is set when the entry is chosen. leading and
  48.  * trailing blanks are ignored. if the baud specified is invalid, the dial
  49.  * is aborted.
  50.  *
  51.  * if a dial string is specified, it is sent to the modem with interpretation.
  52.  * leading blanks are ignored. tailing ones are significant. the dial string
  53.  * is interpreted as follows:
  54.  *   \n, \r, \\ send newline, carriage return and backslash respectively.
  55.  *   \nnn    send octal char nnn
  56.  *   \s<number> sleep for <number> seconds
  57.  *   \t<number> set char wait timeout to <number> seconds (default 10 seconds)
  58.  *   \w<char>   wait until char, all chars occuring in the mean while
  59.  *        are skipped. Abort dial on timeout. the char maybe
  60.  *        specified in its octal form \nnn  (\r etc not recognized).
  61.  *
  62.  * examples:
  63.  *  unix direct login : 19200 : \w:bammi\r\w:mypasswd\r
  64.  *  # switch to 19200 baud, wait for ':' send string "bammi\r" wait for ':'
  65.  *  # send string "mypasswd\r". use default char wait timeout period.
  66.  *  unix dialup : 2400 : atdt5551212\w:bammi\r\w:mypasswd\r
  67.  *  compuserve : 2400 : atdt5551515\w2\w4\w0\w0\r\w:CIS\r\w:71515,111\r\w:xxx\r
  68.  *  timbaktu :: atdt1timbaktu\r
  69.  *  # use current baud rate
  70.  *  2400 : 2400 :
  71.  *  # just change baud rate
  72.  *
  73.  */
  74. #include <stddef.h>
  75. #include <stdlib.h>
  76. #include <osbind.h>
  77. #include <mintbind.h>
  78. #include <string.h>
  79. #include <setjmp.h>
  80. #include <signal.h>
  81. #include <unistd.h>
  82. #include <fcntl.h>
  83. #include <term.h>
  84. #include "proto.h"
  85.  
  86. #ifndef Bconmap
  87. #define Bconmap(dev) (short)trap_14_ww((short)(0x2c), (short)(dev))
  88. #endif
  89.  
  90. #define Bconws(s) Boutput(2, (s))
  91. #define CTRL(x) ((x) & 0x1f)
  92. #define    ESCAPE  0x001D        /* CTRL-]                */
  93. #define QUIT    0x0080        /* <UNDO>                    */
  94. #define    MAXWAIT    20000L        /* Maximum number of failed attempts    */
  95.                 /* to read a character before we    */
  96.                 /* start snoozing            */
  97. #define MIDIDEV    3        /* bios midi dev id            */
  98.  
  99. int mgr = 1;                /* mgr not pure MiNT            */
  100. int half = 0;            /* doing half duplex            */
  101. int rsdev = 1;            /* serial line                */
  102. char *phones = NULL;        /* whitepages file            */
  103. char *default_phones = "d:/etc/white";
  104. int baud;            /* current baud rate            */
  105. int flow = 0;            /* current flow                */
  106. int olddev = 0x2c;
  107.  
  108. typedef struct {
  109.     char *name;
  110.     char *baud;
  111.     char *number;
  112. } WHITEPAGE;
  113.  
  114. WHITEPAGE *whitepages = 0;    /* white pages entries            */
  115.  
  116. int main(int argc, const char **argv)
  117. {
  118.     unsigned long counter = 0;
  119.     unsigned short c;
  120.     extern char *optarg;
  121.         extern int optind, opterr;
  122.  
  123.     while((c = getopt(argc, argv, "P:")) != -1)
  124.     {
  125.         switch(c)
  126.         {
  127.           case 'P':
  128.         rsdev = atoi(optarg);
  129.         if(rsdev != MIDIDEV)
  130.             olddev = Bconmap(rsdev);
  131.         break;
  132.           case '?':
  133.         Bconws((char *)(argv[0])); Bconws(" [-P serial device] [whitepages file]\r\n");
  134.         exit(1);
  135.         }
  136.     }
  137.     if(optind < argc)
  138.        phones = (char *)(argv[optind]);
  139.  
  140.     init();
  141.     do{
  142.         /* We haven't found any activity yet    */
  143.         counter++;
  144.  
  145.         /* Check for a character from the modem    */
  146.         if( Bconstat(rsdev) ) {
  147.             counter = 0;
  148.             c = ((int)Bconin(rsdev)) & 0x7f;
  149.             Bconout(2,c);
  150.         }
  151.  
  152.         /* Check for a character from the cons    */
  153.         if( Bconstat(2) ) {
  154.             counter = 0;
  155.             c = ((int)Bconin(2)) & 0x00FF;
  156.             if( c == QUIT )
  157.                 do_quit();
  158.             else if( (c &= 0x7f) == ESCAPE )
  159.                 do_escape();
  160.             else
  161.             {
  162.                 Bconout(rsdev,c);
  163.                 if(half)
  164.                 Bconout(2, c);
  165.             }
  166.         }
  167.  
  168.         /* Don't soak up CPU time if there is    */
  169.         /* nothing going on!            */
  170.         if( counter >= MAXWAIT )
  171.             Syield();
  172.     } while( 1 );
  173.     return 0;
  174. }
  175.  
  176. struct {
  177.    int    id;
  178.    char *str;
  179. } men[] = {
  180.   {1, "\005\
  181.   Suspend        \005\
  182.   BaudRate    ==>\005\
  183.   DialNumber  ==>\005\
  184.   ToggleDuplex   \005\
  185.   FlowControl ==>\005\
  186.   StuffTermcap   \005\
  187.   ShellCommand   \005\
  188.   PrintStatus    \005\
  189. -----------------\005\
  190.   Quit           \005\
  191. \035z\005\
  192. \035b\005\
  193. \035d\005\
  194. \035h\005\
  195. \035f\005\
  196. \035t\005\
  197. \035!\005\
  198. \035s\005\
  199. \005\
  200. \035q\005" },
  201.   { 2, "\005\
  202.   19200 \005\
  203.    9600 \005\
  204.    4800 \005\
  205.    3600 \005\
  206.    2400 \005\
  207.    2000 \005\
  208.    1800 \005\
  209.    1200 \005\
  210.     600 \005\
  211.     300 \005\
  212.     200 \005\
  213.     150 \005\
  214.     134 \005\
  215.     110 \005\
  216.      75 \005\
  217.      50 \005\
  218. 19200\r\005\
  219. 9600\r\005\
  220. 4800\r\005\
  221. 3600\r\005\
  222. 2400\r\005\
  223. 2000\r\005\
  224. 1800\r\005\
  225. 1200\r\005\
  226. 600\r\005\
  227. 300\r\005\
  228. 200\r\005\
  229. 150\r\005\
  230. 134\r\005\
  231. 110\r\005\
  232. 75\r\005\
  233. 50\r\005" },
  234.   {3, "\005\
  235.   None     \005\
  236.   Rts/Cts  \005\
  237.   Xon/Xoff \005\
  238.   Both     \005\
  239. n\r\005\
  240. r\r\005\
  241. x\r\005\
  242. b\r\005" },
  243.   {0, (char *)0 }}, default_dial =
  244.   { 4, "\005\
  245.   none \005\
  246. ATH\r\005" };
  247.  
  248. int ndialmenus; /* number of dial sub menus menus */
  249. int ndial;    /* number of whitepages entries   */
  250. int lastm;    /* last menu before dial menus(or first dial menu)  */
  251.  
  252. _IOREC *iorec_p, save_iorec;
  253. char   myrsbuf[16384];
  254. char linebuf[132];
  255.  
  256. void init(void)
  257. {
  258.     char *getenv(const char *);
  259.     char *s = getenv("TERM");
  260.  
  261.     if(s)
  262.     mgr = !strcmp(s, "mgr");
  263.     else
  264.     mgr = 1;    /* no TERM -- assume mgr */
  265.  
  266.     iorec_p = (_IOREC *)Iorec((rsdev == MIDIDEV)? 2 : 0);
  267.     save_iorec = *iorec_p;
  268.     iorec_p->ibuf = myrsbuf;
  269.     iorec_p->ibufsiz = sizeof(myrsbuf);
  270.     iorec_p->ibuflow = sizeof(myrsbuf) >> 3;
  271.     iorec_p->ibufhi  = (sizeof(myrsbuf) >> 2) * 3;
  272.     iorec_p->ibufhd  = iorec_p->ibuftl = 0;
  273.     if(rsdev != MIDIDEV)
  274.     {
  275.         baud = Rsconf(-2, -1, -1, -1, -1, -1);
  276.         Rsconf(-1, 0, -1, -1, -1, -1);
  277.     }
  278.     else
  279.     {
  280.     baud = 16;
  281.     flow = 0;
  282.     }
  283.     if(!phones)
  284.     phones = getenv("WHITEPAGES");
  285.     if(!phones)
  286.     phones = default_phones;
  287.     if(access(phones, R_OK))
  288.     phones = NULL;
  289.     if(phones) read_whitepages(phones);
  290.  
  291.     if( mgr )
  292.     {
  293.     m_setup(M_FLUSH|M_DEBUG);
  294.     m_push(P_FLAGS|P_MENU);
  295.     m_setmode(M_BACKGROUND);
  296.     download_menus();
  297.     }
  298. }
  299.  
  300. void do_quit(void)
  301. {
  302.     int i;
  303.  
  304.     *iorec_p = save_iorec;
  305.     Bconws("\r\n");
  306.     if( mgr )
  307.     {
  308.     m_nomenu();
  309.     for(i = ndialmenus+lastm-1; i > lastm; i--)
  310.     {
  311.         m_unpagemenu(i-1);
  312.     }
  313.     m_unlinkmenu(1, 2);
  314.         m_unlinkmenu(1, 4);
  315.         m_unlinkmenu(1, 1);
  316.  
  317.     for(i = lastm; i < ndialmenus+lastm; i++)
  318.         m_clearmenu(i);
  319.     for(i = 0; men[i].id; i++)
  320.         m_clearmenu(men[i].id);
  321.     m_pop();
  322.     }
  323.     if((rsdev != MIDIDEV) && (olddev != 0x2c))
  324.     (void)Bconmap(olddev);
  325.     exit(0);
  326. }
  327.  
  328. void download_menus(void)
  329. {
  330.     int i, j, k, l, len;
  331.  
  332.     for(i = 0; men[i].id; i++)
  333.     {
  334.     m_loadmenu(men[i].id, men[i].str);
  335.     lastm = men[i].id;
  336.     }
  337.     m_linkmenu(1, 1, 2, 0);
  338.     m_linkmenu(1, 4, 3, 0);
  339.     i = ++lastm;
  340.     if(whitepages)
  341.     {
  342.     for(j = 0; (j < ndial) && (whitepages[j].name); j += 15)
  343.     {
  344. #if 0
  345.  printf("Downloading %d\n", i);
  346. #endif
  347.         fprintf(m_termout,"%c%d,", m_escchar, i);
  348.         for(len = 0, k = j; (k < (j+15)) && whitepages[k].name; k++)
  349.         len += (((int)strlen(whitepages[k].name)) + 1) * 2 + 1;
  350.         fprintf(m_termout, "%d%c", len+1, E_MENU);
  351.         strcpy(linebuf, "\005");
  352.             for(l = 0; l < 2; l++)
  353.             {
  354.           for(k = j; (k < (j+15)) && whitepages[k].name; k++)
  355.           {
  356.         strcat(linebuf, whitepages[k].name);
  357.             if(l == 0)
  358.             strcat(linebuf, "\005");
  359.         else
  360.             strcat(linebuf, "\r\005");
  361.         fprintf(m_termout, "%s", linebuf);
  362.             strcpy(linebuf, "");
  363.           }
  364.         }
  365.         fflush(m_termout);
  366. #if 0
  367.  printf("Done Downloading %d(%d)\n", i, len+1);
  368. #endif
  369.         if(i != lastm)
  370.         {
  371.         m_pagemenu(i-1, i);
  372. #if 0
  373.  printf("Page %d to %d\n", i, i-1);
  374. #endif
  375.         }
  376.         i++;
  377.         if(!(whitepages[k].name)) break;
  378.     }
  379.     ndialmenus = i - lastm;
  380.     }
  381.     else
  382.     {
  383.     m_loadmenu(lastm, default_dial.str);
  384.     ndialmenus = 1;
  385.     }
  386.     m_linkmenu(1, 2, lastm, 0);
  387.     m_selectmenu(1);
  388. #if 0
  389.  printf("%d dial menus\n", ndialmenus);
  390. #endif
  391. }
  392.    
  393. char *prompt = "\r\nenter one of z b d h f t ! s q or ? for help: ";
  394. char *help   = "\r\n\n\
  395. \tz\t\tto suspend\r\n\
  396. \tb speed\t\tto set baud rate\r\n\
  397. \td num\t\tto dial number\r\n\
  398. \th\t\tto toggle duplex\r\n\
  399. \tf nrxb\t\tto set flow control\r\n\
  400. \tt\t\tto stuff termcap\r\n\
  401. \t! cmd\t\tto execute cmd\r\n\
  402. \ts\t\tto print status\r\n\
  403. \tq\t\tto quit\r\n\
  404.    or <return> to cancel\r\n\n";
  405.  
  406. #define EECHO(c) if(!mgr) Bconout(2, (c))
  407.  
  408. void do_escape(void)
  409. {
  410.     int c, done = 0;
  411.  
  412.     while(!done)
  413.     {
  414.     if(!mgr)
  415.         Bconws(prompt);
  416.         c = Bconin(2) & 0x7f;
  417.     EECHO(c); 
  418.     done = 1;
  419.         switch(c)
  420.         {
  421.         case '?':
  422.         Bconws(help);
  423.         done = 0;
  424.         break;
  425.       case '!': 
  426.         do_shell();
  427.         break;
  428.       case 'b': case 'B':
  429.         do_baud();
  430.         break;
  431.       case 'q': case 'Q':
  432.         do_quit();
  433.         break;
  434.       case 'z': case 'Z': case '\032': /* ctl-z */
  435.         do_stop();
  436.         break;
  437.       case '\r':
  438.             Bconout(2, '\n');
  439.         break;
  440.           case '\n':
  441.         Bconout(2, '\r');
  442.         break;
  443.       case 'd': case 'D':
  444.         do_dial();
  445.         break;
  446.       case 'h': case 'H':
  447.         do_duplex();
  448.         break;
  449.       case 'f': case 'F':
  450.         do_flow();
  451.         break;
  452.       case 't': case 'T':
  453.         do_termcap();
  454.         break;
  455.       case 's': case 'S':
  456.         do_status();
  457.         break;
  458.       default:
  459.         done = 0;
  460.     }
  461.     }
  462. }
  463.  
  464.  
  465. char *getline(int echo)
  466. {
  467.     char *l = linebuf;
  468.     int c;
  469.  
  470.     while(! rindex("\n\r", (c = Bconin(2) &0x7f)) )
  471.     {
  472.     switch(c)
  473.     {
  474.       case '\b': case '\177':
  475.         if(echo) Bconws("\b \b");
  476.         break;
  477.       case CTRL('U'):
  478.         if(echo)
  479.             while(l-- != linebuf) Bconws("\b \b");
  480.         l = linebuf;
  481.         break;
  482.       default:
  483.         *l++ = c;
  484.         if(echo) Bconout(2, c);
  485.     }
  486.     }
  487.     if(echo)
  488.     Bconws("\r\n");
  489.     *l = '\0';
  490.     l = linebuf;
  491.     while((*l == ' ') || (*l == '\t')) l++;
  492.     return l;
  493. }
  494.  
  495. void do_shell(void)
  496. {
  497.     char *s;
  498.  
  499.     if(mgr)
  500.     {
  501.     m_nomenu();
  502.     Bconws("\r\ncmd: ");
  503.     }
  504.     s = getline(1);
  505.     if(!(*s))
  506.     goto ret;
  507.  
  508.     system(s);
  509.     Bconws("\r\nhit <return> to continue");
  510.     (void)getline(1);
  511. ret:
  512.     if( mgr )
  513.     {
  514.     m_selectmenu(1);
  515.     }
  516. }
  517.  
  518. struct {
  519.     char *string;
  520.     int  value;
  521. } bauds[] = {
  522.   { "19200", 0 },
  523.   { "9600",  1 },
  524.   { "4800",  2 },
  525.   { "3600",  3 },
  526.   { "2400",  4 },
  527.   { "2000",  5 },
  528.   { "1800",  6 },
  529.   { "1200",  7 },
  530.   { "600",   8 },
  531.   { "300",   9 },
  532.   { "200",  10 },
  533.   { "150",  11 },
  534.   { "134",  12 },
  535.   { "110",  13 },
  536.   { "75",   14 },
  537.   { "50",   15 },
  538.   { "MidiBaud", 16},
  539.   { (char *)0, -1}
  540. };
  541.  
  542. void do_baud(void)
  543. {
  544.     char *s;
  545.  
  546.     while(1)
  547.     {
  548.     s = getline(!mgr);
  549.     if(!(*s))
  550.         return;
  551.  
  552.     if(set_baud(s))
  553.         Bconws("Unknown baud rate, enter again or <return> to cancel: ");
  554.     else
  555.         return;
  556.     }
  557. }
  558.  
  559. int set_baud(char *s)
  560. {
  561.     int i;
  562.     for(i = 0; bauds[i].string; i++)
  563.     {
  564.         if(strcmp(s, bauds[i].string) == 0)
  565.         {
  566.         if(rsdev != MIDIDEV)
  567.         {
  568.                 Rsconf(bauds[i].value, -1, -1, -1, -1, -1);
  569.                 baud = bauds[i].value;
  570.         }
  571.             return 0;
  572.        }
  573.     }
  574.     return 1;
  575. }
  576.  
  577. #include <signal.h>
  578. void do_stop(void)
  579. {
  580.     unsigned long omask;
  581.  
  582.     if(mgr)
  583.     {
  584.     m_nomenu();
  585.     }
  586.     Bconws("\r\n");
  587.     omask = Psigsetmask(0L);
  588.     (void) Pkill(0, SIGTSTP);
  589.     (void) Psigsetmask(omask);
  590.     if( mgr )
  591.     {
  592.     m_selectmenu(1);
  593.     }
  594. }
  595.  
  596. void do_duplex(void)
  597. {
  598.     half = !half;
  599. }
  600.  
  601. struct {
  602.     char c;
  603.     char *string;
  604. } flows[] = {
  605.   { 'n', "none"     },
  606.   { 'r', "Rts/Cts"  },
  607.   { 'x', "Xon/Xoff" },
  608.   { 'b', "both"     },
  609.   { '\377', (char *)0 }
  610. };
  611.  
  612. void do_flow(void)
  613. {
  614.    int i, c;
  615.    if(!mgr)
  616.    {
  617.     Bconws("\r\nn(none) r(rts/cts) x(xon/xoff) or b(both): ");
  618.    }
  619.    while(1)
  620.    {
  621.     c = *(getline(!mgr));
  622.     if(c == '\0')
  623.         return;
  624.     for (i = 0; flows[i].c != '\377'; i++)
  625.     {
  626.         if(flows[i].c == c)
  627.             {
  628.         if(rsdev != MIDIDEV)
  629.         {
  630.                 Rsconf(-1, i, -1, -1, -1, -1);
  631.                 flow = i;
  632.         }
  633.             return;
  634.         }
  635.         }
  636.         Bconws("Unknown flow type, enter again or <return> to cancel: ");
  637.     }
  638. }
  639.  
  640. char *atermcap = "\
  641. atari|st52|Atari ST without al dl:\\\r\
  642.     :am:bl=^G:bs:cd=\\EJ:ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :co#80:\\\r\
  643.     :do=^J:eo:ho=\\EH:is=\\Eq\\EE\\Ee\\Ev:it#8:le=^H:li#25:ll=\\EY9!:\\\r\
  644.     :me=\\Eq:mr=\\Ep:nd=\\EC:rc=\\Ek:sc=\\Ej:se=\\Eq:so=\\Ep:ta=^I:\\\r\
  645.     :ti=\\Eq\\Ev\\Ee:up=\\EA:ve=\\Ee:vi=\\Ef:";
  646.  
  647. void do_termcap(void)
  648. {
  649.     char *termcap = (mgr)? get_termcap() : atermcap;
  650.     if(termcap)
  651.     {
  652.     Boutput(rsdev, "setenv TERMCAP '");
  653.     Boutput(rsdev, termcap);
  654.     Boutput(rsdev,"'\r");
  655.     }
  656. }
  657.  
  658. void do_status(void)
  659. {
  660.    Bconws("\r\nMgrterm $Revision: 1.2 $\r\n");
  661.    Bconws("\tBaud rate: "); Bconws(bauds[baud].string); 
  662.    Bconws("\r\n\tFlow type: "); Bconws(flows[flow].string); 
  663.    Bconws("\r\n\tSerial dev: "); Bconout(2, (rsdev+'0'));
  664.    Bconws("\r\n\tWhitepages: "); Bconws((phones)? phones:"none"); Bconws("\r\n");
  665. }
  666.  
  667. void Boutput(int dev, char *s)
  668. {
  669.     for( ; *s ; s++)
  670.     Bconout(dev, *s);
  671. }
  672.  
  673. /* dialing stuff */
  674.  
  675. void do_dial(void)
  676. {
  677.     char *s = getline(!mgr);
  678.     int i;
  679.     size_t len;
  680.  
  681.     if((!(*s)) || (!whitepages))
  682.     return;
  683.     len = strlen(s);
  684.     for(i = 0; whitepages[i].name; i++)
  685.     {
  686.     if(!strncmp(whitepages[i].name, s, len))
  687.     {
  688.         if((*(whitepages[i].baud)) &&
  689.            strcmp(bauds[baud].string, whitepages[i].baud))
  690.         {
  691.             if(set_baud(whitepages[i].baud))
  692.         {
  693.             Bconws("\r\nInvalid baud rate ");Bconws(whitepages[i].baud);
  694.             Bconws(" for "); Bconws(whitepages[i].name);
  695.             Bconws(" dial aborted\r\n");
  696.             return;
  697.             }
  698.         Bconout(rsdev, '\r');
  699.         }
  700.         send_dial(whitepages[i].number);
  701.         return;
  702.     }
  703.     }
  704.     Bconws("\r\n"); Bconws(s); Bconws(": unlisted in whitepages\r\n");
  705. }
  706.  
  707. #if __STDC__
  708.     char *  strdup(const char *s);
  709. #else
  710.     extern char *strdup();
  711. #endif
  712.  
  713. void read_whitepages(char *file)
  714. {
  715.     int pass, n = 0, i = 0;
  716.     FILE *fp = fopen(file, "r");
  717.     char *s, *p, *q, *r, *next;
  718.  
  719.     if(!fp)
  720.     {
  721.     Bconws("\r\nCant find "); Bconws(file);
  722.     Bconws(" Continuing without it\r\n");
  723.         return;
  724.     }
  725.     for(pass = 0; pass < 2; pass++)
  726.     {
  727.     do {
  728.         do {
  729.             if((s = fgets(linebuf, sizeof(linebuf), fp)) == NULL)
  730.                 break;
  731.             while((*s == ' ') || (*s == '\t')) s++;
  732.         } while((*s == '#') || (*s == '\n') || (*s == '\r'));
  733.         if(s == NULL)
  734.         {
  735.             if(pass == 0)
  736.         {
  737.                 if((whitepages = (WHITEPAGE *)malloc((n+1) * sizeof(WHITEPAGE))) == NULL)
  738.                 {
  739.                 goto nomem;
  740.                 }
  741.                 fseek(fp, 0L, SEEK_SET);
  742.                 bzero(whitepages, (n+1) * sizeof(WHITEPAGE));
  743.             }
  744.             break;
  745.         }
  746.         if(pass == 0)
  747.         {
  748.         n++;
  749.                 continue;
  750.             }
  751.         s[(strlen(s) - 1)] = '\0';
  752.         p = s;
  753.         q = index(p, ':');
  754.         if((!q) || (q == p))
  755.         {
  756.           Invalid:
  757.         Bconws("Invalid entry: "); Bconws(s);
  758.         Bconws("\r\n  Continuing without it\r\n");
  759.         if(whitepages[i].name) free(whitepages[i].name);
  760.         whitepages[i].name = NULL;
  761.             continue;
  762.         }
  763.         next = q+1;
  764.         for(--q; ((*q == ' ') || (*q == '\t')); --q) ;
  765.         *++q = '\0';
  766.         if(!(r = strdup(p)))
  767.         goto nomem;
  768.         whitepages[i].name = r;
  769.         p = next;
  770.         while((*p == ' ') || (*p == '\t')) p++;
  771.         q = index(p, ':');
  772.         if(!q) goto Invalid;
  773.         next = q+1;
  774.         if(q == p)
  775.         *q = '\0';
  776.         else
  777.         {
  778.             for(--q; ((*q == ' ') || (*q == '\t')); --q) ;
  779.             *++q = '\0';
  780.             }
  781.         if(!(r = strdup(p)))
  782.         goto nomem;
  783.         whitepages[i].baud = r;
  784.         p = next;
  785.         while((*p == ' ') || (*p == '\t')) p++;
  786.         if(!(r = strdup(p)))
  787.         goto nomem;
  788.         whitepages[i].number = r;
  789.         i++;        
  790.     } while(1);
  791.     }
  792.     if(i == 0)
  793.     {
  794.     if(whitepages)
  795.         free(whitepages);
  796.     whitepages == NULL;
  797.     ndial = 0;
  798.     goto closeup;
  799.     }
  800.     if(i != n)
  801.     whitepages = realloc(whitepages, sizeof(WHITEPAGE)*(i+1));
  802.     if(!whitepages) goto nomem;
  803.     ndial = i;    /* # of whitepages entries */
  804.   closeup:
  805.     fclose(fp);
  806. #if 0
  807.  printf("Found %d entries\n", ndial);
  808.  for(i = 0; i < ndial; i++)
  809.   printf("%s %s %s\n", whitepages[i].name, whitepages[i].baud,
  810.           whitepages[i].number);
  811. #endif
  812.     return;
  813.  
  814. nomem:
  815.     fclose(fp);
  816.     if(whitepages)
  817.     {
  818.     for(i = 0; whitepages[i].name; i++)
  819.     {
  820.         free(whitepages[i].name);
  821.         if(whitepages[i].baud) free(whitepages[i].baud);
  822.         if(whitepages[i].number) free(whitepages[i].number);
  823.     }
  824.     free(whitepages);
  825.     }
  826.     whitepages = NULL;
  827.     ndial = 0;
  828.     Bconws("\r\nNot enough memory for whitepages, continuing without them\r\n");
  829.     return;
  830. }
  831.  
  832. #define isnumber(c) (((c) >= '0') && ((c) <= '9'))
  833. int timeout = 10;    /* char wait timeout    */
  834.  
  835. void send_dial(char *s)
  836. {
  837.     char c;
  838.  
  839.     for(; (c = *s) ; s++)
  840.     {
  841.     if(c != '\\')
  842.         {
  843.         Bconout(rsdev, c);
  844.         if(half) Bconout(2, c);
  845.         continue;
  846.         }
  847.     switch((c = *++s))
  848.         {
  849.         case 'r':
  850.         Bconout(rsdev, '\r'); if(half) Bconout(2, '\r'); break;
  851.         case 'n':
  852.         Bconout(rsdev, '\n'); if(half) Bconout(2, '\n'); break;
  853.         case '\\':
  854.         Bconout(rsdev, '\\'); if(half) Bconout(2, '\\'); break;
  855.         case 's':
  856.         sleep(getnum(&s, 10)); break;
  857.         case 't':
  858.         timeout = getnum(&s, 10); if(timeout == 0) timeout = 10; break;
  859.         case 'w':
  860.         if((c = *++s) == '\\') c = getnum(&s, 8);
  861.         if(await_char(c))
  862.         {
  863.             Bconws("\r\nCharacter wait time out\r\n");
  864.             return;
  865.         }
  866.         break;
  867.         default:
  868.         if(isnumber(c))
  869.             {
  870.            unsigned char n = 0;
  871.            int i = 0;
  872.            do {
  873.             n = (n << 3) | (c - '0');
  874.             c = *++s;
  875.             i++;
  876.            } while(isnumber(c) && (i < 3));
  877.            --s;
  878.            Bconout(rsdev, n); if(half) Bconout(2, n);
  879.         }
  880.         else
  881.         {
  882.             Bconws("\r\nIllegal dial string escape, skipped\r\n");
  883.             if(!(*s)) return;
  884.         }
  885.     }
  886.     }
  887. }
  888.  
  889. int getnum(char **stringp, int base)
  890. {
  891.     char *s = *stringp;
  892.     int n = 0;
  893.     
  894.     for(++s; isnumber(*s); s++)
  895.     {
  896.     n = n * base + (*s - '0');
  897.     }
  898.     *stringp = --s;
  899.     return (n < 0)? 0 : n;
  900. }
  901.  
  902. jmp_buf alrm_buf;
  903.  
  904. void alrm(void)
  905. {
  906.     Psigreturn();
  907.     longjmp(alrm_buf, -1);
  908. }
  909.  
  910. int await_char(int ch)
  911. {
  912.     int c;
  913.     void (*save)(void) = signal(SIGALRM, alrm);
  914.  
  915.     if(setjmp(alrm_buf))
  916.     {
  917.     (void)signal(SIGALRM, save);
  918.     return 1;
  919.     }
  920.  
  921.     alarm(timeout);
  922.     while((c = Bconin(rsdev) & 0x7f) != ch)
  923.     Bconout(2, c);
  924.     alarm(0);
  925.     Bconout(2, c);
  926.     (void)signal(SIGALRM, save);
  927.     return 0;
  928. }
  929.