home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------------*/
- /* */
- /* */
- /* ------------ Bit-Bucket Software, Co. */
- /* \ 10001101 / Writers and Distributors of */
- /* \ 011110 / Freely Available<tm> Software. */
- /* \ 1011 / */
- /* ------ */
- /* */
- /* (C) Copyright 1987-96, Bit Bucket Software Co. */
- /* */
- /* This module originally written by Michael Buenter */
- /* Original UNIX sources Henry Minsky 11/02/90 hqm@ai.mit.edu */
- /* BinkleyTerm FAX file reception 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"
- #include "faxproto.h"
-
- /*--------------------------------------------------------------------------*/
- /* Local routines */
- /*--------------------------------------------------------------------------*/
-
- static int LOCALFUNC get_fax_file (int);
- static int LOCALFUNC read_g3_stream (FILE *, int);
- static void LOCALFUNC get_faxline (char *, int, unsigned int);
- static void LOCALFUNC init_swaptable (void);
- static void LOCALFUNC init_modem_response (void);
- static void LOCALFUNC get_modem_result_code (void);
- static void LOCALFUNC parse_text_response (char *);
-
- static int LOCALFUNC faxmodem_receive_page (int);
- static void LOCALFUNC fax_status (char *);
-
- /*--------------------------------------------------------------------------*/
- /* Private data */
- /*--------------------------------------------------------------------------*/
-
- static int gEnd_of_document;
- static unsigned char swaptable[256];
- static int swaptableinit = FALSE;
- static struct faxmodem_response response;
-
- static unsigned long faxsize = 0L;
-
- /*--------------------------------------------------------------------------*/
- /* FAX RECEIVE Routines */
- /*--------------------------------------------------------------------------*/
-
- /* receive fax files into basefilename */
-
- int
- faxreceive (int zmode)
- {
- int result;
- int page;
-
- if (!fax_in)
- return (0);
-
- happy_compiler = zmode;
-
- if (!swaptableinit)
- init_swaptable ();
-
- (void) time (&etm);
-
- if (fax_baud != -1)
- {
- baud = fax_baud;
- cur_baud = pbtypes[baud];
- MDM_ENABLE (cur_baud.rate_mask);
- (void) sprintf (junk, "%-6lu Com%d", cur_baud.rate_value, port_ptr + 1);
- sb_move (settingswin, SET_PORT_ROW, SET_COL);
- sb_puts (settingswin, junk);
- }
-
- do_ready ("FAX Rcv ");
-
- (void) init_modem_response ();
- gEnd_of_document = FALSE;
- response.fcon = TRUE; /* we already connected */
-
- result = 0;
-
- for (page = 0; gEnd_of_document == FALSE; page++)
- {
- result = get_fax_file (page);
- status_line (">FAX get_fax_file returns = %d", result);
- switch ((int) result)
- {
- case PAGE_GOOD:
-
- continue;
-
- case PAGE_HANGUP:
-
- status_line (" FAX Received %d pages", page);
- result = 1;
- gEnd_of_document = TRUE;
- break;
-
- default:
-
- status_line (" FAX Error during transmission");
- result = page;
- gEnd_of_document = TRUE;
- break;
- }
- }
-
- set_baud (max_baud.rate_value, 0);
- (void) sprintf (junk, "%-6lu", max_baud.rate_value);
- sb_move (settingswin, SET_PORT_ROW, SET_COL);
- sb_puts (settingswin, junk);
-
- return result;
- }
-
- /* This executes the +FDR receive page command, and looks for
- * the proper CONNECT response, or, if the document is finished,
- * looks for the FHNG/FHS code.
- *
- * returns:
- * PAGE_GOOD no error conditions occured during reception
- * PAGE_HANGUP normal end of transmission
- * PAGE_ERROR something's wrong
- */
-
- static int LOCALFUNC
- get_fax_file (int page)
- {
- char buf[256], j[100];
- int result;
- FILE *fp = NULL;
- int opage = page;
-
- status_line (">FAX [get_fax_file]");
-
- do
- {
- if (TaskNumber)
- sprintf (buf, "%sPAGE%02x%02x.FAX", fax_in, (TaskNumber & 0xff), opage++);
- else
- sprintf (buf, "%sPAGE%04x.FAX", fax_in, opage++);
- }
- while (dexists (buf) && (opage < 256));
-
- if (opage == 256)
- {
- status_line ("!FAX Couldn't create output file");
- return (PAGE_ERROR);
- }
-
- if ((result = faxmodem_receive_page (page)) == 0)
- {
- /* filename to create for this page of document */
- if ((fp = fopen (buf, write_binary)) == NULL)
- {
- status_line ("!FAX Couldn't create output file %s", buf);
- return (PAGE_ERROR);
- }
-
- if (!page)
- status_line (" FAX Connect with %s", response.remote_id);
-
- (void) sprintf (j, "%s %s; page %02x", "FAX Rcv", buf, page);
-
- if (un_attended && fullscreen)
- {
- clear_filetransfer ();
- sb_move (filewin, 1, 2);
- sb_puts (filewin, j);
- (void) sprintf (j, " vr%d br%d wd%d ln%d df%d ec%d bf%d st%d",
- response.T30.vr, response.T30.br, response.T30.wd,
- response.T30.ln, response.T30.df, response.T30.ec,
- response.T30.bf, response.T30.st);
- sb_move (filewin, 2, 40);
- sb_puts (filewin, j);
- status_line (j);
- elapse_time ();
- }
- else
- {
- set_xy (j);
- set_xy (NULL);
- locate_x += 2;
- }
-
- result = read_g3_stream (fp, page);
- }
-
- if (fp != NULL)
- {
- fclose (fp);
- if (faxsize <= 256L)
- unlink (buf);
- else
- status_line (" FAX File received %s (%lub)", buf, faxsize);
- }
-
- return (result);
- }
-
- /* Reads a data stream from the faxmodem, unstuffing DLE characters.
- * Returns the +FET value (2 if no more pages) or 4 if hangup.
- */
-
- static int LOCALFUNC
- read_g3_stream (FILE * fp, int page)
- {
- register short c;
- char e_input_buf[11];
- unsigned char *secbuf, *p;
- long ltimer = 0L; /* MB 94-01-01 */
- int pseudo_carrier; /* MB 94-01-01 */
-
- status_line (">FAX [read_g3_stream]");
-
- happy_compiler = page; /* Make compiler happy */
- response.post_page_response_code = -1; /* reset page codes */
- response.post_page_message_code = -1;
-
- CLEAR_INBOUND (); /* flush echoes or return codes */
-
- if ((secbuf = (unsigned char *) calloc (1, 1024)) == NULL)
- goto fax_error;
-
- p = secbuf;
-
- (void) fax_status (ultoa (faxsize, e_input_buf, 10));
-
- pseudo_carrier = !(CARRIER); /* test if modem sets DCD */
- if (pseudo_carrier)
- status_line (">FAX modem doesn't assert DCD [read_g3_stream]");
-
- status_line (">FAX DC2 [read_g3_stream]");
-
- /* Send DC2 to start phase C data stream */
-
- SENDBYTE ((unsigned char) DC2);
-
- while (pseudo_carrier || CARRIER) /* data only when carrier high */
- {
- if (!CHAR_AVAIL ()) /* if nothing ready,*/
- {
- if (pseudo_carrier) /* MB 94-01-01 */
- { /* process timeout if modem does not */
- /* set DCD, this is only a kludge, but */
- /* it could prevent an endless loop */
- if (!ltimer)
- ltimer = timerset (1500); /* 15 secs timeout */
- else
- if (timeup(ltimer))
- goto fax_error; /* Houston, we lost the downlink */
- }
- time_release ();
- continue; /* process timeouts */
- }
- else
- ltimer = 0L; /* reset no char waiting timer */
-
- c = MODEM_IN () & 0xff; /* get a character */
-
- if (c == DLE) /* DLE handling */
- {
- long ltimer2 = 0L;
-
- while (!CHAR_AVAIL ())
- {
- if (!ltimer2)
- ltimer2 = timerset (400);
- else
- if (timeup (ltimer2))
- {
- faxsize = 0L;
- goto fax_error; /* give up */
- }
- }
-
- c = TIMED_READ (0);
-
- if (c == ETX) /* end of stream */
- goto end_page;
-
- /* DLE DLE gives DLE. We don't know what to do if it
- isn't ETX (above) or DLE. So we'll just always treat
- DLE (not ETX) as (not ETX).
-
- Fall out of here into storage. */
- }
-
- *p++ = swaptable[(unsigned char) c];
- faxsize++;
-
- if (!(faxsize % 1024))
- {
- (void) fax_status (ultoa (faxsize, e_input_buf, 10));
- if (fwrite (secbuf, 1, 1024, fp) != 1024)
- {
- goto fax_error; /* hoppala */
- }
- p = secbuf;
- time_release ();
- }
- }
-
- end_page:
-
- if (faxsize % 1024)
- {
- if (fwrite (secbuf, 1, (size_t) (faxsize % 1024), fp) != (size_t) (faxsize % 1024))
- goto fax_error; /* hoppala */
- (void) fax_status (ultoa (faxsize, e_input_buf, 10));
- }
-
- free (secbuf);
-
- status_line (">FAX Waiting for +FET/+FHNG [read_g3_stream]");
- c = 0;
- while (response.post_page_message_code == -1) /* wait for +FET */
- {
- (void) get_modem_result_code ();
- c++;
- if ((!response.post_page_response_code) || (c > 5) || (response.error))
- return (PAGE_ERROR);
- if (response.hangup_code != -1)
- return (PAGE_HANGUP);
- }
- return (PAGE_GOOD);
-
- fax_error:
-
- if (secbuf != NULL)
- free (secbuf);
- status_line ("!FAX Error receiving page");
- (void) get_modem_result_code ();
- return (PAGE_ERROR);
- }
-
- /*--------------------------------------------------------------------------*/
- /* Class 2 Faxmodem Protocol Functions */
- /* */
- /* Taken from EIA Standards Proposal No. 2388: Proposed New Standard */
- /* "Asynchronous Facsimile DCE Control Standard" (if approved, */
- /* to be published as EIA/TIA-592) */
- /*--------------------------------------------------------------------------*/
-
- /* reads a line of characters, terminated by a newline */
-
- static void LOCALFUNC
- get_faxline (char *p, int nbytes, unsigned int wtime)
- {
- short c; /* current modem character */
- int count = 1; /* character count (+null) */
- long t;
- char *resp;
-
- t = timerset (wtime);
-
- resp = p;
-
- while ((count < nbytes) /* until we have n bytes, */
- && (!timeup (t))) /* or out of time */
- {
- if (!CHAR_AVAIL ()) /* if nothing ready yet, */
- {
- time_release ();
- continue; /* just process timeouts */
- }
- c = MODEM_IN () & 0xff; /* get a character */
- if (c == '\n')
- continue;
- if (c == '\r')
- if (count > 1)
- break; /* get out */
- else
- continue; /* otherwise just keep going */
- *p++ = (char) c; /* store the character */
- ++count; /* increment the counter */
- }
-
- *p = '\0'; /* terminate the new string */
-
- if (debugging_log && (count > 1) && strnicmp (resp, "AT", 2))
- status_line (">FAX %s", resp); /* pop it on screen */
- }
-
- static void LOCALFUNC
- init_swaptable (void)
- {
- int i, j;
-
- for (i = 0; i < 256; i++)
- {
- /* swap the low order 4 bits with the high order */
-
- j = (((i & 0x01) << 7) |
- ((i & 0x02) << 5) |
- ((i & 0x04) << 3) |
- ((i & 0x08) << 1) |
- ((i & 0x10) >> 1) |
- ((i & 0x20) >> 3) |
- ((i & 0x40) >> 5) |
- ((i & 0x80) >> 7));
- swaptable[i] = (unsigned char) j;
- }
- swaptableinit = TRUE;
- }
-
- /****************************************************************
- * Initialize a faxmodem_response struct
- */
-
- static void LOCALFUNC
- init_modem_response (void)
- {
- response.remote_id[0] = '\0';
- response.fcon = FALSE;
- response.connect = FALSE;
- response.ok = FALSE;
- response.error = FALSE;
- response.hangup_code = -1;
- response.post_page_response_code = -1;
- response.post_page_message_code = -1;
- response.T30.ec = response.T30.bf = 0;
- }
-
- /* This function parses numeric responses from the faxmodem.
- * It fills in any relevant slots of the faxmodem_response structure.
- */
-
- static void LOCALFUNC
- get_modem_result_code (void)
- {
- char buf[256];
- long t;
-
- status_line (">FAX [get_modem_result_code]");
-
- t = timerset (400);
-
- while (!timeup (t))
- {
- buf[0] = '\0';
- (void) get_faxline (buf, 255, 100);
- if (buf[0])
- {
- (void) parse_text_response (buf);
- return;
- }
- }
- return;
- }
-
- static void LOCALFUNC
- fax_status (char *str)
- {
- if (fullscreen && un_attended)
- {
- sb_move (filewin, 2, 2);
- sb_puts (filewin, str);
- elapse_time ();
- }
- else
- {
- gotoxy (locate_x, locate_y);
- (void) cputs (str);
- }
- }
-
- static void LOCALFUNC
- parse_text_response (char *str)
- {
- /* Look for +FCON, +FDCS, +FDIS, +FHNG, +FHS, +FPTS, +FK, +FTSI */
-
- if (!strnicmp ("+FCO", str, 4))
- {
- response.fcon = TRUE;
- (void) fax_status ("+FCO ");
- return;
- }
-
- if (!strnicmp (str, "OK", 2))
- {
- response.ok = TRUE;
- return;
- }
-
- if (!strnicmp (str, "CONNECT", 7))
- {
- response.connect = TRUE;
- return;
- }
-
- if (!strnicmp (str, "NO CARRIER", 10) || !strnicmp (str, "ERROR", 5))
- {
- response.error = TRUE;
- response.hangup_code = 0;
- return;
- }
-
- if (!strnicmp (str, "+FDCS", 5))
- {
- sscanf (str + 6, "%d,%d,%d,%d,%d,%d,%d,%d",
- &response.T30.vr, &response.T30.br, &response.T30.wd,
- &response.T30.ln, &response.T30.df, &response.T30.ec,
- &response.T30.bf, &response.T30.st);
- (void) fax_status ("+FDCS ");
- return;
- }
-
- if (!strnicmp (str, "+FHNG", 5))
- {
- sscanf (str + 6, "%d", &response.hangup_code);
- (void) fax_status ("+FHNG ");
- return;
- }
-
- if (!strnicmp (str, "+FPTS", 5))
- {
- sscanf (str + 6, "%d", &response.post_page_response_code);
- (void) fax_status ("+FPTS ");
- return;
- }
-
- if (!strnicmp (str, "+FTSI", 5))
- {
- (void) strcpy (response.remote_id, str + 6);
- (void) fax_status ("+FTSI ");
- return;
- }
-
- if (!strnicmp (str, "+FET", 4))
- {
- sscanf (str + 5, "%d", &response.post_page_message_code);
- (void) fax_status ("+FET ");
- return;
- }
-
- if (!strnicmp (str, "+FHS", 4)) /* Class 2.0 */
- {
- sscanf (str + 5, "%d", &response.hangup_code);
- (void) fax_status ("+FHS ");
- return;
- }
-
- if (!strnicmp (str, "+FCS", 4)) /* Class 2.0 */
- {
- sscanf (str + 5, "%d,%d,%d,%d,%d,%d,%d,%d",
- &response.T30.vr, &response.T30.br, &response.T30.wd,
- &response.T30.ln, &response.T30.df, &response.T30.ec,
- &response.T30.bf, &response.T30.st);
- (void) fax_status ("+FCS ");
- return;
- }
-
- if (!strnicmp (str, "+FPS", 4)) /* Class 2.0 */
- {
- sscanf (str + 5, "%d", &response.post_page_response_code);
- (void) fax_status ("+FPS ");
- return;
- }
-
- if (!strnicmp (str, "+FTI", 4)) /* Class 2.0 */
- {
- (void) strcpy (response.remote_id, str + 5);
- (void) fax_status ("+FTI ");
- return;
- }
-
- }
-
- /****************************************************************
- * Action Commands
- */
-
- /* Receive a page
- * after receiving OK,
- * send +FDR
- * This is somewhat ugly, because the FDR command can return
- * a couple of possible results;
- * If the connection is valid, it returns something like
- * +FCFR
- * +FDCS: <params>
- * CONNECT
- *
- * If, on the other hand, the other machine has hung up, it returns
- * +FHNG: <code> or
- * +FHS: <code>
- *
- * and if the connection was never made at all, it returns ERROR (actually numeric
- * code 4)
- *
- * faxmodem_receive_page returns values:
- * PAGE_GOOD page reception OK, data coming
- * PAGE_HANGUP normal hangup
- * PAGE_ERROR page error
- */
-
- static int LOCALFUNC
- faxmodem_receive_page (int page)
- {
- long t;
- char buf[100];
-
- faxsize = 0L;
- response.connect = response.ok = FALSE;
-
- /* We wait until a string "OK" is seen
- * or a "+FHNG"
- * or a "ERROR" or "NO CARRIER"
- * or until 10 seconds for a response.
- */
-
- t = timerset (1000);
-
- status_line (">FAX Waiting for OK [faxmodem_receive_page]");
-
- while (!timeup (t) && (!response.ok))
- {
- (void) get_faxline (buf, 100, 100);
- status_line ("> Response from peer: %s", buf);
- (void) parse_text_response (buf);
-
- if (response.hangup_code != -1)
- return (PAGE_HANGUP);
-
- if (response.error)
- return (PAGE_ERROR);
- }
-
- if (!response.ok)
- return (PAGE_ERROR);
-
- SENDCHARS ("AT+FDR\r", 7, 1);
- status_line (">FAX AT+FDR [faxmodem_receive_page]");
-
- /* We wait until either a string "CONNECT" is seen
- * or a "+FHNG"
- * or until 10 seconds for a response.
- */
-
- t = timerset (1000);
-
- status_line (">FAX Waiting for CONNECT [faxmodem_receive_page]");
-
- while (!timeup (t))
- {
- (void) get_faxline (buf, 100, 100);
- status_line ("> Response from peer: %s", buf);
- (void) parse_text_response (buf);
-
- if (response.connect == TRUE)
- return (PAGE_GOOD);
-
- if (response.hangup_code != -1)
- return (PAGE_HANGUP);
-
- if (response.error)
- return (PAGE_ERROR);
- }
-
- return (PAGE_ERROR);
- }
-
-