/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-96, Bit Bucket Software Co. */ /* */ /* 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.260. */ /* */ /* 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:42/1491 */ /* 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" static int LOCALFUNC dial_modem (char *); static void LOCALFUNC phone_translate (char *, char *); static int LOCALFUNC parse_response (char *); static void LOCALFUNC empty_delay (void); static void LOCALFUNC MNP_Filter (void); static char response_string[128]; void do_dial_strings () { MDM_TRNS *m; predial = normprefix; postdial = normsuffix; m = mm_head; while (m != NULL) { if ((m->mdm == newnodedes.ModemType) && (*(m->pre) || *(m->suf))) { 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 (historywin, HIST_ATT_ROW, HIST_COL); sb_puts (historywin, 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 (historywin, HIST_ATT_ROW, HIST_COL); sb_puts (historywin, junk); } predial = normprefix; postdial = normsuffix; return (k); } static void LOCALFUNC 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; } } } static int LOCALFUNC dial_modem (char *numbertocall) { int resp; int retval = 0; long t; char *translated = response_string; P_ANUMS altnums = anum_head; char *number = numbertocall; int dialmsg = M_DIALING_NUMBER; janus_OK = 0; ARQ_lock = 0; for (;;) { phone_translate (number, translated); if (translated[0] == '\"') /* If it's a script */ { retval = do_script (translated);/* then do it that way */ if (fullscreen) /* & clean up the bottom line*/ bottom_line (); break; } status_line (MSG_TXT (dialmsg), 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 ()) { retval = -1; break; } 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 ()) /* Is there something? return*/ { retval = -1; break; } 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 now */ mdm_cmd_char (CR); /* terminate the string */ resp = modem_response (7500); if (resp) /* we got a good response, */ { if (resp == RINGING || (resp & FAX)) /* Process incoming */ { retval = -1; break; } if (resp == INCOMING) /* No dial tone. That's */ { retval = -2; /* a potential remote. */ break; } if (resp == DIALRETRY) /* retry condition */ { if (altnums == NULL) /* no retry number get out */ break; number = NULL; /* precondition next number */ /* Scan alternate number list for another match */ while (altnums != NULL) { if (!stricmp (altnums->num, numbertocall)) { number = altnums->alt; altnums = altnums->next; dialmsg = M_DIALING_ALTNUM; CLEAR_INBOUND (); break; } else altnums = altnums->next; } if (number == NULL) break; else continue; } /* Not RINGING, FAX, INCOMING or DIALRETRY */ 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... */ else time_release ();/*PLF Sun 12-01-1991 05:55:16 */ } retval = ((int) CARRIER); /* Carrier should be on now */ } /* If we get here we want out of the loop. */ break; } return (retval); /* pass what we got back to the caller */ } 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 < 127) /* 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 onscreen */ } return (response_string); /* return the pointer */ } static int LOCALFUNC parse_response (char *response) { char *p; /* temp character pointer */ register int i; /* array pointer */ if (!mdm_resps) /* If we have no strings, */ return (IGNORE); /* always ignore... */ for (i = 0; i < resp_count; i++) /* scan through array */ { p = mdm_resps[i].resp; /* point at possible response*/ if (strnicmp (response, p, strlen (p)) == 0) { /* We matched this result. Return its disposition*/ return ((int) (mdm_resps[i].disp)); } } return (IGNORE); /* ignore all unknowns */ } int modem_response (int ths) { unsigned long 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 */ 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 */ { mdm_reliable[0] = '\0'; /* Start with nothing */ if (strnicmp (response, "connect", 7) == 0) /* if this is CONNECT*/ { strcpy (saved_response, response); c = skip_blanks (&response[7]); /* get past the blanks */ mdm_reliable[0] = '\0'; /* Start with nothing */ if (*c == '\0') /* if nothing there, */ { baudrate = 300L; /* say that it's 300 baud */ } else { baudrate = (unsigned long) atol (c); /* else do fallback */ /* For 1200/75 split speed modems and "Connect 212" */ if ((baudrate == 1275) || (baudrate == 7512) || (baudrate == 75) || (baudrate == 212) || (baudrate == 12)) baudrate = 1200L; /* For "Connect 103" */ if (baudrate == 103) baudrate = 300L; } if ((fax_in) && !strnicmp (c, "FAX", 3)) return (ZYXFAX); 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 (); } else if (result == FAX) /* FAX is a special case */ { strcpy (saved_response, response); } 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 badness */ 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 */ } } static void LOCALFUNC 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); /* 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 */ } if (un_attended || (term_init == NULL)) { mdm_init (modem_init); /* re-init the modem */ } else { mdm_init (term_init); /* use term init if term mode*/ } 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 .5sec */ (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 3 seconds 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 2 seconds. */ static void LOCALFUNC MNP_Filter () { long t, t1; int c; int logged = 0; t = timerset (300); /* at most a three second delay */ t1 = timerset (50); /* From same point, .5 sec for LF*/ while (!CARRIER && !timeup (t)) time_release (); /*PLF Sun 12-01-1991 04:28:38 */ /* Look for terminator character on connect string. If we see one, eat it. Only wait up to .5 sec for it, though. (Note that if we delayed for DCD, we count that time, since the LF should have already been coming in from the modem) */ do { c = PEEKBYTE (); if (c != -1) break; } while (!timeup (t1)); if (c == LF) MODEM_IN (); /* If this was a MNP connection, bail out right now. */ for (c = 0; c < cMNP; c++) { if ((strnicmp (mdm_reliable, pchMNP[c], strlen (pchMNP[c]))) == 0) return; } t1 = timerset (1000); /* 10 second drop dead timer */ t = timerset (200); /* at most a 2 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 (500); if ((logged++) == 0) status_line (MSG_TXT (M_FILTER)); } } else time_release (); /*PLF Sun 12-01-1991 04:28:38 */ } }