--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/smsmtm/servermtm/src/SmssSimUtils.cpp Fri Apr 16 14:56:15 2010 +0300
@@ -0,0 +1,1169 @@
+// Copyright (c) 2000-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:
+//
+
+#ifdef _DEBUG
+#undef _MSG_NO_LOGGING
+#endif
+
+#include <smutset.h>
+#include <txtrich.h>
+#include <smuthdr.h>
+#include <msventry.h>
+#include <msvuids.h>
+#include <mmlist.h>
+#include <smutsimparam.h>
+#include <biodb.h>
+#include <biouids.h>
+#include <csmsaccount.h>
+
+#include "SmssSimUtils.h"
+#include "SMSSPAN.H"
+
+//Logging constants
+
+#ifndef _MSG_NO_LOGGING
+_LIT(KDeleteFromSimLog, "DeleteFromSim.txt");
+_LIT(KEnumerateSimLog, "EnumerateSim.txt");
+_LIT(KCopyToSimLog, "CopyToSim.txt");
+#endif
+
+//CopyToSim constants
+
+
+CSmsSimUtils* CSmsSimUtils::NewL(CMsvServerEntry& aServerEntry, RFs& aFs, TMsvId aSmsServiceId)
+ {
+ CSmsSimUtils* self = new (ELeave) CSmsSimUtils(aServerEntry, aFs, aSmsServiceId);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CSmsSimUtils::ConstructL()
+ {
+ iSettings = CSmsSettings::NewL();
+
+ // load ECOM interface used to create SMS details and description values.
+ iGetDetDesc = CSmsGetDetDescInterface::NewL();
+ }
+
+CSmsSimUtils::~CSmsSimUtils()
+ {
+ Cancel();
+
+ iWriteStream.Close();
+ iReadStream.Close();
+
+ iSocket.Close();
+ iSocketServ.Close();
+
+ delete iSelection;
+ delete iCompletedSelection;
+
+ delete iHeader;
+ delete iBody;
+ delete iCharFormat;
+ delete iParaFormat;
+
+ delete iBioDb;
+ delete iSettings;
+
+ delete iGetDetDesc;
+ REComSession::FinalClose();
+ }
+
+void CSmsSimUtils::ReadSimParamsL(TRequestStatus& aStatus)
+/**
+ Reads the SMS parameters from the SIM
+
+ @since 7.0
+ @param aStatus Indicates the completion status of a request made to
+ a service provider.
+ @pre None
+ @post Starts the reading async operation.
+ */
+ {
+ SMSSLOG(FLogFormat(_L8("Reading SMS SIM Parameters")));
+
+ Queue(aStatus);
+
+ iProgress = TSmsProgress();
+ iProgress.iType = TSmsProgress::ESmsProgressTypeReadSimParams;
+
+ ConnectL();
+
+ iSocket.Ioctl(KIoctlReadSmsParams, iStatus, NULL, KSolSmsProv);
+
+ SetActive();
+ iReadingSimParams = ETrue;
+ }
+
+void CSmsSimUtils::WriteSimParamsL(TRequestStatus& aStatus)
+/**
+ Writes the SMS parameters to the SIM
+
+ @since 7.0
+ @param aStatus
+ @pre The parameters are stored in the message store.
+ @post The parameters are retrived form the message store and the writing
+ async operation is started.
+ */
+ {
+ SMSSLOG(FLogFormat(_L8("Writing SMS SIM Parameters")));
+
+ Queue(aStatus);
+
+ iProgress = TSmsProgress();
+ iProgress.iType = TSmsProgress::ESmsProgressTypeWriteSimParams;
+
+ CMobilePhoneSmspList* smspList = CMobilePhoneSmspList::NewL();
+ CleanupStack::PushL(smspList);
+
+ User::LeaveIfError(iServerEntry.SetEntry(iSmsServiceId));
+
+ CMsvStore* store = iServerEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+
+ CSmsSimParamOperation::RestoreSimParamsL(*store, *smspList);
+
+ TInt count = 0;
+ count = smspList->Enumerate();
+
+ if (!count)
+ User::Leave(KErrNotFound);
+
+ ConnectL();
+
+ iWriteStream << *smspList;
+ iWriteStream.CommitL();
+
+ CleanupStack::PopAndDestroy(2); //smspList, store
+ User::LeaveIfError(iServerEntry.SetEntry(KMsvNullIndexEntryId));
+
+ iSocket.Ioctl(KIoctlWriteSmsParams, iStatus, NULL, KSolSmsProv);
+
+ SetActive();
+ }
+
+void CSmsSimUtils::EnumerateL(const TDesC8& aParameter, TRequestStatus& aStatus)
+ {
+ SMSSLOG(FLogFormat(_L8("Enumerate messages in SIM [param=%d]"), aParameter.Length()));
+
+ //Enumerate messages on the SIM.
+ //First obtains a count of messages on the SIM.
+
+ Queue(aStatus);
+ iProgress = TSmsProgress();
+ iProgress.iType = TSmsProgress::ESmsProgressTypeEnumeratingPhoneStores;
+
+ ConstructHeaderAndBodyL();
+ SetAndCleanEnumerateFolderL(aParameter);
+ SMSSLOG(FLogFormat(_L8("\tUsing folder %d"), iProgress.iEnumerateFolder, aParameter.Length()));
+
+ //Obtain a count of the messages on the SIM
+ CountMessagesInPhoneStoresL();
+ }
+
+void CSmsSimUtils::SetAndCleanEnumerateFolderL(const TDesC8& aParameter)
+/**
+ *
+ *
+ * @param aParameter Optionally contains the ID of the folder to store the phone store messages
+ */
+ {
+ iProgress.iEnumerateFolder = KErrNotFound;
+
+ //Restore the iSimUtilsData.
+ //This should be moved to a more general ContructL() if other functions other than EnumerateL() need to use this data
+ RestoreSimUtilsDataL();
+
+ //Delete messages under the last folder used to store phone-side messages
+ const TInt err = iServerEntry.SetEntry(iSimUtilsData.iLastEnumerateFolder);
+ if (err == KErrNotFound)
+ {
+ iSimUtilsData.iLastEnumerateFolder = KErrNotFound;
+ }
+ else
+ {
+ //Clean the last folder used to store phone-side messages
+ User::LeaveIfError(err);
+ DeleteChildrenL(iSimUtilsData.iLastEnumerateFolder);
+ }
+
+ if (aParameter.Length() != 0)
+ {
+ //Use the TMsvId packaged in aParameter as the folder in which to store phone-side messages
+ TPckgC<TMsvId> enumFolder(KErrNotFound);
+ enumFolder.Set(aParameter);
+ iProgress.iEnumerateFolder = enumFolder();
+ SMSSLOG(FLogFormat(_L8("\tAsked to use folder %d [last=%d]"), iProgress.iEnumerateFolder, iSimUtilsData.iLastEnumerateFolder));
+
+ switch (iProgress.iEnumerateFolder)
+ {
+ case KMsvRootIndexEntryId:
+ case KMsvLocalServiceIndexEntryId:
+ case KMsvGlobalInBoxIndexEntryId:
+ case KMsvGlobalOutBoxIndexEntryId:
+ case KMsvDraftEntryId:
+ case KMsvSentEntryId:
+ User::Leave(KErrArgument); //cannot store phone-side messages under a standard folder
+ break;
+ default:
+ break;
+ }
+
+ //Check the folder exists and delete all its children
+ User::LeaveIfError(iServerEntry.SetEntry(iProgress.iEnumerateFolder));
+ DeleteChildrenL(iProgress.iEnumerateFolder);
+ }
+ else
+ {
+ //else use the last folder used to store phone-side messages
+ iProgress.iEnumerateFolder = iSimUtilsData.iLastEnumerateFolder;
+ }
+
+ if (iProgress.iEnumerateFolder == KErrNotFound)
+ {
+ //Create a new folder if last is not found AND aParameter,Length() == 0
+ //Note: CreateNewEnumerateFolderL() sets iSimUtilsData.iLastEnumerateFolder
+ iProgress.iEnumerateFolder = CreateNewEnumerateFolderL();
+ }
+
+ if (iProgress.iEnumerateFolder != iSimUtilsData.iLastEnumerateFolder)
+ {
+ //Delete the last enumerate folder if it is under the SMS service
+ DeleteEnumerateFolderL(iSimUtilsData.iLastEnumerateFolder);
+
+ //Store the enumerate folder for next time
+ iSimUtilsData.iLastEnumerateFolder = iProgress.iEnumerateFolder;
+ StoreSimUtilsDataL();
+ }
+ }
+
+void CSmsSimUtils::DeleteEnumerateFolderL(TMsvId aId)
+/**
+ * Deletes entry aId if its parent is iSmsServiceId
+ */
+ {
+ SMSSLOG(FLogFormat(_L8("\tAttempting to delete enumerate folder %d"), aId));
+ const TInt err = iServerEntry.SetEntry(aId);
+
+ if (err != KErrNotFound)
+ {
+ User::LeaveIfError(aId);
+
+ if (iServerEntry.Entry().Parent() == iSmsServiceId)
+ {
+ SMSSLOG(FLogFormat(_L8("\tDeleting enumerate folder %d"), aId));
+ User::LeaveIfError(iServerEntry.SetEntry(iSmsServiceId));
+ User::LeaveIfError(iServerEntry.DeleteEntry(aId));
+ }
+ }
+ }
+
+void CSmsSimUtils::DeleteChildrenL(TMsvId aId)
+/**
+ * Deletes all messages under parent aId
+ */
+ {
+ SMSSLOG(FLogFormat(_L8("\tDeleting children from %d"), aId));
+
+ User::LeaveIfError(iServerEntry.SetEntry(aId));
+
+ TMsvSelectionOrdering order;
+ order.SetShowInvisibleEntries(ETrue);
+ iServerEntry.SetSort(order);
+
+ CMsvEntrySelection* sel = new (ELeave) CMsvEntrySelection();
+ CleanupStack::PushL(sel);
+ User::LeaveIfError(iServerEntry.GetChildren(*sel));
+
+ if (sel->Count() != 0)
+ {
+ User::LeaveIfError(iServerEntry.DeleteEntries(*sel));
+ }
+
+ CleanupStack::PopAndDestroy(sel);
+ }
+
+TMsvId CSmsSimUtils::CreateNewEnumerateFolderL()
+/**
+ * Creates a new folder under the SMS service where phone-side messages will be stored
+ * iSimUtilsData.iLastEnumerateFolder is set to the new folder's ID then stored against the SMS service
+ *
+ * @return the new folder's ID
+ */
+ {
+ SMSSLOG(FLogFormat(_L8("\tCreating new folder...")));
+ User::LeaveIfError(iServerEntry.SetEntry(iSmsServiceId));
+
+ TMsvEntry entry;
+
+ //Create a new invisible folder under the local service
+ entry.SetVisible(EFalse);
+ entry.iType = KUidMsvFolderEntry;
+ entry.iMtm = KUidMsgTypeSMS;
+ entry.iServiceId = iSmsServiceId;
+ User::LeaveIfError(iServerEntry.CreateEntry(entry));
+ iSimUtilsData.iLastEnumerateFolder = entry.Id();
+
+ TRAPD(err, StoreSimUtilsDataL());
+
+ if (err != KErrNone)
+ {
+ iServerEntry.DeleteEntry(entry.Id()); //remove the folder if StoreSimUtilsDataL() leaves
+ User::Leave(err);
+ }
+
+ return iSimUtilsData.iLastEnumerateFolder;
+ }
+
+void CSmsSimUtils::CountMessagesInPhoneStoresL()
+ {
+ SMSSLOG(FLogFormat(_L8("\tCounting Messages on SIM. Calling Ioctl KIoctlEnumerateSmsMessages")));
+
+ User::LeaveIfError(iServerEntry.SetEntry(KMsvNullIndexEntryId));
+ ConnectL();
+ CreateBioDbL();
+ iSocket.Ioctl(KIoctlEnumerateSmsMessages, iStatus, &iEnumerateCountBuf, KSolSmsProv);
+ SetActive();
+ }
+
+void CSmsSimUtils::CreateBioDbL()
+ {
+ if (iBioDb == NULL)
+ iBioDb = CBIODatabase::NewL(iFs);
+ }
+
+TBool CSmsSimUtils::GetDefaultSendBearerL(TInt aBioType, TBioMsgIdType aBearer, TBioMsgId& rBioMsgId) const
+ {
+ TInt index = 0;
+ TUid uid;
+ uid.iUid = aBioType;
+ TBool found = EFalse;
+ TRAPD(ret,iBioDb->GetBioIndexWithMsgIDL(uid, index)); //leaves with KErrNotFound if aBioType does not exist in bdb
+ if (ret==KErrNone)
+ {
+ const CArrayFix<TBioMsgId>* bioIDs = iBioDb->BIOEntryLC(index);
+ const TInt count = bioIDs->Count();
+
+ for (TInt i = 0; !found && i < count; i++) //order important
+ {
+ rBioMsgId = bioIDs->At(i);
+ found = (rBioMsgId.iType == aBearer);
+ }
+
+ CleanupStack::PopAndDestroy(); // bioIDs
+ }
+ else if (ret!=KErrNotFound)
+ User::LeaveIfError(ret);
+ return found;
+ }
+
+TUid CSmsSimUtils::DecodeBioMessageL(TBioMsgId& rId)
+ {
+ TUid biomsguid=KNullUid;
+ rId.iType=EBioMsgIdNbs;
+ // Take text off front of message
+ CSmsMessage& smsmessage=iHeader->Message();
+ const TInt length=smsmessage.Buffer().Length();
+ smsmessage.Buffer().Extract(rId.iText,0,length<KMaxBioIdText? length: KMaxBioIdText);
+ TInt originator;
+ TInt destination;
+ // Has the message got application port addressing?
+ if (smsmessage.SmsPDU().ApplicationPortAddressing(destination,originator))
+ {
+ rId.iPort=STATIC_CAST(TUint16,destination);
+ rId.iType=EBioMsgIdWap;
+ // Is it WAP?
+ if (iBioDb->IsBioMessageL(rId,biomsguid)==KErrNotFound)
+ {
+ rId.iType=EBioMsgIdWapSecure;
+ // Is it WAP secure?
+ if (iBioDb->IsBioMessageL(rId,biomsguid)==KErrNotFound)
+ {
+ rId.iType=EBioMsgIdWsp;
+ // Is it WSP?
+ if(iBioDb->IsBioMessageL(rId,biomsguid)==KErrNotFound)
+ {
+ rId.iType=EBioMsgIdWspSecure;
+ // Is it WSP secure?
+ iBioDb->IsBioMessageL(rId,biomsguid);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Is it an NBS style text message?
+ TInt index=rId.iText.Locate('\r');
+ if (index==KErrNotFound)
+ index=rId.iText.Locate('\n');
+ // Look for text match in BIO database
+ if ((index>0) && (iBioDb->IsBioMessageL(EBioMsgIdNbs,rId.iText.Left(index),0,biomsguid) != KErrNotFound))
+ smsmessage.Buffer().DeleteL(0,index+1); // Remove BIO text
+ }
+ iHeader->SetBioMsgIdType(rId.iType);
+ return biomsguid;
+ }
+
+void CSmsSimUtils::EncodeBioMessageL()
+ {
+ CSmsMessage& smsmessage=iHeader->Message();
+ TBioMsgId bioMsgId;
+ // Is it a BIO message?
+ if (GetDefaultSendBearerL(iServerEntry.Entry().iBioType, iHeader->BioMsgIdType(), bioMsgId))
+ {
+ switch (bioMsgId.iType)
+ {
+ case EBioMsgIdNbs:
+ {
+ // Put text on NBS message
+ TBioMsgIdText text;
+ CSmsBufferBase& buffer=smsmessage.Buffer();
+ TInt textlength=bioMsgId.iText.Length();
+ buffer.Extract(text,0,textlength<buffer.Length()? textlength: 0);
+ if (bioMsgId.iText.CompareF(text))
+ {
+ _LIT(KSmsNewLine,"\n");
+ buffer.InsertL(0,KSmsNewLine);
+ buffer.InsertL(0,bioMsgId.iText);
+ }
+ break;
+ }
+ case EBioMsgIdWap:
+ case EBioMsgIdWapSecure:
+ case EBioMsgIdWsp:
+ case EBioMsgIdWspSecure:
+ {
+ // Put port addressing on binary messages
+ smsmessage.SmsPDU().SetApplicationPortAddressingL(ETrue,bioMsgId.iPort,bioMsgId.iPort,bioMsgId.iPort>255);
+ smsmessage.SmsPDU().SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet8Bit);
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+void CSmsSimUtils::SetupMoveDeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
+ {
+ __ASSERT_DEBUG(aSelection.Count(), Panic(KSmssPanicNoMessagesInSelection));
+
+ Queue(aStatus);
+ iProgress = TSmsProgress();
+
+ if (iSelection != &aSelection)
+ {
+ delete iSelection;
+ iSelection = NULL;
+ iSelection = aSelection.CopyL();
+ iSelection->Delete(0); // Remove the SMS service entry id
+ }
+
+ iProgress.iMsgCount = iSelection->Count();
+ }
+
+void CSmsSimUtils::DeleteEachMessageFromPhoneStoreL()
+ {
+ iState = ESimUtilsStateOther;
+
+ if (iProgress.iMsgDone < iProgress.iMsgCount)
+ {
+ ConstructHeaderAndBodyL();
+
+ const TMsvId id = iSelection->At(iProgress.iMsgDone);
+ const TInt err = iServerEntry.SetEntry(id);
+
+ if (err == KErrNone)
+ {
+ CMsvStore* store = iServerEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+
+ store->RestoreBodyTextL(*iBody);
+ iHeader->RestoreL(*store);
+ CleanupStack::PopAndDestroy(); //store
+
+ iProgress.iError = KErrNone;
+
+ SMSSLOG(FLogMessage(iServerEntry.Entry(), iHeader->Message(), iHeader->BioMsgIdType(), KDeleteFromSimLog));
+ SMSSLOG(FLogFormat(_L8("\tDeleting %d from SIM (%d/%d)"), id, iProgress.iMsgDone+1, iProgress.iMsgCount));
+
+ iWriteStream << iHeader->Message();
+ iWriteStream.CommitL();
+ iSocket.Ioctl(KIoctlDeleteSmsMessage, iStatus, NULL, KSolSmsProv);
+ iState = ESimUtilsDeleteEachMessage;
+ }
+ else
+ {
+ SMSSLOG(FLogFormat(_L8("\tIgnoring %d, Error=%d"), id, err));
+ RequestComplete(&iStatus, KErrNone);
+ }
+
+ SetActive();
+ iProgress.iMsgDone++;
+ User::LeaveIfError(iServerEntry.SetEntry(KMsvNullIndexEntryId));
+ }
+ else
+ {
+ iState = ESimUtilsDeletedLastMessage;
+ }
+ }
+
+void CSmsSimUtils::ConstructHeaderAndBodyL()
+ {
+ if (!iParaFormat)
+ iParaFormat = CParaFormatLayer::NewL();
+
+ if (!iCharFormat)
+ iCharFormat = CCharFormatLayer::NewL();
+
+ if (!iBody)
+ iBody = CRichText::NewL(iParaFormat, iCharFormat);
+
+ if (!iHeader)
+ iHeader = CSmsHeader::NewL(CSmsPDU::ESmsDeliver, *iBody);
+ }
+
+void CSmsSimUtils::RestoreSimUtilsDataL()
+/**
+ * Restore iSimUtilsData from the SMS service entry
+ * Does not attempt to restore if the stream is not present
+ */
+ {
+ User::LeaveIfError(iServerEntry.SetEntry(iSmsServiceId));
+ CMsvStore* store = iServerEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+
+ if (iSimUtilsData.IsPresentL(*store))
+ {
+ iSimUtilsData.RestoreL(*store);
+ }
+
+ CleanupStack::PopAndDestroy(store);
+ }
+
+void CSmsSimUtils::StoreSimUtilsDataL()
+/**
+ * Store iSimUtilsData against the SMS service entry
+ */
+ {
+ User::LeaveIfError(iServerEntry.SetEntry(iSmsServiceId));
+ CMsvStore* store = iServerEntry.EditStoreL();
+ CleanupStack::PushL(store);
+ iSimUtilsData.StoreL(*store);
+ store->CommitL();
+ CleanupStack::PopAndDestroy(store);
+ }
+
+void CSmsSimUtils::DeleteFromPhoneStoreL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
+ {
+ SMSSLOG(FLogFormat(_L8("Deleting %d messages from SIM"), aSelection.Count()));
+
+ SetupMoveDeleteL(aSelection, aStatus);
+ DoDeleteFromPhoneStoreL();
+ }
+
+void CSmsSimUtils::DoDeleteFromPhoneStoreL()
+ {
+ iProgress.iType = TSmsProgress::ESmsProgressTypeDeleteFromPhoneStore;
+
+ ConnectL();
+ RequestComplete(&iStatus, KErrNone, ETrue);
+ }
+
+void CSmsSimUtils::DoDeleteThenMoveFromPhoneStoreL()
+ {
+ iProgress.iType = TSmsProgress::ESmsProgressTypeMoveFromPhoneStore;
+
+ ConnectL();
+ RequestComplete(&iStatus, KErrNone, ETrue);
+ }
+
+void CSmsSimUtils::LoadClass2FolderIdL()
+ {
+ RestoreSmsSettingsL();
+ iClass2Folder = iSettings->Class2Folder();
+ }
+
+void CSmsSimUtils::RestoreSmsSettingsL()
+ {
+ CSmsAccount* account = CSmsAccount::NewLC();
+ // just v2
+ account->LoadSettingsL(*iSettings);
+ CleanupStack::PopAndDestroy(account);
+ }
+
+void CSmsSimUtils::CopyToPhoneStoreL(const CMsvEntrySelection& aSelection, const TDesC8& /*aParameter*/, TRequestStatus& aStatus)
+ {
+ SMSSLOG(FLogFormat(_L8("Copying messages to SIM")));
+
+ __ASSERT_DEBUG(aSelection.Count(), Panic(KSmssPanicNoMessagesInSelection));
+
+ SetupMoveDeleteL(aSelection,aStatus);
+ iProgress.iType = TSmsProgress::ESmsProgressTypeCopyToPhoneStore;
+ iProgress.iMsgCount = iSelection->Count();
+ iProgress.iMsgDone = -1;
+ iState=EWritingToSIM;
+ iRecipientCount = 0;
+ iRecipientIndex = 0;
+
+ LoadClass2FolderIdL();
+
+ ConnectL();
+ ConstructHeaderAndBodyL();
+ CreateBioDbL();
+
+ DoCopyToPhoneStoreL();
+ }
+
+void CSmsSimUtils::MoveToPhoneStoreL(const CMsvEntrySelection& aSelection, const TDesC8& /*aParameter*/, TRequestStatus& aStatus)
+ {
+ SMSSLOG(FLogFormat(_L8("Moving messages to SIM")));
+
+ __ASSERT_DEBUG(aSelection.Count(), Panic(KSmssPanicNoMessagesInSelection));
+
+ SetupMoveDeleteL(aSelection,aStatus);
+ iProgress.iType = TSmsProgress::ESmsProgressTypeMoveToPhoneStore;
+ iProgress.iMsgCount = iSelection->Count();
+ iProgress.iMsgDone = -1;
+ iState=EWritingToSIM;
+ iRecipientCount = 0;
+ iRecipientIndex = 0;
+
+ LoadClass2FolderIdL();
+
+ ConnectL();
+ ConstructHeaderAndBodyL();
+ CreateBioDbL();
+
+ DoCopyToPhoneStoreL();
+ }
+
+
+void CSmsSimUtils::DoCopyToPhoneStoreL()
+ {
+ User::LeaveIfError(iServerEntry.SetEntry(KMsvNullIndexEntryId));
+ if(iState==EWritingToSIM)
+ {
+ if (iRecipientCount == 0)
+ ++iProgress.iMsgDone;
+
+ if (iProgress.iMsgDone < iProgress.iMsgCount)
+ {
+ User::LeaveIfError(iServerEntry.SetEntry(iSelection->At(iProgress.iMsgDone)));
+
+ CMsvStore* store = iServerEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+
+ iHeader->RestoreL(*store);
+ iBody->Reset();
+ store->RestoreBodyTextL(*iBody);
+
+ CleanupStack::PopAndDestroy(); //store
+
+ // Set correct address on the CSmsMessage if it out going
+ CSmsMessage& smsmessage=iHeader->Message();
+ if (smsmessage.Type()==CSmsPDU::ESmsSubmit || (smsmessage.Type()==CSmsPDU::ESmsCommand))
+ {
+ // Get the count of recipients for the current message
+ if (iRecipientCount == 0)
+ {
+ iRecipientCount = iHeader->Recipients().Count();
+ iRecipientIndex = 0;
+ }
+ // Create separate copy of message for each recipient
+ if (iRecipientCount > 0)
+ {
+ CSmsNumber& rcpt = *iHeader->Recipients().At(iRecipientIndex);
+ iHeader->Message().SetToFromAddressL(rcpt.Address());
+ }
+ ++iRecipientIndex;
+ // Check if all the recipients are processed
+ if (iRecipientIndex >= iRecipientCount)
+ {
+ // Yes all are done
+ iRecipientIndex = 0;
+ iRecipientCount = 0;
+ }
+ }
+ SMSSLOG(FLogMessage(iServerEntry.Entry(), iHeader->Message(), iHeader->BioMsgIdType(), KCopyToSimLog));
+
+ smsmessage.SetStorage(CSmsMessage::ESmsSIMStorage); //Set to store on SIM
+
+ if (iServerEntry.Entry().Unread())
+ {
+ smsmessage.SetStatus(NMobileSmsStore::EStoredMessageUnread);
+ }
+ else
+ {
+ smsmessage.SetStatus(NMobileSmsStore::EStoredMessageRead);
+ }
+
+ // This may be a BIO message, so test and set up SMS message correctly!
+ if ((smsmessage.Type()==CSmsPDU::ESmsSubmit) || (smsmessage.Type()==CSmsPDU::ESmsDeliver))
+ EncodeBioMessageL();
+
+ iWriteStream << iHeader->Message();
+ iWriteStream.CommitL();
+ iSocket.Ioctl(KIoctlWriteSmsMessage, iStatus, &iSlotBuffer, KSolSmsProv);
+ SetActive();
+
+ // if we have a class 2 folder, and its not the current parent
+ // then update the class 2 folder with the new message one the sim
+ if(iClass2Folder!=KMsvNullIndexEntryId &&
+ iClass2Folder != iServerEntry.Entry().Parent())
+ iState=EUpdatingClass2;
+ else
+ iState=EWritingToSIM;
+ }
+ }
+ else
+ {
+ __ASSERT_DEBUG(iState==EUpdatingClass2,Panic(ESmssBadState));
+ __ASSERT_DEBUG(iClass2Folder!=KMsvNullIndexEntryId,Panic(ESmssNoClass2Folder));
+ TMsvId toCopy=iSelection->At(iProgress.iMsgDone);
+ User::LeaveIfError(iServerEntry.SetEntry(toCopy));
+
+ // Update the slot array of the CSmsMessage so that
+ // it can be deleted at a later time without the need for a re-enumeration
+ TMsvEntry entry = iServerEntry.Entry();
+ TBool wasReadOnly = entry.ReadOnly();
+
+ if (wasReadOnly)
+ {
+ entry.SetReadOnly(EFalse);
+ iServerEntry.ChangeEntry(entry);
+ }
+
+ CMsvStore* store = iServerEntry.EditStoreL();
+ CleanupStack::PushL(store);
+ iHeader->RestoreL(*store);
+ CSmsMessage& smsmessage=iHeader->Message();
+
+ smsmessage.UpdateSlotsL(iSlotBuffer);
+ smsmessage.SetStorage(CSmsMessage::ESmsSIMStorage);
+ iHeader->StoreL(*store);
+ store->CommitL();
+
+ if (wasReadOnly)
+ {
+ entry.SetReadOnly(ETrue);
+ iServerEntry.ChangeEntry(entry);
+ }
+
+ CleanupStack::PopAndDestroy(store);
+ User::LeaveIfError(iServerEntry.SetEntry(iServerEntry.Entry().Parent()));
+
+ if(iProgress.iType == TSmsProgress::ESmsProgressTypeMoveToPhoneStore)
+ iServerEntry.MoveEntryL(toCopy,iClass2Folder,iStatus);
+ else
+ iServerEntry.CopyEntryL(toCopy,iClass2Folder,iStatus);
+
+ SetActive();
+ iState=EWritingToSIM;
+ }
+ }
+
+void CSmsSimUtils::CopyFromPhoneStoreL(const CMsvEntrySelection& aSelection, const TDesC8& aParameter, TRequestStatus& aStatus)
+ {
+ SMSSLOG(FLogFormat(_L8("Copying messages from phone store")));
+ __ASSERT_DEBUG(aSelection.Count(), Panic(KSmssPanicNoMessagesInSelection));
+
+ SetupMoveDeleteL(aSelection, aStatus);
+ iProgress.iType = TSmsProgress::ESmsProgressTypeCopyFromPhoneStore;
+ SetDestination(aParameter);
+ MoveEntriesL(*iSelection, ETrue);
+ }
+
+void CSmsSimUtils::MoveEntriesL(const CMsvEntrySelection& aSelection, TBool aCopy)
+ {
+ // Uses the enumeration folder under the service to copy from
+ User::LeaveIfError(iServerEntry.SetEntry(aSelection[0]));
+ User::LeaveIfError(iServerEntry.SetEntry(iServerEntry.Entry().Parent()));
+ if (aCopy)
+ {
+ if (iCompletedSelection)
+ iCompletedSelection->Reset();
+ else
+ iCompletedSelection = new(ELeave) CMsvEntrySelection;
+
+ iServerEntry.CopyEntriesL(aSelection, iDestination, *iCompletedSelection, iStatus);
+ }
+ else
+ iServerEntry.MoveEntriesL(aSelection, iDestination, iStatus);
+ SetActive();
+ }
+
+void CSmsSimUtils::MoveFromPhoneStoreL(const CMsvEntrySelection& aSelection, const TDesC8& aParameter, TRequestStatus& aStatus)
+ {
+ SMSSLOG(FLogFormat(_L8("Moving messages from phone store")));
+ __ASSERT_DEBUG(aSelection.Count(), Panic(KSmssPanicNoMessagesInSelection));
+
+ SetupMoveDeleteL(aSelection, aStatus);
+ iProgress.iType = TSmsProgress::ESmsProgressTypeMoveFromPhoneStore;
+ SetDestination(aParameter);
+
+ DoDeleteThenMoveFromPhoneStoreL();
+ }
+
+void CSmsSimUtils::SetDestination(const TDesC8& aParameter)
+ {
+ TPckgBuf<TMsvId> pkg;
+ pkg.Copy(aParameter);
+ iDestination = pkg();
+ __ASSERT_DEBUG(iDestination, Panic(KSmssPanicDestinationFolderNotSet));
+ }
+
+void CSmsSimUtils::SetLocalStorageInfoL(const CMsvEntrySelection& aSelection)
+ {
+ // After a copy/move from phone store the iSlotArray and Storage members
+ // need to be reset to reflect the local storage.
+ __ASSERT_DEBUG(aSelection.Count(), Panic(KSmssPanicNoMessagesInSelection));
+ TInt count = aSelection.Count();
+ ConstructHeaderAndBodyL();
+ TBool wasReadOnly = EFalse;
+
+ while (count--)
+ {
+ // RetrieveMessageFromPhoneStoreL() may have set the TMsvEntry
+ // to read only if the message is a CSmsPDU::ESmsSubmit
+ iServerEntry.SetEntry(aSelection.At(count));
+ TMsvEntry entry = iServerEntry.Entry();
+ wasReadOnly = entry.ReadOnly();
+
+ if (wasReadOnly)
+ {
+ entry.SetReadOnly(EFalse);
+ iServerEntry.ChangeEntry(entry);
+ }
+
+ CMsvStore* store = iServerEntry.EditStoreL();
+ CleanupStack::PushL(store);
+ iHeader->RestoreL(*store);
+ CSmsMessage& smsmessage = iHeader->Message();
+
+ // Set the destination attributes
+ smsmessage.SetStorage(CSmsMessage::ESmsPhoneStorage);
+ smsmessage.iSlotArray.Reset();
+
+ iHeader->StoreL(*store);
+ store->CommitL();
+ CleanupStack::PopAndDestroy(store);
+
+ if (wasReadOnly)
+ {
+ entry.SetReadOnly(ETrue);
+ iServerEntry.ChangeEntry(entry);
+ }
+ }
+ }
+
+void CSmsSimUtils::ConnectL()
+ {
+ ConnectL(iSocketServ, iSocket, ESmsAddrLocalOperation);
+ }
+
+void CSmsSimUtils::ConnectL(RSocketServ& arSocketServ, RSocket& arSocket, TSmsAddrFamily aSmsAddrFamily)
+ {
+ if (!arSocketServ.Handle())
+ {
+ User::LeaveIfError(arSocketServ.Connect());
+ }
+
+ TProtocolDesc protoinfo;
+ TProtocolName protocolname(KSmsDatagram);
+ User::LeaveIfError(arSocketServ.FindProtocol(protocolname,protoinfo));
+
+ if (!arSocket.SubSessionHandle())
+ {
+ User::LeaveIfError(arSocket.Open(arSocketServ,protoinfo.iAddrFamily,protoinfo.iSockType,protoinfo.iProtocol));
+ }
+
+ TSmsAddr smsaddr;
+ smsaddr.SetSmsAddrFamily(aSmsAddrFamily);
+ User::LeaveIfError(arSocket.Bind(smsaddr));
+ }
+
+
+CSmsSimUtils::CSmsSimUtils(CMsvServerEntry& aServerEntry, RFs& aFs, TMsvId aSmsServiceId)
+ : CSmssActive(aFs, aServerEntry),
+ iState(ESimUtilsStateOther),
+ iReadStream(iSocket),
+ iSmsServiceId(aSmsServiceId),
+ iWriteStream(iSocket)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CSmsSimUtils::DoRunReadSimParamsL()
+/**
+ Retrive and store the parameters to the message store.
+
+ @since 7.0
+ @leave KErrNotFound
+ @pre The reading async operation is complete.
+ @post The parameters are retrived and stored in the message store.
+ */
+ {
+ iProgress.iMsgDone = iSmsServiceId;
+
+ CMobilePhoneSmspList* smspList = CMobilePhoneSmspList::NewL();
+ CleanupStack::PushL(smspList);
+
+ iReadStream >> *smspList;
+
+ iProgress.iMsgCount = smspList->Enumerate();
+
+ if (!iProgress.iMsgCount)
+ User::Leave(KErrNotFound);
+
+ User::LeaveIfError(iServerEntry.SetEntry(iSmsServiceId));
+
+ CMsvStore* store = iServerEntry.EditStoreL();
+ CleanupStack::PushL(store);
+
+ CSmsSimParamOperation::StoreSimParamsL(*store, *smspList);
+
+ CleanupStack::PopAndDestroy(2); //smspList, store
+ User::LeaveIfError(iServerEntry.SetEntry(KMsvNullIndexEntryId));
+ }
+
+void CSmsSimUtils::DoRunL()
+/**
+ Handles completed async operations
+
+ @since 7.0
+ @leave ESmscPanicUnexpectedCommand, KErrNone
+ @pre The async operation is complete
+ @post The operation is complete
+ */
+ {
+ switch (iProgress.iType)
+ {
+ case TSmsProgress::ESmsProgressTypeCopyFromPhoneStore:
+ {
+ __ASSERT_DEBUG(iCompletedSelection, Panic(KSmssPanicNoMessagesInSelection));
+ SetLocalStorageInfoL(*iCompletedSelection);
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeWriteSimParams:
+ {
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeReadSimParams:
+ {
+ if (iReadingSimParams)
+ {
+ iReadingSimParams = EFalse;
+ TRAP(iProgress.iError, DoRunReadSimParamsL());
+ iSocket.Ioctl(KIoctlCompleteReadSmsParams, iStatus, NULL, KSolSmsProv);
+ SetActive();
+ }
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeEnumeratingPhoneStores:
+ {
+ iProgress.iMsgCount = iEnumerateCountBuf();
+ RetrieveMessageFromPhoneStoreL();
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeDeleteFromPhoneStore:
+ {
+ DeleteEachMessageFromPhoneStoreL();
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeMoveFromPhoneStore:
+ {
+ DeleteEachMessageFromPhoneStoreL();
+
+ if (iState == ESimUtilsDeletedLastMessage)
+ {
+ // We have finished deleting the messages from the SIM so set
+ // the Storage & iSlotArray then move the entries
+ SetLocalStorageInfoL(*iSelection);
+ iState = ESimUtilsStateOther;
+ iProgress.iType = TSmsProgress::ESmsProgressTypeMovingEntries;
+ MoveEntriesL(*iSelection, EFalse);
+ }
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeCopyToPhoneStore:
+ case TSmsProgress::ESmsProgressTypeMoveToPhoneStore:
+ {
+ DoCopyToPhoneStoreL();
+ break;
+ }
+ case TSmsProgress::ESmsProgressTypeMovingEntries:
+ break;
+ default:
+ {
+ Panic(KSmssPanicUnexpectedState);
+ }
+ }
+ }
+
+void CSmsSimUtils::RetrieveMessageFromPhoneStoreL()
+ {
+ // If one message fails to be restored the rest fail
+ if (iProgress.iMsgDone < iProgress.iMsgCount)
+ {
+ CSmsMessage& smsmessage=iHeader->Message();
+ iReadStream >> smsmessage;
+
+ TUid biomsguid=KNullUid;
+ TBioMsgId id;
+ if ((smsmessage.Type()==CSmsPDU::ESmsSubmit) || (smsmessage.Type()==CSmsPDU::ESmsDeliver))
+ biomsguid=DecodeBioMessageL(id);
+
+ TMsvEntry entry;
+ RestoreSmsSettingsL();
+ TInt length = iSettings->DescriptionLength();
+ HBufC* buf = HBufC::NewLC(length);
+ TPtr description = buf->Des();
+
+ if (biomsguid != KNullUid)
+ {
+ TSmsUtilities::PopulateMsgEntry(entry, smsmessage, iSmsServiceId, *iSettings, KUidBIOMessageTypeMtm);
+
+ // BioficateEntry!!!
+ // Set up all the needed ids
+ entry.iBioType = biomsguid.iUid;
+ entry.iServiceId = KMsvLocalServiceIndexEntryId;
+ entry.iMtm = KUidBIOMessageTypeMtm;
+
+ // Look up and set the description
+ TInt index;
+ iBioDb->GetBioIndexWithMsgIDL(biomsguid, index);
+ description.Copy(iBioDb->BifReader(index).Description().Left(length));
+ }
+ else
+ {
+ // Set the details
+ TSmsUtilities::PopulateMsgEntry(entry, smsmessage, iSmsServiceId, *iSettings);
+
+ iGetDetDesc->GetDescription(smsmessage, description, length);
+ }
+
+ entry.iDescription.Set(description);
+
+ if (smsmessage.Status() == NMobileSmsStore::EStoredMessageUnread)
+ entry.SetUnread(ETrue);
+ else
+ entry.SetUnread(EFalse);
+
+ TBuf<KSmsDetailsLength> details;
+ if (iGetDetDesc->GetDetails(iFs, smsmessage, details) == KErrNone)
+ entry.iDetails.Set(details);
+
+ User::LeaveIfError(iServerEntry.SetEntry(iProgress.iEnumerateFolder));
+ User::LeaveIfError(iServerEntry.CreateEntry(entry));
+ User::LeaveIfError(iServerEntry.SetEntry(entry.Id()));
+ CMsvStore* store = iServerEntry.EditStoreL();
+ CleanupStack::PushL(store);
+ store->StoreBodyTextL(*iBody);
+ iHeader->StoreL(*store);
+ store->CommitL();
+
+ if (iHeader->Type() != CSmsPDU::ESmsSubmit)
+ {
+ entry.SetReadOnly(ETrue);
+ }
+
+ entry.iSize = store->SizeL();
+ CleanupStack::PopAndDestroy(store);
+ User::LeaveIfError(iServerEntry.ChangeEntry(entry));
+
+ SMSSLOG(FLogMessage(entry, iHeader->Message(), iHeader->BioMsgIdType(), KEnumerateSimLog));
+
+ User::LeaveIfError(iServerEntry.SetEntry(KMsvNullIndexEntryId));
+
+ iSocket.Ioctl(KIoctlReadMessageSucceeded, iStatus, NULL, KSolSmsProv);
+ SetActive();
+
+ iProgress.iMsgDone++;
+
+ SMSSLOG(FLogFormat(_L8("\tRead %d from SIM (%d/%d)"), entry.Id(), iProgress.iMsgDone, iProgress.iMsgCount));
+
+ CleanupStack::PopAndDestroy(buf);
+ }
+ }
+
+void CSmsSimUtils::DoComplete(TInt& aStatus)
+ {
+ if (iState == ESimUtilsDeleteEachMessage && aStatus == KErrNotFound)
+ {
+#ifndef _MSG_NO_LOGGING
+ const TMsvId id = iServerEntry.Entry().Id();
+ _LIT(KLogTxt, "\tERROR: %d NOT deleted from the SIM. Error=KErrNotFound");
+ SMSSLOG(FLogFormat(KDeleteFromSimLog, KLogTxt, id));
+ SMSSLOG(FLogFormat(KLogTxt, id));
+#endif
+
+ TRAP(iProgress.iError, DeleteEachMessageFromPhoneStoreL());
+ }
+ else if (aStatus != KErrNone)
+ {
+ iServerEntry.SetEntry(KMsvNullIndexEntryId);
+ iProgress.iError = aStatus;
+ }
+
+#ifndef _MSG_NO_LOGGING
+ if (!IsActive())
+ SMSSLOG(FLogFormat(_L8("SmsSimUtils completed. Error %d, MsgCount %d, MsgDone %d"), iProgress.iError, iProgress.iMsgCount, iProgress.iMsgDone));
+#endif
+
+ aStatus = KErrNone;
+ }
+
+void CSmsSimUtils::DoSmssCancel()
+ {
+ if (iSocket.SubSessionHandle())
+ iSocket.CancelIoctl();
+ }
+
+
+/**
+ * TSmsSimUtilsData
+ */
+
+void TSmsSimUtilsData::StoreL(CMsvStore& aStore) const
+ {
+ RMsvWriteStream writeStream;
+ writeStream.AssignLC(aStore, KSmsSimUtilsDataUid);
+ ExternalizeL(writeStream);
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(&writeStream);
+ }
+
+void TSmsSimUtilsData::RestoreL(const CMsvStore& aStore)
+ {
+ RMsvReadStream readStream;
+ readStream.OpenLC(aStore, KSmsSimUtilsDataUid);
+ InternalizeL(readStream);
+ CleanupStack::PopAndDestroy(&readStream);
+ }
+
+void TSmsSimUtilsData::ExternalizeL(RWriteStream& aStream) const
+ {
+ aStream.WriteInt16L(KSmsSimUtilsDataVersion);
+ aStream.WriteInt32L(iLastEnumerateFolder);
+ }
+
+void TSmsSimUtilsData::InternalizeL(RReadStream& aStream)
+ {
+ aStream.ReadInt16L(); // version, not used until version > 1
+ iLastEnumerateFolder = aStream.ReadInt32L();
+ }