diff -r 000000000000 -r 72b543305e3a mobilemessaging/smsmtm/servermtm/src/SmssSimUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobilemessaging/smsmtm/servermtm/src/SmssSimUtils.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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* 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,lengthIsBioMessageL(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,textlength255); + 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 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 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(); + }