diff -r 000000000000 -r b26acd06ea60 sdkcreationmw/sdkruntimes/msgsimulation/MsgRelay/Src/MsgRelayDll.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdkcreationmw/sdkruntimes/msgsimulation/MsgRelay/Src/MsgRelayDll.cpp Mon Mar 08 12:09:11 2010 +0530 @@ -0,0 +1,714 @@ +/* +* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + + +// Include Files + +#include // GLDEF_C +#include // RDesReadStream +#include // CSmsMessage +#include // CSmsBuffer +#include // KUidMsgTypeSMS +#include // KUidMsvMessageEntry +#include // CSmsClientMtm +#include // CClientMtmRegistry +#include // CBaseMtmUi +#include // CRichText +#include // CSmsSettings +#include // CSmsHeader +#include // RProperty +#include "MsgRelay.h" + +static const TInt KMaxSubjectLength = 30; + +const TUid KPSUidIdleInformation = {0x102071C0}; +const TUint32 KTelephonyIdleStatus = 0x00000001; +enum TPSTelephonyIdleStatus { EPSTelephonyNotIdle, EPSTelephonyIdle }; +const TUid KPSUidAiInformation = {0x102750F0}; // ActiveIdle2 SID +const TUint KActiveIdleState = 0x00000002; // Contains one value from following emuneration +enum EPSActiveIdleState { EPSAiBackground = 0,EPSAiForeground, EPSAiNumberEntry }; + +TVersion MessageRelayVersion = TVersion(1, 0, 0); + +/**************************************************************************** +* CRelaySession +***************************************************************************** +* +* +* +****************************************************************************/ +/* Implements actual functionality for clients. */ +class CRelaySession : public CSession2 +{ + CMessageRelay *iOwner; + + /* Is the session listening for messages. */ + TBool iListening; + + /* The port that is listened, if iListening is ETrue. + Port 0 means that port is not specified. */ + TUint iListenPort; + + /* The message type that is listened. */ + TMessageType iListenType; + + /* Notifies new messages to client...*/ + TRequestStatus *iListenStatus; + + /* Used for message passing. */ + RMessage2 iRcvMessage; + + void ConstructL(); + + CRelaySession(CMessageRelay *aOwner); +public: + + static CRelaySession *NewL(CMessageRelay *aOwner); + static CRelaySession *NewLC(CMessageRelay *aOwner); + + ~CRelaySession(); + + void ServiceL(const RMessage2& aMessage); + + /* If message is accepted ETrue is returned, otherwise EFalse. + An accepted message is relayed to the client listening for the + messages or to the system Inbox(if no port specified). */ + TBool AcceptL(TPtr8 &aMessage, TUint aPort, TMessageType aType); + + /* Returns ETrue, is the port is already listened for. */ + TBool IsListening(TUint aPort, TMessageType aType); + +}; + +CRelaySession::CRelaySession(CMessageRelay *aOwner) : +CSession2(), +iOwner(aOwner), +iListening(EFalse) + { + + } + +void CRelaySession::ConstructL() + { + + } + +CRelaySession *CRelaySession::NewL(CMessageRelay *aOwner) + { + CRelaySession *self = CRelaySession::NewLC(aOwner); + CleanupStack::Pop(); + return self; + } + +CRelaySession *CRelaySession::NewLC(CMessageRelay *aOwner) + { + CRelaySession *self = new (ELeave) CRelaySession(aOwner); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CRelaySession::~CRelaySession() + { + for( int i = 0; i < iOwner->iSessions->Count(); i++) + { + if( iOwner->iSessions->At( i ) == this) + { + iOwner->iSessions->Delete( i ); + break; + } + } + } + +/* Returns ETrue, is the port is already listened for. */ +TBool CRelaySession::IsListening(TUint aPort, TMessageType aType) + { + if (iListening == EFalse) + return EFalse; + + if (aType != iListenType) + return EFalse; + + if (aPort != iListenPort) + return EFalse; + + return ETrue; + } + +void CRelaySession::ServiceL(const RMessage2& aMessage) + { + HBufC8 *newMessage = NULL; + TMessageType type; + TUint port; + + switch (aMessage.Function()) + { + case KNewMessage: + { + if (iOwner == NULL) + User::Leave(KErrNotReady); + + if (iOwner->iWriter == NULL) + User::Leave(KErrNotReady); + + newMessage = HBufC8::NewL(aMessage.Int0()); + TPtr8 ptr(newMessage->Des()); + aMessage.ReadL( 1, ptr ); + + type = (TMessageType)aMessage.Int2(); + iOwner->iWriter->WriteMessageL(ptr, type); + + aMessage.Complete(KErrNone); + + delete newMessage; + + break; + } + case KReceive: + + if (iListening) { + if (!iRcvMessage.IsNull()) { + iRcvMessage.Complete(KErrCancel); + } + iRcvMessage = aMessage; + iOwner->TraverseInboxL(); + } + else { + aMessage.Complete(KErrNotReady); + } + break; + case KCancelReceive: + if (!iRcvMessage.IsNull()) { + iRcvMessage.Complete(KErrCancel); + } + aMessage.Complete(KErrNone); + break; + case KStartListening: + + if (iOwner == NULL) + User::Leave(KErrNotReady); + + type = (TMessageType)aMessage.Int1(); + port = (TUint)aMessage.Int2(); + + if (iOwner->IsAnyBodyListening(port, type) != EFalse) + { + aMessage.Complete(KErrInUse); + return; + } + + iListenType = type; + iListenPort = port; + iListening = ETrue; + aMessage.Complete(KErrNone); + break; + + case KStopListening: + iListening = EFalse; + if (!iRcvMessage.IsNull()) { + iRcvMessage.Complete(KErrCancel); + } + aMessage.Complete(KErrNone); + break; + + default: + User::Leave(KErrNotSupported); + } + + } + +/* If message is accepted ETrue is returned, otherwise EFalse. + An accepted message is relayed to the client listening for the + messages. */ +TBool CRelaySession::AcceptL(TPtr8 &aMessage, TUint aPort, TMessageType aType) + { + if (IsListening(aPort, aType) == EFalse) + return EFalse; + + /* Write data to client */ + if (!iRcvMessage.IsNull()) { + iRcvMessage.WriteL(0, aMessage); + iRcvMessage.Complete(KErrNone); + } + + return ETrue; + } + +/**************************************************************************** +* CMessageRelay +***************************************************************************** +* +* +* +****************************************************************************/ +EXPORT_C CMessageRelay::CMessageRelay() : CServer2(EPriorityNormal) + { + + } + +EXPORT_C void CMessageRelay::ConstructL(CMessageWriter *aWriter) + { + iSessions = new (ELeave) CArrayFixFlat(1); + + SetWriter(aWriter); + + } + +EXPORT_C CMessageRelay *CMessageRelay::NewL(CMessageWriter *aWriter /*= NULL*/) + { + CMessageRelay *self = CMessageRelay::NewLC(aWriter); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CMessageRelay *CMessageRelay::NewLC(CMessageWriter *aWriter /*= NULL*/) + { + CMessageRelay *self = new (ELeave) CMessageRelay(); + CleanupStack::PushL(self); + self->ConstructL(aWriter); + return self; + } + +EXPORT_C CMessageRelay::~CMessageRelay() + { + delete iSessions; + } + +/* Goes through all sessions and returns ETrue, is someone + is listening the given port. */ +TBool CMessageRelay::IsAnyBodyListening(TUint aPort, TMessageType aType) + { + TInt i = 0; + + for (i = 0; i < iSessions->Count(); i++) + { + if (iSessions->At(i)->IsListening(aPort, aType) != EFalse) + return ETrue; + } + + return EFalse; + } + +CSession2* CMessageRelay::NewSessionL(const TVersion& aVersion) const + { + if (!User::QueryVersionSupported(MessageRelayVersion, + aVersion)) + { + /* Wrong version. */ + User::Leave(KErrNotSupported); + } + + CRelaySession *session = CRelaySession::NewL( (CMessageRelay *)this ); + + iSessions->AppendL(session); + + return session; + } + +CSession2* CMessageRelay::NewSessionL(const TVersion& aVersion, const RMessage2&) const + { + return NewSessionL( aVersion ); + } + +/* Starts the server. */ +void CMessageRelay::StartRelayL() + { + CServer2::StartL(KRelayServiceName); + } + +/* Call this method when a new message is received to relay it + to possible listeners. Returns ETrue, if the message was + accepted. If the message was not accepted, it must not be + destroyed, but it must be offered again, as soon as there + is a listener for it. */ +EXPORT_C TBool CMessageRelay::NewMessageL(TPtr8 &aMessage, TMessageType aType) + { + TInt i = 0; + + if (aType != ESmsMessage) + User::Leave(KErrNotSupported); + + + /* Extract the port and check if it's listened to. */ + RFs fs; + fs.Connect(); + + CSmsBuffer *smsBuf = CSmsBuffer::NewL(); + CSmsMessage *smsMsg = CSmsMessage::NewL(fs, CSmsPDU::ESmsSubmit, smsBuf); + + RDesReadStream rs(aMessage); + smsMsg->InternalizeL(rs); + + rs.Close(); + fs.Close(); + + CSmsPDU &pdu = smsMsg->SmsPDU(); + + TInt src, dst; + + TBool isPorts = pdu.ApplicationPortAddressing(dst, src); + + if (isPorts == EFalse) + { + /* Copy to inbox. */ + CopyMessageToSmsInboxL(aMessage); + return ETrue; + } + + for (i = 0; i < iSessions->Count(); i++) + { + if (iSessions->At(i)->AcceptL(aMessage, dst, aType) != EFalse) + return ETrue; + } + + /* No listeners. Cache the message to Inbox. Inbox is traversed, + when new listener are created. */ + TPtr8 &aMessage2 = aMessage; + CopyMessageToSmsInboxL(aMessage2); + return ETrue; + } + +/* Sets the message writer. Writers WriteMessageL(...) method + is called when a client wants to send a message. */ +EXPORT_C void CMessageRelay::SetWriter(CMessageWriter *aWriter) + { + iWriter = aWriter; + } + +/* Copies the message to inbox. */ +void CMessageRelay::CopyMessageToSmsInboxL(TPtr8 &aMessage) + { + // Get the idle statuses from P&S + TInt aiStatus(0); + TInt aiGetErr = RProperty::Get( KPSUidAiInformation, + KActiveIdleState, + aiStatus ); + TInt tiStatus(0); + TInt tiGetErr = RProperty::Get( KPSUidIdleInformation, + KTelephonyIdleStatus, + tiStatus ); + + _LIT(KIdleStatus,"MSGRelay -- aiState:%d aiGetErr:%d tiState:%d tiGetErr:%d"); + RDebug::Print(KIdleStatus, aiStatus, aiGetErr, tiStatus, tiGetErr); + + // Update telephony idle status to idle and active idle status + // to foreground if needed. Without these "New message" notifications + // might not be visible in some cases. + if( aiStatus != EPSAiForeground ) + { + TInt setAiErr = RProperty::Set( KPSUidAiInformation, + KActiveIdleState, + EPSAiForeground ); + _LIT( KAISetErr,"MSGRelay -- setAiErr:%d" ); + RDebug::Print( KAISetErr, setAiErr ); + } + + if( tiStatus != EPSTelephonyIdle ) + { + TInt setTiErr = RProperty::Set( KPSUidIdleInformation, + KTelephonyIdleStatus, + EPSTelephonyIdle ); + _LIT( KTISetErr,"MSGRelay -- setTiErr:%d" ); + RDebug::Print( KTISetErr, setTiErr ); + } + + RFs fs; + + User::LeaveIfError(fs.Connect()); + + CSmsBuffer *smsBuf = CSmsBuffer::NewL(); + CSmsMessage *smsMessage = CSmsMessage::NewL(fs, CSmsPDU::ESmsSubmit, smsBuf); + CMsvSession *iMsvSession = CMsvSession::OpenSyncL(*this); + CClientMtmRegistry *registry = CClientMtmRegistry::NewL(*iMsvSession); + + RDesReadStream rs(aMessage); + rs >> *smsMessage; + rs.Close(); + + TMsvEntry index; + + index.iMtm = KUidMsgTypeSMS; + index.iType = KUidMsvMessageEntry; + index.iServiceId = KMsvLocalServiceIndexEntryId; + index.iDate.HomeTime(); + index.SetInPreparation(ETrue); + + TMsvSelectionOrdering ordering; + CMsvEntry *entry = CMsvEntry::NewL(*iMsvSession, KMsvGlobalInBoxIndexEntryIdValue, + ordering); + + entry->CreateL(index); + + entry->SetEntryL(index.Id()); + + CSmsClientMtm* mtm = (CSmsClientMtm*)registry->NewMtmL(KUidMsgTypeSMS); + + mtm->SetCurrentEntryL(entry); + + index = mtm->Entry().Entry(); + + index.iDetails.Set(smsMessage->ToFromAddress()); + + index.SetInPreparation(EFalse); + + index.SetSendingState(KMsvSendStateNotApplicable); + index.iDate = smsMessage->Time(); + + // Set the new and unread flags. Enables "New message" notifications. + index.SetNew( ETrue ); + index.SetUnread( ETrue ); + + CRichText &mtmBody = mtm->Body(); + mtmBody.Reset(); + + HBufC *data = HBufC::NewLC(smsBuf->Length()); + TPtr ptr(data->Des()); + + smsBuf->Extract(ptr, 0, smsBuf->Length()); + + mtmBody.InsertL(0, ptr); + + if (ptr.Length() > KMaxSubjectLength) + index.iDescription.Set(ptr.Left(KMaxSubjectLength)); + else + index.iDescription.Set(ptr); + + mtm->RestoreServiceAndSettingsL(); + + CSmsHeader &hdr = mtm->SmsHeader(); + + CSmsSettings *sendOpt = CSmsSettings::NewL(); + CleanupStack::PushL(sendOpt); + + sendOpt->CopyL(mtm->ServiceSettings()); + sendOpt->SetDelivery(ESmsDeliveryImmediately); + + hdr.SetSmsSettingsL(*sendOpt); + hdr.SetFromAddressL(smsMessage->ToFromAddress()); + + CleanupStack::PopAndDestroy(sendOpt); + + CSmsMessage &newMsg = hdr.Message(); + + newMsg.SetServiceCenterAddressL(smsMessage->ServiceCenterAddress()); + + CSmsPDU &pdu = newMsg.SmsPDU(); + CSmsPDU &oldPdu = smsMessage->SmsPDU(); + + pdu.SetAlphabet(oldPdu.Alphabet()); + + TSmsDataCodingScheme::TSmsClass coding; + TBool b = oldPdu.Class(coding); + pdu.SetClass(b, coding); + + TInt dst = -1; + TInt src = -1; + TBool is16; + + b = oldPdu.ApplicationPortAddressing(dst, src, &is16); + + if(b != EFalse) + { + pdu.SetApplicationPortAddressingL(b, dst, src, is16); + } + + mtm->AddAddresseeL(smsMessage->ToFromAddress(), index.iDetails); + + CMsvEntry &newEntry = mtm->Entry(); + newEntry.ChangeL(index); + + mtm->SaveMessageL(); + + CleanupStack::PopAndDestroy(1); + + } + +static CSmsMessage *ConvertEntryToMessageL(TMsvEntry &aIndex, CMsvSession *aSession) + { + CClientMtmRegistry *registry = CClientMtmRegistry::NewL(*aSession); + CleanupStack::PushL(registry); + + CSmsClientMtm* mtm = (CSmsClientMtm*)registry->NewMtmL(aIndex.iMtm); + CleanupStack::PushL(mtm); + + mtm->SwitchCurrentEntryL(aIndex.Id()); + mtm->LoadMessageL(); + + CSmsHeader &hdr = mtm->SmsHeader(); + + CSmsMessage &msg = hdr.Message(); + + HBufC8 *buf = HBufC8::NewLC(KMaxSmsBufferSize); + TPtr8 ptr(buf->Des()); + RDesWriteStream ws(ptr); + + ws << msg; + + ws.Close(); + + RFs fs; + + User::LeaveIfError(fs.Connect()); + + CSmsBuffer *smsBuf = CSmsBuffer::NewL(); + CSmsMessage *newMsg = CSmsMessage::NewL(fs, CSmsPDU::ESmsSubmit, smsBuf); + + RDesReadStream rs(ptr); + rs >> *newMsg; + + rs.Close(); + fs.Close(); + + CleanupStack::PopAndDestroy(3); + + return newMsg; + } + +static void DeleteEntryFromInboxL(CMsvEntry *aEntry, CMsvSession *aSession) + { + TMsvEntry index = aEntry->Entry(); + TMsvSelectionOrdering sort = aEntry->SortType(); + sort.SetShowInvisibleEntries(ETrue); + CMsvEntry* parentEntry = CMsvEntry::NewL(*aSession, index.Parent(), sort); + CleanupStack::PushL(parentEntry); + + TRAPD(err, parentEntry->DeleteL(index.Id())); + + if(err != KErrNone) + { + aSession->RemoveEntry(index.Id()); + } + + CleanupStack::PopAndDestroy(parentEntry); + } + +/* Traverses the inbox and sends messages to listeners. */ +void CMessageRelay::TraverseInboxL() + { + TInt count = 0; + CMsvEntrySelection* childrenEntrySelection; + CMsvEntry* rootEntry; + CMsvEntry* child; + + CMsvSession *iMsvSession = CMsvSession::OpenSyncL(*this); + CleanupStack::PushL(iMsvSession); + + rootEntry = iMsvSession->GetEntryL(KMsvGlobalInBoxIndexEntryId); + count = rootEntry->Count(); + + childrenEntrySelection = rootEntry->ChildrenL(); + + for(TInt i = 0; i < count; i++) + { + child = iMsvSession->GetEntryL((*childrenEntrySelection)[i]); + TMsvEntry msvEntry = child->Entry(); + + if (msvEntry.iMtm != KUidMsgTypeSMS) + /* Not to us. */ + continue; + + CSmsMessage *smsMsg = ConvertEntryToMessageL(msvEntry, iMsvSession); + + HBufC8 *buf = HBufC8::NewLC(KMaxSmsBufferSize); + TPtr8 ptr(buf->Des()); + RDesWriteStream ws(ptr); + + ws << *smsMsg; + + ws.Close(); + + CSmsPDU &pdu = smsMsg->SmsPDU(); + + TInt src, dst; + + TBool isPorts = pdu.ApplicationPortAddressing(dst, src); + + if (isPorts == EFalse) + { + /* No ports, no listeners, leave to inbox. */ + CleanupStack::PopAndDestroy(1); //buf + continue; + + } + + for (i = 0; i < iSessions->Count(); i++) + { + if (iSessions->At(i)->AcceptL(ptr, dst, ESmsMessage) != EFalse) + { + /* Remove from inbox */ + DeleteEntryFromInboxL(child, iMsvSession); + + /* Inbox has changed, start traversing again. */ + rootEntry = iMsvSession->GetEntryL(KMsvGlobalInBoxIndexEntryId); + count = rootEntry->Count(); + childrenEntrySelection = rootEntry->ChildrenL(); + + i = -1; /* Will be incremented before testing... */ + break; + } + } + + CleanupStack::PopAndDestroy(1); //buf + + } + CleanupStack::PopAndDestroy(1); // iMsvSesssion + } + +void CMessageRelay::HandleSessionEventL(TMsvSessionEvent, TAny*, + TAny*, TAny*) + { + } +/**************************************************************************** +* CMessageWriter +***************************************************************************** +* +* +* +****************************************************************************/ +EXPORT_C void CMessageWriter::ConstructL() + { + + } + +EXPORT_C CMessageWriter *CMessageWriter::NewL() + { + CMessageWriter *self = CMessageWriter::NewLC(); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CMessageWriter *CMessageWriter::NewLC() + { + CMessageWriter *self = new (ELeave) CMessageWriter; + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +EXPORT_C CMessageWriter::~CMessageWriter() + { + + } + +/* Called when a message is received from client for sending. */ +EXPORT_C void CMessageWriter::WriteMessageL(TPtr8 & /*aMessage*/, TMessageType /*aType*/) + { + /* Nothing to do, inherited class will override. */ + } + +// End of file