telephonyserver/etelserverandcore/SETEL/ET_PHONE.CPP
branchopencode
changeset 24 6638e7f4bd8f
parent 0 3553901f7fa8
child 32 58332560b319
--- a/telephonyserver/etelserverandcore/SETEL/ET_PHONE.CPP	Mon May 03 13:37:20 2010 +0300
+++ b/telephonyserver/etelserverandcore/SETEL/ET_PHONE.CPP	Thu May 06 15:10:38 2010 +0100
@@ -1,2282 +1,2564 @@
-// 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:
-//
-
-/**
- @file
-*/
-
-#include "ET_SSTD.H"
-#include "et_record.h"
-#include "et_phone_util.h"
-
-//
-// CReqEntry class definitions
-//
-
-CReqEntry* CReqEntry::NewL(TTsyReqHandle aTsyReqHandle, const RMessage2& aMessage, CTelSession* aSession, CBuffer* aBuffer, const CTelObject* aTelObject, TInt aFunction, RHeap* aHeap)
-//
-//	Create new request entry.  aHeap should be NULL unless this is to be allocated on the 
-//	priority client heap.
-//
-	{
-	if (aHeap != NULL)
-		{
-		return new(aHeap) CReqEntry(aTsyReqHandle,aMessage,aSession,aBuffer,aTelObject,aFunction,aHeap);
-		}
-
-	return new(ELeave) CReqEntry(aTsyReqHandle,aMessage,aSession,aBuffer,aTelObject,aFunction,NULL);
-	}
-
-
-CReqEntry::CReqEntry(TTsyReqHandle aTsyReqHandle,const RMessage2& aMessage,CTelSession* aSession,CBuffer* aBuffer,const CTelObject* aTelObject,TInt aFunction,RHeap* aHeap)
-//
-//	CReqEntry constructor
-//
-	: iTsyReqHandle(aTsyReqHandle), iMessage(aMessage), iSession(aSession), iTelObject(aTelObject),
-	iClientInterested(ETrue), iCancelFnCalled(EFalse), iFunction(aFunction), iBuffer(aBuffer), 
-	iReadByClient(ETrue), iMessageNulled(EFalse), iHeap(aHeap)
-	{}
-
-CReqEntry::~CReqEntry()
-//
-//	CReqEntry destructor
-//
-	{
-	delete iBuffer;
-	}
-
-void CReqEntry::Deque()
-//
-//	Deque CReqEntry list
-//
-	{
-	iLink.Deque();
-	iLink.iPrev=iLink.iNext=NULL;
-	}
-
-void CReqEntry::CompleteAndDeque(TInt aError)
-	{
-	LOGTEXT("CReqEntry::CompleteAndDeque");
-	// if client does not interested in this request do not completed
-	if (iClientInterested) 
-		{		
-		RECORD_COMPLETE_SUB(iMessage.Session(), iTelObject, iMessage.Int3(), iMessage.Function(), aError);
-		iMessage.Complete(aError);
-		}
-		
-	iLink.Deque();
-	}
-
-TAny* CReqEntry::operator new(TUint aSize,RHeap* aHeap) __NO_THROW
-//
-// overloaded new using the priority client heap - can leave
-//
-	{
-	TAny *pM=NULL;
-	TRAPD(err, pM=aHeap->AllocL(aSize) );
-	
-	if(err!=KErrNone)
-		pM = NULL;
-	else
-		Mem::FillZ(pM,aSize);
-	return(pM);
-	}
-
-TAny* CReqEntry::operator new(TUint aSize) __NO_THROW
-	{
-	return CBase::operator new(aSize);
-	}
-	
-TAny* CReqEntry::operator new(TUint aSize,TLeave aLeave)
-	{
-	return CBase::operator new(aSize,aLeave);
-	}
-
-TAny* CReqEntry::operator new(TUint aSize,TUint aExtraSize) __NO_THROW
-	{
-	return CBase::operator new(aSize,aExtraSize);
-	}
-
-void CReqEntry::operator delete(TAny* aPtr)
-//
-// overloaded delete - deletes from priority client heap if iHeap is not NULL
-//
-	{
-	if (((CReqEntry*)aPtr)->iHeap!=NULL)
-		((CReqEntry*)aPtr)->iHeap->Free(aPtr);
-	else
-		User::Free(aPtr);
-	}
-	
-//
-//	CBuffer class definitions
-//
-CBuffer* CBuffer::NewL(HEtelBufC8* aBuf8,HEtelBufC16* aBuf16,RHeap* aHeap,TInt aSizeOfData1,TInt aSizeOfData2,TInt aNoOfSlots)
-	{
-	if (aHeap!=NULL)
-		return new(aHeap) CBuffer(aBuf8,aBuf16,aHeap,aSizeOfData1,aSizeOfData2,aNoOfSlots);
-
-	return new(ELeave) CBuffer(aBuf8,aBuf16,NULL,aSizeOfData1,aSizeOfData2,aNoOfSlots);
-	}
-
-CBuffer::CBuffer(HEtelBufC8* aBuf8,HEtelBufC16* aBuf16,RHeap* aHeap,TInt aSizeOfData1,TInt aSizeOfData2,TInt aNoOfSlots)
-	: iBuf8(aBuf8),iBuf16(aBuf16),iHeap(aHeap),iRead(0),iWrite(0),iNoOfSlots(aNoOfSlots),
-		iSizeOfData1(aSizeOfData1),iSizeOfData2(aSizeOfData2),
-		iOverFlow(EFalse),iBufferFull(EFalse)
-	{}
-
-CBuffer::~CBuffer()
-	{
-	delete iBuf8;
-	delete iBuf16;
-	}
-
-TAny* CBuffer::operator new(TUint aSize,RHeap* aHeap) __NO_THROW
-//
-// overloaded new using the priority client heap - can leave
-//
-	{
-	TAny *pM=NULL;
-	TRAPD(err, pM=aHeap->AllocL(aSize) );
-	
-	if(err!=KErrNone)
-		pM = NULL;
-	else
-		Mem::FillZ(pM,aSize);
-	return(pM);
-	}
-
-TAny* CBuffer::operator new(TUint aSize) __NO_THROW
-	{
-	return CBase::operator new(aSize);
-	}
-	
-TAny* CBuffer::operator new(TUint aSize,TLeave aLeave)
-	{
-	return CBase::operator new(aSize,aLeave);
-	}
-
-TAny* CBuffer::operator new(TUint aSize,TUint aExtraSize) __NO_THROW
-	{
-	return CBase::operator new(aSize,aExtraSize);
-	}
-
-void CBuffer::operator delete(TAny* aPtr)
-//
-// overloaded delete - deletes from priority client heap if iHeap not NULL
-//
-	{
-	if (((CBuffer*)aPtr)->iHeap!=NULL)
-		((CBuffer*)aPtr)->iHeap->Free(aPtr);
-	else
-		User::Free(aPtr);
-	}
-
-TUint CBuffer::Size() const
-	{
-	return iSizeOfData1 + iSizeOfData2;
-	}
-	
-void CBuffer::IncRead()
-	{
-	if(++iRead==iNoOfSlots)
-		iRead=0;
-	iOverFlow=EFalse;
-	iBufferFull=EFalse;
-	LOGTEXT2("ETel:\tiRead incremented to %d", iRead);
-	}
-
-void CBuffer::IncWrite()
-	{
-	if(++iWrite==iNoOfSlots)
-		iWrite=0;
-	if (iOverFlow)
-		 iRead=iWrite;
-	else
-		{
-		if (!iBufferFull)
-			{
-			if (iWrite==iRead)
-				iBufferFull=ETrue;
-			}
-		else
-			{
-			iRead=iWrite;
-			iOverFlow=ETrue;
-			}
-		}
-	LOGTEXT2("ETel:\tiWrite incremented to %d", iWrite);
-	}
-
-TUint8* CBuffer::CurrentSlotData1(TWhichSlot aWhichSlot) const
-//
-// iSizeOfData1 and iSizeOfData2 include the sizes of the TPtr's
-//
-	{
-	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
-
-	if (iBuf8==NULL)
-		{
-		return NULL;
-		}
-	else if (iBuf16==NULL)
-		{
-		TInt slotSize = iSizeOfData1 + iSizeOfData2;
-		return (const_cast<TUint8*> (iBuf8->Des().Mid(pos*(slotSize),iSizeOfData1-sizeof(TPtr8)).Ptr()));
-		}
-	else
-		{
-		// we have a narrow and a unicode parameter. Data1 is always narrow
-		return (const_cast<TUint8*> (iBuf8->Des().Mid(pos*iSizeOfData1,iSizeOfData1-sizeof(TPtr8)).Ptr()));
-		}
-	}
-
-TUint8* CBuffer::CurrentSlotData2(TWhichSlot aWhichSlot) const
-	{
-	if (iSizeOfData2==0)
-		return NULL;
-	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
-
-	if (iBuf8!=NULL  &&  iBuf16==NULL)
-		{
-		TInt slotSize = iSizeOfData1 + iSizeOfData2;
-		return (const_cast<TUint8*> (iBuf8->Des().Mid(pos*(slotSize)+iSizeOfData1,iSizeOfData2-sizeof(TPtr8)).Ptr()));
-		}
-
-	return NULL;
-	}
-
-TUint16* CBuffer::CurrentSlotData1u(TWhichSlot aWhichSlot) const
-//
-// Unicode version
-//
-	{
-	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
-
-	if (iBuf8==NULL  &&  iBuf16!=NULL)
-		{
-		TInt slotSize = iSizeOfData1 + iSizeOfData2;
-		return (const_cast<TUint16*> (iBuf16->Des().Mid(pos*(slotSize),iSizeOfData1-sizeof(TPtr16)).Ptr()));
-		}
-
-	return NULL;	// Data1 will be narrow if we have a mixture of both 8 and 16 bit
-	}
-
-TUint16* CBuffer::CurrentSlotData2u(TWhichSlot aWhichSlot) const
-//
-// Unicode version
-//
-	{
-	if (iSizeOfData2==0)
-		return NULL;
-	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
-
-	if (iBuf16==NULL)
-		{
-		return NULL;
-		}
-	else if (iBuf8==NULL)
-		{
-		TInt slotSize = iSizeOfData1 + iSizeOfData2;
-		return (const_cast<TUint16*> (iBuf16->Des().Mid(pos*(slotSize)+iSizeOfData1,iSizeOfData2-sizeof(TPtr16)).Ptr()));
-		}
-	else
-		{
-		// we have a narrow and a unicode parameter. Data2 is always unicode
-		return (const_cast<TUint16*> (iBuf16->Des().Mid(pos*iSizeOfData2,iSizeOfData2-sizeof(TPtr16)).Ptr()));
-		}
-	}
-
-TBool CBuffer::EqualSizes(TInt aSize1, TInt aSize2) const
-    {
-    if(iSizeOfData1 != aSize1)
-        {
-        return EFalse;
-        }
-    if(iSizeOfData2 != aSize2)
-        {
-        return EFalse;
-        }
-    return ETrue;
-    }
-
-TInt CBuffer::CompareRWPtrs() const
-	{
-	return (iRead-iWrite);
-	}
-
-//
-//
-// CTelObject class definitions
-//
-
-EXPORT_C CTelObject::CTelObject()
-//
-// CTelObject constructor
-//
-	:iActiveReqCount(0), iTelServer(NULL), iDestroyDummySubSession(NULL), iCreateDummy(EFalse)
-	{
-	__DECLARE_NAME(_S("CTelObject"));
-	}
-
-EXPORT_C CTelObject::~CTelObject()
-//
-// Destructor
-//
-	{
-	delete iDestroyDummySubSession;
-	}
-
-EXPORT_C void CTelObject::CTelObject_Reserved1()
-//
-// Reserved virtual function
-//
-	{}
-
-void CTelObject::CreateDummySessionObjectL(CTelSession* aTelSession)
-	{
-	if (iDestroyDummySubSession==NULL)
-		{
-		LOGTEXT("CDestroyDummySubSession object does not already exist and will be created.");
-		iDestroyDummySubSession = CDestroyDummySubSession::NewL(aTelSession->TelServer(),this);
-		}
-	else
-		{
-		LOGTEXT("CDestroyDummySubSession object already exists and will not be created");
-		}
-
-	}
-	
-void CTelObject::CreateDummySession(CTelSession* aSession, const TInt aSubSessionHandle, TBool aCreateDummy)
-//
-// So the server has to create a dummy session just to keep session alive until completed
-// function is called.
-//
-	{
-	LOGTEXT2("CreateDummySession() with iDestroyDummySubSession = %x", iDestroyDummySubSession);
-	iCreateDummy=aCreateDummy;
-	
-	if (iDestroyDummySubSession->iOpen == EFalse)
-		{
-		if ( IsActiveReq(aSession,aSubSessionHandle) || aCreateDummy)
-			{
-			LOGTEXT("About to create dummy session");
-			__ASSERT_ALWAYS(aSession!=NULL,Fault(EEtelFaultBadTelSessionPointer));
-			CObject* theObj=this;
-			while(theObj->Owner())
-				{
-				theObj->Open();
-				theObj=theObj->Owner();
-				}
-			theObj->Open();
-			iTelServer=aSession->TelServer();
-	
-			// incrementing the server's session count to include the dummy session, which
-			// has been previously allocated upon the CTelObject creation (by calling
-			// CreateDummySessionObjectL() )
-			iTelServer->Inc();
-			LOGTEXT2("Added a Dummy Session, producing server's session count of %d", iTelServer->Count());
-				
-			iDestroyDummySubSession->iTelServer = iTelServer;
-			iDestroyDummySubSession->iTelObject = this;
-			iDestroyDummySubSession->iOpen = ETrue;
-			}
-		}
-	}
-	
-void CTelObject::TelObjectClose()
-//
-// Perform an iterative close of Tel Objects
-//
-	{	
-	CTelObject* owner = reinterpret_cast<CTelObject*> (Owner());
-	Close();
-	if(owner)
-		owner->TelObjectClose();
-	}
-
-void CTelObject::CompleteAndDestroyReq(CReqEntry* aReqEntry,const TInt aStatus) const
-//
-//	complete the entry and remove from entry list and associate heap
-//
-	{
-	if (!aReqEntry->iMessageNulled)
-		{
-		RECORD_COMPLETE_SUB(aReqEntry->iMessage.Session(), this, aReqEntry->iMessage.Int3(), aReqEntry->iMessage.Function(), aStatus);
-		aReqEntry->iMessage.Complete(aStatus);
-		}
-	DestroyReq(aReqEntry);
-	}
-
-void CTelObject::DestroyReq(CReqEntry* aReqEntry) const
-//
-//	remove from entry list and associate heap
-//
-	{
-	aReqEntry->Deque();
-	delete aReqEntry;
-	}
-
-TBool CTelObject::IsActiveReq(CTelSession* aSession,const TInt aSubSessionHandle)
-//
-// Return True if found the active req still out standing
-// going through and counting the total of active req
-//
-	{
-	TBool ret=EFalse;
-	CReqEntry* reqEntry=NULL;
-	TDblQueIter<CReqEntry> iter(PhoneOwner()->ReqActiveList());
-	while(reqEntry=iter++,reqEntry!=NULL) // go through the list from begin to end
-		{
-		if (aSession==reqEntry->iSession && aSubSessionHandle==reqEntry->iMessage.Int3() &&	reqEntry->iClientInterested )
-			{
-			iActiveReqCount++;
-			ret=ETrue;
-			}
-		}
-	LOGTEXT2("IsActiveReq found %d active reqs", iActiveReqCount);
-	return ret;
-	}
-
-void CTelObject::CancelActiveReq(CTelSession* aSession,const TInt aSubSessionHandle)
-//
-// active list - must inform tsy by calling CancelService
-// this request will be destroyed when Tsy do an up call ReqCompleted with KErrCancel
-// Only go through the list once set the count to zero at start to count number of requests 
-//
-	{
-	LOGTEXT("Entered CancelActiveReq");
-	CReqEntry* reqEntry=NULL;
-	TDblQueIter<CReqEntry> iter(PhoneOwner()->ReqActiveList());
-	while(reqEntry=iter++,reqEntry!=NULL) // go through the list from begin to end
-		{
-		if (aSession==reqEntry->iSession && aSubSessionHandle==reqEntry->iMessage.Int3() &&	reqEntry->iClientInterested )
-			{
-			reqEntry->iClientInterested=EFalse;
-			__ASSERT_ALWAYS(iActiveReqCount>=0,Fault(EEtelFaultNegativeActiveReqCount));
-			if (reqEntry->iCancelFnCalled==FALSE)
-				{
-				if (reqEntry->iPlacedRequest)
-					{
-					LOGTEXT2("Calling Cancel Service ActiveReq TsyReq=%d", reqEntry->iTsyReqHandle);
-					reqEntry->iCancelFnCalled=ETrue;
-					CancelService(reqEntry->iFunction,reqEntry->iTsyReqHandle);
-					
-					//
-					// In calling CancelService() it is possible that a second
-					// handle has performed the same request (e.g. a notify) and
-					// that ETel will re-post the notify using that handle. In
-					// some cases it could happen that the re-posted notify is
-					// invalid and fails, thereby completing that next request.
-					// Finally, if that request is the next one after this one,
-					// then the iterator is going to be invalid. So reset it now
-					// and start at the beginning of the list!
-					//
-					if (PhoneOwner()->ReqActiveList().IsEmpty() == EFalse)
-						{
-						iter.Set(*PhoneOwner()->ReqActiveList().First());
-						}
-					else
-
-						{
-						break;
-						}
-					}
-				else
-					{
-					LOGTEXT("Destroying request");
-					DestroyReq(reqEntry);
-					CheckAndDestroyDummySubSession();
-					}
-				}
-			}
-		}
-	}
-
-void CTelObject::CancelSubSession(CTelSession* aSession,const TInt aSubSessionHandle)
-//
-// Flush outstanding requests from the queue for this client only
-// Cancel the service if request already passed to Tsy
-//
-	{
-	CReqEntry* reqEntry=NULL;
-	while (reqEntry=PhoneOwner()->FindClientReqInWaitList(aSession,aSubSessionHandle),reqEntry)
-		CompleteAndDestroyReq(reqEntry,KErrCancel);
-
-	CancelActiveReq(aSession,aSubSessionHandle);
-	}
-
-void CTelObject::FlushReqs(CTelSession* aSession,const TInt aSubSessionHandle)
-//
-// Flush outstanding requests from the queue for this client only
-// Cancel the service if request already passed to Tsy
-// Return ETrue if it have to create a dummy session
-//
-	{
-	CReqEntry* reqEntry=NULL;
-	// wait list
-	while (reqEntry=PhoneOwner()->FindClientReqInWaitList(aSession,aSubSessionHandle),reqEntry)
-		DestroyReq(reqEntry);
-
-	CancelActiveReq(aSession,aSubSessionHandle);
-
-	}
-
-CPhoneBase* CTelObject::PhoneOwner() const
-//
-// Get the owner handle
-//
-	{
- 	return iPhoneOwner;
-	}
-
-void CTelObject::SetPhoneOwner(CPhoneBase* aPhoneOwner)
-//
-// Set the owner of phone
-//
-	{
-	iPhoneOwner=aPhoneOwner;
-	}
-
-void CTelObject::GetMessageDescriptorSizes(const RMessage2& aMessage,TInt &aSize1, TInt &aSize2) const
-    {
-    TInt messageType=aMessage.Int1();
-    aSize1=0;
-    aSize2=0;
-
-    if (messageType!=EIsaNull &&
-        messageType!=EIsaCancelMessage &&
-        messageType!=EIsPriorityClientReqWithNull)
-        {                       // we're going to create server-side buffer
-        TInt basicMsgType = messageType&(~(KUnicodeReq|KPriorityClientReq));
-
-        if (messageType==EIsaNarrowAndUnicodeDoubleDesTobeSet)
-            basicMsgType=EIsaDoubleDesTobeSet;
-        if (messageType==EIsaNarrowAndUnicodeDoubleDesTobeRead)
-            basicMsgType=EIsaDoubleDesTobeRead;
-
-        switch (basicMsgType)
-            {
-        case EIsaDoubleDesTobeSet:// if we're setting data, get length
-            aSize2=aMessage.GetDesLength(2); // no break
-        case EIsaDesTobeSet:
-            aSize1=aMessage.GetDesLength(0);
-            break;
-        case EIsaDoubleDesTobeRead:// if we're reading data, get max length
-            aSize2=aMessage.GetDesMaxLength(2);  // no break
-        case EIsaDesTobeRead:
-            aSize1=aMessage.GetDesMaxLength(0);
-            break;
-        case EIsaNarrowDesToSetAndGet:
-            aSize1=aMessage.GetDesLength(0);    // set data
-            aSize2=aMessage.GetDesMaxLength(2); // get data
-            break;
-        case EIsaNarrowDesToGetUnicodeDesToSet:
-            aSize1=aMessage.GetDesMaxLength(0); // get data
-            aSize2=aMessage.GetDesLength(2);    // set data
-            break;
-        case EIsaUnicodeDesToSetAndGet:
-            aSize1=aMessage.GetDesLength(0);     // set data
-            aSize2=aMessage.GetDesMaxLength(2);  // get data
-            break;
-        case EIsaUnicodeDesToGetNarrowDesToSet:
-            aSize1=aMessage.GetDesLength(0);      // set data
-            aSize2=aMessage.GetDesMaxLength(2);    // get data
-            break;
-        default:
-            PanicClient(EEtelPanicInvalidRequestType,aMessage);
-            break;
-            }
-        }
-    }
-
-TBool CTelObject::IsSameMessageType(const RMessage2& aMessage,CReqEntry* aReqEntry) const
-    {
-    TInt size1;
-    TInt size2;
-    TInt ptrSize=sizeof(TPtr8);
-    GetMessageDescriptorSizes(aMessage, size1, size2);
-
-    if(size1)
-        {
-        CheckAndResize(size1,aMessage);
-        size1+=ptrSize;
-        }
-    if (size2)
-        {
-        CheckAndResize(size2,aMessage);
-        size2+=ptrSize;
-        }
-    if(aReqEntry->iBuffer->EqualSizes(size1,size2))
-        {
-        return ETrue;
-        }
-    return EFalse;
-    }
-
-void CTelObject::CompleteOrBufferRead(const RMessage2& aMessage, CReqEntry* aReqEntry) 
-//
-//	Check and complete if possible this notification/multislot command from 
-//	this subsession in the ReqActive list
-//	aMessage is the message just received from the client
-//	aReqEntry is the Entry previously created when the same client called the same function
-//
-	{
-	if(aReqEntry->iMessageNulled==FALSE)	// same client already posted this notification
-		{
-		PanicClient(EEtelPanicRequestAsyncTwice,aMessage);
-		return;
-		}
-    TInt slots=0;
-    TRAP_IGNORE(slots = NumberOfSlotsL(aReqEntry->iFunction));
-    TBool sameMessageType = IsSameMessageType(aMessage, aReqEntry); 
-    
-	if (slots>1)
-		{
-		TInt comparison = aReqEntry->iBuffer->CompareRWPtrs();
-		if (comparison==0 && aReqEntry->iBuffer->BufferFull()==FALSE)
-			{	// if the client has already read value,the automatic server-TSY 
-				// notify request becomes the "true" request
-			if(sameMessageType)
-			    {
-			    aReqEntry->iMessage=aMessage;	
-			    aReqEntry->iMessageNulled=EFalse;
-			    }
-			else
-			    {
-			    // cancel in ctsy
-                aReqEntry->iCancelFnCalled = ETrue;
-			    CancelService(aReqEntry->iFunction, aReqEntry->iTsyReqHandle);
-                aReqEntry->iCancelFnCalled = EFalse;
-			    GeneralReq(aMessage,aReqEntry->iSession,NULL);
-			    }
-			}
-		else
-			{
-			if (aReqEntry->iBuffer->OverFlow())
-				WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrOverflow);
-			else
-			    {
-			    if(sameMessageType)
-			        {
-			        WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrNone);
-			        }
-			    else
-			        {
-			        WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrOverflow);
-			        }
-			    }
-			}
-		}
-	else			// this is a non-registered notification (ie single-slot)
-		{
-		if(aReqEntry->iReadByClient)
-			{
-			if(sameMessageType)
-			    {
-			    aReqEntry->iMessage=aMessage;
-			    aReqEntry->iMessageNulled=EFalse;
-			    }
-			else
-			    {
-                CancelService(aReqEntry->iFunction, aReqEntry->iTsyReqHandle);
-                GeneralReq(aMessage,aReqEntry->iSession,NULL);
-			    }
-			}
-		else	// Client has not read this new value yet
-			{
-			if(sameMessageType)
-			    {
-			    WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrNone);
-			    }
-			else
-			    {
-			    WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrOverflow);
-			    }
-			}
-		}
-	}
-
-void CTelObject::CheckAndResize(TInt& aSizeOfData,const RMessage2& aMessage) const
-//
-//	Checks that size of data is non-zero - if not, panic client.
-//  Also checks that size of data is word-aligned, ie a multiple of 4 bytes. 
-//	If not, ensure that in the space in buffer for data is word-aligned.
-//
-	{
-	if(aSizeOfData<0)
-		PanicClient(EEtelPanicDesLengthNegative,aMessage);
-	aSizeOfData=(aSizeOfData+3)&~3;
-	}
-
-HEtelBufC8* CTelObject::CreateNarrowBufferLC(RHeap* aHeap,const RMessage2& aMessage,TUint aIndexOfClientPtr1,TUint aIndexOfClientPtr2,TInt& aSize1,TInt& aSize2,TInt aNoOfSlots) const
-//
-//	aSize1 = size of 1st descriptor buffer
-//	aSize2 = size of 2nd descriptor buffer (default=0)
-//  aHeap may be NULL if the priority heap is not to be used
-//	aNoOfSlots will usually be 1. Only if this request is a notification that requires 
-//	registering, ie increasing the number of events the server will buffer, will it be greater than 1
-//
-	{
-	TInt desSize1=aSize1;
-	TInt desSize2=aSize2;
-	CheckAndResize(aSize1,aMessage);
-	
-	TInt ptrSize=sizeof(TPtr8);
-	TInt allocSize=aSize1+ptrSize;
-	if (aSize2)
-		{
-		CheckAndResize(aSize2,aMessage);
-		allocSize += aSize2+ptrSize;
-		}
-	HEtelBufC8* buf = HEtelBufC8::NewMaxLC(allocSize*aNoOfSlots,aHeap);	// allocate a buffer for the Des and Data				
-
-	TPtr8 firstptrDes1(const_cast<TUint8*> (buf->Des().Left(ptrSize).Ptr()),ptrSize,ptrSize);			// carve the thing up
-	TPtr8 firstdataDes1(const_cast<TUint8*> (buf->Des().Mid(ptrSize,aSize1).Ptr()),desSize1,desSize1);
-	TPtr8 firstdataDes2(NULL,0,0);
-	aMessage.ReadL(aIndexOfClientPtr1,firstdataDes1);// Read the Data. If it leaves, buf will be cleaned up
-	firstptrDes1.Copy(reinterpret_cast<TUint8*> (&firstdataDes1),ptrSize);	// Copy the new Des
-	if (aSize2)
-		// Construct Second descriptor
-		{
-		TPtr8 firstptrDes2(const_cast<TUint8*> (buf->Des().Mid(ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
-		firstdataDes2.Set(const_cast<TUint8*> (buf->Des().Mid((ptrSize*2)+aSize1,aSize2).Ptr()),desSize2,desSize2);
-		aMessage.ReadL(aIndexOfClientPtr2,firstdataDes2);
-		firstptrDes2.Copy(reinterpret_cast<TUint8*> (&firstdataDes2),ptrSize);
-		}
-	for (TInt i=1; i<aNoOfSlots;i++)	
-		{// Copy descriptors into each slot
-		TPtr8 ptrDes1(const_cast<TUint8*> (buf->Des().Mid(i*allocSize,ptrSize).Ptr()),ptrSize,ptrSize);
-		TPtr8 dataDes1(const_cast<TUint8*> (buf->Des().Mid(i*allocSize+ptrSize,aSize1).Ptr()),desSize1,desSize1);
-		dataDes1.Copy(firstdataDes1);
-		ptrDes1.Copy(reinterpret_cast<TUint8*> (&dataDes1),ptrSize);
-		if (aSize2)
-			{
-			TPtr8 ptrDes2(const_cast<TUint8*> (buf->Des().Mid(i*allocSize+ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
-			TPtr8 dataDes2(const_cast<TUint8*> (buf->Des().Mid(i*allocSize+(ptrSize*2)+aSize1).Ptr()),desSize2,desSize2);
-			dataDes2.Copy(firstdataDes2);
-			ptrDes2.Copy(reinterpret_cast<TUint8*> (&dataDes2),ptrSize);
-			}
-		}
-	return buf;
-	}
-
-HEtelBufC16* CTelObject::CreateUnicodeBufferLC(RHeap* aHeap,const RMessage2& aMessage,TUint aIndexOfClientPtr1,TUint aIndexOfClientPtr2,TInt& aSize1,TInt& aSize2,TInt aNoOfSlots) const
-//
-//	We place both parameters in the same buffer which is either narrow or unicode (unicode in this case)
-//	Should a function ever require one parameter to be narrow and the other unicode,
-//	will need to review.
-//
-	{
-	TInt desSize1=aSize1;
-	TInt desSize2=aSize2;
-	CheckAndResize(aSize1,aMessage);
-	TInt ptrSize=sizeof(TPtr16);
-	TInt allocSize=aSize1+ptrSize;
-	if (aSize2)
-		{
-		CheckAndResize(aSize2,aMessage);
-		allocSize += aSize2+ptrSize;
-		}
-	HEtelBufC16* buf = HEtelBufC16::NewMaxLC(allocSize*aNoOfSlots,aHeap);	// allocate a buffer for the Des and Data				
-
-	TPtr16 firstptrDes1(const_cast<TUint16*> (buf->Des().Left(ptrSize).Ptr()),ptrSize,ptrSize);			// carve the thing up
-	TPtr16 firstdataDes1(const_cast<TUint16*> (buf->Des().Mid(ptrSize,aSize1).Ptr()),desSize1,desSize1);
-	TPtr16 firstdataDes2(NULL,0,0);
-	aMessage.ReadL(aIndexOfClientPtr1,firstdataDes1);// Read the Data. If it leaves, buf will be cleaned up
-	firstptrDes1.Copy(reinterpret_cast<TUint16*> (&firstdataDes1),ptrSize);	// Copy the new Des
-	if (aSize2)
-		// Construct Second descriptor
-		{
-		TPtr16 firstptrDes2(const_cast<TUint16*> (buf->Des().Mid(ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
-		firstdataDes2.Set(const_cast<TUint16*> (buf->Des().Mid((ptrSize*2)+aSize1,aSize2).Ptr()),desSize2,desSize2);
-		aMessage.ReadL(aIndexOfClientPtr2,firstdataDes2);
-		firstptrDes2.Copy(reinterpret_cast<TUint16*> (&firstdataDes2),ptrSize);
-		}
-	for (TInt i=1; i<aNoOfSlots;i++)	
-		{// Copy descriptors into each slot
-		TPtr16 ptrDes1(const_cast<TUint16*> (buf->Des().Mid(i*allocSize,ptrSize).Ptr()),ptrSize,ptrSize);
-		TPtr16 dataDes1(const_cast<TUint16*> (buf->Des().Mid(i*allocSize+ptrSize,aSize1).Ptr()),desSize1,desSize1);
-		dataDes1.Copy(firstdataDes1);
-		ptrDes1.Copy(reinterpret_cast<TUint16*> (&dataDes1),ptrSize);
-		if (aSize2)
-			{
-			TPtr16 ptrDes2(const_cast<TUint16*> (buf->Des().Mid(i*allocSize+ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
-			TPtr16 dataDes2(const_cast<TUint16*> (buf->Des().Mid(i*allocSize+(ptrSize*2)+aSize1).Ptr()),desSize2,desSize2);
-			dataDes2.Copy(firstdataDes2);
-			ptrDes2.Copy(reinterpret_cast<TUint16*> (&dataDes2),ptrSize);
-			}
-		}
-	return buf;
-	}
-
-CReqEntry* CTelObject::ReqAnalyserL(const RMessage2& aMessage,CTelSession* aSession,TReqMode& aReqMode) 
-//
-// Analyse the request. First search for an entry from the same client for the same request,
-// and if found either panic if this is a non-buffered request(ie the request is already
-// pending) or look at the buffer to see if there is any unread data to complete with.
-// If the identical entry was not found and this is a request of type multiple completion, search 
-// for a similar one by a different client (on this TelObject) and if found simply create a new
-// entry with the same request handle that will be completed at the same time as the current
-// posted notification. 
-// If this request has not been found in the active or wait lists, create the necessary 
-// address space on server side
-//
-	{
-	HEtelBufC8* buf8=NULL;
-	HEtelBufC16* buf16=NULL;
-	CReqEntry* reqEntry=NULL;
-	
-	reqEntry = PhoneOwner()->FindSameClientEntry(aSession,aMessage.Int3(),aMessage.Function());
-	if (reqEntry) 
-		{	
-		if (aReqMode&KReqModeRePostImmediately)	
-			{
-			// same notification/buffered command has been found 
-			// and either the read has completed or it has been stored in
-			// the request entry waiting for the completion from the TSY.
-			CompleteOrBufferRead(aMessage,reqEntry);
-			}
-		else	// found an outstanding async req - panic
-			{
-			PanicClient(EEtelPanicRequestAsyncTwice,aMessage);
-			}
-		return NULL;
-		}
-	TInt messageType=aMessage.Int1();
-	TInt noOfSlots = 1;
-	if (aReqMode&KReqModeRePostImmediately)
-		noOfSlots = NumberOfSlotsL(aMessage.Function());
-    TInt size1;
-    TInt size2;
-	if (messageType!=EIsaNull &&
-		messageType!=EIsaCancelMessage &&
-		messageType!=EIsPriorityClientReqWithNull)
-		{						// we're going to create server-side buffer
-	    GetMessageDescriptorSizes(aMessage, size1, size2);
-		if (size1<0 || size2<0)
-			{
-			PanicClient(EEtelPanicBadDescriptor,aMessage);
-			return NULL;
-			}
-		if (messageType==EIsaNarrowAndUnicodeDoubleDesTobeSet || 
-			messageType==EIsaNarrowAndUnicodeDoubleDesTobeRead ||
-			messageType==EIsaNarrowDesToGetUnicodeDesToSet ||
-			messageType==EIsaUnicodeDesToGetNarrowDesToSet)
-			{
-			TInt zeroSize=0;
-
-			buf8 = CreateNarrowBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,zeroSize,noOfSlots);
-			buf16 = CreateUnicodeBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,2,NULL,size2,zeroSize,noOfSlots);	// the second client parameter pointer is passed as the first, so that the second parameter will be copied as the first
-			}
-		else 
-			if (messageType==EIsaUnicodeDesToSetAndGet)
-				buf16 = CreateUnicodeBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,size2,noOfSlots);
-
-		else
-			if (!(aSession->IsUnicodeReq(messageType)))
-				buf8 = CreateNarrowBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,size2,noOfSlots);
-
-			else
-				buf16 = CreateUnicodeBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,size2,noOfSlots);	
-		size1+=sizeof(TPtr);	// passed into CBuffer::NewL() later as these sizes
-		if (size2!=0)	// remain zero otherwise
-			size2+=sizeof(TPtr);	//sizeof(TPtr)==sizeof(TPtr8)==sizeof(TPtr16)
-		}
-	else
-	    {
-	    size1 = 0;
-	    size2 = 0;
-	    }
-	//
-	//	Now create the wrapper class, which manages the circular buffer. 
-	//
-	CBuffer* buffer = CBuffer::NewL(buf8,buf16,aSession->EmergencyClientHeap(messageType),size1,size2,noOfSlots);
-	if (buf8)
-		CleanupStack::Pop();	// pops HEtelBufC8 off cleanup stack
-	if (buf16)
-		CleanupStack::Pop();	// pops HEtelBufC16 off cleanup stack
-	CleanupStack::PushL(buffer);	// since buffer is still not owned by anything
-	//
-	// Now create the request entry for this client request - even if it's not to be passed
-	// down to the TSY in the case of MultipleCompletion.
-	//
-	reqEntry=PhoneOwner()->NewReqL(aMessage,aSession,buffer,this,aMessage.Function());
-	CleanupStack::Pop();
-	if (aReqMode&KReqModeMultipleCompletionEnabled)
-				// this client has not currently got this request outstanding
-				// but another client may have 
-		{
-		CReqEntry* previousReq=NULL;
-		previousReq=PhoneOwner()->FindByIpcAndTelObject(aMessage.Function(),this, buffer->Size());	// search in active list
-		if (previousReq)
-			{
-			reqEntry->iTsyReqHandle=previousReq->iTsyReqHandle;
-			reqEntry->iReqMode=aReqMode;
-			PhoneOwner()->AddReqToActive(reqEntry);
-			reqEntry=NULL;
-			}
-		else if (aReqMode&KReqModeFlowControlObeyed)
-			{
-			previousReq=PhoneOwner()->FindByIpcAndTelObjectInWaiting(aMessage.Function(),this, buffer->Size());
-			if (previousReq)
-				{
-				reqEntry->iTsyReqHandle=previousReq->iTsyReqHandle;
-				reqEntry->iReqMode=aReqMode;
-				PhoneOwner()->AddReqToWaiting(reqEntry);
-				reqEntry=NULL;
-				}
-			}
-		}
-	return reqEntry;
-	}
-
-void CTelObject::GeneralReq(const RMessage2& aMessage,CTelSession* aSession,CReqEntry* aNewReqEntry, TBool aFromFlowControlResume)
-//
-// On any CTelObject based class, do the general processing around sequential and parallel
-// request modes for the server, before calling the pure virtual Service in the class to do
-// the actual command.
-//
-	{
-
-	LOGTEXT2("CTelObject::GeneralReq - IPC=%d", aMessage.Function());
-	RECORD_IPC(aMessage,aSession,this,aFromFlowControlResume);
-	if (aFromFlowControlResume && !aFromFlowControlResume){	; } // avoid compiler warning when ETEL_RECORDER is not defined
-	
-	TInt type=aMessage.Int1();
-	CReqEntry* reqEntry=NULL;
-	TInt basicMsgType = type&(~(KUnicodeReq|KPriorityClientReq));
-	switch(basicMsgType)
-		{
-	case EIsaNull:
-	case EIsaDesTobeSet:
-	case EIsaDesTobeRead:
-	case EIsaDoubleDesTobeSet:
-	case EIsaDoubleDesTobeRead:
-	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
-	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
-	case EIsaNarrowDesToSetAndGet:
-	case EIsaNarrowDesToGetUnicodeDesToSet:
-	case EIsaUnicodeDesToSetAndGet:
-	case EIsaUnicodeDesToGetNarrowDesToSet:
-		{
-		TInt ipc=aMessage.Function();
-
-		TReqMode reqMode=0;
-		TRAPD(res,(reqMode=ReqModeL(ipc)));
-		if (res)
-			{
-			RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), res);
-			aMessage.Complete(res);
-			return;
-			}
-		if (aNewReqEntry==NULL)
-			{
-			TRAP(res,reqEntry=ReqAnalyserL(aMessage,aSession,reqMode));
-			if (res)
-				{
-				RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), res);
-				aMessage.Complete(res);
-				return;				
-				}
-			else 
-				if (reqEntry==NULL) // there was no need to construct another reqEntry, 
-						// or another reqEntry with identical IPC for a different client 
-						// has been added inside ReqAnalyserL()
-
-					return;
-			reqEntry->iReqMode = reqMode;	// so ReqCompleted() needn't ask for it again
-			}
-		else
-			reqEntry=aNewReqEntry;	// aNewReqEntry has just come from the waiting list
-				
-		if (reqMode&KReqModeFlowControlObeyed) // flow control obeyed
-			{
-			if (PhoneOwner()->FlowControl())
-				PhoneOwner()->AddReqToWaiting(reqEntry);
-			else 
-				{
-				PhoneOwner()->FlowControlInc();
-				if (aNewReqEntry==NULL)
-					PhoneOwner()->AddReqToActive(reqEntry);
-				res=Service(aMessage,reqEntry);
-				if (res!=KErrNone) // can not do the service to tsy properly
-					{
-					CompleteAndDestroyReq(reqEntry,res);
-					PhoneOwner()->FlowControlDec(); // Dec() as service is being abandoned
-					}
-				}
-			}
-		else // Ignored 
-			{
-			PhoneOwner()->AddReqToActive(reqEntry);
-			if (reqMode&KReqModeRePostImmediately)
-				res=RegisterNotification(ipc);	// this tells the TSY the first time any client
-												// calls a particular notification.
-			if (res!=KErrNone)
-				CompleteAndDestroyReq(reqEntry,res);
-			else
-				{	
-				res=Service(aMessage,reqEntry);	// down to the TSY
-				if (res!=KErrNone)
-					CompleteAndDestroyReq(reqEntry,res);
-				}
-			}
-		break;
-		}
-	case EIsaCancelMessage:
-		// This is for Cancel Req - Int0 contains the original IPC 
-		{
-		TInt cancelIpc=aMessage.Int0();
-		reqEntry=PhoneOwner()->FindClientInWaiting(aSession,aMessage.Int3(),cancelIpc);
-		if(reqEntry!=NULL)				// Is it Waiting to be passed to the TSY?
-			{
-			CompleteAndDestroyReq(reqEntry,KErrCancel);	// If yes then complete it.
-			RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
-			aMessage.Complete(KErrNone);
-			return;
-			}
-		reqEntry=PhoneOwner()->FindClientInActive(aSession,aMessage.Int3(),cancelIpc);
-		if(reqEntry) // found in active list
-			{
-			TReqMode reqMode=0;
-			TRAPD(res,(reqMode=ReqModeL(reqEntry->iFunction)));
-			if (res)
-				{
-				// client cannot check return value of Cancel()
-				// so use return value of original function call
-				RECORD_COMPLETE_SUB(reqEntry->iMessage.Session(), this, reqEntry->iMessage.Int3(), reqEntry->iMessage.Function(), res);
-				reqEntry->iMessage.Complete(res);
-				return;
-				}
-			if (reqMode&KReqModeRePostImmediately && reqEntry->iMessageNulled)	
-				{
-				// client has called Cancel on a notification
-				// after it had completed to the client
-				RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
-				aMessage.Complete(KErrNone);
-				return;
-				}
-				// so now we know the client must have the request outstanding
-			if (reqMode&KReqModeMultipleCompletionEnabled && !(reqEntry->iPlacedRequest))
-				{
-				CompleteAndDestroyReq(reqEntry,KErrCancel);	// the request hadn't been passed to the TSY
-				RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
-				aMessage.Complete(KErrNone);
-				return;
-				}
-			// so the request is outstanding on the TSY
-			if (reqEntry->iCancelFnCalled==FALSE)
-				{
-				reqEntry->iCancelFnCalled=ETrue;
-				TInt status=CancelService(aMessage.Int0(),reqEntry->iTsyReqHandle);
-				if(status!=KErrNone)
-					CompleteAndDestroyReq(reqEntry,status);
-				}
-			}
-		RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
-		aMessage.Complete(KErrNone);
-		}
-		break;
-
-	case EIsaCancelSubSession:
-		// This is a special case for cancelling all asynchronous requests for this subsession
-		{
-		CancelSubSession(aSession,aMessage.Int3());
-		RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
-		aMessage.Complete(KErrNone);
-		}
-		break;
-
-	default:
-		PanicClient(EEtelPanicInvalidRequestType,aMessage);
-		break;
-		}
-	}
-
-EXPORT_C void CTelObject::ReqCompleted(const TTsyReqHandle aTsyReqHandle,const TInt aError)
-//
-// General complete function for all CTelObject derived classes
-//
-	{
-	__ASSERT_ALWAYS(aTsyReqHandle!=TSY_HANDLE_INIT_VALUE,Fault(EEtelFaultNotRecognisedTsyHandle));
-	TInt ipc=0;
-	CReqEntry* updatedReqEntry = NULL;
-	CReqEntry* nextPostedReqEntry = NULL;
-	updatedReqEntry=PhoneOwner()->FindByTsyHandleAndPlacedRequest(aTsyReqHandle);
-	__ASSERT_ALWAYS(updatedReqEntry!=NULL, Fault(EEtelFaultCompletionReceivedWithNoReqPackage));
-
-	TInt error = ResolveError(updatedReqEntry->iSession,aError);		// set error as either low or high byte
-
-	ipc=updatedReqEntry->iFunction;
-	LOGTEXT4("CTelObject::ReqCompleted, IPC=%d, TsyHandle=%d, Error=%d", ipc, aTsyReqHandle, aError);
-
-	TReqMode reqMode = updatedReqEntry->iReqMode;
-	TBool ret=EFalse;
-	if (error!=KErrCancel)
-		{
-		//  Multiple-completion malarky.
-		//	Don't copy data across to other buffers and complete their reqs if TSY knows about
-		//  each client that has called it. In that case, 
-		//  TSY will fill in the appropriate client's buffer and complete each separately.
-		if (reqMode&KReqModeMultipleCompletionEnabled)
-			PhoneOwner()->CheckAndCompleteAllActive(updatedReqEntry,reqMode,ipc,aError);
-
-		if (reqMode&KReqModeRePostImmediately && error==KErrNone)
-			nextPostedReqEntry = updatedReqEntry;					
-		updatedReqEntry->iBuffer->IncWrite();
-		}
-	else	// if a cancel comes from the TSY, then if it is a notification 
-			// there may be other clients who have also called the notification and who 
-			// have entries in active list, so one of these must be re-posted.
-		{
-		if (reqMode&KReqModeMultipleCompletionEnabled)
-			nextPostedReqEntry = PhoneOwner()->FindThisReqByAnotherClient(updatedReqEntry->iSession,updatedReqEntry->iMessage.Int3(),ipc,updatedReqEntry->iBuffer->Size(),this);
-		if (!nextPostedReqEntry)
-			// then we don't want to post any other client's requests in place of this one
-			{
-			nextPostedReqEntry = PhoneOwner()->FindNonCancelledClientReq(updatedReqEntry->iSession,updatedReqEntry->iMessage.Int3(),ipc);
-			__ASSERT_DEBUG(updatedReqEntry!=nextPostedReqEntry, Fault(EEtelFaultCancelErrorWithoutCancelled));
-			if (nextPostedReqEntry==NULL && reqMode&KReqModeRePostImmediately)
-				{
-				TInt ret = DeregisterNotification(ipc);	// no more clients are interested so
-														// tell TSY to stop looking at notifies
-				if (ret!=KErrNone)
-					error=ret;	// so the KErrCancel wouldn't reach the client
-				}
-			}
-		}
-	if (reqMode & KReqModeRePostImmediately)
-		UpdateAndCompleteIfNecessary(updatedReqEntry,error);	// this will destroy the reqEntry
-																// if an error occurred.
-	else
-		WriteBackAndCompleteReq(updatedReqEntry,error);
-	if (nextPostedReqEntry)	// will be NULL if no following request for TSY
-		{
-		if(nextPostedReqEntry->iReqMode&KReqModeFlowControlObeyed)
-			{ // since the request mode is flow control obeyed, increment the flow control counter
-			FlowControlSuspend();
-			}
-		Service(nextPostedReqEntry->iMessage,nextPostedReqEntry);
-		}
-
-	
-	if (!(reqMode&KReqModeFlowControlObeyed)) // If flow control not enabled, go home
-		ret=ETrue;
-
-// So everything below assumes it obeyed flow control
-// Resume Flow control ...
-	if (!ret)
-		FlowControlResume();
-//
-// Check and destroying the dummy session
-//
-	CheckAndDestroyDummySubSession();
-	}
-
-TInt CTelObject::ResolveError(CTelSession* aSession, const TInt aError) const
-/**
- * Converts a coded error into the correct error to return.  The coded error value
- * allows an extended error code to be present allong with a basic error code.  If
- * the client has specified awareness of the extended codes, then they are returned.
- * Otherwise the basic error code will be returned.  The advanced error codes do not
- * overlap the basic ones.
- *
- * In the case of no extended error code available, then the core error code will
- * be returned regardless of the client's extended error granularity.
- *
- * @return Either the basic error code or the advanced error coded if available and
- *         requested.
- * @param aSession The CTelSession of the client.
- * @param aError The coded error. 
- */
-	{
-	//
-	// Handle the common cases to make the code more efficent....
-	//
-	if ((aError==KErrNone) || (aError==KErrCancel))
-		{
-		return aError;
-		}
-
-	//
-	// 'aError' is coded into two halves (eXtended and baSic): 0xXXXXSSSS.  Take the
-	// top 16 bits for the eXtended code, and the bottom 16 bit for the baSic code.
-	//
-	// So, basicError becomes 0xffffSSSS and extendedError becomes 0xffffXXXX.
-	//
-	// A special case exists if the 16 bits were 0x0000 as this is KErrNone, and we must
-	// treat this as a positive int and not a negative one (e.g. clear the top 16 bits).
-	//
-	TInt basicError    = (aError | 0xFFFF0000);
-	TInt extendedError = ((aError >> 16) | 0xFFFF0000);
-
-	if (basicError == (TInt)(0xffff0000))
-		{
-		basicError = KErrNone;
-		}
-
-	if (extendedError == (TInt)(0xffff0000))
-		{
-		extendedError = KErrNone;
-		}
-	
-	//
-	// If the an extended error code is available and if client wants extended errors
-	// then return the extended error.  Otherwise return the basic error code.
-	//
-	// The extended error is not available if 'extendedError' is KErrNotFound (e.g.
-	// the top 16 bits were 0xffff.
-	//
-	if (extendedError != KErrNotFound  &&  aSession->IsExpectingExtendedError())	
-		{
-		return extendedError;
-		}
-	else
-		{
-		return basicError;
-		}
-	}
-
-void CTelObject::UpdateAndCompleteIfNecessary(CReqEntry* aReqEntry,TInt aError) const
-//
-//	If client has this request outstanding on the server, complete it, otherwise set Read
-//	flag to false. Destroy the request if an error has occurred.
-//
-	{
-	if (aReqEntry->iMessageNulled)
-		aReqEntry->iReadByClient=EFalse;	
-	else 
-		WriteBackAndCompleteBufferedReq(aReqEntry->iMessage,aReqEntry,aError);
-	if (aError)
-		DestroyReq(aReqEntry);
-	}
-
-void CTelObject::CheckAndDestroyDummySubSession()
-	{
-	if (iActiveReqCount)
-		{
-		iActiveReqCount--;
-		LOGTEXT2("In CheckAndDestroyDummySubSession(), iActiveReqCount down to %d", iActiveReqCount);
-		if ((iActiveReqCount==0) && (iCreateDummy==FALSE))
-			{
-			__ASSERT_ALWAYS(iDestroyDummySubSession!=NULL,Fault(EEtelFaultBadTelSessionPointer));
-			if (!(iDestroyDummySubSession->IsActive())) // only set going if not already active!
-				{
-				iDestroyDummySubSession->Call();
-				iTelServer->Dec();
-				}
-			}
-		}
-	else if (iCreateDummy)
-		{
-		__ASSERT_ALWAYS(iDestroyDummySubSession!=NULL,Fault(EEtelFaultBadTelSessionPointer));
-		if (!(iDestroyDummySubSession->IsActive())) // only set going if not already active!
-			{
-			iDestroyDummySubSession->Call();
-			iTelServer->Dec();
-			}
-		iCreateDummy=EFalse;
-		}
-	}
-
-void CTelObject::WriteBackAndCompleteBufferedReq(const RMessage2& aNewMessage,CReqEntry* aReqEntry,TInt aError) const
-	{
-	TInt basicMessageType =0; 
-	basicMessageType = (aNewMessage.Int1() & ~(KPriorityClientReq));
-	switch (basicMessageType)
-		{
-	case EIsaNull:
-		if (aReqEntry->iClientInterested)
-			{
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		break;
-	case EIsaDesTobeRead:
-	case EIsaDoubleDesTobeRead:
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aNewMessage.WriteL(0,*dataDes1)); // if this fails, panic the client
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-
-			if (basicMessageType==EIsaDoubleDesTobeRead)
-				{
-				TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
-				__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-				TRAP(ret,aNewMessage.WriteL(2,*dataDes2));
-				if(ret!=KErrNone)
-					{
-					PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-					break;
-					}				
-				}
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		break;
-	case EIsaUnicodeDesTobeRead:
-	case EIsaUnicodeDoubleDesTobeRead:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			// The TDes16 will be at the start of the HBufC buffer
-			TDes16* unicodeDataDes1=BufferDes1u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(unicodeDataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aNewMessage.WriteL(0,*unicodeDataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-				
-			if (basicMessageType==EIsaUnicodeDoubleDesTobeRead)
-				{
-				TDes16* unicodeDataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-				__ASSERT_ALWAYS(unicodeDataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-				TRAP(ret,aNewMessage.WriteL(2,*unicodeDataDes2));
-				if(ret!=KErrNone)
-					{
-					PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-					break;
-					}
-				}
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		}
-		break;
-	
-	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aNewMessage.WriteL(0,*dataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-				
-			TDes16* unicodeDataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(unicodeDataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-			TRAP(ret,aNewMessage.WriteL(2,*unicodeDataDes2));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		}
-		break;
-
-    case EIsaNarrowDesToSetAndGet:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-			TRAPD(ret,aNewMessage.WriteL(2,*dataDes2));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		}
-		break;
-
-	case EIsaUnicodeDesToGetNarrowDesToSet:
-	case EIsaUnicodeDesToSetAndGet: 
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes16* dataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-			TRAPD(ret,aNewMessage.WriteL(2,*dataDes2));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		break;
-
-    case EIsaNarrowDesToGetUnicodeDesToSet:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EEtelFaultDes1DoesNotExist));
-
-			TRAPD(ret,aNewMessage.WriteL(0,*dataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
-				break;
-				}
-			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
-			aNewMessage.Complete(aError);
-			}
-		}
-		break;
-
-	case EIsaDesTobeSet:
-	case EIsaDoubleDesTobeSet:
-	case EIsaUnicodeDesTobeSet:
-	case EIsaUnicodeDoubleDesTobeSet:
-	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
-	case EIsaCancelMessage:
-	case EIsaCancelSubSession:
-
-	default:
-		Fault(EEtelFaultBadMessageType);
-		break;
-		}
-	if (aError==KErrNone || aError==KErrOverflow)
-		{
-		aReqEntry->iReadByClient=ETrue;
-		aReqEntry->iMessageNulled=ETrue;
-		aReqEntry->iBuffer->IncRead();
-		}
-	}
-
-void CTelObject::WriteBackAndCompleteReq(CReqEntry* aReqEntry,const TInt aError) const
-//
-//	Complete a request entry and write data back to client
-//
-	{
-	__ASSERT_ALWAYS(aReqEntry!=NULL,Fault(EEtelFaultCompleteReqWithoutReqEntry));
-	LOGTEXT("CTelObject::WriteBackAndCompleteReq");
-	TInt basicMessageType = (aReqEntry->iMessage.Int1() & ~KPriorityClientReq);
-
-	switch (basicMessageType)
-		{
-	case EIsaNull:
-		aReqEntry->CompleteAndDeque(aError);
-		break;
-	case EIsaDesTobeSet:
-	case EIsaDoubleDesTobeSet:
-		__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-		aReqEntry->CompleteAndDeque(aError);
-		break;
-	case EIsaUnicodeDesTobeSet:
-	case EIsaUnicodeDoubleDesTobeSet:
-	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
-		__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-		aReqEntry->CompleteAndDeque(aError);
-		break;
-	case EIsaDesTobeRead:
-	case EIsaDoubleDesTobeRead:		
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			// The TPtr8 will be at the start of the HBufC buffer
-			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-			
-			if (basicMessageType==EIsaDoubleDesTobeRead)
-				{
-				TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
-
-				TRAP(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
-				if(ret!=KErrNone)
-					{
-					PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-					break;
-					}
-				}
-			}
-		aReqEntry->CompleteAndDeque(aError);
-		}
-		break;
-	case EIsaUnicodeDesTobeRead:
-	case EIsaUnicodeDoubleDesTobeRead:		
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes16* dataDes1=BufferDes1u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-
-			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-				
-			if (basicMessageType==EIsaUnicodeDoubleDesTobeRead)
-				{
-				TDes16* dataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-				__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-				TRAP(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
-				if(ret!=KErrNone)
-					{
-					PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-					break;
-					}
-				}
-			}
-		aReqEntry->CompleteAndDeque(aError);
-		}
-		break;
-	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-				
-			TDes16* unicodeDataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(unicodeDataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
-
-			TRAP(ret,aReqEntry->iMessage.WriteL(2,*unicodeDataDes2));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-			}
-		aReqEntry->CompleteAndDeque(aError);
-		}
-		break;
-
-    case EIsaNarrowDesToSetAndGet:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			// only write back the second parameter		
-			TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-			}
-		aReqEntry->CompleteAndDeque(aError);
-		}
-		break;
-
-    case EIsaNarrowDesToGetUnicodeDesToSet:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			// only write back the first parameter		
-			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-			}
-		aReqEntry->CompleteAndDeque(aError);
-		}
-		break;
-	
-	case EIsaUnicodeDesToSetAndGet:
-	case EIsaUnicodeDesToGetNarrowDesToSet:
-		{
-		if (aReqEntry->iClientInterested)
-			{
-			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-			// only write back the second parameter		
-			TDes16* dataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
-			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EETelFaultRequestWithoutBuffer));
-
-			TRAPD(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
-			if(ret!=KErrNone)
-				{
-				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
-				break;
-				}
-			}
-		aReqEntry->CompleteAndDeque(aError);
-		}
-		break;
-	
-	default:
-		Fault(EEtelFaultBadMessageType);
-		break;
-		}
-	aReqEntry->Deque();
-	delete aReqEntry;
-	}
-
-EXPORT_C void CTelObject::FlowControlSuspend()
-//
-// Suspend the Request Flow
-//
-	{
-	PhoneOwner()->FlowControlInc();
-	}
-
-
-EXPORT_C void CTelObject::FlowControlResume()
-
-//
-// Resume the Request Flow
-//
-	{
- 	PhoneOwner()->FlowControlDec();
- 	if(PhoneOwner()->FlowControl()>0)			// check for outstanding request
-		return;
-
-	CReqEntry* reqEntry=PhoneOwner()->ActivateNextWaitingReq();
-	if (reqEntry==NULL)
-		return;
-
-	RMessage2& message=reqEntry->iMessage;
-
-	CTelObject* theObj=reqEntry->iSession->CObjectFromHandle(message.Int3());
-	__ASSERT_ALWAYS(theObj!=NULL, Fault(EEtelFaultWaitingReqLostCObject));
-	theObj->GeneralReq(message,reqEntry->iSession,reqEntry, ETrue);
-	}
-
-//
-//	Future proofing in server
-//
-EXPORT_C TInt CTelObject::DownCallOption(TInt /*aOptionNumber*/, TAny* /*aData*/)
-	{
-	return KErrNotSupported;
-	}
-
-EXPORT_C TInt CTelObject::UpCallOption(TInt /*aOptionNumber*/, TAny* /*aData*/)
-	{
-	return KErrNotSupported;
-	}
-
-EXPORT_C TInt CTelObject::ServerVersion() const
-//
-// Lets TSY know which version of server this is, ie which extra options the server will support.
-//
-	{
-	return KETelServerVersion;
-	}
-
-EXPORT_C TSecurityPolicy CTelObject::GetRequiredPlatSecCaps(const TInt /*aIpc*/)
-/**
- *	Default implementation of TSY side of the Etel capability policy checking delegation.
- *	If the TSY does not support CustomAPIs or the TSY does not implement it's own version
- *	of this virtual function, then this default implementation will get used and shall always
- *	return a policy that fails the capability check.
- *
- *	@return This base implementation always returns a TSecurityPolicy::EAlwaysFail.
- *	@param aIpc This parameter is not used in the base implementation of this virtual function.
- */
-	{
-	return TSecurityPolicy(TSecurityPolicy::EAlwaysFail);
-	}
-
-
-TDes8* CTelObject::BufferDes1(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const
-//
-//	Returns pointer to first descriptor in current slot. More specifically, a pointer to the
-//	TPtr which is stored just before the data that it points to.
-
-//  The buffer is circular, and there are
-//	two "current" slots - one slot for where the next data should be written to by the TSY,
-//	the other from which the client should next read from. aWhichSlot specifies which of these
-//	should be returned.
-//
-	{
-	TDes8* des1=NULL;
-	if (aBuffer->iBuf8)
-		{
-		TUint8* pos = aBuffer->CurrentSlotData1(aWhichSlot);
-		if (pos)
-			des1=reinterpret_cast<TDes8*> (pos);
-		}
-	return des1;
-	}
-
-TDes8* CTelObject::BufferDes2(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const 
-	{
-	TDes8* des2=NULL;
-	if (aBuffer->iBuf8)
-		{
-		TUint8* pos = aBuffer->CurrentSlotData2(aWhichSlot);
-		if (pos)
-			des2=reinterpret_cast<TDes8*> (pos);
-		}
-	return des2;
-	}
-
-TDes16* CTelObject::BufferDes1u(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const
-	{
-	TDes16* des1=NULL;
-	if (aBuffer->iBuf16)
-		{
-		TUint16* pos = aBuffer->CurrentSlotData1u(aWhichSlot);
-		if (pos)
-			des1=reinterpret_cast<TDes16*> (pos);
-		}
-	return des1;
-	}
-
-TDes16* CTelObject::BufferDes2u(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const 
-	{
-	TDes16* des2=NULL;
-	if (aBuffer->iBuf16)
-		{
-		TUint16* pos = aBuffer->CurrentSlotData2u(aWhichSlot);
-		if (pos)
-			des2=reinterpret_cast<TDes16*> (pos);
-		}
-	return des2;
-	}
-
-TUint8* CTelObject::Ptr1(const TDes8* aDes1) const
-//
-// return the pointer to the data of the first descriptor
-// return NULL if does not exist
-//
-	{
-	TUint8* ptr1=NULL;
-	if (aDes1)
-		ptr1=const_cast<TUint8*> (aDes1->Ptr());
-	return ptr1;
-	}
-
-void CTelObject::RemoveDummySubSessionDestroyer()
-	{
-	iDestroyDummySubSession = NULL;
-	}
-
-//
-//
-// CSubSessionExtBase
-//
-//
-EXPORT_C CSubSessionExtBase::CSubSessionExtBase()
-//
-//	C'Tor
-//
-	{
-	__DECLARE_NAME(_S("CSubSessionExtBase"));
-	}
-
-EXPORT_C CSubSessionExtBase::~CSubSessionExtBase()
-//
-//	D'Tor
-//
-	{}
-
-TInt CSubSessionExtBase::ServiceExtFunc(const RMessage2& aMessage,CReqEntry* aReqEntry)
-//
-// Sort out Des1 and Des2 before calling ExtFunc()
-//
-	{
-	__ASSERT_ALWAYS(aReqEntry!=NULL,Fault(EEtelFaultCallTsyServiceWithoutReqPackage));
-	TTsyReqHandle tsyReqHandle=aReqEntry->iTsyReqHandle;
-
-	LOGTEXT2("Entered ServiceExtFunc with TSY handle %d", tsyReqHandle);
-	TInt ret=KErrNone;
-
-	TInt basicMessageType = aMessage.Int1() & ~(KPriorityClientReq);
-	switch (basicMessageType)
-		{
-	case EIsaNull:
-	case EIsaCancelMessage:
-		{
-		TDataPackage package;	// a package with all data pointers nulled
-		ret=ExtFunc(tsyReqHandle,aMessage.Function(),package);
-		}
-		break;
-	case EIsaDesTobeSet:
-	case EIsaDesTobeRead:
-	case EIsaDoubleDesTobeSet:
-	case EIsaDoubleDesTobeRead:	// may have been multi-slot registered
-	case EIsaNarrowDesToSetAndGet:
-		{
-		TDes8* des1 = BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotWrite);
-		if (!des1)
-            {
-            return KErrArgument;
-            }
-		TDes8* des2=NULL;
-		if (basicMessageType==EIsaDoubleDesTobeSet || 
-			basicMessageType==EIsaDoubleDesTobeRead ||
-			basicMessageType==EIsaNarrowDesToSetAndGet)
-			{
-			des2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotWrite);
-			if (!des2)
-			    {
-			    return KErrArgument;
-			    }
-			}
-		TDataPackage package(des1,des2);
-		ret=ExtFunc(tsyReqHandle,aReqEntry->iFunction,package);
-		}
-		break;
-	case EIsaUnicodeDesTobeSet:
-	case EIsaUnicodeDesTobeRead:
-	case EIsaUnicodeDoubleDesTobeSet:
-	case EIsaUnicodeDoubleDesTobeRead:
-	case EIsaUnicodeDesToSetAndGet:
-		{
-		TDes16* des1 = BufferDes1u(aReqEntry->iBuffer,CBuffer::ESlotWrite);
-		if (!des1)
-            {
-            return KErrArgument;
-            }
-		TDes16* des2=NULL;
-		if (basicMessageType==EIsaUnicodeDoubleDesTobeSet || 
-			basicMessageType==EIsaUnicodeDoubleDesTobeRead ||
-			basicMessageType==EIsaUnicodeDesToSetAndGet)
-			{
-			des2 = BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotWrite);
-			if (!des2)
-                {
-                return KErrArgument;
-                }
-			}	
-		TDataPackage package(des1,des2);
-		ret=ExtFunc(tsyReqHandle,aReqEntry->iFunction,package);
-		}
-		break;
-	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
-	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
-	case EIsaNarrowDesToGetUnicodeDesToSet:
-	case EIsaUnicodeDesToGetNarrowDesToSet:
-		{
-		TDes8* des1 = BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotWrite);
-        if (!des1)
-            {
-            return KErrArgument;
-            }
-		TDes16* des2=NULL;
-		des2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotWrite);
-		if (!des2)
-            {
-            return KErrArgument;
-            }
-		TDataPackage package(des1,des2);
-		ret=ExtFunc(tsyReqHandle,aReqEntry->iFunction,package);
-		}
-		break;
-
-	default:
-		Fault(EEtelFaultMessageTypeCorrupted);
-		break;
-		}
-	return ret;
-	}
-
-EXPORT_C TInt CSubSessionExtBase::Service(const RMessage2& aMessage, CReqEntry* aReqEntry)
-//
-// The ServiceL functionality for the ext base
-//
-	{
-	aReqEntry->iPlacedRequest=ETrue;
-	return ServiceExtFunc(aMessage,aReqEntry);
-	}
-
-EXPORT_C void CSubSessionExtBase::CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle)
-	{
-	CreateDummySession(aSession,aSubSessionHandle);
-	FlushReqs(aSession,aSubSessionHandle);
-	}
-
-EXPORT_C void CSubSessionExtBase::OpenPostProcessing(CTelSession* /*aSession*/,const TInt)
-//
-// Perform post-processing after object has been added to session's CObjectIx.
-//
-	{
-	}
-	
-EXPORT_C RHandleBase* CSubSessionExtBase::GlobalKernelObjectHandle()
-	{	
-	return NULL;	
-	}
-	
-EXPORT_C void CSubSessionExtBase::NullMethod1()
-	{}
-
-EXPORT_C void CFaxBase::NullMethod2()
-	{}
-
-//
-//
-// CLibUnloader
-//
-//
-CLibUnloader::CLibUnloader()
-//
-// C'tor
-//
-	:CAsyncOneShot(CActive::EPriorityHigh)
-	{
-	__DECLARE_NAME(_S("CLibUnloader"));
-	}
-
-CLibUnloader* CLibUnloader::NewL(RLibrary &aLib)
-//
-// New Library Unloader
-//
-	{
-	CLibUnloader *s=new(ELeave)CLibUnloader;
-	s->iLib=aLib;
-	return s;
-	}
-
-CLibUnloader::~CLibUnloader()
-	{
-	Cancel();
-	iLib.Close();
-	}
-
-void CLibUnloader::RunL()
-//
-// Unload TSY module
-//
-	{
-	delete this;
-	}
-
-//
-//
-// CPhoneFactoryBase definition
-//
-//
-EXPORT_C TBool CPhoneFactoryBase::QueryVersionSupported( TVersion const & aVersion )const
-//
-// Pass through to default QVS
-//
-	{
-	return(User::QueryVersionSupported(iVersion,aVersion));
-	}
-
-EXPORT_C CPhoneFactoryBase::CPhoneFactoryBase()
-//
-// C'Tor
-//
-	{
-	__DECLARE_NAME(_S("CPhoneFactoryBase"));
-	}
-
-void CPhoneFactoryBase::ConstructL(RLibrary& aLib)
-//
-// Allocate a CLibrary Unloader
-//
-	{
-	iLibUnloader=CLibUnloader::NewL(aLib);
-	}
-
-EXPORT_C CPhoneFactoryBase::~CPhoneFactoryBase()
-//
-// D'Tor
-//
-	{
-	if (iLibUnloader)
-		{
-		LOGTEXT("About to call iLibUnloader");
-		iLibUnloader->Call();
-		}
-	}
-
-EXPORT_C void CPhoneFactoryBase::CPhoneFactoryBase_Reserved1()
-//
-// Reserved virtual function
-//
-	{}
-
-//
-// HEtelBufC definitions
-//
-
-
-//
-// HEtelBufC8
-//
-HEtelBufC8* HEtelBufC8::NewMaxLC(TInt aMaxLength,RHeap* aHeap)
-	{
-	__ASSERT_ALWAYS(aMaxLength>=0,Fault(EEtelFaultMaxDesLengthNegative));
-
-	HEtelBufC8* pH=NULL;
-	TInt size=sizeof(HEtelBufC8)+(aMaxLength*sizeof(TUint8));
-	if (aHeap!=NULL)
-		pH=(HEtelBufC8*)aHeap->AllocLC(size);
-	else
-		pH=(HEtelBufC8*)User::AllocLC(size);
-	pH->iLength=aMaxLength;
-	pH->iHeap=aHeap;
-	pH->Des().SetLength(aMaxLength);
-	return(pH);
-	}
-
-TPtr8 HEtelBufC8::Des()
-	{
-	TUint8* ptr = reinterpret_cast<TUint8*> (((reinterpret_cast<TInt> (this)) +
-													sizeof(HEtelBufC8))
-											);
-	return TPtr8(ptr,iLength,iLength);
-	}
-
-const TUint8* HEtelBufC8::Ptr() const
-	{
-	return reinterpret_cast<const TUint8*> (((reinterpret_cast<TInt> (this)) +
-													sizeof(HEtelBufC8))
-											);
-	}
-
-void HEtelBufC8::operator delete(TAny* aPtr)
-//
-// overloaded delete - deletes from priority client heap if iHeap is not NULL
-//
-	{
-	RHeap* heap=NULL;
-	if (aPtr!=NULL)
-		{
-		heap = (reinterpret_cast<HEtelBufC8*> (aPtr))->iHeap;
-		}
-
-	if (heap!=NULL)
-		{
-		reinterpret_cast<HEtelBufC8*> (aPtr)->iHeap->Free(aPtr);
-		}
-	else
-		{
-		User::Free(aPtr);
-		}
-	}
-
-//
-// HEtelBufC16
-//			  
-HEtelBufC16* HEtelBufC16::NewMaxLC(TInt aMaxLength,RHeap* aHeap)
-	{
-	__ASSERT_ALWAYS(aMaxLength>=0,Fault(EEtelFaultMaxDesLengthNegative));
-
-	HEtelBufC16* pH=NULL;
-	TInt size=sizeof(HEtelBufC16)+(aMaxLength*sizeof(TUint16));
-	if (aHeap!=NULL)
-		pH=(HEtelBufC16*)aHeap->AllocLC(size);
-	else
-		pH=(HEtelBufC16*)User::AllocLC(size);
-	pH->iLength=aMaxLength;
-	pH->iHeap=aHeap;
-	pH->Des().SetLength(aMaxLength);
-	return(pH);
-	}
-
-TPtr16 HEtelBufC16::Des()
-	{
-	TUint16* ptr=reinterpret_cast<TUint16*> ((reinterpret_cast<TInt> (this)+sizeof(HEtelBufC16)));
-	return TPtr16(ptr,iLength,iLength);
-	}
-
-const TUint16* HEtelBufC16::Ptr() const
-	{
-	return reinterpret_cast<const TUint16*> ((reinterpret_cast<TInt> (this)+sizeof(HEtelBufC16)));
-	}
-
-void HEtelBufC16::operator delete(TAny* aPtr)
-//
-// overloaded delete - deletes from priority client heap if iHeap is not NULL
-//
-	{
-	RHeap* heap=NULL;
-	if (aPtr!=NULL)
-		heap=reinterpret_cast<HEtelBufC16*> (aPtr)->iHeap;
-
-	if (heap!=NULL)
-		reinterpret_cast<HEtelBufC16*> (aPtr)->iHeap->Free(aPtr);
-	else
-		User::Free(aPtr);
-	}
-
-//
-//	TDataPackage class contains the data pointers to be passed down to the TSY in ExtFunc()
-//
-TDataPackage::TDataPackage()
-	: iDes1(NULL),iDes2(NULL),iDes1u(NULL),iDes2u(NULL)
-	{}
-TDataPackage::TDataPackage(TDes8* aDes1, TDes8* aDes2)
-	: iDes1(aDes1),iDes2(aDes2),iDes1u(NULL),iDes2u(NULL)
-	{}
-
-TDataPackage::TDataPackage(TDes16* aDes1, TDes16* aDes2)
-	: iDes1(NULL),iDes2(NULL),iDes1u(aDes1),iDes2u(aDes2)
-	{}
-TDataPackage::TDataPackage(TDes8* aDes1, TDes16* aDes2)
-	: iDes1(aDes1),iDes2(NULL),iDes1u(NULL),iDes2u(aDes2)
-	{}
-
-EXPORT_C TDes8* TDataPackage::Des1n() const
-	{
-	__ASSERT_ALWAYS(iDes1,Fault(EEtelFaultDes1DoesNotExist));
-	return iDes1;
-	}
-EXPORT_C TDes8* TDataPackage::Des2n() const
-	{
-	__ASSERT_ALWAYS(iDes2,Fault(EEtelFaultDes2DoesNotExist));
-	return iDes2;
-	}
-EXPORT_C TDes16* TDataPackage::Des1u() const
-	{
-	__ASSERT_ALWAYS(iDes1u,Fault(EEtelFaultDes1DoesNotExist));
-	return iDes1u;
-	}
-EXPORT_C TDes16* TDataPackage::Des2u() const
-	{
-	__ASSERT_ALWAYS(iDes2u,Fault(EEtelFaultDes2DoesNotExist));
-	return iDes2u;
-	}
-
-EXPORT_C TAny* TDataPackage::Ptr1() const
-	{
-	if (iDes1u)
-		return reinterpret_cast<TAny*> (const_cast<TUint16*> (iDes1u->Ptr()));		
-	if (iDes1)
-		return reinterpret_cast<TAny*> (const_cast<TUint8*> (iDes1->Ptr()));
-	return NULL;
-	}
-
-EXPORT_C TAny* TDataPackage::Ptr2() const
-	{
-	if (iDes2u)
-		return reinterpret_cast<TAny*> (const_cast<TUint16*> (iDes2u->Ptr()));
-	if (iDes2)
-		return reinterpret_cast<TAny*> (const_cast<TUint8*> (iDes2->Ptr()));
-	return NULL;
-	}
-
-/**
-* This helper utility returns the type of a packaged data structure.
-* It is very useful to know which type of variables (unicode or narrow) a package contains
-* before passing it to any functions. It could also help to provide more generic implementation
-* on the TSY, that currently assumes knowledge of the way the data are packaged.
-*
-*/
-
-EXPORT_C TDataPackage::TDataPackageType TDataPackage::Type() const
-	{
-	if(iDes1 && iDes2)
-		return EPackage1n2n;
-	else if (iDes1u && iDes2u)
-		return EPackage1u2u;
-	else if (iDes1 && iDes2u)
-		return EPackage1n2u;
-	else if (iDes1 && !iDes2)
-		return EPackage1n;
-	else if (iDes1u && !iDes2u)
-		return EPackage1u;
-	else 
-		return EPackageUnknown;
-	}
-
-/**
-Non-exported static factory constructor.  This class should only be instantiated by Etel server.
-*/
-CFaxSharedFileHandles* CFaxSharedFileHandles::NewL(const RMessage2& aMsg)
-	{
-	CFaxSharedFileHandles* obj = new(ELeave) CFaxSharedFileHandles();	
-	CleanupStack::PushL(obj);
-	obj->ConstructL(aMsg);
-	CleanupStack::Pop(obj);
-	return obj;		
-	}	
-	
-/**
-Destructor.
-
-@publishedPartner
-@released 
-*/
-EXPORT_C CFaxSharedFileHandles::~CFaxSharedFileHandles()
-	{
-	iFile.Close();	
-	}
-
-/**
-Default constructor.
-*/	
-CFaxSharedFileHandles::CFaxSharedFileHandles()
-	{
-	//empty
-	}
-	
-/**
-Reference to an adopted file.
-
-@return RFile& Reference to an open file handle.
-@publishedPartner
-@released 
-*/
-EXPORT_C RFile& CFaxSharedFileHandles::File() 
-	{
-	return iFile;	
-	};
-
-/**
-Adopt the file during construction.
-*/
-void CFaxSharedFileHandles::ConstructL(const RMessage2& aMsg)
-	{
-	//Use the RMessage2 and EKA2 adopt functions to adopt the file.  Slots 0 & 2 contain relevant session handles.
-	User::LeaveIfError(iFile.AdoptFromClient(aMsg, 0, 2));
-	}
+// 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:
+//
+
+/**
+ @file
+*/
+
+#include "ET_SSTD.H"
+#include "et_record.h"
+#include "et_phone_util.h"
+#include "et_patchdata.h"
+//
+// CReqEntry class definitions
+//
+
+CReqEntry* CReqEntry::NewL(TTsyReqHandle aTsyReqHandle, const RMessage2& aMessage, CTelSession* aSession, CBuffer* aBuffer, const CTelObject* aTelObject, TInt aFunction, RHeap* aHeap)
+//
+//	Create new request entry.  aHeap should be NULL unless this is to be allocated on the 
+//	priority client heap.
+//
+	{
+	if (aHeap != NULL)
+		{
+		return new(aHeap) CReqEntry(aTsyReqHandle,aMessage,aSession,aBuffer,aTelObject,aFunction,aHeap);
+		}
+
+	return new(ELeave) CReqEntry(aTsyReqHandle,aMessage,aSession,aBuffer,aTelObject,aFunction,NULL);
+	}
+
+
+CReqEntry::CReqEntry(TTsyReqHandle aTsyReqHandle,const RMessage2& aMessage,CTelSession* aSession,CBuffer* aBuffer,const CTelObject* aTelObject,TInt aFunction,RHeap* aHeap)
+//
+//	CReqEntry constructor
+//
+	: iTsyReqHandle(aTsyReqHandle), iMessage(aMessage), iSession(aSession), iTelObject(aTelObject),
+	iClientInterested(ETrue), iCancelFnCalled(EFalse), iFunction(aFunction), iBuffer(aBuffer), 
+	iReadByClient(ETrue), iMessageNulled(EFalse), iHeap(aHeap)
+	{}
+
+CReqEntry::~CReqEntry()
+//
+//	CReqEntry destructor
+//
+	{
+	delete iBuffer;
+	}
+
+void CReqEntry::Deque()
+//
+//	Deque CReqEntry list
+//
+	{
+	iLink.Deque();
+	iLink.iPrev=iLink.iNext=NULL;
+	}
+
+void CReqEntry::CompleteAndDeque(TInt aError)
+	{
+	LOGTEXT("CReqEntry::CompleteAndDeque");
+	// if client does not interested in this request do not completed
+	if (iClientInterested) 
+		{		
+		RECORD_COMPLETE_SUB(iMessage.Session(), iTelObject, iMessage.Int3(), iMessage.Function(), aError);
+		iMessage.Complete(aError);
+		}
+		
+	iLink.Deque();
+	}
+
+TAny* CReqEntry::operator new(TUint aSize,RHeap* aHeap) __NO_THROW
+//
+// overloaded new using the priority client heap - can leave
+//
+	{
+	TAny *pM=NULL;
+	TRAPD(err, pM=aHeap->AllocL(aSize) );
+	
+	if(err!=KErrNone)
+		pM = NULL;
+	else
+		Mem::FillZ(pM,aSize);
+	return(pM);
+	}
+
+TAny* CReqEntry::operator new(TUint aSize) __NO_THROW
+	{
+	return CBase::operator new(aSize);
+	}
+	
+TAny* CReqEntry::operator new(TUint aSize,TLeave aLeave)
+	{
+	return CBase::operator new(aSize,aLeave);
+	}
+
+TAny* CReqEntry::operator new(TUint aSize,TUint aExtraSize) __NO_THROW
+	{
+	return CBase::operator new(aSize,aExtraSize);
+	}
+
+void CReqEntry::operator delete(TAny* aPtr)
+//
+// overloaded delete - deletes from priority client heap if iHeap is not NULL
+//
+	{
+	if (((CReqEntry*)aPtr)->iHeap!=NULL)
+		((CReqEntry*)aPtr)->iHeap->Free(aPtr);
+	else
+		User::Free(aPtr);
+	}
+	
+//
+//	CBuffer class definitions
+//
+CBuffer* CBuffer::NewL(HEtelBufC8* aBuf8,HEtelBufC16* aBuf16,RHeap* aHeap,TInt aSizeOfData1,TInt aSizeOfData2,TInt aNoOfSlots)
+	{
+	if (aHeap!=NULL)
+		return new(aHeap) CBuffer(aBuf8,aBuf16,aHeap,aSizeOfData1,aSizeOfData2,aNoOfSlots);
+
+	return new(ELeave) CBuffer(aBuf8,aBuf16,NULL,aSizeOfData1,aSizeOfData2,aNoOfSlots);
+	}
+
+CBuffer::CBuffer(HEtelBufC8* aBuf8,HEtelBufC16* aBuf16,RHeap* aHeap,TInt aSizeOfData1,TInt aSizeOfData2,TInt aNoOfSlots)
+	: iBuf8(aBuf8),iBuf16(aBuf16),iHeap(aHeap),iRead(0),iWrite(0),iNoOfSlots(aNoOfSlots),
+		iSizeOfData1(aSizeOfData1),iSizeOfData2(aSizeOfData2),
+		iOverFlow(EFalse),iBufferFull(EFalse)
+	{}
+
+CBuffer::~CBuffer()
+	{
+	delete iBuf8;
+	delete iBuf16;
+	}
+
+TAny* CBuffer::operator new(TUint aSize,RHeap* aHeap) __NO_THROW
+//
+// overloaded new using the priority client heap - can leave
+//
+	{
+	TAny *pM=NULL;
+	TRAPD(err, pM=aHeap->AllocL(aSize) );
+	
+	if(err!=KErrNone)
+		pM = NULL;
+	else
+		Mem::FillZ(pM,aSize);
+	return(pM);
+	}
+
+TAny* CBuffer::operator new(TUint aSize) __NO_THROW
+	{
+	return CBase::operator new(aSize);
+	}
+	
+TAny* CBuffer::operator new(TUint aSize,TLeave aLeave)
+	{
+	return CBase::operator new(aSize,aLeave);
+	}
+
+TAny* CBuffer::operator new(TUint aSize,TUint aExtraSize) __NO_THROW
+	{
+	return CBase::operator new(aSize,aExtraSize);
+	}
+
+void CBuffer::operator delete(TAny* aPtr)
+//
+// overloaded delete - deletes from priority client heap if iHeap not NULL
+//
+	{
+	if (((CBuffer*)aPtr)->iHeap!=NULL)
+		((CBuffer*)aPtr)->iHeap->Free(aPtr);
+	else
+		User::Free(aPtr);
+	}
+
+TUint CBuffer::Size() const
+	{
+	return iSizeOfData1 + iSizeOfData2;
+	}
+	
+void CBuffer::IncRead()
+	{
+	if(++iRead==iNoOfSlots)
+		iRead=0;
+	iOverFlow=EFalse;
+	iBufferFull=EFalse;
+	LOGTEXT2("ETel:\tiRead incremented to %d", iRead);
+	}
+
+void CBuffer::IncWrite()
+	{
+	if(++iWrite==iNoOfSlots)
+		iWrite=0;
+	if (iOverFlow)
+		 iRead=iWrite;
+	else
+		{
+		if (!iBufferFull)
+			{
+			if (iWrite==iRead)
+				iBufferFull=ETrue;
+			}
+		else
+			{
+			iRead=iWrite;
+			iOverFlow=ETrue;
+			}
+		}
+	LOGTEXT2("ETel:\tiWrite incremented to %d", iWrite);
+	}
+
+TUint8* CBuffer::CurrentSlotData1(TWhichSlot aWhichSlot) const
+//
+// iSizeOfData1 and iSizeOfData2 include the sizes of the TPtr's
+//
+	{
+	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
+
+	if (iBuf8==NULL)
+		{
+		return NULL;
+		}
+	else if (iBuf16==NULL)
+		{
+		TInt slotSize = iSizeOfData1 + iSizeOfData2;
+		return (const_cast<TUint8*> (iBuf8->Des().Mid(pos*(slotSize),iSizeOfData1-sizeof(TPtr8)).Ptr()));
+		}
+	else
+		{
+		// we have a narrow and a unicode parameter. Data1 is always narrow
+		return (const_cast<TUint8*> (iBuf8->Des().Mid(pos*iSizeOfData1,iSizeOfData1-sizeof(TPtr8)).Ptr()));
+		}
+	}
+
+TUint8* CBuffer::CurrentSlotData2(TWhichSlot aWhichSlot) const
+	{
+	if (iSizeOfData2==0)
+		return NULL;
+	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
+
+	if (iBuf8!=NULL  &&  iBuf16==NULL)
+		{
+		TInt slotSize = iSizeOfData1 + iSizeOfData2;
+		return (const_cast<TUint8*> (iBuf8->Des().Mid(pos*(slotSize)+iSizeOfData1,iSizeOfData2-sizeof(TPtr8)).Ptr()));
+		}
+
+	return NULL;
+	}
+
+TUint16* CBuffer::CurrentSlotData1u(TWhichSlot aWhichSlot) const
+//
+// Unicode version
+//
+	{
+	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
+
+	if (iBuf8==NULL  &&  iBuf16!=NULL)
+		{
+		TInt slotSize = iSizeOfData1 + iSizeOfData2;
+		return (const_cast<TUint16*> (iBuf16->Des().Mid(pos*(slotSize),iSizeOfData1-sizeof(TPtr16)).Ptr()));
+		}
+
+	return NULL;	// Data1 will be narrow if we have a mixture of both 8 and 16 bit
+	}
+
+TUint16* CBuffer::CurrentSlotData2u(TWhichSlot aWhichSlot) const
+//
+// Unicode version
+//
+	{
+	if (iSizeOfData2==0)
+		return NULL;
+	TInt pos=((aWhichSlot==ESlotRead) ? iRead : iWrite);
+
+	if (iBuf16==NULL)
+		{
+		return NULL;
+		}
+	else if (iBuf8==NULL)
+		{
+		TInt slotSize = iSizeOfData1 + iSizeOfData2;
+		return (const_cast<TUint16*> (iBuf16->Des().Mid(pos*(slotSize)+iSizeOfData1,iSizeOfData2-sizeof(TPtr16)).Ptr()));
+		}
+	else
+		{
+		// we have a narrow and a unicode parameter. Data2 is always unicode
+		return (const_cast<TUint16*> (iBuf16->Des().Mid(pos*iSizeOfData2,iSizeOfData2-sizeof(TPtr16)).Ptr()));
+		}
+	}
+
+TBool CBuffer::EqualSizes(TInt aSize1, TInt aSize2) const
+    {
+    if(iSizeOfData1 != aSize1)
+        {
+        return EFalse;
+        }
+    if(iSizeOfData2 != aSize2)
+        {
+        return EFalse;
+        }
+    return ETrue;
+    }
+
+TInt CBuffer::CompareRWPtrs() const
+	{
+	return (iRead-iWrite);
+	}
+
+//
+//
+// CTelObject class definitions
+//
+
+EXPORT_C CTelObject::CTelObject()
+//
+// CTelObject constructor
+//
+	:iActiveReqCount(0), iTelServer(NULL), iDestroyDummySubSession(NULL), iCreateDummy(EFalse)
+	{
+	__DECLARE_NAME(_S("CTelObject"));
+	}
+
+EXPORT_C CTelObject::~CTelObject()
+//
+// Destructor
+//
+	{
+	delete iDeliveryObject;
+	delete iDestroyDummySubSession;
+	}
+
+EXPORT_C void CTelObject::CTelObject_Reserved1()
+//
+// Reserved virtual function
+//
+	{}
+
+void CTelObject::CreateDummySessionObjectL(CTelSession* aTelSession)
+	{
+	if (iDestroyDummySubSession==NULL)
+		{
+		LOGTEXT("CDestroyDummySubSession object does not already exist and will be created.");
+		iDestroyDummySubSession = CDestroyDummySubSession::NewL(aTelSession->TelServer(),this);
+		}
+	else
+		{
+		LOGTEXT("CDestroyDummySubSession object already exists and will not be created");
+		}
+
+	}
+	
+void CTelObject::CreateDummySession(CTelSession* aSession, const TInt aSubSessionHandle, TBool aCreateDummy)
+//
+// So the server has to create a dummy session just to keep session alive until completed
+// function is called.
+//
+	{
+	LOGTEXT2("CreateDummySession() with iDestroyDummySubSession = %x", iDestroyDummySubSession);
+	iCreateDummy=aCreateDummy;
+	
+	if (iDestroyDummySubSession->iOpen == EFalse)
+		{
+		if ( IsActiveReq(aSession,aSubSessionHandle) || aCreateDummy)
+			{
+			LOGTEXT("About to create dummy session");
+			__ASSERT_ALWAYS(aSession!=NULL,Fault(EEtelFaultBadTelSessionPointer));
+			CObject* theObj=this;
+			while(theObj->Owner())
+				{
+				theObj->Open();
+				theObj=theObj->Owner();
+				}
+			theObj->Open();
+			iTelServer=aSession->TelServer();
+	
+			// incrementing the server's session count to include the dummy session, which
+			// has been previously allocated upon the CTelObject creation (by calling
+			// CreateDummySessionObjectL() )
+			iTelServer->Inc();
+			LOGTEXT2("Added a Dummy Session, producing server's session count of %d", iTelServer->Count());
+				
+			iDestroyDummySubSession->iTelServer = iTelServer;
+			iDestroyDummySubSession->iTelObject = this;
+			iDestroyDummySubSession->iOpen = ETrue;
+			}
+		}
+	}
+	
+void CTelObject::TelObjectClose()
+//
+// Perform an iterative close of Tel Objects
+//
+	{	
+	CTelObject* owner = reinterpret_cast<CTelObject*> (Owner());
+	Close();
+	if(owner)
+		owner->TelObjectClose();
+	}
+
+void CTelObject::CompleteAndDestroyReq(CReqEntry* aReqEntry,const TInt aStatus) const
+//
+//	complete the entry and remove from entry list and associate heap
+//
+	{
+	if (!aReqEntry->iMessageNulled)
+		{
+		RECORD_COMPLETE_SUB(aReqEntry->iMessage.Session(), this, aReqEntry->iMessage.Int3(), aReqEntry->iMessage.Function(), aStatus);
+		aReqEntry->iMessage.Complete(aStatus);
+		}
+	DestroyReq(aReqEntry);
+	}
+
+void CTelObject::DestroyReq(CReqEntry* aReqEntry) const
+//
+//	remove from entry list and associate heap
+//
+	{
+	aReqEntry->Deque();
+	delete aReqEntry;
+	}
+
+TBool CTelObject::IsActiveReq(CTelSession* aSession,const TInt aSubSessionHandle)
+//
+// Return True if found the active req still out standing
+// going through and counting the total of active req
+//
+	{
+	TBool ret=EFalse;
+	CReqEntry* reqEntry=NULL;
+	TDblQueIter<CReqEntry> iter(PhoneOwner()->ReqActiveList());
+	while(reqEntry=iter++,reqEntry!=NULL) // go through the list from begin to end
+		{
+		if (aSession==reqEntry->iSession && aSubSessionHandle==reqEntry->iMessage.Int3() &&	reqEntry->iClientInterested )
+			{
+			iActiveReqCount++;
+			ret=ETrue;
+			}
+		}
+	LOGTEXT2("IsActiveReq found %d active reqs", iActiveReqCount);
+	return ret;
+	}
+
+void CTelObject::CancelActiveReq(CTelSession* aSession,const TInt aSubSessionHandle)
+//
+// active list - must inform tsy by calling CancelService
+// this request will be destroyed when Tsy do an up call ReqCompleted with KErrCancel
+// Only go through the list once set the count to zero at start to count number of requests 
+//
+	{
+	LOGTEXT("Entered CancelActiveReq");
+	CReqEntry* reqEntry=NULL;
+	TDblQueIter<CReqEntry> iter(PhoneOwner()->ReqActiveList());
+	while(reqEntry=iter++,reqEntry!=NULL) // go through the list from begin to end
+		{
+		if (aSession==reqEntry->iSession && aSubSessionHandle==reqEntry->iMessage.Int3() &&	reqEntry->iClientInterested )
+			{
+			reqEntry->iClientInterested=EFalse;
+			__ASSERT_ALWAYS(iActiveReqCount>=0,Fault(EEtelFaultNegativeActiveReqCount));
+			if (reqEntry->iCancelFnCalled==FALSE)
+				{
+			    TReqMode reqMode = reqEntry->iReqMode;
+				
+				if (reqEntry->iPlacedRequest)
+					{
+					LOGTEXT2("Calling Cancel Service ActiveReq TsyReq=%d", reqEntry->iTsyReqHandle);
+					reqEntry->iCancelFnCalled=ETrue;
+					CancelService(reqEntry->iFunction,reqEntry->iTsyReqHandle);
+					
+					//
+					// In calling CancelService() it is possible that a second
+					// handle has performed the same request (e.g. a notify) and
+					// that ETel will re-post the notify using that handle. In
+					// some cases it could happen that the re-posted notify is
+					// invalid and fails, thereby completing that next request.
+					// Finally, if that request is the next one after this one,
+					// then the iterator is going to be invalid. So reset it now
+					// and start at the beginning of the list!
+					//
+					if (PhoneOwner()->ReqActiveList().IsEmpty() == EFalse)
+						{
+						iter.Set(*PhoneOwner()->ReqActiveList().First());
+						}
+					else
+						{
+						break;
+						}
+					}
+				else 
+					{
+		            if (reqMode&KReqModeMultipleCompletionWithInterestLevel && iDeliveryObject)
+		                {
+		                iDeliveryObject->DeletedReqEntry(reqEntry);
+		                }
+					
+                        LOGTEXT("Destroying request");
+                        DestroyReq(reqEntry);
+                        CheckAndDestroyDummySubSession();
+					}
+				}
+			}
+		}
+	}
+
+void CTelObject::CancelSubSession(CTelSession* aSession,const TInt aSubSessionHandle)
+//
+// Flush outstanding requests from the queue for this client only
+// Cancel the service if request already passed to Tsy
+//
+	{
+	CReqEntry* reqEntry=NULL;
+	while (reqEntry=PhoneOwner()->FindClientReqInWaitList(aSession,aSubSessionHandle),reqEntry)
+		CompleteAndDestroyReq(reqEntry,KErrCancel);
+
+	CancelActiveReq(aSession,aSubSessionHandle);
+	}
+
+void CTelObject::FlushReqs(CTelSession* aSession,const TInt aSubSessionHandle)
+//
+// Flush outstanding requests from the queue for this client only
+// Cancel the service if request already passed to Tsy
+// Return ETrue if it have to create a dummy session
+//
+	{
+	CReqEntry* reqEntry=NULL;
+	// wait list
+	while (reqEntry=PhoneOwner()->FindClientReqInWaitList(aSession,aSubSessionHandle),reqEntry)
+		DestroyReq(reqEntry);
+
+	CancelActiveReq(aSession,aSubSessionHandle);
+
+	}
+
+CPhoneBase* CTelObject::PhoneOwner() const
+//
+// Get the owner handle
+//
+	{
+ 	return iPhoneOwner;
+	}
+
+void CTelObject::SetPhoneOwner(CPhoneBase* aPhoneOwner)
+//
+// Set the owner of phone
+//
+	{
+	iPhoneOwner=aPhoneOwner;
+	}
+
+void CTelObject::GetMessageDescriptorSizes(const RMessage2& aMessage,TInt &aSize1, TInt &aSize2) const
+    {
+    TInt messageType=aMessage.Int1();
+    aSize1=0;
+    aSize2=0;
+
+    if (messageType!=EIsaNull &&
+        messageType!=EIsaCancelMessage &&
+        messageType!=EIsPriorityClientReqWithNull)
+        {                       // we're going to create server-side buffer
+        TInt basicMsgType = messageType&(~(KUnicodeReq|KPriorityClientReq));
+
+        if (messageType==EIsaNarrowAndUnicodeDoubleDesTobeSet)
+            basicMsgType=EIsaDoubleDesTobeSet;
+        if (messageType==EIsaNarrowAndUnicodeDoubleDesTobeRead)
+            basicMsgType=EIsaDoubleDesTobeRead;
+
+        switch (basicMsgType)
+            {
+        case EIsaDoubleDesTobeSet:// if we're setting data, get length
+            aSize2=aMessage.GetDesLength(2); // no break
+        case EIsaDesTobeSet:
+            aSize1=aMessage.GetDesLength(0);
+            break;
+        case EIsaDoubleDesTobeRead:// if we're reading data, get max length
+            aSize2=aMessage.GetDesMaxLength(2);  // no break
+        case EIsaDesTobeRead:
+            aSize1=aMessage.GetDesMaxLength(0);
+            break;
+        case EIsaNarrowDesToSetAndGet:
+            aSize1=aMessage.GetDesLength(0);    // set data
+            aSize2=aMessage.GetDesMaxLength(2); // get data
+            break;
+        case EIsaNarrowDesToGetUnicodeDesToSet:
+            aSize1=aMessage.GetDesMaxLength(0); // get data
+            aSize2=aMessage.GetDesLength(2);    // set data
+            break;
+        case EIsaUnicodeDesToSetAndGet:
+            aSize1=aMessage.GetDesLength(0);     // set data
+            aSize2=aMessage.GetDesMaxLength(2);  // get data
+            break;
+        case EIsaUnicodeDesToGetNarrowDesToSet:
+            aSize1=aMessage.GetDesLength(0);      // set data
+            aSize2=aMessage.GetDesMaxLength(2);    // get data
+            break;
+        default:
+            PanicClient(EEtelPanicInvalidRequestType,aMessage);
+            break;
+            }
+        }
+    }
+
+TBool CTelObject::IsSameMessageType(const RMessage2& aMessage,CReqEntry* aReqEntry) const
+    {
+    TInt size1;
+    TInt size2;
+    TInt ptrSize=sizeof(TPtr8);
+    GetMessageDescriptorSizes(aMessage, size1, size2);
+
+    if(size1)
+        {
+        CheckAndResize(size1,aMessage);
+        size1+=ptrSize;
+        }
+    if (size2)
+        {
+        CheckAndResize(size2,aMessage);
+        size2+=ptrSize;
+        }
+    if(aReqEntry->iBuffer->EqualSizes(size1,size2))
+        {
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+void CTelObject::CompleteOrBufferRead(const RMessage2& aMessage, CReqEntry* aReqEntry) 
+//
+//	Check and complete if possible this notification/multislot command from 
+//	this subsession in the ReqActive list
+//	aMessage is the message just received from the client
+//	aReqEntry is the Entry previously created when the same client called the same function
+//
+	{
+	if(aReqEntry->iMessageNulled==FALSE)	// same client already posted this notification
+		{
+		PanicClient(EEtelPanicRequestAsyncTwice,aMessage);
+		return;
+		}
+    TInt slots=0;
+    TRAP_IGNORE(slots = NumberOfSlotsL(aReqEntry->iFunction));
+    TBool sameMessageType = IsSameMessageType(aMessage, aReqEntry); 
+    
+	if (slots>1)
+		{
+		TInt comparison = aReqEntry->iBuffer->CompareRWPtrs();
+		if (comparison==0 && aReqEntry->iBuffer->BufferFull()==FALSE)
+			{	// if the client has already read value,the automatic server-TSY 
+				// notify request becomes the "true" request
+			if(sameMessageType)
+			    {
+			    aReqEntry->iMessage=aMessage;	
+			    aReqEntry->iMessageNulled=EFalse;
+			    }
+			else
+			    {
+			    // cancel in ctsy
+                aReqEntry->iCancelFnCalled = ETrue;
+			    CancelService(aReqEntry->iFunction, aReqEntry->iTsyReqHandle);
+                aReqEntry->iCancelFnCalled = EFalse;
+			    GeneralReq(aMessage,aReqEntry->iSession,NULL);
+			    }
+			}
+		else
+			{
+			if (aReqEntry->iBuffer->OverFlow())
+				WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrOverflow);
+			else
+			    {
+			    if(sameMessageType)
+			        {
+			        WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrNone);
+			        }
+			    else
+			        {
+			        WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrOverflow);
+			        }
+			    }
+			}
+		}
+	else			// this is a non-registered notification (ie single-slot)
+		{
+		if(aReqEntry->iReadByClient)
+			{
+			if(sameMessageType)
+			    {
+			    aReqEntry->iMessage=aMessage;
+			    aReqEntry->iMessageNulled=EFalse;
+			    }
+			else
+			    {
+                CancelService(aReqEntry->iFunction, aReqEntry->iTsyReqHandle);
+                GeneralReq(aMessage,aReqEntry->iSession,NULL);
+			    }
+			}
+		else	// Client has not read this new value yet
+			{
+			if(sameMessageType)
+			    {
+			    WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrNone);
+			    }
+			else
+			    {
+			    WriteBackAndCompleteBufferedReq(aMessage,aReqEntry,KErrOverflow);
+			    }
+			}
+		}
+	}
+
+void CTelObject::CheckAndResize(TInt& aSizeOfData,const RMessage2& aMessage) const
+//
+//	Checks that size of data is non-zero - if not, panic client.
+//  Also checks that size of data is word-aligned, ie a multiple of 4 bytes. 
+//	If not, ensure that in the space in buffer for data is word-aligned.
+//
+	{
+	if(aSizeOfData<0)
+		PanicClient(EEtelPanicDesLengthNegative,aMessage);
+	aSizeOfData=(aSizeOfData+3)&~3;
+	}
+
+HEtelBufC8* CTelObject::CreateNarrowBufferLC(RHeap* aHeap,const RMessage2& aMessage,TUint aIndexOfClientPtr1,TUint aIndexOfClientPtr2,TInt& aSize1,TInt& aSize2,TInt aNoOfSlots) const
+//
+//	aSize1 = size of 1st descriptor buffer
+//	aSize2 = size of 2nd descriptor buffer (default=0)
+//  aHeap may be NULL if the priority heap is not to be used
+//	aNoOfSlots will usually be 1. Only if this request is a notification that requires 
+//	registering, ie increasing the number of events the server will buffer, will it be greater than 1
+//
+	{
+	TInt desSize1=aSize1;
+	TInt desSize2=aSize2;
+	CheckAndResize(aSize1,aMessage);
+	
+	TInt ptrSize=sizeof(TPtr8);
+	TInt allocSize=aSize1+ptrSize;
+	if (aSize2)
+		{
+		CheckAndResize(aSize2,aMessage);
+		allocSize += aSize2+ptrSize;
+		}
+	HEtelBufC8* buf = HEtelBufC8::NewMaxLC(allocSize*aNoOfSlots,aHeap);	// allocate a buffer for the Des and Data				
+
+	TPtr8 firstptrDes1(const_cast<TUint8*> (buf->Des().Left(ptrSize).Ptr()),ptrSize,ptrSize);			// carve the thing up
+	TPtr8 firstdataDes1(const_cast<TUint8*> (buf->Des().Mid(ptrSize,aSize1).Ptr()),desSize1,desSize1);
+	TPtr8 firstdataDes2(NULL,0,0);
+	aMessage.ReadL(aIndexOfClientPtr1,firstdataDes1);// Read the Data. If it leaves, buf will be cleaned up
+	firstptrDes1.Copy(reinterpret_cast<TUint8*> (&firstdataDes1),ptrSize);	// Copy the new Des
+	if (aSize2)
+		// Construct Second descriptor
+		{
+		TPtr8 firstptrDes2(const_cast<TUint8*> (buf->Des().Mid(ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
+		firstdataDes2.Set(const_cast<TUint8*> (buf->Des().Mid((ptrSize*2)+aSize1,aSize2).Ptr()),desSize2,desSize2);
+		aMessage.ReadL(aIndexOfClientPtr2,firstdataDes2);
+		firstptrDes2.Copy(reinterpret_cast<TUint8*> (&firstdataDes2),ptrSize);
+		}
+	for (TInt i=1; i<aNoOfSlots;i++)	
+		{// Copy descriptors into each slot
+		TPtr8 ptrDes1(const_cast<TUint8*> (buf->Des().Mid(i*allocSize,ptrSize).Ptr()),ptrSize,ptrSize);
+		TPtr8 dataDes1(const_cast<TUint8*> (buf->Des().Mid(i*allocSize+ptrSize,aSize1).Ptr()),desSize1,desSize1);
+		dataDes1.Copy(firstdataDes1);
+		ptrDes1.Copy(reinterpret_cast<TUint8*> (&dataDes1),ptrSize);
+		if (aSize2)
+			{
+			TPtr8 ptrDes2(const_cast<TUint8*> (buf->Des().Mid(i*allocSize+ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
+			TPtr8 dataDes2(const_cast<TUint8*> (buf->Des().Mid(i*allocSize+(ptrSize*2)+aSize1).Ptr()),desSize2,desSize2);
+			dataDes2.Copy(firstdataDes2);
+			ptrDes2.Copy(reinterpret_cast<TUint8*> (&dataDes2),ptrSize);
+			}
+		}
+	return buf;
+	}
+
+HEtelBufC16* CTelObject::CreateUnicodeBufferLC(RHeap* aHeap,const RMessage2& aMessage,TUint aIndexOfClientPtr1,TUint aIndexOfClientPtr2,TInt& aSize1,TInt& aSize2,TInt aNoOfSlots) const
+//
+//	We place both parameters in the same buffer which is either narrow or unicode (unicode in this case)
+//	Should a function ever require one parameter to be narrow and the other unicode,
+//	will need to review.
+//
+	{
+	TInt desSize1=aSize1;
+	TInt desSize2=aSize2;
+	CheckAndResize(aSize1,aMessage);
+	TInt ptrSize=sizeof(TPtr16);
+	TInt allocSize=aSize1+ptrSize;
+	if (aSize2)
+		{
+		CheckAndResize(aSize2,aMessage);
+		allocSize += aSize2+ptrSize;
+		}
+	HEtelBufC16* buf = HEtelBufC16::NewMaxLC(allocSize*aNoOfSlots,aHeap);	// allocate a buffer for the Des and Data				
+
+	TPtr16 firstptrDes1(const_cast<TUint16*> (buf->Des().Left(ptrSize).Ptr()),ptrSize,ptrSize);			// carve the thing up
+	TPtr16 firstdataDes1(const_cast<TUint16*> (buf->Des().Mid(ptrSize,aSize1).Ptr()),desSize1,desSize1);
+	TPtr16 firstdataDes2(NULL,0,0);
+	aMessage.ReadL(aIndexOfClientPtr1,firstdataDes1);// Read the Data. If it leaves, buf will be cleaned up
+	firstptrDes1.Copy(reinterpret_cast<TUint16*> (&firstdataDes1),ptrSize);	// Copy the new Des
+	if (aSize2)
+		// Construct Second descriptor
+		{
+		TPtr16 firstptrDes2(const_cast<TUint16*> (buf->Des().Mid(ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
+		firstdataDes2.Set(const_cast<TUint16*> (buf->Des().Mid((ptrSize*2)+aSize1,aSize2).Ptr()),desSize2,desSize2);
+		aMessage.ReadL(aIndexOfClientPtr2,firstdataDes2);
+		firstptrDes2.Copy(reinterpret_cast<TUint16*> (&firstdataDes2),ptrSize);
+		}
+	for (TInt i=1; i<aNoOfSlots;i++)	
+		{// Copy descriptors into each slot
+		TPtr16 ptrDes1(const_cast<TUint16*> (buf->Des().Mid(i*allocSize,ptrSize).Ptr()),ptrSize,ptrSize);
+		TPtr16 dataDes1(const_cast<TUint16*> (buf->Des().Mid(i*allocSize+ptrSize,aSize1).Ptr()),desSize1,desSize1);
+		dataDes1.Copy(firstdataDes1);
+		ptrDes1.Copy(reinterpret_cast<TUint16*> (&dataDes1),ptrSize);
+		if (aSize2)
+			{
+			TPtr16 ptrDes2(const_cast<TUint16*> (buf->Des().Mid(i*allocSize+ptrSize+aSize1,ptrSize).Ptr()),ptrSize,ptrSize);
+			TPtr16 dataDes2(const_cast<TUint16*> (buf->Des().Mid(i*allocSize+(ptrSize*2)+aSize1).Ptr()),desSize2,desSize2);
+			dataDes2.Copy(firstdataDes2);
+			ptrDes2.Copy(reinterpret_cast<TUint16*> (&dataDes2),ptrSize);
+			}
+		}
+	return buf;
+	}
+
+CReqEntry* CTelObject::ReqAnalyserL(const RMessage2& aMessage,CTelSession* aSession,TReqMode& aReqMode) 
+//
+// Analyse the request. First search for an entry from the same client for the same request,
+// and if found either panic if this is a non-buffered request(ie the request is already
+// pending) or look at the buffer to see if there is any unread data to complete with.
+// If the identical entry was not found and this is a request of type multiple completion, search 
+// for a similar one by a different client (on this TelObject) and if found simply create a new
+// entry with the same request handle that will be completed at the same time as the current
+// posted notification. 
+// If this request has not been found in the active or wait lists, create the necessary 
+// address space on server side
+//
+	{
+	HEtelBufC8* buf8=NULL;
+	HEtelBufC16* buf16=NULL;
+	CReqEntry* reqEntry=NULL;
+
+	reqEntry = PhoneOwner()->FindSameClientEntry(aSession,aMessage.Int3(),aMessage.Function());
+	if (reqEntry) 
+		{	
+		if (aReqMode&KReqModeRePostImmediately)	
+			{
+			// same notification/buffered command has been found 
+			// and either the read has completed or it has been stored in
+			// the request entry waiting for the completion from the TSY.
+			CompleteOrBufferRead(aMessage,reqEntry);
+			}
+		else	// found an outstanding async req - panic
+			{
+			PanicClient(EEtelPanicRequestAsyncTwice,aMessage);
+			}
+		return NULL;
+		}
+	TInt messageType=aMessage.Int1();
+	TInt noOfSlots = 1;
+	if (aReqMode&KReqModeRePostImmediately)
+		noOfSlots = NumberOfSlotsL(aMessage.Function());
+    TInt size1;
+    TInt size2;
+	if (messageType!=EIsaNull &&
+		messageType!=EIsaCancelMessage &&
+		messageType!=EIsPriorityClientReqWithNull)
+		{						// we're going to create server-side buffer
+	    GetMessageDescriptorSizes(aMessage, size1, size2);
+		if (size1<0 || size2<0)
+			{
+			PanicClient(EEtelPanicBadDescriptor,aMessage);
+			return NULL;
+			}
+		if (messageType==EIsaNarrowAndUnicodeDoubleDesTobeSet || 
+			messageType==EIsaNarrowAndUnicodeDoubleDesTobeRead ||
+			messageType==EIsaNarrowDesToGetUnicodeDesToSet ||
+			messageType==EIsaUnicodeDesToGetNarrowDesToSet)
+			{
+			TInt zeroSize=0;
+
+			buf8 = CreateNarrowBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,zeroSize,noOfSlots);
+			buf16 = CreateUnicodeBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,2,NULL,size2,zeroSize,noOfSlots);	// the second client parameter pointer is passed as the first, so that the second parameter will be copied as the first
+			}
+		else 
+			if (messageType==EIsaUnicodeDesToSetAndGet)
+				buf16 = CreateUnicodeBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,size2,noOfSlots);
+
+		else
+			if (!(aSession->IsUnicodeReq(messageType)))
+				buf8 = CreateNarrowBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,size2,noOfSlots);
+
+			else
+				buf16 = CreateUnicodeBufferLC(aSession->EmergencyClientHeap(messageType),aMessage,0,2,size1,size2,noOfSlots);	
+		size1+=sizeof(TPtr);	// passed into CBuffer::NewL() later as these sizes
+		if (size2!=0)	// remain zero otherwise
+			size2+=sizeof(TPtr);	//sizeof(TPtr)==sizeof(TPtr8)==sizeof(TPtr16)
+		}
+	else
+	    {
+	    size1 = 0;
+	    size2 = 0;
+	    }
+	//
+	//	Now create the wrapper class, which manages the circular buffer. 
+	//
+	CBuffer* buffer = CBuffer::NewL(buf8,buf16,aSession->EmergencyClientHeap(messageType),size1,size2,noOfSlots);
+	if (buf8)
+		CleanupStack::Pop();	// pops HEtelBufC8 off cleanup stack
+	if (buf16)
+		CleanupStack::Pop();	// pops HEtelBufC16 off cleanup stack
+	CleanupStack::PushL(buffer);	// since buffer is still not owned by anything
+	//
+	// Now create the request entry for this client request - even if it's not to be passed
+	// down to the TSY in the case of MultipleCompletion.
+	//
+	reqEntry=PhoneOwner()->NewReqL(aMessage,aSession,buffer,this,aMessage.Function());
+	CleanupStack::Pop();
+
+	reqEntry->iInterestCategory = FindInterestCategory(aMessage.SecureId());
+
+    if ( aReqMode & (KReqModeMultipleCompletionEnabled | KReqModeMultipleCompletionWithInterestLevel) )
+		// this client has not currently got this request outstanding but another client may have 
+		{
+        CReqEntry* previousReq=NULL;
+		previousReq=PhoneOwner()->FindByIpcAndTelObject(aMessage.Function(),this, buffer->Size());	// search in active list
+		if (previousReq)
+			{
+			reqEntry->iTsyReqHandle=previousReq->iTsyReqHandle;
+			reqEntry->iReqMode=aReqMode;
+			PhoneOwner()->AddReqToActive(reqEntry);
+			reqEntry=NULL;
+			}
+		else if (aReqMode&KReqModeFlowControlObeyed)
+			{
+			previousReq=PhoneOwner()->FindByIpcAndTelObjectInWaiting(aMessage.Function(),this, buffer->Size());
+			if (previousReq)
+				{
+				reqEntry->iTsyReqHandle=previousReq->iTsyReqHandle;
+				reqEntry->iReqMode=aReqMode;
+				PhoneOwner()->AddReqToWaiting(reqEntry);
+				reqEntry=NULL;
+				}
+			}
+		}
+	return reqEntry;
+	}
+
+void CTelObject::GeneralReq(const RMessage2& aMessage,CTelSession* aSession,CReqEntry* aNewReqEntry, TBool aFromFlowControlResume)
+//
+// On any CTelObject based class, do the general processing around sequential and parallel
+// request modes for the server, before calling the pure virtual Service in the class to do
+// the actual command.
+//
+	{
+
+	LOGTEXT2("CTelObject::GeneralReq - IPC=%d", aMessage.Function());
+	RECORD_IPC(aMessage,aSession,this,aFromFlowControlResume);
+	if (aFromFlowControlResume && !aFromFlowControlResume){	; } // avoid compiler warning when ETEL_RECORDER is not defined
+	
+	TInt type=aMessage.Int1();
+	CReqEntry* reqEntry=NULL;
+	TInt basicMsgType = type&(~(KUnicodeReq|KPriorityClientReq));
+	switch(basicMsgType)
+		{
+	case EIsaNull:
+	case EIsaDesTobeSet:
+	case EIsaDesTobeRead:
+	case EIsaDoubleDesTobeSet:
+	case EIsaDoubleDesTobeRead:
+	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
+	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
+	case EIsaNarrowDesToSetAndGet:
+	case EIsaNarrowDesToGetUnicodeDesToSet:
+	case EIsaUnicodeDesToSetAndGet:
+	case EIsaUnicodeDesToGetNarrowDesToSet:
+		{
+		TInt ipc=aMessage.Function();
+
+		TReqMode reqMode=0;
+		TRAPD(res,(reqMode=ReqModeL(ipc)));
+		if (res)
+			{
+			RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), res);
+			aMessage.Complete(res);
+			return;
+			}
+
+        // If a call is session based then it can only be used
+        // when the client is the session owner.
+        if (reqMode&KReqModeSessionBased && IsSessionInProgress() 
+                /*&& aMessage.Int3() != iSessionOwner.iSubSessionId TODO*/)
+            {
+            // Each type of session only allowed to have one ongoing 'session/dialogue'.
+			RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), res);
+            aMessage.Complete(KErrServerBusy);
+            return;
+            }
+			
+		if (aNewReqEntry==NULL)
+			{
+			TRAP(res,reqEntry=ReqAnalyserL(aMessage,aSession,reqMode));
+			if (res)
+				{
+				RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), res);
+				aMessage.Complete(res);
+				return;				
+				}
+			else 
+				if (reqEntry==NULL) // there was no need to construct another reqEntry, 
+						// or another reqEntry with identical IPC for a different client 
+						// has been added inside ReqAnalyserL()
+
+					return;
+			reqEntry->iReqMode = reqMode;	// so ReqCompleted() needn't ask for it again
+			}
+		else
+			reqEntry=aNewReqEntry;	// aNewReqEntry has just come from the waiting list
+				
+		if (reqMode&KReqModeFlowControlObeyed) // flow control obeyed
+			{
+			if (PhoneOwner()->FlowControl())
+				PhoneOwner()->AddReqToWaiting(reqEntry);
+			else 
+				{
+				PhoneOwner()->FlowControlInc();
+				if (aNewReqEntry==NULL)
+					PhoneOwner()->AddReqToActive(reqEntry);
+				res=Service(aMessage,reqEntry);
+				if (res!=KErrNone) // can not do the service to tsy properly
+					{
+					CompleteAndDestroyReq(reqEntry,res);
+					PhoneOwner()->FlowControlDec(); // Dec() as service is being abandoned
+					}
+				}
+			}
+		else // Ignored 
+			{
+			PhoneOwner()->AddReqToActive(reqEntry);
+			if (reqMode&KReqModeRePostImmediately)
+				res=RegisterNotification(ipc);	// this tells the TSY the first time any client
+												// calls a particular notification.
+			if (res!=KErrNone)
+				CompleteAndDestroyReq(reqEntry,res);
+			else
+				{	
+				res=Service(aMessage,reqEntry);	// down to the TSY
+				if (res!=KErrNone)
+					CompleteAndDestroyReq(reqEntry,res);
+				}
+			}
+		break;
+		}
+	case EIsaCancelMessage:
+		// This is for Cancel Req - Int0 contains the original IPC 
+		{
+		TInt cancelIpc=aMessage.Int0();
+		reqEntry=PhoneOwner()->FindClientInWaiting(aSession,aMessage.Int3(),cancelIpc);
+		if(reqEntry!=NULL)				// Is it Waiting to be passed to the TSY?
+			{
+			CompleteAndDestroyReq(reqEntry,KErrCancel);	// If yes then complete it.
+			RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
+			aMessage.Complete(KErrNone);
+			return;
+			}
+		reqEntry=PhoneOwner()->FindClientInActive(aSession,aMessage.Int3(),cancelIpc);
+		if(reqEntry) // found in active list
+			{
+			TReqMode reqMode=0;
+			TRAPD(res,(reqMode=ReqModeL(reqEntry->iFunction)));
+			if (res)
+				{
+				// client cannot check return value of Cancel()
+				// so use return value of original function call
+				RECORD_COMPLETE_SUB(reqEntry->iMessage.Session(), this, reqEntry->iMessage.Int3(), reqEntry->iMessage.Function(), res);
+				reqEntry->iMessage.Complete(res);
+				return;
+				}
+			if (reqMode&KReqModeRePostImmediately && reqEntry->iMessageNulled)	
+				{
+				// client has called Cancel on a notification
+				// after it had completed to the client
+				RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
+				aMessage.Complete(KErrNone);
+				return;
+				}
+				// so now we know the client must have the request outstanding
+            if ((reqMode&KReqModeMultipleCompletionEnabled || reqMode&KReqModeMultipleCompletionWithInterestLevel) && !(reqEntry->iPlacedRequest))
+				{
+				if (iDeliveryObject)
+				    {
+					iDeliveryObject->DeletedReqEntry(reqEntry);
+				    }
+
+				CompleteAndDestroyReq(reqEntry,KErrCancel);	// the request hadn't been passed to the TSY
+				RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
+				aMessage.Complete(KErrNone);
+				return;
+				}
+			// so the request is outstanding on the TSY
+			if (reqEntry->iCancelFnCalled==FALSE)
+				{
+				reqEntry->iCancelFnCalled=ETrue;
+				TInt status=CancelService(aMessage.Int0(),reqEntry->iTsyReqHandle);
+				if(status!=KErrNone)
+					CompleteAndDestroyReq(reqEntry,status);
+				}
+			}
+		RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
+		aMessage.Complete(KErrNone);
+		}
+		break;
+
+	case EIsaCancelSubSession:
+		// This is a special case for cancelling all asynchronous requests for this subsession
+		{
+		CancelSubSession(aSession,aMessage.Int3());
+		RECORD_COMPLETE_SUB(aMessage.Session(), this, aMessage.Int3(), aMessage.Function(), KErrNone);
+		aMessage.Complete(KErrNone);
+		}
+		break;
+
+	default:
+		PanicClient(EEtelPanicInvalidRequestType,aMessage);
+		break;
+		}
+	}
+
+void CTelObject::AcceptIncoming(const RMessage2& aMessage,CTelSession* aSession)
+    {
+    TInt status = KErrNotReady;
+    if (iDeliveryObject)
+        {
+        status = iDeliveryObject->ClientsDecision(aMessage, aSession, ETrue);
+        }
+    aMessage.Complete(status);
+    }
+
+void CTelObject::RejectIncoming(const RMessage2& aMessage,CTelSession* aSession)
+    {
+    TInt status = KErrNotReady;
+    if (iDeliveryObject)
+        {
+        if (iDeliveryObject->DeliveryInProgress())
+            {
+            status = iDeliveryObject->ClientsDecision(aMessage, aSession, EFalse);
+            }
+        else
+            {
+            // Rejecting when the time out has occurred will lead to a KErrNone
+            // error rather than KErrTimedOut.
+            status = KErrNone;
+            }
+        }
+    aMessage.Complete(status);
+    }
+
+EXPORT_C void CTelObject::ReqCompleted(const TTsyReqHandle aTsyReqHandle,const TInt aError)
+//
+// General complete function for all CTelObject derived classes
+//
+	{
+	__ASSERT_ALWAYS(aTsyReqHandle!=TSY_HANDLE_INIT_VALUE,Fault(EEtelFaultNotRecognisedTsyHandle));
+	TInt ipc=0;
+	CReqEntry* updatedReqEntry = NULL;
+	CReqEntry* nextPostedReqEntry = NULL;
+	updatedReqEntry=PhoneOwner()->FindByTsyHandleAndPlacedRequest(aTsyReqHandle);
+	__ASSERT_ALWAYS(updatedReqEntry!=NULL, Fault(EEtelFaultCompletionReceivedWithNoReqPackage));
+
+	TInt error = ResolveError(updatedReqEntry->iSession,aError);		// set error as either low or high byte
+
+	ipc=updatedReqEntry->iFunction;
+	LOGTEXT4("CTelObject::ReqCompleted, IPC=%d, TsyHandle=%d, Error=%d", ipc, aTsyReqHandle, aError);
+
+	TReqMode reqMode = updatedReqEntry->iReqMode;
+	TBool ret=EFalse;
+	if (error!=KErrCancel)
+		{
+		//  Multiple-completion malarky.
+		//	Don't copy data across to other buffers and complete their reqs if TSY knows about
+		//  each client that has called it. In that case, 
+		//  TSY will fill in the appropriate client's buffer and complete each separately.
+		if (reqMode&KReqModeMultipleCompletionEnabled)
+		    {
+			
+			PhoneOwner()->CheckAndCompleteAllActive(updatedReqEntry,reqMode,ipc,aError);
+		    }
+        else if (reqMode&KReqModeMultipleCompletionWithInterestLevel && error ==KErrNone)
+            {
+            // TODO if delivery is active for this req then return 
+            // KErrInUse / KErrServerBusy?
+            // TODO what if one CTelObject has multiple requests which are 
+            // KReqModeMultipleCompletionWithInterestLevel. Would we need multiple
+            // delivery managers?
+            if (!IsSessionInProgress())
+                {
+                // Find an owner for the new session by offering it to the 
+                // interested clients one by one.
+                DeliverReqL(updatedReqEntry,reqMode, ipc, aError);
+                }
+            else
+                {
+                // Route response direct to session owner
+				FindReq(updatedReqEntry, reqMode, ipc, aError);
+               }
+
+            }
+			
+		if (reqMode&KReqModeRePostImmediately && error==KErrNone)
+			nextPostedReqEntry = updatedReqEntry;					
+		updatedReqEntry->iBuffer->IncWrite();
+		}
+	else	// if a cancel comes from the TSY, then if it is a notification 
+			// there may be other clients who have also called the notification and who 
+			// have entries in active list, so one of these must be re-posted.
+		{
+
+		if ( reqMode&KReqModeMultipleCompletionEnabled || reqMode&KReqModeMultipleCompletionWithInterestLevel)
+		    {
+			nextPostedReqEntry = PhoneOwner()->FindThisReqByAnotherClient(updatedReqEntry->iSession,
+			        updatedReqEntry->iMessage.Int3(),ipc,updatedReqEntry->iBuffer->Size(),this);
+			}
+			
+		if (!nextPostedReqEntry)
+			// then we don't want to post any other client's requests in place of this one
+			{
+			nextPostedReqEntry = PhoneOwner()->FindNonCancelledClientReq(updatedReqEntry->iSession,updatedReqEntry->iMessage.Int3(),ipc);
+			__ASSERT_DEBUG(updatedReqEntry!=nextPostedReqEntry, Fault(EEtelFaultCancelErrorWithoutCancelled));
+			if (nextPostedReqEntry==NULL && reqMode&KReqModeRePostImmediately)
+				{
+				TInt ret = DeregisterNotification(ipc);	// no more clients are interested so
+														// tell TSY to stop looking at notifies
+				if (ret!=KErrNone)
+					error=ret;	// so the KErrCancel wouldn't reach the client
+				}
+			}
+		}
+		
+	if (error && reqMode&KReqModeMultipleCompletionWithInterestLevel && iDeliveryObject)
+        {
+        // We need to do this before the updatedReqEntry is destroyed
+        iDeliveryObject->DeletedReqEntry(updatedReqEntry);
+        }
+	
+	if (reqMode & KReqModeRePostImmediately)
+		{
+		// this will destroy the reqEntry if an error occurred.
+		UpdateAndCompleteIfNecessary(updatedReqEntry,error);	
+		}														
+	else
+		{
+		WriteBackAndCompleteReq(updatedReqEntry,error);
+		}
+	
+	if (nextPostedReqEntry)	// will be NULL if no following request for TSY
+		{
+		if(nextPostedReqEntry->iReqMode&KReqModeFlowControlObeyed && 
+								!(nextPostedReqEntry->iReqMode&KReqModeMultipleCompletionWithInterestLevel))
+			{ // since the request mode is flow control obeyed, increment the flow control counter
+			FlowControlSuspend();
+			}
+		Service(nextPostedReqEntry->iMessage,nextPostedReqEntry);
+		}
+
+	
+	if (!(reqMode&KReqModeFlowControlObeyed)) // If flow control not enabled, go home
+		{
+		ret=ETrue;
+		}
+		
+// So everything below assumes it obeyed flow control
+// Resume Flow control ...
+	if (!ret)
+		{
+		FlowControlResume();
+		}
+//
+// Check and destroying the dummy session
+//
+	CheckAndDestroyDummySubSession();
+	}
+
+TInt CTelObject::DeliverReqL(CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aIpc, const TInt aError)
+    {
+    // There is no active session therefore we have to work out who to deliver it to. 
+    if (!iDeliveryObject)
+        {
+		iDeliveryObject = CMmDeliveryObject::NewL(*this); 
+        }
+    
+    if (iDeliveryObject->DeliveryInProgress())
+        {
+		// Session in progress.
+        return KErrPermissionDenied;
+        }
+
+	return iDeliveryObject->DeliverReqL(PhoneOwner()->ReqActiveList(), aUpdatedReqEntry, aReqMode, aIpc, aError);
+    }
+	
+void CTelObject::FindReq(CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aIpc,const TInt aError)
+    {
+	CReqEntry* reqEntry;
+	TDblQueIter<CReqEntry> iter(PhoneOwner()->ReqActiveList());
+	while(reqEntry = iter++, reqEntry!=NULL)
+		{
+		if(reqEntry->iFunction==aIpc 
+			&& reqEntry->iTelObject==aUpdatedReqEntry->iTelObject 
+			&& reqEntry->iBuffer->Size()==aUpdatedReqEntry->iBuffer->Size()
+			/*&& IsSessionOwner(reqEntry)*/)    
+			{
+			if (aUpdatedReqEntry != reqEntry)
+				{
+				// Copy data from the 'placed' request to the one
+				// that is owned by the client.
+				PhoneOwner()->UpdateBuffer(aUpdatedReqEntry,reqEntry);
+				}
+			OfferToClient(reqEntry, aUpdatedReqEntry, aReqMode, aError);
+			RepostRequest(aUpdatedReqEntry, aError);
+			}
+		}   
+	}
+	
+void CTelObject::OfferToClient(CReqEntry* aReqEntry,CReqEntry* aUpdatedReqEntry,const TReqMode aReqMode,const TInt aError)
+    {
+   if (aReqEntry == aUpdatedReqEntry)
+        {
+        aUpdatedReqEntry->iBuffer->IncWrite();
+        if (aReqMode&KReqModeRePostImmediately)
+			{
+			// this will destroy the reqEntry if an error occurred.
+            UpdateAndCompleteIfNecessary(aUpdatedReqEntry,aError);                         
+			}
+        else
+			{
+            WriteBackAndCompleteReq(aUpdatedReqEntry,aError);
+			}
+        }
+    else
+        {
+        TInt error = ResolveError(aReqEntry->iSession,aError); // set error as either low or high byte
+        if (aReqMode&KReqModeRePostImmediately)
+			{
+            UpdateAndCompleteIfNecessary(aReqEntry,error);    
+			}			
+        else
+			{
+            WriteBackAndCompleteReq(aReqEntry,error);
+			}
+        }
+    
+    CheckAndDestroyDummySubSession(); //TODO
+    }
+
+void CTelObject::RepostRequest(CReqEntry* aUpdatedReqEntry, const TInt aError)
+    {
+	TReqMode reqMode = aUpdatedReqEntry->iReqMode;
+    TBool ret=EFalse;
+    
+    CReqEntry* nextPostedReqEntry = NULL;
+    if (reqMode&KReqModeRePostImmediately && aError==KErrNone) 
+		{
+		nextPostedReqEntry = aUpdatedReqEntry;
+		}
+		
+    if (nextPostedReqEntry) // will be NULL if no following request for TSY
+        {
+        if(nextPostedReqEntry->iReqMode&KReqModeFlowControlObeyed)
+            { // since the request mode is flow control obeyed, increment the flow control counter
+            FlowControlSuspend();
+            }
+        Service(nextPostedReqEntry->iMessage,nextPostedReqEntry);
+        }
+    
+    if (!(reqMode&KReqModeFlowControlObeyed && aError == KErrNone)) // If flow control not enabled, go home
+            ret=ETrue;
+
+    // So everything below assumes it obeyed flow control
+    // Resume Flow control ...
+        if (!ret)
+            FlowControlResume();
+    }
+
+void CTelObject::SetSessionOwner(TInt aSessionHandle, TInt aSubSessionHandle)
+    {
+	iDeliveryObject->iSessionOwner = TPhoneClientId(aSessionHandle, aSubSessionHandle);
+    // TODO notify TSY that the session owner has changed 
+    }
+
+// TODO can be used by the TSY to set the session owner to the current request.
+// For each request the CTSY is given a TsyReqHandle so this is a sensible thing
+// for it to be dealing with.
+// TODO note that once a session has an owner the reserved state is irrelevant.
+
+EXPORT_C void CTelObject::SetSessionOwnerByTsyHandle(const TTsyReqHandle aTsyReqHandle)
+    {
+//    const TInt owningsession = PhoneOwner()->FindSessionByTsyHandle( aTsyReqHandle );
+//    const TInt owningsubsession = PhoneOwner()->FindSubSessionByTsyHandle( aTsyReqHandle );
+	
+//	iSessionOwner = TPhoneClientId(owningsession, owningsubsession);
+    // TODO notify TSY that the session owner has changed 
+    }
+
+
+TBool CTelObject::IsSessionOwner(CReqEntry* aReqEntry) const
+    {
+	// TODO Neil's experimental update
+    TPhoneClientId clientId(reinterpret_cast<TInt>(aReqEntry->iSession),aReqEntry->iMessage.Int3());
+	return (clientId == iDeliveryObject->iSessionOwner);
+    }
+
+TInterestCategory CTelObject::FindInterestCategory( const TSecureId aSid)
+	{
+	if (aSid == KUssdPriorityClientSid)
+	    {
+	    return EInterestCategoryPriority;
+	    }
+	else if(aSid == KUssdDefaultClientSid)
+	    {
+	    return EInterestCategoryDefault;
+	    }
+	else
+	    return EInterestCategoryStandard;
+	}	
+
+EXPORT_C TBool CTelObject::IsSessionInProgress() const
+    {
+	// TODO Neil's experimental update
+	if (iDeliveryObject)
+		{
+		return iDeliveryObject->iSessionOwner != TPhoneClientId();
+		}
+	return EFalse;
+    }
+
+EXPORT_C TInt CTelObject::ReserveSession()
+    {
+	// TODO Neil's experimental update
+	ASSERT(iDeliveryObject);
+    if (iDeliveryObject->iSessionReserved)
+        {
+        return KErrInUse;
+        }
+    iDeliveryObject->iSessionReserved = ETrue;
+	return KErrNone;
+    }
+
+EXPORT_C TBool CTelObject::IsSessionReserved() const
+    {
+	// TODO Neil's experimental update
+    return iDeliveryObject->iSessionReserved;
+    }
+
+EXPORT_C void CTelObject::CancelReserveSession()
+    {
+	// TODO Neil's experimental update
+    iDeliveryObject->iSessionReserved = EFalse;
+    }
+
+EXPORT_C void CTelObject::EndSession()
+    {
+	// TODO Neil's experimental update
+    iDeliveryObject->iSessionOwner = TPhoneClientId();
+    iDeliveryObject->iSessionReserved = EFalse;
+    }
+
+TInt CTelObject::ResolveError(CTelSession* aSession, const TInt aError) const
+/**
+ * Converts a coded error into the correct error to return.  The coded error value
+ * allows an extended error code to be present allong with a basic error code.  If
+ * the client has specified awareness of the extended codes, then they are returned.
+ * Otherwise the basic error code will be returned.  The advanced error codes do not
+ * overlap the basic ones.
+ *
+ * In the case of no extended error code available, then the core error code will
+ * be returned regardless of the client's extended error granularity.
+ *
+ * @return Either the basic error code or the advanced error coded if available and
+ *         requested.
+ * @param aSession The CTelSession of the client.
+ * @param aError The coded error. 
+ */
+	{
+	//
+	// Handle the common cases to make the code more efficent....
+	//
+	if ((aError==KErrNone) || (aError==KErrCancel))
+		{
+		return aError;
+		}
+
+	//
+	// 'aError' is coded into two halves (eXtended and baSic): 0xXXXXSSSS.  Take the
+	// top 16 bits for the eXtended code, and the bottom 16 bit for the baSic code.
+	//
+	// So, basicError becomes 0xffffSSSS and extendedError becomes 0xffffXXXX.
+	//
+	// A special case exists if the 16 bits were 0x0000 as this is KErrNone, and we must
+	// treat this as a positive int and not a negative one (e.g. clear the top 16 bits).
+	//
+	TInt basicError    = (aError | 0xFFFF0000);
+	TInt extendedError = ((aError >> 16) | 0xFFFF0000);
+
+	if (basicError == (TInt)(0xffff0000))
+		{
+		basicError = KErrNone;
+		}
+
+	if (extendedError == (TInt)(0xffff0000))
+		{
+		extendedError = KErrNone;
+		}
+	
+	//
+	// If the an extended error code is available and if client wants extended errors
+	// then return the extended error.  Otherwise return the basic error code.
+	//
+	// The extended error is not available if 'extendedError' is KErrNotFound (e.g.
+	// the top 16 bits were 0xffff.
+	//
+	if (extendedError != KErrNotFound  &&  aSession->IsExpectingExtendedError())	
+		{
+		return extendedError;
+		}
+	else
+		{
+		return basicError;
+		}
+	}
+
+void CTelObject::UpdateAndCompleteIfNecessary(CReqEntry* aReqEntry,TInt aError) const
+//
+//	If client has this request outstanding on the server, complete it, otherwise set Read
+//	flag to false. Destroy the request if an error has occurred.
+//
+	{
+	if (aReqEntry->iMessageNulled)
+		aReqEntry->iReadByClient=EFalse;	
+	else 
+		WriteBackAndCompleteBufferedReq(aReqEntry->iMessage,aReqEntry,aError);
+	if (aError)
+		DestroyReq(aReqEntry);
+	}
+
+void CTelObject::CheckAndDestroyDummySubSession()
+	{
+	if (iActiveReqCount)
+		{
+		iActiveReqCount--;
+		LOGTEXT2("In CheckAndDestroyDummySubSession(), iActiveReqCount down to %d", iActiveReqCount);
+		if ((iActiveReqCount==0) && (iCreateDummy==FALSE))
+			{
+			__ASSERT_ALWAYS(iDestroyDummySubSession!=NULL,Fault(EEtelFaultBadTelSessionPointer));
+			if (!(iDestroyDummySubSession->IsActive())) // only set going if not already active!
+				{
+				iDestroyDummySubSession->Call();
+				iTelServer->Dec();
+				}
+			}
+		}
+	else if (iCreateDummy)
+		{
+		__ASSERT_ALWAYS(iDestroyDummySubSession!=NULL,Fault(EEtelFaultBadTelSessionPointer));
+		if (!(iDestroyDummySubSession->IsActive())) // only set going if not already active!
+			{
+			iDestroyDummySubSession->Call();
+			iTelServer->Dec();
+			}
+		iCreateDummy=EFalse;
+		}
+	}
+
+void CTelObject::WriteBackAndCompleteBufferedReq(const RMessage2& aNewMessage,CReqEntry* aReqEntry,TInt aError) const
+	{
+	TInt basicMessageType =0; 
+	basicMessageType = (aNewMessage.Int1() & ~(KPriorityClientReq));
+	switch (basicMessageType)
+		{
+	case EIsaNull:
+		if (aReqEntry->iClientInterested)
+			{
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		break;
+	case EIsaDesTobeRead:
+	case EIsaDoubleDesTobeRead:
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aNewMessage.WriteL(0,*dataDes1)); // if this fails, panic the client
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+
+			if (basicMessageType==EIsaDoubleDesTobeRead)
+				{
+				TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
+				__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
+
+				TRAP(ret,aNewMessage.WriteL(2,*dataDes2));
+				if(ret!=KErrNone)
+					{
+					PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+					break;
+					}				
+				}
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		break;
+	case EIsaUnicodeDesTobeRead:
+	case EIsaUnicodeDoubleDesTobeRead:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			// The TDes16 will be at the start of the HBufC buffer
+			TDes16* unicodeDataDes1=BufferDes1u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(unicodeDataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aNewMessage.WriteL(0,*unicodeDataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+				
+			if (basicMessageType==EIsaUnicodeDoubleDesTobeRead)
+				{
+				TDes16* unicodeDataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+				__ASSERT_ALWAYS(unicodeDataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
+
+				TRAP(ret,aNewMessage.WriteL(2,*unicodeDataDes2));
+				if(ret!=KErrNone)
+					{
+					PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+					break;
+					}
+				}
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		}
+		break;
+	
+	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aNewMessage.WriteL(0,*dataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+				
+			TDes16* unicodeDataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(unicodeDataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
+
+			TRAP(ret,aNewMessage.WriteL(2,*unicodeDataDes2));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		}
+		break;
+
+    case EIsaNarrowDesToSetAndGet:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
+
+			TRAPD(ret,aNewMessage.WriteL(2,*dataDes2));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		}
+		break;
+
+	case EIsaUnicodeDesToGetNarrowDesToSet:
+	case EIsaUnicodeDesToSetAndGet: 
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes16* dataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
+
+			TRAPD(ret,aNewMessage.WriteL(2,*dataDes2));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		break;
+
+    case EIsaNarrowDesToGetUnicodeDesToSet:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EEtelFaultDes1DoesNotExist));
+
+			TRAPD(ret,aNewMessage.WriteL(0,*dataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aNewMessage);
+				break;
+				}
+			RECORD_COMPLETE_SUB(aNewMessage.Session(), this, aNewMessage.Int3(), aNewMessage.Function(), aError);
+			aNewMessage.Complete(aError);
+			}
+		}
+		break;
+
+	case EIsaDesTobeSet:
+	case EIsaDoubleDesTobeSet:
+	case EIsaUnicodeDesTobeSet:
+	case EIsaUnicodeDoubleDesTobeSet:
+	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
+	case EIsaCancelMessage:
+	case EIsaCancelSubSession:
+
+	default:
+		Fault(EEtelFaultBadMessageType);
+		break;
+		}
+	if (aError==KErrNone || aError==KErrOverflow)
+		{
+		aReqEntry->iReadByClient=ETrue;
+		aReqEntry->iMessageNulled=ETrue;
+		aReqEntry->iBuffer->IncRead();
+		}
+	}
+
+void CTelObject::WriteBackAndCompleteReq(CReqEntry* aReqEntry,const TInt aError) const
+//
+//	Complete a request entry and write data back to client
+//
+	{
+	__ASSERT_ALWAYS(aReqEntry!=NULL,Fault(EEtelFaultCompleteReqWithoutReqEntry));
+	LOGTEXT("CTelObject::WriteBackAndCompleteReq");
+	TInt basicMessageType = (aReqEntry->iMessage.Int1() & ~KPriorityClientReq);
+
+	switch (basicMessageType)
+		{
+	case EIsaNull:
+		aReqEntry->CompleteAndDeque(aError);
+		break;
+	case EIsaDesTobeSet:
+	case EIsaDoubleDesTobeSet:
+		__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+		aReqEntry->CompleteAndDeque(aError);
+		break;
+	case EIsaUnicodeDesTobeSet:
+	case EIsaUnicodeDoubleDesTobeSet:
+	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
+		__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+		aReqEntry->CompleteAndDeque(aError);
+		break;
+	case EIsaDesTobeRead:
+	case EIsaDoubleDesTobeRead:		
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			// The TPtr8 will be at the start of the HBufC buffer
+			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+			
+			if (basicMessageType==EIsaDoubleDesTobeRead)
+				{
+				TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
+
+				TRAP(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
+				if(ret!=KErrNone)
+					{
+					PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+					break;
+					}
+				}
+			}
+		aReqEntry->CompleteAndDeque(aError);
+		}
+		break;
+	case EIsaUnicodeDesTobeRead:
+	case EIsaUnicodeDoubleDesTobeRead:		
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes16* dataDes1=BufferDes1u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+
+			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+				
+			if (basicMessageType==EIsaUnicodeDoubleDesTobeRead)
+				{
+				TDes16* dataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+
+				TRAP(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
+				if(ret!=KErrNone)
+					{
+					PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+					break;
+					}
+				}
+			}
+		aReqEntry->CompleteAndDeque(aError);
+		}
+		break;
+	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+				
+			TDes16* unicodeDataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(unicodeDataDes2!=NULL,Fault(EEtelFaultDes2DoesNotExist));
+
+			TRAP(ret,aReqEntry->iMessage.WriteL(2,*unicodeDataDes2));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+			}
+		aReqEntry->CompleteAndDeque(aError);
+		}
+		break;
+
+    case EIsaNarrowDesToSetAndGet:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			// only write back the second parameter		
+			TDes8* dataDes2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+			}
+		aReqEntry->CompleteAndDeque(aError);
+		}
+		break;
+
+    case EIsaNarrowDesToGetUnicodeDesToSet:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf8!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			// only write back the first parameter		
+			TDes8* dataDes1=BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes1!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aReqEntry->iMessage.WriteL(0,*dataDes1));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+			}
+		aReqEntry->CompleteAndDeque(aError);
+		}
+		break;
+	
+	case EIsaUnicodeDesToSetAndGet:
+	case EIsaUnicodeDesToGetNarrowDesToSet:
+		{
+		if (aReqEntry->iClientInterested)
+			{
+			__ASSERT_ALWAYS(aReqEntry->iBuffer->iBuf16!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+			// only write back the second parameter		
+			TDes16* dataDes2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotRead);
+			__ASSERT_ALWAYS(dataDes2!=NULL,Fault(EETelFaultRequestWithoutBuffer));
+
+			TRAPD(ret,aReqEntry->iMessage.WriteL(2,*dataDes2));
+			if(ret!=KErrNone)
+				{
+				PanicClient(EEtelPanicBadDescriptor,aReqEntry->iMessage);
+				break;
+				}
+			}
+		aReqEntry->CompleteAndDeque(aError);
+		}
+		break;
+	
+	default:
+		Fault(EEtelFaultBadMessageType);
+		break;
+		}
+	aReqEntry->Deque();
+	delete aReqEntry;
+	}
+
+EXPORT_C void CTelObject::FlowControlSuspend()
+//
+// Suspend the Request Flow
+//
+	{
+	PhoneOwner()->FlowControlInc();
+	}
+
+
+EXPORT_C void CTelObject::FlowControlResume()
+
+//
+// Resume the Request Flow
+//
+	{
+ 	PhoneOwner()->FlowControlDec();
+ 	if(PhoneOwner()->FlowControl()>0)			// check for outstanding request
+		return;
+
+	CReqEntry* reqEntry=PhoneOwner()->ActivateNextWaitingReq();
+	if (reqEntry==NULL)
+		return;
+
+	RMessage2& message=reqEntry->iMessage;
+
+	CTelObject* theObj=reqEntry->iSession->CObjectFromHandle(message.Int3());
+	__ASSERT_ALWAYS(theObj!=NULL, Fault(EEtelFaultWaitingReqLostCObject));
+	theObj->GeneralReq(message,reqEntry->iSession,reqEntry, ETrue);
+	}
+
+//
+//	Future proofing in server
+//
+EXPORT_C TInt CTelObject::DownCallOption(TInt /*aOptionNumber*/, TAny* /*aData*/)
+	{
+	return KErrNotSupported;
+	}
+
+EXPORT_C TInt CTelObject::UpCallOption(TInt /*aOptionNumber*/, TAny* /*aData*/)
+	{
+	return KErrNotSupported;
+	}
+
+EXPORT_C TInt CTelObject::ServerVersion() const
+//
+// Lets TSY know which version of server this is, ie which extra options the server will support.
+//
+	{
+	return KETelServerVersion;
+	}
+
+EXPORT_C TSecurityPolicy CTelObject::GetRequiredPlatSecCaps(const TInt /*aIpc*/)
+/**
+ *	Default implementation of TSY side of the Etel capability policy checking delegation.
+ *	If the TSY does not support CustomAPIs or the TSY does not implement it's own version
+ *	of this virtual function, then this default implementation will get used and shall always
+ *	return a policy that fails the capability check.
+ *
+ *	@return This base implementation always returns a TSecurityPolicy::EAlwaysFail.
+ *	@param aIpc This parameter is not used in the base implementation of this virtual function.
+ */
+	{
+	return TSecurityPolicy(TSecurityPolicy::EAlwaysFail);
+	}
+
+
+TDes8* CTelObject::BufferDes1(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const
+//
+//	Returns pointer to first descriptor in current slot. More specifically, a pointer to the
+//	TPtr which is stored just before the data that it points to.
+
+//  The buffer is circular, and there are
+//	two "current" slots - one slot for where the next data should be written to by the TSY,
+//	the other from which the client should next read from. aWhichSlot specifies which of these
+//	should be returned.
+//
+	{
+	TDes8* des1=NULL;
+	if (aBuffer->iBuf8)
+		{
+		TUint8* pos = aBuffer->CurrentSlotData1(aWhichSlot);
+		if (pos)
+			des1=reinterpret_cast<TDes8*> (pos);
+		}
+	return des1;
+	}
+
+TDes8* CTelObject::BufferDes2(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const 
+	{
+	TDes8* des2=NULL;
+	if (aBuffer->iBuf8)
+		{
+		TUint8* pos = aBuffer->CurrentSlotData2(aWhichSlot);
+		if (pos)
+			des2=reinterpret_cast<TDes8*> (pos);
+		}
+	return des2;
+	}
+
+TDes16* CTelObject::BufferDes1u(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const
+	{
+	TDes16* des1=NULL;
+	if (aBuffer->iBuf16)
+		{
+		TUint16* pos = aBuffer->CurrentSlotData1u(aWhichSlot);
+		if (pos)
+			des1=reinterpret_cast<TDes16*> (pos);
+		}
+	return des1;
+	}
+
+TDes16* CTelObject::BufferDes2u(const CBuffer* aBuffer,CBuffer::TWhichSlot aWhichSlot) const 
+	{
+	TDes16* des2=NULL;
+	if (aBuffer->iBuf16)
+		{
+		TUint16* pos = aBuffer->CurrentSlotData2u(aWhichSlot);
+		if (pos)
+			des2=reinterpret_cast<TDes16*> (pos);
+		}
+	return des2;
+	}
+
+TUint8* CTelObject::Ptr1(const TDes8* aDes1) const
+//
+// return the pointer to the data of the first descriptor
+// return NULL if does not exist
+//
+	{
+	TUint8* ptr1=NULL;
+	if (aDes1)
+		ptr1=const_cast<TUint8*> (aDes1->Ptr());
+	return ptr1;
+	}
+
+void CTelObject::RemoveDummySubSessionDestroyer()
+	{
+	iDestroyDummySubSession = NULL;
+	}
+	
+//
+//
+// CSubSessionExtBase
+//
+//
+EXPORT_C CSubSessionExtBase::CSubSessionExtBase()
+//
+//	C'Tor
+//
+	{
+	__DECLARE_NAME(_S("CSubSessionExtBase"));
+	}
+
+EXPORT_C CSubSessionExtBase::~CSubSessionExtBase()
+//
+//	D'Tor
+//
+	{}
+
+TInt CSubSessionExtBase::ServiceExtFunc(const RMessage2& aMessage,CReqEntry* aReqEntry)
+//
+// Sort out Des1 and Des2 before calling ExtFunc()
+//
+	{
+	__ASSERT_ALWAYS(aReqEntry!=NULL,Fault(EEtelFaultCallTsyServiceWithoutReqPackage));
+	TTsyReqHandle tsyReqHandle=aReqEntry->iTsyReqHandle;
+
+	LOGTEXT2("Entered ServiceExtFunc with TSY handle %d", tsyReqHandle);
+	TInt ret=KErrNone;
+
+	TInt basicMessageType = aMessage.Int1() & ~(KPriorityClientReq);
+	switch (basicMessageType)
+		{
+	case EIsaNull:
+	case EIsaCancelMessage:
+		{
+		TDataPackage package;	// a package with all data pointers nulled
+		ret=ExtFunc(tsyReqHandle,aMessage.Function(),package);
+		}
+		break;
+	case EIsaDesTobeSet:
+	case EIsaDesTobeRead:
+	case EIsaDoubleDesTobeSet:
+	case EIsaDoubleDesTobeRead:	// may have been multi-slot registered
+	case EIsaNarrowDesToSetAndGet:
+		{
+		TDes8* des1 = BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotWrite);
+		if (!des1)
+            {
+            return KErrArgument;
+            }
+		TDes8* des2=NULL;
+		if (basicMessageType==EIsaDoubleDesTobeSet || 
+			basicMessageType==EIsaDoubleDesTobeRead ||
+			basicMessageType==EIsaNarrowDesToSetAndGet)
+			{
+			des2=BufferDes2(aReqEntry->iBuffer,CBuffer::ESlotWrite);
+			if (!des2)
+			    {
+			    return KErrArgument;
+			    }
+			}
+		TDataPackage package(des1,des2);
+		ret=ExtFunc(tsyReqHandle,aReqEntry->iFunction,package);
+		}
+		break;
+	case EIsaUnicodeDesTobeSet:
+	case EIsaUnicodeDesTobeRead:
+	case EIsaUnicodeDoubleDesTobeSet:
+	case EIsaUnicodeDoubleDesTobeRead:
+	case EIsaUnicodeDesToSetAndGet:
+		{
+		TDes16* des1 = BufferDes1u(aReqEntry->iBuffer,CBuffer::ESlotWrite);
+		if (!des1)
+            {
+            return KErrArgument;
+            }
+		TDes16* des2=NULL;
+		if (basicMessageType==EIsaUnicodeDoubleDesTobeSet || 
+			basicMessageType==EIsaUnicodeDoubleDesTobeRead ||
+			basicMessageType==EIsaUnicodeDesToSetAndGet)
+			{
+			des2 = BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotWrite);
+			if (!des2)
+                {
+                return KErrArgument;
+                }
+			}	
+		TDataPackage package(des1,des2);
+		ret=ExtFunc(tsyReqHandle,aReqEntry->iFunction,package);
+		}
+		break;
+	case EIsaNarrowAndUnicodeDoubleDesTobeSet:
+	case EIsaNarrowAndUnicodeDoubleDesTobeRead:
+	case EIsaNarrowDesToGetUnicodeDesToSet:
+	case EIsaUnicodeDesToGetNarrowDesToSet:
+		{
+		TDes8* des1 = BufferDes1(aReqEntry->iBuffer,CBuffer::ESlotWrite);
+        if (!des1)
+            {
+            return KErrArgument;
+            }
+		TDes16* des2=NULL;
+		des2=BufferDes2u(aReqEntry->iBuffer,CBuffer::ESlotWrite);
+		if (!des2)
+            {
+            return KErrArgument;
+            }
+		TDataPackage package(des1,des2);
+		ret=ExtFunc(tsyReqHandle,aReqEntry->iFunction,package);
+		}
+		break;
+
+	default:
+		Fault(EEtelFaultMessageTypeCorrupted);
+		break;
+		}
+	return ret;
+	}
+
+EXPORT_C TInt CSubSessionExtBase::Service(const RMessage2& aMessage, CReqEntry* aReqEntry)
+//
+// The ServiceL functionality for the ext base
+//
+	{
+	aReqEntry->iPlacedRequest=ETrue;
+	return ServiceExtFunc(aMessage,aReqEntry);
+	}
+
+EXPORT_C void CSubSessionExtBase::CloseSubSessionPreProcessing(CTelSession* aSession,const TInt aSubSessionHandle)
+	{
+	CreateDummySession(aSession,aSubSessionHandle);
+	FlushReqs(aSession,aSubSessionHandle);
+	}
+
+EXPORT_C void CSubSessionExtBase::OpenPostProcessing(CTelSession* /*aSession*/,const TInt)
+//
+// Perform post-processing after object has been added to session's CObjectIx.
+//
+	{
+	}
+	
+EXPORT_C RHandleBase* CSubSessionExtBase::GlobalKernelObjectHandle()
+	{	
+	return NULL;	
+	}
+	
+EXPORT_C void CSubSessionExtBase::NullMethod1()
+	{}
+
+EXPORT_C void CFaxBase::NullMethod2()
+	{}
+
+//
+//
+// CLibUnloader
+//
+//
+CLibUnloader::CLibUnloader()
+//
+// C'tor
+//
+	:CAsyncOneShot(CActive::EPriorityHigh)
+	{
+	__DECLARE_NAME(_S("CLibUnloader"));
+	}
+
+CLibUnloader* CLibUnloader::NewL(RLibrary &aLib)
+//
+// New Library Unloader
+//
+	{
+	CLibUnloader *s=new(ELeave)CLibUnloader;
+	s->iLib=aLib;
+	return s;
+	}
+
+CLibUnloader::~CLibUnloader()
+	{
+	Cancel();
+	iLib.Close();
+	}
+
+void CLibUnloader::RunL()
+//
+// Unload TSY module
+//
+	{
+	delete this;
+	}
+
+//
+//
+// CPhoneFactoryBase definition
+//
+//
+EXPORT_C TBool CPhoneFactoryBase::QueryVersionSupported( TVersion const & aVersion )const
+//
+// Pass through to default QVS
+//
+	{
+	return(User::QueryVersionSupported(iVersion,aVersion));
+	}
+
+EXPORT_C CPhoneFactoryBase::CPhoneFactoryBase()
+//
+// C'Tor
+//
+	{
+	__DECLARE_NAME(_S("CPhoneFactoryBase"));
+	}
+
+void CPhoneFactoryBase::ConstructL(RLibrary& aLib)
+//
+// Allocate a CLibrary Unloader
+//
+	{
+	iLibUnloader=CLibUnloader::NewL(aLib);
+	}
+
+EXPORT_C CPhoneFactoryBase::~CPhoneFactoryBase()
+//
+// D'Tor
+//
+	{
+	if (iLibUnloader)
+		{
+		LOGTEXT("About to call iLibUnloader");
+		iLibUnloader->Call();
+		}
+	}
+
+EXPORT_C void CPhoneFactoryBase::CPhoneFactoryBase_Reserved1()
+//
+// Reserved virtual function
+//
+	{}
+
+//
+// HEtelBufC definitions
+//
+
+
+//
+// HEtelBufC8
+//
+HEtelBufC8* HEtelBufC8::NewMaxLC(TInt aMaxLength,RHeap* aHeap)
+	{
+	__ASSERT_ALWAYS(aMaxLength>=0,Fault(EEtelFaultMaxDesLengthNegative));
+
+	HEtelBufC8* pH=NULL;
+	TInt size=sizeof(HEtelBufC8)+(aMaxLength*sizeof(TUint8));
+	if (aHeap!=NULL)
+		pH=(HEtelBufC8*)aHeap->AllocLC(size);
+	else
+		pH=(HEtelBufC8*)User::AllocLC(size);
+	pH->iLength=aMaxLength;
+	pH->iHeap=aHeap;
+	pH->Des().SetLength(aMaxLength);
+	return(pH);
+	}
+
+TPtr8 HEtelBufC8::Des()
+	{
+	TUint8* ptr = reinterpret_cast<TUint8*> (((reinterpret_cast<TInt> (this)) +
+													sizeof(HEtelBufC8))
+											);
+	return TPtr8(ptr,iLength,iLength);
+	}
+
+const TUint8* HEtelBufC8::Ptr() const
+	{
+	return reinterpret_cast<const TUint8*> (((reinterpret_cast<TInt> (this)) +
+													sizeof(HEtelBufC8))
+											);
+	}
+
+void HEtelBufC8::operator delete(TAny* aPtr)
+//
+// overloaded delete - deletes from priority client heap if iHeap is not NULL
+//
+	{
+	RHeap* heap=NULL;
+	if (aPtr!=NULL)
+		{
+		heap = (reinterpret_cast<HEtelBufC8*> (aPtr))->iHeap;
+		}
+
+	if (heap!=NULL)
+		{
+		reinterpret_cast<HEtelBufC8*> (aPtr)->iHeap->Free(aPtr);
+		}
+	else
+		{
+		User::Free(aPtr);
+		}
+	}
+
+//
+// HEtelBufC16
+//			  
+HEtelBufC16* HEtelBufC16::NewMaxLC(TInt aMaxLength,RHeap* aHeap)
+	{
+	__ASSERT_ALWAYS(aMaxLength>=0,Fault(EEtelFaultMaxDesLengthNegative));
+
+	HEtelBufC16* pH=NULL;
+	TInt size=sizeof(HEtelBufC16)+(aMaxLength*sizeof(TUint16));
+	if (aHeap!=NULL)
+		pH=(HEtelBufC16*)aHeap->AllocLC(size);
+	else
+		pH=(HEtelBufC16*)User::AllocLC(size);
+	pH->iLength=aMaxLength;
+	pH->iHeap=aHeap;
+	pH->Des().SetLength(aMaxLength);
+	return(pH);
+	}
+
+TPtr16 HEtelBufC16::Des()
+	{
+	TUint16* ptr=reinterpret_cast<TUint16*> ((reinterpret_cast<TInt> (this)+sizeof(HEtelBufC16)));
+	return TPtr16(ptr,iLength,iLength);
+	}
+
+const TUint16* HEtelBufC16::Ptr() const
+	{
+	return reinterpret_cast<const TUint16*> ((reinterpret_cast<TInt> (this)+sizeof(HEtelBufC16)));
+	}
+
+void HEtelBufC16::operator delete(TAny* aPtr)
+//
+// overloaded delete - deletes from priority client heap if iHeap is not NULL
+//
+	{
+	RHeap* heap=NULL;
+	if (aPtr!=NULL)
+		heap=reinterpret_cast<HEtelBufC16*> (aPtr)->iHeap;
+
+	if (heap!=NULL)
+		reinterpret_cast<HEtelBufC16*> (aPtr)->iHeap->Free(aPtr);
+	else
+		User::Free(aPtr);
+	}
+
+//
+//	TDataPackage class contains the data pointers to be passed down to the TSY in ExtFunc()
+//
+TDataPackage::TDataPackage()
+	: iDes1(NULL),iDes2(NULL),iDes1u(NULL),iDes2u(NULL)
+	{}
+TDataPackage::TDataPackage(TDes8* aDes1, TDes8* aDes2)
+	: iDes1(aDes1),iDes2(aDes2),iDes1u(NULL),iDes2u(NULL)
+	{}
+
+TDataPackage::TDataPackage(TDes16* aDes1, TDes16* aDes2)
+	: iDes1(NULL),iDes2(NULL),iDes1u(aDes1),iDes2u(aDes2)
+	{}
+TDataPackage::TDataPackage(TDes8* aDes1, TDes16* aDes2)
+	: iDes1(aDes1),iDes2(NULL),iDes1u(NULL),iDes2u(aDes2)
+	{}
+
+EXPORT_C TDes8* TDataPackage::Des1n() const
+	{
+	__ASSERT_ALWAYS(iDes1,Fault(EEtelFaultDes1DoesNotExist));
+	return iDes1;
+	}
+EXPORT_C TDes8* TDataPackage::Des2n() const
+	{
+	__ASSERT_ALWAYS(iDes2,Fault(EEtelFaultDes2DoesNotExist));
+	return iDes2;
+	}
+EXPORT_C TDes16* TDataPackage::Des1u() const
+	{
+	__ASSERT_ALWAYS(iDes1u,Fault(EEtelFaultDes1DoesNotExist));
+	return iDes1u;
+	}
+EXPORT_C TDes16* TDataPackage::Des2u() const
+	{
+	__ASSERT_ALWAYS(iDes2u,Fault(EEtelFaultDes2DoesNotExist));
+	return iDes2u;
+	}
+
+EXPORT_C TAny* TDataPackage::Ptr1() const
+	{
+	if (iDes1u)
+		return reinterpret_cast<TAny*> (const_cast<TUint16*> (iDes1u->Ptr()));		
+	if (iDes1)
+		return reinterpret_cast<TAny*> (const_cast<TUint8*> (iDes1->Ptr()));
+	return NULL;
+	}
+
+EXPORT_C TAny* TDataPackage::Ptr2() const
+	{
+	if (iDes2u)
+		return reinterpret_cast<TAny*> (const_cast<TUint16*> (iDes2u->Ptr()));
+	if (iDes2)
+		return reinterpret_cast<TAny*> (const_cast<TUint8*> (iDes2->Ptr()));
+	return NULL;
+	}
+
+/**
+* This helper utility returns the type of a packaged data structure.
+* It is very useful to know which type of variables (unicode or narrow) a package contains
+* before passing it to any functions. It could also help to provide more generic implementation
+* on the TSY, that currently assumes knowledge of the way the data are packaged.
+*
+*/
+
+EXPORT_C TDataPackage::TDataPackageType TDataPackage::Type() const
+	{
+	if(iDes1 && iDes2)
+		return EPackage1n2n;
+	else if (iDes1u && iDes2u)
+		return EPackage1u2u;
+	else if (iDes1 && iDes2u)
+		return EPackage1n2u;
+	else if (iDes1 && !iDes2)
+		return EPackage1n;
+	else if (iDes1u && !iDes2u)
+		return EPackage1u;
+	else 
+		return EPackageUnknown;
+	}
+
+/**
+Non-exported static factory constructor.  This class should only be instantiated by Etel server.
+*/
+CFaxSharedFileHandles* CFaxSharedFileHandles::NewL(const RMessage2& aMsg)
+	{
+	CFaxSharedFileHandles* obj = new(ELeave) CFaxSharedFileHandles();	
+	CleanupStack::PushL(obj);
+	obj->ConstructL(aMsg);
+	CleanupStack::Pop(obj);
+	return obj;		
+	}	
+	
+/**
+Destructor.
+
+@publishedPartner
+@released 
+*/
+EXPORT_C CFaxSharedFileHandles::~CFaxSharedFileHandles()
+	{
+	iFile.Close();	
+	}
+
+/**
+Default constructor.
+*/	
+CFaxSharedFileHandles::CFaxSharedFileHandles()
+	{
+	//empty
+	}
+	
+/**
+Reference to an adopted file.
+
+@return RFile& Reference to an open file handle.
+@publishedPartner
+@released 
+*/
+EXPORT_C RFile& CFaxSharedFileHandles::File() 
+	{
+	return iFile;	
+	};
+
+/**
+Adopt the file during construction.
+*/
+void CFaxSharedFileHandles::ConstructL(const RMessage2& aMsg)
+	{
+	//Use the RMessage2 and EKA2 adopt functions to adopt the file.  Slots 0 & 2 contain relevant session handles.
+	User::LeaveIfError(iFile.AdoptFromClient(aMsg, 0, 2));
+	}