--- /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();
+ }