fax/faxclientandserver/FAXSVR/CFAXMDRV.CPP
branchRCL_3
changeset 65 630d2f34d719
parent 61 17af172ffa5f
child 66 07a122eea281
equal deleted inserted replaced
61:17af172ffa5f 65:630d2f34d719
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "FAXSERV.H"
       
    17 #include "fax_reversebytes.h"
       
    18 #include "FONT8X16.DAT"
       
    19 #include "ZEROS.DAT"
       
    20 #include "FAXMDRV.H"
       
    21 #include "FAXMODEM.H"
       
    22 
       
    23 #include "FAXLOG.H"
       
    24 #include <et_phone.h>
       
    25 
       
    26 const TInt KLineReadTimeout=6;				// < The time-out (in secs) for a line read
       
    27 const TInt KECMLineReadTimeout=132;			// < The time-out (in secs) for a line read when using Error Correction Mode
       
    28 const TInt KSubsequentLineReadTimeout=10;	// < The time-out (in secs) for a subsequent line read
       
    29 const TInt KSubsequentECMLineReadTimeout=140;	// < The time-out (in secs) for a subsequent line read when using Error Correction Mode
       
    30 
       
    31 /********************************************************************/
       
    32 
       
    33 // we need to keep a local pointer to the current TDialstorModemPreferences in order to
       
    34  // do whatever is required
       
    35 
       
    36 void CFaxModemDriver::ConstructL (TFaxServerSessionSettings * iFaxServerSessionSettings, RFax::TProgress & aProgress)
       
    37 {
       
    38 	iModem = CFaxModem::NewL (iFaxServerSessionSettings, aProgress);
       
    39 }
       
    40 /********************************************************************/
       
    41 
       
    42 
       
    43 CFaxModemDriver::CFaxModemDriver()
       
    44                 :CBase(), iSharedHandles(NULL)
       
    45 {
       
    46 }
       
    47 
       
    48 CFaxModemDriver::~CFaxModemDriver ()
       
    49 {
       
    50 	delete iModem;
       
    51 }
       
    52 /********************************************************************/
       
    53 
       
    54 // function to check that we don't send commands out when there's less than half a second
       
    55 // before the next RING comes in
       
    56 
       
    57 
       
    58 /**
       
    59 *	function to check that we don't send commands out when there's less than half a second
       
    60 *	before the next RING comes in.
       
    61 *	This function has been modified by Dmitry Lyokhin for the sake of PIA-586KGE defect fix
       
    62 *
       
    63 * @param	aCommand	-	contains the command to be sent to the modem.
       
    64 *
       
    65 * @see	ExportL function
       
    66 *
       
    67 * @return	number of symbols sent to the modem.
       
    68 *			
       
    69 *
       
    70 */
       
    71 TInt CFaxModemDriver::CheckCadenceExportL(const TDesC8 & aCommand)
       
    72 {
       
    73 	
       
    74 	
       
    75 	const TInt RingTimeout_Sec	= 5;		//-- 5 sec. waiting for 'RING' timeout
       
    76 	const TInt RingCadence_uSec	= 3000000;	//-- 3 sec. time span after 'RING' receiving during that commands 
       
    77 											//-- can be sent to the modem
       
    78 
       
    79 	const TInt CmdSendDelay_uSec= 100000;	//-- 100 ms delay between adjacent commands to the modem
       
    80 
       
    81 	TTime CurrentTime;
       
    82 
       
    83     __FLOG_FAXSRV( _L8("-CFaxModemDriver::CheckCadenceExportL entering"));
       
    84   
       
    85   	
       
    86 	//-- @note iCadence now is used like a flag. If its value is 0 (thai is set initially) we will
       
    87 	//-- try to wait for 'RING' indication i.e synchronize with incoming rings. Otherwise - no.
       
    88 	while( iCadence.Int64() == 0 )
       
    89 	{
       
    90 		if(iTimeOfLastRing.Int64() == 0) 
       
    91 		{//-- we need to wait for 'RING' from the modem
       
    92 
       
    93             __FLOG_FAXSRV( _L8("-CFaxModemDriver::CheckCadenceExportL waiting for RING"));
       
    94 	  
       
    95 			//-- wait for 'RING' from modem
       
    96 			if( iModem->GetMatchL (_L8 ("RING"), RingTimeout_Sec) == 0) 
       
    97 			{	//User::Leave(KFaxErrReceiveTimeout); //-- 'RING' waiting timeout, leaving
       
    98 				
       
    99 				//-- There is no 'RING'indication, no we will not leave, instead of that
       
   100 				//-- disable sync. with incoming rings and pass on to sending commands to the modem straightforward.
       
   101 				iCadence = 1;
       
   102 				break;
       
   103 			}
       
   104 
       
   105 			iTimeOfLastRing.UniversalTime(); //-- note the time
       
   106 		}
       
   107 
       
   108 		//-- get current time and check if we are in time to send a command to the modem
       
   109 		CurrentTime.UniversalTime ();
       
   110 	
       
   111 		if( CurrentTime < iTimeOfLastRing + TTimeIntervalMicroSeconds32(RingCadence_uSec) )
       
   112 			break; //-- send the command
       
   113 		else
       
   114 		{	//-- wait for the next 'RING'
       
   115             __FLOG_FAXSRV( _L8("-CFaxModemDriver::CheckCadenceExportL Resetting"));
       
   116 			iTimeOfLastRing = 0;
       
   117 		}
       
   118 	}
       
   119 
       
   120 	//-- I had to introduce this delay between sending adjacent commands to the modem because
       
   121 	//-- some modems (e.g. Nokia9210) lose data.
       
   122 	iModem->Silence(CmdSendDelay_uSec);
       
   123 
       
   124 	//-- send the command
       
   125 	return iModem->ExportL (aCommand);
       
   126 }
       
   127 
       
   128 /********************************************************************/
       
   129 
       
   130 // if we have called FaxInL with a dial request, it calls this routine
       
   131  // to dial up a fax on demand service
       
   132  //
       
   133  // if not polling, we end with a colon to return to command mode and then
       
   134  // we delay for whatever time has been requested by the user
       
   135  // before returning, at which point FaxInL continues with ATA
       
   136 
       
   137 void CFaxModemDriver::DialFaxOnDemandL ()
       
   138 {
       
   139 	iModem->ExportL (_L8 ("ATD"));
       
   140 	iModem->ExportL (iFaxServerSessionSettings->iPhoneNumber);
       
   141 
       
   142 	if (iFaxServerSessionSettings->iMode & KFaxPoll)
       
   143 		iModem->TxcharL (Kreturn);
       
   144 	else
       
   145 		{
       
   146 		iModem->ExportL (_L8 (";"));
       
   147 		iModem->TxcharL (Kreturn);
       
   148 		if ((iModem->GetMatchL (_L8 ("OK"), KDialTimeout)) == 0)
       
   149 			User::Leave (KFaxErrNoDial);
       
   150 		iModem->Silence (CLK_TCK * iFaxServerSessionSettings->iFaxOnDemandDelay);
       
   151 		}
       
   152 }
       
   153 /********************************************************************/
       
   154 
       
   155 // now the routines to add a header line to the top of each fax page
       
   156 
       
   157 /********************************************************************/
       
   158 
       
   159 // we send four blank scan lines
       
   160  // we create a line of text containing time and date,
       
   161  // the Fax ID and Username,
       
   162  // the page number and total number of pages,
       
   163  // we digitize that, and send it out
       
   164  // our font height is 16 so that means 20 scan lines
       
   165  // are added to the top of each sent fax
       
   166 
       
   167 void CFaxModemDriver::SendFaxHeaderL ()
       
   168 {
       
   169 	TFaxHeaderInfo faxHeader;
       
   170 	TRawScanLine headline;
       
   171 	TRawScanLine fontline;
       
   172 	TBuf8 < KFaxT4MaxDesLength > encodedHeadLine;
       
   173 	TTime timeOfTransmission;
       
   174 	TBuf < 12 > timeText;
       
   175 
       
   176 	timeOfTransmission.HomeTime();
       
   177 	timeOfTransmission.FormatL (timeText, (_L ("%F%D%M%Y%H%T")));
       
   178 
       
   179 	iModem->iOurMessage.Format (_L8 ("Sending page header"));
       
   180 	iModem->ProgressUpdateL ();
       
   181 
       
   182 	for (TInt r = iModem->iProgress.iResolution ; r >= 0; r--)
       
   183 		{
       
   184 		for (TInt x = 0, y = 4 ; x < 4; x++)
       
   185 			{
       
   186 			iModem->iTransmitBuffer.Append (0x00);
       
   187 			if (iModem->iProgress.iCompression)
       
   188 				{
       
   189 				iModem->iTransmitBuffer.Append (Invert (0x00));
       
   190 				iModem->iTransmitBuffer.Append (Invert (0x34));
       
   191 				y = 5;
       
   192 				}
       
   193 			else
       
   194 				iModem->iTransmitBuffer.Append (Invert (0x14));
       
   195 			iModem->iTransmitBuffer.Append (Invert (0xD9));
       
   196 			iModem->iTransmitBuffer.Append (Invert (0xA8));
       
   197 			padLineL (y);
       
   198 			}
       
   199 		}
       
   200 
       
   201 	CFaxT4 * faxT4 =CFaxT4::NewLC();
       
   202 	faxT4->PageInitialize (iModem->iProgress.iResolution, iModem->iProgress.iCompression);
       
   203 	if(!iSharedHandles)
       
   204 		{
       
   205 		User::Leave(KErrBadHandle);
       
   206 		}
       
   207 	CFaxHeaderLines * faxheader = CFaxHeaderLines::NewLC (&iSharedHandles->File());	
       
   208 
       
   209 	faxheader->ReadFaxHeaderInfoL (faxHeader);
       
   210 	for (TInt n = 0; n < 12; n++)
       
   211 		timeText[n] -= '0';
       
   212 
       
   213 	// Forces 2 digit day - 2 digit month - 4 digit year - 2 digit hour - 2 digit minute
       
   214 
       
   215 	for (TInt scanline = 0; scanline < faxHeader.iHeaderFontHeightInLines; scanline++)
       
   216 		{
       
   217 		faxheader->ReadRawHeaderLineL (scanline, headline);
       
   218 		faxheader->ReadRawFontLineL (scanline, fontline);
       
   219 		for (TInt fontByte = 0; fontByte < faxHeader.iHeaderFontWidthInBytes; fontByte++)
       
   220 			{
       
   221 			headline[((faxHeader.iOffsetToDay) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[0] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   222 			headline[((faxHeader.iOffsetToDay + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[1] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   223 			headline[((faxHeader.iOffsetToMonth) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[2] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   224 			headline[((faxHeader.iOffsetToMonth + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[3] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   225 			headline[((faxHeader.iOffsetToYear) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[4] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   226 			headline[((faxHeader.iOffsetToYear + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[5] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   227 			headline[((faxHeader.iOffsetToYear + 2) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[6] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   228 			headline[((faxHeader.iOffsetToYear + 3) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[7] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   229 			headline[((faxHeader.iOffsetToHour) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[8] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   230 			headline[((faxHeader.iOffsetToHour + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[9] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   231 			headline[((faxHeader.iOffsetToMinute) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[10] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   232 			headline[((faxHeader.iOffsetToMinute + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[(timeText[11] * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   233 
       
   234 			// put the page info in
       
   235 
       
   236 
       
   237 			if (iModem->iProgress.iPage > 9)
       
   238 				headline[((faxHeader.iOffsetToCurrentPage) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[((iModem->iProgress.iPage / 10) * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   239 			headline[((faxHeader.iOffsetToCurrentPage + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[((iModem->iProgress.iPage % 10) * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   240 			if (iFaxServerSessionSettings->iTxPages > 9)
       
   241 				headline[((faxHeader.iOffsetToTotalPages) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[((iFaxServerSessionSettings->iTxPages / 10) * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   242 			headline[((faxHeader.iOffsetToTotalPages + 1) * faxHeader.iHeaderFontWidthInBytes) + fontByte] = fontline[((iFaxServerSessionSettings->iTxPages % 10) * faxHeader.iHeaderFontWidthInBytes) + fontByte];
       
   243 			}
       
   244 
       
   245 		// we send the line once in normal resolution but twice in fine resolution
       
   246 
       
   247 		for (TInt r = iModem->iProgress.iResolution ; r >= 0; r--)
       
   248 			{
       
   249 			faxT4->EncodeScanLine (headline, encodedHeadLine);
       
   250 
       
   251 			// always add the extra null at the start for the initial eol
       
   252 
       
   253 			iModem->iTransmitBuffer.Append (Knul);
       
   254 
       
   255 			// and then invert and finally send the encoded line
       
   256 
       
   257 			const TUint8 *px = CONST_CAST (TUint8 *, encodedHeadLine.Ptr ());
       
   258 			const TUint8 *ex = px + encodedHeadLine.Length ();;
       
   259 			TUint8 thisChar;
       
   260 			TInt bytesSent = 0;
       
   261 			while (px < ex)
       
   262 				{
       
   263 				thisChar = Invert (*px++);
       
   264 				iModem->iTransmitBuffer.Append (thisChar);
       
   265 				if (thisChar == Kdle)
       
   266 					iModem->iTransmitBuffer.Append (Kdle);
       
   267 				iModem->SendTransmitBufferL ();
       
   268 				bytesSent++;
       
   269 				}
       
   270 			padLineL (bytesSent);
       
   271 			}
       
   272 		}
       
   273 
       
   274 	CleanupStack::PopAndDestroy(faxheader);
       
   275     CleanupStack::PopAndDestroy(faxT4);
       
   276 }
       
   277 
       
   278 /********************************************************************/
       
   279 
       
   280 // this function handles line padding out for minimum scan line times
       
   281  // this feature should really only be needed on class 1 modems ...
       
   282  // it takes a single integer parameter, which is the number of bytes sent
       
   283 
       
   284 void CFaxModemDriver::padLineL (TInt aByteCount)
       
   285 {
       
   286 	if (iFaxServerSessionSettings->iFaxClass == EClass1)
       
   287 		{
       
   288 		while (iMinlinelength > aByteCount)
       
   289 			{
       
   290 			aByteCount++;
       
   291 			iModem->iTransmitBuffer.Append (Knul);
       
   292 			iModem->SendTransmitBufferL ();
       
   293 			}
       
   294 		}
       
   295 }
       
   296 /********************************************************************/
       
   297 
       
   298 // rewritten to avoid using any AT commands August 1997 Andrew Margolis
       
   299  // pointer arithmetic courtesy of Andrew Thoelke
       
   300  // Though this doesn't use any AT command but it does need to know
       
   301  // about the various modem classes ... GetFaxDataL is in the same boat
       
   302 
       
   303 // the client has buffered up lines to minimize interaction
       
   304  // aData starts with a TInt containing the number of lines
       
   305  // Each line follows, preceded with a TInt containing its length
       
   306  // which must be copied as it might not be aligned on a 4-byte
       
   307  // boundary
       
   308 
       
   309 TInt CFaxModemDriver::SendFaxDataL (const TDesC8 * aData)
       
   310 {
       
   311 	TUint8 thisChar;
       
   312 	TInt ticks;
       
   313 	TInt numberOfLines;
       
   314 	TInt lengthOfLine;
       
   315 
       
   316 	TUint8 *thisLine = CONST_CAST (TUint8 *, (*aData).Ptr ());
       
   317 	Mem::Copy (&numberOfLines, thisLine, sizeof (TInt));
       
   318 	thisLine += sizeof (TInt);
       
   319 
       
   320 	// buffering debug message
       
   321 
       
   322 	iModem->iOurMessage.Format (_L8 ("%u lines in buffer taking up %u bytes"), numberOfLines, (*aData).Length ());
       
   323 	iModem->ProgressUpdateL ();
       
   324 
       
   325 	while (numberOfLines--)
       
   326 		{
       
   327 		Mem::Copy (&lengthOfLine, thisLine, sizeof (TInt));
       
   328 		thisLine += sizeof (TInt);
       
   329 		iModem->iProgress.iLines++;
       
   330 
       
   331 		TInt bytesSent = 0;
       
   332 		const TUint8 *px = thisLine;
       
   333 		const TUint8 *ex = px + lengthOfLine;
       
   334 		while (px < ex)
       
   335 			{
       
   336 			thisChar = Invert (*px++);
       
   337 			iModem->iTransmitBuffer.Append (thisChar);
       
   338 			if (thisChar == Kdle)
       
   339 				iModem->iTransmitBuffer.Append (Kdle);
       
   340 			iModem->SendTransmitBufferL ();
       
   341 			bytesSent++;
       
   342 			}
       
   343 		padLineL (bytesSent);
       
   344 
       
   345 		// we must check for cancel commands from the modem in class 2.0 transmission
       
   346 
       
   347 		if (iFaxServerSessionSettings->iFaxClass == EClass2point0)
       
   348 			{
       
   349 			while (iModem->Rxstat () != 0)
       
   350 				{
       
   351 				ticks = CLK_TCK;
       
   352 				iModem->RxcharWaitL (ticks);
       
   353 				if (iModem->iReadone[0] == Kcan)
       
   354 					{
       
   355 					iModem->TxcharL (Kdle);
       
   356 					iModem->TxcharL (Ketx);
       
   357 					iModem->CommitTransmitBufferL ();
       
   358 					iModem->Xonoff ();
       
   359 					iModem->GetMatchL (_L8 ("OK"), 5);
       
   360 					return (KFaxErrModemDisconnect);
       
   361 					}
       
   362 				}
       
   363 			}
       
   364 		thisLine += lengthOfLine;
       
   365 		}
       
   366 	return (KErrNone);
       
   367 }
       
   368 /********************************************************************/
       
   369  // This function takes a pointer to a binary data buffer.
       
   370  // We are guaranteed that the buffer is big enough to take
       
   371  // two entire scan lines up to KMaxT4Des in size.
       
   372 
       
   373  // We call GetLineL to fill the buffer up with scan lines, and
       
   374  // we keep a count of the number of lines received as an integer
       
   375  // at the start of the buffer.  We return when either we haven't
       
   376  // enough room to guarantee another line, or when we have received
       
   377  // a line of zero length, which means an end of page. The descriptor
       
   378  // is set to the correct length on return
       
   379 
       
   380  // So on return, aData starts with a TInt containing the number of lines
       
   381  // Each line follows, preceded with a TInt containing its length
       
   382  // which must be copied as it might not be aligned on a 4-byte
       
   383  // boundary - a line of zero length indicates we have reached
       
   384  // the end of the page
       
   385 
       
   386 void CFaxModemDriver::GetFaxDataL (TDes8 * aData)
       
   387 {
       
   388 	TUint8 *startData;
       
   389 	TUint8 *lineData;
       
   390 	const TUint8 *maxData;
       
   391 	TInt lineLength;
       
   392 	TInt numberOfLines = 0;
       
   393 
       
   394 	lineData = startData = CONST_CAST (TUint8 *, (*aData).Ptr ());
       
   395 	maxData = startData + (*aData).MaxLength () - KMaxT4Des - sizeof (TInt);
       
   396 
       
   397 	(*aData).SetMax ();
       
   398 	lineData += sizeof (TInt);
       
   399 
       
   400 	for (;;)
       
   401 		{
       
   402 		numberOfLines++;
       
   403 		lineLength = GetLineL (lineData);
       
   404 		Mem::Copy (lineData, &lineLength, sizeof (TInt));
       
   405 		lineData += sizeof (TInt);
       
   406 		lineData += lineLength;
       
   407 		if (lineData > maxData)
       
   408 			break;
       
   409 		if (lineLength == 0)
       
   410 			break;
       
   411 		}
       
   412 	Mem::Copy (startData, &numberOfLines, sizeof (TInt));
       
   413 	(*aData).SetLength (lineData - startData);
       
   414 
       
   415 	// buffering debug message
       
   416 
       
   417 	iModem->iOurMessage.Format (_L8 ("%u lines in buffer taking up %u bytes"), numberOfLines, (*aData).Length ());
       
   418 	iModem->ProgressUpdateL ();
       
   419 }
       
   420 /********************************************************************/
       
   421 // This function takes a pointer to a binary data buffer.
       
   422  // We are guaranteed that the buffer is big enough to take
       
   423  // an entire scan line up to KMaxT4Des in size.
       
   424  // We receive the scan line, with a leave if we timeout.
       
   425  // We return with the length of the scan line and the buffer has
       
   426  // a space for this to be placed as an integer by the caller,
       
   427  // followed by the scan line data.  If the length of the scan line
       
   428  // is zero, we have reached the end of the page
       
   429 
       
   430 TInt CFaxModemDriver::GetLineL (TUint8 * aFaxData)
       
   431 {
       
   432 	TUint8 *lineStart;
       
   433 	TUint8 *lineEnd;
       
   434 	TUint8 *currentByte;
       
   435 
       
   436 	lineStart = currentByte = (aFaxData + sizeof (TInt));
       
   437 	lineEnd = lineStart + KMaxT4Des;
       
   438 
       
   439 	TUint8 thisChar = 0;
       
   440 	TUint8 leading0s = 0;
       
   441 	TUint8 trailing0s = 0;
       
   442 	TInt nullcount = 0;
       
   443 
       
   444 	TInt ticks = CLK_TCK * KLineReadTimeout;
       
   445 	if (iModem->iProgress.iECM != 0)
       
   446 		ticks = CLK_TCK * KECMLineReadTimeout;
       
   447 
       
   448 	iModem->iProgress.iLines++;
       
   449 
       
   450 	TInt bol = 1;
       
   451 	TUint8 lastChar = 0xff;
       
   452 
       
   453 	// lastChar set to 0xff flags the entry to the function
       
   454 	// during iterations lastChar must be either 0 or 1
       
   455 	// we always come here just after detecting an EOL, and the character
       
   456 	// which contains the EOL bit is guaranteed to be re-readable
       
   457 	// lastChar set to 0xff indicates that's is not been read,
       
   458 	// so we re-read it, set its trailing0s, and put it in the buffer
       
   459 	// without bothering to do any dle checking (we already know it's ok)
       
   460 
       
   461 	for (;;)
       
   462 		{
       
   463 		if (lastChar == 0xff)
       
   464 			{
       
   465 			lastChar = 0;
       
   466 			thisChar = iModem->iReadone[0];
       
   467 			}
       
   468 		else
       
   469 			{
       
   470 			if ((iModem->RxcharWaitL (ticks)) == 0)
       
   471 				User::Leave (KFaxErrReceiveTimeout);
       
   472 			thisChar = iModem->iReadone[0];
       
   473 
       
   474 			// check if we have the character after a leading dle
       
   475 			// if we have unmark the last character as being a dle -
       
   476 			// dle etx is end of data
       
   477 			// dle dle is a shielded dle
       
   478 			// dle sub is two times dle for class 2.0 only
       
   479 			// dle and anything else we ignore
       
   480 
       
   481 			if (lastChar == Kdle)
       
   482 				{
       
   483 				lastChar = 0;
       
   484 
       
   485 				if (thisChar == Ketx)
       
   486 					{
       
   487 					iModem->iOurMessage.Format (_L8 ("<dle><etx> detected after %u lines"), iModem->iProgress.iLines);
       
   488 					iModem->ProgressUpdateL ();
       
   489 					return (0);
       
   490 					}
       
   491 
       
   492 				if (iFaxServerSessionSettings->iFaxClass == EClass2point0)
       
   493 					{
       
   494 					if (thisChar == 0x1a)
       
   495 						{
       
   496 						thisChar = Kdle;
       
   497 						*currentByte++ = Invert (thisChar);   // invert class 2.0
       
   498 						if (currentByte == lineEnd)
       
   499 							{
       
   500 							return (KMaxT4Des);
       
   501 							}
       
   502 						trailing0s = 4;
       
   503 						}
       
   504 					}
       
   505 
       
   506 				if (thisChar != Kdle)
       
   507 					continue;
       
   508 				}                   // drop through only with a data dle
       
   509 
       
   510 			// if not a trailing dle
       
   511 			// check if this character is itself a leading dle
       
   512 			// drop through only if it isn't
       
   513 
       
   514 			else if (thisChar == Kdle)
       
   515 				{
       
   516 				lastChar = Kdle;
       
   517 				continue;
       
   518 				}
       
   519 			}
       
   520 
       
   521 		// if we've received six EOL codes already, ignore everything
       
   522 		// till dle etx arrives
       
   523 
       
   524 		if (bol == 6)
       
   525 			continue;
       
   526 
       
   527 		// have we a null ? if yes we ignore nulls if they come in
       
   528 		// anything more than pairs - if no, we zero nullcount and
       
   529 		// invert the byte back the right way for non-class 2 modems
       
   530 		// THIS LAST IS IMPORTANT
       
   531 
       
   532 		if (thisChar == Knul)
       
   533 			{
       
   534 			if (nullcount == 2)
       
   535 				continue;
       
   536 			else
       
   537 				nullcount++;
       
   538 			}
       
   539 		else
       
   540 			{
       
   541 			nullcount = 0;
       
   542 			if (iFaxServerSessionSettings->iFaxClass != EClass2)
       
   543 				thisChar = Invert (thisChar);
       
   544 			}
       
   545 
       
   546 		// count the leading zeros in this byte
       
   547 
       
   548 		leading0s = zerotable[thisChar][0];
       
   549 
       
   550 		// if the leading zeros in this byte and the trailing zeros in the
       
   551 		// previous byte total 11 or more we have ourselves an EOL
       
   552 		// so we write the data we have so far as an entire line
       
   553 		// we are guaranteed than an eol will span at least two bytes
       
   554 		// so the data we have must include the end of the last line
       
   555 		// if this is a nul we don't write anything yet as we haven't
       
   556 		// detected a proper eol code
       
   557 		// we don't write anything for consecutibe eols
       
   558 
       
   559 		if (((trailing0s + leading0s) > 10) && (thisChar != Knul))
       
   560 			{
       
   561 			bol++;
       
   562 			if ((bol == 1) && (currentByte != lineStart))
       
   563 				{
       
   564 				return (currentByte - lineStart);
       
   565 				}
       
   566 			if (iModem->iProgress.iECM == 0)
       
   567 				ticks = CLK_TCK * KSubsequentLineReadTimeout;
       
   568 			else
       
   569 				ticks = CLK_TCK * KSubsequentECMLineReadTimeout;				// 11/1/01 AMC: ECM requires longer time-outs due to retries
       
   570 			}
       
   571 
       
   572 		// else if we had received an eol and this character is not nul
       
   573 		// we have ourselves a new line start
       
   574 
       
   575 		else
       
   576 			{
       
   577 			if (bol)
       
   578 				if (thisChar != Knul)
       
   579 					bol = 0;
       
   580 			}
       
   581 
       
   582 		// if we have a nul, add 8 to our trailing zero bits
       
   583 		// else count them by hand
       
   584 
       
   585 		if (thisChar == Knul)
       
   586 			trailing0s += 8;
       
   587 		else
       
   588 			trailing0s = zerotable[thisChar][1];
       
   589 
       
   590 		// ignore multiple eols
       
   591 
       
   592 		if (bol > 1)
       
   593 			continue;
       
   594 
       
   595 		// save everything else - we've already inverted the data if needed
       
   596 
       
   597 		*currentByte++ = thisChar;
       
   598 		if (currentByte == lineEnd)
       
   599 			{
       
   600 			return (KMaxT4Des);
       
   601 			}
       
   602 		}
       
   603 }
       
   604 /********************************************************************/
       
   605 
       
   606 TInt CFaxModemDriver::TxStartPageL ()
       
   607 {
       
   608 	iModem->iProgress.iPhase = EDataTransfer;
       
   609 	iModem->iProgress.iLines = 0;
       
   610 	iModem->iOurMessage.Format (_L8 ("About to send page %u"), ++iModem->iProgress.iPage);
       
   611 	iModem->ProgressUpdateL ();
       
   612 	iModem->Xonon ();
       
   613 
       
   614 	// for class 1 modems we start each page with a short burst of binary 1s
       
   615 
       
   616 	if (iFaxServerSessionSettings->iFaxClass == EClass1)
       
   617 		{
       
   618 		for (TInt x = (iActualFaxSpeed * 20 / 8); x; x--)
       
   619 			{
       
   620 			iModem->iTransmitBuffer.Append (0xff);
       
   621 			iModem->SendTransmitBufferL ();
       
   622 			}
       
   623 		iModem->CommitTransmitBufferL ();
       
   624 		}
       
   625 
       
   626 	// we're now in phase C so we start the page by sending the fax header
       
   627 
       
   628 	SendFaxHeaderL ();
       
   629 	return (KErrNone);
       
   630 }
       
   631 /********************************************************************/
       
   632 
       
   633 TInt CFaxModemDriver::RxStartPageL ()
       
   634 {
       
   635 	TUint8 thisChar, leading0s, trailing0s = 0;
       
   636 	TInt ticks = CLK_TCK * KLineReadTimeout;
       
   637 	if (iModem->iProgress.iECM != 0)
       
   638 		ticks = CLK_TCK * KECMLineReadTimeout;  // ECM mode requires longer time-outs due to retries
       
   639 
       
   640 	iModem->iProgress.iPhase = EDataTransfer;
       
   641 	iModem->iProgress.iLines = 0;
       
   642 	iModem->iOurMessage.Format (_L8 ("Awaiting page %u"), ++iModem->iProgress.iPage);
       
   643 	iModem->ProgressUpdateL ();
       
   644 	trailing0s = 0;
       
   645 
       
   646 	// this function looks for the start of the received fax
       
   647 	// this is the first EOL code - we invert bytes for non-class 2 modems
       
   648 
       
   649 	for (;;)
       
   650 		{
       
   651 		if ((iModem->RxcharWaitL (ticks)) == 0)
       
   652 			return (KFaxErrReceiveTimeout);
       
   653 		thisChar = iModem->iReadone[0];
       
   654 		if (iFaxServerSessionSettings->iFaxClass != EClass2)
       
   655 			thisChar = Invert (thisChar);
       
   656 		leading0s = zerotable[thisChar][0];
       
   657 		if (((trailing0s + leading0s) > 10) && (thisChar != 0))
       
   658 			break;
       
   659 		if (thisChar == Knul)
       
   660 			trailing0s += 8;
       
   661 		else
       
   662 			trailing0s = zerotable[thisChar][1];
       
   663 		}
       
   664 
       
   665 	// we've found the first EOL - it's left in iModem->iReadone[0]
       
   666 
       
   667 	iModem->iOurMessage.Format (_L8 ("Receiving data .... "));
       
   668 	iModem->ProgressUpdateL ();
       
   669 	return (KErrNone);
       
   670 }
       
   671 /********************************************************************/
       
   672 
       
   673 TInt CFaxModemDriver::RxConnectL ()
       
   674 {
       
   675 	return (KFaxErrWrongModemType);
       
   676 }
       
   677 TInt CFaxModemDriver::RxPrePageL ()
       
   678 {
       
   679 	return (KFaxErrWrongModemType);
       
   680 }
       
   681 TInt CFaxModemDriver::RxPostPageL ()
       
   682 {
       
   683 	return (KFaxErrWrongModemType);
       
   684 }
       
   685 TInt CFaxModemDriver::TxConnectL ()
       
   686 {
       
   687 	return (KFaxErrWrongModemType);
       
   688 }
       
   689 TInt CFaxModemDriver::TxPrePageL ()
       
   690 {
       
   691 	return (KFaxErrWrongModemType);
       
   692 }
       
   693 TInt CFaxModemDriver::TxPostPageL ()
       
   694 {
       
   695 	return (KFaxErrWrongModemType);
       
   696 }
       
   697 /********************************************************************/
       
   698 
       
   699 
       
   700 
       
   701