--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/ewsrv/ws_main.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,2198 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// e32\ewsrv\ws_main.cpp
+//
+//
+
+#include "ws_std.h"
+#include <e32hal.h>
+#include <hal.h>
+#include <e32math.h>
+#include <domainmanager.h>
+#ifdef __WINS__
+#include <e32wins.h>
+#endif
+
+GLREF_D CKeyTranslator *KeyTranslator;
+GLREF_D CKeyRepeat* KeyRepeat;
+
+// password notifier support functions
+LOCAL_C void RenderPassword(RConsole *aCon, TInt aPWLeft, const TDesC& aPW);
+
+_LIT(KShellProcessName, "ESHELL");
+_LIT(KShellCommandLine, "/p");
+
+//
+// class CKeyRepeat
+//
+
+CKeyRepeat::CKeyRepeat(TInt aPriority) : CTimer(aPriority)
+//
+// Constructor. Set default repeat delay and rate
+//
+ {
+ iDelay=EDefaultKeyRepeatDelay;
+ iRate=EDefaultKeyRepeatRate;
+ }
+
+void CKeyRepeat::ConstructL()
+ {
+
+ CTimer::ConstructL();
+ CActiveScheduler::Add(this);
+ }
+
+void CKeyRepeat::RunL()
+//
+// Send a repeat keypress to the window
+//
+ {
+
+ After(iRate);
+ CWsWindow::KeyPress(iKeyData);
+ }
+
+void CKeyRepeat::Request(TKeyData& aKeyData)
+//
+// Request a repeat event
+//
+ {
+
+ iKeyData=aKeyData;
+ Cancel();
+ After(iDelay);
+ }
+
+void CKeyRepeat::SetRepeatTime(TInt aDelay,TInt aRate)
+ {
+
+ iDelay=aDelay;
+ iRate=aRate;
+ }
+
+void CKeyRepeat::RepeatTime(TInt& aDelay,TInt& aRate)
+ {
+
+ aDelay=iDelay;
+ aRate=iRate;
+ }
+
+//
+// class CWsSession
+//
+
+CWsSession::CWsSession()
+ {
+ iTestFast = (UserSvr::DebugMask(2)&0x00000002) ? 1 : 0;
+ }
+
+CWsSession::~CWsSession()
+//
+// Destructor
+//
+ {
+
+ delete iWindow;
+ }
+
+//
+// class CWsServer
+//
+
+void CWsServer::New()
+//
+// Create a new CWsServer.
+//
+ {
+
+ CWsServer *pS=new CWsServer(EPriority);
+ __ASSERT_ALWAYS(pS!=NULL,Fault(ECreateServer));
+ pS->SetPinClientDescriptors(EFalse); // don't pin because client interface can't cope with errors if pin fails under real or simulated OOM
+ TInt r=pS->Start(KE32WindowServer);
+ __ASSERT_ALWAYS(r==KErrNone,Fault(EStartServer));
+ RProcess::Rendezvous(KErrNone);
+
+ }
+
+CWsServer::CWsServer(TInt aPriority)
+//
+// Constructor.
+//
+ : CServer2(aPriority)
+ {
+ }
+
+CSession2* CWsServer::NewSessionL(const TVersion& aVersion,const RMessage2&) const
+//
+// Create a new client for this server.
+//
+ {
+
+ TVersion v(KW32MajorVersionNumber,KW32MinorVersionNumber,KE32BuildVersionNumber);
+ TBool r=User::QueryVersionSupported(v,aVersion);
+ if (!r)
+ User::Leave(KErrNotSupported);
+ return new(ELeave) CWsSession;
+ }
+
+void CWsSession::ServiceL(const RMessage2& aMessage)
+//
+// Handle messages for this session.
+//
+ {
+
+ iCurMsg = aMessage;
+ CWsWindow::WaitOnService();
+ CWsWindow* pW=iWindow;
+ TInt r=EPrematureOperation;
+ TBool delayCompletion=EFalse;
+ switch (aMessage.Function())
+ {
+ case EConsoleCreate:
+ {
+ if (pW)
+ {
+ delete pW;
+ iWindow=NULL;
+ }
+ pW=new CWsWindow;
+ if (!pW)
+ {
+ r=EWindowOutOfMemory;
+ break;
+ }
+ iWindow=pW;
+ pW->iAllowResize=ETrue;
+ pW->iIsVisible=ETrue;
+ pW->iOnTop=EFalse;
+ pW->SetCursorHeight(50);
+ pW->iKQueue.SetOffset(_FOFF(SWsKey,iLink));
+ break;
+ }
+ case EConsoleSet:
+ {
+ if (!pW)
+ {
+ pW=new(ELeave) CWsWindow;
+ iWindow=pW;
+ pW->iAllowResize=ETrue;
+ pW->iIsVisible=ETrue;
+ pW->iOnTop=EFalse;
+ pW->SetCursorHeight(50);
+ pW->iKQueue.SetOffset(_FOFF(SWsKey,iLink));
+ }
+ pW->iAllowSlide=ETrue;
+ TFileName name;
+ iCurMsg.ReadL(0, name);
+ pW->iTitle=name;
+ TPckgBuf<TSize> size;
+ iCurMsg.ReadL(1, size);
+ TRAP(r,pW->CreateL(size()));
+ if (r != KErrNone)
+ {
+ delete pW;
+ iWindow=NULL;
+ }
+ break;
+ }
+ case EConsoleClearScreen:
+ {
+ if (pW)
+ {
+ pW->Clear();
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleClearToEndOfLine:
+ {
+ if (pW)
+ {
+ pW->ClearToEndOfLine();
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSetTitle:
+ {
+ if (pW)
+ {
+ TFileName name;
+ iCurMsg.ReadL(0, name);
+ pW->SetTitle(name);
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSetSize:
+ {
+ if (pW)
+ {
+ TPckgBuf<TSize> size;
+ iCurMsg.ReadL(0, size);
+// pW->SetSize(size());
+// r=KErrNone;
+ r=KErrNotSupported;
+ }
+ break;
+ }
+ case EConsoleSetWindowPosAbs:
+ {
+ if (pW)
+ {
+ TPckgBuf<TPoint> point;
+ iCurMsg.ReadL(0, point);
+ pW->SetWindowPosAbs(point());
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSetCursorHeight:
+ {
+ if (pW)
+ {
+ pW->SetCursorHeight(aMessage.Int0());
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSetCursorPosAbs:
+ {
+ if (pW)
+ {
+ TPckgBuf<TPoint> point;
+ iCurMsg.ReadL(0, point);
+ pW->SetCursorPosAbs(point());
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSetCursorPosRel:
+ {
+ if (pW)
+ {
+ TPckgBuf<TPoint> point;
+ iCurMsg.ReadL(0, point);
+ pW->SetCursorPosRel(point());
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleCursorPos:
+ {
+ if (pW)
+ {
+ TPckgBuf<TPoint> point;
+ point()=pW->CursorPosition();
+ aMessage.WriteL(0,point);
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSize:
+ {
+ if (pW)
+ {
+ TPckgBuf<TSize> size;
+ size()=pW->Size();
+ aMessage.WriteL(0,size);
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleScreenSize:
+ {
+ if (pW)
+ {
+ TPckgBuf<TSize> size;
+ size()=CWsWindow::ScreenSize;
+ aMessage.WriteL(0,size);
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleControl:
+ {
+ if (pW)
+ {
+ TBool indicator=ETrue;
+ TInt offset=0;
+ TBuf<0x100> b;
+ do
+ {
+ iCurMsg.ReadL(0,b,offset);
+ for (const TText* pB=b.Ptr();pB<b.Ptr()+b.Length();pB++)
+ {
+ switch(*pB)
+ {
+ case '+':
+
+ indicator=ETrue;
+ break;
+ case '-':
+ indicator=EFalse;
+ break;
+ case 'S':
+ pW->ControlScrollBars(indicator);
+ break;
+ case 'W':
+ pW->ControlWrapLock(indicator);
+ break;
+ case 'P':
+ pW->ControlPointerEvents(indicator);
+ break;
+ case 'L':
+ pW->ControlScrollLock(indicator);
+ break;
+ case 'V':
+ pW->ControlVisibility(indicator);
+ break;
+ case 'C':
+ pW->ControlCursorRequired(indicator);
+ break;
+ case 'M':
+ pW->ControlMaximised(indicator);
+ break;
+ case 'N':
+ pW->ControlNewLineMode(indicator);
+ break;
+ case 'O':
+ pW->ControlOnTop(indicator);
+ break;
+ case 'I':
+ pW->ControlInformAllMouse(indicator);
+ break;
+ case 'R':
+ pW->ControlRawEventMode(indicator);
+ break;
+ case 'A':
+ pW->ControlAllowResize(indicator);
+ }
+ }
+ offset+=b.Length();
+ }
+ while (b.Length()==b.MaxLength());
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleWrite:
+ {
+ if (pW)
+ {
+ switch(iTestFast)
+ {
+ case 0:
+ {
+ TInt offset=0;
+ TBuf<0x100> b;
+ do
+ {
+ iCurMsg.ReadL(0,b,offset);
+ pW->Write(b);
+ offset+=b.Length();
+ }
+ while (b.Length()==b.MaxLength());
+ pW->WriteDone();
+ }
+ r=KErrNone;
+ break;
+
+ case 1:
+ {
+ pW->Write(_L("Output suppressed because TESTFAST mode is set..."));
+ pW->WriteDone();
+ ++iTestFast;
+ }
+ r=KErrNone;
+ break;
+
+ default:
+ r=KErrNone;
+ break;
+ }
+ }
+ break;
+ }
+ case EConsoleRead:
+ {
+ if (pW)
+ {
+ if (pW->EnqueReadRequest(aMessage))
+ {
+ delayCompletion=ETrue;
+ r=KErrNone;
+ }
+ else
+ r=EDoubleReadRequest;
+ }
+ break;
+ }
+ case EConsoleReadCancel:
+ {
+ if (pW)
+ {
+ pW->DequeReadRequest();
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleDestroy:
+ {
+ if (pW)
+ {
+ delete pW;
+ iWindow=NULL;
+ r=KErrNone;
+ }
+ break;
+ }
+ case EConsoleSetMode:
+ {
+ r=CWsWindow::SetMode((TVideoMode)aMessage.Int0());
+ break;
+ }
+ case EConsoleSetPaletteEntry:
+ {
+ CWsWindow::ScreenDriver->SetPaletteEntry((TColorIndex)aMessage.Int0(),(TUint8)aMessage.Int1(),(TUint8)aMessage.Int2(),(TUint8)aMessage.Int3());
+ pW->Redraw();
+ r=KErrNone;
+ break;
+ }
+ case EConsoleGetPaletteEntry:
+ {
+ TUint8 r,g,b;
+ TPckgBuf<TUint8> red,green,blue;
+ CWsWindow::ScreenDriver->GetPaletteEntry((TColorIndex)aMessage.Int0(),r,g,b);
+ red()=r; green()=g; blue()=b;
+ aMessage.WriteL(1,red);
+ aMessage.WriteL(2,green);
+ aMessage.WriteL(3,blue);
+ }
+ r=KErrNone;
+ break;
+ case EConsoleSetTextColors:
+ {
+ if(pW)
+ {
+ pW->iFgColor=(TColorIndex)aMessage.Int0();
+ pW->iBgColor=(TColorIndex)aMessage.Int1();
+ }
+ r=KErrNone;
+ break;
+ }
+ case EConsoleSetUIColors:
+ {
+ CWsWindow::WindowBgColor=(TColorIndex)aMessage.Int0();
+ CWsWindow::BorderColor=(TColorIndex)aMessage.Int1();
+ CWsWindow::ScreenColor=(TColorIndex)aMessage.Int2();
+ CWsWindow::ChangeUIColors();
+ r=KErrNone;
+ break;
+ }
+ case EConsoleSetTextAttribute:
+ {
+ if(pW)
+ pW->SetTextAttribute((TTextAttribute)aMessage.Int0());
+ r=KErrNone;
+ break;
+ }
+ default:
+ r=KErrNotSupported;
+ }
+ if (!delayCompletion)
+ aMessage.Complete(r);
+ CWsWindow::SignalService();
+ }
+
+void CWsSession::ServiceError(const RMessage2& aMessage,TInt aError)
+ {
+ if (!aMessage.IsNull())
+ {
+ if (aError>0)
+ {
+ aMessage.Panic(_L("WServ panic"),aError);
+ }
+ else
+ {
+ aMessage.Complete(aError);
+ }
+ }
+ }
+
+CWsServer::~CWsServer()
+//
+// Destructor
+//
+ {
+ }
+
+//
+// class CEvent
+//
+
+void CEvent::New()
+//
+// Create the CEvent active object.
+//
+ {
+
+ CEvent *pE=new CEvent(EPriority);
+ __ASSERT_ALWAYS(pE!=NULL,Fault(ECreateEvent));
+ pE->CaptureKeys=new CCaptureKeys();
+ __ASSERT_ALWAYS(pE->CaptureKeys!=NULL,Fault(ECreateEvent));
+
+ pE->CaptureKeys->Construct();
+
+ CActiveScheduler::Add(pE);
+ UserSvr::CaptureEventHook();
+ pE->Request();
+ }
+
+CEvent::~CEvent()
+//
+// Destroy the CEvent active object
+//
+ {
+
+ Cancel();
+ }
+
+#pragma warning( disable : 4705 ) // statement has no effect
+CEvent::CEvent(TInt aPriority)
+//
+// Constructor
+//
+ : CActive(aPriority)
+ {
+ }
+#pragma warning( default : 4705 )
+
+void CEvent::Request()
+//
+// Issue a request for the next event.
+//
+ {
+
+ UserSvr::RequestEvent(iEvent,iStatus);
+ SetActive();
+ }
+
+void CEvent::DoCancel()
+//
+// Cancel a pending event.
+//
+ {
+
+ UserSvr::RequestEventCancel();
+ }
+
+void CEvent::RunL()
+//
+// Event has completed.
+//
+ {
+
+ if (CWsWindow::RawEventMode())
+ {
+ KeyRepeat->Cancel();
+ CWsWindow::QueueRawEvent(iEvent.Event());
+ Request();
+ return;
+ }
+ switch(iEvent.Event().Type())
+ {
+ case TRawEvent::ERedraw:
+ CWsWindow::Redraw();
+ break;
+ case TRawEvent::EButton1Down:
+ if(!CWsWindow::MouseIsCaptured)
+ {
+ CWsWindow::MouseMove(iEvent.Event().Pos());
+ CWsWindow::MouseLeftButton();
+ }
+ else
+ CWsWindow::InformTopMouse(iEvent.Event().Pos());
+ break;
+ case TRawEvent::EButton1Up:
+ if(!CWsWindow::MouseIsCaptured)
+ {
+ CWsWindow::MouseMove(iEvent.Event().Pos());
+ CWsWindow::MouseLeftButtonUp();
+ }
+ break;
+ case TRawEvent::EButton2Down:
+ break;
+ case TRawEvent::EButton2Up:
+ break;
+ case TRawEvent::EButton3Down:
+ break;
+ case TRawEvent::EButton3Up:
+ break;
+ case TRawEvent::EPointerMove:
+ CWsWindow::MouseMove(iEvent.Event().Pos());
+ break;
+ case TRawEvent::EInactive:
+ KeyRepeat->Cancel();
+ break;
+ case TRawEvent::EActive:
+ break;
+ case TRawEvent::EUpdateModifiers:
+ KeyTranslator->UpdateModifiers(iEvent.Event().Modifiers());
+ break;
+ case TRawEvent::EKeyDown:
+ {
+ TKeyData keyData;
+ if (KeyTranslator->TranslateKey(iEvent.Event().ScanCode(), EFalse,*CaptureKeys,keyData))
+ CWsWindow::KeyPress(keyData);
+ if (keyData.iModifiers&EModifierAutorepeatable)
+ KeyRepeat->Request(keyData);
+ break;
+ }
+ case TRawEvent::EKeyUp:
+ {
+ TKeyData keyData;
+ KeyRepeat->Cancel();
+ if (KeyTranslator->TranslateKey(iEvent.Event().ScanCode(), ETrue,*CaptureKeys,keyData))
+ CWsWindow::KeyPress(keyData);
+ break;
+ }
+ case TRawEvent::ESwitchOn:
+ case TRawEvent::ECaseOpen:
+ HAL::Set(HAL::EDisplayState, 1);
+ {
+ RDmDomainManager mgr;
+ TInt r = mgr.Connect();
+ if (r != KErrNone)
+ User::Panic(_L("EWSRV SwitchOn0"), r);
+ TRequestStatus status;
+ mgr.RequestDomainTransition(KDmIdUiApps, EPwActive, status);
+ User::WaitForRequest(status);
+ if (status.Int() != KErrNone)
+ User::Panic(_L("EWSRV SwitchOn1"), status.Int());
+ mgr.Close();
+ }
+ break;
+ case TRawEvent::EPointerSwitchOn:
+#if defined(_DEBUG)
+ User::Beep(440,250000);
+#endif
+ break;
+ case TRawEvent::ESwitchOff:
+ {
+ RDmDomainManager mgr;
+ TInt r = mgr.Connect();
+ if (r != KErrNone)
+ User::Panic(_L("EWSRV SwitchOff0"), r);
+ TRequestStatus status;
+ mgr.RequestSystemTransition(EPwStandby, status);
+ User::WaitForRequest(status);
+ if (status.Int() != KErrNone)
+ User::Panic(_L("EWSRV SwitchOff1"), status.Int());
+ mgr.Close();
+ }
+ break;
+ case TRawEvent::ECaseClose:
+ {
+ RDmDomainManager mgr;
+ TInt r = mgr.Connect();
+ if (r != KErrNone)
+ User::Panic(_L("EWSRV CaseClosed"), r);
+ TRequestStatus status;
+ mgr.RequestDomainTransition(KDmIdUiApps, EPwStandby, status);
+ User::WaitForRequest(status);
+ if (status.Int() != KErrNone)
+ User::Panic(_L("EWSRV CaseClosed1"), status.Int());
+ mgr.Close();
+ }
+ HAL::Set(HAL::EDisplayState, 0);
+ break;
+ case TRawEvent::ENone:
+ break;
+ default:
+ break;
+ }
+ Request();
+ }
+
+LOCAL_C void RenderPassword(RConsole *aCon, TInt aPWLeft, const TDesC& aPW)
+// pre: aCon points to a console being used to read a password.
+// aPWLeft is the column number from which the left brace should be drawn.
+// aPasswd is a valid password.
+// post: the password is rendered onto the console and followed by a '#' and
+// padding spaces. Everything is enclosed in a pair of square brackets.
+ {
+ aCon->SetCursorPosAbs(TPoint(aPWLeft, 3));
+ aCon->Write(_L("["));
+ aCon->Write(aPW);
+ aCon->Write(_L("#"));
+
+ TInt i;
+ for (i = 0; i < KMaxMediaPassword - aPW.Length(); i++)
+ {
+ aCon->Write(_L(" "));
+ }
+
+ aCon->Write(_L("]"));
+ }
+
+
+void CNotifierSession::RunPasswordWindowL(const RMessage2 &aMsg)
+//
+// Eight unicode chars are mapped to (up to) sixteen bytes. Remainder of array is
+// zeroed. Message is completed in CNotifierSession::ServiceL().
+//
+ {
+ // local copies of dialog data, 5 * (8 + 32 * 2) bytes
+ TBuf<0x20> line1, line2, unlockBtn, storeBtn, cancelBtn;
+ line1.Copy(_L("Password notifier"));
+ line2.Copy(_L("Enter password"));
+ unlockBtn.Copy(_L("Unlock"));
+ storeBtn.Copy(_L("Store"));
+ cancelBtn.Copy(_L("Cancel"));
+
+ TPckgBuf<TMediaPswdReplyNotifyInfoV1> reply;
+
+ // Format the console window.
+
+ const TInt KPasswordBarLen(1 + KMaxMediaPassword + 1 + 1);
+ const TInt KButtonBarLen(
+ 1 + unlockBtn.Length() + 1
+ + 1 + 1 + cancelBtn.Length() + 1
+ + 1 + 1 + storeBtn.Length() + 1);
+
+ // Work out width of window.
+ // (Buttons are enclosed by angle brackets and separted by a space.)
+ // (Password is followed by '#' and delimited by square brackets.)
+ // If KButtonBarLen is at least as long as any other line then it will write
+ // to the bottom right corner and cause the console to scroll. To counter
+ // this, an extra padding character is added if necessary.
+
+ TInt width;
+ width = Max(line1.Length(), line2.Length());
+ width = Max(width, KPasswordBarLen);
+ width = KButtonBarLen >= width ? KButtonBarLen + 1: width;
+
+ // Create the window and render its contents.
+
+ RConsole con;
+ con.Create();
+ con.Control(_L("-Visible"));
+ TInt r = con.Init(_L(""), TSize(width, 2 + 1 + 1 + 1 + 1));
+ if (KErrNone != r)
+ {
+ PanicClient(aMsg, ENotifierPanicPasswordWindow);
+ User::Leave(KErrGeneral);
+ }
+ con.Control(_L("+Max -Cursor -AllowResize +OnTop"));
+
+ con.SetCursorPosAbs(TPoint(0, 0));
+ con.Write(line1);
+ con.SetCursorPosAbs(TPoint(0, 1));
+ con.Write(line2);
+ const TInt KPasswordLeft((width - KPasswordBarLen) / 2);
+ con.SetCursorPosAbs(TPoint(KPasswordLeft, 3));
+ con.Write(_L("[# ]"));
+ con.SetCursorPosAbs(TPoint((width - KButtonBarLen) / 2, 5));
+ con.Write(_L("<"));
+ con.Write(unlockBtn);
+ con.Write(_L("> <"));
+ con.Write(storeBtn);
+ con.Write(_L("> <"));
+ con.Write(cancelBtn);
+ con.Write(_L(">"));
+
+ // Allow the user to edit the password until they either press enter or escape.
+
+ TBool done(EFalse);
+ TBuf<KMaxMediaPassword> pw;
+ pw.Zero();
+ TMediaPswdNotifyExitMode em(EMPEMUnlock); // avoid VC warning C4701 (used w/o init).
+
+ const TInt sendInfoLen = User::LeaveIfError(aMsg.GetDesLength(1));
+
+ if (sendInfoLen == sizeof(TMediaPswdSendNotifyInfoV1Debug))
+ {
+ // debug mode - wait for specified period and close notifier
+
+ TPckgBuf<TMediaPswdSendNotifyInfoV1Debug> sendDbg;
+ aMsg.ReadL(1, sendDbg);
+ if (sendDbg().iSleepPeriod >= 0)
+ User::After(sendDbg().iSleepPeriod);
+ else
+ {
+ TTime now;
+ now.HomeTime();
+ TInt64 seed = now.Int64();
+ User::After(Math::Rand(seed) % -(sendDbg().iSleepPeriod));
+ }
+
+ reply().iEM = sendDbg().iEM;
+ Mem::Copy(reply().iPW, sendDbg().iPW, KMaxMediaPassword);
+ }
+ else
+ {
+ RenderPassword(&con, KPasswordLeft, pw);
+ do
+ {
+ TConsoleKey key;
+
+ con.Read(key);
+ TInt keyCode = key.Code();
+
+ switch (keyCode)
+ {
+ case EKeyEscape:
+ em = EMPEMCancel;
+ done = ETrue;
+ break;
+
+ case EKeyEnter:
+ em = EMPEMUnlock;
+ done = ETrue;
+ break;
+
+ case EKeySpace:
+ em = EMPEMUnlockAndStore;
+ done = ETrue;
+ break;
+
+ case EKeyBackspace:
+ if (pw.Length() > 0)
+ {
+ pw.SetLength(pw.Length() - 1);
+ RenderPassword(&con, KPasswordLeft, pw);
+ }
+ break;
+
+ default: // interpret other keys as pw contents
+ TChar ch(keyCode);
+ // unicode encoding, so number of password characters is half byte length
+ if (ch.IsPrint() && pw.Length() < KMaxMediaPassword / 2)
+ {
+ pw.Append(ch);
+ RenderPassword(&con, KPasswordLeft, pw);
+ }
+ break;
+ }
+ } while (! done);
+
+ // Fill the TMediaPswdReplyNotifyInfoV1 structure.
+
+ if (em == EMPEMUnlock || em == EMPEMUnlockAndStore)
+ {
+ const TInt byteLen = pw.Length() * 2;
+
+ // zero entire array; and then copy in valid section of TMediaPassword,
+ // not converting Unicode to ASCII.
+ TPtr8 pt8(reply().iPW, KMaxMediaPassword); // length = 0
+ pt8.FillZ(KMaxMediaPassword); // length = KMaxMediaPassword
+ pt8.Zero(); // length = 0
+ // length = byteLen
+ pt8.Copy(reinterpret_cast<const TUint8 *>(pw.Ptr()), byteLen);
+ }
+
+ // Set exit mode to tell user how dialog handled.
+
+ reply().iEM = em;
+ } // else (sendInfoLen == sizeof(TMediaPswdSendNotifyInfoV1Debug))
+
+ con.Destroy();
+
+ aMsg.WriteL(2, reply);
+ }
+
+//
+// class MNotifierBase2
+//
+
+void MNotifierBase2::SetManager(MNotifierManager* aManager)
+ {
+ iManager=aManager;
+ }
+
+//
+// class CNotifierServer
+//
+
+_LIT(__NOTIFIER_SERVER,"TextNotifierSrvr");
+
+CNotifierServer* CNotifierServer::NewL()
+ {
+ CNotifierServer* server=new(ELeave) CNotifierServer(200);
+ CleanupStack::PushL(server);
+ server->ConstructL();
+ server->StartL(__NOTIFIER_NAME);
+ CleanupStack::Pop(); // server
+ return server;
+ }
+
+CNotifierServer::~CNotifierServer()
+ {
+ SetIsExiting();
+ delete iManager;
+ }
+
+void CNotifierServer::SetIsExiting()
+ {
+ iExiting=ETrue;
+ }
+
+TBool CNotifierServer::IsExiting() const
+ {
+ return iExiting;
+ }
+
+CNotifierServer::CNotifierServer(TInt aPriority)
+ : CServer2(aPriority)
+ {}
+
+void CNotifierServer::ConstructL()
+ {
+ iManager=CNotifierManager::NewL();
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+ iManager->RegisterL(fs);
+ CleanupStack::PopAndDestroy(); // fs.Close()
+ }
+
+CSession2* CNotifierServer::NewSessionL(const TVersion &aVersion,const RMessage2&) const
+ {
+ TVersion v(1,0,0); // !! liaise with E32
+ if (!User::QueryVersionSupported(v,aVersion))
+ User::Leave(KErrNotSupported);
+ return new(ELeave) CNotifierSession(*this);
+ }
+
+//
+// class CNotifierSession
+//
+
+CNotifierSession::CNotifierSession(const CNotifierServer& aServer)
+ {
+ iServer=&aServer;
+ iClientId=(TInt)this;
+ }
+
+CNotifierSession::~CNotifierSession()
+ {
+ const CNotifierServer* server=static_cast<const CNotifierServer*>(Server());
+ if (!server->IsExiting())
+ {
+ server->Manager()->HandleClientExit(iClientId);
+ }
+ }
+
+void CNotifierSession::ServiceL(const RMessage2 &aMessage)
+ {
+ TBool completeMessage=ETrue;
+ switch (aMessage.Function())
+ {
+ case ENotifierNotify:
+ DisplayAlertL(aMessage);
+ break;
+ case ENotifierNotifyCancel:
+ // do nothing - this server doesn't support cancelling RNotifier::Notify - the client will just have to wait
+ break;
+ case ENotifierInfoPrint:
+ DisplayInfoMsgL(aMessage);
+ break;
+ case EStartNotifier:
+ DoStartNotifierL(aMessage);
+ break;
+ case ECancelNotifier:
+ iServer->Manager()->NotifierCancel(TUid::Uid(aMessage.Int0()));
+ break;
+ case EUpdateNotifierAndGetResponse:
+ case EUpdateNotifier:
+ DoUpdateNotifierL(aMessage);
+ break;
+ case EStartNotifierAndGetResponse:
+ {
+ if (aMessage.Int0()==KMediaPasswordNotifyUid)
+ {
+ RunPasswordWindowL(aMessage);
+ }
+ else
+ {
+ TBool cleanupComplete=ETrue;
+ StartNotifierAndGetResponseL(aMessage,cleanupComplete);
+ // if the plug-in starts successfully, it has
+ // responsibility for completing the message (either
+ // synchronously or asynchronously)
+ completeMessage=EFalse;
+ }
+ }
+ break;
+ default:
+ aMessage.Complete(KErrNotSupported);
+ break;
+ }
+ if (completeMessage && !aMessage.IsNull())
+ {
+ aMessage.Complete(KErrNone);
+ }
+ }
+
+void CNotifierSession::DisplayAlertL(const RMessage2& aMessage)
+ {
+ const TInt lengthOfCombinedBuffer=User::LeaveIfError(aMessage.GetDesLength(1));
+ const TInt lengthOfLine1=(STATIC_CAST(TUint,aMessage.Int2())>>16);
+ const TInt lengthOfLine2=(aMessage.Int2()&KMaxTUint16);
+ const TInt lengthOfBut1=(STATIC_CAST(TUint,aMessage.Int3())>>16);
+ const TInt lengthOfBut2=(aMessage.Int3()&KMaxTUint16);
+ if (lengthOfCombinedBuffer!=lengthOfLine1+lengthOfLine2+lengthOfBut1+lengthOfBut2)
+ {
+ PanicClient(aMessage,ENotifierPanicInconsistentDescriptorLengths);
+ return;
+ }
+ HBufC* const combinedBuffer=HBufC::NewLC(lengthOfCombinedBuffer);
+ {TPtr combinedBuffer_asWritable(combinedBuffer->Des());
+ aMessage.ReadL(1,combinedBuffer_asWritable);}
+ const TPtrC line1(combinedBuffer->Left(lengthOfLine1));
+ const TPtrC line2(combinedBuffer->Mid(lengthOfLine1,lengthOfLine2));
+ const TPtrC but1(combinedBuffer->Mid(lengthOfLine1+lengthOfLine2,lengthOfBut1));
+ const TPtrC but2(combinedBuffer->Mid(lengthOfLine1+lengthOfLine2+lengthOfBut1,lengthOfBut2));
+ TInt buttons, len, offset;
+ if (lengthOfBut2==0)
+ {
+ buttons=1;
+ len=lengthOfBut1+2;
+ }
+ else
+ {
+ buttons=2;
+ len=lengthOfBut1+lengthOfBut2+5;
+ }
+ if (lengthOfLine1>len)
+ len=lengthOfLine1;
+ if (lengthOfLine2>len)
+ len=lengthOfLine2;
+ RConsole con;
+ con.Create();
+ TSize scsz;
+ con.ScreenSize(scsz);
+ con.Control(_L("-Visible"));
+ TInt ww=Min(len,scsz.iWidth-4);
+ TInt wh=3;
+ if ((lengthOfBut1+lengthOfBut2+5)>ww)
+ wh++;
+ if (lengthOfLine1>ww)
+ wh++;
+ if (lengthOfLine2>ww)
+ wh++;
+ con.Init(_L(""),TSize(ww,wh));
+ con.Control(_L("+Max -Cursor -Allowresize +Ontop +Wrap"));
+ con.Write(line1);
+ con.SetCursorPosAbs(TPoint(0,1));
+ con.Write(line2);
+ if (buttons==2)
+ offset=(len-lengthOfBut1-lengthOfBut2-5)/2;
+ else
+ offset=(len-lengthOfBut1-2)/2;
+ con.SetCursorPosAbs(TPoint(offset,2));
+ con.Write(_L("<"));
+ con.Write(but1);
+ con.Write(_L(">"));
+ if(buttons==2)
+ {
+ con.Write(_L(" <"));
+ con.Write(but2);
+ con.Write(_L(">"));
+ }
+
+ TConsoleKey key;
+ TInt keycode;
+ do
+ {
+ con.Read(key);
+ keycode=key.Code();
+ }
+ while((keycode!=EKeyEscape&&keycode!=EKeyEnter&&buttons==2)||(keycode!=EKeyEnter&&buttons==1));
+ if(keycode==EKeyEscape)
+ keycode=0;
+ else
+ keycode=1;
+ con.Destroy();
+ aMessage.WriteL(0,TPckgC<TInt>(keycode));
+ CleanupStack::PopAndDestroy(combinedBuffer);
+ }
+
+TInt CNotifierSession::InfoPrintThread(TAny* aMessage)
+ {
+ TBuf<0x50> des; // 0x50 max size of message
+ RConsole con;
+ des=*(TBuf<0x50> *)aMessage;
+ TInt l=des.Length();
+ NotifierSemaphore.Signal();
+ con.Create();
+ con.Control(_L("-Visible"));
+ TSize size;
+ con.ScreenSize(size);
+ TInt ww=Min(size.iWidth-6,l);
+ TInt wh=(l+ww-1)/ww;
+ if (wh==0)
+ wh=1;
+ con.Init(_L(""),TSize(ww,wh));
+ con.Control(_L("+Maximise"));
+ con.SetWindowPosAbs(TPoint(size.iWidth-ww-4,1));
+ con.Control(_L("+Wrap +Ontop"));
+ con.Write(des);
+
+ User::After(1300000);
+ con.Destroy();
+ return KErrNone;
+ }
+
+void CNotifierSession::DisplayInfoMsgL(const RMessage2& aMessage)
+ {
+ TInt r;
+ TBuf<0x50> des; // 0x50 max size of message lines
+ aMessage.ReadL(0,des);
+ RThread thread;
+ do
+ {
+ r=thread.Create(_L("Info Window"),InfoPrintThread,KDefaultStackSize,&User::Allocator(),(TAny*)&des);
+ if(r==KErrAlreadyExists)
+ User::After(200000);
+ } while(r==KErrAlreadyExists);
+ User::LeaveIfError(r);
+ thread.Resume();
+ NotifierSemaphore.Wait();
+ thread.Close();
+ }
+
+void CNotifierSession::DoStartNotifierL(const RMessage2& aMessage)
+ {
+ const TUid targetUid={aMessage.Int0()};
+ HBufC8* const inputBuffer=HBufC8::NewLC(User::LeaveIfError(aMessage.GetDesLength(1)));
+ {TPtr8 input(inputBuffer->Des());
+ aMessage.ReadL(1,input);}
+ TPtrC8 output(0,0);
+ iServer->Manager()->NotifierStartL(targetUid,*inputBuffer,&output,iClientId);
+ if(aMessage.Int2())
+ aMessage.WriteL(2,output);
+ CleanupStack::PopAndDestroy(inputBuffer);
+ }
+
+void CNotifierSession::DoUpdateNotifierL(const RMessage2& aMessage)
+ {
+ const TUid targetUid={aMessage.Int0()};
+ HBufC8* const inputBuffer=HBufC8::NewLC(User::LeaveIfError(aMessage.GetDesLength(1)));
+ {TPtr8 input(inputBuffer->Des());
+ aMessage.ReadL(1, input);}
+ HBufC8* const outputBuffer=HBufC8::NewLC(User::LeaveIfError(aMessage.GetDesMaxLength(2)));
+ {TPtr8 output(outputBuffer->Des());
+ iServer->Manager()->NotifierUpdateL(targetUid,*inputBuffer,&output,iClientId);}
+ aMessage.WriteL(2,*outputBuffer);
+ CleanupStack::PopAndDestroy(2,inputBuffer);
+ }
+
+void CNotifierSession::StartNotifierAndGetResponseL(const RMessage2& aMessage,TBool& aCleanupComplete)
+ {
+ const TUid targetUid={aMessage.Int0()};
+ HBufC8* const inputBuffer=HBufC8::NewLC(User::LeaveIfError(aMessage.GetDesLength(1)));
+ {TPtr8 input(inputBuffer->Des());
+ aMessage.ReadL(1,input);}
+ iServer->Manager()->NotifierStartAndGetResponseL(targetUid,*inputBuffer,2,aMessage,iClientId,aCleanupComplete);
+ CleanupStack::PopAndDestroy(inputBuffer);
+ }
+
+void CNotifierSession::PanicClient(const RMessage2& aMessage,TNotifierPanic aCode)
+ {
+ aMessage.Panic(__NOTIFIER_SERVER,aCode);
+ }
+
+//
+// class CNotifierManager
+//
+
+const TInt KNullClientId=0;
+
+CNotifierManager* CNotifierManager::NewL()
+ {
+ CNotifierManager* self=new(ELeave) CNotifierManager;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CNotifierManager::~CNotifierManager()
+ {
+ if (iObservedList)
+ {
+ const TInt count=iObservedList->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ (*iObservedList)[ii]->Release();
+ }
+ delete iObservedList;
+ }
+ if (iLibraries)
+ {
+ const TInt count=iLibraries->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ (*iLibraries)[ii].Close();
+ }
+ delete iLibraries;
+ }
+ delete iChannelMonitor;
+ delete iActivityMonitor;
+ delete iQueue;
+ }
+
+
+void CNotifierManager::RegisterL(RFs& aFs)
+ {
+#ifdef SUPPORT_OLD_PLUGIN_PATH
+ TBool old;
+ for(old=0; old<2; old++)
+ {
+#endif
+ TFindFile* findFile=new(ELeave) TFindFile(aFs);
+ CleanupStack::PushL(findFile);
+ TParse* fileNameParser=new(ELeave) TParse;
+ CleanupStack::PushL(fileNameParser);
+ CDir* directory=NULL;
+ TInt error;
+#ifdef SUPPORT_OLD_PLUGIN_PATH
+ _LIT(KNotifierPlugInOldSearchPath,"\\system\\tnotifiers\\");
+ if(old)
+ error=findFile->FindWildByDir(KNotifierPlugInExt, KNotifierPlugInOldSearchPath, directory);
+ else
+#endif
+ error=findFile->FindWildByDir(KNotifierPlugInExt, KNotifierPlugInSearchPath, directory);
+ for (; error!=KErrNotFound; error=findFile->FindWild(directory))
+ {
+ CleanupStack::PushL(directory);
+ User::LeaveIfError(error);
+ const TInt numberOfEntries=directory->Count();
+ for (TInt i=0; i<numberOfEntries; ++i)
+ {
+ const TEntry& entry=(*directory)[i];
+ fileNameParser->SetNoWild(entry.iName, &findFile->File(), NULL); // findFile->File() returns a reference rather than an object, therefore taking the address of it is fine
+
+ if (entry.iType[0].iUid==0x10000079)
+ {
+ // It's a DLL
+ if( (entry.iType[1]==KUidTextNotifierPlugInV2))
+ {
+ // Its a notifier...
+ TPtrC path(fileNameParser->DriveAndPath());
+ TPtrC name(fileNameParser->NameAndExt());
+ DoAddPlugInL(path,name,entry.iType);
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(); // directory
+ directory=NULL;
+ }
+ delete directory;
+ CleanupStack::PopAndDestroy(2); // fileNameParser and findFile
+#ifdef SUPPORT_OLD_PLUGIN_PATH
+ }
+#endif
+ }
+
+LOCAL_C void DeleteTemp(TAny* aPtr)
+ {
+ CArrayPtr<MNotifierBase2>* array=REINTERPRET_CAST(CArrayPtr<MNotifierBase2>*,aPtr);
+ const TInt count=array->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ (*array)[ii]->Release();
+ }
+ delete array;
+ }
+
+
+
+void CNotifierManager::DoAddPlugInL(const TDesC& aPath,const TDesC& aFileName,const TUidType& aUidType)
+ {
+ RLibrary lib;
+ User::LeaveIfError(lib.Load(aFileName,aPath,aUidType));
+ CleanupClosePushL(lib);
+ iLibraries->AppendL(lib);
+ CleanupStack::Pop(); // lib
+ TLibraryFunction libEntry=lib.Lookup(1);
+ CArrayPtr<MNotifierBase2>* array=REINTERPRET_CAST(CArrayPtr<MNotifierBase2>*,(libEntry)());
+ User::LeaveIfNull(array);
+ CleanupStack::PushL(TCleanupItem(DeleteTemp,array));
+ while (array->Count()>0)
+ {
+ MNotifierBase2* notif=(*array)[0];
+ {
+ iObservedList->AppendL(notif);
+ array->Delete(0);
+ notif->SetManager(this);
+ }
+ MNotifierBase2::TNotifierInfo info=notif->RegisterL();
+ if (!iChannelMonitor->AlreadyHasChannel(info.iChannel))
+ iChannelMonitor->AddNewChannelL(info.iChannel);
+ }
+ CleanupStack::PopAndDestroy(); // array
+ }
+
+CNotifierManager::CNotifierManager()
+ {}
+
+void CNotifierManager::ConstructL()
+ {
+ iObservedList=new(ELeave) CArrayPtrSeg<MNotifierBase2>(6);
+ iLibraries=new(ELeave) CArrayFixFlat<RLibrary>(2);
+ iChannelMonitor=CChannelMonitor::NewL();
+ iActivityMonitor=CActivityMonitor::NewL();
+ iQueue=CNotifierQueue::NewL();
+ }
+
+struct SActivityCleanup
+ {
+ CActivityMonitor* iMonitor;
+ TUid iNotifier;
+ TInt iClientId;
+ };
+
+LOCAL_C void CleanupActivityMonitor(TAny* aPtr)
+ {
+ SActivityCleanup& cleanup=*REINTERPRET_CAST(SActivityCleanup*,aPtr);
+ cleanup.iMonitor->Remove(cleanup.iNotifier,cleanup.iClientId);
+ }
+
+void CNotifierManager::NotifierStartL(TUid aNotifierUid,const TDesC8& aBuffer,TPtrC8* aResponse,TInt aClientId)
+ {
+ TInt result=KErrNotFound;
+ const TInt count=iObservedList->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ MNotifierBase2* notif=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo info=notif->Info();
+ if (info.iUid==aNotifierUid)
+ {
+ if (iActivityMonitor->IsNotifierActive(aNotifierUid,info.iChannel))
+ {
+ result=KErrAlreadyExists;
+ }
+ else if (info.iPriority>iChannelMonitor->ActivityLevel(info.iChannel))
+ {
+ TUid notifier;
+ MNotifierBase2::TNotifierPriority priority;
+ const TBool channelWasActive=iActivityMonitor->IsChannelActive(info.iChannel,notifier,priority);
+ iActivityMonitor->AddL(info,aClientId);
+ SActivityCleanup cleanup;
+ cleanup.iMonitor=iActivityMonitor;
+ cleanup.iNotifier=aNotifierUid;
+ cleanup.iClientId=aClientId;
+ CleanupStack::PushL(TCleanupItem(CleanupActivityMonitor,&cleanup));
+ TPtrC8 response(notif->StartL(aBuffer));
+ if(aResponse)
+ aResponse->Set(response);
+ CleanupStack::Pop(); // cleanup;
+ if (channelWasActive)
+ {
+ for (TInt jj=0;jj<count;jj++)
+ {
+ MNotifierBase2* notifForUpdate=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo infoForUpdate=notifForUpdate->Info();
+ if (infoForUpdate.iUid==notifier && infoForUpdate.iChannel==info.iChannel)
+ {
+ TRAP_IGNORE(notifForUpdate->UpdateL(KNotifierPaused));
+ }
+ }
+ }
+ iChannelMonitor->UpdateChannel(info.iChannel,info.iPriority);
+ if (result!=ENotExtRequestQueued)
+ {
+ result=ENotExtRequestCompleted;
+ }
+ }
+ else
+ {
+ if (iQueue->IsAlreadyQueued(info.iUid,info.iChannel))
+ {
+ result=KErrAlreadyExists;
+ }
+ else
+ {
+ CQueueItem* queueCopy=CQueueItem::NewL(info,aBuffer,aClientId);
+ CleanupStack::PushL(queueCopy);
+ iQueue->QueueItemL(queueCopy);
+ CleanupStack::Pop(); // queueCopy
+ result=ENotExtRequestQueued;
+ }
+ }
+ }
+ }
+ User::LeaveIfError(result);
+ }
+
+TInt CNotifierManager::NotifierUpdateL(TUid aNotifierUid,const TDesC8& aBuffer,TDes8* aResponse,TInt aClientId)
+ {
+ TInt result=KErrNotFound;
+ const TInt count=iObservedList->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ MNotifierBase2* notif=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo info=notif->Info();
+ if (info.iUid==aNotifierUid)
+ {
+ if (iActivityMonitor->IsNotifierActive(aNotifierUid,info.iChannel))
+ {
+ if (!iActivityMonitor->IsClientPresent(aNotifierUid,info.iChannel,aClientId))
+ {
+ iActivityMonitor->AddL(info,aClientId);
+ }
+ if (aResponse==NULL)
+ {
+ notif->UpdateL(aBuffer);
+ }
+ else
+ {
+ aResponse->Copy(notif->UpdateL(aBuffer));
+ }
+ }
+ else
+ {
+ ; // not all channels have been started yet so update the queue
+ }
+ result=KErrNone;
+ }
+ }
+ return result;
+ }
+
+void CNotifierManager::NotifierStartAndGetResponseL(TUid aNotifierUid,const TDesC8& aBuffer,TInt aReplySlot,
+ const RMessage2& aMessage,TInt aClientId,TBool& aCleanupComplete)
+ {
+ NotifierStartAndGetResponseL(aNotifierUid,TUid::Null(),aBuffer,aReplySlot,aMessage,aClientId,aCleanupComplete);
+ }
+
+void CNotifierManager::NotifierStartAndGetResponseL(TUid aNotifierUid,TUid aChannelUid,const TDesC8& aBuffer,TInt aReplySlot,
+ const RMessage2& aMessage,TInt aClientId,TBool& aCleanupComplete)
+ {
+ TInt result=KErrNotFound;
+ const TInt count=iObservedList->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ MNotifierBase2* notif=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo info=notif->Info();
+ if (info.iUid==aNotifierUid && (aChannelUid==TUid::Null() || info.iChannel==aChannelUid))
+ {
+ if (iActivityMonitor->IsNotifierActive(aNotifierUid,info.iChannel))
+ {
+ notif->StartL(aBuffer,aReplySlot,aMessage); // asynch notifier can decide whether to support multiple clients
+ result=KErrNone;
+ }
+ else if (info.iPriority>iChannelMonitor->ActivityLevel(info.iChannel))
+ {
+ TUid notifier;
+ MNotifierBase2::TNotifierPriority priority;
+ const TBool channelWasActive=iActivityMonitor->IsChannelActive(info.iChannel,notifier,priority);
+ iActivityMonitor->AddL(info,aClientId);
+ SActivityCleanup activityCleanup;
+ activityCleanup.iMonitor=iActivityMonitor;
+ activityCleanup.iNotifier=aNotifierUid;
+ activityCleanup.iClientId=aClientId;
+ CleanupStack::PushL(TCleanupItem(CleanupActivityMonitor,&activityCleanup));
+ aCleanupComplete=EFalse;
+ // IMPORTANT, aMessage needs to be a full RMessage object until suport for V1 notifiers is removed
+ // I.e. until CNotifierBaseAdaptor is removed
+ notif->StartL(aBuffer,aReplySlot,aMessage);
+ CleanupStack::Pop(&activityCleanup);
+ if (channelWasActive)
+ {
+ for (TInt jj=0;jj<count;jj++)
+ {
+ MNotifierBase2* notifForUpdate=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo infoForUpdate=notifForUpdate->Info();
+ if (infoForUpdate.iUid==notifier && infoForUpdate.iChannel==info.iChannel)
+ {
+ TRAP_IGNORE(notifForUpdate->UpdateL(KNotifierPaused));
+ }
+ }
+ }
+ iChannelMonitor->UpdateChannel(info.iChannel,info.iPriority);
+ result=KErrNone;
+ }
+ else
+ {
+ if (iQueue->IsAlreadyQueued(info.iUid,info.iChannel))
+ {
+ result=KErrAlreadyExists;
+ }
+ else
+ {
+ CQueueItem* queueCopy=CQueueItem::NewL(info,aBuffer,aReplySlot,aMessage,aClientId);
+ CleanupStack::PushL(queueCopy);
+ iQueue->QueueItemL(queueCopy);
+ CleanupStack::Pop(queueCopy);
+ result=ENotExtRequestQueued;
+ }
+ }
+ }
+ }
+ User::LeaveIfError(result);
+ }
+
+TInt CNotifierManager::NotifierCancel(TUid aNotifierUid)
+ {
+ TInt result=KErrNotFound;
+ const TInt count=iObservedList->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ MNotifierBase2* notif=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo info=notif->Info();
+ if (info.iUid==aNotifierUid)
+ {
+ notif->Cancel();
+ iActivityMonitor->RemoveNotifier(aNotifierUid,info.iChannel);
+ MNotifierBase2::TNotifierPriority priority=MNotifierBase2::ENotifierPriorityLowest;
+ TUid notifier;
+ //check channel activity and get highest priority on channnel
+ if (iActivityMonitor->IsChannelActive(info.iChannel,notifier,priority))
+ {
+
+ //check if priority of a queued item on the same channel is
+ //greater
+ MNotifierBase2::TNotifierPriority queuePriority=
+ (MNotifierBase2::TNotifierPriority)iQueue->GetHighestQueuePriority(info.iChannel);
+ if (queuePriority>priority)
+ {
+ iChannelMonitor->UpdateChannel(info.iChannel,MNotifierBase2::ENotifierPriorityLowest);
+ CQueueItem* next=iQueue->FetchItem(info.iChannel);
+ if (next)
+ {
+ TUid notif=next->iInfo.iUid;
+ TRAPD(err,StartFromQueueL(next));
+ if (err!=KErrNone)
+ {
+ NotifierCancel(notif);
+ }
+ }
+ }
+ else
+ {
+ for (TInt jj=0;jj<count;jj++)
+ {
+ MNotifierBase2* notifForUpdate=(*iObservedList)[ii];
+ MNotifierBase2::TNotifierInfo infoForUpdate=notifForUpdate->Info();
+ if (infoForUpdate.iUid==notifier && infoForUpdate.iChannel==info.iChannel)
+ {
+ TRAP_IGNORE(notifForUpdate->UpdateL(KNotifierPaused));
+ }
+ }
+ iChannelMonitor->UpdateChannel(info.iChannel,priority);
+ }
+ }
+ else
+ {
+ iChannelMonitor->UpdateChannel(info.iChannel,MNotifierBase2::ENotifierPriorityLowest);
+ CQueueItem* next=iQueue->FetchItem(info.iChannel);
+ if (next)
+ {
+ TUid notif=next->iInfo.iUid;
+ TRAPD(err,StartFromQueueL(next));
+ if (err!=KErrNone)
+ {
+ NotifierCancel(notif);
+ }
+ }
+ }
+ result=KErrNone;
+ }
+ }
+ return result;
+ }
+
+struct SCleanupMessage
+ {
+ TBool* iDoCleanup;
+ RMessage2* iMessage;
+ };
+
+LOCAL_C void CleanupStartAndGetResponse(TAny* aPtr)
+ {
+ SCleanupMessage& cleanup=*REINTERPRET_CAST(SCleanupMessage*,aPtr);
+ if (cleanup.iDoCleanup)
+ {
+ cleanup.iMessage->Complete(KErrNoMemory);
+ }
+ }
+
+void CNotifierManager::StartFromQueueL(CQueueItem* aItem)
+ {
+ CleanupStack::PushL(aItem);
+ TPtr8 buffer=aItem->iBuffer->Des();
+ if (aItem->iAsynchronous)
+ {
+ SCleanupMessage cleanup;
+ TBool doCleanup=ETrue;
+ cleanup.iDoCleanup=&doCleanup;
+ cleanup.iMessage=&aItem->iMessage;
+ CleanupStack::PushL(TCleanupItem(CleanupStartAndGetResponse,&cleanup));
+ // IMPORTANT, aItem->iMessage needs to be a full RMessage object until suport for V1 notifiers is removed
+ // I.e. until CNotifierBaseAdaptor is removed
+ NotifierStartAndGetResponseL(aItem->iInfo.iUid,aItem->iInfo.iChannel,buffer,aItem->iReplySlot,aItem->iMessage,aItem->iClientId,doCleanup);
+ CleanupStack::Pop(&cleanup);
+ }
+ else
+ {
+ NotifierStartL(aItem->iInfo.iUid,buffer,NULL,aItem->iClientId);
+ }
+ CleanupStack::PopAndDestroy(); // aItem
+ CQueueItem* update=iQueue->FetchItem(aItem->iInfo.iChannel);
+ while (update)
+ {
+ CleanupStack::PushL(update);
+ NotifierUpdateL(update->iInfo.iUid,*update->iBuffer,NULL,update->iClientId);
+ CleanupStack::PopAndDestroy(); // update
+ update=iQueue->FetchItem(aItem->iInfo.iChannel);
+ }
+ }
+
+void CNotifierManager::HandleClientExit(TInt aClientId)
+ {
+ TUid notifier=KNullUid;
+ while (iActivityMonitor->NotifierForClient(notifier,aClientId))
+ {
+ const TInt count=iObservedList->Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ MNotifierBase2* notif=(*iObservedList)[ii];
+ if (notif->Info().iUid==notifier)
+ {
+ NotifierCancel(notifier);
+ }
+ }
+ iActivityMonitor->Remove(notifier,aClientId);
+ }
+ iActivityMonitor->RemoveClient(aClientId);
+ iQueue->RemoveClient(aClientId);
+ }
+
+void CNotifierManager::StartNotifierL(TUid aNotifierUid,const TDesC8& aBuffer,TDes8& aResponse)
+ {
+ TPtrC8 response(0,0);
+ NotifierStartL(aNotifierUid,aBuffer, &response,KNullClientId);
+ aResponse.Copy(response);
+ }
+
+void CNotifierManager::CancelNotifier(TUid aNotifierUid)
+ {
+ NotifierCancel(aNotifierUid);
+ }
+
+void CNotifierManager::UpdateNotifierL(TUid aNotifierUid,const TDesC8& aBuffer,TDes8& aResponse)
+ {
+ NotifierUpdateL(aNotifierUid,aBuffer,&aResponse,KNullClientId);
+ }
+
+//
+// class CChannelMonitor
+//
+
+CChannelMonitor* CChannelMonitor::NewL()
+ {
+ CChannelMonitor* self=new(ELeave) CChannelMonitor;
+ return self;
+ }
+
+TBool CChannelMonitor::AlreadyHasChannel(TUid aChannel)const
+ {
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ if (iMonitor[ii].iChannel==aChannel)
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+TInt CChannelMonitor::ActivityLevel(TUid aChannel) const
+ {
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ TChannelActivity activity=iMonitor[ii];
+ if (activity.iChannel==aChannel)
+ return activity.iHighestPriorityRunning;
+ }
+ return 0;
+ }
+
+void CChannelMonitor::UpdateChannel(TUid aChannel,TInt aLevel)
+ {
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ TChannelActivity& activity=iMonitor[ii];
+ if (activity.iChannel==aChannel)
+ {
+ activity.iHighestPriorityRunning=aLevel;
+ break;
+ }
+ }
+ }
+
+CChannelMonitor::CChannelMonitor()
+ :iMonitor(3)
+ {}
+
+//
+// class CNotifierActivity
+//
+
+CNotifierActivity* CNotifierActivity::NewLC(const MNotifierBase2::TNotifierInfo& aInfo,TInt aClientId)
+ { // static
+ CNotifierActivity* self=new(ELeave) CNotifierActivity(aInfo);
+ CleanupStack::PushL(self);
+ self->ConstructL(aClientId);
+ return self;
+ }
+
+CNotifierActivity::~CNotifierActivity()
+ {
+ iClientArray.Reset();
+ }
+
+TInt CNotifierActivity::Find(TInt aClientId) const
+ {
+ TInt index=KErrNotFound;
+ const TInt count=iClientArray.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ TInt clientId=iClientArray[ii];
+ if (clientId==aClientId)
+ {
+ index=ii;
+ break;
+ }
+ }
+ return index;
+ }
+
+CNotifierActivity::CNotifierActivity(const MNotifierBase2::TNotifierInfo& aInfo)
+ : iInfo(aInfo), iClientArray(1)
+ {}
+
+void CNotifierActivity::ConstructL(TInt aClientId)
+ {
+ iClientArray.AppendL(aClientId);
+ }
+
+//
+// class CActivityMonitor
+//
+
+CActivityMonitor* CActivityMonitor::NewL()
+ { // static
+ CActivityMonitor* self=new(ELeave) CActivityMonitor();
+ return self;
+ }
+
+CActivityMonitor::~CActivityMonitor()
+ {
+ iMonitor.ResetAndDestroy();
+ }
+
+void CActivityMonitor::AddL(const MNotifierBase2::TNotifierInfo& aInfo,TInt aClientId)
+ {
+ const TInt index=Find(aInfo.iUid,aInfo.iChannel);
+ if (index==KErrNotFound)
+ {
+ CNotifierActivity* activity=CNotifierActivity::NewLC(aInfo,aClientId);
+ iMonitor.AppendL(activity);
+ CleanupStack::Pop(); // activity
+ }
+ else
+ {
+ iMonitor[index]->iClientArray.AppendL(aClientId);
+ }
+ }
+
+void CActivityMonitor::Remove(TUid aNotifierUid,TInt aClientId)
+ {
+ const TInt index=Find(aNotifierUid);
+ if (index!=KErrNotFound)
+ {
+ CNotifierActivity* activity=iMonitor[index];
+ const TInt clientIndex=activity->Find(aClientId);
+ if (clientIndex!=KErrNotFound)
+ {
+ if (activity->iClientArray.Count()==1)
+ {
+ delete activity;
+ iMonitor.Delete(index);
+ }
+ else
+ {
+ activity->iClientArray.Delete(index);
+ }
+ }
+ }
+ }
+
+void CActivityMonitor::RemoveNotifier(TUid aNotifierUid,TUid aChannel)
+ {
+ const TInt index=Find(aNotifierUid,aChannel);
+ if (index!=KErrNotFound)
+ {
+ delete iMonitor[index];
+ iMonitor.Delete(index);
+ }
+ }
+
+void CActivityMonitor::RemoveClient(TInt aClientId)
+ {
+ TInt ii=0;
+ while (ii<iMonitor.Count())
+ {
+ CNotifierActivity* ptr=iMonitor[ii];
+ TInt index=ptr->Find(aClientId);
+ if (index!=KErrNotFound)
+ {
+ ptr->iClientArray.Delete(index);
+ }
+ if (ptr->iClientArray.Count()==0)
+ {
+ iMonitor.Delete(ii);
+ }
+ else
+ {
+ ++ii;
+ }
+ }
+ }
+
+TBool CActivityMonitor::IsNotifierActive(TUid aNotifierUid,TUid aChannel) const
+ {
+ const TInt index=Find(aNotifierUid,aChannel);
+ return (index!=KErrNotFound);
+ }
+
+TBool CActivityMonitor::IsClientPresent(TUid aNotifierUid,TUid aChannel,TInt aClientId) const
+ {
+ TBool found=EFalse;
+ const TInt index=Find(aNotifierUid,aChannel);
+ if (index!=KErrNotFound)
+ {
+ found=(iMonitor[index]->Find(aClientId)!=KErrNotFound);
+ }
+ return found;
+ }
+
+TBool CActivityMonitor::IsChannelActive(TUid aChannel,TUid& aNotifier,MNotifierBase2::TNotifierPriority& aHighestPriority) const
+ {
+ TBool ret=EFalse;
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ MNotifierBase2::TNotifierInfo info=iMonitor[ii]->iInfo;
+ if (info.iChannel==aChannel)
+ {
+ ret=ETrue;
+ if ((MNotifierBase2::TNotifierPriority)info.iPriority>aHighestPriority)
+ {
+ aNotifier=info.iUid;
+ aHighestPriority=(MNotifierBase2::TNotifierPriority)info.iPriority;
+ }
+ }
+ }
+ return ret;
+ }
+
+TBool CActivityMonitor::NotifierForClient(TUid& aNotifierUid,TInt aClientId) const
+ {
+ TBool isOnlyClient=EFalse;
+ aNotifierUid=KNullUid;
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ CNotifierActivity* ptr=iMonitor[ii];
+ if (ptr->Find(aClientId)!=KErrNotFound)
+ {
+ aNotifierUid=ptr->iInfo.iUid;
+ isOnlyClient=ptr->iClientArray.Count()==1;
+ break;
+ }
+ }
+ return isOnlyClient;
+ }
+
+CActivityMonitor::CActivityMonitor()
+ : iMonitor(1)
+ {}
+
+TInt CActivityMonitor::Find(TUid aNotifierUid) const
+ {
+ TInt index=KErrNotFound;
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ if (iMonitor[ii]->iInfo.iUid==aNotifierUid)
+ {
+ index=ii;
+ break;
+ }
+ }
+ return index;
+ }
+
+TInt CActivityMonitor::Find(TUid aNotifierUid,TUid aChannel) const
+ {
+ TInt index=KErrNotFound;
+ const TInt count=iMonitor.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ CNotifierActivity* ptr=iMonitor[ii];
+ if (ptr->iInfo.iUid==aNotifierUid && ptr->iInfo.iChannel==aChannel)
+ {
+ index=ii;
+ break;
+ }
+ }
+ return index;
+ }
+
+//
+// class CQueueItem
+//
+
+CQueueItem* CQueueItem::NewL(const MNotifierBase2::TNotifierInfo& aInfo,const TDesC8& aBuffer,
+ TInt aReplySlot,const RMessage2& aMessage,TInt aClientId) //Asynchronous
+ {
+ CQueueItem* self=new(ELeave) CQueueItem(aInfo);
+ CleanupStack::PushL(self);
+ self->ConstructL(aBuffer,aMessage,aClientId,aReplySlot);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+CQueueItem* CQueueItem::NewL(const MNotifierBase2::TNotifierInfo& aInfo,const TDesC8& aBuffer,TInt aClientId) //synchronous
+ {
+ CQueueItem* self=new(ELeave) CQueueItem(aInfo);
+ CleanupStack::PushL(self);
+ self->ConstructL(aBuffer,aClientId);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+CQueueItem::~CQueueItem()
+ {
+ delete iBuffer;
+ }
+
+CQueueItem::CQueueItem(const MNotifierBase2::TNotifierInfo& aInfo)
+ : iInfo(aInfo)
+ {}
+
+void CQueueItem::ConstructL(const TDesC8& aBuffer,TInt aClientId)
+ {
+ iBuffer=aBuffer.AllocL();
+ iClientId=aClientId;
+ iAsynchronous=EFalse;
+ }
+
+void CQueueItem::ConstructL(const TDesC8& aBuffer,const RMessage2& aMessage,TInt aClientId,TInt aReplySlot)
+ {
+ iBuffer=aBuffer.AllocL();
+ iAsynchronous=ETrue;
+ iMessage=aMessage;
+ iClientId=aClientId;
+ iReplySlot=aReplySlot;
+ }
+
+//
+// class CNotifierQueue
+//
+
+CNotifierQueue* CNotifierQueue::NewL()
+ {
+ CNotifierQueue* self=new(ELeave) CNotifierQueue;
+ return self;
+ }
+
+CQueueItem* CNotifierQueue::FetchItem(TUid aChannel)
+ {
+ CQueueItem* result=NULL;
+ const TInt count=iQueue.Count();
+ TInt priority=MNotifierBase2::ENotifierPriorityLowest-1;
+ TInt index=KErrNotFound;
+ for (TInt ii=0;ii<count;ii++)
+ {
+ CQueueItem* item=iQueue[ii];
+ if (item->iInfo.iChannel==aChannel && item->iInfo.iPriority>priority)
+ {
+ index=ii;
+ priority=item->iInfo.iPriority;
+ result=item;
+ }
+ }
+ if (index!=KErrNotFound)
+ {
+ iQueue.Delete(index);
+ }
+ return result;
+ }
+
+TBool CNotifierQueue::IsAlreadyQueued(TUid aNotifier,TUid aChannel) const
+ {
+ TBool ret=EFalse;
+ const TInt count=iQueue.Count();
+ for (TInt ii=0;ii<count;ii++)
+ {
+ CQueueItem* item=iQueue[ii];
+ if (item->iInfo.iUid==aNotifier && item->iInfo.iChannel==aChannel)
+ {
+ ret=ETrue;
+ break;
+ }
+ }
+ return ret;
+ }
+
+void CNotifierQueue::RemoveClient(TInt aClientId)
+ {
+ const TInt count=iQueue.Count();
+ for (TInt ii=count-1;ii>=0;ii--)
+ {
+ CQueueItem* item=iQueue[ii];
+ TInt clientId=item->iClientId;
+ if (clientId==aClientId)
+ {
+ iQueue.Delete(ii);
+ }
+ }
+ }
+
+
+TInt CNotifierQueue::GetHighestQueuePriority(TUid aChannel)
+ {
+ const TInt count=iQueue.Count();
+ TInt priority=MNotifierBase2::ENotifierPriorityLowest-1;
+
+ for (TInt ii=0;ii<count;ii++)
+ {
+ CQueueItem* item=iQueue[ii];
+ if (item->iInfo.iChannel==aChannel && item->iInfo.iPriority>priority)
+ {
+ priority=item->iInfo.iPriority;
+ }
+ }
+
+ return priority;
+ }
+
+
+void CWsActiveScheduler::New()
+//
+// Create and install the active scheduler.
+//
+ {
+
+ CWsActiveScheduler *pA=new CWsActiveScheduler;
+ __ASSERT_ALWAYS(pA!=NULL,Fault(ECreateScheduler));
+ CActiveScheduler::Install(pA);
+ }
+
+void CWsActiveScheduler::Error(TInt) const
+//
+// Called if any Run() method leaves.
+//
+ {
+ }
+
+
+TInt NotifierServerThread(TAny*)
+ {
+ CTrapCleanup* CleanUpStack=CTrapCleanup::New();
+ CWsActiveScheduler::New();
+ TRAP_IGNORE(CNotifierServer::NewL());
+ CNotifierSession::NotifierSemaphore.Signal();
+ CWsActiveScheduler::Start();
+ delete CleanUpStack;
+ return(0);
+ }
+
+
+_LIT(KLitKeyDataDllNameBase, "EKDATA");
+_LIT(TwoDigExt,".%02d");
+
+GLDEF_C TInt E32Main()
+ {
+ UserSvr::WsRegisterThread();
+ UserSvr::WsRegisterSwitchOnScreenHandling(ETrue);
+ User::SetProcessCritical(User::ESystemPermanent);
+ User::SetCritical(User::ESystemPermanent);
+
+ CWsActiveScheduler::New();
+ CWsServer::New();
+ CWsWindow::New();
+ CEvent::New();
+
+ KeyTranslator=CKeyTranslator::New();
+ if (!KeyTranslator)
+ Fault(ENoKeyboardTranslator);
+
+// Change keyboard mapping according to information in the HAL
+// This code is the same as WSERV
+ TInt keyboardIndex;
+ if (HAL::Get(HALData::EKeyboardIndex,keyboardIndex)==KErrNone)
+ {
+ TBuf<16> keyDataDllName(KLitKeyDataDllNameBase);
+ keyDataDllName.AppendFormat(TwoDigExt, keyboardIndex);
+ KeyTranslator->ChangeKeyData(keyDataDllName);
+ }
+
+ KeyRepeat=new(ELeave) CKeyRepeat(CKeyRepeat::EKeyRepeatPriority);
+ TRAPD(r,KeyRepeat->ConstructL());
+ if (r!=KErrNone)
+ User::Panic(_L("KEYREPEAT"),r);
+
+#ifndef __WINS__
+ if (UserSvr::TestBootSequence())
+ {
+ RDebug::Print(_L("WS_MAIN: TestBootSequence=TRUE, not loading ESHELL.EXE"));
+ }
+#else
+ if (EmulatorAutoRun())
+ { // don't start ESHELL if we used a self-bootstrapping EXE
+ }
+#endif
+ else
+ {
+ RProcess shell;
+ r=shell.Create(KShellProcessName, KShellCommandLine);
+ __ASSERT_ALWAYS(r==KErrNone,Fault(ECreateShell));
+ shell.Resume();
+ shell.Close();
+ }
+
+ RThread t;
+ r=CNotifierSession::NotifierSemaphore.CreateLocal(0);
+ if (r!=KErrNone)
+ Fault(ECreateNotifierSemaphore);
+ r=t.Create(_L("NotifierServer"),NotifierServerThread,KDefaultStackSize,0x2000,0x100000,NULL);
+ if (r!=KErrNone)
+ Fault(ECreateNotifierThread);
+ t.Resume();
+ CNotifierSession::NotifierSemaphore.Wait();
+
+ CWsActiveScheduler::Start();
+ UserSvr::ReleaseEventHook();
+ return(KErrNone);
+ }
+