diff -r 238255e8b033 -r 84d9eb65b26f messagingappbase/smsmtm/servermtm/src/SMSSOUTB.CPP --- a/messagingappbase/smsmtm/servermtm/src/SMSSOUTB.CPP Fri Apr 16 14:56:15 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,783 +0,0 @@ -// 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: -// - -#include "SMSSOUTB.H" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SMSSendSession.h" -#include "SMSSPAN.H" - -CSmsOutboxSend* CSmsOutboxSend::NewL(CMsvServerEntry& aServerEntry, CMsvScheduleSend& aScheduleSend, RFs& aFs) - { - CSmsOutboxSend* outboxsend=new(ELeave) CSmsOutboxSend(aServerEntry, aScheduleSend, aFs); - CleanupStack::PushL(outboxsend); - outboxsend->ConstructL(); - CleanupStack::Pop(); - return outboxsend; - } - -CSmsOutboxSend::~CSmsOutboxSend() - { - Cancel(); - delete iSendSession; - delete iMsvEntrySelection; - delete iLogger; - delete iSmsHeader; - - delete iRichText; - delete iParaLayer; - delete iCharLayer; - -#if (defined SYMBIAN_USER_PROMPT_SERVICE) - iUpsSubsession.Close(); - iUpsSession.Close(); -#endif - } - - -#if (defined SYMBIAN_USER_PROMPT_SERVICE) -void CSmsOutboxSend::StartL(TRequestStatus& aStatus,const CMsvEntrySelection& aSelection, const TBool aMove, const TDesC8& aParameter, TThreadId aClientThreadId, TBool aHasCapability) // kicks off the send session - { - // Connect to UPS service..... - User::LeaveIfError(iUpsSession.Connect()); - - RThread clientThread; - User::LeaveIfError(clientThread.Open(aClientThreadId)); - CleanupClosePushL(clientThread); - User::LeaveIfError(iUpsSubsession.Initialise(iUpsSession, clientThread)); - CleanupStack::PopAndDestroy(&clientThread); - - iHasCapability = aHasCapability; - Start(aStatus, aSelection, aMove, aParameter); - } -#endif - -void CSmsOutboxSend::Start(TRequestStatus& aStatus,const CMsvEntrySelection& aSelection, const TBool aMove, const TDesC8& aParameter) // kicks off the send session - { - __ASSERT_DEBUG(iProgress.iState==ESmsOutboxSendStateWaiting,Panic(KSmssPanicAlreadySending)); - Queue(aStatus); - - iPackage.iParameter = aParameter; - iMove = aMove; - iStartTime.UniversalTime(); //used by FailOutstandingMessages - TRAPD(err, FindOtherMessagesL(aSelection)); - RequestComplete(&iStatus, err, ETrue); - } - -void CSmsOutboxSend::DoSmssCancel() - { - switch (iProgress.iState) - { - case ESmsOutboxSendStateWaiting: - case ESmsOutboxSendStateFindingOtherMessages: - case ESmsOutboxSendStateReScheduling: - case ESmsOutboxSendStateLogEntryComplete: - case ESmsOutboxSendStateMovingEntry: - case ESmsOutboxSendStateComplete: - { - break; - } -#if (defined SYMBIAN_USER_PROMPT_SERVICE) - case ESmsOutboxSendAuthoriseState: - { - iUpsSubsession.CancelPrompt(); - break; - } -#endif - case ESmsOutboxSendStateAddLogEvent: - case ESmsOutboxSendStateGetLogEvent: - case ESmsOutboxSendStateChangeLogEvent: - { - SMSSLOG(FLogFormat(_L8("CSmsOutboxSend::DoSmssCancel() cancelling logging for msg %d"), iCurrentMessage)); - iLogger->Cancel(); - break; - } - case ESmsOutboxSendStateSending: - { - SMSSLOG(FLogFormat(_L8("CSmsOutboxSend::DoSmssCancel() cancelling sending for msg %d"), iCurrentMessage)); - iSendSession->Cancel(); - break; - } - default: - { - Panic(KSmssPanicUnexpectedState); - } - } - - SMSSLOG(FLogFormat(_L8("CSmsOutboxSend::DoSmssCancel() setting sending state to SUSPENDED for unsent msgs"))); - - FailOutstandingMessages(KErrCancel, KMsvSendStateSuspended); - } - -void CSmsOutboxSend::FailOutstandingMessages(TInt aError, TInt aSendingState) - { - TInt count = iMsvEntrySelection->Count(); - while (count--) - { - const TInt err = iServerEntry.SetEntry(iMsvEntrySelection->At(count)); - - if (err == KErrNone) - { - TMsvEntry entry(iServerEntry.Entry()); - TBool failMsg = EFalse; - - switch (entry.SendingState()) - { - case KMsvSendStateSending: - case KMsvSendStateWaiting: - - failMsg = ETrue; - break; - - case KMsvSendStateScheduled: - case KMsvSendStateResend: - - failMsg = (entry.iDate < iStartTime); - break; - - default: - - //failMsg = EFalse; - break; - } - - if (failMsg) - { - entry.SetSendingState(aSendingState); - entry.iError = aError; - entry.SetFailed(ETrue); - entry.SetConnected(EFalse); - entry.SetScheduled(EFalse); - iServerEntry.ChangeEntry(entry); //ignore error - } - } //end if - } //end while - } - -void CSmsOutboxSend::DoRunL() // required by PV declaration in CActive - { - switch (iProgress.iState) - { - case ESmsOutboxSendStateFindingOtherMessages: - case ESmsOutboxSendStateMovingEntry: - { - SendNextHeaderL(); - break; - } -#if (defined SYMBIAN_USER_PROMPT_SERVICE) - case ESmsOutboxSendAuthoriseState: - { - if(iDecision == EUpsDecYes || iDecision == EUpsDecSessionYes) - { - SendHeader(); - } - else - { - // The decision from UPS server was NO, so do not send the message. - iProgress.iState = ESmsOutboxSendStateReScheduling; - iEntry = iServerEntry.Entry(); - iEntry.SetFailed(ETrue); - iEntry.SetSendingState(KMsvSendStateFailed); - TRequestStatus* status=&iStatus; - iStatus=KRequestPending; - User::RequestComplete(status,KErrNone); - SetActive(); - } - break; - } -#endif - case ESmsOutboxSendStateSending: - { - if (iCurrentMessage) - { - ReScheduleFailedMessageL(); - } - else - { - __ASSERT_DEBUG(iProgress.iError == KErrNotFound, Panic(KSmssPanicUnexpectedErrorCode)); - } - break; - } - case ESmsOutboxSendStateReScheduling: - { - iProgress.iRcpDone = -1; - iProgress.iRcpCount = iSmsHeader->Recipients().Count(); - LogEntry(); - break; - } - case ESmsOutboxSendStateGetLogEvent: - { - if (iLogger->iStatus == KErrNone) - { - ChangeLogEvent(); - } - else - { - //Log error has occurred - if (-(iLogger->iStatus.Int()) == KErrNotFound) - { - AddLogEvent(); - } - else - { - LogEntry(); - } - } - break; - } - case ESmsOutboxSendStateAddLogEvent: - { - TLogId logId = KLogNullId; - - if (iLogger->iStatus.Int() == KErrNone) - { - //No log error has occurred - logId = iLogger->Event().Id(); - } - - iSmsHeader->Recipients()[iProgress.iRcpDone]->SetLogId(logId); - iSmsHeader->Message().SetLogServerId(logId); - //do not break here... - } - case ESmsOutboxSendStateChangeLogEvent: - { - LogEntry(); - break; - } - case ESmsOutboxSendStateLogEntryComplete: - { - MoveEntryL(); - break; - } - case ESmsOutboxSendStateComplete: - { - break; - } - case ESmsOutboxSendStateWaiting: - default: - Panic(KSmssPanicUnexpectedState); - } - } - -void CSmsOutboxSend::FindOtherMessagesL(const CMsvEntrySelection& aSelection) -// Finds any other messages in the outbox that are waiting to send - { - iProgress.iState = ESmsOutboxSendStateFindingOtherMessages; - - delete iMsvEntrySelection; - iMsvEntrySelection = NULL; - iMsvEntrySelection = aSelection.CopyL(); - SMSSLOG(FLogFormat(_L8("Asked to send %d message(s)"), iMsvEntrySelection->Count())); - - CMsvEntrySelection* sel = new (ELeave) CMsvEntrySelection(); - CleanupStack::PushL(sel); - - User::LeaveIfError(iServerEntry.SetEntry(KMsvGlobalOutBoxIndexEntryId)); - - //Find the children of the outbox for the SMS Mtm - User::LeaveIfError(iServerEntry.GetChildrenWithMtm(KUidMsgTypeSMS, *sel)); - - TInt count = sel->Count(); - - while (count--) - { - TMsvId id = sel->At(count); - User::LeaveIfError(iServerEntry.SetEntry(id)); - - TInt sendState = iServerEntry.Entry().SendingState(); - - if (sendState == KMsvSendStateWaiting || sendState == KMsvSendStateUnknown) - { - // check that the entry is not already in iMsvEntrySelection - TBool foundMessage = EFalse; - TInt numberMessages = iMsvEntrySelection->Count(); - for(TInt a = 0; a < numberMessages; a++) - { - if(iMsvEntrySelection->At(a) == id) - { - foundMessage = ETrue; - break; - } - } - - // only add the id of the message if it has not been found in iMsvEntrySelection - if(!foundMessage) - iMsvEntrySelection->AppendL(id); - } - } - - CleanupStack::PopAndDestroy(); //sel - - //Instantiate iSendSession with the updated iMsvEntrySelection - iSendSession = CSmsSendSession::NewL(iProgress, iServerEntry, iFs, *iSmsHeader, *iRichText, iEntry); - iSendSession->DivideMessagesL(*iMsvEntrySelection); //Leaves with KErrNotFound if iMsvEntrySelecion.Count() == 0 (on the way in) - //Leaves with KErrUnknownBioType if iMsvEntrySelection.Count() == 0 (on the way out) - //Leaves with another error if iServerEntry.SetEntry() failed and iMsvEntrySelection.Count() == 0 (on the way out) - - iProgress.iError = KErrNone; - iProgress.iMsgCount = iMsvEntrySelection->Count(); - iProgress.iMsgDone= -1; - - __ASSERT_DEBUG(iProgress.iMsgCount, Panic(KSmssPanicNoMessagesInSelection)); - SMSSLOG(FLogFormat(_L8("\tActually sending %d message(s)"), iProgress.iMsgCount)); - - TMsvSendErrorAction action; - iCondMet = ConditionsRightForSending(action); //Checks the system agent - if (!iCondMet) - { - SMSSLOG(FLogFormat(_L8("Conditions NOT right for sending. Scheduling all messages"))); - iProgress.iState = ESmsOutboxSendStateComplete; - } - - count = iMsvEntrySelection->Count(); - - while (count--) - { - //Should not leave at this point, as it would have left at DivideMessagesL(). - User::LeaveIfError(iServerEntry.SetEntry(iMsvEntrySelection->At(count))); - - iEntry = iServerEntry.Entry(); - - if (!iCondMet) - { - iEntry = iServerEntry.Entry(); - iEntry.SetFailed(ETrue); - iEntry.iError = action.iError; - DoReScheduleL(&action); - } - else if (iEntry.SendingState() != KMsvSendStateWaiting && CanSendMessage(iEntry)) - { - iEntry.SetSendingState(KMsvSendStateWaiting); - iServerEntry.ChangeEntry(iEntry); - } - } - } - -void CSmsOutboxSend::DoReScheduleL(const TMsvSendErrorAction* aErrorAction) - { - __ASSERT_DEBUG(iServerEntry.Entry().Id() == iEntry.Id(), Panic(ESmssEntryNotSet)); - - //Log the failed message - SMSSLOG(FLogFormat(_L8("Sending FAILED for msg %d with error %d. Attempting re-schedule"), iEntry.Id(), iEntry.iError)); - - CMsvEntrySelection* reSch = new (ELeave) CMsvEntrySelection(); - CleanupStack::PushL(reSch); - - reSch->AppendL(iEntry.Id()); - - TMsvSchedulePackage schPkg; - schPkg.iCommandId = iMove ? ESmsMtmCommandSendScheduledMove : ESmsMtmCommandSendScheduledCopy; - - //Re-Schedule the failed message - iScheduleSend.ReScheduleL(*reSch, schPkg, aErrorAction); - - CleanupStack::PopAndDestroy(); //reSch - - //Restore iEntry, because it may have changed while re-scheuling - User::LeaveIfError(iServerEntry.SetEntry(iEntry.Id())); - iEntry = iServerEntry.Entry(); - - //Restore the iSmsHeader, because it may have changed while re-scheduling - CMsvStore* store = iServerEntry.ReadStoreL(); - CleanupStack::PushL(store); - iSmsHeader->RestoreL(*store); - CleanupStack::PopAndDestroy(); //store - } - -void CSmsOutboxSend::ReScheduleFailedMessageL() - { - __ASSERT_DEBUG(iCurrentMessage == iEntry.Id(), Panic(ESmssEntryNotSet)); - - iProgress.iState = ESmsOutboxSendStateReScheduling; - TInt err = KErrNone; - - //Check to make sure the message still exits - if (iServerEntry.Entry().Id() != iEntry.Id()) - { - err = iServerEntry.SetEntry(iEntry.Id()); - if (err == KErrNone) - iEntry = iServerEntry.Entry(); - else if (err != KErrNotFound) - User::Leave(err); - } - - if (err == KErrNone) - { - if (!iEntry.Failed() && iProgress.iError) - { - iEntry.SetFailed(ETrue); - iEntry.iError = iProgress.iError; - } - - if (iEntry.Failed() && iEntry.SendingState() != KMsvSendStateSuspended) - { - DoReScheduleL(); - } - else - { - iScheduleSend.SendingCompleteL(iEntry, EFalse); - } - RequestComplete(&iStatus, KErrNone, ETrue); - } - else // err == KErrNotFound (the user has deleted the message) - { - SendNextHeaderL(); //send the next message - } - } - -CSmsOutboxSend::CSmsOutboxSend(CMsvServerEntry& aServerEntry, CMsvScheduleSend& aScheduleSend, RFs& aFs) - :CSmssActive(aFs, aServerEntry, KSmsSessionPriority), - iProgress(TSmsProgress::ESmsProgressTypeSending), - iScheduleSend(aScheduleSend) - { - CActiveScheduler::Add(this); - } - -void CSmsOutboxSend::ConstructL() - { - iLogger = CSmsEventLogger::NewL(iFs); - - // stuff for the body text.... - iParaLayer = CParaFormatLayer::NewL(); - iCharLayer = CCharFormatLayer::NewL(); - iRichText = CRichText::NewL( iParaLayer, iCharLayer, CEditableText::EFlatStorage, 256); - iSmsHeader = CSmsHeader::NewL(CSmsPDU::ESmsSubmit,*iRichText); - - TInt ret = iServerEntry.SetEntry(KMsvSentEntryId); - - if (ret != KErrNotFound) - { - User::LeaveIfError(ret); - iSentFolderExists = ETrue; - } - else - { - iSentFolderExists = EFalse; - } - } - -void CSmsOutboxSend::SendNextHeaderL() - { - iProgress.iMsgDone++; - iCurrentMessage = iSendSession->IncSms(); - - if(iProgress.iMsgDone >= iProgress.iMsgCount || !iCurrentMessage) - { - iProgress.iState = ESmsOutboxSendStateComplete; - RequestComplete(&iStatus, KErrNone, ETrue); - } - else - { - iErr = iServerEntry.SetEntry(iCurrentMessage); - -#if (defined SYMBIAN_USER_PROMPT_SERVICE) - iDecision = EUpsDecNo; - iProgress.iState = ESmsOutboxSendAuthoriseState; - - //Restore the CSmsHeader - CMsvStore* store = iServerEntry.ReadStoreL(); - CleanupStack::PushL(store); - iSmsHeader->RestoreL(*store); - CleanupStack::PopAndDestroy(); //store - - // Need to create a single TDesC using the the Recipient list - CArrayPtrFlat& numbers = iSmsHeader->Recipients(); - TInt size = 0; - TInt num = numbers.Count(); - CSmsNumber* rcpt = NULL; - for(TInt i=0;iAddress().Size(); - } - - _LIT16(KComma, ","); - - RBuf16 buffer; - buffer.Create(size+num); - if(num > 0) - { - rcpt = numbers[0]; - buffer.Append(rcpt->Address()); - } - - for(TInt i=1;iAddress()); - } - - //Query the UPS server if the client thread is authorised to send messages. - iUpsSubsession.Authorise( iHasCapability, KUidSMSService, buffer, iDecision, iStatus); - SetActive(); - buffer.Close(); -#else - SendHeader(); -#endif - } - } - -TBool CSmsOutboxSend::ConditionsRightForSending(TMsvSendErrorAction& rErrorAction) - { - TBool retVal = ETrue; - - TRAPD(err, retVal = iScheduleSend.AgentActions().ConditionsMetL(rErrorAction)); - //ignore the error - - if (err) - { - retVal = ETrue; - } - - return retVal; - } - -void CSmsOutboxSend::DoComplete(TInt& aError) - { - iProgress.iState = ESmsOutboxSendStateWaiting; - - if (iProgress.iError == KErrNone) - iProgress.iError = aError; - - if (iProgress.iError != KErrNone || !iCondMet) - FailOutstandingMessages(iProgress.iError, KMsvSendStateFailed); - - SMSSLOG(FLogFormat(_L8("CSmsOutboxSend completed with %d"), iProgress.iError)); - } - -void CSmsOutboxSend::MoveEntryL() - { - __ASSERT_DEBUG(iServerEntry.Entry().Id() == iEntry.Id(), Panic(ESmssEntryNotSet)); - __ASSERT_DEBUG(iCurrentMessage == iEntry.Id(), Panic(ESmssEntryNotSet)); - - iProgress.iState = ESmsOutboxSendStateMovingEntry; - SMSSLOG(FLogFormat(_L8("MoveEntryL Msg=%d Sent=%d SentFldr=%d Move=%d"), iEntry.Id(), MessageSent(), iSentFolderExists, iMove)); - - if (MessageSent()) - { - if (iMove) - { - User::LeaveIfError(iServerEntry.SetEntry(iEntry.Parent())); // change context to parent of iMsvEntry - User::LeaveIfError(iServerEntry.DeleteEntry(iEntry.Id())); - } - else - { - //The following members should be set already, but set them again just in case ;) - iEntry.SetConnected(EFalse); - iEntry.SetFailed(EFalse); - iEntry.SetSendingState(KMsvSendStateSent); - - //Only update the message if it has changed - if (!(iEntry == iServerEntry.Entry())) - User::LeaveIfError(iServerEntry.ChangeEntry(iEntry)); - - if (iSentFolderExists) - { - User::LeaveIfError(iServerEntry.SetEntry(iEntry.Parent())); - User::LeaveIfError(iServerEntry.MoveEntryWithinService(iEntry.Id(),KMsvSentEntryId)); - User::LeaveIfError(iServerEntry.SetEntry(iEntry.Id())); - iEntry = iServerEntry.Entry(); - } - } - } - else - { - if (!(iEntry == iServerEntry.Entry())) - { - //Store iSmsHeader. This is required because of potential changes to the recipients' LogIds. - CMsvStore* store = iServerEntry.EditStoreL(); - CleanupStack::PushL(store); - iSmsHeader->StoreL(*store); - store->CommitL(); - CleanupStack::PopAndDestroy(); //store - User::LeaveIfError(iServerEntry.ChangeEntry(iEntry)); - } - } - - RequestComplete(&iStatus, KErrNone, ETrue); - } - -void CSmsOutboxSend::LogEntry() - { - __ASSERT_DEBUG(iServerEntry.Entry().Id() == iEntry.Id(), Panic(ESmssEntryNotSet)); - - iProgress.iRcpDone++; - - if (!MessageSent() && iProgress.iRcpDone < iProgress.iRcpCount) - { - CSmsNumber* rcpt = iSmsHeader->Recipients()[iProgress.iRcpDone]; - - if (CanLogRecipient(*rcpt)) - { - TLogId logId = rcpt->LogId(); - iSmsHeader->Message().SetLogServerId(logId); - - if (logId == KLogNullId) - { - AddLogEvent(); - } - else - { - GetLogEvent(logId); - } - } - else - { - LogEntry(); - } - } - else - { - iProgress.iState = ESmsOutboxSendStateLogEntryComplete; - RequestComplete(&iStatus, KErrNone, ETrue); - } - } - -void CSmsOutboxSend::GetLogEvent(TLogId aId) - { - iProgress.iState = ESmsOutboxSendStateGetLogEvent; - iLogger->GetEvent(iStatus, aId); - SetActive(); - } - -void CSmsOutboxSend::AddLogEvent() - { - iProgress.iState = ESmsOutboxSendStateAddLogEvent; - TInt logStatus = GetLogStatus(); - TLogSmsPduData data; - // Initialise the data members - data.iType = 0; - data.iTotal = 0; - data.iSent = 0; - data.iDelivered = 0; - data.iFailed = 0; - data.iReceived = 0; - iLogger->AddEvent(iStatus, iSmsHeader->Message(), data, &logStatus); - SetActive(); - } - -void CSmsOutboxSend::ChangeLogEvent() - { - __ASSERT_DEBUG(iProgress.iState == ESmsOutboxSendStateGetLogEvent, Panic(KSmssPanicUnexpectedState)); - iProgress.iState = ESmsOutboxSendStateChangeLogEvent; - TInt logStatus = GetLogStatus(); - iLogger->ChangeEvent(iStatus, iSmsHeader->Message(), iLogger->SmsPDUData(), &logStatus); - SetActive(); - } - -TBool CSmsOutboxSend::MessageSent() const - { - TInt sendingState = iEntry.SendingState(); - return (sendingState == KMsvSendStateSent) || - (!iEntry.iError && - !iEntry.Failed() && - (sendingState != KMsvSendStateFailed) && - (sendingState != KMsvSendStateScheduled) && - (sendingState != KMsvSendStateSuspended) && - (sendingState != KMsvSendStateResend)); - } - -TBool CSmsOutboxSend::CanLogRecipient(const CSmsNumber& aNumber) const - { - return aNumber.Status() != CMsvRecipient::ESentSuccessfully; - } - -TInt CSmsOutboxSend::GetLogStatus() const - { - TInt logStatus = R_LOG_DEL_NONE; - - switch (iEntry.SendingState()) - { - case KMsvSendStateFailed: - { - logStatus = R_LOG_DEL_NOT_SENT; - break; - } - case KMsvSendStateScheduled: - case KMsvSendStateResend: - { - logStatus = R_LOG_DEL_SCHEDULED; - break; - } - default: - { - //do nothing - break; - } - } - - return logStatus; - } - -const TSmsProgress& CSmsOutboxSend::Progress() // called by the UI to check on prgress through the message selection object - { - if (iProgress.iState == ESmsOutboxSendStateSending && iCurrentMessage) - { - SMSSLOG(FLogFormat(_L8("CSmsOutboxSend::Progress() called while sending msg %d"), iCurrentMessage)); - - TInt err = KErrNone; - TMsvId oldId = iServerEntry.Entry().Id(); - - if (oldId != iCurrentMessage) - err = iServerEntry.SetEntry(iCurrentMessage); - - TBool cancelSending = (err == KErrNotFound); - - if (!err) - { - cancelSending = (iServerEntry.Entry().SendingState() == KMsvSendStateSuspended); - } - - iServerEntry.SetEntry(oldId); //ignore error, because there shouldn't be one - - if (cancelSending) - { - SMSSLOG(FLogFormat(_L8("Cancelled sending msg %d - state SUSPENDED"), iCurrentMessage)); - iSendSession->Cancel(); - } - } - - return iProgress; - } - - -/** -This method actually sends the message, if a positive response is -returned by the UPS server. -@param None. -@return void. -*/ -void CSmsOutboxSend::SendHeader() - { - if (!iErr && CanSendMessage(iServerEntry.Entry())) - { - iProgress.iState = ESmsOutboxSendStateSending; - iSendSession->SendSms(iStatus); - SetActive(); - } - else - { - TRAPD(err, SendNextHeaderL()); - } - }