|
1 /* |
|
2 * Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * State machine for message receiving |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 |
|
21 // INCLUDE FILES |
|
22 #include <apparc.h> |
|
23 #include <msventry.h> |
|
24 #include <msvids.h> |
|
25 #include <charconv.h> |
|
26 #include <badesca.h> |
|
27 #include <cmsvmimeheaders.h> |
|
28 #include <mmsvattachmentmanager.h> |
|
29 #include <mmsvattachmentmanagersync.h> |
|
30 |
|
31 #include <centralrepository.h> |
|
32 |
|
33 // mms private headers |
|
34 #include "mmsconst.h" |
|
35 #include "mmsreceivemessage.h" |
|
36 #include "mmssession.h" |
|
37 #include "mmssettings.h" |
|
38 #include "mmsservercommon.h" |
|
39 #include "mmsheaders.h" |
|
40 #include "mmsdecode.h" |
|
41 #include "mmsencode.h" |
|
42 #include "mmsscheduledentry.h" |
|
43 #include "mmserrors.h" |
|
44 #include "mmsserverentry.h" |
|
45 #include "mmsconninit.h" |
|
46 #include "MmsEnginePrivateCRKeys.h" |
|
47 #include "MmsPhoneClient.H" |
|
48 |
|
49 // EXTERNAL DATA STRUCTURES |
|
50 |
|
51 // EXTERNAL FUNCTION PROTOTYPES |
|
52 extern void gPanic(TMmsPanic aPanic); |
|
53 |
|
54 // CONSTANTS |
|
55 // return codes for handling of messages addressed to an application |
|
56 const TInt KMmsMessageForUnregisteredApplication = 1; |
|
57 const TInt KMmsMessageMovedToApplicationFolder = 2; |
|
58 |
|
59 // MACROS |
|
60 |
|
61 // LOCAL CONSTANTS AND MACROS |
|
62 |
|
63 // MODULE DATA STRUCTURES |
|
64 |
|
65 // LOCAL FUNCTION PROTOTYPES |
|
66 |
|
67 // ==================== LOCAL FUNCTIONS ==================== |
|
68 |
|
69 |
|
70 // ================= MEMBER FUNCTIONS ======================= |
|
71 |
|
72 // C++ default constructor can NOT contain any code, that |
|
73 // might leave. |
|
74 // |
|
75 CMmsReceiveMessage::CMmsReceiveMessage( RFs& aFs ) |
|
76 :CMmsBaseOperation( aFs ) |
|
77 { |
|
78 } |
|
79 |
|
80 // Symbian OS default constructor can leave. |
|
81 void CMmsReceiveMessage::ConstructL( CMmsSettings* aMmsSettings ) |
|
82 { |
|
83 iFileOpen = EFalse; |
|
84 CMmsBaseOperation::ConstructL( aMmsSettings ); |
|
85 iMmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() ); |
|
86 iNotification = CMmsHeaders::NewL( iMmsSettings->MmsVersion() ); |
|
87 iBad = new( ELeave ) CMsvEntrySelection; |
|
88 TRAPD ( error, {iMessageDrive = MessageServer::CurrentDriveL( iFs );}); |
|
89 if ( error != KErrNone ) |
|
90 { |
|
91 // if cannot ask, use default |
|
92 iMessageDrive = EDriveC; |
|
93 } |
|
94 |
|
95 CActiveScheduler::Add( this ); |
|
96 } |
|
97 |
|
98 // Two-phased constructor. |
|
99 CMmsReceiveMessage* CMmsReceiveMessage::NewL( RFs& aFs, CMmsSettings* aMmsSettings ) |
|
100 { |
|
101 CMmsReceiveMessage* self = new ( ELeave ) CMmsReceiveMessage( aFs ); |
|
102 |
|
103 CleanupStack::PushL( self ); |
|
104 self->ConstructL( aMmsSettings ); |
|
105 CleanupStack::Pop( self ); |
|
106 |
|
107 return self; |
|
108 } |
|
109 |
|
110 |
|
111 // Destructor |
|
112 CMmsReceiveMessage::~CMmsReceiveMessage() |
|
113 { |
|
114 |
|
115 Cancel(); |
|
116 |
|
117 delete iMmsHeaders; |
|
118 delete iNotification; |
|
119 delete iBad; |
|
120 // This is the message for local mode testing |
|
121 // It is closed here only to make sure that it is |
|
122 // always closed even if we encounter a serious error. |
|
123 // otherwise it should already be closed by now. |
|
124 if ( iFileOpen ) |
|
125 { |
|
126 iFile.Close(); |
|
127 } |
|
128 } |
|
129 |
|
130 |
|
131 // --------------------------------------------------------- |
|
132 // CMmsReceiveMessage::StartL |
|
133 // |
|
134 // --------------------------------------------------------- |
|
135 // |
|
136 void CMmsReceiveMessage::StartL( |
|
137 CMsvEntrySelection& aSelection, |
|
138 CMsvServerEntry& aServerEntry, |
|
139 TMsvId aService, |
|
140 TRequestStatus& aStatus ) |
|
141 { |
|
142 __ASSERT_DEBUG( iState == EMmsOperationIdle, gPanic( EMmsAlreadyBusy ) ); |
|
143 |
|
144 #ifndef _NO_MMSS_LOGGING_ |
|
145 TMmsLogger::Log( _L("ReceiveMsg StartL") ); |
|
146 #endif |
|
147 // just initialize common member variables |
|
148 CMmsBaseOperation::InitializeL( aSelection, aServerEntry, aService ); |
|
149 |
|
150 iReceivingMode = iMmsSettings->ReceivingModeHome(); |
|
151 |
|
152 iNotificationParent = KMsvNullIndexEntryId; |
|
153 iBad->Reset(); |
|
154 iNotification->Reset(); |
|
155 iResponse->Reset(); // This sets the correct version |
|
156 iMmsHeaders->Reset(); |
|
157 iEntryUnderConstruction = KMsvNullIndexEntryId; |
|
158 iAlreadyDeferred = EFalse; |
|
159 iFileOpen = EFalse; |
|
160 |
|
161 // selection is supposed to point to a bunch of notifications |
|
162 // containing the URIs the messages are to be fetched from |
|
163 TInt count = iCurrentMessageNo; |
|
164 iError = KErrNone; |
|
165 |
|
166 while ( count > 0 && ( iNotificationParent == KMsvNullIndexEntryId ) ) |
|
167 { |
|
168 // Load the notification |
|
169 // iCurrentMessageNo (and therefore also count) has originally been |
|
170 // set to iSelection->Count() so the index is always valid. |
|
171 count--; // indexes are zero based |
|
172 if ( count < iSelection->Count() ) |
|
173 { |
|
174 iError = iServerEntry->SetEntry( iSelection->At( count ) ); |
|
175 } |
|
176 else |
|
177 { |
|
178 iError = KErrNotFound; |
|
179 } |
|
180 if ( iError == KErrNone ) |
|
181 { |
|
182 TMsvEntry entry = iServerEntry->Entry(); |
|
183 iNotificationParent = entry.Parent(); |
|
184 } |
|
185 } |
|
186 |
|
187 // release the last notification |
|
188 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
189 |
|
190 if ( iNotificationParent == KMsvNullIndexEntryId ) |
|
191 { |
|
192 #ifndef _NO_MMSS_LOGGING_ |
|
193 TMmsLogger::Log( _L("- could not access any entry to get parent") ); |
|
194 #endif |
|
195 // nothing to receive. Give up immediately |
|
196 aStatus = KRequestPending; |
|
197 TRequestStatus* status = &aStatus; |
|
198 User::RequestComplete( status, iError ); |
|
199 return; |
|
200 } |
|
201 |
|
202 // Initialize everything into the failed list. |
|
203 // Very pessimistic indeed. |
|
204 |
|
205 iBad->SetReserveL( iCurrentMessageNo ); |
|
206 |
|
207 Queue( aStatus ); |
|
208 |
|
209 // We complete ourselves to get into the state machine loop. |
|
210 // The first thing to do is to check the roaming state. |
|
211 FallThrough(); |
|
212 |
|
213 } |
|
214 |
|
215 // --------------------------------------------------------- |
|
216 // CMmsReceiveMessage::DoComplete |
|
217 // |
|
218 // --------------------------------------------------------- |
|
219 // |
|
220 void CMmsReceiveMessage::DoComplete(TInt& aError ) |
|
221 { |
|
222 |
|
223 #ifndef _NO_MMSS_LOGGING_ |
|
224 TMmsLogger::Log( _L("Receivemsg DoComplete")); |
|
225 #endif |
|
226 // We should get here if we are cancelled, or if |
|
227 // the cycle has completed (with or without error) |
|
228 // Make sure the store is released |
|
229 iDecoder->RelaseDataSink(); |
|
230 |
|
231 // If we have an error, we must delete the entry |
|
232 // under construction. |
|
233 // If we have successfully created the entry, we have set |
|
234 // iEntryUnderConstruction to KMsvNullIndexEntryId. |
|
235 // If iEntryUnderConstruction still points to an entry, it means |
|
236 // that the cycle has been aborted, and the incomplete entry |
|
237 // must be deleted. |
|
238 if ( iEntryUnderConstruction != KMsvNullIndexEntryId ) |
|
239 { |
|
240 if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ) == KErrNone ) |
|
241 { |
|
242 iServerEntry->DeleteEntry ( iEntryUnderConstruction ); |
|
243 } |
|
244 iEntryUnderConstruction = KMsvNullIndexEntryId; |
|
245 } |
|
246 |
|
247 // Set error to entries that are still left |
|
248 // If some of the entries already have an error set, |
|
249 // it is not overridden. |
|
250 UnSetSendMask( *iFailed, aError ); |
|
251 |
|
252 // If we are supporting MMBox, we must also clear the duplicates |
|
253 // if we have notifications in bad list |
|
254 |
|
255 if ( iMmsSettings->MMBoxFolder() != KMsvNullIndexEntryId ) |
|
256 { |
|
257 TInt i = 0; |
|
258 #ifndef _NO_MMSS_LOGGING_ |
|
259 if ( iBad->Count() > 0 ) |
|
260 { |
|
261 TMmsLogger::Log( _L("- %d notifications on bad list "), iBad->Count() ); |
|
262 } |
|
263 #endif |
|
264 |
|
265 for ( i = 0; i < iBad->Count(); i++ ) |
|
266 { |
|
267 if ( iServerEntry->SetEntry( iBad->At( i )) == KErrNone ) |
|
268 { |
|
269 // we don't want to leave here, we do our best |
|
270 TRAP_IGNORE( ClearDuplicateEntryOperationL() ); |
|
271 } |
|
272 } |
|
273 } |
|
274 } |
|
275 |
|
276 // start of ROAMING CHECK handling |
|
277 // --------------------------------------------------------- |
|
278 // CMmsReceiveMessage::RoamingCheck |
|
279 // |
|
280 // --------------------------------------------------------- |
|
281 // |
|
282 void CMmsReceiveMessage::RoamingCheck() |
|
283 { |
|
284 |
|
285 TInt error = KErrNone; |
|
286 |
|
287 #ifndef _NO_MMSS_LOGGING_ |
|
288 TMmsLogger::Log( _L("Receivemsg roaming check start")); |
|
289 #endif |
|
290 |
|
291 if ( !iMmsSettings->LocalMode() && !iMmsSettings->FetchOverride() && |
|
292 ( ( iMmsSettings->ReceivingModeHome() != iMmsSettings->ReceivingModeForeign() ) || |
|
293 ( iMmsSettings->ReceivingModeForeign() == EMmsReceivingManual ) || |
|
294 ( iMmsSettings->ReceivingModeForeign() == EMmsReceivingPostpone ) ) ) |
|
295 { |
|
296 // In offline mode we cannot ask if we are roaming - just give up |
|
297 if ( !NetworkOperationsAllowed() ) |
|
298 { |
|
299 #ifndef _NO_MMSS_LOGGING_ |
|
300 TMmsLogger::Log( _L("- Offline mode - cannot check network status")); |
|
301 #endif |
|
302 error = KMmsErrorOfflineMode; |
|
303 iError = error; |
|
304 } |
|
305 else |
|
306 { |
|
307 // if we get an error we have not been able to connect to phone module |
|
308 // and we cannot ask if we are roaming |
|
309 TRAP( error, iPhone = CMmsPhoneClient::NewL() ) |
|
310 } |
|
311 |
|
312 if ( error == KErrNone ) |
|
313 { |
|
314 #ifndef _NO_MMSS_LOGGING_ |
|
315 TMmsLogger::Log( _L("- Receivemsg getting network status")); |
|
316 #endif |
|
317 iPhone->Roaming( iStatus ); |
|
318 } |
|
319 } |
|
320 else |
|
321 { |
|
322 // no roaming check needed |
|
323 #ifndef _NO_MMSS_LOGGING_ |
|
324 TMmsLogger::Log( _L("- Roaming check not needed")); |
|
325 #endif |
|
326 TRequestStatus* status = &iStatus; |
|
327 iStatus = KRequestPending; |
|
328 // 0 = home network. If we don't care, we behave as at home |
|
329 User::RequestComplete( status, 0 ); |
|
330 } |
|
331 |
|
332 if ( error != KErrNone ) |
|
333 { |
|
334 // we got an error - iPhone is not going to complete us |
|
335 TRequestStatus* status = &iStatus; |
|
336 iStatus = KRequestPending; |
|
337 User::RequestComplete( status, error ); |
|
338 } |
|
339 SetActive(); |
|
340 |
|
341 } |
|
342 |
|
343 // --------------------------------------------------------- |
|
344 // CMmsReceiveMessage::GetRoamingState |
|
345 // |
|
346 // --------------------------------------------------------- |
|
347 // |
|
348 void CMmsReceiveMessage::GetRoamingState() |
|
349 { |
|
350 |
|
351 // if current receiving modes are valid, we have to set the message fetch state |
|
352 // according to the receiving mode of the current (home or foreign ) network |
|
353 |
|
354 // Set the message fetch state according to current network value |
|
355 if( iRegistrationStatus != 0 ) |
|
356 { |
|
357 #ifndef _NO_MMSS_LOGGING_ |
|
358 TMmsLogger::Log( _L("roaming") ); |
|
359 #endif |
|
360 iReceivingMode = iMmsSettings->ReceivingModeForeign(); |
|
361 } |
|
362 else |
|
363 { |
|
364 #ifndef _NO_MMSS_LOGGING_ |
|
365 TMmsLogger::Log( _L("in home network") ); |
|
366 #endif |
|
367 iReceivingMode = iMmsSettings->ReceivingModeHome(); |
|
368 } |
|
369 |
|
370 #ifndef _NO_MMSS_LOGGING_ |
|
371 TMmsLogger::Log( _L("- message receiving mode is %d"), iReceivingMode ); |
|
372 #endif |
|
373 |
|
374 // if something is wrong, entries are marked failed. |
|
375 if ( iError != KErrNone ) |
|
376 { |
|
377 // Set error to all entries |
|
378 // If some of the entries already have an error set, |
|
379 // it is not overridden. |
|
380 UnSetSendMask( *iFailed, iError ); |
|
381 |
|
382 } |
|
383 // if we have something in iError, we shall not continue |
|
384 // to open IAP, and RunL will complete. |
|
385 // All entries will be rescheduled |
|
386 |
|
387 } |
|
388 // end of ROAMING CHECK handling |
|
389 |
|
390 // --------------------------------------------------------- |
|
391 // CMmsReceiveMessage::DecodeResponseL |
|
392 // |
|
393 // --------------------------------------------------------- |
|
394 // |
|
395 void CMmsReceiveMessage::DecodeResponseL() |
|
396 { |
|
397 FallThrough(); |
|
398 return; |
|
399 } |
|
400 |
|
401 // --------------------------------------------------------- |
|
402 // CMmsReceiveMessage::ConnectToIapL |
|
403 // |
|
404 // --------------------------------------------------------- |
|
405 // |
|
406 void CMmsReceiveMessage::ConnectToIAPL() |
|
407 { |
|
408 #ifndef _NO_MMSS_LOGGING_ |
|
409 TMmsLogger::Log( _L("Receivemsg open IAP") ); |
|
410 #endif |
|
411 if ( !iMmsSettings->LocalMode() ) |
|
412 { |
|
413 iError = iMmsSettings->ValidateSettings(); |
|
414 } |
|
415 CMmsBaseOperation::ConnectToIAPL(); |
|
416 } |
|
417 |
|
418 // --------------------------------------------------------- |
|
419 // CMmsReceiveMessage::InitializeSessionL |
|
420 // |
|
421 // --------------------------------------------------------- |
|
422 // |
|
423 void CMmsReceiveMessage::InitializeSessionL() |
|
424 { |
|
425 |
|
426 // Here we should connect to MMSC |
|
427 |
|
428 #ifndef _NO_MMSS_LOGGING_ |
|
429 TMmsLogger::Log( _L("Receivemsg Connecting") ); |
|
430 #endif |
|
431 |
|
432 // for testing purposes our messages are in files in the folder |
|
433 // defined in iMmsSettings->iRootFolder. |
|
434 if ( iMmsSettings->LocalMode() ) |
|
435 { |
|
436 HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() ); |
|
437 CleanupStack::PushL( filename ); |
|
438 TPtr fileNamePtr = filename->Des(); |
|
439 fileNamePtr.Copy( iMmsSettings->LocalModeIn() ); |
|
440 iFs.SetSessionPath( fileNamePtr ); |
|
441 CleanupStack::PopAndDestroy( filename ); |
|
442 } |
|
443 |
|
444 CMmsBaseOperation::InitializeSessionL(); |
|
445 |
|
446 } |
|
447 |
|
448 // --------------------------------------------------------- |
|
449 // CMmsReceiveMessage::SubmitTransactionL |
|
450 // |
|
451 // --------------------------------------------------------- |
|
452 // |
|
453 void CMmsReceiveMessage::SubmitTransactionL() |
|
454 { |
|
455 |
|
456 #ifndef _NO_MMSS_LOGGING_ |
|
457 TMmsLogger::Log( _L("Receivemsg Receiving") ); |
|
458 #endif |
|
459 iEntryUnderConstruction = KMsvNullIndexEntryId; |
|
460 iResponse->Reset(); // Reset sets the correct version |
|
461 iAlreadyDeferred = EFalse; |
|
462 iMmsHeaders->Reset(); |
|
463 iEncodeBuffer->Reset(); |
|
464 |
|
465 // We don't totally give up in case of an error. |
|
466 // We may have a long list of entries to handle. |
|
467 // One entry may be garbage while others will be ok. |
|
468 |
|
469 // Call to IsConnected() clears error for a new entry or |
|
470 // sets the error if we are not connected. If we are not |
|
471 // connected, we must terminate the state machine loop |
|
472 if ( !IsConnected() ) |
|
473 { |
|
474 return; |
|
475 } |
|
476 |
|
477 TMsvEntry entry; |
|
478 |
|
479 // Load the notification. If an error occurs, we cannot continue |
|
480 // with this notification. |
|
481 if ( !LoadNotificationL( entry ) ) |
|
482 { |
|
483 // LoadNotificationL sets the state machine active if we can continue |
|
484 // to next entry. |
|
485 // If the situation is hopeless, the state machine is not active, and |
|
486 // the loop terminates |
|
487 return; |
|
488 } |
|
489 |
|
490 |
|
491 TInt size = iNotification->MessageSize(); |
|
492 #ifndef _NO_MMSS_LOGGING_ |
|
493 TMmsLogger::Log( _L("- message size %d"), size); |
|
494 #endif |
|
495 // If the size in notification is bigger than the maximum size we can receive |
|
496 // use the maximum size instead for the memory checks (we are not receiving |
|
497 // more than that anyway) |
|
498 if ( size > iMmsSettings->MaximumReceiveSize() ) |
|
499 { |
|
500 // reduce the size to maximum allowed |
|
501 size = iMmsSettings->MaximumReceiveSize(); |
|
502 } |
|
503 |
|
504 // Now we must check if the message should be rejected or deferred |
|
505 // The function IsNotificationInsaneL() checks if the notification |
|
506 // has incorrect message type or incorrect major version number. |
|
507 // If the message is unrecognized, the response will be "unrecognized" |
|
508 // The funtion sets the status, and later the response will be sent |
|
509 // but there is no need to check for expiration or disk space in |
|
510 // case the message will be rejected anyway. |
|
511 |
|
512 if ( !IsNotificationInsaneL() ) |
|
513 { |
|
514 // Check if message has expired. |
|
515 // If it has, and we are in automatic mode, there is no need |
|
516 // to send a response. |
|
517 if ( !CheckExpirationL() ) |
|
518 { |
|
519 return; |
|
520 } |
|
521 |
|
522 // Check disk space. |
|
523 // we must add the safety margin here... |
|
524 size += KMmsDiskSafetyMargin; |
|
525 |
|
526 // Query about disk space. |
|
527 if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( |
|
528 &iFs, size, iMessageDrive ) ) |
|
529 { |
|
530 iNotification->SetStatus( KMmsMessageStatusDeferred ); |
|
531 iError = KErrDiskFull; |
|
532 } |
|
533 } |
|
534 |
|
535 // if we have got an error for this message (KErrNoMemory or |
|
536 // KErrDiskFull) we must store the information in the notification |
|
537 // entry to discern these situations from cases where there |
|
538 // is something wrong with the actual transaction. |
|
539 if ( iError != KErrNone ) |
|
540 { |
|
541 TInt error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
542 // If we cannot update our entry - that's too bad |
|
543 if ( error == KErrNone ) |
|
544 { |
|
545 TMsvEntry tEntry; |
|
546 tEntry = iServerEntry->Entry(); |
|
547 tEntry.iError = iError; |
|
548 iServerEntry->ChangeEntry( tEntry ); |
|
549 } |
|
550 // we clear the error now. The rest of the branching |
|
551 // is not based on iError but on the notification status |
|
552 iError = KErrNone; |
|
553 // Release the entry |
|
554 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
555 } |
|
556 |
|
557 #ifndef _NO_MMSS_LOGGING_ |
|
558 TMmsLogger::Log( _L("- notification status %d"), iNotification->Status() ); |
|
559 switch ( iNotification->Status() ) |
|
560 { |
|
561 case KMmsMessageStatusRejected: |
|
562 TMmsLogger::Log( _L("- rejected") ); |
|
563 break; |
|
564 case KMmsMessageStatusDeferred: |
|
565 TMmsLogger::Log( _L("- deferred") ); |
|
566 break; |
|
567 case KMmsMessageStatusRetrieved: |
|
568 TMmsLogger::Log( _L("- retrieved") ); |
|
569 break; |
|
570 case KMmsMessageStatusUnrecognized: |
|
571 TMmsLogger::Log( _L("- unrecognized") ); |
|
572 break; |
|
573 default : |
|
574 TMmsLogger::Log( _L("- whatever") ); |
|
575 break; |
|
576 } |
|
577 #endif |
|
578 |
|
579 #ifndef _NO_MMSS_LOGGING_ |
|
580 TMmsLogger::Log( _L("- receiving mode: %d"), iReceivingMode ); |
|
581 #endif |
|
582 |
|
583 // Sending the response tells the MMSC that the |
|
584 // notification has been received and understood. |
|
585 // If we do not want to fetch the message the |
|
586 // WantToFetchThisL() subroutine will change the state |
|
587 // so that after return the response will be sent to MMSC |
|
588 |
|
589 if ( !WantToFetchThisL( entry ) ) |
|
590 { |
|
591 return; |
|
592 } |
|
593 |
|
594 // Now it seems that we are supposed to fetch something |
|
595 // The notification has cleared all our tests and fetching is on |
|
596 |
|
597 // Now we should start a GET transaction with the |
|
598 // URI we obtain from the headers |
|
599 |
|
600 // If we fail to get anything because the message has expired, |
|
601 // we set iEntryUnderConstruction to KMsvNullIndexEntryId |
|
602 // Otherwise we must reschedule the receive |
|
603 |
|
604 // At this point we will invoke the transaction that sends |
|
605 // our get request to MMSC and when the transaction completes, |
|
606 // the data has been stored in our encode buffer, if the status |
|
607 // is KErrNone. Otherwise the completion status will contain the |
|
608 // error code. |
|
609 |
|
610 if ( iMmsSettings->LocalMode() ) |
|
611 { |
|
612 LocalModeFetchL(); |
|
613 // if only local mode, we complete ourselves |
|
614 #ifndef _NO_MMSS_LOGGING_ |
|
615 TMmsLogger::Log( _L("- local mode, completing fetch with status %d"), iError ); |
|
616 #endif |
|
617 if ( !IsActive() ) |
|
618 { |
|
619 // If Local mode fetch fails it already calls ChangeStateL() and becomes active |
|
620 // we cannot set us active a second time |
|
621 FallThrough(); |
|
622 } |
|
623 } |
|
624 else // global mode |
|
625 { |
|
626 // Chunked mode in global mode, too |
|
627 // chunked mode is turned on here - other changes are generic |
|
628 DoCreateEntryL(); |
|
629 iDecoder->InitializeChunkedMode( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer ); |
|
630 // end of chunked preparation |
|
631 |
|
632 // we get this far only if we are connected |
|
633 HBufC* uri = HBufC::NewL( iNotification->ContentLocation().Length() + KMMSBufferExtra ); |
|
634 CleanupStack::PushL( uri ); |
|
635 uri->Des().Copy( iNotification->ContentLocation() ); |
|
636 #ifndef _NO_MMSS_LOGGING_ |
|
637 TMmsLogger::Log( _L("...Fetching from URI: %S"), uri ); |
|
638 #endif |
|
639 iMmsSession->FetchMessageL( |
|
640 *uri, |
|
641 *iEncodeBuffer, |
|
642 // Use this buffer size when in chunked mode |
|
643 KMmsChunkedBufferSize, // tell that only this buffer size is needed |
|
644 *iEncoder, |
|
645 *iDecoder, |
|
646 iStatus ); |
|
647 CleanupStack::PopAndDestroy( uri ); |
|
648 SetActive(); |
|
649 } |
|
650 |
|
651 } |
|
652 |
|
653 // --------------------------------------------------------- |
|
654 // |
|
655 // --------------------------------------------------------- |
|
656 TBool CMmsReceiveMessage::IsConnected() |
|
657 { |
|
658 if ( iConnected ) |
|
659 { |
|
660 // We clear the error at this point to tell that this message |
|
661 // is all right so far. Notifications for failed messages |
|
662 // remain in the selection, and they are rescheduled later |
|
663 // The error is saved in the schedule data for the notification. |
|
664 iError = KErrNone; |
|
665 } |
|
666 else |
|
667 { |
|
668 // We are in a totally hopeless mess. |
|
669 // We don't have a connection. iError should contain the reason |
|
670 // all we can do is give up |
|
671 // If we return from RunL without becoming active again |
|
672 // RunL completes. |
|
673 // That's all we can do here... |
|
674 // The selection arrays have information about |
|
675 // which messages have succeeded and which not. |
|
676 |
|
677 // DoComplete sets an error code to those entries in the |
|
678 // failed list that do not already have their error set. |
|
679 // If we don't know what went wrong, we just say "disconnected" |
|
680 if ( iError == KErrNone ) |
|
681 { |
|
682 iError = KErrDisconnected; |
|
683 } |
|
684 } |
|
685 return iConnected; |
|
686 } |
|
687 |
|
688 // --------------------------------------------------------- |
|
689 // |
|
690 // --------------------------------------------------------- |
|
691 // |
|
692 TBool CMmsReceiveMessage::LoadNotificationL( TMsvEntry& aEntry ) |
|
693 { |
|
694 // set entry to next notification in list |
|
695 iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
696 if ( iError != KErrNone ) |
|
697 { |
|
698 // The code called by SkipEntryL will make us active again |
|
699 // We may now try the next entry. |
|
700 SkipEntryL(); |
|
701 return EFalse; |
|
702 } |
|
703 |
|
704 aEntry = iServerEntry->Entry(); |
|
705 if ( aEntry.iMtmData2 & KMmsNotifyResponseSent ) |
|
706 { |
|
707 iAlreadyDeferred = ETrue; |
|
708 } |
|
709 |
|
710 CMsvStore* store = NULL; |
|
711 |
|
712 TRAP (iError, {store = iServerEntry->ReadStoreL();}); |
|
713 // We have managed to generate some mysterious notifications |
|
714 // where the ReadStoreL fails. |
|
715 // These must be deleted, as they are garbage. |
|
716 // I assume they are used by someone else. |
|
717 // This means we just delete them from our list and forget them |
|
718 // If we cannot get a read store, we cannot do anything with the |
|
719 // schedule either. |
|
720 if ( iError == KErrNoMemory ) |
|
721 { |
|
722 // Out of memory - hopeless. |
|
723 // We return without becoming active again and the |
|
724 // whole loop completes. |
|
725 // We should try to disconnect, but if there is a serious |
|
726 // memory problem I doubt that anything will work. |
|
727 |
|
728 // Release the entry |
|
729 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
730 return EFalse; |
|
731 } |
|
732 |
|
733 if ( iError != KErrNone ) |
|
734 { |
|
735 // don't discard the entry completely now |
|
736 delete store; |
|
737 store = NULL; |
|
738 // The code called by SkipEntryL will make us active again |
|
739 SkipEntryL(); |
|
740 return EFalse; |
|
741 } |
|
742 |
|
743 // We have access to the notification |
|
744 CleanupStack::PushL( store ); |
|
745 iNotification->RestoreL( *store ); |
|
746 CleanupStack::PopAndDestroy( store ); |
|
747 |
|
748 // We must clear deferred status always: |
|
749 // If we did not have enough memory the first time, |
|
750 // the message was deferred. If we now have enough |
|
751 // memory the old status must be cleared |
|
752 |
|
753 iNotification->SetResponseStatus( 0 ); // clear possible old status |
|
754 iNotification->SetResponseTextL( TPtrC() ); // clear possible old text |
|
755 |
|
756 if ( iNotification->Status() == KMmsMessageStatusDeferred ) |
|
757 { |
|
758 iNotification->SetStatus( 0 ); |
|
759 } |
|
760 |
|
761 // We must check if message fetching is deferred or totally off. |
|
762 // if iReceivingMode == EMmsReceivingReject, notification has been deleted already. |
|
763 if ( !iMmsSettings->FetchOverride() && |
|
764 iNotification->Status() == 0 && |
|
765 ( iReceivingMode == EMmsReceivingManual || iReceivingMode == EMmsReceivingPostpone ) ) |
|
766 { |
|
767 iNotification->SetStatus( KMmsMessageStatusDeferred ); |
|
768 } |
|
769 |
|
770 // We get this far only if we are connected |
|
771 aEntry.SetConnected( ETrue ); |
|
772 aEntry.SetSendingState( KMsvSendStateSending ); |
|
773 aEntry.iError = KErrNone; // optimistic... |
|
774 iServerEntry->ChangeEntry( aEntry ); |
|
775 |
|
776 // Release the entry |
|
777 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
778 |
|
779 // Continue with this notification |
|
780 return ETrue; |
|
781 } |
|
782 |
|
783 // --------------------------------------------------------- |
|
784 // |
|
785 // --------------------------------------------------------- |
|
786 // |
|
787 TBool CMmsReceiveMessage::CheckExpirationL() |
|
788 { |
|
789 |
|
790 // If the message has expired, it can be rejected without further ado |
|
791 // We allow a little slack here, if it expired just a few seconds ago, |
|
792 // we still have hope... |
|
793 // use universal time in case user changes location |
|
794 TTime now; |
|
795 TMsvEntry entry; |
|
796 TBool canContinue = ETrue; // optimistic |
|
797 |
|
798 now.UniversalTime(); |
|
799 #ifndef _NO_MMSS_LOGGING_ |
|
800 TMmsLogger::Log( _L("MMS terminal universal datetime: ") ); |
|
801 CMmsBaseOperation::LogDateL( now ); |
|
802 TMmsLogger::Log( _L("MMS message expiry datetime:") ); |
|
803 CMmsBaseOperation::LogNetworkFormatDateL( iNotification->ExpiryDate() ); |
|
804 #endif |
|
805 if ( ( ( iNotification->ExpiryDate() + iMmsSettings->ExpiryOvershoot() ) * KMmsMillion ) < |
|
806 now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() ) |
|
807 { |
|
808 #ifndef _NO_MMSS_LOGGING_ |
|
809 TMmsLogger::Log( _L("message has expired by %d seconds"), |
|
810 ( now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64())/KMmsMillion - |
|
811 iNotification->ExpiryDate() - iMmsSettings->ExpiryOvershoot() ); |
|
812 #endif |
|
813 // If the notification is in inbox or in MMBox folder, fetch will continue. |
|
814 if( entry.Parent() == KMsvGlobalInBoxIndexEntryId || |
|
815 entry.Parent() == iMmsSettings->MMBoxFolder() ) |
|
816 { |
|
817 // Mark the notification expired |
|
818 iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
819 if ( iError == KErrNone ) |
|
820 { |
|
821 entry = iServerEntry->Entry(); |
|
822 entry.iMtmData2 |= KMmsMessageExpired; |
|
823 iServerEntry->ChangeEntry( entry ); |
|
824 } |
|
825 // Release the entry |
|
826 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
827 |
|
828 #ifndef _NO_MMSS_LOGGING_ |
|
829 TMmsLogger::Log( _L("Expired notification. Fetch continues") ); |
|
830 #endif |
|
831 } |
|
832 else |
|
833 { |
|
834 // iError == KErrNone, the last stage will just remove our entry from the list |
|
835 // There is no need to send any reply to an expired message. |
|
836 // The MMSC will not be interested in getting a "reject" |
|
837 // response to an expired message. |
|
838 iResponse->SetStatus( KMmsMessageStatusRejected ); |
|
839 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
840 // return to the beginning of the state machine loop |
|
841 iState = EMmsOperationUpdatingEntryStatus; |
|
842 // The code called by ChangeStateL will make us active again |
|
843 ChangeStateL(); |
|
844 canContinue = EFalse; // loop to next state |
|
845 } |
|
846 } |
|
847 return canContinue; // can continue |
|
848 } |
|
849 |
|
850 // --------------------------------------------------------- |
|
851 // |
|
852 // --------------------------------------------------------- |
|
853 // |
|
854 TBool CMmsReceiveMessage::IsNotificationInsaneL() |
|
855 { |
|
856 TBool isInsane = EFalse; // optimistic |
|
857 // If the message is unrecognized, the response will be "unrecognized" |
|
858 // Either the message type is unknown, or the major version number differs |
|
859 if ( ( iNotification->MmsVersion() & KMmsMajorVersionMask ) != |
|
860 ( iMmsSettings->MmsVersion() & KMmsMajorVersionMask ) ) |
|
861 { |
|
862 // major versions differ, send back 1.0 version response |
|
863 iResponse->SetMmsVersion( KMmsVersion1 ); |
|
864 iNotification->SetStatus( KMmsMessageStatusUnrecognized ); |
|
865 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
866 isInsane = ETrue; |
|
867 } |
|
868 else if ( iNotification->MessageType() != KMmsMessageTypeMNotificationInd && |
|
869 iNotification->MessageType() != KMmsMessageTypeMBoxDescr ) |
|
870 { |
|
871 // We have been pushed something we cannot handle. |
|
872 // delivery reports have been picked out earlier, so they cause |
|
873 // no problems here. |
|
874 iNotification->SetStatus( KMmsMessageStatusUnrecognized ); |
|
875 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
876 isInsane = ETrue; |
|
877 } |
|
878 return isInsane; |
|
879 } |
|
880 |
|
881 // --------------------------------------------------------- |
|
882 // |
|
883 // --------------------------------------------------------- |
|
884 // |
|
885 TBool CMmsReceiveMessage::WantToFetchThisL( TMsvEntry& aEntry ) |
|
886 { |
|
887 if ( ( iReceivingMode != EMmsReceivingAutomatic && !iMmsSettings->FetchOverride() ) || |
|
888 iNotification->Status() == KMmsMessageStatusRejected || |
|
889 iNotification->Status() == KMmsMessageStatusDeferred || |
|
890 iNotification->Status() == KMmsMessageStatusRetrieved || |
|
891 iNotification->Status() == KMmsMessageStatusUnrecognized ) |
|
892 { |
|
893 // We don't want this message for one reason or another |
|
894 // We shall send reject message or deferred message and |
|
895 // remove this notification from the scheduling. |
|
896 // If the fetching is deferred, the notification should remain |
|
897 // in the machine waiting for better times. |
|
898 // If the message is rejected, the notification is deleted. |
|
899 // In both cases the schedule must be removed. A deferred |
|
900 // notification is not rescheduled before the message fetching |
|
901 // is turned on again. |
|
902 |
|
903 // If the whole message is in the extended notification, |
|
904 // the status is "retrieved" |
|
905 |
|
906 // However, if the "deferred" response has already been sent, |
|
907 // we should not send it again |
|
908 |
|
909 iResponse->SetStatus( iNotification->Status() ); |
|
910 |
|
911 if ( iResponse->Status() != KMmsMessageStatusRejected && |
|
912 iResponse->Status() != KMmsMessageStatusDeferred && |
|
913 iResponse->Status() != KMmsMessageStatusRetrieved && |
|
914 iResponse->Status() != KMmsMessageStatusUnrecognized ) |
|
915 { |
|
916 // We have an unlucky message. The notification arrived |
|
917 // while we were supposed to fetch it, but before it was |
|
918 // actually fetched, receiving was turned off. |
|
919 // We try to defer it hoping it can be fetched before it |
|
920 // expires. |
|
921 // A message should be scheduled for fetching only a few |
|
922 // seconds after the notification arrives, so that if the |
|
923 // user manages to turn the fetching off before we fetch |
|
924 // the message we can assume that he does not want this one either |
|
925 // (at least not now). We are a bit conservative, though, |
|
926 // we don't reject this one as it was supposed to be fetched |
|
927 // before it fell into the time trap. |
|
928 iResponse->SetStatus( KMmsMessageStatusDeferred ); |
|
929 } |
|
930 |
|
931 if ( aEntry.iMtmData2 & KMmsNotifyResponseSent ) |
|
932 { |
|
933 // if the notify response has already been sent for this message, |
|
934 // we don't send it again. |
|
935 // When the message fetch state is switched back on, |
|
936 // server Mtm must check the pending notifications and |
|
937 // reschedule them for fetching. |
|
938 // An already deferred notification should not be in our |
|
939 // list, but I'm paranoid and check in case some notification |
|
940 // has fallen into a time trap. |
|
941 iAlreadyDeferred = ETrue; |
|
942 iState = EMmsOperationStoringResponseData; |
|
943 } |
|
944 else |
|
945 { |
|
946 // The function called by ChangeStateL will make us active again |
|
947 iState = EMmsOperationStoringResponseData; |
|
948 } |
|
949 // We are not fetching this message. |
|
950 // Either we send a response to MMSC or we just move to next notification. |
|
951 ChangeStateL(); |
|
952 return EFalse; |
|
953 } |
|
954 return ETrue; |
|
955 } |
|
956 |
|
957 // --------------------------------------------------------- |
|
958 // |
|
959 // --------------------------------------------------------- |
|
960 // |
|
961 void CMmsReceiveMessage::DoCreateEntryL() |
|
962 { |
|
963 |
|
964 #ifndef _NO_MMSS_LOGGING_ |
|
965 TMmsLogger::Log( _L("Receivemsg DoCreateEntryL") ); |
|
966 #endif |
|
967 |
|
968 // We create a message entry into the inbox |
|
969 // it is invisible and in preparation until |
|
970 // we decide that we have successfully fetched the message |
|
971 // The entry must exist before the message is fetched, because |
|
972 // decode puts data into an existing entry, and |
|
973 // creates children to the entry for attachments. |
|
974 |
|
975 // If we have failed in storing data to the entry, it may be non-zero |
|
976 // We try to delete it before creating a new one |
|
977 |
|
978 if ( iEntryUnderConstruction != KMsvNullIndexEntryId ) |
|
979 { |
|
980 if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ) == KErrNone ) |
|
981 { |
|
982 iServerEntry->DeleteEntry ( iEntryUnderConstruction ); |
|
983 } |
|
984 iEntryUnderConstruction = KMsvNullIndexEntryId; |
|
985 } |
|
986 |
|
987 // If the creation of the entry is successful, we |
|
988 // set our entry to point to the newly created entry |
|
989 // to get data content to it. |
|
990 if ( iError == KErrNone ) |
|
991 { |
|
992 TMsvId targetId = KMsvGlobalInBoxIndexEntryId; |
|
993 |
|
994 TMsvEntry tEntry; |
|
995 |
|
996 // set all relevant flags in tMsvEntry |
|
997 tEntry.iType = KUidMsvMessageEntry; |
|
998 tEntry.iMtm = KUidMsgTypeMultimedia; |
|
999 tEntry.iServiceId = iService; |
|
1000 tEntry.SetUnread( ETrue ); |
|
1001 tEntry.SetNew( ETrue ); |
|
1002 tEntry.SetVisible( EFalse ); |
|
1003 tEntry.SetComplete( EFalse ); |
|
1004 tEntry.SetInPreparation( ETrue ); |
|
1005 tEntry.SetReadOnly( EFalse ); |
|
1006 |
|
1007 // Query about disk space. |
|
1008 if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( |
|
1009 &iFs, KMmsIndexEntryExtra, iMessageDrive ) ) |
|
1010 { |
|
1011 // we use standard error code here |
|
1012 iError = KErrDiskFull; |
|
1013 } |
|
1014 if ( iError == KErrNone ) |
|
1015 { |
|
1016 iError = iServerEntry->SetEntry( targetId ); |
|
1017 } |
|
1018 |
|
1019 if ( iError == KErrNone ) |
|
1020 { |
|
1021 iError = iServerEntry->CreateEntry( tEntry ); |
|
1022 } |
|
1023 iEntryUnderConstruction = tEntry.Id(); |
|
1024 if ( iError == KErrNone ) |
|
1025 { |
|
1026 iError = iEntryWrapper->SetCurrentEntry( iEntryUnderConstruction ); |
|
1027 } |
|
1028 } |
|
1029 } |
|
1030 |
|
1031 // --------------------------------------------------------- |
|
1032 // CMmsReceiveMessage::StoreResponseL |
|
1033 // |
|
1034 // --------------------------------------------------------- |
|
1035 // |
|
1036 void CMmsReceiveMessage::StoreResponseL() |
|
1037 { |
|
1038 #ifndef _NO_MMSS_LOGGING_ |
|
1039 TMmsLogger::Log( _L("Receivemsg Store Response") ); |
|
1040 #endif |
|
1041 TInt error; |
|
1042 TInt fatal = EFalse; // fatal error, no use to retry |
|
1043 |
|
1044 // If we have got this far, we don't return to CreateEntry anymore |
|
1045 // even if we encounter backup/restore problems later. |
|
1046 |
|
1047 if ( iError == KErrNone ) |
|
1048 { |
|
1049 // if we have no error, me must retry to make the entry visible |
|
1050 iCriticalState = EMmsOperationStoringResponseData; |
|
1051 } |
|
1052 else |
|
1053 { |
|
1054 iCriticalState = EMmsOperationSendingAck; |
|
1055 } |
|
1056 |
|
1057 // At the moment we should not receive any extra message types, |
|
1058 // so that the only error of this type would |
|
1059 // be wrong type of message either from WAP stack or from MMSC. |
|
1060 // Send request is all right in local mode, as we get back |
|
1061 // the messages we send ourselves. |
|
1062 // We accept the send requests as retrieve confirmations, |
|
1063 // as they are importand during testing phase: |
|
1064 // We can put any message someone has sent into the folder |
|
1065 // representing the simulated MMSC and try to fetch it as |
|
1066 // if it were a real message. |
|
1067 // We can't check the message type if we have encountered an error. |
|
1068 // In that case the headers may not have been correctly decoded |
|
1069 if ( iError == KErrNone && |
|
1070 iResponse->Status() != KMmsMessageStatusRejected && |
|
1071 iResponse->Status() != KMmsMessageStatusDeferred && |
|
1072 iResponse->Status() != KMmsMessageStatusRetrieved && |
|
1073 iMmsHeaders->MessageType() != KMmsMessageTypeMRetrieveConf && |
|
1074 iMmsHeaders->MessageType() != KMmsMessageTypeMSendReq ) |
|
1075 { |
|
1076 iResponse->SetStatus( KMmsMessageStatusUnrecognized ); |
|
1077 iError = KMmsErrorStatusUnsupportedMessage; |
|
1078 } |
|
1079 |
|
1080 // If we have managed to decode the response, it may contain a status |
|
1081 // that must be mapped to an error. The error may be permanent or temporary |
|
1082 |
|
1083 if ( iError == KErrNone ) |
|
1084 { |
|
1085 // we have got a response from MMSC, and decoded it, but in version 1.1 |
|
1086 // or later the response may still contain an error code. |
|
1087 // if response text length was 0, it was deleted |
|
1088 |
|
1089 // - if error is permanent, notification will be deleted. |
|
1090 // - if error is transient, response text is copied to notification |
|
1091 // and UI components may show it to the user if needed. |
|
1092 |
|
1093 // iError is set to the correct value depending on response status |
|
1094 // "fatal" indicates if the error is permanent or temporary |
|
1095 fatal = MapErrorStatus( iMmsHeaders->ResponseStatus() ); |
|
1096 } |
|
1097 |
|
1098 // If we get a transient failure from MMSC, we store the possible text and status code |
|
1099 // into our notification. UI may show the text to the user in case there is something |
|
1100 // the user might do about the failure. Permament failures are stored in the message |
|
1101 // entry. |
|
1102 // The application id is also copied to the notification in case application id is present |
|
1103 // in the message but not in the notification. |
|
1104 // If the application has not been registered or memory runs out, the user may be |
|
1105 // informed that the notification refers to a message that belongs to an application. |
|
1106 |
|
1107 CopyDataFromMessageToNotificationL(); |
|
1108 |
|
1109 // If there has been an error and logging is allowed, dump the buffer into a file |
|
1110 // to support error analysis later |
|
1111 DumpIfNeededL(); |
|
1112 |
|
1113 // We must try to finalize even if we have encountered an error. |
|
1114 // If the decode has failed, iError contains something like "KErrCorrupt". |
|
1115 // If the operation has been successful, we make the entry visible |
|
1116 // and remove the in preparation flag. The user should then be able |
|
1117 // to see the new message entry. |
|
1118 |
|
1119 // free the memory we don't need anymore |
|
1120 if ( iEncodeBuffer ) |
|
1121 { |
|
1122 iEncodeBuffer->Reset(); |
|
1123 } |
|
1124 TMsvEntry tEntry; |
|
1125 |
|
1126 // Check if the message is going to an unregistered application. |
|
1127 // If it is, it's going to be rejected |
|
1128 iRegistered = EFalse; |
|
1129 |
|
1130 if ( iMmsHeaders->ApplicId().Length() > 0 ) |
|
1131 { |
|
1132 iRegistered = RegisteredL( iMmsHeaders->ApplicId() ); |
|
1133 if ( !iRegistered ) |
|
1134 { |
|
1135 // not registered - reject it |
|
1136 iResponse->SetStatus( KMmsMessageStatusRejected ); |
|
1137 // we clear whatever error we may have because we are |
|
1138 // going to reject the message anyway. |
|
1139 iError = KErrNone; |
|
1140 } |
|
1141 } |
|
1142 |
|
1143 // If the message is going to an application we must check if we can free disk |
|
1144 // space by deleting older messages addressed to the same application. |
|
1145 |
|
1146 if ( iError == KErrDiskFull && iRegistered ) |
|
1147 { |
|
1148 // Check if we can free disk space and reschedule the fetch. |
|
1149 // In manual mode the fetch will not be rescheduled. |
|
1150 // If we can free memory we will change the error code to KMmsErrorApplicationDiskFull |
|
1151 // If we cannot free memory, the error code is left as is and the user must |
|
1152 // delete something else in order to be able to receive the message. |
|
1153 DeleteApplicationMessagesL(); |
|
1154 } |
|
1155 |
|
1156 // If we have tried to fetch a message, and got |
|
1157 // EMRUExceeded, we'll reject the message. If it |
|
1158 // was already deferred, no new response is sent. |
|
1159 // The notification will be deleted, it is hopeless. |
|
1160 |
|
1161 if ( iError == KMmsErrorEMRUExceeded ) |
|
1162 { |
|
1163 iResponse->SetStatus( KMmsMessageStatusRejected ); |
|
1164 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1165 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1166 } |
|
1167 |
|
1168 if ( iError != KErrNone || |
|
1169 iResponse->Status() == KMmsMessageStatusRejected || |
|
1170 iResponse->Status() == KMmsMessageStatusDeferred || |
|
1171 iResponse->Status() == KMmsMessageStatusRetrieved || |
|
1172 iResponse->Status() == KMmsMessageStatusUnrecognized ) |
|
1173 { |
|
1174 // If the failure was fatal (permanent error from MMSC) |
|
1175 // we don't send any response back. If the failure was |
|
1176 // not fatal, we send "deferred" hoping we can retry later |
|
1177 if ( fatal ) |
|
1178 { |
|
1179 // The notification is deleted, as we have got an MMS message. |
|
1180 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1181 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1182 // we don't send back a response if failing was fatal. |
|
1183 iResponse->Reset(); |
|
1184 } |
|
1185 else if ( iError == KMmsErrorHTTPConfiguration || |
|
1186 iError == KMmsErrorHTTPNotFound || |
|
1187 iError == KMmsErrorHTTPServerDown || |
|
1188 iError == KMmsErrorHTTPClientError ) |
|
1189 { |
|
1190 // if we have got a HTTP error, there is no sense to send ack back |
|
1191 iResponse->Reset(); |
|
1192 } |
|
1193 else if ( !iAlreadyDeferred && |
|
1194 iResponse->Status() != KMmsMessageStatusRejected && |
|
1195 iResponse->Status() != KMmsMessageStatusRetrieved && |
|
1196 iResponse->Status() != KMmsMessageStatusUnrecognized) |
|
1197 { |
|
1198 iResponse->SetStatus( KMmsMessageStatusDeferred ); |
|
1199 EncodeNotifyResponseL(); |
|
1200 } |
|
1201 else if ( iResponse->Status() == KMmsMessageStatusUnrecognized || |
|
1202 iResponse->Status() == KMmsMessageStatusRejected) |
|
1203 { |
|
1204 EncodeNotifyResponseL(); |
|
1205 } |
|
1206 else if ( iResponse->Status() == KMmsMessageStatusRetrieved ) |
|
1207 { |
|
1208 EncodeNotifyResponseL(); |
|
1209 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1210 iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1211 } |
|
1212 else |
|
1213 { |
|
1214 // We have nothing to send, we hope we can try |
|
1215 // again later. |
|
1216 iResponse->Reset(); |
|
1217 } |
|
1218 } |
|
1219 |
|
1220 #ifndef _NO_MMSS_LOGGING_ |
|
1221 // log the response status we are about to send |
|
1222 TMmsLogger::Log( _L("- Response status to be: %d"), iResponse->Status() ); |
|
1223 #endif |
|
1224 |
|
1225 // If we have no entry, the fetching has failed. If the failing was fatal, |
|
1226 // the notification has been appended to the iBad list. |
|
1227 // It will be deleted from the iFailed list later. |
|
1228 // Those entries that end in the iBad list are just |
|
1229 // deleted, not rescheduled. |
|
1230 |
|
1231 TInt applicationMessageStatus = 0; |
|
1232 |
|
1233 // If we got an error, we delete the entry under construction. |
|
1234 // But if the error is "fatal" it means MMSC returned some error message, |
|
1235 // and the error message entry must be kept and shown to the user |
|
1236 // The corresponding notification remains in the failed list |
|
1237 // in order to be rescheduled. |
|
1238 // If the notification was bad, the corresponding notification |
|
1239 // has already been appended to bad list to be removed from |
|
1240 // task scheduler. |
|
1241 if ( iEntryUnderConstruction != KMsvNullIndexEntryId && iError != KErrNone && !fatal ) |
|
1242 { |
|
1243 if ( iMmsSettings->LocalMode() ) |
|
1244 { |
|
1245 CloseLocalFileL( EFalse ); |
|
1246 } |
|
1247 // if setting server entry to inbox fails, deletion of entry will fail, |
|
1248 // but there is nothing we can do about it. |
|
1249 iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ); |
|
1250 iServerEntry->DeleteEntry ( iEntryUnderConstruction ); |
|
1251 iEntryUnderConstruction = KMsvNullIndexEntryId; |
|
1252 } |
|
1253 |
|
1254 if ( iEntryUnderConstruction != KMsvNullIndexEntryId ) |
|
1255 { |
|
1256 // We don't care if this leaves. We just do our best. |
|
1257 // If this function fails, our message will have some extra parts |
|
1258 TRAP( error, HandleMultipartAlternativeL() ); |
|
1259 } |
|
1260 |
|
1261 // If we have an entry we have either successfully fetched a message |
|
1262 // or received an error message about a fatal (permanent) error from MMSC |
|
1263 // The entry must now be made visible to the user. |
|
1264 if ( iEntryUnderConstruction != KMsvNullIndexEntryId ) |
|
1265 { |
|
1266 error = iServerEntry->SetEntry( iEntryUnderConstruction ); |
|
1267 |
|
1268 if ( error == KErrNone ) |
|
1269 { |
|
1270 // we don't check disk space here, as this |
|
1271 // is local mode only: We just save the message id |
|
1272 // for testing purposes. The message id is about 5 bytes |
|
1273 // And we clear possible TID, that makes message shorter than before. |
|
1274 CMsvStore* store = NULL; |
|
1275 TRAP ( error, store = iServerEntry->EditStoreL() ) |
|
1276 if ( store ) |
|
1277 { |
|
1278 CleanupStack::PushL( store ); |
|
1279 } |
|
1280 if ( iMmsSettings->LocalMode() && |
|
1281 iMmsHeaders->MessageId().Length() == 0 ) |
|
1282 { |
|
1283 iMmsHeaders->SetMessageIdL( |
|
1284 iNotification->ContentLocation().Mid( |
|
1285 iMmsSettings->LocalModeIn().Length() ) ); |
|
1286 } |
|
1287 if ( iAlreadyDeferred ) |
|
1288 { |
|
1289 // we need to save the TID from the message to the response |
|
1290 iResponse->SetTidL( iMmsHeaders->Tid() ); |
|
1291 } |
|
1292 // clear TID from the message to prevent the same TID from being used later |
|
1293 // in case the message is copied around. |
|
1294 iMmsHeaders->SetTidL( TPtrC8() ); |
|
1295 // Data is copied in case the message does not contain sender or subject |
|
1296 // Data is copied only if disk space is not below critical level |
|
1297 CopyDataFromNotificationToMessageL(); |
|
1298 if ( store ) |
|
1299 { |
|
1300 TRAP ( error, |
|
1301 { |
|
1302 iMmsHeaders->StoreL(*store); |
|
1303 store->CommitL(); |
|
1304 }); |
|
1305 // If we managed to create the store without leaving, it is on cleanup stack |
|
1306 CleanupStack::PopAndDestroy( store ); |
|
1307 store = NULL; |
|
1308 } |
|
1309 if ( iAlreadyDeferred ) |
|
1310 { |
|
1311 // restore the TID |
|
1312 iMmsHeaders->SetTidL( iResponse->Tid() ); |
|
1313 } |
|
1314 |
|
1315 tEntry = iServerEntry->Entry(); |
|
1316 |
|
1317 // If message contains application id, check, |
|
1318 // if a folder, the name of which is application id is found |
|
1319 // and move the message to this folder. |
|
1320 // If the application is not registered, the message is deleted |
|
1321 applicationMessageStatus = MoveToApplicationFolderIfNeededL( tEntry ); |
|
1322 |
|
1323 if ( applicationMessageStatus != KMmsMessageForUnregisteredApplication ) |
|
1324 { |
|
1325 // reload the entry in case the message was moved |
|
1326 tEntry = iServerEntry->Entry(); |
|
1327 |
|
1328 SetIndexEntryBitsForReceivedMessage( tEntry ); |
|
1329 |
|
1330 // if we cannot make our entry visible because of backup/restore, we must retry. |
|
1331 error = iServerEntry->ChangeEntry( tEntry ); |
|
1332 |
|
1333 // This is the critical point. |
|
1334 // We must return before iEntryUnderConstruction is set to KMsvNullIndexEntryId |
|
1335 // and the notification list is edited |
|
1336 |
|
1337 if ( error <= (TInt) KMsvMediaUnavailable && |
|
1338 error >= (TInt) KMsvIndexRestore && |
|
1339 !iDoNotWaitForBackupEnd ) |
|
1340 { |
|
1341 #ifndef _NO_MMSS_LOGGING_ |
|
1342 TMmsLogger::Log( _L("- must wait for backup end ") ); |
|
1343 #endif |
|
1344 iState = EMmsOperationWaitingForBackupEnd; |
|
1345 // This will take us back to RunL |
|
1346 WaitForBackupEnd(); |
|
1347 return; |
|
1348 } |
|
1349 } |
|
1350 |
|
1351 if ( iMmsSettings->LocalMode() ) |
|
1352 { |
|
1353 CloseLocalFileL( ETrue ); |
|
1354 } |
|
1355 |
|
1356 // done with this entry |
|
1357 iEntryUnderConstruction = KMsvNullIndexEntryId; |
|
1358 } |
|
1359 |
|
1360 // The task manager seems to handle deletion of entries |
|
1361 // gracefully nowadays. We can just delete handled entries |
|
1362 // We delete the notification as soon as possible |
|
1363 // as we don't want it hanging around after the message |
|
1364 // has been successfully fetched |
|
1365 |
|
1366 if ( !fatal ) |
|
1367 { |
|
1368 // Check duplicate before deleting notification entry |
|
1369 if ( iNotificationParent == KMsvGlobalInBoxIndexEntryIdValue || |
|
1370 ( iNotificationParent == iMmsSettings->MMBoxFolder() )) |
|
1371 { |
|
1372 // For the time being Java wants these notifications to be deleted |
|
1373 // and applicationMessageStatus is always 0. |
|
1374 // This may change for other type of applications. |
|
1375 ClearOperationL( applicationMessageStatus ); |
|
1376 } |
|
1377 else |
|
1378 { |
|
1379 // If the notification is not visible to the user, |
|
1380 // we don't need to save the application routing status. |
|
1381 // The rest of the handling can proceed normally - |
|
1382 // the notification will be deleted |
|
1383 applicationMessageStatus = 0; |
|
1384 } |
|
1385 |
|
1386 // If the notification does not need to be left around to inform user, |
|
1387 // it can be deleted now |
|
1388 if ( applicationMessageStatus == 0 ) |
|
1389 { |
|
1390 error = iServerEntry->SetEntry( iNotificationParent ); |
|
1391 if ( error == KErrNone ) |
|
1392 { |
|
1393 iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1394 } |
|
1395 else |
|
1396 { |
|
1397 // we use this list as backup: |
|
1398 // if we cannot delete now, we try again later. |
|
1399 iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1400 } |
|
1401 } |
|
1402 // Even if the notification was left in the inbox, |
|
1403 // it is deleted from the failed list because it needs no more handling |
|
1404 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1405 |
|
1406 // All went well. We can acknowledge the delivery. |
|
1407 // If the MMSC is not interested in the acknowledgement, |
|
1408 // it has sent us no TID. |
|
1409 // If there is no TID, the response won't be sent. |
|
1410 // If Retrieve confirmation has not been sent, it must be |
|
1411 // sent instead of acknowledge indication |
|
1412 |
|
1413 // We don't send an ack back if we have received a response |
|
1414 // from MMSC that indicates a fatal failure. |
|
1415 // Most likely the message was expired or has disappeared |
|
1416 // for some other reason (or did not exist in the first place) |
|
1417 |
|
1418 iResponse->SetStatus( KMmsMessageStatusRetrieved ); |
|
1419 if ( !iAlreadyDeferred ) |
|
1420 { |
|
1421 EncodeNotifyResponseL(); |
|
1422 } |
|
1423 else |
|
1424 { |
|
1425 EncodeAcknowledgeIndicationL(); |
|
1426 } |
|
1427 } |
|
1428 } |
|
1429 |
|
1430 if ( iFileOpen ) |
|
1431 { |
|
1432 iFile.Close(); // just in case... |
|
1433 iFileOpen = EFalse; |
|
1434 } |
|
1435 |
|
1436 // release entry in case we were holding the service entry |
|
1437 // We should not leave our entry pointing to the serive entry |
|
1438 // when we become active, others may want to use it. |
|
1439 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
1440 |
|
1441 iStatus = KRequestPending; |
|
1442 SetActive(); |
|
1443 TRequestStatus* status = &iStatus; |
|
1444 // We propagate the original error no matter what has happened here |
|
1445 User::RequestComplete( status, iError ); |
|
1446 |
|
1447 } |
|
1448 |
|
1449 // --------------------------------------------------------- |
|
1450 // CMmsReceiveMessage::SendAckL |
|
1451 // |
|
1452 // --------------------------------------------------------- |
|
1453 // |
|
1454 void CMmsReceiveMessage::SendAckL() |
|
1455 { |
|
1456 #ifndef _NO_MMSS_LOGGING_ |
|
1457 TMmsLogger::Log( _L("Receivemsg Sending response to receive request") ); |
|
1458 #endif |
|
1459 |
|
1460 // Send response to MMSC. |
|
1461 // response is in iResponse. |
|
1462 // If no reply should actually be sent, length of TID is 0. |
|
1463 |
|
1464 // We may try to send response even if we have encountered an error. |
|
1465 // We try to send "deferred" if we couldn't fetch the message. |
|
1466 // We hope the MMSC will try to keep the message in that case. |
|
1467 |
|
1468 // iResponse has Tid, if it contains something reasonable. |
|
1469 |
|
1470 if ( iResponse->Tid().Length() > 0 ) |
|
1471 { |
|
1472 if ( !iMmsSettings->LocalMode() ) |
|
1473 { |
|
1474 // send the response |
|
1475 iMmsSession->SendMessageL( |
|
1476 iUri->Des(), |
|
1477 *iEncodeBuffer, |
|
1478 *iEncoder, |
|
1479 *iDecoder, |
|
1480 iStatus ); |
|
1481 SetActive(); |
|
1482 } |
|
1483 else |
|
1484 { |
|
1485 iStatus = KRequestPending; |
|
1486 SetActive(); |
|
1487 TRequestStatus* status = &iStatus; |
|
1488 // We propagate the original error no matter what has happened here |
|
1489 User::RequestComplete( status, iError ); |
|
1490 } |
|
1491 } |
|
1492 else |
|
1493 { |
|
1494 // No response to send. |
|
1495 // Just continue to next state. |
|
1496 iStatus = KRequestPending; |
|
1497 SetActive(); |
|
1498 TRequestStatus* status = &iStatus; |
|
1499 // We propagate the original error no matter what has happened here |
|
1500 User::RequestComplete( status, iError ); |
|
1501 } |
|
1502 } |
|
1503 |
|
1504 // --------------------------------------------------------- |
|
1505 // CMmsReceiveMessage::UpdateEntryStatusL() |
|
1506 // |
|
1507 // --------------------------------------------------------- |
|
1508 // |
|
1509 void CMmsReceiveMessage::UpdateEntryStatusL() |
|
1510 { |
|
1511 |
|
1512 #ifndef _NO_MMSS_LOGGING_ |
|
1513 TMmsLogger::Log( _L("Receivemsg Checking response success") ); |
|
1514 #endif |
|
1515 |
|
1516 TInt error; |
|
1517 TMsvEntry tEntry; |
|
1518 TInt count = iBad->Count() - 1; |
|
1519 |
|
1520 // update scheduling info for this notification |
|
1521 error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1522 if ( error == KErrNone ) |
|
1523 { |
|
1524 tEntry = iServerEntry->Entry(); |
|
1525 error = tEntry.iError; |
|
1526 if ( error == KErrNone ) |
|
1527 { |
|
1528 error = iError; |
|
1529 } |
|
1530 // In some rare cases accessing the store for the notification may fail |
|
1531 // in that case the schedule is not updated. |
|
1532 TRAP( error, |
|
1533 { |
|
1534 CMsvStore* store = iServerEntry->EditStoreL(); |
|
1535 CleanupStack::PushL( store ); |
|
1536 CMmsScheduledEntry* mmsScheduledEntry = |
|
1537 CMmsScheduledEntry::NewL( iServerEntry->Entry() ); |
|
1538 CleanupStack::PushL( mmsScheduledEntry ); |
|
1539 mmsScheduledEntry->RestoreL( *store ); |
|
1540 UpdateRecipient( iError, *mmsScheduledEntry ); |
|
1541 mmsScheduledEntry->StoreL( *store ); |
|
1542 store->CommitL(); |
|
1543 CleanupStack::PopAndDestroy( mmsScheduledEntry ); |
|
1544 CleanupStack::PopAndDestroy( store ); |
|
1545 }); |
|
1546 } |
|
1547 |
|
1548 // If the current notification has entered the "bad" list, |
|
1549 // it should not be rescheduled. |
|
1550 // For example, the message may be "deferred" because it is too |
|
1551 // big to ever fit in our phone. It must be deleted from the "failed" |
|
1552 // list, because it should not be rescheduled. |
|
1553 |
|
1554 TInt count2 = iFailed->Count() - 1; |
|
1555 if ( count >= 0 && |
|
1556 count2 >= ( iCurrentMessageNo - 1 ) && |
|
1557 iBad->At( count ) == iFailed->At( iCurrentMessageNo - 1 ) ) |
|
1558 { |
|
1559 // should not be rescheduled. |
|
1560 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1561 } |
|
1562 else if ( iError == KErrNone ) |
|
1563 { |
|
1564 |
|
1565 #ifndef _NO_MMSS_LOGGING_ |
|
1566 TMmsLogger::Log( _L("Receivemsg all is well") ); |
|
1567 #endif |
|
1568 // All is well. |
|
1569 // If message was rejected the notification can be thrown away |
|
1570 |
|
1571 if ( iResponse->Status() == KMmsMessageStatusRejected || |
|
1572 iResponse->Status() == KMmsMessageStatusUnrecognized ) |
|
1573 { |
|
1574 // The notifications in the received list will be deleted. |
|
1575 // If the message was rejected, the notification will be |
|
1576 // deleted. |
|
1577 error = iServerEntry->SetEntry( iNotificationParent ); |
|
1578 if ( error == KErrNone ) |
|
1579 { |
|
1580 iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1581 } |
|
1582 else |
|
1583 { |
|
1584 // we use this list as backup: |
|
1585 // if we cannot delete now, we try again later. |
|
1586 iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1587 } |
|
1588 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1589 } |
|
1590 |
|
1591 if ( iResponse->Status() == KMmsMessageStatusDeferred ) |
|
1592 { |
|
1593 |
|
1594 #ifndef _NO_MMSS_LOGGING_ |
|
1595 TMmsLogger::Log( _L("Receivemsg responsestatus is deferred.") ); |
|
1596 #endif |
|
1597 // we have sent a "deferred" response. |
|
1598 // We should keep the notification, but not reschedule it. |
|
1599 // If we delete it from failed list, it wont get rescheduled. |
|
1600 // If we don't add it into received list, it will not be deleted. |
|
1601 // We must mark, that the "deferred" response was successfully sent |
|
1602 // so that we will not send it again later. |
|
1603 |
|
1604 error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1605 // If we cannot update our entry - that's too bad |
|
1606 // it just means that the response may be sent a second time... |
|
1607 // The system must not get mad about that. |
|
1608 // The system may be unreliable anyway, and some response may get lost. |
|
1609 // We just do our best. |
|
1610 if ( error == KErrNone ) |
|
1611 { |
|
1612 iNotification->SetStatus( KMmsMessageStatusDeferred ); |
|
1613 CMsvStore * store = iServerEntry->EditStoreL(); |
|
1614 CleanupStack::PushL( store ); |
|
1615 iNotification->StoreL( *store ); |
|
1616 store->CommitL(); |
|
1617 CleanupStack::PopAndDestroy( store ); |
|
1618 tEntry = iServerEntry->Entry(); |
|
1619 tEntry.iMtmData2 |= KMmsNotifyResponseSent; |
|
1620 tEntry.iMtmData2 &= ~KMmsDeferredButResponseNotSent; |
|
1621 tEntry.SetConnected( EFalse ); |
|
1622 tEntry.SetFailed( EFalse ); |
|
1623 tEntry.SetSendingState( KMsvSendStateUnknown ); |
|
1624 |
|
1625 #ifndef _NO_MMSS_LOGGING_ |
|
1626 TMmsLogger::Log( _L("Receivemsg notify response sent") ); |
|
1627 #endif |
|
1628 |
|
1629 // change the iMtm type to notification |
|
1630 // and move the notification to the inbox |
|
1631 TBool moveToInbox = EFalse; |
|
1632 |
|
1633 #ifndef _NO_MMSS_LOGGING_ |
|
1634 TMmsLogger::Log( _L("- message receiving mode %d"), iReceivingMode ); |
|
1635 #endif |
|
1636 if( iReceivingMode == EMmsReceivingManual && !iMmsSettings->FetchOverride() ) |
|
1637 { |
|
1638 // Change the iMtm from KUidMsgTypeMultimedia to |
|
1639 // KUidMsgMMSNotification |
|
1640 tEntry.iMtm = KUidMsgMMSNotification; |
|
1641 #ifndef _NO_MMSS_LOGGING_ |
|
1642 TMmsLogger::Log( _L("marking as a notification") ); |
|
1643 #endif |
|
1644 |
|
1645 #ifndef _NO_MMSS_LOGGING_ |
|
1646 TMmsLogger::Log( _L("tentry.iMtm is %d"), tEntry.iMtm.iUid ); |
|
1647 #endif |
|
1648 tEntry.SetVisible( ETrue ); |
|
1649 tEntry.SetComplete( ETrue ); |
|
1650 tEntry.SetInPreparation( EFalse ); |
|
1651 tEntry.SetReadOnly( ETrue ); |
|
1652 // This is a notification, therefore there is no sending time available. |
|
1653 // We can only display the arrival time |
|
1654 tEntry.iDate.UniversalTime(); // this is arrival time |
|
1655 |
|
1656 tEntry.iMtmData1 |= KMmsMessageMobileTerminated; |
|
1657 |
|
1658 // Subject, sender and size are set in CMmsDecode. |
|
1659 // Notification cannot contain multiple recipients |
|
1660 // no need to check or set the multiple recipient bit |
|
1661 |
|
1662 moveToInbox = ETrue; |
|
1663 } |
|
1664 iServerEntry->ChangeEntry( tEntry ); |
|
1665 |
|
1666 |
|
1667 // if manual mode is on and the fetchoverride is not on. |
|
1668 // we have received a notification and sent a notifyresponse to the MMSC |
|
1669 // the notification should be moved to the inbox |
|
1670 if ( moveToInbox ) |
|
1671 { |
|
1672 |
|
1673 #ifndef _NO_MMSS_LOGGING_ |
|
1674 TMmsLogger::Log( _L("Receivemsg notification entry to Inbox") ); |
|
1675 #endif |
|
1676 |
|
1677 if ( iServerEntry->SetEntry( tEntry.Parent() ) == KErrNone ) |
|
1678 { |
|
1679 iServerEntry->MoveEntryWithinService( tEntry.Id(), |
|
1680 KMsvGlobalInBoxIndexEntryIdValue ); |
|
1681 } |
|
1682 } |
|
1683 } |
|
1684 |
|
1685 if ( iReceivingMode != EMmsReceivingAutomatic && !iMmsSettings->FetchOverride() ) |
|
1686 { |
|
1687 // If fetching is on, the message was deferred because of an error. |
|
1688 // In that case we let it remain in the failed list for retries. |
|
1689 // If fetching is deferred, manual or off, we don't keep the failed list, |
|
1690 // The receiving mode must be changed before we retry the operation. |
|
1691 |
|
1692 // Should we remove the schedule... |
|
1693 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
1694 #ifndef _NO_MMSS_LOGGING_ |
|
1695 TMmsLogger::Log( _L("Receivemsg deleting from the iFailedList") ); |
|
1696 #endif |
|
1697 } |
|
1698 } |
|
1699 } |
|
1700 else |
|
1701 { |
|
1702 // keep LINT happy |
|
1703 } |
|
1704 |
|
1705 // release entry in case we were holding the service entry |
|
1706 // We should not leave our entry pointing to the serive entry |
|
1707 // when we become active, others may want to use it. |
|
1708 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
1709 // just return back to the start of the loop |
|
1710 // to handle next message |
|
1711 iStatus = KRequestPending; |
|
1712 SetActive(); |
|
1713 TRequestStatus* status = &iStatus; |
|
1714 // We propagate the original error no matter what has happened here |
|
1715 User::RequestComplete( status, iError ); |
|
1716 |
|
1717 } |
|
1718 |
|
1719 // --------------------------------------------------------- |
|
1720 // CMmsReceiveMessage::EncodeNotifyResponseL |
|
1721 // |
|
1722 // --------------------------------------------------------- |
|
1723 // |
|
1724 void CMmsReceiveMessage::EncodeNotifyResponseL() |
|
1725 { |
|
1726 #ifndef _NO_MMSS_LOGGING_ |
|
1727 TMmsLogger::Log( _L("- encoding m-notifyresp-ind") ); |
|
1728 #endif |
|
1729 iResponse->SetMessageType( KMmsMessageTypeMNotifyRespInd ); |
|
1730 iResponse->SetTidL( iNotification->Tid() ); |
|
1731 // message status has been set before we are called. |
|
1732 iResponse->SetReportAllowed( iMmsSettings->DeliveryReportSendingAllowed() ); |
|
1733 iEncoder->EncodeHeadersL( *iResponse, *iEncodeBuffer ); |
|
1734 } |
|
1735 |
|
1736 // --------------------------------------------------------- |
|
1737 // CMmsReceiveMessage::EncodeAcknowledgeIndicationL |
|
1738 // |
|
1739 // --------------------------------------------------------- |
|
1740 // |
|
1741 void CMmsReceiveMessage::EncodeAcknowledgeIndicationL() |
|
1742 { |
|
1743 #ifndef _NO_MMSS_LOGGING_ |
|
1744 TMmsLogger::Log( _L("- encoding m-acknowledge-ind") ); |
|
1745 #endif |
|
1746 iResponse->SetMessageType( KMmsMessageTypeAcknowledgeInd ); |
|
1747 |
|
1748 // The TID has already been set to iResponse earlier, do not override it here |
|
1749 |
|
1750 // version value is set by the encoder. |
|
1751 // This response has no status. It is only sent when the status is "Retrieved" |
|
1752 iResponse->SetReportAllowed( iMmsSettings->DeliveryReportSendingAllowed() ); |
|
1753 iEncoder->EncodeHeadersL( *iResponse, *iEncodeBuffer ); |
|
1754 } |
|
1755 |
|
1756 // --------------------------------------------------------- |
|
1757 // CMmsReceiveMessage::HandleMultipartAlternativeL() |
|
1758 // |
|
1759 // --------------------------------------------------------- |
|
1760 // |
|
1761 void CMmsReceiveMessage::HandleMultipartAlternativeL() |
|
1762 { |
|
1763 // This is just "best effort" |
|
1764 // If we cannot properly clear the extra attachments, they are just left "as is" |
|
1765 |
|
1766 if ( iMmsHeaders->MultipartType() != KMmsAssignedApplicationVndWapMultipartAlternative ) |
|
1767 { |
|
1768 return; // nothing to do |
|
1769 } |
|
1770 |
|
1771 User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iEntryUnderConstruction ) ); |
|
1772 CMsvStore* store = iEntryWrapper->EditStoreL(); |
|
1773 CleanupStack::PushL( store ); |
|
1774 |
|
1775 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
1776 MMsvAttachmentManagerSync& attachManSync = store->AttachmentManagerExtensionsL(); |
|
1777 |
|
1778 TInt count = attachMan.AttachmentCount(); |
|
1779 |
|
1780 if ( count <= 1 ) |
|
1781 { |
|
1782 CleanupStack::PopAndDestroy( store ); |
|
1783 return; // only one part, keep it |
|
1784 } |
|
1785 |
|
1786 TInt i; |
|
1787 CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL(); |
|
1788 CleanupStack::PushL( mimeHeaders ); |
|
1789 |
|
1790 for ( i = count; i > 0; i-- ) |
|
1791 { |
|
1792 CMsvAttachment* attachInfo = attachMan.GetAttachmentInfoL( i - 1 ); |
|
1793 CleanupStack::PushL( attachInfo ); |
|
1794 TPtrC8 pointer; |
|
1795 pointer.Set( attachInfo->MimeType() ); |
|
1796 HBufC8* temp = NULL; |
|
1797 if ( pointer.Length() == 0 ) |
|
1798 { |
|
1799 // mime type not set. Try mime headers |
|
1800 mimeHeaders->RestoreL( *attachInfo ); |
|
1801 temp = HBufC8::NewL( mimeHeaders->ContentType().Length() + |
|
1802 mimeHeaders->ContentSubType().Length() + 1 ); |
|
1803 temp->Des().Copy( mimeHeaders->ContentType() ); |
|
1804 temp->Des().Append( KMmsSlash8 ); |
|
1805 temp->Des().Append( mimeHeaders->ContentSubType() ); |
|
1806 pointer.Set( temp->Des() ); |
|
1807 } |
|
1808 CleanupStack::PushL( temp ); |
|
1809 if ( pointer.CompareF( KMmsTextPlain ) != 0 ) |
|
1810 { |
|
1811 attachManSync.RemoveAttachmentL( i - 1 ); |
|
1812 count--; |
|
1813 } |
|
1814 CleanupStack::PopAndDestroy( temp ); |
|
1815 CleanupStack::PopAndDestroy( attachInfo ); |
|
1816 temp = NULL; |
|
1817 attachInfo = NULL; |
|
1818 } |
|
1819 |
|
1820 if ( count > 0 ) |
|
1821 { |
|
1822 // we have something left in the selection |
|
1823 // When we commit the store, deleted attachments should disappear |
|
1824 store->CommitL(); |
|
1825 } |
|
1826 |
|
1827 CleanupStack::PopAndDestroy( mimeHeaders ); |
|
1828 CleanupStack::PopAndDestroy( store ); |
|
1829 iEntryWrapper->SetCurrentEntry( KMsvNullIndexEntryId ); |
|
1830 } |
|
1831 |
|
1832 // --------------------------------------------------------- |
|
1833 // CMmsReceiveMessage::::EncodePDUL |
|
1834 // |
|
1835 // --------------------------------------------------------- |
|
1836 // |
|
1837 void CMmsReceiveMessage::EncodePDUL() |
|
1838 { |
|
1839 // This state is used to check what must be done to the notification |
|
1840 #ifndef _NO_MMSS_LOGGING_ |
|
1841 TMmsLogger::Log( _L("CMmsReceiveMessage EncodePDUL - Finalize of continue")); |
|
1842 #endif |
|
1843 |
|
1844 iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1845 |
|
1846 if ( iError != KErrNone ) |
|
1847 { |
|
1848 // The code called by SkipEntryL will make us active again |
|
1849 SkipEntryL(); |
|
1850 return; |
|
1851 } |
|
1852 |
|
1853 TMsvEntry tEntry; |
|
1854 tEntry = iServerEntry->Entry(); |
|
1855 |
|
1856 if ( iReceivingMode == EMmsReceivingAutomatic || iMmsSettings->FetchOverride() ) |
|
1857 { |
|
1858 // if notification is in Inbox, set the fetch flags on |
|
1859 if ( tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue ) |
|
1860 { |
|
1861 // mark the flags to reserve the notification for fetch |
|
1862 MarkNotificationOperationReserved( tEntry, KMmsOperationFetch ); |
|
1863 |
|
1864 iServerEntry->ChangeEntry( tEntry ); |
|
1865 #ifndef _NO_MMSS_LOGGING_ |
|
1866 TMmsLogger::Log( _L("mark notification that is being fetched") ); |
|
1867 #endif |
|
1868 } |
|
1869 // continue fetching |
|
1870 FallThrough(); |
|
1871 return; |
|
1872 } |
|
1873 |
|
1874 // mode is deferred of reject |
|
1875 |
|
1876 // entry is in inbox - clear flags and leave it |
|
1877 if ( tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue ) |
|
1878 { |
|
1879 tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; |
|
1880 tEntry.SetReadOnly( ETrue ); |
|
1881 iServerEntry->ChangeEntry( tEntry ); |
|
1882 #ifndef _NO_MMSS_LOGGING_ |
|
1883 TMmsLogger::Log( _L("notification in inbox. Let it be") ); |
|
1884 #endif |
|
1885 LoopToNextEntryL(); |
|
1886 return; |
|
1887 } |
|
1888 |
|
1889 // entry is in mms folder or mmbox folder |
|
1890 |
|
1891 // already deferred - leave it and loop to next entry |
|
1892 if ( tEntry.iMtmData2 & KMmsNotifyResponseSent ) |
|
1893 { |
|
1894 #ifndef _NO_MMSS_LOGGING_ |
|
1895 TMmsLogger::Log( _L("notification already deferred. Let it be") ); |
|
1896 #endif |
|
1897 tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; |
|
1898 iServerEntry->ChangeEntry( tEntry ); |
|
1899 LoopToNextEntryL(); |
|
1900 return; |
|
1901 } |
|
1902 |
|
1903 // reject mode is on |
|
1904 if ( iReceivingMode == EMmsReceivingReject ) |
|
1905 { |
|
1906 // Let the notification be, if we have received this notification |
|
1907 // earlier in the manual or postpone mode when we have roamed. |
|
1908 // In that case KMmsDeferredButResponseNotSent flag is set. |
|
1909 // Delete it, if it is a new one that has arrives while we are in reject mode |
|
1910 tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; |
|
1911 iServerEntry->ChangeEntry( tEntry ); |
|
1912 if ( !( tEntry.iMtmData2 & KMmsDeferredButResponseNotSent ) ) |
|
1913 { |
|
1914 #ifndef _NO_MMSS_LOGGING_ |
|
1915 TMmsLogger::Log( _L("deleting the notification") ); |
|
1916 #endif |
|
1917 // we ignore the error. If setting entry to parent fails, deletion will fail |
|
1918 iServerEntry->SetEntry( tEntry.Parent() ); |
|
1919 iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1920 } |
|
1921 LoopToNextEntryL(); |
|
1922 return; |
|
1923 } |
|
1924 |
|
1925 // deferred and response not yet sent |
|
1926 |
|
1927 if ( iRegistrationStatus == 0 ) // home network - continue |
|
1928 { |
|
1929 #ifndef _NO_MMSS_LOGGING_ |
|
1930 TMmsLogger::Log( _L("in homenw and deferred mode") ); |
|
1931 #endif |
|
1932 // continue fetching - will send "deferred" response |
|
1933 FallThrough(); |
|
1934 return; |
|
1935 } |
|
1936 |
|
1937 // state is deferred, and we are roaming |
|
1938 |
|
1939 // if the status of the notification is retrieved, this |
|
1940 // notification will be deleted. |
|
1941 // This happens if the notification was extended notification |
|
1942 // and the whole message arrived in the notification. |
|
1943 // When roaming, no response is sent. The extended notification |
|
1944 // is already in the inbox. This notification is deleted. |
|
1945 |
|
1946 CMsvStore* store = iServerEntry->ReadStoreL(); |
|
1947 CleanupStack::PushL( store ); |
|
1948 iNotification->RestoreL( *store ); |
|
1949 CleanupStack::PopAndDestroy( store ); |
|
1950 store = NULL; |
|
1951 |
|
1952 if ( iNotification->Status() == KMmsMessageStatusRetrieved ) |
|
1953 { |
|
1954 #ifndef _NO_MMSS_LOGGING_ |
|
1955 TMmsLogger::Log( _L(" the whole extended notification received") ); |
|
1956 TMmsLogger::Log( _L("deleting the notification") ); |
|
1957 #endif |
|
1958 // ignore error, if setting parent fails, deletion will fail |
|
1959 iServerEntry->SetEntry( tEntry.Parent() ); |
|
1960 iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
1961 LoopToNextEntryL(); |
|
1962 return; |
|
1963 } |
|
1964 |
|
1965 // The notification is not completely fetched, finalize flags |
|
1966 |
|
1967 #ifndef _NO_MMSS_LOGGING_ |
|
1968 TMmsLogger::Log( _L("Finalizing the notification") ); |
|
1969 #endif |
|
1970 iNotification->SetStatus( KMmsMessageStatusDeferred ); |
|
1971 store = iServerEntry->EditStoreL(); |
|
1972 CleanupStack::PushL( store ); |
|
1973 iNotification->StoreL( *store ); |
|
1974 store->CommitL(); |
|
1975 CleanupStack::PopAndDestroy( store ); |
|
1976 store = NULL; |
|
1977 |
|
1978 tEntry.SetConnected( EFalse ); |
|
1979 tEntry.SetFailed( EFalse ); |
|
1980 tEntry.SetSendingState( KMsvSendStateUnknown ); |
|
1981 |
|
1982 tEntry.iMtmData1 |= KMmsMessageMobileTerminated; |
|
1983 |
|
1984 // When roaming it is not allowed to send a notify response |
|
1985 // to MMSC. |
|
1986 tEntry.iMtmData2 |= KMmsDeferredButResponseNotSent; |
|
1987 |
|
1988 // The receiving mode is either manual or postpone, when roaming. |
|
1989 // If the manual mode is on, the mtm type is changed to notification |
|
1990 // and the notification is moved to Inbox. |
|
1991 // |
|
1992 if ( iMmsSettings->ReceivingModeForeign() != EMmsReceivingManual ) |
|
1993 { |
|
1994 // this is all we need |
|
1995 iServerEntry->ChangeEntry( tEntry ); |
|
1996 } |
|
1997 else |
|
1998 { |
|
1999 // Change the iMtm from KUidMsgTypeMultimedia to |
|
2000 // KUidMsgMMSNotification |
|
2001 tEntry.iMtm = KUidMsgMMSNotification; |
|
2002 tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; |
|
2003 #ifndef _NO_MMSS_LOGGING_ |
|
2004 TMmsLogger::Log( _L("marking as a notification") ); |
|
2005 #endif |
|
2006 // Readonly flag has to be set on in inbox. |
|
2007 // Not in mms folder |
|
2008 tEntry.SetReadOnly( ETrue ); |
|
2009 iServerEntry->ChangeEntry( tEntry ); |
|
2010 #ifndef _NO_MMSS_LOGGING_ |
|
2011 TMmsLogger::Log( _L("moving to inbox") ); |
|
2012 #endif |
|
2013 // Ignore error from set entry. If it fails, move will fail (not panic) |
|
2014 // Setting service entry to a folder should not fail. |
|
2015 iServerEntry->SetEntry( tEntry.Parent() ); |
|
2016 iServerEntry->MoveEntryWithinService( tEntry.Id(), KMsvGlobalInBoxIndexEntryIdValue ); |
|
2017 } |
|
2018 |
|
2019 LoopToNextEntryL(); |
|
2020 |
|
2021 } |
|
2022 |
|
2023 // --------------------------------------------------------- |
|
2024 // CMmsReceiveMessage::::SkipEntryL |
|
2025 // |
|
2026 // --------------------------------------------------------- |
|
2027 // |
|
2028 void CMmsReceiveMessage::SkipEntryL() |
|
2029 { |
|
2030 #ifndef _NO_MMSS_LOGGING_ |
|
2031 TMmsLogger::Log( _L("receivemsg - can't access notification") ); |
|
2032 #endif |
|
2033 // If the notification cannot be accessed, we must try the next one |
|
2034 // If the notification was not found, or was used by someone else, |
|
2035 // then nothing can be done. Nothing can be done to the scheduling data. |
|
2036 |
|
2037 // We completely discard only entries that cannot be found |
|
2038 if ( iError == KErrNotFound ) |
|
2039 { |
|
2040 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
2041 } |
|
2042 // we must return to the beginning of the loop without doing anything |
|
2043 iState = EMmsOperationUpdatingEntryStatus; |
|
2044 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
2045 // The code called by ChangeStateL will make us active again |
|
2046 ChangeStateL(); |
|
2047 } |
|
2048 |
|
2049 // --------------------------------------------------------- |
|
2050 // CMmsReceiveMessage::::LoopToNextEntryL |
|
2051 // |
|
2052 // --------------------------------------------------------- |
|
2053 // |
|
2054 void CMmsReceiveMessage::LoopToNextEntryL() |
|
2055 { |
|
2056 // release entry |
|
2057 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
2058 // loop to next entry |
|
2059 iFailed->Delete( iCurrentMessageNo - 1 ); |
|
2060 iState = EMmsOperationUpdatingEntryStatus; |
|
2061 SelectNextState(); |
|
2062 // The code called by ChangeStateL will make us active again |
|
2063 ChangeStateL(); |
|
2064 } |
|
2065 |
|
2066 // --------------------------------------------------------- |
|
2067 // CMmsReceiveMessage::FolderEntryL |
|
2068 // |
|
2069 // --------------------------------------------------------- |
|
2070 // |
|
2071 TInt CMmsReceiveMessage::FolderEntryL( |
|
2072 TMsvId aParent, const TDesC& aFolderName, TMsvId& aFolderId ) |
|
2073 { |
|
2074 aFolderId = KMsvNullIndexEntryId; |
|
2075 |
|
2076 TInt error = KErrNone; |
|
2077 |
|
2078 // get a new entry, don't mess up with the original entry. |
|
2079 CMsvServerEntry* workingEntry = NULL; |
|
2080 TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent ) ); |
|
2081 CleanupStack::PushL( workingEntry ); |
|
2082 |
|
2083 if ( error != KErrNone ) |
|
2084 { |
|
2085 CleanupStack::PopAndDestroy( workingEntry ); // workingEntry |
|
2086 return error; |
|
2087 } |
|
2088 |
|
2089 // Show invisible entries |
|
2090 TMsvSelectionOrdering ordering = |
|
2091 TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByIdReverse, ETrue ); |
|
2092 workingEntry->SetSort( ordering ); |
|
2093 |
|
2094 CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; |
|
2095 error = workingEntry->GetChildrenWithType( KUidMsvFolderEntry, *selection ); |
|
2096 if ( error == KErrNone ) |
|
2097 { |
|
2098 // If selection contains folders, check if the folder is found. |
|
2099 TInt count = selection->Count(); |
|
2100 for ( TInt i = 0; i < count && aFolderId == KMsvNullIndexEntryId; i++ ) |
|
2101 { |
|
2102 error = workingEntry->SetEntry( selection->At( i ) ); |
|
2103 if ( error == KErrNone ) |
|
2104 { |
|
2105 // must be exact match |
|
2106 if ( workingEntry->Entry().iDetails.Compare( aFolderName ) == 0 ) |
|
2107 { |
|
2108 aFolderId = selection->At( i ); |
|
2109 } |
|
2110 } |
|
2111 } |
|
2112 } |
|
2113 delete selection; |
|
2114 selection = NULL; |
|
2115 CleanupStack::PopAndDestroy( workingEntry ); |
|
2116 workingEntry = NULL; |
|
2117 |
|
2118 return error; |
|
2119 |
|
2120 } |
|
2121 |
|
2122 // ----------------------------------------------------------------------------- |
|
2123 // CMmsReceiveMessage::CreateFolderEntryL |
|
2124 // |
|
2125 // ----------------------------------------------------------------------------- |
|
2126 // |
|
2127 TInt CMmsReceiveMessage::CreateFolderEntryL( |
|
2128 TMsvId aParentFolder, const TDesC& aFolderName, TMsvId& aFolderId ) |
|
2129 { |
|
2130 |
|
2131 // Check if the folder already exists under parent folder. |
|
2132 TInt error = FolderEntryL( aParentFolder, aFolderName, aFolderId ); |
|
2133 if ( aFolderId != KMsvNullIndexEntryId || error != KErrNone ) |
|
2134 { |
|
2135 // if error == KErrNone and aFolderId not equal to KMsvNullIndexEntryId |
|
2136 // the folder already exists, and we don't need to create anything |
|
2137 return error; |
|
2138 } |
|
2139 |
|
2140 CMsvServerEntry* serverEntry = NULL; |
|
2141 TRAP( error, serverEntry = iServerEntry->NewEntryL( aParentFolder ) ); |
|
2142 CleanupStack::PushL( serverEntry ); |
|
2143 |
|
2144 if ( error != KErrNone ) |
|
2145 { |
|
2146 CleanupStack::PopAndDestroy( serverEntry ); |
|
2147 return error; |
|
2148 } |
|
2149 |
|
2150 // Create a new folder. |
|
2151 error = serverEntry->SetEntry( aParentFolder ); |
|
2152 |
|
2153 if ( error == KErrNone ) |
|
2154 { |
|
2155 TMsvEntry entry; |
|
2156 entry.iType = KUidMsvFolderEntry; |
|
2157 entry.iMtm = KUidMsvLocalServiceMtm; |
|
2158 entry.iDetails.Set( aFolderName ); |
|
2159 entry.SetVisible( EFalse ); |
|
2160 entry.SetInPreparation( EFalse ); |
|
2161 entry.iServiceId = KMsvLocalServiceIndexEntryId; |
|
2162 error = serverEntry->CreateEntry( entry ); |
|
2163 aFolderId = entry.Id(); |
|
2164 } |
|
2165 CleanupStack::PopAndDestroy( serverEntry ); |
|
2166 serverEntry = NULL; |
|
2167 return error; |
|
2168 |
|
2169 } |
|
2170 |
|
2171 |
|
2172 // --------------------------------------------------------- |
|
2173 // CMmsReceiveMessage::FindDuplicateNotificationL |
|
2174 // |
|
2175 // --------------------------------------------------------- |
|
2176 // |
|
2177 TInt CMmsReceiveMessage::FindDuplicateNotificationL( |
|
2178 TMsvId aParent, CMmsHeaders& aHeaders, TMsvId& aDuplicate ) |
|
2179 { |
|
2180 #ifndef _NO_MMSS_LOGGING_ |
|
2181 TMmsLogger::Log( _L("CMmsReceiveMessage::FindDuplicateNotificationL") ); |
|
2182 #endif |
|
2183 |
|
2184 aDuplicate = KMsvNullIndexEntryId; |
|
2185 |
|
2186 if ( aParent == KMsvNullIndexEntryId ) |
|
2187 { |
|
2188 return KErrNotSupported; |
|
2189 } |
|
2190 |
|
2191 // Get a new entry, dont mess up with our original entry |
|
2192 TInt error = KErrNone; |
|
2193 |
|
2194 CMsvServerEntry* workingEntry = NULL; |
|
2195 TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent )); |
|
2196 CleanupStack::PushL( workingEntry ); |
|
2197 |
|
2198 if ( error != KErrNone ) |
|
2199 { |
|
2200 CleanupStack::PopAndDestroy( workingEntry ); |
|
2201 return error; |
|
2202 } |
|
2203 |
|
2204 CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; |
|
2205 CleanupStack::PushL( selection ); |
|
2206 |
|
2207 error = workingEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection ); |
|
2208 |
|
2209 TInt count = selection->Count(); |
|
2210 if ( count == 0 ) |
|
2211 { |
|
2212 error = KErrNotSupported; |
|
2213 } |
|
2214 |
|
2215 if ( error != KErrNone ) |
|
2216 { |
|
2217 CleanupStack::PopAndDestroy( selection ); |
|
2218 CleanupStack::PopAndDestroy( workingEntry ); |
|
2219 return error; |
|
2220 } |
|
2221 |
|
2222 CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() ); |
|
2223 CleanupStack::PushL( mmsHeaders ); |
|
2224 |
|
2225 for ( TInt i = count; i > 0 && ( aDuplicate == KMsvNullIndexEntryId ); i-- ) |
|
2226 { |
|
2227 error = workingEntry->SetEntry( selection->At( i - 1 ) ); |
|
2228 if ( error == KErrNone ) |
|
2229 { |
|
2230 CMsvStore* store = workingEntry->ReadStoreL(); |
|
2231 CleanupStack::PushL( store ); |
|
2232 mmsHeaders->RestoreL( *store ); |
|
2233 CleanupStack::PopAndDestroy( store ); |
|
2234 |
|
2235 // content location must match |
|
2236 if ( mmsHeaders->ContentLocation().Compare( aHeaders.ContentLocation() ) == 0 ) |
|
2237 { |
|
2238 // Identical. This probably means that we have not sent a response yet, |
|
2239 // and MMSC has sent us a new notification. |
|
2240 |
|
2241 #ifndef _NO_MMSS_LOGGING_ |
|
2242 TMmsLogger::Log( _L("- content locations match") ); |
|
2243 #endif |
|
2244 TMsvEntry entry = workingEntry->Entry(); |
|
2245 aDuplicate = entry.Id(); |
|
2246 } |
|
2247 } |
|
2248 } |
|
2249 |
|
2250 CleanupStack::PopAndDestroy( mmsHeaders ); |
|
2251 CleanupStack::PopAndDestroy( selection ); |
|
2252 CleanupStack::PopAndDestroy( workingEntry ); |
|
2253 |
|
2254 return error; |
|
2255 } |
|
2256 |
|
2257 // --------------------------------------------------------- |
|
2258 // CMmsReceiveMessage::LocalModeFetchL |
|
2259 // |
|
2260 // --------------------------------------------------------- |
|
2261 // |
|
2262 void CMmsReceiveMessage::LocalModeFetchL() |
|
2263 { |
|
2264 |
|
2265 HBufC* buffer = HBufC::NewL( KMaxFileName ); |
|
2266 CleanupStack::PushL( buffer ); |
|
2267 if ( iNotification->ContentLocation().Length() <= KMaxPath && |
|
2268 iMmsSettings->LocalMode() ) |
|
2269 { |
|
2270 buffer->Des().Copy( iNotification->ContentLocation() ); |
|
2271 } |
|
2272 TPtr temp = buffer->Des(); |
|
2273 #ifndef _NO_MMSS_LOGGING_ |
|
2274 TMmsLogger::Log( _L("...Fetching from : %S"), &temp ); |
|
2275 #endif |
|
2276 |
|
2277 HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() ); |
|
2278 CleanupStack::PushL( filename ); |
|
2279 TPtr fileNamePtr = filename->Des(); |
|
2280 fileNamePtr.Copy( iMmsSettings->LocalModeIn() ); |
|
2281 |
|
2282 if ( iNotification->ContentLocation().Length() <= KMaxPath && |
|
2283 buffer->Des().FindF( fileNamePtr ) == 0 ) |
|
2284 { |
|
2285 // The file reading code is for local mode (simulated MMSC) |
|
2286 // Only one can try to get the file at a time |
|
2287 #ifndef _NO_MMSS_LOGGING_ |
|
2288 TMmsLogger::Log( _L("opening file") ); |
|
2289 #endif |
|
2290 iError = iFile.Open( iFs, temp, EFileShareExclusive ); |
|
2291 |
|
2292 if ( iError == KErrNone ) |
|
2293 { |
|
2294 #ifndef _NO_MMSS_LOGGING_ |
|
2295 TMmsLogger::Log( _L("file opened") ); |
|
2296 #endif |
|
2297 iFileOpen = ETrue; |
|
2298 TInt size = 0; |
|
2299 iError = iFile.Size( size ); |
|
2300 |
|
2301 // Here we try to use chunked buffer. |
|
2302 // Read the message in chunks and keep calling decode |
|
2303 // Before we can do that, we must create the message entry |
|
2304 // Because it must be ready to receive data |
|
2305 // If receiving fails, the entry must be removed |
|
2306 |
|
2307 DoCreateEntryL(); |
|
2308 iDecoder->InitializeChunkedMode( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer ); |
|
2309 TInt chunkSize = KMmsChunkedBufferSize; |
|
2310 if ( iError == KErrNone ) |
|
2311 { |
|
2312 TRAP( iError, iEncodeBuffer->ResizeL( chunkSize ) ); |
|
2313 } |
|
2314 if ( iError != KErrNone ) |
|
2315 { |
|
2316 #ifndef _NO_MMSS_LOGGING_ |
|
2317 TMmsLogger::Log( _L("Receivemsg can't resize buffer, error %d"), iError ); |
|
2318 TMmsLogger::Log( _L("- message size %d"), chunkSize ); |
|
2319 #endif |
|
2320 iFile.Close(); |
|
2321 iFileOpen = EFalse; |
|
2322 iDecoder->RelaseDataSink(); |
|
2323 CleanupStack::PopAndDestroy( filename ); |
|
2324 CleanupStack::PopAndDestroy( buffer ); |
|
2325 return; |
|
2326 } |
|
2327 |
|
2328 // We now have an open file. |
|
2329 // We read it in chunks and feed it to decoder piecewise |
|
2330 TPtr8 pos = iEncodeBuffer->Ptr( 0 ); |
|
2331 |
|
2332 TInt position = 0; |
|
2333 TInt readData = 0; |
|
2334 TInt amount = 0; |
|
2335 TBool lastChunk = EFalse; |
|
2336 TInt error = KErrNone; |
|
2337 |
|
2338 while ( readData < size && error == KErrNone ) |
|
2339 { |
|
2340 chunkSize = KMmsChunkedBufferSize; |
|
2341 const TInt KMmsTwo = 2; |
|
2342 if ( chunkSize - amount < KMmsChunkedBufferSize / KMmsTwo ) |
|
2343 { |
|
2344 // if almost all data has been left to buffer, increase buffer size |
|
2345 chunkSize = amount + KMmsChunkedBufferSize / KMmsTwo; |
|
2346 } |
|
2347 iEncodeBuffer->ResizeL( chunkSize ); |
|
2348 pos.Set( iEncodeBuffer->Ptr( amount ) ); |
|
2349 pos.SetLength( chunkSize - amount ); |
|
2350 error = iFile.Read( pos, chunkSize - amount ); |
|
2351 amount += pos.Length(); |
|
2352 readData += pos.Length(); |
|
2353 if ( readData >= size ) |
|
2354 { |
|
2355 lastChunk = ETrue; |
|
2356 } |
|
2357 if ( error == KErrNone ) |
|
2358 { |
|
2359 // this is how much data we have |
|
2360 iEncodeBuffer->ResizeL( amount ); |
|
2361 error = iDecoder->NextDataPart( *iEncodeBuffer, position, lastChunk ); |
|
2362 } |
|
2363 if ( position > iEncodeBuffer->Size() ) |
|
2364 { |
|
2365 position = iEncodeBuffer->Size(); |
|
2366 } |
|
2367 // Check if we can continue and shift the buffer if needed |
|
2368 if ( error == KErrNone ) |
|
2369 { |
|
2370 // now position points to the beginning of unhandled data |
|
2371 // it must be shifted to the beginning |
|
2372 amount -= position; // this much left unhandled |
|
2373 if ( amount < 0 ) |
|
2374 { |
|
2375 amount = 0; |
|
2376 } |
|
2377 iEncodeBuffer->Delete( 0, position ); |
|
2378 // start from the beginning the next time |
|
2379 position = 0; |
|
2380 } |
|
2381 } |
|
2382 if ( error != KErrNone ) |
|
2383 { |
|
2384 iError = error; |
|
2385 } |
|
2386 // when the loop ends, all data should be handled and all attachments should be created |
|
2387 // Decode has also saved message headers. |
|
2388 // The changed state indicates what is complete |
|
2389 iDecoder->RelaseDataSink(); |
|
2390 iState = EMmsOperationDecodingResponse; |
|
2391 } |
|
2392 else |
|
2393 { |
|
2394 // This corresponds to the situation, where the message |
|
2395 // has expired or for some other reason is no longer available. |
|
2396 // We lie to RunL that we have already decoded the message |
|
2397 iFile.Close(); |
|
2398 iFileOpen = EFalse; |
|
2399 iState = EMmsOperationDecodingResponse; |
|
2400 if ( iError != KErrInUse ) |
|
2401 { |
|
2402 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
2403 } |
|
2404 } |
|
2405 // We don't close the file yet. |
|
2406 // We want to keep it exclusively to ourselves until we are done with it |
|
2407 } |
|
2408 else |
|
2409 { |
|
2410 // No directory found in notification |
|
2411 // this notification cannot be handled. |
|
2412 // It will be marked bad and deleted. |
|
2413 iError = KErrNotFound; |
|
2414 iState = EMmsOperationDecodingResponse; |
|
2415 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
2416 } |
|
2417 CleanupStack::PopAndDestroy( filename ); |
|
2418 CleanupStack::PopAndDestroy( buffer ); |
|
2419 } |
|
2420 |
|
2421 // --------------------------------------------------------- |
|
2422 // CMmsReceiveMessage::DumpIfNeededL |
|
2423 // |
|
2424 // --------------------------------------------------------- |
|
2425 // |
|
2426 void CMmsReceiveMessage::DumpIfNeededL() |
|
2427 { |
|
2428 #ifndef _NO_MMSS_LOGGING_ |
|
2429 TInt error = KErrNone; |
|
2430 TBool dumpIncoming = EFalse; |
|
2431 // |
|
2432 // Reading binary dumping from CenRep |
|
2433 // |
|
2434 CRepository* repository = NULL; |
|
2435 TInt retval = KErrNone; |
|
2436 TRAP( retval, repository = CRepository::NewL( KUidMmsServerMtm ) ); // *** |
|
2437 if( retval == KErrNone ) |
|
2438 { |
|
2439 CleanupStack::PushL( repository ); |
|
2440 TInt temp = 0; |
|
2441 retval = repository->Get( KMmsEngineBinaryDump, temp ); |
|
2442 if( retval == KErrNone ) |
|
2443 { |
|
2444 dumpIncoming = (TBool)temp; |
|
2445 } |
|
2446 CleanupStack::PopAndDestroy( repository ); |
|
2447 } |
|
2448 |
|
2449 TMmsLogger::Log( _L("Receivemsg Dumping Entry") ); |
|
2450 // If the result was bad, we dump the binary data into file |
|
2451 // - unless decode already did it. |
|
2452 if ( ( ( !dumpIncoming ) && iError != KErrNone ) && |
|
2453 iEncodeBuffer && |
|
2454 iEncodeBuffer->Size() > 0 ) |
|
2455 { |
|
2456 TParse parse; |
|
2457 TFileName fileName; |
|
2458 fileName.Copy( KMmsDefaultLogDirectory ); |
|
2459 TUint att; |
|
2460 if ( iFs.Att( fileName, att ) == KErrNone ) |
|
2461 { |
|
2462 _LIT( KRelated, "Rec.mms"); |
|
2463 parse.Set( fileName, &KRelated, NULL ); |
|
2464 fileName = parse.FullName(); |
|
2465 error = CApaApplication::GenerateFileName( iFs, fileName ); |
|
2466 if ( error == KErrNone ) |
|
2467 { |
|
2468 RFile file; |
|
2469 error = file.Create( iFs, fileName, EFileWrite | EFileShareExclusive ); |
|
2470 // for message id generation |
|
2471 parse.Set( fileName, NULL, NULL ); |
|
2472 |
|
2473 if ( error == KErrNone ) |
|
2474 { |
|
2475 // the data is supposed to be in the encode buffer |
|
2476 TPtr8 ptr = iEncodeBuffer->Ptr( 0 ); |
|
2477 file.Write( ptr ); |
|
2478 file.Flush(); |
|
2479 } |
|
2480 |
|
2481 // done - close files |
|
2482 file.Close(); |
|
2483 } |
|
2484 } |
|
2485 } |
|
2486 #endif |
|
2487 } |
|
2488 |
|
2489 // --------------------------------------------------------- |
|
2490 // CMmsReceiveMessage::CloseLocalFile |
|
2491 // |
|
2492 // --------------------------------------------------------- |
|
2493 // |
|
2494 void CMmsReceiveMessage::CloseLocalFileL( TBool aDeleteFile ) |
|
2495 { |
|
2496 HBufC* buffer = HBufC::NewL( KMaxFileName ); |
|
2497 CleanupStack::PushL( buffer ); |
|
2498 buffer->Des().Copy( iNotification->ContentLocation() ); |
|
2499 HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() ); |
|
2500 CleanupStack::PushL( filename ); |
|
2501 TPtr fileNamePtr = filename->Des(); |
|
2502 fileNamePtr.Copy( iMmsSettings->LocalModeIn() ); |
|
2503 if ( buffer->Des().FindF( fileNamePtr ) == 0 ) |
|
2504 { |
|
2505 // this was our local message file |
|
2506 iFile.Close(); |
|
2507 iFileOpen = EFalse; |
|
2508 if ( aDeleteFile ) |
|
2509 { |
|
2510 iFs.Delete( *buffer ); |
|
2511 } |
|
2512 } |
|
2513 CleanupStack::PopAndDestroy( filename ); |
|
2514 CleanupStack::PopAndDestroy( buffer ); |
|
2515 } |
|
2516 |
|
2517 // --------------------------------------------------------- |
|
2518 // CMmsReceiveMessage::MoveToApplicationFolderIfNeededL |
|
2519 // |
|
2520 // --------------------------------------------------------- |
|
2521 // |
|
2522 TInt CMmsReceiveMessage::MoveToApplicationFolderIfNeededL( TMsvEntry& aEntry ) |
|
2523 { |
|
2524 TInt error = KErrNone; |
|
2525 TInt returnCode = 0; |
|
2526 |
|
2527 if ( iMmsHeaders->ApplicId().Length() > 0 ) |
|
2528 { |
|
2529 // check if application id is registered |
|
2530 if ( iRegistered ) |
|
2531 { |
|
2532 #ifndef _NO_MMSS_LOGGING_ |
|
2533 TMmsLogger::Log( _L("- message to registered application") ); |
|
2534 #endif |
|
2535 TMsvId targetFolder = KMsvNullIndexEntryId; |
|
2536 // target folder's parent is application folder |
|
2537 TMsvId applicationFolder = iMmsSettings->ApplicationFolder(); |
|
2538 // code scanner gives false positive from the next line |
|
2539 error = CreateFolderEntryL( applicationFolder, iMmsHeaders->ApplicId(), targetFolder ); |
|
2540 if ( targetFolder != KMsvNullIndexEntryId && error == KErrNone ) |
|
2541 { |
|
2542 error = iServerEntry->SetEntry( aEntry.Parent() ); |
|
2543 if ( error == KErrNone ) |
|
2544 { |
|
2545 error = iServerEntry->MoveEntryWithinService( aEntry.Id(), targetFolder ); |
|
2546 } |
|
2547 if ( error == KErrNone ) |
|
2548 { |
|
2549 // Message was successfully moved to application folder |
|
2550 // If we want to keep the notification in inbox we return |
|
2551 // KMmsMessageMovedToApplicationFolder. |
|
2552 // As long as we serve only Java applications, the notifications |
|
2553 // will disappear from inbox if the message was moved to application folder. |
|
2554 // Java will start the applet if it is not running, and that should |
|
2555 // be sufficient information for the user. |
|
2556 #ifndef _NO_MMSS_LOGGING_ |
|
2557 TMmsLogger::Log( _L("- moved to application folder") ); |
|
2558 #endif |
|
2559 returnCode = 0; |
|
2560 } |
|
2561 // If we cannot set our entry back to the one we are handling, |
|
2562 // we are in deep trouble |
|
2563 User::LeaveIfError( iServerEntry->SetEntry( iEntryUnderConstruction )); |
|
2564 } |
|
2565 } |
|
2566 else |
|
2567 { |
|
2568 // There was an application id, but the application was not registered |
|
2569 // Message will be deleted |
|
2570 // If deletion fails, the message remains invisible and under construction |
|
2571 // and will be deleted by message server at next boot. |
|
2572 #ifndef _NO_MMSS_LOGGING_ |
|
2573 TMmsLogger::Log( _L("- message to unregistered application - deleted") ); |
|
2574 #endif |
|
2575 error = iServerEntry->SetEntry( aEntry.Parent() ); |
|
2576 if ( error == KErrNone ) |
|
2577 { |
|
2578 iServerEntry->DeleteEntry( aEntry.Id() ); |
|
2579 } |
|
2580 returnCode = KMmsMessageForUnregisteredApplication; |
|
2581 } |
|
2582 } |
|
2583 // If no application id, the message is normal |
|
2584 return returnCode; |
|
2585 } |
|
2586 |
|
2587 // --------------------------------------------------------- |
|
2588 // |
|
2589 // --------------------------------------------------------- |
|
2590 // |
|
2591 void CMmsReceiveMessage::ClearDuplicateEntryOperationL() |
|
2592 { |
|
2593 CMsvStore* store = iServerEntry->ReadStoreL(); |
|
2594 CleanupStack::PushL( store ); |
|
2595 iMmsHeaders->RestoreL( *store ); |
|
2596 CleanupStack::PopAndDestroy( store ); |
|
2597 TMsvId duplicate = KMsvNullIndexEntryId; |
|
2598 TMsvId mmboxFolder = iMmsSettings->MMBoxFolder(); |
|
2599 TMsvEntry dupEntry; |
|
2600 |
|
2601 if ( iNotificationParent == KMsvGlobalInBoxIndexEntryIdValue ) |
|
2602 { |
|
2603 // if duplicate is found from mmbox folder, |
|
2604 // mark it as "deleted from mmbox server" |
|
2605 if ( mmboxFolder != KMsvNullIndexEntryId ) |
|
2606 { |
|
2607 FindDuplicateNotificationL( mmboxFolder, *iMmsHeaders, duplicate ); |
|
2608 } |
|
2609 if ( duplicate != KMsvNullIndexEntryId ) |
|
2610 { |
|
2611 #ifndef _NO_MMSS_LOGGING_ |
|
2612 TMmsLogger::Log( _L("- duplicate found ") ); |
|
2613 #endif |
|
2614 if ( iServerEntry->SetEntry( duplicate ) == KErrNone ) |
|
2615 { |
|
2616 // Mark duplicate as deleted from mmbox server. |
|
2617 // If it was successfully fetched it is no longer in MMBox. |
|
2618 // This is not exactly correct for full MMBox support but as long as |
|
2619 // we don't have full MMBox support this works correctly |
|
2620 dupEntry = iServerEntry->Entry(); |
|
2621 MarkNotificationDeletedFromMmbox( dupEntry ); |
|
2622 iServerEntry->ChangeEntry( dupEntry ); |
|
2623 #ifndef _NO_MMSS_LOGGING_ |
|
2624 TMmsLogger::Log( _L("- duplicate marked as deleted from mmbox ") ); |
|
2625 #endif |
|
2626 } |
|
2627 } |
|
2628 } |
|
2629 else if ( iNotificationParent == mmboxFolder ) |
|
2630 { |
|
2631 duplicate = iMmsHeaders->RelatedEntry(); |
|
2632 if ( duplicate != KMsvNullIndexEntryId ) |
|
2633 { |
|
2634 #ifndef _NO_MMSS_LOGGING_ |
|
2635 TMmsLogger::Log( _L("- duplicate found ") ); |
|
2636 #endif |
|
2637 if ( iServerEntry->SetEntry( duplicate ) == KErrNone ) |
|
2638 { |
|
2639 // Mark it deleted just in case the actual deletion fails. |
|
2640 // This is not exactly correct for full MMBox support but as long as |
|
2641 // we don't have full MMBox support this works correctly |
|
2642 dupEntry = iServerEntry->Entry(); |
|
2643 MarkNotificationDeletedFromMmbox( dupEntry ); |
|
2644 iServerEntry->ChangeEntry( dupEntry ); |
|
2645 // delete the duplicate notification from inbox |
|
2646 if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryIdValue ) |
|
2647 == KErrNone ) |
|
2648 { |
|
2649 TInt err = iServerEntry->DeleteEntry( duplicate ); |
|
2650 #ifndef _NO_MMSS_LOGGING_ |
|
2651 if ( err == KErrNone ) |
|
2652 { |
|
2653 TMmsLogger::Log( _L("- duplicate deleted from inbox ") ); |
|
2654 } |
|
2655 #endif |
|
2656 } |
|
2657 } |
|
2658 } |
|
2659 } |
|
2660 else |
|
2661 { |
|
2662 // nothing to do - just keep compiler and code analyzer tools happy |
|
2663 } |
|
2664 } |
|
2665 |
|
2666 // --------------------------------------------------------- |
|
2667 // |
|
2668 // --------------------------------------------------------- |
|
2669 // |
|
2670 void CMmsReceiveMessage::ClearOperationL( TInt aApplicationMessageStatus ) |
|
2671 { |
|
2672 if ( iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ) == KErrNone ) |
|
2673 { |
|
2674 if ( aApplicationMessageStatus != 0 ) |
|
2675 { |
|
2676 // The entry is not deleted if it is in inbox or MMBox |
|
2677 // and has been routed to application. |
|
2678 // We save the error code or routing status to the entry. |
|
2679 TMsvEntry tEntry = iServerEntry->Entry(); |
|
2680 MarkNotificationDeletedFromMmbox( tEntry ); |
|
2681 tEntry.SetConnected( EFalse ); |
|
2682 tEntry.SetReadOnly( ETrue ); |
|
2683 |
|
2684 if ( aApplicationMessageStatus == KMmsMessageMovedToApplicationFolder ) |
|
2685 { |
|
2686 // This is a successful case |
|
2687 tEntry.iMtmData2 |= KMmsMessageRoutedToApplication; |
|
2688 } |
|
2689 if ( aApplicationMessageStatus == |
|
2690 KMmsMessageForUnregisteredApplication ) |
|
2691 { |
|
2692 // This will be marked as failed operation |
|
2693 // even if the message was actually successfully fetched |
|
2694 // but it was discarded because it does not belong to anybody |
|
2695 tEntry.iError = KMmsErrorUnregisteredApplication; |
|
2696 // The earlier operation cleared the possible MMBox bit |
|
2697 // This operation marks the result as failed. |
|
2698 MarkNotificationOperationFailed( tEntry ); |
|
2699 } |
|
2700 |
|
2701 // error status not checked here - we just do our best |
|
2702 iServerEntry->ChangeEntry( tEntry ); |
|
2703 } |
|
2704 ClearDuplicateEntryOperationL(); |
|
2705 } |
|
2706 } |
|
2707 |
|
2708 |
|
2709 // --------------------------------------------------------- |
|
2710 // |
|
2711 // --------------------------------------------------------- |
|
2712 // |
|
2713 void CMmsReceiveMessage::CopyDataFromNotificationToMessageL() |
|
2714 { |
|
2715 // Only subject and sender take up space when headers are added |
|
2716 TInt size = iNotification->Sender().Length() + |
|
2717 iNotification->Subject().Length(); |
|
2718 if ( size > 0 && |
|
2719 TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &iFs, size, iMessageDrive ) ) |
|
2720 { |
|
2721 size = 0; |
|
2722 } |
|
2723 |
|
2724 // We copy data from notification to message if the values are missing |
|
2725 // But if the message is already complete (status == OK) |
|
2726 // we do not copy anything. |
|
2727 if ( iMmsHeaders->ResponseStatus() > KMmsResponseStatusOK ) |
|
2728 { |
|
2729 // The critical disk space is checked only when adding the subject. |
|
2730 // The sender number is important and only takes a small amount of space |
|
2731 // The other fields take the same amount of space regardless of the value. |
|
2732 // As the headers have been saved already, only subject may consume |
|
2733 // significantly more disk space. |
|
2734 if ( size > 0 ) |
|
2735 { |
|
2736 if ( iMmsHeaders->Subject().Length() == 0 ) |
|
2737 { |
|
2738 iMmsHeaders->SetSubjectL( iNotification->Subject() ); |
|
2739 } |
|
2740 } |
|
2741 if ( iMmsHeaders->Sender().Length() == 0 ) |
|
2742 { |
|
2743 iMmsHeaders->SetSenderL( iNotification->Sender() ); |
|
2744 } |
|
2745 if ( iMmsHeaders->MessageClass() == 0 ) |
|
2746 { |
|
2747 iMmsHeaders->SetMessageClass( iNotification->MessageClass() ); |
|
2748 } |
|
2749 if ( iMmsHeaders->MessagePriority() == 0 ) |
|
2750 { |
|
2751 iMmsHeaders->SetMessagePriority( iNotification->MessagePriority() ); |
|
2752 } |
|
2753 // Copy the expiry, too |
|
2754 if ( iMmsHeaders->ExpiryDate() == 0 && iMmsHeaders->ExpiryInterval() == 0 ) |
|
2755 { |
|
2756 // No expiration data in the message - use what is in the notification |
|
2757 iMmsHeaders->SetExpiryDate( iNotification->ExpiryDate() ); |
|
2758 } |
|
2759 } |
|
2760 } |
|
2761 |
|
2762 // --------------------------------------------------------- |
|
2763 // |
|
2764 // --------------------------------------------------------- |
|
2765 // |
|
2766 void CMmsReceiveMessage::CopyDataFromMessageToNotificationL() |
|
2767 { |
|
2768 TBool saveNotification = EFalse; |
|
2769 TInt error = KErrNone; |
|
2770 |
|
2771 iNotification->SetResponseTextL( iMmsHeaders->ResponseText() ); |
|
2772 iNotification->SetResponseStatus( iMmsHeaders->ResponseStatus() ); |
|
2773 |
|
2774 // Notifications do not originally contain any response texts. |
|
2775 // If the length is not 0, we have added something |
|
2776 if ( iNotification->ResponseText().Length() > 0 || iNotification->ResponseStatus() != 0 ) |
|
2777 { |
|
2778 saveNotification = ETrue; |
|
2779 } |
|
2780 |
|
2781 if ( iNotification->ApplicId().Length() == 0 ) |
|
2782 { |
|
2783 iNotification->SetApplicIdL( iMmsHeaders->ApplicId() ); |
|
2784 if ( iNotification->ApplicId().Length() > 0 ) |
|
2785 { |
|
2786 // If we copied the application id, we must save it. |
|
2787 saveNotification = ETrue; |
|
2788 } |
|
2789 } |
|
2790 |
|
2791 // update the notification |
|
2792 if ( saveNotification ) |
|
2793 { |
|
2794 // We update the notification if we added something |
|
2795 error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ); |
|
2796 if ( error == KErrNone ) |
|
2797 { |
|
2798 TRAP( error, |
|
2799 { |
|
2800 CMsvStore* store = iServerEntry->EditStoreL(); |
|
2801 CleanupStack::PushL( store ); |
|
2802 iNotification->StoreL( *store ); |
|
2803 store->CommitL(); |
|
2804 CleanupStack::PopAndDestroy( store ); |
|
2805 }) |
|
2806 } |
|
2807 // If we cannot update the entry, the user does not see the error text, but that's not fatal |
|
2808 } |
|
2809 // Release the entry |
|
2810 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
2811 |
|
2812 } |
|
2813 |
|
2814 // --------------------------------------------------------- |
|
2815 // |
|
2816 // --------------------------------------------------------- |
|
2817 // |
|
2818 TBool CMmsReceiveMessage::MapErrorStatus( const TInt32 aErrorStatus ) |
|
2819 { |
|
2820 TBool fatal = EFalse; |
|
2821 |
|
2822 switch ( aErrorStatus ) |
|
2823 { |
|
2824 case 0: // if the header is not present, it is 0 |
|
2825 case KMmsStatusOk: |
|
2826 // No error, don't change iError |
|
2827 break; |
|
2828 case KMmsErrorPermanentFailure: |
|
2829 fatal = ETrue; |
|
2830 iError = KMmsErrorStatusPermanentFailure; |
|
2831 break; |
|
2832 case KMmsErrorTransientFailure: |
|
2833 iError = KMmsErrorStatusTransientFailure; |
|
2834 break; |
|
2835 case KMmsErrorReceivePermanentMessageNotFound: |
|
2836 fatal = ETrue; |
|
2837 iError = KMmsErrorStatusMessageNotFound; |
|
2838 break; |
|
2839 case KMmsErrorReceiveTransientMessageNotFound: |
|
2840 iError = KMmsErrorStatusTransientMessageNotFound; |
|
2841 break; |
|
2842 case KMmsErrorReceiveTransientNetworkProblem: |
|
2843 iError = KMmsErrorStatusNetworkProblem; |
|
2844 break; |
|
2845 case KMmsErrorPermanentServiceDenied: |
|
2846 fatal = ETrue; |
|
2847 iError = KMmsErrorStatusServiceDenied; |
|
2848 break; |
|
2849 case KMmsErrorReceivePermanentContentUnsupported: |
|
2850 fatal = ETrue; |
|
2851 iError = KMmsErrorStatusContentUnsupported; |
|
2852 break; |
|
2853 default: |
|
2854 // Unknown error, if not transient, it is fatal |
|
2855 if ( ( aErrorStatus & KMmsErrorRangeMask ) == KMmsErrorTransient ) |
|
2856 { |
|
2857 iError = KMmsErrorStatusTransientFailure; |
|
2858 } |
|
2859 else |
|
2860 { |
|
2861 iError = KMmsErrorPermanentFailure; |
|
2862 fatal = ETrue; |
|
2863 } |
|
2864 break; |
|
2865 } |
|
2866 |
|
2867 return fatal; |
|
2868 } |
|
2869 |
|
2870 // --------------------------------------------------------- |
|
2871 // |
|
2872 // --------------------------------------------------------- |
|
2873 // |
|
2874 void CMmsReceiveMessage::SetIndexEntryBitsForReceivedMessage( TMsvEntry& aEntry ) |
|
2875 { |
|
2876 aEntry.iMtmData1 &= ~KMmsMessageTypeMask; |
|
2877 // We override message type for now. |
|
2878 // We get send requests instead of retrieve confirmations if in local mode |
|
2879 aEntry.iMtmData1 |= KMmsMessageMRetrieveConf | KMmsMessageMobileTerminated; |
|
2880 |
|
2881 aEntry.SetVisible( ETrue ); |
|
2882 aEntry.SetComplete( ETrue ); |
|
2883 aEntry.SetInPreparation( EFalse ); |
|
2884 aEntry.SetReadOnly( ETrue ); |
|
2885 aEntry.iDate.UniversalTime(); // this is arrival time |
|
2886 |
|
2887 if ( iMmsSettings->ShowSentTime() ) |
|
2888 { |
|
2889 // show the time the message was received by MMSC instead of |
|
2890 // the time the message was received by the terminal |
|
2891 if ( iMmsHeaders->Date() > 0 ) |
|
2892 { |
|
2893 // date is given as seconds from 1.1.1970, UTC time |
|
2894 TTime time = TTime( KMmsYear1970String ) + |
|
2895 TTimeIntervalMicroSeconds( iMmsHeaders->Date() * KMmsMillion ); |
|
2896 aEntry.iDate = time.Int64(); |
|
2897 } |
|
2898 } |
|
2899 // subject, sender and size are set in CMmsDecode |
|
2900 // - except if we get an empty error message. |
|
2901 // In that case the fields were copied from the notification, |
|
2902 // and we set sender and subject here. |
|
2903 if ( aEntry.iDetails.Length() == 0 ) |
|
2904 { |
|
2905 aEntry.iDetails.Set( iMmsHeaders->Sender() ); |
|
2906 } |
|
2907 if ( aEntry.iDescription.Length() == 0 ) |
|
2908 { |
|
2909 aEntry.iDescription.Set( iMmsHeaders->Subject() ); |
|
2910 } |
|
2911 |
|
2912 // Set multiple recipients |
|
2913 if ( iMmsHeaders->ToRecipients().MdcaCount() + |
|
2914 iMmsHeaders->CcRecipients().MdcaCount() + |
|
2915 iMmsHeaders->BccRecipients().MdcaCount() > 1 ) |
|
2916 { |
|
2917 aEntry.SetMultipleRecipients( ETrue ); |
|
2918 } |
|
2919 } |
|
2920 |
|
2921 |
|
2922 // --------------------------------------------------------- |
|
2923 // |
|
2924 // --------------------------------------------------------- |
|
2925 // |
|
2926 void CMmsReceiveMessage::DeleteApplicationMessagesL() |
|
2927 { |
|
2928 // target folder's parent is application folder |
|
2929 TMsvId messageFolder = KMsvNullIndexEntryId; |
|
2930 TMsvId applicationFolder = iMmsSettings->ApplicationFolder(); |
|
2931 // code scanner gives false positive from the next line |
|
2932 TInt error = KErrNone; |
|
2933 error = FolderEntryL( applicationFolder, iMmsHeaders->ApplicId(), messageFolder ); |
|
2934 |
|
2935 if ( messageFolder == KMsvNullIndexEntryId || error != KErrNone ) |
|
2936 { |
|
2937 // We could not find the folder - we cannot free space |
|
2938 return; |
|
2939 } |
|
2940 |
|
2941 // List all messages in the folder and try to see if we can free enough room. |
|
2942 TInt size = iNotification->MessageSize(); |
|
2943 if ( size > iMmsSettings->MaximumReceiveSize() ) |
|
2944 { |
|
2945 // We cannot fetch more than this anyway |
|
2946 size = iMmsSettings->MaximumReceiveSize(); |
|
2947 } |
|
2948 // The safety margin must be added to the indicated size as the size in the |
|
2949 // notification only specifies the payload, not all headers and space taken |
|
2950 // by message entry and folder entry needed. |
|
2951 size += KMmsDiskSafetyMargin; |
|
2952 |
|
2953 error = iServerEntry->SetEntry( messageFolder ); |
|
2954 if ( error != KErrNone ) |
|
2955 { |
|
2956 // no can do |
|
2957 return; |
|
2958 } |
|
2959 |
|
2960 // sort entries by date |
|
2961 TMsvSelectionOrdering ordering = |
|
2962 TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByDate, EFalse ); |
|
2963 iServerEntry->SetSort( ordering ); |
|
2964 |
|
2965 CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; |
|
2966 CleanupStack::PushL( selection ); |
|
2967 error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *selection ); |
|
2968 if ( error != KErrNone ) |
|
2969 { |
|
2970 // no can do |
|
2971 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
2972 CleanupStack::PopAndDestroy( selection ); |
|
2973 } |
|
2974 |
|
2975 TInt i; |
|
2976 TInt deleteCount = 0; // entries to be deleted to free space |
|
2977 TInt oldSize = 0; |
|
2978 for ( i = 0; i < selection->Count() && deleteCount == 0; i++ ) |
|
2979 { |
|
2980 error = iServerEntry->SetEntry( selection->At( i ) ); |
|
2981 if ( error == KErrNone ) |
|
2982 { |
|
2983 // If we could not access some entry, it will end up in the |
|
2984 // delete list anyway. It may or may not be deleted. |
|
2985 oldSize += iServerEntry->Entry().iSize; |
|
2986 } |
|
2987 if ( oldSize >= size ) |
|
2988 { |
|
2989 deleteCount = i + 1; |
|
2990 } |
|
2991 } |
|
2992 |
|
2993 // Check if we fond enough old messages to free space. |
|
2994 if ( deleteCount > 0 ) |
|
2995 { |
|
2996 for ( i = selection->Count(); i > deleteCount; i-- ) |
|
2997 { |
|
2998 // We may be able to leave some entries |
|
2999 selection->Delete( i - 1 ); |
|
3000 } |
|
3001 |
|
3002 error = iServerEntry->SetEntry( messageFolder ); |
|
3003 if ( error == KErrNone ) |
|
3004 { |
|
3005 error = iServerEntry->DeleteEntries( *selection ); |
|
3006 } |
|
3007 // If we get an error because some entry is locked or open |
|
3008 // the original KErrNoDisk remains and no entries are deleted |
|
3009 // The situation will follow normal low disk space handling |
|
3010 // If the entries are being accessed by the application, the |
|
3011 // space may be freed soon by the application. |
|
3012 if ( error == KErrNone ) |
|
3013 { |
|
3014 // We have successfully deleted enough entries |
|
3015 // The new message should now fit. |
|
3016 // It can be rescheduled or fetch can be manually restarted |
|
3017 iError = KMmsErrorApplicationDiskFull; |
|
3018 } |
|
3019 } |
|
3020 iServerEntry->SetEntry( KMsvNullIndexEntryId ); |
|
3021 CleanupStack::PopAndDestroy( selection ); |
|
3022 } |
|
3023 |
|
3024 |
|
3025 // ================= OTHER EXPORTED FUNCTIONS ============== |
|
3026 |
|
3027 // End of File |
|
3028 |