libraries/iosrv/server/console.cpp
changeset 0 7f656887cf89
child 83 2a78c4ff2eab
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/iosrv/server/console.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,1394 @@
+// console.cpp
+// 
+// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+#include <e32cons.h>
+#include <e32uid.h>
+#include "server.h"
+#include "console.h"
+#include "log.h"
+
+
+#ifdef IOSRV_LOGGING
+#define CONSOLE_NAME TName consoleName(Name())
+#define READER_NAME(x) TName readerName((x).IorName())
+#define WRITER_NAME(x) TName writerName((x).IowName())
+#else
+#define CONSOLE_NAME
+#define READER_NAME(x)
+#define WRITER_NAME(x)
+#endif
+
+const TInt KConsoleThreadMinHeapSize = 0x1000;
+const TInt KConsoleThreadMaxHeapSize = 0x1000000;
+
+CIoConsole* CIoConsole::NewLC(const TDesC& aImplementation, const TDesC& aTitle, const TSize& aSize, const TIoConfig& aConfig, CIoConsole* aUnderlying, TUint aOptions)
+	{
+	CIoConsole* self = new(ELeave) CIoConsole(aConfig);
+	CleanupClosePushL(*self);
+	self->ConstructL(aImplementation, aTitle, aSize, aUnderlying, aOptions);
+	return self;
+	}
+
+CIoConsole::~CIoConsole()
+	{
+	// if the sub-thread is servicing a request of ours now, we have to kill it. Otherwise, we might hang
+	// when we try and cancel the request AO, if (for example) it's servicing a long-standing Create request.
+	if (iRequestAo && (iRequestAo->IsActive()) && (iServerThread.Handle()!=KNullHandle))
+		{
+		iServerThread.Kill(KErrCancel);
+		iThreadServer.Close(); // this won't be closed by the sub-thread, as we just killed it.
+		}
+	delete iThreadWatcher;
+	delete iRequestAo;
+	iRequestQueue.Close();
+	delete iImplementation;
+	delete iReader;
+	iConsole.Close();
+	delete iCreationTitle ;
+	iServerThread.Close();
+	}
+
+const TDesC& CIoConsole::Implementation() const
+	{
+	return *iImplementation;
+	}
+
+TBool CIoConsole::IsType(RIoHandle::TType aType) const
+	{
+	return ((aType == RIoHandle::EEndPoint) || (aType == RIoHandle::EConsole));
+	}
+
+void CIoConsole::HandleReaderDetached(MIoReader& aReader)
+	{
+	HandleReadWriterDetached(aReader);
+	}
+
+void CIoConsole::HandleWriterDetached(MIoWriter& aWriter)
+	{
+	HandleReadWriterDetached(aWriter);
+	}
+
+template <class T> void CIoConsole::HandleReadWriterDetached(T& aReadWriter)
+	{
+	// Remove pending requests originated from this reader / writer.
+	for (TInt i = (iRequestQueue.Count() - 1); i >= 0; --i)
+		{
+		TConsoleRequest* request = iRequestQueue[i];
+		if (request->OriginatedFrom(aReadWriter))
+			{
+			delete request;
+			iRequestQueue.Remove(i);
+			}
+		}
+
+	// If this reader / writer originated the request that's currently being process, abort it.
+	if (iRequestAo->CurrentRequest() && iRequestAo->CurrentRequest()->OriginatedFrom(aReadWriter))
+		{
+		iRequestAo->Abort();
+		}
+	}
+
+void CIoConsole::IorepReadL(MIoReader&)
+	{
+	if (!iReader->IsActive())
+		{
+		iReader->QueueRead();
+		}
+	}
+
+void CIoConsole::IorepReadKeyL(MIoReader& aReader)
+	{
+	IorepReadL(aReader);
+	}
+
+void CIoConsole::IorepSetConsoleModeL(RIoReadWriteHandle::TMode aMode, MIoReader& aReader)
+	{
+	NewRequest(new(ELeave)TConsoleSetModeRequest(aReader, *this, aMode));
+	}
+
+void CIoConsole::IowepWriteL(MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleWriteRequest(aWriter));
+	}
+
+void CIoConsole::IowepWriteCancel(MIoWriter&)
+	{
+	}
+
+void CIoConsole::IowepCursorPosL(MIoWriter& aWriter) const
+	{
+	NewRequest(new(ELeave)TConsoleCursorPosRequest(aWriter));
+	}
+
+void CIoConsole::IowepSetCursorPosAbsL(const TPoint& aPoint, MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleSetCursorPosAbsRequest(aWriter, aPoint));
+	}
+
+void CIoConsole::IowepSetCursorPosRelL(const TPoint& aPoint, MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleSetCursorPosRelRequest(aWriter, aPoint));
+	}
+
+void CIoConsole::IowepSetCursorHeightL(TInt aPercentage, MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleSetCursorHeightRequest(aWriter, aPercentage));
+	}
+
+void CIoConsole::IowepSetTitleL(MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleSetTitleRequest(aWriter));
+	}
+
+void CIoConsole::IowepClearScreenL(MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleClearScreenRequest(aWriter));
+	}
+
+void CIoConsole::IowepClearToEndOfLineL(MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleClearToEndOfLineRequest(aWriter));
+	}
+
+void CIoConsole::IowepSetAttributesL(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor, MIoWriter& aWriter)
+	{
+	NewRequest(new(ELeave)TConsoleSetAttributesRequest(aWriter, aAttributes, aForegroundColor, aBackgroundColor));
+	}
+
+void CIoConsole::IowepScreenSizeL(MIoWriter& aWriter) const
+	{
+	NewRequest(new(ELeave)TConsoleScreenSizeRequest(aWriter, iConfig));
+	}
+
+CIoConsole::CIoConsole(const TIoConfig& aConfig)
+	: iConfig(aConfig), iDetectedSize(-1, -1)
+	{
+	}
+
+void CIoConsole::ConstructL(const TDesC& aImplementation, const TDesC& aTitle, const TSize& aSize, CIoConsole* aUnderlying, TUint aOptions)
+	{
+	LOG(CIoLog::Printf(_L("Console 0x%08x created"), this));
+	iCreationTitle = aTitle.AllocL();
+	iCreationSize = aSize;
+	
+	iRequestAo = new(ELeave)CConsoleRequest(*this);
+	
+	if (aImplementation.Length())
+		{
+		iImplementation = aImplementation.AllocL();
+		}
+	else
+		{
+		iImplementation = iConfig.ConsoleImplementation().AllocL();
+		}
+		
+	User::LeaveIfError(iConsole.Connect(CIoConsoleProxyServerNewL, iImplementation, *iImplementation, KDefaultStackSize, KConsoleThreadMinHeapSize, KConsoleThreadMaxHeapSize, iThreadServer, iServerThread));
+	iThreadWatcher = new(ELeave)CServerDeathWatcher(iThreadServer, iServerThread);
+	if (aOptions & RIoConsole::ELazyCreate)
+		{
+		User::LeaveIfError(iConsole.SetLazyConstruct());
+		}
+	if (iConfig.ConsoleSizeDetect())
+		{
+		User::LeaveIfError(iConsole.SetConsoleSizeDetect());
+		}
+	if (aUnderlying)
+		{
+		User::LeaveIfError(aUnderlying->Open());
+		CleanupClosePushL(*aUnderlying);
+		NewRequest(new(ELeave)TConsoleSetUnderlyingRequest(*aUnderlying));
+		CleanupStack::Pop();
+		}
+	NewRequest(new(ELeave)TConsoleCreateRequest(*this));
+		
+	iReader = CConsoleReader::NewL(*this);
+	}
+	
+void CIoConsole::CreateComplete(TInt aError)
+	{
+	iCreateStatus = aError;
+	}
+	
+void CIoConsole::NewRequest(TConsoleRequest* aRequest) const
+	{
+	ASSERT(aRequest);
+	TInt err = iRequestQueue.Append(aRequest);
+	if (err!=KErrNone)
+		{
+		aRequest->CompleteD(err);
+		return;
+		}
+
+	CheckQueue();
+	}
+	
+void CIoConsole::CheckQueue() const
+	{
+	if (iCreateStatus != KErrNone)
+		{
+		while (iRequestQueue.Count())
+			{
+			TConsoleRequest* req = iRequestQueue[0];
+			iRequestQueue.Remove(0);
+			req->CompleteD(iCreateStatus);
+			}
+		return;
+		}
+	if ((!iRequestAo->IsActive()) && (iRequestQueue.Count()))
+		{
+		iRequestAo->Service(iRequestQueue[0]);
+		iRequestQueue.Remove(0);
+		}
+	}
+	
+void CIoConsole::ConsoleDied()
+	{
+	iCreateStatus = KErrGeneral;
+
+	iReader = CConsoleReader::NewL(*this);
+	}
+
+void CIoConsole::ReadComplete(TInt aError)
+	{
+	MIoReader* foregroundReader = AttachedReader(0);
+	if (foregroundReader)
+		{
+		foregroundReader->IorReadKeyComplete(aError, 0, 0);
+		}
+	}
+
+void CIoConsole::ReadComplete(TUint aKeyCode, TUint aModifiers)
+	{
+	TInt index = 0;
+	MIoReader* foregroundReader = AttachedReader(index++);
+	MIoReader* reader = foregroundReader;
+	TBool keyHandled(EFalse);
+	while (reader)
+		{
+		if (reader->IorIsKeyCaptured(aKeyCode, aModifiers))
+			{
+			if (reader->IorReadPending())
+				{
+				TPtrC keyCodePtr((TUint16*)&aKeyCode, 1);
+				reader->IorReadBuf().Append(keyCodePtr);
+				reader->IorDataBuffered(1);
+				}
+			else
+				{
+				reader->IorReadKeyComplete(KErrNone, aKeyCode, aModifiers);
+				}
+			keyHandled = ETrue;
+			break;
+			}
+		reader = AttachedReader(index++);;
+		}
+
+	// Key not captured, so send to foreground (i.e. the first) reader.
+	if (!keyHandled && foregroundReader)
+		{
+		foregroundReader->IorReadKeyComplete(KErrNone, aKeyCode, aModifiers);
+		}
+
+	QueueReaderIfRequired();
+	}
+
+void CIoConsole::QueueReaderIfRequired()
+	{
+	TBool pendingReader(EFalse);
+	TInt index = 0;
+	MIoReader* reader = AttachedReader(index++);
+	while (reader)
+		{
+		if (reader->IorReadPending() || reader->IorReadKeyPending())
+			{
+			pendingReader = ETrue;
+			break;
+			}
+		reader = AttachedReader(index++);
+		}
+
+	if (pendingReader && !iReader->IsActive())
+		{
+		iReader->QueueRead();
+		}
+	else if (!pendingReader && iReader->IsActive())
+		{
+		iReader->Cancel();
+		}
+	}
+
+CIoConsole::CConsoleReader* CIoConsole::CConsoleReader::NewL(CIoConsole& aConsole)
+	{
+	return new(ELeave) CConsoleReader(aConsole);
+	}
+
+CIoConsole::CConsoleReader::~CConsoleReader()
+	{
+	Cancel();
+	}
+
+void CIoConsole::CConsoleReader::QueueRead()
+	{
+	iConsole.iConsole.Read(iKeyCodePckg, iKeyModifiersPckg, iStatus);
+	SetActive();
+	}
+
+CIoConsole::CConsoleReader::CConsoleReader(CIoConsole& aConsole)
+	: CActive(CActive::EPriorityStandard), iConsole(aConsole)
+	, iKeyCodePckg(iKeyCode), iKeyModifiersPckg(iKeyModifiers)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CIoConsole::CConsoleReader::RunL()
+	{
+	TInt err = iStatus.Int();
+	if (err==KErrServerTerminated)
+		{
+		iConsole.ConsoleDied();
+		err = KErrGeneral;
+		}
+	if (err)
+		{
+		iConsole.ReadComplete(err);
+		}
+	else
+		{
+		iConsole.ReadComplete(iKeyCode, iKeyModifiers);
+		}
+	}
+
+void CIoConsole::CConsoleReader::DoCancel()
+	{
+	iConsole.iConsole.ReadCancel();
+	}
+
+//______________________________________________________________________________
+//						TConsoleRequest
+void CIoConsole::TConsoleRequest::PrepareL()
+	{
+	}
+
+TBool CIoConsole::TConsoleRequest::OriginatedFrom(MIoReader&) const
+	{ 
+	return EFalse; 
+	}
+
+TBool CIoConsole::TConsoleRequest::OriginatedFrom(MIoWriter&) const
+	{
+	return EFalse;
+	}
+
+//______________________________________________________________________________
+//						TConsoleWriterRequest
+CIoConsole::TConsoleWriterRequest::TConsoleWriterRequest(MIoWriter& aWriter)
+	: iWriter(aWriter)
+	{
+	}
+
+TBool CIoConsole::TConsoleWriterRequest::OriginatedFrom(MIoWriter& aWriter) const
+	{
+	return (&iWriter == &aWriter);
+	}
+
+//______________________________________________________________________________
+//						TConsoleReaderRequest
+CIoConsole::TConsoleReaderRequest::TConsoleReaderRequest(MIoReader& aReader)
+	: iReader(aReader)
+	{
+	}
+
+TBool CIoConsole::TConsoleReaderRequest::OriginatedFrom(MIoReader& aReader) const
+	{
+	return (&iReader == &aReader);
+	}
+
+//______________________________________________________________________________
+//						TConsoleCreateRequest
+CIoConsole::TConsoleCreateRequest::TConsoleCreateRequest(CIoConsole& aOwner)
+	: iOwner(aOwner)
+	{
+	}
+
+void CIoConsole::TConsoleCreateRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.Create(*iOwner.iCreationTitle, iOwner.iCreationSize, aStatus);
+	}
+
+void CIoConsole::TConsoleCreateRequest::CompleteD(TInt aError)
+	{
+	iOwner.CreateComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleWriteRequest
+CIoConsole::TConsoleWriteRequest::TConsoleWriteRequest(MIoWriter& aWriter)
+	: TConsoleWriterRequest(aWriter), iBuf(NULL)
+	{
+	}
+
+void CIoConsole::TConsoleWriteRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	if (iWriter.IowIsStdErr())
+		{
+		aProxy.WriteStdErr(*iBuf, aStatus);
+		}
+	else
+		{
+		aProxy.Write(*iBuf, aStatus);
+		}
+	}
+
+void CIoConsole::TConsoleWriteRequest::PrepareL()
+	{
+	const TInt length = iWriter.IowWriteLength();
+	if (iBuf == NULL)
+		{
+		iBuf = HBufC::NewL(length);
+		}
+	else if (iBuf->Des().MaxLength() < length)
+		{
+		iBuf = iBuf->ReAllocL(length);
+		}
+
+	TPtr bufPtr(iBuf->Des());
+	bufPtr.Zero();
+	iWriter.IowWrite(bufPtr);
+
+	if (iWriter.IorwMode() == RIoReadWriteHandle::EText)
+		{
+		// Fix line endings (change LF to CRLF).
+		RArray<TInt> indicies(5);
+		CleanupClosePushL(indicies);
+		_LIT(KCarriageReturn, "\r");
+		for (TInt i = 0; i < length; ++i)
+			{
+			if ((*iBuf)[i] == '\n')
+				{
+				if ((i == 0) || ((*iBuf)[i - 1] != '\r'))
+					{
+					User::LeaveIfError(indicies.Append(i));
+					}
+				}
+			}
+		const TInt count = indicies.Count();
+		if (count > 0)
+			{
+			if (bufPtr.MaxLength() < (length + count))
+				{
+				iBuf = iBuf->ReAllocL(length + count);
+				bufPtr.Set(iBuf->Des());
+				}
+			for (TInt i = (count - 1); i >= 0; --i)
+				{
+				bufPtr.Insert(indicies[i], KCarriageReturn);
+				}
+			}
+		CleanupStack::PopAndDestroy(&indicies);
+		}
+	
+	}
+
+void CIoConsole::TConsoleWriteRequest::CompleteD(TInt aError)
+	{
+	delete iBuf;
+	iWriter.IowComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleCursorPosRequest
+CIoConsole::TConsoleCursorPosRequest::TConsoleCursorPosRequest(MIoWriter& aWriter)
+	: TConsoleWriterRequest(aWriter), iPosPckg(iPos)
+	{
+	}
+
+void CIoConsole::TConsoleCursorPosRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.CursorPos(iPosPckg, aStatus);
+	}
+
+void CIoConsole::TConsoleCursorPosRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowCursorPos(aError, iPos);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleSetCursorPosAbsRequest
+CIoConsole::TConsoleSetCursorPosAbsRequest::TConsoleSetCursorPosAbsRequest(MIoWriter& aWriter, const TPoint& aPoint)
+	: TConsoleWriterRequest(aWriter), iPoint(aPoint)
+	{
+	}
+
+void CIoConsole::TConsoleSetCursorPosAbsRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.SetCursorPosAbs(iPoint, aStatus);	
+	}
+
+void CIoConsole::TConsoleSetCursorPosAbsRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowSetCursorPosAbsComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleSetCursorPosRelRequest
+CIoConsole::TConsoleSetCursorPosRelRequest::TConsoleSetCursorPosRelRequest(MIoWriter& aWriter, const TPoint& aPoint)
+	: TConsoleWriterRequest(aWriter), iPoint(aPoint)
+	{
+	}
+
+void CIoConsole::TConsoleSetCursorPosRelRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.SetCursorPosRel(iPoint, aStatus);
+	}
+
+void CIoConsole::TConsoleSetCursorPosRelRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowSetCursorPosRelComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleSetCursorHeightRequest
+CIoConsole::TConsoleSetCursorHeightRequest::TConsoleSetCursorHeightRequest(MIoWriter& aWriter, TInt aHeight)
+	: TConsoleWriterRequest(aWriter), iHeight(aHeight)
+	{
+	}	
+
+void CIoConsole::TConsoleSetCursorHeightRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.SetCursorHeight(iHeight, aStatus);
+	}
+
+void CIoConsole::TConsoleSetCursorHeightRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowSetCursorHeightComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleSetTitleRequest
+CIoConsole::TConsoleSetTitleRequest::TConsoleSetTitleRequest(MIoWriter& aWriter)
+	: TConsoleWriterRequest(aWriter)
+	{
+	}
+
+void CIoConsole::TConsoleSetTitleRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.SetTitle(*iTitle, aStatus);
+	}
+
+void CIoConsole::TConsoleSetTitleRequest::PrepareL()
+	{
+	iTitle = iWriter.IowTitleLC();
+	CleanupStack::Pop(iTitle);
+	}
+
+void CIoConsole::TConsoleSetTitleRequest::CompleteD(TInt aError)
+	{
+	delete iTitle;
+	iWriter.IowSetTitleComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleClearScreenRequest
+CIoConsole::TConsoleClearScreenRequest::TConsoleClearScreenRequest(MIoWriter& aWriter)
+	: TConsoleWriterRequest(aWriter)
+	{
+	}
+
+void CIoConsole::TConsoleClearScreenRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.ClearScreen(aStatus);
+	}
+
+void CIoConsole::TConsoleClearScreenRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowClearScreenComplete(aError);
+	delete this;
+	}
+
+		
+	
+
+//______________________________________________________________________________
+//						TConsoleClearToEndOfLineRequest
+CIoConsole::TConsoleClearToEndOfLineRequest::TConsoleClearToEndOfLineRequest(MIoWriter& aWriter)
+	: TConsoleWriterRequest(aWriter)
+	{
+	}
+
+void CIoConsole::TConsoleClearToEndOfLineRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.ClearToEndOfLine(aStatus);
+	}
+
+void CIoConsole::TConsoleClearToEndOfLineRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowClearToEndOfLineComplete(aError);
+	delete this;
+	}
+
+		
+	
+
+//______________________________________________________________________________
+//						TConsoleScreenSizeRequest
+CIoConsole::TConsoleScreenSizeRequest::TConsoleScreenSizeRequest(MIoWriter& aWriter, const TIoConfig& aConfig)
+	: TConsoleWriterRequest(aWriter), iConfig(aConfig), iSizeBuf(iSize)
+	{
+	}
+
+void CIoConsole::TConsoleScreenSizeRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.GetScreenSize(iSizeBuf, aStatus);
+	}
+
+void CIoConsole::TConsoleScreenSizeRequest::CompleteD(TInt aError)
+	{
+	if (aError==KErrNone)
+		{
+		iSize.iWidth += iConfig.ConsoleSizeAdjustment().iWidth;
+		iSize.iHeight += iConfig.ConsoleSizeAdjustment().iHeight;
+		}
+	iWriter.IowScreenSize(aError, iSize);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleSetAttributesRequest
+CIoConsole::TConsoleSetAttributesRequest::TConsoleSetAttributesRequest(MIoWriter& aWriter, TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor)
+	: TConsoleWriterRequest(aWriter), iAttributes(aAttributes), iForegroundColor(aForegroundColor), iBackgroundColor(aBackgroundColor)
+	{
+	}
+
+void CIoConsole::TConsoleSetAttributesRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.SetAttributes(iAttributes, iForegroundColor, iBackgroundColor, aStatus);
+	}
+
+void CIoConsole::TConsoleSetAttributesRequest::CompleteD(TInt aError)
+	{
+	iWriter.IowSetAttributesComplete(aError);
+	delete this;
+	}
+
+		
+//______________________________________________________________________________
+//						TConsoleSetUnderlyingRequest
+CIoConsole::TConsoleSetUnderlyingRequest::TConsoleSetUnderlyingRequest(CIoConsole& aUnderlyingConsole)
+	: iConsole(aUnderlyingConsole)
+	{
+	}
+
+void CIoConsole::TConsoleSetUnderlyingRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	aProxy.SetUnderlyingConsole(iSession, aStatus);
+	}
+
+void CIoConsole::TConsoleSetUnderlyingRequest::PrepareL()
+	{
+	if (iConsole.iThreadServer.Handle())
+		{
+		User::LeaveIfError(iSession.Connect(iConsole.iThreadServer));
+		}
+	else
+		{
+		User::Leave(KErrBadHandle);
+		}	
+	}
+
+void CIoConsole::TConsoleSetUnderlyingRequest::CompleteD(TInt)
+	{
+	iSession.Close();
+	iConsole.Close();
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						TConsoleSetModeRequest
+CIoConsole::TConsoleSetModeRequest::TConsoleSetModeRequest(MIoReader& aReader,CIoConsole& aConsole, RIoReadWriteHandle::TMode aMode)
+	: TConsoleReaderRequest(aReader), iConsole(aConsole), iMode(aMode)
+	{
+	}
+
+void CIoConsole::TConsoleSetModeRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+	{
+	iConsole.iReader->Cancel();
+	aProxy.SetConsoleMode(iMode, aStatus);
+	}
+
+void CIoConsole::TConsoleSetModeRequest::CompleteD(TInt aError)
+	{
+	iConsole.QueueReaderIfRequired();
+	iReader.IorSetConsoleModeComplete(aError);
+	delete this;
+	}
+
+//______________________________________________________________________________
+//						CConsoleRequest
+CIoConsole::CConsoleRequest::CConsoleRequest(CIoConsole& aConsole)
+	: CActive(EPriorityStandard), iConsole(aConsole)
+	{
+	CActiveScheduler::Add(this);
+	}
+		
+void CIoConsole::CConsoleRequest::Service(TConsoleRequest* aRequest)
+	{
+	ASSERT(!IsActive());
+	ASSERT(!iCurrentRequest);
+	TRAPD(err, aRequest->PrepareL());
+	if (err!=KErrNone)
+		{
+		Complete(aRequest, err);
+		return;
+		}
+	aRequest->Request(iConsole.iConsole, iStatus);
+	SetActive();
+	iCurrentRequest = aRequest;
+	}
+	
+void CIoConsole::CConsoleRequest::Complete(TConsoleRequest* aRequest, TInt aError)
+	{
+	if (aError == KErrServerTerminated)
+		{
+		// console has panicked.
+		iConsole.ConsoleDied();
+		// don't want to send KErrServerTerminated up to our (iosrv) clients, as it will
+		// make them think the iosrv has died.
+		aError = KErrGeneral;
+		}
+	if (aRequest)
+		{
+		aRequest->CompleteD(aError);
+		}
+	iConsole.CheckQueue();
+	}
+
+
+CIoConsole::CConsoleRequest::~CConsoleRequest()
+	{
+	Cancel();
+	}
+	
+void CIoConsole::CConsoleRequest::RunL()
+	{
+	TConsoleRequest* req = iCurrentRequest;
+	iCurrentRequest = NULL;
+	Complete(req, iStatus.Int());
+	}
+
+void CIoConsole::CConsoleRequest::DoCancel()
+	{
+	// request are handled synchronously on the server side, no cancelling is possible.
+	}
+
+const CIoConsole::TConsoleRequest* CIoConsole::CConsoleRequest::CurrentRequest() const
+	{
+	return iCurrentRequest;
+	}
+
+void CIoConsole::CConsoleRequest::Abort()
+	{
+	// We can't cancel a pending request (because they are handled synchronously on the server side),
+	// so instead we delete and NULL the associated request object. This active object will then
+	// continue to wait for the server to complete the request (as normal), but will take no further
+	// action. This is used when the originating MIoReader or MIoWriter object has been detached from
+	// the console and no longer exists.
+	ASSERT(IsActive());
+	ASSERT(iCurrentRequest);
+	delete iCurrentRequest;
+	iCurrentRequest = NULL;
+	}
+
+
+//______________________________________________________________________________
+//						CServerDeathWatcher
+CIoConsole::CServerDeathWatcher::CServerDeathWatcher(RServer2& aServer, RThread& aThread)
+	: CActive(CActive::EPriorityStandard), iServer(aServer), iThread(aThread)
+	{
+	CActiveScheduler::Add(this);
+	aThread.Logon(iStatus);
+	SetActive();
+	}
+	
+CIoConsole::CServerDeathWatcher::~CServerDeathWatcher()
+	{
+	Cancel();
+	}
+
+void CIoConsole::CServerDeathWatcher::RunL()
+	{
+	}
+
+void CIoConsole::CServerDeathWatcher::DoCancel()
+	{
+	iThread.LogonCancel(iStatus);
+	}
+
+//______________________________________________________________________________
+//						RIoConsoleProxy
+TInt RIoConsoleProxy::SetConsoleSizeDetect()
+	{
+	return SendReceive(ESetConsoleSizeDetect);
+	}
+	
+TInt RIoConsoleProxy::SetLazyConstruct()
+	{
+	return SendReceive(ESetLazyConstruct);
+	}
+	
+void RIoConsoleProxy::SetConsoleMode(RIoReadWriteHandle::TMode aMode, TRequestStatus& aStatus)
+	{
+	SendReceive(ESetConsoleMode, TIpcArgs(aMode), aStatus);
+	}
+	
+void RIoConsoleProxy::SetUnderlyingConsole(const RIoConsoleProxy& aUnderlyingSession, TRequestStatus& aStatus)
+	{
+	SendReceive(ESetUnderlyingConsole, TIpcArgs(aUnderlyingSession), aStatus);
+	}
+	
+TInt RIoConsoleProxy::OpenExisting()
+	{
+	return SendReceive(EOpenExistingConsole);
+	}
+
+void RIoConsoleProxy::WriteStdErr(const TDesC& aDescriptor, TRequestStatus& aStatus)
+	{
+	SendReceive(EWriteStdErr, TIpcArgs(&aDescriptor), aStatus);
+	}
+
+//______________________________________________________________________________
+//						CIoConsoleProxyServer
+CConsoleProxyServer* CIoConsoleProxyServerNewL(TAny* aParams)
+	{
+	const TDesC* dllName = (const TDesC*)aParams;
+	RLibrary lib;
+
+	User::LeaveIfError(lib.Load(*dllName));
+	CleanupClosePushL(lib);
+	if ((lib.Type()[1] == KSharedLibraryUid) && (lib.Type()[2] == KConsoleDllUid))
+		{
+		TConsoleCreateFunction entry = (TConsoleCreateFunction)lib.Lookup(1);
+		if (!entry) User::Leave(KErrNotSupported);
+		CleanupStack::Pop(&lib);
+		return CIoConsoleProxyServer::NewL(entry, lib);
+		}
+	else
+		{
+		User::Leave(KErrNotSupported);
+		return NULL; // ASSERT(Happy(compiler))
+		}
+	}
+	
+CIoConsoleProxyServer* CIoConsoleProxyServer::NewL(TConsoleCreateFunction aConsoleCreate, RLibrary& aConsoleLibrary)
+	{
+	CIoConsoleProxyServer* self = new CIoConsoleProxyServer(aConsoleCreate, aConsoleLibrary);
+	if (!self)
+		{
+		aConsoleLibrary.Close();
+		User::Leave(KErrNoMemory);
+		}
+	CleanupStack::PushL(self);
+	self->ConstructL(KNullDesC);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CIoConsoleProxyServer::CIoConsoleProxyServer(TConsoleCreateFunction aConsoleCreate, const RLibrary& aConsoleLibrary)
+	: CConsoleProxyServer(aConsoleCreate, CActive::EPriorityStandard)
+	, iConsoleLibrary(aConsoleLibrary)
+	{
+	}
+
+CSession2* CIoConsoleProxyServer::NewSessionL(const TVersion&,const RMessage2&) const
+	{
+	return new(ELeave)CIoConsoleProxySession(iConsoleCreate);
+	}
+	
+CIoConsoleProxyServer::~CIoConsoleProxyServer()
+	{
+	iConsoleLibrary.Close();
+	}
+	
+MProxiedConsole* CIoConsoleProxyServer::TheConsole() const
+	{
+	return iTheConsole;
+	}
+	
+void CIoConsoleProxyServer::SetTheConsole(MProxiedConsole* aConsole)
+	{
+	ASSERT(!iTheConsole);
+	iTheConsole = aConsole;
+	}
+
+//______________________________________________________________________________
+TSize DetectConsoleSize(CConsoleBase* aConsole)
+	{
+	TSize detectedSize;
+	aConsole->SetCursorHeight(0);
+	aConsole->ScreenSize(); // This used to be assigned to a variable, which was never used, but I'm not sure if calling ScreenSize() has side-effects so I'm leaving the call in
+	aConsole->SetCursorPosAbs(TPoint(0, 0));
+	_LIT(KSpace, " ");
+	for (TInt x = 0; ; ++x)
+		{
+		aConsole->Write(KSpace);
+		if (aConsole->CursorPos().iX == 0)
+			{
+			detectedSize.iWidth = x + 1;
+			break;
+			}
+		}
+	aConsole->SetCursorPosAbs(TPoint(0, 0));
+	TInt prevYPos = 0;
+	_LIT(KNewLine, "\r\n");
+	for (TInt y = 0; ; ++y)
+		{
+		aConsole->Write(KNewLine);
+		if (aConsole->CursorPos().iY == prevYPos)
+			{
+			detectedSize.iHeight = y;
+			break;
+			}
+		else
+			{
+			prevYPos = y;
+			}
+		}
+	aConsole->ClearScreen();
+	aConsole->SetCursorHeight(20);
+	return detectedSize;
+	}
+
+//______________________________________________________________________________
+//						CIoConsoleProxySession
+CIoConsoleProxySession::CIoConsoleProxySession(TConsoleCreateFunction aConsoleCreate)
+	: CConsoleProxySession(aConsoleCreate), iFlags(ESupportsStdErr)
+	{
+	// Assume ESupportsStdErr until proven otherwise
+	}
+
+CIoConsoleProxySession::~CIoConsoleProxySession()
+	{
+	delete iUnderlyingConsole;
+	}
+
+void CIoConsoleProxySession::ServiceL(const RMessage2& aMessage)
+	{
+	switch (aMessage.Function())
+		{
+	case RIoConsoleProxy::ESetConsoleSizeDetect:
+		if (iConsole) User::Leave(KErrNotReady); // too late!
+		SetFlag(EAutoDetectSize, ETrue);
+		aMessage.Complete(KErrNone);
+		return;
+	case RIoConsoleProxy::ESetLazyConstruct:
+		if (iConsole) User::Leave(KErrNotReady); // too late!
+		SetFlag(ELazy, ETrue);
+		aMessage.Complete(KErrNone);
+		return;
+	case RIoConsoleProxy::ESetConsoleMode:
+		SetModeL(aMessage);
+		return;
+	case RIoConsoleProxy::ESetUnderlyingConsole:
+		SetUnderlyingConsoleL(aMessage);
+		return;
+	case RIoConsoleProxy::EOpenExistingConsole:
+		OpenExistingL(aMessage);
+		return;	
+	case RConsoleProxy::EGetScreenSize:
+		if (GetFlag(EAutoDetectSize) && !GetFlag(ELazy))
+			{
+			DetectSizeL(aMessage);
+			return;
+			}
+		break;
+	case RIoConsoleProxy::EWriteStdErr:
+		{
+		RBuf buf;
+		CleanupClosePushL(buf);
+		buf.CreateL(aMessage.GetDesLengthL(0));
+		aMessage.ReadL(0, buf);
+		if (iFlags & ESupportsStdErr)
+			{
+			TInt err = ConsoleStdErr::Write(iConsole->Console(), buf);
+			if (err != KErrNone)
+				{
+				// Clearly it doesn't support it, clear the flag so we fall back to normal write and don't bother trying again
+				iFlags &= ~ESupportsStdErr;
+				}
+			}
+
+		if (!(iFlags & ESupportsStdErr))
+			{
+			iConsole->Console()->Write(buf);
+			}
+		CleanupStack::PopAndDestroy(&buf);
+		aMessage.Complete(KErrNone);
+		return;
+		}
+	default:
+		break;
+		}
+
+	CConsoleProxySession::ServiceL(aMessage);
+	}
+	
+MProxiedConsole* CIoConsoleProxySession::InstantiateConsoleL()
+	{
+	if (Server()->TheConsole()!=NULL)
+		{
+		// make sure that only 1 console is ever created in this server
+		User::Leave(KErrAlreadyExists);
+		}
+	MProxiedConsole* cons;
+	if (GetFlag(ELazy))
+		{
+		CLazyConsole* lazy = new(ELeave)CLazyConsole(iConsoleCreate, GetFlag(EAutoDetectSize));
+		CleanupStack::PushL(lazy);
+		cons = MProxiedConsole::DefaultL(lazy);
+		CleanupStack::Pop();
+		}
+	else
+		{
+		cons = CConsoleProxySession::InstantiateConsoleL();
+		}
+	
+	Server()->SetTheConsole(cons);
+	
+	if (iUnderlyingConsole)
+		{
+		TInt err = UnderlyingConsole::Set(cons->Console(), iUnderlyingConsole);
+		// if this succeeds, ownership of the underlying console has been taken
+		// if it didn't, we should delete it as it's not needed.
+		if (err!=KErrNone)
+			{
+			delete iUnderlyingConsole;
+			}
+		iUnderlyingConsole = NULL;
+		}
+	
+	return cons;	
+	}
+	
+void CIoConsoleProxySession::ConsoleCreatedL(MProxiedConsole* aConsole)
+	{
+	if (GetFlag(EAutoDetectSize) && !(GetFlag(ELazy)))
+		{
+		iDetectedSize = DetectConsoleSize(aConsole->Console());
+		}
+	}
+
+void CIoConsoleProxySession::DetectSizeL(const RMessage2& aMessage)
+	{
+	if (!iConsole) User::Leave(KErrNotReady);
+	
+	aMessage.WriteL(0, TPckg<TSize>(iDetectedSize));
+	aMessage.Complete(KErrNone);	
+	}
+
+void CIoConsoleProxySession::SetModeL(const RMessage2& aMessage)
+	{
+	if (!iConsole) User::Leave(KErrNotReady);
+	RIoReadWriteHandle::TMode mode = (RIoReadWriteHandle::TMode)aMessage.Int0();
+	TInt err = ConsoleMode::Set(iConsole->Console(), (mode == RIoReadWriteHandle::EBinary) ? ConsoleMode::EBinary : ConsoleMode::EText);
+	aMessage.Complete(err);
+	}
+
+void CIoConsoleProxySession::SetUnderlyingConsoleL(const RMessage2& aMessage)
+	{
+	if (iUnderlyingConsole) User::Leave(KErrAlreadyExists);
+	
+	RIoConsoleProxy underlyingSession;
+	RThread client;
+	aMessage.ClientL(client, EOwnerThread);
+	CleanupClosePushL(client);
+
+	underlyingSession.SetHandle(aMessage.Int0());
+	User::LeaveIfError(underlyingSession.Duplicate(client, EOwnerThread));
+	
+	CleanupClosePushL(underlyingSession);
+	User::LeaveIfError(underlyingSession.OpenExisting());
+	
+	CConsoleProxy* underlying = CWriteOnlyConsoleProxy::NewL(underlyingSession);
+	
+	CleanupStack::PopAndDestroy(2, &client); // we can close underlyingSession as it's been duplicated by CConsoleProxy::NewL
+	
+	if (iConsole && iConsole->Console())
+		{
+		CleanupStack::PushL(underlying);
+		User::LeaveIfError(UnderlyingConsole::Set(iConsole->Console(), underlying));
+		// ownership of underlying now taken.
+		CleanupStack::Pop();
+		}
+	else
+		{
+		// save it for when the console is instantiated
+		iUnderlyingConsole = underlying;
+		}
+	
+	aMessage.Complete(KErrNone);
+	}
+
+void CIoConsoleProxySession::OpenExistingL(const RMessage2& aMessage)
+	{
+	if (Server()->TheConsole()==NULL) User::Leave(KErrNotReady); // no console to connect to
+	
+	iConsole = Server()->TheConsole();
+	iConsole->Open();
+	aMessage.Complete(KErrNone);
+	}
+
+TBool CIoConsoleProxySession::GetFlag(TFlag aFlag)
+	{
+	return iFlags & aFlag ? (TBool)ETrue : EFalse;
+	}
+	
+void CIoConsoleProxySession::SetFlag(TFlag aFlag, TBool aSet)
+	{
+	if (aSet)
+		{
+		iFlags |= aFlag;
+		}
+	else
+		{
+		iFlags &= (~(TUint)aFlag);
+		}
+	}
+
+
+//______________________________________________________________________________
+//						CWriteOnlyConsoleProxy
+CConsoleProxy* CWriteOnlyConsoleProxy::NewL(const RConsoleProxy& aProxySession)
+	{
+	CWriteOnlyConsoleProxy* self = new(ELeave)CWriteOnlyConsoleProxy();
+	CleanupStack::PushL(self);
+	self->ConstructL(aProxySession);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CWriteOnlyConsoleProxy::CWriteOnlyConsoleProxy()
+	{
+	}
+
+void CWriteOnlyConsoleProxy::Read(TRequestStatus&)
+	{
+	User::Panic(KIoServerName, EPanicCannotReadFromUnderlyingConsole);
+	}
+
+void CWriteOnlyConsoleProxy::ReadCancel()
+	{
+	}
+
+TKeyCode CWriteOnlyConsoleProxy::KeyCode() const
+	{
+	return EKeyNull;
+	}
+
+
+TUint CWriteOnlyConsoleProxy::KeyModifiers() const
+	{
+	return 0;
+	}
+
+//______________________________________________________________________________
+//						CLazyConsole
+CLazyConsole::CLazyConsole(TConsoleCreateFunction aConsoleCreate, TBool aAutoDetectSize)
+	: iConsoleCreate(aConsoleCreate), iSizeAutoDetect(aAutoDetectSize)
+	{
+	}
+
+CLazyConsole::~CLazyConsole()
+	{
+	iTitle.Close();
+	delete iConsole;
+	}
+
+TInt CLazyConsole::Create(const TDesC &aTitle,TSize aSize)
+	{
+	iSize = aSize;
+	return iTitle.Create(aTitle);
+	}
+	
+TInt CLazyConsole::CheckCreated() const
+	{
+	if (iCreateError) return iCreateError;
+	if (iConsole) return KErrNone;
+	
+	TRAP(iCreateError, iConsole = iConsoleCreate());
+	if ((iCreateError==KErrNone) && (!iConsole))
+		{
+		iCreateError = KErrNoMemory;
+		}
+	if (iCreateError == KErrNone)
+		{
+		TName procName = RProcess().Name(); // econseik sets the process name to the console title...
+		iCreateError = iConsole->Create(iTitle, iSize);
+		User::RenameProcess(procName.Left(procName.Locate('['))); // ...so restore it just in case
+		}
+	if ((iCreateError == KErrNone) && iSizeAutoDetect)
+		{
+		iDetectedSize = DetectConsoleSize(iConsole);
+		}
+	if (iCreateError != KErrNone)
+		{
+		delete iConsole;
+		iConsole = NULL;
+		}
+	return iCreateError;
+	}
+
+void CLazyConsole::Read(TRequestStatus &aStatus)
+	{
+	TInt err = CheckCreated();
+	if (err)
+		{
+		TRequestStatus* stat = &aStatus;
+		User::RequestComplete(stat, err);
+		return;
+		}
+	iConsole->Read(aStatus);
+	}
+
+void CLazyConsole::ReadCancel()
+	{
+	if (iConsole)
+		{
+		iConsole->ReadCancel();
+		}
+	}
+
+void CLazyConsole::Write(const TDesC &aDes)
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		iConsole->Write(aDes);
+		}
+	}
+
+TPoint CLazyConsole::CursorPos() const
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->CursorPos();
+		}
+	return TPoint(0,0);
+	}
+
+void CLazyConsole::SetCursorPosAbs(const TPoint &aPoint)
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->SetCursorPosAbs(aPoint);
+		}
+	}
+
+void CLazyConsole::SetCursorPosRel(const TPoint &aPoint)
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->SetCursorPosRel(aPoint);
+		}
+	}
+
+void CLazyConsole::SetCursorHeight(TInt aPercentage)
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->SetCursorHeight(aPercentage);
+		}
+	}
+
+void CLazyConsole::SetTitle(const TDesC &aTitle)
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->SetTitle(aTitle);
+		}
+	}
+
+void CLazyConsole::ClearScreen()
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->ClearScreen();
+		}
+	}
+
+void CLazyConsole::ClearToEndOfLine()
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->ClearToEndOfLine();
+		}
+	}
+
+TSize CLazyConsole::ScreenSize() const
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		if (iSizeAutoDetect)
+			{
+			return iDetectedSize;
+			}
+		else
+			{
+			return iConsole->ScreenSize();
+			}
+		}
+	else
+		{
+		return TSize(0,0);
+		}
+	}
+
+TKeyCode CLazyConsole::KeyCode() const
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->KeyCode();
+		}
+	return EKeyNull;
+	}
+
+TUint CLazyConsole::KeyModifiers() const
+	{
+	if (CheckCreated() == KErrNone)
+		{
+		return iConsole->KeyModifiers();
+		}
+	return 0;
+	}
+
+TInt CLazyConsole::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+	{
+	if (aExtensionId == LazyConsole::KLazyConsoleExtension)
+		{
+		TBool* constructed = (TBool*)a1;
+		*constructed = (iConsole != NULL);
+		return KErrNone;
+		}
+	else 
+		{
+		TInt err = CheckCreated();
+		if (err == KErrNone)
+			{
+			return ((CLazyConsole*)iConsole)->Extension_(aExtensionId, a0, a1);
+			}
+		return err;
+		}
+	}