--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/biomsgfw/BioWatchers/Src/NBSSocketWatcher.cpp Wed Nov 03 22:41:46 2010 +0530
@@ -0,0 +1,812 @@
+// Copyright (c) 1999-2009 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:
+// NBSocketWatcher.cpp
+//
+//
+
+#include "NBSSocketWatcher.h"
+#include "SmsSocketWatcher.h"
+
+#include <smuthdr.h>
+#include <msventry.h>
+#include <msvstd.h>
+#include <msvuids.h>
+#include <smut.h>
+#include <watcher.h>
+#include <smsuaddr.h>
+#include <gsmuelem.h>
+#include <gsmunonieoperations.h>
+#include <s32strm.h>
+#include <s32mem.h>
+#include <gsmubuf.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <tmsvsmsentry.h>
+#include "cwatcher.h"
+#endif
+
+const TInt KSmsWRetryTimer = 1000000 * 15; // 15 Secs
+
+/*
+ * CNbsSocketWatcher
+ */
+
+CNbsSmsSocketWatcher::CNbsSmsSocketWatcher(CWatcherLog& aWatcherLog, TInt aPriority, TUid aBioID, RFs& aFs, const TDesC& aNbsPattern, TSmsAddrFamily aAddrFamily)
+: CBaseSmsActiveSocketWatcher(aWatcherLog, aPriority, aBioID, aFs),
+ iAddrFamily(aAddrFamily),
+ iNbsPattern(aNbsPattern)
+ {
+ }
+
+CNbsSmsSocketWatcher::~CNbsSmsSocketWatcher()
+ {
+ Cancel();
+
+ if (iSocket.SubSessionHandle())
+ iSocket.Close();
+
+ if (iSocketServer.Handle())
+ iSocketServer.Close();
+
+ //destroying class 0 SMS E-Com pluin implementation
+ if (iSmsClass0 != NULL)
+ {
+ REComSession::DestroyedImplementation(iDtor_ID_Key);
+ REComSession::FinalClose();
+ delete iSmsClass0;
+ }
+ RProperty::Delete(KUidSystemCategory, KUidPSDiskSpaceMonitorKeyType);
+ }
+
+CNbsSmsSocketWatcher* CNbsSmsSocketWatcher::NewLC(TMsvId aBioServiceId,
+ TMsvId aSmsServiceId,
+ CBIODatabase& aBioDb,
+ CWatcherLog& aWatcherLog,
+ TInt aPriority,
+ TUid aBioID,
+ RFs& aFs,
+ const TDesC& aNbsPattern,
+ TSmsAddrFamily aAddrFamily /*= ESmsAddrMatchText*/)
+ {
+ CNbsSmsSocketWatcher* self = new(ELeave) CNbsSmsSocketWatcher(aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily);
+ CleanupStack::PushL(self);
+ self->ConstructL(aBioServiceId, aSmsServiceId, aBioDb);
+ return self;
+ }
+
+
+void CNbsSmsSocketWatcher::ConstructL(TMsvId aBioServiceId, TMsvId aSmsServiceId, CBIODatabase& aBioDb)
+ {
+ CBaseSmsActiveSocketWatcher::ConstructL(aBioDb, aBioServiceId, aSmsServiceId);
+ User::LeaveIfError(iSocketServer.Connect());
+ TSecurityPolicy readPolicy(ECapabilityReadDeviceData);
+ TSecurityPolicy writePolicy(ECapabilityWriteDeviceData);
+
+
+ TInt ret = RProperty::Define(KUidSystemCategory, KUidPSDiskSpaceMonitorKeyType,
+ RProperty::EInt, readPolicy, writePolicy);
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L(" Define return value %d"), ret));
+
+ if (ret != KErrNone && ret != KErrAlreadyExists)
+ {
+ User::Leave(ret);
+ }
+
+ TInt setRet = RProperty::Set(KUidSystemCategory, KUidPSDiskSpaceMonitorKeyType, ESmsDiskSpaceAvailable);
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L(" Set value %d"), setRet));
+
+ if (setRet != KErrNone)
+ {
+ User::Leave(setRet);
+ }
+ }
+
+void CNbsSmsSocketWatcher::DoCancel()
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: DoCancel")));
+ if (iIoCtlActive)
+ {
+ iSocket.CancelIoctl();
+ }
+
+ if(iTimer.Handle() != NULL)
+ iTimer.Cancel();
+
+ Complete(KErrCancel);
+ }
+
+void CNbsSmsSocketWatcher::DoRunL()
+ {
+ iIoCtlActive = EFalse;
+ switch(iState)
+ {
+ case ESmsWWaitForMsg:
+ iState = ESmsWReadMsg;
+ WaitForMessageL();
+ break;
+
+ case ESmsWReadMsg:
+ iState = ESmsWWaitForMsg;
+ ReceiveL();
+ break;
+
+ case ESmsWRetryError:
+ if (!iTimer.Handle())
+ {
+ User::LeaveIfError(iTimer.CreateLocal());
+ }
+
+ iState=ESmsWWaitForMsg;
+ iTimer.After(iStatus, KSmsWRetryTimer);
+ break;
+
+ case ESmsIsClass0Msg:
+ iState = ESmsSupportClass0Msg;
+ CheckForClass0SmsSupport();
+ break;
+
+ case ESmsSupportClass0Msg:
+ iState = ESmsWWaitForMsg;
+ SupportForClass0SmsL();
+ break;
+ }
+
+ SetActive();
+
+ }
+
+void CNbsSmsSocketWatcher::DoSetupL()
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: DoSetupL: %S"), &iBioMsgText));
+
+ // Set up the Socket to watch the port
+
+ // test if it's there...
+ TProtocolDesc protoInfo;
+ TProtocolName protocolname;
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: DoSetupL: Finding protocol")));
+
+ protocolname.Copy(KSmsDatagram);
+ User::LeaveIfError(iSocketServer.FindProtocol(protocolname,protoInfo));
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: DoSetupL: Opening socket")));
+
+ // Create the RSocket
+ User::LeaveIfError(iSocket.Open(iSocketServer,
+ protoInfo.iAddrFamily,
+ protoInfo.iSockType,
+ protoInfo.iProtocol));
+
+ // Set up the Socket to watch the pattern
+ if (iBioMsgUID != KNullUid && iAddrFamily == ESmsAddrMatchText)
+ {
+ // need an 8 bit pattern
+ TBuf8<KMaxBioIdText> pattern;
+ pattern.Copy(iNbsPattern);
+
+ iSmsAddr.SetSmsAddrFamily(ESmsAddrMatchText);
+ iSmsAddr.SetTextMatch(pattern);
+ }
+ else
+ {
+ // Binding to a non-patter address family
+ // like StatusReports, Special Messages, and RecieveAny
+ iSmsAddr.SetSmsAddrFamily(iAddrFamily);
+ }
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: DoSetupL: Binding socket")));
+
+ User::LeaveIfError(iSocket.Bind(iSmsAddr));
+ }
+
+void CNbsSmsSocketWatcher::DoComplete(TInt& rStatus)
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: DoComplete: %S, status %d"), &iBioMsgText, rStatus));
+
+ if (iSocket.SubSessionHandle())
+ {
+ iSocket.Close();
+ }
+ }
+
+void CNbsSmsSocketWatcher::WaitForMessageL()
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: WaitForMessageL: %S"), &iBioMsgText));
+ iOctlRes()= KSockSelectRead;
+ iIoCtlActive = ETrue;
+ iSocket.Ioctl(KIOctlSelect, iStatus, &iOctlRes, KSOLSocket);
+ }
+
+// CNbsSmsSocketWatcher::CheckForClass0SmsSupport to find out whether SMS stack is
+// configured for this new behaviour of class 0 message or not.
+void CNbsSmsSocketWatcher::CheckForClass0SmsSupport()
+ {
+ // Need verify SMS stack configuration, if type of socket address is ESmsAddrRecvAny only
+ if (iAddrFamily == ESmsAddrRecvAny)
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: CheckForClass0SmsSupport")));
+ iOctlRes()= KSockSelectRead;
+ iIoCtlActive = ETrue;
+ //iStatus will return KErrNone if stack supports new way of handling class 0 messages.
+ //Otherwise it will return KErrNotSupported.
+ iSocket.Ioctl(KIoctlSupportOODClass0SmsMessages, iStatus, NULL, KSolSmsProv);
+ }
+ else
+ {
+ //Change state to Wait For Message
+ iState = ESmsWWaitForMsg;
+ //Complete self to enter state machine
+ TRequestStatus* status = &iStatus;
+ iStatus=KRequestPending;
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+
+void CNbsSmsSocketWatcher::DoReceiveL()
+ {
+ // Get the Message
+ CSmsMessage* smsmessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, CSmsBuffer::NewL());
+ CleanupStack::PushL(smsmessage);
+
+ RSmsSocketReadStream readstream(iSocket);
+ readstream >> *smsmessage; //can leave
+
+ CleanupStack::Pop(smsmessage);
+
+ //get the class type here
+ TSmsDataCodingScheme::TSmsClass classType(TSmsDataCodingScheme::ESmsClass2);
+ const CSmsDeliver& deliver = static_cast<const CSmsDeliver&>(smsmessage->SmsPDU());
+ TBool classDefined = deliver.Class(classType);
+
+ //handling class 0 sms message
+ if(iSmsClass0 != NULL && classType == TSmsDataCodingScheme::ESmsClass0)
+ {
+ //destroy the CSmsMessage, once passed succesfully to Class0SMS plugin
+ CleanupStack::PushL(smsmessage);
+
+ //Externalize CSmsMessage into a TDesC8
+ CSmsBufferBase& convSmsMsg = smsmessage->Buffer();
+ TInt len = convSmsMsg.Length() ;
+
+ //for sending Incomplete MessageInfo to UI.
+ TInt startPos = 0;
+ TInt endPos = 0;
+ TBool isLastMessage = EFalse;
+
+ HBufC *buffer = HBufC::NewLC(len);
+ TPtr temp = buffer->Des();
+ convSmsMsg.Extract(temp, 0, len);
+
+ //allocate memory for CBufFlat, length sholud be: length of Class0SMS data + 2*(size of TInt)+(size of TBool)
+ CBufFlat* flat = CBufFlat::NewL(len + (3 * sizeof(TInt)));
+ CleanupStack::PushL(flat);
+ flat->ExpandL(0, len);
+
+ RBufWriteStream writeStream(*flat);
+ CleanupClosePushL (writeStream);
+
+ if (smsmessage->IsComplete())
+ {
+ //if it's complete class 0 SMS message
+ //passing startPos, endPos and isLastMessage value to 0
+ ExternalizeL(writeStream, startPos, endPos, isLastMessage, temp);
+ TPtr8 smsMsg(flat->Ptr(0));
+ iSmsClass0->DisplayMessageHandler(smsMsg, ETrue);
+ }
+ else
+ {
+ //handling incomplete SMS Message
+ CIncompleteClass0MessageInfo &incompleteMessageInfo = (CIncompleteClass0MessageInfo&)smsmessage->GetOperationsForNonIEL(ESmsIncompleteClass0MessageParameter);
+ TInt msgRefNo = smsmessage->SmsPDU().ConcatenatedMessageReference();
+
+ //get the information about the messsage & externalize it..
+ incompleteMessageInfo.GetIncompleteMessageInfoL(startPos, endPos, isLastMessage);
+ ExternalizeL(writeStream, startPos, endPos, isLastMessage, temp);
+ TPtr8 smsMsg(flat->Ptr(0));
+
+ if (iMsgRefNumber == -1 || iMsgRefNumber == msgRefNo)
+ {
+ //if it's 1st part of the Message, assign msgRefNo to iMsgRefNumber
+ if (iMsgRefNumber == -1)
+ {
+ iMsgRefNumber = msgRefNo;
+ }
+
+ iSmsClass0->DisplayMessageHandler(smsMsg, EFalse);
+
+ //if it's last part of the Message, assign iMsgRefNumber to -1
+ if (isLastMessage)
+ {
+ iMsgRefNumber = -1;
+ }
+ }
+ }
+ //delete smsmessage, as owned by header
+ CleanupStack::PopAndDestroy(4, smsmessage);
+ } //handling class 0 sms message
+
+ // If the message is delivered to an unknown port (as opposed to no port at all)
+ // then we should only store the message if it is a "TextMessage".
+ // Otherwise the message should be silently consumed without being delivered.
+ // This is a requirement of the Java "Mobile Service Architecture", JSR 248, section 6.11.3.2
+
+ else if ( iAddrFamily == ESmsAddrRecvAny // << This watcher is listening on an unknown port
+ && MessageHasPort(*smsmessage) // << The message is addressed to a specific port
+ && ! IsJavaTextMessage(*smsmessage) ) // << The message is defined by JSR 205 as NOT a TextMessage object
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: Non-text message delivered to unknown port - deleting message")));
+ }
+ else
+ {
+ StoreMsgL(smsmessage, ETrue); // Store the messaage and check for SID entry for ownership
+ }
+ }
+
+void CNbsSmsSocketWatcher::ReceiveL()
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: ReceiveL: %S"), &iBioMsgText));
+
+ TInt error;
+
+ switch (iStatus.Int())
+ {
+ case KErrNone:
+ {
+ TRAP(error, DoReceiveL());
+
+ // Tell the socket if we handled the message or not
+ if (error == KErrNone)
+ {
+ iIoCtlActive = ETrue;
+ iSocket.Ioctl(KIoctlReadMessageSucceeded, iStatus, NULL, KSolSmsProv);
+ }
+ else
+ {
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: Recv fail %d: %S"), error, &iBioMsgText));
+ iState = ESmsWRetryError;
+ iIoCtlActive = ETrue;
+ iSocket.Ioctl(KIoctlReadMessageFailed, iStatus, NULL, KSolSmsProv);
+ }
+ }
+ break;
+
+ case KIoctlSelectModemPresent:
+ // Enumerate to see it there are any messages when the phone's hooked up
+ // Only enumerate with default recievAny watcher
+ // this pattern watcher should do nothing
+ // SMS Prot should get the phone memory's SMS messages here
+ case KIoctlSelectModemNotPresent:
+ {
+ // Phone's disconnected ... wait in Ioctl again
+ // base class does this ... we're okay
+ TRequestStatus* pS=&iStatus;
+ User::RequestComplete(pS,0);
+ }
+ break;
+
+ default:
+ User::Leave(iStatus.Int());
+ }
+ }
+
+/**
+Returns whether the message contains optional port addressing information.
+@return ETrue if message contains port addressing information, otherwise EFalse.
+*/
+TBool CNbsSmsSocketWatcher::MessageHasPort(const CSmsMessage& aSmsMessage)
+ {
+ // Declare variables that will receive their values in ApplicationPortAddressing()
+ TInt destinationPort=0;
+ TInt originatorPort=0;
+ TBool is16bit=EFalse;
+ TBool hasPortAddressing = aSmsMessage.SmsPDU().ApplicationPortAddressing(destinationPort, originatorPort, &is16bit);
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: MessageHasPort()")));
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: > has:%d, dest:%d, orig:%d, 16bit:%d)"), hasPortAddressing, destinationPort, originatorPort, is16bit));
+
+ return hasPortAddressing;
+ }
+
+/**
+Check whether Discard Unknown Port message flag is set, if not check for Java wireless messaging.
+
+Returns whether the message is considered a TextMessage, according to Java wireless messaging
+specifications - JSR 205 "Wireless Messaging API" Appendix A.5.0 - which associates the TextMessage
+object with the 7-bit and 16-bit UCS-2 alphabets, and BinaryMessage with the 8-bit alphabet.
+@param aSmsMessage the message whose alphabet we are testing.
+@return ETrue if the alphabet is 7-bit or 16-bit UCS-2, otherwise EFalse.
+*/
+TBool CNbsSmsSocketWatcher::IsJavaTextMessage(const CSmsMessage& aSmsMessage)
+ {
+ TBool isTextMessage = EFalse;
+ if(!iSettings->DiscardUnknownPortMessage())
+ {
+ TSmsDataCodingScheme::TSmsAlphabet alphabet = aSmsMessage.SmsPDU().Alphabet();
+
+ if (alphabet == TSmsDataCodingScheme::ESmsAlphabet7Bit || alphabet == TSmsDataCodingScheme::ESmsAlphabetUCS2)
+ {
+ isTextMessage = ETrue;
+ }
+
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: IsJavaTextMessage()")));
+ BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: > isTextMessage:%d, alphabet:%d)"), isTextMessage, alphabet));
+ }
+
+ return isTextMessage;
+ }
+
+/*
+ * CSpecialNbsSmsSocketWatcher Implementation
+ */
+
+CSpecialNbsSmsSocketWatcher* CSpecialNbsSmsSocketWatcher::NewLC(
+ TMsvId aBioServiceId,
+ TMsvId aSmsServiceId,
+ CBIODatabase& aBioDb,
+ CWatcherLog& aWatcherLog,
+ TInt aPriority,
+ TUid aBioID,
+ RFs& aFs,
+ const TDesC& aNbsPattern,
+ TSmsAddrFamily aAddrFamily)
+ {
+ CSpecialNbsSmsSocketWatcher* self = new (ELeave) CSpecialNbsSmsSocketWatcher(aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily);
+ CleanupStack::PushL(self);
+ self->ConstructL(aBioServiceId, aSmsServiceId, aBioDb);
+ return self;
+ }
+
+CSpecialNbsSmsSocketWatcher* CSpecialNbsSmsSocketWatcher::NewL(
+ TMsvId aBioServiceId,
+ TMsvId aSmsServiceId,
+ CBIODatabase& aBioDb,
+ CWatcherLog& aWatcherLog,
+ TInt aPriority,
+ TUid aBioID,
+ RFs& aFs,
+ const TDesC& aNbsPattern,
+ TSmsAddrFamily aAddrFamily)
+ {
+ CSpecialNbsSmsSocketWatcher* self = NewLC(aBioServiceId, aSmsServiceId, aBioDb, aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CSpecialNbsSmsSocketWatcher::CSpecialNbsSmsSocketWatcher(CWatcherLog& aWatcherLog, TInt aPriority, TUid aBioID, RFs& aFs, const TBioMsgIdText& aNbsPattern, TSmsAddrFamily aAddrFamily)
+: CNbsSmsSocketWatcher(aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily)
+ {
+ }
+
+void CSpecialNbsSmsSocketWatcher::RestoreSettingsL(CMsvSession& aSession)
+ {
+ CBaseSmsActiveSocketWatcher::RestoreSettingsL(aSession);
+
+ switch(iAddrFamily)
+ {
+ case ESmsAddrMessageIndication:
+ iReportHandling = iSettings->SpecialMessageHandling();
+ break;
+ case ESmsAddrStatusReport:
+ iReportHandling = iSettings->StatusReportHandling();
+ break;
+ default:
+ PanicWatcher(EAddrFamilyNotSupported1);
+ break;
+ }
+ }
+
+void CSpecialNbsSmsSocketWatcher::RestoreSettingsL(TMsvId aBioServiceId, TMsvId aSmsServiceId)
+ {
+ CBaseSmsActiveSocketWatcher::RestoreSettingsL(aBioServiceId, aSmsServiceId);
+
+ switch(iAddrFamily)
+ {
+ case ESmsAddrMessageIndication:
+ iReportHandling = iSettings->SpecialMessageHandling();
+ break;
+ case ESmsAddrStatusReport:
+ iReportHandling = iSettings->StatusReportHandling();
+ break;
+ default:
+ PanicWatcher(EAddrFamilyNotSupported2);
+ break;
+ }
+ }
+
+void CSpecialNbsSmsSocketWatcher::ConstructL(TMsvId aBioServiceId, TMsvId aSmsServiceId, CBIODatabase& aBioDb)
+ {
+ CNbsSmsSocketWatcher::ConstructL(aBioServiceId, aSmsServiceId, aBioDb);
+
+ if (iReportHandling == CSmsSettings::EDoNotWatchForReport)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ }
+
+
+CSpecialNbsSmsSocketWatcher::~CSpecialNbsSmsSocketWatcher()
+ {
+ Cancel();
+ }
+
+void CSpecialNbsSmsSocketWatcher::SetBioMsgText(CBIODatabase& /*aBioDb*/)
+ {
+ switch(iAddrFamily)
+ {
+ case ESmsAddrMessageIndication:
+ iBioMsgText = _L("Special Messages");
+ break;
+ case ESmsAddrStatusReport:
+ iBioMsgText = _L("Status Report");
+ break;
+ default:
+ PanicWatcher(EAddrFamilyNotSupported3);
+ break;
+ }
+ }
+
+void CSpecialNbsSmsSocketWatcher::PreStoreActionL(CMsvSession& aSession, CSmsMessage& aSmsMessage)
+ {
+ if( iAddrFamily == ESmsAddrStatusReport &&
+ (iReportHandling == CSmsSettings::EMoveReportToInboxInvisibleAndMatch ||
+ iReportHandling == CSmsSettings::EMoveReportToInboxVisibleAndMatch ||
+ iReportHandling == CSmsSettings::EDiscardReportAndMatch) )
+ {
+ // This is a Status Report and the matching has been requested - so
+ // do the matching!
+ TLogId logId = aSmsMessage.LogServerId();
+ CSmsStatusReport& report = static_cast<CSmsStatusReport&>(aSmsMessage.SmsPDU());
+
+ MatchStatusReportL(aSession, logId, report.Status());
+ }
+ }
+
+void CSpecialNbsSmsSocketWatcher::MatchStatusReportL(CMsvSession& aSession, TLogId aLogId, TSmsStatus::TSmsStatusValue aDeliveryStatus)
+ {
+ // Need to check all SMS messages in the sent folder.
+ CMsvEntry* msvEntry = aSession.GetEntryL(KMsvSentEntryId);
+ CleanupStack::PushL(msvEntry);
+
+ CMsvEntrySelection* selSent = msvEntry->ChildrenWithMtmL(KUidMsgTypeSMS);
+ CleanupStack::PushL(selSent);
+
+ // Also need to check the Outbox - if the message failed to send at least
+ // one of its recipients then it will still be in the Outbox.
+ msvEntry->SetEntryL(KMsvGlobalOutBoxIndexEntryId);
+
+ CMsvEntrySelection* selOut = msvEntry->ChildrenWithMtmL(KUidMsgTypeSMS);
+ CleanupStack::PushL(selOut);
+
+ // Create a header object here for efficiency
+ CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL();
+ CleanupStack::PushL(paraFormatLayer);
+ CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL();
+ CleanupStack::PushL(charFormatLayer);
+ CRichText* richText = CRichText::NewL(paraFormatLayer,charFormatLayer);
+ CleanupStack::PushL(richText);
+
+ CSmsHeader* header = CSmsHeader::NewL(CSmsPDU::ESmsSubmit, *richText);
+ CleanupStack::PushL(header);
+
+ TMsvId messageId;
+ TBool found = SearchForMessageL(*msvEntry, *header, *selSent, aLogId, messageId);
+
+ if( !found )
+ {
+ // Search the outbox just in case it is still there.
+ found = SearchForMessageL(*msvEntry, *header, *selOut, aLogId, messageId);
+ }
+
+ if( found )
+ {
+ UpdateMessageEntryL(*msvEntry, *header, messageId, aLogId, aDeliveryStatus);
+ }
+
+ CleanupStack::PopAndDestroy(7, msvEntry);
+ }
+
+TBool CSpecialNbsSmsSocketWatcher::SearchForMessageL(CMsvEntry& aMsvEntry, CSmsHeader& aHeader, const CMsvEntrySelection& aSelection, TLogId aLogId, TMsvId& aMessageId)
+ {
+ TInt count = aSelection.Count();
+
+ if( count == 0 )
+ {
+ // Empty selection - cannot do search.
+ return EFalse;;
+ }
+
+ TBool found = EFalse;
+ while( !found && count-- > 0 )
+ {
+ aMsvEntry.SetEntryL(aSelection.At(count));
+ TMsvSmsEntry entry = aMsvEntry.Entry();
+
+ if( entry.AckSummary(ESmsAckTypeDelivery) == TMsvSmsEntry::EPendingAcks )
+ {
+ // This message is waiting for delivery report - is this it?
+ TLogId logId = 0;
+ TBool validId = entry.MessageId(logId);
+
+ if( validId )
+ {
+ // Check the logId is the one
+ if( aLogId == logId )
+ {
+ found = ETrue;
+ aMessageId = entry.Id();
+ }
+ }
+ else
+ {
+ // The long way round - restore the entry and search the list of
+ // recipients.
+ CMsvStore* store = aMsvEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+ aHeader.RestoreL(*store); // no need to restore message body
+ CleanupStack::PopAndDestroy(store);
+
+ TInt rcptCount = aHeader.Recipients().Count();
+
+ while( !found && rcptCount-- > 0 )
+ {
+ CSmsNumber& rcpt = *aHeader.Recipients()[rcptCount];
+
+ if( rcpt.AckStatus(ESmsAckTypeDelivery) == CSmsNumber::EPendingAck &&
+ rcpt.LogId() == aLogId )
+ {
+ found = ETrue;
+ aMessageId = entry.Id();
+ }
+ }
+ }
+ }
+ }
+ return found;
+ }
+
+void CSpecialNbsSmsSocketWatcher::UpdateMessageEntryL(CMsvEntry& aMsvEntry, CSmsHeader& aHeader, TMsvId aMessageId, TLogId aLogId, TSmsStatus::TSmsStatusValue aDeliveryStatus)
+ {
+ // Set the entry - probably not necessary...
+ aMsvEntry.SetEntryL(aMessageId);
+
+ // Update the message entry.
+ CMsvStore* store = aMsvEntry.EditStoreL();
+ CleanupStack::PushL(store);
+ aHeader.RestoreL(*store); // no need to restore message body
+
+ const TInt rcptCount = aHeader.Recipients().Count();
+ TInt pending = 0;
+ TInt fail = 0;
+ TInt last = 0;
+ TInt sent = 0;
+
+ for( TInt count = 0; count < rcptCount; ++count )
+ {
+ CSmsNumber& rcpt = *aHeader.Recipients()[count];
+
+ if( rcpt.Status() == CMsvRecipient::ESentSuccessfully )
+ {
+ ++sent;
+
+ CSmsNumber::TSmsAckStatus status = rcpt.AckStatus(ESmsAckTypeDelivery);
+ if( status == CSmsNumber::EPendingAck )
+ {
+ if( rcpt.LogId() == aLogId )
+ {
+ // Update the recipient with the delivery status.
+ if( aDeliveryStatus == TSmsStatus::ESmsShortMessageReceivedBySME )
+ rcpt.SetAckStatus(ESmsAckTypeDelivery, CSmsNumber::EAckSuccessful);
+ else
+ {
+ // Recipient failed to get the message :(
+ rcpt.SetAckStatus(ESmsAckTypeDelivery, CSmsNumber::EAckError);
+ rcpt.SetStatus(CMsvRecipient::EFailedToSend);
+ rcpt.SetError(aDeliveryStatus);
+ ++fail;
+ }
+ }
+ else
+ {
+ // This message has recipients waiting for status reports...
+ ++pending;
+ last = count; // index to last pending recipient.
+ }
+ }
+ else if( status == CSmsNumber::EAckError )
+ {
+ // There is a recipient that failed to get the message
+ ++fail;
+ }
+ }
+ }
+
+ // Store the updated recipient info
+ aHeader.StoreL(*store);
+ store->CommitL();
+ CleanupStack::PopAndDestroy(store);
+
+ // Update the delivery summary info in the index...
+ // 1. EPendingAcks - there are still recipients waiting for status reports.
+ // 2. EAllSuccessful - all recipients were delivered to successfully.
+ // 3. EAllFailed - all recipients failed to be delivered to.
+ // 4. EMixed - a mixture of successful and failed deliveries to the recipients.
+ TMsvSmsEntry entry = aMsvEntry.Entry();
+ if( pending == 0 )
+ {
+ // Cases 2, 3 or 4 - check how many failed.
+ if( fail == 0 )
+ {
+ // Case 2 - EAllSuccessful.
+ entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EAllSuccessful);
+ }
+ else if( fail < sent )
+ {
+ // Case 4 - EMixed.
+ entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EMixed);
+ }
+ else
+ {
+ // Case 3 - EAllFailed.
+ entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EAllFailed);
+ }
+ }
+ else
+ {
+ // Case 1 - EPendingAcks.
+ entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EPendingAcks);
+
+ if( (entry.iBioType == 0) && (pending == 1) )
+ {
+ // This message has only one pending recipient - update the entry to
+ // reflect this.
+ TLogId logId = aHeader.Recipients()[last]->LogId();
+ entry.SetMessageId(logId, ETrue);
+ }
+ }
+ aMsvEntry.ChangeL(entry);
+ }
+
+//SupportForClass0SmsL for launching the Class 0 SMS plugin, If Class 0 SMS support enabled from SMS Stack.
+void CNbsSmsSocketWatcher::SupportForClass0SmsL()
+ {
+ //if iStatus is KErrNotSupported, class 0 messages will be handled as normal Class2 messages
+ if( iStatus.Int() == KErrNone )
+ {
+ iMsgRefNumber = -1;
+
+ //launch class 0 sms plugin
+ iSmsClass0 = reinterpret_cast<CSmsClass0Base*>
+ (REComSession::CreateImplementationL(
+ KUidClass0SmsHandler,
+ _FOFF(CNbsSmsSocketWatcher ,iDtor_ID_Key)));
+
+ }
+
+ // Complete self to enter state machine
+ TRequestStatus* status = &iStatus;
+ iStatus=KRequestPending;
+ User::RequestComplete(status, KErrNone);
+ }
+
+
+//externalize start position, end position, isLastMessage flag and Class 0 SMS data,
+void CNbsSmsSocketWatcher::ExternalizeL(RBufWriteStream& aWriteStream, TInt aStartPos, TInt endPos, TBool aIsLastMessage, TPtr aData)
+ {
+ aWriteStream.WriteInt32L(aStartPos);
+ aWriteStream.WriteInt32L(endPos);
+ aWriteStream.WriteInt32L(aIsLastMessage);
+ aWriteStream << aData;
+ }