--- /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 <xqconversions.h>
+#include "msgnotifier_p.h"
+#include <ccsrequesthandler.h>
+#include <ccsconversationentry.h>
+#include <ccsclientconversation.h>
+#include "msgcontacthandler.h"
+#include <msvids.h>
+#include <mmsconst.h>
+#include <smuthdr.h>
+#include <SendUiConsts.h>
+#include <msvsearchsortquery.h>
+#include <msvsearchsortoperation.h>
+#include <tmsvsmsentry.h>
+#include <txtrich.h>
+#include <ssm/ssmdomaindefs.h>
+#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<TMsvId> 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