diff -r fa1df4b99609 -r ebe688cedc25 messagingapp/msgnotifications/msgnotifier/src/msgstorehandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingapp/msgnotifications/msgnotifier/src/msgstorehandler.cpp Tue Aug 31 15:11:31 2010 +0300 @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2008 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: Message Store Handling for Indications + * + */ + +#include "msgstorehandler.h" +#include +#include "msgnotifier_p.h" +#include +#include +#include +#include "msgcontacthandler.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "debugtraces.h" + +// CONSTANTS +_LIT(KUnixEpoch, "19700000:000000.000000"); + +// ================= MEMBER FUNCTIONS ======================= + +// --------------------------------------------------------- +// Default constructor. +// --------------------------------------------------------- +// +MsgStoreHandler::MsgStoreHandler(MsgNotifierPrivate* notifier, CCSRequestHandler* aCvServer) : + CActive(EPriorityStandard), iMsvSession(NULL), iNotifier(notifier), iRequestHandler(aCvServer) +{ + InitL(); +} + +// --------------------------------------------------------- +// Destructor. +// --------------------------------------------------------- +// +MsgStoreHandler::~MsgStoreHandler() +{ + Cancel(); + iStateAwareSession.Close(); + + if (iMsvEntry) { + delete iMsvEntry; + iMsvEntry = NULL; + } + + if (iMsvSession) { + delete iMsvSession; + iMsvSession = NULL; + } + + if (iFailedMessages) { + delete iFailedMessages; + iFailedMessages = NULL; + } + +} + +// --------------------------------------------------------- +// InitL( ) +// Initialize the Store handler. +// --------------------------------------------------------- +void MsgStoreHandler::InitL() +{ + iMsvSession = CMsvSession::OpenSyncL(*this); + iMsvEntry = iMsvSession->GetEntryL(KMsvGlobalOutBoxIndexEntryId); + iMsvEntry->AddObserverL(*this); + + iFailedMessages = new (ELeave) CMsvEntrySelection; + + User::LeaveIfError(iStateAwareSession.Connect(KSM2GenMiddlewareDomain3)); + CActiveScheduler::Add(this); + + TSsmState ssmState = iStateAwareSession.State(); + + if (ssmState.MainState() != ESsmNormal) + { + iStateAwareSession.RequestStateNotification(iStatus); + SetActive(); + } + else + { + RunL(); + } + +} + +void MsgStoreHandler::RunL() +{ + TSsmState ssmState = iStateAwareSession.State(); + if (ssmState.MainState() != ESsmNormal) + { + iStateAwareSession.RequestStateNotification(iStatus); + SetActive(); + } + else + { + //Create the query/operation object + CMsvSearchSortOperation *operation = CMsvSearchSortOperation::NewL(*iMsvSession); + CleanupStack::PushL(operation); + CMsvSearchSortQuery *query = CMsvSearchSortQuery::NewL(); + CleanupStack::PushL(query); + + //set the query options + query->SetParentId(KMsvGlobalInBoxIndexEntryId); + query->SetResultType(EMsvResultAsTMsvId); + query->AddSearchOptionL(EMsvMtmTypeUID, KSenduiMtmSmsUidValue, EMsvEqual); + query->AddSearchOptionL(EMsvUnreadMessages, ETrue); + CleanupStack::Pop(query); + + CMsvOperationActiveSchedulerWait* wait = CMsvOperationActiveSchedulerWait::NewLC(); + //ownership of Query transferred to Operation + operation->RequestL(query, EFalse, wait->iStatus); + wait->Start(); + + //Get No of entries + RArray messageArray; + operation->GetResultsL(messageArray); + + CMsvEntry* entry = NULL; + for (TInt i = 0; i < messageArray.Count(); ++i) + { + entry = iMsvSession->GetEntryL(messageArray[i]); + TMsvSmsEntry smsEntry = entry->Entry(); + TSmsDataCodingScheme::TSmsClass classType(TSmsDataCodingScheme::ESmsClass0); + if (smsEntry.Class(classType)) + { + HandleClass0SmsL(entry, smsEntry.Id()); + } + else + { + delete entry; + entry = NULL; + } + } + messageArray.Close(); + CleanupStack::PopAndDestroy(2, operation); + } + +} + +void MsgStoreHandler::DoCancel() +{ + iStateAwareSession.RequestStateNotificationCancel(); +} +// --------------------------------------------------------- +// MsgStoreHandler::HandleSessionEventL() +// --------------------------------------------------------- +// +void MsgStoreHandler::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* /*aArg3*/) +{ + CMsvEntrySelection* selection = NULL; + TMsvId parent; + + //args + if (aArg1 == NULL || aArg2 == NULL) { + return; + } + + //start, processing the event + selection = (CMsvEntrySelection*) aArg1; + parent = *(TMsvId*) aArg2; + + // Return when not (outbox or inbox) and event not EMsvEntriesChanged + if (!(parent == KMsvGlobalOutBoxIndexEntryIdValue || parent == KMsvGlobalInBoxIndexEntryIdValue) + && aEvent != EMsvEntriesChanged) { + return; + } + + // check for incoming class 0 sms + if (parent == KMsvGlobalInBoxIndexEntryIdValue && aEvent == EMsvEntriesChanged) { + CMsvEntry* inboxEntry = iMsvSession->GetEntryL(KMsvGlobalInBoxIndexEntryId); + for (TInt i = 0; i < selection->Count(); ++i) { + TMsvEntry entry = inboxEntry->ChildDataL(selection->At(i)); + if (KSenduiMtmSmsUidValue == entry.iMtm.iUid) { + CMsvEntry* msgEntry = iMsvSession->GetEntryL(entry.Id()); + TMsvSmsEntry smsEntry = msgEntry->Entry(); + TSmsDataCodingScheme::TSmsClass classType(TSmsDataCodingScheme::ESmsClass0); + + if (smsEntry.Class(classType) && smsEntry.Unread()) + { + HandleClass0SmsL(msgEntry, smsEntry.Id()); + } + else + { + delete msgEntry; + msgEntry = NULL; + } + } + + } // for (TInt i = 0; i < selection->Count(); ++i) + delete inboxEntry; + } + //Handling for outbox entries + else if (parent == KMsvGlobalOutBoxIndexEntryIdValue) { + CMsvEntry* rootEntry = iMsvSession->GetEntryL(KMsvGlobalOutBoxIndexEntryId); + + for (TInt i = 0; i < selection->Count(); ++i) { + TMsvEntry entry = rootEntry->ChildDataL(selection->At(i)); + + if ((entry.iMtm == KSenduiMtmSmsUid) || (entry.iMtm == KSenduiMtmMmsUid)) { + TUint sendingState = entry.SendingState(); + TInt index = iFailedMessages->Find(entry.Id()); + + if (sendingState == KMsvSendStateFailed && KErrNotFound == index) { + + iFailedMessages->AppendL(entry.Id()); + MsgInfo aInfo; + ProcessIndicatorDataL(entry.Id(), aInfo); + iNotifier->displayFailedNote(aInfo); + } + else if (sendingState != KMsvSendStateFailed && KErrNotFound != index) { + iFailedMessages->Delete(index); + iFailedMessages->Compress(); + } + + } + }//end for + } + else { + TMsvEntry entry; + TMsvId service; + TInt error = KErrNone; + for (TInt i = 0; i < selection->Count(); ++i) { + error = iMsvSession->GetEntry(selection->At(i), service, entry); + + if (error == KErrNone && entry.iMtm == KUidMsgMMSNotification && + MmsNotificationStatus(entry) == EMsgStatusFailed) { + + TInt index = iFailedMessages->Find(entry.Id()); + + if (KErrNotFound == index) { + iFailedMessages->AppendL(entry.Id()); + MsgInfo aInfo; + //Fill aInfo with appropriate data + aInfo.mMessageType = ECsMmsNotification; + ProcessIndicatorDataL(entry.Id(), aInfo); + iNotifier->displayFailedNote(aInfo); + + }// end of if + } + else if (error == KErrNone && entry.iMtm == KUidMsgMMSNotification + && MmsNotificationStatus(entry) == EMsgStatusRetrieving) { + + TInt index = iFailedMessages->Find(entry.Id()); + if (KErrNotFound != index) { + iFailedMessages->Delete(index); + iFailedMessages->Compress(); + }// end of KErrNotFound != index if block + + } // end of 2nd if + } // for loop + } + +} + +// --------------------------------------------------------- +// MsgStoreHandler::HandleClass0SmsL() +// --------------------------------------------------------- +// +void MsgStoreHandler::HandleClass0SmsL(CMsvEntry* aMsgEntry, TMsvId aMsgId) +{ + CleanupStack::PushL(aMsgEntry); + + CMsvStore* store = aMsgEntry->ReadStoreL(); + CleanupStack::PushL(store); + + CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL(); + CleanupStack::PushL(paraFormatLayer); + + CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL(); + CleanupStack::PushL(charFormatLayer); + + CRichText* richText = CRichText::NewL(paraFormatLayer, charFormatLayer); + CleanupStack::PushL(richText); + + store->RestoreBodyTextL(*richText); + + TInt len = richText->DocumentLength(); + HBufC* bufBody = HBufC::NewLC(len * 2); + + // Get Body content of SMS message + TPtr bufBodyPtr = bufBody->Des(); + richText->Extract(bufBodyPtr, 0, len); + + //convert bufbody to qstring.. + QString body = XQConversions::s60DescToQString(*bufBody); + + Class0Info class0Info; + + class0Info.body = body; + CleanupStack::PopAndDestroy(bufBody); + + // Get From address of SMS message + CPlainText* nullString = CPlainText::NewL(); + CleanupStack::PushL(nullString); + + CSmsHeader* smsheader = CSmsHeader::NewL(CSmsPDU::ESmsDeliver, *nullString); + CleanupStack::PushL(smsheader); + smsheader->RestoreL(*store); + + QString address = XQConversions::s60DescToQString(smsheader->FromAddress()); + class0Info.address = address; + + // Get alias of SMS message + QString alias; + int count; + MsgContactHandler::resolveContactDisplayName(address, alias, count); + class0Info.alias = alias; + + // Get timestamp of SMS message + QDateTime timeStamp; + TTime time = aMsgEntry->Entry().iDate; + TTime unixEpoch(KUnixEpoch); + TTimeIntervalSeconds seconds; + time.SecondsFrom(unixEpoch, seconds); + timeStamp.setTime_t(seconds.Int()); + + const QString times = timeStamp.toString("dd/MM/yy hh:mm ap"); + class0Info.time = times; + + class0Info.messageId = aMsgId; + CleanupStack::PopAndDestroy(7); + aMsgEntry = NULL; + + // Show the SMS message.. + iNotifier->ShowClass0Message(class0Info); +} + +// --------------------------------------------------------- +// MsgStoreHandler::HandleEntryEventL() +// --------------------------------------------------------- + +void MsgStoreHandler::HandleEntryEventL(TMsvEntryEvent aEvent, TAny* /*aArg1*/, TAny* /*aArg2*/, + TAny* /*aArg3*/) +{ + switch (aEvent) { + case EMsvChildrenChanged: + case EMsvDeletedChildren: + { + UpdateOutboxIndications(); + break; + } + default: + break; + + } +} + +// --------------------------------------------------------- +// UpdateOutboxIndications() +// Outgoing Pending message/messages +// --------------------------------------------------------- +void MsgStoreHandler::UpdateOutboxIndications() +{ + MsgInfo failedIndicatorData; + MsgInfo pendingIndicatorData; + + TInt err = KErrNone; + + TRAP(err, GetOutboxEntriesL(failedIndicatorData, pendingIndicatorData)); + + if (err == KErrNone) { + iNotifier->displayOutboxIndications(failedIndicatorData); + iNotifier->displayOutboxIndications(pendingIndicatorData); + } +} + +// --------------------------------------------------------- +// GetOutboxEntries() +// Outgoing Pending message/messages +// --------------------------------------------------------- +TInt MsgStoreHandler::GetOutboxEntriesL(MsgInfo& aFailedIndicatorData, + MsgInfo& aPendingIndicatorData) +{ + CMsvEntry* rootEntry = iMsvSession->GetEntryL(KMsvGlobalOutBoxIndexEntryId); + CMsvEntrySelection* messages = rootEntry->ChildrenL(); + + TInt failedMessageCount = 0; + TInt pendingMessageCount = 0; + + for (TInt i = 0; i < messages->Count(); ++i) { + TMsvEntry entry = rootEntry->ChildDataL(messages->At(i)); + if ((entry.iMtm != KSenduiMtmSmsUid) && (entry.iMtm != KSenduiMtmMmsUid)) { + continue; + } + + if (entry.SendingState() == KMsvSendStateFailed) { + ++failedMessageCount; + } + else { + ++pendingMessageCount; + } + + if (entry.SendingState() == KMsvSendStateFailed) { + ProcessIndicatorDataL(entry.Id(), aFailedIndicatorData); + } + else { + ProcessIndicatorDataL(entry.Id(), aPendingIndicatorData); + } + + } + + aFailedIndicatorData.mFromSingle = (failedMessageCount > 1) ? false : true; + aPendingIndicatorData.mFromSingle = (pendingMessageCount > 1) ? false : true; + aFailedIndicatorData.mIndicatorType = FailedIndicatorPlugin; + aPendingIndicatorData.mIndicatorType = PendingIndicatorPlugin; + aFailedIndicatorData.mMsgCount = failedMessageCount; + aPendingIndicatorData.mMsgCount = pendingMessageCount; + + return KErrNone; +} + +// --------------------------------------------------------- +// ProcessIndicatorData() +// Process the data in the MsgInfo object. +// --------------------------------------------------------- + +void MsgStoreHandler::ProcessIndicatorDataL(TMsvId msgId, MsgInfo& indicatorData) +{ + CCsClientConversation* conversation = iRequestHandler->GetConversationFromMessageIdL(msgId); + if (conversation == NULL) + return; + + indicatorData.mConversationId = conversation->GetConversationEntryId(); + CCsConversationEntry* convEntry = conversation->GetConversationEntry(); + + //check for valid data + if ((indicatorData.mConversationId == -1) || (convEntry == NULL)) { + delete conversation; + return; + } + + //set indicator data + HBufC* displayName = conversation->GetDisplayName(); + + if (displayName) { + indicatorData.mDisplayName.append(XQConversions::s60DescToQString(*displayName)); + } + else { + HBufC* number = convEntry->Contact(); + if (number) + indicatorData.mDisplayName.append(XQConversions::s60DescToQString(*number)); + } + delete conversation; +} + +// --------------------------------------------------------- +// GetUnreadMessageCountL() +// Get Unread message count. +// --------------------------------------------------------- + +int MsgStoreHandler::GetUnreadMessageCountL() +{ + //Create the query/operation object + CMsvSearchSortOperation *operation = CMsvSearchSortOperation::NewL(*iMsvSession); + CleanupStack::PushL(operation); + CMsvSearchSortQuery *query = CMsvSearchSortQuery::NewL(); + CleanupStack::PushL(query); + + //set the query options + query->SetParentId(KMsvGlobalInBoxIndexEntryId); + query->SetResultType(EMsvResultAsTMsvEntry); + query->AddSearchOptionL(EMsvUnreadMessages, ETrue); + CleanupStack::Pop(query); + + CMsvOperationWait* wait = CMsvOperationWait::NewLC(); + //ownership of Query transferred to Operation + operation->RequestL(query, EFalse, wait->iStatus); + wait->Start(); + CActiveScheduler::Start(); + + //Get No of entries + int count = operation->GetResultCountL(); + CleanupStack::PopAndDestroy(2, operation); + + return count; +} + +// --------------------------------------------------------- +// MsgStoreHandler::MmsNotificationStatus +// --------------------------------------------------------- +// +TCsMmsNotificationMsgState MsgStoreHandler:: +MmsNotificationStatus( TMsvEntry entry ) + { + TCsMmsNotificationMsgState status = EMsgStatusNull; + + // operationMask includes operation type. It is not bitmap but ordinal number. + // It does not include operation status and result + TInt operationMask = (entry.iMtmData2 & KMmsOperationIdentifier) ; + + // Note! Ongoing operation resets every bit of operation type, operation status + // and result. E.g. If message has been forwarded and then fetching starts, + // information about forwarding is lost + + if( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageMNotificationInd ) + { + if( operationMask == KMmsOperationFetch + && OperationOngoing( entry ) ) + { + // It's in retrieving state + status = EMsgStatusRetrieving; + } + else if( operationMask == KMmsOperationForward + && OperationOngoing( entry ) ) + { + // It's in forwarding state + status = EMsgStatusForwarding; + } + else if( operationMask == KMmsOperationForward + && OperationFinished( entry ) + && !( entry.iMtmData2 & KMmsOperationResult ) ) + { + // It's been forwarded succesfully + status = EMsgStatusForwarded; + } + else if( operationMask == KMmsOperationFetch + && OperationFinished( entry ) + && ( entry.iMtmData2 & KMmsOperationResult + || entry.iError ) ) + { + // Fetch has been failed + status = EMsgStatusFailed; + } + else if( operationMask == KMmsOperationDelete + && OperationFinished( entry ) + && !( entry.iMtmData2 & KMmsOperationResult ) ) + { + // It's been deleted succesfully + status = EMsgStatusDeleted; + } + else + { // Normal waiting state + status = EMsgStatusReadyForFetching; + } + } + + return status; + } + +// --------------------------------------------------------- +// MsgStoreHandler::OperationOngoing +// --------------------------------------------------------- +// +TBool MsgStoreHandler::OperationOngoing( const TMsvEntry& aEntry ) const + { + return ( aEntry.iMtmData2 & KMmsOperationOngoing + && !( aEntry.iMtmData2 & KMmsOperationFinished ) ); + } + +// --------------------------------------------------------- +// ConversationMsgStoreHandler::OperationFinished +// --------------------------------------------------------- +// +TBool MsgStoreHandler::OperationFinished( + const TMsvEntry& aEntry ) const + { + return ( aEntry.iMtmData2 & KMmsOperationFinished + && !( aEntry.iMtmData2 & KMmsOperationOngoing ) ); + } + +// End of file