|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "csendasmessage.h" |
|
17 |
|
18 #include <u32std.h> |
|
19 #include <mtclbase.h> |
|
20 #include <msvuids.h> |
|
21 #include <mtmuids.h> |
|
22 #include <txtrich.h> |
|
23 #include <mturutils.h> |
|
24 |
|
25 #include "csendassender.h" |
|
26 #include "csendassession.h" |
|
27 #include "csendasattachment.h" |
|
28 #include "csendasmtmmanager.h" |
|
29 #include "sendasserverdefs.h" |
|
30 #include "csendasactivecontainer.h" |
|
31 #include "csendaseditwatcher.h" |
|
32 #include "tsendasserverpanic.h" |
|
33 |
|
34 // max index for incoming RMessage parameters |
|
35 const TInt KSendAsMaxMessageIndex = 3; |
|
36 |
|
37 CSendAsMessage* CSendAsMessage::NewL(CSendAsSession& aSession) |
|
38 { |
|
39 CSendAsMessage* self = new(ELeave) CSendAsMessage(aSession); |
|
40 return self; |
|
41 } |
|
42 |
|
43 CSendAsMessage::~CSendAsMessage() |
|
44 { |
|
45 delete iSender; |
|
46 delete iClientMtm; |
|
47 delete iAttachment; |
|
48 } |
|
49 |
|
50 CSendAsMessage::CSendAsMessage(CSendAsSession& aSession) |
|
51 : iSession(aSession) |
|
52 { |
|
53 // the data members of iProgress are defined such that when they |
|
54 // are zero initialised (like being embedded in a C-Class) this is |
|
55 // the same as the default progress structure. |
|
56 } |
|
57 |
|
58 /** Dispatch the subsession message to the correct handler. |
|
59 |
|
60 The return value indicates to the owner session if we are doing an |
|
61 asynchronous operation. ETrue is async: EFalse is sync. |
|
62 Errors can only be returned by leaving. This method should be encapsulated |
|
63 in a trap harness to prevent the server AO from leaving during a ServiceL. |
|
64 |
|
65 @param aMesasge |
|
66 The IPC message. |
|
67 |
|
68 @return |
|
69 A value of true if the request is asynchronous, otherwise a value of false |
|
70 indicating that the request is synchronous. |
|
71 */ |
|
72 TBool CSendAsMessage::DoSubSessionServiceL(const RMessage2& aMessage) |
|
73 { |
|
74 TBool async = EFalse; |
|
75 |
|
76 switch( aMessage.Function() ) |
|
77 { |
|
78 case ESAMCreateForAccount: |
|
79 { |
|
80 CreateMessageForAccountL(aMessage); |
|
81 } break; |
|
82 case ESAMCreateByType: |
|
83 { |
|
84 CreateMessageByTypeL(aMessage); |
|
85 } break; |
|
86 case ESAMGetProgress: |
|
87 { |
|
88 ProgressL(aMessage); |
|
89 } break; |
|
90 case ESAMDelete: |
|
91 { |
|
92 DeleteMessageL(aMessage); |
|
93 } break; |
|
94 case ESAMSetBodyFirst: |
|
95 { |
|
96 SetBodyTextL(aMessage, ETrue); |
|
97 } break; |
|
98 case ESAMSetBodyNext: |
|
99 { |
|
100 SetBodyTextL(aMessage, EFalse); |
|
101 } break; |
|
102 case ESAMSetSubject: |
|
103 { |
|
104 SetSubjectL(aMessage); |
|
105 } break; |
|
106 case ESAMSetBioType: |
|
107 { |
|
108 SetBioTypeL(aMessage); |
|
109 } break; |
|
110 case ESAMAddRecipient: |
|
111 { |
|
112 AddRecipientL(aMessage); |
|
113 } break; |
|
114 case ESAMAddRecipientWithAlias: |
|
115 { |
|
116 AddRecipientWithAliasL(aMessage); |
|
117 } break; |
|
118 case ESAMTransferAttachmentFile: |
|
119 { |
|
120 TransferAttachmentFileL(aMessage); |
|
121 } break; |
|
122 case ESAMAddAttachment: |
|
123 { |
|
124 AddAttachmentL(aMessage); |
|
125 async = ETrue; |
|
126 } break; |
|
127 case ESAMAddAttachmentWithType: |
|
128 { |
|
129 AddAttachmentWithMimeTypeL(aMessage); |
|
130 async = ETrue; |
|
131 } break; |
|
132 case ESAMAddLinkedAttachment: |
|
133 { |
|
134 AddLinkedAttachmentL(aMessage); |
|
135 async = ETrue; |
|
136 } break; |
|
137 case ESAMAddLinkedAttachmentWithType: |
|
138 { |
|
139 AddLinkedAttachmentWithMimeTypeL(aMessage); |
|
140 async = ETrue; |
|
141 } break; |
|
142 case ESAMCreateAttachment: |
|
143 { |
|
144 // Message will complete upon transfering ownership of file to client. |
|
145 CreateAttachmentL(aMessage); |
|
146 async = ETrue; |
|
147 } break; |
|
148 case ESAMCreateAttachmentWithType: |
|
149 { |
|
150 // Message will complete upon transfering ownership of file to client. |
|
151 CreateAttachmentWithMimeTypeL(aMessage); |
|
152 async = ETrue; |
|
153 } break; |
|
154 case ESAMCancel: |
|
155 { |
|
156 Cancel(); |
|
157 } break; |
|
158 case ESAMLaunchEditor: |
|
159 { |
|
160 LaunchEditorL(aMessage); |
|
161 } break; |
|
162 case ESAMSendMessageConfirmed: |
|
163 { |
|
164 async = ETrue; |
|
165 // drop through to next case... |
|
166 } |
|
167 case ESAMSendMessageConfirmedBackground: |
|
168 { |
|
169 SendMessageL(aMessage, ETrue, !async); |
|
170 } break; |
|
171 case ESAMSendMessage: |
|
172 { |
|
173 async = ETrue; |
|
174 // drop through to next case... |
|
175 } |
|
176 case ESAMSendMessageBackground: |
|
177 { |
|
178 SendMessageL(aMessage, EFalse, !async); |
|
179 } break; |
|
180 case ESAMSaveMessage: |
|
181 { |
|
182 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage)); |
|
183 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
184 |
|
185 DoSaveMessageL(); |
|
186 } break; |
|
187 case ESAMSetCharacterSet: |
|
188 { |
|
189 // For setting the charset encoding value for the message. |
|
190 SetMessageCharacterSetL(aMessage); |
|
191 }break; |
|
192 |
|
193 case ESAMCharSetInfoForAttachment: |
|
194 { |
|
195 // For setting the charset encoding value for the message. |
|
196 SetCharsetInfoForAttachment(aMessage); |
|
197 }break; |
|
198 default: |
|
199 PanicClientL(aMessage, ESendAsClientPanicBadRequest); |
|
200 break; |
|
201 } |
|
202 return async; |
|
203 } |
|
204 |
|
205 /** Cancels any asynchronous activity being done by the message. |
|
206 */ |
|
207 void CSendAsMessage::CancelMessage() |
|
208 { |
|
209 // cancelling is a safe thing to do, like closing. |
|
210 switch( iState ) |
|
211 { |
|
212 case EAddingOrCreatingAttachment: |
|
213 { |
|
214 __ASSERT_DEBUG( iAttachment != NULL, User::Invariant() ); |
|
215 |
|
216 // cancel and then delete the attachment object. |
|
217 iAttachment->Cancel(); |
|
218 |
|
219 delete iAttachment; |
|
220 iAttachment = NULL; |
|
221 } break; |
|
222 case ESendingMessage: |
|
223 { |
|
224 __ASSERT_DEBUG( iSender != NULL, User::Invariant() ); |
|
225 |
|
226 // cancel and then delete the sender object. |
|
227 iSender->Cancel(); |
|
228 |
|
229 delete iSender; |
|
230 iSender = NULL; |
|
231 } break; |
|
232 case EIdle: |
|
233 case EMessageCreated: |
|
234 case ESendingMessageComplete: |
|
235 case EMessageDeleted: |
|
236 case EPendingClose: |
|
237 default: |
|
238 // do nothing as cancel is a safe thing... |
|
239 break; |
|
240 } |
|
241 } |
|
242 |
|
243 /** Allocate a heap buffer to hold a descriptor parameter and copy it in. |
|
244 |
|
245 This method leaves if the desciptor is not valid. This method pushes the buffer |
|
246 onto the cleanup stack and leaves it there when it returns. |
|
247 |
|
248 @param aMessage |
|
249 The IPC message. |
|
250 |
|
251 @param aIndex |
|
252 The index of the parameter to read from the IPC message. |
|
253 |
|
254 @return |
|
255 A pointer to an array populated with the descriptor data. A copy of the pointer |
|
256 is left on the cleanup stack. |
|
257 */ |
|
258 HBufC* CSendAsMessage::GetDesParamLC(const RMessage2& aMessage, TInt aIndex) |
|
259 { |
|
260 __ASSERT_DEBUG((aIndex >=0 && aIndex <=KSendAsMaxMessageIndex), PanicClientL(aMessage, ESendAsClientPanicBadRequestArgument)); |
|
261 |
|
262 TInt len = User::LeaveIfError(aMessage.GetDesLength(aIndex)); |
|
263 HBufC* buffer = HBufC::NewLC(len); |
|
264 TPtr ptr(buffer->Des()); |
|
265 aMessage.Read(aIndex, ptr); |
|
266 return buffer; |
|
267 } |
|
268 |
|
269 /** Allocate a heap buffer to hold a descriptor parameter and copy it in. |
|
270 |
|
271 This method leaves if the desciptor is not valid. This method pushes the buffer |
|
272 onto the cleanup stack and leaves it there when it returns. |
|
273 |
|
274 @param aMessage |
|
275 The IPC message. |
|
276 |
|
277 @param aIndex |
|
278 The index of the parameter to read from the IPC message. |
|
279 |
|
280 @return |
|
281 A pointer to an array populated with the descriptor data. A copy of the pointer |
|
282 is left on the cleanup stack. |
|
283 */ |
|
284 HBufC8* CSendAsMessage::GetDesParam8LC(const RMessage2& aMessage, TInt aIndex) |
|
285 { |
|
286 __ASSERT_DEBUG((aIndex >=0 && aIndex <=KSendAsMaxMessageIndex), PanicClientL(aMessage, ESendAsClientPanicBadRequestArgument)); |
|
287 |
|
288 TInt len = User::LeaveIfError(aMessage.GetDesLength(aIndex)); |
|
289 HBufC8* buffer = HBufC8::NewLC(len); |
|
290 TPtr8 ptr(buffer->Des()); |
|
291 aMessage.Read(aIndex, ptr); |
|
292 return buffer; |
|
293 } |
|
294 |
|
295 /** |
|
296 Create a message in the drafts folder and set up this CSendAsMessage instance to |
|
297 operate on it. |
|
298 |
|
299 This method requires either an MTM UID or a valid account ID. |
|
300 |
|
301 If the MTM UID is NULL, then the account ID must be valid otherwise the method will |
|
302 leave. If the account ID is valid, then the MTM of the account is used. |
|
303 |
|
304 @param aMtm |
|
305 The UID of the MTM for the new message. |
|
306 |
|
307 @param aAccount |
|
308 The account ID under which the message is created. |
|
309 |
|
310 @leave KErrNotFound |
|
311 The MTM UID is NULL and the account ID is not valid. |
|
312 */ |
|
313 void CSendAsMessage::DoCreateMessageL(TUid aMtm, TSendAsAccount aAccount) |
|
314 { |
|
315 // new context |
|
316 CMsvEntry* msvEntry = CMsvEntry::NewL(iSession.GetMsvSessionL(), aAccount, TMsvSelectionOrdering()); |
|
317 CleanupStack::PushL(msvEntry); |
|
318 if( aMtm == KNullUid ) |
|
319 { |
|
320 if( aAccount == KMsvRootIndexEntryId || msvEntry->Entry().iType != KUidMsvServiceEntry ) |
|
321 { |
|
322 // not a valid account |
|
323 User::Leave(KErrNotFound); |
|
324 } |
|
325 // get associated mtm uid |
|
326 aMtm = msvEntry->Entry().iMtm; |
|
327 } |
|
328 |
|
329 // create mtm by uid |
|
330 DeleteClientMtm(); |
|
331 iClientMtm = iSession.GetClientMtmL(aMtm); |
|
332 |
|
333 // if no account provided, get default for this MTM |
|
334 if( aAccount == KMsvRootIndexEntryId ) |
|
335 { |
|
336 aAccount = iClientMtm->DefaultServiceL(); |
|
337 } |
|
338 |
|
339 // create message in drafts folder |
|
340 msvEntry->SetEntryL(KMsvDraftEntryId); |
|
341 |
|
342 // mtm takes ownership of entry context |
|
343 CleanupStack::Pop(msvEntry); |
|
344 iClientMtm->SetCurrentEntryL(msvEntry); |
|
345 |
|
346 // create message |
|
347 iClientMtm->CreateMessageL(aAccount); |
|
348 iMessageType = aMtm; |
|
349 |
|
350 // Change the context of the client MTM to the newly created message entry |
|
351 iClientMtm->SwitchCurrentEntryL(iClientMtm->Entry().EntryId()); |
|
352 |
|
353 // Load the message created so far into the client MTMs cache. This ensures |
|
354 // that SendAs will not overwrite any body text added during the |
|
355 // CreateMessageL routine (such as signature text). |
|
356 // Some MTMs don't actually write anything to store during the |
|
357 // CreateMessageL phase, so the LoadMessageL can leave with KErrNotFound. |
|
358 // It is safe to trap and ignore this as it just means there is no message |
|
359 // body text to be loaded. |
|
360 TRAPD(err, iClientMtm->LoadMessageL()); |
|
361 |
|
362 if (err != KErrNone && err != KErrNotFound) |
|
363 { |
|
364 User::Leave(err); |
|
365 } |
|
366 |
|
367 iState = EMessageCreated; |
|
368 } |
|
369 |
|
370 /** Create a new message in the drafts folder, using the specified account. |
|
371 |
|
372 The account to use is passed from the client in a package buffer, held in |
|
373 parameter 0 of the message. |
|
374 |
|
375 @param aMessage |
|
376 The IPC message. |
|
377 */ |
|
378 void CSendAsMessage::CreateMessageForAccountL(const RMessage2& aMessage) |
|
379 { |
|
380 __ASSERT_ALWAYS( iState == EIdle, PanicClientL(aMessage, ESendAsClientPanicSubsessionInUse) ); |
|
381 |
|
382 TPckgBuf<TSendAsAccount> accountBuf; |
|
383 aMessage.Read(0, accountBuf); |
|
384 |
|
385 DoCreateMessageL(KNullUid, accountBuf()); |
|
386 } |
|
387 |
|
388 /** Create a new message in the drafts folder, of the specified type. |
|
389 |
|
390 The message type (a TUid) to create is passed from the client in a package buffer, |
|
391 held in parameter 0 of the message. |
|
392 |
|
393 @param aMessage |
|
394 The IPC message. |
|
395 */ |
|
396 void CSendAsMessage::CreateMessageByTypeL(const RMessage2& aMessage) |
|
397 { |
|
398 __ASSERT_ALWAYS( iState == EIdle, PanicClientL(aMessage, ESendAsClientPanicSubsessionInUse) ); |
|
399 |
|
400 // extract mtm uid |
|
401 TPckgBuf<TUid> uidBuf; |
|
402 aMessage.Read(0, uidBuf); |
|
403 |
|
404 // create message using default account for this mtm |
|
405 DoCreateMessageL(uidBuf()); |
|
406 } |
|
407 |
|
408 /** Delete the open message from the drafts folder. |
|
409 @param aMessage |
|
410 The IPC message. |
|
411 */ |
|
412 void CSendAsMessage::DeleteMessageL(const RMessage2& aMessage) |
|
413 { |
|
414 // Client code should cancel any outstanding requests prior to deleting |
|
415 // the message. Failure to do so will result in the client being panicked. |
|
416 switch (iState) |
|
417 { |
|
418 case EMessageCreated: |
|
419 { |
|
420 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
421 |
|
422 iClientMtm->Session().RemoveEntry(iClientMtm->Entry().EntryId()); |
|
423 iState = EMessageDeleted; |
|
424 } break; |
|
425 case EIdle: |
|
426 case ESendingMessageComplete: |
|
427 case EPendingClose: |
|
428 break; |
|
429 case ESendingMessage: |
|
430 { |
|
431 PanicClientL(aMessage, ESendAsClientPanicSendingMessage); |
|
432 } break; |
|
433 case EAddingOrCreatingAttachment: |
|
434 { |
|
435 PanicClientL(aMessage, ESendAsClientPanicAddingCreatingAttachment); |
|
436 } break; |
|
437 case EMessageDeleted: |
|
438 default: |
|
439 PanicClientL(aMessage, ESendAsClientPanicMessageAlreadyDeleted); |
|
440 break; |
|
441 } |
|
442 |
|
443 DeleteClientMtm(); |
|
444 } |
|
445 |
|
446 /** Set the body text of the open message. |
|
447 |
|
448 The body text is specified using a CRichText object. This object is streamed |
|
449 into a descriptor which is passed over the IPC boundary in parameter 0 of the |
|
450 message. The CRichText object is then internalised by the server. |
|
451 |
|
452 @param aMessage |
|
453 The IPC message. |
|
454 |
|
455 @param aFirstChunk |
|
456 A flag that indicates whether this is the first chunk of rich text received |
|
457 from the client. |
|
458 */ |
|
459 void CSendAsMessage::SetBodyTextL(const RMessage2& aMessage, TBool aFirstChunk) |
|
460 { |
|
461 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
462 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
463 |
|
464 TInt response = 0; |
|
465 User::LeaveIfError(iClientMtm->QueryCapability(KUidMtmQuerySupportedBody, response)); |
|
466 |
|
467 // This location in the body text at which the text is to be inserted. |
|
468 TInt insertLoc = 0; |
|
469 |
|
470 if( aFirstChunk ) |
|
471 { |
|
472 // Store the size of the signature text. This is added to the body |
|
473 // text on creation of the message by the client MTM. |
|
474 // All added body text is to be added before the signature text. |
|
475 iSignatureSize = iClientMtm->Body().DocumentLength(); |
|
476 } |
|
477 else |
|
478 { |
|
479 // insert added text before the signature text. |
|
480 insertLoc = iClientMtm->Body().DocumentLength() - iSignatureSize; |
|
481 } |
|
482 |
|
483 TInt chunkLength = User::LeaveIfError(aMessage.GetDesLength(0)); |
|
484 HBufC* textBuffer = GetDesParamLC(aMessage, 0); |
|
485 // Append the next chunk to the mtm's CRichText object. |
|
486 TRAPD(insertError, iClientMtm->Body().InsertL(insertLoc, *textBuffer)); |
|
487 if( insertError != KErrNone ) |
|
488 { |
|
489 iClientMtm->Body().Reset(); |
|
490 User::Leave(insertError); |
|
491 } |
|
492 CleanupStack::PopAndDestroy(textBuffer); |
|
493 } |
|
494 |
|
495 /** Set the subject of the open message. |
|
496 |
|
497 The subject is plain text, held in a descriptor passed in parameter 0 of the |
|
498 message. |
|
499 |
|
500 @param aMessage |
|
501 The IPC message. |
|
502 */ |
|
503 void CSendAsMessage::SetSubjectL(const RMessage2& aMessage) |
|
504 { |
|
505 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
506 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
507 |
|
508 HBufC* subject = GetDesParamLC(aMessage, 0); |
|
509 iClientMtm->SetSubjectL(*subject); |
|
510 |
|
511 CleanupStack::PopAndDestroy(subject); |
|
512 } |
|
513 |
|
514 /** Set the BIO type of the message. |
|
515 |
|
516 The BIO type is passed from the client in a package buffer, pointed to by |
|
517 parameter 0 of the message. |
|
518 |
|
519 @param aMessage |
|
520 The IPC message. |
|
521 */ |
|
522 void CSendAsMessage::SetBioTypeL(const RMessage2& aMessage) |
|
523 { |
|
524 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
525 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
526 |
|
527 TPckgBuf<TUid> uidBuf; |
|
528 aMessage.Read(0, uidBuf); |
|
529 iClientMtm->BioTypeChangedL(uidBuf()); |
|
530 |
|
531 TUid bioTypeUid = uidBuf(); |
|
532 iClientMtm->SaveMessageL(); |
|
533 |
|
534 TMsvEntry tempEntry = iClientMtm->Entry().Entry(); |
|
535 tempEntry.iBioType = bioTypeUid.iUid; |
|
536 iClientMtm->Entry().ChangeL(tempEntry); |
|
537 } |
|
538 |
|
539 /** Add a recipient (plus alias) to the message. |
|
540 |
|
541 The recipient's address is passed in a descriptor, pointed to by parameter 0 of |
|
542 the message. The alias is also passed in as a descriptor, this time pointed to |
|
543 by parameter 1. |
|
544 |
|
545 The recipient type (which indicates if a recipient is a To, Cc or Bcc type) is |
|
546 passed inside a package buffer pointed to by parameter 2. |
|
547 |
|
548 @param aMessage |
|
549 The IPC message. |
|
550 */ |
|
551 void CSendAsMessage::AddRecipientWithAliasL(const RMessage2& aMessage) |
|
552 { |
|
553 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
554 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
555 |
|
556 HBufC* address = GetDesParamLC(aMessage, 0); |
|
557 HBufC* alias = GetDesParamLC(aMessage, 1); |
|
558 |
|
559 TPckgBuf<RSendAsMessage::TSendAsRecipientType> recipientTypeBuf; |
|
560 aMessage.Read(2, recipientTypeBuf); |
|
561 |
|
562 // client MTM manages handling of Bcc recipients |
|
563 iClientMtm->AddAddresseeL(recipientTypeBuf(), *address, *alias); |
|
564 |
|
565 CleanupStack::PopAndDestroy(2, address); // alias, address |
|
566 } |
|
567 |
|
568 /** Add a recipient to the message. |
|
569 |
|
570 The recipient's address is passed in a descriptor, pointed to by parameter 0 of |
|
571 the message. |
|
572 |
|
573 The recipient type (which indicates if a recipient is a To, Cc or Bcc type) is |
|
574 passed inside a package buffer pointed to by parameter 1. |
|
575 |
|
576 @param aMessage |
|
577 The IPC message. |
|
578 */ |
|
579 void CSendAsMessage::AddRecipientL(const RMessage2& aMessage) |
|
580 { |
|
581 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
582 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
583 |
|
584 HBufC* address = GetDesParamLC(aMessage, 0); |
|
585 |
|
586 TPckgBuf<RSendAsMessage::TSendAsRecipientType> recipientTypeBuf; |
|
587 aMessage.Read(1, recipientTypeBuf); |
|
588 |
|
589 // call new implementation - let it manage handling of Bcc recipients |
|
590 iClientMtm->AddAddresseeL(recipientTypeBuf(), *address); |
|
591 |
|
592 CleanupStack::PopAndDestroy(address); |
|
593 } |
|
594 |
|
595 /** Prepare the message for subsequent add or create attachment operations. |
|
596 |
|
597 @param aMessage |
|
598 The IPC message. |
|
599 */ |
|
600 void CSendAsMessage::PrepareAddCreateAttachmentL(const RMessage2& aMessage) |
|
601 { |
|
602 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
603 |
|
604 // delete any orphaned attachment object. |
|
605 delete iAttachment; |
|
606 iAttachment = NULL; |
|
607 |
|
608 // queue the IPC message - used to notify the client when the attachment |
|
609 // operation is complete. |
|
610 iQueuedMessage = aMessage; |
|
611 iAttachment = CSendAsAttachment::NewL(*this, *iClientMtm); |
|
612 } |
|
613 |
|
614 /** Take ownership of the RFile attachment |
|
615 |
|
616 @param aMessage |
|
617 The IPC message. |
|
618 */ |
|
619 void CSendAsMessage::TransferAttachmentFileL(const RMessage2& aMessage) |
|
620 { |
|
621 // Close if left open previously. |
|
622 iAttachmentFile.Close(); |
|
623 |
|
624 // need to adopt the file from the client. |
|
625 User::LeaveIfError(iAttachmentFile.AdoptFromClient(aMessage, 0, 1)); |
|
626 } |
|
627 |
|
628 /** Add an attachment to the message. |
|
629 |
|
630 The attachment added to the message is copied into a new attachment by the |
|
631 message server. The new attachment lives in the message store which is private |
|
632 to the msg server. |
|
633 |
|
634 The client must pass a file handle over to the server. The server assumes that |
|
635 this handle allows it to have read access to the open file once it has been adopted. |
|
636 |
|
637 The file handles are passed over in the usual manner. |
|
638 |
|
639 @param aMessage |
|
640 The IPC message. |
|
641 */ |
|
642 void CSendAsMessage::AddAttachmentL(const RMessage2& aMessage) |
|
643 { |
|
644 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
645 |
|
646 PrepareAddCreateAttachmentL(aMessage); |
|
647 iAttachment->AddExistingFileAttachmentL(iAttachmentFile); |
|
648 iState = EAddingOrCreatingAttachment; |
|
649 } |
|
650 |
|
651 /** Add an attachment to the message. |
|
652 |
|
653 The attachment added to the message is copied into a new attachment by the |
|
654 message server. The new attachment lives in the message store which is private |
|
655 to the msg server. |
|
656 |
|
657 The client must pass a file handle over to the server. The server assumes that |
|
658 this handle allows it to have read access to the open file once it has been adopted. |
|
659 |
|
660 The mime type of the attachment is specified in aMessage parameter 2. |
|
661 |
|
662 The file handles are passed over in the usual manner. |
|
663 |
|
664 @param aMessage |
|
665 The IPC message. |
|
666 */ |
|
667 void CSendAsMessage::AddAttachmentWithMimeTypeL(const RMessage2& aMessage) |
|
668 { |
|
669 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
670 |
|
671 HBufC8* mimeType = GetDesParam8LC(aMessage, 0); |
|
672 TUint charset = aMessage.Int1(); |
|
673 |
|
674 PrepareAddCreateAttachmentL(aMessage); |
|
675 iAttachment->AddExistingFileAttachmentWithMimeTypeL(iAttachmentFile, *mimeType, charset); |
|
676 iState = EAddingOrCreatingAttachment; |
|
677 |
|
678 CleanupStack::PopAndDestroy(mimeType); |
|
679 } |
|
680 |
|
681 /** Add an attachment to the message. |
|
682 |
|
683 The filename of the attachment is linked to the message. |
|
684 |
|
685 The file must be in a location which the message server is able to read and it |
|
686 must also remain until the message has been sent or deleted. |
|
687 |
|
688 @param aMessage |
|
689 The IPC message. |
|
690 */ |
|
691 void CSendAsMessage::AddLinkedAttachmentL(const RMessage2& aMessage) |
|
692 { |
|
693 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
694 |
|
695 HBufC* fileName = GetDesParamLC(aMessage, 0); |
|
696 |
|
697 PrepareAddCreateAttachmentL(aMessage); |
|
698 iAttachment->AddFileLinkAttachmentL(*fileName); |
|
699 iState = EAddingOrCreatingAttachment; |
|
700 |
|
701 CleanupStack::PopAndDestroy(fileName); |
|
702 } |
|
703 |
|
704 /** Add an attachment to the message. |
|
705 |
|
706 The filename of the attachment is linked to the message. |
|
707 |
|
708 The file must be in a location which the message server is able to read and it |
|
709 must also remain until the message has been sent or deleted. |
|
710 |
|
711 The mime type of the linked file is supplied. |
|
712 |
|
713 @param aMessage |
|
714 The IPC message. |
|
715 */ |
|
716 void CSendAsMessage::AddLinkedAttachmentWithMimeTypeL(const RMessage2& aMessage) |
|
717 { |
|
718 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
719 |
|
720 HBufC* fileName = GetDesParamLC(aMessage, 0); |
|
721 HBufC8* mimeType = GetDesParam8LC(aMessage, 1); |
|
722 TUint charset = aMessage.Int2(); |
|
723 |
|
724 PrepareAddCreateAttachmentL(aMessage); |
|
725 iAttachment->AddFileLinkAttachmentWithMimeTypeL(*fileName, *mimeType, charset); |
|
726 iState = EAddingOrCreatingAttachment; |
|
727 |
|
728 CleanupStack::PopAndDestroy(2, fileName); // mimeType, fileName |
|
729 } |
|
730 |
|
731 /** Create an empty attachment in the open message. |
|
732 |
|
733 The SendAs server makes the empty attachment and returns a file handle to the |
|
734 client ready for writing. |
|
735 |
|
736 @param aMessage |
|
737 The IPC message. |
|
738 */ |
|
739 void CSendAsMessage::CreateAttachmentL(const RMessage2& aMessage) |
|
740 { |
|
741 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
742 |
|
743 HBufC* fileName = GetDesParamLC(aMessage, 1); |
|
744 |
|
745 PrepareAddCreateAttachmentL(aMessage); |
|
746 iAttachment->CreateNewFileAttachmentL(iAttachmentFile, *fileName); |
|
747 iState = EAddingOrCreatingAttachment; |
|
748 |
|
749 CleanupStack::PopAndDestroy(fileName); |
|
750 } |
|
751 |
|
752 /** Create an empty attachment in the open message. |
|
753 |
|
754 The mime type of the attachment is specified. |
|
755 |
|
756 The SendAs server makes the empty attachment and returns a file handle to the |
|
757 client ready for writing. |
|
758 |
|
759 @param aMessage |
|
760 The IPC message. |
|
761 */ |
|
762 void CSendAsMessage::CreateAttachmentWithMimeTypeL(const RMessage2& aMessage) |
|
763 { |
|
764 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
765 |
|
766 HBufC* fileName = GetDesParamLC(aMessage, 1); |
|
767 |
|
768 HBufC8* mimeType = GetDesParam8LC(aMessage, 2); |
|
769 |
|
770 PrepareAddCreateAttachmentL(aMessage); |
|
771 iAttachment->CreateNewFileAttachmentWithMimeTypeL(iAttachmentFile, *fileName, *mimeType, iCharSet); |
|
772 iState = EAddingOrCreatingAttachment; |
|
773 |
|
774 CleanupStack::PopAndDestroy(2, fileName); // mimeType, fileName |
|
775 } |
|
776 |
|
777 void CSendAsMessage::SetCharsetInfoForAttachment(const RMessage2& aMessage) |
|
778 { |
|
779 iCharSet = aMessage.Int0(); |
|
780 } |
|
781 |
|
782 |
|
783 /** Cancel any asynchronous activity being done by the message. |
|
784 |
|
785 @param aMessage |
|
786 The IPC message. |
|
787 */ |
|
788 void CSendAsMessage::Cancel() |
|
789 { |
|
790 CancelMessage(); |
|
791 } |
|
792 |
|
793 /** Launch the message editor for the open message. |
|
794 |
|
795 @param aMessage |
|
796 The IPC message. |
|
797 */ |
|
798 void CSendAsMessage::LaunchEditorL(const RMessage2& aMessage) |
|
799 { |
|
800 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
801 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
802 |
|
803 iClientMtm->SaveMessageL(); |
|
804 |
|
805 // the observer and owner is the SendAs Server, via active container. |
|
806 CSendAsEditWatcher* editWatcher = CSendAsEditWatcher::NewL(iSession.ActiveContainer(), iSession.EditUtilsPluginUid()); |
|
807 iSession.ActiveContainer().AddEditWatcherL(*editWatcher); |
|
808 |
|
809 TMsvId entryId = iClientMtm->Entry().EntryId(); |
|
810 DeleteClientMtm(); |
|
811 editWatcher->LaunchEditorL(entryId); |
|
812 |
|
813 iState = EPendingClose; |
|
814 } |
|
815 |
|
816 /** Send the message. |
|
817 |
|
818 This method handles both confirmed and unconfirmed sends. If an unconfirmed send |
|
819 is attempted but the client does not have the MTM-required capabilities then the |
|
820 send will be downgraded to a confirmed send. |
|
821 |
|
822 @param aMessage |
|
823 The IPC message. |
|
824 |
|
825 @param aConfirmed |
|
826 A value of true indicates that the send should be confirmed. |
|
827 |
|
828 @param aBackground |
|
829 A value of true indicates that the send should be done in the background. This |
|
830 implies that the client does not wish to be notified of the progress of the send. |
|
831 |
|
832 @leave KErrNotSupported |
|
833 The client MTM does not support SendAs message sending. |
|
834 */ |
|
835 void CSendAsMessage::SendMessageL(const RMessage2& aMessage, TBool aConfirmed, TBool aBackground) |
|
836 { |
|
837 __ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) ); |
|
838 __ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() ); |
|
839 |
|
840 #if (defined SYMBIAN_USER_PROMPT_SERVICE) |
|
841 TBool hasCapability = EFalse; |
|
842 #endif |
|
843 // for unconfirmed send, check capabilities of client |
|
844 if( !aConfirmed ) |
|
845 { |
|
846 VerifyCallerCapabilitiesL(aMessage, aConfirmed); |
|
847 #if (defined SYMBIAN_USER_PROMPT_SERVICE) |
|
848 if(!aConfirmed) |
|
849 { |
|
850 hasCapability = ETrue; |
|
851 } |
|
852 #endif |
|
853 } |
|
854 |
|
855 |
|
856 TBool result = KErrNone; |
|
857 if( iClientMtm->QueryCapability(KUidMtmQuerySendAsMessageSendSupport, result) == KErrNotSupported ) |
|
858 { |
|
859 User::Leave(KErrNotSupported); |
|
860 } |
|
861 // save message |
|
862 DoSaveMessageL(); |
|
863 |
|
864 // create the sender obejct |
|
865 CSendAsSender* sender = NULL; |
|
866 if( aBackground ) |
|
867 { |
|
868 // this a background send - the observer and owner is the active container. |
|
869 sender = CSendAsSender::NewL(iSession.ActiveContainer()); |
|
870 iSession.ActiveContainer().AddSenderL(*sender); |
|
871 |
|
872 iState = ESendingMessageComplete; |
|
873 } |
|
874 else |
|
875 { |
|
876 // this is a non-background send - the observer and owner is the send-as |
|
877 // message. |
|
878 delete iSender; |
|
879 iSender = NULL; |
|
880 |
|
881 sender = CSendAsSender::NewL(*this); |
|
882 iSender = sender; |
|
883 |
|
884 // queue the IPC message - used to notify the client when the send is complete |
|
885 iQueuedMessage = aMessage; |
|
886 |
|
887 iState = ESendingMessage; |
|
888 } |
|
889 // new sender takes ownership of the client MTM |
|
890 sender->SetClientMtm(*iClientMtm); |
|
891 |
|
892 #if (defined SYMBIAN_USER_PROMPT_SERVICE) |
|
893 TRAPD(err, sender->SendMessageL(aMessage, hasCapability)); |
|
894 if(err!=KErrNone) |
|
895 { |
|
896 // There was a error while sending the message... so delete the entry |
|
897 iClientMtm->Session().RemoveEntry(iClientMtm->Entry().EntryId()); |
|
898 iClientMtm = NULL; |
|
899 iState = ESendingMessageComplete; |
|
900 User::Leave(err); |
|
901 } |
|
902 iClientMtm = NULL; |
|
903 #else |
|
904 iClientMtm = NULL; |
|
905 if( aConfirmed ) |
|
906 { |
|
907 TSecurityInfo securityInfo(aMessage); |
|
908 sender->SendMessage(securityInfo, iSession.NotifierUid()); |
|
909 } |
|
910 else |
|
911 { |
|
912 sender->SendMessage(); |
|
913 } |
|
914 #endif |
|
915 } |
|
916 |
|
917 void CSendAsMessage::DeleteClientMtm() |
|
918 { |
|
919 delete iClientMtm; |
|
920 iClientMtm = NULL; |
|
921 } |
|
922 |
|
923 /** Get progress information |
|
924 |
|
925 Used to provide progress information to the client. |
|
926 |
|
927 1. Before sending, the progress is set to ESendStateInPreparation. |
|
928 |
|
929 2. Whilst sending, the progress is obtained from the send operation. |
|
930 |
|
931 3. After sending, the final progress is returned to the client (always a TMsvSendOperationProgress). |
|
932 |
|
933 @param aMessage |
|
934 The IPC message. |
|
935 */ |
|
936 void CSendAsMessage::ProgressL(const RMessage2& aMessage) |
|
937 { |
|
938 switch( iState ) |
|
939 { |
|
940 case EIdle: |
|
941 case EMessageCreated: |
|
942 case EAddingOrCreatingAttachment: |
|
943 case EMessageDeleted: |
|
944 case EPendingClose: |
|
945 { |
|
946 iProgress().iState = CMsvSendOperation::ESendStateInPreparation; |
|
947 iProgress().iError = KErrNone; |
|
948 iProgress().iProgressMax = 0; |
|
949 iProgress().iProgress = 0; |
|
950 } break; |
|
951 case ESendingMessage: |
|
952 { |
|
953 __ASSERT_DEBUG( iSender != NULL, User::Invariant() ); |
|
954 |
|
955 iSender->ProgressL(iProgress); |
|
956 } break; |
|
957 case ESendingMessageComplete: |
|
958 { |
|
959 // return the final progress |
|
960 if( iProgress().iError == KErrNone ) |
|
961 { |
|
962 iProgress().iState = CMsvSendOperation::ESendStateDone; |
|
963 } |
|
964 else |
|
965 { |
|
966 iProgress().iState = CMsvSendOperation::ESendStateFailed; |
|
967 } |
|
968 } break; |
|
969 default: |
|
970 User::Invariant(); |
|
971 break; |
|
972 } |
|
973 |
|
974 aMessage.WriteL(0, iProgress); |
|
975 } |
|
976 |
|
977 /** Verify that the client has the required capabilities to use the server MTM |
|
978 to send this message unconfirmed. Otherwise changes request to confirmed send. |
|
979 |
|
980 @param aMessage |
|
981 The IPC message. |
|
982 */ |
|
983 void CSendAsMessage::VerifyCallerCapabilitiesL(const RMessage2& aMessage, TBool& aConfirmed) |
|
984 { |
|
985 // get required capabilities |
|
986 TCapabilitySet caps; |
|
987 iClientMtm->Session().GetMtmRequiredCapabilitiesL(iMessageType, caps); |
|
988 |
|
989 // get client thread capabilities |
|
990 TSecurityInfo securityInfo(aMessage); |
|
991 |
|
992 // check client capabilities with required capabilities |
|
993 if( !securityInfo.iCaps.HasCapabilities(caps) ) |
|
994 { |
|
995 // fail capability check... |
|
996 caps.Remove(securityInfo.iCaps); |
|
997 PlatSec::CapabilityCheckFail(aMessage, caps, __PLATSEC_DIAGNOSTIC_STRING("Unconfirmed send downgraded to confirmed by CSendAsMessage::VerifyCallerCapabilitiesL")); |
|
998 aConfirmed = ETrue; |
|
999 } |
|
1000 } |
|
1001 |
|
1002 /** Panic the client |
|
1003 |
|
1004 @param aMessage |
|
1005 The IPC message. |
|
1006 |
|
1007 @param aPanic |
|
1008 The panic code. |
|
1009 */ |
|
1010 void CSendAsMessage::PanicClientL(const RMessage2& aMessage, TSendAsClientPanic aPanic) const |
|
1011 { |
|
1012 iSession.PanicClient(aMessage, aPanic); |
|
1013 } |
|
1014 |
|
1015 /* |
|
1016 * Methods from MSendAsSenderObserver |
|
1017 */ |
|
1018 |
|
1019 /** Notify the client that the send has completed |
|
1020 |
|
1021 @param aError |
|
1022 The error code. |
|
1023 */ |
|
1024 void CSendAsMessage::SenderComplete(TInt aError) |
|
1025 { |
|
1026 __ASSERT_ALWAYS( iState == ESendingMessage, User::Invariant() ); |
|
1027 __ASSERT_DEBUG( iSender != NULL, User::Invariant() ); |
|
1028 |
|
1029 // get final progress from the sender. |
|
1030 iSender->FinalProgress(iProgress); |
|
1031 |
|
1032 // capture error |
|
1033 if( iProgress().iError == KErrNone ) |
|
1034 { |
|
1035 iProgress().iError = aError; |
|
1036 } |
|
1037 // notify the client that the send has completed - always complete with |
|
1038 // KErrNone as actual error is in the progress. |
|
1039 iQueuedMessage.Complete(KErrNone); |
|
1040 |
|
1041 // Set the state to complete so we can call FinalProgress |
|
1042 iState = ESendingMessageComplete; |
|
1043 } |
|
1044 |
|
1045 /* |
|
1046 * Methods from MSendAsAttachmentObserver |
|
1047 */ |
|
1048 |
|
1049 /** Notify the client that the attachment operation has completed |
|
1050 |
|
1051 If the message is complete, the client is notified, otherwise the created |
|
1052 attachment is transferred to the client. |
|
1053 |
|
1054 @param aError |
|
1055 The error code. |
|
1056 |
|
1057 @param aCompleteMessage |
|
1058 Indicates if the message is complete. |
|
1059 */ |
|
1060 void CSendAsMessage::AttachmentCompleteL(TInt aError, TBool aCompleteMessage) |
|
1061 { |
|
1062 __ASSERT_ALWAYS( iState == EAddingOrCreatingAttachment, User::Invariant() ); |
|
1063 |
|
1064 // notify the client that the attachment operation has completed - if an |
|
1065 // error has occurred the error code is returned in the complete status. |
|
1066 if (aCompleteMessage) |
|
1067 { |
|
1068 iQueuedMessage.Complete(aError); |
|
1069 } |
|
1070 else |
|
1071 { |
|
1072 // transfer the created file to the client. Argument 0 of iQueuedMessage |
|
1073 // contains the address to which the client should receive the file handle. |
|
1074 User::LeaveIfError(iAttachmentFile.TransferToClient(iQueuedMessage, 0)); |
|
1075 iAttachmentFile.Close(); |
|
1076 } |
|
1077 // the attachment file is now closed - set it to a blank RFile so that any |
|
1078 // later closes don't panic. |
|
1079 iAttachmentFile = RFile(); |
|
1080 |
|
1081 // The client can continue editing the message - move to appropriate state |
|
1082 // and delete attachment object |
|
1083 |
|
1084 // Delete the attachment object after use. If this is a notification of a |
|
1085 // cancel then the delete should happen after the cancel operation to avoid |
|
1086 // a second cancel in the attachment object's destructor. |
|
1087 if( aError != KErrCancel ) |
|
1088 { |
|
1089 delete iAttachment; |
|
1090 iAttachment = NULL; |
|
1091 } |
|
1092 |
|
1093 iState = EMessageCreated; |
|
1094 } |
|
1095 |
|
1096 /** Sets the message entry's Visible flag to ETrue and inPreparation flag to EFalse |
|
1097 saves the message, commits the changes |
|
1098 */ |
|
1099 |
|
1100 void CSendAsMessage::DoSaveMessageL() |
|
1101 { |
|
1102 iClientMtm->SaveMessageL(); |
|
1103 |
|
1104 // set the InPreparation to false and visible to true |
|
1105 TMsvEntry tempEntry= iClientMtm->Entry().Entry(); |
|
1106 tempEntry.iDate.UniversalTime(); |
|
1107 tempEntry.SetVisible(ETrue); |
|
1108 tempEntry.SetInPreparation(EFalse); |
|
1109 |
|
1110 iClientMtm->Entry().ChangeL(tempEntry); |
|
1111 } |
|
1112 |
|
1113 /** |
|
1114 Sets the character encoding value. The character encoding value options are 7-bit, |
|
1115 8-bit and 16-Bit Unicode. By default the character set encoding is 7 bit encoding. |
|
1116 It call the MTM functionality for setting the charset value. |
|
1117 @param aMessage The IPC message. |
|
1118 @return void |
|
1119 */ |
|
1120 |
|
1121 void CSendAsMessage::SetMessageCharacterSetL(const RMessage2& aMessage) |
|
1122 { |
|
1123 TInt err = iClientMtm->SetMessageCharacterSet(aMessage.Int0()); |
|
1124 TPckgBuf<TInt> pckg = err; |
|
1125 aMessage.WriteL(1,pckg); |
|
1126 } |