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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: Class2Send.c++,v 1.15 2007/11/04 01:45:30 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-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 <stdio.h>
  27. #include "Sys.h"
  28. #include "Class2.h"
  29. #include "ModemConfig.h"
  30. #include "FaxRequest.h"
  31. /*
  32.  * Send Protocol for Class-2-style modems.
  33.  */
  34. bool
  35. Class2Modem::sendSetup(FaxRequest& req, const Class2Params& dis, fxStr& emsg)
  36. {
  37.     const char* cmdFailed = " (modem command failed)";
  38.     /*
  39.      * PWD and SUB setup don't belong here, they should be done
  40.      * in setupSetupPhaseB at which time we know whether or not
  41.      * the receiver supports them.  However since no status message
  42.      * is defined for T.class2 such that we can determine this
  43.      * information and since some modems will undoubtedly require
  44.      * all session state to be setup prior to the initial call
  45.      * we'll send this stuff to the modem here (for now at least).
  46.      */
  47.     if (req.passwd != "" && pwCmd != "" && !class2Cmd(pwCmd, req.passwd)) {
  48. emsg = fxStr::format("Unable to send password%s {E204}", cmdFailed);
  49. return (false);
  50.     }
  51.     if (req.subaddr != "" && saCmd != "" && !class2Cmd(saCmd, req.subaddr)) {
  52. emsg = fxStr::format("Unable to send subaddress%s {E205}", cmdFailed);
  53. return (false);
  54.     }
  55.     if (minsp != BR_2400 && !class2Cmd(minspCmd, minsp)) {
  56. emsg = fxStr::format("Unable to restrict minimum transmit speed to %s%s {E206}",
  57.     Class2Params::bitRateNames[req.minbr], cmdFailed);
  58. return (false);
  59.     }
  60.     if (conf.class2DDISCmd != "") {
  61. if (!class2Cmd(conf.class2DDISCmd, dis, false)) {
  62.     emsg = fxStr::format("Unable to setup session parameters "
  63. "prior to call%s {E207}", cmdFailed);
  64.     return (false);
  65. }
  66. params = dis;
  67.     }
  68.     hadHangup = false;
  69.     return (FaxModem::sendSetup(req, dis, emsg));
  70. }
  71. /*
  72.  * Process the response to a dial command.
  73.  */
  74. CallStatus
  75. Class2Modem::dialResponse(fxStr& emsg)
  76. {
  77.     ATResponse r;
  78.     hangupCode[0] = '';
  79.     do {
  80. /*
  81.  * Use a dead-man timeout since some
  82.  * modems seem to get hosed and lockup.
  83.  */
  84. r = atResponse(rbuf, conf.dialResponseTimeout);
  85. // Blacklisting (see notes in Class1Send.c++)
  86. if (strncmp(rbuf, "BLACKLISTED", 11) == 0
  87. || strncmp(rbuf, "DELAYED", 7) == 0
  88. || strncmp(rbuf, "DIALING DISABLED", 16) == 0) {
  89.     emsg = "Blacklisted by modem {E010}";
  90.     return (NOCARRIER);
  91. }
  92. switch (r) {
  93. case AT_ERROR:     return (ERROR); // error in dial command
  94. case AT_BUSY:     return (BUSY); // busy signal
  95. case AT_NOCARRIER:  return (NOCARRIER); // no carrier detected
  96. case AT_OK:     return (NOCARRIER); // (for AT&T DataPort)
  97. case AT_NODIALTONE: return (NODIALTONE);// local phone connection hosed
  98. case AT_NOANSWER:   return (NOANSWER); // no answer or ring back
  99. case AT_FHNG: // Class 2 hangup code
  100.     emsg = fxStr::format("%s {%s}", hangupCause(hangupCode), hangupCause(hangupCode, true));
  101.     switch (atoi(hangupCode)) {
  102.     case 1:     return (NOANSWER); // Ring detected w/o handshake
  103.     case 3:     return (NOANSWER); // No loop current (???)
  104.     case 4:     return (NOANSWER); // Ringback detected, no answer
  105.     case 5:     return (NOANSWER); // Ringback ", no answer w/o CED
  106.     case 10:     return (NOFCON); // Unspecified Phase A error
  107.     case 11:     return (NOFCON); // No answer (T.30 timeout)
  108.     }
  109.     break;
  110. case AT_FCON:     return (OK); // fax connection
  111. case AT_TIMEOUT:    return (FAILURE); // timed out w/o response
  112. case AT_CONNECT:    return (DATACONN); // modem thinks data connection
  113. }
  114.     } while (r == AT_OTHER && isNoise(rbuf));
  115.     return (FAILURE);
  116. }
  117. #define BATCH_FIRST 1
  118. #define BATCH_LAST  2
  119. /*
  120.  * Process the string of session-related information
  121.  * sent to the caller on connecting to a fax machine.
  122.  */
  123. FaxSendStatus
  124. Class2Modem::getPrologue(Class2Params& dis, bool& hasDoc, fxStr& emsg, u_int& batched)
  125. {
  126.     bool gotParams = false;
  127.     hasDoc = false;
  128.     if (batched & BATCH_FIRST) { // only for the first document
  129. ATResponse r;
  130. for (;;) {
  131.     r  = atResponse(rbuf, conf.t1Timer);
  132.     switch (r) {
  133.     case AT_FPOLL:
  134. hasDoc = true;
  135. protoTrace("REMOTE has document to POLL");
  136. break;
  137.     case AT_FDIS:
  138. gotParams = parseClass2Capabilities(skipStatus(rbuf), dis, true);
  139. break;
  140.     case AT_FNSF:
  141. recvNSF(NSF(skipStatus(rbuf), conf.class2HexNSF));
  142. break;
  143.     case AT_FCSI:
  144. recvCSI(stripQuotes(skipStatus(rbuf)));
  145. break;
  146.     case AT_OK:
  147. if (gotParams)
  148.     return (send_ok);
  149. /* fall thru... */
  150.     case AT_TIMEOUT:
  151.     case AT_EMPTYLINE:
  152.     case AT_NOCARRIER:
  153.     case AT_NODIALTONE:
  154.     case AT_NOANSWER:
  155.     case AT_ERROR:
  156. processHangup("20"); // Unspecified Phase B error
  157. /* fall thru... */
  158.     case AT_FHNG:
  159. if (r == AT_FHNG) waitFor(AT_OK);
  160. emsg = fxStr::format("%s {%s}", hangupCause(hangupCode), hangupCause(hangupCode, true));
  161. return (send_retry);
  162.     }
  163. }
  164.     } else {
  165. /*
  166.  * We already have the remote DIS.  Class 2 protocol says to now send
  167.  * +FIS and then +FDT, expecting CONNECT, so we skip this "prologue".
  168.  */
  169. return (send_ok);
  170.     }
  171. }
  172. /*
  173.  * Initiate data transfer from the host to the modem when
  174.  * doing a send.  Note that some modems require that we
  175.  * wait for an XON from the modem in response to the +FDT,
  176.  * before actually sending any data.
  177.  */
  178. bool
  179. Class2Modem::dataTransfer()
  180. {
  181.     bool status = false;
  182.     if (xmitWaitForXON) {
  183. /*
  184.  * Wait for XON (DC1) from the modem after receiving
  185.  * CONNECT and before sending page data.  If XON/XOFF
  186.  * flow control is in use then disable it temporarily
  187.  * so that we can read the input stream for DC1.
  188.  */
  189. if (flowControl == FLOW_XONXOFF)
  190.     setXONXOFF(FLOW_NONE, getOutputFlow(), ACT_NOW);
  191.     }
  192.     u_short tries = 0;
  193.     ATResponse r;
  194.     do {
  195. atCmd("AT+FDT", AT_NOTHING, conf.pageStartTimeout);
  196. do {
  197.     r = atResponse(rbuf, conf.pageStartTimeout);
  198. } while (r == AT_OTHER || r > AT_FHNG); // ignore all Class 2-specific other than +FHNG
  199.     } while (!hadHangup && r == AT_OK && tries++ < 3);
  200.     status = (r == AT_CONNECT);
  201.     if (xmitWaitForXON) {
  202. if (status) {
  203.     protoTrace("SEND wait for XON");
  204.     int c;
  205.     startTimeout(10*1000); // 5 seconds *should* be enough
  206.     while ((c = getModemChar(0)) != EOF) {
  207. modemTrace("--> [1:%c]", c);
  208. if (c == DC1)
  209.     break;
  210.     }
  211.     stopTimeout("waiting for XON before sending page data");
  212.     status = (c == DC1);
  213. }
  214. if (flowControl == FLOW_XONXOFF) {
  215.     FlowControl oiFlow = getInputFlow();
  216.     setXONXOFF(oiFlow, getOutputFlow(), ACT_NOW);
  217. }
  218.     }
  219.     return (status);
  220. }
  221. static bool
  222. pageInfoChanged(const Class2Params& a, const Class2Params& b)
  223. {
  224.     return (a.vr != b.vr || a.wd != b.wd || a.ln != b.ln || a.df != b.df || a.br != b.br);
  225. }
  226. /*
  227.  * Send the specified document using the supplied
  228.  * parameters.  The pph is the post-page-handling
  229.  * indicators calculated prior to intiating the call.
  230.  */
  231. FaxSendStatus
  232. Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
  233.     fxStr& pph, fxStr& emsg, u_int& batched)
  234. {
  235.     int ntrys = 0; // # retraining/command repeats
  236.     u_int ppm, previousppm = 0;
  237.     setDataTimeout(180, next.br); // 180 seconds for 1024 byte writes, increased for potential ECM delays
  238.     hangupCode[0] = '';
  239.     bool transferOK;
  240.     bool morePages = false;
  241.     do {
  242. transferOK = false;
  243. if (abortRequested())
  244.      goto failed;
  245. /*
  246.  * Check the next page to see if the transfer
  247.  * characteristics change.  If so, update the
  248.  * current T.30 session parameters.
  249.  */
  250. if (pageInfoChanged(params, next)) {
  251.     if (!class2Cmd(disCmd, next, false)) {
  252. emsg = "Unable to set session parameters {E208}";
  253. break;
  254.     }
  255.     params = next;
  256. }
  257. if (dataTransfer() && sendPage(tif, decodePageChop(pph, params))) {
  258.     /*
  259.      * Page transferred, process post page response from
  260.      * remote station (XXX need to deal with PRI requests).).
  261.      */
  262.     morePages = !TIFFLastDirectory(tif);
  263.     if (!decodePPM(pph, ppm, emsg))
  264. goto failed;
  265.     if (ppm == PPM_EOP && !(batched & BATCH_LAST)) {
  266. ppm = PPM_EOM;
  267. // this should force us to resend disCmd, since some modems don't remember
  268. params.vr = (u_int) -1;
  269.     }
  270.     tracePPM("SEND send", ppm);
  271.     u_int ppr;
  272.     if (pageDone(ppm, ppr)) {
  273. tracePPR("SEND recv", ppr);
  274. switch (ppr) {
  275. case PPR_MCF: // page good
  276. case PPR_PIP: // page good, interrupt requested
  277. case PPR_RTP: // page good, retrain requested
  278.                 ignore:
  279.     countPage(); // bump page count
  280.     notifyPageSent(tif);// update server
  281.     if (pph[2] == 'Z')
  282. pph.remove(0,2+5+1); // discard page-chop+handling
  283.     else
  284. pph.remove(0,3); // discard page-handling info
  285.     ntrys = 0;
  286.     if (morePages) {
  287. if (ppr == PPR_PIP) {
  288.     emsg = "Procedure interrupt (operator intervention) {E280}";
  289.     goto failed;
  290. }
  291. if (!TIFFReadDirectory(tif)) {
  292.     emsg = "Problem reading document directory {E302}";
  293.     goto failed;
  294. }
  295. if (ppr == PPR_MCF) {
  296.     /*
  297.      * The session parameters cannot change except following
  298.      * the reception of an RTN or RTP signal or the transmission
  299.      * of an EOM signal.
  300.      *
  301.      * Since we did not receive RTN or RTP, and since batching (EOM)
  302.      * triggers retraining in other ways, we require that the
  303.      * next page have the same characteristics as this page.
  304.      */
  305.     next = params;
  306. }
  307.     }
  308.     transferOK = true;
  309.     break;
  310. case PPR_RTN: // page bad, retrain requested
  311.                     switch( conf.rtnHandling ){
  312.     case RTN_RETRANSMITIGNORE:
  313. if (ntrys < 2) break;
  314.                     case RTN_IGNORE:
  315.                         goto ignore; // ignore error and trying to send next page
  316.                     case RTN_GIVEUP:
  317.                         emsg = "Unable to transmit page (giving up after RTN) {E281}";
  318.                         goto failed; // "over and out"
  319.                     }
  320.                     // case RTN_RETRANSMIT
  321.     if (++ntrys >= 3) {
  322. emsg = "Unable to transmit page (giving up after 3 attempts) {E282}";
  323. break;
  324.     }
  325.     if (params.br == BR_2400) {
  326. emsg = "Unable to transmit page (NAK at all possible signalling rates) {E283}";
  327. break;
  328.     }
  329.     next.br--;
  330.     morePages = true; // retransmit page
  331.     transferOK = true;
  332.     break;
  333. case PPR_PIN: // page bad, interrupt requested
  334.     emsg = "Unable to transmit page (NAK with operator intervention) {E284}";
  335.     goto failed;
  336. default:
  337.     emsg = "Modem protocol error (unknown post-page response) {E285}";
  338.     break;
  339. }
  340.     } else {
  341. /*
  342.  * We received no PPR.
  343.  */
  344. if (ppm == PPM_EOM && (batched & BATCH_FIRST)) {
  345.     emsg = "Batching protocol error {E286}";
  346.     protoTrace("The destination appears to not support batching.");
  347.     return (send_batchfail);
  348. }
  349.     }
  350. } else {
  351.     /*
  352.      * We were unable to negotiate settings and transfer page image data.
  353.      */
  354.     if (previousppm == PPM_EOM) {
  355. emsg = "Batching protocol error {E286}";
  356. protoTrace("The destination appears to not support batching.");
  357. return (send_batchfail);
  358.     }
  359. }
  360. previousppm = ppm;
  361.     } while (transferOK && morePages && !hadHangup);
  362.     if (!transferOK) {
  363. if (emsg == "") {
  364.     if (hangupCode[0])
  365. emsg = fxStr::format("%s {%s}", hangupCause(hangupCode), hangupCause(hangupCode, true));
  366.     else
  367. emsg = "Communication failure during Phase B/C {E287}";
  368. }
  369. sendAbort(); // terminate session
  370.     } else if (hadHangup && morePages) {
  371. /*
  372.  * Modem hung up before the transfer completed (e.g. PPI
  373.  * modems which get confused when they receive RTN and return
  374.  * +FHNG:0).  Setup an error return so that the job will
  375.  * be retried.
  376.  */
  377. transferOK = false;
  378. emsg = "Communication failure during Phase B/C (modem protocol botch) {E288}";
  379.     }
  380.     return (transferOK ? send_ok : send_retry);
  381. failed:
  382.     sendAbort();
  383.     return (send_failed);
  384. }
  385. /*
  386.  * Send one page of data to the modem, imaging any
  387.  * tag line that is configured.  We also implement
  388.  * page chopping based on the calculation done by
  389.  * faxq during document preparation.
  390.  *
  391.  * Note that we read an entire page of encoded data
  392.  * into memory before sending it to the modem.  This
  393.  * is done to avoid timing problems when the document
  394.  * is comprised of multiple strips.
  395.  */
  396. bool
  397. Class2Modem::sendPageData(TIFF* tif, u_int pageChop)
  398. {
  399.     bool rc = true;
  400.     /* For debugging purposes we may want to write the image-data to file. */
  401.     if (conf.saverawimage) imagefd = Sys::open("/tmp/out.fax", O_RDWR|O_CREAT|O_EXCL);
  402.     tstrip_t nstrips = TIFFNumberOfStrips(tif);
  403.     if (nstrips > 0) {
  404. /*
  405.  * RTFCC may mislead us here, so we temporarily
  406.  * adjust params.
  407.  */
  408. Class2Params newparams = params;
  409. uint16 compression;
  410. TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
  411. if (compression != COMPRESSION_CCITTFAX4) {
  412.     uint32 g3opts = 0;
  413.     TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &g3opts);
  414.     if ((g3opts & GROUP3OPT_2DENCODING) == DF_2DMR)
  415. params.df = DF_2DMR;
  416.     else
  417. params.df = DF_1DMH;
  418. } else
  419.     params.df = DF_2DMMR;
  420. /*
  421.  * Correct bit order of data if not what modem expects.
  422.  */
  423. uint16 fillorder;
  424. TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
  425. const u_char* bitrev =
  426.     TIFFGetBitRevTable(fillorder != sendFillOrder);
  427. /*
  428.  * Setup tag line processing.
  429.  */
  430. bool doTagLine = setupTagLineSlop(params);
  431. u_int ts = getTagLineSlop();
  432. /*
  433.  * Calculate total amount of space needed to read
  434.  * the image into memory (in its encoded format).
  435.  */
  436. uint32* stripbytecount;
  437. (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbytecount);
  438. tstrip_t strip;
  439. u_long totdata = 0;
  440. for (strip = 0; strip < nstrips; strip++)
  441.     totdata += stripbytecount[strip];
  442. /*
  443.  * Read the image into memory.
  444.  */
  445. u_char* data = new u_char[totdata+ts];
  446. u_int off = ts; // skip tag line slop area
  447. for (strip = 0; strip < nstrips; strip++) {
  448.     uint32 sbc = stripbytecount[strip];
  449.     if (sbc > 0 && TIFFReadRawStrip(tif, strip, data+off, sbc) >= 0)
  450. off += (u_int) sbc;
  451. }
  452. totdata -= pageChop; // deduct trailing white space not sent
  453. /*
  454.  * Image the tag line, if intended, and then
  455.  * pass the data to the modem, filtering DLE's
  456.  * and being careful not to get hung up.
  457.  */
  458. u_char* dp;
  459. if (doTagLine) {
  460.     u_long totbytes = totdata;
  461.     dp = imageTagLine(data+ts, fillorder, params, totbytes);
  462.     totdata = (params.df == DF_2DMMR) ? totbytes : totdata+ts - (dp-data);
  463. } else
  464.     dp = data;
  465. uint32 rows = 0;
  466. if (conf.softRTFCC && !conf.class2RTFCC && params.df != newparams.df) {
  467.     switch (params.df) {
  468. case DF_1DMH:
  469.     protoTrace("Reading MH-compressed image file");
  470.     break;
  471. case DF_2DMR:
  472.     protoTrace("Reading MR-compressed image file");
  473.     break;
  474. case DF_2DMMR:
  475.     protoTrace("Reading MMR-compressed image file");
  476.     break;
  477.     }
  478.     dp = convertPhaseCData(dp, totdata, fillorder, params, newparams, rows);
  479.     params = newparams; // revert back
  480. }
  481.         /*
  482.          * correct broken Phase C (T.4) data if necessary
  483.          */
  484.         if (params.df < DF_2DMMR) {
  485.     correctPhaseCData(dp, totdata, fillorder, params, rows);
  486. } else if (params.df == DF_JBIG) {
  487.     // JBIG needs the data bit-reversed as we get it backwards from the library
  488.     TIFFReverseBits(dp, totdata);
  489. }
  490. if (imagefd > 0) Sys::write(imagefd, (const char*) dp, (u_int) totdata);
  491. beginTimedTransfer();
  492. rc = putModemDLEData(dp, (u_int) totdata, bitrev, getDataTimeout(), conf.doPhaseCDebug);
  493. endTimedTransfer();
  494. protoTrace("SENT %u bytes of data", totdata);
  495.     }
  496.     if (imagefd > 0) {
  497. Sys::close(imagefd);
  498. imagefd = 0;
  499.     }
  500.     return (rc);
  501. }
  502. /*
  503.  * Send RTC to terminate a page.
  504.  */
  505. bool
  506. Class2Modem::sendRTC(Class2Params params)
  507. {
  508.     if (params.df > DF_2DMR) return (true); // nothing to do
  509.     // these are intentionally reverse-encoded in order to keep
  510.     // rtcRev and bitrev in sendPage() in agreement
  511.     static const u_char RTC1D[9] =
  512. { 0x00,0x08,0x80,0x00,0x08,0x80,0x00,0x08,0x80 };
  513.     static const u_char RTC2D[10] =
  514. { 0x00,0x18,0x00,0x03,0x60,0x00,0x0C,0x80,0x01,0x30 };
  515.     protoTrace("SEND %s RTC", params.is2D() ? "2D" : "1D");
  516.     if (params.is2D())
  517. return putModemDLEData(RTC2D, sizeof (RTC2D), rtcRev, getDataTimeout());
  518.     else
  519. return putModemDLEData(RTC1D, sizeof (RTC1D), rtcRev, getDataTimeout());
  520. }
  521. /*
  522.  * Abort an active Class 2 session.
  523.  */
  524. void
  525. Class2Modem::sendAbort()
  526. {
  527.     if (!hadHangup)
  528. (void) atCmd(abortCmd);
  529. }