--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mobilemessaging/smsmtm/servermtm/src/SMSSSEND.CPP Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,348 @@
+// 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 "SMSSSEND.H"
+
+#include <smuthdr.h>
+#include <msventry.h>
+#include <txtrich.h>
+#include <smutset.h>
+
+#include "SMSSPAN.H"
+#include "SMSRecipientSend.h"
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <tmsvsmsentry.h>
+#endif
+
+
+CSmsSend* CSmsSend::NewL(TSmsProgress& aProgress,CMsvServerEntry& aServerEntry, RFs& aFs, CSmsHeader& aHeader, CRichText& aRichText, TMsvEntry& aEntry)
+ {
+ return new(ELeave) CSmsSend(aProgress, aServerEntry, aFs, aHeader, aRichText, aEntry);
+ }
+
+CSmsSend::~CSmsSend()
+ {
+ Cancel();
+ }
+
+void CSmsSend::Start(TRequestStatus& aStatus,TMsvId aMsvId, CSmsRecipientSend* aRecipientSend)
+ {
+ __ASSERT_DEBUG(iState==ESmsSendWaiting,Panic(KSmssPanicUnexpectedState));
+
+ iRecipientSend = aRecipientSend;
+ Queue(aStatus);
+ iEntry=TMsvEntry();
+ TRAPD(err,OpenEntryL(aMsvId));
+ RequestComplete(&iStatus, err, ETrue);
+ }
+
+void CSmsSend::DoSmssCancel()
+ {
+ switch (iState)
+ {
+ case ESmsSendWaiting:
+ break;
+ case ESmsSendOpeningEntry:
+ break;
+ case ESmsSendUpdatingRecipient:
+ case ESmsSendSendingEntry:
+ {
+ iRecipientSend->Cancel();
+ break;
+ }
+ default:
+ Panic(KSmssPanicUnexpectedState);
+ }
+ }
+
+CSmsSend::CSmsSend(TSmsProgress& aProgress, CMsvServerEntry& aServerEntry, RFs& aFs, CSmsHeader& aHeader, CRichText& aRichText, TMsvEntry& aEntry)
+: CSmssActive(aFs, aServerEntry, KSmsSessionPriority),
+ iProgress(aProgress),
+ iEntry(aEntry),
+ iSmsHeader(aHeader),
+ iRichText(aRichText),
+ iState(ESmsSendWaiting)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CSmsSend::DoRunL()
+ {
+ switch (iState)
+ {
+ case ESmsSendOpeningEntry:
+ {
+ SendNextRecipientL();
+ break;
+ }
+ case ESmsSendSendingEntry:
+ {
+ ++iProgress.iRcpDone;
+ UpdateAfterRecipientSentL(iProgress.iError);
+ break;
+ }
+ case ESmsSendUpdatingRecipient:
+ {
+ SendNextRecipientL();
+ break;
+ }
+ case ESmsSendWaiting:
+ default:
+ Panic(KSmssPanicUnexpectedState);
+ };
+ }
+
+void CSmsSend::OpenEntryL(const TMsvId aMsvId)
+ {
+ iState = ESmsSendOpeningEntry;
+ User::LeaveIfError(iServerEntry.SetEntry(aMsvId));
+ iEntry = iServerEntry.Entry();
+ CMsvStore* msvstore = iServerEntry.ReadStoreL();
+ CleanupStack::PushL(msvstore);
+ iSmsHeader.RestoreL(*msvstore);
+ iRichText.Reset();
+ msvstore->RestoreBodyTextL(iRichText);
+
+ CleanupStack::PopAndDestroy(msvstore);
+
+ iProgress.iRcpDone = 0;
+ iProgress.iRcpCount = iSmsHeader.Recipients().Count();
+
+ // Check that there is at least one recipient for this message
+ if( iProgress.iRcpCount == 0 )
+ User::Leave(KErrNotFound);
+
+ iSentRecipients = 0;
+ iLastSentIndex = 0;
+
+ //Check if Last Segment Staus has been requested . If so , make iDeliveryReports as ETrue
+ //so that acknowledgement status is EPendingAck , since the last segment acknowledgement is pending .
+ CSmsSettings* smsSet = CSmsSettings::NewL();
+ CleanupStack::PushL(smsSet);
+
+ iSmsHeader.GetSmsSettingsL(*smsSet);
+ if(smsSet->LastSegmentDeliveryReport())
+ {
+ iDeliveryReports = ETrue;
+ }
+ else
+ {
+ iDeliveryReports = iSmsHeader.Submit().StatusReportRequest();
+ }
+ CleanupStack::PopAndDestroy(smsSet);
+
+ iEntry.SetConnected(ETrue);
+ iEntry.SetFailed(EFalse);
+ iEntry.SetSendingState(KMsvSendStateSending);
+ iEntry.iError = KErrNone;
+
+ ChangeEntryL(iEntry);
+ }
+
+void CSmsSend::SendNextRecipientL()
+ {
+ iState = ESmsSendSendingEntry;
+
+ if (iProgress.iRcpDone < iProgress.iRcpCount)
+ {
+ CSmsNumber& rcpt = *(iSmsHeader.Recipients()[iProgress.iRcpDone]);
+ iSmsHeader.Message().SetToFromAddressL(rcpt.Address());
+
+ //Do not send to the recipient if they failed or was successfully sent previously.
+ //Whether to send to a recipient is dependent on CSmsScheduledEntry::CheckRecipient().
+ if (CanSendMessageToRecipient(iEntry, rcpt))
+ {
+ //Move off the current entry so it isn't locked while sending
+ iServerEntry.SetEntry(KMsvNullIndexEntryId); //ignore any error
+
+ //Send the message to the recipient
+ iRecipientSend->Start(iStatus, iEntry, iSmsHeader, rcpt);
+ SetActive();
+ }
+ else
+ {
+#ifndef _MSG_NO_LOGGING
+ TPtrC addr(rcpt.Address());
+ SMSSLOG(FLogFormat(_L("Cannot send %d to %S (state %d, status %d)"), iEntry.Id(), &addr, iEntry.SendingState(), rcpt.Status()));
+#endif
+ iProgress.iRcpDone++;
+ SendNextRecipientL();
+ }
+ }
+ else
+ {
+ // Sending Complete
+ UpdateEntryAfterAllSentL();
+ }
+ }
+
+void CSmsSend::UpdateAfterRecipientSentL(const TInt aError)
+ {
+ iState = ESmsSendUpdatingRecipient;
+
+ User::LeaveIfError(iServerEntry.SetEntry(iEntry.Id()));
+ iEntry = iServerEntry.Entry();
+
+ CSmsNumber* rcpt = iSmsHeader.Recipients()[iProgress.iRcpDone - 1];
+
+ //In a list of recipients if message send to any one of the recipient has failed
+ //means the message should be in outbox (user can edit the message and send) and also
+ //UI will be intimated with proper status. iProgress.iError will contain only the last
+ // recipient's status after sending all recipients. So save the all recipient's failed
+ //status (if any) and update the same to iProgress.iError after sending a message to all recipients.
+ if(aError != KErrNone && (iProgress.iRcpCount > 1))
+ {
+ iRecipientFailedStatus = aError;
+ }
+
+ rcpt->Time().UniversalTime();
+ rcpt->SetError(aError);
+ CMsvRecipient::TRecipientStatus rcptStatus = CMsvRecipient::ESentSuccessfully;
+
+ if( aError != KErrNone )
+ {
+ if( aError == KErrCancel )
+ {
+ rcptStatus = CMsvRecipient::ENotYetSent;
+ }
+ else
+ {
+ rcptStatus = CMsvRecipient::EFailedToSend;
+ }
+
+ iEntry.iError = aError;
+ iEntry.SetFailed(ETrue);
+ }
+ else if( iDeliveryReports )
+ {
+ // Set the deliver info in the recipiant to pending ack.
+ rcpt->SetAckStatus(ESmsAckTypeDelivery, CSmsNumber::EPendingAck);
+
+ // Update flag to indicate that a recipient has successfully sent to
+ // and record the index of the last recipient to be sent.
+ ++iSentRecipients;
+ iLastSentIndex = iProgress.iRcpDone - 1;
+ }
+
+ rcpt->SetStatus(rcptStatus);
+ StoreHeaderL(iSmsHeader);
+
+ RequestComplete(&iStatus, KErrNone, ETrue);
+ }
+
+void CSmsSend::UpdateEntryAfterAllSentL()
+ {
+ // Assumes iServerEntry is already set to iEntry.Id()
+
+ iEntry.SetConnected(EFalse);
+
+ //if a message to last recipient is sent successfully and failed to send to some of the other recipients in
+ //a list of recipients then update the iProgress.iError with iRecipientFailedStatus
+ if( iProgress.iError == KErrNone && iRecipientFailedStatus != KErrNone )
+ {
+ iProgress.iError = iRecipientFailedStatus;
+ }
+ iRecipientFailedStatus = KErrNone;
+
+ if( iEntry.SendingState() != KMsvSendStateSuspended )
+ {
+ TInt newSendingState = KMsvSendStateSent;
+ TBool failed = iEntry.Failed() || iEntry.iError;
+
+ if( failed )
+ {
+ if( iEntry.iError == KErrCancel )
+ {
+ newSendingState = KMsvSendStateSuspended;
+ }
+ else
+ {
+ newSendingState = KMsvSendStateFailed;
+ }
+ }
+ if( iDeliveryReports && iSentRecipients > 0 )
+ {
+ // At least one recipient has been sent and delivery reports have
+ // been requested - update the entry summary to reflect this.
+ TMsvSmsEntry& entry = static_cast<TMsvSmsEntry&>(iEntry);
+
+ // Set the message ID field only if this is not a bio-message. Need
+ // to do this before updating the summary as the current summary
+ // will determine if the message ID can be set.
+ if( entry.iBioType == 0 )
+ {
+ TBool validMessageId = EFalse;
+ TLogId logId = 0;
+
+ // NOTE - need to ensure correct index information in the cases
+ // when a message with multiple recipients only sends to one
+ // recipient the first time and then on the re-schedule sends to
+ // one or more remaining recipients.
+ if( (iSentRecipients == 1) && (entry.AckSummary(ESmsAckTypeDelivery) != TMsvSmsEntry::EPendingAcks) )
+ {
+ if(iProgress.iRcpCount <= 0)
+ {
+ newSendingState = KMsvSendStateFailed;
+ failed =ETrue;
+ }
+ else
+ {
+ // There is now only a single recpient that is pending delivery
+ // reports - store the log ID in the index.
+ logId = iSmsHeader.Recipients()[iLastSentIndex]->LogId();
+ validMessageId = ETrue;
+ }
+ }
+ entry.SetMessageId(logId, validMessageId);
+ }
+ // It is now safe to update the summary.
+ entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EPendingAcks);
+ }
+ iEntry.SetFailed(failed);
+
+ if( newSendingState != KMsvSendStateFailed )
+ iEntry.SetSendingState(newSendingState);
+ }
+
+ ChangeEntryL(iEntry);
+ }
+
+void CSmsSend::DoComplete(TInt& aStatus)
+ {
+ //If there is an error, then update the entry accordingly.
+ if (aStatus != KErrNone)
+ {
+ __ASSERT_DEBUG(iEntry.Connected() || iState == ESmsSendOpeningEntry, Panic(KSmssPanicUnexpectedErrorCode));
+
+ TInt err = iServerEntry.SetEntry(iEntry.Id());
+
+ if (!err)
+ {
+ iEntry = iServerEntry.Entry();
+ iEntry.iError = aStatus;
+ TRAP(err, UpdateEntryAfterAllSentL()); //ignore error
+ }
+
+ iProgress.iError = aStatus;
+ aStatus = KErrNone;
+ }
+
+ iState = ESmsSendWaiting;
+ }