|
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 "csendassession.h" |
|
17 |
|
18 #include <msvids.h> |
|
19 #include <s32mem.h> |
|
20 #include <csendasaccounts.h> |
|
21 #include <csendasmessagetypes.h> |
|
22 #include <mtmuids.h> |
|
23 #include <mtclreg.h> |
|
24 #include <mtclbase.h> |
|
25 |
|
26 #include "csendasserver.h" |
|
27 #include "csendasmtmmanager.h" |
|
28 #include "csendasmessage.h" |
|
29 #include "sendasserverdefs.h" |
|
30 #include "tsendasserverpanic.h" |
|
31 |
|
32 CSendAsSession* CSendAsSession::NewL(const TVersion& aVersion, CSendAsServer& aServer) |
|
33 { |
|
34 TVersion version(KSendAsServerVersionMajor, KSendAsServerVersionMinor, KSendAsServerVersionBuild); |
|
35 if( !User::QueryVersionSupported(version, aVersion) ) |
|
36 { |
|
37 User::Leave(KErrNotSupported); |
|
38 } |
|
39 |
|
40 CSendAsSession* self = new(ELeave) CSendAsSession(aServer); |
|
41 CleanupStack::PushL(self); |
|
42 self->ConstructL(); |
|
43 CleanupStack::Pop(self); |
|
44 return self; |
|
45 } |
|
46 |
|
47 void CSendAsSession::ConstructL() |
|
48 { |
|
49 iMessages = CObjectIx::NewL(); |
|
50 iContainer = iServer.NewContainerL(); |
|
51 TMsvSelectionOrdering order(KMsvNoGrouping, EMsvSortByDetails, ETrue); |
|
52 iMsvEntry = CMsvEntry::NewL(GetMsvSessionL(), KMsvRootIndexEntryId, order); |
|
53 iSendAsAccounts = CSendAsAccounts::NewL(); |
|
54 |
|
55 // Prepare available message type list |
|
56 iAvailableMessageTypes = CSendAsMessageTypes::NewL(); |
|
57 ResetTypeFilterL(); |
|
58 } |
|
59 |
|
60 CSendAsSession::CSendAsSession(CSendAsServer& aServer) |
|
61 : iServer(aServer) |
|
62 { |
|
63 } |
|
64 |
|
65 CSendAsSession::~CSendAsSession() |
|
66 { |
|
67 delete iMessages; |
|
68 // iContainer will be deleted by the server |
|
69 iServer.SessionClosed(iContainer); |
|
70 delete iSendAsAccounts; |
|
71 delete iAvailableMessageTypes; |
|
72 delete iMsvEntry; |
|
73 } |
|
74 |
|
75 /** Service the incoming message. |
|
76 |
|
77 If the message is for the session object, it will be dispatched to |
|
78 the correct handler. If the message is for the subsession object, |
|
79 it will be dispatched to the handler located in the subsession. |
|
80 |
|
81 This allows all of the subsession logic to be internal to itself. |
|
82 |
|
83 If a handler requires an asynchronous response, then this method |
|
84 should return ETrue. If this method leaves, the trap harness in |
|
85 the ServiceL method will catch the error and complete the message |
|
86 with the error code. |
|
87 |
|
88 @param aMessage |
|
89 The IPC message object. |
|
90 */ |
|
91 TBool CSendAsSession::DoServiceL(const RMessage2& aMessage) |
|
92 { |
|
93 // session methods |
|
94 switch (aMessage.Function()) |
|
95 { |
|
96 case ESASSetFilter: |
|
97 DoSetMessageTypeFilterL(aMessage); |
|
98 break; |
|
99 case ESASClearFilter: |
|
100 DoClearMessageTypeFilterL(); |
|
101 break; |
|
102 case ESAMDestroySubSession: |
|
103 // this is a sub session message, which means that the handle is transmitted |
|
104 // automatically, but we will handle it at the session level so we can |
|
105 // not only close the subsession, but also delete the object properly. |
|
106 RemoveMessage(aMessage.Int3()); |
|
107 break; |
|
108 case ESASGetMessageTypeListLength: |
|
109 DoGetMessageTypeListLengthL(aMessage); |
|
110 break; |
|
111 case ESASGetMessageTypes: |
|
112 DoGetMessageTypeListL(aMessage); |
|
113 break; |
|
114 case ESASGetAccountListLength: |
|
115 DoGetAccountListLengthL(aMessage); |
|
116 break; |
|
117 case ESASGetAccountList: |
|
118 DoGetAccountListL(aMessage); |
|
119 break; |
|
120 case ESASCreateSubSession: |
|
121 CreateSubsessionL(aMessage); |
|
122 break; |
|
123 default: |
|
124 { |
|
125 // must be a subsession method |
|
126 CSendAsMessage* msg = MessageFromHandle(aMessage.Int3()); |
|
127 if( msg == NULL ) |
|
128 { |
|
129 PanicClient(aMessage, ESendAsClientPanicBadSubSessionHandle); |
|
130 User::Leave(KErrBadHandle); |
|
131 } |
|
132 return msg->DoSubSessionServiceL(aMessage); |
|
133 } |
|
134 } |
|
135 return EFalse; |
|
136 } |
|
137 |
|
138 /** Create a new subsession object to represent a message. |
|
139 |
|
140 Each message is represented by a CSendAsMessage object. These objects |
|
141 are derived from CContainer. This allows us to use the object container |
|
142 framework to keep track of allocated objects and to ensure that the |
|
143 object handles are unique. |
|
144 |
|
145 The RMessage is required so that the session can pass the new |
|
146 subsession handle to the client-side RSubSession object. |
|
147 |
|
148 @param aMessage |
|
149 The IPC message object. |
|
150 */ |
|
151 void CSendAsSession::CreateSubsessionL(const RMessage2& aMessage) |
|
152 { |
|
153 // new message (subsession) |
|
154 CSendAsMessage* message = CSendAsMessage::NewL(*this); |
|
155 CleanupClosePushL(*message); |
|
156 |
|
157 // add message class into the container and obtain a handle for it. |
|
158 iContainer->AddL(message); |
|
159 TInt id = iMessages->AddL(message); |
|
160 CleanupStack::Pop(message); |
|
161 |
|
162 // write the handle back to the client |
|
163 TPckg<TInt> pckg(id); |
|
164 TInt err = aMessage.Write(3, pckg); |
|
165 |
|
166 if( err != KErrNone ) |
|
167 { |
|
168 iMessages->Remove(id); |
|
169 message->Close(); |
|
170 |
|
171 User::Leave(err); |
|
172 } |
|
173 ++iMessageCount; |
|
174 } |
|
175 |
|
176 /** Find a subsession pointer from its handle. |
|
177 |
|
178 A message sent from an RSubSession-derived object will always contain |
|
179 a handle to the server-side subsession object in parameter 3. |
|
180 |
|
181 This method takes that handle and looks it up in the object index to |
|
182 find the pointer to the correct subsession instance. |
|
183 |
|
184 @param aHandle |
|
185 The handle for the subsession object |
|
186 |
|
187 @return |
|
188 The pointer to the subsesion object referred to by aHandle if it exists, |
|
189 otherwise NULL is returned. |
|
190 */ |
|
191 CSendAsMessage* CSendAsSession::MessageFromHandle(TUint aHandle) |
|
192 { |
|
193 return static_cast<CSendAsMessage*>(iMessages->At(aHandle)); |
|
194 } |
|
195 |
|
196 void CSendAsSession::RemoveMessage(TUint aHandle) |
|
197 { |
|
198 // this operation will delete the subsession. |
|
199 iMessages->Remove(aHandle); |
|
200 --iMessageCount; |
|
201 } |
|
202 |
|
203 void CSendAsSession::PanicClient(const RMessage2& aMessage, TSendAsClientPanic aPanic) const |
|
204 { |
|
205 _LIT(KSendAsServerSession, "SendAsSession"); |
|
206 aMessage.Panic(KSendAsServerSession, aPanic); |
|
207 } |
|
208 |
|
209 /** Add a message type filter to the list. |
|
210 |
|
211 This removes any non-compliant MTMs from the list of available MTMs. |
|
212 |
|
213 This is a cumulative operation, filters are applied as they are received |
|
214 and the list is shortened each time. |
|
215 |
|
216 @param aMessage |
|
217 The IPC message object. |
|
218 */ |
|
219 void CSendAsSession::DoSetMessageTypeFilterL(const RMessage2& aMessage) |
|
220 { |
|
221 // extract filter |
|
222 TPckgBuf<TSendAsMessageTypeFilter> filterBuf; |
|
223 aMessage.ReadL(0, filterBuf); |
|
224 |
|
225 // apply to available mtm list |
|
226 AddTypeFilterL(filterBuf()); |
|
227 } |
|
228 |
|
229 /** Remove the message type filter. |
|
230 |
|
231 In reality, this means that we repopulate the entire list. |
|
232 */ |
|
233 void CSendAsSession::DoClearMessageTypeFilterL() |
|
234 { |
|
235 ResetTypeFilterL(); |
|
236 } |
|
237 |
|
238 void CSendAsSession::DoGetMessageTypeListLengthL(const RMessage2& aMessage) |
|
239 { |
|
240 // return size of message types data |
|
241 TPckgBuf<TUint32> buf(iAvailableMessageTypes->Size()); |
|
242 aMessage.WriteL(0, buf); |
|
243 } |
|
244 |
|
245 void CSendAsSession::DoGetMessageTypeListL(const RMessage2& aMessage) |
|
246 { |
|
247 // buffer to hold message types data |
|
248 HBufC8* buffer = HBufC8::NewLC(iAvailableMessageTypes->Size()); |
|
249 |
|
250 // stream |
|
251 RDesWriteStream strm; |
|
252 CleanupClosePushL(strm); |
|
253 TPtr8 ptr(buffer->Des()); |
|
254 strm.Open(ptr); |
|
255 |
|
256 // write to stream |
|
257 iAvailableMessageTypes->ExternalizeL(strm); |
|
258 strm.CommitL(); |
|
259 aMessage.WriteL(0, *buffer); |
|
260 |
|
261 // clean up |
|
262 CleanupStack::PopAndDestroy(2, buffer); // buffer, strm |
|
263 } |
|
264 |
|
265 void CSendAsSession::DoGetAccountListLengthL(const RMessage2& aMessage) |
|
266 { |
|
267 // message slot 1 contains the mtm uid |
|
268 TPckgBuf<TUid> uidBuf; |
|
269 aMessage.ReadL(1, uidBuf); |
|
270 |
|
271 // reset the account list |
|
272 iSendAsAccounts->Reset(); |
|
273 |
|
274 // get account list for this mtm |
|
275 TUid acctUid = uidBuf(); |
|
276 iMsvEntry->SetEntryL(KMsvRootIndexEntryId); |
|
277 CMsvEntrySelection* selection = iMsvEntry->ChildrenWithMtmL(acctUid); |
|
278 CleanupStack::PushL(selection); |
|
279 |
|
280 // populate account list |
|
281 TInt count = selection->Count(); |
|
282 iSendAsAccounts->SetMessageType(acctUid); |
|
283 for (TInt i=0; i<count; ++i) |
|
284 { |
|
285 TSendAsAccount id = selection->At(i); |
|
286 // set context |
|
287 iMsvEntry->SetEntryL(id); |
|
288 // add account |
|
289 iSendAsAccounts->AppendAccountL(iMsvEntry->Entry().iDetails, id); |
|
290 } |
|
291 CleanupStack::PopAndDestroy(selection); |
|
292 |
|
293 // get size |
|
294 TPckgBuf<TInt> buf(iSendAsAccounts->Size()); |
|
295 aMessage.WriteL(0, buf); |
|
296 } |
|
297 |
|
298 void CSendAsSession::DoGetAccountListL(const RMessage2& aMessage) |
|
299 { |
|
300 // buffer to hold accounts data |
|
301 HBufC8* buffer = HBufC8::NewLC(iSendAsAccounts->Size()); |
|
302 |
|
303 // buffer write stream |
|
304 RDesWriteStream strm; |
|
305 CleanupClosePushL(strm); |
|
306 TPtr8 ptr(buffer->Des()); |
|
307 strm.Open(ptr); |
|
308 |
|
309 // write to buffer |
|
310 iSendAsAccounts->ExternalizeL(strm); |
|
311 |
|
312 // commit and return buffer |
|
313 strm.CommitL(); |
|
314 aMessage.WriteL(0, *buffer); |
|
315 |
|
316 // clean up |
|
317 CleanupStack::PopAndDestroy(2, buffer); // buffer, strm |
|
318 } |
|
319 |
|
320 CMsvSession& CSendAsSession::GetMsvSessionL() |
|
321 { |
|
322 return iServer.GetMsvSessionL(); |
|
323 } |
|
324 |
|
325 CSendAsActiveContainer& CSendAsSession::ActiveContainer() |
|
326 { |
|
327 return iServer.ActiveContainer(); |
|
328 } |
|
329 |
|
330 const TUid& CSendAsSession::NotifierUid() const |
|
331 { |
|
332 return iServer.NotifierUid(); |
|
333 } |
|
334 |
|
335 const TUid& CSendAsSession::EditUtilsPluginUid() const |
|
336 { |
|
337 return iServer.EditUtilsPluginUid(); |
|
338 } |
|
339 |
|
340 /* |
|
341 * methods from CSession2 |
|
342 */ |
|
343 |
|
344 /** Session ServiceL method. |
|
345 |
|
346 This method traps the real serviceL method so that leaves can |
|
347 be trapped and returned as error completion codes on the message. |
|
348 |
|
349 This prevents the session from leaving during the server AO's |
|
350 RunL and causing a panic. |
|
351 |
|
352 @param aMessage |
|
353 The IPC message object. |
|
354 */ |
|
355 void CSendAsSession::ServiceL(const RMessage2& aMessage) |
|
356 { |
|
357 TBool async = EFalse; |
|
358 TRAPD(err, async = DoServiceL(aMessage)); |
|
359 |
|
360 // complete the message if necessary. |
|
361 if (!async || err != KErrNone) |
|
362 { |
|
363 aMessage.Complete(err); |
|
364 } |
|
365 } |
|
366 |
|
367 |
|
368 /** Handles session disconnect. |
|
369 |
|
370 @param aMessage |
|
371 The IPC message object. |
|
372 */ |
|
373 void CSendAsSession::Disconnect(const RMessage2& aMessage) |
|
374 { |
|
375 // Cancel all sub-session objects. |
|
376 TInt count = iMessages->Count(); |
|
377 for( TInt i=0; i<count; ++i) |
|
378 { |
|
379 CSendAsMessage* message = static_cast<CSendAsMessage*>((*iMessages)[i]); |
|
380 message->CancelMessage(); |
|
381 } |
|
382 |
|
383 // Must call the base class implementation - this will delete the object. |
|
384 CSession2::Disconnect(aMessage); |
|
385 } |
|
386 |
|
387 |
|
388 /* |
|
389 * available Client MTM array management and access methods. |
|
390 */ |
|
391 |
|
392 /** Resets the available message type list |
|
393 |
|
394 */ |
|
395 void CSendAsSession::ResetTypeFilterL() |
|
396 { |
|
397 // get unfiltered MTM array |
|
398 RArray<TUid>& aMtmUidArray = iServer.GetMtmManager()->GetMtmUidArray(); |
|
399 |
|
400 // get client registry |
|
401 CClientMtmRegistry* aClientRegistry = iServer.GetMtmManager()->GetClientMtmRegistry(); |
|
402 |
|
403 // reset filtered MTM array |
|
404 iAvailableMessageTypes->Reset(); |
|
405 |
|
406 // populate filtered MTM array |
|
407 TInt count = aMtmUidArray.Count(); |
|
408 for( TInt i=0; i<count; ++i ) |
|
409 { |
|
410 // mtm uid |
|
411 TUid mtmUid = aMtmUidArray[i]; |
|
412 // mtm name |
|
413 TPtrC name = aClientRegistry->RegisteredMtmDllInfo(mtmUid).HumanReadableName(); |
|
414 iAvailableMessageTypes->AppendMessageTypeL(name, mtmUid); |
|
415 } |
|
416 } |
|
417 |
|
418 /** Reduces available message type list according to filter |
|
419 |
|
420 @param aFilter |
|
421 The filter to be applied |
|
422 */ |
|
423 void CSendAsSession::AddTypeFilterL(const TSendAsMessageTypeFilter& aFilter) |
|
424 { |
|
425 if( aFilter.iMessageCapability == KUidMtmQueryCanSendMsg ) |
|
426 { |
|
427 // the list of mtms available to sendas sessions is created with this |
|
428 // capability by default by the sendas MTM manager, so no action needed |
|
429 return; |
|
430 } |
|
431 |
|
432 // locals used in scan loop |
|
433 CBaseMtm* mtm = NULL; |
|
434 TInt response; |
|
435 TInt error; |
|
436 TBool capable; |
|
437 |
|
438 // scan list of mtms and filter out those without the required capabilities |
|
439 TInt count = iAvailableMessageTypes->Count(); |
|
440 while( count-- > 0 ) |
|
441 { |
|
442 // get mtm by uid |
|
443 mtm = iServer.GetMtmManager()->FindStoredMtmL(iAvailableMessageTypes->MessageTypeUid(count)); |
|
444 |
|
445 // check if capability supported |
|
446 response = 0; |
|
447 error = mtm->QueryCapability(aFilter.iMessageCapability, response); |
|
448 |
|
449 // if capability supported, check conditions |
|
450 capable = EFalse; |
|
451 if( error == KErrNone ) |
|
452 { |
|
453 switch (aFilter.iCondition) |
|
454 { |
|
455 case RSendAs::ESendAsNoCondition: |
|
456 capable = ETrue; |
|
457 break; |
|
458 case RSendAs::ESendAsEquals: |
|
459 capable = (response == aFilter.iValue); |
|
460 break; |
|
461 case RSendAs::ESendAsNotEquals: |
|
462 capable = (response != aFilter.iValue); |
|
463 break; |
|
464 case RSendAs::ESendAsGreaterThan: |
|
465 capable = (response > aFilter.iValue); |
|
466 break; |
|
467 case RSendAs::ESendAsLessThan: |
|
468 capable = (response < aFilter.iValue); |
|
469 break; |
|
470 case RSendAs::ESendAsBitwiseAnd: |
|
471 capable = (response & aFilter.iValue); |
|
472 break; |
|
473 case RSendAs::ESendAsBitwiseOr: |
|
474 capable = (response | aFilter.iValue); |
|
475 break; |
|
476 case RSendAs::ESendAsBitwiseNand: |
|
477 capable = !(response & aFilter.iValue); |
|
478 break; |
|
479 case RSendAs::ESendAsBitwiseNor: |
|
480 capable = !(response | aFilter.iValue); |
|
481 break; |
|
482 default: |
|
483 break; |
|
484 } |
|
485 } |
|
486 else if( error != KErrNotSupported ) |
|
487 { |
|
488 User::Leave(error); |
|
489 } |
|
490 |
|
491 if( !capable ) |
|
492 { |
|
493 // mtm is not capable, so remove it from the available list |
|
494 iAvailableMessageTypes->RemoveMessageType(count); |
|
495 } |
|
496 } |
|
497 } |
|
498 |
|
499 /** Updates the array of available Client MTMs |
|
500 |
|
501 */ |
|
502 void CSendAsSession::HandleMtmChange() |
|
503 { |
|
504 // get unfiltered MTM UID array |
|
505 RArray<TUid>& aMtmUidArray = iServer.GetMtmManager()->GetMtmUidArray(); |
|
506 |
|
507 // check for removed mtm from filtered lists |
|
508 TInt count = iAvailableMessageTypes->Count(); |
|
509 for( TInt i=0; i<count; ++i ) |
|
510 { |
|
511 if (aMtmUidArray.Find(iAvailableMessageTypes->MessageTypeUid(i)) == KErrNotFound) |
|
512 { |
|
513 iAvailableMessageTypes->RemoveMessageType(i); |
|
514 break; |
|
515 } |
|
516 } |
|
517 } |
|
518 |
|
519 /** Returns the client MTM specified by UID |
|
520 |
|
521 @param aMtmUid |
|
522 The UID of the Client MTM |
|
523 */ |
|
524 CBaseMtm* CSendAsSession::GetClientMtmL(TUid aMtmUid) |
|
525 { |
|
526 return ( iServer.GetMtmManager()->GetClientMtmL(aMtmUid) ); |
|
527 } |