home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1996 October / PCO_10.ISO / filesbbs / bsrc_260.arj / SRC.ZIP / b_faxrcv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-23  |  18.8 KB  |  696 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
  11. /*                                                                          */
  12. /*             This module originally written by Michael Buenter            */
  13. /*       Original UNIX sources Henry Minsky 11/02/90    hqm@ai.mit.edu      */
  14. /*                  BinkleyTerm FAX file reception module                   */
  15. /*                                                                          */
  16. /*                                                                          */
  17. /*    For complete  details  of the licensing restrictions, please refer    */
  18. /*    to the License  agreement,  which  is published in its entirety in    */
  19. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
  20. /*                                                                          */
  21. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  22. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  23. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  24. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  25. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  26. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  27. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  28. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  29. /*                                                                          */
  30. /*                                                                          */
  31. /* You can contact Bit Bucket Software Co. at any one of the following      */
  32. /* addresses:                                                               */
  33. /*                                                                          */
  34. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  35. /* P.O. Box 460398                AlterNet 7:42/1491                        */
  36. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  37. /*                                Internet f491.n343.z1.fidonet.org         */
  38. /*                                                                          */
  39. /* Please feel free to contact us at any time to share your comments about  */
  40. /* our software and/or licensing policies.                                  */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. /* Include this file before any other includes or defines! */
  45.  
  46. #include "includes.h"
  47. #include "faxproto.h"
  48.  
  49. /*--------------------------------------------------------------------------*/
  50. /* Local routines                                                           */
  51. /*--------------------------------------------------------------------------*/
  52.  
  53. static int LOCALFUNC get_fax_file (int);
  54. static int LOCALFUNC read_g3_stream (FILE *, int);
  55. static void LOCALFUNC get_faxline (char *, int, unsigned int);
  56. static void LOCALFUNC init_swaptable (void);
  57. static void LOCALFUNC init_modem_response (void);
  58. static void LOCALFUNC get_modem_result_code (void);
  59. static void LOCALFUNC parse_text_response (char *);
  60.  
  61. static int LOCALFUNC faxmodem_receive_page (int);
  62. static void LOCALFUNC fax_status (char *);
  63.  
  64. /*--------------------------------------------------------------------------*/
  65. /* Private data                                                             */
  66. /*--------------------------------------------------------------------------*/
  67.  
  68. static int gEnd_of_document;
  69. static unsigned char swaptable[256];
  70. static int swaptableinit = FALSE;
  71. static struct faxmodem_response response;
  72.  
  73. static unsigned long faxsize = 0L;
  74.  
  75. /*--------------------------------------------------------------------------*/
  76. /* FAX RECEIVE Routines                                                     */
  77. /*--------------------------------------------------------------------------*/
  78.  
  79. /* receive fax files into basefilename */
  80.  
  81. int 
  82. faxreceive (int zmode)
  83. {
  84.     int result;
  85.     int page;
  86.  
  87.     if (!fax_in)
  88.         return (0);
  89.  
  90.     happy_compiler = zmode;
  91.  
  92.     if (!swaptableinit)
  93.         init_swaptable ();
  94.  
  95.     (void) time (&etm);
  96.  
  97.     if (fax_baud != -1)
  98.     {
  99.         baud = fax_baud;
  100.         cur_baud = pbtypes[baud];
  101.         MDM_ENABLE (cur_baud.rate_mask);
  102.         (void) sprintf (junk, "%-6lu Com%d", cur_baud.rate_value, port_ptr + 1);
  103.         sb_move (settingswin, SET_PORT_ROW, SET_COL);
  104.         sb_puts (settingswin, junk);
  105.     }
  106.  
  107.     do_ready ("FAX Rcv   ");
  108.  
  109.     (void) init_modem_response ();
  110.     gEnd_of_document = FALSE;
  111.     response.fcon = TRUE;                /* we already connected */
  112.  
  113.     result = 0;
  114.  
  115.     for (page = 0; gEnd_of_document == FALSE; page++)
  116.     {
  117.         result = get_fax_file (page);
  118.         status_line (">FAX get_fax_file returns = %d", result);
  119.         switch ((int) result)
  120.         {
  121.         case PAGE_GOOD:
  122.  
  123.             continue;
  124.  
  125.         case PAGE_HANGUP:
  126.  
  127.             status_line (" FAX Received %d pages", page);
  128.             result = 1;
  129.             gEnd_of_document = TRUE;
  130.             break;
  131.  
  132.         default:
  133.  
  134.             status_line (" FAX Error during transmission");
  135.             result = page;
  136.             gEnd_of_document = TRUE;
  137.             break;
  138.         }
  139.     }
  140.  
  141.     set_baud (max_baud.rate_value, 0);
  142.     (void) sprintf (junk, "%-6lu", max_baud.rate_value);
  143.     sb_move (settingswin, SET_PORT_ROW, SET_COL);
  144.     sb_puts (settingswin, junk);
  145.  
  146.     return result;
  147. }
  148.  
  149. /* This executes the +FDR receive page command, and looks for
  150.  * the proper CONNECT response, or, if the document is finished,
  151.  * looks for the FHNG/FHS code.
  152.  *
  153.  * returns:
  154.  *  PAGE_GOOD                no error conditions occured during reception
  155.  *  PAGE_HANGUP              normal end of transmission
  156.  *  PAGE_ERROR               something's wrong
  157.  */
  158.  
  159. static int LOCALFUNC 
  160. get_fax_file (int page)
  161. {
  162.     char buf[256], j[100];
  163.     int result;
  164.     FILE *fp = NULL;
  165.     int opage = page;
  166.  
  167.     status_line (">FAX [get_fax_file]");
  168.  
  169.     do
  170.     {
  171.         if (TaskNumber)
  172.             sprintf (buf, "%sPAGE%02x%02x.FAX", fax_in, (TaskNumber & 0xff), opage++);
  173.         else
  174.             sprintf (buf, "%sPAGE%04x.FAX", fax_in, opage++);
  175.     }
  176.     while (dexists (buf) && (opage < 256));
  177.  
  178.     if (opage == 256)
  179.     {
  180.         status_line ("!FAX Couldn't create output file");
  181.         return (PAGE_ERROR);
  182.     }
  183.  
  184.     if ((result = faxmodem_receive_page (page)) == 0)
  185.     {
  186.         /* filename to create for this page of document */
  187.         if ((fp = fopen (buf, write_binary)) == NULL)
  188.         {
  189.             status_line ("!FAX Couldn't create output file %s", buf);
  190.             return (PAGE_ERROR);
  191.         }
  192.  
  193.         if (!page)
  194.             status_line (" FAX Connect with %s", response.remote_id);
  195.  
  196.         (void) sprintf (j, "%s %s; page %02x", "FAX Rcv", buf, page);
  197.  
  198.         if (un_attended && fullscreen)
  199.         {
  200.             clear_filetransfer ();
  201.             sb_move (filewin, 1, 2);
  202.             sb_puts (filewin, j);
  203.             (void) sprintf (j, " vr%d br%d wd%d ln%d df%d ec%d bf%d st%d",
  204.                 response.T30.vr, response.T30.br, response.T30.wd,
  205.                 response.T30.ln, response.T30.df, response.T30.ec,
  206.                 response.T30.bf, response.T30.st);
  207.             sb_move (filewin, 2, 40);
  208.             sb_puts (filewin, j);
  209.             status_line (j);
  210.             elapse_time ();
  211.         }
  212.         else
  213.         {
  214.             set_xy (j);
  215.             set_xy (NULL);
  216.             locate_x += 2;
  217.         }
  218.  
  219.         result = read_g3_stream (fp, page);
  220.     }
  221.  
  222.     if (fp != NULL)
  223.     {
  224.         fclose (fp);
  225.         if (faxsize <= 256L)
  226.             unlink (buf);
  227.         else
  228.             status_line (" FAX File received %s (%lub)", buf, faxsize);
  229.     }
  230.  
  231.     return (result);
  232. }
  233.  
  234. /* Reads a data stream from the faxmodem, unstuffing DLE characters.
  235.  * Returns the +FET value (2 if no more pages) or 4 if hangup.
  236.  */
  237.  
  238. static int LOCALFUNC 
  239. read_g3_stream (FILE * fp, int page)
  240. {
  241.     register short c;
  242.     char e_input_buf[11];
  243.     unsigned char *secbuf, *p;
  244.     long ltimer = 0L;                        /* MB 94-01-01 */
  245.     int pseudo_carrier;                        /* MB 94-01-01 */ 
  246.  
  247.     status_line (">FAX [read_g3_stream]");
  248.  
  249.     happy_compiler = page;                        /* Make compiler happy      */
  250.     response.post_page_response_code = -1;        /* reset page codes         */
  251.     response.post_page_message_code = -1;
  252.  
  253.     CLEAR_INBOUND ();                        /* flush echoes or return codes */
  254.  
  255.     if ((secbuf = (unsigned char *) calloc (1, 1024)) == NULL)
  256.         goto fax_error;
  257.  
  258.     p = secbuf;
  259.  
  260.     (void) fax_status (ultoa (faxsize, e_input_buf, 10));
  261.  
  262.     pseudo_carrier = !(CARRIER);            /* test if modem sets DCD */
  263.     if (pseudo_carrier)
  264.         status_line (">FAX modem doesn't assert DCD [read_g3_stream]");
  265.  
  266.     status_line (">FAX DC2  [read_g3_stream]");
  267.  
  268.     /* Send DC2 to start phase C data stream */
  269.  
  270.     SENDBYTE ((unsigned char) DC2);    
  271.  
  272.     while (pseudo_carrier || CARRIER)        /* data only when carrier high */
  273.     {
  274.         if (!CHAR_AVAIL ())            /* if nothing ready,*/
  275.         {
  276.             if (pseudo_carrier)        /* MB 94-01-01 */  
  277.             {                        /* process timeout if modem does not   */
  278.                                     /* set DCD, this is only a kludge, but */
  279.                                     /* it could prevent an endless loop    */
  280.                 if (!ltimer)                     
  281.                     ltimer = timerset (1500);    /* 15 secs timeout */
  282.                 else
  283.                 if (timeup(ltimer))
  284.                     goto fax_error;    /* Houston, we lost the downlink   */
  285.             }          
  286.             time_release ();
  287.             continue;                /* process timeouts */
  288.         }
  289.         else
  290.             ltimer = 0L;            /* reset no char waiting timer */
  291.  
  292.         c = MODEM_IN () & 0xff;        /* get a character  */
  293.  
  294.         if (c == DLE)                /* DLE handling     */
  295.         {
  296.             long ltimer2 = 0L;
  297.  
  298.             while (!CHAR_AVAIL ())
  299.             {
  300.                 if (!ltimer2)
  301.                     ltimer2 = timerset (400);
  302.                 else
  303.                 if (timeup (ltimer2))
  304.                 {
  305.                     faxsize = 0L;
  306.                     goto fax_error;        /* give up */
  307.                 }
  308.             }
  309.  
  310.             c = TIMED_READ (0);
  311.  
  312.             if (c == ETX)        /* end of stream */
  313.                 goto end_page;
  314.  
  315.             /* DLE DLE gives DLE. We don't know what to do if it
  316.                isn't ETX (above) or DLE. So we'll just always treat
  317.                DLE (not ETX) as (not ETX). 
  318.  
  319.                Fall out of here into storage. */
  320.         }
  321.  
  322.         *p++ = swaptable[(unsigned char) c];
  323.         faxsize++;
  324.  
  325.         if (!(faxsize % 1024))
  326.         {
  327.             (void) fax_status (ultoa (faxsize, e_input_buf, 10));
  328.             if (fwrite (secbuf, 1, 1024, fp) != 1024)
  329.             {
  330.                 goto fax_error;    /* hoppala */
  331.             }
  332.             p = secbuf;
  333.             time_release ();
  334.         }
  335.     }
  336.  
  337. end_page:
  338.  
  339.     if (faxsize % 1024)
  340.     {
  341.         if (fwrite (secbuf, 1, (size_t) (faxsize % 1024), fp) != (size_t) (faxsize % 1024))
  342.             goto fax_error;        /* hoppala */
  343.         (void) fax_status (ultoa (faxsize, e_input_buf, 10));
  344.     }
  345.  
  346.     free (secbuf);
  347.  
  348.     status_line (">FAX Waiting for +FET/+FHNG  [read_g3_stream]");
  349.     c = 0;
  350.     while (response.post_page_message_code == -1)    /* wait for +FET */
  351.     {
  352.         (void) get_modem_result_code ();
  353.         c++;
  354.         if ((!response.post_page_response_code) || (c > 5) || (response.error))
  355.             return (PAGE_ERROR);
  356.         if (response.hangup_code != -1)
  357.             return (PAGE_HANGUP);
  358.     }
  359.     return (PAGE_GOOD);
  360.  
  361. fax_error:
  362.  
  363.     if (secbuf != NULL)
  364.         free (secbuf);
  365.     status_line ("!FAX Error receiving page");
  366.     (void) get_modem_result_code ();
  367.     return (PAGE_ERROR);
  368. }
  369.  
  370. /*--------------------------------------------------------------------------*/
  371. /* Class 2 Faxmodem Protocol Functions                                      */
  372. /*                                                                          */
  373. /* Taken from EIA Standards Proposal No. 2388: Proposed New Standard        */
  374. /* "Asynchronous Facsimile DCE Control Standard" (if approved,              */
  375. /* to be published as EIA/TIA-592)                                          */
  376. /*--------------------------------------------------------------------------*/
  377.  
  378. /* reads a line of characters, terminated by a newline */
  379.  
  380. static void LOCALFUNC 
  381. get_faxline (char *p, int nbytes, unsigned int wtime)
  382. {
  383.     short c;                    /* current modem character   */
  384.     int count = 1;                /* character count (+null)   */
  385.     long t;
  386.     char *resp;
  387.  
  388.     t = timerset (wtime);
  389.  
  390.     resp = p;
  391.  
  392.     while ((count < nbytes)        /* until we have n bytes,    */
  393.         && (!timeup (t)))        /* or out of time            */
  394.     {
  395.         if (!CHAR_AVAIL ())        /* if nothing ready yet,     */
  396.         {
  397.             time_release ();
  398.             continue;            /* just process timeouts     */
  399.         }
  400.         c = MODEM_IN () & 0xff;    /* get a character           */
  401.         if (c == '\n')
  402.             continue;
  403.         if (c == '\r')
  404.             if (count > 1)
  405.                 break;            /* get out                   */
  406.             else
  407.                 continue;        /* otherwise just keep going */
  408.         *p++ = (char) c;        /* store the character       */
  409.         ++count;                /* increment the counter     */
  410.     }
  411.  
  412.     *p = '\0';                    /* terminate the new string  */
  413.  
  414.     if (debugging_log && (count > 1) && strnicmp (resp, "AT", 2))
  415.         status_line (">FAX %s", resp);    /* pop it on screen  */
  416. }
  417.  
  418. static void LOCALFUNC 
  419. init_swaptable (void)
  420. {
  421.     int i, j;
  422.  
  423.     for (i = 0; i < 256; i++)
  424.     {
  425.         /* swap the low order 4 bits with the high order */
  426.  
  427.         j = (((i & 0x01) << 7) |
  428.             ((i & 0x02) << 5) |
  429.             ((i & 0x04) << 3) |
  430.             ((i & 0x08) << 1) |
  431.             ((i & 0x10) >> 1) |
  432.             ((i & 0x20) >> 3) |
  433.             ((i & 0x40) >> 5) |
  434.             ((i & 0x80) >> 7));
  435.         swaptable[i] = (unsigned char) j;
  436.     }
  437.     swaptableinit = TRUE;
  438. }
  439.  
  440. /****************************************************************
  441.  * Initialize a faxmodem_response struct
  442.  */
  443.  
  444. static void LOCALFUNC 
  445. init_modem_response (void)
  446. {
  447.     response.remote_id[0] = '\0';
  448.     response.fcon = FALSE;
  449.     response.connect = FALSE;
  450.     response.ok = FALSE;
  451.     response.error = FALSE;
  452.     response.hangup_code = -1;
  453.     response.post_page_response_code = -1;
  454.     response.post_page_message_code = -1;
  455.     response.T30.ec = response.T30.bf = 0;
  456. }
  457.  
  458. /* This function parses numeric responses from the faxmodem.
  459.  * It fills in any relevant slots of the faxmodem_response structure.
  460.  */
  461.  
  462. static void LOCALFUNC 
  463. get_modem_result_code (void)
  464. {
  465.     char buf[256];
  466.     long t;
  467.  
  468.     status_line (">FAX [get_modem_result_code]");
  469.  
  470.     t = timerset (400);
  471.  
  472.     while (!timeup (t))
  473.     {
  474.         buf[0] = '\0';
  475.         (void) get_faxline (buf, 255, 100);
  476.         if (buf[0])
  477.         {
  478.             (void) parse_text_response (buf);
  479.             return;
  480.         }
  481.     }
  482.     return;
  483. }
  484.  
  485. static void LOCALFUNC 
  486. fax_status (char *str)
  487. {
  488.     if (fullscreen && un_attended)
  489.     {
  490.         sb_move (filewin, 2, 2);
  491.         sb_puts (filewin, str);
  492.         elapse_time ();
  493.     }
  494.     else
  495.     {
  496.         gotoxy (locate_x, locate_y);
  497.         (void) cputs (str);
  498.     }
  499. }
  500.  
  501. static void LOCALFUNC 
  502. parse_text_response (char *str)
  503. {
  504.     /* Look for +FCON, +FDCS, +FDIS, +FHNG, +FHS, +FPTS, +FK, +FTSI */
  505.  
  506.     if (!strnicmp ("+FCO", str, 4))
  507.     {
  508.         response.fcon = TRUE;
  509.         (void) fax_status ("+FCO      ");
  510.         return;
  511.     }
  512.  
  513.     if (!strnicmp (str, "OK", 2))
  514.     {
  515.         response.ok = TRUE;
  516.         return;
  517.     }
  518.  
  519.     if (!strnicmp (str, "CONNECT", 7))
  520.     {
  521.         response.connect = TRUE;
  522.         return;
  523.     }
  524.  
  525.     if (!strnicmp (str, "NO CARRIER", 10) || !strnicmp (str, "ERROR", 5))
  526.     {
  527.         response.error = TRUE;
  528.         response.hangup_code = 0;
  529.         return;
  530.     }
  531.  
  532.     if (!strnicmp (str, "+FDCS", 5))
  533.     {
  534.         sscanf (str + 6, "%d,%d,%d,%d,%d,%d,%d,%d",
  535.             &response.T30.vr, &response.T30.br, &response.T30.wd,
  536.             &response.T30.ln, &response.T30.df, &response.T30.ec,
  537.             &response.T30.bf, &response.T30.st);
  538.         (void) fax_status ("+FDCS     ");
  539.         return;
  540.     }
  541.  
  542.     if (!strnicmp (str, "+FHNG", 5))
  543.     {
  544.         sscanf (str + 6, "%d", &response.hangup_code);
  545.         (void) fax_status ("+FHNG     ");
  546.         return;
  547.     }
  548.  
  549.     if (!strnicmp (str, "+FPTS", 5))
  550.     {
  551.         sscanf (str + 6, "%d", &response.post_page_response_code);
  552.         (void) fax_status ("+FPTS     ");
  553.         return;
  554.     }
  555.  
  556.     if (!strnicmp (str, "+FTSI", 5))
  557.     {
  558.         (void) strcpy (response.remote_id, str + 6);
  559.         (void) fax_status ("+FTSI     ");
  560.         return;
  561.     }
  562.  
  563.     if (!strnicmp (str, "+FET", 4))
  564.     {
  565.         sscanf (str + 5, "%d", &response.post_page_message_code);
  566.         (void) fax_status ("+FET      ");
  567.         return;
  568.     }
  569.  
  570.     if (!strnicmp (str, "+FHS", 4))    /* Class 2.0 */
  571.     {
  572.         sscanf (str + 5, "%d", &response.hangup_code);
  573.         (void) fax_status ("+FHS      ");
  574.         return;
  575.     }
  576.  
  577.     if (!strnicmp (str, "+FCS", 4))    /* Class 2.0 */
  578.     {
  579.         sscanf (str + 5, "%d,%d,%d,%d,%d,%d,%d,%d",
  580.             &response.T30.vr, &response.T30.br, &response.T30.wd,
  581.             &response.T30.ln, &response.T30.df, &response.T30.ec,
  582.             &response.T30.bf, &response.T30.st);
  583.         (void) fax_status ("+FCS      ");
  584.         return;
  585.     }
  586.  
  587.     if (!strnicmp (str, "+FPS", 4))    /* Class 2.0 */
  588.     {
  589.         sscanf (str + 5, "%d", &response.post_page_response_code);
  590.         (void) fax_status ("+FPS      ");
  591.         return;
  592.     }
  593.  
  594.     if (!strnicmp (str, "+FTI", 4))    /* Class 2.0 */
  595.     {
  596.         (void) strcpy (response.remote_id, str + 5);
  597.         (void) fax_status ("+FTI      ");
  598.         return;
  599.     }
  600.  
  601. }
  602.  
  603. /****************************************************************
  604.  * Action Commands
  605.  */
  606.  
  607. /* Receive a page
  608.  * after receiving OK,
  609.  * send +FDR
  610.  * This is somewhat ugly, because the FDR command can return
  611.  * a couple of possible results;
  612.  * If the connection is valid, it returns something like
  613.  *  +FCFR
  614.  *  +FDCS: <params>
  615.  *  CONNECT
  616.  *
  617.  * If, on the other hand, the other machine has hung up, it returns
  618.  * +FHNG: <code>  or
  619.  * +FHS: <code>
  620.  *
  621.  * and if the connection was never made at all, it returns ERROR (actually numeric
  622.  * code 4)
  623.  *
  624.  * faxmodem_receive_page returns values:
  625.  * PAGE_GOOD     page reception OK, data coming
  626.  * PAGE_HANGUP   normal hangup
  627.  * PAGE_ERROR    page error
  628.  */
  629.  
  630. static int LOCALFUNC 
  631. faxmodem_receive_page (int page)
  632. {
  633.     long t;
  634.     char buf[100];
  635.  
  636.     faxsize = 0L;
  637.     response.connect = response.ok = FALSE;
  638.  
  639.   /* We wait until a string "OK" is seen
  640.    * or a "+FHNG"
  641.    * or a "ERROR" or "NO CARRIER"
  642.    * or until 10 seconds for a response.
  643.    */
  644.  
  645.     t = timerset (1000);
  646.  
  647.     status_line (">FAX Waiting for OK  [faxmodem_receive_page]");
  648.  
  649.     while (!timeup (t) && (!response.ok))
  650.     {
  651.         (void) get_faxline (buf, 100, 100);
  652.         status_line ("> Response from peer: %s", buf);
  653.         (void) parse_text_response (buf);
  654.  
  655.         if (response.hangup_code != -1)
  656.             return (PAGE_HANGUP);
  657.  
  658.         if (response.error)
  659.             return (PAGE_ERROR);
  660.     }
  661.  
  662.     if (!response.ok)
  663.         return (PAGE_ERROR);
  664.  
  665.     SENDCHARS ("AT+FDR\r", 7, 1);
  666.     status_line (">FAX AT+FDR  [faxmodem_receive_page]");
  667.  
  668.     /* We wait until either a string "CONNECT" is seen
  669.     * or a "+FHNG"
  670.     * or until 10 seconds for a response.
  671.     */
  672.  
  673.     t = timerset (1000);
  674.  
  675.     status_line (">FAX Waiting for CONNECT  [faxmodem_receive_page]");
  676.  
  677.     while (!timeup (t))
  678.     {
  679.         (void) get_faxline (buf, 100, 100);
  680.         status_line ("> Response from peer: %s", buf);
  681.         (void) parse_text_response (buf);
  682.  
  683.         if (response.connect == TRUE)
  684.             return (PAGE_GOOD);
  685.  
  686.         if (response.hangup_code != -1)
  687.             return (PAGE_HANGUP);
  688.  
  689.         if (response.error)
  690.             return (PAGE_ERROR);
  691.     }
  692.  
  693.     return (PAGE_ERROR);
  694. }
  695.  
  696.