]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
FaxRequest: Status codes for jobs
authorAidan Van Dyk <aidan@ifax.com>
Mon, 4 Jun 2007 17:11:07 +0000 (17:11 +0000)
committerAidan Van Dyk <aidan@ifax.com>
Mon, 4 Jun 2007 17:11:07 +0000 (17:11 +0000)
This patch introduces a Status object, and uses it in FaxRequest instead
of the fxStr notice to make sure we always have a code associated with any
error/status change in a job.

It introduces a new JPARM STATUSCODE command in the clinet-server protocol
so clients can retreive the "code" of the status as well as the status
string.

Status codes are documented in faxd/STATUS.txt

42 files changed:
faxd/Class0.c++
faxd/Class0.h
faxd/Class1.c++
faxd/Class1.h
faxd/Class1Poll.c++
faxd/Class1Recv.c++
faxd/Class1Send.c++
faxd/Class2.c++
faxd/Class2.h
faxd/Class2Poll.c++
faxd/Class2Recv.c++
faxd/Class2Send.c++
faxd/ClassModem.c++
faxd/ClassModem.h
faxd/CopyQuality.c++
faxd/FaxModem.c++
faxd/FaxModem.h
faxd/FaxPoll.c++
faxd/FaxRecv.c++
faxd/FaxRequest.c++
faxd/FaxRequest.h
faxd/FaxSend.c++
faxd/FaxServer.h
faxd/ModemServer.c++
faxd/ModemServer.h
faxd/STATUS.txt [new file with mode: 0644]
faxd/faxGettyApp.c++
faxd/faxGettyApp.h
faxd/faxQueueApp.c++
faxd/faxQueueApp.h
faxd/faxSendApp.c++
faxd/mkhash.c
faxd/pageSendApp.c++
faxd/pageSendApp.h
hfaxd/HylaFAXServer.h
hfaxd/Jobs.c++
hfaxd/Parser.c++
man/sendq.4f
util/Makefile.in
util/Sequence.c++
util/Status.c++ [new file with mode: 0644]
util/Status.h [new file with mode: 0644]

index 4c89e0df001ba6ee8d7b9dc96668202ca310822e..4354c332ad07fe0f28c44bb7da78cf6046b85397 100644 (file)
@@ -89,16 +89,16 @@ Class0Modem::setupFlowControl(FlowControl fc)
 }
 
 CallStatus
-Class0Modem::dial(const char* number, fxStr& emsg)
+Class0Modem::dial(const char* number, Status& eresult)
 {
-    return (ClassModem::dial(number, emsg));
+    return (ClassModem::dial(number, eresult));
 }
 
 /*
  * Wait-for and process a dial command response.
  */
 CallStatus
-Class0Modem::dialResponse(fxStr&)
+Class0Modem::dialResponse(Status&)
 {
     ATResponse r;
     do {
index 5ffa44fc9378bd6ab37a9963deff4089ef7480cc..d8699d05555a8972678443576ed5c4940e9a8c7b 100644 (file)
@@ -37,8 +37,8 @@ public:
 
     bool setupModem(bool isSend = true);
     virtual bool setupFlowControl(FlowControl fc);
-    CallStatus dial(const char* number, fxStr& emsg);
-    CallStatus dialResponse(fxStr& emsg);
+    CallStatus dial(const char* number, Status& eresult);
+    CallStatus dialResponse(Status& eresult);
 
     bool isFaxModem() const;                   // XXX safe to cast
 };
index 305141a855f0658b87abe877b5690ee9fe9522de..2ac8282bc3d52a6cc2b774eb77745bbacff1ee66 100644 (file)
@@ -472,7 +472,7 @@ Class1Modem::decodePWD(fxStr& ascii, const HDLCFrame& binary)
 }
 
 bool
-Class1Modem::switchingPause(fxStr& emsg, u_int times)
+Class1Modem::switchingPause(Status& eresult, u_int times)
 {
     /*
      * If class1SwitchingCmd is of the AT+FRS=n form we honor
@@ -492,8 +492,8 @@ Class1Modem::switchingPause(fxStr& emsg, u_int times)
        }
     }
     if (!silenceHeard && !atCmd(scmd, AT_OK)) {
-       emsg = "Failure to receive silence.";
-       protoTrace(emsg);
+       eresult = Status(100, "Failure to receive silence (synchronization failure).");
+       protoTrace(eresult.string());
        if (wasTimeout()) abortReceive();
        return (false);
     }
@@ -1432,7 +1432,7 @@ Class1Modem::recvFrame(HDLCFrame& frame, u_char dir, long ms, bool readPending,
             abortReceive();
             return (false);
         }
-       fxStr emsg;
+       Status eresult;
        do {
            if (crpcnt || rhcnt) {
                if (rhcnt) crpcnt = 0;
@@ -1462,7 +1462,7 @@ Class1Modem::recvFrame(HDLCFrame& frame, u_char dir, long ms, bool readPending,
             * So we simply repeat AT+FRH=3 in that case.
             */
        } while (!gotframe && !wasTimeout() && ((conf.class1HasRHConnectBug && !frame.getLength() && lastResponse == AT_NOCARRIER && rhcnt++ < 30) ||
-           (docrp && crpcnt++ < 3 && switchingPause(emsg, 3) && transmitFrame(dir|FCF_CRP)))); /* triple switchingPause to avoid sending CRP during TCF */
+           (docrp && crpcnt++ < 3 && switchingPause(eresult, 3) && transmitFrame(dir|FCF_CRP))));      /* triple switchingPause to avoid sending CRP during TCF */
        return (gotframe);
     } else {
        gotCONNECT = false;
index 8bdc9640c37766bf3a2fc30234b527fe4ef74585..cadd55ed2cf4b970bf871fcf255e35173b674094 100644 (file)
@@ -128,13 +128,13 @@ protected:
     void       checkReceiverDIS(Class2Params&);
     bool       dropToNextBR(Class2Params&);
     bool       raiseToNextBR(Class2Params&);
-    bool       sendTraining(Class2Params&, int, fxStr& emsg);
+    bool       sendTraining(Class2Params&, int, Status& eresult);
     bool       sendTCF(const Class2Params&, u_int ms);
-    bool       sendPage(TIFF* tif, Class2Params&, u_int, u_int, fxStr& emsg);
-    bool       sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm, fxStr& emsg);
-    bool       sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 rowsperstrip, fxStr& emsg);
-    bool       sendPPM(u_int ppm, HDLCFrame& mcf, fxStr& emsg);
-    bool       decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg);
+    bool       sendPage(TIFF* tif, Class2Params&, u_int, u_int, Status& eresult);
+    bool       sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm, Status& eresult);
+    bool       sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 rowsperstrip, Status& eresult);
+    bool       sendPPM(u_int ppm, HDLCFrame& mcf, Status& eresult);
+    bool       decodePPM(const fxStr& pph, u_int& ppm, Status& eresult);
 // reception support
     const AnswerMsg* findAnswer(const char*);
     bool       recvIdentification(
@@ -143,12 +143,12 @@ protected:
                    u_int f3, const fxStr& nsf,
                    u_int f4, const fxStr& id,
                    u_int f5, FaxParams& dics,
-                   u_int timer, bool notransmit, fxStr& emsg);
+                   u_int timer, bool notransmit, Status& eresult);
     bool       recvDCSFrames(HDLCFrame& frame);
     bool       recvTraining();
-    bool       recvPPM(int& ppm, fxStr& emsg);
-    bool       recvPageData(TIFF*, fxStr& emsg);
-    bool       raiseRecvCarrier(bool& dolongtrain, fxStr& emsg);
+    bool       recvPPM(int& ppm, Status& eresult);
+    bool       recvPageData(TIFF*, Status& eresult);
+    bool       raiseRecvCarrier(bool& dolongtrain, Status& eresult);
     void       recvData(TIFF*, u_char* buf, int n);
     void       processDCSFrame(const HDLCFrame& frame);
     void       abortPageRecv();
@@ -160,7 +160,7 @@ protected:
     virtual ATResponse atResponse(char* buf, long ms = 30*1000);
     virtual bool waitFor(ATResponse wanted, long ms = 30*1000);
     virtual bool atCmd(const fxStr& cmd, ATResponse = AT_OK, long ms = 30*1000);
-    bool       switchingPause(fxStr& emsg, u_int times = 1);
+    bool       switchingPause(Status& eresult, u_int times = 1);
     void       encodeTSI(fxStr& binary, const fxStr& ascii);
     void       encodeNSF(fxStr& binary, const fxStr& ascii);
     const fxStr& decodeTSI(fxStr& ascii, const HDLCFrame& binary);
@@ -184,7 +184,7 @@ protected:
     bool       sendRawFrame(HDLCFrame& frame);
     bool       sendClass1Data(const u_char* data, u_int cc, const u_char* bitrev, bool eod, long ms);
     bool       sendClass1ECMData(const u_char* data, u_int cc,
-                    const u_char* bitrev, bool eod, u_int ppmcmd, fxStr& emsg);
+                    const u_char* bitrev, bool eod, u_int ppmcmd, Status& eresult);
     bool       recvFrame(HDLCFrame& frame, u_char dir, long ms = 10*1000, bool readPending = false, bool docrp = true);
     bool       recvTCF(int br, HDLCFrame&, const u_char* bitrev, long ms);
     bool       recvRawFrame(HDLCFrame& frame);
@@ -193,9 +193,9 @@ protected:
     bool        renegotiatePrimary(bool constrain);
     bool       syncECMFrame();
     void       abortPageECMRecv(TIFF* tif, const Class2Params& params, u_char* block, u_int fcount, u_short seq, bool pagedataseen);
-    bool       recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg);
+    bool       recvPageECMData(TIFF* tif, const Class2Params& params, Status& eresult);
     void       blockData(u_int byte, bool flag);
-    bool       blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxStr& emsg);
+    bool       blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, Status& eresult);
     bool       endECMBlock();
     void       abortReceive();
     void       traceHDLCFrame(const char* direction, const HDLCFrame& frame, bool isecm = false);
@@ -208,31 +208,31 @@ public:
     void       hangup();
 
 // send support
-    bool       sendSetup(FaxRequest&, const Class2Params&, fxStr& emsg);
-    CallStatus dialResponse(fxStr& emsg);
-    FaxSendStatus getPrologue(Class2Params&, bool&, fxStr&, u_int&);
+    bool       sendSetup(FaxRequest&, const Class2Params&, Status& eresult);
+    CallStatus dialResponse(Status& eresult);
+    FaxSendStatus getPrologue(Class2Params&, bool&, Status& eresult, u_int&);
     void       sendBegin();
     void       sendSetupPhaseB(const fxStr& pwd, const fxStr& sub);
     FaxSendStatus sendPhaseB(TIFF* tif, Class2Params&, FaxMachineInfo&,
-                   fxStr& pph, fxStr& emsg, u_int& batched);
+                   fxStr& pph, Status& eresult, u_int& batched);
     void       sendEnd();
     void       sendAbort();
 
 // receive support
-    CallType   answerCall(AnswerType, fxStr& emsg, const char* number);
+    CallType   answerCall(AnswerType, Status& eresult, const char* number);
     FaxParams  modemDIS() const;
     bool       setupReceive();
-    bool       recvBegin(fxStr& emsg);
-    bool       recvEOMBegin(fxStr& emsg);
-    bool       recvPage(TIFF*, u_int& ppm, fxStr& emsg, const fxStr& id);
-    bool       recvEnd(fxStr& emsg);
+    bool       recvBegin(Status& eresult);
+    bool       recvEOMBegin(Status& eresult);
+    bool       recvPage(TIFF*, u_int& ppm, Status& eresult, const fxStr& id);
+    bool       recvEnd(Status& eresult);
     void       recvAbort();
     void       pokeConfig(bool isSend);
 
 // polling support
-    bool       requestToPoll(fxStr&);
+    bool       requestToPoll(Status& eresult);
     bool       pollBegin(const fxStr& cig, const fxStr& sep, const fxStr& pwd,
-                   fxStr& emsg);
+                   Status& eresult);
 
 // miscellaneous
     bool       faxService(bool enableV34, bool enableV17);     // switch to fax mode (send)
index d561f4e2f6fdd5950bb5264072550c1f574ff3be..6106164b9808afcba31b389af2635a396b343e25 100644 (file)
 #include "config.h"
 
 bool
-Class1Modem::requestToPoll(fxStr&)
+Class1Modem::requestToPoll(Status&)
 {
     return true;
 }
 
 bool
 Class1Modem::pollBegin(const fxStr& cig0,
-    const fxStr& sep0, const fxStr& pwd0, fxStr& emsg)
+    const fxStr& sep0, const fxStr& pwd0, Status& eresult)
 {
     FaxParams dtc = modemDIS();
     u_int send = 0;
@@ -66,5 +66,5 @@ Class1Modem::pollBegin(const fxStr& cig0,
            0, fxStr::null,
            FCF_CIG, cig,
            FCF_DTC, dtc,
-           conf.t1Timer, false, emsg);
+           conf.t1Timer, false, eresult);
 }
index aaeba1690adba21789adebe07cbf94fbe6793e68..8a01ec5c2eac2380dc789f269c8d43e8a7760814 100644 (file)
@@ -47,7 +47,7 @@
  * flow control state to be setup to our liking.
  */
 CallType
-Class1Modem::answerCall(AnswerType type, fxStr& emsg, const char* number)
+Class1Modem::answerCall(AnswerType type, Status& eresult, const char* number)
 {
     // Reset modemParams.br to non-V.34 settings.  If V.8 handshaking
     // succeeds, then it will be changed again.
@@ -55,7 +55,7 @@ Class1Modem::answerCall(AnswerType type, fxStr& emsg, const char* number)
 
     if (flowControl == FLOW_XONXOFF)
        setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_FLUSH);
-    return ClassModem::answerCall(type, emsg, number);
+    return ClassModem::answerCall(type, eresult, number);
 }
 
 /*
@@ -84,7 +84,7 @@ Class1Modem::findAnswer(const char* s)
  * Begin the receive protocol.
  */
 bool
-Class1Modem::recvBegin(fxStr& emsg)
+Class1Modem::recvBegin(Status& eresult)
 {
     setInputBuffering(false);
     prevPage = 0;                              // no previous page received
@@ -102,20 +102,20 @@ Class1Modem::recvBegin(fxStr& emsg)
 
     FaxParams dis = modemDIS();
 
-    return FaxModem::recvBegin(emsg) && recvIdentification(
+    return FaxModem::recvBegin(eresult) && recvIdentification(
        0, fxStr::null,
        0, fxStr::null,
        FCF_NSF|FCF_RCVR, nsf,
        FCF_CSI|FCF_RCVR, lid,
        FCF_DIS|FCF_RCVR, dis,
-       conf.class1RecvIdentTimer, false, emsg);
+       conf.class1RecvIdentTimer, false, eresult);
 }
 
 /*
  * Begin the receive protocol after an EOM signal.
  */
 bool
-Class1Modem::recvEOMBegin(fxStr& emsg)
+Class1Modem::recvEOMBegin(Status& eresult)
 {
     /*
      * We must raise the transmission carrier to mimic the state following ATA.
@@ -123,12 +123,12 @@ Class1Modem::recvEOMBegin(fxStr& emsg)
     if (!useV34) {
        pause(conf.t2Timer);    // T.30 Fig 5.2B requires T2 to elapse
        if (!(atCmd(thCmd, AT_NOTHING) && atResponse(rbuf, 0) == AT_CONNECT)) {
-           emsg = "Failure to raise V.21 transmission carrier.";
-           protoTrace(emsg);
+           eresult = Status(101, "Failure to raise V.21 transmission carrier.");
+           protoTrace(eresult.string());
            return (false);
        }
     }
-    return Class1Modem::recvBegin(emsg);
+    return Class1Modem::recvBegin(eresult);
 }
 
 /*
@@ -142,14 +142,14 @@ Class1Modem::recvIdentification(
     u_int f3, const fxStr& nsf,
     u_int f4, const fxStr& id,
     u_int f5, FaxParams& dics,
-    u_int timer, bool notransmit, fxStr& emsg)
+    u_int timer, bool notransmit, Status& eresult)
 {
     u_int t1 = howmany(timer, 1000);           // in seconds
     time_t start = Sys::now();
     HDLCFrame frame(conf.class1FrameOverhead);
     bool framesSent = false;
 
-    emsg = "No answer (T.30 T1 timeout)";
+    eresult = Status(102, "No sender protocol (T.30 T1 timeout)");
     if (!notransmit) {
        /*
         * Transmit (PWD) (SUB) (CSI) DIS frames when the receiving
@@ -212,7 +212,7 @@ Class1Modem::recvIdentification(
                        if (!recvDCSFrames(frame)) {
                            switch (frame.getFCF()) {
                                case FCF_DCN:
-                                   emsg = "RSPREC error/got DCN";
+                                   eresult = Status(103, "RSPREC error/got DCN (sender abort)");
                                    recvdDCN = true;
                                    return (false);
                                case FCF_CRP:
@@ -221,19 +221,19 @@ Class1Modem::recvIdentification(
                                case FCF_MPS:
                                case FCF_EOP:
                                case FCF_EOM:
-                                   if (!useV34 && !switchingPause(emsg)) return (false);
+                                   if (!useV34 && !switchingPause(eresult)) return (false);
                                    transmitFrame(signalSent);
                                    traceFCF("RECV send", (u_char) signalSent[2]);
                                    break;
                                default:        // XXX DTC/DIS not handled
-                                   emsg = "RSPREC invalid response received";
+                                   eresult = Status(104, "RSPREC invalid response received");
                                    break;
                            }
                            break;
                        }
                        gotframe = false;
                        if (recvTraining()) {
-                           emsg = "";
+                           eresult.clear();
                            return (true);
                        } else {
                            if (lastResponse == AT_FRH3 && waitFor(AT_CONNECT,0)) {
@@ -245,7 +245,7 @@ Class1Modem::recvIdentification(
                        }
                    }
                    if (gotframe) break;        // where recvDCSFrames fails without DCN
-                   emsg = "Failure to train modems";
+                   eresult = Status(105, "Failure to train modems");
                    /*
                     * Reset the timeout to insure the T1 timer is
                     * used.  This is done because the adaptive answer
@@ -260,7 +260,7 @@ Class1Modem::recvIdentification(
            }
        }
        if (gotEOT) {
-           emsg = "RSPREC error/got EOT";
+           eresult = Status(106, "RSPREC error/got EOT");
            return (false);
        }
        /*
@@ -280,7 +280,7 @@ Class1Modem::recvIdentification(
             * The best way to do that is to make sure that there is
             * silence on the line, and  we do that with Class1SwitchingCmd.
             */
-           if (!switchingPause(emsg)) {
+           if (!switchingPause(eresult)) {
                return (false);
            }
        }
@@ -450,8 +450,8 @@ Class1Modem::recvTraining()
      * Send training response; we follow the spec
      * by delaying 75ms before switching carriers.
      */
-    fxStr emsg;
-    if (!switchingPause(emsg)) return (false);
+    Status eresult;
+    if (!switchingPause(eresult)) return (false);
     if (ok) {
        /*
         * Send CFR later so that we can cancel
@@ -502,7 +502,7 @@ const u_int Class1Modem::modemPPMCodes[8] = {
  * sending a post-page response in a multi-page document.
  */
 bool
-Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
+Class1Modem::recvPage(TIFF* tif, u_int& ppm, Status& eresult, const fxStr& id)
 {
     if (lastPPM == FCF_MPS && prevPage) {
        /*
@@ -522,7 +522,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
            FaxParams dis = modemDIS();
            if (!recvIdentification(0, fxStr::null, 0, fxStr::null, 
                0, fxStr::null, 0, fxStr::null, 0, dis,
-               conf.class1RecvIdentTimer, true, emsg)) {
+               conf.class1RecvIdentTimer, true, eresult)) {
                return (false);
            }
        }
@@ -545,7 +545,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
            recvSetupTIFF(tif, group3opts, FILLORDER_LSB2MSB, id);
            ATResponse rmResponse = AT_NOTHING;
            if (params.ec != EC_DISABLE || useV34) {
-               pageGood = recvPageData(tif, emsg);
+               pageGood = recvPageData(tif, eresult);
                messageReceived = true;
                prevPage++;
            } else {
@@ -556,7 +556,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                 * Same reasoning here as before receiving TCF.
                 */
                if (!atCmd(conf.class1MsgRecvHackCmd, AT_OK)) {
-                   emsg = "Failure to receive silence.";
+                   eresult = Status(100, "Failure to receive silence (synchronization failure).");
                    return (false);
                }
                /*
@@ -593,7 +593,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                     * receive the Phase C data.
                     */
                    protoTrace("RECV: begin page");
-                   pageGood = recvPageData(tif, emsg);
+                   pageGood = recvPageData(tif, eresult);
                    protoTrace("RECV: end page");
                    if (!wasTimeout()) {
                        /*
@@ -675,7 +675,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
         */
        if (abortRequested()) {
            // XXX no way to purge TIFF directory
-           emsg = "Receive aborted due to operator intervention";
+           eresult = Status(301, "Receive aborted due to operator intervention");
            return (false);
        }
 
@@ -701,7 +701,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
            case FCF_DIS:                       // XXX no support
                if (!pageGood) recvResetPage(tif);
                protoTrace("RECV DIS/DTC");
-               emsg = "Can not continue after DIS/DTC";
+               eresult = Status(107, "Can not continue after DIS/DTC");
                return (false);
            case FCF_PWD:
            case FCF_SUB:
@@ -712,7 +712,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                    signalRcvd = 0;
                    if (!pageGood) recvResetPage(tif);
                    // look for high speed carrier only if training successful
-                   messageReceived = !(FaxModem::recvBegin(emsg));
+                   messageReceived = !(FaxModem::recvBegin(eresult));
                    bool trainok = true;
                    short traincount = 0;
                    do {
@@ -742,11 +742,11 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                    // We have a null page, don't save it because it makes readers fail.
                    pageGood = false;
                    if (params.ec != EC_DISABLE) {
-                       if (emsg == "") {
+                       if (eresult.value() == 0) {
                            /*
                             * We negotiated ECM, got no valid ECM image data, and the 
                             * ECM page reception routines did not set an error message.
-                            * The empty emsg is due to the ECM routines detecting a 
+                            * The empty eresult is due to the ECM routines detecting a
                             * non-ECM-specific partial-page signal and wants it to
                             * be handled here.  The sum total of all of this, and the 
                             * fact that we got MPS/EOP/EOM tells us that the sender
@@ -772,7 +772,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                     * that we just received, write it to disk.
                     */
                    if (messageReceived) {
-                       if (!useV34 && emsg == "") (void) switchingPause(emsg);
+                       if (!useV34 && eresult.value() == 0) (void) switchingPause(eresult);
                        /*
                         * On servers where disk access may be bottlenecked or stressed,
                         * the TIFFWriteDirectory call can lag.  The strategy, then, is
@@ -811,7 +811,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                                            bool gotresponse = true;
                                            u_short rnrcnt = 0;
                                            do {
-                                               if (emsg != "") break;
+                                               if (eresult.value() != 0) break;
                                                (void) transmitFrame(params.ec != EC_DISABLE ? FCF_RNR : FCF_CRP|FCF_RCVR);
                                                traceFCF("RECV send", params.ec != EC_DISABLE ? FCF_RNR : FCF_CRP);
                                                HDLCFrame rrframe(conf.class1FrameOverhead);
@@ -819,16 +819,16 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                                                    traceFCF("RECV recv", rrframe.getFCF());
                                                    if (rrframe.getFCF() == FCF_DCN) {
                                                        protoTrace("RECV recv DCN");
-                                                       emsg = "COMREC received DCN";
+                                                       eresult = Status(108, "COMREC received DCN (sender abort)");
                                                        gotEOT = true;
                                                        recvdDCN = true;
                                                    } else if (params.ec != EC_DISABLE && rrframe.getFCF() != FCF_RR) {
                                                        protoTrace("Ignoring invalid response to RNR.");
                                                    }
-                                                   if (!useV34) (void) switchingPause(emsg);
+                                                   if (!useV34) (void) switchingPause(eresult);
                                                }
                                            } while (!gotEOT && !recvdDCN && !gotresponse && ++rnrcnt < 2 && Sys::now()-rrstart < 60);
-                                           if (!gotresponse) emsg = "No response to RNR repeated 3 times.";
+                                           if (!gotresponse) eresult = Status(109, "No response to RNR repeated 3 times.");
                                        } else {                // parent finished TIFFWriteDirectory
                                            tbuf[0] = 0;
                                        }
@@ -847,7 +847,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                            protoTrace("Protocol flow control unavailable due to pipe error.");
                            TIFFWriteDirectory(tif);
                        }
-                       if (emsg == "") {       // confirm only if there was no error
+                       if (eresult.value() == 0) {     // confirm only if there was no error
                            if (lastPPM == FCF_MPS) {
                                /*
                                 * Raise the HDLC transmission carrier but do not
@@ -856,7 +856,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                                 * processes.
                                 */
                                if (!useV34 && !atCmd(thCmd, AT_CONNECT)) {
-                                   emsg = "Failure to raise V.21 transmission carrier.";
+                                   eresult = Status(101, "Failure to raise V.21 transmission carrier.");
                                    return (false);
                                }
                            } else {
@@ -897,7 +897,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                     * to implement than using +FRH and more reliable than
                     * using +FTS
                     */
-                   if (!switchingPause(emsg)) {
+                   if (!switchingPause(eresult)) {
                        return (false);
                    }
                    signalRcvd = 0;
@@ -934,7 +934,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                break;
            case FCF_DCN:                       // DCN
                protoTrace("RECV recv DCN");
-               emsg = "COMREC received DCN";
+               eresult = Status(108, "COMREC received DCN (sender abort)");
                recvdDCN = true;
                if (prevPage && conf.saveUnconfirmedPages && getRecvEOLCount()) {       // only if there was data
                    TIFFWriteDirectory(tif);
@@ -944,7 +944,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
                return (false);
            default:
                if (!pageGood) recvResetPage(tif);
-               emsg = "COMREC invalid response received";
+               eresult = Status(110, "COMREC invalid response received");
                return (false);
            }
            t2end = 0;
@@ -965,7 +965,7 @@ Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
            }
        }
     } while (gotCONNECT && !wasTimeout() && lastResponse != AT_EMPTYLINE);
-    emsg = "T.30 T2 timeout, expected page not received";
+    eresult = Status(111, "T.30 T2 timeout, expected page not received");
     if (prevPage && conf.saveUnconfirmedPages && getRecvEOLCount()) {
        TIFFWriteDirectory(tif);
        protoTrace("RECV keeping unconfirmed page");
@@ -983,10 +983,10 @@ Class1Modem::abortPageRecv()
 }
 
 bool
-Class1Modem::raiseRecvCarrier(bool& dolongtrain, fxStr& emsg)
+Class1Modem::raiseRecvCarrier(bool& dolongtrain, Status& eresult)
 {
     if (!atCmd(conf.class1MsgRecvHackCmd, AT_OK)) {
-       emsg = "Failure to receive silence.";
+       eresult = Status(100, "Failure to receive silence (synchronization failure).");
        return (false);
     }
     /*
@@ -1008,7 +1008,7 @@ Class1Modem::raiseRecvCarrier(bool& dolongtrain, fxStr& emsg)
        gotEOT = false;
     }
     if (lastResponse != AT_CONNECT && !gotRTNC) {
-       emsg = "Failed to properly detect high-speed data carrier.";
+       eresult = Status(112, "Failed to properly detect high-speed data carrier.");
        return (false);
     }
     dolongtrain = false;
@@ -1032,7 +1032,7 @@ Class1Modem::abortPageECMRecv(TIFF* tif, const Class2Params& params, u_char* blo
  * Receive Phase C data in T.30-A ECM mode.
  */
 bool
-Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
+Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, Status& eresult)
 {
     HDLCFrame frame(5);                                        // A+C+FCF+FCS=5 bytes
     u_char* block = (u_char*) malloc(frameSize*256);   // 256 frames per block - totalling 16/64KB
@@ -1059,7 +1059,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
            bool dataseen = false;
            if (!useV34) {
                gotRTNC = false;
-               if (!raiseRecvCarrier(dolongtrain, emsg) && !gotRTNC) {
+               if (!raiseRecvCarrier(dolongtrain, eresult) && !gotRTNC) {
                    if (wasTimeout()) {
                        abortReceive();         // return to command mode
                        setTimeout(false);
@@ -1069,7 +1069,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                        // sender is transmitting V.21 instead, we may have
                        // missed the first signal attempt, but should catch
                        // the next attempt.  This "simulates" adaptive receive.
-                       emsg = "";      // reset
+                       eresult.clear();        // reset
                        gotRTNC = true;
                    } else {
                        if (wasTimeout()) abortReceive();
@@ -1121,7 +1121,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                            case FCF_PRI_EOM:
                                            case FCF_PRI_MPS:
                                            case FCF_PRI_EOP:
-                                               if (!useV34 && !switchingPause(emsg)) {
+                                               if (!useV34 && !switchingPause(eresult)) {
                                                    abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                    return (false);
                                                }
@@ -1158,7 +1158,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                                    if (signalRcvd) lastblock = true;
                                                    sendERR = true;
                                                } else {
-                                                   if (!useV34 && !switchingPause(emsg)) {
+                                                   if (!useV34 && !switchingPause(eresult)) {
                                                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                        return (false);
                                                    }
@@ -1174,7 +1174,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                        u_int dcs;                      // possible bits 1-16 of DCS in FIF
                                        if (useV34) {
                                            // T.30 F.3.4.5 Note 1 does not permit CTC in V.34-fax
-                                           emsg = "Received invalid CTC signal in V.34-Fax.";
+                                           eresult = Status(113, "Received invalid CTC signal in V.34-Fax.");
                                            abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                            return (false);
                                        }
@@ -1186,7 +1186,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                        dcs = rtncframe[3] | (rtncframe[4]<<8);
                                        curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
                                        // requisite pause before sending response (CTR)
-                                       if (!switchingPause(emsg)) {
+                                       if (!switchingPause(eresult)) {
                                            abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                            return (false);
                                        }
@@ -1198,7 +1198,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                    }
                                case FCF_CRP:
                                    // command repeat... just repeat whatever we last sent
-                                   if (!useV34 && !switchingPause(emsg)) {
+                                   if (!useV34 && !switchingPause(eresult)) {
                                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                        return (false);
                                    }
@@ -1206,7 +1206,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                    traceFCF("RECV send", (u_char) signalSent[2]);
                                    break;
                                case FCF_DCN:
-                                   emsg = "COMREC received DCN";
+                                   eresult = Status(108, "COMREC received DCN (sender abort)");
                                    gotEOT = true;
                                    recvdDCN = true;
                                    continue;
@@ -1230,7 +1230,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                        prevPage--;             // counteract the forthcoming increment
                                        return (true);
                                    } else {
-                                       emsg = "COMREC invalid response received";      // plain ol' error
+                                       eresult = Status(110, "COMREC invalid response received");      // plain ol' error
                                        return (false);
                                    }
                            }
@@ -1238,7 +1238,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                if (useV34) gotprimary = waitForDCEChannel(false);
                                else {
                                    gotRTNC = false;
-                                   if (!raiseRecvCarrier(dolongtrain, emsg) && !gotRTNC) {
+                                   if (!raiseRecvCarrier(dolongtrain, eresult) && !gotRTNC) {
                                        if (wasTimeout()) {
                                            abortReceive();     // return to command mode
                                            setTimeout(false);
@@ -1246,7 +1246,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                        long wait = BIT(curcap->br) & BR_ALL ? 273066 / (curcap->br+1) : conf.t2Timer;
                                        if (lastResponse != AT_NOCARRIER && atCmd(rhCmd, AT_CONNECT, wait)) {   // wait longer
                                            // simulate adaptive receive
-                                           emsg = "";          // clear the failure
+                                           eresult.clear();            // clear the failure
                                            gotRTNC = true;
                                        } else {
                                            if (wasTimeout()) abortReceive();
@@ -1269,18 +1269,18 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                        }
                    }
                    if (!gotprimary && !sendERR) {
-                       if (emsg == "") {
-                           if (useV34) emsg = "Failed to properly open V.34 primary channel.";
-                           else emsg = "Failed to properly detect high-speed data carrier.";
+                       if (eresult.value() == 0) {
+                           if (useV34) eresult = Status(114, "Failed to properly open V.34 primary channel.");
+                           else eresult = Status(112, "Failed to properly detect high-speed data carrier.");
                        }
-                       protoTrace(emsg);
+                       protoTrace(eresult.string());
                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                        return (false);
                    }
                }
                if (gotEOT) {           // intentionally not an else of the previous if
-                   if (useV34 && emsg == "") emsg = "Received premature V.34 termination.";
-                   protoTrace(emsg);
+                   if (useV34 && eresult.value() == 0) eresult = Status(115, "Received premature V.34 termination.");
+                   protoTrace(eresult.string());
                    abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                    return (false);
                }
@@ -1334,14 +1334,14 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                setInputBuffering(false);
                if (useV34) {
                    if (!gotEOT && !gotCTRL && !waitForDCEChannel(true)) {
-                       emsg = "Failed to properly open V.34 control channel.";
-                       protoTrace(emsg);
+                       eresult = Status(116, "Failed to properly open V.34 control channel.");
+                       protoTrace(eresult.string());
                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                        return (false);
                    }
                    if (gotEOT) {
-                       emsg = "Received premature V.34 termination.";
-                       protoTrace(emsg);
+                       eresult = Status(115, "Received premature V.34 termination.");
+                       protoTrace(eresult.string());
                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                        return (false);
                    }
@@ -1450,7 +1450,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                }
 
                                // requisite pause before sending response (PPR/MCF)
-                               if (!blockgood && !useV34 && !switchingPause(emsg)) {
+                               if (!blockgood && !useV34 && !switchingPause(eresult)) {
                                    abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                    return (false);
                                }
@@ -1489,7 +1489,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                        lastResponse = AT_NOTHING;
                                        while (rtnframe.getFCF() == FCF_PPS && !gotEOT && recvFrameCount < 5 && gotrtnframe) {
                                            // we sent PPR, but got PPS again...
-                                           if (!useV34 && !switchingPause(emsg)) {
+                                           if (!useV34 && !switchingPause(eresult)) {
                                                abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                return (false);
                                            }
@@ -1504,7 +1504,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                            case FCF_CTC:
                                                if (useV34) {
                                                    // T.30 F.3.4.5 Note 1 does not permit CTC in V.34-fax
-                                                   emsg = "Received invalid CTC signal in V.34-Fax.";
+                                                   eresult = Status(113, "Received invalid CTC signal in V.34-Fax.");
                                                    abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                    return (false);
                                                }
@@ -1512,7 +1512,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                                dcs = rtnframe[3] | (rtnframe[4]<<8);
                                                curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
                                                // requisite pause before sending response (CTR)
-                                               if (!switchingPause(emsg)) {
+                                               if (!switchingPause(eresult)) {
                                                    abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                    return (false);
                                                }
@@ -1545,23 +1545,23 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                                        signalRcvd = rtnframe.getFCF2();
                                                        break;
                                                    default:
-                                                       emsg = "COMREC invalid response to repeated PPR received";
+                                                       eresult = Status(117, "COMREC invalid response to repeated PPR received");
                                                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                        return (false);
                                                }
                                                sendERR = true;         // do it later
                                                break;
                                            case FCF_DCN:
-                                               emsg = "COMREC received DCN";
+                                               eresult = Status(108, "COMREC received DCN (sender abort)");
                                                gotEOT = true;
                                                recvdDCN = true;  
                                            default:
-                                               if (emsg == "") emsg = "COMREC invalid response to repeated PPR received";
+                                               if (eresult.value() == 0) eresult = Status(117, "COMREC invalid response to repeated PPR received");
                                                abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                                return (false);
                                        }
                                    } else {
-                                       emsg = "T.30 T2 timeout, expected signal not received";
+                                       eresult = Status(118, "T.30 T2 timeout, expected signal not received");
                                        abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                        return (false);
                                    }
@@ -1583,7 +1583,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                        break;
                                    default:
                                        if (blockgood) {
-                                           emsg = "COMREC invalid partial-page signal received";
+                                           eresult = Status(119, "COMREC invalid partial-page signal received");
                                            abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                                            return (false);
                                        }
@@ -1598,7 +1598,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                            }
                            break;
                        case FCF_DCN:
-                           emsg = "COMREC received DCN";
+                           eresult = Status(108, "COMREC received DCN (sender abort)");
                            gotEOT = true;
                            recvdDCN = true;
                            abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
@@ -1613,19 +1613,19 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                 prevPage--;            // counteract the forthcoming increment
                                return (true);
                            } else {
-                               emsg = "COMREC invalid response received";      // plain ol' error
+                               eresult = Status(110, "COMREC invalid response received");      // plain ol' error
                                return (false);
                            }
                    }
                } else {
-                   emsg = "T.30 T2 timeout, expected signal not received";
+                   eresult = Status(118, "T.30 T2 timeout, expected signal not received");
                    abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
                    return (false);
                }
            } else {
                if (wasTimeout()) abortReceive();
                if (syncattempts++ > 20) {
-                   emsg = "Cannot synchronize ECM frame reception.";
+                   eresult = Status(120, "Cannot synchronize ECM frame reception.");
                    abortPageECMRecv(tif, params, block, fcount, seq, true);
                    return(false);
                }
@@ -1677,8 +1677,8 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                            bool gotresponse = true;
                            u_short rnrcnt = 0;
                            do {
-                               if (!useV34) (void) switchingPause(emsg);
-                               if (emsg != "") break;
+                               if (!useV34) (void) switchingPause(eresult);
+                               if (eresult.value() != 0) break;
                                (void) transmitFrame(FCF_RNR|FCF_RCVR);
                                traceFCF("RECV send", FCF_RNR);
                                HDLCFrame rrframe(conf.class1FrameOverhead);
@@ -1686,7 +1686,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                    traceFCF("RECV recv", rrframe.getFCF());
                                    if (rrframe.getFCF() == FCF_DCN) {
                                        protoTrace("RECV recv DCN");
-                                       emsg = "COMREC received DCN";
+                                       eresult = Status(108, "COMREC received DCN (sender abort)");
                                        gotEOT = true;
                                        recvdDCN = true;
                                    } else if (params.ec != EC_DISABLE && rrframe.getFCF() != FCF_RR) {
@@ -1694,7 +1694,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
                                    }
                                }
                            } while (!recvdDCN && !gotEOT && !gotresponse && ++rnrcnt < 2 && Sys::now()-rrstart < 60);
-                           if (!gotresponse) emsg = "No response to RNR repeated 3 times.";
+                           if (!gotresponse) eresult = Status(109, "No response to RNR repeated 3 times.");
                        } else tbuf[0] = 0;     // parent finished writeECMData
                    } while (!gotEOT && !recvdDCN && tbuf[0] != 0 && Sys::now()-rrstart < 60);
                    Sys::read(fcfd[0], NULL, 1);
@@ -1715,7 +1715,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
 
        if (!lastblock) {
            // confirm block received as good
-           if (!useV34) (void) switchingPause(emsg);
+           if (!useV34) (void) switchingPause(eresult);
            (void) transmitFrame((sendERR ? FCF_ERR : FCF_MCF)|FCF_RCVR);
            traceFCF("RECV send", sendERR ? FCF_ERR : FCF_MCF);
        }
@@ -1729,7 +1729,7 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
        // Just because image data blocks are received properly doesn't guarantee that
        // those blocks actually contain image data.  If the decoder finds no image
        // data at all we send DCN instead of MCF in hopes of a retransmission.
-       emsg = "ECM page received containing no image data.";
+       eresult = Status(121, "ECM page received containing no image data.");
        return (false);
     }
     return (true);             // signalRcvd is set, full page is received...
@@ -1739,13 +1739,13 @@ Class1Modem::recvPageECMData(TIFF* tif, const Class2Params& params, fxStr& emsg)
  * Receive Phase C data w/ or w/o copy quality checking.
  */
 bool
-Class1Modem::recvPageData(TIFF* tif, fxStr& emsg)
+Class1Modem::recvPageData(TIFF* tif, Status& eresult)
 {
     /*
      * T.30-A ECM mode requires a substantially different protocol than non-ECM faxes.
      */
     if (params.ec != EC_DISABLE) {
-       if (!recvPageECMData(tif, params, emsg)) {
+       if (!recvPageECMData(tif, params, eresult)) {
            /*
             * The previous page experienced some kind of error.  Falsify
             * some event settings in order to cope with the error gracefully.
@@ -1758,7 +1758,7 @@ Class1Modem::recvPageData(TIFF* tif, fxStr& emsg)
        TIFFSetField(tif, TIFFTAG_IMAGELENGTH, getRecvEOLCount());
        return (true);          // no RTN with ECM
     } else {
-       (void) recvPageDLEData(tif, checkQuality(), params, emsg);
+       (void) recvPageDLEData(tif, checkQuality(), params, eresult);
        TIFFSetField(tif, TIFFTAG_IMAGELENGTH, getRecvEOLCount());
        TIFFSetField(tif, TIFFTAG_CLEANFAXDATA, getRecvBadLineCount() ?
            CLEANFAXDATA_REGENERATED : CLEANFAXDATA_CLEAN);
@@ -1775,7 +1775,7 @@ Class1Modem::recvPageData(TIFF* tif, fxStr& emsg)
  * Complete a receive session.
  */
 bool
-Class1Modem::recvEnd(fxStr& emsg)
+Class1Modem::recvEnd(Status& eresult)
 {
     if (!recvdDCN && !gotEOT) {
        u_int t1 = howmany(conf.t1Timer, 1000); // T1 timer in seconds
@@ -1791,7 +1791,7 @@ Class1Modem::recvEnd(fxStr& emsg)
                case FCF_PPS:
                case FCF_EOP:
                case FCF_CRP:
-                   if (!useV34) (void) switchingPause(emsg);
+                   if (!useV34) (void) switchingPause(eresult);
                    (void) transmitFrame(FCF_MCF|FCF_RCVR);
                    traceFCF("RECV send", FCF_MCF);
                    break;
@@ -1799,7 +1799,7 @@ Class1Modem::recvEnd(fxStr& emsg)
                    recvdDCN = true;
                    break;
                default:
-                   if (!useV34) (void) switchingPause(emsg);
+                   if (!useV34) (void) switchingPause(eresult);
                    transmitFrame(FCF_DCN|FCF_RCVR);
                    recvdDCN = true;
                    break;
index ed16d94da0cf1c86b4130091051866dd40929961..cf52a20674bda1c45340d6b5fa1b7301a87a8c97 100644 (file)
  * Force the tty into a known flow control state.
  */
 bool
-Class1Modem::sendSetup(FaxRequest& req, const Class2Params& dis, fxStr& emsg)
+Class1Modem::sendSetup(FaxRequest& req, const Class2Params& dis, Status& eresult)
 {
     if (flowControl == FLOW_XONXOFF)
        setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_FLUSH);
-    return (FaxModem::sendSetup(req, dis, emsg));
+    return (FaxModem::sendSetup(req, dis, eresult));
 }
 
 /*
  * Wait-for and process a dial command response.
  */
 CallStatus
-Class1Modem::dialResponse(fxStr& emsg)
+Class1Modem::dialResponse(Status& eresult)
 {
     // This is as good a time as any, perhaps, to reset modemParams.br.
     // If the call does V.8 handshaking, then it will be altered.
@@ -63,7 +63,7 @@ Class1Modem::dialResponse(fxStr& emsg)
        
        /*
         * Blacklisting is handled internally just like a NOCARRIER.
-        * emsg is customized to let the user know the problem lies in
+        * eresult is customized to let the user know the problem lies in
         * the modem and not in line conditions, cables ...
         * The known blacklisting modem responses are:
         * 1. "BLACKLISTED"
@@ -78,7 +78,7 @@ Class1Modem::dialResponse(fxStr& emsg)
        if (strncmp(rbuf, "BLACKLISTED", 11) == 0
                || strncmp(rbuf, "DELAYED", 7) == 0
                || strncmp(rbuf, "DIALING DISABLED", 16) == 0) {
-           emsg = "Blacklisted by modem";
+           eresult = Status(10, "Blacklisted by modem");
            return (NOCARRIER);
        }
 
@@ -101,8 +101,8 @@ Class1Modem::dialResponse(fxStr& emsg)
             * several times (haven't yet encountered anyone that does).
             */
            if (++ntrys == 3) {
-               emsg = "Ringback detected, no answer without CED"; // XXX
-               protoTrace(emsg);
+               eresult = Status(11, "Ringback detected, no answer without CED"); // XXX
+               protoTrace(eresult.string());
                return (NOFCON);
            }
            break;
@@ -142,7 +142,7 @@ Class1Modem::checkReceiverDIS(Class2Params& params)
  * Get the initial DIS command.
  */
 FaxSendStatus
-Class1Modem::getPrologue(Class2Params& params, bool& hasDoc, fxStr& emsg, u_int& batched)
+Class1Modem::getPrologue(Class2Params& params, bool& hasDoc, Status& eresult, u_int& batched)
 {
     u_int t1 = howmany(conf.t1Timer, 1000);            // T1 timer in seconds
     time_t start = Sys::now();
@@ -158,7 +158,7 @@ Class1Modem::getPrologue(Class2Params& params, bool& hasDoc, fxStr& emsg, u_int&
        // We're not really switching directions of communication, but we don't want
        // to start listening for prologue frames until we're sure that the receiver 
        // has dropped the carrier used to signal MCF.
-       if (!useV34) (void) switchingPause(emsg);
+       if (!useV34) (void) switchingPause(eresult);
        // The receiver will allow T2 to elapse intentionally here.
        // To keep recvFrame from timing out we double our wait.
        framerecvd = recvFrame(frame, FCF_SNDR, conf.t2Timer * 2);
@@ -192,23 +192,23 @@ Class1Modem::getPrologue(Class2Params& params, bool& hasDoc, fxStr& emsg, u_int&
                case FCF_DIS:
                    hasDoc = dis_caps.isBitEnabled(FaxParams::BITNUM_T4XMTR);// documents to poll?
                    if (!dis_caps.isBitEnabled(FaxParams::BITNUM_T4RCVR)) {
-                       emsg = "Remote has no T.4 receiver capability";
-                       protoTrace(emsg);
+                       eresult = Status(122, "Remote has no T.4 receiver capability");
+                       protoTrace(eresult.string());
                        if (! hasDoc)   // don't die if we can poll
                            return (send_failed);
                    }
                    return (send_ok);
                case FCF_DTC:                           // NB: don't handle DTC
-                   emsg = "DTC received when expecting DIS (not supported)";
+                   eresult = Status(123, "DTC received when expecting DIS (not supported)");
                    break;
                case FCF_DCN:
-                   emsg = "COMREC error in transmit Phase B/got DCN";
+                   eresult = Status(124, "COMREC error in transmit Phase B/got DCN");
                    break;
                default:
-                   emsg = "COMREC invalid command received/no DIS or DTC";
+                   eresult = Status(125, "COMREC invalid command received/no DIS or DTC");
                    break;
                }
-               protoTrace(emsg);
+               protoTrace(eresult.string());
                return (send_retry);
            }
        }
@@ -217,11 +217,11 @@ Class1Modem::getPrologue(Class2Params& params, bool& hasDoc, fxStr& emsg, u_int&
         */
        if ((unsigned) Sys::now()-start >= t1)
            break;
-       if (!useV34) (void) switchingPause(emsg);
+       if (!useV34) (void) switchingPause(eresult);
        framerecvd = recvFrame(frame, FCF_SNDR, conf.t2Timer);
     }
-    emsg = "No answer (T.30 T1 timeout)";
-    protoTrace(emsg);
+    eresult = Status(126, "No receiver protocol (T.30 T1 timeout)");
+    protoTrace(eresult.string());
     return (send_retry);
 }
 
@@ -254,9 +254,9 @@ const u_int Class1Modem::modemPFMCodes[8] = {
 };
 
 bool
-Class1Modem::decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg)
+Class1Modem::decodePPM(const fxStr& pph, u_int& ppm, Status& eresult)
 {
-    if (FaxModem::decodePPM(pph, ppm, emsg)) {
+    if (FaxModem::decodePPM(pph, ppm, eresult)) {
        ppm = modemPFMCodes[ppm];
        return (true);
     } else
@@ -270,7 +270,7 @@ Class1Modem::decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg)
  */
 FaxSendStatus
 Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
-    fxStr& pph, fxStr& emsg, u_int& batched)
+    fxStr& pph, Status& eresult, u_int& batched)
 {
     int ntrys = 0;                     // # retraining/command repeats
     bool morePages = true;             // more pages still to send
@@ -291,7 +291,7 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
            params.br = (u_int) -1;             // force retraining
            batched = batched & ~BATCH_FIRST;   // must raise V.21 receive carrier
            bool hasDoc;
-           FaxSendStatus status = getPrologue(params, hasDoc, emsg, batched);
+           FaxSendStatus status = getPrologue(params, hasDoc, eresult, batched);
            if (status != send_ok) return (send_retry);
            repeatPhaseB = false;
        }
@@ -305,7 +305,7 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
         * DIS frame.
         */
        if (params != next) {
-           if (!sendTraining(next, 3, emsg)) {
+           if (!sendTraining(next, 3, eresult)) {
                if (hadV34Trouble) {
                    protoTrace("The destination appears to have trouble with V.34-Fax.");
                    return (send_v34fail);
@@ -330,7 +330,7 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
             * "before sending any signals using V.27 ter/V.29/V.33/V.17 
             * modulation system"
             */
-           if (!switchingPause(emsg)) {
+           if (!switchingPause(eresult)) {
                return (send_failed);
            }
        }
@@ -340,7 +340,7 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
         */
        morePages = !TIFFLastDirectory(tif);
        u_int cmd;
-       if (!decodePPM(pph, cmd, emsg))
+       if (!decodePPM(pph, cmd, eresult))
            return (send_failed);
        /*
         * If pph tells us that the PPM is going to be EOM it means that the
@@ -356,7 +356,7 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
        /*
         * Transmit the facsimile message/Phase C.
         */
-       if (!sendPage(tif, params, decodePageChop(pph, params), cmd, emsg)) {
+       if (!sendPage(tif, params, decodePageChop(pph, params), cmd, eresult)) {
            if (hadV34Trouble) {
                protoTrace("The destination appears to have trouble with V.34-Fax.");
                return (send_v34fail);
@@ -390,8 +390,8 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
             * by a simple pause.  +FTS must be used.
             */
            if (!atCmd(cmd == FCF_MPS ? conf.class1PPMWaitCmd : conf.class1EOPWaitCmd, AT_OK)) {
-               emsg = "Stop and wait failure (modem on hook)";
-               protoTrace(emsg);
+               eresult = Status(127, "Stop and wait failure (modem on hook)");
+               protoTrace(eresult.string());
                return (send_retry);
            }
        }
@@ -402,7 +402,7 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                /*
                 * Send post-page message and get response.
                 */
-               if (!sendPPM(cmd, frame, emsg)) {
+               if (!sendPPM(cmd, frame, eresult)) {
                    if (cmd == FCF_EOM && (batched & BATCH_FIRST)) {
                        protoTrace("The destination appears to not support batching.");
                        return (send_batchfail);
@@ -427,19 +427,19 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                    pph.remove(0,2+5+1);// discard page-chop+handling info
                else
                    pph.remove(0,3);    // discard page-handling info
-               if (params.ec == EC_DISABLE) (void) switchingPause(emsg);
+               if (params.ec == EC_DISABLE) (void) switchingPause(eresult);
                ntrys = 0;
                if (morePages) {        // meaning, more pages in this file, but there may be other files
                    if (!TIFFReadDirectory(tif)) {
-                       emsg = "Problem reading document directory";
-                       protoTrace(emsg);
+                       eresult = Status(302, "Problem reading document directory");
+                       protoTrace(eresult.string());
                        return (send_failed);
                    }
                }
                if (cmd != FCF_EOP) {
                    if (ppr == FCF_PIP) {
-                       emsg = "Procedure interrupt (operator intervention)";
-                       protoTrace(emsg);
+                       eresult = Status(129, "Procedure interrupt (operator intervention)");
+                       protoTrace(eresult.string());
                        return (send_failed);
                    }
                    if (ppr == FCF_MCF && !repeatPhaseB) {
@@ -457,8 +457,8 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                }
                break;
            case FCF_DCN:               // disconnect, abort
-               emsg = "Remote fax disconnected prematurely";
-               protoTrace(emsg);
+               eresult = Status(128, "Remote fax disconnected prematurely");
+               protoTrace(eresult.string());
                return (send_retry);
            case FCF_RTN:               // nak, retry after retraining
                 switch( conf.rtnHandling ){
@@ -476,64 +476,60 @@ Class1Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                        pph.remove(0,3);        // discard page-handling info
                    ntrys = 0;
                    if (ppr == FCF_PIP) {
-                       emsg = "Procedure interrupt (operator intervention)";
-                       protoTrace(emsg);
+                       eresult = Status(129, "Procedure interrupt (operator intervention)");
+                       protoTrace(eresult.string());
                        return (send_failed);
                    }
                    if (morePages) {
                        if (!TIFFReadDirectory(tif)) {
-                           emsg = "Problem reading document directory";
-                           protoTrace(emsg);
+                           eresult = Status(302, "Problem reading document directory");
+                           protoTrace(eresult.string());
                            return (send_failed);
                        }
                        FaxSendStatus status =
-                           sendSetupParams(tif, next, info, emsg);
+                           sendSetupParams(tif, next, info, eresult);
                        if (status != send_ok)
                            return (status);
                    }
                    continue;
                 case RTN_GIVEUP:
-                    emsg = "Unable to transmit page"
-                        " (giving up after RTN)";
-                   protoTrace(emsg);
+                    eresult = Status(130, "Unable to transmit page (giving up after RTN)");
+                   protoTrace(eresult.string());
                     return (send_failed); // "over and out"
                 }
                 // case RTN_RETRANSMIT
                 if (++ntrys >= 3) {
-                    emsg = "Unable to transmit page"
-                        " (giving up after 3 attempts)";
-                   protoTrace(emsg);
+                    eresult = Status(131, "Unable to transmit page (giving up after 3 attempts)");
+                   protoTrace(eresult.string());
                     return (send_retry);
 
                 }
                params.br = (u_int) -1; // force training
                if (!dropToNextBR(next)) {
-                    emsg = "Unable to transmit page"
-                        " (NAK at all possible signalling rates)";
-                   protoTrace(emsg);
+                    eresult = Status(132, "Unable to transmit page (NAK at all possible signalling rates)");
+                   protoTrace(eresult.string());
                     return (send_retry);
                }
                 morePages = true;      // retransmit page
                break;
            case FCF_PIN:               // nak, retry w/ operator intervention
-               emsg = "Unable to transmit page"
-                      " (NAK with operator intervention)";
-               protoTrace(emsg);
+               eresult = Status(133, "Unable to transmit page (NAK with operator intervention)");
+               protoTrace(eresult.string());
                return (send_failed);
            case FCF_CRP:
-               if (!useV34 && !switchingPause(emsg)) {
+               if (!useV34 && !switchingPause(eresult)) {
                    return (send_retry);
                }
                break;
            default:                    // unexpected abort
-               emsg = "Fax protocol error (unknown frame received)";
-               protoTrace(emsg);
+               eresult = Status(134, "Fax protocol error (unknown frame received)");
+               protoTrace(eresult.string());
                return (send_retry);
            }
        } while (ppr == FCF_CRP && ++ncrp < 3);
        if (ncrp == 3) {
-           emsg = "Fax protocol error (command repeated 3 times)";
-           protoTrace(emsg);
+           eresult = Status(135, "Fax protocol error (command repeated 3 times)");
+           protoTrace(eresult.string());
            return (send_retry);
        }
     } while (morePages);
@@ -577,8 +573,8 @@ Class1Modem::sendPrologue(FaxParams& dcs_caps, const fxStr& tsi)
     bool frameSent;
     if (useV34) frameSent = true;
     else {
-       fxStr emsg;
-       if (!switchingPause(emsg)) {
+       Status eresult;
+       if (!switchingPause(eresult)) {
            return (false);
        }
        frameSent = (atCmd(thCmd, AT_NOTHING) && atResponse(rbuf, 7550) == AT_CONNECT);
@@ -654,13 +650,13 @@ Class1Modem::isCapable(u_int sr, FaxParams& dis)
  * Send capabilities and do training.
  */
 bool
-Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
+Class1Modem::sendTraining(Class2Params& params, int tries, Status& eresult)
 {
     bool again = false;
     u_short attempt = 0;
     if (tries == 0) {
-       emsg = "DIS/DTC received 3 times; DCS not recognized";
-       protoTrace(emsg);
+       eresult = Status(136, "DIS/DTC received 3 times; DCS not recognized");
+       protoTrace(eresult.string());
        if (useV34) hadV34Trouble = true;       // sadly, some receivers will do this with V.34
        return (false);
     }
@@ -765,8 +761,8 @@ Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
                 * Class1PPMWaitCmd above.
                 */
                if (!atCmd(conf.class1TCFWaitCmd, AT_OK)) {
-                   emsg = "Stop and wait failure (modem on hook)";
-                   protoTrace(emsg);
+                   eresult = Status(127, "Stop and wait failure (modem on hook)");
+                   protoTrace(eresult.string());
                    return (send_retry);
                }
 
@@ -837,7 +833,7 @@ Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
                            curcap = NULL;
                        }
                    }
-                   return (sendTraining(params, --tries, emsg));
+                   return (sendTraining(params, --tries, eresult));
                default:
                    if (frame.getFCF() == FCF_DCN) {
                        /*
@@ -851,9 +847,9 @@ Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
                         * through.
                         */
                        if (curcap->mod == V17 && attempt == 1 && tries == 3) hadV17Trouble = true;
-                       emsg = "RSRPEC error/got DCN";
+                       eresult = Status(103, "RSPREC error/got DCN (sender abort)");
                    } else
-                       emsg = "RSPREC invalid response received";
+                       eresult = Status(104, "RSPREC invalid response received");
                    goto done;
                }
            } else {
@@ -866,7 +862,7 @@ Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
                 * The best way to do that is to make sure that there is
                 * silence on the line, and  we do that with Class1SwitchingCmd.
                 */
-               if (useV34 || !switchingPause(emsg)) {
+               if (useV34 || !switchingPause(eresult)) {
                    return (false);
                }
            }
@@ -889,7 +885,7 @@ Class1Modem::sendTraining(Class2Params& params, int tries, fxStr& emsg)
        }
     } while (!useV34 && again);
 failed:
-    emsg = "Failure to train remote modem at 2400 bps or minimum speed";
+    eresult = Status(137, "Failure to train remote modem at 2400 bps or minimum speed");
 done:
     if (!useV34) protoTrace("TRAINING failed");
     return (false);
@@ -994,7 +990,7 @@ Class1Modem::blockData(u_int byte, bool flag)
  * Perform T.30-A image block transmission protocol.
  */
 bool
-Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxStr& emsg)
+Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, Status& eresult)
 {
     // we have a full image frame
 
@@ -1106,7 +1102,7 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                setXONXOFF(FLOW_XONXOFF, FLOW_NONE, ACT_FLUSH);
            if (!useV34) {
                // T.30 5.3.2.4 (03/93) gives this to be a 75ms minimum
-               if (!switchingPause(emsg)) {
+               if (!switchingPause(eresult)) {
                    return (false);
                }
                /*
@@ -1164,8 +1160,8 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                if (!putModemData(buf, 2)) return (false);
                // wait for the ready indicator, <DLE><ctrl><DLE><crate>
                if (!waitForDCEChannel(true)) {
-                   emsg = "Failed to properly open control V.34 channel.";
-                   protoTrace(emsg);
+                   eresult = Status(116, "Failed to properly open control V.34 channel.");
+                   protoTrace(eresult.string());
                    return (false);
                }
            } else {
@@ -1193,8 +1189,8 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_DRAIN);
 
            if (!useV34 && !atCmd(ppmcmd == FCF_MPS ? conf.class1PPMWaitCmd : conf.class1EOPWaitCmd, AT_OK)) {
-               emsg = "Stop and wait failure (modem on hook)";
-               protoTrace(emsg);
+               eresult = Status(127, "Stop and wait failure (modem on hook)");
+               protoTrace(eresult.string());
                return (false);
            }
            /*
@@ -1239,14 +1235,14 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                        gotppr = false;
                        crpcnt++;
                        ppscnt = 0;
-                       if (!useV34 && !switchingPause(emsg)) {
+                       if (!useV34 && !switchingPause(eresult)) {
                            return (false);
                        }
                    }
                }
            } while (!gotppr && (++ppscnt < 3) && (crpcnt < 3) && !(useV34 && gotEOT));
            if (gotppr) {
-               if (!useV34 && !switchingPause(emsg)) {
+               if (!useV34 && !switchingPause(eresult)) {
                    return (false);
                }
                if (pprframe.getFCF() == FCF_RNR) {
@@ -1256,9 +1252,9 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                    do {
                        if ((unsigned) Sys::now()-start >= t1) {
                            // we use T1 rather than T5 to "minimize transmission inefficiency" (T.30 A.5.4.1)
-                           emsg = "Receiver flow control exceeded timer.";
+                           eresult = Status(138, "Receiver flow control exceeded timer.");
                            if (ppmcmd == FCF_EOM) batchingError = true;
-                           protoTrace(emsg);
+                           protoTrace(eresult.string());
                            return (false);
                        }
                        u_short rrcnt = 0, crpcnt = 0;
@@ -1277,15 +1273,15 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                    gotmsg = false;
                                    crpcnt++;
                                    rrcnt = 0;
-                                   if (!useV34 && !switchingPause(emsg)) {
+                                   if (!useV34 && !switchingPause(eresult)) {
                                        return (false);
                                    }
                                }
                            }
-                       } while (!gotmsg && (++rrcnt < 3) && (crpcnt < 3) && (useV34 || switchingPause(emsg)));
+                       } while (!gotmsg && (++rrcnt < 3) && (crpcnt < 3) && (useV34 || switchingPause(eresult)));
                        if (!gotmsg) {
-                           emsg = "No response to RR repeated 3 times.";
-                           protoTrace(emsg);
+                           eresult = Status(139, "No response to RR repeated 3 times.");
+                           protoTrace(eresult.string());
                            return (false);
                        }
                        switch (pprframe.getFCF()) {
@@ -1294,13 +1290,13 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                gotppr = true;
                                break;
                            case FCF_RNR:
-                               if (!useV34 && !switchingPause(emsg)) {
+                               if (!useV34 && !switchingPause(eresult)) {
                                    return (false);
                                }
                                break;
                            default:
-                               emsg = "COMREC invalid response received to RR.";
-                               protoTrace(emsg);
+                               eresult = Status(140, "COMREC invalid response received to RR.");
+                               protoTrace(eresult.string());
                                return (false);
                        }
                    } while (!gotppr);          
@@ -1402,20 +1398,20 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                            gotctr = false;
                                            crpcnt++;
                                            ctccnt = 0;
-                                           if (!switchingPause(emsg)) {
+                                           if (!switchingPause(eresult)) {
                                                return (false);
                                            }
                                        }
                                    }
                                } while (!gotctr && (++ctccnt < 3) && (crpcnt < 3));
                                if (!gotctr) {
-                                   emsg = "No response to CTC repeated 3 times.";
-                                   protoTrace(emsg);
+                                   eresult = Status(141, "No response to CTC repeated 3 times.");
+                                   protoTrace(eresult.string());
                                    return (false);
                                }
                                if (!ctrframe.getFCF() == FCF_CTR) {
-                                   emsg = "COMREC invalid response received to CTC.";
-                                   protoTrace(emsg);
+                                   eresult = Status(142, "COMREC invalid response received to CTC.");
+                                   protoTrace(eresult.string());
                                    return (false);
                                }
                                dolongtrain = true;     // T.30 states that we must use long-training next
@@ -1434,8 +1430,8 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                 */
                                if (blockgood == false && (params.df >= DF_2DMMR ||
                                    (params.df <= DF_2DMR && badframes > frameNumber/2))) {
-                                   emsg = "Failure to transmit clean ECM image data.";
-                                   protoTrace(emsg);
+                                   eresult = Status(143, "Failure to transmit clean ECM image data.");
+                                   protoTrace(eresult.string());
                                    return (false);
                                }
                                bool goterr = false;
@@ -1455,16 +1451,16 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                            goterr = false;
                                            crpcnt++;
                                            eorcnt = 0;
-                                           if (!useV34 && !switchingPause(emsg)) {
+                                           if (!useV34 && !switchingPause(eresult)) {
                                                return (false);
                                            }
                                        }
                                    }
                                } while (!goterr && (++eorcnt < 3) && (crpcnt < 3));
                                if (!goterr) {
-                                   emsg = "No response to EOR repeated 3 times.";
+                                   eresult = Status(144, "No response to EOR repeated 3 times.");
                                    if (ppmcmd == FCF_EOM) batchingError = true;
-                                   protoTrace(emsg);
+                                   protoTrace(eresult.string());
                                    return (false);
                                }
                                if (errframe.getFCF() == FCF_RNR) {
@@ -1474,9 +1470,9 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                    do {
                                        if ((unsigned) Sys::now()-start >= t1) {
                                            // we use T1 rather than T5 to "minimize transmission inefficiency" (T.30 A.5.4.1)
-                                           emsg = "Receiver flow control exceeded timer.";
+                                           eresult = Status(138, "Receiver flow control exceeded timer.");
                                            if (ppmcmd == FCF_EOM) batchingError = true;
-                                           protoTrace(emsg);
+                                           protoTrace(eresult.string());
                                            return (false);
                                        }
                                        u_short rrcnt = 0, crpcnt = 0;
@@ -1495,15 +1491,15 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                                    gotmsg = false;
                                                    crpcnt++;
                                                    rrcnt = 0;
-                                                   if (!useV34 && !switchingPause(emsg)) {
+                                                   if (!useV34 && !switchingPause(eresult)) {
                                                        return (false);
                                                    }
                                                }
                                            }
-                                       } while (!gotmsg && (++rrcnt < 3) && (crpcnt < 3) && (useV34 || switchingPause(emsg)));
+                                       } while (!gotmsg && (++rrcnt < 3) && (crpcnt < 3) && (useV34 || switchingPause(eresult)));
                                        if (!gotmsg) {
-                                           emsg = "No response to RR repeated 3 times.";
-                                           protoTrace(emsg);
+                                           eresult = Status(139, "No response to RR repeated 3 times.");
+                                           protoTrace(eresult.string());
                                            return (false);
                                        }
                                        switch (errframe.getFCF()) {
@@ -1511,20 +1507,20 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                                                goterr = true;
                                                break;
                                            case FCF_RNR:
-                                               if (!useV34 && !switchingPause(emsg)) {
+                                               if (!useV34 && !switchingPause(eresult)) {
                                                    return (false);
                                                }
                                                break;
                                            default:
-                                               emsg = "COMREC invalid response received to RR.";
-                                               protoTrace(emsg);
+                                               eresult = Status(140, "COMREC invalid response received to RR.");
+                                               protoTrace(eresult.string());
                                                return (false);
                                        }
                                    } while (!goterr);          
                                }
                                if (!(errframe.getFCF() == FCF_ERR)) {
-                                   emsg = "COMREC invalid response received to EOR.";
-                                   protoTrace(emsg);
+                                   eresult = Status(145, "COMREC invalid response received to EOR.");
+                                   protoTrace(eresult.string());
                                    return (false);
                                }
                                blockgood = true;
@@ -1533,14 +1529,14 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
                        }
                        break;
                    default:
-                       emsg = "COMREC invalid response received to PPS.";
-                       protoTrace(emsg);
+                       eresult = Status(146, "COMREC invalid response received to PPS.");
+                       protoTrace(eresult.string());
                        return(false);
                }
            } else {
-               emsg = "No response to PPS repeated 3 times.";
+               eresult = Status(147, "No response to PPS repeated 3 times.");
                if (ppmcmd == FCF_EOM) batchingError = true;
-               protoTrace(emsg);
+               protoTrace(eresult.string());
                return (false);
            }
        } while (!blockgood);
@@ -1555,7 +1551,7 @@ Class1Modem::blockFrame(const u_char* bitrev, bool lastframe, u_int ppmcmd, fxSt
  * Send T.30-A framed image data.
  */
 bool
-Class1Modem::sendClass1ECMData(const u_char* data, u_int cc, const u_char* bitrev, bool eod, u_int ppmcmd, fxStr& emsg)
+Class1Modem::sendClass1ECMData(const u_char* data, u_int cc, const u_char* bitrev, bool eod, u_int ppmcmd, Status& eresult)
 {
     /*
      * Buffer data into the block.  We buffer the entire block
@@ -1573,7 +1569,7 @@ Class1Modem::sendClass1ECMData(const u_char* data, u_int cc, const u_char* bitre
        ecmFrame[ecmFramePos++] = frameRev[data[i]];
        if (ecmFramePos == (frameSize + 4)) {
            bool lastframe = ((i == (cc - 1)) && eod);
-           if (!blockFrame(bitrev, lastframe, ppmcmd, emsg))
+           if (!blockFrame(bitrev, lastframe, ppmcmd, eresult))
                return (false);
            if (lastframe)
                return (true);
@@ -1584,7 +1580,7 @@ Class1Modem::sendClass1ECMData(const u_char* data, u_int cc, const u_char* bitre
            // frame must be filled to end with zero-data
            while (ecmFramePos < (frameSize + 4)) ecmFrame[ecmFramePos++] = 0x00;
        }
-       if (!blockFrame(bitrev, true, ppmcmd, emsg))
+       if (!blockFrame(bitrev, true, ppmcmd, eresult))
            return (false);
     }
     return (true);
@@ -1594,12 +1590,12 @@ Class1Modem::sendClass1ECMData(const u_char* data, u_int cc, const u_char* bitre
  * Send data for the current page.
  */
 bool
-Class1Modem::sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm, fxStr& emsg)
+Class1Modem::sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm, Status& eresult)
 {
     beginTimedTransfer();
     bool rc;
     if (ecm)
-       rc = sendClass1ECMData(data, cc, bitrev, false, 0, emsg);
+       rc = sendClass1ECMData(data, cc, bitrev, false, 0, eresult);
     else {
        rc = sendClass1Data(data, cc, bitrev, false, getDataTimeout());
        protoTrace("SENT %u bytes of data", cc);
@@ -1615,7 +1611,7 @@ Class1Modem::sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm
  * send all the data they are presented.
  */
 bool
-Class1Modem::sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 rows, fxStr& emsg)
+Class1Modem::sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 rows, Status& eresult)
 {
     if (params.df == DF_JBIG) {
        /*
@@ -1625,8 +1621,8 @@ Class1Modem::sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 row
        //u_char newlen[8] = { 0xFF, 0x05, 
        //    (rows>>24)&0xFF, (rows>>16)&0xFF, (rows>>8)&0xFF, rows&0xFF,
        //    0xFF, 0x02 };     // SDNORM is added per spec
-       //return sendClass1ECMData(newlen, 8, rtcRev, true, ppmcmd, emsg);
-       return sendClass1ECMData(NULL, 0, rtcRev, true, ppmcmd, emsg);
+       //return sendClass1ECMData(newlen, 8, rtcRev, true, ppmcmd, eresult);
+       return sendClass1ECMData(NULL, 0, rtcRev, true, ppmcmd, eresult);
     }
 
     // determine the number of trailing zeros on the last byte of data
@@ -1658,18 +1654,18 @@ Class1Modem::sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 row
        EOFB[2] = 0x80 >> zeros;
     if (params.df == DF_2DMMR) {
        protoTrace("SEND EOFB");
-       return sendClass1ECMData(EOFB, 3, rtcRev, true, ppmcmd, emsg);
+       return sendClass1ECMData(EOFB, 3, rtcRev, true, ppmcmd, eresult);
     }
     if (params.is2D()) {
        protoTrace("SEND 2D RTC");
        if (params.ec != EC_DISABLE)
-           return sendClass1ECMData(RTC2D, 9, rtcRev, true, ppmcmd, emsg);
+           return sendClass1ECMData(RTC2D, 9, rtcRev, true, ppmcmd, eresult);
        else
            return sendClass1Data(RTC2D, sizeof (RTC2D), rtcRev, true, getDataTimeout());
     } else {
        protoTrace("SEND 1D RTC");
        if (params.ec != EC_DISABLE)
-           return sendClass1ECMData(RTC1D, 10, rtcRev, true, ppmcmd, emsg);
+           return sendClass1ECMData(RTC1D, 10, rtcRev, true, ppmcmd, eresult);
        else
            return sendClass1Data(RTC1D, sizeof (RTC1D), rtcRev, true, getDataTimeout());
     }
@@ -1714,7 +1710,7 @@ EOLcode(u_long& w)
  * Send a page of data.
  */
 bool
-Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppmcmd, fxStr& emsg)
+Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppmcmd, Status& eresult)
 {
     int lastbyte = 0;
     if (params.ec == EC_DISABLE) {     // ECM does it later
@@ -1726,8 +1722,8 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
         */
        fxStr tmCmd(curcap[HasShortTraining(curcap)].value, tmCmdFmt);
        if (!atCmd(tmCmd, AT_CONNECT)) {
-           emsg = "Unable to establish message carrier";
-           protoTrace(emsg);
+           eresult = Status(148, "Unable to establish message carrier");
+           protoTrace(eresult.string());
            return (false);
        }
        // As with TCF, T.31 8.3.3 requires the DCE to report CONNECT at the beginning
@@ -1907,7 +1903,7 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
                     * the current data and reset the pointer into
                     * the zero fill buffer.
                     */
-                   rc = sendPageData(fill, fp-fill, bitrev, (params.ec != EC_DISABLE), emsg);
+                   rc = sendPageData(fill, fp-fill, bitrev, (params.ec != EC_DISABLE), eresult);
                    fp = fill;
                    if (!rc)                    // error writing data
                        break;
@@ -1918,7 +1914,7 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
                     * scanline alone.  Flush this scanline
                     * also.  lineLen is greater than minLen.
                     */
-                   rc = sendPageData(bol, lineLen, bitrev, (params.ec != EC_DISABLE), emsg);
+                   rc = sendPageData(bol, lineLen, bitrev, (params.ec != EC_DISABLE), eresult);
                    if (!rc)                    // error writing
                        break;
                } else {
@@ -1944,18 +1940,18 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
             * Flush anything that was not sent above.
             */
            if (fp > fill && rc)
-               rc = sendPageData(fill, fp-fill, bitrev, (params.ec != EC_DISABLE), emsg);
+               rc = sendPageData(fill, fp-fill, bitrev, (params.ec != EC_DISABLE), eresult);
            delete fill;
        } else {
            /*
             * No EOL-padding needed, just jam the bytes.
             */
-           rc = sendPageData(dp, (u_int) totdata, bitrev, (params.ec != EC_DISABLE), emsg);
+           rc = sendPageData(dp, (u_int) totdata, bitrev, (params.ec != EC_DISABLE), eresult);
        }
        delete data;
     }
     if (rc || abortRequested())
-       rc = sendRTC(params, ppmcmd, lastbyte, rowsperstrip, emsg);
+       rc = sendRTC(params, ppmcmd, lastbyte, rowsperstrip, eresult);
     protoTrace("SEND end page");
     if (params.ec == EC_DISABLE) {
        // these were already done by ECM protocol
@@ -1983,9 +1979,9 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
        if (flowControl == FLOW_XONXOFF)
            setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_DRAIN);
     }
-    if (!rc && (emsg == "")) {
-       emsg = "Unspecified Transmit Phase C error";    // XXX
-       protoTrace(emsg);
+    if (!rc && (eresult.value() == 0)) {
+       eresult = Status(149, "Unspecified Transmit Phase C error");    // XXX
+       protoTrace(eresult.string());
     }
     return (rc);
 }
@@ -1994,7 +1990,7 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
  * Send the post-page-message and wait for a response.
  */
 bool
-Class1Modem::sendPPM(u_int ppm, HDLCFrame& mcf, fxStr& emsg)
+Class1Modem::sendPPM(u_int ppm, HDLCFrame& mcf, Status& eresult)
 {
     for (int t = 0; t < 3; t++) {
        traceFCF("SEND send", ppm);
@@ -2006,19 +2002,19 @@ Class1Modem::sendPPM(u_int ppm, HDLCFrame& mcf, fxStr& emsg)
     }
     switch (ppm) {
        case FCF_MPS:
-           emsg = "No response to MPS repeated 3 tries";
+           eresult = Status(150, "No response to MPS repeated 3 tries");
            break;
        case FCF_EOP:
-           emsg = "No response to EOP repeated 3 tries";
+           eresult = Status(151, "No response to EOP repeated 3 tries");
            break;
        case FCF_EOM:
-           emsg = "No response to EOM repeated 3 tries";
+           eresult = Status(152, "No response to EOM repeated 3 tries");
            break;
        default:
-           emsg = "No response to PPM repeated 3 tries";
+           eresult = Status(153, "No response to PPM repeated 3 tries");
            break;
     }
-    protoTrace(emsg);
+    protoTrace(eresult.string());
     return (false);
 }
 
@@ -2028,8 +2024,8 @@ Class1Modem::sendPPM(u_int ppm, HDLCFrame& mcf, fxStr& emsg)
 void
 Class1Modem::sendEnd()
 {
-    fxStr emsg;
-    if (!useV34) (void) switchingPause(emsg);
+    Status eresult;
+    if (!useV34) (void) switchingPause(eresult);
     transmitFrame(FCF_DCN|FCF_SNDR);           // disconnect
     setInputBuffering(true);
 }
index 2495cb2431128f941711e875a4664c5ffa33b69f..be1b0e58544a87bdff624f49d6731956cda93afc 100644 (file)
@@ -735,80 +735,81 @@ Class2Modem::skipStatus(const char* s)
  * hexadecimal renumbering done in 2388-B!
  */
 static struct HangupCode {
-    const char*        code[3];        // from 2388/89, 2388/90, 2388-A, and 2388-B
+    const char*        code[3];        // from 2388/89, 2388/90, 2388-A, 2388-B
+    const int status;          // HylaFAX code
     const char*        message;        // what code means
 } hangupCodes[] = {
 // Call placement and termination
-    {{  "0",  "0",  "0" }, "Normal and proper end of connection" },
-    {{  "1",  "1",  "1" }, "Ring detect without successful handshake" },
-    {{  "2",  "2",  "2" }, "Call aborted,  from +FK or <CAN>" },
-    {{ NULL,  "3",  "3" }, "No loop current" },
-    {{ NULL, NULL,  "4" }, "Ringback detected, no answer (timeout)" },
-    {{ NULL, NULL,  "5" }, "Ringback detected, no answer without CED" },
+    {{  "0",  "0",  "0"}, 211, "Normal and proper end of connection" },
+    {{  "1",  "1",  "1"}, 212, "Ring detect without successful handshake" },
+    {{  "2",  "2",  "2"}, 213, "Call aborted,  from +FK or <CAN>" },
+    {{ NULL,  "3",  "3"}, 214, "No loop current" },
+    {{ NULL, NULL,  "4"}, 215, "Ringback detected, no answer (timeout)" },
+    {{ NULL, NULL,  "5"}, 216, "Ringback detected, no answer without CED" },
 // Transmit Phase A & miscellaneous errors
-    {{ "10", "10", "10" }, "Unspecified Phase A error" },
-    {{ "11", "11", "11" }, "No answer (T.30 T1 timeout)" },
+    {{ "10", "10", "10"}, 217, "Unspecified Phase A error" },
+    {{ "11", "11", "11"}, 218, "No answer (T.30 T1 timeout)" },
 // Transmit Phase B
-    {{ "20", "20", "20" }, "Unspecified Transmit Phase B error" },
-    {{ "21", "21", "21" }, "Remote cannot be polled" },
-    {{ "22", "22", "22" }, "COMREC error in transmit Phase B/got DCN" },
-    {{ "23", "23", "23" }, "COMREC invalid command received/no DIS or DTC" },
-    {{ "24", "24", "24" }, "RSPREC error/got DCN" },
-    {{ "25", "25", "25" }, "DCS sent 3 times without response" },
-    {{ "26", "26", "26" }, "DIS/DTC received 3 times; DCS not recognized" },
-    {{ "27", "27", "27" }, "Failure to train at 2400 bps or +FMINSP value" },
-    {{ "28", "28", "28" }, "RSPREC invalid response received" },
+    {{ "20", "20", "20"}, 219, "Unspecified Transmit Phase B error" },
+    {{ "21", "21", "21"}, 220, "Remote cannot be polled" },
+    {{ "22", "22", "22"}, 221, "COMREC error in transmit Phase B/got DCN" },
+    {{ "23", "23", "23"}, 222, "COMREC invalid command received/no DIS or DTC" },
+    {{ "24", "24", "24"}, 223, "RSPREC error/got DCN" },
+    {{ "25", "25", "25"}, 224, "DCS sent 3 times without response" },
+    {{ "26", "26", "26"}, 225, "DIS/DTC received 3 times; DCS not recognized" },
+    {{ "27", "27", "27"}, 226, "Failure to train at 2400 bps or +FMINSP value" },
+    {{ "28", "28", "28"}, 227, "RSPREC invalid response received" },
 // Transmit Phase C
-    {{ "30", "40", "40" }, "Unspecified Transmit Phase C error" },
-    {{ NULL, NULL, "41" }, "Unspecified Image format error" },
-    {{ NULL, NULL, "42" }, "Image conversion error" },
-    {{ "33", "43", "43" }, "DTE to DCE data underflow" },
-    {{ NULL, NULL, "44" }, "Unrecognized Transparent data command" },
-    {{ NULL, NULL, "45" }, "Image error, line length wrong" },
-    {{ NULL, NULL, "46" }, "Image error, page length wrong" },
-    {{ NULL, NULL, "47" }, "Image error, wrong compression code" },
+    {{ "30", "40", "40"}, 228, "Unspecified Transmit Phase C error" },
+    {{ NULL, NULL, "41"}, 229, "Unspecified Image format error" },
+    {{ NULL, NULL, "42"}, 230, "Image conversion error" },
+    {{ "33", "43", "43"}, 231, "DTE to DCE data underflow" },
+    {{ NULL, NULL, "44"}, 232, "Unrecognized Transparent data command" },
+    {{ NULL, NULL, "45"}, 233, "Image error, line length wrong" },
+    {{ NULL, NULL, "46"}, 234, "Image error, page length wrong" },
+    {{ NULL, NULL, "47"}, 235, "Image error, wrong compression code" },
 // Transmit Phase D
-    {{ "40", "50", "50" }, "Unspecified Transmit Phase D error, including"
-                          " +FPHCTO timeout between data and +FET command" },
-    {{ "41", "51", "51" }, "RSPREC error/got DCN" },
-    {{ "42", "52", "52" }, "No response to MPS repeated 3 times" },
-    {{ "43", "53", "53" }, "Invalid response to MPS" },
-    {{ "44", "54", "54" }, "No response to EOP repeated 3 times" },
-    {{ "45", "55", "55" }, "Invalid response to EOP" },
-    {{ "46", "56", "56" }, "No response to EOM repeated 3 times" },
-    {{ "47", "57", "57" }, "Invalid response to EOM" },
-    {{ "48", "58", "58" }, "Unable to continue after PIN or PIP" },
+    {{ "40", "50", "50"}, 236, "Unspecified Transmit Phase D error, including"
+                                  " +FPHCTO timeout between data and +FET command" },
+    {{ "41", "51", "51"}, 237, "RSPREC error/got DCN" },
+    {{ "42", "52", "52"}, 238, "No response to MPS repeated 3 times" },
+    {{ "43", "53", "53"}, 239, "Invalid response to MPS" },
+    {{ "44", "54", "54"}, 240, "No response to EOP repeated 3 times" },
+    {{ "45", "55", "55"}, 241, "Invalid response to EOP" },
+    {{ "46", "56", "56"}, 242, "No response to EOM repeated 3 times" },
+    {{ "47", "57", "57"}, 243, "Invalid response to EOM" },
+    {{ "48", "58", "58"}, 244, "Unable to continue after PIN or PIP" },
 // Received Phase B
-    {{ "50", "70", "70" }, "Unspecified Receive Phase B error" },
-    {{ "51", "71", "71" }, "RSPREC error/got DCN" },
-    {{ "52", "72", "72" }, "COMREC error" },
-    {{ "53", "73", "73" }, "T.30 T2 timeout, expected page not received" },
-    {{ "54", "74", "74" }, "T.30 T1 timeout after EOM received" },
+    {{ "50", "70", "70"}, 245, "Unspecified Receive Phase B error" },
+    {{ "51", "71", "71"}, 246, "RSPREC error/got DCN" },
+    {{ "52", "72", "72"}, 247, "COMREC error" },
+    {{ "53", "73", "73"}, 248, "T.30 T2 timeout, expected page not received" },
+    {{ "54", "74", "74"}, 249, "T.30 T1 timeout after EOM received" },
 // Receive Phase C
-    {{ "60", "90", "90" }, "Unspecified Phase C error, including too much delay"
-                          " between TCF and +FDR command" },
-    {{ "61", "91", "91" }, "Missing EOL after 5 seconds (section 3.2/T.4)" },
-    {{ "63", "93", "93" }, "DCE to DTE buffer overflow" },
-    {{ "64", "94", "92" }, "Bad CRC or frame (ECM or BFT modes)" },
+    {{ "60", "90", "90"}, 250, "Unspecified Phase C error, including too much delay"
+                                  " between TCF and +FDR command" },
+    {{ "61", "91", "91"}, 251, "Missing EOL after 5 seconds (section 3.2/T.4)" },
+    {{ "63", "93", "93"}, 252, "DCE to DTE buffer overflow" },
+    {{ "64", "94", "92"}, 253, "Bad CRC or frame (ECM or BFT modes)" },
 // Receive Phase D
-    {{ "70","100", "A0" }, "Unspecified Phase D error" },
-    {{ "71","101", "A1" }, "RSPREC invalid response received" },
-    {{ "72","102", "A2" }, "COMREC invalid response received" },
-    {{ "73","103", "A3" }, "Unable to continue after PIN or PIP, no PRI-Q" },
+    {{ "70","100", "A0"}, 254, "Unspecified Phase D error" },
+    {{ "71","101", "A1"}, 255, "RSPREC invalid response received" },
+    {{ "72","102", "A2"}, 256, "COMREC invalid response received" },
+    {{ "73","103", "A3"}, 257, "Unable to continue after PIN or PIP, no PRI-Q" },
 // Agere proprietary error codes
-    {{ NULL, NULL, "E0" }, "Command or signal 10 sec. timeout" },
+    {{ NULL, NULL, "E0"}, 258, "Command or signal 10 sec. timeout" },
 // Everex proprietary error codes (9/28/90)
-    {{ NULL,"128", NULL }, "Cannot send: +FMINSP > remote's +FDIS(BR) code" },
-    {{ NULL,"129", NULL }, "Cannot send: remote is V.29 only,"
-                          " local DCE constrained to 2400 or 4800 bps" },
-    {{ NULL,"130", NULL }, "Remote station cannot receive (DIS bit 10)" },
-    {{ NULL,"131", NULL }, "+FK aborted or <CAN> aborted" },
-    {{ NULL,"132", NULL }, "+Format conversion error in +FDT=DF,VR, WD,LN"
-                          " Incompatible and inconvertable data format" },
-    {{ NULL,"133", NULL }, "Remote cannot receive" },
-    {{ NULL,"134", NULL }, "After +FDR, DCE waited more than 30 seconds for"
-                          " XON from DTE after XOFF from DTE" },
-    {{ NULL,"135", NULL }, "In Polling Phase B, remote cannot be polled" },
+    {{ NULL,"128", NULL}, 259, "Cannot send: +FMINSP > remote's +FDIS(BR) code" },
+    {{ NULL,"129", NULL}, 260, "Cannot send: remote is V.29 only,"
+                                  " local DCE constrained to 2400 or 4800 bps" },
+    {{ NULL,"130", NULL}, 261, "Remote station cannot receive (DIS bit 10)" },
+    {{ NULL,"131", NULL}, 262, "+FK aborted or <CAN> aborted" },
+    {{ NULL,"132", NULL}, 263, "+Format conversion error in +FDT=DF,VR, WD,LN"
+                                  " Incompatible and inconvertable data format" },
+    {{ NULL,"133", NULL}, 264, "Remote cannot receive" },
+    {{ NULL,"134", NULL}, 265, "After +FDR, DCE waited more than 30 seconds for"
+                                  " XON from DTE after XOFF from DTE" },
+    {{ NULL,"135", NULL}, 266, "In Polling Phase B, remote cannot be polled" },
 };
 #define        NCODES  (sizeof (hangupCodes) / sizeof (hangupCodes[0]))
 
@@ -833,6 +834,21 @@ Class2Modem::hangupCause(const char* code)
     return ("Unknown hangup code");
 }
 
+const Status& Class2Modem::hangupStatus (const char* code)
+{
+    static Status s;
+    s.clear();
+    for (u_int i = 0; i < NCODES; i++) {
+       const HangupCode& c = hangupCodes[i];
+       if ((c.code[1] != NULL && strcasecmp(code, c.code[1]) == 0) ||
+           (c.code[2] != NULL && strcasecmp(code, c.code[2]) == 0))
+           s = Status(c.status, c.message);
+           return s;
+    }
+    s = Status(210, "Unknown hangup code");
+    return s;
+}
+
 /*
  * Process a hangup code string.
  */
index 4fae70422b760da34ca4b3b3ff5abcfe71cc53e0..ede53a7ff3b4a3117421741bb74eb18a6c48e2d9 100644 (file)
@@ -69,7 +69,7 @@ protected:
     bool       useExtendedDF;          // if true, modem has T.32-A data format extension
     bool       useJP;                  // if true, modem has JP +FCC parameter option
     char       recvDataTrigger;        // char to send to start recv'ing data
-    char       hangupCode[4];          // hangup reason (from modem)
+    char       hangupCode[5];          // hangup reason (from modem)
     bool       hadHangup;              // true if +FHNG:/+FHS: received
     fxStr      lid;                    // prepared local identifier string
 
@@ -90,7 +90,7 @@ protected:
 // reception support
     const AnswerMsg* findAnswer(const char*);
     bool       recvDCS(const char*);
-    bool       recvPageData(TIFF*, fxStr& emsg);
+    bool       recvPageData(TIFF*, Status& eresult);
     bool       recvPPM(TIFF*, int& ppr);
     bool       parseFPTS(TIFF*, const char* cp, int& ppr);
     void       abortPageRecv();
@@ -119,6 +119,7 @@ protected:
     void       processHangup(const char*);
     bool       isNormalHangup();
     const char*        hangupCause(const char* code);
+    const Status&      hangupStatus(const char* code);
     void       tracePPR(const char* dir, u_int ppr);
     void       tracePPM(const char* dir, u_int ppm);
 // class 2 command support routines
@@ -138,26 +139,26 @@ public:
     virtual ~Class2Modem();
 
 // send support
-    bool       sendSetup(FaxRequest&, const Class2Params&, fxStr& emsg);
-    CallStatus dialResponse(fxStr& emsg);
-    FaxSendStatus getPrologue(Class2Params&, bool&, fxStr&, u_int&);
+    bool       sendSetup(FaxRequest&, const Class2Params&, Status& eresult);
+    CallStatus dialResponse(Status& eresult);
+    FaxSendStatus getPrologue(Class2Params&, bool&, Status& eresult, u_int&);
     FaxSendStatus sendPhaseB(TIFF* tif, Class2Params&, FaxMachineInfo&,
-                   fxStr& pph, fxStr& emsg, u_int& batched);
+                   fxStr& pph, Status& eresult, u_int& batched);
     void       sendAbort();
 
 // receive support
     bool       setupReceive();
-    bool       recvBegin(fxStr& emsg);
-    bool       recvEOMBegin(fxStr& emsg);
-    bool       recvPage(TIFF*, u_int& ppm, fxStr& emsg, const fxStr& id);
-    bool       recvEnd(fxStr& emsg);
+    bool       recvBegin(Status& eresult);
+    bool       recvEOMBegin(Status& eresult);
+    bool       recvPage(TIFF*, u_int& ppm, Status& eresult, const fxStr& id);
+    bool       recvEnd(Status& eresult);
     void       recvAbort();
     void       pokeConfig(bool isSend);
 
 // polling support
-    bool       requestToPoll(fxStr& emsg);
+    bool       requestToPoll(Status& eresult);
     bool       pollBegin(const fxStr& cig, const fxStr& sep, const fxStr& pwd,
-                   fxStr& emsg);
+                   Status& eresult);
 
 // miscellaneous
     bool       faxService(bool enableV34, bool enableV17);     // switch to fax mode (send)
index 96e93ae105f8f6d00153cb1796b8ed760348f14b..a4bec6e89c02b95957e52b98e08983f945f3df61 100644 (file)
  * Request to poll remote documents.
  */
 bool
-Class2Modem::requestToPoll(fxStr& emsg)
+Class2Modem::requestToPoll(Status& eresult)
 {
     if (!class2Cmd(splCmd, 1)) {
-       emsg = "Unable to request polling operation"
-           " (modem may not support polling)";
+       eresult = Status(200, "Unable to request polling operation (modem may not support polling)");
        return (false);
     } else
        return (true);
@@ -44,20 +43,20 @@ Class2Modem::requestToPoll(fxStr& emsg)
  * Startup a polled receive operation.
  */
 bool
-Class2Modem::pollBegin(const fxStr& cig, const fxStr& sep, const fxStr& pwd, fxStr& emsg)
+Class2Modem::pollBegin(const fxStr& cig, const fxStr& sep, const fxStr& pwd, Status& eresult)
 {
     const char* cmdFailed = "Unable to setup %s (modem command failed)";
 
     if (!class2Cmd(cigCmd, cig)) {             // set polling ID
-       emsg = fxStr::format(cmdFailed, "polling identifer");
+       eresult = Status(201, cmdFailed, "polling identifer");
        return (false);
     }
     if (sep != "" && paCmd != "" && !class2Cmd(paCmd, sep)) {
-       emsg = fxStr::format(cmdFailed, "selective polling address");
+       eresult = Status(202, cmdFailed, "selective polling address");
        return (false);
     }
     if (pwd != "" && pwCmd != "" && !class2Cmd(pwCmd, pwd)) {
-       emsg = fxStr::format(cmdFailed, "polling password");
+       eresult = Status(203, cmdFailed, "polling password");
        return (false);
     }
     return (true);
index 460dca676b03fe7984ee5f0b245b8c619bd204dc..9762480fe3448ec570004e853cf18cf5977db82f 100644 (file)
@@ -57,7 +57,7 @@ Class2Modem::findAnswer(const char* s)
  * Begin a fax receive session.
  */
 bool
-Class2Modem::recvBegin(fxStr& emsg)
+Class2Modem::recvBegin(Status& eresult)
 {
     bool status = false;
     hangupCode[0] = '\0';
@@ -72,7 +72,7 @@ Class2Modem::recvBegin(fxStr& emsg)
        case AT_TIMEOUT:
        case AT_EMPTYLINE:
            processHangup("70");
-           emsg = hangupCause(hangupCode);
+           eresult = hangupStatus(hangupCode);
            return (false);
        case AT_FNSS:
            // XXX parse and pass on to server
@@ -100,7 +100,7 @@ Class2Modem::recvBegin(fxStr& emsg)
        }
     } while (r != AT_OK);
     if (!status)
-       emsg = hangupCause(hangupCode);
+       eresult = hangupStatus(hangupCode);
     return (status);
 }
 
@@ -108,7 +108,7 @@ Class2Modem::recvBegin(fxStr& emsg)
  * Begin a fax receive session after EOM.
  */
 bool
-Class2Modem::recvEOMBegin(fxStr& emsg)
+Class2Modem::recvEOMBegin(Status&)
 {
     /*
      * There's nothing to do because the modem
@@ -140,7 +140,7 @@ Class2Modem::recvDCS(const char* cp)
  * received post-page-message.
  */
 bool
-Class2Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
+Class2Modem::recvPage(TIFF* tif, u_int& ppm, Status& eresult, const fxStr& id)
 {
     int ppr;
     bool prevPage = false;
@@ -199,7 +199,7 @@ Class2Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
         *     don't understand the FillOrder tag!
         */
        recvSetupTIFF(tif, group3opts, FILLORDER_LSB2MSB, id);
-       if (!recvPageData(tif, emsg)) {
+       if (!recvPageData(tif, eresult)) {
            prevPage = false;
            goto bad;
        }
@@ -229,7 +229,7 @@ Class2Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
         */
        if (abortRequested()) {
            // XXX no way to purge TIFF directory
-           emsg = "Receive aborted due to operator intervention";
+           eresult = Status(301, "Receive aborted due to operator intervention");
            return (false);
        }
        // XXX deal with PRI interrupts
@@ -259,7 +259,7 @@ Class2Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
 bad:
     if (hangupCode[0] == 0)
        processHangup("90");                    // "Unspecified Phase C error"
-    emsg = hangupCause(hangupCode);
+    eresult = hangupStatus(hangupCode);
     if (prevPage && conf.saveUnconfirmedPages) {
        TIFFWriteDirectory(tif);
        protoTrace("RECV keeping unconfirmed page");
@@ -279,7 +279,7 @@ Class2Modem::abortPageRecv()
  * Receive Phase C data using the Class 2 ``stream interface''.
  */
 bool
-Class2Modem::recvPageData(TIFF* tif, fxStr& emsg)
+Class2Modem::recvPageData(TIFF* tif, Status& eresult)
 {
     if (flowControl == FLOW_XONXOFF)
        (void) setXONXOFF(FLOW_NONE, FLOW_XONXOFF, ACT_FLUSH);
@@ -300,7 +300,7 @@ Class2Modem::recvPageData(TIFF* tif, fxStr& emsg)
        hostDidCQ = modemCQ == 0 && checkQuality();
     protoTrace("Copy quality checking performed by %s", hostDidCQ ? "host" : "modem");
 
-    bool pageRecvd = recvPageDLEData(tif, hostDidCQ, params, emsg);
+    bool pageRecvd = recvPageDLEData(tif, hostDidCQ, params, eresult);
 
     // be careful about flushing here -- otherwise we lose +FPTS codes
     if (flowControl == FLOW_XONXOFF)
@@ -382,7 +382,7 @@ Class2Modem::parseFPTS(TIFF* tif, const char* cp, int& ppr)
  * Complete a receive session.
  */
 bool
-Class2Modem::recvEnd(fxStr&)
+Class2Modem::recvEnd(Status&)
 {
     if (!hadHangup) {
        if (isNormalHangup()) {
index b38d3e52235205ee81adf2ae50b8697e9af8dda0..01d031177beefcd6ea9857a94bcebde10f729e44 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 bool
-Class2Modem::sendSetup(FaxRequest& req, const Class2Params& dis, fxStr& emsg)
+Class2Modem::sendSetup(FaxRequest& req, const Class2Params& dis, Status& eresult)
 {
     const char* cmdFailed = " (modem command failed)";
 
@@ -47,35 +47,35 @@ Class2Modem::sendSetup(FaxRequest& req, const Class2Params& dis, fxStr& emsg)
      * we'll send this stuff to the modem here (for now at least).
      */
     if (req.passwd != "" && pwCmd != "" && !class2Cmd(pwCmd, req.passwd)) {
-       emsg = fxStr::format("Unable to send password%s", cmdFailed);
+       eresult = Status(204, "Unable to send password%s", cmdFailed);
        return (false);
     }
     if (req.subaddr != "" && saCmd != "" && !class2Cmd(saCmd, req.subaddr)) {
-       emsg = fxStr::format("Unable to send subaddress%s", cmdFailed);
+       eresult = Status(205, "Unable to send subaddress%s", cmdFailed);
        return (false);
     }
     if (minsp != BR_2400 && !class2Cmd(minspCmd, minsp)) {
-       emsg = fxStr::format("Unable to restrict minimum transmit speed to %s",
+       eresult = Status(206, "Unable to restrict minimum transmit speed to %s%s",
            Class2Params::bitRateNames[req.minbr], cmdFailed);
        return (false);
     }
     if (conf.class2DDISCmd != "") {
        if (!class2Cmd(conf.class2DDISCmd, dis, false)) {
-           emsg = fxStr::format("Unable to setup session parameters "
-               "prior to call%s", cmdFailed);
+           eresult = Status(207, "Unable to setup session parameters "
+                        "prior to call%s", cmdFailed);
            return (false);
        }
        params = dis;
     }
     hadHangup = false;
-    return (FaxModem::sendSetup(req, dis, emsg));
+    return (FaxModem::sendSetup(req, dis, eresult));
 }
 
 /*
  * Process the response to a dial command.
  */
 CallStatus
-Class2Modem::dialResponse(fxStr& emsg)
+Class2Modem::dialResponse(Status& eresult)
 {
     ATResponse r;
 
@@ -91,7 +91,7 @@ Class2Modem::dialResponse(fxStr& emsg)
        if (strncmp(rbuf, "BLACKLISTED", 11) == 0
                || strncmp(rbuf, "DELAYED", 7) == 0
                || strncmp(rbuf, "DIALING DISABLED", 16) == 0) {
-           emsg = "Blacklisted by modem";
+           eresult = Status(10, "Blacklisted by modem");
            return (NOCARRIER);
        }
 
@@ -103,7 +103,7 @@ Class2Modem::dialResponse(fxStr& emsg)
        case AT_NODIALTONE: return (NODIALTONE);// local phone connection hosed
        case AT_NOANSWER:   return (NOANSWER);  // no answer or ring back
        case AT_FHNG:                           // Class 2 hangup code
-           emsg = hangupCause(hangupCode);
+           eresult = hangupStatus(hangupCode);;
            switch (atoi(hangupCode)) {
            case 1:         return (NOANSWER);  // Ring detected w/o handshake
            case 3:         return (NOANSWER);  // No loop current (???)
@@ -129,7 +129,7 @@ Class2Modem::dialResponse(fxStr& emsg)
  * sent to the caller on connecting to a fax machine.
  */
 FaxSendStatus
-Class2Modem::getPrologue(Class2Params& dis, bool& hasDoc, fxStr& emsg, u_int& batched)
+Class2Modem::getPrologue(Class2Params& dis, bool& hasDoc, Status& eresult, u_int& batched)
 {
     bool gotParams = false;
     hasDoc = false;
@@ -162,7 +162,7 @@ Class2Modem::getPrologue(Class2Params& dis, bool& hasDoc, fxStr& emsg, u_int& ba
                processHangup("20");            // Unspecified Phase B error
                /* fall thru... */
            case AT_FHNG:
-               emsg = hangupCause(hangupCode);
+               eresult = hangupStatus(hangupCode);
                return (send_retry);
            }
        }
@@ -238,7 +238,7 @@ pageInfoChanged(const Class2Params& a, const Class2Params& b)
  */
 FaxSendStatus
 Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
-    fxStr& pph, fxStr& emsg, u_int& batched)
+    fxStr& pph, Status& eresult, u_int& batched)
 {
     int ntrys = 0;                     // # retraining/command repeats
     u_int ppm, previousppm = 0;
@@ -259,7 +259,7 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
         */
        if (pageInfoChanged(params, next)) {
            if (!class2Cmd(disCmd, next, false)) {
-               emsg = "Unable to set session parameters";
+               eresult = Status(208, "Unable to set session parameters");
                break;
            }
            params = next;
@@ -270,7 +270,7 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
             * remote station (XXX need to deal with PRI requests).).
             */
            morePages = !TIFFLastDirectory(tif);
-           if (!decodePPM(pph, ppm, emsg))
+           if (!decodePPM(pph, ppm, eresult))
                goto failed;
 
            if (ppm == PPM_EOP && !(batched & BATCH_LAST)) {
@@ -297,11 +297,11 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                    ntrys = 0;
                    if (morePages) {
                        if (ppr == PPR_PIP) {
-                           emsg = "Procedure interrupt (operator intervention)";
+                           eresult = Status(280, "Procedure interrupt (operator intervention)");
                            goto failed;
                        }
                        if (!TIFFReadDirectory(tif)) {
-                           emsg = "Problem reading document directory";
+                           eresult = Status(302, "Problem reading document directory");
                            goto failed;
                        }
                        if (ppr == PPR_MCF) {
@@ -326,19 +326,16 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                     case RTN_IGNORE:
                         goto ignore; // ignore error and trying to send next page
                     case RTN_GIVEUP:
-                        emsg = "Unable to transmit page"
-                            " (giving up after RTN)";
+                        eresult = Status(281, "Unable to transmit page (giving up after RTN)");
                         goto failed; // "over and out"
                     }
                     // case RTN_RETRANSMIT
                    if (++ntrys >= 3) {
-                       emsg = "Unable to transmit page"
-                              " (giving up after 3 attempts)";
+                       eresult = Status(282, "Unable to transmit page (giving up after 3 attempts)");
                        break;
                    }
                    if (params.br == BR_2400) {
-                       emsg = "Unable to transmit page"
-                               "(NAK at all possible signalling rates)";
+                       eresult = Status(283, "Unable to transmit page (NAK at all possible signalling rates)");
                        break;
                    }
                    next.br--;
@@ -346,11 +343,10 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                    transferOK = true;
                    break;
                case PPR_PIN:           // page bad, interrupt requested
-                   emsg = "Unable to transmit page"
-                      " (NAK with operator intervention)";
+                   eresult = Status(284, "Unable to transmit page (NAK with operator intervention)");
                    goto failed;
                default:
-                   emsg = "Modem protocol error (unknown post-page response)";
+                   eresult = Status(285, "Modem protocol error (unknown post-page response)");
                    break;
                }
            } else {
@@ -358,7 +354,7 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
                 * We received no PPR.
                 */
                if (ppm == PPM_EOM && (batched & BATCH_FIRST)) {
-                   emsg = "Batching protocol error";
+                   eresult = Status(286, "Batching protocol error");
                    protoTrace("The destination appears to not support batching.");
                    return (send_batchfail);
                }
@@ -368,7 +364,7 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
             * We were unable to negotiate settings and transfer page image data.
             */
            if (previousppm == PPM_EOM) {
-               emsg = "Batching protocol error";
+               eresult = Status(286, "Batching protocol error");
                protoTrace("The destination appears to not support batching.");
                return (send_batchfail);
            }
@@ -376,11 +372,11 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
        previousppm = ppm;
     } while (transferOK && morePages && !hadHangup);
     if (!transferOK) {
-       if (emsg == "") {
+       if (eresult.value() == 0) {
            if (hangupCode[0])
-               emsg = hangupCause(hangupCode);
+               eresult = hangupStatus(hangupCode);
            else
-               emsg = "Communication failure during Phase B/C";
+               eresult = Status(287, "Communication failure during Phase B/C");
        }
        sendAbort();                    // terminate session
     } else if (hadHangup && morePages) {
@@ -391,7 +387,7 @@ Class2Modem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
         * be retried.
         */
        transferOK = false;
-       emsg = "Communication failure during Phase B/C (modem protocol botch)";
+       eresult = Status(288, "Communication failure during Phase B/C (modem protocol botch)");
     }
     return (transferOK ? send_ok : send_retry);
 failed:
index c4c329bc92b86d1a598277b05f4dd5a4af3391c4..2e2170b7a7ed8e84f7e318a830978dc97caedc89 100644 (file)
 /*
  * Call status description strings.
  */
-const char* ClassModem::callStatus[10] = {
-    "Call successful",                         // OK
-    "Busy signal detected",                    // BUSY
-    "No carrier detected",                     // NOCARRIER
-    "No answer from remote",                   // NOANSWER
-    "No local dialtone",                       // NODIALTONE
-    "Invalid dialing command",                 // ERROR
-    "Unknown problem",                         // FAILURE
-    "Carrier established, but Phase A failure",        // NOFCON
-    "Data connection established (wanted fax)",        // DATACONN
-    "Glare - RING detected",                   // RING
+Status ClassModem::callStatus[10] = {
+    Status(0, "Call successful"),                              // OK
+    Status(1, "Busy signal detected"),                 // BUSY
+    Status(2, "No carrier detected"),                          // NOCARRIER
+    Status(3, "No answer from remote"),                        // NOANSWER
+    Status(4, "No local dialtone"),                            // NODIALTONE
+    Status(5, "Invalid dialing command"),                      // ERROR
+    Status(6, "Unknown problem"),                              // FAILURE
+    Status(7, "Carrier established, but Phase A failure"),     // NOFCON
+    Status(8, "Data connection established (wanted fax)"),     // DATACONN
+    Status(9, "Glare - RING detected"),                        // RING
 };
 /*
  * Service class descriptions.  The first three
@@ -129,15 +129,15 @@ ClassModem::dataService()
 }
 
 CallStatus
-ClassModem::dial(const char* number, fxStr& emsg)
+ClassModem::dial(const char* number, Status& eresult)
 {
     dialedNumber = fxStr(number);
     protoTrace("DIAL %s", number);
     fxStr buf = fxStr::format((const char*) conf.dialCmd, number);
-    emsg = "";
-    CallStatus cs = (atCmd(buf, AT_NOTHING) ? dialResponse(emsg) : FAILURE);
-    if (cs != OK && emsg == "") {
-        emsg = callStatus[cs];
+    eresult.clear();
+    CallStatus cs = (atCmd(buf, AT_NOTHING) ? dialResponse(eresult) : FAILURE);
+    if (cs != OK && eresult.value() == 0) {
+        eresult = callStatus[cs];
     }
     return (cs);
 }
@@ -222,7 +222,7 @@ ClassModem::findAnswer(const char* s)
  * Deduce connection kind: fax, data, or voice.
  */
 CallType
-ClassModem::answerResponse(fxStr& emsg)
+ClassModem::answerResponse(Status& eresult)
 {
     CallStatus cs = FAILURE;
     ATResponse r;
@@ -259,16 +259,16 @@ again:
            break;
        }
        if (r == AT_EMPTYLINE) {
-           emsg = callStatus[cs];
+           eresult = callStatus[cs];
            return (CALLTYPE_ERROR);
        }
     } while ((unsigned) Sys::now()-start < conf.answerResponseTimeout);
-    emsg = "Ring detected without successful handshake";
+    eresult = Status(12, "Ring detected without successful handshake");
     return (CALLTYPE_ERROR);
 }
 
 CallType
-ClassModem::answerCall(AnswerType atype, fxStr& emsg, const char* number)
+ClassModem::answerCall(AnswerType atype, Status& eresult, const char* number)
 {
     CallType ctype = CALLTYPE_ERROR;
     /*
@@ -283,13 +283,13 @@ ClassModem::answerCall(AnswerType atype, fxStr& emsg, const char* number)
     case ANSTYPE_VOICE:        answerCmd = conf.answerVoiceCmd; break;
     case ANSTYPE_DIAL:
                        answerCmd = conf.answerDialCmd;
-                       dial(number, emsg);     // no error-checking
+                       dial(number, eresult);  // no error-checking
                        break;
     }
     if (answerCmd == "")
        answerCmd = conf.answerAnyCmd;
     if (atCmd(answerCmd, AT_NOTHING)) {
-       ctype = answerResponse(emsg);
+       ctype = answerResponse(eresult);
        if (atype == ANSTYPE_DIAL) ctype = CALLTYPE_FAX;        // force as fax
        if (ctype == CALLTYPE_UNKNOWN) {
            /*
index 6b81117cb66567441383588a7830968940d60711..5e21c6928c36db39712dfa23e859b3769bb1f588 100644 (file)
@@ -31,6 +31,7 @@
 #include <stdarg.h>
 #include "Str.h"
 #include "CallID.h"
+#include "Status.h"
 
 class ModemServer;
 class ModemConfig;
@@ -202,7 +203,7 @@ protected:
     fxStr      revQueryCmd;    // product revision identification command
 
     static const char* serviceNames[9];         // class 2 services
-    static const char* callStatus[10];  // printable call status
+    static Status callStatus[10];       // printable call status
     static const char* ATresponses[17];
 
     ClassModem(ModemServer&, const ModemConfig&);
@@ -217,8 +218,8 @@ protected:
     bool doQuery(const fxStr& queryCmd, fxStr& result, long ms = 30*1000);
 // dial/answer interactions with derived classes
     virtual const AnswerMsg* findAnswer(const char* s);
-    virtual CallType answerResponse(fxStr& emsg);
-    virtual CallStatus dialResponse(fxStr& emsg) = 0;
+    virtual CallType answerResponse(Status& eresult);
+    virtual CallStatus dialResponse(Status& eresult) = 0;
     virtual bool isNoise(const char*);
 // miscellaneous
     void       modemSupports(const char* fmt, ...);
@@ -299,19 +300,19 @@ public:
     /*
      * Send support:
      *
-     * if (dial(number, params, emsg) == OK) {
+     * if (dial(number, params, eresult) == OK) {
      *   ...do stuff...
      * }
      * hangup();
      */
     virtual bool dataService();
-    virtual CallStatus dial(const char* number, fxStr& emsg);
+    virtual CallStatus dial(const char* number, Status& eresult);
 
     /*
      * Receive support:
      *
      * if (waitForRings(nrings, ctype, cid)) { // wait before answering phone
-     *    case (answerCall(type, emsg)) {
+     *    case (answerCall(type, eresult)) {
      *    CALLTYPE_FAX:
      *         ...do fax kinds of things...
      *      break;
@@ -328,7 +329,7 @@ public:
      * at any time in this procedure.
      */
     virtual bool waitForRings(u_short rings, CallType&, CallID&);
-    virtual CallType answerCall(AnswerType, fxStr& emsg, const char* dialnumber = NULL);
+    virtual CallType answerCall(AnswerType, Status& eresult, const char* dialnumber = NULL);
     virtual void answerCallCmd(CallType);
 };
 inline long ClassModem::getDataTimeout() const         { return dataTimeout; }
index c1f54f87d74c99c4a20b5d6aae6ca436aef4056f..aa1464be2c1e37828035e5c013ee2be354dea528 100644 (file)
@@ -124,7 +124,7 @@ FaxModem::initializeDecoder(const Class2Params& params)
  */
 bool
 FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality,
-    const Class2Params& params, fxStr& emsg)
+    const Class2Params& params, Status& eresult)
 {
     initializeDecoder(params);
     u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 4864
@@ -143,8 +143,8 @@ FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality,
     bytePending = 0;
     if (EOFraised()) {
        abortPageRecv();
-       emsg = "Missing EOL after 5 seconds";
-       recvTrace("%s", (const char*) emsg);
+       eresult = Status(50, "Missing EOL after 5 seconds");
+       recvTrace("%s", eresult.string());
        return (false);
     }
     if (checkQuality && params.ec == EC_DISABLE) {
index 7e1530188ffafef4b52fc948a348ee6a5f2f846f..0aadc6d275bb644fa2786c90da04bb6e9ae0691d 100644 (file)
@@ -63,7 +63,7 @@ u_int FaxModem::getTagLineSlop() const                { return tagLineSlop; }
  * Do setup work prior to placing the call.
  */
 bool
-FaxModem::sendSetup(FaxRequest& req, const Class2Params&, fxStr&)
+FaxModem::sendSetup(FaxRequest& req, const Class2Params&, Status&)
 {
     minsp = fxmax((u_int) req.minbr, fxmax((u_int) conf.minSpeed, modemParams.getMinSpeed()));
     pageNumber = 1;
@@ -90,21 +90,21 @@ void FaxModem::sendSetupPhaseB(const fxStr&, const fxStr&){}
 void FaxModem::sendEnd()       {}
 
 bool
-FaxModem::recvBegin(fxStr&)
+FaxModem::recvBegin(Status&)
 {
     optFrames = 0;
     return (true);
 }
 
 bool
-FaxModem::recvEOMBegin(fxStr&)
+FaxModem::recvEOMBegin(Status&)
 {
     optFrames = 0;
     return (true);
 }
 
 bool
-FaxModem::pollBegin(const fxStr&, const fxStr&, const fxStr&, fxStr&)
+FaxModem::pollBegin(const fxStr&, const fxStr&, const fxStr&, Status&)
 {
     optFrames = 0;
     return (true);
@@ -272,7 +272,7 @@ FaxModem::decodePageChop(const fxStr& pph, const Class2Params& params)
  * construction of this string.
  */ 
 bool
-FaxModem::decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg)
+FaxModem::decodePPM(const fxStr& pph, u_int& ppm, Status& eresult)
 {
     const char* what;
     if (pph.length() >= 3 && (pph[2] != 'Z' || pph.length() >= 2+5+1)) {
@@ -284,7 +284,7 @@ FaxModem::decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg)
        what = "unknown";
     } else
        what = "bad";
-    emsg = fxStr::format( "Internal botch; %s post-page handling string \"%s\"",
+    eresult = Status(303, "Internal botch; %s post-page handling string \"%s\"",
        what, (const char*) pph);
     return (false);
 }
@@ -692,9 +692,9 @@ bool FaxModem::getECMTracing()
 
 FaxSendStatus
 FaxModem::sendSetupParams(TIFF* tif, Class2Params& params,
-    FaxMachineInfo& info, fxStr& emsg)
+    FaxMachineInfo& info, Status& eresult)
 {
-    return server.sendSetupParams(tif, params, info, emsg);
+    return server.sendSetupParams(tif, params, info, eresult);
 }
 
 
index be998d117ed229d65a9308336a4f96121b89c391..87b91deb3c4f907a0eff3e3ec17b66318c1652d4 100644 (file)
@@ -133,7 +133,7 @@ protected:
     bool       getHDLCTracing();
     bool       getECMTracing();
     FaxSendStatus sendSetupParams(TIFF*, Class2Params&,
-                   FaxMachineInfo&, fxStr&);
+                   FaxMachineInfo&, Status&);
     void       recvTSI(const fxStr&);
     void       recvPWD(const fxStr&);
     void       recvSUB(const fxStr&);
@@ -144,11 +144,11 @@ protected:
     void       recvStartPage(TIFF* tif);
     void       recvResetPage(TIFF* tif);
     u_int      decodePageChop(const fxStr& pph, const Class2Params&);
-    bool       decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg);
+    bool       decodePPM(const fxStr& pph, u_int& ppm, Status& eresult);
     void       notifyPageSent(TIFF*);
 // phase c data receive & copy quality checking
     bool       recvPageDLEData(TIFF* tif, bool checkQuality,
-                   const Class2Params& params, fxStr& emsg);
+                   const Class2Params& params, Status& eresult);
     void       setupStartPage(TIFF* tif, const Class2Params& params);
     void       recvEndPage(TIFF* tif, const Class2Params& params);
     void       writeECMData(TIFF*, u_char*, u_int, const Class2Params&, u_short);
@@ -248,13 +248,14 @@ public:
      * single T.30 document.
      */
     virtual bool faxService(bool enableV34, bool enableV17) = 0;
-    virtual bool sendSetup(FaxRequest&, const Class2Params& dis, fxStr& emsg);
+    virtual bool sendSetup(FaxRequest&, const Class2Params& dis, Status&
+                   eresult);
     virtual void sendBegin();
     virtual FaxSendStatus getPrologue(Class2Params&,
-       bool& hasDoc, fxStr& emsg, u_int& batched) = 0;
+       bool& hasDoc, Status& eresult, u_int& batched) = 0;
     virtual void sendSetupPhaseB(const fxStr& pwd, const fxStr& sub);
     virtual FaxSendStatus sendPhaseB(TIFF*, Class2Params&, FaxMachineInfo&,
-       fxStr& pph, fxStr& emsg, u_int& batched) = 0;
+       fxStr& pph, Status& eresult, u_int& batched) = 0;
     virtual void sendEnd();
     virtual void sendAbort() = 0;
     // query interfaces for optional state
@@ -290,10 +291,10 @@ public:
      * }
      */
     virtual bool setupReceive() = 0;
-    virtual bool recvBegin(fxStr& emsg);
-    virtual bool recvEOMBegin(fxStr& emsg);
-    virtual bool recvPage(TIFF*, u_int& ppm, fxStr& em, const fxStr& id) = 0;
-    virtual bool recvEnd(fxStr& emsg) = 0;
+    virtual bool recvBegin(Status& eresult);
+    virtual bool recvEOMBegin(Status& eresult);
+    virtual bool recvPage(TIFF*, u_int& ppm, Status& result, const fxStr& id) = 0;
+    virtual bool recvEnd(Status& eresult) = 0;
     virtual void recvAbort() = 0;
     virtual void recvSucceeded();
     virtual void pokeConfig(bool isSend) = 0;
@@ -318,9 +319,9 @@ public:
      *
      * (i.e. it's just like a receive operation.)
      */
-    virtual bool requestToPoll(fxStr& emsg) = 0;
+    virtual bool requestToPoll(Status& eresult) = 0;
     virtual bool pollBegin(
        const fxStr& cig, const fxStr& sep, const fxStr& pwd,
-       fxStr& emsg);
+       Status& eresult);
 };
 #endif /* _FAXMODEM_ */
index 6e1bd31a64bc77d83219b24bcd8a168ca3e0a942..bb3357fcbed6fb86f6f594e00f270b133416549d 100644 (file)
@@ -37,7 +37,7 @@
  * Initiate a polling receive and invoke the receiving protocol.
  */
 bool
-FaxServer::pollFaxPhaseB(const fxStr& sep, const fxStr& pwd, FaxRecvInfoArray& docs, fxStr& emsg)
+FaxServer::pollFaxPhaseB(const fxStr& sep, const fxStr& pwd, FaxRecvInfoArray& docs, Status& result)
 {
     bool pollOK = false;
     changeState(RECEIVING);
@@ -50,20 +50,20 @@ FaxServer::pollFaxPhaseB(const fxStr& sep, const fxStr& pwd, FaxRecvInfoArray& d
      * be lost.)
      */
     FaxRecvInfo info;
-    TIFF* tif = setupForRecv(info, docs, emsg);
+    TIFF* tif = setupForRecv(info, docs, result);
     if (tif) {
        recvPages = 0;                  // count of received pages
        fileStart = Sys::now();         // count initial negotiation on failure
-       if (modem->pollBegin(canonicalizePhoneNumber(FAXNumber), sep, pwd, emsg)) {
-           pollOK = recvDocuments(tif, info, docs, emsg);
+       if (modem->pollBegin(canonicalizePhoneNumber(FAXNumber), sep, pwd, result)) {
+           pollOK = recvDocuments(tif, info, docs, result);
            if (!pollOK)
-               traceProtocol("POLL FAX: %s", (const char*) emsg);
-           if (!modem->recvEnd(emsg))
-               traceProtocol("POLL FAX: %s", (const char*) emsg);
+               traceProtocol("POLL FAX: %s", result.string());
+           if (!modem->recvEnd(result))
+               traceProtocol("POLL FAX: %s", result.string());
        } else
-           traceProtocol("POLL FAX: %s", (const char*) emsg);
+           traceProtocol("POLL FAX: %s", result.string());
     } else
-       traceProtocol("POLL FAX: %s", (const char*) emsg);
+       traceProtocol("POLL FAX: %s", result.string());
     traceProtocol("POLL FAX: end");
     return (pollOK);
 }
index af218a1dd498906661fe13a30cdccf09e7248532..81505cfa9b2b2f179d4d90113f3513804201144a 100644 (file)
  */
 
 bool
-FaxServer::recvFax(const CallID& callid, fxStr& emsg)
+FaxServer::recvFax(const CallID& callid, Status& result)
 {
     traceProtocol("RECV FAX: begin");
 
     FaxRecvInfoArray docs;
     FaxRecvInfo info;
     bool faxRecognized = false;
-    emsg = "";
+    result.clear();
     abortCall = false;
     waitNotifyPid = 0;
 
@@ -60,11 +60,11 @@ FaxServer::recvFax(const CallID& callid, fxStr& emsg)
      * be lost.)
      */
     info.callid = callid;
-    TIFF* tif = setupForRecv(info, docs, emsg);
+    TIFF* tif = setupForRecv(info, docs, result);
     if (tif) {
        recvPages = 0;                  // total count of received pages
        fileStart = pageStart = Sys::now();
-       if (faxRecognized = modem->recvBegin(emsg)) {
+       if (faxRecognized = modem->recvBegin(result)) {
            /*
             * If the system is busy then notifyRecvBegun may not return
             * quickly.  Thus we run it in a child process and move on.
@@ -84,18 +84,18 @@ FaxServer::recvFax(const CallID& callid, fxStr& emsg)
                    Dispatcher::instance().startChild(waitNotifyPid, this);
                    break;
            }
-           if (!recvDocuments(tif, info, docs, emsg)) {
-               traceProtocol("RECV FAX: %s", (const char*) emsg);
+           if (!recvDocuments(tif, info, docs, result)) {
+               traceProtocol("RECV FAX: %s", result.string());
                modem->recvAbort();
            }
-           if (!modem->recvEnd(emsg))
-               traceProtocol("RECV FAX: %s", (const char*) emsg);
+           if (!modem->recvEnd(result))
+               traceProtocol("RECV FAX: %s", result.string());
        } else {
-           traceProtocol("RECV FAX: %s", (const char*) emsg);
+           traceProtocol("RECV FAX: %s", result.string());
            TIFFClose(tif);
        }
     } else
-       traceServer("RECV FAX: %s", (const char*) emsg);
+       traceServer("RECV FAX: %s", result.string());
 
     /*
      * Possibly issue a command upon successful reception.
@@ -127,7 +127,9 @@ FaxServer::getRecvFile(fxStr& qfile, fxStr& emsg)
     u_long seqnum = Sequence::getNext(FAX_RECVDIR "/" FAX_SEQF, emsg);
 
     if (seqnum == (u_long) -1)
+    {
        return -1;
+    }
 
     qfile = fxStr::format(FAX_RECVDIR "/fax" | Sequence::format | ".tif", seqnum);
     int ftmp = Sys::open(qfile, O_RDWR|O_CREAT|O_EXCL, recvFileMode);
@@ -144,8 +146,9 @@ FaxServer::getRecvFile(fxStr& qfile, fxStr& emsg)
  * Create and lock a temp file for receiving data.
  */
 TIFF*
-FaxServer::setupForRecv(FaxRecvInfo& ri, FaxRecvInfoArray& docs, fxStr& emsg)
+FaxServer::setupForRecv(FaxRecvInfo& ri, FaxRecvInfoArray& docs, Status& result)
 {
+    fxStr emsg;
     int ftmp = getRecvFile(ri.qfile, emsg);
     if (ftmp >= 0) {
        ri.commid = getCommID();        // should be set at this point
@@ -155,11 +158,12 @@ FaxServer::setupForRecv(FaxRecvInfo& ri, FaxRecvInfoArray& docs, fxStr& emsg)
        if (tif != NULL)
            return (tif);
        Sys::close(ftmp);
-       emsg = fxStr::format("Unable to open TIFF file %s for writing",
+       result = Status(901, "Unable to open TIFF file %s for writing",
            (const char*) ri.qfile);
-       ri.reason = emsg;               // for notifyRecvDone
+       ri.reason = result.string();            // for notifyRecvDone
     } else
-       emsg.insert("Unable to create temp file for received data: ");
+       result = Status(902, "Unable to create temp file for received data: %s",
+               (const char*)emsg);
     return (NULL);
 }
 
@@ -167,14 +171,14 @@ FaxServer::setupForRecv(FaxRecvInfo& ri, FaxRecvInfoArray& docs, fxStr& emsg)
  * Receive one or more documents.
  */
 bool
-FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, fxStr& emsg)
+FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, Status& result)
 {
     bool recvOK;
     u_int ppm = PPM_EOP;
     batchid = getCommID();
     for (;;) {
        bool okToRecv = true;
-       fxStr reason;
+       Status reason;
        modem->getRecvSUB(info.subaddr);                // optional subaddress
        /*
         * Check a received TSI/PWD against the list of acceptable
@@ -190,7 +194,7 @@ FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, f
            info.sender = "<UNSPECIFIED>";
        if (qualifyTSI != "") {
            okToRecv = isTSIOk(info.sender);
-           reason = "Permission denied (unnacceptable client TSI)";
+           reason = Status(350, "Permission denied (unnacceptable client TSI)");
            traceServer("%s TSI \"%s\"", okToRecv ? "ACCEPT" : "REJECT",
                (const char*) info.sender);
        }
@@ -198,24 +202,24 @@ FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, f
            info.passwd = "<UNSPECIFIED>";
        if (qualifyPWD != "") {
            okToRecv = isPWDOk(info.passwd);
-           reason = "Permission denied (unnacceptable client PWD)";
+           reason = Status(351, "Permission denied (unnacceptable client PWD)");
            traceServer("%s PWD \"%s\"", okToRecv ? "ACCEPT" : "REJECT",
                (const char*) info.passwd);
        }
        if (!okToRecv) {
-           emsg = reason;
+           result = reason;
            info.time = (u_int) getFileTransferTime();
-           info.reason = emsg;
+           info.reason = result.string();
            docs[docs.length()-1] = info;
            notifyDocumentRecvd(info);
            TIFFClose(tif);
            return (false);
        }
        setServerStatus("Receiving from \"%s\"", (const char*) info.sender);
-       recvOK = recvFaxPhaseD(tif, info, ppm, emsg);
+       recvOK = recvFaxPhaseD(tif, info, ppm, result);
        TIFFClose(tif);
        info.time = (u_int) getFileTransferTime();
-       info.reason = emsg;
+       info.reason = result.string();
        docs[docs.length()-1] = info;
        /*
         * If syslog is busy then notifyDocumentRecvd may not return
@@ -250,12 +254,12 @@ FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, f
            batchid.append(","|getCommID());
            traceServer("SESSION BATCH %s", (const char*)batchid);
        }
-       tif = setupForRecv(info, docs, emsg);
+       tif = setupForRecv(info, docs, result);
        if (tif == NULL)
            return (false);
        fileStart = pageStart = Sys::now();
-       if (!modem->recvEOMBegin(emsg)) {
-           info.reason = emsg;
+       if (!modem->recvEOMBegin(result)) {
+           info.reason = result.string();
            docs[docs.length()-1] = info;
            TIFFClose(tif);
            return (false);
@@ -268,7 +272,7 @@ FaxServer::recvDocuments(TIFF* tif, FaxRecvInfo& info, FaxRecvInfoArray& docs, f
  * Receive Phase B protocol processing.
  */
 bool
-FaxServer::recvFaxPhaseD(TIFF* tif, FaxRecvInfo& info, u_int& ppm, fxStr& emsg)
+FaxServer::recvFaxPhaseD(TIFF* tif, FaxRecvInfo& info, u_int& ppm, Status& result)
 {
     fxStr id = info.sender;
     for (u_int i = 0; i < info.callid.size(); i++) {
@@ -277,10 +281,10 @@ FaxServer::recvFaxPhaseD(TIFF* tif, FaxRecvInfo& info, u_int& ppm, fxStr& emsg)
     }
     do {
        if (++recvPages > maxRecvPages) {
-           emsg = "Maximum receive page count exceeded, job terminated";
+           result = Status(304, "Maximum receive page count exceeded, call terminated");
            return (false);
        }
-       if (!modem->recvPage(tif, ppm, emsg, id))
+       if (!modem->recvPage(tif, ppm, result, id))
            return (false);
        info.npages++;
        info.time = (u_int) getPageTransferTime();
@@ -306,9 +310,10 @@ FaxServer::recvFaxPhaseD(TIFF* tif, FaxRecvInfo& info, u_int& ppm, fxStr& emsg)
                Dispatcher::instance().startChild(waitNotifyPid, this);
                break;
        }
-       if (emsg != "") return (false);         // got page with fatal error
+       if (result.value() != 0)
+               return (false);         // got page with fatal error
        if (PPM_PRI_MPS <= ppm && ppm <= PPM_PRI_EOP) {
-           emsg = "Procedure interrupt received, job terminated";
+           result = Status(351, "Procedure interrupt received, job terminated");
            return (false);
        }
     } while (ppm == PPM_MPS || ppm == PPM_PRI_MPS);
index 72a87d7a028817fbd47ca17db54222635a54aaea..a32e5106dd77bfb7b2405cde13a71019919ebe04 100644 (file)
@@ -33,6 +33,7 @@
 #include <ctype.h>
 #include <errno.h>
 
+
 /*
  * HylaFAX job request file handling.
  */
@@ -182,6 +183,8 @@ char* FaxRequest::chopVals[4] = {
 bool
 FaxRequest::readQFile(bool& rejectJob)
 {
+    fxStr notice;
+    u_int errorcode = 999;
     rejectJob = false;
     lineno = 0;
     lseek(fd, 0L, SEEK_SET);                   // XXX should only for re-read
@@ -350,6 +353,7 @@ FaxRequest::readQFile(bool& rejectJob)
        case H_PAGECHOP:        checkChopValue(tag); break;
        case H_CHOPTHRESHOLD:   chopthreshold = atof(tag); break;
        case H_NSF:             nsf = tag; break;
+       case H_ERRORCODE:       errorcode = atoi(tag); break;
        case H_DONEOP:          doneop = tag; break;
        case H_STATUS:
            /*
@@ -444,6 +448,15 @@ FaxRequest::readQFile(bool& rejectJob)
                               "owner"
        );
     }
+
+    /*
+     * We try to default it to something sane if it wasn't in
+     * the qfile already
+     */
+    if (errorcode == 999 && notice.length() == 0)
+           errorcode = 0;
+
+    result = Status(errorcode, "%s", (const char*)notice);
     if (minbr > BR_33600)      minbr = BR_33600;
     if (desiredbr > BR_33600)  desiredbr = BR_33600;
     if (desiredst > ST_40MS)   desiredst = ST_40MS;
@@ -501,13 +514,14 @@ FaxRequest::writeQFile()
     sb.fput("tts:%u\n", tts);
     sb.fput("killtime:%u\n", killtime);
     sb.fput("retrytime:%u\n", retrytime);
+
     DUMP(fp, shortvals,        "%s:%d\n", (int));
     DUMP(fp, strvals,  "%s:%s\n", (const char*));
     /*
      * Escape unprotected \n's with \\.
      */
     sb.put("status:");
-    const char* cp = notice;
+    const char* cp = result.string();
     const char* sp = cp;
     while (*cp) {
        if (*cp == '\n' && cp[-1] != '\\') {
@@ -518,6 +532,7 @@ FaxRequest::writeQFile()
        cp++;
     }
     sb.put(sp, cp-sp); sb.put('\n');
+    sb.fput("errorcode:%d\n", result.value());
     sb.fput("returned:%d\n", status);
     sb.fput("notify:%s\n", notifyVals[notify&3]);
     sb.fput("pagechop:%s\n", chopVals[pagechop&3]);
index 5f529e256fc1da73f8d02fa1d6c34399b65d1ef9..750896bdd78256c69139f6783388752cc8f13fe6 100644 (file)
 #include <time.h>
 #include <stdio.h>
 
+#include "Status.h"
+
 class Class2Params;
 
+
 /*
  * This structure is passed from the queue manager
  * to the fax modem+protocol service for each job
@@ -142,7 +145,6 @@ public:
     fxStr      subaddr;        // transmit subaddress
     fxStr      passwd;         // transmit password
     fxStr      external;       // displayable phone number for fax machine
-    fxStr      notice;         // message to send for notification
     fxStr      modem;          // outgoing modem to use
     fxStr      faxnumber;      // Sender's number to advertise to phone company
     fxStr      tsi;            // TSI to use instead of LocalIdentifier
@@ -195,6 +197,14 @@ public:
     static fxStr mkbasedoc(const fxStr& file);
     void renameSaved(u_int fi);
     bool isUnreferenced(u_int fi);
+
+    Status result;
+
+#if 0
+private:
+    fxStr      notice;         // message to send for notification
+    fxStr      code;           // code relating to notice
+#endif
 };
 inline bool FaxRequest::isNotify(u_int what) const
     { return (notify & (u_short) what) != 0; }
index a44f54f9ff00234267474257ffbfee408cd54b3d..0adbcc2301ffe5db83f4325cfa6d509c2fe7b2b4 100644 (file)
@@ -106,8 +106,8 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, FaxAcctInfo& ai,
        }
     } else {
        if (state != LOCKWAIT)
-           sendFailed(fax, send_retry,
-               "Can not lock modem device", 2*pollLockWait);
+           sendFailed(fax, send_retry, Status(346,
+               "Can not lock modem device"), 2*pollLockWait);
        if (state != SENDING && state != ANSWERING && state != RECEIVING)
            changeState(LOCKWAIT, pollLockWait);
     }
@@ -125,10 +125,10 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, FaxAcctInfo& ai,
 }
 
 void
-FaxServer::sendFailed(FaxRequest& fax, FaxSendStatus stat, const char* notice, u_int tts)
+FaxServer::sendFailed(FaxRequest& fax, FaxSendStatus stat, const Status& result, u_int tts)
 {
     fax.status = stat;
-    fax.notice = notice;
+    fax.result = result;
     /*
      * When requeued for the default interval (called with 3 args),
      * don't adjust the time-to-send field so that the spooler
@@ -137,10 +137,11 @@ FaxServer::sendFailed(FaxRequest& fax, FaxSendStatus stat, const char* notice, u
      */
     if (tts != 0)
        fax.tts = Sys::now() + tts;
-    traceServer("SEND FAILED: JOB %s DEST %s ERR %s"
+    traceServer("SEND FAILED: JOB %s DEST %s ERR [%d] %s"
        , (const char*) fax.jobid
        , (const char*) fax.external
-       , (const char*) notice
+       , result.value()
+       , result.string()
     );
 
 }
@@ -153,7 +154,7 @@ void
 FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& number, u_int& batched)
 {
     connTime = 0;                              // indicate no connection
-    fxStr notice;
+    Status result;
     /*
      * Calculate initial page-related session parameters so
      * that braindead Class 2 modems which ignore AT+FIS can constrain
@@ -179,7 +180,7 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& num
     if ((batched & BATCH_FIRST) &&
        !modem->faxService(!clientInfo.getHasV34Trouble() && clientParams.ec != EC_DISABLE && clientParams.br > BR_14400,
            !clientInfo.getHasV17Trouble() && clientParams.br > BR_9600)) {
-       sendFailed(fax, send_failed, "Unable to configure modem for fax use");
+       sendFailed(fax, send_failed, Status(420,"Unable to configure modem for fax use"));
        return;
     }
     /*
@@ -189,19 +190,19 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& num
      * not documents are available for retrieval.
      */
     if (fax.findItem(FaxRequest::send_poll) != fx_invalidArrayIndex &&
-       !modem->requestToPoll(notice)) {
-       sendFailed(fax, send_failed, notice);
+       !modem->requestToPoll(result)) {
+       sendFailed(fax, send_failed, result);
        return;
     }
-    if (!modem->sendSetup(fax, clientParams, notice)) {
-       sendFailed(fax, send_failed, notice);
+    if (!modem->sendSetup(fax, clientParams, result)) {
+       sendFailed(fax, send_failed, result);
        return;
     }
-    fax.notice = "";
+    fax.result.clear();
     notifyCallPlaced(fax);
     CallStatus callstat;
     if (batched & BATCH_FIRST)
-       callstat = modem->dial(number, notice);
+       callstat = modem->dial(number, result);
     else
        callstat = ClassModem::OK;
     if (callstat == ClassModem::OK)
@@ -222,9 +223,9 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& num
        bool remoteHasDoc = false;
        notifyConnected(fax);
        FaxSendStatus status = modem->getPrologue(
-           clientCapabilities, remoteHasDoc, notice, batched);
+           clientCapabilities, remoteHasDoc, result, batched);
        if (status != send_ok) {
-           sendFailed(fax, status, notice, requeueProto);
+           sendFailed(fax, status, result, requeueProto);
        } else {
            // CSI
            fxStr csi("<UNSPECIFIED>");
@@ -243,9 +244,9 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& num
            clientCapabilities.asciiEncode(clientdis);
            clientInfo.setDIS(clientdis);
 
-           if (!sendClientCapabilitiesOK(fax, clientInfo, notice)) {
+           if (!sendClientCapabilitiesOK(fax, clientInfo, result)) {
                // NB: mark job completed 'cuz there's no way recover
-               sendFailed(fax, send_failed, notice);
+               sendFailed(fax, send_failed, result);
            } else {
                modem->sendSetupPhaseB(fax.passwd, fax.subaddr);
                /*
@@ -312,7 +313,7 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& num
            modem->sendEnd();
        if (fax.status != send_done) {
            clientInfo.setSendFailures(clientInfo.getSendFailures()+1);
-           clientInfo.setLastSendFailure(fax.notice);
+           clientInfo.setLastSendFailure(fax.result.string());
        } else
            clientInfo.setSendFailures(0);
     } else if (!abortCall) {
@@ -333,37 +334,39 @@ FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& num
        case ClassModem::BUSY:          // busy signal
        case ClassModem::NOANSWER:      // no answer or ring back
            if (!clientInfo.getCalledBefore() && fax.ndials > retryMAX[callstat])
-               sendFailed(fax, send_failed, notice);
+               sendFailed(fax, send_failed, result);
            else if (fax.retrytime != 0)
-               sendFailed(fax, send_retry, notice, fax.retrytime);
+               sendFailed(fax, send_retry, result, fax.retrytime);
            else
-               sendFailed(fax, send_retry, notice, requeueTTS[callstat]);
+               sendFailed(fax, send_retry, result, requeueTTS[callstat]);
            break;
        case ClassModem::NODIALTONE:    // no local dialtone, possibly unplugged
        case ClassModem::ERROR:         // modem might just need to be reset
        case ClassModem::FAILURE:       // modem returned something unexpected
            if (!clientInfo.getCalledBefore() && fax.ndials > retryMAX[callstat])
-               sendFailed(fax, send_failed, notice);
+               sendFailed(fax, send_failed, result);
            else
-               sendFailed(fax, send_retry, notice, requeueTTS[callstat]);
+               sendFailed(fax, send_retry, result, requeueTTS[callstat]);
            break;
        case ClassModem::OK:            // call was aborted by user
            break;
        }
        if (callstat != ClassModem::OK) {
            clientInfo.setDialFailures(clientInfo.getDialFailures()+1);
-           clientInfo.setLastDialFailure(fax.notice);
+           clientInfo.setLastDialFailure(fax.result.string());
        }
     }
     if (abortCall)
-       sendFailed(fax, send_retry, "Call aborted by user");
+       sendFailed(fax, send_retry, Status(345, "Call aborted by user"));
     else if (fax.status == send_retry) {
        if (fax.totdials == fax.maxdials) {
-           notice = fax.notice | "; too many attempts to dial";
-           sendFailed(fax, send_failed, notice);
+           result = fax.result;
+           result.append(333, "too many attempts to dial");
+           sendFailed(fax, send_failed, result);
        } else if (fax.tottries == fax.maxtries) {
-           notice = fax.notice | "; too many attempts to send";
-           sendFailed(fax, send_failed, notice);
+           result = fax.result;
+           result.append(334, "too many attempts to send");
+           sendFailed(fax, send_failed, result);
        }
     }
     if ((batched & BATCH_LAST) || (fax.status != send_done)) {
@@ -403,19 +406,19 @@ FaxServer::sendPoll(FaxRequest& fax, bool remoteHasDoc)
 {
     u_int ix = fax.findItem(FaxRequest::send_poll);
     if (ix == fx_invalidArrayIndex) {
-       fax.notice = "polling operation not done because of internal failure";
+       fax.result = Status(907, "polling operation not done because of internal failure");
        traceServer("internal muckup, lost polling request");
        // NB: job is marked done
     } else if (!remoteHasDoc) {
-       fax.notice = "remote has no document to poll";
-       traceServer("REJECT: " | fax.notice);
+       fax.result = Status(601, "remote has no document to poll");
+       traceServer("REJECT: %s", fax.result.string());
        // override to force status about polling failure
        if (fax.notify == FaxRequest::no_notice)
            fax.notify = FaxRequest::when_done;
     } else {
        FaxItem& freq = fax.items[ix];
        FaxRecvInfoArray docs;
-       fax.status = (pollFaxPhaseB(freq.addr, freq.item, docs, fax.notice) ?
+       fax.status = (pollFaxPhaseB(freq.addr, freq.item, docs, fax.result) ?
            send_done : send_retry);
        for (u_int j = 0; j < docs.length(); j++) {
            FaxRecvInfo& ri = docs[j];
@@ -443,7 +446,7 @@ FaxServer::sendFaxPhaseB(FaxRequest& fax, FaxItem& freq, FaxMachineInfo& clientI
     if (tif && (freq.dirnum == 0 || TIFFSetDirectory(tif, freq.dirnum))) {
        if (dosetup) {
            // set up DCS according to file characteristics
-           fax.status = sendSetupParams(tif, clientParams, clientInfo, fax.notice);
+           fax.status = sendSetupParams(tif, clientParams, clientInfo, fax.result);
        }
        if (fax.status == send_ok) {
            /*
@@ -456,8 +459,8 @@ FaxServer::sendFaxPhaseB(FaxRequest& fax, FaxItem& freq, FaxMachineInfo& clientI
             */
            u_int prevPages = fax.npages;
            fax.status = modem->sendPhaseB(tif, clientParams, clientInfo,
-               fax.pagehandling, fax.notice, batched);
-           if (fax.status == send_v17fail && fax.notice == "") {
+               fax.pagehandling, fax.result, batched);
+           if (fax.status == send_v17fail && fax.result.value() == 0) {
                // non-fatal V.17 incompatibility
                clientInfo.setHasV17Trouble(true);
                fax.status = send_ok;
@@ -465,12 +468,11 @@ FaxServer::sendFaxPhaseB(FaxRequest& fax, FaxItem& freq, FaxMachineInfo& clientI
            if (fax.npages == prevPages) {
                fax.ntries++;
                if (fax.ntries > 2) {
-                   if (fax.notice != "")
-                       fax.notice.append("; ");
-                   fax.notice.append(
-                       "Giving up after 3 attempts to send same page");
+                   const char* msg =
+                       "Giving up after 3 attempts to send same page";
+                   fax.result.append(999, msg);
                    traceServer("SEND: %s \"%s\", dirnum %d",
-                       (const char*) fax.notice, (const char*) freq.item, freq.dirnum);
+                       msg, (const char*) freq.item, freq.dirnum);
                    fax.status = send_failed;
                }
            } else {
@@ -479,10 +481,10 @@ FaxServer::sendFaxPhaseB(FaxRequest& fax, FaxItem& freq, FaxMachineInfo& clientI
            }
        }
     } else {
-       fax.notice = tif ? "Can not set directory in document file" :
-                          "Can not open document file";
+       fax.result = tif ? Status(903, "Can not set directory in document file") :
+                          Status(904, "Can not open document file");
        traceServer("SEND: %s \"%s\", dirnum %d",
-           (const char*) fax.notice, (const char*) freq.item, freq.dirnum);
+           fax.result.string(), (const char*) freq.item, freq.dirnum);
     }
     if (tif)
        TIFFClose(tif);
@@ -494,7 +496,7 @@ FaxServer::sendFaxPhaseB(FaxRequest& fax, FaxItem& freq, FaxMachineInfo& clientI
  * modem and select the parameters that are best for us.
  */
 bool
-FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo, fxStr& emsg)
+FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo, Status& result)
 {
     /*
      * Select signalling rate and minimum scanline time
@@ -506,7 +508,7 @@ FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo,
        modem->selectSignallingRate(
            fxmin(clientInfo.getMaxSignallingRate(), fax.desiredbr));
     if (signallingRate == -1) {
-       emsg = "Modem does not support negotiated signalling rate";
+       result = Status(400, "Modem does not support negotiated signalling rate");
        return (false);
     }
     clientParams.br = signallingRate;
@@ -517,7 +519,7 @@ FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo,
        modem->selectScanlineTime(
            fxmax(clientInfo.getMinScanlineTime(), fax.desiredst));
     if (minScanlineTime == -1) {
-       emsg = "Modem does not support negotiated min scanline time";
+       result = Status(401, "Modem does not support negotiated min scanline time");
        return (false);
     }
     clientParams.st = minScanlineTime;
@@ -582,13 +584,13 @@ FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo,
  */
 FaxSendStatus
 FaxServer::sendSetupParams1(TIFF* tif,
-    Class2Params& params, const FaxMachineInfo& clientInfo, fxStr& emsg)
+    Class2Params& params, const FaxMachineInfo& clientInfo, Status& result)
 {
     uint16 compression;
     (void) TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
     if (compression != COMPRESSION_CCITTFAX3 && compression != COMPRESSION_CCITTFAX4) {
-       emsg = fxStr::format("Document is not in a Group 3 or Group 4 compatible"
-           " format (compression %u)", compression);
+       result = Status(402, "Document is not in a Group 3 or Group 4 compatible"
+                       " format (compression %u)", compression);
        return (send_failed);
     }
 
@@ -637,30 +639,25 @@ FaxServer::sendSetupParams1(TIFF* tif,
     } else {
        if (compression == COMPRESSION_CCITTFAX4) {
            if (!clientInfo.getSupportsMMR()) {
-               emsg = "Document was encoded with 2DMMR,"
-                   " but client does not support this data format";
+               result = Status(403, "Document was encoded with 2DMMR, but client does not support this data format");
                return (send_reformat);
            }
            if (!modem->supportsMMR()) {
-               emsg = "Document was encoded with 2DMMR,"
-                   " but modem does not support this data format";
+               result = Status(404, "Document was encoded with 2DMMR, but modem does not support this data format");
                return (send_reformat);
            }
            if (params.ec == EC_DISABLE) {
-               emsg = "Document was encoded with 2DMMR,"
-                   " but ECM is not being used.";
+               result = Status(405, "Document was encoded with 2DMMR, but ECM is not being used.");
                return (send_reformat);
            }
            params.df = DF_2DMMR;
        } else if (g3opts & GROUP3OPT_2DENCODING) {
            if (!clientInfo.getSupports2DEncoding()) {
-               emsg = "Document was encoded with 2DMR,"
-                   " but client does not support this data format";
+               result = Status(406, "Document was encoded with 2DMR, but client does not support this data format");
                return (send_reformat);
            }
            if (!modem->supports2D()) {
-               emsg = "Document was encoded with 2DMR,"
-                   " but modem does not support this data format";
+               result = Status(407, "Document was encoded with 2DMR, but modem does not support this data format");
                return (send_reformat);
            }
            params.df = DF_2DMR;
@@ -712,25 +709,25 @@ FaxServer::sendSetupParams1(TIFF* tif,
     if (yres >= 15.) {
        if (xres > 10) {
            if (!(clientInfo.getSupportsVRes() & VR_R16)) {
-               emsg = fxStr::format("Hyperfine resolution document is not supported"
-                   " by client, image resolution %g x %g lines/mm", xres, yres);
+               result = Status(408, "Hyperfine resolution document is not supported"
+                       " by client, image resolution %g x %g lines/mm", xres, yres);
                return (send_reformat);
            }
            if (!modem->supportsVRes(20)) {     // "20" is coded for R16
-               emsg = fxStr::format("Hyperfine resolution document is not supported"
-                   " by modem, image resolution %g x %g lines/mm", xres, yres);
+               result = Status(409, "Hyperfine resolution document is not supported"
+                       " by modem, image resolution %g x %g lines/mm", xres, yres);
                return (send_reformat);
            }
        params.vr = VR_R16;
        } else {
            if (!((clientInfo.getSupportsVRes() & VR_R8) || (clientInfo.getSupportsVRes() & VR_200X400))) {
-               emsg = fxStr::format("Superfine resolution document is not supported"
-                   " by client, image resolution %g lines/mm", yres);
+               result = Status(410, "Superfine resolution document is not supported"
+                       " by client, image resolution %g lines/mm", yres);
                return (send_reformat);
            }
            if (!modem->supportsVRes(yres)) {
-               emsg = fxStr::format("Superfine resolution document is not supported"
-                   " by modem, image resolution %g lines/mm", yres);
+               result = Status(411, "Superfine resolution document is not supported"
+                       " by modem, image resolution %g lines/mm", yres);
                return (send_reformat);
            }
        if (clientInfo.getSupportsVRes() & VR_R8) params.vr = VR_R8;
@@ -738,25 +735,25 @@ FaxServer::sendSetupParams1(TIFF* tif,
        }
     } else if (yres >= 10.) {
        if (!(clientInfo.getSupportsVRes() & VR_300X300)) {
-           emsg = fxStr::format("300x300 resolution document is not supported"
-               " by client, image resolution %g lines/mm", yres);
+           result = Status(412, "300x300 resolution document is not supported"
+                       " by client, image resolution %g lines/mm", yres);
            return (send_reformat);
        }
        if (!modem->supportsVRes(yres)) {
-           emsg = fxStr::format("300x300 resolution document is not supported"
-               " by modem, image resolution %g lines/mm", yres);
+           result = Status(413, "300x300 resolution document is not supported"
+                       " by modem, image resolution %g lines/mm", yres);
            return (send_reformat);
        }
        params.vr = VR_300X300;
     } else if (yres >= 7.) {
        if (!((clientInfo.getSupportsVRes() & VR_FINE) || (clientInfo.getSupportsVRes() & VR_200X200))) {
-           emsg = fxStr::format("High resolution document is not supported"
-               " by client, image resolution %g lines/mm", yres);
+           result = Status(414, "High resolution document is not supported"
+                       " by client, image resolution %g lines/mm", yres);
            return (send_reformat);
        }
        if (!modem->supportsVRes(yres)) {
-           emsg = fxStr::format("High resolution document is not supported"
-               " by modem, image resolution %g lines/mm", yres);
+           result = Status(415, "High resolution document is not supported"
+                       " by modem, image resolution %g lines/mm", yres);
            return (send_reformat);
        }
        if (clientInfo.getSupportsVRes() & VR_FINE) params.vr = VR_FINE;
@@ -773,7 +770,7 @@ FaxServer::sendSetupParams1(TIFF* tif,
     (void) TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
     double rf = (params.vr == VR_R16 ? 2 : params.vr == VR_300X300 ? 1.5 : 1);
     if (w > (clientInfo.getMaxPageWidthInPixels()*rf)) {
-       emsg = fxStr::format("Client does not support document page width"
+       result = Status(416, "Client does not support document page width"
                ", max remote page width %u pixels, image width %lu pixels",
                (uint32) (clientInfo.getMaxPageWidthInPixels()*rf), w);
        return (send_reformat);
@@ -789,7 +786,7 @@ FaxServer::sendSetupParams1(TIFF* tif,
            0,
            0,
        };
-       emsg = fxStr::format("Modem does not support document page width"
+       result = Status(417, "Modem does not support document page width"
                ", max page width %u pixels, image width %lu pixels",
                (uint32)(widths[modem->getBestPageWidth()&7]*rf), w);
        return (send_reformat);
@@ -810,7 +807,7 @@ FaxServer::sendSetupParams1(TIFF* tif,
        (void) TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
        float len = h / yres;                   // page length in mm
        if ((int) len > clientInfo.getMaxPageLengthInMM()) {
-           emsg = fxStr::format("Client does not support document page length"
+           result = Status(418, "Client does not support document page length"
                          ", max remote page length %d mm"
                          ", image length %lu rows (%.2f mm)",
                clientInfo.getMaxPageLengthInMM(), h, len);
@@ -823,7 +820,7 @@ FaxServer::sendSetupParams1(TIFF* tif,
                "<unlimited>",  // unlimited
                "<undefined>",  // US letter (used internally)
            };
-           emsg = fxStr::format("Modem does not support document page length"
+           result = Status(419, "Modem does not support document page length"
                          ", max page length %s mm"
                          ", image length %lu rows (%.2f mm)",
                lengths[modem->getBestPageLength()&3], h, len);
@@ -855,9 +852,9 @@ FaxServer::sendSetupParams1(TIFF* tif,
 }
 
 FaxSendStatus
-FaxServer::sendSetupParams(TIFF* tif, Class2Params& params, const FaxMachineInfo& clientInfo, fxStr& emsg)
+FaxServer::sendSetupParams(TIFF* tif, Class2Params& params, const FaxMachineInfo& clientInfo, Status& result)
 {
-    FaxSendStatus status = sendSetupParams1(tif, params, clientInfo, emsg);
+    FaxSendStatus status = sendSetupParams1(tif, params, clientInfo, result);
     if (status == send_ok) {
        traceProtocol("USE %s", params.pageWidthName());
        traceProtocol("USE %s", params.pageLengthName());
@@ -865,9 +862,9 @@ FaxServer::sendSetupParams(TIFF* tif, Class2Params& params, const FaxMachineInfo
        traceProtocol("USE %s", params.dataFormatName());
        traceProtocol("USE %s", params.scanlineTimeName());
     } else if (status == send_reformat) {
-       traceServer(emsg);
+       traceServer("%s", result.string());
     } else if (status == send_failed) {
-       traceServer("REJECT: " | emsg);
+       traceServer("REJECT: %s", result.string());
     }
     return (status);
 }
index 2b0478006aa00976cb2ad277d5214bf1d105d437..7bb545fe23b2311493d2ca9d4e7af1d782520eeb 100644 (file)
@@ -31,6 +31,7 @@
 #include "ModemServer.h"
 #include "FaxRecvInfo.h"
 #include "Array.h"
+#include "FaxRequest.h"
 
 class FaxAcctInfo;
 
@@ -65,23 +66,22 @@ private:
 
 // FAX transmission protocol support
     void       sendFax(FaxRequest& fax, FaxMachineInfo&, const fxStr& number, u_int&);
-    bool       sendClientCapabilitiesOK(FaxRequest&, FaxMachineInfo&, fxStr&);
+    bool       sendClientCapabilitiesOK(FaxRequest&, FaxMachineInfo&, Status& result);
     bool       sendFaxPhaseB(FaxRequest&, FaxItem&, FaxMachineInfo&, u_int, bool);
     void       sendPoll(FaxRequest& fax, bool remoteHasDoc);
     FaxSendStatus sendSetupParams(TIFF*,
-                   Class2Params&, const FaxMachineInfo&, fxStr&);
+                   Class2Params&, const FaxMachineInfo&, Status& result);
     FaxSendStatus sendSetupParams1(TIFF*,
-                   Class2Params&, const FaxMachineInfo&, fxStr&);
+                   Class2Params&, const FaxMachineInfo&, Status& result);
     void       sendFailed(FaxRequest& fax,
-                   FaxSendStatus, const char* notice, u_int tts = 0);
+                   FaxSendStatus, const Status& result, u_int tts = 0);
 // FAX reception support
     int                getRecvFile(fxStr& qfile, fxStr& emsg);
-    TIFF*      setupForRecv(FaxRecvInfo&, FaxRecvInfoArray&, fxStr& emsg);
-    bool       recvDocuments(TIFF*, FaxRecvInfo&, FaxRecvInfoArray&,
-                   fxStr& emsg);
-    bool       recvFaxPhaseD(TIFF* tif, FaxRecvInfo&, u_int& ppm, fxStr& emsg);
+    TIFF*      setupForRecv(FaxRecvInfo&, FaxRecvInfoArray&, Status& eresult);
+    bool       recvDocuments(TIFF*, FaxRecvInfo&, FaxRecvInfoArray&, Status& eresult);
+    bool       recvFaxPhaseD(TIFF* tif, FaxRecvInfo&, u_int& ppm, Status& eresult);
     bool       pollFaxPhaseB(const fxStr& sep, const fxStr& pwd,
-                   FaxRecvInfoArray&, fxStr& emsg);
+                   FaxRecvInfoArray&, Status& eresult);
 protected:
     FaxServer(const fxStr& deviceName, const fxStr& devID);
 
@@ -94,7 +94,7 @@ protected:
     void       setLocalIdentifier(const fxStr& lid);
 
     void       sendFax(FaxRequest&, FaxMachineInfo&, FaxAcctInfo&, u_int&);
-    bool       recvFax(const CallID& callid, fxStr& emsg);
+    bool       recvFax(const CallID& callid, Status& eresult);
 
     time_t     getFileTransferTime() const;
     time_t     getPageTransferTime() const;
index 18089c4114aad9f110c40cd5837b8c4b439ada8d..73f8b16a7bf773c3122635d6910ca11620c60a9b 100644 (file)
@@ -670,7 +670,7 @@ ModemServer::beginSession(const fxStr& number)
     if (seqnum == (u_long)-1)
     {
        logError("Couldn't get next seqnum for session log: %s",
-                (const char*)emsg);
+                (const char*) emsg);
        return;
     }
     commid = fxStr::format(Sequence::format, seqnum);
@@ -792,8 +792,8 @@ bool ModemServer::serverBusy() const
 
 bool ModemServer::modemWaitForRings(u_short rings, CallType& type, CallID& callid)
     { return modem->waitForRings(rings, type, callid); }
-CallType ModemServer::modemAnswerCall(AnswerType atype, fxStr& emsg, const char* dialnumber)
-    { return modem->answerCall(atype, emsg, dialnumber); }
+CallType ModemServer::modemAnswerCall(AnswerType atype, Status& eresult, const char* dialnumber)
+    { return modem->answerCall(atype, eresult, dialnumber); }
 void ModemServer::modemAnswerCallCmd(CallType ctype)
     { modem->answerCallCmd(ctype); }
 void ModemServer::modemHangup()                        { modem->hangup(); }
index d67efa53f37bf4af5e56f8de2364b87da622dcdd..8223f89a7ac3020904a61891c99ffe02b1d98b08 100644 (file)
@@ -161,7 +161,7 @@ protected:
     bool       modemStopOutput();
 // modem driver interfaces
     bool       modemWaitForRings(u_short rings, CallType&, CallID&);
-    CallType   modemAnswerCall(AnswerType, fxStr&, const char* dialnumber = NULL);
+    CallType   modemAnswerCall(AnswerType, Status& eresult, const char* dialnumber = NULL);
     void       modemAnswerCallCmd(CallType);
     void       modemFlushInput();
     void       modemHangup();
diff --git a/faxd/STATUS.txt b/faxd/STATUS.txt
new file mode 100644 (file)
index 0000000..e40b765
--- /dev/null
@@ -0,0 +1,266 @@
+000-049 : call failures
+===============================================================================
+000      : Call successful
+001      : Busy signal detected
+002      : No carrier detected
+003      : No answer from remote
+004      : No local dialtone
+005      : Invalid dialing command
+006      : Unknown problem
+007      : Carrier established, but Phase A failure
+008      : Data connection established (wanted fax)
+009      : Glare - RING detected
+010      : Blacklisted by modem
+011      : Ringback detected, no answer without CED
+012      : Ring detected without successful handshake
+
+050-099 : non Class-specific fax protocol failures
+===============================================================================
+050      : Missing EOL after 5 seconds
+051      : Procedure interrupt received, job terminated
+
+100-199 : Class 1-specific protocol failure
+===============================================================================
+100      : Failure to receive silence (synchronization failure).
+101      : Failure to raise V.21 transmission carrier.
+102      : No sender protocol (T.30 T1 timeout)
+103      : RSPREC error/got DCN (sender abort)
+104      : RSPREC invalid response received
+105      : Failure to train modems
+106      : RSPREC error/got EOT
+107      : Can not continue after DIS/DTC
+108      : COMREC received DCN (sender abort)
+109      : No response to RNR repeated 3 times.
+110      : COMREC invalid response received
+111      : T.30 T2 timeout, expected page not received
+112      : Failed to properly detect high-speed data carrier.
+113      : Received invalid CTC signal in V.34-Fax.
+114      : Failed to properly open V.34 primary channel.
+115      : Received premature V.34 termination.
+116      : Failed to properly open V.34 control channel.
+117      : COMREC invalid response to repeated PPR received
+118      : T.30 T2 timeout, expected signal not received
+119      : COMREC invalid partial-page signal received
+120      : Cannot synchronize ECM frame reception.
+121      : ECM page received containing no image data.
+122      : Remote has no T.4 receiver capability
+123      : DTC received when expecting DIS (not supported)
+124      : COMREC error in transmit Phase B/got DCN
+125      : COMREC invalid command received/no DIS or DTC
+126      : No receiver protocol (T.30 T1 timeout)
+127      : Stop and wait failure (modem on hook)
+128      : Remote fax disconnected prematurely
+129      : Procedure interrupt (operator intervention)
+130      : Unable to transmit page (giving up after RTN)
+131      : Unable to transmit page (giving up after 3 attempts)
+132      : Unable to transmit page (NAK at all possible signalling rates)
+133      : Unable to transmit page (NAK with operator intervention)
+134      : Fax protocol error (unknown frame received)
+135      : Fax protocol error (command repeated 3 times)
+136      : DIS/DTC received 3 times; DCS not recognized
+137      : Failure to train remote modem at 2400 bps or minimum speed
+138      : Receiver flow control exceeded timer.
+139      : No response to RR repeated 3 times.
+140      : COMREC invalid response received to RR.
+141      : No response to CTC repeated 3 times.
+142      : COMREC invalid response received to CTC.
+143      : Failure to transmit clean ECM image data.
+144      : No response to EOR repeated 3 times.
+145      : COMREC invalid response received to EOR.
+146      : COMREC invalid response received to PPS.
+147      : No response to PPS repeated 3 times.
+148      : Unable to establish message carrier
+149      : Unspecified Transmit Phase C error
+150      : No response to MPS repeated 3 tries
+151      : No response to EOP repeated 3 tries
+152      : No response to EOM repeated 3 tries
+153      : No response to PPM repeated 3 tries
+
+200-299 : Class 2-specific protocol failure
+===============================================================================
+200      : Unable to request polling operation (modem may not support polling)
+201      : Unable to setup polling identifer (modem command failed)
+202      : Unable to setup selective polling address (modem command failed)
+203      : Unable to setup polling password (modem command failed)
+204      : Unable to send password (modem command failed)
+205      : Unable to send subaddress (modem command failed)
+206      : Unable to restrict minimum transmit speed to %s (modem command failed)
+207      : Unable to setup session parameters prior to call (modem command failed)
+208      : Unable to set session parameters
+209      :
+210      : Unknown hangup code
+211      : Normal and proper end of connection
+212      : Ring detect without successful handshake
+213      : Call aborted,  from +FK or <CAN>
+214      : No loop current
+215      : Ringback detected, no answer (timeout)
+216      : Ringback detected, no answer without CED
+217      : Unspecified Phase A error
+218      : No answer (T.30 T1 timeout)
+219      : Unspecified Transmit Phase B error
+220      : Remote cannot be polled
+221      : COMREC error in transmit Phase B/got DCN
+222      : COMREC invalid command received/no DIS or DTC
+223      : RSPREC error/got DCN
+224      : DCS sent 3 times without response
+225      : DIS/DTC received 3 times; DCS not recognized
+226      : Failure to train at 2400 bps or +FMINSP value
+227      : RSPREC invalid response received
+228      : Unspecified Transmit Phase C error
+229      : Unspecified Image format error
+230      : Image conversion error
+231      : DTE to DCE data underflow
+232      : Unrecognized Transparent data command
+233      : Image error, line length wrong
+234      : Image error, page length wrong
+235      : Image error, wrong compression code
+236      : Unspecified Transmit Phase D error, including +FPHCTO timeout between data and +FET command
+237      : RSPREC error/got DCN
+238      : No response to MPS repeated 3 times
+239      : Invalid response to MPS
+240      : No response to EOP repeated 3 times
+241      : Invalid response to EOP
+242      : No response to EOM repeated 3 times
+243      : Invalid response to EOM
+244      : Unable to continue after PIN or PIP
+245      : Unspecified Receive Phase B error
+246      : RSPREC error/got DCN
+247      : COMREC error
+248      : T.30 T2 timeout, expected page not received
+249      : T.30 T1 timeout after EOM received
+250      : Unspecified Phase C error, including too much delay between TCF and +FDR command
+251      : Missing EOL after 5 seconds (section 3.2/T.4)
+252      : DCE to DTE buffer overflow
+253      : Bad CRC or frame (ECM or BFT modes)
+254      : Unspecified Phase D error
+255      : RSPREC invalid response received
+256      : COMREC invalid response received
+257      : Unable to continue after PIN or PIP, no PRI-Q
+258      : Command or signal 10 sec. timeout
+259      : Cannot send: +FMINSP > remote's +FDIS(BR) code
+260      : Cannot send: remote is V.29 only, local DCE constrained to 2400 or 4800 bps
+261      : Remote station cannot receive (DIS bit 10)
+262      : +FK aborted or <CAN> aborted
+263      : +Format conversion error in +FDT=DF,VR, WD,LN Incompatible and inconvertable data format
+264      : Remote cannot receive
+265      : After +FDR, DCE waited more than 30 seconds for XON from DTE after XOFF from DTE
+266      : In Polling Phase B, remote cannot be polled
+267-279 (currently unused)
+280      : Procedure interrupt (operator intervention)
+281      : Unable to transmit page (giving up after RTN)
+282      : Unable to transmit page (giving up after 3 attempts)
+283      : Unable to transmit page (NAK at all possible signalling rates)
+284      : Unable to transmit page (NAK with operator intervention)
+285      : Modem protocol error (unknown post-page response)
+286      : Batching protocol error
+287      : Communication failure during Phase B/C
+288      : Communication failure during Phase B/C (modem protocol botch)
+
+300-399 : Non-T.30 client or server failure
+===============================================================================
+301      : Receive aborted due to operator intervention
+302      : Problem reading document directory
+303      : Internal botch; %s post-page handling string "%s"
+304      : Maximum receive page count exceeded, call terminated
+305      : Could not fork for local ID.
+306      : Bad exit status %#o for '%s'
+307      : Could not open a pipe for local ID.
+308      : ANSWER: CALL REJECTED
+309      : ANSWER: Call deduced as %s, but told to answer as %s; call ignored
+310      : External getty use is not permitted {E310}
+311      : %s: could not create
+312      : "%s: can not fork: %s
+313      : ERROR: Unknown status
+314      : Can not open document file %s
+315      : Can not set directory %u in document file %s
+316      : Error reading directory %u in document file %s
+317      : Too many pages in submission; max %u
+318      : Unable to lock shared document file
+319      : Unable to open shared document file
+320      : Unable to create document file
+321      : Converted document is not valid TIFF
+322      : Could not reopen converted document to verify format
+323      : Job contains no documents
+324      : Modem does not support polling
+325      : Kill time expired
+326      : Invalid or corrupted job description file
+327      : REJECT: Unable to convert dial string to canonical format
+328      : REJECT: Requested modem %s is not registered
+329      : REJECT: No work found in job file
+330      : REJECT: Page width (%u) appears invalid
+331      : REJECT: Job expiration time (%u) appears invalid
+332      : REJECT: Time-to-send (%u) appears invalid
+333      : REJECT: Too many attempts to dial
+334      : REJECT: Too many attempts to transmit: %u, max %u
+335      : REJECT: Too many pages in submission: %u, max %u
+336      : REJECT: Modem is configured as exempt from accepting jobs
+337      : Blocked by concurrent calls
+338      : Delayed by time-of-day restrictions
+339      : Delayed by outbound call staggering
+340      : Could not fork to prepare job for transmission
+341      : Could not fork to start job transmission
+342      : Delayed by prior call
+343      : Send program terminated abnormally; unable to exec %s
+344      : Job interrupted by user
+345      : Call aborted by user
+346      : Can not lock modem device
+347      : %s  [document conversion failure output]
+348      : REJECT: %s [JobControl reject notice]
+350      : Permission denied (unnacceptable client TSI)
+351      : Permission denied (unnacceptable client PWD)
+
+400-499 : job/modem incompatibility
+===============================================================================
+400      : Modem does not support negotiated signalling rate
+401      : Modem does not support negotiated min scanline time
+402      : Document is not in a Group 3 or Group 4 compatible format (compression %u)
+403      : Document was encoded with 2DMMR, but client does not support this data format
+404      : Document was encoded with 2DMMR, but modem does not support this data format
+405      : Document was encoded with 2DMMR, but ECM is not being used.
+406      : Document was encoded with 2DMR, but client does not support this data format
+407      : Document was encoded with 2DMR, but modem does not support this data format
+408      : Hyperfine resolution document is not supported by client, image resolution %g x %g lines/mm
+409      : Hyperfine resolution document is not supported by modem, image resolution %g x %g lines/mm
+410      : Superfine resolution document is not supported by client, image resolution %g lines/mm
+411      : Superfine resolution document is not supported by modem, image resolution %g lines/mm
+412      : 300x300 resolution document is not supported by client, image resolution %g lines/mm
+413      : 300x300 resolution document is not supported by modem, image resolution %g lines/mm
+414      : High resolution document is not supported by client, image resolution %g lines/mm
+415      : High resolution document is not supported by modem, image resolution %g lines/mm
+416      : Client does not support document page width, max remote page width %g pixels, image width %lu pixels
+417      : Modem does not support document page width, max page width %g pixels, image width %lu pixels
+418      : Client does not support document page length, max remote page length %d mm, image length %lu rows (%.2f mm)
+419      : Modem does not support document page length, max page length %s mm, image length %lu rows (%.2f mm)
+420      : Unable to configure modem for fax use
+421      : Unable to configure modem for data use
+422      : Can not setup modem
+
+500-E599 : paging failures
+===============================================================================
+500      : No initial ID response from paging central
+501      : Login failed multiple times
+502      : Protocol failure: %s from paging central
+503      : Protocol failure: %s waiting for go-ahead message
+504      : Message block not acknowledged by paging central after multiple tries
+505      : Message block transmit failed paging central rejected it
+506      : Protocol failure: paging central responded to message block transmit with forced disconnect
+507      : Protocol failure: %s to message block transmit
+508      : Paging central rejected content; check PIN
+509      : Protocol failure: timeout waiting for transaction ACK/NAK from paging central
+510      : Paging central responded with forced disconnect
+511      : Job has no PIN to send to
+512      : No PIN specified
+
+600-699 : Polling failures
+===============================================================================
+601      : remote has no document to poll
+
+900-999  : HylaFAX errors
+===============================================================================
+901      : Unable to open TIFF file %s for writing
+902      : Unable to create temp file for received data: %s
+903      : Can not set directory in document file
+904      : Can not open document file
+905      : Internal error: unable to open text message file
+906      : Internal error: unable to read text message file
+907      : polling operation not done because of internal failure
index 02b6bddaad49863f5d448630186b80d7e57e96a1..095b786885e449c581630f1fa321b4ac6105d292 100644 (file)
@@ -325,7 +325,7 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
      */
     bool callResolved;
     bool advanceRotary = true;
-    fxStr emsg;
+    Status eresult;
 
     fxStr callid_formatted = "";
 
@@ -352,8 +352,8 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
        pid_t pid = fork();
        switch (pid) {
            case -1:
-               emsg = "Could not fork for local ID.";
-               logError("%s", (const char*)emsg);
+               eresult = Status(305, "Could not fork for local ID");
+               logError("%s", eresult.string());
                Sys::close(pipefd[0]);
                Sys::close(pipefd[1]);
                break;
@@ -375,8 +375,8 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
                    Sys::waitpid(pid, status);
                    if (status != 0)
                    {
-                       emsg = fxStr::format("Bad exit status %#o for \'%s\'", status, (const char*) cmd);
-                       logError("%s", (const char*)emsg);
+                       eresult = Status(306, "Bad exit status %#o for \'%s\'", status, (const char*) cmd);
+                       logError("%s", eresult.string());
                    }
                    // modem settings may have changed...
                    FaxModem* modem = (FaxModem*) ModemServer::getModem();
@@ -392,8 +392,8 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
        /*
         * Call was rejected based on Caller ID information.
         */
-       emsg = "ANSWER: CALL REJECTED";
-       traceServer("%s", (const char*)emsg);
+       eresult = Status(308, "ANSWER: CALL REJECTED");
+       traceServer("%s", eresult.string());
        callResolved = false;
        advanceRotary = false;
     } else {
@@ -406,18 +406,18 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
             * deduced call type.
             */
            if (atype != ClassModem::ANSTYPE_ANY && ctype != atype) {
-               emsg = fxStr::format("ANSWER: Call deduced as %s,"
-                    "but told to answer as %s; call ignored",
+               eresult = Status(309, "ANSWER: Call deduced as %s,"
+                    " but told to answer as %s; call ignored",
                     ClassModem::callTypes[ctype],
                     ClassModem::answerTypes[atype]);
-               traceServer("%s", (const char*)emsg);
+               traceServer("%s", eresult.string());
                callResolved = false;
                advanceRotary = false;
            } else {
                // NB: answer based on ctype, not atype
                if (!(noAnswerVoice && ctype == ClassModem::CALLTYPE_VOICE)) 
-                   ctype = modemAnswerCall(ctype, emsg, dialnumber);
-               callResolved = processCall(ctype, emsg, callid);
+                   ctype = modemAnswerCall(ctype, eresult, dialnumber);
+               callResolved = processCall(ctype, eresult, callid);
            }
        } else if (atype == ClassModem::ANSTYPE_ANY) {
            /*
@@ -426,7 +426,7 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
             */
            int r = answerRotor;
            do {
-               callResolved = answerCall(answerRotary[r], ctype, emsg, callid, dialnumber);
+               callResolved = answerCall(answerRotary[r], ctype, eresult, callid, dialnumber);
                r = (r+1) % answerRotorSize;
            } while (!callResolved && adaptiveAnswer && r != answerRotor);
        } else {
@@ -435,11 +435,11 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
             * any existing call type information such as
             * distinctive ring.
             */
-           callResolved = answerCall(atype, ctype, emsg, callid, dialnumber);
+           callResolved = answerCall(atype, ctype, eresult, callid, dialnumber);
        }
     }
-    if (emsg.length())
-       traceProtocol((const char*) emsg);
+    if (eresult.value() != 0)
+       traceProtocol("%s", eresult.string());
     /*
      * Call resolved.  If we were able to recognize the call
      * type and setup a session, then reset the answer rotary
@@ -459,7 +459,7 @@ faxGettyApp::answerPhone(AnswerType atype, CallType ctype, const CallID& callid,
     sendModemStatus("I");
     endSession();
 
-    ai.status = emsg;
+    ai.status = eresult.string();
     ai.duration = Sys::now() - ai.start;
     ai.conntime = ai.duration;
     if (logCalls && !ai.record("CALL"))
@@ -517,7 +517,7 @@ faxGettyApp::answerCleanup()
  * the modem layer arrives at as the call type.
  */
 bool
-faxGettyApp::answerCall(AnswerType atype, CallType& ctype, fxStr& emsg, const CallID& callid, const char* dialnumber)
+faxGettyApp::answerCall(AnswerType atype, CallType& ctype, Status& eresult, const CallID& callid, const char* dialnumber)
 {
     bool callResolved;
     if (atype == ClassModem::ANSTYPE_EXTERN) {
@@ -530,16 +530,16 @@ faxGettyApp::answerCall(AnswerType atype, CallType& ctype, fxStr& emsg, const Ca
             * then we take action based on the returned call type.
             */
            ctype = runGetty("EXTERN GETTY", OSnewEGetty,
-               egettyArgs, emsg, lockExternCalls, callid, true);
+               egettyArgs, eresult, lockExternCalls, callid, true);
            if (ctype == ClassModem::CALLTYPE_DONE)     // NB: call completed
                return (true);
            if (ctype != ClassModem::CALLTYPE_ERROR)
                modemAnswerCallCmd(ctype);
        } else
-           emsg = "External getty use is not permitted";
+           eresult = Status(310, "External getty use is not permitted");
     } else
-       ctype = modemAnswerCall(atype, emsg, dialnumber);
-    callResolved = processCall(ctype, emsg, callid);
+       ctype = modemAnswerCall(atype, eresult, dialnumber);
+    callResolved = processCall(ctype, eresult, callid);
     return (callResolved);
 }
 
@@ -557,7 +557,7 @@ faxGettyApp::answerCall(AnswerType atype, CallType& ctype, fxStr& emsg, const Ca
  * to recondition the modem for incoming calls (if configured).
  */
 bool
-faxGettyApp::processCall(CallType ctype, fxStr& emsg, const CallID& callid)
+faxGettyApp::processCall(CallType ctype, Status& eresult, const CallID& callid)
 {
     bool callHandled = false;
 
@@ -576,14 +576,14 @@ faxGettyApp::processCall(CallType ctype, fxStr& emsg, const CallID& callid)
        );
        changeState(RECEIVING);
        sendRecvStatus(getModemDeviceID(), "B");
-       callHandled = recvFax(callid, emsg);
+       callHandled = recvFax(callid, eresult);
        sendRecvStatus(getModemDeviceID(), "E");
        break;
     case ClassModem::CALLTYPE_DATA:
        traceServer("ANSWER: DATA CONNECTION");
        if (gettyArgs != "") {
            sendModemStatus("d");
-           runGetty("GETTY", OSnewGetty, gettyArgs, emsg, lockDataCalls, callid);
+           runGetty("GETTY", OSnewGetty, gettyArgs, eresult, lockDataCalls, callid);
            sendModemStatus("e");
        } else
            traceServer("ANSWER: Data connections are not permitted");
@@ -593,14 +593,14 @@ faxGettyApp::processCall(CallType ctype, fxStr& emsg, const CallID& callid)
        traceServer("ANSWER: VOICE CONNECTION");
        if (vgettyArgs != "") {
            sendModemStatus("v");
-           runGetty("VGETTY", OSnewVGetty, vgettyArgs, emsg, lockVoiceCalls, callid);
+           runGetty("VGETTY", OSnewVGetty, vgettyArgs, eresult, lockVoiceCalls, callid);
            sendModemStatus("w");
        } else
            traceServer("ANSWER: Voice connections are not permitted");
        callHandled = true;
        break;
     case ClassModem::CALLTYPE_ERROR:
-       traceServer("ANSWER: %s", (const char*) emsg);
+       traceServer("ANSWER: %s", eresult.string());
        break;
     }
     return (callHandled);
@@ -616,7 +616,7 @@ faxGettyApp::runGetty(
     const char* what,
     Getty* (*newgetty)(const fxStr&, const fxStr&),
     const char* args,
-    fxStr& emsg,
+    Status& eresult,
     bool keepLock,
     const CallID& callid,
     bool keepModem
@@ -628,7 +628,7 @@ faxGettyApp::runGetty(
        dev.remove(0, prefix.length());
     Getty* getty = (*newgetty)(dev, fxStr::format("%u", getModemRate()));
     if (getty == NULL) {
-       emsg = fxStr::format("%s: could not create", what);
+       eresult = Status(311, "%s: could not create", what);
        return (ClassModem::CALLTYPE_ERROR);
     }
 
@@ -650,7 +650,7 @@ faxGettyApp::runGetty(
     bool parentIsInit = (getppid() == 1);
     pid_t pid = fork();
     if (pid == -1) {
-       emsg = fxStr::format("%s: can not fork: %s", what, strerror(errno));
+       eresult = Status(312, "%s: can not fork: %s", what, strerror(errno));
        delete getty;
        return (ClassModem::CALLTYPE_ERROR);
     }
@@ -705,7 +705,7 @@ faxGettyApp::runGetty(
     getty->wait(status, true);         // wait for getty/login work to complete
     if ( status > 1280 ) { // codes returned larger than 1280 are undefined and must be an error    
         status = 1024;
-        emsg = "ERROR: Unknown status";
+        eresult = Status(313, "ERROR: Unknown status");
     }
     /*
      * Retake ownership of the modem.  Note that there's
index c083e5753f920c52017c4e7e0d418afff2be46ae..5b9f21746057dc1fdace72168abbb722055ce89e 100644 (file)
@@ -106,10 +106,10 @@ private:
     bool       setupModem(bool isSend);
     void       discardModem(bool dropDTR);
 // inbound call handling
-    bool       processCall(CallType ctype, fxStr& emsg, const CallID& callid);
+    bool       processCall(CallType ctype, Status& eresult, const CallID& callid);
     CallType   runGetty(const char* what,
                    Getty* (*newgetty)(const fxStr&, const fxStr&),
-                   const char* args, fxStr &emsg,
+                   const char* args, Status &eresult,
                     bool keepLock, const CallID& callid, 
                    bool keepModem = false);
     void       setRingsBeforeAnswer(int rings);
@@ -118,7 +118,7 @@ private:
     void       answerPhoneCmd(AnswerType, const char* dialnumber = NULL);
     void       answerPhone(AnswerType, CallType, const CallID& callid, const char* dialnumber = NULL);
     void       answerCleanup();
-    bool       answerCall(AnswerType atype, CallType& ctype, fxStr& emsg, const CallID& callid, const char* dialnumber = NULL);
+    bool       answerCall(AnswerType atype, CallType& ctype, Status& eresult, const CallID& callid, const char* dialnumber = NULL);
 
     friend void AnswerTimeoutHandler::timerExpired(long, long);
 // miscellaneous stuff
index 894c1098475656c7b5226a21220ccffbf8924cb5..0a4d3455bf3105eb3652c18e9468fda319da7789 100644 (file)
@@ -343,7 +343,7 @@ void
 faxQueueApp::processJob(Batch& batch, Job& job, FaxRequest* req)
 {
     job.commid = "";                   // set on return
-    req->notice = "";                  // Clear for new procssing
+    req->result.clear();                       // Clear for new procssing
     JobStatus status;
     setActive(batch,job);
     req->status = send_nobatch;
@@ -372,9 +372,9 @@ bool
 faxQueueApp::prepareJobNeeded(Job& job, FaxRequest& req, JobStatus& status)
 {
     if (!req.items.length()) {
-       req.notice = "Job contains no documents";
+       req.result = Status(323, "Job contains no documents");
        status = Job::rejected;
-       jobError(job, "SEND REJECT: %s", (const char*) req.notice);
+       jobError(job, "SEND REJECT: %s", req.result.string());
        return (false);
     }
     for (u_int i = 0, n = req.items.length(); i < n; i++)
@@ -386,9 +386,9 @@ faxQueueApp::prepareJobNeeded(Job& job, FaxRequest& req, JobStatus& status)
            return (true);
        case FaxRequest::send_poll:             // verify modem is capable
            if (!job.modem->supportsPolling()) {
-               req.notice = "Modem does not support polling";
+               req.result = Status(324, "Modem does not support polling");
                status = Job::rejected;
-               jobError(job, "SEND REJECT: %s", (const char*) req.notice);
+               jobError(job, "SEND REJECT: %s", req.result.string());
                return (false);
            }
            break;
@@ -446,7 +446,7 @@ faxQueueApp::prepareStart(Batch& batch, Job& job, FaxRequest* req)
        /*NOTREACHED*/
     case -1:                           // fork failed, sleep and retry
        job.remove();                   // Remove from active queue
-       delayJob(job, *req, "Could not fork to prepare job for transmission",
+       delayJob(job, *req, Status(340, "Could not fork to prepare job for transmission"),
            Sys::now() + random() % requeueInterval);
        delete req;
        fillBatch(batch);
@@ -499,8 +499,8 @@ faxQueueApp::prepareDone(Batch& batch, int status)
                (const char*) job.jobid);
            setDead(job);
        } else if (status == Job::requeued) {
-           delayJob(job, *req, "Cannot fork to prepare job for transmission",
-           Sys::now() + random() % requeueInterval);
+           delayJob(job, *req, Status(340, "Cannot fork to prepare job for transmission"),
+                   Sys::now() + random() % requeueInterval);
            delete req;
        } else {
            deleteRequest(job, req, status, true);
@@ -735,7 +735,7 @@ faxQueueApp::prepareJob(Job& job, FaxRequest& req,
        case FaxRequest::send_tiff:             // verify&possibly convert TIFF
         case FaxRequest::send_pdf:             // convert PDF
            tmp = FaxRequest::mkbasedoc(fitem.item) | ";" | params.encodePage();
-           status = convertDocument(job, fitem, tmp, params, req.notice);
+           status = convertDocument(job, fitem, tmp, params, req.result);
            if (status == Job::done) {
                /*
                 * Insert converted file into list and mark the
@@ -768,9 +768,11 @@ faxQueueApp::prepareJob(Job& job, FaxRequest& req,
             * Calculate/recalculate the per-page session parameters
             * and check the page count against the max pages.
             */
-           if (!preparePageHandling(job, req, info, req.notice)) {
+            Status r;
+           if (!preparePageHandling(job, req, info, r)) {
                status = Job::rejected;         // XXX
-               req.notice.insert("Document preparation failed: ");
+               req.result= Status(314, "Document preparation failed: %s"
+                       , r.string());
            }
            updateQFile = true;
        }    
@@ -791,7 +793,7 @@ faxQueueApp::prepareJob(Job& job, FaxRequest& req,
  */
 bool
 faxQueueApp::preparePageHandling(Job& job, FaxRequest& req,
-    const FaxMachineInfo& info, fxStr& emsg)
+    const FaxMachineInfo& info, Status& result)
 {
     /*
      * Figure out whether to try chopping off white space
@@ -838,16 +840,16 @@ faxQueueApp::preparePageHandling(Job& job, FaxRequest& req,
            const FaxItem& fitem = req.items[i];
            tif = TIFFOpen(fitem.item, "r");
            if (tif == NULL) {
-               emsg = "Can not open document file " | fitem.item;
+               result = Status(314, "Can not open document file %s", (const char*)fitem.item);
                if (tif)
                    TIFFClose(tif);
                return (false);
            }
            if (fitem.dirnum != 0 && !TIFFSetDirectory(tif, fitem.dirnum)) {
-               emsg = fxStr::format(
-                   "Can not set directory %u in document file %s"
+               result = Status(315,
+                               fxStr::format("Can not set directory %u in document file %s"
                    , fitem.dirnum
-                   , (const char*) fitem.item
+                   , (const char*) fitem.item)
                );
                if (tif)
                    TIFFClose(tif);
@@ -859,19 +861,17 @@ faxQueueApp::preparePageHandling(Job& job, FaxRequest& req,
             * Read the next TIFF directory.
             */
            if (!TIFFReadDirectory(tif)) {
-               emsg = fxStr::format(
-                   "Error reading directory %u in document file %s"
+               result = Status(316, "Error reading directory %u in document file %s"
                    , TIFFCurrentDirectory(tif)
-                   , TIFFFileName(tif)
-               );
+                   , TIFFFileName(tif));
                if (tif)
                    TIFFClose(tif);
                return (false);
            }
        }
        if (++req.totpages > maxPages) {
-           emsg = fxStr::format("Too many pages in submission; max %u",
-               maxPages);
+           result = Status(317, "Too many pages in submission; max %u"
+               ,maxPages);
            if (tif)
                TIFFClose(tif);
            return (false);
@@ -1028,7 +1028,7 @@ faxQueueApp::convertDocument(Job& job,
     const FaxItem& req,
     const fxStr& outFile,
     const Class2Params& params,
-    fxStr& emsg)
+    Status& result)
 {
     JobStatus status;
     /*
@@ -1062,7 +1062,7 @@ faxQueueApp::convertDocument(Job& job,
            if (fd != -1) {
                if (flock(fd, LOCK_SH) == -1) {
                    status = Job::format_failed;
-                   emsg = "Unable to lock shared document file";
+                   result = Status(318, "Unable to lock shared document file");
                } else
                    status = Job::done;
                (void) Sys::close(fd);          // NB: implicit unlock
@@ -1073,18 +1073,18 @@ faxQueueApp::convertDocument(Job& job,
                 * limit or a malformed PostScript submission).
                 */
                status = Job::format_failed;
-               emsg = "Unable to open shared document file";
+               result = Status(319, "Unable to open shared document file");
            }
        } else {
            status = Job::format_failed;
-           emsg = "Unable to create document file";
+           result = Status(320, "Unable to create document file");
        }
        /*
         * We were unable to open, create, or flock
         * the file.  This should not happen.
         */
        if (status != Job::done)
-           jobError(job, "CONVERT DOCUMENT: %s: %m", (const char*) emsg);
+           jobError(job, "CONVERT DOCUMENT: %s: %m", result.string());
     } else {
        (void) flock(fd, LOCK_EX);              // XXX check for errors?
        /*
@@ -1122,7 +1122,7 @@ faxQueueApp::convertDocument(Job& job,
        argv[ac++] = req.item;
        argv[ac] = NULL;
        // XXX the (char* const*) is a hack to force type compatibility
-       status = runConverter(job, argv[0], (char* const*) argv, emsg);
+       status = runConverter(job, argv[0], (char* const*) argv, result);
        if (status == Job::done) {
            /*
             * Many converters exit with zero status even when
@@ -1143,20 +1143,20 @@ faxQueueApp::convertDocument(Job& job,
                while (!TIFFLastDirectory(tif))
                    if (!TIFFReadDirectory(tif)) {
                        status = Job::format_failed;
-                       emsg = "Converted document is not valid TIFF";
+                       result = Status(321, "Converted document is not valid TIFF");
                        break;
                    }
                TIFFClose(tif);
            } else {
                status = Job::format_failed;
-               emsg = "Could not reopen converted document to verify format";
+               result = Status(322, "Could not reopen converted document to verify format");
            }
            if (status == Job::done)    // discard any debugging output
-               emsg = "";
+               result.clear();
            else
-               jobError(job, "CONVERT DOCUMENT: %s", (const char*) emsg);
+               jobError(job, "CONVERT DOCUMENT: %s", result.string());
        } else if (status == Job::rejected)
-           jobError(job, "SEND REJECT: %s", (const char*) emsg);
+           jobError(job, "SEND REJECT: %s", result.string());
        (void) Sys::close(fd);          // NB: implicit unlock
     }
     return (status);
@@ -1178,7 +1178,7 @@ closeAllBut(int fd)
  * of rejected.
  */
 JobStatus
-faxQueueApp::runConverter(Job& job, const char* app, char* const* argv, fxStr& emsg)
+faxQueueApp::runConverter(Job& job, const char* app, char* const* argv, Status& result)
 {
     fxStr cmdline(argv[0]);
     for (u_int i = 1; argv[i] != NULL; i++)
@@ -1205,7 +1205,8 @@ faxQueueApp::runConverter(Job& job, const char* app, char* const* argv, fxStr& e
            /*NOTREACHED*/
        default:                        // parent, read from pipe and wait
            Sys::close(pfd[1]);
-           if (runConverter1(job, pfd[0], emsg)) {
+           fxStr output;
+           if (runConverter1(job, pfd[0], output)) {
                int estat = -1;
                (void) Sys::waitpid(pid, estat);
                if (estat)
@@ -1216,6 +1217,7 @@ faxQueueApp::runConverter(Job& job, const char* app, char* const* argv, fxStr& e
                case (255<<8): case 255: status = Job::no_formatter; break;
                default:                 status = Job::format_failed; break;
                }
+               result = Status(347, "%s", (const char*)output);
            } else {
                kill(pid, SIGTERM);
                (void) Sys::waitpid(pid);
@@ -1291,15 +1293,15 @@ faxQueueApp::makeCoverPage(Job& job, FaxRequest& req, const Class2Params& params
     );
     traceQueue(job, "COVER PAGE: %s", (const char*)cmd);
     if (runCmd(cmd, true)) {
-       fxStr emsg;
+       Status result;
        fxStr tmp = fitem.item | ";" | params.encodePage();
-       if (convertDocument(job, fitem, tmp, params, emsg)) {
+       if (convertDocument(job, fitem, tmp, params, result)) {
            req.insertFax(0, tmp);
            req.cover = tmp;                    // needed in sendJobDone
            req.pagehandling = "";              // XXX force recalculation
        } else {
            jobError(job, "SEND: No continuation cover page, "
-               " document conversion failed: %s", (const char*) emsg);
+               " document conversion failed: %s", result.string());
        }
        Sys::unlink(fitem.item);
     } else {
@@ -1488,16 +1490,15 @@ faxQueueApp::sendDone(Batch& batch, int status)
        {
            traceJob(job, "Filling in status from %#x", status);
            if (status & 0xFF) {
-               req->notice = fxStr::format(
-                   "Send program terminated abnormally with exit status %#x", status);
+               req->result = Status(343, "Send program terminated abnormally with exit status %#x", status);
                req->status = send_failed;
-               logError("JOB %s: %s", (const char*)job.jobid, (const char*) req->notice);
+               logError("JOB %s: %s", (const char*)job.jobid, req->result.string());
            } else if ((status >>= 8) == 127) {
-               req->notice = "Send program terminated abnormally; unable to exec " |
-                   pickCmd(req->jobtype);
+               req->result = Status(343, "Send program terminated abnormally; unable to exec " |
+                   pickCmd(req->jobtype));
                req->status = send_failed;
                logError("JOB %s: %s",
-                       (const char*)job.jobid, (const char*)req->notice);
+                       (const char*)job.jobid, req->result.string());
            } else
                req->status = (FaxSendStatus) status;
        };
@@ -1616,7 +1617,7 @@ faxQueueApp::sendJobDone(Job& job, FaxRequest* req)
      * it does get rescheduled.
      */
     if (req->status != send_done && job.suspendPending) {
-       req->notice = "Job interrupted by user";
+       req->result = Status(344, "Job interrupted by user");
        req->status = send_retry;
     }
     if (job.killtime == 0 && !job.suspendPending && req->status == send_retry) {
@@ -1627,7 +1628,7 @@ faxQueueApp::sendJobDone(Job& job, FaxRequest* req)
         * notified of the requeue as well as the timeout?
         */
        timeoutAccounting(job, *req);
-       req->notice = "Kill time expired";
+       req->result = Status(325, "Kill time expired");
        updateRequest(*req, job);
        job.state = FaxRequest::state_failed;
        deleteRequest(job, req, Job::timedout, true);
@@ -1699,14 +1700,14 @@ faxQueueApp::sendJobDone(Job& job, FaxRequest* req)
            job.remove();                       // remove from active list
            if (req->tts > now) {
                traceQueue(job, "SEND INCOMPLETE: requeue for %s; %s",
-                   (const char*)strTime(req->tts - now), (const char*)req->notice);
+                   (const char*)strTime(req->tts - now), req->result.string());
                setSleep(job, req->tts);
                Trigger::post(Trigger::SEND_REQUEUE, job);
                if (req->isNotify(FaxRequest::when_requeued))
                    notifySender(job, Job::requeued);
            } else {
                traceQueue(job, "SEND INCOMPLETE: retry immediately; %s",
-                   (const char*)req->notice); 
+                   req->result.string());
                setReadyToRun(job, *req, jobCtrlWait);          // NB: job.tts will be <= now
            }
        } else                                  // signal waiting co-thread
@@ -1883,7 +1884,7 @@ faxQueueApp::setReady(Job& job, FaxRequest& req)
        /*
         * Since we skipped we know the job is blocked for now...
         */
-       blockJob(job, req, "Blocked by concurrent calls");
+       blockJob(job, req, Status(337, "Blocked by concurrent calls"));
     }
     /*
      * In order to deliberately batch jobs by using a common
@@ -2001,7 +2002,7 @@ faxQueueApp::submitJob(Job& job, FaxRequest& req, bool checkState)
        if (req.external == "")                 // NB: for notification logic
            req.external = req.number;
        rejectSubmission(job, req,
-           "REJECT: Unable to convert dial string to canonical format");
+           Status(327, "REJECT: Unable to convert dial string to canonical format"));
        return (false);
     }
     time_t now = Sys::now();
@@ -2019,17 +2020,16 @@ faxQueueApp::submitJob(Job& job, FaxRequest& req, bool checkState)
     }
     if (!Modem::modemExists(req.modem) && !ModemGroup::find(req.modem)) {
        rejectSubmission(job, req,
-           "REJECT: Requested modem " | req.modem | " is not registered");
+           Status(328, "REJECT: Requested modem %s is not registered", (const char*)req.modem));
        return (false);
     }
     if (req.items.length() == 0) {
-       rejectSubmission(job, req, "REJECT: No work found in job file");
+       rejectSubmission(job, req, Status(329, "REJECT: No work found in job file"));
        return (false);
     }
     if (req.pagewidth > 303) {
        rejectSubmission(job, req,
-           fxStr::format("REJECT: Page width (%u) appears invalid",
-               req.pagewidth));
+           Status(330, "REJECT: Page width (%u) appears invalid", req.pagewidth));
        return (false);
     }
     /*
@@ -2039,7 +2039,7 @@ faxQueueApp::submitJob(Job& job, FaxRequest& req, bool checkState)
      */
     if (req.killtime-now > 365*24*60*60) {     // XXX should be based on tts
        rejectSubmission(job, req,
-           fxStr::format("REJECT: Job expiration time (%u) appears invalid",
+           Status(331, "REJECT: Job expiration time (%u) appears invalid",
                req.killtime));
        return (false);
     }
@@ -2075,9 +2075,8 @@ faxQueueApp::submitJob(Job& job, FaxRequest& req, bool checkState)
         * Check time-to-send as for killtime above.
         */
        if (req.tts - now > 365*24*60*60) {
-           rejectSubmission(job, req,
-               fxStr::format("REJECT: Time-to-send (%u) appears invalid",
-                   req.tts));
+           rejectSubmission(job, req, Status(332,
+                   fxStr::format("REJECT: Time-to-send (%u) appears invalid", req.tts)));
            return (false);
        }
        job.startKillTimer(req.killtime);
@@ -2095,12 +2094,12 @@ faxQueueApp::submitJob(Job& job, FaxRequest& req, bool checkState)
  * Reject a job submission.
  */
 void
-faxQueueApp::rejectSubmission(Job& job, FaxRequest& req, const fxStr& reason)
+faxQueueApp::rejectSubmission(Job& job, FaxRequest& req, const Status& r)
 {
     Trigger::post(Trigger::JOB_REJECT, job);
     req.status = send_failed;
-    req.notice = reason;
-    traceServer("JOB %s: ", (const char*)job.jobid, (const char*)reason);
+    req.result = r;
+    traceServer("JOB %s: ", (const char*)job.jobid, r.string());
     deleteRequest(job, req, Job::rejected, true);
     setDead(job);                              // dispose of job
 }
@@ -2211,7 +2210,7 @@ faxQueueApp::terminateJob(const fxStr& jobid, JobStatus why)
        Trigger::post(Trigger::JOB_KILL, *job);
        FaxRequest* req = readRequest(*job);
        if (req) {
-           req->notice = "Job aborted by request";
+           req->result = Status(345, "Job aborted by request");
            deleteRequest(*job, req, why, why != Job::removed);
        }
        setDead(*job);
@@ -2224,12 +2223,12 @@ faxQueueApp::terminateJob(const fxStr& jobid, JobStatus why)
  * Reject a job at some time before it's handed off to the server thread.
  */
 void
-faxQueueApp::rejectJob(Job& job, FaxRequest& req, const fxStr& reason)
+faxQueueApp::rejectJob(Job& job, FaxRequest& req, const Status& r)
 {
     req.status = send_failed;
-    req.notice = reason;
+    req.result = r;
     traceServer("JOB %s: %s",
-           (const char*)job.jobid, (const char*)reason);
+           (const char*)job.jobid, r.string());
     job.state = FaxRequest::state_failed;
     Trigger::post(Trigger::JOB_REJECT, job);
     setDead(job);                              // dispose of job
@@ -2239,12 +2238,12 @@ faxQueueApp::rejectJob(Job& job, FaxRequest& req, const fxStr& reason)
  * Deal with a job that's blocked by a concurrent call.
  */
 void
-faxQueueApp::blockJob(Job& job, FaxRequest& req, const char* mesg)
+faxQueueApp::blockJob(Job& job, FaxRequest& req, const Status& r)
 {
     job.state = FaxRequest::state_blocked;
-    req.notice = mesg;
+    req.result = r;
     updateRequest(req, job);
-    traceQueue(job, "%s", mesg);
+    traceQueue(job, "%s", r.string());
     if (req.isNotify(FaxRequest::when_requeued))
        notifySender(job, Job::blocked); 
     Trigger::post(Trigger::JOB_BLOCKED, job);
@@ -2254,20 +2253,19 @@ faxQueueApp::blockJob(Job& job, FaxRequest& req, const char* mesg)
  * Requeue a job that's delayed for some reason.
  */
 void
-faxQueueApp::delayJob(Job& job, FaxRequest& req, const char* mesg, time_t tts)
+faxQueueApp::delayJob(Job& job, FaxRequest& req, const Status& r, time_t tts)
 {
     job.state = FaxRequest::state_sleeping;
-    fxStr reason(mesg);
     req.tts = tts;
     time_t delay = tts - Sys::now();
     // adjust kill time so job isn't removed before it runs
     job.stopKillTimer();
     req.killtime += delay;
     job.startKillTimer(req.killtime);
-    req.notice = reason;
+    req.result = r;
     updateRequest(req, job);
     traceQueue(job, "%s: requeue for %s",
-           (const char*)mesg, (const char*)strTime(delay));
+           r.string(), (const char*)strTime(delay));
     if (req.isNotify(FaxRequest::when_requeued))
        notifySender(job, Job::requeued); 
     Trigger::post(Trigger::JOB_DELAYED, job);
@@ -2331,7 +2329,7 @@ faxQueueApp::timeoutJob(Job& job)
        FaxRequest* req = readRequest(job);
        if (req) {
            timeoutAccounting(job, *req);
-           req->notice = "Kill time expired";
+           req->result = Status(325, "Kill time expired");
            deleteRequest(job, req, Job::timedout, true);
        }
        setDead(job);
@@ -2356,7 +2354,7 @@ faxQueueApp::timeoutJob(Job& job, FaxRequest& req)
     traceQueue(job, "KILL TIME EXPIRED");
     Trigger::post(Trigger::JOB_TIMEDOUT, job);
     timeoutAccounting(job, req);
-    req.notice = "Kill time expired";
+    req.result = Status(325, "Kill time expired");
     deleteRequest(job, req, Job::timedout, true);
     setDead(job);
 }
@@ -2424,8 +2422,8 @@ faxQueueApp::submitJob(const fxStr& jobid, bool checkState)
                Job job(req);
                job.state = FaxRequest::state_failed;
                req.status = send_failed;
-               req.notice = "Invalid or corrupted job description file";
-               traceServer("JOB %s : %s", (const char*)jobid, (const char*) req.notice);
+               req.result = Status(326, "Invalid or corrupted job description file");
+               traceServer("JOB %s : %s", (const char*)jobid, req.result.string());
                // NB: this may not work, but we try...
                deleteRequest(job, req, Job::rejected, true);
            } else if (req.state == FaxRequest::state_done ||
@@ -2481,16 +2479,15 @@ faxQueueApp::isJobSendOK (Job& job, FaxRequest* req)
      */
     u_short maxdials = fxmin((u_short) job.getJCI().getMaxDials(),req->maxdials);
     if (req->totdials >= maxdials) {
-       rejectJob(job, *req, fxStr::format(
-           "REJECT: Too many attempts to dial: %u, max %u",
-           req->totdials, maxdials));
+       rejectJob(job, *req, Status(333,
+               fxStr::format("REJECT: Too many attempts to dial: %u, max %u",
+           req->totdials, maxdials)));
        deleteRequest(job, req, Job::rejected, true);
        return false;
     }
     u_short maxtries = fxmin((u_short) job.getJCI().getMaxTries(),req->maxtries);
     if (req->tottries >= maxtries) {
-       rejectJob(job, *req, fxStr::format(
-           "REJECT: Too many attempts to transmit: %u, max %u",
+       rejectJob(job, *req, Status(334, "REJECT: Too many attempts to transmit: %u, max %u",
            req->tottries, maxtries));
        deleteRequest(job, req, Job::rejected, true);
        return false;
@@ -2498,8 +2495,7 @@ faxQueueApp::isJobSendOK (Job& job, FaxRequest* req)
     // NB: repeat this check so changes in max pages are applied
     u_int maxpages = job.getJCI().getMaxSendPages();
     if (req->totpages > maxpages) {
-       rejectJob(job, *req, fxStr::format(
-           "REJECT: Too many pages in submission: %u, max %u",
+       rejectJob(job, *req, Status(335, "REJECT: Too many pages in submission: %u, max %u",
            req->totpages, maxpages));
        deleteRequest(job, req, Job::rejected, true);
        return false;
@@ -2509,7 +2505,7 @@ faxQueueApp::isJobSendOK (Job& job, FaxRequest* req)
         * Calls to this destination are being rejected for
         * a specified reason that we return to the sender.
         */
-       rejectJob(job, *req, "REJECT: " | job.getJCI().getRejectNotice());
+       rejectJob(job, *req, Status(348, "REJECT: %s", (const char*) job.getJCI().getRejectNotice()));
        deleteRequest(job, req, Job::rejected, true);
        return false;
     }
@@ -2521,7 +2517,7 @@ faxQueueApp::isJobSendOK (Job& job, FaxRequest* req)
         * restrictions.  Reschedule it for the next possible time.
         */
        job.remove();                   // remove from run queue
-       delayJob(job, *req, "Delayed by time-of-day restrictions", tts);
+       delayJob(job, *req, Status(338, "Delayed by time-of-day restrictions"), tts);
        delete req;
        return false;
     }
@@ -2633,7 +2629,7 @@ faxQueueApp::runScheduler()
                 * be stay ready to run and go when one of the existing
                 * jobs terminates.
                 */
-               blockJob(job, *req, "Blocked by concurrent calls");
+               blockJob(job, *req, Status(337, "Blocked by concurrent calls"));
                delete req;
            } else if (assignModem(job))
            {
index fa448f820270b46492d13697678e8fe04c552d54..e0b90b927298a43389c43f1046111f894cca7bc9 100644 (file)
@@ -45,6 +45,7 @@ class UUCPLock;
 class FaxItem;
 class Modem;
 class Trigger;
+class Status;
 
 /*
  * This class represents a thread of control that manages the
@@ -210,12 +211,12 @@ private:
     void       processJob(Batch&, Job&, FaxRequest* req);
     void       sendJobDone(Job& job, FaxRequest* req);
     void       doneJob(Job& job);
-    void       blockJob(Job&, FaxRequest&, const char*);
-    void       delayJob(Job&, FaxRequest&, const char*, time_t);
-    void       rejectJob(Job& job, FaxRequest& req, const fxStr& reason);
+    void       blockJob(Job&, FaxRequest&, const Status&);
+    void       delayJob(Job&, FaxRequest&, const Status&, time_t);
+    void       rejectJob(Job& job, FaxRequest& req, const Status&);
     bool       submitJob(const fxStr& jobid, bool checkState = false);
     bool       suspendJob(const fxStr& jobid, bool abortActive);
-    void       rejectSubmission(Job&, FaxRequest&, const fxStr& reason);
+    void       rejectSubmission(Job&, FaxRequest&, const Status&);
 
     void       startBatch(Modem*, Job&, FaxRequest*, DestInfo&);
     void       fillBatch (Batch&);
@@ -254,13 +255,13 @@ private:
     JobStatus  convertDocument(Job&,
                    const FaxItem& input, const fxStr& outFile,
                    const Class2Params& params,
-                   fxStr& emsg);
+                   Status&);
     JobStatus  runConverter(Job& job, const char* app, char* const* argv,
-                   fxStr& emsg);
+                   Status&);
     bool       runConverter1(Job& job, int fd, fxStr& output);
     void       makeCoverPage(Job&, FaxRequest&, const Class2Params&);
     bool       preparePageHandling(Job&, FaxRequest&,
-                   const FaxMachineInfo&, fxStr& emsg);
+                   const FaxMachineInfo&, Status&);
     void       preparePageChop(const FaxRequest&,
                    TIFF*, const Class2Params&, fxStr&);
     void       setupParams(TIFF*, Class2Params&, const FaxMachineInfo&);
index cc5ada4ced584294a85f8698a5cdbc1b37bb14ca..136c7a9056c33ad244c112c26c8931e63376e2c5 100644 (file)
@@ -120,7 +120,7 @@ faxSendApp::send(const char** filenames, int num)
 {
     u_int batched = BATCH_FIRST;
     FaxSendStatus status = send_done;
-    fxStr batchcommid, notice;
+    fxStr batchcommid, errorcode;
     time_t retrybatchtts = 0;
 
     for (int i = 0; i < num; i++)
@@ -193,8 +193,7 @@ faxSendApp::send(const char** filenames, int num)
                    if (req->status == send_done)
                        ai.status = "";
                    else {
-                       notice = req->notice;
-                       ai.status = req->notice;
+                       ai.status = req->result.string();
                        retrybatchtts = req->tts;
                    }
                    if (!ai.record("SEND"))
index 6cc88d51a5edcfbec240e5495117ef7791c47afa..794224f366a4e77e12476b99338da010e4ba2457 100644 (file)
@@ -144,6 +144,7 @@ main()
     hash("csi");
     hash("nsf");
     hash("status");
+    hash("errorcode");
     hash("returned");
     hash("doneop");
     hash("commid");
index 48d5c3a181f41c69bf90539d402b9c7e33c42f70..870962d283bef31ebbc4e32df11b1bf39b4a6cde 100644 (file)
@@ -119,7 +119,7 @@ pageSendApp::send(const char** filenames, int num)
 {
     u_int batched = BATCH_FIRST;
     FaxSendStatus status = send_done;
-    fxStr batchcommid, notice;
+    fxStr batchcommid, notice, errorcode;
     time_t retrybatchtts = 0;
 
     for (int i = 0; i < num; i++) {
@@ -164,12 +164,12 @@ pageSendApp::send(const char** filenames, int num)
                            if (req->status == send_done)
                                ai.status = "";
                            else
-                               ai.status = req->notice;
+                               ai.status = req->result.string();
                            if (!ai.record("PAGE"))
                                logError("Error writing %s accounting record, dest=%s",
                                    "PAGE", (const char*) ai.dest);
                        } else
-                           sendFailed(*req, send_failed, "Job has no PIN to send to");
+                           sendFailed(*req, send_failed, Status(511, "Job has no PIN to send to"));
 
                        status = req->status;
                    } else {
@@ -188,16 +188,18 @@ pageSendApp::send(const char** filenames, int num)
                         * don't set the tts, allowing faxq to reschedule the job, expecting that
                         * to disassemble and "shuffle" the entire batch.
                         */
-                       if (notice == "No carrier detected" ||
-                           notice == "Busy signal detected" ||
-                           notice == "No answer from remote") {
-                           req->notice = notice;
-                           req->status = send_retry;
-                           req->tts = retrybatchtts;
-                           req->totdials++;
-                       } else {
-                           req->notice = "Blocked by another job";
-                           req->status = send_retry;
+                       switch (req->result.value())
+                       {
+                               case 1: // busy
+                               case 2: // no carrier
+                               case 3: // no answer
+                                       break;
+                                   req->status = send_retry;
+                                   req->tts = retrybatchtts;
+                                   req->totdials++;
+                               default:
+                                   req->status = send_retry;
+                                   req->result = Status(337, "Blocked by concurrent calls");
                        }
                    }
                    req->writeQFile();          // update on-disk copy
@@ -256,7 +258,7 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, u_int& batched)
            if (prepareMsg(req, info, msg))
               sendPage(req, info, prepareDialString(req.number), msg, batched);
         } else
-              sendFailed(req, send_retry, "Can not setup modem", 4*pollModemWait);
+              sendFailed(req, send_retry, Status(422, "Can not setup modem"), 4*pollModemWait);
 
         if ((batched & BATCH_LAST) || (req.status != send_done)) {
             discardModem(true);
@@ -265,7 +267,7 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, u_int& batched)
             endSession();
         } 
     } else {
-       sendFailed(req, send_retry, "Can not lock modem device",2*pollLockWait);
+       sendFailed(req, send_retry, Status(346, "Can not lock modem device") ,2*pollLockWait);
     }
 }
 
@@ -278,15 +280,15 @@ pageSendApp::prepareMsg(FaxRequest& req, FaxMachineInfo& info, fxStr& msg)
     int fd = Sys::open(req.items[i].item, O_RDONLY);
     if (fd < 0) {
        sendFailed(req, send_failed,
-           "Internal error: unable to open text message file");
+           Status(905, "Internal error: unable to open text message file"));
        return (false);
     }
     struct stat sb;
     (void) Sys::fstat(fd, sb);
     msg.resize((u_int) sb.st_size);
     if (Sys::read(fd, &msg[0], (u_int) sb.st_size) != sb.st_size) {
-       sendFailed(req, send_failed,
-           "Internal error: unable to read text message file");
+       sendFailed(req, send_failed, Status(906,
+           "Internal error: unable to read text message file"));
        return (false);
     }
     Sys::close(fd);
@@ -303,10 +305,10 @@ pageSendApp::prepareMsg(FaxRequest& req, FaxMachineInfo& info, fxStr& msg)
 }
 
 void
-pageSendApp::sendFailed(FaxRequest& req, FaxSendStatus stat, const char* notice, u_int tts)
+pageSendApp::sendFailed(FaxRequest& req, FaxSendStatus stat, const Status& result, u_int tts)
 {
     req.status = stat;
-    req.notice = notice;
+    req.result = result;
     /*
      * When requeued for the default interval (called with 3 args),
      * don't adjust the time-to-send field so that the spooler
@@ -315,7 +317,7 @@ pageSendApp::sendFailed(FaxRequest& req, FaxSendStatus stat, const char* notice,
      */
     if (tts != 0)
        req.tts = Sys::now() + tts;
-    traceServer("PAGE FAILED: %s", notice);
+    traceServer("PAGE FAILED: %s", result.string());
 }
 
 void
@@ -323,11 +325,10 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
 {
     connTime = 0;                              // indicate no connection
     if ((batched & BATCH_FIRST) && !getModem()->dataService()) {
-       sendFailed(req, send_failed, "Unable to configure modem for data use");
+       sendFailed(req, send_failed, Status(421, "Unable to configure modem for data use"));
        return;
     }
-    req.notice = "";
-    fxStr notice;
+    Status result;
     time_t pageStart = Sys::now();
     if (batched & BATCH_FIRST) {
         if (info.getPagerSetupCmds() != "")        // use values from info file
@@ -340,7 +341,7 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
     CallStatus callstat;
 
     if (batched & BATCH_FIRST)
-        callstat = getModem()->dial(number, notice);
+        callstat = getModem()->dial(number, result);
     else
         callstat = ClassModem::OK;
     if (callstat == ClassModem::OK)
@@ -357,12 +358,12 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
 
        // from this point on, the treatment of the two protocols differs
        if (streq(info.getPagingProtocol(), "ixo")) {
-           sendIxoPage(req, info, msg, notice, batched);
+           sendIxoPage(req, info, msg, result, batched);
        } else if (streq(info.getPagingProtocol(), "ucp")) {
-           sendUcpPage(req, info, msg, notice);
+           sendUcpPage(req, info, msg, result);
        } else {
-           notice = req.notice | "; paging protocol unknown ";
-           sendFailed(req, send_failed, notice);
+           result.append(999, "paging protocol unknown");
+           sendFailed(req, send_failed, result);
            req.status = send_failed;
        }
 
@@ -375,7 +376,7 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
            info.setSendFailures(0);
        } else {
            info.setSendFailures(info.getSendFailures()+1);
-           info.setLastSendFailure(req.notice);
+           info.setLastSendFailure(req.result.string());
        }
     } else if (!abortCall) {
        /*
@@ -398,7 +399,7 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
             * ``No Carrier'' and ``No Answer''.
             */
            if (!info.getCalledBefore() && req.ndials > retryMAX[callstat]) {
-               sendFailed(req, send_failed, notice);
+               sendFailed(req, send_failed, result);
                break;
            }
            /* fall thru... */
@@ -407,25 +408,27 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
        case ClassModem::FAILURE:       // modem returned something unexpected
        case ClassModem::BUSY:          // busy signal
        case ClassModem::NOANSWER:      // no answer or ring back
-           sendFailed(req, send_retry, notice, requeueTTS[callstat]);
+           sendFailed(req, send_retry, result, requeueTTS[callstat]);
            /* fall thru... */
        case ClassModem::OK:            // call was aborted by user
            break;
        }
        if (callstat != ClassModem::OK) {
            info.setDialFailures(info.getDialFailures()+1);
-           info.setLastDialFailure(req.notice);
+           info.setLastDialFailure(req.result.string());
        }
     }
     if (abortCall)
-       sendFailed(req, send_retry, "Call aborted by user");
+       sendFailed(req, send_retry, Status(345, "Call aborted by user"));
     else if (req.status == send_retry) {
        if (req.totdials == req.maxdials) {
-           notice = req.notice | "; too many attempts to dial";
-           sendFailed(req, send_failed, notice);
+           result = req.result;
+           result.append(333, "too many attempts to dial");
+           sendFailed(req, send_failed, result);
        } else if (req.tottries == req.maxtries) {
-           notice = req.notice | "; too many attempts to send";
-           sendFailed(req, send_failed, notice);
+           result = req.result;
+           result.append(334, "too many attempts to send");
+           sendFailed(req, send_failed, result);
        }
     }
 
@@ -460,11 +463,11 @@ pageSendApp::sendPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& number
  */
 void
 pageSendApp::sendIxoPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& msg,
-    fxStr& notice, u_int& batched)
+    Status& result, u_int& batched)
 {
        if (batched & BATCH_FIRST) {
-               if(!pagePrologue(req, info, notice)) {
-                       sendFailed(req, req.status, notice, requeueProto);
+               if(!pagePrologue(req, info, result)) {
+                       sendFailed(req, req.status, result, requeueProto);
                        return;
                }
        }
@@ -474,10 +477,10 @@ pageSendApp::sendIxoPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& msg
            if (i == fx_invalidArrayIndex)
                break;
            if (req.items[i].item.length() == 0) {
-               sendFailed(req, send_failed, "No PIN specified");
+               sendFailed(req, send_failed, Status(512, "No PIN specified"));
                break;
            }
-           if (!sendPagerMsg(req, req.items[i], msg, req.notice)) {
+           if (!sendPagerMsg(req, req.items[i], msg, req.result)) {
                /*
                 * On protocol errors retry more quickly
                 * (there's no reason to wait is there?).
@@ -492,7 +495,7 @@ pageSendApp::sendIxoPage(FaxRequest& req, FaxMachineInfo& info, const fxStr& msg
 
     if ((batched & BATCH_LAST)
             && req.status == send_ok) {
-        (void) pageEpilogue(req, info, notice);
+        (void) pageEpilogue(req, info, result);
     }
 }
 
@@ -537,7 +540,7 @@ scanForCode(const u_char*& cp, u_int& len)
 }
 
 bool
-pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& emsg)
+pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, Status& eresult)
 {
     fxStackBuffer buf;
     time_t start;
@@ -567,7 +570,7 @@ pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& em
            traceResponse(buf);
     } while (!gotID && (unsigned) Sys::now() - start < ixoIDTimeout);
     if (!gotID) {
-       emsg = "No initial ID response from paging central";
+       eresult = Status(500, "No initial ID response from paging central");
        req.status = send_retry;
        return (false);
     }
@@ -609,11 +612,11 @@ pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& em
            switch (cp[0]) {
            case ACK:                   // login successful, wait for go-ahead
                traceIXO("RECV ACK (login successful)");
-               return (pageGoAhead(req, info, emsg));
+               return (pageGoAhead(req, info, eresult));
            case NAK:                   // login failed, retry
                traceIXO("RECV NAK (login unsuccessful)");
                if (--ntries == 0) {
-                   emsg = "Login failed multiple times";
+                   eresult = Status(501, "Login failed multiple times");
                    req.status = send_retry;
                    return (false);
                }
@@ -636,8 +639,8 @@ pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& em
                if (len > 1) {
                    if (cp[1] == EOT) {
                        traceIXO("RECV EOT (forced disconnect)");
-                       emsg =
-                           "Paging central responded with forced disconnect";
+                       eresult = Status(510,
+                           "Paging central responded with forced disconnect");
                        req.status = send_failed;
                        return (false);
                    }
@@ -653,7 +656,7 @@ pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& em
                traceResponse(buf);
        }
     } while ((unsigned)Sys::now()-start < ixoLoginTimeout && --unknown != 0);
-    emsg = fxStr::format("Protocol failure: %s from paging central",
+    eresult = Status(502, "Protocol failure: %s from paging central",
        (unknown ?
            "timeout waiting for response" : "too many unknown responses"));
     req.status = send_retry;
@@ -661,7 +664,7 @@ pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& em
 }
 
 bool
-pageSendApp::pageGoAhead(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
+pageSendApp::pageGoAhead(FaxRequest& req, const FaxMachineInfo&, Status& eresult)
 {
     fxStackBuffer buf;
     time_t start = Sys::now();
@@ -678,7 +681,7 @@ pageSendApp::pageGoAhead(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
        }
        traceResponse(buf);
     } while ((unsigned) Sys::now()-start < ixoGATimeout && --unknown != 0);
-    emsg = fxStr::format("Protocol failure: %s waiting for go-ahead message",
+    eresult = Status(503, "Protocol failure: %s waiting for go-ahead message",
        unknown ? "timeout" : "too many unknown responses");
     req.status = send_retry;
     return (false);
@@ -702,7 +705,7 @@ addChecksum(fxStackBuffer& buf)
 }
 
 bool
-pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxStr& emsg)
+pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, Status& eresult)
 {
     /*
      * Build page packet:
@@ -750,8 +753,8 @@ pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxSt
                traceIXO("RECV NAK (message block rejected)");
                if (--ntries == 0) {
                    req.status = send_retry;
-                   emsg = "Message block not acknowledged by paging central "
-                       "after multiple tries";
+                   eresult = Status(504, "Message block not acknowledged by paging central "
+                       "after multiple tries");
                    return (false);
                }
                /*
@@ -780,15 +783,15 @@ pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxSt
                 * the right thing to do.
                 */
                req.status = send_failed;
-               emsg = "Message block transmit failed; "
-                   "paging central rejected it";
+               eresult = Status(505, "Message block transmit failed; "
+                   "paging central rejected it");
                return (false);
            case ESC:
                if (len > 1 && cp[1] == EOT) {
                    traceIXO("RECV EOT (forced disconnect)");
                    req.status = send_failed;
-                   emsg = "Protocol failure: paging central responded to "
-                       "message block transmit with forced disconnect";
+                   eresult = Status(506, "Protocol failure: paging central responded to "
+                       "message block transmit with forced disconnect");
                    return (false);
                }
                /* fall thru... */
@@ -800,7 +803,7 @@ pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxSt
                traceResponse(resp);
        }
     } while ((unsigned)Sys::now()-start < ixoXmitTimeout && unknown < ixoMaxUnknown);
-    emsg = fxStr::format("Protocol failure: %s to message block transmit",
+    eresult = Status(507, "Protocol failure: %s to message block transmit",
        (unknown ?
            "timeout waiting for response" : "too many unknown responses"));
     req.status = send_retry;
@@ -808,7 +811,7 @@ pageSendApp::sendPagerMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxSt
 }
 
 bool
-pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
+pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, Status& eresult)
 {
     putModem("\4\r", 2);               // EOT then <CR>
 
@@ -827,7 +830,7 @@ pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
                break;
            case RS:
                traceIXO("RECV RS (message content rejected)");
-               emsg = "Paging central rejected content; check PIN";
+               eresult = Status(508, "Paging central rejected content; check PIN");
                req.status = send_failed;
                return (false);
            }
@@ -837,8 +840,8 @@ pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
        // NB: ignore unknown responses
     } while ((unsigned)Sys::now() - start < ixoAckTimeout);
     req.status = send_retry;
-    emsg = "Protocol failure: timeout waiting for transaction ACK/NAK "
-       "from paging central";
+    eresult = Status(509, "Protocol failure: timeout waiting for transaction ACK/NAK "
+       "from paging central");
     return (false);
 }
 
@@ -904,7 +907,7 @@ pageSendApp::traceIXO(const char* fmt ...)
  */
 void
 pageSendApp::sendUcpPage(FaxRequest& req, FaxMachineInfo& info,
-    const fxStr& msg, fxStr& notice)
+    const fxStr& msg, Status& result)
 {
 
     while (req.items.length() > 0) {   // messages
@@ -912,10 +915,10 @@ pageSendApp::sendUcpPage(FaxRequest& req, FaxMachineInfo& info,
        if (i == fx_invalidArrayIndex)
            break;
        if (req.items[i].item.length() == 0) {
-           sendFailed(req, send_failed, "No PIN specified");
+           sendFailed(req, send_failed, Status(512, "No PIN specified"));
            break;
        }
-       if (!sendUcpMsg(req, req.items[i], msg, req.notice, info)) {
+       if (!sendUcpMsg(req, req.items[i], msg, req.result, info)) {
            /*
             * On protocol errors retry more quickly
             * (there's no reason to wait is there?).
@@ -928,7 +931,7 @@ pageSendApp::sendUcpPage(FaxRequest& req, FaxMachineInfo& info,
        req.items.remove(i);
     }
 //    if (req.status == send_ok) 
-//        (void) pageEpilogue(req, info, notice);
+//        (void) pageEpilogue(req, info, result);
 }
 // the (simplistic) UCP checksum algorithm
 static void
@@ -1112,7 +1115,7 @@ addUcpCodedMsg(fxStackBuffer& buf, const fxStr& msg)
 }
 
 bool
-pageSendApp::sendUcpMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxStr& emsg, FaxMachineInfo& info)
+pageSendApp::sendUcpMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, Status& eresult, FaxMachineInfo& info)
 {
     /*
      * Build page packet:
@@ -1206,8 +1209,8 @@ pageSendApp::sendUcpMsg(FaxRequest& req, FaxItem& preq, const fxStr& msg, fxStr&
                        traceIXO("RECV NACK (message block rejected)");
                        if(--ntries==0) {
                            req.status = send_retry;
-                           emsg="Message block not acknowledged by paging central"
-                             "after multiple tries";
+                           eresult=Status(504, "Message block not acknowledged by paging central"
+                             "after multiple tries");
                            return(false);
                        }
                        traceIXO("SEND message block (retransmit)");
index a8a74ae887e194e923202507ff4b7c5549eae2b4..0e52d8b78036867723516d3ea71ca0abd9046a76 100644 (file)
@@ -87,18 +87,19 @@ private:
     void       sendPage(FaxRequest&, FaxMachineInfo&, const fxStr&, 
                        const fxStr&, u_int&);  
 // IXO transmission support
-    void       sendIxoPage(FaxRequest&, FaxMachineInfo&, const fxStr&, fxStr&, u_int&);
-    bool       sendPagerMsg(FaxRequest&, FaxItem&, const fxStr&, fxStr&);
+    void       sendIxoPage(FaxRequest&, FaxMachineInfo&, const fxStr&, Status& result, u_int&);
+    bool       sendPagerMsg(FaxRequest&, FaxItem&, const fxStr&, Status& result);
     u_int      getResponse(fxStackBuffer& buf, long secs);
     bool       prepareMsg(FaxRequest&, FaxMachineInfo&, fxStr&);
-    bool       pagePrologue(FaxRequest&, const FaxMachineInfo&, fxStr&);
-    bool       pageGoAhead(FaxRequest&, const FaxMachineInfo&, fxStr&);
-    bool       pageEpilogue(FaxRequest&, const FaxMachineInfo&, fxStr&);
-    void       sendFailed(FaxRequest&, FaxSendStatus, const char*, u_int = 0);
+    bool       pagePrologue(FaxRequest&, const FaxMachineInfo&, Status& result);
+    bool       pageGoAhead(FaxRequest&, const FaxMachineInfo&, Status& result);
+    bool       pageEpilogue(FaxRequest&, const FaxMachineInfo&, Status& result);
+    void       sendFailed(FaxRequest&, FaxSendStatus, const Status&, u_int = 0);
     void       notifyPageSent(FaxRequest& req, u_int fi);
     time_t     getConnectTime() const;
 // UCP transmission support
-    void       sendUcpPage(FaxRequest&, FaxMachineInfo&, const fxStr&, fxStr&);    bool        sendUcpMsg(FaxRequest&, FaxItem&, const fxStr&, fxStr&,
+    void       sendUcpPage(FaxRequest&, FaxMachineInfo&, const fxStr&, Status& result);
+    bool       sendUcpMsg(FaxRequest&, FaxItem&, const fxStr&, Status& result,
                    FaxMachineInfo&);
 // modem handling
     bool       canLockModem();
index a3f0df503959fd2c3adbe048b45d57704c19a59d..a7dbd58395cac718dc2b5e111a1e049b7a8f8b00 100644 (file)
@@ -116,7 +116,7 @@ enum Token {
     T_MAXTRIES,         T_MINBR,       T_MODEM,        T_NDIALS,       T_NOTIFY,
     T_NOTIFYADDR,T_NPAGES,     T_NTRIES,       T_OWNER,        T_PAGECHOP,
     T_PAGELENGTH,T_PAGEWIDTH,  T_PASSWD,       T_POLL,         T_REGARDING,
-    T_RETRYTIME, T_SCHEDPRI,   T_SENDTIME,     T_STATE,        T_STATUS,
+    T_RETRYTIME, T_SCHEDPRI,   T_SENDTIME,     T_STATE,        T_STATUS,       T_STATUSCODE,
     T_SUBADDR,  T_TAGLINE,     T_TOTDIALS,     T_TOTPAGES,     T_TOTTRIES,
     T_TO_COMPANY,T_TO_LOCATION,        T_TO_USER,      T_TO_VOICE,     T_TSI,          T_USE_CONTCOVER,
     T_USE_ECM,  T_USE_TAGLINE, T_USE_XVRES,    T_USRKEY,       T_VRES,
index 57b04aa4f1a1ce78e9d9163ec937a887e0c76b5a..b35478c1ec6b629556db7dfe7f79c7545d09a25e 100644 (file)
@@ -146,7 +146,8 @@ static const struct {
     { T_SCHEDPRI,      A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH },
     { T_SENDTIME,      A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_STATE,         A_RUSR|A_RADM|A_ROTH },
-    { T_STATUS,                A_RUSR|A_RADM|A_WADM|A_ROTH },
+    { T_STATUS,                A_RUSR|A_RADM|A_ROTH },
+    { T_STATUSCODE,    A_RUSR|A_RADM|A_ROTH },
     { T_SUBADDR,       A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_TAGLINE,       A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_TOTDIALS,      A_RUSR|A_RADM|A_ROTH },
@@ -227,7 +228,6 @@ static struct {
     { T_JOBID,         &Job::jobid },
     { T_JOBINFO,       &Job::jobtag },
     { T_OWNER,         &Job::owner },
-    { T_STATUS,                &Job::notice },
     { T_DONEOP,                &Job::doneop },
     { T_COMMID,                &Job::commid },
     { T_REGARDING,     &Job::regarding },
@@ -480,6 +480,12 @@ HylaFAXServer::replyJobParamValue(Job& job, int code, Token t)
        }
        reply(code, "End of polling items.");
        return;
+    case T_STATUSCODE:
+       reply(code, "%03d", job.result.value());
+       return;
+    case T_STATUS:
+       reply(code, "%s", job.result.string());
+       return;
     default:
        break;
     }
@@ -558,6 +564,10 @@ HylaFAXServer::jstatCmd(const Job& job)
        jstatLine(T_USE_XVRES,"%s", boolString(job.usexvres));
     if (checkAccess(job, T_USE_CONTCOVER, A_READ))
        jstatLine(T_USE_CONTCOVER,"%s", boolString(job.useccover));
+    if (checkAccess(job, T_STATUSCODE, A_READ))
+       jstatLine(T_STATUSCODE,"%03d", job.result.value());
+    if (checkAccess(job, T_STATUS, A_READ))
+       jstatLine(T_STATUS, "%s", job.result.string());
     u_int i, n;
     for (i = 0, n = N(strvals); i < n; i++)
        if (checkAccess(job, strvals[i].t, A_READ))
@@ -1911,7 +1921,7 @@ HylaFAXServer::Jprintf(FILE* fd, const char* fmt, const Job& job)
                fprintf(fd, fspec, job.resolution);
                break;
            case 's':
-               fprintf(fd, fspec, (const char*) job.notice);
+               fprintf(fd, fspec, job.result.string());
                break;
            case 't':
                fprintf(fd, fspec, job.tottries);
index b6c0df4caf01d15fef466431dc361b95215beb56..5876a607321934922d24730573fab07fe86e6a39 100644 (file)
@@ -162,7 +162,8 @@ static const tab parmtab[] = {
 { "SCHEDPRI",     T_SCHEDPRI,    false, true, "[<number>]" },
 { "SENDTIME",     T_SENDTIME,    false, true, "[NOW|YYYYMMDDHHSS]" },
 { "STATE",        T_STATE,       false, true, "(job state)" },
-{ "STATUS",       T_STATUS,       false, true, "[<string>" },
+{ "STATUS",       T_STATUS,       false, true, "[string]" },
+{ "STATUSCODE",   T_STATUSCODE,   false, true, "[code]" },
 { "SUBADDR",      T_SUBADDR,     false, true, "[<string>]" },
 { "TAGLINE",      T_TAGLINE,     false, true, "[<string>]" },
 { "TOCOMPANY",    T_TO_COMPANY,          false, true, "[<string>]" },
@@ -1113,6 +1114,7 @@ HylaFAXServer::param_cmd(Token t)
     case T_OWNER:
     case T_STATE:
     case T_STATUS:
+    case T_STATUSCODE:
     case T_DONEOP:
     case T_COMMID:
     case T_REGARDING:
index 807fe4323e325f0b2c8fdf024c9203e16ad1b812..003f5951ebbb32b36f87f281c3431fef5ea14845 100644 (file)
@@ -86,6 +86,7 @@ desiredec     integer desired use of Error Correction Mode (\s-1ECM\s+1)
 desiredst      integer desired minimum scanline time
 desiredtl      integer whether or not to use \fBtagline\fP parameter
 doneop string  operation to perform when job is reaped
+errorcode      string  job status error code
 external       string  external form of dialstring
 fax    string  document ready for transmission
 faxnumber      string  faxnumber to use sending
@@ -252,6 +253,10 @@ Consult
 .I faxqclean
 more details on other information that may be included in this string.
 .TP 14
+.B errorcode
+The codified form of the status message intended for use by clients
+which provide customized status messages keyed from this standard index.
+.TP 14
 .B external
 The external form of the dialstring.
 This string is used instead of the dialstring in any status
index 11b11c5316542be1bbddcb7e8a9390e95be460c6..51dbfd266d19541af20aca7b03023b32437c40da 100644 (file)
@@ -82,6 +82,7 @@ C++FILES=Array.c++ \
        ModemExt.c++ \
        SendFaxJob.c++ \
        SendFaxClient.c++ \
+       Status.c++ \
        TypeRules.c++ \
        Transport.c++ \
        InetTransport.c++ \
index 684128aab4e6ea498499abd7836f00f3b7663a11..b90184542c5724f4d849f88e1fa54b536ed4b8d1 100644 (file)
@@ -35,6 +35,7 @@
 #include <sys/file.h>
 #include <errno.h>
 
+
 const fxStr Sequence::format("%09u");
 
 u_long Sequence::getNext(const char* name, fxStr& emsg)
diff --git a/util/Status.c++ b/util/Status.c++
new file mode 100644 (file)
index 0000000..cddb010
--- /dev/null
@@ -0,0 +1,71 @@
+/*     $Id$ */
+/*
+ * Copyright (c) 2007 iFAX Solutions, Inc.
+ * HylaFAX is a trademark of Silicon Graphics
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+#include "Status.h"
+
+Status::Status (void)
+  :  id(0)
+{
+}
+
+Status::Status (int code, const char* fmt, ...)
+ : id(code)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    message = fxStr::vformat(fmt, ap);
+    va_end(ap);
+}
+
+void Status::clear (void)
+{
+    id = 0;
+    message = fxStr::null;
+}
+
+const char* Status::string (void) const
+{
+    return message;
+}
+
+int Status::value (void) const
+{
+    return id;
+}
+
+void Status::append (int code, const char* fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    message.append("; ");
+    message.append(fxStr::vformat(fmt, ap));
+    va_end(ap);
+    /*
+     * The last error code is always the "final" one
+     */
+    id = code;
+}
diff --git a/util/Status.h b/util/Status.h
new file mode 100644 (file)
index 0000000..2055a84
--- /dev/null
@@ -0,0 +1,49 @@
+/*     $Id$ */
+/*
+ * Copyright (c) 2007 iFAX Solutions, Inc.
+ * HylaFAX is a trademark of Silicon Graphics
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#ifndef _Status_
+#define        _Status_
+
+#include "Str.h"
+
+class Status
+{
+public:
+       Status (void);
+       Status (int code, const char* fmt, ...);
+
+       const char* string (void) const;
+       int value (void) const;
+
+       void append (int code, const char* fmt, ...);
+
+       void clear (void);
+private:
+       fxStr message;
+       int id;
+};
+
+
+
+#endif