Class20.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:10k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: Class20.c++,v 1.3 2007/10/18 06:05:09 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1994-1996 Sam Leffler
  4.  * Copyright (c) 1994-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "Class20.h"
  27. #include "ModemConfig.h"
  28. #include "StackBuffer.h"
  29. #include <stdlib.h>
  30. #include <ctype.h>
  31. Class20Modem::Class20Modem(FaxServer& s, const ModemConfig& c) : Class2Modem(s,c)
  32. {
  33.     serviceType = SERVICE_CLASS20;
  34.     setupDefault(classCmd, conf.class2Cmd, "AT+FCLASS=2.0");
  35.     setupDefault(mfrQueryCmd, conf.mfrQueryCmd, "AT+FMI?");
  36.     setupDefault(modelQueryCmd, conf.modelQueryCmd, "AT+FMM?");
  37.     setupDefault(revQueryCmd, conf.revQueryCmd, "AT+FMR?");
  38.     setupDefault(dccQueryCmd, conf.class2DCCQueryCmd, "AT+FCC=?");
  39.     setupDefault(abortCmd, conf.class2AbortCmd, "AT+FKS");
  40.     setupDefault(borCmd, conf.class2BORCmd, "AT+FBO=0");
  41.     setupDefault(tbcCmd, conf.class2TBCCmd, "AT+FPP=0");
  42.     setupDefault(crCmd, conf.class2CRCmd, "AT+FCR=1");
  43.     setupDefault(phctoCmd, conf.class2PHCTOCmd, "AT+FCT=30");
  44.     setupDefault(bugCmd, conf.class2BUGCmd, "AT+FBU=1");
  45.     setupDefault(lidCmd, conf.class2LIDCmd, "AT+FLI");
  46.     setupDefault(dccCmd, conf.class2DCCCmd, "AT+FCC");
  47.     setupDefault(disCmd, conf.class2DISCmd, "AT+FIS");
  48.     setupDefault(cigCmd, conf.class2CIGCmd, "AT+FPI");
  49.     setupDefault(splCmd, conf.class2SPLCmd, "AT+FSP");
  50.     setupDefault(ptsCmd, conf.class2PTSCmd, "AT+FPS");
  51.     setupDefault(ptsQueryCmd, conf.class2PTSQueryCmd, "AT+FPS?");
  52.     setupDefault(minspCmd, conf.class2MINSPCmd, "AT+FMS");
  53.     setupDefault(noFlowCmd, conf.class2NFLOCmd, "AT+FLO=0");
  54.     setupDefault(softFlowCmd, conf.class2SFLOCmd, "AT+FLO=1");
  55.     setupDefault(hardFlowCmd, conf.class2HFLOCmd, "AT+FLO=2");
  56.     // ignore procedure interrupts
  57.     setupDefault(pieCmd, conf.class2PIECmd, "AT+FIE=0");
  58.     // enable reporting of everything
  59.     setupDefault(nrCmd, conf.class2NRCmd, "AT+FNR=1,1,1,1");
  60. }
  61. Class20Modem::~Class20Modem()
  62. {
  63. }
  64. ATResponse
  65. Class20Modem::atResponse(char* buf, long ms)
  66. {
  67.     if (FaxModem::atResponse(buf, ms) == AT_OTHER &&
  68.       (buf[0] == '+' && buf[1] == 'F')) {
  69. if (strneq(buf, "+FHS:", 5)) {
  70.     processHangup(buf+5);
  71.     lastResponse = AT_FHNG;
  72.     hadHangup = true;
  73. } else if (strneq(buf, "+FCO", 4))
  74.     lastResponse = AT_FCON;
  75. else if (strneq(buf, "+FPO", 4))
  76.     lastResponse = AT_FPOLL;
  77. else if (strneq(buf, "+FVO", 4))
  78.     lastResponse = AT_FVO;
  79. else if (strneq(buf, "+FIS:", 5))
  80.     lastResponse = AT_FDIS;
  81. else if (strneq(buf, "+FNF:", 5))
  82.     lastResponse = AT_FNSF;
  83. else if (strneq(buf, "+FCI:", 5))
  84.     lastResponse = AT_FCSI;
  85. else if (strneq(buf, "+FPS:", 5))
  86.     lastResponse = AT_FPTS;
  87. else if (strneq(buf, "+FCS:", 5))
  88.     lastResponse = AT_FDCS;
  89. else if (strneq(buf, "+FNS:", 5))
  90.     lastResponse = AT_FNSS;
  91. else if (strneq(buf, "+FTI:", 5))
  92.     lastResponse = AT_FTSI;
  93. else if (strneq(buf, "+FET:", 5))
  94.     lastResponse = AT_FET;
  95. else if (strneq(buf, "+FPA:", 5))
  96.     lastResponse = AT_FPA;
  97. else if (strneq(buf, "+FSA:", 5))
  98.     lastResponse = AT_FSA;
  99. else if (strneq(buf, "+FPW:", 5))
  100.     lastResponse = AT_FPW;
  101.     }
  102.     return (lastResponse);
  103. }
  104. /*
  105.  * Abort a data transfer in progress.
  106.  */
  107. void
  108. Class20Modem::abortDataTransfer()
  109. {
  110.     protoTrace("SEND abort data transfer");
  111.     char c = CAN;
  112.     putModemData(&c, 1);
  113. }
  114. /*
  115.  * Send a page of data using the ``stream interface''.
  116.  */
  117. bool
  118. Class20Modem::sendPage(TIFF* tif, u_int pageChop)
  119. {
  120.     /*
  121.      * Support MT5634ZBA-V92 real-time fax compression conversion:
  122.      * AT+FFC=? gives us non-zero data if RTFCC is supported.
  123.      * Firstly, we must have set our FCC to MMR support (+FCC=,,,,3), and
  124.      * we may need to have ECM enabled (+FCC=,,,,,1) if we intend to
  125.      * allow RTFCC to send in MMR.  Now we send <DLE><char> where char =
  126.      *    6Bh  -  if we formatted the image in MH
  127.      *    6Ch  -  if we formatted the image in MR
  128.      *    6Eh  -  if we formatted the image in MMR
  129.      */
  130.     if (conf.class2RTFCC) {
  131. protoTrace("Enable Real-Time Fax Compression Conversion");
  132. uint16 compression;
  133. char rtfcc[2];
  134. rtfcc[0] = DLE;
  135. TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
  136. if (compression != COMPRESSION_CCITTFAX4) {
  137.     uint32 g3opts = 0;
  138.     TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &g3opts);
  139.     if ((g3opts & GROUP3OPT_2DENCODING) == DF_2DMR) {
  140. rtfcc[1] = 0x6C; // MR
  141. protoTrace("Reading MR-compressed image file");
  142.     } else {
  143. rtfcc[1] = 0x6B; // MH
  144. protoTrace("Reading MH-compressed image file");
  145.     }
  146. } else {
  147.     rtfcc[1] = 0x6E; // MMR
  148.     protoTrace("Reading MMR-compressed image file");
  149. }
  150. putModemData(rtfcc, sizeof (rtfcc));
  151.     }
  152.     protoTrace("SEND begin page");
  153.     if (flowControl == FLOW_XONXOFF)
  154. setXONXOFF(FLOW_XONXOFF, FLOW_NONE, ACT_FLUSH);
  155.     bool rc = sendPageData(tif, pageChop);
  156.     if (!rc)
  157. abortDataTransfer();
  158.     else if( conf.class2SendRTC )
  159. rc = sendRTC(params);
  160.     if (flowControl == FLOW_XONXOFF)
  161. setXONXOFF(getInputFlow(), FLOW_XONXOFF, ACT_DRAIN);
  162.     protoTrace("SEND end page");
  163.     return (rc);
  164. }
  165. /*
  166.  * Handle the page-end protocol.  Class 2.0 returns
  167.  * OK/ERROR according to the post-page response.  We
  168.  * should query the modem to get the actual code, but
  169.  * some modems don't support +FPS? and so instead we
  170.  * synthesize codes, ignoring whether or not the
  171.  * modem does retraining on the next page transfer.
  172.  */
  173. bool
  174. Class20Modem::pageDone(u_int ppm, u_int& ppr)
  175. {
  176.     static char ppmCodes[3] = { 0x2C, 0x3B, 0x2E };
  177.     char eop[2];
  178.     eop[0] = DLE;
  179.     eop[1] = ppmCodes[ppm];
  180.     ppr = 0;            // something invalid
  181.     if (putModemData(eop, sizeof (eop))) {
  182.         for (;;) {
  183.     switch (atResponse(rbuf, conf.pageDoneTimeout)) {
  184.             case AT_FHNG:
  185. waitFor(AT_OK);
  186.                 if (!isNormalHangup()) {
  187.                     return (false);
  188.                 }
  189.                 ppr = PPR_MCF;
  190.                 return (true);
  191.             case AT_OK:
  192.                 /*
  193.                  * We do explicit status query e.g. to
  194.                  * distinguish between MCF, RTP, and PIP.
  195.  * If we don't understand the response,
  196.  * assume that our query isn't supported.
  197.                  */
  198.                 {
  199.     if (strcasecmp(conf.class2PTSQueryCmd, "none") != 0) {
  200. fxStr s;
  201. if(!atQuery(conf.class2PTSQueryCmd, s) ||
  202.     sscanf(s, "%u", &ppr) != 1) {
  203.     protoTrace("MODEM protocol botch ("%s"), %s",
  204.     (const char*)s, "can not parse PPR");
  205.     ppr = PPR_MCF;
  206. }
  207.     } else
  208. ppr = PPR_MCF; // could be PPR_RTP/PPR_PIP
  209.                 }
  210.                 return (true);
  211.             case AT_ERROR:
  212.                 /*
  213.                  * We do explicit status query e.g. to
  214.                  * distinguish between RTN and PIN 
  215.  * If we don't understand the response,
  216.  * assume that our query isn't supported.
  217.                  */
  218.                 {
  219.     if (strcasecmp(conf.class2PTSQueryCmd, "none") != 0) {
  220. fxStr s;
  221. if(!atQuery(conf.class2PTSQueryCmd, s) ||
  222.     sscanf(s, "%u", &ppr) != 1) {
  223.     protoTrace("MODEM protocol botch ("%s"), %s",
  224.     (const char*)s, "can not parse PPR");
  225.     ppr = PPR_RTN;
  226. }
  227.     } else
  228. ppr = PPR_RTN; // could be PPR_PIN
  229.                 }
  230.                 return (true);
  231.             case AT_EMPTYLINE:
  232.             case AT_TIMEOUT:
  233.             case AT_NOCARRIER:
  234.             case AT_NODIALTONE:
  235.             case AT_NOANSWER:
  236.                 goto bad;
  237.             }
  238.         }
  239.     }
  240. bad:
  241.     processHangup("50");        // Unspecified Phase D error
  242.     return (false);
  243. }
  244. /*
  245.  * Class 2.0 must override the default behaviour used
  246.  * Class 1+2 modems in order to do special handling of
  247.  * <DLE><SUB> escape (translate to <DLE><DLE>).
  248.  */
  249. int
  250. Class20Modem::nextByte()
  251. {
  252.     int b;
  253.     if (bytePending & 0x100) {
  254. b = bytePending & 0xff;
  255. bytePending = 0;
  256.     } else {
  257. b = getModemDataChar();
  258. if (b == EOF)
  259.     raiseEOF();
  260.     }
  261.     if (b == DLE) {
  262. switch (b = getModemDataChar()) {
  263.     case 0x01: // +FDB=1 support
  264. {
  265.     fxStr dbdata;
  266.     bool notdone = true;
  267.     do {
  268. b = getModemDataChar();
  269. if (b == DLE) {
  270.     b = getModemDataChar();
  271.     if (b == 0x04) {
  272. notdone = false;
  273. protoTrace("DCE DEBUG: %s", (const char*) dbdata);
  274.     } else {
  275. dbdata.append(DLE);
  276.     }
  277. }
  278. if (b != '' && b != 'r' && b != 'n')
  279.     dbdata.append(b);
  280.     } while (notdone);
  281.     b = nextByte();
  282. }
  283.     break;
  284. case EOF: raiseEOF();
  285. case ETX: raiseRTC(); // RTC
  286. case DLE: break; // <DLE><DLE> -> <DLE>
  287. case SUB: b = DLE; // <DLE><SUB> -> <DLE><DLE>
  288.     /* fall thru... */
  289. default:
  290.     bytePending = b | 0x100;
  291.     b = DLE;
  292.     break;
  293. }
  294.     }
  295.     b = getBitmap()[b];
  296.     if (recvBuf)
  297. recvBuf->put(b);
  298.     return (b);
  299. }