|
1 /* |
|
2 * Copyright (c) 2003-2009 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 the License "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 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32debug.h> |
|
20 #include <ecom/ecom.h> |
|
21 |
|
22 #include "resolver.h" |
|
23 #include "agentfactory.h" |
|
24 #include "agentinterface.h" |
|
25 #include "agentinfo.h" |
|
26 #include "agent.h" |
|
27 #include "cafpanic.h" |
|
28 #include "caferr.h" |
|
29 #include "patchdata.h" |
|
30 |
|
31 |
|
32 using namespace ContentAccess; |
|
33 |
|
34 // Constants for the F32 agent |
|
35 _LIT(KF32Agent,"F32 CA Agent"); |
|
36 |
|
37 |
|
38 _LIT(KParentDir, "..\\"); |
|
39 _LIT(KPrivateDir, "\\private\\"); |
|
40 const TInt KPrivateDirLength = 9; // "\\private\\" |
|
41 const TInt KPrivateDirAndDriveLength = 11; // "x:\\private\\" |
|
42 const TInt KPrivateDirOffset = 2; // "x:\\" |
|
43 |
|
44 |
|
45 EXPORT_C CAgentResolver* CAgentResolver::NewLC(const TBool aDynamicAgentUpdate) |
|
46 { |
|
47 CAgentResolver* self = new (ELeave) CAgentResolver(aDynamicAgentUpdate); |
|
48 CleanupStack::PushL(self); |
|
49 self->ConstructL(); |
|
50 return self; |
|
51 } |
|
52 |
|
53 EXPORT_C CAgentResolver* CAgentResolver::NewL(const TBool aDynamicAgentUpdate) |
|
54 { |
|
55 CAgentResolver* self = CAgentResolver::NewLC(aDynamicAgentUpdate); |
|
56 CleanupStack::Pop(self); |
|
57 return self; |
|
58 } |
|
59 |
|
60 CAgentResolver::CAgentResolver(const TBool aDynamicAgentUpdate) : CActive(EPriorityStandard), iDynamicAgentUpdate(aDynamicAgentUpdate) |
|
61 { |
|
62 } |
|
63 |
|
64 CAgentResolver::~CAgentResolver() |
|
65 { |
|
66 // remove ourselves from the ActiveScheduler |
|
67 if(IsAdded()) |
|
68 { |
|
69 Deque(); |
|
70 } |
|
71 |
|
72 // Unload all the agents |
|
73 DestroyListOfAgents(); |
|
74 |
|
75 // Close our ECOM session |
|
76 if(iEcomSession) |
|
77 { |
|
78 if(iDynamicAgentUpdate) |
|
79 { |
|
80 iEcomSession->CancelNotifyOnChange(iStatus); |
|
81 } |
|
82 iEcomSession->Close(); |
|
83 REComSession::FinalClose(); |
|
84 } |
|
85 |
|
86 iSupplierMimeTypes.Close(); |
|
87 iConsumerMimeTypes.Close(); |
|
88 iAgentInfos.Close(); |
|
89 } |
|
90 |
|
91 void CAgentResolver::ConstructL() |
|
92 { |
|
93 if(iDynamicAgentUpdate) |
|
94 { |
|
95 // Add ourselves to the current active scheduler so we can get dynamic |
|
96 // updates when agents are removed or new agents are added |
|
97 CActiveScheduler::Add(this); |
|
98 } |
|
99 |
|
100 iEcomSession = &REComSession::OpenL(); |
|
101 |
|
102 // find all the agents |
|
103 BuildListOfAgentsL(); |
|
104 |
|
105 if(iDynamicAgentUpdate) |
|
106 { |
|
107 // register for ECOM update notifications in case a new agent appears |
|
108 SetActive(); |
|
109 iEcomSession->NotifyOnChange(iStatus); |
|
110 } |
|
111 } |
|
112 |
|
113 void CAgentResolver::BuildListOfAgentsL() |
|
114 { |
|
115 TInt err = KErrNone; |
|
116 |
|
117 // Get all plugins which implement the agent interface |
|
118 RImplInfoPtrArray implArray; |
|
119 CleanupStack::PushL(TCleanupItem(CleanImplArray, &implArray)); |
|
120 REComSession::ListImplementationsL(KCAAgentInterfaceUid, implArray); |
|
121 |
|
122 for (TInt i = 0; i < implArray.Count(); ++i) |
|
123 { |
|
124 #ifdef __EPOC32__ |
|
125 // On hardware - to load agents from sources other than ROM the patch |
|
126 // data KCafLoadPostProductionAgents must be set to True (non-zero). |
|
127 // Default SymbianOS behavior is to only load agents from ROM |
|
128 if ((KCafLoadPostProductionAgents == 0) && |
|
129 !implArray[i]->RomBased()) |
|
130 { |
|
131 // If the agent is not in ROM, don't load it because it might |
|
132 // be a security risk. |
|
133 continue; |
|
134 } |
|
135 #endif |
|
136 |
|
137 // Construct all the agent infos from these implementations |
|
138 TRAP(err, AddAgentL(*implArray[i])); |
|
139 |
|
140 // If we ran out of memory proagate the leave to the caller |
|
141 // otherwise don't let a dodgy agent affect the construction of the other |
|
142 // agents |
|
143 if(err == KErrNoMemory) |
|
144 { |
|
145 User::Leave(KErrNoMemory); |
|
146 } |
|
147 } |
|
148 CleanupStack::PopAndDestroy(&implArray); |
|
149 |
|
150 |
|
151 if (!iDefaultAgent) |
|
152 { |
|
153 // If we didn't find a default agent, we have a big problem so panic |
|
154 User::Panic(KCafPanicString, ECafPanicNoF32Agent); |
|
155 } |
|
156 } |
|
157 |
|
158 void CAgentResolver::AddAgentL(const CImplementationInformation& aImplInfo) |
|
159 { |
|
160 // Create a CAgentInfo instance |
|
161 CAgentInfo* agentInfo = CAgentInfo::NewLC(aImplInfo); |
|
162 |
|
163 |
|
164 if(IsF32Agent(*agentInfo)) |
|
165 { |
|
166 // It's the F32 Agent |
|
167 if(iDefaultAgent) |
|
168 { |
|
169 // If we already have a default agent something is seriously wrong |
|
170 User::Panic(KCafPanicString, ECafPanicDuplicateF32Agent); |
|
171 } |
|
172 |
|
173 // Note that the default agent is NOT stored in the agents list, it is a special case |
|
174 iDefaultAgent = agentInfo; |
|
175 CleanupStack::Pop(agentInfo); |
|
176 } |
|
177 else |
|
178 { |
|
179 // All other agents go in the agent list |
|
180 User::LeaveIfError(iAgentInfos.Append(agentInfo)); |
|
181 CleanupStack::Pop(agentInfo); |
|
182 |
|
183 TInt mimeIndex=0; |
|
184 |
|
185 // Update our list of all supplier mime types supported by CAF |
|
186 for(mimeIndex=0;mimeIndex < agentInfo->SupplierMimeTypes().Count(); mimeIndex++) |
|
187 { |
|
188 User::LeaveIfError(iSupplierMimeTypes.Append(*agentInfo->SupplierMimeTypes()[mimeIndex])); |
|
189 } |
|
190 |
|
191 // Update our list of all consumer mime types supported by CAF |
|
192 for(mimeIndex=0;mimeIndex < agentInfo->ConsumerMimeTypes().Count(); mimeIndex++) |
|
193 { |
|
194 User::LeaveIfError(iConsumerMimeTypes.Append(*agentInfo->ConsumerMimeTypes()[mimeIndex])); |
|
195 } |
|
196 } |
|
197 } |
|
198 |
|
199 void CAgentResolver::DestroyListOfAgents() |
|
200 { |
|
201 iSupplierMimeTypes.Reset(); |
|
202 iConsumerMimeTypes.Reset(); |
|
203 |
|
204 // cant forget to delete the default agent |
|
205 delete iDefaultAgent; |
|
206 iDefaultAgent = NULL; |
|
207 |
|
208 // Free memory assocated with the iAgentInfos array |
|
209 iAgentInfos.ResetAndDestroy(); |
|
210 } |
|
211 |
|
212 void CAgentResolver::DoCancel() |
|
213 { |
|
214 // Abort any update notification |
|
215 iEcomSession->CancelNotifyOnChange(iStatus); |
|
216 } |
|
217 |
|
218 void CAgentResolver::RunL() |
|
219 { |
|
220 // Called by the ECOM framework if a new agent appears |
|
221 |
|
222 // remove the existing list of agents and build a new one |
|
223 DestroyListOfAgents(); |
|
224 BuildListOfAgentsL(); |
|
225 |
|
226 // request notification of any further changes |
|
227 iEcomSession->NotifyOnChange(iStatus); |
|
228 SetActive(); |
|
229 } |
|
230 |
|
231 TBool CAgentResolver::IsF32Agent(CAgentInfo& aAgentInfo) |
|
232 { |
|
233 // Check if the agent has no consumer or supplier mime types |
|
234 // and that it has the correct name and Uid |
|
235 if (aAgentInfo.Agent().ImplementationUid() == KF32AgentImplUid |
|
236 && aAgentInfo.Agent().Name().Compare(KF32Agent()) == 0 |
|
237 && aAgentInfo.ConsumerMimeTypes().Count() == 0 |
|
238 && aAgentInfo.SupplierMimeTypes().Count() == 0) |
|
239 { |
|
240 return ETrue; |
|
241 } |
|
242 else |
|
243 { |
|
244 return EFalse; |
|
245 } |
|
246 } |
|
247 |
|
248 CAgentInfo& CAgentResolver::ResolveSupplierMimeL(const TDesC8& aMimeType) const |
|
249 { |
|
250 // Go through all the agents and return the one which supports the |
|
251 // required supplier mime type |
|
252 CAgentInfo* retVal=NULL; |
|
253 |
|
254 for (TInt i = 0; i < iAgentInfos.Count(); ++i) |
|
255 { |
|
256 if (iAgentInfos[i]->IsSupportedSupplier(aMimeType)) |
|
257 { |
|
258 retVal = iAgentInfos[i]; |
|
259 break; |
|
260 } |
|
261 } |
|
262 |
|
263 if (!retVal) |
|
264 { |
|
265 User::Leave(KErrCANoAgent); |
|
266 } |
|
267 return *retVal; |
|
268 } |
|
269 |
|
270 CAgentInfo& CAgentResolver::ResolveConsumerMime(const TDesC8& aMimeType) const |
|
271 { |
|
272 // By default, set the return value to be the default agent. If we find |
|
273 // anything better, then we change it |
|
274 CAgentInfo* retVal = iDefaultAgent; |
|
275 |
|
276 for (TInt i = 0; i < iAgentInfos.Count(); ++i) |
|
277 { |
|
278 if (iAgentInfos[i]->IsSupportedConsumer(aMimeType)) |
|
279 { |
|
280 retVal = iAgentInfos[i]; |
|
281 break; |
|
282 } |
|
283 } |
|
284 |
|
285 ASSERT(retVal); |
|
286 return *retVal; |
|
287 } |
|
288 |
|
289 CAgentInfo& CAgentResolver::ResolveFileL(const TDesC& aURI, TDes& aActualUri, TContentShareMode aShareMode) const |
|
290 { |
|
291 // Go through all the agents and return the one which supports the file at the given URI |
|
292 TBool thePrivateDir = EFalse; |
|
293 TUid agentUid = ResolveDirectory(aURI, aActualUri, thePrivateDir); |
|
294 |
|
295 if(agentUid != iDefaultAgent->Agent().ImplementationUid()) |
|
296 { |
|
297 // this file must be living in a private server directory |
|
298 // return the agent who owns the directory |
|
299 return AgentInfoL(agentUid); |
|
300 } |
|
301 else |
|
302 { |
|
303 TInt agentsCount(iAgentInfos.Count()); |
|
304 CAgentManager* agentManager = NULL; |
|
305 for (TInt i = 0; i < agentsCount; ++i) |
|
306 { |
|
307 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL()); |
|
308 if(result != KErrNone) |
|
309 { |
|
310 if(KErrNoMemory == result) |
|
311 { |
|
312 User::Leave(result); |
|
313 } |
|
314 else |
|
315 { |
|
316 continue; |
|
317 } |
|
318 } |
|
319 if (agentManager->IsRecognizedL(aURI, aShareMode)) |
|
320 { |
|
321 return *iAgentInfos[i]; |
|
322 } |
|
323 } |
|
324 } |
|
325 return *iDefaultAgent; |
|
326 } |
|
327 |
|
328 CAgentInfo& CAgentResolver::ResolveFileL(RFile& aFile) const |
|
329 { |
|
330 // Go through all the agents and return the one which supports the file |
|
331 |
|
332 TInt agentsCount(iAgentInfos.Count()); |
|
333 CAgentManager* agentManager = NULL; |
|
334 for (TInt i = 0; i < agentsCount; ++i) |
|
335 { |
|
336 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL()); |
|
337 if(result != KErrNone) |
|
338 { |
|
339 if(KErrNoMemory == result) |
|
340 { |
|
341 User::Leave(result); |
|
342 } |
|
343 else |
|
344 { |
|
345 continue; |
|
346 } |
|
347 } |
|
348 if (agentManager->IsRecognizedL(aFile)) |
|
349 { |
|
350 return *iAgentInfos[i]; |
|
351 } |
|
352 } |
|
353 return *iDefaultAgent; |
|
354 } |
|
355 |
|
356 TUid CAgentResolver::ResolveDirectory(const TDesC& aPath, TDes& aActualPath, TBool& aThePrivateDir) const |
|
357 { |
|
358 TInt i = 0; |
|
359 TInt pathLength = 0; |
|
360 TBuf <KPrivateDirAndDriveLength> pathLowerCase; |
|
361 |
|
362 // Assume it's a publicly accessable path |
|
363 aThePrivateDir = EFalse; |
|
364 |
|
365 // Find the length of the path and private directory |
|
366 pathLength = aPath.Length(); |
|
367 |
|
368 // Check that the path is long enough to be within a private directory |
|
369 // and does not include "..\\".The "..\\" sequence could be a security risk |
|
370 if(aPath.Find(KParentDir()) == KErrNotFound && pathLength >= KPrivateDirAndDriveLength) |
|
371 { |
|
372 // Create a lower case copy of the left hand side of the path |
|
373 TPtrC lowerCasePtr = aPath.Mid(KPrivateDirOffset, KPrivateDirLength); |
|
374 pathLowerCase.Copy(lowerCasePtr); |
|
375 pathLowerCase.LowerCase(); |
|
376 |
|
377 // Compare the first directory in the path to \\private\\ |
|
378 if(KPrivateDir() == pathLowerCase) |
|
379 { |
|
380 // It is a private directory of some sort |
|
381 if(pathLength > KPrivateDirAndDriveLength) |
|
382 { |
|
383 // It must be a server private directory data cage |
|
384 TPtrC serverDirectoryPath = aPath.Right(pathLength - KPrivateDirAndDriveLength); |
|
385 for(i = 0; i < AgentInfoCount(); i++) |
|
386 { |
|
387 // See if the part after \\private\\ matches the agent name |
|
388 TPtrC privateDirectoryName = AgentInfo(i).PrivateDirectoryName(); |
|
389 TPtrC agentName = AgentInfo(i).Agent().Name(); |
|
390 if(privateDirectoryName.Length() && agentName.Length() && agentName == serverDirectoryPath.Left(agentName.Length())) |
|
391 { |
|
392 // It must be this agent's private directory |
|
393 // Convert \\private\\agentName\\... to \\private\\SID\\... |
|
394 aActualPath.Copy(aPath.Left(KPrivateDirAndDriveLength)); |
|
395 aActualPath.Append(privateDirectoryName); |
|
396 aActualPath.Append(aPath.Right(pathLength - KPrivateDirAndDriveLength - agentName.Length())); |
|
397 return AgentInfo(i).Agent().ImplementationUid(); |
|
398 } |
|
399 } |
|
400 } |
|
401 else |
|
402 { |
|
403 // It's just the c:\\private\\ directory |
|
404 // Use the default agent, any calls will just fail |
|
405 aThePrivateDir = ETrue; |
|
406 } |
|
407 } |
|
408 } |
|
409 |
|
410 // Not an agent private directory so just return the default agent |
|
411 aActualPath.Copy(aPath); |
|
412 return iDefaultAgent->Agent().ImplementationUid(); |
|
413 } |
|
414 |
|
415 HBufC* CAgentResolver::ConvertAgentFileNameL(const TDesC& aFileName) const |
|
416 { |
|
417 TInt i = 0; |
|
418 TInt fileNameLength = 0; |
|
419 TBuf <KPrivateDirAndDriveLength> pathLowerCase; |
|
420 |
|
421 fileNameLength = aFileName.Length(); |
|
422 |
|
423 // If the path is shorter than the x:\\private\\ it must be a F32 file |
|
424 if(fileNameLength > KPrivateDirAndDriveLength) |
|
425 { |
|
426 // Create a lower case copy of the left hand side of the path |
|
427 TPtrC lowerCasePtr = aFileName.Mid(KPrivateDirOffset, KPrivateDirLength); |
|
428 pathLowerCase.Copy(lowerCasePtr); |
|
429 pathLowerCase.LowerCase(); |
|
430 |
|
431 // Compare the first directory in the path to \\private\\ |
|
432 if(KPrivateDir() == pathLowerCase) |
|
433 { |
|
434 // It is a private directory of some sort |
|
435 if(fileNameLength > KPrivateDirAndDriveLength) |
|
436 { |
|
437 // It must be a server private directory data cage |
|
438 TPtrC serverDirectoryPath = aFileName.Right(fileNameLength - KPrivateDirAndDriveLength); |
|
439 for(i = 0; i < AgentInfoCount(); i++) |
|
440 { |
|
441 // See if the part after \\private\\ matches the agent name |
|
442 TPtrC privateDirectoryName = AgentInfo(i).PrivateDirectoryName(); |
|
443 TPtrC agentName = AgentInfo(i).Agent().Name(); |
|
444 if(privateDirectoryName.Length() && agentName.Length() && privateDirectoryName == serverDirectoryPath.Left(privateDirectoryName.Length())) |
|
445 { |
|
446 // It is this agent's private directory |
|
447 // Convert \\private\\SID\\... \\private\\agentName\\... |
|
448 HBufC* buffer = HBufC::NewL(fileNameLength - privateDirectoryName.Length() + agentName.Length()); |
|
449 TPtr ptr = buffer->Des(); |
|
450 ptr.Copy(aFileName.Left(KPrivateDirAndDriveLength)); |
|
451 ptr.Append(agentName); |
|
452 ptr.Append(aFileName.Right(fileNameLength - KPrivateDirAndDriveLength - privateDirectoryName.Length())); |
|
453 return buffer; |
|
454 } |
|
455 } |
|
456 } |
|
457 } |
|
458 } |
|
459 return aFileName.AllocL(); |
|
460 } |
|
461 |
|
462 EXPORT_C TBool CAgentResolver::DoRecognizeL(const TDesC& aName, const TDesC8& aBuffer, TDes8& aFileMimeType, TDes8& aContentMimeType) |
|
463 { |
|
464 |
|
465 // Given the filename and buffer from apparc, ask the agents in turn if they recognize the file |
|
466 // Note this will not call the DefaultAgent (F32) because it won't be able to recognize anything |
|
467 |
|
468 TInt agentsCount(iAgentInfos.Count()); |
|
469 CAgentManager* agentManager = NULL; |
|
470 for (TInt i = 0; i < agentsCount; ++i) |
|
471 { |
|
472 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL()); |
|
473 if(result != KErrNone) |
|
474 { |
|
475 if(KErrNoMemory == result) |
|
476 { |
|
477 User::Leave(result); |
|
478 } |
|
479 else |
|
480 { |
|
481 continue; |
|
482 } |
|
483 } |
|
484 if (agentManager->RecognizeFileL(aName, aBuffer, aFileMimeType, aContentMimeType)) |
|
485 { |
|
486 // force to lower case to ensure that chosen lower case scheme for mime types is maintained |
|
487 aFileMimeType.LowerCase(); |
|
488 aContentMimeType.LowerCase(); |
|
489 return ETrue; |
|
490 } |
|
491 } |
|
492 return EFalse; |
|
493 } |
|
494 |
|
495 |
|
496 void CAgentResolver::CleanImplArray(TAny* aArray) |
|
497 { |
|
498 static_cast<RImplInfoPtrArray*>(aArray)->ResetAndDestroy(); |
|
499 } |
|
500 |
|
501 EXPORT_C TInt CAgentResolver::PreferredBufferSize() |
|
502 { |
|
503 TInt size=0; |
|
504 |
|
505 if(iDefaultAgent != NULL) |
|
506 { |
|
507 size = iDefaultAgent->PreferredBufferSize(); |
|
508 } |
|
509 |
|
510 // Find out the maximum buffer requested by any agent |
|
511 for (TInt i = 0; i < iAgentInfos.Count(); ++i) |
|
512 { |
|
513 if(iAgentInfos[i]->PreferredBufferSize() > size) |
|
514 { |
|
515 size = iAgentInfos[i]->PreferredBufferSize(); |
|
516 } |
|
517 } |
|
518 return size; |
|
519 } |
|
520 |
|
521 |
|
522 EXPORT_C const RArray<TPtrC8>& CAgentResolver::ConsumerMimeTypes() const |
|
523 { |
|
524 return iConsumerMimeTypes; |
|
525 } |
|
526 |
|
527 |
|
528 EXPORT_C const RArray<TPtrC8>& CAgentResolver::SupplierMimeTypes() const |
|
529 { |
|
530 return iSupplierMimeTypes; |
|
531 } |
|
532 |
|
533 |
|
534 CAgentInfo& CAgentResolver::AgentInfoL(const TDesC& aAgentName) const |
|
535 { |
|
536 TBool found = EFalse; |
|
537 TInt i = 0; |
|
538 for(i = 0; i < iAgentInfos.Count(); i++) |
|
539 { |
|
540 if(iAgentInfos[i]->Agent().Name() == aAgentName) |
|
541 { |
|
542 found = ETrue; |
|
543 break; |
|
544 } |
|
545 } |
|
546 |
|
547 if(!found) |
|
548 { |
|
549 // Can't find the agent so leave |
|
550 User::Leave(KErrNotFound); |
|
551 } |
|
552 |
|
553 return *iAgentInfos[i]; |
|
554 } |
|
555 |
|
556 CAgentInfo& CAgentResolver::AgentInfoL(const TUid& aUid) const |
|
557 { |
|
558 TInt i = 0; |
|
559 TBool found = EFalse; |
|
560 |
|
561 // See if it's the F32 agent |
|
562 if(aUid == DefaultAgentUid()) |
|
563 { |
|
564 return *iDefaultAgent; |
|
565 } |
|
566 |
|
567 for(i = 0; i < iAgentInfos.Count(); i++) |
|
568 { |
|
569 if(iAgentInfos[i]->Agent().ImplementationUid() == aUid) |
|
570 { |
|
571 found = ETrue; |
|
572 break; |
|
573 } |
|
574 } |
|
575 |
|
576 if(!found) |
|
577 { |
|
578 // couldn't find the agent so leave |
|
579 User::Leave(KErrNotFound); |
|
580 } |
|
581 |
|
582 return *iAgentInfos[i]; |
|
583 } |
|
584 |
|
585 CAgentInfo& CAgentResolver::AgentInfo(TInt aIndex) const |
|
586 { |
|
587 return *iAgentInfos[aIndex]; |
|
588 } |
|
589 |
|
590 TInt CAgentResolver::AgentInfoCount() const |
|
591 { |
|
592 return iAgentInfos.Count(); |
|
593 } |
|
594 |
|
595 TUid CAgentResolver::DefaultAgentUid() const |
|
596 { |
|
597 return iDefaultAgent->Agent().ImplementationUid(); |
|
598 } |