fax/faxclientandserver/FAXSVR/CFAX20.CPP
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:40:21 +0100
branchRCL_3
changeset 20 07a122eea281
parent 0 3553901f7fa8
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201035 Kit: 201035

// 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 KClass20HangupStatusTimer=20;	// < Time used to wait for final +FHS: report.  Was 5s, but typical GSM delays range between 4s and 10s.

// this module has two parts
// first receive routines rx
// second transmit routines tx

/********************************************************************/

CFaxModemDriver* CFaxClass20::NewLC(TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress)
	{
	CFaxModemDriver* self = new(ELeave) CFaxClass20;
	CleanupStack::PushL(self);
	self->ConstructL(aFaxServerSessionSettings, aProgress);
	return self;
	}

CFaxModemDriver* CFaxClass20::NewL(TFaxServerSessionSettings * aFaxServerSessionSettings, RFax::TProgress & aProgress)
	{
	CFaxModemDriver* self = NewLC(aFaxServerSessionSettings, aProgress);
	CleanupStack::Pop();
	return self;
	}
/********************************************************************/

TInt CFaxClass20::RxConnectL()
	{
	__FLOG_FAXSRV( _L8("CFaxClass20::RxConnectL entering"));

	CheckCadenceExportL (_L8 ("AT+FNR=1,1,1,0\r"));
	if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0)
		return (KFaxErrModemNotWorking);

	CheckCadenceExportL(_L8("AT+FCC=?\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;

	if (iFaxServerSessionSettings->iPreferredECM == 0)
		iModem->iProgress.iECM = 0;

	iResults.Copy(_L8("AT+FCC=0,0,0,2,0,0,0,0\r"));

	iResults[7] = (TUint8) (iResults[7] + iModem->iProgress.iResolution);
	iResults[9] = (TUint8) (((iActualFaxSpeed / 2400) - 1) + '0');
	iResults[15] = (TUint8) (iResults[15] + iModem->iProgress.iCompression);
	iResults[17] = (TUint8) (iModem->iProgress.iECM + '0');
	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<RCall::KFaxIdUserNameMaxSize> narrowBuf;
	narrowBuf.Copy(iFaxServerSessionSettings->iFaxId);	 // convert from unicode to narrow
	
	//-- By Dmitry Lyokhin. concerns PIA-58ELQK defect.
	if( narrowBuf.Length() < 1 )
		{
		narrowBuf.Append(' ');
		}

	if (iFaxServerSessionSettings->iMode & KFaxPoll)
		{
		iModem->ExportL(_L8 ("AT+FSP=1\r"));
		if ((iModem->GetMatchL(_L8("OK"), 5)) == 0)
			{
			return (KFaxPollingUnsupported);
			}
		iModem->ExportL(_L8("AT+FPI=\""));
		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+FLI=\""));
		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)
		{
		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("FHS"))) >= 0)
			return (KFaxErrPrematureHangup);
		if ((iResults.FindF(_L8("FCO"))) >= 0)
			iModem->iProgress.iPhase = ESessionNegotiation;
		else if ((iResults.FindF(_L8("FPO"))) >= 0)
			pollDocsAvailable = 1;
		else if ((iResults.FindF(_L8("FTI"))) >= 0)
			ExtractAnswerback(iResults);
		else if ((iResults.FindF(_L8("FCS"))) >= 0)
			ParseResults(iResults);
		}

	if ((iFaxServerSessionSettings->iMode & KFaxPoll) && (pollDocsAvailable == 0))
		return (KFaxNothingToPoll);

	iModem->iOurMessage.Format(_L8 ("about to receive fax"));
	iModem->ProgressUpdateL();
	return RxPrePageL();
	}

/********************************************************************/
TInt CFaxClass20::RxPrePageL()
	{
	__FLOG_FAXSRV( _L8("CFaxClass20::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 ("FHS"))) >= 0)
			return (KFaxErrPrematureHangup);
		if ((iResults.FindF (_L8 ("CONNECT"))) >= 0)
			break;
		if ((iResults.FindF (_L8 ("FCS"))) >= 0)
			ParseResults (iResults);
		}

	iModem->TxcharL (Kdc2);
	return (RxStartPageL ());
}
/********************************************************************/
TInt CFaxClass20::RxPostPageL ()
{
    __FLOG_FAXSRV( _L8("CFaxClass20::RxPostPageL entering"));

	iModem->iProgress.iPhase = EPostPageStatus;
	iModem->ProgressUpdateL ();
	for (;;)
		{
		if (iModem->iProgress.iECM == 0)
			{
			if (!(iModem->ImportL (iResults, 20)))
				return (KFaxErrModemResponse);
			}
        else
            {
            // coverity[check_return]
            iModem->ImportL (iResults, 0x7fff);     // no timeout if ECM enabled
            }

		iModem->iOurMessage.Format (_L8 ("%S"), &iResults);
		iModem->ProgressUpdateL ();

		if ((iResults.FindF (_L8 ("OK"))) >= 0)
			return (KFaxErrPrematureOK);
		if ((iResults.FindF (_L8 ("FHS"))) >= 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 ("FHS"), KClass20HangupStatusTimer) == 0)
			return (KFaxErrNoHangup);
		if (iModem->GetMatchL (_L8 ("OK"), 5) == 0)
			return (KFaxErrNoFinalOK);
		return (KErrNone);
		}
	return (KFaxErrUnknownPageCode);
}
/********************************************************************/

TInt CFaxClass20::TxConnectL ()
{
    __FLOG_FAXSRV( _L8("CFaxClass20::TxConnectL entering"));

	iModem->ExportL (_L8 ("AT+FNR=1,1,1,0\r"));
	if ((iModem->GetMatchL (_L8 ("OK"), 5)) == 0)
		return (KFaxErrModemNotWorking);
	TBuf8<RCall::KFaxIdUserNameMaxSize> narrowBuf;
	narrowBuf.Copy(iFaxServerSessionSettings->iFaxId);	 // convert from unicode to narrow
	
	//-- By Dmitry Lyokhin. concerns PIA-58ELQK defect.
	if( narrowBuf.Length() < 1 ) narrowBuf.Append(' ');

	
	iModem->ExportL (_L8 ("AT+FLI=\""));
	iModem->ExportL (narrowBuf);
	iModem->ExportL (_L8 ("\"\r"));
	if ((iModem->GetMatchL (_L8 ("OK"), 3)) == 0)
		return (KFaxErrModemNotWorking);

	iModem->ExportL (_L8 ("AT+FCC=?\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;

	if (iFaxServerSessionSettings->iPreferredECM == 0)
		iModem->iProgress.iECM = 0;

	iResults.Copy (_L8 ("AT+FCC=0,0,0,2,0,0,0,0\r"));

	iResults[7] = (TUint8) (iResults[7] + iFaxServerSessionSettings->iTxResolution);
	iResults[9] = (TUint8) (((iActualFaxSpeed / 2400) - 1) + '0');

	
	// added to support 2Dfaxing using class 2.0
	if (iModem->iProgress.iCompression)
		iResults[15] = (TUint8) (iResults[15] + iFaxServerSessionSettings->iTxCompression);
	else
		iResults[15] = (TUint8) (iResults[15] + EModifiedHuffman);
	
	//iResults[15] = (TUint8) (iResults[15] + iFaxServerSessionSettings->iTxCompression);
	
		
	iResults[17] = (TUint8) (iModem->iProgress.iECM + '0');
	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 ("FHS"))) >= 0)
			return (KFaxErrNoNegotiate);
		if ((iResults.FindF (_L8 ("OK"))) >= 0)
			break;
		if ((iResults.FindF (_L8 ("FCO"))) >= 0)
			iModem->iProgress.iPhase = ESessionNegotiation;
		else if ((iResults.FindF (_L8 ("FCI"))) >= 0)
			ExtractAnswerback (iResults);
		}
	return (TxPrePageL ());
}
/********************************************************************/
TInt CFaxClass20::TxPrePageL ()
{
    __FLOG_FAXSRV(_L8("CFaxClass20::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 ("FHS"))) >= 0)
			return (KFaxErrNoNegotiate);
		if ((iResults.FindF (_L8 ("CONNECT"))) >= 0)
			break;
		if ((iResults.FindF (_L8 ("FCS"))) >= 0)
			ParseResults (iResults);
		}

	for (;;)
		{
		TInt XonTimeoutSec = CLK_TCK * 3; 
		
		if ((iModem->RxcharWaitL(XonTimeoutSec)) == 0)
			{
			break;
			}

		if (iModem->iReadone[0] == Kxon)
			{
			break;
			}
		}
	return (TxStartPageL());
}
/********************************************************************/

//
 // TxPostPageL 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 CFaxClass20::TxPostPageL ()
{
	if (iModem->iProgress.iCompression == EModifiedRead)
		{
		iModem->iTransmitBuffer.Append (0x00);
		iModem->iTransmitBuffer.Append (0x60);
		iModem->iTransmitBuffer.Append (0x00);
		iModem->iTransmitBuffer.Append (0x0C);
		iModem->iTransmitBuffer.Append (0x80);
		iModem->iTransmitBuffer.Append (0x01);
		iModem->iTransmitBuffer.Append (0x30);
		iModem->iTransmitBuffer.Append (0x00);
		iModem->iTransmitBuffer.Append (0x06);
		iModem->iTransmitBuffer.Append (0xC0);
		}
	else
		{
		for (TInt x = 3; x; x--)
			{
			iModem->iTransmitBuffer.Append (0x0);
			iModem->iTransmitBuffer.Append (0x08);
			iModem->iTransmitBuffer.Append (0x80);
			}
		}

	iModem->iTransmitBuffer.Append (Kdle);
	iModem->iOurMessage.Format (_L8 ("RTC transmitted after %d lines"), iModem->iProgress.iLines);
	iModem->ProgressUpdateL ();
	if (iFaxServerSessionSettings->iTxPages == iModem->iProgress.iPage)
		{
		iModem->iTransmitBuffer.Append (0x2e);
		iModem->iOurMessage.Format (_L8 ("End of document transmitted <dle><eop>"));
		}
	else
		{
		iModem->iTransmitBuffer.Append (0x2c);
		iModem->iOurMessage.Format (_L8 ("End of page %u transmitted <dle><mps>"), iModem->iProgress.iPage);
		}
    __FLOG_FAXSRV( iModem->iOurMessage);

	iModem->CommitTransmitBufferL ();

	iModem->iProgress.iPhase = EPostPageStatus;
	iModem->ProgressUpdateL ();
	while (iModem->Txstat () != 0)
		;
	iModem->Xonoff ();

	// we've just ended phase C data, so we need to wait for the modem to respond with OK or ERROR

	for (;;)
		{
		if (iModem->iProgress.iECM == 0)
			{
			if (!(iModem->ImportL (iResults, (32 * 1024) / (iModem->iProgress.iSpeed / 10))))
				return (KFaxErrCannotEndData);
			}
        else
            {
            // coverity[check_return]
            iModem->ImportL (iResults, 0x7fff);     // no timeout if ECM enabled, but NO CARRIER possible from some mobile phones
            if ((iResults.FindF (_L8 ("NO CARRIER"))) >= 0)
                return (KFaxErrCannotEndData);
            }

		iModem->iOurMessage.Format (_L8 ("%S"), &iResults);
		iModem->ProgressUpdateL ();

		if ((iResults.FindF (_L8 ("ERROR"))) >= 0)
			break;
		if ((iResults.FindF (_L8 ("OK"))) >= 0)
			break;
		}
	if (((iResults.FindF (_L8 ("ERROR"))) >= 0) && (iRepeatPage == 0))
		{
		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);
}
/********************************************************************/