messagingappbase/smsmtm/servermtm/src/SMSSSEND.CPP
changeset 25 84d9eb65b26f
parent 23 238255e8b033
child 27 e4592d119491
child 37 518b245aa84c
child 79 2981cb3aa489
equal deleted inserted replaced
23:238255e8b033 25:84d9eb65b26f
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #ifdef _DEBUG
       
    17 #undef _MSG_NO_LOGGING
       
    18 #endif
       
    19 
       
    20 #include "SMSSSEND.H"
       
    21 
       
    22 #include <smuthdr.h>			
       
    23 #include <msventry.h>
       
    24 #include <txtrich.h>
       
    25 #include <smutset.h>
       
    26 
       
    27 #include "SMSSPAN.H"
       
    28 #include "SMSRecipientSend.h"
       
    29 
       
    30 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
       
    31 #include <tmsvsmsentry.h>
       
    32 #endif
       
    33 
       
    34 
       
    35 CSmsSend* CSmsSend::NewL(TSmsProgress& aProgress,CMsvServerEntry& aServerEntry, RFs& aFs, CSmsHeader& aHeader, CRichText& aRichText, TMsvEntry& aEntry)
       
    36 	{
       
    37 	return new(ELeave) CSmsSend(aProgress, aServerEntry, aFs, aHeader, aRichText, aEntry);
       
    38 	}
       
    39 
       
    40 CSmsSend::~CSmsSend()
       
    41 	{
       
    42 	Cancel();
       
    43 	}
       
    44 
       
    45 void CSmsSend::Start(TRequestStatus& aStatus,TMsvId aMsvId, CSmsRecipientSend* aRecipientSend)
       
    46 	{
       
    47 	__ASSERT_DEBUG(iState==ESmsSendWaiting,Panic(KSmssPanicUnexpectedState));
       
    48 
       
    49 	iRecipientSend = aRecipientSend;
       
    50 	Queue(aStatus);
       
    51 	iEntry=TMsvEntry();
       
    52 	TRAPD(err,OpenEntryL(aMsvId));
       
    53 	RequestComplete(&iStatus, err, ETrue);
       
    54 	}
       
    55 
       
    56 void CSmsSend::DoSmssCancel()
       
    57 	{
       
    58 	switch (iState)
       
    59 		{
       
    60 		case ESmsSendWaiting:
       
    61 			break;
       
    62 		case ESmsSendOpeningEntry:
       
    63 			break;
       
    64 		case ESmsSendUpdatingRecipient:				
       
    65 		case ESmsSendSendingEntry:
       
    66 			{
       
    67 			iRecipientSend->Cancel();
       
    68 			break;
       
    69 			}
       
    70 		default:
       
    71 			Panic(KSmssPanicUnexpectedState);
       
    72 		}
       
    73 	}
       
    74 
       
    75 CSmsSend::CSmsSend(TSmsProgress& aProgress, CMsvServerEntry& aServerEntry, RFs& aFs, CSmsHeader& aHeader, CRichText& aRichText, TMsvEntry& aEntry)
       
    76 :	CSmssActive(aFs, aServerEntry, KSmsSessionPriority),
       
    77 	iProgress(aProgress),
       
    78 	iEntry(aEntry),
       
    79 	iSmsHeader(aHeader),
       
    80 	iRichText(aRichText),
       
    81 	iState(ESmsSendWaiting)
       
    82 	{
       
    83 	CActiveScheduler::Add(this);
       
    84 	}
       
    85 
       
    86 void CSmsSend::DoRunL()
       
    87 	{
       
    88 	switch (iState)
       
    89 		{
       
    90 		case ESmsSendOpeningEntry:
       
    91 			{
       
    92 			SendNextRecipientL();
       
    93 			break;
       
    94 			}
       
    95 		case ESmsSendSendingEntry:
       
    96 			{
       
    97 			++iProgress.iRcpDone;
       
    98 			UpdateAfterRecipientSentL(iProgress.iError);
       
    99 			break;
       
   100 			}
       
   101 		case ESmsSendUpdatingRecipient:
       
   102 			{
       
   103 			SendNextRecipientL();
       
   104 			break;
       
   105 			}
       
   106 		case ESmsSendWaiting:
       
   107 		default:
       
   108 			Panic(KSmssPanicUnexpectedState);
       
   109 		};
       
   110 	}
       
   111 
       
   112 void CSmsSend::OpenEntryL(const TMsvId aMsvId)
       
   113 	{
       
   114 	iState = ESmsSendOpeningEntry;
       
   115 	User::LeaveIfError(iServerEntry.SetEntry(aMsvId));
       
   116 	iEntry = iServerEntry.Entry();
       
   117 	CMsvStore* msvstore = iServerEntry.ReadStoreL();
       
   118 	CleanupStack::PushL(msvstore);
       
   119 	iSmsHeader.RestoreL(*msvstore);
       
   120 	iRichText.Reset();
       
   121 	msvstore->RestoreBodyTextL(iRichText);
       
   122 
       
   123 	CleanupStack::PopAndDestroy(msvstore);
       
   124 
       
   125 	iProgress.iRcpDone	= 0;
       
   126 	iProgress.iRcpCount	= iSmsHeader.Recipients().Count();
       
   127 	
       
   128 	// Check that there is at least one recipient for this message
       
   129 	if( iProgress.iRcpCount == 0 )
       
   130 		User::Leave(KErrNotFound);
       
   131 
       
   132 	iSentRecipients = 0;
       
   133 	iLastSentIndex	= 0;
       
   134 	
       
   135 	//Check if Last Segment Staus has been requested . If so , make iDeliveryReports as ETrue 
       
   136 	//so that acknowledgement status is EPendingAck , since the last segment acknowledgement is pending .
       
   137 	CSmsSettings* smsSet = CSmsSettings::NewL();
       
   138 	CleanupStack::PushL(smsSet);
       
   139 
       
   140 	iSmsHeader.GetSmsSettingsL(*smsSet);
       
   141 	if(smsSet->LastSegmentDeliveryReport())
       
   142 		{
       
   143 		iDeliveryReports = ETrue;
       
   144 		}
       
   145 	else
       
   146 		{
       
   147 		iDeliveryReports = iSmsHeader.Submit().StatusReportRequest();
       
   148 		}
       
   149 	CleanupStack::PopAndDestroy(smsSet);
       
   150 
       
   151 	iEntry.SetConnected(ETrue);
       
   152 	iEntry.SetFailed(EFalse);
       
   153 	iEntry.SetSendingState(KMsvSendStateSending);
       
   154 	iEntry.iError = KErrNone;
       
   155 
       
   156 	ChangeEntryL(iEntry);
       
   157 	}
       
   158 
       
   159 void CSmsSend::SendNextRecipientL()
       
   160 	{
       
   161 	iState = ESmsSendSendingEntry;
       
   162 
       
   163 	if (iProgress.iRcpDone < iProgress.iRcpCount)
       
   164 		{
       
   165 		CSmsNumber& rcpt = *(iSmsHeader.Recipients()[iProgress.iRcpDone]);
       
   166 		iSmsHeader.Message().SetToFromAddressL(rcpt.Address());
       
   167 
       
   168 		//Do not send to the recipient if they failed or was successfully sent previously.
       
   169 		//Whether to send to a recipient is dependent on CSmsScheduledEntry::CheckRecipient().
       
   170 		if (CanSendMessageToRecipient(iEntry, rcpt))
       
   171 			{
       
   172 			//Move off the current entry so it isn't locked while sending
       
   173 			iServerEntry.SetEntry(KMsvNullIndexEntryId); //ignore any error
       
   174 
       
   175 			//Send the message to the recipient
       
   176 			iRecipientSend->Start(iStatus, iEntry, iSmsHeader, rcpt);
       
   177 			SetActive();
       
   178 			}
       
   179 		else
       
   180 			{
       
   181 #ifndef _MSG_NO_LOGGING
       
   182 			TPtrC addr(rcpt.Address());
       
   183 			SMSSLOG(FLogFormat(_L("Cannot send %d to %S (state %d, status %d)"), iEntry.Id(), &addr, iEntry.SendingState(), rcpt.Status()));
       
   184 #endif
       
   185 			iProgress.iRcpDone++;
       
   186 			SendNextRecipientL();
       
   187 			}
       
   188 		}
       
   189 	else
       
   190 		{
       
   191 		// Sending Complete
       
   192 		UpdateEntryAfterAllSentL();
       
   193 		}
       
   194 	}
       
   195 
       
   196 void CSmsSend::UpdateAfterRecipientSentL(const TInt aError)
       
   197 	{
       
   198 	iState = ESmsSendUpdatingRecipient;
       
   199 
       
   200 	User::LeaveIfError(iServerEntry.SetEntry(iEntry.Id()));
       
   201 	iEntry = iServerEntry.Entry();
       
   202 
       
   203 	CSmsNumber* rcpt = iSmsHeader.Recipients()[iProgress.iRcpDone - 1];
       
   204 	
       
   205 	//In a list of recipients if message send to any one of the recipient has failed 
       
   206 	//means the message should be in outbox (user can edit the message and send) and also 
       
   207 	//UI will be intimated with proper status. iProgress.iError will contain only the last
       
   208 	// recipient's status after sending all recipients. So save the all recipient's failed 
       
   209 	//status (if any) and update the same to iProgress.iError after sending a message to all recipients.
       
   210 	if(aError != KErrNone && (iProgress.iRcpCount > 1))
       
   211 		{
       
   212 		iRecipientFailedStatus = aError;
       
   213 		}
       
   214 
       
   215 	rcpt->Time().UniversalTime();
       
   216 	rcpt->SetError(aError);
       
   217 	CMsvRecipient::TRecipientStatus rcptStatus = CMsvRecipient::ESentSuccessfully;
       
   218 
       
   219 	if( aError != KErrNone )
       
   220 		{
       
   221 		if( aError == KErrCancel )
       
   222 			{
       
   223 			rcptStatus = CMsvRecipient::ENotYetSent;
       
   224 			}
       
   225 		else
       
   226 			{
       
   227 			rcptStatus = CMsvRecipient::EFailedToSend;
       
   228 			}
       
   229 
       
   230 		iEntry.iError = aError;
       
   231 		iEntry.SetFailed(ETrue);
       
   232 		}
       
   233 	else if( iDeliveryReports )
       
   234 		{
       
   235 		// Set the deliver info in the recipiant to pending ack.
       
   236 		rcpt->SetAckStatus(ESmsAckTypeDelivery, CSmsNumber::EPendingAck);
       
   237 		
       
   238 		// Update flag to indicate that a recipient has successfully sent to 
       
   239 		// and record the index of the last recipient to be sent.
       
   240 		++iSentRecipients;
       
   241 		iLastSentIndex = iProgress.iRcpDone - 1;
       
   242 		}
       
   243 
       
   244 	rcpt->SetStatus(rcptStatus);
       
   245 	StoreHeaderL(iSmsHeader);
       
   246 
       
   247 	RequestComplete(&iStatus, KErrNone, ETrue);
       
   248 	}
       
   249 
       
   250 void CSmsSend::UpdateEntryAfterAllSentL()
       
   251 	{
       
   252 	// Assumes iServerEntry is already set to iEntry.Id()
       
   253 
       
   254 	iEntry.SetConnected(EFalse);
       
   255 	
       
   256 	//if a message to last recipient is sent successfully and failed to send to some of the other recipients in 
       
   257 	//a list of recipients then update the iProgress.iError with iRecipientFailedStatus
       
   258 	if( iProgress.iError == KErrNone && iRecipientFailedStatus != KErrNone )
       
   259 		{
       
   260 		iProgress.iError = iRecipientFailedStatus;
       
   261 		}
       
   262 	iRecipientFailedStatus = KErrNone;
       
   263 
       
   264 	if( iEntry.SendingState() != KMsvSendStateSuspended )
       
   265 		{
       
   266 		TInt newSendingState = KMsvSendStateSent;
       
   267 		TBool failed = iEntry.Failed() || iEntry.iError;
       
   268 
       
   269 		if( failed )
       
   270 			{
       
   271 			if( iEntry.iError == KErrCancel )
       
   272 				{
       
   273 				newSendingState = KMsvSendStateSuspended;
       
   274 				}
       
   275 			else
       
   276 				{
       
   277 				newSendingState = KMsvSendStateFailed;
       
   278 				}
       
   279 			}
       
   280 		if( iDeliveryReports && iSentRecipients > 0 )
       
   281 			{
       
   282 			// At least one recipient has been sent and delivery reports have
       
   283 			// been requested - update the entry summary to reflect this.
       
   284 			TMsvSmsEntry& entry = static_cast<TMsvSmsEntry&>(iEntry);
       
   285 
       
   286 			// Set the message ID field only if this is not a bio-message. Need 
       
   287 			// to do this before updating the summary as the current summary 
       
   288 			// will determine if the message ID can be set.
       
   289 			if( entry.iBioType == 0 )
       
   290 				{
       
   291 				TBool validMessageId = EFalse;
       
   292 				TLogId logId = 0;
       
   293 				
       
   294 				// NOTE - need to ensure correct index information in the cases 
       
   295 				// when a message with multiple recipients only sends to one 
       
   296 				// recipient the first time and then on the re-schedule sends to
       
   297 				// one or more remaining recipients.
       
   298 				if( (iSentRecipients == 1) && (entry.AckSummary(ESmsAckTypeDelivery) != TMsvSmsEntry::EPendingAcks) )
       
   299 					{
       
   300 					if(iProgress.iRcpCount <= 0)
       
   301 						{
       
   302 						newSendingState = KMsvSendStateFailed;
       
   303 						failed =ETrue;
       
   304 						}
       
   305 					else
       
   306 						{
       
   307 						// There is now only a single recpient that is pending delivery
       
   308 						// reports - store the log ID in the index.
       
   309 						logId = iSmsHeader.Recipients()[iLastSentIndex]->LogId();
       
   310 						validMessageId = ETrue;	
       
   311 						}
       
   312 					}
       
   313 				entry.SetMessageId(logId, validMessageId);
       
   314 				}
       
   315 			// It is now safe to update the summary.
       
   316 			entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EPendingAcks);
       
   317 			}
       
   318 		iEntry.SetFailed(failed);
       
   319 		
       
   320 		if( newSendingState != KMsvSendStateFailed )
       
   321 			iEntry.SetSendingState(newSendingState);
       
   322 		}
       
   323 
       
   324 	ChangeEntryL(iEntry);
       
   325 	}
       
   326 
       
   327 void CSmsSend::DoComplete(TInt& aStatus)
       
   328 	{
       
   329 	//If there is an error, then update the entry accordingly.
       
   330 	if (aStatus != KErrNone)
       
   331 		{
       
   332    		__ASSERT_DEBUG(iEntry.Connected() || iState == ESmsSendOpeningEntry, Panic(KSmssPanicUnexpectedErrorCode));
       
   333 
       
   334 		TInt err = iServerEntry.SetEntry(iEntry.Id());
       
   335 
       
   336 		if (!err)
       
   337 			{
       
   338 			iEntry = iServerEntry.Entry();
       
   339 			iEntry.iError = aStatus;
       
   340 			TRAP(err, UpdateEntryAfterAllSentL()); //ignore error
       
   341 			}
       
   342 
       
   343 		iProgress.iError = aStatus;
       
   344 		aStatus = KErrNone;
       
   345 		}
       
   346 	
       
   347 	iState = ESmsSendWaiting;
       
   348 	}