#include <SystemConfiguration/SystemConfiguration.h>
#include "CNSLHeaders.h"
#include "CommandLineUtilities.h"
#include "SLPSystemConfiguration.h"
#include "CSLPPlugin.h"
#include "CSLPNodeLookupThread.h"
#include "CSLPServiceLookupThread.h"
#include "CNSLTimingUtils.h"
void AddToAttributeList( const void* key, const void* value, void* context );
CFStringRef CreateHexEncodedString( CFStringRef rawStringRef );
CFStringRef CreateEncodedString( CFStringRef rawStringRef );
CFStringRef CreateSLPTypeFromDSType ( CFStringRef inDSType );
#define kCommandParamsID 128
const CFStringRef kDSStdAttrTypePrefixSAFE_CFSTR = CFSTR(kDSStdAttrTypePrefix);
const CFStringRef kDSNativeAttrTypePrefixSAFE_CFSTR = CFSTR(kDSNativeAttrTypePrefix);
const CFStringRef kDSSLPPluginTagSAFE_CFSTR = CFSTR("com.apple.DirectoryService.DSSLPPlugIn");
const CFStringRef kSLPTagSAFE_CFSTR = CFSTR("com.apple.slp");
const CFStringRef gBundleIdentifier = CFSTR("com.apple.DirectoryService.SLP");
const CFStringRef kSLPDefaultRegistrationScopeTagSAFE_CFSTR = CFSTR("com.apple.slp.defaultRegistrationScope");
const CFStringRef kAttributeListSAFE_CFSTR = CFSTR("attributeList");
const CFStringRef kAttributeListForURLSAFE_CFSTR = CFSTR("attributeForURL");
const char* gProtocolPrefixString = "SLP";
static char* gLocalNodeString = NULL;
extern "C" {
CFUUIDRef ModuleFactoryUUID = CFUUIDGetConstantUUIDWithBytes ( NULL, \
0x55, 0xD9, 0xE4, 0x58, 0x9B, 0x3B, 0x11, 0xD5, \
0xAB, 0xFD, 0x00, 0x30, 0x65, 0x3D, 0x61, 0xE4 );
}
static CDSServerModule* _Creator ( void )
{
DBGLOG( "Creating new SLP Plugin\n" );
return( new CSLPPlugin );
}
CDSServerModule::tCreator CDSServerModule::sCreator = _Creator;
CSLPPlugin::CSLPPlugin( void )
: CNSLPlugin()
{
DBGLOG( "CSLPPlugin::CSLPPlugin\n" );
mNodeLookupThread = NULL;
mSLPRef = NULL;
}
CSLPPlugin::~CSLPPlugin( void )
{
DBGLOG( "CSLPPlugin::~CSLPPlugin\n" );
if ( mSLPRef )
SLPClose( mSLPRef );
}
sInt32 CSLPPlugin::InitPlugin( void )
{
sInt32 siResult = eDSNoErr;
DBGLOG( "CSLPPlugin::InitPlugin\n" );
if ( getenv( "NSLDEBUG" ) )
SLPSetProperty("com.apple.slp.logAll", "true" );
if ( getenv( "com.apple.slp.interface" ) != 0 )
{
SLPSetProperty("com.apple.slp.interface", getenv( "com.apple.slp.interface" ) );
DBGLOG( "Setting interface to: %s", getenv( "com.apple.slp.interface" ) );
}
if ( getenv( "net.slp.DAAddresses" ) != 0 )
{
SLPSetProperty("net.slp.DAAddresses", getenv( "net.slp.DAAddresses" ) );
DBGLOG( "Setting da to: %s", getenv( "net.slp.DAAddresses" ) );
}
SCPreferencesRef prefRef = ::SCPreferencesCreate( NULL, kDSSLPPluginTagSAFE_CFSTR, kSLPTagSAFE_CFSTR );
executecommand( "rm /var/slp.regfile" );
DBGLOG( "CSLPPlugin::InitPlugin is deleting regfile:/var/slp.regfile" );
CFPropertyListRef propertyList = ::SCPreferencesGetValue( prefRef, kSLPDefaultRegistrationScopeTagSAFE_CFSTR );
if( gLocalNodeString )
{
free( gLocalNodeString );
gLocalNodeString = NULL;
}
if ( propertyList )
{
if ( ::CFGetTypeID(propertyList) == ::CFStringGetTypeID() )
{
CFIndex tempPtrSize = ::CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef)propertyList), kCFStringEncodingUTF8)+1;
char* tempPtr = (char*)malloc( tempPtrSize );
if ( ::CFStringGetCString( (CFStringRef)propertyList, tempPtr, tempPtrSize, kCFStringEncodingUTF8 ) )
{
gLocalNodeString = tempPtr;
}
else
free( tempPtr );
}
else if ( ::CFGetTypeID(propertyList) == ::CFArrayGetTypeID() )
{
DBGLOG( "CSLPPlugin::InitPlugin we don't support multiple default registration scopes yet!\n" );
}
}
else
{
CFStringRef localNodeRef = NULL;
gLocalNodeString = CreateLocalNodeFromConfigFile();
localNodeRef = ::CFStringCreateWithCString( NULL, gLocalNodeString, kCFStringEncodingUTF8 );
if ( ::SCPreferencesLock( prefRef, true ) )
{
::SCPreferencesSetValue( prefRef, kSLPDefaultRegistrationScopeTagSAFE_CFSTR, localNodeRef );
::SCPreferencesUnlock( prefRef );
}
::CFRelease( localNodeRef );
}
::CFRelease( prefRef );
#ifdef USE_DEFAULT_SA_ONLY_SCOPE
if ( gLocalNodeString && strcmp( gLocalNodeString, v2_Default_Scope ) == 0 )
{
free( gLocalNodeString );
gLocalNodeString = (char*)malloc( strlen( SLP_DEFAULT_SA_ONLY_SCOPE )+1 );
strcpy( gLocalNodeString, SLP_DEFAULT_SA_ONLY_SCOPE );
}
#endif
DBGLOG( "CSLPPlugin::InitPlugin we are currently located in scope %s\n", gLocalNodeString );
AddNode( GetLocalNodeString() );
return siResult;
}
void CSLPPlugin::ActivateSelf( void )
{
DBGLOG( "CSLPPlugin::ActivateSelf called, runloopRef = 0x%x\n", GetRunLoopRef() );
InitPlugin();
if ( !mSLPRef && GetRunLoopRef() && IsNetworkSetToTriggerDialup() == false )
SLPOpen( "en", SLP_FALSE, &mSLPRef, GetRunLoopRef() );
CNSLPlugin::ActivateSelf();
}
void CSLPPlugin::DeActivateSelf( void )
{
DBGLOG( "CSLPPlugin::DeActivateSelf called\n" );
StopSLPDALocator();
TellSLPdToQuit();
if ( mNodeLookupThread )
mNodeLookupThread->Cancel();
if ( mSLPRef )
SLPClose( mSLPRef );
mSLPRef = NULL;
CNSLPlugin::DeActivateSelf();
}
void CSLPPlugin::TellSLPdToQuit( void )
{
uInt32 bufLen = 0, returnBufLen = 0;
char* sendBuf = MakeSLPIOCallBuffer( false, &bufLen );
char* returnBuf = NULL;
SendDataToSLPd( sendBuf, bufLen, &returnBuf, &returnBufLen );
if ( sendBuf )
free( sendBuf );
if ( returnBuf )
free( returnBuf );
}
sInt32 CSLPPlugin::SetServerIdleRunLoopRef( CFRunLoopRef idleRunLoopRef )
{
CNSLPlugin::SetServerIdleRunLoopRef( idleRunLoopRef );
return eDSNoErr;
}
char* CSLPPlugin::CreateLocalNodeFromConfigFile( void )
{
const char* defaultRegScope = NULL;
char* localNodeString = (char*)malloc( strlen( v2_Default_Scope ) +1 );
strcpy( localNodeString, v2_Default_Scope );
SLPReadConfigFile( "/etc/slpsa.conf" );
defaultRegScope = SLPGetProperty("com.apple.slp.defaultRegistrationScope");
if ( defaultRegScope && strcmp(localNodeString,defaultRegScope) != 0 )
{
free( localNodeString );
localNodeString = (char*)malloc( strlen( defaultRegScope ) +1 );
strcpy( localNodeString, defaultRegScope );
}
return localNodeString;
}
CFStringRef CSLPPlugin::GetBundleIdentifier( void )
{
return gBundleIdentifier;
}
const char* CSLPPlugin::GetProtocolPrefixString( void )
{
return gProtocolPrefixString;
}
const char* CSLPPlugin::GetLocalNodeString( void )
{
return gLocalNodeString;
}
Boolean CSLPPlugin::IsLocalNode( const char *inNode )
{
Boolean result = false;
if ( gLocalNodeString )
{
result = ( strcmp( inNode, gLocalNodeString ) == 0 );
}
return result;
}
Boolean CSLPPlugin::IsADefaultOnlyNode( const char *inNode )
{
Boolean result = false;
#ifdef USE_DEFAULT_SA_ONLY_SCOPE
DBGLOG( "CSLPPlugin::IsADefaultOnlyNode called on (%s)\n", inNode );
if ( strcmp( inNode, SLP_DEFAULT_SA_ONLY_SCOPE ) == 0 )
result = true;
#endif
return result;
}
sInt32 CSLPPlugin::HandleNetworkTransition( sHeader *inData )
{
sInt32 siResult = eDSNoErr;
siResult = CNSLPlugin::HandleNetworkTransition( inData );
if ( !siResult )
{
if ( mActivatedByNSL && IsActive() && IsNetworkSetToTriggerDialup() == false )
{
KickSLPDALocator(); }
}
return ( siResult );
}
void CSLPPlugin::NodeLookupComplete( void )
{
CNSLPlugin::NodeLookupComplete();
DBGLOG( "CSLPPlugin::NodeLookupComplete\n" );
mNodeLookupThread = NULL;
}
void CSLPPlugin::NewNodeLookup( void )
{
DBGLOG( "CSLPPlugin::NewNodeLookup\n" );
if ( mActivatedByNSL && IsActive() && IsNetworkSetToTriggerDialup() == false )
{
AddNode( GetLocalNodeString() );
if ( !mNodeLookupThread )
{
DBGLOG( "CSLPPlugin::NewNodeLookup creating a new CSLPNodeLookupThread\n" );
mNodeLookupThread = new CSLPNodeLookupThread( this );
mNodeLookupThread->Resume();
}
else
{
DBGLOG( "CSLPPlugin::NewNodeLookup telling mNodeLookupThread to DoItAgain\n" );
mNodeLookupThread->DoItAgain(); }
}
}
void CSLPPlugin::NewServiceLookup( char* serviceType, CNSLDirNodeRep* nodeDirRep )
{
if ( serviceType && (strcmp( serviceType, "cifs" ) == 0 || strcmp( serviceType, "webdav" ) == 0) )
{
DBGLOG( "CSLPPlugin::NewServicesLookup ignoring lookup on %s\n", serviceType );
}
else if ( mActivatedByNSL && IsActive() && IsNetworkSetToTriggerDialup() == false )
{
DBGLOG( "CSLPPlugin::NewServicesLookup on %s\n", serviceType );
CSLPServiceLookupThread* newLookup = new CSLPServiceLookupThread( this, serviceType, nodeDirRep );
if ( OKToStartNewSearch() )
{
DBGLOG( "CSLPPlugin::NewServicesLookup on %s is being started.\n", serviceType );
newLookup->Resume();
}
else
{
DBGLOG( "CSLPPlugin::NewServicesLookup on %s is being queued.\n", serviceType );
QueueNewSearch( newLookup );
}
}
}
Boolean CSLPPlugin::OKToOpenUnPublishedNode( const char* nodeName )
{
return true; }
#pragma mark -
sInt32 CSLPPlugin::RegisterService( tRecordReference recordRef, CFDictionaryRef service )
{
sInt32 status = eDSNoErr;
CFStringRef urlRef = NULL;
CFStringRef scopeRef = NULL;
CFTypeRef urlResultRef = NULL;
if ( service )
urlResultRef = (CFTypeRef)::CFDictionaryGetValue( service, kDSNAttrURLSAFE_CFSTR);
if ( urlResultRef )
{
if ( CFGetTypeID(urlResultRef) == CFStringGetTypeID() )
{
urlRef = (CFStringRef)urlResultRef;
}
else if ( CFGetTypeID(urlResultRef) == CFArrayGetTypeID() )
{
DBGLOG( "CSLPPlugin::RegisterService, we have more than one URL (%ld) in this service! Just register the first one\n", CFArrayGetCount((CFArrayRef)urlResultRef) );
urlRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)urlResultRef, 0 );
}
}
DBGLOG( "CSLPPlugin::RegisterService\n" );
if ( getenv("NSLDEBUG") && service )
CFShow(service);
if ( service && urlRef && CFGetTypeID(urlRef) == CFStringGetTypeID() && CFStringGetLength( urlRef ) > 0 )
{
UInt32 scopePtrLength = 0;
char* scopePtr = NULL;
DBGLOG( "CSLPPlugin::RegisterService, check for specified location to register in\n" );
if ( (scopeRef = (CFStringRef)::CFDictionaryGetValue( service, kDS1AttrLocationSAFE_CFSTR )) )
{
if ( CFGetTypeID( scopeRef ) == CFArrayGetTypeID() )
{
scopeRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)scopeRef, 0 ); }
if ( scopeRef != NULL )
{
scopePtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( scopeRef ), kCFStringEncodingUTF8 ) + 1;
scopePtr = (char*)malloc( scopePtrLength );
::CFStringGetCString( scopeRef, scopePtr, scopePtrLength, kCFStringEncodingUTF8 );
}
}
if ( scopePtr == NULL )
{
DBGLOG( "CSLPPlugin::RegisterService, no location specified, using empty scope for default\n" );
scopePtr = (char*)malloc(1);
scopePtr[0] = '\0';
}
UInt32 urlPtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( urlRef ), kCFStringEncodingUTF8 ) + 1;
char* urlPtr = (char*)malloc( urlPtrLength );
::CFStringGetCString( urlRef, urlPtr, urlPtrLength, kCFStringEncodingUTF8 );
if ( urlPtr[0] != '\0' )
{
char* attributePtr = NULL;
#ifdef REGISTER_WITH_ATTRIBUTE_DATA_IN_URL
CFMutableStringRef attributeRef = ::CFStringCreateMutable( NULL, 0 );
CFMutableStringRef attributeForURLRef = ::CFStringCreateMutable( NULL, 0 ); CFMutableDictionaryRef attributesDictRef = ::CFDictionaryCreateMutable( NULL, 2, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks );
::CFDictionaryAddValue( attributesDictRef, kAttributeListSAFE_CFSTR, attributeRef );
::CFDictionaryAddValue( attributesDictRef, kAttributeListForURLSAFE_CFSTR, attributeForURLRef );
::CFDictionaryApplyFunction( service, AddToAttributeList, attributesDictRef );
CFStringInsert( attributeForURLRef, 0, urlRef );
free( urlPtr );
urlPtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( attributeForURLRef ), kCFStringEncodingUTF8 ) + 1;
urlPtr = (char*)malloc( urlPtrLength );
::CFStringGetCString( attributeForURLRef, urlPtr, urlPtrLength, kCFStringEncodingUTF8 );
CFIndex attributePtrSize = ::CFStringGetMaximumSizeForEncoding( CFStringGetLength(attributeRef), kCFStringEncodingUTF8) + 1;
attributePtr = (char*)malloc( attributePtrSize );
attributePtr[0] = '\0';
::CFStringGetCString( attributeRef, attributePtr, attributePtrSize, kCFStringEncodingUTF8 );
if ( attributePtr && attributePtr[strlen(attributePtr)-1] == ',' )
attributePtr[strlen(attributePtr)] = '\0';
::CFRelease( attributeRef );
#else
attributePtr = (char*)malloc( 1 );
attributePtr[0] = '\0';
#endif
status = DoSLPRegistration( scopePtr, urlPtr, attributePtr );
if ( attributePtr )
free( attributePtr );
}
if ( scopePtr )
free( scopePtr );
if ( urlPtr )
free( urlPtr );
}
else
status = eDSNullAttribute;
return status;
}
sInt32 CSLPPlugin::DeregisterService( tRecordReference recordRef, CFDictionaryRef service )
{
sInt32 status = eDSNoErr;
CFStringRef urlRef = NULL;
CFStringRef scopeRef = NULL;
CFTypeRef urlResultRef = NULL;
if ( service )
urlResultRef = (CFTypeRef)::CFDictionaryGetValue( service, kDSNAttrURLSAFE_CFSTR);
if ( urlResultRef )
{
if ( CFGetTypeID(urlResultRef) == CFStringGetTypeID() )
{
urlRef = (CFStringRef)urlResultRef;
}
else if ( CFGetTypeID(urlResultRef) == CFArrayGetTypeID() )
{
DBGLOG( "CSLPPlugin::DeregisterService, we have more than one URL (%ld) in this service! Just deregister the first one\n", CFArrayGetCount((CFArrayRef)urlResultRef) );
urlRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)urlResultRef, 0 );
}
}
if ( urlRef && CFGetTypeID(urlRef) == CFStringGetTypeID() && CFStringGetLength( urlRef ) > 0 )
{
UInt32 scopePtrLength;
char* scopePtr = NULL;
if ( (scopeRef = (CFStringRef)::CFDictionaryGetValue( service, kDS1AttrLocationSAFE_CFSTR)) )
{
if ( CFGetTypeID( scopeRef ) == CFArrayGetTypeID() )
{
scopeRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)scopeRef, 0 ); }
scopePtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( scopeRef ), kCFStringEncodingUTF8 ) + 1;
scopePtr = (char*)malloc( scopePtrLength );
::CFStringGetCString( scopeRef, scopePtr, scopePtrLength, kCFStringEncodingUTF8 );
}
else
{
scopePtr = (char*)malloc(1);
scopePtr[0] = '\0';
}
UInt32 urlPtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( urlRef ), kCFStringEncodingUTF8 ) + 1;
char* urlPtr = (char*)malloc( urlPtrLength );
::CFStringGetCString( urlRef, urlPtr, urlPtrLength, kCFStringEncodingUTF8 );
if ( urlPtr[0] != '\0' )
{
#ifdef REGISTER_WITH_ATTRIBUTE_DATA_IN_URL
char* attributePtr = NULL;
CFMutableStringRef attributeRef = ::CFStringCreateMutable( NULL, 0 );
CFMutableStringRef attributeForURLRef = ::CFStringCreateMutable( NULL, 0 ); CFMutableDictionaryRef attributesDictRef = ::CFDictionaryCreateMutable( NULL, 2, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks );
::CFDictionaryAddValue( attributesDictRef, kAttributeListSAFE_CFSTR, attributeRef );
::CFDictionaryAddValue( attributesDictRef, kAttributeListForURLSAFE_CFSTR, attributeForURLRef );
::CFDictionaryApplyFunction( service, AddToAttributeList, attributesDictRef );
CFStringInsert( attributeForURLRef, 0, urlRef );
free( urlPtr );
urlPtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( attributeForURLRef ), kCFStringEncodingUTF8 ) + 1;
urlPtr = (char*)malloc( urlPtrLength );
::CFStringGetCString( attributeForURLRef, urlPtr, urlPtrLength, kCFStringEncodingASCII );
CFIndex attributePtrSize = ::CFStringGetMaximumSizeForEncoding( CFStringGetLength(attributeRef), kCFStringEncodingUTF8 ) + 1;
attributePtr = (char*)malloc( attributePtrSize );
attributePtr[0] = '\0';
::CFStringGetCString( attributeRef, attributePtr, attributePtrSize, kCFStringEncodingUTF8 );
if ( attributePtr && attributePtr[strlen(attributePtr)-1] == ',' )
attributePtr[strlen(attributePtr)] = '\0';
::CFRelease( attributeRef );
#endif
status = DoSLPDeregistration( scopePtr, urlPtr );
}
free( scopePtr );
free( urlPtr );
}
else
status = eDSNullAttribute;
return status;
}
OSStatus CSLPPlugin::DoSLPRegistration( char* scopeList, char* url, char* attributeList )
{
char* dataBuffer = NULL;
char* returnBuffer = NULL;
UInt32 dataBufferLen = 0;
UInt32 returnBufferLen = 0;
OSStatus status = noErr;
DBGLOG( "CSLPPlugin::DoSLPRegistration called, scope: %s, url: %s, attributeList: %s\n", scopeList, url, attributeList );
dataBuffer = MakeSLPRegistrationDataBuffer ( scopeList, strlen(scopeList), url, strlen(url), attributeList, strlen(attributeList), &dataBufferLen );
if ( dataBuffer )
{
status = SendDataToSLPd( dataBuffer, dataBufferLen, &returnBuffer, &returnBufferLen );
if ( status )
{
if ( returnBuffer )
free( returnBuffer );
returnBuffer = NULL;
SmartSleep(1*USEC_PER_SEC); status = SendDataToSLPd( dataBuffer, dataBufferLen, &returnBuffer, &returnBufferLen );
}
}
else
status = eMemoryAllocError;
if ( !status && returnBuffer && returnBufferLen > 0 )
status = ((SLPdMessageHeader*)returnBuffer)->messageStatus;
if ( dataBuffer )
free( dataBuffer );
if ( returnBuffer )
free( returnBuffer );
return status;
}
OSStatus CSLPPlugin::DoSLPDeregistration( char* scopeList, char* url )
{
char* dataBuffer = NULL;
char* returnBuffer = NULL;
UInt32 dataBufferLen = 0;
UInt32 returnBufferLen = 0;
OSStatus status = noErr;
DBGLOG( "CSLPPlugin::DoSLPDeregistration called, scope: %s, url: %s\n", scopeList, url );
dataBuffer = MakeSLPDeregistrationDataBuffer( scopeList, strlen(scopeList), url, strlen(url), &dataBufferLen );
if ( dataBuffer )
status = SendDataToSLPd( dataBuffer, dataBufferLen, &returnBuffer, &returnBufferLen );
else
status = eMemoryAllocError;
if ( !status && returnBuffer && returnBufferLen > 0 )
status = ((SLPdMessageHeader*)returnBuffer)->messageStatus;
if ( dataBuffer )
free( dataBuffer );
if ( returnBuffer )
free( returnBuffer );
return status;
}
#pragma mark -
void AddToAttributeList( const void* key, const void* value, void* context )
{
DBGLOG( "AddToAttributeList called with key:%s value:%s", (char*)key, (char*)value );
if ( key && context )
{
CFDictionaryRef attrDict = (CFDictionaryRef)context;
CFStringRef keyRef = (CFStringRef) key;
CFMutableStringRef attributeListRef = (CFMutableStringRef)CFDictionaryGetValue( attrDict, kAttributeListSAFE_CFSTR );
CFMutableStringRef attributeListForURLRef = (CFMutableStringRef)CFDictionaryGetValue( attrDict, kAttributeListForURLSAFE_CFSTR );
CFPropertyListRef valueRef = (CFPropertyListRef) value;
if ( ::CFStringCompare( kDSNAttrURLSAFE_CFSTR, keyRef, 0 ) == kCFCompareEqualTo )
return;
else if ( ::CFStringCompare( kDS1AttrLocationSAFE_CFSTR, keyRef, 0 ) == kCFCompareEqualTo )
return;
if ( attributeListRef )
{
::CFStringAppendCString( attributeListRef, "(", kCFStringEncodingUTF8 );
::CFStringAppendCString( attributeListForURLRef, ";", kCFStringEncodingUTF8 );
::CFStringRef keyConvertedRef = CreateSLPTypeFromDSType( (CFStringRef)keyRef );
::CFStringAppend( attributeListRef, keyConvertedRef );
::CFStringAppend( attributeListForURLRef, keyConvertedRef );
::CFRelease( keyConvertedRef );
if ( valueRef )
{
::CFStringAppendCString( attributeListRef, "=", kCFStringEncodingUTF8 );
::CFStringAppendCString( attributeListForURLRef, "=", kCFStringEncodingASCII );
if ( ::CFGetTypeID( valueRef ) == ::CFArrayGetTypeID() )
{
CFIndex valueCount = CFArrayGetCount((CFArrayRef)valueRef);
for ( CFIndex i=0; i<valueCount; i++ )
{
CFStringRef valueStringRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)valueRef, i );
if ( valueStringRef )
{
CFStringRef encodedValueRef = CreateEncodedString(valueStringRef);
CFStringRef hexEncodedValueRef = CreateHexEncodedString(valueStringRef);
::CFStringAppend( attributeListRef, encodedValueRef );
::CFStringAppend( attributeListForURLRef, hexEncodedValueRef );
if ( i+1 < valueCount )
{
::CFStringAppendCString( attributeListRef, ",", kCFStringEncodingUTF8 );
::CFStringAppendCString( attributeListForURLRef, ",", kCFStringEncodingASCII );
}
::CFRelease( encodedValueRef );
::CFRelease( hexEncodedValueRef );
}
}
}
else if ( ::CFGetTypeID( valueRef ) == ::CFStringGetTypeID() )
{
CFStringRef encodedValueRef = CreateEncodedString((CFStringRef)valueRef);
CFStringRef hexEncodedValueRef = CreateHexEncodedString((CFStringRef)valueRef);
::CFStringAppend( attributeListRef, encodedValueRef );
::CFStringAppend( attributeListForURLRef, hexEncodedValueRef );
::CFRelease( encodedValueRef );
::CFRelease( hexEncodedValueRef );
}
}
::CFStringAppendCString( attributeListRef, "),", kCFStringEncodingUTF8 );
}
}
}
CFStringRef CreateEncodedString( CFStringRef rawStringRef )
{
char* buffer = NULL;
UInt32 bufferSize = 0;
bufferSize = ::CFStringGetMaximumSizeForEncoding(CFStringGetLength(rawStringRef), kCFStringEncodingUTF8) +1;
buffer = (char*)malloc( bufferSize );
if ( !buffer )
{
DBGLOG( "CreateEncodedString, Couldn't malloc a buffer!\n" );
return NULL;
}
if ( ::CFStringGetCString( rawStringRef, buffer, bufferSize, kCFStringEncodingASCII ) )
{
return CFStringCreateCopy( NULL, rawStringRef );
}
else if ( ::CFStringGetCString( rawStringRef, buffer, bufferSize, kCFStringEncodingUTF8 ) )
{
CFMutableStringRef newStringRef = ::CFStringCreateMutable( NULL, 0 );
char* curPtr = buffer;
char temp[4] = {0};
DBGLOG( "CreateEncodedString parsing: %s\n", buffer );
while ( *curPtr != '\0' )
{
if (*curPtr == '(' || *curPtr == ')' || *curPtr == ',' || *curPtr == '\\' ||
*curPtr == '!' || *curPtr == '<' || *curPtr == '=' || *curPtr == '>' ||
*curPtr == '~' || (*curPtr>= 0x00 && *curPtr<= 0x1F) )
{
div_t result;
UInt8 hexValue = *curPtr;
char c1, c2;
result = div( hexValue, 16 );
if ( (UInt8)(result.quot) < 0xA )
c1 = (UInt8)result.quot + '0';
else
c1 = (UInt8)result.quot + 'A' - 10;
if ( (UInt8)(result.rem) < 0xA )
c2 = (UInt8)result.rem + '0';
else
c2 = (UInt8)result.rem + 'A' - 10;
temp[0] = '\\';
temp[1] = c1;
temp[2] = c2;
::CFStringAppendCString( newStringRef, temp, kCFStringEncodingASCII );
}
else
{
sprintf( temp, "%c", *curPtr );
::CFStringAppendCString( newStringRef, temp, kCFStringEncodingUTF8 );
}
curPtr++;
}
return newStringRef;
}
else
DBGLOG( "CreateEncodedString, Couldn't get UTF8 version of the original string!\n" );
return NULL;
}
CFStringRef CreateHexEncodedString( CFStringRef rawStringRef )
{
char* buffer = NULL;
UInt32 bufferSize = 0;
bufferSize = ::CFStringGetMaximumSizeForEncoding(CFStringGetLength(rawStringRef), kCFStringEncodingUTF8) +1;
buffer = (char*)malloc( bufferSize );
if ( !buffer )
{
DBGLOG( "CreateHexEncodedString, Couldn't malloc a buffer!\n" );
return NULL;
}
if ( ::CFStringGetCString( rawStringRef, buffer, bufferSize, kCFStringEncodingUTF8 ) )
{
CFMutableStringRef newStringRef = ::CFStringCreateMutable( NULL, 0 );
char* curPtr = buffer;
char temp[4] = {0};
Boolean encode = false;
DBGLOG( "CreateHexEncodedString parsing: %s\n", buffer );
while ( *curPtr != '\0' )
{
char c = *curPtr;
if ( c <= 0x1F || c == 0x7F || (unsigned char)c >= 0x80 )
encode = true;
else
{
switch (c)
{
case '<':
case '>':
case 0x22: case 0x5c: case '#':
case '{':
case '}':
case '|':
case '^':
case '~':
case '[':
case ']':
case '`':
case ';':
case '/':
case '?':
case ':':
case '@':
case '=':
case '&':
case ' ':
case ',':
case '%':
encode = true;
break;
default:
encode = false;
break;
}
}
if ( encode )
{
div_t result;
UInt8 hexValue = *curPtr;
char c1, c2;
result = div( hexValue, 16 );
if ( (UInt8)(result.quot) < 0xA )
c1 = (UInt8)result.quot + '0';
else
c1 = (UInt8)result.quot + 'A' - 10;
if ( (UInt8)(result.rem) < 0xA )
c2 = (UInt8)result.rem + '0';
else
c2 = (UInt8)result.rem + 'A' - 10;
temp[0] = '\\';
temp[1] = c1;
temp[2] = c2;
::CFStringAppendCString( newStringRef, temp, kCFStringEncodingASCII );
}
else
{
sprintf( temp, "%c", *curPtr );
::CFStringAppendCString( newStringRef, temp, kCFStringEncodingASCII );
}
curPtr++;
}
return newStringRef;
}
else
DBGLOG( "CreateHexEncodedString, Couldn't get UTF8 version of the original string!\n" );
return NULL;
}
#define kSLPNameKey "name"
CFStringRef CreateSLPTypeFromDSType ( CFStringRef inDSType )
{
CFStringRef result = NULL;
if ( CFStringCompare( inDSType, kDSNAttrRecordNameSAFE_CFSTR, 0 ) == kCFCompareEqualTo )
{
result = CFStringCreateWithCString( NULL, kSLPNameKey, kCFStringEncodingUTF8 );
}
else if ( CFStringHasPrefix( inDSType, kDSStdAttrTypePrefixSAFE_CFSTR ) )
{
result = CFStringCreateWithSubstring( NULL, inDSType, CFRangeMake( strlen(kDSStdAttrTypePrefix), CFStringGetLength(inDSType) - strlen(kDSStdAttrTypePrefix) ) );
}
else if ( CFStringHasPrefix( inDSType, kDSNativeAttrTypePrefixSAFE_CFSTR ) )
{
result = CFStringCreateWithSubstring( NULL, inDSType, CFRangeMake( strlen(kDSNativeAttrTypePrefix), CFStringGetLength(inDSType) - strlen(kDSNativeAttrTypePrefix) ) );
}
else
{
result = CFStringCreateCopy( NULL, inDSType );
}
return( result );
}