home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / DIALER.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  31KB  |  1,344 lines

  1. /* Automatic SLIP/PPP line dialer.
  2.  *
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  *
  5.  *    Mar '91    Bill Simpson & Glenn McGregor
  6.  *        completely re-written;
  7.  *        human readable control file;
  8.  *        includes wait for string, and speed sense;
  9.  *        dials immediately when invoked.
  10.  *    May '91 Bill Simpson
  11.  *        re-ordered command line;
  12.  *        allow dial only;
  13.  *        allow inactivity timeout without ping.
  14.  *    Sep '91 Bill Simpson
  15.  *        Check known DTR & RSLD state for redial decision
  16.  *    11 Mar 92 Giles Todd
  17.  *        Add "configure:" and "execute:" sections and new commands.
  18.  *    19 Mar 92 Giles Todd
  19.  *        Fix failure string processing.
  20.  *    31 May 92 Giles Todd
  21.  *        Fix empty configure string problems.
  22.  *    02 Jun 92 Giles Todd
  23.  *        Fix dial session cancel bug.
  24.  *
  25.  $Id: dialer.c 1.12 93/07/16 11:43:38 ROOT_DOS Exp $
  26.  *
  27.  *    04 Aug 92    1.6        GT    No change.
  28.  *    09 Aug 92    1.7        GT    Inline dialing.
  29.  *    17 Aug 92    1.8        GT    Allow escape from inline dial.
  30.  *    13 Sep 92    1.9        CMS    Ignore script lines consisting only of a newline.
  31.  *    03 Apr 93    1.11    GT    Fix order of calls.
  32.  *    08 May 93    1.12    GT    Fix warnings.
  33.  *                            Improve dialer interruption.
  34.  */
  35.  
  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #include <string.h>
  39. #include "global.h"
  40. #include "config.h"
  41. #include "mbuf.h"
  42. #include "timer.h"
  43. #include "proc.h"
  44. #include "iface.h"
  45. #include "netuser.h"
  46. #include "8250.h"
  47. #include "asy.h"
  48. #include "tty.h"
  49. #include "session.h"
  50. #include "socket.h"
  51. #include "cmdparse.h"
  52. #include "devparam.h"
  53. #include "icmp.h"
  54. #include "files.h"
  55. #include "main.h"
  56. #include "trace.h"
  57. #include "hardware.h"
  58. #include "commands.h"
  59.  
  60. extern struct cmds Cmds[];
  61.  
  62. #define MIN_INTERVAL    5L
  63.  
  64. typedef struct item ITEM;
  65.  
  66. struct item
  67.     {
  68.     char *data;                            /* some text                        */
  69.     ITEM *next;                            /* -> next in list                    */
  70.     };
  71.  
  72.  
  73. static int redial __ARGS((struct iface *ifp, char *file));
  74.  
  75. static int cfg_init            __ARGS((int argc, char *argv[], void *p));
  76. static int cfg_dial_cmd        __ARGS((int argc, char *argv[], void *p));
  77. static int cfg_ld_code        __ARGS((int argc, char *argv[], void *p));
  78. static int cfg_number        __ARGS((int argc, char *argv[], void *p));
  79. static int cfg_retries        __ARGS((int argc, char *argv[], void *p));
  80.  
  81. static int dodial_control    __ARGS((int argc, char *argv[], void *p));
  82. static int dodial_dial        __ARGS((int argc, char *argv[], void *p));
  83. static int dodial_init        __ARGS((int argc, char *argv[], void *p));
  84. static int dodial_send        __ARGS((int argc, char *argv[], void *p));
  85. static int dodial_speed        __ARGS((int argc, char *argv[], void *p));
  86. static int dodial_status    __ARGS((int argc, char *argv[], void *p));
  87. static int dodial_wait        __ARGS((int argc, char *argv[], void *p));
  88. static int dodial_cwait        __ARGS((int argc, char *argv[], void *p));
  89.  
  90. static void add_cmd __ARGS((ITEM **hdr, ITEM **ptr, char *buf));
  91. static char *next_cmd __ARGS((char *buf, ITEM **ptr));
  92. static void clean_up __ARGS((void));
  93. static void clean __ARGS((ITEM **hdr));
  94. static int internal_send __ARGS((char *ptr, void *p));
  95. static int asy_kb_poll __ARGS((int dev));
  96.  
  97. static struct cmds dial_cmds[] =
  98.     {
  99.     { "control",     dodial_control,     0, 2, "control up | down" },
  100.     { "dial",        dodial_dial,        0, 0, "dial" },
  101.     { "init",        dodial_init,        0, 0, "init" },
  102.     { "send",         dodial_send,     0, 2, 
  103.     "send \"string\" [<milliseconds>]" }, 
  104.     { "speed",     dodial_speed,     0, 2, "speed <bps>" }, 
  105.     { "status",     dodial_status, 0, 2, "status up | down" }, 
  106.     { "wait",         dodial_wait,     0, 2, 
  107.     "wait <milliseconds> [ \"string\" [speed] ]" }, 
  108.     { "cwait",         dodial_cwait,     0, 2, 
  109.     "cwait <milliseconds> [ \"success string\" \"failure string\" [, \"failure string\" ...] [speed] ]" }, 
  110.     { NULLCHAR,     NULLFP,         0, 0, "Unknown command" }, 
  111.     };
  112.  
  113. static struct cmds cfg_cmds[] =
  114.     {
  115.     { "init",        cfg_init,            0, 2, "init \"string\"" },
  116.     { "dial_cmd",    cfg_dial_cmd,        0, 2, "dial_cmd \"string\"" },
  117.     { "ld_code",    cfg_ld_code,        0, 2, "ld_code \"string\"" },
  118.     { "number",    cfg_number,            0, 2, "number \"string\"" },
  119.     { "retries",    cfg_retries,        0, 2, "retries <count>" },
  120.     { NULLCHAR,     NULLFP,         0, 0, "Unknown command" }, 
  121.     };
  122.  
  123. static char cfg_intro[] = "configure:";
  124. static char exe_intro[] = "execute:";
  125. static int configuring = 0;                /* nz - found configuration section    */
  126.     
  127. static char *init = NULL;                /* initialization string            */
  128. static char *dial_cmd = NULL;            /* modem dial command                */
  129. static char *ld_code = NULL;            /* long distance code                */
  130. static ITEM *number = NULL;                /* telephone numbers                */
  131. static ITEM *nr_ptr = NULL;                /* -> current number                */
  132. static unsigned retries = 1;            /* number of dial retries            */
  133. static ITEM *cfg_cmd = NULL;            /* configuration commands            */
  134. static ITEM *exe_cmd = NULL;            /* script commands                    */
  135. static ITEM *cmd_ptr = NULL;            /* -> current script command        */
  136.  
  137. static int dial_inline = 0;                /* nz - dial inline                    */
  138. static int interrupted;                    /* nz - dial interrupted            */
  139.  
  140.  
  141. /****************************************************************************
  142. *    do_inline                                                                *
  143. *    Toggles the "inline dialing" flag and sets and resets the dialer task's    *
  144. *    stack size.                                                                *
  145. ****************************************************************************/
  146.  
  147. #define    DIALER_STACK    512
  148.  
  149. int do_inline (argc, argv, p)
  150. int argc;
  151. char *argv[];
  152. void *p;
  153.     {
  154.     int rc;                                    /* return value                    */
  155.     struct cmds *cmd_ptr;                    /* -> command structure            */
  156.     
  157.     /* Set / reset / report flag value. */
  158.     
  159.     rc = setbool (&dial_inline, "Inline dialing", argc, argv);
  160.  
  161.     /* Set the dialer stack size. */
  162.  
  163.     cmd_ptr = Cmds;
  164.     while (cmd_ptr->name != NULLCHAR)
  165.         {
  166.         if (strcmp (cmd_ptr->name, "dialer") == 0)
  167.             break;
  168.  
  169.         cmd_ptr++;
  170.         }
  171.         
  172.     if (dial_inline == 0)
  173.         cmd_ptr->stksize = DIALER_STACK;    /* asynch process                */
  174.     else
  175.         cmd_ptr->stksize = 0;                /* inline process                */
  176.  
  177.     return (rc);
  178.     }    /* int do_inline (argc, argv, p) */
  179.     
  180.         
  181. /* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
  182.  *    <iface>        must be asy type
  183.  *    <filename>    contains commands which are executed.
  184.  *            missing: kill outstanding dialer.
  185.  *    <seconds>    interval to check for activity on <iface>.
  186.  *                (if 0 then demand dial)
  187.  *    <pings>     number of missed pings before redial.
  188.  *    <hostid>    interface to ping.
  189.  */
  190.  
  191. int dodialer (argc, argv, p)
  192. int argc;
  193. char *argv[];
  194. void *p;
  195.     {
  196.     struct iface *ifp;
  197.     struct asy *ap;
  198.     int32 interval = 0L;        /* in seconds */
  199.     int32 last_wait = 0L;
  200.     int32 target = 0L;
  201.     int pings = 0;
  202.     int countdown;
  203.     char *filename;
  204.     char *ifn;
  205.     int result;
  206.     int s;
  207.     int exit_on_fail;
  208.  
  209.     if ((ifp = if_lookup (argv[1])) == NULLIF)
  210.         {
  211.         tprintf ("Interface %s unknown\n", argv[1]);
  212.         return 1;
  213.         }
  214.         
  215.     if (ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp)
  216.         {
  217.         tprintf ("Interface %s not asy port\n", argv[1]);
  218.         return 1;
  219.         }
  220.  
  221.     if (ifp->supv != NULLPROC)
  222.         {
  223.         while (ifp->supv != NULLPROC)
  224.             {
  225.             alert (ifp->supv, EABORT);
  226.             pwait (NULL);
  227.             }
  228.             
  229.         tprintf ("dialer terminated on %s\n", argv[1]);
  230.         }
  231.  
  232.     if (argc < 3)
  233.         {
  234.         /* just terminating */
  235.         return 0;
  236.         }
  237.  
  238.     chname (Curproc, ifn = if_name (ifp, " dialer"));
  239.     free (ifn);
  240.     filename = rootdircat (argv[2]);
  241.     ap = &Asy[ ifp->dev ];
  242.  
  243.     if (argc == 4 && strcmp(argv[3], "failexit") == 0)
  244.         exit_on_fail = 1;
  245.     else exit_on_fail = 0;
  246.  
  247.     /* handle minimal command (just thru filename) */
  248.     
  249.     if (argc < 4 || exit_on_fail)
  250.         {
  251.         /* just dialing */
  252.         ifp->supv = Curproc;                /* so that it can be cancelled    */
  253.         result = redial (ifp, filename);
  254.  
  255.         if (filename != argv[2])
  256.             free (filename);
  257.  
  258.         ifp->supv = NULLPROC;
  259.         
  260.         if (result != 0 && exit_on_fail == 1)
  261.             doexit (0, NULL, NULL);
  262.  
  263.         return result;
  264.         }
  265.     /* get polling interval (arg 3) */
  266.     else if (strcmp(argv[3], "demand")
  267.             && (interval = atol (argv[3])) <= MIN_INTERVAL)
  268.         {
  269.         tprintf ("interval must be > %d seconds\n", MIN_INTERVAL);
  270.         return 1;
  271.         }
  272.  
  273.     if (strcmp(argv[3], "demand") == 0)
  274.         /* Interval of 0, so we're demand dialing */
  275.         {
  276.         int32 backoff;
  277.         tprintf("Demand dialing enabled\n");
  278.         backoff = 4;
  279.         ifp->supv = Curproc;                /* so that it can be cancelled    */
  280.         ifp->dial_me = 0;
  281.         while (!main_exit)
  282.             {
  283.             alarm (2000L);
  284.             if (pwait (& (ifp->supv)) == EABORT)
  285.                 break;
  286.             alarm (0L);
  287.             if (ifp->dial_me)
  288.                 {
  289.                 if (ap->dtr_usage == FOUND_DOWN ||
  290.                     ap->dtr_usage == MOVED_DOWN ||
  291.                     ap->rlsd_line_control == MOVED_DOWN)
  292.                     /* dial has been requested _and_ the link is down */
  293.                     {    
  294.                     tprintf("About to dial\n");
  295.                     if (redial (ifp, filename) == 0) {
  296.                         tprintf("Dial succeeded\n");
  297.                         backoff = 4;
  298.                         }
  299.                     else {
  300.                         if (backoff < 90000L) /* Max backoff is day & a bit */
  301.                             backoff = backoff * 2;
  302.                         tprintf("Dial failed, backing off for %lu seconds\n",
  303.                                                                     backoff);
  304.                         }
  305.                     }
  306.                 alarm (backoff * 1000L);
  307.                 if (pwait (& (ifp->supv)) == EABORT)
  308.                     break;
  309.                 alarm (0L);
  310.                 ifp->dial_me = 0;
  311.                 }
  312.             }
  313.         ifp->supv = NULLPROC;
  314.         tprintf("Demand dialing finished\n");
  315.         return 0;
  316.         }
  317.  
  318.     /* get the number of pings before redialing (arg 4) */
  319.  
  320.     if (argc < 5)
  321.         {
  322.         }
  323.     else if ((pings = atoi (argv[4])) <= 0)
  324.         {
  325.         tprintf ("pings must be > 0\n");
  326.         return 1;
  327.         }
  328.  
  329.     /* retrieve the host name (arg 5) */
  330.  
  331.     if (argc < 6)
  332.         {
  333.         }
  334.     else if ((target = resolve (argv[5])) == 0L)
  335.         {
  336.         tprintf (Badhost, argv[5]);
  337.         return 1;
  338.         }
  339.  
  340.     countdown = pings;
  341.     ifp->supv = Curproc;
  342.  
  343.     while (!main_exit)
  344.         {
  345.         int32 wait_for = interval;
  346.  
  347.         if (ap->dtr_usage == FOUND_DOWN ||
  348.             ap->dtr_usage == MOVED_DOWN ||
  349.             ap->rlsd_line_control == MOVED_DOWN)
  350.             {
  351.             /* definitely down */
  352.  
  353.             if (redial (ifp, filename) < 0)
  354.                 break;
  355.  
  356.             }
  357.         else if (ifp->lastrecv >= last_wait)
  358.             {
  359.             /* got something recently */
  360.  
  361.             wait_for -= secclock () - ifp->lastrecv;
  362.             countdown = pings;
  363.             }
  364.         else if (countdown < 1)
  365.             {
  366.             /* we're down, or host we ping is down */
  367.  
  368.             if (redial (ifp, filename) < 0)
  369.                 break;
  370.  
  371.             countdown = pings;
  372.             }
  373.         else if (target != 0L &&
  374.                 (s = socket (AF_INET, SOCK_RAW, ICMP_PTCL)) != -1)
  375.             {
  376.             pingem (s, target, 0, (int16)s, 0);
  377.             close_s (s);
  378.             countdown--;
  379.             }
  380.         else if (ifp->echo != NULLFP)
  381.             {
  382.             (*ifp->echo) (ifp, NULLBUF);
  383.             countdown--;
  384.             }
  385.  
  386.         last_wait = secclock ();
  387.         if (wait_for != 0L)
  388.             {
  389.             alarm (wait_for * 1000L);
  390.             if (pwait (& (ifp->supv)) == EABORT)
  391.                 break;
  392.  
  393.             alarm (0L);        /* clear alarm */
  394.             }
  395.             
  396.         }    /* while (!main_exit) */
  397.  
  398.     if (filename != argv[2])
  399.         free (filename);
  400.  
  401.     ifp->supv = NULLPROC;    /* We're being terminated */
  402.     return 0;
  403.     }    /* int dodialer (argc, argv, p) */
  404.  
  405.  
  406. /* execute dialer commands
  407.  * returns: -1 fatal error, 0 OK, 1 try again
  408.  */
  409.  
  410. static int redial (ifp, file)
  411. struct iface *ifp;
  412. char *file;
  413.     {
  414.     char *inbuf, *intmp;
  415.     FILE *fp;
  416.     int (*rawsave) __ARGS ((struct iface *, struct mbuf *));
  417.     struct session *sp;
  418.     int result = 0;
  419.     int save_input = Curproc->input;
  420.     int save_output = Curproc->output;
  421.     unsigned i;                            /* loop counter                        */
  422.  
  423.     if ((fp = fopen (file, READ_TEXT)) == NULLFILE)
  424.         {
  425.         tprintf ("redial: can't read %s\n", file);
  426.         return -1;    /* Causes dialer proc to terminate */
  427.         }
  428.         
  429.     /* Save output handler and temporarily redirect output to null */
  430.  
  431.     if (ifp->raw == bitbucket)
  432.         {
  433.         tprintf ("redial: tip or dialer already active on %s\n", ifp->name);
  434.         (void) fclose (fp);
  435.         return -1;
  436.         }
  437.  
  438.     /* allocate a session descriptor */
  439.  
  440.     if (dial_inline == 0)
  441.         {
  442.         if ((sp = newsession (ifp->name, DIAL)) == NULLSESSION)
  443.             {
  444.             tprintf ("Too many sessions\n");
  445.             (void) fclose (fp);
  446.             return 1;
  447.             }
  448.  
  449.         }
  450.         
  451.     tprintf ("Dialing on %s\n\n", ifp->name);
  452.  
  453.     /* Save output handler and temporarily redirect output to null */
  454.     
  455.     rawsave = ifp->raw;
  456.     ifp->raw = bitbucket;
  457.  
  458.     /* Suspend the packet input driver. Note that the transmit driver
  459.      * is left running since we use it to send buffers to the line.
  460.      */
  461.      
  462.     suspend (ifp->rxproc);
  463.  
  464. #ifdef notdef
  465.     tprintf ("rlsd: 0x%02x, dtr: 0x%02x\n", 
  466.              Asy[ifp->dev].rlsd_line_control, 
  467.              Asy[ifp->dev].dtr_usage);
  468. #endif
  469.  
  470.     inbuf = mallocw (BUFSIZ);
  471.  
  472.     /* Read the file into cfg_cmd and exe_cmd. */
  473.  
  474.     cfg_cmd = NULL;
  475.     exe_cmd = NULL;
  476.     cmd_ptr = cfg_cmd;                    /* initialize list pointer            */
  477.     configuring = 0;                    /* not configuring yet                */
  478.     while (fgets (inbuf, BUFSIZ, fp) != NULLCHAR)
  479.         {
  480.         if (strnicmp (inbuf, cfg_intro, strlen (cfg_intro)) == 0)
  481.             {
  482.             configuring = 1;            /* found config section                */
  483.             break;
  484.             }
  485.  
  486.         }
  487.  
  488.     if (configuring == 0)
  489.         {
  490.         tprintf ("redial: no \"configure:\" section\n");
  491.         (void) fclose (fp);
  492.         free (inbuf);
  493.         ifp->raw = rawsave;
  494.         resume (ifp->rxproc);
  495.         tprintf ("\nDial %s complete\n", ifp->name);
  496.  
  497.         /* Wait for awhile, so the user can read the screen. */
  498.      
  499.         pause (10000L);
  500.         if (dial_inline == 0)
  501.             {
  502.             freesession (sp);
  503.             }
  504.             
  505.         Curproc->input = save_input;
  506.         Curproc->output = save_output;
  507.         return (-1);
  508.         }
  509.  
  510.     while (fgets (inbuf, BUFSIZ, fp) != NULLCHAR)
  511.         {
  512.         if (strnicmp (inbuf, exe_intro, strlen (exe_intro)) == 0)
  513.             {
  514.             configuring = 0;            /* found execute section            */
  515.             break;
  516.             }
  517.  
  518.         if (*inbuf != '#' && *inbuf != '\n')
  519.             add_cmd (&cfg_cmd, &cmd_ptr, inbuf);    /* add to list            */
  520.  
  521.         }
  522.  
  523.     if (configuring == 1)
  524.         {
  525.         tprintf ("redial: no \"execute:\" section\n");
  526.         clean_up ();                    /* free list                        */
  527.         (void) fclose (fp);
  528.         free (inbuf);
  529.         ifp->raw = rawsave;
  530.         resume (ifp->rxproc);
  531.         tprintf ("\nDial %s complete\n", ifp->name);
  532.  
  533.         /* Wait for awhile, so the user can read the screen. */
  534.      
  535.         pause (10000L);
  536.         if (dial_inline == 0)
  537.             {
  538.             freesession (sp);
  539.             }
  540.             
  541.         Curproc->input = save_input;
  542.         Curproc->output = save_output;
  543.         return (-1);
  544.         }
  545.  
  546.     cmd_ptr = exe_cmd;                    /* read in execute commands            */
  547.     while (fgets (inbuf, BUFSIZ, fp) != NULLCHAR)
  548.         {
  549.         if (*inbuf != '#' && *inbuf != '\n')
  550.             add_cmd (&exe_cmd, &cmd_ptr, inbuf);    /* add to list            */
  551.  
  552.         }
  553.  
  554.     (void) fclose (fp);
  555.     intmp = mallocw (BUFSIZ);
  556.  
  557.     /* Do the configure commands. */
  558.  
  559.     cmd_ptr = cfg_cmd;
  560.     while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR)
  561.         {
  562.         strcpy (intmp, inbuf);
  563.         rip (intmp);
  564.         log (-1, "%s dialer: %s", ifp->name, intmp);
  565.         if ((result = cmdparse (cfg_cmds, inbuf, ifp)) != 0)
  566.             {
  567.             tprintf ("input line: %s\n", intmp);
  568.             break;
  569.             }
  570.             
  571.         }    /* while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR) */
  572.  
  573.     /* Do the execute commands. */
  574.  
  575.     nr_ptr = number;                    /* initialize number pointer        */
  576.     if (result == 0)
  577.         {
  578.         interrupted = 0;
  579.         for (i = 0; i < retries; i++)
  580.             {
  581.             if (pwait (NULL) == EABORT)
  582.                 break;                        /* we are being killed            */
  583.  
  584.             cmd_ptr = exe_cmd;
  585.             while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR)
  586.                 {
  587.                 int c;                        /* input character                */
  588.                 
  589.                 /* Poll the keyboard for 1/10 of a second to
  590.                  * see if <ESC> has been pressed.
  591.                  */
  592.  
  593.                 if (dial_inline != 0)
  594.                     {
  595.                     alarm (100L);
  596.                     if ((c = recvchar (Curproc->input)) != EOF)
  597.                         {
  598.                         alarm (0L);
  599.                         recv_mbuf(Curproc->input,NULLBUFP,0,NULLCHAR,0);
  600.                         if (c == 0x01b)
  601.                             {
  602.                             /* <ESC> pressed - give up. */
  603.                             
  604.                             interrupted = 1;
  605.                             result = -1;
  606.                             tprintf ("interrupted\n");
  607.                             break;
  608.                             }
  609.  
  610.                         }
  611.  
  612.                     alarm (0L);
  613.                     }    /* if (dial_inline != 0) */
  614.  
  615.                 /* Process script command. */
  616.                 
  617.                 strcpy (intmp, inbuf);
  618.                 rip (intmp);
  619.                 log (-1, "%s dialer: %s", ifp->name, intmp);
  620.                 if ((result = cmdparse (dial_cmds, inbuf, ifp)) != 0)
  621.                     {
  622.                     tprintf ("input line: %s\n", intmp);
  623.                     break;
  624.                     }
  625.             
  626.                 }    /* while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR) */
  627.  
  628.             if (result == 0 || interrupted != 0)
  629.                 break;                    /* dial succeeded                    */
  630.  
  631.             }    /* for (i = 0; i < retries; i++) */
  632.  
  633.         }    /* if (result == 0) */
  634.  
  635.     clean_up ();                        /* free lists                        */
  636.     free (inbuf);
  637.     free (intmp);
  638.  
  639.     if (result == 0)
  640.         {
  641.         ifp->lastsent = ifp->lastrecv = secclock ();
  642.         }
  643.  
  644.     ifp->raw = rawsave;
  645.     resume (ifp->rxproc);
  646.     tprintf ("\nDial %s complete\n", ifp->name);
  647.  
  648.     /* Wait for awhile, so the user can read the screen, 
  649.      * AND to give it time to send some packets on the new connection!
  650.      */
  651.      
  652.     pause (10000L);
  653.     if (dial_inline == 0)
  654.         {
  655.         freesession (sp);
  656.         }
  657.         
  658.     Curproc->input = save_input;
  659.     Curproc->output = save_output;
  660.     return result;
  661.     }    /* static int redial (ifp, file) */
  662.  
  663.  
  664. static int dodial_control (argc, argv, p)
  665. int argc;
  666. char *argv[];
  667. void *p;
  668.     {
  669.     struct iface *ifp = p;
  670.     int param;
  671.  
  672.     if (ifp->ioctl == NULL)
  673.         return -1;
  674.  
  675.     if ((param = devparam (argv[1])) == -1)
  676.         return -1;
  677.  
  678.     (*ifp->ioctl) (ifp, param, TRUE, atol (argv[2]));
  679.     return 0;
  680.     }    /* static int dodial_control (argc, argv, p) */
  681.  
  682.  
  683. static int dodial_send (argc, argv, p)
  684. int argc;
  685. char *argv[];
  686. void *p;
  687.     {
  688.     struct iface *ifp = p;
  689.     struct mbuf *bp;
  690.  
  691.     if (argc > 2)
  692.         {
  693.         /* Send characters with inter-character delay
  694.          * (for dealing with prehistoric Micom switches that
  695.          * can't take back-to-back characters...yes, they
  696.          * still exist.)
  697.          */
  698.          
  699.         char *cp;
  700.         int32 cdelay = atol (argv[2]);
  701.  
  702.         for (cp = argv[1];*cp != '\0';cp++)
  703.             {
  704.             bp = qdata (cp, 1);
  705.             asy_send (ifp->dev, bp);
  706.             pause (cdelay);
  707.             }
  708.             
  709.         }
  710.     else
  711.         {
  712.         bp = qdata (argv[1], strlen (argv[1]));
  713.         if (ifp->trace & IF_TRACE_RAW)
  714.             raw_dump (ifp, IF_TRACE_OUT, bp);
  715.             
  716.         asy_send (ifp->dev, bp);
  717.         }
  718.         
  719.     return 0;
  720.     }    /* static int dodial_send (argc, argv, p) */
  721.  
  722.  
  723. static int dodial_speed (argc, argv, p)
  724. int argc;
  725. char *argv[];
  726. void *p;
  727.     {
  728.     struct iface *ifp = p;
  729.  
  730.     if (argc < 2)
  731.         {
  732.         tprintf ("current speed = %u bps\n", Asy[ifp->dev].speed);
  733.         return 0;
  734.         }
  735.         
  736.     return asy_speed (ifp->dev, (int16) atol (argv[1]));
  737.     }    /* static int dodial_speed (argc, argv, p) */
  738.  
  739.  
  740. static int dodial_status (argc, argv, p)
  741. int argc;
  742. char *argv[];
  743. void *p;
  744.     {
  745.     struct iface *ifp = p;
  746.     int param;
  747.  
  748.     if (ifp->iostatus == NULL)
  749.         return -1;
  750.  
  751.     if ((param = devparam (argv[1])) == -1)
  752.         return -1;
  753.  
  754.     (*ifp->iostatus) (ifp, param, atol (argv[2]));
  755.     return 0;
  756.     }    /* static int dodial_status (argc, argv, p) */
  757.  
  758.  
  759. static int dodial_wait (argc, argv, p)
  760. int argc;
  761. char *argv[];
  762. void *p;
  763.     {
  764.     struct iface *ifp = p;
  765.     register int c = -1;
  766.  
  767.     alarm (atol (argv[1]));
  768.  
  769.     if (argc == 2)
  770.         {
  771.         while ((c = asy_kb_poll (ifp->dev)) != -1)
  772.             {
  773.             tputc (c &= 0x7F);
  774.             tflush ();
  775.             }
  776.  
  777.         alarm (0L);
  778.         return 0;
  779.         }
  780.     else
  781.         {
  782.         register char *cp = argv[2];
  783.  
  784.         while (*cp != '\0' && (c = asy_kb_poll (ifp->dev)) != -1)
  785.             {
  786.             tputc (c &= 0x7F);
  787.             tflush ();
  788.  
  789.             if (*cp++ != c)
  790.                 {
  791.                 cp = argv[2];
  792.                 }
  793.                 
  794.             }    /* while (*cp != '\0' && (c = asy_kb_poll (ifp->dev)) != -1) */
  795.  
  796.         if (argc > 3)
  797.             {
  798.             if (stricmp (argv[3], "speed") == 0)
  799.                 {
  800.                 int16 speed = 0;
  801.  
  802.                 while ((c = asy_kb_poll (ifp->dev)) != -1)
  803.                     {
  804.                     tputc (c &= 0x7F);
  805.                     tflush ();
  806.  
  807.                     if (isdigit (c))
  808.                         {
  809.                         speed *= 10;
  810.                         speed += c - '0';
  811.                         }
  812.                     else
  813.                         {
  814.                         alarm (0L);
  815.                         return asy_speed (ifp->dev, speed);
  816.                         }
  817.                         
  818.                     }    /* while ((c = asy_kb_poll (ifp->dev)) != -1) */
  819.                     
  820.                 }    /* if (stricmp (argv[3], "speed") == 0) */
  821.             else
  822.                 {
  823.                 return -1;
  824.                 }
  825.                 
  826.             }    /* if (argc > 3) */
  827.             
  828.         }    /* if (argc != 2) */
  829.         
  830.     alarm (0L);
  831.     return (c == -1);
  832.     }    /* static int dodial_wait (argc, argv, p) */
  833.  
  834.  
  835. /****************************************************************************
  836. *    cfg_init                                                                *
  837. *    Sets up the modem initialization string.                                *
  838. ****************************************************************************/
  839.  
  840. static int cfg_init (argc, argv, p)
  841. int argc;
  842. char **argv;
  843. void *p;
  844.     {
  845.     if (init != NULL)
  846.         free (init);
  847.  
  848.     if (strlen (argv[1]) == 0)
  849.         {
  850.         init = NULL;
  851.         return (0);
  852.         }
  853.         
  854.     init = mallocw (strlen (argv[1]) + 1);
  855.     (void) strcpy (init, argv[1]);
  856.     return (0);
  857.     }    /* static int cfg_init (argc, argv, p) */
  858.  
  859.  
  860. /****************************************************************************
  861. *    cfg_dial_cmd                                                            *
  862. *    Sets up the modem dial command.                                            *
  863. ****************************************************************************/
  864.  
  865. static int cfg_dial_cmd (argc, argv, p)
  866. int argc;
  867. char **argv;
  868. void *p;
  869.     {
  870.     if (dial_cmd != NULL)
  871.         free (dial_cmd);
  872.         
  873.     if (strlen (argv[1]) == 0)
  874.         {
  875.         dial_cmd = NULL;
  876.         return (0);
  877.         }
  878.         
  879.     dial_cmd = mallocw (strlen (argv[1]) + 1);
  880.     (void) strcpy (dial_cmd, argv[1]);
  881.     return (0);
  882.     }    /* static int cfg_dial_cmd (argc, argv, p) */
  883.  
  884.  
  885. /****************************************************************************
  886. *    cfg_ld_code                                                                *
  887. *    Sets up the long distance code.                                            *
  888. ****************************************************************************/
  889.  
  890. static int cfg_ld_code (argc, argv, p)
  891. int argc;
  892. char **argv;
  893. void *p;
  894.     {
  895.     if (ld_code != NULL)
  896.         free (ld_code);
  897.         
  898.     if (strlen (argv[1]) == 0)
  899.         {
  900.         ld_code = NULL;
  901.         return (0);
  902.         }
  903.         
  904.     ld_code = mallocw (strlen (argv[1]) + 1);
  905.     (void) strcpy (ld_code, argv[1]);
  906.     return (0);
  907.     }    /* static int cfg_ld_code (argc, argv, p) */
  908.  
  909.  
  910. /****************************************************************************
  911. *    cfg_retries                                                                *
  912. *    Sets up the number of dial retries.                                        *
  913. ****************************************************************************/
  914.  
  915. static int cfg_retries (argc, argv, p)
  916. int argc;
  917. char **argv;
  918. void *p;
  919.     {
  920.     (void) sscanf (argv[1], "%u", &retries);
  921.     if (retries <= 0)
  922.         return (-1);                    /* must be >= 1                        */
  923.  
  924.     return (0);
  925.     }    /* static int cfg_retries (argc, argv, p) */
  926.  
  927.  
  928. /****************************************************************************
  929. *    cfg_number                                                                *
  930. *    Adds a number to the dial list.                                            *
  931. ****************************************************************************/
  932.  
  933. static int cfg_number (argc, argv, p)
  934. int argc;
  935. char **argv;
  936. void *p;
  937.     {
  938.     add_cmd (&number, &nr_ptr, argv[1]);
  939.     return (0);
  940.     }    /* static int cfg_number (argc, argv, p) */
  941.  
  942.  
  943. /****************************************************************************
  944. *    internal_send                                                            *
  945. *    Sends a string to dodial_send ().                                        *
  946. ****************************************************************************/
  947.  
  948. static int internal_send (ptr, p)
  949. char *ptr;
  950. void *p;
  951.     {
  952.     char *argv[2];
  953.  
  954.     argv[0] = NULL;
  955.     argv[1] = ptr;
  956.     return (dodial_send (2, argv, p));
  957.     }    /* static int internal_send (ptr, p) */
  958.     
  959.  
  960. /****************************************************************************
  961. *    dodial_init                                                                *
  962. *    Send the initialisation string to the modem.                            *
  963. ****************************************************************************/
  964.  
  965. static int dodial_init (argc, argv, p)
  966. int argc;
  967. char **argv;
  968. void *p;
  969.     {
  970.     if (init == NULL)
  971.         return (0);                        /* no initialization string - ok    */
  972.  
  973.     return (internal_send (init, p));
  974.     }    /* static int dodial_init (argc, argv, p) */
  975.  
  976.  
  977. /****************************************************************************
  978. *    dodial_dial                                                                *
  979. *    Send the dialer commands and the next number to the modem.                *
  980. ****************************************************************************/
  981.  
  982. static int dodial_dial (argc, argv, p)
  983. int argc;
  984. char **argv;
  985. void *p;
  986.     {
  987.     char *buf;                            /* -> number buffer                    */
  988.     int rc;                                /* result code                        */
  989.  
  990.     if (number == NULL)
  991.         return (-1);                    /* no numbers specified                */
  992.         
  993.     buf = mallocw (BUFSIZ);                /* get a buffer for the number        */
  994.     if (dial_cmd != NULL)
  995.         {
  996.         /* Send the dial command. */
  997.         
  998.         if ((rc = internal_send (dial_cmd, p)) != 0)
  999.             {
  1000.             free (buf);
  1001.             return (rc);
  1002.             }
  1003.  
  1004.         }    /* if (dial_cmd != NULL) */
  1005.  
  1006.     if (ld_code != NULL)
  1007.         {
  1008.         /* Send the long distance code. */
  1009.         
  1010.         if ((rc = internal_send (ld_code, p)) != 0)
  1011.             {
  1012.             free (buf);
  1013.             return (rc);
  1014.             }
  1015.  
  1016.         }    /* if (ld_code != NULL) */
  1017.  
  1018.     /* Send the next number. */
  1019.  
  1020.     if (next_cmd (buf, &nr_ptr) == NULLCHAR)
  1021.         {
  1022.         /* Try resetting the pointer. */
  1023.  
  1024.         nr_ptr = number;
  1025.         if (next_cmd (buf, &nr_ptr) == NULLCHAR)
  1026.             {
  1027.             free (buf);                    /* gone badly wrong                    */
  1028.             return (-1);
  1029.             }
  1030.  
  1031.         }    /* if (next_cmd (buf, nr_ptr) == NULLCHAR) */
  1032.  
  1033.     if ((rc = internal_send (buf, p)) != 0)    /* send the number                */
  1034.         {
  1035.         free (buf);
  1036.         return (rc);
  1037.         }
  1038.  
  1039.     rc = internal_send ("\r", p);
  1040.     free (buf);
  1041.     return (rc);
  1042.     }    /* static int dodial_dial (argc, argv, p) */
  1043.  
  1044.  
  1045. /****************************************************************************
  1046. *    dodial_cwait                                                            *
  1047. *    Conditional version of dodial_wait ().                                    *
  1048. ****************************************************************************/
  1049.  
  1050. static int dodial_cwait (argc, argv, p)
  1051. int argc;
  1052. char *argv[];
  1053. void *p;
  1054.     {
  1055.     struct iface *ifp = p;
  1056.     register int c = -1;
  1057.     int speedarg;                        /* index of "speed" argument        */
  1058.     int lastarg;                        /* index of last argument            */
  1059.     int i;                                /* loop counter                        */
  1060.     char failed;                        /* failure flag - nz means failed    */
  1061.     
  1062.     alarm (atol (argv[1]));
  1063.  
  1064.     lastarg = argc - 1;
  1065.     if (stricmp (argv[lastarg], "speed") == 0)
  1066.         {
  1067.         speedarg = lastarg;
  1068.         lastarg--;
  1069.         }
  1070.     else
  1071.         speedarg = 0;                    /* no "speed" argument                */
  1072.         
  1073.     if (argc == 2)
  1074.         {
  1075.         /* Wait for duration expiry only. */
  1076.         
  1077.         while ((c = asy_kb_poll (ifp->dev)) != -1)
  1078.             {
  1079.             tputc (c &= 0x7F);
  1080.             tflush ();
  1081.             }
  1082.  
  1083.         alarm (0L);
  1084.         return 0;
  1085.         }
  1086.     else
  1087.         {
  1088.         register char *cp = argv[2];    /* -> success string                */
  1089.         char **fail_ptr;                /* array of ptrs to failure strings    */
  1090.  
  1091.         /* Set up the array of failure string pointers. */
  1092.  
  1093.         fail_ptr = (char **) mallocw ((lastarg - 2) * sizeof (char *));
  1094.         for (i = 0; i < (lastarg - 2); i++)
  1095.             fail_ptr[i] = argv[i + 3];
  1096.  
  1097.         /* Looking for string matches. */
  1098.  
  1099.         failed = 0;
  1100.         while ((c = asy_kb_poll (ifp->dev)) != -1)
  1101.             {
  1102.             tputc (c &= 0x7F);
  1103.             tflush ();
  1104.  
  1105.             /* Check the success string first. */
  1106.  
  1107.             if (*cp == '\0')
  1108.                 break;                    /* we got a connect                    */
  1109.                 
  1110.             if (*cp++ != c)
  1111.                 {
  1112.                 cp = argv[2];
  1113.                 }
  1114.  
  1115.             /* Now check the failure strings. */
  1116.  
  1117.             for (i = 0; i < (lastarg - 2); i++)
  1118.                 {
  1119.                 if (*fail_ptr[i] == '\0')
  1120.                     {
  1121.                     failed = 1;
  1122.                     break;                /* we lost                            */
  1123.                     }
  1124.  
  1125.                 if (*fail_ptr[i]++ != c)
  1126.                     {
  1127.                     fail_ptr[i] = argv[i + 3];
  1128.                     }
  1129.  
  1130.                 }
  1131.  
  1132.             if (failed)
  1133.                 break;
  1134.                 
  1135.             }    /* while ((c = asy_kb_poll (ifp->dev)) != -1) */
  1136.                 
  1137.         free (fail_ptr);                /* give back heap memory            */
  1138.         
  1139.         /* If we get here, we may have matched the "success" string. */
  1140.  
  1141.         if (*cp != '\0')
  1142.             {
  1143.             alarm (0L);
  1144.             return (-1);                /* we didn't                        */
  1145.             }
  1146.             
  1147.         if (speedarg != 0)
  1148.             {
  1149.             int16 speed = 0;
  1150.  
  1151.             while ((c = asy_kb_poll (ifp->dev)) != -1)
  1152.                 {
  1153.                 tputc (c &= 0x7F);
  1154.                 tflush ();
  1155.  
  1156.                 if (isdigit (c))
  1157.                     {
  1158.                     speed *= 10;
  1159.                     speed += c - '0';
  1160.                     }
  1161.                 else
  1162.                     {
  1163.                     alarm (0L);
  1164.                     return asy_speed (ifp->dev, speed);
  1165.                     }
  1166.                         
  1167.                 }    /* while ((c = asy_kb_poll (ifp->dev)) != -1) */
  1168.                     
  1169.             }    /* if (stricmp (lastarg, "speed") == 0) */
  1170.             
  1171.         }    /* if (argc != 2) */
  1172.         
  1173.     alarm (0L);
  1174.     return (c == -1);
  1175.     }    /* static int dodial_cwait (argc, argv, p) */
  1176.  
  1177.     
  1178. /****************************************************************************
  1179. *    add_cmd                                                                    *
  1180. *    Add a string to the end of the list whose header is pointed to by         *
  1181. *    <*hdr>.  <*ptr>    (if non-NULL) points to the last item in the list.        *
  1182. *    <buf> points to the data to be added to the list and is assumed to be    *
  1183. *    an ASCIIZ string.                                                        *
  1184. ****************************************************************************/
  1185.  
  1186. static void add_cmd (hdr, ptr, buf)
  1187. ITEM **hdr;
  1188. ITEM **ptr;
  1189. char *buf;
  1190.     {
  1191.     if (strlen (buf) == 0)
  1192.         return;
  1193.         
  1194.     if (*hdr == NULL)
  1195.         {
  1196.         /* Empty list. */
  1197.  
  1198.         *hdr = (ITEM *) mallocw (sizeof (ITEM));
  1199.         *ptr = *hdr;
  1200.         }
  1201.     else
  1202.         {
  1203.         (*ptr)->next = (ITEM *) mallocw (sizeof (ITEM));
  1204.         *ptr = (*ptr)->next;
  1205.         }
  1206.  
  1207.     (*ptr)->data = (char *) mallocw (strlen (buf) + 1);
  1208.     (*ptr)->next = NULL;
  1209.     (void) strcpy ((*ptr)->data, buf);
  1210.     }    /* static void add_cmd (hdr, ptr, buf) */
  1211.  
  1212.  
  1213. /****************************************************************************
  1214. *    next_cmd                                                                *
  1215. *    Copies the data part of the item pointed to by <*ptr> into the buffer    *
  1216. *    pointed to by <buf>.  This area is assumed to be large enough to hold    *
  1217. *    the data.  <*ptr> is advanced to point to the next item.  Returns <buf>    *
  1218. *    if there is another item, NULLCHAR at the end of the list.                *
  1219. ****************************************************************************/
  1220.     
  1221. static char *next_cmd (buf, ptr)
  1222. char *buf;
  1223. ITEM **ptr;
  1224.     {
  1225.     if (*ptr == NULL)
  1226.         return (NULLCHAR);
  1227.         
  1228.     (void) strcpy (buf, (*ptr)->data);
  1229.     *ptr = (*ptr)->next;
  1230.     return (buf);
  1231.     }    /* static char *next_cmd (buf, ptr) */
  1232.     
  1233.  
  1234. /****************************************************************************
  1235. *    clean_up                                                                *
  1236. *    Frees the heap memory used by the various lists.                        *
  1237. ****************************************************************************/
  1238.  
  1239. static void clean_up ()
  1240.     {
  1241.     clean (&number);
  1242.     clean (&cfg_cmd);
  1243.     clean (&exe_cmd);
  1244.     if (init != NULL)
  1245.         {
  1246.         free (init);
  1247.         init = NULL;
  1248.         }
  1249.  
  1250.     if (dial_cmd != NULL)
  1251.         {
  1252.         free (dial_cmd);
  1253.         dial_cmd = NULL;
  1254.         }
  1255.         
  1256.     if (ld_code != NULL)
  1257.         {
  1258.         free (ld_code);
  1259.         ld_code = NULL;
  1260.         }
  1261.  
  1262.     retries = 1;        
  1263.     }    /* static void clean_up () */
  1264.  
  1265.  
  1266. /****************************************************************************
  1267. *    clean                                                                    *
  1268. *    Free up the list pointed to by <*hdr>.                                    *
  1269. ****************************************************************************/
  1270.  
  1271. static void clean (hdr)
  1272. ITEM **hdr;
  1273.     {
  1274.     ITEM *p, *q;                        /* list followers                    */
  1275.  
  1276.     p = *hdr;
  1277.     while (p != NULL)
  1278.         {
  1279.         q = p->next;
  1280.         free (p->data);
  1281.         free (p);
  1282.         p = q;
  1283.         }
  1284.  
  1285.     *hdr = NULL;
  1286.     }    /* static void clean (hdr) */
  1287.  
  1288.  
  1289. /****************************************************************************
  1290. *    asy_kb_poll                                                                *
  1291. *    Polls the async interface for incoming characters and the keyboard for    *
  1292. *    <ESC>.  Returns the character on the async receive queue or -1 if timed    *
  1293. *    out or <ESC> detected.                                                    *
  1294. ****************************************************************************/
  1295.  
  1296. static int asy_kb_poll (dev)
  1297. int dev;
  1298.     {
  1299.     int c;                                /* input character                    */
  1300.  
  1301.     for (;;)
  1302.         {
  1303.         /* Check keyboard. */
  1304.         
  1305.         if (socklen (Curproc->input,0) > 0)
  1306.             {
  1307.             c = recvchar (Curproc->input);
  1308.             if (c != EOF)
  1309.                 {
  1310.                 recv_mbuf (Curproc->input, NULLBUFP, 0, NULLCHAR, 0);
  1311.                 if (c == 0x1b)
  1312.                     {
  1313.                     /* <ESC> pressed - give up. */
  1314.  
  1315.                     interrupted = 1;
  1316.                     c = -1;
  1317.                     break;
  1318.                     }
  1319.  
  1320.                 }    /* if (c != EOF) */
  1321.  
  1322.             }    /* if (socklen (Curproc->input,0) > 0) */
  1323.  
  1324.         /* Check async. */
  1325.  
  1326.         if (asy_len (dev) > 0)
  1327.             {
  1328.             c = get_asy (dev);
  1329.             break;
  1330.             }
  1331.  
  1332.         /* Let someone else run. */
  1333.  
  1334.         if (pwait (0) != 0)
  1335.             {
  1336.             c = -1;
  1337.             break;
  1338.             }
  1339.  
  1340.         }    /* for (;;) */
  1341.  
  1342.     return (c);
  1343.     }    /* static int asy_kb_poll (dev) */
  1344.