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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: pageSendApp.c++,v 1.10 2009/07/13 04:50:41 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 <sys/types.h>
  27. #include <unistd.h>
  28. #include <errno.h>
  29. #include <fcntl.h>
  30. #include <stdlib.h>
  31. #include <sys/file.h>
  32. #include <signal.h>
  33. #include <ctype.h>
  34. #include "FaxMachineInfo.h"
  35. #include "FaxAcctInfo.h"
  36. #include "UUCPLock.h"
  37. #include "pageSendApp.h"
  38. #include "FaxRequest.h"
  39. #include "Dispatcher.h"
  40. #include "StackBuffer.h"
  41. #include "Sys.h"
  42. #include "ixo.h"
  43. #include "config.h"
  44. /*
  45.  * Send messages with IXO/TAP protocol.
  46.  */
  47. pageSendApp* pageSendApp::_instance = NULL;
  48. pageSendApp::pageSendApp(const fxStr& devName, const fxStr& devID)
  49.     : ModemServer(devName, devID)
  50. {
  51.     ready = false;
  52.     modemLock = NULL;
  53.     setupConfig();
  54.     fxAssert(_instance == NULL, "Cannot create multiple pageSendApp instances");
  55.     _instance = this;
  56. }
  57. pageSendApp::~pageSendApp()
  58. {
  59.     delete modemLock;
  60. }
  61. pageSendApp& pageSendApp::instance() { return *_instance; }
  62. void
  63. pageSendApp::initialize(int argc, char** argv)
  64. {
  65.     ModemServer::initialize(argc, argv);
  66.     faxApp::initialize(argc, argv);
  67.     // NB: must do last to override config file information
  68.     for (GetoptIter iter(argc, argv, getOpts()); iter.notDone(); iter++)
  69. switch (iter.option()) {
  70. case 'l': // do uucp locking
  71.     modemLock = getUUCPLock(getModemDevice());
  72.     break;
  73. case 'c': // set configuration parameter
  74.     readConfigItem(iter.optArg());
  75.     break;
  76. }
  77. }
  78. void
  79. pageSendApp::open()
  80. {
  81.     ModemServer::open();
  82.     faxApp::open();
  83. }
  84. void
  85. pageSendApp::close()
  86. {
  87.     if (isRunning()) {
  88. if (state == ModemServer::SENDING) {
  89.     /*
  90.      * Terminate the active job and let the send
  91.      * operation complete so that the transfer is
  92.      * logged and the appropriate exit status is
  93.      * returned to the caller.
  94.      */
  95.     ModemServer::abortSession();
  96. } else {
  97.     ModemServer::close();
  98.     faxApp::close();
  99. }
  100.     }
  101. }
  102. # define BATCH_FIRST 1
  103. # define BATCH_LAST  2
  104. FaxSendStatus
  105. pageSendApp::send(const char** filenames, int num)
  106. {
  107.     u_int batched = BATCH_FIRST;
  108.     FaxSendStatus status = send_done;
  109.     fxStr batchcommid, notice, errorcode;
  110.     time_t retrybatchtts = 0;
  111.     for (int i = 0; i < num; i++) {
  112. if (i+1 == num)
  113.     batched |= BATCH_LAST;
  114.     
  115. int fd = Sys::open(filenames[i], O_RDWR);
  116. if (fd >= 0) {
  117.     if (flock(fd, LOCK_EX) >= 0) {
  118. FaxRequest* req = new FaxRequest(filenames[i], fd);
  119. bool reject;
  120. if (req->readQFile(reject) && !reject) {
  121.     if (status == send_done) {
  122. if (req->findItem(FaxRequest::send_page) != fx_invalidArrayIndex) {
  123.     FaxMachineInfo info;
  124.     info.updateConfig(canonicalizePhoneNumber(req->number));
  125.     FaxAcctInfo ai;
  126.     ai.start = Sys::now();
  127.     req->commid = batchcommid; // pass commid on...
  128.     sendPage(*req, info, batched);
  129.     batchcommid = req->commid; // ... to all batched jobs
  130.     ai.jobid = req->jobid;
  131.     ai.jobtag = req->jobtag;
  132.     ai.user = req->mailaddr;
  133.     ai.duration = Sys::now() - ai.start;
  134.     ai.conntime = getConnectTime();
  135.     ai.commid = req->commid;
  136.     ai.device = getModemDeviceID();
  137.     ai.dest = req->external;
  138.     ai.csi = "";
  139.     ai.params = 0;
  140.     ai.npages = 0;
  141.     CallID empty_callid;
  142.     ai.callid = empty_callid;
  143.     ai.owner = req->owner;
  144.     if (req->status == send_done)
  145. ai.status = "";
  146.     else {
  147. errorcode = req->errorcode;
  148. notice = req->notice;
  149. ai.status = req->notice;
  150. retrybatchtts = req->tts;
  151.     }
  152.     ai.jobinfo = fxStr::format("%u/%u/%u/%u/%u/%u/%u", 
  153. req->totpages, req->ntries, req->ndials, req->totdials, req->maxdials, req->tottries, req->maxtries);
  154.     if (!ai.record("PAGE"))
  155. logError("Error writing %s accounting record, dest=%s",
  156.     "PAGE", (const char*) ai.dest);
  157. } else
  158.     sendFailed(*req, send_failed, "Job has no PIN to send to");
  159. status = req->status;
  160.     } else {
  161. /*
  162.  * This job cannot get sent right now due to an error in a previous
  163.  * job in the batch.
  164.  *
  165.  * In the event that the previous error was not an in-job error (e.g.
  166.  * a busy signal) then we treat that error as if it applies to all jobs.
  167.  * We "keep the batch together" by synchronizing their tts.
  168.  *
  169.  * In the event that the previous error was an in-job error, then the
  170.  * previous job processing is essentially blocking this job from
  171.  * processing, and so we set the notice accordingly and don't increase
  172.  * the dial-count.  In case batching itself triggered the problem, we
  173.  * don't set the tts, allowing faxq to reschedule the job, expecting that
  174.  * to disassemble and "shuffle" the entire batch.
  175.  */
  176. if (errorcode == "E001" ||
  177.     errorcode == "E002" ||
  178.     errorcode == "E003") {
  179.     /* busy, no carrier, no answer */
  180.     req->notice = notice;
  181.     req->status = send_retry;
  182.     req->tts = retrybatchtts;
  183.     req->totdials++;
  184. } else {
  185.     req->notice = "Blocked by another job";
  186.     req->status = send_retry;
  187. }
  188.     }
  189.     req->writeQFile(); // update on-disk copy
  190.     delete req;
  191. } else {
  192.     delete req;
  193.     logError("Could not read request file");
  194.     status = send_failed;
  195. }
  196.     } else {
  197. logError("Could not lock request file: %m");
  198. Sys::close(fd);
  199. status = send_failed;
  200.     }
  201. } else {
  202.     logError("Could not open request file "%s": %m", filenames[i]);
  203.     status = send_failed;
  204. }
  205. batched = 0; // disable BATCH_FIRST and BATCH_LAST routines
  206.     }
  207.     return (status); // return status for exit
  208. }
  209. void
  210. pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, u_int& batched)
  211. {
  212.     if (!(batched & BATCH_FIRST) || lockModem()) {
  213.         if (batched & BATCH_FIRST) {
  214.             beginSession(req.number);
  215.             batchid = getCommID();
  216.         }
  217.         req.commid = getCommID();        // set by beginSession
  218.         traceServer("SEND PAGE (possibly batched): JOB %s DEST %s COMMID %s DEVICE '%s'"
  219.                     , (const char*) req.jobid
  220.                     , (const char*) req.external
  221.                     , (const char*) req.commid
  222.                     , (const char*) getModemDevice()
  223.                    );
  224. /*
  225.  * Setup tty parity; per-destination information takes
  226.  * precedence over command-line arguments/config params;
  227.  * otherwise the IXO/TAP spec is used (set below).
  228.  */
  229. if (info.getPagerTTYParity() != "")
  230.     pagerTTYParity = info.getPagerTTYParity();
  231. // NB: may need to set tty baud rate here XXX
  232.         if (!(batched & BATCH_FIRST) || setupModem(true)) {
  233.     changeState(SENDING);
  234.     setServerStatus("Sending page " | req.jobid);
  235.     /*
  236.      * Construct the phone number to dial by applying the
  237.      * dialing rules to the user-specified dialing string.
  238.      */
  239.     fxStr msg;
  240.     if (prepareMsg(req, info, msg))
  241. sendPage(req, info, prepareDialString(req.number), msg, batched);
  242.         } else
  243.        sendFailed(req, send_retry, "Can not setup modem", 4*pollModemWait);
  244.         if ((batched & BATCH_LAST) || (req.status != send_done)) {
  245.             discardModem(true);
  246.             changeState(MODEMWAIT, 5);
  247.             unlockModem();
  248.             endSession();
  249.         } 
  250.     } else {
  251. sendFailed(req, send_retry, "Can not lock modem device",2*pollLockWait);
  252.     }
  253. }
  254. bool
  255. pageSendApp::prepareMsg(FaxRequest& req, FaxMachineInfo& info, fxStr& msg)
  256. {
  257.     u_int i = req.findItem(FaxRequest::send_data);
  258.     if (i == fx_invalidArrayIndex) // page w/o text
  259. return (true);
  260.     int fd = Sys::open(req.items[i].item, O_RDONLY);
  261.     if (fd < 0) {
  262. sendFailed(req, send_failed,
  263.     "Internal error: unable to open text message file");
  264. return (false);
  265.     }
  266.     struct stat sb;
  267.     (void) Sys::fstat(fd, sb);
  268.     msg.resize((u_int) sb.st_size);
  269.     if (Sys::read(fd, &msg[0], (u_int) sb.st_size) != sb.st_size) {
  270. sendFailed(req, send_failed,
  271.     "Internal error: unable to read text message file");
  272. return (false);
  273.     }
  274.     Sys::close(fd);
  275.     u_int maxMsgLen = info.getPagerMaxMsgLength();
  276.     if (maxMsgLen == (u_int) -1) // not set, use default
  277. maxMsgLen = pagerMaxMsgLength;
  278.     if (msg.length() > maxMsgLen) {
  279. traceServer("Pager message length %u too large; truncated to %u",
  280.     msg.length(), maxMsgLen);
  281. msg.resize(maxMsgLen);
  282.     }
  283.     return (true);
  284. }
  285. void
  286. pageSendApp::sendFailed(FaxRequest& req, FaxSendStatus stat, const char* notice, u_int tts)
  287. {
  288.     req.status = stat;
  289.     req.notice = notice;
  290.     /*
  291.      * When requeued for the default interval (called with 3 args),
  292.      * don't adjust the time-to-send field so that the spooler
  293.      * will set it according to the default algorithm that 
  294.      * uses the command-line parameter or requeueOther and a random jitter.
  295.      */
  296.     if (tts != 0)
  297. req.tts = Sys::now() + tts;
  298.     traceServer("PAGE FAILED: %s", notice);
  299. }
  300. void
  301. pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number, const fxStr& msg, u_int& batched)
  302. {
  303.     connTime = 0; // indicate no connection
  304.     if ((batched & BATCH_FIRST) && !getModem()->dataService()) {
  305. sendFailed(req, send_failed, "Unable to configure modem for data use");
  306. return;
  307.     }
  308.     req.notice = "";
  309.     fxStr notice;
  310.     time_t pageStart = Sys::now();
  311.     if (batched & BATCH_FIRST) {
  312.         if (info.getPagerSetupCmds() != "")        // use values from info file
  313.             pagerSetupCmds = info.getPagerSetupCmds();
  314.         if (pagerSetupCmds != "")            // configure line speed, etc.
  315.             (void) getModem()->atCmd(pagerSetupCmds);
  316.     }
  317.     CallStatus callstat;
  318.     if (batched & BATCH_FIRST)
  319.         callstat = getModem()->dial(number, req.faxnumber, notice);
  320.     else
  321.         callstat = ClassModem::OK;
  322.     if (callstat == ClassModem::OK)
  323. connTime = Sys::now(); // connection start time
  324.     (void) abortRequested(); // check for user abort
  325.     if (callstat == ClassModem::OK && !abortCall) {
  326. req.ndials = 0; // consec. failed dial attempts
  327. req.tottries++; // total answered calls
  328. req.totdials++; // total attempted calls
  329. info.setCalledBefore(true);
  330. info.setDialFailures(0);
  331. req.status = send_ok; // be optimistic
  332. // from this point on, the treatment of the two protocols differs
  333. if (streq(info.getPagingProtocol(), "ixo")) {
  334.     sendIxoPage(req, info, msg, notice, batched);
  335. } else if (streq(info.getPagingProtocol(), "ucp")) {
  336.     sendUcpPage(req, info, msg, notice);
  337. } else {
  338.     notice = req.notice | "; paging protocol unknown ";
  339.     sendFailed(req, send_failed, notice);
  340.     req.status = send_failed;
  341. }
  342. // here again, we have identical code
  343. if (req.status == send_ok) {
  344.     time_t now = Sys::now();
  345.     traceServer("SEND PAGE: FROM " | req.mailaddr
  346. | " TO " | req.external | " (sent in %s)",
  347. fmtTime(now - pageStart));
  348.     info.setSendFailures(0);
  349. } else {
  350.     info.setSendFailures(info.getSendFailures()+1);
  351.     info.setLastSendFailure(req.notice);
  352. }
  353.     } else if (!abortCall) {
  354. /*
  355.  * Analyze the call status codes and selectively decide if the
  356.  * job should be retried.  We try to avoid the situations where
  357.  * we might be calling the wrong number so that we don't end up
  358.  * harrassing someone w/ repeated calls.
  359.  */
  360. req.ndials++;
  361. req.totdials++; // total attempted calls
  362. switch (callstat) {
  363. case ClassModem::NOCARRIER: // no carrier detected on remote side
  364.     /*
  365.      * Since some modems can not distinguish between ``No Carrier''
  366.      * and ``No Answer'' we offer this configurable hack whereby
  367.      * we'll retry the job <n> times in the face of ``No Carrier''
  368.      * dialing errors; if we've never previously reached a modem
  369.      * at that number.  This should not be used except if
  370.      * the modem is incapable of distinguishing between
  371.      * ``No Carrier'' and ``No Answer''.
  372.      */
  373.     if (!info.getCalledBefore() && req.ndials > retryMAX[callstat]) {
  374. sendFailed(req, send_failed, notice);
  375. break;
  376.     }
  377.     /* fall thru... */
  378. case ClassModem::NODIALTONE: // no local dialtone, possibly unplugged
  379. case ClassModem::ERROR: // modem might just need to be reset
  380. case ClassModem::FAILURE: // modem returned something unexpected
  381. case ClassModem::BUSY: // busy signal
  382. case ClassModem::NOANSWER: // no answer or ring back
  383.     sendFailed(req, send_retry, notice, requeueTTS[callstat]);
  384.     /* fall thru... */
  385. case ClassModem::OK: // call was aborted by user
  386.     break;
  387. }
  388. if (callstat != ClassModem::OK) {
  389.     info.setDialFailures(info.getDialFailures()+1);
  390.     info.setLastDialFailure(req.notice);
  391. }
  392.     }
  393.     if (abortCall)
  394. sendFailed(req, send_retry, "Call aborted by user");
  395.     else if (req.status == send_retry) {
  396. if (req.totdials == req.maxdials) {
  397.     notice = req.notice | "; too many attempts to dial";
  398.     sendFailed(req, send_failed, notice);
  399. } else if (req.tottries == req.maxtries) {
  400.     notice = req.notice | "; too many attempts to send";
  401.     sendFailed(req, send_failed, notice);
  402. }
  403.     }
  404.    if ((batched & BATCH_LAST) || (req.status != send_done))
  405.     {
  406.     /*
  407.      * Cleanup after the call.  If we have new information on
  408.      * the client's remote capabilities, the machine info
  409.      * database will be updated when the instance is destroyed.
  410.      */
  411.     getModem()->hangup();
  412.     }
  413.     /*
  414.      * This may not be exact--the line may already have been
  415.      * dropped--but it should be close enough unless the modem
  416.      * gets wedged and the hangup work times out.  Also be
  417.      * sure to register a non-zero amount of connect time so
  418.      * that folks doing accounting can adjust charge-back costs
  419.      * to reflect any minimum connect time tarrifs imposted by
  420.      * their PTT (e.g. calls < 1 minute are rounded up to 1 min.)
  421.      */
  422.     if (connTime) {
  423. connTime = Sys::now() - connTime;
  424. if (connTime == 0)
  425.     connTime++;
  426.     }
  427. }
  428. /*
  429.  * here comes the IXO specific code for sendPage, search for the
  430.  * string 'BEGIN UCP Support' for UCP specific code
  431.  */
  432. void
  433. pageSendApp::sendIxoPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& msg,
  434.     fxStr& notice, u_int& batched)
  435. {
  436. if (batched & BATCH_FIRST) {
  437. if(!pagePrologue(req, info, notice)) {
  438. sendFailed(req, req.status, notice, requeueProto);
  439. return;
  440. }
  441. }
  442. while (req.items.length() > 0) {    // messages
  443.     u_int i = req.findItem(FaxRequest::send_page);
  444.     if (i == fx_invalidArrayIndex)
  445. break;
  446.     if (req.items[i].item.length() == 0) {
  447. sendFailed(req, send_failed, "No PIN specified");
  448. break;
  449.     }
  450.     if (!sendPagerMsg(req, req.items[i], msg, req.notice)) {
  451. /*
  452.  * On protocol errors retry more quickly
  453.  * (there's no reason to wait is there?).
  454.  */
  455. if (req.status == send_retry) {
  456.     req.tts = time(0) + requeueProto;
  457.     break;
  458. }
  459.     }
  460.     req.items.remove(i);
  461.     }
  462.     if ((batched & BATCH_LAST)
  463.             && req.status == send_ok) {
  464.         (void) pageEpilogue(req, info, notice);
  465.     }
  466. }
  467. u_int
  468. pageSendApp::getResponse(fxStackBuffer& buf, long secs)
  469. {
  470.     buf.reset();
  471.     if (secs) startTimeout(secs*1000);
  472.     for (;;) {
  473. int c = getModemChar(0);
  474. if (c == EOF)
  475.     break;
  476. if (c == 'r' || c == '03') {
  477.     if (buf.getLength() > 0) // discard leading r's or ETX
  478. break;
  479. } else if (c != 'n') // discard all n's
  480.     buf.put(c);
  481.     }
  482.     if (secs) stopTimeout("reading line from modem");
  483.     if (buf.getLength() > 0)
  484. traceIXOCom("-->", (u_char*) (const char*) buf, buf.getLength());
  485.     return (buf.getLength());
  486. }
  487. /*
  488.  * Scan through a buffer looking for a potential
  489.  * code byte return in a protocol response.
  490.  * This is needed because some pager services such
  491.  * as PageNet intersperse protocol messages and
  492.  * verbose text messages.
  493.  */
  494. static bool
  495. scanForCode(const u_char*& cp, u_int& len)
  496. {
  497.     if (len > 0) {
  498. do {
  499.     cp++, len--;
  500. } while (len > 0 &&
  501.     *cp != ACK && *cp != NAK && *cp != ESC && *cp != RS);
  502.     }
  503.     return (len > 0);
  504. }
  505. bool
  506. pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& emsg)
  507. {
  508.     fxStackBuffer buf;
  509.     time_t start;
  510.     /*
  511.      * Send r and wait for ``ID='' response.
  512.      * Repeat at 2 second intervals until a
  513.      * response is received or ntries have
  514.      * been done.
  515.      */
  516.     traceIXO("EXPECT ID (paging central identification)");
  517.     start = Sys::now();
  518.     bool gotID = false;
  519.     do {
  520. putModem("r", 1);
  521. if (getResponse(buf, ixoIDProbe) >= 3) {
  522.     // skip leading white space
  523.     const char* cp;
  524.     for (cp = buf; *cp && isspace(*cp); cp++)
  525. ;
  526.     gotID = strneq(cp, "ID=", 3);
  527. }
  528. if (gotID) {
  529.     traceIXO("RECV ID ("%.*s")",
  530. buf.getLength(), (const char*) buf);
  531. } else
  532.     traceResponse(buf);
  533.     } while (!gotID && (unsigned) Sys::now() - start < ixoIDTimeout);
  534.     if (!gotID) {
  535. emsg = "No initial ID response from paging central {E500}";
  536. req.status = send_retry;
  537. return (false);
  538.     }
  539.     flushModemInput(); // paging central may send multiple ID=
  540.     /*
  541.      * Identify use of automatic protocol (as opposed
  542.      * to manual) and proceed with login procedure:
  543.      *
  544.      *    ESC SST<pwd>.
  545.      *
  546.      * ESC means ``automatic dump mode'' protocol.
  547.      * SS  identifies service:
  548.      *    P = Pager ID
  549.      *    G = Message (?)
  550.      * T identifies type of terminal or device sending:
  551.      *    1 = ``category of entry devices using the same protocol''
  552.      *       (PETs and IXO)
  553.      *    7,8,9 = ``wild card terminals or devices which may 
  554.      *         relate to a specific users' system''.
  555.      * <pwd> is a 6-character alpha-numeric password
  556.      *    string (optional)
  557.      */
  558.     const fxStr& pass = info.getPagerPassword();
  559.     fxStr prolog("33" | ixoService | ixoDeviceID);
  560.     if (pass != "")
  561. prolog.append(pass);
  562.     prolog.append('r');
  563.     traceIXO("SEND device identification/login request");
  564.     putModem((const char*) prolog, prolog.length());
  565.     int ntries = ixoLoginRetries; // retry login up to 3 times
  566.     int unknown = ixoMaxUnknown; // accept up to 3 unknown messages
  567.     start = Sys::now();
  568.     do {
  569. u_int len = getResponse(buf, ixoLoginTimeout);
  570. const u_char* cp = buf;
  571. while (len > 0) {
  572.     switch (cp[0]) {
  573.     case ACK: // login successful, wait for go-ahead
  574. traceIXO("RECV ACK (login successful)");
  575. return (pageGoAhead(req, info, emsg));
  576.     case NAK: // login failed, retry
  577. traceIXO("RECV NAK (login unsuccessful)");
  578. if (--ntries == 0) {
  579.     emsg = "Login failed multiple times {E501}";
  580.     req.status = send_retry;
  581.     return (false);
  582. }
  583. /*
  584.  * Resend the login request.
  585.  */
  586. traceIXO("SEND device identification/login request");
  587. putModem((const char*) prolog, prolog.length());
  588. start = Sys::now(); // restart timer
  589. /*
  590.  * NB: we should just goto the top of the loop,
  591.  *     but old cfront-based compilers aren't
  592.  *     smart enough to handle goto's that might
  593.  *     bypass destructors.
  594.  */
  595. unknown++; // counteract loop iteration
  596. len = 0; // don't scan forward in buffer
  597. break;
  598.     case ESC:
  599. if (len > 1) {
  600.     if (cp[1] == EOT) {
  601. traceIXO("RECV EOT (forced disconnect)");
  602. emsg =
  603.     "Paging central responded with forced disconnect";
  604. req.status = send_failed;
  605. return (false);
  606.     }
  607.     // check for go-ahead message
  608.     if (len > 2 && cp[1] == '[' && cp[2] == 'p') {
  609. traceIXO("RECV ACK (login successful & got go-ahead)");
  610. return (true);
  611.     }
  612. }
  613. break;
  614.     }
  615.     if (!scanForCode(cp, len))
  616. traceResponse(buf);
  617. }
  618.     } while ((unsigned)Sys::now()-start < ixoLoginTimeout && --unknown != 0);
  619.     emsg = fxStr::format("Protocol failure: %s from paging central {E502}",
  620. (unknown ?
  621.     "timeout waiting for response" : "too many unknown responses"));
  622.     req.status = send_retry;
  623.     return (false);
  624. }
  625. bool
  626. pageSendApp::pageGoAhead(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
  627. {
  628.     fxStackBuffer buf;
  629.     time_t start = Sys::now();
  630.     u_int unknown = ixoMaxUnknown;
  631.     do {
  632. u_int len = getResponse(buf, ixoGATimeout);
  633. const u_char* cp = buf;
  634. while (len > 0) {
  635.     if (len > 2 && cp[0] == ESC && cp[1] == '[' && cp[2] == 'p') {
  636. traceIXO("RECV go-ahead (prologue done)");
  637. return (true);
  638.     }
  639.     (void) scanForCode(cp, len);
  640. }
  641. traceResponse(buf);
  642.     } while ((unsigned) Sys::now()-start < ixoGATimeout && --unknown != 0);
  643.     emsg = fxStr::format("Protocol failure: %s waiting for go-ahead message {E503}",
  644. unknown ? "timeout" : "too many unknown responses");
  645.     req.status = send_retry;
  646.     return (false);
  647. }
  648. /*
  649.  * Calculate packet checksum and append to buffer.
  650.  */
  651. static void
  652. addChecksum(fxStackBuffer& buf)
  653. {
  654.     int sum = 0;
  655.     for (u_int i = 0; i < buf.getLength(); i++)
  656. sum += buf[i];
  657.     char check[3];
  658.     check[2] = '0' + (sum & 15); sum = sum >> 4;
  659.     check[1] = '0' + (sum & 15); sum = sum >> 4;
  660.     check[0] = '0' + (sum & 15);
  661.     buf.put(check, 3);
  662. }
  663. bool
  664. pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxStr& emsg)
  665. {
  666.     /*
  667.      * Build page packet:
  668.      *
  669.      *    STX pin CR line1 CR ... linen CR EEE checksum CR
  670.      *
  671.      * where pin is the destination Pager ID and line<n>
  672.      * are the lines of the message to send.  The trailing
  673.      * EEE depends on whether or not the message is continued
  674.      * on into the next block and/or whether this is the last
  675.      * block in the transaction.
  676.      */
  677.     fxStackBuffer buf;
  678.     buf.put(STX);
  679.     buf.put(preq.item); // copy PIN to packet
  680.     buf.put('r');
  681.     buf.put(msg); // copy text message
  682.     buf.put('r');
  683.     buf.put(ETX); // XXX
  684.     addChecksum(buf); // append packet checksum
  685.     buf.put('r');
  686.     /*
  687.      * Send the packet to paging central.
  688.      */
  689.     traceIXO("SEND message block");
  690.     putModem((const char*) buf, buf.getLength());
  691.     /*
  692.      * Process replies, possibly retransmitting the packet.
  693.      */
  694.     fxStackBuffer resp; // paging central response
  695.     u_int ntries = ixoXmitRetries; // up to 3 xmits of message
  696.     u_int unknown = 0; // count of unknown responses
  697.     time_t start = Sys::now();
  698.     do {
  699. u_int len = getResponse(resp, ixoXmitTimeout);
  700. const u_char* cp = resp;
  701. while (len > 0) {
  702.     switch (cp[0]) {
  703.     case ACK:
  704. traceIXO("RECV ACK (message block accepted)");
  705. return (true);
  706.     case NAK:
  707. traceIXO("RECV NAK (message block rejected)");
  708. if (--ntries == 0) {
  709.     req.status = send_retry;
  710.     emsg = "Message block not acknowledged by paging central "
  711. "after multiple tries {E504}";
  712.     return (false);
  713. }
  714. /*
  715.  * Retransmit the packet to paging central.
  716.  */
  717. traceIXO("SEND message block (retransmit)");
  718. putModem((const char*) buf, buf.getLength());
  719. start = Sys::now(); // restart timer
  720. unknown = 0; // reset unknown response count
  721. /*
  722.  * NB: we should just goto the top of the loop,
  723.  *     but old cfront-based compilers aren't
  724.  *     smart enough to handle goto's that might
  725.  *     bypass destructors.
  726.  */
  727. len = 0; // flush response buffer
  728. flushModemInput(); // flush pending data
  729. break;
  730.     case RS:
  731. traceIXO("RECV RS (message block rejected; skip to next)");
  732. /*
  733.  * This actually means to abandon the current transaction
  734.  * and proceed to the next.  However we treat it as a
  735.  * total failure since it's not clear within the present
  736.  * design whether proceeding to the next transaction is
  737.  * the right thing to do.
  738.  */
  739. req.status = send_failed;
  740. emsg = "Message block transmit failed; "
  741.     "paging central rejected it {E505}";
  742. return (false);
  743.     case ESC:
  744. if (len > 1 && cp[1] == EOT) {
  745.     traceIXO("RECV EOT (forced disconnect)");
  746.     req.status = send_failed;
  747.     emsg = "Protocol failure: paging central responded to "
  748. "message block transmit with forced disconnect {E506}";
  749.     return (false);
  750. }
  751. /* fall thru... */
  752.     default: // unrecognized response
  753. unknown++;
  754. break;
  755.     }
  756.     if (!scanForCode(cp, len))
  757. traceResponse(resp);
  758. }
  759.     } while ((unsigned)Sys::now()-start < ixoXmitTimeout && unknown < ixoMaxUnknown);
  760.     emsg = fxStr::format("Protocol failure: %s to message block transmit {E507}",
  761. (unknown ?
  762.     "timeout waiting for response" : "too many unknown responses"));
  763.     req.status = send_retry;
  764.     return (false);
  765. }
  766. bool
  767. pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
  768. {
  769.     putModem("4r", 2); // EOT then <CR>
  770.     fxStackBuffer buf;
  771.     time_t start = Sys::now();
  772.     do {
  773. u_int len = getResponse(buf, ixoAckTimeout);
  774. const u_char* cp = buf;
  775. while (len > 0) {
  776.     switch (cp[0]) {
  777.     case ESC:
  778. if (len > 1 && cp[1] == EOT) {
  779.     traceIXO("RECV EOT (disconnect)");
  780.     return (true);
  781. }
  782. break;
  783.     case RS:
  784. traceIXO("RECV RS (message content rejected)");
  785. emsg = "Paging central rejected content; check PIN {E508}";
  786. req.status = send_failed;
  787. return (false);
  788.     }
  789.     (void) scanForCode(cp, len);
  790. }
  791. traceResponse(buf);
  792. // NB: ignore unknown responses
  793.     } while ((unsigned)Sys::now() - start < ixoAckTimeout);
  794.     req.status = send_retry;
  795.     emsg = "Protocol failure: timeout waiting for transaction ACK/NAK "
  796. "from paging central {E509}";
  797.     return (false);
  798. }
  799. void
  800. pageSendApp::traceResponse(const fxStackBuffer& buf)
  801. {
  802.     const char* extra = "";
  803.     u_int len = buf.getLength();
  804.     if (len > 0) {
  805. const char* cp = buf;
  806. do {
  807.     if (!isprint(*cp++)) {
  808. extra = "unknown paging central response";
  809. break;
  810.     }
  811. } while (--len);
  812. /*
  813.  * No unprintable characters, just log the string w/o
  814.  * the alarming "Unknown paging central response".
  815.  */
  816. traceIXO("RECV%s: %.*s", extra, buf.getLength(), (const char*) buf);
  817.     }
  818. }
  819. void
  820. pageSendApp::traceIXOCom(const char* dir, const u_char* data, u_int cc)
  821. {
  822.     if (log) {
  823. if ((logTracingLevel& FAXTRACE_IXO) == 0)
  824.     return;
  825.     } else if ((tracingLevel & FAXTRACE_IXO) == 0)
  826. return;
  827.     fxStackBuffer buf;
  828.     for (u_int i = 0; i < cc; i++) {
  829. u_char b = data[i];
  830. if (!isprint(b)) {
  831.     const char* octdigits = "01234567";
  832.     char s[4];
  833.     s[0] = '\';
  834.     s[1] = octdigits[b>>6];
  835.     s[2] = octdigits[(b>>3)&07];
  836.     s[3] = octdigits[b&07];
  837.     buf.put(s, 4);
  838. } else
  839.     buf.put(b);
  840.     }
  841.     traceStatus(FAXTRACE_IXO, "%s <%u:%.*s>",
  842. dir, cc, buf.getLength(), (const char*) buf);
  843. }
  844. void
  845. pageSendApp::traceIXO(const char* fmt ...)
  846. {
  847.     va_list ap;
  848.     va_start(ap, fmt);
  849.     vtraceStatus(FAXTRACE_PROTOCOL, fmt, ap);
  850.     va_end(ap);
  851. }
  852. /*
  853.  * BEGIN UCP Support
  854.  */
  855. void
  856. pageSendApp::sendUcpPage(FaxRequest& req, FaxMachineInfo& info,
  857.     const fxStr& msg, fxStr& notice)
  858. {
  859.     while (req.items.length() > 0) { // messages
  860.         u_int i = req.findItem(FaxRequest::send_page);
  861. if (i == fx_invalidArrayIndex)
  862.     break;
  863. if (req.items[i].item.length() == 0) {
  864.     sendFailed(req, send_failed, "No PIN specified");
  865.     break;
  866. }
  867. if (!sendUcpMsg(req, req.items[i], msg, req.notice, info)) {
  868.     /*
  869.      * On protocol errors retry more quickly
  870.      * (there's no reason to wait is there?).
  871.      */
  872.     if (req.status == send_retry) {
  873.         req.tts = time(0) + requeueProto;
  874. break;
  875.     }
  876. }
  877. req.items.remove(i);
  878.     }
  879. //    if (req.status == send_ok) 
  880. //        (void) pageEpilogue(req, info, notice);
  881. }
  882. // the (simplistic) UCP checksum algorithm
  883. static void
  884. addUcpChecksum(fxStackBuffer& buf)
  885. {
  886.     int sum = 0;
  887.     for (u_int i = 1; i < buf.getLength(); i++)
  888. sum += buf[i];
  889.     sum&=0xff;
  890.     buf.put(fxStr::format("%2.2X",sum&0xff));
  891. }
  892. // Encode the message text in HEX, and perform the character set
  893. // translation while doing so.
  894. // Note that SMS uses a very strange character encoding. The switch
  895. // statement below translates the ISO 8859-1 characters that can
  896. // be mapped to there SMS counterpart, the others to something
  897. // recognizable. The characterset RFC was used as a guideline.
  898. static void
  899. addUcpCodedMsg(fxStackBuffer& buf, const fxStr& msg)
  900. {
  901.     u_int c;
  902.     for (u_int i = 0; i < msg.length(); i++) {
  903. c = msg[i];
  904. switch (c) {
  905. case 0:
  906. case 1:
  907. case 2:
  908. case 3:
  909. case 4:
  910. case 5:
  911. case 6:
  912. case 7:
  913. case 8:
  914. case 9:
  915. case 11:
  916. case 13:
  917. case 14:
  918. case 15:
  919. case 16:
  920. case 17:
  921. case 18:
  922. case 19:
  923. case 20:
  924. case 21:
  925. case 22:
  926. case 23:
  927. case 24:
  928. case 25:
  929. case 26:
  930. case 27:
  931. case 28:
  932. case 29:
  933. case 30:
  934. case 31: break;
  935. case 10: buf.put("0A"); break;
  936. case 12: buf.put("0D"); break;
  937. case 36: buf.put("02"); break;
  938. case 64: buf.put("00"); break;
  939. case 91: buf.put("3C28"); break;
  940. case 92: buf.put("2F2F"); break;
  941. case 93: buf.put("293E"); break;
  942. case 94: buf.put("3E"); break;
  943. case 95: buf.put("11"); break;
  944. case 96: buf.put("2C21"); break;
  945. case 123: buf.put("2821"); break;
  946. case 124: buf.put("2121"); break;
  947. case 125: buf.put("2129"); break;
  948. case 126: buf.put("213F"); break;
  949. case 160: buf.put("20"); break;
  950. case 161: buf.put("40"); break;
  951. case 162: buf.put("4374"); break;
  952. case 163: buf.put("01"); break;
  953. case 164: buf.put("24"); break;
  954. case 165: buf.put("03"); break;
  955. case 166: buf.put("4242"); break;
  956. case 167: buf.put("5F"); break;
  957. case 168: buf.put("22"); break;
  958. case 169: buf.put("436F"); break;
  959. case 170: buf.put("61"); break;
  960. case 171: buf.put("3C"); break;
  961. case 172: buf.put("2D"); break;
  962. case 173: buf.put("2D"); break;
  963. case 174: buf.put("52"); break;
  964. case 175: buf.put("2D"); break;
  965. case 176: buf.put("4447"); break;
  966. case 177: buf.put("2B2D"); break;
  967. case 178: buf.put("2A2A32"); break;
  968. case 179: buf.put("2A2A33"); break;
  969. case 180: buf.put("2C"); break;
  970. case 181: buf.put("6D75"); break;
  971. case 182: buf.put("5049"); break;
  972. case 183: buf.put("2E"); break;
  973. case 184: buf.put("2C"); break;
  974. case 185: buf.put("2A2A31"); break;
  975. case 186: buf.put("6F"); break;
  976. case 187: buf.put("3E"); break;
  977. case 188: buf.put("312F34"); break;
  978. case 189: buf.put("312F32"); break;
  979. case 190: buf.put("332F34"); break;
  980. case 191: buf.put("60"); break;
  981. case 192: buf.put("41"); break;
  982. case 193: buf.put("41"); break;
  983. case 194: buf.put("41"); break;
  984. case 195: buf.put("41"); break;
  985. case 196: buf.put("5B"); break;
  986. case 197: buf.put("0E"); break;
  987. case 198: buf.put("1C"); break;
  988. case 199: buf.put("09"); break;
  989. case 200: buf.put("45"); break;
  990. case 201: buf.put("1F"); break;
  991. case 202: buf.put("45"); break;
  992. case 203: buf.put("45"); break;
  993. case 204: buf.put("49"); break;
  994. case 205: buf.put("49"); break;
  995. case 206: buf.put("49"); break;
  996. case 207: buf.put("49"); break;
  997. case 208: buf.put("442D"); break;
  998. case 209: buf.put("5D"); break;
  999. case 210: buf.put("4F"); break;
  1000. case 211: buf.put("4F"); break;
  1001. case 212: buf.put("4F"); break;
  1002. case 213: buf.put("4F"); break;
  1003. case 214: buf.put("4F"); break;
  1004. case 215: buf.put("78"); break;
  1005. case 216: buf.put("0B"); break;
  1006. case 217: buf.put("55"); break;
  1007. case 218: buf.put("55"); break;
  1008. case 219: buf.put("55"); break;
  1009. case 220: buf.put("55"); break;
  1010. case 221: buf.put("59"); break;
  1011. case 222: buf.put("5448"); break;
  1012. case 223: buf.put("1E"); break;
  1013. case 224: buf.put("7F"); break;
  1014. case 225: buf.put("61"); break;
  1015. case 226: buf.put("61"); break;
  1016. case 227: buf.put("61"); break;
  1017. case 228: buf.put("7B"); break;
  1018. case 229: buf.put("0F"); break;
  1019. case 230: buf.put("6165"); break;
  1020. case 231: buf.put("09"); break;
  1021. case 232: buf.put("04"); break;
  1022. case 233: buf.put("05"); break;
  1023. case 234: buf.put("65"); break;
  1024. case 235: buf.put("65"); break;
  1025. case 236: buf.put("07"); break;
  1026. case 237: buf.put("69"); break;
  1027. case 238: buf.put("69"); break;
  1028. case 239: buf.put("69"); break;
  1029. case 240: buf.put("642D"); break;
  1030. case 241: buf.put("7D"); break;
  1031. case 242: buf.put("08"); break;
  1032. case 243: buf.put("6F"); break;
  1033. case 244: buf.put("6F"); break;
  1034. case 245: buf.put("6F"); break;
  1035. case 246: buf.put("7C"); break;
  1036. case 247: buf.put("2F"); break;
  1037. case 248: buf.put("0C"); break;
  1038. case 249: buf.put("06"); break;
  1039. case 250: buf.put("75"); break;
  1040. case 251: buf.put("75"); break;
  1041. case 252: buf.put("7E"); break;
  1042. case 253: buf.put("79"); break;
  1043. case 254: buf.put("7468"); break;
  1044. case 255: buf.put("79"); break;
  1045. default:
  1046. buf.put(fxStr::format("%2.2X",msg[i]&0xff));
  1047. break;
  1048. }
  1049.     }
  1050.     if (msg.length() > 160) {
  1051. msg[320] = '';
  1052.     }
  1053. }
  1054. bool
  1055. pageSendApp::sendUcpMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxStr& emsg, FaxMachineInfo& info)
  1056. {
  1057.     /*
  1058.      * Build page packet:
  1059.      *
  1060.      *    STX trn '/' len '/O/30/' recipient '/' originator '/' password 
  1061.      * '///////' message '/' checksum ETX
  1062.      *
  1063.      * trn a transaction number
  1064.      * len computed at the end, when the character set
  1065.      * translation is complete
  1066.      * recipient who is to receive the message
  1067.      * originator who sent the message, may be different from the
  1068.      * the number of the modem sending the message
  1069.      * password a number, untested
  1070.      * message the hex encoded message (see addUcpCodedMsg)
  1071.      * checksum the UCP checksum
  1072.      *
  1073.      */
  1074.     fxStackBuffer tmp;
  1075.     // first compose the things we know before hand
  1076.     fxStackBuffer buf;
  1077.     buf.put("/O/30/");
  1078.     buf.put(preq.item); // recipient
  1079.     buf.put("/");
  1080.     buf.put(info.getPageSource()); // originator
  1081.     buf.put("/");
  1082.     buf.put(info.getPagerPassword()); // authenticator
  1083.     buf.put("///////");
  1084.     addUcpCodedMsg(buf,msg);
  1085.     buf.put("/");
  1086.     // now we know the length, and we can compute the first field
  1087.     int len = buf.getLength() + 2 /* trn */ + 1 /* slash */ + 5 /* length */
  1088. + 2 /* check sum */;
  1089.     tmp.put(STX);
  1090.     tmp.put("01/");
  1091.     tmp.put(fxStr::format("%5.5d", len));
  1092.     tmp.put(buf, buf.getLength());
  1093.     // know we still have to add the check sum and the trailer
  1094.     addUcpChecksum(tmp);     // append packet checksum
  1095.     tmp.put("x03");
  1096.     buf = tmp;
  1097.     /*
  1098.      * Send the packet to paging central.
  1099.      */
  1100.     traceIXO("SEND message block: [%.*s]", buf.getLength(), (const char*) buf);
  1101.     putModem((const char*) buf, buf.getLength());
  1102.     /*
  1103.      * Process replies, possibly retransmitting the packet.
  1104.      */
  1105.     fxStackBuffer resp; // paging central response
  1106.     u_int ntries = ixoXmitRetries; // up to 3 xmits of message
  1107.     u_int unknown = 0; // count of unknown responses
  1108.     time_t start = Sys::now();
  1109.     do {
  1110. (void) getResponse(resp, ixoXmitTimeout);
  1111. const fxStr str = (const char*)resp;
  1112. //readUcpResponse(str);
  1113. fxStr tmp;
  1114. u_int pos=1,pos2;
  1115. while(pos<str.length()) {
  1116.     tmp=str.token(pos,"03");
  1117.     // Verify checksum
  1118.     int sum = 0;
  1119.     for (u_int i = 0; i < tmp.length()-2; i++)
  1120.           sum += tmp[i];
  1121.     sum&=0xff;
  1122.     pos2=tmp.length();
  1123.     fxStr CSum=tmp.tokenR(pos2,"/");
  1124.     pos2=0;
  1125.     fxStr TRN=tmp.token(pos2,"/");
  1126.     fxStr LEN=tmp.token(pos2,"/");
  1127.     fxStr OR=tmp.token(pos2,"/");
  1128.     fxStr OT=tmp.token(pos2,"/");
  1129.     if(OR=="R") {  // Response
  1130.         if(OT=="30") { 
  1131.     fxStr  N_ACK=tmp.token(pos2,"/");
  1132.     switch( N_ACK[0]) { 
  1133.     case 'A':  // positive result (ACK)
  1134.         traceIXO("RECV ACK (message block accepted)");
  1135. return(true);
  1136.     case 'N': // Negative result (NACK)
  1137.         traceIXO("RECV NACK (message block rejected)");
  1138.         if(--ntries==0) {
  1139.     req.status = send_retry;
  1140.     emsg="Message block not acknowledged by paging central"
  1141.       "after multiple tries";
  1142.     return(false);
  1143. }
  1144. traceIXO("SEND message block (retransmit)");
  1145. putModem((const char*) buf, buf.getLength());
  1146. start = Sys::now(); // restart timer
  1147. unknown = 0; // reset unknown response count
  1148.     }
  1149. }
  1150.     }
  1151. }
  1152.     } while ((unsigned)Sys::now()-start < ixoXmitTimeout && unknown < ixoMaxUnknown);
  1153.     return false;
  1154. }
  1155. /*
  1156.  * END UCP Support
  1157.  */
  1158. bool
  1159. pageSendApp::putModem(const void* data, int n, long ms)
  1160. {
  1161.     traceIXOCom("<--",  (const u_char*) data, n);
  1162.     return (putModem1(data, n, ms));
  1163. }
  1164. time_t pageSendApp::getConnectTime() const { return (connTime); }
  1165. /*
  1166.  * Configuration support.
  1167.  */
  1168. void
  1169. pageSendApp::resetConfig()
  1170. {
  1171.     ModemServer::resetConfig();
  1172.     setupConfig();
  1173. }
  1174. #define N(a) (sizeof (a) / sizeof (a[0]))
  1175. pageSendApp::stringtag pageSendApp::strings[] = {
  1176. { "ixoservice", &pageSendApp::ixoService, IXO_SERVICE },
  1177. { "ixodeviceid", &pageSendApp::ixoDeviceID, IXO_DEVICEID },
  1178. { "pagerttyparity", &pageSendApp::pagerTTYParity, "even" },
  1179. };
  1180. pageSendApp::stringtag pageSendApp::atcmds[] = {
  1181. { "pagersetupcmds", &pageSendApp::pagerSetupCmds },
  1182. };
  1183. pageSendApp::numbertag pageSendApp::numbers[] = {
  1184. { "pagermaxmsglength", &pageSendApp::pagerMaxMsgLength,128 },
  1185. { "ixomaxunknown", &pageSendApp::ixoMaxUnknown, IXO_MAXUNKNOWN },
  1186. { "ixoidprobe", &pageSendApp::ixoIDProbe, IXO_IDPROBE },
  1187. { "ixoidtimeout", &pageSendApp::ixoIDTimeout, IXO_IDTIMEOUT },
  1188. { "ixologinretries", &pageSendApp::ixoLoginRetries, IXO_LOGINRETRIES },
  1189. { "ixologintimeout", &pageSendApp::ixoLoginTimeout, IXO_LOGINTIMEOUT },
  1190. { "ixogatimeout", &pageSendApp::ixoGATimeout, IXO_GATIMEOUT },
  1191. { "ixoxmitretries", &pageSendApp::ixoXmitRetries, IXO_XMITRETRIES },
  1192. { "ixoxmittimeout", &pageSendApp::ixoXmitTimeout, IXO_XMITTIMEOUT },
  1193. { "ixoacktimeout", &pageSendApp::ixoAckTimeout, IXO_ACKTIMEOUT },
  1194. };
  1195. void
  1196. pageSendApp::setupConfig()
  1197. {
  1198.     int i;
  1199.     for (i = N(strings)-1; i >= 0; i--)
  1200. (*this).*strings[i].p = (strings[i].def ? strings[i].def : "");
  1201.     for (i = N(atcmds)-1; i >= 0; i--)
  1202. (*this).*atcmds[i].p = (atcmds[i].def ? atcmds[i].def : "");
  1203.     for (i = N(numbers)-1; i >= 0; i--)
  1204. (*this).*numbers[i].p = numbers[i].def;
  1205. }
  1206. bool
  1207. pageSendApp::setConfigItem(const char* tag, const char* value)
  1208. {
  1209.     u_int ix;
  1210.     if (findTag(tag, (const tags*)atcmds, N(atcmds), ix)) {
  1211. (*this).*atcmds[ix].p = parseATCmd(value);
  1212.     } else if (findTag(tag, (const tags*) strings, N(strings), ix)) {
  1213. (*this).*strings[ix].p = value;
  1214.     } else if (findTag(tag, (const tags*)numbers, N(numbers), ix)) {
  1215. (*this).*numbers[ix].p = getNumber(value);
  1216.     } else
  1217. return (ModemServer::setConfigItem(tag, value));
  1218.     return (true);
  1219. }
  1220. #undef N
  1221. u_int
  1222. pageSendApp::getConfigParity(const char* value) const
  1223. {
  1224.     if (streq(value, "even"))
  1225. return (EVEN);
  1226.     else if (streq(value, "odd"))
  1227. return (ODD);
  1228.     else if (streq(value, "none"))
  1229. return (NONE);
  1230.     else {
  1231. logError("Unknown pager tty parity %s ignored; using EVEN", value);
  1232. return (EVEN); // per IXO/TAP spec
  1233.     }
  1234. }
  1235. /*
  1236.  * Modem and TTY setup
  1237.  */
  1238. bool 
  1239. pageSendApp::setupModem(bool isSend)
  1240. {
  1241.     return (ModemServer::setupModem(isSend) &&
  1242. setParity((Parity) getConfigParity(pagerTTYParity)));
  1243. }
  1244. /*
  1245.  * Modem locking support.
  1246.  */
  1247. bool
  1248. pageSendApp::canLockModem()
  1249. {
  1250.     return (modemLock ? modemLock->check() : true);
  1251. }
  1252. bool
  1253. pageSendApp::lockModem()
  1254. {
  1255.     return (modemLock ? modemLock->lock() : true);
  1256. }
  1257. void
  1258. pageSendApp::unlockModem()
  1259. {
  1260.     if (modemLock)
  1261. modemLock->unlock();
  1262. }
  1263. /*
  1264.  * Notification handlers.
  1265.  */
  1266. /*
  1267.  * Handle notification that the modem device has become
  1268.  * available again after a period of being unavailable.
  1269.  */
  1270. void
  1271. pageSendApp::notifyModemReady()
  1272. {
  1273.     ready = true;
  1274. }
  1275. /*
  1276.  * Handle notification that the modem device looks to
  1277.  * be in a state that requires operator intervention.
  1278.  */
  1279. void
  1280. pageSendApp::notifyModemWedged()
  1281. {
  1282.     if (!sendModemStatus(getModemDeviceID(), "W"))
  1283. logError("MODEM %s appears to be wedged",
  1284.     (const char*) getModemDevice());
  1285.     close();
  1286. }
  1287. /*
  1288.  * Miscellaneous stuff.
  1289.  */
  1290. static void
  1291. usage(const char* appName)
  1292. {
  1293.     faxApp::fatal("usage: %s -m deviceID [-t tracelevel] [-l] qfile ...",
  1294. appName);
  1295. }
  1296. static void
  1297. sigCleanup(int s)
  1298. {
  1299.     int old_errno = errno;
  1300.     signal(s, fxSIGHANDLER(sigCleanup));
  1301.     logError("CAUGHT SIGNAL %d", s);
  1302.     pageSendApp::instance().close();
  1303.     if (!pageSendApp::instance().isRunning())
  1304. _exit(send_failed);
  1305.     errno = old_errno;
  1306. }
  1307. int
  1308. main(int argc, char** argv)
  1309. {
  1310.     faxApp::setupLogging("PageSend");
  1311.     fxStr appName = argv[0];
  1312.     u_int l = appName.length();
  1313.     appName = appName.tokenR(l, '/');
  1314.     faxApp::setOpts("c:m:l");
  1315.     fxStr devID;
  1316.     for (GetoptIter iter(argc, argv, faxApp::getOpts()); iter.notDone(); iter++)
  1317. switch (iter.option()) {
  1318. case 'm': devID = iter.optArg(); break;
  1319. case '?': usage(appName);
  1320. }
  1321.     if (devID == "")
  1322. usage(appName);
  1323.     pageSendApp* app = new pageSendApp(faxApp::idToDev(devID), devID);
  1324.     signal(SIGTERM, fxSIGHANDLER(sigCleanup));
  1325.     signal(SIGINT, fxSIGHANDLER(sigCleanup));
  1326.     app->initialize(argc, argv);
  1327.     app->open();
  1328.     while (app->isRunning() && !app->isReady())
  1329. Dispatcher::instance().dispatch();
  1330.     FaxSendStatus status;
  1331.     if (app->isReady())
  1332. status = app->send((const char**)&argv[optind], argc - optind);
  1333.     else
  1334. status = send_retry;
  1335.     app->close();
  1336.     return (status);
  1337. }