/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-90, 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.240. */ /* */ /* 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:132/491, 1:141/491 */ /* P.O. Box 460398 AlterNet 7:491/0 */ /* Aurora, CO 80046 BBS-Net 86:2030/1 */ /* Internet f491.n132.z1.fidonet.org */ /* */ /* Please feel free to contact us at any time to share your comments about */ /* our software and/or licensing policies. */ /* */ /*--------------------------------------------------------------------------*/ #include #include #include #include #include #include #include "com.h" #include "xfer.h" #include "zmodem.h" #include "keybd.h" #include "sbuf.h" #include "sched.h" #include "externs.h" #include "prototyp.h" static int dial_modem (char *); static void phone_translate (char *, char *); static char *get_response (long); static int parse_response (char *); static void empty_delay (void); #define FAILURE 0 #define IGNORE 1 #define SUCCESS 2 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", 0}, {"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 (phnum) char *phnum; { long t1, timerset (); 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; sb_move (historywin, HIST_ATT_ROW, HIST_COL); (void) sprintf (junk, "%-4d", hist.calls_made); sb_puts (historywin, (unsigned char *) junk); } if ((k > 0) || KEYPRESS ()) break; t1 = timerset (200); while (!timeup (t1) && !KEYPRESS ()) time_release (); /* pause for 2 seconds */ } if (KEYPRESS ()) /* If user's been busy */ { if (!caller) (void) FOSSIL_CHAR (); /* Eat the character */ if (!CARRIER) /* Abort if no carrier */ { status_line (msgtxt[M_CONNECT_ABORTED]); mdm_hangup (); } } predial = normprefix; postdial = normsuffix; } int try_1_connect (phnum) char *phnum; { int k; if ((k = dial_modem (phnum)) <= 0) { mdm_hangup (); } if ((un_attended || doing_poll) && fullscreen) { ++hist.calls_made; sb_move (historywin, HIST_ATT_ROW, HIST_COL); (void) sprintf (junk, "%-4d", hist.calls_made); sb_puts (historywin, (unsigned char *) junk); } predial = normprefix; postdial = normsuffix; return (k); } static void phone_translate (number, translated) 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; } } } static int dial_modem (number) char *number; { int resp; long t; char translated[50]; extern long timerset (); janus_OK = 0; phone_translate (number, translated); if (translated[0] == '\"') /* If it's a script */ return (do_script (translated)); /* then do it that way */ status_line (msgtxt[M_DIALING_NUMBER], translated); if (un_attended && fullscreen) { do_ready (msgtxt[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 { DTR_OFF (); /* drop DTR to reset modem */ timer (20); /* leave it down 2 seconds */ DTR_ON (); /* 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 == 3) /* Incoming ring to be * processed higher up */ return (-1); 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 */ } static char *get_response (end_time) long end_time; /* timeout parameters */ { 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 */ } static int parse_response (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 (ths) int ths; /* millisecs to wait */ { unsigned int baudrate; long end_time; /* holds time at end of 2min */ extern long timerset (); char *response; /* pointer to modem response */ char *c, *skip_blanks (); /* miscellaneous pointer */ int result = IGNORE; /* result code */ /* If this modem doesn't differentiate between RING and RINGING */ if (modemring) mdm_resps[0].disp = 1; 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 */ { response = get_response (end_time); /* get a response */ result = parse_response (response); /* parse, determine status */ time_release (); } if (result == SUCCESS) /* 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; } if (baudrate) (void) set_baud (baudrate, 1); 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 */ } } MNP_Filter (); } return (result); /* timeout or failure or OK */ } void mdm_cmd_string (mdm_cmd, dospace) char *mdm_cmd; int dospace; { register char *c; if (mdm_cmd == NULL) /* defense from shit */ return; for (c = mdm_cmd; *c; c++) { if (dospace || !isspace (*c)) /* don't output spaces */ mdm_cmd_char (*c); /* output the next character */ } } static void empty_delay () { long t, timerset (); t = timerset (500); while ((!OUT_EMPTY ()) && (!timeup (t))) time_release (); /* wait for output to finish */ if (!OUT_EMPTY ()) { MDM_DISABLE (); (void) Cominit (port_ptr); MDM_ENABLE (lock_baud && (btypes[baud].rate_value >= lock_baud) ? max_baud.rate_mask : btypes[baud].rate_mask); DTR_ON (); CLEAR_OUTBOUND (); CLEAR_INBOUND (); if (un_attended && fullscreen) { sb_dirty (); sb_show (); } } } void mdm_cmd_char (outchr) 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, */ DTR_ON (); /* Turn on DTR */ return; /* and return */ case 'v': /* Lower DTR */ empty_delay (); /* wait for buffer to clear, */ DTR_OFF (); /* 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 (msgtxt[M_READY_HANGUP]); } else { status_line (msgtxt[M_MODEM_HANGUP]); /* Tell what we are doing */ } mdm_init (modem_init); /* re-initialize the modem */ timer (5); /* Wait another .5 sec */ set_xy (""); CLEAR_INBOUND (); /* then flush input and exit */ } void mdm_init (str) char *str; { 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 */ DTR_OFF (); /* Drop DTR to hangup */ timer (10); /* Hold it down for 1 sec */ DTR_ON (); /* 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 */ timer (5); /* Hold DTR for .5 sec more */ CLEAR_INBOUND (); /* then flush input and exit */ } void send_break (t) 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) DTR_OFF (); } void MNP_Filter () { long t, t1; int c; t1 = timerset (1000); /* 10 second drop dead timer */ t = timerset (300); /* at most a one second delay */ while (!timeup (t)) { if (timeup (t1)) break; if ((c = PEEKBYTE ()) != 0xffff) { (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) != NULL) || (strchr (BadChars, c&0x7f) != NULL))) { t = timerset (300); status_line (msgtxt[M_FILTER]); } } } }