First public contribution.
2 * Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
20 #include <ecom/ecom.h>
23 #include <caf/agentfactory.h>
24 #include <caf/agentinterface.h>
25 #include "agentinfo.h"
26 #include <caf/agent.h>
27 #include <caf/cafpanic.h>
28 #include <caf/caferr.h>
29 #include <caf/patchdata.h>
32 using namespace ContentAccess;
34 // Constants for the F32 agent
35 _LIT(KF32Agent,"F32 CA Agent");
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:\\"
45 EXPORT_C CAgentResolver* CAgentResolver::NewLC(const TBool aDynamicAgentUpdate)
47 CAgentResolver* self = new (ELeave) CAgentResolver(aDynamicAgentUpdate);
48 CleanupStack::PushL(self);
53 EXPORT_C CAgentResolver* CAgentResolver::NewL(const TBool aDynamicAgentUpdate)
55 CAgentResolver* self = CAgentResolver::NewLC(aDynamicAgentUpdate);
56 CleanupStack::Pop(self);
60 CAgentResolver::CAgentResolver(const TBool aDynamicAgentUpdate) : CActive(EPriorityStandard), iDynamicAgentUpdate(aDynamicAgentUpdate)
64 CAgentResolver::~CAgentResolver()
66 // remove ourselves from the ActiveScheduler
72 // Unload all the agents
73 DestroyListOfAgents();
75 // Close our ECOM session
78 if(iDynamicAgentUpdate)
80 iEcomSession->CancelNotifyOnChange(iStatus);
82 iEcomSession->Close();
83 REComSession::FinalClose();
86 iSupplierMimeTypes.Close();
87 iConsumerMimeTypes.Close();
91 void CAgentResolver::ConstructL()
93 if(iDynamicAgentUpdate)
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);
100 iEcomSession = &REComSession::OpenL();
102 // find all the agents
103 BuildListOfAgentsL();
105 if(iDynamicAgentUpdate)
107 // register for ECOM update notifications in case a new agent appears
109 iEcomSession->NotifyOnChange(iStatus);
113 void CAgentResolver::BuildListOfAgentsL()
117 // Get all plugins which implement the agent interface
118 RImplInfoPtrArray implArray;
119 CleanupStack::PushL(TCleanupItem(CleanImplArray, &implArray));
120 REComSession::ListImplementationsL(KCAAgentInterfaceUid, implArray);
122 for (TInt i = 0; i < implArray.Count(); ++i)
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())
131 // If the agent is not in ROM, don't load it because it might
132 // be a security risk.
137 // Construct all the agent infos from these implementations
138 TRAP(err, AddAgentL(*implArray[i]));
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
143 if(err == KErrNoMemory)
145 User::Leave(KErrNoMemory);
148 CleanupStack::PopAndDestroy(&implArray);
153 // If we didn't find a default agent, we have a big problem so panic
154 User::Panic(KCafPanicString, ECafPanicNoF32Agent);
158 void CAgentResolver::AddAgentL(const CImplementationInformation& aImplInfo)
160 // Create a CAgentInfo instance
161 CAgentInfo* agentInfo = CAgentInfo::NewLC(aImplInfo);
164 if(IsF32Agent(*agentInfo))
166 // It's the F32 Agent
169 // If we already have a default agent something is seriously wrong
170 User::Panic(KCafPanicString, ECafPanicDuplicateF32Agent);
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);
179 // All other agents go in the agent list
180 User::LeaveIfError(iAgentInfos.Append(agentInfo));
181 CleanupStack::Pop(agentInfo);
185 // Update our list of all supplier mime types supported by CAF
186 for(mimeIndex=0;mimeIndex < agentInfo->SupplierMimeTypes().Count(); mimeIndex++)
188 User::LeaveIfError(iSupplierMimeTypes.Append(*agentInfo->SupplierMimeTypes()[mimeIndex]));
191 // Update our list of all consumer mime types supported by CAF
192 for(mimeIndex=0;mimeIndex < agentInfo->ConsumerMimeTypes().Count(); mimeIndex++)
194 User::LeaveIfError(iConsumerMimeTypes.Append(*agentInfo->ConsumerMimeTypes()[mimeIndex]));
199 void CAgentResolver::DestroyListOfAgents()
201 iSupplierMimeTypes.Reset();
202 iConsumerMimeTypes.Reset();
204 // cant forget to delete the default agent
205 delete iDefaultAgent;
206 iDefaultAgent = NULL;
208 // Free memory assocated with the iAgentInfos array
209 iAgentInfos.ResetAndDestroy();
212 void CAgentResolver::DoCancel()
214 // Abort any update notification
215 iEcomSession->CancelNotifyOnChange(iStatus);
218 void CAgentResolver::RunL()
220 // Called by the ECOM framework if a new agent appears
222 // remove the existing list of agents and build a new one
223 DestroyListOfAgents();
224 BuildListOfAgentsL();
226 // request notification of any further changes
227 iEcomSession->NotifyOnChange(iStatus);
231 TBool CAgentResolver::IsF32Agent(CAgentInfo& aAgentInfo)
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)
248 CAgentInfo& CAgentResolver::ResolveSupplierMimeL(const TDesC8& aMimeType) const
250 // Go through all the agents and return the one which supports the
251 // required supplier mime type
252 CAgentInfo* retVal=NULL;
254 for (TInt i = 0; i < iAgentInfos.Count(); ++i)
256 if (iAgentInfos[i]->IsSupportedSupplier(aMimeType))
258 retVal = iAgentInfos[i];
265 User::Leave(KErrCANoAgent);
270 CAgentInfo& CAgentResolver::ResolveConsumerMime(const TDesC8& aMimeType) const
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;
276 for (TInt i = 0; i < iAgentInfos.Count(); ++i)
278 if (iAgentInfos[i]->IsSupportedConsumer(aMimeType))
280 retVal = iAgentInfos[i];
289 CAgentInfo& CAgentResolver::ResolveFileL(const TDesC& aURI, TDes& aActualUri, TContentShareMode aShareMode) const
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);
295 if(agentUid != iDefaultAgent->Agent().ImplementationUid())
297 // this file must be living in a private server directory
298 // return the agent who owns the directory
299 return AgentInfoL(agentUid);
303 TInt agentsCount(iAgentInfos.Count());
304 CAgentManager* agentManager = NULL;
305 for (TInt i = 0; i < agentsCount; ++i)
307 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL());
308 if(result != KErrNone)
310 if(KErrNoMemory == result)
319 if (agentManager->IsRecognizedL(aURI, aShareMode))
321 return *iAgentInfos[i];
325 return *iDefaultAgent;
328 CAgentInfo& CAgentResolver::ResolveFileL(RFile& aFile) const
330 // Go through all the agents and return the one which supports the file
332 TInt agentsCount(iAgentInfos.Count());
333 CAgentManager* agentManager = NULL;
334 for (TInt i = 0; i < agentsCount; ++i)
336 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL());
337 if(result != KErrNone)
339 if(KErrNoMemory == result)
348 if (agentManager->IsRecognizedL(aFile))
350 return *iAgentInfos[i];
353 return *iDefaultAgent;
356 #ifdef SYMBIAN_ENABLE_SDP_WMDRM_SUPPORT
358 CAgentInfo& CAgentResolver::ResolveFileL(const TDesC8& aHeaderData)
360 // Go through all the agents and return the one which supports the given WMDRM content.
362 TInt agentsCount(iAgentInfos.Count());
363 CAgentManager* agentManager = NULL;
365 for (TInt i = 0; i < agentsCount; ++i)
367 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL());
368 if(result != KErrNone)
370 if(KErrNoMemory == result)
380 if (agentManager->IsRecognizedL(aHeaderData))
382 return *iAgentInfos[i];
386 // will never reach here
387 return *iDefaultAgent;
391 EXPORT_C TBool CAgentResolver::DoRecognizeL(const TDesC8& aHeader, TDes8& aFileMimeType, TDes8& aContentMimeType)
393 // Go through all the agents and return the one which supports the given WMDRM content.
394 TInt agentsCount(iAgentInfos.Count());
395 CAgentManager* agentManager = NULL;
396 for (TInt i = 0; i < agentsCount; ++i)
398 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL());
399 if(result != KErrNone)
401 if(KErrNoMemory == result)
411 if (agentManager->RecognizeContentL(aHeader, aFileMimeType, aContentMimeType))
413 // force to lower case to ensure that chosen lower case scheme for mime types is maintained
414 aFileMimeType.LowerCase();
415 aContentMimeType.LowerCase();
423 #endif //#ifdef SYMBIAN_ENABLE_SDP_WMDRM_SUPPORT
425 TUid CAgentResolver::ResolveDirectory(const TDesC& aPath, TDes& aActualPath, TBool& aThePrivateDir) const
429 TBuf <KPrivateDirAndDriveLength> pathLowerCase;
431 // Assume it's a publicly accessable path
432 aThePrivateDir = EFalse;
434 // Find the length of the path and private directory
435 pathLength = aPath.Length();
437 // Check that the path is long enough to be within a private directory
438 // and does not include "..\\".The "..\\" sequence could be a security risk
439 if(aPath.Find(KParentDir()) == KErrNotFound && pathLength >= KPrivateDirAndDriveLength)
441 // Create a lower case copy of the left hand side of the path
442 TPtrC lowerCasePtr = aPath.Mid(KPrivateDirOffset, KPrivateDirLength);
443 pathLowerCase.Copy(lowerCasePtr);
444 pathLowerCase.LowerCase();
446 // Compare the first directory in the path to \\private\\
447 if(KPrivateDir() == pathLowerCase)
449 // It is a private directory of some sort
450 if(pathLength > KPrivateDirAndDriveLength)
452 // It must be a server private directory data cage
453 TPtrC serverDirectoryPath = aPath.Right(pathLength - KPrivateDirAndDriveLength);
454 for(i = 0; i < AgentInfoCount(); i++)
456 // See if the part after \\private\\ matches the agent name
457 TPtrC privateDirectoryName = AgentInfo(i).PrivateDirectoryName();
458 TPtrC agentName = AgentInfo(i).Agent().Name();
459 if(privateDirectoryName.Length() && agentName.Length() && agentName == serverDirectoryPath.Left(agentName.Length()))
461 // It must be this agent's private directory
462 // Convert \\private\\agentName\\... to \\private\\SID\\...
463 aActualPath.Copy(aPath.Left(KPrivateDirAndDriveLength));
464 aActualPath.Append(privateDirectoryName);
465 aActualPath.Append(aPath.Right(pathLength - KPrivateDirAndDriveLength - agentName.Length()));
466 return AgentInfo(i).Agent().ImplementationUid();
472 // It's just the c:\\private\\ directory
473 // Use the default agent, any calls will just fail
474 aThePrivateDir = ETrue;
479 // Not an agent private directory so just return the default agent
480 aActualPath.Copy(aPath);
481 return iDefaultAgent->Agent().ImplementationUid();
484 HBufC* CAgentResolver::ConvertAgentFileNameL(const TDesC& aFileName) const
487 TInt fileNameLength = 0;
488 TBuf <KPrivateDirAndDriveLength> pathLowerCase;
490 fileNameLength = aFileName.Length();
492 // If the path is shorter than the x:\\private\\ it must be a F32 file
493 if(fileNameLength > KPrivateDirAndDriveLength)
495 // Create a lower case copy of the left hand side of the path
496 TPtrC lowerCasePtr = aFileName.Mid(KPrivateDirOffset, KPrivateDirLength);
497 pathLowerCase.Copy(lowerCasePtr);
498 pathLowerCase.LowerCase();
500 // Compare the first directory in the path to \\private\\
501 if(KPrivateDir() == pathLowerCase)
503 // It is a private directory of some sort
504 if(fileNameLength > KPrivateDirAndDriveLength)
506 // It must be a server private directory data cage
507 TPtrC serverDirectoryPath = aFileName.Right(fileNameLength - KPrivateDirAndDriveLength);
508 for(i = 0; i < AgentInfoCount(); i++)
510 // See if the part after \\private\\ matches the agent name
511 TPtrC privateDirectoryName = AgentInfo(i).PrivateDirectoryName();
512 TPtrC agentName = AgentInfo(i).Agent().Name();
513 if(privateDirectoryName.Length() && agentName.Length() && privateDirectoryName == serverDirectoryPath.Left(privateDirectoryName.Length()))
515 // It is this agent's private directory
516 // Convert \\private\\SID\\... \\private\\agentName\\...
517 HBufC* buffer = HBufC::NewL(fileNameLength - privateDirectoryName.Length() + agentName.Length());
518 TPtr ptr = buffer->Des();
519 ptr.Copy(aFileName.Left(KPrivateDirAndDriveLength));
520 ptr.Append(agentName);
521 ptr.Append(aFileName.Right(fileNameLength - KPrivateDirAndDriveLength - privateDirectoryName.Length()));
528 return aFileName.AllocL();
531 EXPORT_C TBool CAgentResolver::DoRecognizeL(const TDesC& aName, const TDesC8& aBuffer, TDes8& aFileMimeType, TDes8& aContentMimeType)
534 // Given the filename and buffer from apparc, ask the agents in turn if they recognize the file
535 // Note this will not call the DefaultAgent (F32) because it won't be able to recognize anything
537 TInt agentsCount(iAgentInfos.Count());
538 CAgentManager* agentManager = NULL;
539 for (TInt i = 0; i < agentsCount; ++i)
541 TRAPD(result, agentManager = &iAgentInfos[i]->AgentManagerL());
542 if(result != KErrNone)
544 if(KErrNoMemory == result)
553 if (agentManager->RecognizeFileL(aName, aBuffer, aFileMimeType, aContentMimeType))
555 // force to lower case to ensure that chosen lower case scheme for mime types is maintained
556 aFileMimeType.LowerCase();
557 aContentMimeType.LowerCase();
565 void CAgentResolver::CleanImplArray(TAny* aArray)
567 static_cast<RImplInfoPtrArray*>(aArray)->ResetAndDestroy();
570 EXPORT_C TInt CAgentResolver::PreferredBufferSize()
574 if(iDefaultAgent != NULL)
576 size = iDefaultAgent->PreferredBufferSize();
579 // Find out the maximum buffer requested by any agent
580 for (TInt i = 0; i < iAgentInfos.Count(); ++i)
582 if(iAgentInfos[i]->PreferredBufferSize() > size)
584 size = iAgentInfos[i]->PreferredBufferSize();
591 EXPORT_C const RArray<TPtrC8>& CAgentResolver::ConsumerMimeTypes() const
593 return iConsumerMimeTypes;
597 EXPORT_C const RArray<TPtrC8>& CAgentResolver::SupplierMimeTypes() const
599 return iSupplierMimeTypes;
603 CAgentInfo& CAgentResolver::AgentInfoL(const TDesC& aAgentName) const
605 TBool found = EFalse;
607 for(i = 0; i < iAgentInfos.Count(); i++)
609 if(iAgentInfos[i]->Agent().Name() == aAgentName)
618 // Can't find the agent so leave
619 User::Leave(KErrNotFound);
622 return *iAgentInfos[i];
625 CAgentInfo& CAgentResolver::AgentInfoL(const TUid& aUid) const
628 TBool found = EFalse;
630 // See if it's the F32 agent
631 if(aUid == DefaultAgentUid())
633 return *iDefaultAgent;
636 for(i = 0; i < iAgentInfos.Count(); i++)
638 if(iAgentInfos[i]->Agent().ImplementationUid() == aUid)
647 // couldn't find the agent so leave
648 User::Leave(KErrNotFound);
651 return *iAgentInfos[i];
654 CAgentInfo& CAgentResolver::AgentInfo(TInt aIndex) const
656 return *iAgentInfos[aIndex];
659 TInt CAgentResolver::AgentInfoCount() const
661 return iAgentInfos.Count();
664 TUid CAgentResolver::DefaultAgentUid() const
666 return iDefaultAgent->Agent().ImplementationUid();