#include "CServerPlugin.h"
#include "ServerControl.h"
#include "CNodeList.h"
#include "CPlugInList.h"
#include "CString.h"
#include "DSUtils.h"
#include "CLog.h"
#include "CConfigurePlugin.h"
#include "COSUtils.h"
#include <stdlib.h> // for rand()
#include <CoreFoundation/CFPlugIn.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFURL.h>
using namespace DSServerPlugin;
static sInt32 _UnregisterNode ( const uInt32, tDataList * );
static void _DebugLog ( const char *inFormat, va_list inArgs );
static SvrLibFtbl _Callbacks = { CServerPlugin::_RegisterNode, _UnregisterNode, _DebugLog };
const sInt32 kNodeNotRegistered = -8000;
const sInt32 kNodeAlreadyRegistered = -8001;
const sInt32 kInvalidToken = -8002;
const sInt32 kNullNodeName = -8003;
const sInt32 kEmptyNodeName = -8004;
const sInt32 kServerError = -8101;
sInt32 CServerPlugin::_RegisterNode ( const uInt32 inToken, tDataList *inNodeList, eDirNodeType inNodeType )
{
sInt32 siResult = eDSNoErr;
tDataList *pNodeList = nil;
char *pNodeName = nil;
CServerPlugin *pPluginPtr = nil;
bool bDone = false;
if ( inNodeType == kUnknownNodeType )
{
return( kNodeNotRegistered );
}
if ( inToken == 0 )
{
return( kInvalidToken );
}
pPluginPtr = gPlugins->GetPlugInPtr( inToken );
if ( pPluginPtr == nil )
{
return( kInvalidToken );
}
if ( inNodeList == nil )
{
return( kNullNodeName );
}
if ( (inNodeList->fDataNodeCount == 0) || (inNodeList->fDataListHead == nil) )
{
return( kEmptyNodeName );
}
if ( gNodeList == nil )
{
return( kServerError );
}
pNodeName = ::dsGetPathFromListPriv( inNodeList, (char *)gNodeList->GetDelimiter() );
if ( pNodeName != nil )
{
if ( inNodeType & kDirNodeType )
{
if ( gNodeList->IsPresent( pNodeName, kDirNodeType ) == false )
{
pNodeList = dsBuildFromPathPriv( pNodeName, (char *)gNodeList->GetDelimiter() );
gNodeList->AddNode( pNodeName, pNodeList, kDirNodeType, pPluginPtr );
}
else
{
siResult = kNodeAlreadyRegistered;
}
bDone = true;
}
if ( inNodeType & kLocalHostedType )
{
if ( gNodeList->IsPresent( pNodeName, kLocalHostedType ) == false )
{
pNodeList = dsBuildFromPathPriv( pNodeName, (char *)gNodeList->GetDelimiter() );
gNodeList->AddNode( pNodeName, pNodeList, kLocalHostedType, pPluginPtr );
}
else
{
siResult = kNodeAlreadyRegistered;
}
bDone = true;
}
if ( inNodeType & kDefaultNetworkNodeType )
{
if ( gNodeList->IsPresent( pNodeName, kDefaultNetworkNodeType ) == false )
{
pNodeList = dsBuildFromPathPriv( pNodeName, (char *)gNodeList->GetDelimiter() );
gNodeList->AddNode( pNodeName, pNodeList, kDefaultNetworkNodeType, pPluginPtr );
}
else
{
siResult = kNodeAlreadyRegistered;
}
bDone = true;
}
if ( !bDone && ( inNodeType & (kLocalNodeType | kSearchNodeType | kConfigNodeType | kContactsSearchNodeType | kNetworkSearchNodeType) ) )
{
pNodeList = dsBuildFromPathPriv( pNodeName, (char *)gNodeList->GetDelimiter() );
siResult = gNodeList->AddNode( pNodeName, pNodeList, inNodeType, pPluginPtr );
if (siResult == 0) {
::dsDataListDeallocatePriv( pNodeList );
free(pNodeList);
pNodeList = nil;
siResult = kNodeAlreadyRegistered;
}
else
{
siResult = eDSNoErr;
}
}
free( pNodeName );
pNodeName = nil;
}
else
{
siResult = kServerError;
}
return( siResult );
}
static sInt32 _UnregisterNode ( const uInt32 inToken, tDataList *inNode )
{
sInt32 siResult = 0;
char *nodePath = nil;
if ( inNode == nil )
{
return( kNullNodeName );
}
if ( (inNode->fDataNodeCount == 0) || (inNode->fDataListHead == nil) )
{
return( kEmptyNodeName );
}
if ( gNodeList == nil )
{
return( kServerError );
}
nodePath = ::dsGetPathFromListPriv( inNode, (char *)gNodeList->GetDelimiter() );
if ( nodePath != nil )
{
if ( gNodeList->DeleteNode( nodePath ) != true )
{
siResult = kNodeNotRegistered;
ERRORLOG1( kLogPlugin, "Can't unregister node %s since not registered", nodePath );
}
else
{
SRVRLOG1( kLogPlugin, "Unregistered node %s", nodePath );
}
free( nodePath );
nodePath = nil;
}
return( siResult );
}
static void _DebugLog ( const char *inPattern, va_list args )
{
CString inLogStr( inPattern, args );
DBGLOG( kLogPlugin, inLogStr.GetData() );
}
CServerPlugin::CServerPlugin ( void ) : mInstance( NULL )
{
SvrLibFtbl stTemp = _Callbacks;
}
CServerPlugin::CServerPlugin ( CFPlugInRef inThis,
CFUUIDRef inFactoryID,
FourCharCode inSig,
uInt32 inVers,
char *inName )
: mInstance( NULL )
{
IUnknownVTbl *spUnknown = NULL;
SvrLibFtbl stTemp = _Callbacks;
fPlugInRef = inThis;
fPlugInVers = inVers; fPlugInName = nil;
spUnknown = (IUnknownVTbl *)::CFPlugInInstanceCreate( kCFAllocatorDefault,
inFactoryID,
kModuleTypeUUID );
if ( spUnknown == NULL )
{
throw( (sInt32) 'ecom' );
}
spUnknown->QueryInterface( spUnknown,
::CFUUIDGetUUIDBytes( kModuleInterfaceUUID ),
(LPVOID *)(&mInstance) );
spUnknown->Release( spUnknown );
if ( mInstance == NULL )
{
throw( (sInt32) 'ecom' );
}
stTemp.fSignature = inSig;
mInstance->linkLibFtbl( mInstance, &stTemp );
if ( inName != nil )
{
fPlugInName = new char[ ::strlen( inName ) + 1 ];
::strcpy( fPlugInName, inName );
}
fPlugInSignature = inSig;
}
CServerPlugin::~CServerPlugin ( void )
{
if ( fPlugInName != nil )
{
delete( fPlugInName );
fPlugInName = nil;
}
if ( mInstance != nil )
{
mInstance->Release( mInstance );
mInstance = nil;
}
}
sInt32 CServerPlugin::ProcessURL ( CFURLRef inURLPlugin )
{
sInt32 siResult = -1;
char *pPIVersion = nil;
char *pPIName = nil;
char *pPIConfigAvail = nil;
char *pPIConfigFile = nil;
bool bGotIt = false;
unsigned char path[ PATH_MAX ] = "\0";
uInt32 ulVers = 0;
CServerPlugin *cpPlugin = nil;
FourCharCode fccPlugInSignature = 0;
CFPlugInRef plgThis = ::CFPlugInCreate( kCFAllocatorDefault, inURLPlugin );
CFStringRef cfsVersion = nil;
CFStringRef cfsName = nil;
CFStringRef cfsConfigAvail = nil;
CFStringRef cfsConfigFile = nil;
CFArrayRef cfaFactories = nil;
CFUUIDRef cfuuidFactory = nil;
CFBundleRef bdlThis = nil;
CFDictionaryRef plInfo = nil;
try
{
::CFURLGetFileSystemRepresentation( inURLPlugin, true, path, sizeof( path ) );
if ( plgThis == nil ) throw ( (sInt32)eCFMGetFileSysRepErr );
bdlThis = ::CFPlugInGetBundle( plgThis );
if ( bdlThis == nil ) throw ( (sInt32)eCFPlugInGetBundleErr );
plInfo = ::CFBundleGetInfoDictionary( bdlThis );
if ( plInfo == nil ) throw ( (sInt32)eCFBndleGetInfoDictErr );
ulVers = ::CFBundleGetVersionNumber( bdlThis );
if ( ::CFDictionaryGetValue( plInfo, kCFPlugInTypesKey ) == nil ) throw ( (sInt32)eCFBndleGetInfoDictErr );
if ( ::CFDictionaryGetValue( plInfo, kCFPlugInFactoriesKey ) == nil ) throw ( (sInt32)eCFBndleGetInfoDictErr );
cfsVersion = (CFStringRef)::CFDictionaryGetValue( plInfo, kPluginVersionStr );
if ( cfsVersion == nil ) throw( (sInt32)ePluginVersionNotFound );
pPIVersion = (char *)::malloc( kMaxPlugInAttributeStrLen );
if ( pPIVersion == nil ) throw( (sInt32)eMemoryError );
bGotIt = CFStringGetCString( cfsVersion, pPIVersion, kMaxPlugInAttributeStrLen, kCFStringEncodingMacRoman );
if (bGotIt == false) throw( (sInt32)ePluginVersionNotFound );
pPIConfigAvail = (char *)::malloc( kMaxPlugInAttributeStrLen );
if ( pPIConfigAvail == nil ) throw( (sInt32)eMemoryError );
cfsConfigAvail = (CFStringRef)::CFDictionaryGetValue( plInfo, kPluginConfigAvailStr );
if (cfsConfigAvail)
{
bGotIt = CFStringGetCString( cfsConfigAvail, pPIConfigAvail, kMaxPlugInAttributeStrLen, kCFStringEncodingMacRoman );
if (bGotIt == false) throw( (sInt32)ePluginConfigAvailNotFound );
}
else
{
::strcpy(pPIConfigAvail, "Not Available");
}
pPIConfigFile = (char *)::malloc( kMaxPlugInAttributeStrLen );
if ( pPIConfigFile == nil ) throw( (sInt32)eMemoryError );
cfsConfigFile = (CFStringRef)::CFDictionaryGetValue( plInfo, kPluginConfigFileStr );
if (cfsConfigFile)
{
bGotIt = CFStringGetCString( cfsConfigFile, pPIConfigFile, kMaxPlugInAttributeStrLen, kCFStringEncodingMacRoman );
if (bGotIt == false) throw( (sInt32)ePluginConfigFileNotFound );
}
else
{
::strcpy(pPIConfigFile, "Not Available");
}
cfsName = (CFStringRef)::CFDictionaryGetValue( plInfo, kPluginNameStr );
if ( cfsName == nil ) throw( (sInt32)ePluginNameNotFound );
pPIName = (char *)::malloc( kMaxPlugInAttributeStrLen );
if ( pPIName == nil ) throw( (sInt32)eMemoryError );
bGotIt = CFStringGetCString( cfsName, pPIName, kMaxPlugInAttributeStrLen, kCFStringEncodingMacRoman );
if (bGotIt == false) throw( (sInt32)ePluginNameNotFound );
if ( gPlugins == nil ) throw( (sInt32)ePluginHandlerNotLoaded );
siResult = gPlugins->IsPresent( pPIName );
if (siResult != kPlugInNotFound) throw( (sInt32)ePluginNameNotFound );
#ifdef vDEBUB
::printf( "Complete Info.plist is:\n" );
::CFShow( plInfo );
::fflush( stdout );
#endif
cfaFactories = ::CFPlugInFindFactoriesForPlugInTypeInPlugIn( kModuleTypeUUID, plgThis );
if ( cfaFactories == nil ) throw ( (sInt32)eNoPluginFactoriesFound );
if (::CFArrayGetCount ( cfaFactories ) == 0) throw( (sInt32)eNoPluginFactoriesFound );
cfuuidFactory = (CFUUIDRef)::CFArrayGetValueAtIndex( cfaFactories, 0 );
try
{
fccPlugInSignature = ::rand();
DBGLOG1( kLogApplication, "Loading plugin: \"%s\"", pPIName );
cpPlugin = new CServerPlugin( plgThis, cfuuidFactory, fccPlugInSignature, ulVers, pPIName );
if ( cpPlugin != nil )
{
gPlugins->AddPlugIn( pPIName, pPIVersion, pPIConfigAvail, pPIConfigFile, fccPlugInSignature, cpPlugin );
cpPlugin->Validate( pPIVersion, fccPlugInSignature );
SRVRLOG2( kLogApplication, "Plugin \"%s\", Version \"%s\", loaded successfully.", pPIName, pPIVersion );
DBGLOG3( kLogApplication, "Plugin \"%s\", Configure HI \"%s\", can be used to configure PlugIn with file \"%s\".", pPIName, pPIConfigAvail, pPIConfigFile );
pPIName = nil;
pPIVersion = nil;
pPIConfigAvail = nil;
pPIConfigFile = nil;
cpPlugin = nil;
}
else
{
ERRORLOG1( kLogApplication, "ERROR: \"%s\" plugin _FAILED_ to loaded.", pPIName );
}
siResult = eDSNoErr;
}
catch( sInt32 err )
{
ERRORLOG1( kLogPlugin, "*** Error in Plugin path = %s.", path );
ERRORLOG2( kLogPlugin, "*** Error attempting to load plugin %s. Error = %ld", pPIName, err );
}
}
catch( sInt32 err )
{
siResult = err;
}
if ( pPIVersion != nil )
{
free( pPIVersion );
pPIVersion = nil;
}
if ( pPIName != nil )
{
free( pPIName );
pPIName = nil;
}
if ( plgThis != nil )
{
::CFRelease( plgThis );
plgThis = nil;
}
if ( cfaFactories != nil )
{
::CFRelease( cfaFactories );
cfaFactories = nil;
}
#if DEBUG
::fflush( stdout );
::fflush( stderr );
#endif
return( siResult );
}
sInt32 CServerPlugin::Validate ( const char *inVersionStr, const uInt32 inSignature )
{
return( mInstance->validate( mInstance, inVersionStr, inSignature ) );
}
sInt32 CServerPlugin::PeriodicTask ( void )
{
return( mInstance->periodicTask( mInstance ) );
}
sInt32 CServerPlugin::Initialize ( void )
{
return( mInstance->initialize( mInstance ) );
}
sInt32 CServerPlugin::ProcessRequest ( void *inData )
{
return( mInstance->processRequest( mInstance, inData ) );
}
sInt32 CServerPlugin::SetPluginState ( const uInt32 inState )
{
return( mInstance->setPluginState( mInstance, inState ) );
}
char* CServerPlugin::GetPluginName ( void )
{
return( fPlugInName );
}
FourCharCode CServerPlugin::GetSignature ( void )
{
return( fPlugInSignature );
}
sInt32 CServerPlugin::ProcessConfigurePlugin ( void )
{
sInt32 siResult = -1;
CConfigurePlugin *cpPlugin = nil;
FourCharCode fccPlugInSignature = 0;
try
{
fccPlugInSignature = ::rand();
DBGLOG( kLogApplication, "Processing Configure plugin." );
cpPlugin = new CConfigurePlugin( fccPlugInSignature, "Configure" );
if ( cpPlugin != nil )
{
gPlugins->AddPlugIn( "Configure", COSUtils::GetStringFromList( kSysStringListID, kStrVersion ), "Not Available", "Not Available", fccPlugInSignature, cpPlugin );
cpPlugin->Validate( COSUtils::GetStringFromList( kSysStringListID, kStrVersion ), fccPlugInSignature );
SRVRLOG1( kLogApplication, "Plugin \"Configure\", Version \"%s\", processed successfully.", COSUtils::GetStringFromList( kSysStringListID, kStrVersion ) );
cpPlugin = nil;
}
else
{
ERRORLOG( kLogApplication, "ERROR: \"Configure\" plugin _FAILED_ to process." );
}
siResult = eDSNoErr;
}
catch( sInt32 err )
{
siResult = err;
ERRORLOG1( kLogPlugin, "*** Error attempting to process Configure plugin . Error = %ld", err );
}
return( siResult );
}