}
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 {
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
};
}
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
}
}
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);
}
abortReceive();
return (false);
}
- fxStr emsg;
+ Status eresult;
do {
if (crpcnt || rhcnt) {
if (rhcnt) crpcnt = 0;
* 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;
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(
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();
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);
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);
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);
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)
#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;
0, fxStr::null,
FCF_CIG, cig,
FCF_DTC, dtc,
- conf.t1Timer, false, emsg);
+ conf.t1Timer, false, eresult);
}
* 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.
if (flowControl == FLOW_XONXOFF)
setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_FLUSH);
- return ClassModem::answerCall(type, emsg, number);
+ return ClassModem::answerCall(type, eresult, number);
}
/*
* Begin the receive protocol.
*/
bool
-Class1Modem::recvBegin(fxStr& emsg)
+Class1Modem::recvBegin(Status& eresult)
{
setInputBuffering(false);
prevPage = 0; // no previous page received
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.
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);
}
/*
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
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:
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)) {
}
}
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
}
}
if (gotEOT) {
- emsg = "RSPREC error/got EOT";
+ eresult = Status(106, "RSPREC error/got EOT");
return (false);
}
/*
* 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);
}
}
* 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
* 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) {
/*
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);
}
}
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 {
* 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);
}
/*
* receive the Phase C data.
*/
protoTrace("RECV: begin page");
- pageGood = recvPageData(tif, emsg);
+ pageGood = recvPageData(tif, eresult);
protoTrace("RECV: end page");
if (!wasTimeout()) {
/*
*/
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);
}
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:
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 {
// 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
* 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
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);
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;
}
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
* 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 {
* to implement than using +FRH and more reliable than
* using +FTS
*/
- if (!switchingPause(emsg)) {
+ if (!switchingPause(eresult)) {
return (false);
}
signalRcvd = 0;
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);
return (false);
default:
if (!pageGood) recvResetPage(tif);
- emsg = "COMREC invalid response received";
+ eresult = Status(110, "COMREC invalid response received");
return (false);
}
t2end = 0;
}
}
} 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");
}
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);
}
/*
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;
* 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
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);
// 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();
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);
}
if (signalRcvd) lastblock = true;
sendERR = true;
} else {
- if (!useV34 && !switchingPause(emsg)) {
+ if (!useV34 && !switchingPause(eresult)) {
abortPageECMRecv(tif, params, block, fcount, seq, pagedataseen);
return (false);
}
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);
}
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);
}
}
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);
}
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;
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);
}
}
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);
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();
}
}
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);
}
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);
}
}
// 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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
}
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);
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);
}
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);
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) {
}
}
} 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);
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);
}
// 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...
* 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.
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);
* 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
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;
recvdDCN = true;
break;
default:
- if (!useV34) (void) switchingPause(emsg);
+ if (!useV34) (void) switchingPause(eresult);
transmitFrame(FCF_DCN|FCF_RCVR);
recvdDCN = true;
break;
* 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.
/*
* 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"
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);
}
* 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;
* 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();
// 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);
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);
}
}
*/
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);
}
};
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
*/
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
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;
}
* 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);
* "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);
}
}
*/
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
/*
* 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);
* 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);
}
}
/*
* 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);
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) {
}
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 ){
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);
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);
* 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);
}
* 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);
}
curcap = NULL;
}
}
- return (sendTraining(params, --tries, emsg));
+ return (sendTraining(params, --tries, eresult));
default:
if (frame.getFCF() == FCF_DCN) {
/*
* 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 {
* 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);
}
}
}
} 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);
* 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
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);
}
/*
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 {
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);
}
/*
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) {
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;
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()) {
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);
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
*/
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;
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) {
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;
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()) {
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;
}
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);
* 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
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);
// 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);
* 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);
* 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) {
/*
//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
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());
}
* 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
*/
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
* 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;
* 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 {
* 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
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);
}
* 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);
}
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);
}
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);
}
* 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]))
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.
*/
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
// 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();
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
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)
* 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);
* 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);
* Begin a fax receive session.
*/
bool
-Class2Modem::recvBegin(fxStr& emsg)
+Class2Modem::recvBegin(Status& eresult)
{
bool status = false;
hangupCode[0] = '\0';
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
}
} while (r != AT_OK);
if (!status)
- emsg = hangupCause(hangupCode);
+ eresult = hangupStatus(hangupCode);
return (status);
}
* Begin a fax receive session after EOM.
*/
bool
-Class2Modem::recvEOMBegin(fxStr& emsg)
+Class2Modem::recvEOMBegin(Status&)
{
/*
* There's nothing to do because the modem
* 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;
* don't understand the FillOrder tag!
*/
recvSetupTIFF(tif, group3opts, FILLORDER_LSB2MSB, id);
- if (!recvPageData(tif, emsg)) {
+ if (!recvPageData(tif, eresult)) {
prevPage = false;
goto bad;
}
*/
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
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");
* 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);
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)
* Complete a receive session.
*/
bool
-Class2Modem::recvEnd(fxStr&)
+Class2Modem::recvEnd(Status&)
{
if (!hadHangup) {
if (isNormalHangup()) {
*/
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)";
* 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;
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);
}
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 (???)
* 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;
processHangup("20"); // Unspecified Phase B error
/* fall thru... */
case AT_FHNG:
- emsg = hangupCause(hangupCode);
+ eresult = hangupStatus(hangupCode);
return (send_retry);
}
}
*/
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;
*/
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;
* 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)) {
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) {
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--;
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 {
* 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);
}
* 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);
}
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) {
* 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:
/*
* 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
}
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);
}
* Deduce connection kind: fax, data, or voice.
*/
CallType
-ClassModem::answerResponse(fxStr& emsg)
+ClassModem::answerResponse(Status& eresult)
{
CallStatus cs = FAILURE;
ATResponse r;
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;
/*
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) {
/*
#include <stdarg.h>
#include "Str.h"
#include "CallID.h"
+#include "Status.h"
class ModemServer;
class ModemConfig;
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&);
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, ...);
/*
* 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;
* 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; }
*/
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
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) {
* 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;
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);
* 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)) {
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);
}
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);
}
bool getHDLCTracing();
bool getECMTracing();
FaxSendStatus sendSetupParams(TIFF*, Class2Params&,
- FaxMachineInfo&, fxStr&);
+ FaxMachineInfo&, Status&);
void recvTSI(const fxStr&);
void recvPWD(const fxStr&);
void recvSUB(const fxStr&);
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);
* 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
* }
*/
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;
*
* (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_ */
* 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);
* 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);
}
*/
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;
* 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.
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.
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);
* 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
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);
}
* 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
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);
}
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
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);
* 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++) {
}
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();
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);
#include <ctype.h>
#include <errno.h>
+
/*
* HylaFAX job request file handling.
*/
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
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:
/*
"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;
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] != '\\') {
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]);
#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
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
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; }
}
} 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);
}
}
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
*/
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()
);
}
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
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;
}
/*
* 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)
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>");
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);
/*
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) {
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)) {
{
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];
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) {
/*
*/
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;
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 {
}
}
} 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);
* 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
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;
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;
*/
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);
}
} 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;
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;
}
} 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;
(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);
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);
(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);
"<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);
}
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());
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);
}
#include "ModemServer.h"
#include "FaxRecvInfo.h"
#include "Array.h"
+#include "FaxRequest.h"
class FaxAcctInfo;
// 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);
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;
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);
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(); }
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();
--- /dev/null
+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
*/
bool callResolved;
bool advanceRotary = true;
- fxStr emsg;
+ Status eresult;
fxStr callid_formatted = "";
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;
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();
/*
* 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 {
* 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) {
/*
*/
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 {
* 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
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"))
* 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) {
* 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);
}
* 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;
);
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");
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);
const char* what,
Getty* (*newgetty)(const fxStr&, const fxStr&),
const char* args,
- fxStr& emsg,
+ Status& eresult,
bool keepLock,
const CallID& callid,
bool keepModem
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);
}
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);
}
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
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);
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
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;
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++)
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;
/*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);
(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);
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
* 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;
}
*/
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
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);
* 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);
const FaxItem& req,
const fxStr& outFile,
const Class2Params& params,
- fxStr& emsg)
+ Status& result)
{
JobStatus status;
/*
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
* 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?
/*
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
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);
* 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++)
/*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)
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);
);
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 {
{
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;
};
* 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) {
* 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);
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
/*
* 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
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();
}
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);
}
/*
*/
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);
}
* 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);
* 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
}
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);
* 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
* 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);
* 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);
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);
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);
}
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 ||
*/
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;
// 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;
* 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;
}
* 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;
}
* 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))
{
class FaxItem;
class Modem;
class Trigger;
+class Status;
/*
* This class represents a thread of control that manages the
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&);
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&);
{
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++)
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"))
hash("csi");
hash("nsf");
hash("status");
+ hash("errorcode");
hash("returned");
hash("doneop");
hash("commid");
{
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++) {
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 {
* 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
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);
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);
}
}
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);
}
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
*/
if (tts != 0)
req.tts = Sys::now() + tts;
- traceServer("PAGE FAILED: %s", notice);
+ traceServer("PAGE FAILED: %s", result.string());
}
void
{
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
CallStatus callstat;
if (batched & BATCH_FIRST)
- callstat = getModem()->dial(number, notice);
+ callstat = getModem()->dial(number, result);
else
callstat = ClassModem::OK;
if (callstat == ClassModem::OK)
// 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;
}
info.setSendFailures(0);
} else {
info.setSendFailures(info.getSendFailures()+1);
- info.setLastSendFailure(req.notice);
+ info.setLastSendFailure(req.result.string());
}
} else if (!abortCall) {
/*
* ``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... */
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);
}
}
*/
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;
}
}
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?).
if ((batched & BATCH_LAST)
&& req.status == send_ok) {
- (void) pageEpilogue(req, info, notice);
+ (void) pageEpilogue(req, info, result);
}
}
}
bool
-pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, fxStr& emsg)
+pageSendApp::pagePrologue(FaxRequest& req, const FaxMachineInfo& info, Status& eresult)
{
fxStackBuffer buf;
time_t start;
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);
}
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);
}
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);
}
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;
}
bool
-pageSendApp::pageGoAhead(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
+pageSendApp::pageGoAhead(FaxRequest& req, const FaxMachineInfo&, Status& eresult)
{
fxStackBuffer buf;
time_t start = Sys::now();
}
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);
}
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:
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);
}
/*
* 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... */
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;
}
bool
-pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, fxStr& emsg)
+pageSendApp::pageEpilogue(FaxRequest& req, const FaxMachineInfo&, Status& eresult)
{
putModem("\4\r", 2); // EOT then <CR>
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);
}
// 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);
}
*/
void
pageSendApp::sendUcpPage(FaxRequest& req, FaxMachineInfo& info,
- const fxStr& msg, fxStr& notice)
+ const fxStr& msg, Status& result)
{
while (req.items.length() > 0) { // messages
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?).
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
}
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:
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)");
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();
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,
{ 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 },
{ 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 },
}
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;
}
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))
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);
{ "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>]" },
case T_OWNER:
case T_STATE:
case T_STATUS:
+ case T_STATUSCODE:
case T_DONEOP:
case T_COMMID:
case T_REGARDING:
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
.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
ModemExt.c++ \
SendFaxJob.c++ \
SendFaxClient.c++ \
+ Status.c++ \
TypeRules.c++ \
Transport.c++ \
InetTransport.c++ \
#include <sys/file.h>
#include <errno.h>
+
const fxStr Sequence::format("%09u");
u_long Sequence::getNext(const char* name, fxStr& emsg)
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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