FAX.CPP
上传用户:xr_qian
上传日期:2007-01-05
资源大小:443k
文件大小:79k
源码类别:

通讯/手机编程

开发平台:

DOS

  1. // ******************************************************************** //
  2. //                                                                      //
  3. //      FAX.CPP                                                         //
  4. //      Copyright (c) 1993, Michael Holmes and Bob Flanders             //
  5. //      C++ Communication Utilities                                     //
  6. //                                                                      //
  7. //      Chapter 7: Facsimile Reception and Transmission                 //
  8. //      Last changed in chapter 7                                       //
  9. //                                                                      //
  10. //      This file contains the functions to implement the Fax class.    //
  11. //      This class contains all of the support for receiving and        //
  12. //      transmitting facsimilies.                                       //
  13. //                                                                      //
  14. // ******************************************************************** //
  15. #define FAX_CLASS1  "AT +FCLASS=1r"        // enter FAX class 1 mode
  16. #define FAX_TX_HDLC "AT +FTH=3r"           // enter HDLC transmit mode
  17. #define FAX_RX_HDLC "AT +FRH=3r"           // enter HDLC recieve mode
  18. #define FAX_TX_DATA "AT +FTM=%dr"          // enter FAX transmit mode
  19. #define FAX_RX_DATA "AT +FRM=%dr"          // enter FAX receive mode
  20. #define FAX_TX_SPD  "AT +FTM=?r"           // get FAX transmit speeds
  21. #define FAX_RX_SPD  "AT +FRM=?r"           // get FAX receive speeds
  22. #define FAX_SILENT  "AT +FRS=8r"           // 80 ms of silence
  23. #define FAX_SILENT1 "AT +FRS=20r"          // 200 ms of silence
  24. #define FAX_CLASS1  "AT +FCLASS=1r"        // enter FAX class 1 mode
  25. #define FAX_MODEM   "AT +FCLASS=0r"        // return to non-FAX mode
  26. #define FAX_ANSWER  "AT Ar"                // answer an incoming call
  27. #define FAX_HANGUP  "AT Hr"                // disconnect from line
  28. #define FAX_DIAL    "AT DT"                 // dial command
  29. #define FAX_OK      "rnOKrn"            // OK response
  30. #define FAX_ERR     "rnERRORrn"         // ERROR response
  31. #define FAX_NO_CARR "rnNO CARRIERrn"    // NO CARRIER response
  32. #define FAX_CONN    "rnCONNECTrn"       // CONNECT response
  33. #define FAX_RING    "rnRINGrn"          // RING message
  34. #define FAX_SETMDM  "AT Q0 V1 E0r"         // set modem parameters
  35. #define FAX_RSTMDM  "AT Zr"                // reset modem
  36. #define FAX_ADDR    0xff                    // value for address byte
  37. #define FAX_CTL     0xC0                    // value for control field
  38. #define FAX_CTL_FF  0xC8                    // control field + final frame
  39. #define FAX_FCF_DIS 0x01                    // digital ID signal
  40. #define FAX_FCF_CSI 0x02                    // called subscriber ID
  41. #define FAX_FCF_NSF 0x04                    // non-standard facilities
  42. #define FAX_FCF_DCS 0xC1                    // digital command signal
  43. #define FAX_FCF_TSI 0xC2                    // transmitting subscriber ID
  44. #define FAX_FCF_CFR 0x21                    // confirmation to receive
  45. #define FAX_FCF_FTT 0x22                    // failure to train
  46. #define FAX_FCF_EOM 0xF1                    // end of message
  47. #define FAX_FCF_MPS 0xF2                    // multipage signal
  48. #define FAX_FCF_EOP 0xF4                    // end of procedure
  49. #define FAX_FCF_MCF 0x31                    // message confirmation
  50. #define FAX_FCF_DCN 0xDF                    // disconnect
  51. #define FINAL       8                       // final frame
  52. #define NON_FINAL   0                       // non-final frame
  53. #define TRANSMIT    0                       // connect in send mode
  54. #define RECEIVE     1                       // connect in receive mode
  55. #define FAX_T9600   0x80                    // 9600 transmit
  56. #define FAX_T7200   0x40                    // 7200 transmit
  57. #define FAX_T4800   0x20                    // 4800 transmit
  58. #define FAX_T2400   0x10                    // 2400 transmit
  59. #define FAX_R9600   0x08                    // 9600 receive
  60. #define FAX_R7200   0x04                    // 7200 receive
  61. #define FAX_R4800   0x02                    // 4800 receive
  62. #define FAX_R2400   0x01                    // 2400 receive
  63. /* ******************************************************************** *
  64.  *
  65.  *  Fax specific variables, structs, etc.
  66.  *
  67.  * ******************************************************************** */
  68. char    dis_msg[] =                         // DIS frame data
  69.           { 0,                              // first byte:
  70.                                             //   not G1, G2
  71.           0x70,                             // second byte:
  72.                                             //   T.4 operation
  73.                                             //   9600/7200/4800/2400 bps
  74.                                             //   3.85 lines/mm
  75.                                             //   one-dimensional coding
  76.           0x02                              // third byte:
  77.           };                                //   1728 pels/215mm
  78.                                             //   A4 paper only
  79.                                             //   40ms receive time
  80. char    dcs_msg[] =                         // DCS frame data
  81.           { 0,                              // first byte:
  82.                                             //   not G1, G2
  83.           0x40,                             // second byte:
  84.                                             //   T.4 operation
  85.                                             //   speed to be set
  86.                                             //   3.85 lines/mm
  87.                                             //   one-dimensional coding
  88.           0x02                              // third byte:
  89.           };                                //   1728 pels/215mm
  90.                                             //   A4 paper only
  91.                                             //   40ms per line
  92. struct HDLC_msg                             // format of HDLC message
  93.     {
  94.     UCHAR   addr;                           // address byte (always 0xff)
  95.     UCHAR   ctl_fld;                        // control field
  96.     UCHAR   fax_ctl_fld;                    // FAX control field (FCF)
  97.     UCHAR   data[253];                      // optional data
  98.     int     len;                            // received frame length
  99.     };
  100. struct FxStat                               // Fax status structure
  101.     {
  102.     void   *f_parm;                         // Fax init parameter
  103.     char   f_msg[50];                       // message string
  104.     char   *f_ptr;                          // pointer to message
  105.     };
  106. struct FxHdr                                // Fax file header structure
  107.     {
  108.     char   ff_type[3];                      // file type (G3)
  109.     char   ff_dcs[16];                      // DCS for transfer
  110.     char   ff_id[21];                       // original station ID
  111.     char   ff_reserved[88];                 // reserved space
  112.     };
  113. /* ******************************************************************** *
  114.  *
  115.  *  Fax class definition
  116.  *
  117.  * ******************************************************************** */
  118. class Fax : Protocol
  119.     {
  120.     public:
  121.         Fax     (Comm *,                    // Fax instance contstructor
  122.                  char *,                    //   Comm instance, station ID
  123.                  int (*)(int,               //   status routine
  124.                          struct FxStat *),
  125.                  void *);                   //   FxStat parameter
  126.                  ~Fax(void);                // destructor
  127.         void     Send(char *, char *),      // send a fax
  128.                  Receive(char *);           // receive a fax
  129.     private:
  130.         Comm    *cp;                        // Comm instance
  131.         int     Send_CSI(void),             // send optional CSI
  132.                 HDLC_Mode(int),             // set HDLC tx|rx mode
  133.                 Data_Mode(int, int),        // set data tx|rx mode
  134.                 Get_Speeds(void),           // get tx and rx speeds
  135.                 Get_Line(char *, int),      // get a CR-terminate line
  136.                 Get_Char(char *, int),      // get a character
  137.                 Rcv_Hmsg(void),             // receive an HDLC frame
  138.                 Send_Our_ID(UCHAR),         // send our ID to remote
  139.                 Send_Hmsg(UCHAR,UCHAR,int), // send an HDLC frame
  140.                 Send_TSI(void),             // send TSI frame to remote
  141.                 Send_DIS(void),             // send DIS frame to remote
  142.                 Send_DCS(void),             // send DCS frame to remote
  143.                 Init_Modem(void),           // initialize modem
  144.                 (*stat)(int,                // status routine pointer
  145.                         struct FxStat *),
  146.                 connected;                  // HDLC link active
  147.         UINT    oldparms,                   // old communications parameters
  148.                 pbi;                        // page buffer index
  149.         long    oldspeed;                   // old commuincations speed
  150.         void    Reverse_Bytes(UCHAR *, int),// reverse bits in char array
  151.                 Display_ID(char *, UCHAR *),// display remote station ID
  152.                 Display_Msg(int),           // display a fax_msgs message
  153.                 Reset_Modem(void);          // reset modem and comm parms
  154.         UCHAR   speeds,                     // speeds supported
  155.                                             // 1... .... 9600 transmit
  156.                                             // .1.. .... 7200
  157.                                             // ..1. .... 4800
  158.                                             // ...1 .... 2400
  159.                                             // .... 1... 9600 receive
  160.                                             // .... .1.. 7200
  161.                                             // .... ..1. 4800
  162.                                             // .... ...1 2400
  163.                *pagebuf,                    // page buffer area
  164.                 Reverse_Byte(UCHAR value);  // reverse bits in a byte
  165.         char   *station;                    // our station id
  166.         struct  FxStat fs;                  // fax status structure
  167.         struct  FxHdr  fh;                  // fax file header structure
  168.         union   {                           // accesss HDLC msg as chars
  169.                 struct  HDLC_msg hmsg;      // HDLC message area
  170.                 UCHAR   cmsg[256];          // .. same as char array
  171.                 };
  172.     };
  173. /* ********************************************************************
  174.  *
  175.  *  Fax -- Fax instance constuctor
  176.  *
  177.  * ********************************************************************/
  178. Fax::Fax(Comm *ci,                          // comm instance
  179.          char *sid,                         // .. our station ID (telno)
  180.          int (*sr)(int, struct FxStat *),   // .. status routine
  181.          void *w)                           // .. fax status parameter
  182. {
  183. cp = ci;                                    // save comm instance pointer
  184. stat = sr;                                  // .. and status routine
  185. station = sid;                              // .. and station ID
  186. connected = 0;                              // no HDLC connection active
  187. fs.f_parm = w;                              // save fax status parameter
  188. strcpy(fh.ff_type, "G3");                   // preset the file type
  189. memset(fh.ff_reserved, ' ',                 // .. and clear reserved area
  190.             sizeof(fh.ff_reserved));
  191. pagebuf = new UCHAR[1024];                  // allocate page buffer
  192. }
  193. /* ********************************************************************
  194.  *
  195.  *  ~Fax -- destructor
  196.  *
  197.  * ********************************************************************/
  198. Fax::~Fax(void)                             // Fax destructor
  199. {
  200. delete pagebuf;                             // free pagebuf memory
  201. }
  202. /* ******************************************************************** *
  203.  *
  204.  *  Init_Modem -- initialize the fax modem
  205.  *
  206.  *  returns: -2 = User pressed ESC
  207.  *           -1 - Timeout
  208.  *            0 = successful; OK response from modem
  209.  *            1 = ERROR response from modem
  210.  *
  211.  * ******************************************************************** */
  212. int Fax::Init_Modem(void)
  213. {
  214. int     rc,                                 // return code
  215.         i;                                  // work counter for loops
  216. char    buf[80],                            // work buffer for speeds
  217.        *c,                                  // work pointer
  218.        *t;                                  // token work pointer
  219. cp->Write("r");                            // send a <CR> to modem
  220. Purge(cp, 2);                               // .. kill any receive messages
  221. oldspeed = cp->GetSpeed();                  // get the old link speed
  222. oldparms = cp->Set8n();                     // .. and old comm parameters
  223.                                             // .. while setting 8,n,1
  224. cp->SetBPS(19200L);                         // set new comm speed
  225. cp->SetBPS(9600L);     // set new comm speed
  226. for (rc = i = 0; (rc == 0) && i++ < 3;)     // try three times
  227.     {
  228.     cp->Write(FAX_SETMDM);                  // set the modem parameters
  229.     rc = wait_for(FAX_OK, FAX_ERR, 2);      // wait for OK response
  230.     }
  231. if (rc < 0)                                 // q. user cancellation?
  232.     return(rc - 1);                         // a. yes .. return error
  233. speeds = 0;                                 // reset speeds supported
  234. cp->Write(FAX_CLASS1);                      // place modem in CLASS 1 mode
  235. rc = wait_for(FAX_OK, FAX_ERR, 5) - 1;      // wait for modem response
  236. if (rc)                                     // q. modem respond ok?
  237.    return(rc);                              // a. no .. tell the caller
  238. cp->Write(FAX_TX_SPD);                      // retrieve transmit speeds
  239. rc = Get_Line(buf, 5);                      // kill the first CR
  240. rc = Get_Line(buf, 5);                      // get the line from the mode
  241. if (rc)                                     // q. any error?
  242.    return(rc);                              // a. yes.. return w/error
  243. Purge(cp, 1);                               // kill additional characters
  244. c = (*buf == 'n') ? buf+1 : buf;           // select start point
  245. while ((t = strtok(c, ",")) != 0)           // while there are tokens
  246.     {
  247.     c = NULL;                               // continue searching buf
  248.     i = atoi(t);                            // get the token's value
  249.     switch(i)                               // for various values..
  250.         {
  251.         case 24:                            // 2400 found
  252.              speeds |= FAX_T2400;           // .. set set the speed flag
  253.              break;
  254.         case 48:                            // 4800 found
  255.              speeds |= FAX_T4800;           // .. set set the speed flag
  256.              break;
  257.         case 72:                            // 7200 found
  258.              speeds |= FAX_T7200;           // .. set set the speed flag
  259.              break;
  260.         case 96:                            // 9600 found
  261.              speeds |= FAX_T9600;           // .. set set the speed flag
  262.              break;
  263.         }
  264.     }
  265. cp->Write(FAX_RX_SPD);                      // retrieve receive speeds
  266. rc = Get_Line(buf, 5);                      // kill the first CR
  267. rc = Get_Line(buf, 5);                      // get the line from the modem
  268. if (rc)                                     // q. any error?
  269.    return(rc);                              // a. yes.. return w/error
  270. Purge(cp, 1);                               // kill additional characters
  271. c = (*buf == 'n') ? buf+1 : buf;           // select start point
  272. while ((t = strtok(c, ",")) != 0)           // while there are tokens
  273.     {
  274.     c = NULL;                               // continue searching buf
  275.     i = atoi(t);                            // get the token's value
  276.     switch(i)                               // for various values..
  277.         {
  278.         case 24:                            // 2400 found
  279.              speeds |= FAX_R2400;           // .. set set the speed flag
  280.              break;
  281.         case 48:                            // 4800 found
  282.              speeds |= FAX_R4800;           // .. set set the speed flag
  283.              break;
  284.         case 72:                            // 7200 found
  285.              speeds |= FAX_R7200;           // .. set set the speed flag
  286.              break;
  287.         case 96:                            // 9600 found
  288.              speeds |= FAX_R9600;           // .. set set the speed flag
  289.              break;
  290.         }
  291.     }
  292. return(0);                                  // return ok
  293. }
  294. /* ******************************************************************** *
  295.  *
  296.  *  Reset_Modem -- reset modem and communications parameters
  297.  *
  298.  * ******************************************************************** */
  299. void Fax::Reset_Modem(void)
  300. {
  301. int     rc;                                 // return code
  302. cp->Write("r");                            // send a <CR> to modem
  303. cp->DTR();                                  // lower DTR
  304. Purge(cp, 1);                               // .. kill any receive messages
  305. cp->SetBPS(oldspeed);                       // reset the comm speed
  306. cp->SetLine(oldparms);                      // .. and the comm parms
  307. cp->Write(FAX_RSTMDM);                      // try to reset the modem
  308. switch (rc = wait_for(FAX_OK, FAX_ERR, 2))  // based on response
  309.     {
  310.     case -1:                                // user pressed escape
  311.         return;                             // .. return without message
  312.     case 0:                                 // time out
  313.     case 1:                                 // received OK
  314.     case 2:                                 // received ERROR
  315.         Display_Msg(37+rc);                 // display appropriate message
  316.     }
  317. }
  318. /* ******************************************************************** *
  319.  *
  320.  *  Send_Our_ID -- send our ID to the other station
  321.  *
  322.  *  returns: -2 = User pressed ESC
  323.  *           -1 - Timeout
  324.  *            0 = successful; CONNECT response from modem
  325.  *            1 = NO CARRIER response from modem
  326.  *
  327.  * ******************************************************************** */
  328. int Fax::Send_Our_ID(UCHAR ctl_byte)        // FAX control field
  329. {
  330. int     i, j;                               // work variables
  331. UCHAR  *ch;                                 // work pointer
  332. ch = hmsg.data;                             // get the data address
  333. for (i = 0; i < 20; ch[i++] = 0x04);        // set to 'reversed' blanks
  334. if (station != NULL)                        // q. station ID set?
  335.     {                                       // a. yes ..
  336.     i = strlen(station);                    // get station ID length
  337.     i = i > 20 ? 20 : i;                    // max ID length = 20
  338.     for (j = 0; i--;)                       // for each char in station ID
  339.         {
  340.         if (strchr("0123456789+ ",          // q. valid ID character?
  341.                        station[i]) != 0)
  342.             ch[j++] =                       // a. yes.. reverse & copy it
  343.                    Reverse_Byte(station[i]);
  344.         }
  345.     }
  346. return(Send_Hmsg(NON_FINAL, ctl_byte, 20)); // send the HDLC message
  347. }
  348. /* ******************************************************************** *
  349.  *
  350.  *  Display_ID -- display remote station ID
  351.  *
  352.  * ******************************************************************** */
  353. void Fax::Display_ID(char *pf,              // prefix
  354.                     UCHAR *id)              // id string
  355. {
  356. char    cw[21];                             // work area
  357. int     i, j;                               // work variables
  358. for (i = 20; i--;)                          // backscan the ID
  359.     if (id[i] != ' ')                       // q. blank?
  360.         break;                              // a. no .. get out now
  361. if (i++ == -1)                              // q. ID found?
  362.    return;                                  // a. no .. leave now
  363. for (j = 0; i--; cw[j++] = id[i]);          // copy the ID in reverse
  364. cw[j] = 0;                                  // .. and end the string
  365. sprintf(fs.f_msg, "%s %srn", pf, cw);     // put message in buffer
  366. (stat)(1, &fs);                             // .. and display it
  367. }
  368. /* ******************************************************************** *
  369.  *
  370.  *  Rcv_Hmsg -- receive an HDLC frame
  371.  *
  372.  *  returns: -2 = User pressed ESC
  373.  *           -1 - Timeout
  374.  *            0 = successfully received
  375.  *            1 = NO CARRIER or error
  376.  *
  377.  * ******************************************************************** */
  378. int Fax::Rcv_Hmsg(void)
  379. {
  380. int     rc,                                 // return code
  381.         loop = 1,                           // loop until finished
  382.         dleflag = FALSE;                    // dle not seen yet
  383. char    *nxtchar,                           // next receive address
  384.         wc;                                 // work for char reads
  385. long    timer;                              // workspace for timer
  386. hmsg.len = 0;                               // initialize length
  387. nxtchar = (char *) cmsg;                    // .. and next receive pointer
  388. if ((rc = HDLC_Mode(RECEIVE)) != 0)         // q. connect ok?
  389.    return(rc);                              // a. no .. leave w/error
  390. timer = SECS(5);                            // start 5 second timer
  391. while(loop)                                 // enter a loop ..
  392.     switch(cp->Read(nxtchar, &wc, &wc))     // attempting to read bytes
  393.         {
  394.         case -1:                            // no character available
  395.             if (TimeOut(&timer))            // q. timeout?
  396.                 return(-1);                 // a. yes.. tell the caller
  397.             if ((stat)(0, &fs))             // q. user press escape?
  398.                 return(-2);                 // a. yes.. tell the caller
  399.             continue;                       // else .. continue loop
  400.         case 0:                             // character received
  401.             hmsg.len++;                     // increment received count
  402.             if (dleflag)                    // q. previous char DLE?
  403.                {                            // a. yes ..
  404.                dleflag = FALSE;             // .. reset the flag
  405.                if (*nxtchar == ETX)         // q. DLE ETX sequence?
  406.                    loop = 0;                // a. yes .. exit the loop
  407.                }
  408.             else if (*nxtchar == DLE)       // q. char a DLE?
  409.                dleflag = TRUE;              // a. yes .. show true
  410.             nxtchar++;                      // point at next character
  411.             break;                          // end this case
  412.         default:                            // lost characters
  413.             return(1);                      // .. show receive unsuccessful
  414.         }
  415. rc = wait_for(FAX_OK, FAX_ERR, 5) - 1;      // OK should follow message
  416. Reverse_Bytes(cmsg, hmsg.len - 2);          // reverse the bits
  417. return(rc);                                 // return to caller
  418. }
  419. /* ******************************************************************** *
  420.  *
  421.  *  Send_Hmsg -- send an HDLC frame
  422.  *
  423.  *  returns: -2 = User pressed ESC
  424.  *           -1 - Timeout
  425.  *            0 = successful; CONNECT response from modem
  426.  *            1 = NO CARRIER response from modem
  427.  *
  428.  * ******************************************************************** */
  429. int Fax::Send_Hmsg(UCHAR finalflg,          // final flag
  430.                    UCHAR ctl_byte,          // fax control field
  431.                    int   len)               // length of data bytes
  432. {
  433. int     rc;                                 // return code
  434. hmsg.addr        = FAX_ADDR;                // set the address field
  435. hmsg.ctl_fld     = FAX_CTL | finalflg;      // .. and the control field
  436. hmsg.fax_ctl_fld = ctl_byte;                // .. and fax control field
  437. hmsg.data[len]   = DLE;                     // .. add DLE
  438. hmsg.data[len+1] = ETX;                     // .. and ETX
  439. Reverse_Bytes(cmsg, len+3);                 // reverse the bits
  440. if (NOT connected)                          // q. connected already?
  441.    {                                        // a. no .. connect now
  442.    rc = HDLC_Mode(TRANSMIT);                // attempt the connection
  443.    if (rc)                                  // q. connect ok?
  444.       return(rc);                           // a. no .. leave w/error
  445.    connected = TRUE;                        // else .. show connected.
  446.    }
  447. cp->Write((char *) cmsg, len+5);            // send to remote
  448. if (finalflg)                               // q. final flag on?
  449.    {                                        // a. yes ..
  450.    rc = wait_for(FAX_OK, FAX_ERR, 5) - 1;   // .. wait for OK
  451.    connected = FALSE;                       // .. and we're not connected
  452.    }
  453.  else
  454.    rc = wait_for(FAX_CONN,                  // else .. wait for CONNECT
  455.                  FAX_NO_CARR, 60) - 1;      // .. or NO CARRIER
  456. return(rc);                                 // return to caller
  457. }
  458. /* ******************************************************************** *
  459.  *
  460.  *  Send_CSI -- Send the called subscriber ID signal to caller
  461.  *
  462.  *  returns: -2 = User pressed ESC
  463.  *           -1 - Timeout
  464.  *            0 = successful; CONNECT response from modem
  465.  *            1 = NO CARRIER response from modem
  466.  *
  467.  * ******************************************************************** */
  468. int Fax::Send_CSI(void)
  469. {
  470. return(Send_Our_ID(FAX_FCF_CSI));           // send CSI frame to caller
  471. }
  472. /* ******************************************************************** *
  473.  *
  474.  *  Send_TSI -- Send the transmitting subscriber ID signal
  475.  *
  476.  *  returns: -2 = User pressed ESC
  477.  *           -1 - Timeout
  478.  *            0 = successful
  479.  *            1 = unsuccessful
  480.  *
  481.  * ******************************************************************** */
  482. int Fax::Send_TSI(void)
  483. {
  484. return(Send_Our_ID(FAX_FCF_TSI));           // send TSI frame
  485. }
  486. /* ******************************************************************** *
  487.  *
  488.  *  Send_DIS -- Send the digital ID signal to caller
  489.  *
  490.  *  returns: -2 = User pressed ESC
  491.  *           -1 - Timeout
  492.  *            0 = successful
  493.  *            1 = unsuccesful
  494.  *
  495.  * ******************************************************************** */
  496. int Fax::Send_DIS(void)
  497. {
  498. int     i;                                  // work variable
  499. for (i = 3; i--; hmsg.data[i] = dis_msg[i]);// copy the DIS to hmsg.data
  500. return(Send_Hmsg(FINAL, FAX_FCF_DIS, 3));   // send the DIS
  501. }
  502. /* ******************************************************************** *
  503.  *
  504.  *  Send_DCS -- Send the digital control signal to called station
  505.  *
  506.  *  returns: -2 = User pressed ESC
  507.  *           -1 - Timeout
  508.  *            0 = successful
  509.  *            1 = unsuccesful
  510.  *
  511.  * ******************************************************************** */
  512. int Fax::Send_DCS(void)
  513. {
  514. int     i;                                  // work variable
  515. for (i = 3; i--; hmsg.data[i] = dcs_msg[i]);// copy the DCS to hmsg.data
  516. return(Send_Hmsg(FINAL, FAX_FCF_DCS, 3));   // send the DCS
  517. }
  518. /* ******************************************************************** *
  519.  *
  520.  *  HDLC_Mode -- Enter HDLC mode (transmit or receive)
  521.  *
  522.  *  returns: -2 = User pressed ESC
  523.  *           -1 - Timeout
  524.  *            0 = successful; CONNECT response from modem
  525.  *            1 = ERROR response from modem
  526.  *
  527.  * ******************************************************************** */
  528. int Fax::HDLC_Mode(int dir)                 // setup for HDLC tx or rx
  529.                                             // 0 = transmit, 1 = receive
  530. {
  531. int rc;                                     // return code
  532. if ((dir == TRANSMIT) && NOT connected)     // q. we transmitting?
  533.     {                                       // a. yes ..
  534.     cp->Write(FAX_SILENT);                  // .. request 80ms silence
  535.     rc = wait_for(FAX_OK,                   // wait for response
  536.                   FAX_ERR, 5) - 1;
  537.     if (rc)                                 // q. any problems?
  538.         return(rc);                         // a. yes .. return the error
  539.     }
  540. else if (connected)                         // q. connected already?
  541.     {                                       // a. yes ..
  542.     connected = FALSE;                      // .. reset connect status
  543.     return(0);                              // .. and return ok
  544.     }
  545. cp->Write(dir ? FAX_RX_HDLC : FAX_TX_HDLC); // start requested HDLC mode
  546. rc = wait_for(FAX_CONN, FAX_NO_CARR, 60)-1; // see if we connect
  547. return(rc);                                 // return to caller
  548. }
  549. /* ******************************************************************** *
  550.  *
  551.  *  Data_Mode() -- Enter Fax Data mode (transmit or receive)
  552.  *
  553.  *  returns: -2 = User pressed ESC
  554.  *           -1 - Timeout
  555.  *            0 = successful; CONNECT response from modem
  556.  *            1 = NO CARRIER response from modem
  557.  *
  558.  * ******************************************************************** */
  559. int Fax::Data_Mode(int dir,                 // 0 = transmit, 1 = receive
  560.                    int speed)               // speed for transfer
  561. {
  562. int rc;                                     // return code
  563. char    msg[20];                            // work area for message
  564. if ((dir == TRANSMIT) && NOT connected)     // q. we transmitting?
  565.     {                                       // a. yes ..
  566.     cp->Write(FAX_SILENT);                  // .. request 80ms silence
  567.     rc = wait_for(FAX_OK,                   // wait for response
  568.                   FAX_ERR, 5) - 1;
  569.     if (rc)                                 // q. any problems?
  570.         return(rc);                         // a. yes .. return the error
  571.     }
  572. sprintf(msg,                                // in message area ..
  573.         dir ? FAX_RX_DATA : FAX_TX_DATA,    // .. select direction of xfer
  574.         speed);                             // .. and build message
  575. cp->Write(msg);                             // write to modem
  576. rc = wait_for(FAX_CONN, FAX_NO_CARR, 60)-1; // see if we connect
  577. return(rc);                                 // return to caller
  578. }
  579. /* ******************************************************************** *
  580.  *
  581.  *  Get_Line -- retrieve a CR-terminated line of information
  582.  *
  583.  *  returns: -2 = User pressed ESC
  584.  *           -1 - Timeout
  585.  *            0 = successful
  586.  *            1 = data overrun
  587.  *
  588.  * ******************************************************************** */
  589. int Fax::Get_Line(char *buf,                // buffer to contain info
  590.                   int  secs)                // length of timeout
  591. {
  592. int     loop = TRUE;                        // loop condition
  593. char    wc;                                 // work for msr, lsr
  594. long    timer;                              // timer value
  595. timer = SECS(secs);                         // initialize timer
  596. while(loop)                                 // for as long as necessary ..
  597.     {
  598.     switch(cp->Read(buf, &wc, &wc))         // attempting to read a byte
  599.         {
  600.         case -1:                            // no character available
  601.             if (TimeOut(&timer))            // q. timeout?
  602.                 return(-1);                 // a. yes.. tell the caller
  603.             if ((stat)(0, &fs))             // q. user press escape?
  604.                 return(-2);                 // a. yes.. tell the caller
  605.             continue;                       // else .. continue loop
  606.         case 0:                             // character received
  607.             if (*buf == 'r')               // q. character a CR?
  608.                {                            // a. yes ..
  609.                *buf = 0;                    // .. null it out
  610.                loop = FALSE;                // .. and end the loop
  611.                }
  612.             else                            // else ..
  613.                buf++;                       // .. point to next char position
  614.             break;                          // end this case
  615.         default:                            // lost characters
  616.             return(1);                      // .. show receive unsuccessful
  617.         }
  618.     }
  619. return(0);                                  // show we finished ok
  620. }
  621. /* ******************************************************************** *
  622.  *
  623.  *  Get_Char -- retrieve a single character
  624.  *
  625.  *  returns: -2 = User pressed ESC
  626.  *           -1 - Timeout
  627.  *            0 = successful
  628.  *            1 = data overrun
  629.  *
  630.  * ******************************************************************** */
  631. int Fax::Get_Char(char *c,                  // character to retrieve
  632.                   int  secs)                // length of timeout
  633. {
  634. int     loop = TRUE;                        // loop condition
  635. char    wc;                                 // work for msr, lsr
  636. long    timer;                              // timer value
  637. timer = SECS(secs);                         // initialize timer
  638. while(loop)                                 // for as long as necessary ..
  639.     {
  640.     switch(cp->Read(c, &wc, &wc))           // attempting to read a byte
  641.         {
  642.         case -1:                            // no character available
  643.             if (TimeOut(&timer))            // q. timeout?
  644.                 return(-1);                 // a. yes.. tell the caller
  645.             if ((stat)(0, &fs))             // q. user press escape?
  646.                 return(-2);                 // a. yes.. tell the caller
  647.             continue;                       // else .. continue loop
  648.         case 0:                             // character received
  649.             loop = FALSE;                   // .. end the loop
  650.             break;
  651.         default:                            // lost characters
  652.             return(1);                      // .. show receive unsuccessful
  653.         }
  654.     }
  655. return(0);                                  // show we finished ok
  656. }
  657. /* ******************************************************************** *
  658.  *
  659.  *  Display_Msg -- display a message without parameters
  660.  *
  661.  * ******************************************************************** */
  662. void Fax::Display_Msg(int msgno)
  663. {
  664. fs.f_ptr = fax_msgs[msgno];                 // set the address
  665. (stat)(2, &fs);                             // display the message
  666. }
  667. /* ******************************************************************** *
  668.  *
  669.  *  Reverse_Byte() -- Reverse the bits in a byte
  670.  *
  671.  * ******************************************************************** */
  672. UCHAR Fax::Reverse_Byte(UCHAR value)        // byte to reverse
  673. {
  674. __asm  mov cx, 8                            // cx = bits to shift
  675. __asm  mov al, value                        // al = starting value
  676. top_loop:                                   // top of reverse loop
  677. __asm  shl  ah, 1                           // shift ah up by one
  678. __asm  shr  al, 1                           // shift out a bit
  679. __asm  adc  ah, 0                           // .. add carry into ah
  680. __asm  loop top_loop                        // .. until all bits moved
  681. __asm  mov  value, ah                       // save reversed value
  682. return(value);                              // .. and return it
  683. }
  684. /* ******************************************************************** *
  685.  *
  686.  *  Reverse_Bytes -- reverse the bits in the bytes of a string
  687.  *
  688.  * ******************************************************************** */
  689. void Fax::Reverse_Bytes(UCHAR *str,         // string to reverse
  690.                         int    len)         // length of string
  691. {
  692. while(len--)                                // while there are bytes..
  693.      {
  694.      *str = Reverse_Byte(*str);             // .. reverse the bits
  695.      str++;                                 // .. next byte
  696.      }
  697. }
  698. /* ********************************************************************
  699.  *
  700.  *  Receive -- Receive a Facsimile transmission
  701.  *
  702.  * ******************************************************************** */
  703. void Fax::Receive(char *faxname)
  704. {
  705. int     rc = 0,                             // return code
  706.         speed,                              // link speed
  707.         fileopen = FALSE,                   // receive file not open
  708.         dcs_received = FALSE,               // DCS not yet received
  709.         i,                                  // work variable
  710.         error = 0,                          // error number
  711.         dleflag = FALSE,                    // DLE sequence found flag
  712.         loop = TRUE;                        // loop until complete
  713. FILE   *faxfile;                            // fax file
  714. char    c;                                  // work character
  715. ULONG   pagelen,                            // length of received page
  716.         reclen,                             // offset of page record length
  717.         et,                                 // elapsed time
  718.         st;                                 // work for timer
  719. enum    RcvStates                           // FAX receive states
  720.           {
  721.           PhaseA,                           // phase A - make connection
  722.           AwaitCall,                        // wait for a call
  723.           AnswerCall,                       // answer incoming call
  724.           SendCSI,                          // send our CSI frame, if needed
  725.           PhaseB,                           // negotiate session parameters
  726.           GetFrames,                        // get HDLC frames
  727.           SetSpeed,                         // set the link speed
  728.           PrepTCF,                          // prepare to receive TCF
  729.           FailConnTCF,                      // fail the TCF connect
  730.           RcvTCF,                           // receive/test TCF
  731.           RcvTCF1,                          // get rest of TCF
  732.           FailTCF,                          // fail the TCF
  733.           Confirm,                          // confirm training check frame
  734.           PhaseC,                           // receive the FAX data
  735.           RcvPage,                          // receive 1 page of data
  736.           EndPage,                          // page complete
  737.           PhaseD,                           // post message procedure
  738.           PhaseE,                           // call is done .. disconnect
  739.           RcvError,                         // error during receive
  740.           UserCan,                          // user cancelled transmission
  741.           ExitFax                           // exit FAX receive
  742.           } state;
  743. strcpy(fh.ff_id, "                    ");   // blank out the ID string
  744. state = PhaseA;                             // start in Phase A
  745. if ((faxfile = fopen(faxname, "wb+"))       // q. receive file open ok?
  746.                     == NULL)
  747.      {                                      // a. no ..
  748.      error = 9;                             // .. set the error code
  749.      state = RcvError;                      // .. and declare an error
  750.      }
  751. fileopen = TRUE;                            // show the file is open
  752. while(loop)                                 // top of state machine
  753.   switch(state)                             // perform next state
  754.     {
  755.     case PhaseA:                            // phase A - make connection
  756.          Display_Msg(1);                    // update the status
  757.          if ((rc = Init_Modem()) != 0)      // q. modem init ok?
  758.              {
  759.              error = 1;                     // a. no .. exit now
  760.              state = RcvError;              // .. declare the error
  761.              continue;
  762.              }
  763.          state = AwaitCall;                 // else .. wait for a ring
  764.          Display_Msg(2);                    // update the status
  765.          break;                             // end this state
  766.     case AwaitCall:                         // wait for a call
  767.          rc = wait_for(FAX_RING,            // wait for a RING from modem
  768.                        FAX_RING, 10);
  769.          if (rc > 0)                        // q. RING arrive?
  770.              {                              // a. yes ..
  771.              state = AnswerCall;            // .. go answer the call
  772.              continue;
  773.              }
  774.          if (rc == -1)                      // q. user press ESC?
  775.             state = UserCan;                // a. yes .. exit now
  776.          break;                             // else .. continue waiting
  777.     case AnswerCall:                        // answer incoming call
  778.          Display_Msg(3);                    // update the status
  779.          cp->Write(FAX_ANSWER);             // send the answer command
  780.          rc = wait_for(FAX_CONN,            // wait for a carrier
  781.                        FAX_NO_CARR, 60);
  782.          if (--rc == 0)                     // q. connect?
  783.              {
  784.              state = SendCSI;               // a. yes .. send our CSI
  785.              connected = TRUE;              // .. show we're connected
  786.              }
  787.          else                               // else ..
  788.              {
  789.              state = RcvError;              // .. process general error
  790.              error = 2;                     // .. show the error type
  791.              }
  792.          break;                             // .. next state
  793.     case SendCSI:                           // send our CSI frame
  794.          Display_Msg(4);                    // update the status
  795.          rc = Send_CSI();                   // .. send our ID
  796.          if (rc)                            // q. error?
  797.              state = RcvError;              // a. yes .. declare the error
  798.          else
  799.              state = PhaseB;                // select next state
  800.          break;
  801.     case PhaseB:                            // negotiate session parameters
  802.          Display_Msg(5);                    //
  803.          state = ((rc = Send_DIS()) != 0) ? // q. DIS send go ok?
  804.                                  RcvError : // a. no .. declare error
  805.                                  GetFrames; // else .. get frames
  806.          break;
  807.     case GetFrames:                         // get HDLC frames
  808.          if ((rc = Rcv_Hmsg()) != 0)        // q. any error getting a frame?
  809.              if (rc < 0)                    // a. yes .. timeout or ESC?
  810.                  {                          // a. yes ..
  811.                  error = 3;                 // .. error receiving HDLC frame
  812.                  state = RcvError;          // .. leave with error.
  813.                  continue;                  // .. continue process
  814.                  }
  815. //           else                           // else .. NO CARRIER
  816. //               {
  817. //               cp->Write(FAX_SILENT1);    // wait for 200ms silence
  818. //
  819. //               rc = wait_for(FAX_OK,      // wait for the OK response
  820. //                             FAX_ERR,
  821. //                             10) - 1;
  822. //
  823. //               state = SetSpeed;          // .. and set the speed
  824. //               }
  825.          if (rc)                            // q. any error yet?
  826.              {                              // a. yes ..
  827.              state = RcvError;              // .. declare an error
  828.              continue;
  829.              }
  830.          switch(hmsg.fax_ctl_fld)           // process based on message type
  831.              {
  832.              case FAX_FCF_TSI:              // transmitting subscriber ID
  833.                 Display_Msg(6);             // update the status
  834.                 Reverse_Bytes(hmsg.data,    // .. reset the bytes to normal
  835.                                      20);
  836.                 hmsg.data[20] = 0;          // .. end string in zero
  837.                 strcpy((char *) fh.ff_id,   // .. copy it to file header
  838.                        (char *) hmsg.data);
  839.                 Display_ID("Called by:",    // .. and display the remote ID
  840.                                 hmsg.data);
  841.                 break;
  842.             case FAX_FCF_DCN:               // disconnect
  843.                 Display_Msg(16);            // update the status
  844.                 state = PhaseE;             // .. and hang up
  845.                 continue;
  846.              case FAX_FCF_DCS:              // digital command signal
  847.                 Display_Msg(7);             // update the status
  848.                 memcpy(fh.ff_dcs, hmsg.data,// .. move the DCS to the header
  849.                           hmsg.len - 7);
  850.                 dcs_received = 1;           // show we got DCS
  851.                 break;
  852.              }
  853.          if (hmsg.ctl_fld == FAX_CTL_FF)    // q. final frame?
  854.              {                              // a. yes ..
  855.              state = SetSpeed;              // .. set link speed
  856.              fseek(faxfile, 0L, SEEK_SET);  // go to start of file
  857.              fwrite(&fh, 128, 1, faxfile);  // .. and write the header
  858.              }
  859.          break;
  860.     case SetSpeed:                          // set the link speed
  861.          if (dcs_received == 0)             // q. dcs received?
  862.              {                              // a. no ..
  863.              error = 4;                     // .. show the error
  864.              state = RcvError;              // .. and go to error state
  865.              continue;                      // .. continue with next state
  866.              }
  867.          switch (fh.ff_dcs[1] & 0x30)       // get modulation value
  868.              {
  869.              case 0x00:                     // q. speed 2400?
  870.                  speed = 24;                // a. yes . set speed
  871.                  i = 44;                    // .. and message
  872.                  break;
  873.              case 0x10:                     // q. speed 4800?
  874.                  speed = 48;                // a. yes .. set speed
  875.                  i = 43;                    // .. and message
  876.                  break;
  877.              case 0x30:                     // q. speed 7200?
  878.                  speed = 72;                // a. yes .. set speed
  879.                  i = 42;                    // .. and message
  880.                  break;
  881.              case 0x20:                     // q. speed 9600?
  882.                  speed = 96;                // a. yes .. set speed
  883.                  i = 41;                    // .. and message
  884.                  break;
  885.              }
  886.          Display_Msg(i);                    // display speed message
  887.          state = PrepTCF;                   // next, prepare to test link
  888.          break;
  889.     case PrepTCF:                           // prepare to receive TCF
  890.          rc = Data_Mode(RECEIVE, speed);    // start the receive
  891.          if (rc == 1)                       // q. did connection fail?
  892.              state = FailConnTCF;           // a. yes.. fail TCF connect
  893.          else if (rc != 0)                  // q. other failure?
  894.              state = RcvError;              // a. yes .. declare an error
  895.          else
  896.              {
  897.              state = RcvTCF;                // receive training check frame
  898.              Display_Msg(9);                // update the status
  899.              }
  900.          break;
  901.     case FailConnTCF:                       // fail the TCF connect
  902.          rc = Send_Hmsg(FINAL,              // send failure to train
  903.                         FAX_FCF_FTT, 0);
  904.          if (rc)                            // q. retrain send fail?
  905.              state = RcvError;              // a. yes .. declare an error
  906.          else
  907.              state = GetFrames;             // get a new set of frames
  908.          break;
  909.     case RcvTCF:                            // receive/test TCF
  910.          rc = Get_Char(&c, 5);              // wait a max of 5 secs for data
  911.          if (rc != 0)                       // q. any error
  912.             {                               // a. yes ..
  913.             state = RcvError;               // .. declare an error
  914.             continue;                       // .. and continue processing
  915.             }
  916.          if ((UCHAR) c == 0)                // q. zero byte?
  917.             state = RcvTCF1;                // a. yes .. receive the rest
  918.          break;
  919.     case RcvTCF1:                           // get rest of TCF
  920.          st = get_time();                   // get time of day in ticks
  921.          for(;;)                            // get characters
  922.              {
  923.              rc = Get_Char(&c, 1);          // get a character
  924.              if (rc != 0)                   // q. any error?
  925.                  {                          // a. yes ..
  926.                  Purge(cp, 1);              // .. purge the comm line
  927.                  error = 7;                 // .. TCF too short
  928.                  state = RcvError;          // .. declare an error
  929.                  break;                     // .. and exit loop
  930.                  }
  931.              if (c != 0)                    // q. end of sequence?
  932.                  break;                     // a. yes .. exit loop
  933.              }
  934.          if (rc != 0)                       // q. was there an error?
  935.              continue;                      // a. yes .. continue process
  936.          et = elapsed_time(st);             // calculate elapsed time
  937.          if ((et < 24) || (et > 31))        // q. 1.5 seconds +/- 10%?
  938.              {                              // a. yes ..
  939.              Purge(cp, 1);                  // .. purge the comm line
  940.              state = FailTCF;               // .. declare train failure
  941.              continue;                      // .. and continue loop
  942.              }
  943.          rc = wait_for(FAX_NO_CARR,         // wait for no carrier
  944.                        FAX_ERR, 5) - 1;     // .. or other information
  945.          if (rc != 0)                       // q. NO CARRIER received?
  946.              {                              // a. no ..
  947.              state = RcvError;              // .. declare receieve error
  948.              continue;                      // .. and continue loop
  949.              }
  950.          state = Confirm;                   // else .. confirm TCF
  951.          break;                             // .. and continue processing
  952.     case FailTCF:                           // fail the TCF
  953.          Display_Msg(19);                   // update the status
  954.          rc = Send_Hmsg(FINAL,              // send failure to train
  955.                         FAX_FCF_FTT, 0);
  956.          if (rc)                            // q. retrain send fail?
  957.              state = RcvError;              // .. declare an error
  958.          else
  959.              state = GetFrames;             // get a new set of frames
  960.          break;
  961.     case Confirm:                           // confirm training check frame
  962.          Display_Msg(10);                   // update the status
  963.          rc = Send_Hmsg(FINAL,              // send the confirmation
  964.                         FAX_FCF_CFR, 0);
  965.          if (rc != 0)                       // q. confirmation go ok?
  966.             {
  967.             state = RcvError;               // a. no .. show the error
  968.             continue;                       // .. continue processing
  969.             }
  970.          state = PhaseC;                    // start receiving FAX
  971.          break;
  972.     case PhaseC:                            // receive the FAX data
  973.          rc = Data_Mode(RECEIVE, speed);    // start receiving the FAX
  974.          if (rc != 0)                       // q. receive start ok?
  975.             {
  976.             state = RcvError;               // a. no .. show the error
  977.             continue;                       // .. continue processing
  978.             }
  979.          Display_Msg(11);                   // update the status
  980.          state = RcvPage;                   // receive a page of data
  981.          dleflag = FALSE;                   // set no DLE seen yet
  982.          pbi = 0;                           // reset  the page buffer index
  983.          pagelen = 0;                       // .. and no page data yet
  984.          fseek(faxfile, 0L, SEEK_END);      // go to end of file
  985.          reclen = ftell(faxfile);           // .. save the position
  986.          fwrite(&pagelen, 4, 1, faxfile);   // .. write the page's length
  987.          break;
  988.     case RcvPage:                           // receive 1 page of data
  989.          rc = Get_Char(&c, 1);              // get a character
  990.          if (rc != 0)                       // q. receive ok?
  991.              {                              // a. no ..
  992.              state = RcvError;              // .. declare an error
  993.              continue;                      // .. and continue processing
  994.              }
  995.          pagebuf[pbi++] = c;                // save the character
  996.          pagelen++;                         // increment bytes in page
  997.          if (pbi == 1024)                   // q. buffer full?
  998.              {                              // a. yes ..
  999.              fwrite(pagebuf, 1024, 1,       // .. write out a page
  1000.                        faxfile);
  1001.              pbi = 0;                       // reset page buffer index
  1002.              }
  1003.          if (dleflag)                       // q. previous char DLE?
  1004.              {                              // a. yes ..
  1005.              dleflag = FALSE;               // .. reset the flag
  1006.              if (c == ETX)                  // q. DLE ETX sequence?
  1007.                  {                          // a. yes ..
  1008.                  state = EndPage;           // .. process end of page
  1009.                  Display_Msg(12);           // update the status
  1010.                  }
  1011.              }
  1012.          else if (c == DLE)                 // q. char a DLE?
  1013.              dleflag = TRUE;                // a. yes .. show true
  1014.          break;                             // continue processing
  1015.     case EndPage:                           // Page complete
  1016.          rc = wait_for(FAX_NO_CARR,         // we should now have no carrier
  1017.                        FAX_ERR, 5) - 1;
  1018.          if (pbi)                           // buffer contain data?
  1019.              fwrite(pagebuf, pbi, 1,        // a. yes.. write out a page
  1020.                        faxfile);
  1021.          fseek(faxfile, reclen, SEEK_SET);  // set postion to length record
  1022.          fwrite(&pagelen, 4, 1, faxfile);   // update the page's length
  1023.          fseek(faxfile, 0L, SEEK_END);      // .. return to end of file
  1024.          if (rc != 0)                       // q. correct response?
  1025.              {                              // a. no ..
  1026.              state = RcvError;              // .. declare an error
  1027.              continue;
  1028.              }
  1029.          state = PhaseD;                    // start post message procedure
  1030.          break;
  1031.     case PhaseD:                            // post message procedure
  1032.          rc = Rcv_Hmsg();                   // get the next message
  1033.          if (rc != 0)                       // q. correct response?
  1034.              {                              // a. no ..
  1035.              state = RcvError;              // .. declare an error
  1036.              continue;
  1037.              }
  1038.          i = hmsg.fax_ctl_fld;              // save the response
  1039.          rc = Send_Hmsg(FINAL,              // send the final frame
  1040.                         FAX_FCF_MCF, 0);    // .. message confirmation
  1041.          if (rc != 0)                       // q. correct response?
  1042.              {                              // a. no ..
  1043.              state = RcvError;              // .. declare an error
  1044.              continue;
  1045.              }
  1046.          switch(i)                          // based on the response..
  1047.             {
  1048.             case FAX_FCF_MPS:               // multi-page signal
  1049.                 Display_Msg(13);            // update the status
  1050.                 state = PhaseC;             // .. receive next page
  1051.                 break;
  1052.             case FAX_FCF_EOM:               // end of message
  1053.                 Display_Msg(14);            // update the status
  1054.                 state = PhaseB;             // .. renegotiate & continue
  1055.                 break;
  1056.             case FAX_FCF_EOP:               // end of procedure
  1057.                 Display_Msg(15);            // update the status
  1058.                 state = PhaseE;             // .. disconnect now
  1059.                 break;
  1060.             case FAX_FCF_DCN:               // disconnect
  1061.                 Display_Msg(16);            // update the status
  1062.                 state = PhaseE;             // .. and hang up
  1063.                 continue;
  1064.             default:
  1065.                 state = RcvError;           // unknown response
  1066.                 break;
  1067.             }
  1068.          break;                             // continue processing
  1069.     case PhaseE:                            // call is done .. disconnect
  1070.          cp->Write(FAX_HANGUP);             // hangup the modem
  1071.          state = ExitFax;                   // .. and exit the fax receive
  1072.          break;
  1073.     case RcvError:                          // error during receive
  1074.          Display_Msg(17);                   // update the status
  1075.          if (rc == -2)                      // q. user cancellation?
  1076.             {                               // a. yes ..
  1077.             state = UserCan;                // .. show the reason
  1078.             continue;                       // .. continue processing
  1079.             }
  1080.          else if (error)                    // q. error set?
  1081.              {                              // a. yes ..
  1082.              fs.f_ptr = fax_errors[error];  // .. set the message pointer
  1083.              (stat)(2, &fs);                // .. and display it
  1084.              }
  1085.          else if (rc == -1)                 // q. timeout?
  1086.              Display_Msg(20);               // a. yes .. show the message
  1087.          else if (rc == 1)                  // q. unexpected response?
  1088.              Display_Msg(21);               // a. yes .. tell the user
  1089.          state = ExitFax;                   // .. set new state
  1090.          break;
  1091.     case UserCan:                           // user cancelled transmission
  1092.          Display_Msg(18);                   // update the status
  1093.          state = ExitFax;                   // .. set new state
  1094.          break;
  1095.     case ExitFax:                           // exit FAX receive
  1096.          if (fileopen)                      // q. fax file open?
  1097.              fclose(faxfile);               // a. yes .. close the file
  1098.          Reset_Modem();                     // reset the modem
  1099.          loop = FALSE;                      // .. end the loop
  1100.          break;                             // .. and return to caller
  1101.     }
  1102. }
  1103. /* ********************************************************************
  1104.  *
  1105.  *  Send -- Send a Facsimile
  1106.  *
  1107.  * ******************************************************************** */
  1108. void Fax::Send(char *faxname,               // fax file name
  1109.                char *telno)                 // telephone number
  1110. {
  1111. int     rc = 0,                             // return code
  1112.         speed,                              // link speed
  1113.         nextspeed,                          // next link speed
  1114.         fileopen = FALSE,                   // receive file not open
  1115.         dis_received = FALSE,               // DIS not yet received
  1116.         i,                                  // work variable
  1117.         error = 0,                          // error number
  1118.         loop = TRUE;                        // loop until complete
  1119. FILE   *faxfile;                            // fax file
  1120. char    dis[16],                            // DIS received
  1121.         csi[21],                            // CSI received
  1122.         c,                                  // work character
  1123.         w;                                  // work register
  1124. ULONG   pagelen,                            // length of received page
  1125.         st;                                 // work for elapsed time
  1126. enum    SndStates                           // FAX send states
  1127.           {
  1128.           PhaseA,                           // phase A - make connection
  1129.           PhaseB,                           // get HDLC frames
  1130.           SetSpeed,                         // set the link speed
  1131.           SendTSI,                          // select speed, send ID & DCS
  1132.           SendTCF,                          // send the TCF
  1133.           GetConfTCF,                       // get TCF confirmation
  1134.           PhaseC,                           // send the document
  1135.           SendPage,                         // send a page of data
  1136.           PhaseD,                           // post message process
  1137.           AnotherPage,                      // another page to send
  1138.           AllSent,                          // send complete
  1139.           PhaseE,                           // disconnect
  1140.           SndError,                         // error during send
  1141.           UserCan,                          // user cancelled transmission
  1142.           ExitFax                           // exit FAX receive
  1143.           } state;
  1144. strcpy(fh.ff_id, "                    ");   // blank out the ID string
  1145. state = PhaseA;                             // start in Phase A
  1146. if ((faxfile = fopen(faxname, "rb"))        // q. send file open ok?
  1147.                     == NULL)
  1148.     {                                       // a. no ..
  1149.     error = 9;                              // .. set the error code
  1150.     state = SndError;                       // .. and declare an error
  1151.     }
  1152. fread(&fh, 128, 1, faxfile);                // read the header
  1153. if (strcmp(fh.ff_type, "G3"))               // q. G3 file?
  1154.     {                                       // a. no ..
  1155.     error = 13;                             // .. show invalid format
  1156.     state = SndError;                       // .. and declare an error
  1157.     }
  1158. fileopen = TRUE;                            // show the file is open
  1159. fread(&pagelen, 4, 1, faxfile);             // read in the first page length
  1160. while(loop)                                 // top of state machine
  1161.   switch(state)                             // perform next state
  1162.     {
  1163.     case PhaseA:                            // phase A - make connection
  1164.          Display_Msg(1);                    // update the status
  1165.          if ((rc = Init_Modem()) != 0)      // q. modem init ok?
  1166.              {
  1167.              error = 1;                     // a. no .. exit now
  1168.              state = SndError;              // .. declare the error
  1169.              continue;
  1170.              }
  1171.          Display_Msg(22);                   // update the status
  1172.          cp->Write(FAX_DIAL);               // send the dial command
  1173.          cp->Write(telno);                  // .. and the phone number
  1174.          cp->Write('r');                   // .. and finish the command
  1175.          rc = wait_for(FAX_CONN,            // wait for a connection
  1176.                        FAX_NO_CARR, 120);
  1177.          if (--rc)                          // q. any error
  1178.              {                              // a. yes ..
  1179.              if (rc == 1)                   // q. connection fail?
  1180.                 error = 10;                 // a. yes .. show connect failed
  1181.              state = SndError;              // declare an error
  1182.              continue;                      // .. go to next state
  1183.              }
  1184.          state = PhaseB;                    // get frames
  1185.          connected = TRUE;                  // ... show we are connected
  1186.          break;
  1187.     case PhaseB:                            // get HDLC frames
  1188.          if ((rc = Rcv_Hmsg()) != 0)        // q. any error getting a frame?
  1189.              if (rc < 0)                    // a. yes .. timeout or ESC?
  1190.                  {                          // a. yes ..
  1191.                  error = 3;                 // .. error receiving HDLC frame
  1192.                  state = SndError;          // .. leave with error.
  1193.                  continue;                  // .. continue process
  1194.                  }
  1195.              else                           // else .. NO CARRIER
  1196.                  {
  1197.                  cp->Write(FAX_SILENT1);    // wait for 200ms silence
  1198.                  rc = wait_for(FAX_OK,      // wait for the OK response
  1199.                                FAX_ERR,
  1200.                                10) - 1;
  1201.                  state = SetSpeed;          // .. and set the speed
  1202.                  }
  1203.          if (rc)                            // q. any error yet?
  1204.              {                              // a. yes ..
  1205.              state = SndError;              // .. declare an error
  1206.              continue;
  1207.              }
  1208.          switch(hmsg.fax_ctl_fld)           // process based on message type
  1209.              {
  1210.              case FAX_FCF_CSI:              // called subscriber ID
  1211.                 Display_Msg(23);            // update the status
  1212.                 Reverse_Bytes(hmsg.data,    // .. reset the bytes to normal
  1213.                                      20);
  1214.                 hmsg.data[20] = 0;          // .. end string in zero
  1215.                 strcpy(csi,                 // .. copy it to work area
  1216.                        (char *) hmsg.data);
  1217.                 Display_ID("Connected to:", // .. and display the remote ID
  1218.                              (UCHAR *) csi);
  1219.                 break;
  1220.              case FAX_FCF_DIS:              // digital information signal
  1221.                 Display_Msg(24);            // update the status
  1222.                 memcpy(dis, hmsg.data,      // .. move the DIS to work area
  1223.                           hmsg.len - 7);
  1224.                 dis_received = 1;           // show we got DIS
  1225.                 break;
  1226.              case FAX_FCF_NSF:              // Non-standard facilities
  1227.                 Display_Msg(8);             // update the status
  1228.                 break;                      // .. we don't process these
  1229.              }
  1230.          break;
  1231.     case SetSpeed:                          // set the link speed
  1232.          if (dis_received == 0)             // q. dis received?
  1233.              {                              // a. no ..
  1234.              error = 11;                    // .. show the error
  1235.              state = SndError;              // .. and go to error state
  1236.              continue;                      // .. continue with next state
  1237.              }
  1238.          switch (dis[1] & 0x30)             // select initial speed
  1239.              {
  1240.              case 0x30:                     // q. speed 7200?
  1241.              case 0x20:                     // q. speed 9600?
  1242.                  nextspeed = 96;            // a. yes .. set speed
  1243.                  break;
  1244.              case 0x10:                     // q. speed 4800?
  1245.                  nextspeed = 48;            // a. yes .. set speed
  1246.                  break;
  1247.              case 0x00:                     // q. speed 2400?
  1248.                  nextspeed = 24;            // a. yes . set speed
  1249.                  break;
  1250.              }
  1251.          state = SendTSI;                   // next, tell 'em about us
  1252.          break;
  1253.     case SendTSI:                           // select speed, send ID & DCS
  1254.          dcs_msg[1] &= 0xcf;                // set off speed bits
  1255.          switch (speed = nextspeed)         // based on selected speed
  1256.            {
  1257.            case 96:                         // q. speed = 9600?
  1258.                dcs_msg[1] |= 0x20;          // a. yes .. set speed
  1259.                if ((dis_msg[1] | 0x30)      // q. 7200 supported?
  1260.                                 == 0x30)
  1261.                    nextspeed = 72;          // a. yes .. next speed = 7200
  1262.                else
  1263.                    nextspeed = 48;          // else .. next speed = 4800
  1264.                i = 41;                      // select speed message
  1265.                break;
  1266.            case 72:                         // q. speed = 7200?
  1267.                dcs_msg[1] |= 0x30;          // a. yes .. set speed
  1268.                nextspeed = 48;              // .. next speed = 4800
  1269.                i = 42;                      // select speed message
  1270.                break;
  1271.            case 48:                         // q. speed = 4800?
  1272.                dcs_msg[1] |= 0x10;          // a. yes .. set speed
  1273.                nextspeed = 24;              // .. next speed = 2400
  1274.                i = 43;                      // select speed message
  1275.                break;
  1276.            case 24:                         // q. speed = 2400?
  1277.                error = 12;                  // a. yes.. can't connect
  1278.                state = SndError;            // .. declare the error
  1279.                i = 44;                      // select speed message
  1280.                continue;                    // .. continue state machine
  1281.            }
  1282.          Display_Msg(25);                   // update the status
  1283.          rc = Send_TSI();                   // .. send our ID
  1284.          if (rc)                            // q. error?
  1285.              {
  1286.              state = SndError;              // a. yes ..
  1287.              continue;                      // .. declare the error
  1288.              }
  1289.          Display_Msg(26);                   // update status again
  1290.          state = ((rc = Send_DCS()) != 0) ? // q. DCS send go ok?
  1291.                                  SndError : // a. no .. declare error
  1292.                                   SendTCF ; // else .. send the check frame
  1293.          break;
  1294.     case SendTCF:                           // send the TCF
  1295.          Display_Msg(i);                    // show speed
  1296.          Display_Msg(27);                   // update the status
  1297.          rc = Data_Mode(TRANSMIT, speed);   // go to data mode
  1298.          if (rc)                            // q. any error?
  1299.              {                              // a. yes ..
  1300.              state = (rc != 1) ? SndError : // .. select general error
  1301.                                GetConfTCF;  // .. or just connection failure
  1302.              continue;
  1303.              }
  1304.          cp->Write(0);                      // Send the TCF
  1305.          for (st = get_time();              // .. let the modem send zeroes
  1306.                  elapsed_time(st) < 28;);   // .. for 1.5 seconds
  1307.          cp->Write(DLE);                    // .. ended with DLE
  1308.          cp->Write(ETX);                    // .. ETX
  1309.          rc = wait_for(FAX_NO_CARR,         // wait for no carrier or OK
  1310.                        FAX_OK, 5);          // .. for 5 seconds
  1311.          if (rc-- < 1)                      // q. error?
  1312.              state = SndError;              // a. yes .. declare the error
  1313.          else
  1314.              state = GetConfTCF;            // else .. try for confirmation
  1315.          break;
  1316.     case GetConfTCF:                        // get TCF confirmation
  1317.          Display_Msg(28);                   // update the status
  1318.          if ((rc = Rcv_Hmsg()) != 0)        // q. any error getting a frame?
  1319.              {                              // a. yes ..
  1320.              error = 3;                     // .. error receiving HDLC frame
  1321.              state = SndError;              // .. leave with error.
  1322.              continue;                      // .. continue process
  1323.              }
  1324.          switch(hmsg.fax_ctl_fld)           // process based on message type
  1325.              {
  1326.              case FAX_FCF_CFR:              // confirmation
  1327.                   state = PhaseC;           // send the document
  1328.                   break;
  1329.              case FAX_FCF_FTT:              // failure to train
  1330.                   Display_Msg(30);          // update the status
  1331.                   state = SendTSI;          // next speed and retry session
  1332.                   break;
  1333.              default:                       // unknown message
  1334.                   error = 21;               // unexpected response
  1335.                   state = SndError;         // .. declare an error
  1336.                   break;
  1337.              }
  1338.          break;
  1339.     case PhaseC:                            // send the document
  1340.          Display_Msg(29);                   // update the status
  1341.          rc = Data_Mode(TRANSMIT, speed);   // .. set data mode
  1342.          if (rc)                            // q. any error?
  1343.              {                              // a. yes ..
  1344.              state = SndError;              // .. declare an error
  1345.              continue;
  1346.              }
  1347.          state = SendPage;                  // else .. send the page
  1348.          break;
  1349.     case SendPage:                          // send a page of data
  1350.          i = pagelen > 128 ?                // determine number of bytes
  1351.                 128 : (int) pagelen;        // .. to read and send
  1352.          pagelen -= i;                      // decrement page length
  1353.          fread(pagebuf, i, 1, faxfile);     // read data from the file
  1354.          cp->Write((char *) pagebuf, i);    // .. and send the data
  1355.          st = SECS(10);                     // for max of 10 seconds
  1356.          while ((cp->OCount() > 256) &&     // let the buffer empty
  1357.                                 error == 0) // .. while there's no error
  1358.              if (time_out(&(long) st))      // q. timeout?
  1359.                  error = 15;                // a. yes .. set the error code
  1360.          if (error)                         // q. error occur?
  1361.              {                              // a. yes ..
  1362.              state = SndError;              // .. declare an error
  1363.              continue;                      // .. and continue processing
  1364.              }
  1365.          if (cp->Read(&c, &w, &w) == 0)     // q. char available?
  1366.              if (c == XOFF)                 // a. yes .. is it XOFF?
  1367.                 {                           // a. yes ..
  1368.                 Display_Msg(35);            // .. show XOFF received
  1369.                 while(cp->Read(&c, &w, &w)  // .. wait for another char
  1370.                              == 0xffff);
  1371.                 Display_Msg(36);            // .. erase XOFF message
  1372.                 }
  1373.          if (pagelen == 0)                  // q. page complete?
  1374.              state = PhaseD;                // a. yes .. continue
  1375.          break;
  1376.     case PhaseD:                            // post message process
  1377.          fread(&pagelen, 4, 1, faxfile);    // read next page length
  1378.          while (cp->OEmpty() != 0);         // wait for transmit complete
  1379.          rc = wait_for(FAX_OK,              // should get OK
  1380.                        FAX_ERR, 5) - 1;
  1381.          if (rc)                            // q. did send complete?
  1382.              {                              // a. no ..
  1383.              state = SndError;              // .. declare an error
  1384.              continue;
  1385.              }
  1386.          Display_Msg(31);                   // update the status
  1387.          if (pagelen)                       // q. more pages?
  1388.              state = AnotherPage;           // a. yes ... send another
  1389.          else
  1390.              state = AllSent;               // else .. all sent
  1391.          break;
  1392.     case AnotherPage:                       // another page to send
  1393.          Display_Msg(32);                   // update the status
  1394.          rc = Send_Hmsg(FINAL,              // send the multipage signal
  1395.                         FAX_FCF_MPS, 0);
  1396.          if (rc != 0)                       // q. send ok?
  1397.             {                               // a. no ..
  1398.             state = SndError;               // .. declare an error
  1399.             continue;                       // .. continue processing
  1400.             }
  1401.          if ((rc = Rcv_Hmsg()) != 0)        // q. any error getting a frame?
  1402.              {                              // a. yes ..
  1403.              error = 3;                     // .. error receiving HDLC frame
  1404.              state = SndError;              // .. leave with error.
  1405.              continue;                      // .. continue process
  1406.              }
  1407.          switch(hmsg.fax_ctl_fld)           // process based on message type
  1408.              {
  1409.              case FAX_FCF_MCF:              // message confirmation
  1410.                   state = PhaseC;           // send next page
  1411.                   break;
  1412.              default:
  1413.                   error = 14;               // unexpected response
  1414.                   state = SndError;         // .. declare an error
  1415.                   continue;
  1416.              }
  1417.          break;
  1418.     case AllSent:                           // send complete
  1419.          Display_Msg(33);                   // update the status
  1420.          rc = Send_Hmsg(FINAL,              // send end of procedure
  1421.                         FAX_FCF_EOP, 0);
  1422.          if (rc != 0)                       // q. send ok?
  1423.             {                               // a. no ..
  1424.             state = SndError;               // .. declare an error
  1425.             continue;                       // .. continue processing
  1426.             }
  1427.          if ((rc = Rcv_Hmsg()) != 0)        // q. any error getting a frame?
  1428.              {                              // a. yes ..
  1429.              error = 3;                     // .. error receiving HDLC frame
  1430.              state = SndError;              // .. leave with error.
  1431.              continue;                      // .. continue process
  1432.              }
  1433.          switch(hmsg.fax_ctl_fld)           // process based on message type
  1434.              {
  1435.              case FAX_FCF_MCF & 0x7f:       // message confirmation
  1436.                   state = PhaseE;           // send next page
  1437.                   break;
  1438.              default:
  1439.                   error = 14;               // unexpected response
  1440.                   state = SndError;         // .. declare an error
  1441.                   continue;
  1442.              }
  1443.          break;
  1444.     case PhaseE:                            // disconnect
  1445.          Display_Msg(34);                   // update the status
  1446.          rc = Send_Hmsg(FINAL,              // send end of procedure
  1447.                         FAX_FCF_DCN, 0);
  1448.          if (rc != 0)                       // q. send ok?
  1449.             {                               // a. no ..
  1450.             state = SndError;               // .. declare an error
  1451.             continue;                       // .. continue processing
  1452.             }
  1453.          state = ExitFax;                   // exit fax send procedure
  1454.          break;
  1455.     case SndError:                          // error during send
  1456.          Display_Msg(17);                   // update the status
  1457.          if (rc == -2)                      // q. user cancellation?
  1458.             {                               // a. yes ..
  1459.             state = UserCan;                // .. show the reason
  1460.             continue;                       // .. continue processing
  1461.             }
  1462.          else if (error)                    // q. error set?
  1463.              {                              // a. yes ..
  1464.              fs.f_ptr = fax_errors[error];  // .. set the message pointer
  1465.              (stat)(2, &fs);                // .. and display it
  1466.              }
  1467.          else if (rc == -1)                 // q. timeout?
  1468.              Display_Msg(20);               // a. yes .. show the message
  1469.          else if (rc == 1)                  // q. unexpected response?
  1470.              Display_Msg(21);               // a. yes .. tell the user
  1471.          state = ExitFax;                   // .. set new state
  1472.          break;
  1473.     case UserCan:                           // user cancelled transmission
  1474.          Display_Msg(18);                   // update the status
  1475.          state = ExitFax;                   // .. set new state
  1476.          break;
  1477.     case ExitFax:                           // exit FAX receive
  1478.          if (fileopen)                      // q. fax file open?
  1479.              fclose(faxfile);               // a. yes .. close the file
  1480.          Reset_Modem();                     // .. reset the modem
  1481.          loop = FALSE;                      // .. end the loop
  1482.          break;                             // .. and return to caller
  1483.     }
  1484. }