diff -r 000000000000 -r 3553901f7fa8 fax/faxclientandserver/FAXSVR/CFAX2.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fax/faxclientandserver/FAXSVR/CFAX2.CPP Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,609 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "FAXSERV.H" +#include "fax_reversebytes.h" +#include "FAXMODEM.H" +#include "FAXMDRV.H" + +#include "FAXLOG.H" + + +const TInt KClass2HangupStatusTimer=20; // < Time used to wait for final +FHNG: report. + +// this module has three parts +// first receive routines rx +// second transmit routines tx +// third utilities + +/********************************************************************/ + +CFaxModemDriver *CFaxClass2::NewLC (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress) +{ + CFaxModemDriver *self = new (ELeave) CFaxClass2; + CleanupStack::PushL (self); + self->ConstructL (aFaxServerSessionSettings, aProgress); + return self; +} + +CFaxModemDriver *CFaxClass2::NewL (TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress) +{ + CFaxModemDriver *self = NewLC (aFaxServerSessionSettings, aProgress); + CleanupStack::Pop (); + return self; +} +/********************************************************************/ + +TInt CFaxClass2::RxConnectL () +{ + __FLOG_FAXSRV( _L8("CFaxClass2::RxConnectL entering")); + + CheckCadenceExportL (_L8 ("AT+FDCC=?\r")); + if (!(iModem->ImportL (iResults, 35))) + return (KFaxErrModemNotWorking); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + ParseResults (iResults); + + iModem->GetMatchL (_L8 ("OK"), 2); + + if (iFaxServerSessionSettings->iRxResolution == EFaxNormal) + iModem->iProgress.iResolution = EFaxNormal; + else + iModem->iProgress.iResolution = EFaxFine; + + if (iFaxServerSessionSettings->iRxCompression == EModifiedRead) + iModem->iProgress.iCompression = EModifiedRead; + else + iModem->iProgress.iCompression = EModifiedHuffman; + iActualFaxSpeed = iModem->iProgress.iSpeed; + if (iActualFaxSpeed > iFaxServerSessionSettings->iMaxSpeed) + iActualFaxSpeed = iFaxServerSessionSettings->iMaxSpeed; + + iResults.Copy (_L8 ("AT+FDCC=0,0,0,2,0,0,0,0\r")); + + iResults[8] = (TUint8) (iResults[8] + iModem->iProgress.iResolution); + iResults[10] = (TUint8) (((iActualFaxSpeed / 2400) - 1) + '0'); + iResults[16] = (TUint8) (iResults[16] + iModem->iProgress.iCompression); + CheckCadenceExportL (iResults); + if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) + return (KFaxErrModemNotWorking); + CheckCadenceExportL (_L8 ("AT+FAA=0\r")); + if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0) + return (KFaxErrNoReceiveMode); + + TBuf8 narrowBuf; + narrowBuf.Copy(iFaxServerSessionSettings->iFaxId); + + //-- By Dmitry Lyokhin. concerns PIA-58ELQK defect. + if( narrowBuf.Length() < 1 ) narrowBuf.Append(' '); + + + if (iFaxServerSessionSettings->iMode & KFaxPoll) + { + iModem->ExportL (_L8 ("AT+FSPL=1\r")); + if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0) + return (KFaxPollingUnsupported); + iModem->ExportL (_L8 ("AT+FCIG=\"")); + iModem->ExportL (narrowBuf); + iModem->ExportL (_L8 ("\"\r")); + if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) + return (KFaxPollingUnsupported); + } + else + { + CheckCadenceExportL (_L8 ("AT+FCR=1\r")); + if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0) + return (KFaxErrNoReceiveMode); + CheckCadenceExportL (_L8 ("AT+FLID=\"")); + iModem->ExportL (narrowBuf); + iModem->ExportL (_L8 ("\"\r")); + if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) + return (KFaxErrModemNotWorking); + } + + if (iFaxServerSessionSettings->iMode & KFaxWaitForRing) + { +// while ((iModem->GetMatchL (_L8 ("RING"), 3)) == 0); +// iTimeOfLastRing.UniversalTime(); + } + else + { + if ((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) + DialFaxOnDemandL (); + } + + if ((iFaxServerSessionSettings->iMode & KFaxPoll) == 0) + { + iModem->Silence (CLK_TCK); + CheckCadenceExportL (_L8 ("ATA\r")); + } + + iModem->iProgress.iPhase = ECallEstablishment; + + TInt pollDocsAvailable = 0; + + for (;;) + { + if (!(iModem->ImportL (iResults, 35))) + return (KFaxErrCannotAnswer); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + + if ((iResults.FindF (_L8 ("NO DIALTONE"))) >= 0 || + iResults.FindF (_L8 ("NO DIAL TONE")) >= 0) + return (KFaxErrNoDialTone); + if ((iResults.FindF (_L8 ("BUSY"))) >= 0) + return (KFaxErrBusy); + if ((iResults.FindF (_L8 ("NO ANSWER"))) >= 0) + return (KFaxErrNoAnswer); + if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0) + return (KFaxErrNoCarrier); + if ((iResults.FindF (_L8 ("OK"))) >= 0) + break; + if ((iResults.FindF (_L8 ("FHNG"))) >= 0) + return (KFaxErrPrematureHangup); + if ((iResults.FindF (_L8 ("FCON"))) >= 0) + iModem->iProgress.iPhase = ESessionNegotiation; + else if ((iResults.FindF (_L8 ("FPOLL"))) >= 0) + pollDocsAvailable = 1; + else if ((iResults.FindF (_L8 ("FTSI"))) >= 0) + ExtractAnswerback (iResults); + else if ((iResults.FindF (_L8 ("FDCS"))) >= 0) + ParseResults (iResults); + } + + if ((iFaxServerSessionSettings->iMode & KFaxPoll) && (pollDocsAvailable == 0)) + return (KFaxNothingToPoll); + + iModem->iOurMessage.Format (_L8 ("about to receive fax")); + iModem->ProgressUpdateL (); + return (RxPrePageL ()); +} + +/********************************************************************/ +TInt CFaxClass2::RxPrePageL () +{ + __FLOG_FAXSRV( _L8("CFaxClass2::RxPrePageL entering")); + + iModem->ExportL (_L8 ("AT+FDR\r")); + for (;;) + { + if (!(iModem->ImportL (iResults, 35))) + return (KFaxErrCannotConnect); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + + if ((iResults.FindF (_L8 ("ERROR"))) >= 0) + return (KFaxErrNoReceiveMode); + if ((iResults.FindF (_L8 ("FHNG"))) >= 0) + return (KFaxErrPrematureHangup); + if ((iResults.FindF (_L8 ("CONNECT"))) >= 0) + break; + if ((iResults.FindF (_L8 ("FDCS"))) >= 0) + ParseResults (iResults); + } + + iModem->TxcharL (Kdc2); + return (RxStartPageL ()); +} +/********************************************************************/ +TInt CFaxClass2::RxPostPageL () +{ + __FLOG_FAXSRV(_L8("CFaxClass2::RxPostPageL entering")); + + iModem->iProgress.iPhase = EPostPageStatus; + iModem->ProgressUpdateL (); + for (;;) + { + if (!(iModem->ImportL (iResults, 20))) + return (KFaxErrModemResponse); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + + if ((iResults.FindF (_L8 ("OK"))) >= 0) + return (KFaxErrPrematureOK); + if ((iResults.FindF (_L8 ("FHNG"))) >= 0) + return (KFaxErrPrematureHangup); + if ((iResults.FindF (_L8 ("FET"))) >= 0) + break; + } + if (iModem->GetMatchL (_L8 ("OK"), 5) == 0) + return (KFaxErrNoFinalOK); + + if ((iResults.FindF (_L8 ("0"))) >= 0) + { + iModem->iOurMessage.Format (_L8 ("page %u successfully received"), iModem->iProgress.iPage); + iModem->ProgressUpdateL (); + return (RxPrePageL ()); + } + if ((iResults.FindF (_L8 ("1"))) >= 0) + { + iModem->iOurMessage.Format (_L8 ("page %u successfully received : end of document"), iModem->iProgress.iPage); + iModem->ProgressUpdateL (); + iModem->iOurMessage.Format (_L8 ("Next fax awaited")); + iModem->ProgressUpdateL (); + return (RxPrePageL ()); + } + if ((iResults.FindF (_L8 ("2"))) >= 0) + { + iModem->iOurMessage.Format (_L8 ("Final page %u successfully received"), iModem->iProgress.iPage); + iModem->ProgressUpdateL (); + iModem->iProgress.iPhase = EDisconnection; + iModem->ExportL (_L8 ("AT+FDR\r")); + if (iModem->GetMatchL (_L8 ("FHNG"), KClass2HangupStatusTimer) == 0) + return (KFaxErrNoHangup); + if (iModem->GetMatchL (_L8 ("OK"), 5) == 0) + return (KFaxErrNoFinalOK); + return (KErrNone); + } + return (KFaxErrUnknownPageCode); +} +/********************************************************************/ + +TInt CFaxClass2::TxConnectL () +{ + // we always use direct bit order when sending + // we always use reversed bit order when receiving + // this is in accordance with the rockwell bug. + // if a modem doesn't have the rockwell bug then + // the fax init string AT+FBOR=1 will force the + // use of reversed bit ordering on reception. + // since we have here a hardwired default AT+FBOR=0 + // on transmission this will override the init string + // which will therefore only be used (as needed) for + // reception, and everything will work again + + __FLOG_FAXSRV( _L8("CFaxClass2::TxConnectL entering")); + + iModem->ExportL (_L8 ("AT+FBOR=0\r")); + iModem->GetMatchL (_L8 ("OK"), 3); + + TBuf8 narrowBuf; + narrowBuf.Copy(iFaxServerSessionSettings->iFaxId); + + //-- if the fax local id string is empty, insert blank + //-- PIA-58ELQK defect fix by Dmitry Lyokhin 26.03.2001 + if( narrowBuf.Length() < 1 ) narrowBuf.Append(' '); + + + iModem->ExportL (_L8 ("AT+FLID=\"")); + iModem->ExportL (narrowBuf); + iModem->ExportL (_L8 ("\"\r")); + if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) + return (KFaxErrModemNotWorking); + + iModem->ExportL (_L8 ("AT+FDCC=?\r")); + if (!(iModem->ImportL (iResults, 35))) + return (KFaxErrModemNotWorking); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + ParseResults (iResults); + + iModem->GetMatchL (_L8 ("OK"), 2); + + iActualFaxSpeed = iModem->iProgress.iSpeed; + if (iActualFaxSpeed > iFaxServerSessionSettings->iMaxSpeed) + iActualFaxSpeed = iFaxServerSessionSettings->iMaxSpeed; + + iResults.Copy (_L8 ("AT+FDCC=0,0,0,2,0,0,0,0\r")); + + iResults[8] = (TUint8) (iResults[8] + iFaxServerSessionSettings->iTxResolution); + iResults[10] = (TUint8) (((iActualFaxSpeed / 2400) - 1) + '0'); + + + // added to support 2Dfaxing using class 2 + if (iModem->iProgress.iCompression==EModifiedRead) + iResults[16] = (TUint8) (iResults[16] + iFaxServerSessionSettings->iTxCompression); + else + iResults[16] = (TUint8) (iResults[16] + EModifiedHuffman); + + iModem->ExportL (iResults); + if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0) + return (KFaxErrModemNotWorking); + + iModem->ExportL (_L8 ("ATD")); + if ((iFaxServerSessionSettings->iMode & KFaxOffHook) == 0) + iModem->ExportL (iFaxServerSessionSettings->iPhoneNumber); + iModem->TxcharL (Kreturn); + + iModem->iProgress.iPhase = ECallEstablishment; + for (;;) + { + if (!(iModem->ImportL (iResults, KDialTimeout))) + return (KFaxErrNoDial); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + + if ((iResults.FindF (_L8 ("NO DIALTONE"))) >= 0 || + iResults.FindF (_L8 ("NO DIAL TONE")) >= 0) + return (KFaxErrNoDialTone); + if ((iResults.FindF (_L8 ("BUSY"))) >= 0) + return (KFaxErrBusy); + if ((iResults.FindF (_L8 ("NO ANSWER"))) >= 0) + return (KFaxErrNoAnswer); + if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0) + return (KFaxErrNoCarrier); + if ((iResults.FindF (_L8 ("FHNG"))) >= 0) + return (KFaxErrNoNegotiate); + if ((iResults.FindF (_L8 ("OK"))) >= 0) + break; + if ((iResults.FindF (_L8 ("FCON"))) >= 0) + iModem->iProgress.iPhase = ESessionNegotiation; + else if ((iResults.FindF (_L8 ("FCSI"))) >= 0) + ExtractAnswerback (iResults); + } + return (TxPrePageL ()); +} +/********************************************************************/ +TInt CFaxClass2::TxPrePageL () +{ + __FLOG_FAXSRV( _L8("CFaxClass2::TxPrePageL entering")); + + iModem->ExportL (_L8 ("AT+FDT\r")); + for (;;) + { + if (!(iModem->ImportL (iResults, 30))) + return (KFaxErrNoNegotiate); + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + + if ((iResults.FindF (_L8 ("FHNG"))) >= 0) + return (KFaxErrNoNegotiate); + if ((iResults.FindF (_L8 ("CONNECT"))) >= 0) + break; + if ((iResults.FindF (_L8 ("FDCS"))) >= 0) + ParseResults (iResults); + } + + for (;;) + { + + //TInt ticks = CLK_TCK * 10; + //-- PIA-58ELQK defect fix by Dmitry Lyokhin 26.03.2001 + TInt XonTimeoutSec = CLK_TCK * 3; + + if ((iModem->RxcharWaitL (XonTimeoutSec)) == 0) + { + //-- XON character sending timeout. Ignore. + //-- PIA-58ELQK defect fix by Dmitry Lyokhin 26.03.2001 + //return (KFaxNoClass2Xon); + break; + } + + if (iModem->iReadone[0] == Kxon) + break; + } + return (TxStartPageL ()); +} +/********************************************************************/ + +// + // TxPostPage should return either with + // + // a) an error code and iPhase set to RFax::EPostPageStatus, in which case the send returns with the error + // b) KErrNone and iPhase set to RFax::EDataTransfer, in which case we send the next page + // c) KErrNone and iPhase set to RFax::EDisconnection, in which case the send returns with KErrNone + // + +TInt CFaxClass2::TxPostPageL () +{ + + iModem->iTransmitBuffer.Append (Kdle); + iModem->iTransmitBuffer.Append (Ketx); + iModem->CommitTransmitBufferL (); + + iModem->iOurMessage.Format (_L8 (" transmitted after %d lines"), iModem->iProgress.iLines); + + __FLOG_FAXSRV(iModem->iOurMessage); + + iModem->iProgress.iPhase = EPostPageStatus; + iModem->ProgressUpdateL (); + while (iModem->Txstat () != 0) + ; + + // we've just ended phase C data, so we need to wait for the modem to respond with OK + + + + if (iModem->GetMatchL (_L8 ("OK"), (32 * 1024) / (iModem->iProgress.iSpeed / 10)) == 0) + return (KFaxErrCannotEndData); + + iModem->Xonoff (); + + if (iFaxServerSessionSettings->iTxPages == iModem->iProgress.iPage) + { + iModem->ExportL (_L8 ("AT+FET=2\r")); + iModem->iOurMessage.Format (_L8 ("End of document transmitted EOP frame")); + } + else + { + iModem->ExportL (_L8 ("AT+FET=0\r")); + iModem->iOurMessage.Format (_L8 ("End of page %u transmitted MPS frame"), iModem->iProgress.iPage); + } + iModem->ProgressUpdateL (); + + for (;;) + { + +//#if defined (__WINS__) +// RDebug::Print(_L("NOW")); +//#endif + + + if (!(iModem->ImportL (iResults, 30))) + { + return (KFaxErrModemResponse); + } + + iModem->iOurMessage.Format (_L8 ("%S"), &iResults); + iModem->ProgressUpdateL (); + + if ((iResults.FindF (_L8 ("FHNG"))) >= 0) + { + if (iResults[7] == '0') + break; + return (KFaxErrNoNegotiate); + } + + if ((iResults.FindF (_L8 ("FPTS"))) >= 0) + { + + if (iResults.FindF (_L8("1"))==6) // 6 is the position of the error code in descriptor + { + iModem->iOurMessage.Append (_L8("FPTS:1 MCF frame")); + iModem->ProgressUpdateL (); + break; + } + else if (iResults.FindF(_L8("2"))==6) + { + iModem->iOurMessage.Append (_L8("FPTS:2 RTN frame")); + iModem->ProgressUpdateL (); + break; + } + else if (iResults.FindF(_L8("3"))==6) + { + iModem->iOurMessage.Append (_L8("FPTS:3 RTP frame")); + iModem->ProgressUpdateL (); + break; + } + else if (iResults.FindF(_L8("4"))==6) + { + iModem->iOurMessage.Append (_L8("FPTS:4 PIN frame")); + iModem->ProgressUpdateL (); + break; + } + else if (iResults.FindF(_L8("5"))==6) + { + iModem->iOurMessage.Append (_L8("FPTS:5 PIP frame")); + iModem->ProgressUpdateL (); + break; + } + break; + + } + } // for(;;) ends here + + if (iModem->GetMatchL (_L8 ("OK"), 5) == 0) + return (KFaxErrNoFinalOK); + + if ((((iResults.FindF (_L8 ("2"))) >= 0) || (iResults.FindF (_L8 ("4")) >= 0)) && (iRepeatPage <= 3)) //RTN and + { //PIN responses + iModem->iProgress.iPhase = ESessionNegotiation; + iRepeatPage++; + iModem->iProgress.iPage--; + return (TxPrePageL ()); + } + if (iFaxServerSessionSettings->iTxPages != iModem->iProgress.iPage) + { + iRepeatPage = 0; + return (TxPrePageL ()); + } + iModem->iProgress.iPhase = EDisconnection; + return (KErrNone); +} +/********************************************************************/ + +// this routine parses both class 2 and class 2.0 + // T.30 session subparameter strings, from both interrogatories + // and reports - for interrogatories, we assume that later capabilities + // (inside the brackets) are preferable to earlier ones + +// amended July 1998 to support ECM for class 2.0 + +void CFaxClass2::ParseResults (TDesC8 & aResults) +{ + TInt x, field, inbracket; + static const TInt minscans[][2] = + { + {0, 0 + }, + {5, 5 + }, + {10, 5 + }, + {10, 10 + }, + {20, 10 + }, + {20, 20 + }, + {40, 20 + }, + {40, 40 + } + }; + + for ( x = 0, field = 0, inbracket = 0; x < aResults.Length (); x++) + { + if ((aResults[x] > '0' - 1) && (aResults[x] < '9' + 1)) + { + if (field == 0) + iModem->iProgress.iResolution = TFaxResolution (aResults[x] & 1); + else if (field == 1) + iModem->iProgress.iSpeed = (aResults[x] - '0' + 1) * 2400; + else if (field == 4) + iModem->iProgress.iCompression = TFaxCompression (aResults[x] & 1); + else if (field == 5) + iModem->iProgress.iECM = (aResults[x] - '0'); + else if (field == 7) + { + iMinscan = minscans[aResults[x] - '0'][iModem->iProgress.iResolution]; + if (iMinscan == 0) + iMinlinelength = 0; + else + iMinlinelength = ((iModem->iProgress.iSpeed / (1000 / iMinscan)) / 8) + 1; + } + } + if (aResults[x] == 0) + break; + if (aResults[x] == 0x28) + inbracket = 1; + if (aResults[x] == 0x29) + inbracket = 0; + if ((aResults[x] == 0x2c) && (inbracket == 0)) + field++; + if (field == 8) + break; + } + if (iFaxServerSessionSettings->iFaxClass == EClass2) + iModem->iProgress.iECM = 0; // no ECM using class 2 + if (iModem->iProgress.iECM) + iModem->iProgress.iECM = 1; // and treat EC as a boolean +} +/********************************************************************/ + +// this routine extract an ID string from a result code + +void CFaxClass2::ExtractAnswerback (TDesC8 & aResults) +{ + TInt startID = aResults.Locate (0x22); + if (startID != KErrNotFound) + { + startID++; + TInt maxIDlength = (aResults.Length () - startID); + if (maxIDlength > 20) + maxIDlength = 20; + iModem->iProgress.iAnswerback.Copy (aResults.Mid (startID, maxIDlength)); + } +} +/********************************************************************/