/* * CSLPPlugin.cpp * DSSLPPlugIn * * Created by imlucid on Wed Aug 15 2001. * Copyright (c) 2001 Apple Computer. All rights reserved. * */ #include #include "CNSLHeaders.h" #include "CommandLineUtilities.h" #include "CSLPPlugin.h" #include "CSLPNodeLookupThread.h" #include "CSLPServiceLookupThread.h" #include "TGetCFBundleResources.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 gBundleIdentifier = CFSTR("com.apple.DirectoryService.SLP"); const char* gProtocolPrefixString = "SLP"; static char* gLocalNodeString = NULL; // get this from SCPreferences 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, CFSTR("com.apple.DirectoryService.DSSLPPlugIn"), CFSTR("com.apple.slp") ); // system( "rm /var/slp.regfile" ); executecommand( "rm /var/slp.regfile" ); DBGLOG( "CSLPPlugin::InitPlugin is deleting regfile:/var/slp.regfile" ); CFPropertyListRef propertyList = ::SCPreferencesGetValue( prefRef, CFSTR("com.apple.slp.defaultRegistrationScope") ); if ( propertyList ) { if ( ::CFGetTypeID(propertyList) == ::CFStringGetTypeID() ) { // cool, just a single scope registration 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() ) { // ah, we are configured with multiple scopes to register in... DBGLOG( "CSLPPlugin::InitPlugin we don't support multiple default registration scopes yet!\n" ); } } else { CFStringRef localNodeRef = NULL; // look in the config file and register the preference gLocalNodeString = CreateLocalNodeFromConfigFile(); localNodeRef = ::CFStringCreateWithCString( NULL, gLocalNodeString, kCFStringEncodingUTF8 ); if ( ::SCPreferencesLock( prefRef, true ) ) { ::SCPreferencesSetValue( prefRef, CFSTR("com.apple.slp.defaultRegistrationScope"), localNodeRef ); ::SCPreferencesUnlock( prefRef ); } ::CFRelease( localNodeRef ); // gLocalNodeString = (char*)malloc( strlen( v2_Default_Scope ) +1 ); // strcpy( gLocalNodeString, v2_Default_Scope ); } ::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() ); // always register the default registration node return siResult; } sInt32 CSLPPlugin::SetServerIdleRunLoopRef( CFRunLoopRef idleRunLoopRef ) { CNSLPlugin::SetServerIdleRunLoopRef( idleRunLoopRef ); SLPInternalError status = SLPOpen( "en", SLP_FALSE, &mSLPRef, GetRunLoopRef() ); return eDSNoErr; } char* CSLPPlugin::CreateLocalNodeFromConfigFile( void ) { char* localNodeString = (char*)malloc( strlen( v2_Default_Scope ) +1 ); strcpy( localNodeString, v2_Default_Scope ); SLPReadConfigFile( "/etc/slpsa.conf" ); if ( SLPGetProperty("com.apple.slp.defaultRegistrationScope") && strcmp(localNodeString,SLPGetProperty("com.apple.slp.defaultRegistrationScope")) != 0 ) { free( localNodeString ); localNodeString = (char*)malloc( strlen( SLPGetProperty("com.apple.slp.defaultRegistrationScope") ) +1 ); strcpy( localNodeString, SLPGetProperty("com.apple.slp.defaultRegistrationScope") ); } return localNodeString; } CFStringRef CSLPPlugin::GetBundleIdentifier( void ) { return gBundleIdentifier; } // this is used for top of the node's path "NSL" const char* CSLPPlugin::GetProtocolPrefixString( void ) { return gProtocolPrefixString; } // this is where our machine is currently located 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 ) { // we not only need to reset the scopes we have published, but we need to reset our thread that is looking for DAs sInt32 siResult = eDSNoErr; if ( mActivatedByNSL ) { KickSLPDALocator(); // wake this guy ClearOutAllNodes(); // clear these out StartNodeLookup(); // and then start all over } return ( siResult ); } void CSLPPlugin::NodeLookupComplete( void ) { CNSLPlugin::NodeLookupComplete(); DBGLOG( "CSLPPlugin::NodeLookupComplete\n" ); mNodeLookupThread = NULL; } // NodeLookupComplete void CSLPPlugin::NewNodeLookup( void ) { DBGLOG( "CSLPPlugin::NewNodeLookup\n" ); // First add our local scope AddNode( GetLocalNodeString() ); // always register the default registration node if ( !mNodeLookupThread ) { mNodeLookupThread = new CSLPNodeLookupThread( this ); mNodeLookupThread->Resume(); } else { mNodeLookupThread->DoItAgain(); // we need to start a new one as soon as the old one finishes } } void CSLPPlugin::NewServiceLookup( char* serviceType, CNSLDirNodeRep* nodeDirRep ) { DBGLOG( "CSLPPlugin::NewServicesLookup on %s\n", serviceType ); CSLPServiceLookupThread* newLookup = new CSLPServiceLookupThread( this, serviceType, nodeDirRep ); // if we have too many threads running, just queue this search object and run it later 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; // allow users to create their own nodes? } 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, CFSTR(kDSNAttrURL)); 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; char* scopePtr = NULL; DBGLOG( "CSLPPlugin::RegisterService, check for specified location to register in\n" ); if ( (scopeRef = (CFStringRef)::CFDictionaryGetValue( service, CFSTR(kDS1AttrLocation) )) ) { if ( CFGetTypeID( scopeRef ) == CFArrayGetTypeID() ) { scopeRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)scopeRef, 0 ); // just get the first one for now } scopePtrLength = ::CFStringGetMaximumSizeForEncoding( ::CFStringGetLength( scopeRef ), kCFStringEncodingUTF8 ) + 1; scopePtr = (char*)malloc( scopePtrLength ); ::CFStringGetCString( scopeRef, scopePtr, scopePtrLength, kCFStringEncodingUTF8 ); } else { 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 ); // mod this for appending to URL CFMutableDictionaryRef attributesDictRef = ::CFDictionaryCreateMutable( NULL, 2, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks ); ::CFDictionaryAddValue( attributesDictRef, CFSTR("attributeList"), attributeRef ); ::CFDictionaryAddValue( attributesDictRef, CFSTR("attributeForURL"), 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 ); // we should be putting together an attribute list from the other key/value pairs in service if ( attributePtr ) free( attributePtr ); } free( scopePtr ); 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, CFSTR(kDSNAttrURL)); 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, CFSTR(kDS1AttrLocation))) ) { if ( CFGetTypeID( scopeRef ) == CFArrayGetTypeID() ) { scopeRef = (CFStringRef)::CFArrayGetValueAtIndex( (CFArrayRef)scopeRef, 0 ); // just get the first one for now } 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 ); // mod this for appending to URL CFMutableDictionaryRef attributesDictRef = ::CFDictionaryCreateMutable( NULL, 2, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks ); ::CFDictionaryAddValue( attributesDictRef, CFSTR("attributeList"), attributeRef ); ::CFDictionaryAddValue( attributesDictRef, CFSTR("attributeForURL"), 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; sleep(1); // try again status = SendDataToSLPd( dataBuffer, dataBufferLen, &returnBuffer, &returnBufferLen ); } } else status = memFullErr; // now check for any message status 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 = memFullErr; // now check for any message status if ( !status && returnBuffer && returnBufferLen > 0 ) status = ((SLPdMessageHeader*)returnBuffer)->messageStatus; if ( dataBuffer ) free( dataBuffer ); if ( returnBuffer ) free( returnBuffer ); return status; } void AddToAttributeList( const void* key, const void* value, void* context ) { // for each key value we need to wrap it like one of these: // (key), // (key=value), // (key=value1,value2), DBGLOG( "AddToAttributeList called with key:%s value:%s", (char*)key, (char*)value ); // when we are done, we will end up with a string with an extra comma at the end that we will delete later if ( key /*&& value*/ && context ) { CFDictionaryRef attrDict = (CFDictionaryRef)context; CFStringRef keyRef = (CFStringRef) key; CFMutableStringRef attributeListRef = (CFMutableStringRef)CFDictionaryGetValue( attrDict, CFSTR("attributeList") ); CFMutableStringRef attributeListForURLRef = (CFMutableStringRef)CFDictionaryGetValue( attrDict, CFSTR("attributeForURL") ); CFPropertyListRef valueRef = (CFPropertyListRef) value; // first check to see if this key is one to ignore if ( ::CFStringCompare( CFSTR(kDSNAttrURL), keyRef, 0 ) == kCFCompareEqualTo ) return; else if ( ::CFStringCompare( CFSTR(kDS1AttrLocation), keyRef, 0 ) == kCFCompareEqualTo ) return; if ( attributeListRef ) { ::CFStringAppendCString( attributeListRef, "(", kCFStringEncodingUTF8 ); ::CFStringAppendCString( attributeListForURLRef, ";", kCFStringEncodingASCII ); // url needs to be encoded ASCII ::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() ) { for ( CFIndex i=0; i' || *curPtr == '~' || (*curPtr>= 0x00 && *curPtr<= 0x1F) ) { // Convert ascii to \xx equivalent 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; /* Max bytes a string of specified length (in UniChars) will take up if encoded */ buffer = (char*)malloc( bufferSize ); if ( !buffer ) { DBGLOG( "CreateHexEncodedString, Couldn't malloc a buffer!\n" ); return NULL; } /* if ( ::CFStringGetCString( rawStringRef, buffer, bufferSize, kCFStringEncodingASCII ) ) { // no encoding needed, just pass back a copy return CFStringCreateCopy( NULL, rawStringRef ); } else */ 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 ); //CFStringAppendCString( newStringRef, "\\FF", kCFStringEncodingASCII ); while ( *curPtr != '\0' ) { char c = *curPtr; if ( c <= 0x1F || c == 0x7F || (unsigned char)c >= 0x80 ) encode = true; else { switch (c) { case '<': case '>': case 0x22: // double quote case 0x5c: // back slash 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 ) { // Convert ascii to \xx equivalent 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" // CreateSLPTypeFromDSType // // At first we just want to strip off the standard type here, we'll probably want some better mapping, especially between some of // the standard types (i.e. "dsAttrTypeStandard:RecordName" to "Name", etc.) CFStringRef CreateSLPTypeFromDSType ( CFStringRef inDSType ) { CFStringRef result = NULL; if ( CFStringCompare( inDSType, CFSTR(kDSNAttrRecordName), 0 ) == kCFCompareEqualTo ) { result = CFStringCreateWithCString( NULL, kSLPNameKey, kCFStringEncodingUTF8 ); } else if ( CFStringHasPrefix( inDSType, CFSTR(kDSStdAttrTypePrefix) ) ) { result = CFStringCreateWithSubstring( NULL, inDSType, CFRangeMake( strlen(kDSStdAttrTypePrefix), CFStringGetLength(inDSType) - strlen(kDSStdAttrTypePrefix) ) ); } else if ( CFStringHasPrefix( inDSType, CFSTR(kDSNativeAttrTypePrefix) ) ) { result = CFStringCreateWithSubstring( NULL, inDSType, CFRangeMake( strlen(kDSNativeAttrTypePrefix), CFStringGetLength(inDSType) - strlen(kDSNativeAttrTypePrefix) ) ); } else { // just pass the raw type result = CFStringCreateCopy( NULL, inDSType ); } return( result ); } // CreateSLPTypeFromDSType