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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: FaxRecv.c++,v 1.18 2008/04/26 22:34:28 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 "Sys.h"
  27. #include <sys/file.h>
  28. #include <ctype.h>
  29. #include <errno.h>
  30. #include "Dispatcher.h"
  31. #include "tiffio.h"
  32. #include "FaxServer.h"
  33. #include "FaxRecvInfo.h"
  34. #include "FaxMachineInfo.h"
  35. #include "faxApp.h" // XXX
  36. #include "t.30.h"
  37. #include "config.h"
  38. /*
  39.  * FAX Server Reception Protocol.
  40.  */
  41. bool
  42. FaxServer::recvFax(const CallID& callid, FaxMachineInfo clientInfo, fxStr& emsg)
  43. {
  44.     traceProtocol("RECV FAX: begin");
  45.     FaxRecvInfoArray docs;
  46.     FaxRecvInfo info;
  47.     bool faxRecognized = false;
  48.     emsg = "";
  49.     abortCall = false;
  50.     waitNotifyPid = 0;
  51.     FaxSetup setupinfo;
  52.     setupinfo.senderSkipsV29 = clientInfo.getSenderSkipsV29();
  53.     setupinfo.senderHasV17Trouble = clientInfo.getSenderHasV17Trouble();
  54.     /*
  55.      * Create the first file ahead of time to avoid timing
  56.      * problems with Class 1 modems.  (Creating the file
  57.      * after recvBegin can cause part of the first page to
  58.      * be lost.)
  59.      */
  60.     info.callid = callid;
  61.     TIFF* tif = setupForRecv(info, docs, emsg);
  62.     if (tif) {
  63. recvPages = 0; // total count of received pages
  64. fileStart = pageStart = Sys::now();
  65. faxRecognized = modem->recvBegin(&setupinfo, emsg);
  66. if (faxRecognized) {
  67.     /*
  68.      * If the system is busy then notifyRecvBegun may not return
  69.      * quickly.  Thus we run it in a child process and move on.
  70.      */
  71.     waitNotifyPid = fork(); // waitNotifyPid keeps the notifies ordered
  72.     switch (waitNotifyPid) {
  73. case 0:
  74.     // NB: partially fill in info for notification call
  75.     notifyRecvBegun(info);
  76.     sleep(1); // XXX give parent time
  77.     _exit(0);
  78. case -1:
  79.     logError("Can not fork for non-priority processing.");
  80.     notifyRecvBegun(info);
  81.     break;
  82. default:
  83.     Dispatcher::instance().startChild(waitNotifyPid, this);
  84.     break;
  85.     }
  86.     if (!recvDocuments(tif, info, docs, &setupinfo, emsg)) {
  87. traceProtocol("RECV FAX: %s", (const char*) emsg);
  88. modem->recvAbort();
  89.     }
  90.     if (!modem->recvEnd(&setupinfo, emsg))
  91. traceProtocol("RECV FAX: %s", (const char*) emsg);
  92. } else {
  93.     traceProtocol("RECV FAX: %s", (const char*) emsg);
  94.     TIFFClose(tif);
  95. }
  96.     } else
  97. traceServer("RECV FAX: %s", (const char*) emsg);
  98.     clientInfo.setSenderSkipsV29(setupinfo.senderSkipsV29);
  99.     clientInfo.setSenderHasV17Trouble(setupinfo.senderHasV17Trouble);
  100.     /*
  101.      * Possibly issue a command upon successful reception.
  102.      */
  103.     if (info.npages > 0 && info.reason == "")
  104.     modem->recvSucceeded();
  105.     /*
  106.      * Now that the session is completed, do local processing
  107.      * that might otherwise slow down the protocol (and potentially
  108.      * cause timing problems).
  109.      */
  110.     for (u_int i = 0, n = docs.length(); i < n; i++) {
  111. FaxRecvInfo& ri = docs[i];
  112. if (ri.npages == 0)
  113.     Sys::unlink(ri.qfile);
  114. else
  115.     Sys::chmod(ri.qfile, recvFileMode);
  116. if (faxRecognized)
  117.     notifyRecvDone(ri);
  118.     }
  119.     traceProtocol("RECV FAX: end");
  120.     return (faxRecognized);
  121. }
  122. int
  123. FaxServer::getRecvFile(fxStr& qfile, fxStr& emsg)
  124. {
  125.     u_long seqnum = Sequence::getNext(FAX_RECVDIR "/" FAX_SEQF, emsg);
  126.     if (seqnum == (u_long) -1)
  127. return -1;
  128.     qfile = fxStr::format(FAX_RECVDIR "/fax" | Sequence::format | ".tif", seqnum);
  129.     int ftmp = Sys::open(qfile, O_RDWR|O_CREAT|O_EXCL, recvFileMode);
  130.     if (ftmp < 0)
  131.         emsg = "Failed to find unused filename";
  132.     (void) flock(ftmp, LOCK_EX);
  133.     return ftmp;
  134. }
  135. /*
  136.  * Create and lock a temp file for receiving data.
  137.  */
  138. TIFF*
  139. FaxServer::setupForRecv(FaxRecvInfo& ri, FaxRecvInfoArray& docs, fxStr& emsg)
  140. {
  141.     int ftmp = getRecvFile(ri.qfile, emsg);
  142.     if (ftmp >= 0) {
  143. ri.commid = getCommID(); // should be set at this point
  144. ri.npages = 0; // mark it to be deleted...
  145. docs.append(ri); // ...add it in to the set
  146. TIFF* tif = TIFFFdOpen(ftmp, ri.qfile, "w");
  147. if (tif != NULL)
  148.     return (tif);
  149. Sys::close(ftmp);
  150. emsg = fxStr::format("Unable to open TIFF file %s for writing",
  151.     (const char*) ri.qfile);
  152. ri.reason = emsg; // for notifyRecvDone
  153.     } else
  154. emsg.insert("Unable to create temp file for received data: ");
  155.     return (NULL);
  156. }
  157. /*
  158.  * Receive one or more documents.
  159.  */
  160. bool
  161. FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, FaxSetup* setupinfo, fxStr& emsg)
  162. {
  163.     bool recvOK;
  164.     u_int ppm = PPM_EOP;
  165.     batchid = getCommID();
  166.     for (;;) {
  167. bool okToRecv = true;
  168. fxStr reason;
  169. modem->getRecvSUB(info.subaddr); // optional subaddress
  170. /*
  171.  * Check a received TSI/PWD against the list of acceptable
  172.  * patterns defined for the server.  This form of access
  173.  * control depends on the sender passing a valid TSI/PWD.
  174.  * Note that to accept/reject unspecified values one
  175.  * should match "<UNSPECIFIED>".
  176.  *
  177.  * NB: Caller-ID access control is done elsewhere; prior
  178.  *     to answering a call.
  179.  */
  180. if (!modem->getRecvTSI(info.sender)) // optional TSI
  181.     info.sender = "<UNSPECIFIED>";
  182. if (qualifyTSI != "") {
  183.     okToRecv = isTSIOk(info.sender);
  184.     reason = "Permission denied (unnacceptable client TSI)";
  185.     traceServer("%s TSI "%s"", okToRecv ? "ACCEPT" : "REJECT",
  186. (const char*) info.sender);
  187. }
  188. if (!modem->getRecvPWD(info.passwd)) // optional PWD
  189.     info.passwd = "<UNSPECIFIED>";
  190. if (qualifyPWD != "") {
  191.     okToRecv = isPWDOk(info.passwd);
  192.     reason = "Permission denied (unnacceptable client PWD)";
  193.     traceServer("%s PWD "%s"", okToRecv ? "ACCEPT" : "REJECT",
  194. (const char*) info.passwd);
  195. }
  196. if (okToRecv) okToRecv = processTSIRecvdCmd(info, reason);
  197. if (!okToRecv) {
  198.     emsg = reason;
  199.     info.time = (u_int) getFileTransferTime();
  200.     info.reason = emsg;
  201.     docs[docs.length()-1] = info;
  202.     notifyDocumentRecvd(info);
  203.     TIFFClose(tif);
  204.     return (false);
  205. }
  206. fxStr statusmsg = fxStr::format("Receiving from "%s"", (const char*) info.sender);
  207. for (u_int i = 0; i < info.callid.size(); i++) {
  208.     if (info.callid[i].length() && modem->doCallIDDisplay(i)) {
  209. statusmsg.append(", ");
  210. statusmsg.append(modem->getCallIDLabel(i));
  211. statusmsg.append(":");
  212. statusmsg.append(info.callid[i]);
  213.     }
  214. }
  215. setServerStatus((const char*) statusmsg);
  216. recvOK = recvFaxPhaseD(tif, info, ppm, emsg);
  217. TIFFClose(tif);
  218. info.time = (u_int) getFileTransferTime();
  219. info.reason = emsg;
  220. docs[docs.length()-1] = info;
  221. /*
  222.  * If syslog is busy then notifyDocumentRecvd may not return
  223.  * quickly.  Thus we run it in a child process and move on.
  224.  */
  225. if (waitNotifyPid > 0) (void) Sys::waitpid(waitNotifyPid); // keep the notifies ordered
  226. waitNotifyPid = fork();
  227. switch (waitNotifyPid) {
  228.     case 0:
  229. notifyDocumentRecvd(info);
  230. sleep(1); // XXX give parent time
  231. _exit(0);
  232.     case -1:
  233. logError("Can not fork for non-priority logging.");
  234. notifyDocumentRecvd(info);
  235. break;
  236.     default:
  237. Dispatcher::instance().startChild(waitNotifyPid, this);
  238. break;
  239. }
  240. if (!recvOK || ppm == PPM_EOP)
  241.     return (recvOK);
  242. /*
  243.  * Setup state for another file.
  244.  */
  245. if (! batchLogs)
  246. {
  247.     traceServer("SESSION BATCH CONTINUING");
  248.     endSession();
  249.     beginSession(FAXNumber);
  250.     batchid.append(","|getCommID());
  251.     traceServer("SESSION BATCH %s", (const char*)batchid);
  252. }
  253. tif = setupForRecv(info, docs, emsg);
  254. if (tif == NULL)
  255.     return (false);
  256. fileStart = pageStart = Sys::now();
  257. if (!modem->recvEOMBegin(setupinfo, emsg)) {
  258.     info.reason = emsg;
  259.     docs[docs.length()-1] = info;
  260.     TIFFClose(tif);
  261.     return (false);
  262. }
  263.     }
  264.     /*NOTREACHED*/
  265. }
  266. /*
  267.  * Receive Phase B protocol processing.
  268.  */
  269. bool
  270. FaxServer::recvFaxPhaseD(TIFF* tif, FaxRecvInfo& info, u_int& ppm, fxStr& emsg)
  271. {
  272.     fxStr id = info.sender;
  273.     for (u_int i = 0; i < info.callid.size(); i++) {
  274. if (modem->doCallIDRecord(i)) {
  275.     id.append('n');
  276.     if (modem->getCallIDLabel(i).length()) {
  277. id.append(modem->getCallIDLabel(i));
  278. id.append('t');
  279.     }
  280.     id.append(info.callid[i]);
  281. }
  282.     }
  283.     do {
  284. ++recvPages;
  285. if (!modem->recvPage(tif, ppm, emsg, id))
  286.     return (false);
  287. info.npages++;
  288. info.time = (u_int) getPageTransferTime();
  289. info.params = modem->getRecvParams();
  290. /*
  291.  * If syslog is busy then notifyPageRecvd may not return quickly.
  292.  * Thus we run it in a child process and move on.  Timestamps
  293.  * in syslog cannot be expected to have exact precision anyway.
  294.  */
  295. if (waitNotifyPid > 0) (void) Sys::waitpid(waitNotifyPid); // keep the notifies ordered
  296. waitNotifyPid = fork();
  297. switch (waitNotifyPid) {
  298.     case 0:
  299. notifyPageRecvd(tif, info, ppm);
  300. sleep(1); // XXX give parent time
  301. _exit(0);
  302.     case -1:
  303. logError("Can not fork for non-priority logging.");
  304. notifyPageRecvd(tif, info, ppm);
  305. break;
  306.     default:
  307. Dispatcher::instance().startChild(waitNotifyPid, this);
  308. break;
  309. }
  310. if (emsg != "") return (false); // got page with fatal error
  311. if (PPM_PRI_MPS <= ppm && ppm <= PPM_PRI_EOP) {
  312.     emsg = "Procedure interrupt received, job terminated {E051}";
  313.     return (false);
  314. }
  315. if (recvPages > maxRecvPages) {
  316.     emsg = "Maximum receive page count exceeded, call terminated {E304}";
  317.     return (false);
  318. }
  319.     } while (ppm == PPM_MPS || ppm == PPM_PRI_MPS);
  320.     return (true);
  321. }
  322. void
  323. FaxServer::notifyRecvBegun(FaxRecvInfo&)
  324. {
  325. }
  326. bool
  327. FaxServer::processTSIRecvdCmd(FaxRecvInfo&, fxStr&)
  328. {
  329.     return (true);
  330. }
  331. /*
  332.  * Handle notification that a page has been received.
  333.  */
  334. void
  335. FaxServer::notifyPageRecvd(TIFF*, FaxRecvInfo& ri, int)
  336. {
  337.     traceServer("RECV FAX (%s): from %s, page %u in %s, %s, %s, %s, %s"
  338. , (const char*) ri.commid
  339. , (const char*) ri.sender
  340. , ri.npages
  341. , fmtTime((time_t) ri.time)
  342. , (ri.params.ln == LN_A4 ? "A4" : ri.params.ln == LN_B4 ? "B4" : "INF")
  343. , ri.params.verticalResName()
  344. , ri.params.dataFormatName()
  345. , ri.params.bitRateName()
  346.     );
  347. }
  348. /*
  349.  * Handle notification that a document has been received.
  350.  */
  351. void
  352. FaxServer::notifyDocumentRecvd(FaxRecvInfo& ri)
  353. {
  354.     traceServer("RECV FAX (%s): %s from %s, subaddress %s, %u pages in %s"
  355. , (const char*) ri.commid
  356. , (const char*) ri.qfile
  357. , (const char*) ri.sender
  358. , ri.subaddr != "" ? (const char*) ri.subaddr : "<unspecified>"
  359. , ri.npages
  360. , fmtTime((time_t) ri.time)
  361.     );
  362. }
  363. /*
  364.  * Handle final actions associated with a document being received.
  365.  */
  366. void
  367. FaxServer::notifyRecvDone(FaxRecvInfo& ri)
  368. {
  369.     if (ri.reason != "")
  370. traceServer("RECV FAX (%s): session with %s terminated abnormally: %s"
  371.     , (const char*) ri.commid
  372.     , (const char*) ri.sender
  373.     , (const char*) ri.reason
  374. );
  375. }