telephonyserver/etelserverandcore/SETEL/ET_MAN.CPP
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserver/etelserverandcore/SETEL/ET_MAN.CPP	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,599 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+*/
+
+
+#include <e32svr.h>
+#include <f32file.h>
+#include "ET_SSTD.H"
+
+const TUint KColonChar=':';
+_LIT(KDoubleColon, "::");
+const TInt KDoubleColonLength = 2;
+
+//
+// CPhoneManager class
+//
+
+CPhoneManager* CPhoneManager::NewL()
+//
+// Create new instance of phone manager
+//
+	{
+	CPhoneManager* phoneManager=new(ELeave) CPhoneManager();
+	CleanupStack::PushL(phoneManager);
+	phoneManager->ConstructL();
+	CleanupStack::Pop();
+	return phoneManager;
+	}
+
+CPhoneManager::CPhoneManager()
+	{}
+
+void CPhoneManager::ConstructL()
+	{
+	iContainerIx=CObjectConIx::NewL();
+	iObjectCon=iContainerIx->CreateL();
+	iTsyModulesCon =iContainerIx->CreateL();
+	iDuplicatePhones = new (ELeave) CArrayPtrFlat<CDuplicatePhoneInfo>(3);
+	}
+
+CPhoneManager::~CPhoneManager()
+//
+//	Destroy all objects in global storage
+//
+	{
+	if (iContainerIx)
+		{
+		iContainerIx->Remove(iObjectCon);
+		iContainerIx->Remove(iTsyModulesCon);
+		delete iContainerIx;
+		}
+	if(iDuplicatePhones)
+		{
+		iDuplicatePhones->ResetAndDestroy();
+		delete iDuplicatePhones;
+		}
+	}
+
+void CloseObject(TAny* aObj)
+//
+// Utility func for cleanup stack
+//
+	{
+	CObject* obj=REINTERPRET_CAST(CObject*,aObj);
+	obj->Close();
+	}
+
+CPhoneBase* CPhoneManager::OpenPhoneFromFactoryL(CPhoneFactoryBase* aParent,const TDesC& aName)
+//
+// Search for the name of this TelObject if found open it if not create new instances of the object
+//
+	{
+	CPhoneBase* newObject=NULL;
+	TInt handle=0;
+	TFullName dummy;
+	TInt res=iObjectCon->FindByFullName(handle,aName,dummy);
+	switch (res)
+		{
+	case KErrNotFound:
+			{
+			TInt len=aName.LocateReverse(KColonChar);
+			if (len==KErrNotFound)
+				User::Leave(KErrBadName);
+			TName name=aName;
+			name=aName.Right(aName.Length()-len-1);
+			TName originalName(name);
+			ConvertPhoneNameToOriginal(originalName);	// this converts phone name to original if it has been previously converted
+
+			newObject=aParent->NewPhoneL(originalName);
+
+			TCleanupItem newObjectClose(CloseObject,newObject);
+			CleanupStack::PushL(newObjectClose);
+			newObject->SetNameL(&name); // MUST not be a full name. It must be the name recognised by clients
+					// not necessarily what the TSY calls it, if another TSY has already been loaded
+					// with an identical phone name
+			newObject->SetOwner(aParent);
+			newObject->SetPhoneOwner(newObject);
+			iObjectCon->AddL(newObject);
+			newObject->Init(); // Call Tsy Init
+			CleanupStack::Pop();
+			}
+		break;
+	case KErrNone:
+		newObject=REINTERPRET_CAST(CPhoneBase*,iObjectCon->At(handle));
+		newObject->Open();
+		break;
+	default:
+		User::Leave(res);
+		}
+	return newObject;
+	}
+
+CTelObject* CPhoneManager::OpenSubSessionObjectL(CTelObject* aParent, TDes& aNewName)
+//
+//	Create a new instance of this TelObject, expecting to be given a name back
+//
+	{
+	CTelObject* newObject=NULL;
+	newObject=aParent->OpenNewObjectL(aNewName);
+	
+	__ASSERT_ALWAYS(newObject!=NULL,Fault(EEtelFaultBadPhonePointer));
+	
+	TCleanupItem newObjectClose(CloseObject,newObject);
+	CleanupStack::PushL(newObjectClose);
+	newObject->SetOwner(aParent);
+	newObject->SetNameL(&aNewName); // MUST not be a full name	
+	newObject->SetPhoneOwner(aParent->PhoneOwner());
+	if(iObjectCon->CheckUniqueFullName(newObject)!=KErrAlreadyExists)		// If the TSY is allocating objects from a pool, this one may already be registered.
+		iObjectCon->AddL(newObject);
+	newObject->Init();
+	CleanupStack::Pop();
+	return newObject;
+	}
+	
+CTelObject* CPhoneManager::OpenSubSessionObjectByNameL(CTelObject* aParent, const TDesC& aName/*,TTelObjectOpenSource aSource*/)
+//
+// Search for the name of this TelObject if found open it if not create new instances of the object
+//
+	{
+	CTelObject* newObject=NULL;
+	TInt handle=0;
+	TFullName dummy;
+	TInt res=iObjectCon->FindByFullName(handle,aName,dummy);
+	switch (res)
+		{
+	case KErrNotFound:
+			{
+			// All parsing of the name string done so far has been from left to right
+			// Cannot simply start parsing from right to left to extract the last name element
+			// There is an, albiet unlikely, error case in which the string ":::" appears, which would cause a problem
+			TInt len = 0;
+			TName name = aName;
+			// Loop through the name string, removing each element deliminated by two colons, until only the tail of the string is left
+			do
+				{
+				len = name.Find(KDoubleColon);
+
+				if ( (len != KErrNotFound) && (name.Length() > KDoubleColonLength) )
+					{
+					name.Copy(name.Mid(len + KDoubleColonLength));
+					}
+				else
+					{
+					// Length wasn't greater than KDoubleColonLength, so the double colon was at the end of the string
+					// This shouldn't ever happen.
+					break;
+					}
+				
+				} while (len != KErrNotFound);
+
+			if (name.Length())
+				newObject=aParent->OpenNewObjectByNameL(name);
+			else
+				newObject=aParent->OpenNewObjectL(name);	// TSY will supply a name
+				
+			__ASSERT_ALWAYS(newObject!=NULL,Fault(EEtelFaultBadPhonePointer));				
+			
+			TCleanupItem newObjectClose(CloseObject,newObject);
+			CleanupStack::PushL(newObjectClose);
+			newObject->SetNameL(&name); // MUST not be a full name
+			newObject->SetOwner(aParent);
+			newObject->SetPhoneOwner(aParent->PhoneOwner());
+			iObjectCon->AddL(newObject);
+			newObject->Init();
+			CleanupStack::Pop();
+			break;
+			}
+	case KErrNone:
+		newObject=REINTERPRET_CAST(CTelObject*,iObjectCon->At(handle));
+		newObject->Open();
+		break;
+	default:
+		User::Leave(res);
+		}
+	return newObject;
+	}
+	
+void CloseLibrary(TAny* aLib)
+//
+// Close a library from the cleanup stack
+//
+	{
+	RLibrary* lib=REINTERPRET_CAST(RLibrary*,aLib);
+	lib->Close();
+	}
+
+CPhoneFactoryBase* CPhoneManager::OpenPhoneFactoryFromTsyL(const TDesC& aName)
+//
+// Find a previously opened phone by name
+//
+	{
+	TInt handle=0;
+	TName matching;
+	User::LeaveIfError(iTsyModulesCon->FindByName(handle,aName,matching));
+	return REINTERPRET_CAST(CPhoneFactoryBase*,iTsyModulesCon->At(handle));
+	}
+
+//
+// Typedef required for returning PhoneFactoryBase instance
+//
+typedef CPhoneFactoryBase*(*TPhoneFactoryBaseNewL)();
+
+CPhoneFactoryBase* CPhoneManager::LoadPhoneModuleL(const TDesC& aFileName)
+//
+// Load an Etel module (TSY) on user request
+//
+	{
+	// Strip .TSY Off
+	TName name(aFileName);
+	TInt len=name.Locate('.');
+	name.SetLength(len);
+
+	TName foundName;
+	TInt findHandle=0;
+	TInt found=iTsyModulesCon->FindByName(findHandle,name,foundName);	// Is already loaded?
+	if(found==KErrNone)
+		{	// The TSY is already loaded, we'll just open, and bump up the reference count.
+		LOGTEXT("LoadPhoneModuleL\tTSY already loaded - inc ref count");
+		CPhoneFactoryBase* s=REINTERPRET_CAST(CPhoneFactoryBase*,iTsyModulesCon->At(findHandle));
+		s->Open();
+		return s;
+		}
+
+	RLibrary lib;
+#ifdef _DEBUG
+	TBuf8<128> buf;
+	buf.Copy(aFileName);
+#endif // _DEBUG
+	LOGTEXT2("Loading %S", &buf);
+	TInt r=lib.Load(aFileName);
+	if (r!=KErrNone)
+		User::Leave(r);
+	LOGTEXT2("Loaded %S", &buf);
+	TCleanupItem libClose(CloseLibrary,&lib);
+	CleanupStack::PushL(libClose);
+
+	// Check the Uid2
+	if(lib.Type()[1]!=TUid::Uid(KUidUnicodeEtelServerModule))
+		User::Leave(KErrBadLibraryEntryPoint);
+
+	TPhoneFactoryBaseNewL libEntry=(TPhoneFactoryBaseNewL)lib.Lookup(1);
+	if (libEntry==NULL)
+		User::Leave(KErrBadLibraryEntryPoint);
+	LOGTEXT("About to get CPhoneFactoryBase ptr");
+	CPhoneFactoryBase* s=NULL;
+	s=(*libEntry)();	// libEntry may leave.
+	if(s==NULL)
+		User::Leave(KErrNoMemory);
+	LOGTEXT("Got CPhoneFactoryBase ptr");
+	TRAPD(error, s->ConstructL(lib));
+	if(error)
+		{
+		s->Close();
+		User::Leave(error);
+		}
+	CleanupStack::Pop();
+
+	if (DuplicatePhoneName(s))
+		{
+		s->Close();
+		User::Leave(KErrEtelDuplicatePhoneName);
+		}
+
+	TInt errorName = s->SetName(&name);
+	if(errorName!=KErrNone)
+		{
+		s->Close();
+		User::Leave(errorName);
+		}
+
+	TRAPD(ret,iTsyModulesCon->AddL(s));
+	if(ret!=KErrNone)
+		{
+		s->Close();
+		User::Leave(ret);
+		}
+
+	if (iTsyModulesCon->Count()>1)	// only check for phone name clashes if have >1 TSYs loaded
+		{
+		TInt ret = RenameDuplicatePhoneName();
+		if (ret!=KErrNone)
+			{
+			s->Close();
+			User::Leave(ret);
+			}
+		}
+	return s;
+	}
+
+TInt CPhoneManager::EnumeratePhones() const
+//
+// Return the number of phones in all loaded tsy
+//
+	{
+	TInt tsyCount=0;
+	TUint numPhones=0;
+	while (tsyCount<iTsyModulesCon->Count())
+		{
+		CPhoneFactoryBase* phoneFac=REINTERPRET_CAST(CPhoneFactoryBase*,iTsyModulesCon->operator[](tsyCount));
+		numPhones+=phoneFac->EnumeratePhones();
+		tsyCount++;
+		}
+	return numPhones;
+	}
+
+TInt CPhoneManager::GetPhoneInfo(TUint aIndex,RTelServer::TPhoneInfo& aInfo) const
+//
+// Get info by number on a specified phone.
+//
+	{
+	TInt tsyCount=0;
+	TUint numPhones=0;
+	TUint lastCount=0;
+	while (tsyCount<iTsyModulesCon->Count())
+		{
+		CPhoneFactoryBase* phoneFac=REINTERPRET_CAST(CPhoneFactoryBase*,iTsyModulesCon->operator[](tsyCount));
+		numPhones+=phoneFac->EnumeratePhones();
+		if (aIndex<numPhones) // the phone index refers to is in this tsy
+			{
+			return phoneFac->GetPhoneInfo(aIndex-lastCount,aInfo);
+			}
+		tsyCount++;
+		lastCount=numPhones;
+		}
+	return KErrNotFound;
+	}
+
+TInt CPhoneManager::GetTsyName(const TInt aIndexOfPhone,TDes& aTsyName) const
+	{
+	CPhoneFactoryBase* phoneFac = PhoneFactoryObjectFromPhoneIndex(aIndexOfPhone);
+	if (phoneFac!=NULL)
+		{
+		aTsyName = phoneFac->Name();
+		return KErrNone;
+		}
+	else
+		return KErrNotFound;
+	}
+
+CPhoneFactoryBase* CPhoneManager::PhoneFactoryObjectFromPhoneIndex(TUint aIndex) const
+//
+// Return a factory handle for a given phone index.
+//
+	{
+	TInt tsyCount=0;
+	TUint numPhones=0;
+	while (tsyCount<iTsyModulesCon->Count())
+		{
+		CPhoneFactoryBase* phoneFac=REINTERPRET_CAST(CPhoneFactoryBase*,iTsyModulesCon->operator[](tsyCount));
+		numPhones+=phoneFac->EnumeratePhones();
+		if (aIndex<numPhones) // the phone index refers to is in this tsy
+			return phoneFac;
+		tsyCount++;
+		}
+	return NULL;
+	}
+
+CPhoneFactoryBase* CPhoneManager::PhoneFactoryObjectFromPhoneName(const TDesC& aPhoneName) const
+//
+// Return a handle for phone factory base with given name
+// NULL if not found in any tsy module
+//
+	{
+	RTelServer::TPhoneInfo info;
+	TUint numPhones=EnumeratePhones();
+	TUint count=0;
+	CPhoneFactoryBase* fact=NULL;
+	
+	while (count<numPhones)
+		{
+		GetPhoneInfo(count,info);
+		fact = PhoneFactoryObjectFromPhoneIndex(count);
+		ConvertPhoneNameFromOriginal(fact->Name(),info.iName);	// convert original phone name to munged if possible, 
+					// because aPhoneName will be in that form
+		if (info.iName.Compare(aPhoneName)==KErrNone) // found a match phone name
+			return fact;
+		count++;
+		}
+	return NULL;
+	}
+
+TBool CPhoneManager::DuplicatePhoneName(CPhoneFactoryBase* aPhoneFac) const
+//
+// Scan throu' phone names in this TSY and check that no two phones has the same name
+//
+	{
+	RTelServer::TPhoneInfo infoToCompare;
+	RTelServer::TPhoneInfo infoToMatch;
+	TUint numPhones=aPhoneFac->EnumeratePhones();
+	TUint indexToCompare=0;
+	if (numPhones<=1)
+		return EFalse;
+	do
+		{
+		aPhoneFac->GetPhoneInfo(indexToCompare,infoToCompare);
+		for (TUint i=indexToCompare+1;i<numPhones;i++)
+			{
+			aPhoneFac->GetPhoneInfo(i,infoToMatch);
+			if (infoToMatch.iName.Compare(infoToCompare.iName)==KErrNone) // found a match
+				return ETrue;
+			}
+		indexToCompare++;
+		}
+	while (indexToCompare<numPhones);
+	return EFalse;
+	}
+
+TInt CPhoneManager::RenameDuplicatePhoneName() const
+//
+// Scan through phone names and check for identical phone names (because a new TSY has just been
+// loaded for instance). 
+// Assumes that for all TSYs loaded, if they have more than one phone, that the phone 
+// names within that TSY are all different. This assumption should be OK since this is checked at load time.
+// Make a note of which phone has an identical name
+//
+	{
+	RTelServer::TPhoneInfo infoToCompare;
+	RTelServer::TPhoneInfo infoToMatch;
+	TUint numPhones=EnumeratePhones();
+	TUint indexToCompare=0;
+	if (numPhones<=1)
+		return EFalse;
+	do
+		{
+		GetPhoneInfo(indexToCompare,infoToCompare);
+		for (TUint i=indexToCompare+1;i<numPhones;i++)
+			{
+			GetPhoneInfo(i,infoToMatch);
+			if (infoToMatch.iName.Compare(infoToCompare.iName)==KErrNone) // found a match
+				{
+				TName tsyName;
+				TInt err = GetTsyName(i,tsyName);
+				if(err != KErrNone)
+					return err;
+				_LIT(KDash,"-");
+				TName newName(tsyName);
+				newName.Append(KDash);
+				newName.Append(infoToMatch.iName);	// Create unique name
+				LOGTEXT2("new name = %S", &newName);
+				LOGTEXT2("tsy name = %S", &tsyName);
+				LOGTEXT2("old name = %S", &infoToMatch.iName);	
+				TRAPD(ret,StoreDuplicateNameL(tsyName,infoToMatch.iName,newName));// even if this returns with 
+									//KErrAlreadyExists, carry on searching for another match
+				if (ret!=KErrNone && ret!=KErrAlreadyExists)
+					return ret;
+				}
+			}
+		indexToCompare++;
+		}
+	while (indexToCompare<numPhones);
+	return KErrNone;
+	}
+
+void CPhoneManager::StoreDuplicateNameL(const TDesC& aTsyName, const TDesC& aOriginalName, const TDesC& aNewName) const
+	{
+	for (TInt i=0; i<iDuplicatePhones->Count(); i++)
+		{
+		if (iDuplicatePhones->At(i)->iNewName->CompareF(aNewName)==KErrNone)
+			User::Leave(KErrAlreadyExists);	// Leave if the munged name has already been chosen.
+		}
+	CDuplicatePhoneInfo* phoneInfo = CDuplicatePhoneInfo::NewLC(&aTsyName,&aOriginalName,&aNewName);
+	iDuplicatePhones->AppendL(phoneInfo);
+	CleanupStack::Pop();
+	}
+
+TInt CPhoneManager::ConvertPhoneNameToOriginal(TDes& aName) const
+	{
+	CDuplicatePhoneInfo* eachInfo;
+	for (TInt i=0; i<iDuplicatePhones->Count();i++)
+		{
+		eachInfo = iDuplicatePhones->At(i);
+		if (eachInfo->iNewName->Des()==aName)
+			{
+			aName=eachInfo->iOriginalName->Des();
+			return KErrNone;
+			}
+		}
+	return KErrNotFound;
+	}
+
+TInt CPhoneManager::ConvertPhoneNameFromOriginal(const TDesC& aTsyName, TDes& aPhoneName) const
+	{
+	CDuplicatePhoneInfo* eachInfo;
+	for (TInt i=0; i<iDuplicatePhones->Count();i++)
+		{
+		eachInfo = iDuplicatePhones->At(i);
+		if (eachInfo->iOriginalName->Des()==aPhoneName && eachInfo->iTsyName->Des()==aTsyName)
+			{
+			aPhoneName=eachInfo->iNewName->Des();
+			return KErrNone;
+			}
+		}
+	return KErrNotFound;
+	}
+				
+void CPhoneManager::RemoveDuplicatePhoneInfo(const TDesC& aTsyName)
+//
+//	If a session Closes a Phone Module, and it was the last session to have a handle open on the
+//	Module, the Duplicate Phone Information needs to be removed.
+//	So search currently loaded TSYs to see if the session's removed TSY has in fact been removed
+//	altogether, and if so remove the duplicate phone info.
+//
+	{	
+	TRAPD(ret,OpenPhoneFactoryFromTsyL(aTsyName));
+	if (ret==KErrNone)	// a session still has a handle on it
+		return;
+	CDuplicatePhoneInfo* eachInfo;
+	TInt max = iDuplicatePhones->Count()-1;
+	for (TInt i=max; i>=0;--i)	// otherwise we need to remove it
+		{
+		eachInfo = iDuplicatePhones->At(i);
+		if (eachInfo->iTsyName->Des()==aTsyName)
+			{
+			delete eachInfo;
+			iDuplicatePhones->Delete(i);
+			}
+		}
+	}
+//
+// CDuplicatePhoneInfo
+//	
+
+CDuplicatePhoneInfo* CDuplicatePhoneInfo::NewLC(const TDesC* aTsyName,const TDesC* aOriginalName, const TDesC* aNewName)
+	{
+	CDuplicatePhoneInfo* p = new (ELeave) CDuplicatePhoneInfo();
+	CleanupStack::PushL(p);
+	p->ConstructL(aTsyName,aOriginalName,aNewName);
+	return p;
+	}
+
+CDuplicatePhoneInfo::CDuplicatePhoneInfo()
+	{}
+
+CDuplicatePhoneInfo::~CDuplicatePhoneInfo()
+	{
+	delete iTsyName;
+	delete iNewName;
+	delete iOriginalName;
+	}
+
+void CDuplicatePhoneInfo::ConstructL(const TDesC* aTsyName,const TDesC* aOriginalName,const TDesC* aNewName)
+	{
+	delete(iTsyName);
+	iTsyName=NULL;
+
+	if (aTsyName!=NULL)
+		{
+		iTsyName=aTsyName->AllocL();
+		}
+
+	delete(iNewName);
+	iNewName=NULL;
+
+	if (aNewName!=NULL)
+		{
+		iNewName=aNewName->AllocL();
+		}
+
+	delete(iOriginalName);
+	iOriginalName=NULL;
+
+	if (aOriginalName!=NULL)
+		iOriginalName=aOriginalName->AllocL();
+	}