MDM_PROC.C

23.1 KB d910300e9e092355…
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*                                                                          */
/*      ------------         Bit-Bucket Software, Co.                       */
/*      \ 10001101 /         Writers and Distributors of                    */
/*       \ 011110 /          Freely Available<tm> Software.                 */
/*        \ 1011 /                                                          */
/*         ------                                                           */
/*                                                                          */
/*  (C) Copyright 1987-91, Bit Bucket Software Co., a Delaware Corporation. */
/*                                                                          */
/*                                                                          */
/*               This module was written by Vince Perriello                 */
/*                                                                          */
/*                                                                          */
/*                    BinkleyTerm Modem Handler Module                      */
/*                                                                          */
/*                                                                          */
/*    For complete  details  of the licensing restrictions, please refer    */
/*    to the License  agreement,  which  is published in its entirety in    */
/*    the MAKEFILE and BT.C, and also contained in the file LICENSE.250.    */
/*                                                                          */
/*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
/*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
/*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
/*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
/*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
/*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
/*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
/*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
/*                                                                          */
/*                                                                          */
/* You can contact Bit Bucket Software Co. at any one of the following      */
/* addresses:                                                               */
/*                                                                          */
/* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
/* P.O. Box 460398                AlterNet 7:491/0                          */
/* Aurora, CO 80046               BBS-Net  86:2030/1                        */
/*                                Internet f491.n343.z1.fidonet.org         */
/*                                                                          */
/* Please feel free to contact us at any time to share your comments about  */
/* our software and/or licensing policies.                                  */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/* Include this file before any other includes or defines! */

#include "includes.h"

int dial_modem (char *);
void phone_translate (char *, char *);
char *get_response (long);
int parse_response (char *);
void empty_delay (void);

#define FAILURE   0
#define IGNORE    1
#define CONNECTED 2
#define RINGING   3
#define INCOMING  4

struct resp_str
{
   char *resp;
   unsigned disp;
};

static struct resp_str mdm_resps[] = {
                                      {"RINGING", 1},
                                      {"RING RESPONSE", 1},
                                      {"RING", 3},
                                      {"CONNECT", 2},
                                      {"RRING", 1},
                                      {"BUSY", 0},
                                      {"VOICE", 0},
                                      {"ERROR", 0},
                                      {"OK", 0},
                                      {"NO CARRIER", 0},
/* "NO DIAL TONE" or "NO DIALTONE" */ {"NO DIAL", 4},
                                      {"DIALING", 1},
                                      {"NO ANSWER", 0},
                                      {"DIAL TONE", 1},
                                      {NULL, 0}
};

static char *response_string = "                                                  ";

void do_dial_strings ()
{
   MDM_TRNS *m;

   predial = normprefix;
   postdial = normsuffix;

   m = mm_head;
   while (m != NULL)
      {
      if (m->mdm & newnodedes.ModemType)
         {
         predial = m->pre;
         postdial = m->suf;
         return;
         }
      m = m->next;
      }
}

void try_2_connect (char *phnum)
{
   long t1;
   int j, k;

   for (j = 0; (j < poll_tries && !KEYPRESS ()); j++) /* do polltries or till keypress */
      {
      CLEAR_INBOUND ();
      k = dial_modem (phnum);

      if ((un_attended || doing_poll) && fullscreen)
         {
         ++hist.calls_made;
         (void) sprintf (junk, "%-4d", hist.calls_made);
         sb_move (history_hWnd, HIST_ATT_ROW, HIST_COL);
         sb_puts (history_Out, junk);
         }

      if ((k > 0) || KEYPRESS ())
         break;
      t1 = timerset (200);
      mdm_hangup ();
      while (!timeup (t1) && !KEYPRESS ())
         time_release ();                        /* pause for 2 seconds */
      }
   if (KEYPRESS ())                              /* If user's been busy */
      {
      (void) FOSSIL_CHAR ();                     /* Eat the character   */
      if (!CARRIER)                              /* Abort if no carrier */
         {
         status_line (MSG_TXT(M_CONNECT_ABORTED));
         mdm_hangup ();
         }
      }

   predial = normprefix;
   postdial = normsuffix;
}

int try_1_connect (char *phnum)
{
   int k;

   if ((k = dial_modem (phnum)) <= 0)
      {
      if (k != -2)            /* NO DIAL TONE needs express service */
         mdm_hangup ();
      }

   if ((un_attended || doing_poll) && fullscreen)
      {
      ++hist.calls_made;
      (void) sprintf (junk, "%-4d", hist.calls_made);
      sb_move (history_hWnd, HIST_ATT_ROW, HIST_COL);
      sb_puts (history_Out, junk);
      }

   predial = normprefix;
   postdial = normsuffix;

   return (k);
}

void phone_translate (char *number, char *translated)
{
   PN_TRNS *p;

   (void) strcpy (translated, number);
   for (p = pn_head; p != NULL; p = p->next)
      {
      if (strncmp (p->num, number, (unsigned int) (p->len)) == 0)
         {
         (void) sprintf (translated, "%s%s%s", p->pre, &(number[p->len]), p->suf);
         break;
         }
      }
}

int dial_modem (char *number)
{
   int resp;
   long t;
   char translated[50];

   janus_OK = 0;
   ARQ_lock = 0;

   phone_translate (number, translated);
   if (translated[0] == '\"')                    /* If it's a script          */
      {
      resp = do_script (translated);             /* then do it that way       */
      if (fullscreen)                            /* & clean up the bottom line*/
         bottom_line ();
      return (resp);
      }

   status_line (MSG_TXT(M_DIALING_NUMBER), translated);
   if (un_attended && fullscreen)
      {
      do_ready (MSG_TXT(M_READY_DIALING));
      }

   /* First of all, if we have something, don't hang up on the guy! */
   if (!no_collide && CHAR_AVAIL ())
      return (-1);

   if (dial_setup != NULL)
      {
      mdm_cmd_string (dial_setup, 1);
      }
   else
      {
      LOWER_DTR ();                              /* drop DTR to reset modem   */
      timer (20);                                /* leave it down 2 seconds   */
      RAISE_DTR ();                              /* then raise DTR again      */
      timer (5);                                 /* and wait .5 sec for modem */
      }

   if (!no_collide && CHAR_AVAIL ())             /* If we have something
                                                  * here, return */
      return (-1);

   mdm_cmd_string (predial, 0);                  /* transmit the dial prefix  */
   mdm_cmd_string (translated, 0);               /* then the phone number     */
   mdm_cmd_string (postdial, 0);                 /* finally the dial suffix   */
   if (no_collide)
      CLEAR_INBOUND ();                          /* Throw out all echo to
                                                  * this point  */
   mdm_cmd_char (CR);                            /* terminate the string      */

   resp = modem_response (7500);
   if (resp)                                     /* we got a good response,   */
      {
      if (resp == RINGING)                       /* Incoming ring to be
                                                  * processed higher up */
         return (-1);

      if (resp == INCOMING)                      /* No dial tone. That's */
         {
         return (-2);                            /* a potential remote. */
         }

      t = timerset (200);                        /* Wait up to 2 seconds      */
      while (!timeup (t))
         {                                       /* If carrier detect, AND    */
         if ((CHAR_AVAIL ()) && CARRIER)         /* some sign of life, */
            break;                               /* leave early...            */
         }
      return ((int) CARRIER);                    /* Carrier should be on now  */
      }
   return (0);                                   /* no good */
}

char *get_response (long end_time)
{
   char *p = response_string;                    /* points to character cell  */
   char c;                                       /* current modem character   */
   int count = 0;                                /* count of characters       */

   while ((count < 50)                           /* until we have 50 chars,   */
          && (!timeup (end_time))                /* or out of time,           */
          && (!KEYPRESS ()))                     /* or user gets impatient    */
      {
      if (!CHAR_AVAIL ())                        /* if nothing ready yet,     */
         {
         time_release ();
         continue;                               /* just process timeouts     */
         }
      c = (char) (MODEM_IN () & 0xff);           /* get a character           */
      if (c == '\r' || c == '\n')                /* if a line ending          */
         {
         if (count != 0)                         /* and we have something,    */
            break;                               /* get out                   */
         else continue;                          /* otherwise just keep going */
         }
      *p++ = c;                                  /* store the character       */
      ++count;                                   /* increment the counter     */
      }
   *p = '\0';                                    /* terminate the new string  */

   if (count != 0 && strnicmp (response_string, "AT", 2))
      {
      (void) fancy_str (response_string);               /* make it pretty            */
      status_line ("#%s", response_string);     /* pop it out on the screen  */
      }

   return (response_string);                     /* return the pointer        */
}

int parse_response (char *response)
{
   char *p;                                      /* temp character pointer    */
   register int i;                               /* array pointer             */

   for (i = 0; mdm_resps[i].resp != NULL; i++)   /* scan through array        */
      {
      p = mdm_resps[i].resp;                     /* point at possible
                                                  * response */
      if (strnicmp (response, p, strlen (p)) == 0)      /* if a match,               */
         return ((int) (mdm_resps[i].disp));             /* return disposition of it  */
      }
   return (1);                                   /* ignore all unknowns       */
}


int modem_response (int ths)
{
   unsigned int baudrate;
   long end_time;                                /* holds time at end of 2min */
   char *response;                               /* pointer to modem response */
   char *c;                                      /* miscellaneous pointer     */
   int result = IGNORE;                          /* result code               */
   int i;
   int ring_count = 0;                           /* # of RINGING responses    */

   /* If this modem doesn't differentiate between RING and RINGING */
   if (modemring)
      mdm_resps[2].disp = IGNORE;

   end_time = timerset ((unsigned int) ths);     /* arm the timeout           */
   while ((result == IGNORE)                     /* until success or failure, */
          && (!timeup (end_time))                /* or out of time,           */
          && (!KEYPRESS ()))                     /* or user gets impatient    */
      {
  /*
   *  See if we've been through this code enough times to reach
   *  the user-defined failure threshold. For this purpose,
   *  we crudely assume that all IGNORE cases are rings.
   *
   *  Henry Clark and Ron Bemis get credit for this one.
   */
      if (ring_count++ >= ring_tries)
         {
         response = "NO ANSWER";
         (void) fancy_str (response);
         status_line ("#%s", response);
         result = parse_response(response);
         break;
         }
  /*
   *  We're still here. So get the next modem response 
   *  (or time out trying).
   */
      response = get_response (end_time);        /* get a response            */
      result = parse_response (response);        /* parse, determine status   */
      time_release ();
      }

   if (result == CONNECTED)                      /* Got to be a CONNECT msg   */
      {
      if (strnicmp (response, "connect", 7) == 0)/* if this is a CONNECT,     */
         {
         c = skip_blanks (&response[7]);         /* get past the blanks       */
         mdm_reliable[0] = '\0';                 /* Start with nothing        */

         if (*c == '\0')                         /* if nothing there,         */
            {
            baudrate = (unsigned int) 300;       /* say that it's 300 baud    */
            }
         else
            {
            baudrate = (unsigned int) atoi (c);  /* else do baudrate fallback */

            /* For 1200/75 split speed modems and "Connect 212" */

            if ((baudrate == 1275) || (baudrate == 7512)
            ||  (baudrate == 75) || (baudrate == 212) || (baudrate == 12))
               baudrate = 1200;

            /* For "Connect 103" */
            if (baudrate == 103)
               baudrate = 300;
            }

            ARQ_lock = 0;

            while (isdigit (*c))                 /* Get past digits           */
               ++c;
            c = skip_blanks (c);                 /* Get rid of blanks         */
            if (*c != '\0')                      /* We have "reliable" info.  */
               {
               (void) strcpy (mdm_reliable, c);  /* Copy in the info          */
               can_Janus (mdm_reliable);         /* Set the flag for Janus    */
               for (i = 0; i < ARQs; i++)
                  {
                  if ((strnicmp (mdm_reliable, ARQ[i], strlen(ARQ[i]))) == 0)
                     {
                     ARQ_lock = 1;
                     break;
                     }
                  }
               }

         if (baudrate)
            (void) set_baud (baudrate, 1);              
         }

      MNP_Filter ();
      }

   return (result);                              /* timeout or failure or OK  */
}

void mdm_cmd_string (char *mdm_cmd, int dospace)
{
   register char *c;
   register int escaped = 0;

   if (mdm_cmd == NULL)                          /* defense from shit         */
      return;

   for (c = mdm_cmd; *c; c++)
      {
      if (escaped)
         {
         SENDBYTE (*c);
         escaped = 0;
         continue;
         }

      if (*c == '\\')
         {
         escaped = 1;
         continue;
         }
      
      if (!isspace (*c) || dospace)              /* don't output spaces       */
         mdm_cmd_char (*c);                      /* output the next character */
      }
}

void empty_delay ()
{
   long t;

   t = timerset (500);
   while ((!OUT_EMPTY ()) && (!timeup (t)))
      time_release ();                           /* wait for output to finish */

   if (!OUT_EMPTY ())
      {
      MDM_DISABLE ();
      (void) Cominit (port_ptr, buftmo);
      program_baud ();
      RAISE_DTR ();
      CLEAR_OUTBOUND ();
      CLEAR_INBOUND ();
      if (un_attended && fullscreen)
         {
         sb_dirty ();
         sb_show ();
         }
      }
}

void mdm_cmd_char (int outchr)
{
   switch (outchr)
      {
      case '-':                                /* if it's a dash (phone no) */
         return;                                 /* ignore it                 */

      case '|':                                /* if the CR character,      */
         outchr = CR;                            /* substitute a real CR here */
         break;

      case '.':                                 /* Substitute ',' for '.'    */
         outchr = ',';                           /* for compatibility         */
         break;

      case '~':                                /* if the "delay" character, */
         empty_delay ();                         /* wait for buffer to clear, */
         timer (10);                             /* then wait 1 second        */
         return;                                 /* and return                */

      case '^':                                 /* Raise DTR                 */
         empty_delay ();                         /* wait for buffer to clear, */
         RAISE_DTR ();                              /* Turn on DTR               */
         return;                                 /* and return                */

      case 'v':                                 /* Lower DTR         */
         empty_delay ();                         /* wait for buffer to clear, */
         LOWER_DTR ();                             /* Turn off DTR              */
         return;                                 /* and return                */

      case '`':                                 /* Short delay         */
         timer (1);                              /* short pause, .1 second    */
         return;                                 /* and return                */

      default:
         break;
      }

   SENDBYTE ((unsigned char) outchr);            /* then write the character  */

   if (outchr == CR)                             /* if it was a CR,           */
      {
      empty_delay ();
      timer (1);                                 /* allow .1 sec line quiet   */
      }
   else if (slowmodem)
      {
      timer (1);                                 /* wait .1 sec for output    */
      }
}

void mdm_hangup ()
{

   /*
    * First, if a dial command is in progress, try to get the modem to abort
    * it... 
    */

   CLEAR_OUTBOUND ();
   CLEAR_INBOUND ();

   if (un_attended && fullscreen)
      {
      do_ready (MSG_TXT(M_READY_HANGUP));
      }
   else
      {
      status_line (MSG_TXT(M_MODEM_HANGUP));      /* Tell what we are doing    */
      }

   mdm_init (modem_init);                        /* re-initialize the modem   */
   timer (5);                                    /* Wait another .5 sec       */

   ARQ_lock = 0;                                 /* Re-init lockbaud          */

   set_xy ("");
   CLEAR_INBOUND ();                             /* then flush input and exit */
}

void mdm_init (char *str)
{
   set_prior(4);                                           /* Always High    */

   CLEAR_OUTBOUND ();
   CLEAR_INBOUND ();
   if (init_setup != NULL)
      {
      (void) set_baud (max_baud.rate_value, 0);
      mdm_cmd_string (init_setup, 1);
      }
   else
      {
      mdm_cmd_char (CR);                            /* output a CR, then         */
      LOWER_DTR ();                                   /* Drop DTR to hangup        */
      timer (10);                                   /* Hold it down for 1 sec    */

      RAISE_DTR ();                                    /* Raise DTR,                */
      timer (5);                                    /* Then hold it up for .5
                                                  * sec */
      (void) set_baud (max_baud.rate_value, 0);

      mdm_cmd_char (' ');                           /* output a space            */
      mdm_cmd_char (CR);                            /* then another CR           */
      }
   mdm_cmd_string (str, 0);                      /* then the modem init
                                                  * string */

   set_prior(2);                                           /* Regular        */

   timer (5);                                    /* Hold DTR for .5 sec more  */
   CLEAR_INBOUND ();                             /* then flush input and exit */
}

void send_break (int t)
{
   long t1;

   t1 = timerset ((unsigned int) t);
   do_break (1);
   while (!timeup (t1))
      time_release ();
   do_break (0);
}

void exit_DTR ()
{
   if (!leave_dtr_high)
      LOWER_DTR ();
}

/*
 * We get here right after the CONNECT message. It could happen
 * so quickly that we don't even have DCD set. (On a 33MHz 386
 * and a T2500, that happens!)
 *
 * So: this routine waits up to 1 second for a carrier.
 *
 * It then eats anything that looks like an MNP string, with 
 * a total time allowed of 10 seconds (for streaming garbage)
 * and maximum inter-character delay of 3 seconds.
 */


void MNP_Filter ()
{
   long t, t1;
   int c;
   int logged = 0;

   t = timerset (100);      /* at most a one second delay  */

   while (!CARRIER && !timeup (t))
      ;

   t1 = timerset (1000);   /* 10 second drop dead timer    */
   t = timerset (300);     /* at most a three second delay */

   while (CARRIER && !timeup (t))
      {
      if (got_ESC ())
         {                                       /* Manual abort?        */
         LOWER_DTR ();                             /* Yes, drop carrier    */
         return;
         }

      if (timeup (t1))
         break;

      if ((c = PEEKBYTE ()) != -1)
         {
         (void) TIMED_READ(0);

         /* If we get an MNP or v.42 character, eat it and wait for clear line */
         if ((c != 0) && ((strchr (BadChars, (c | 0x80)) != NULL) || (strchr (BadChars, (c & 0x7f)) != NULL)))
            {
            t = timerset (300);
            if ((logged++) == 0)
               status_line (MSG_TXT(M_FILTER));
            }
         }
      }
}