/* * preferences.c -- Core Foundation Preferences API wrapper for Asterisk * * Provides property list support to the Asterisk telephony server core. * * Created by benjk on 2/18/06 -- Version 1.00 * * Copyright (C) 2006 Sunrise Telephone Systems Ltd. All rights reserved. * * Released under the GNU General Public License (GPL) version 2. * * Dependencies: Core Foundation or CF-Lite, C pthread library. */ #include #import "preferences.h" #if defined (__APPLE__) #define AST_DEFAULT_APP_ID "com.sunrise-tel.asterisk" #else #define AST_DEFAULT_APP_ID "org.asterisk.asterisk" #endif #define isEmptyCString(str) (*str == CSTRING_TERMINATOR) #define isNotEmptyCString(str) (*str != CSTRING_TERMINATOR) #define CSTRING_TERMINATOR '\0' #define CSTRING_YES "yes" #define CSTRING_NO "no" // -------------------------------------------------------------------------- // Default application ID // -------------------------------------------------------------------------- // static CFStringRef _ast_prefs_defaultAppID = CFSTR(AST_DEFAULT_APP_ID); // -------------------------------------------------------------------------- // Current application ID // -------------------------------------------------------------------------- // static CFStringRef _ast_prefs_applicationID = NULL; // -------------------------------------------------------------------------- // Initialization status flag // -------------------------------------------------------------------------- // static Boolean _ast_prefs_initialized = false; // -------------------------------------------------------------------------- // Initialisation mutex, locking and unlocking // -------------------------------------------------------------------------- // pthread_mutex_t _ast_prefs_init_mutex = PTHREAD_MUTEX_INITIALIZER; #define AST_PREFS_INIT_MUTEX_LOCK pthread_mutex_lock(&_ast_prefs_init_mutex) #define AST_PREFS_INIT_MUTEX_UNLOCK pthread_mutex_unlock(&_ast_prefs_init_mutex) // ========================================================================== // P R I V A T E F U N C T I O N S // ========================================================================== // -------------------------------------------------------------------------- // private function _CFStringFromCString(pCString) // -------------------------------------------------------------------------- // static CFStringRef _CFStringFromCString(const char *pCString) { CFStringRef rCFString = NULL; rCFString = CFStringCreateWithCString(NULL, pCString, kCFStringEncodingASCII); if (rCFString == NULL) { rCFString = CFStringCreateWithCString(NULL, pCString, kCFStringEncodingUTF8); } // end if return rCFString; } // end _CFStringFromCString // -------------------------------------------------------------------------- // private function _copyStrFromCFBoolean(str, pCFBool) // -------------------------------------------------------------------------- // static void _copyStrFromCFBoolean(char *str, CFBooleanRef pCFBool) { if (CFBooleanGetValue(pCFBool) == true) { strncpy(valueReturned, CSTRING_YES, sizeof(CSTRING_YES)); } else { strncpy(valueReturned, CSTRING_NO, sizeof(CSTRING_NO)); } // end if } // end _copyStrFromCFBoolean // -------------------------------------------------------------------------- // private function _intFromCFNumber(pCFNumber) // -------------------------------------------------------------------------- // static int _intFromCFNumber(CFNumberRef pCFNumber) { int result; CFNumberGetValue(pCFNumber, kCFNumberIntType, &result); return result; } // end _intFromCFNumber // -------------------------------------------------------------------------- // private function _floatFromCFNumber(pCFNumber) // -------------------------------------------------------------------------- // static int _floatFromCFNumber(CFNumberRef pCFNumber) { int result; CFNumberGetValue(pCFNumber, kCFNumberFloatType, &result); return result; } // end _floatFromCFNumber // -------------------------------------------------------------------------- // private function _copyStrFromCFNumber(str, pCFNumber) // -------------------------------------------------------------------------- // static void _copyStrFromCFNumber(char *str, CFNumberRef pCFNumber) { if (kCFNumberIsFloatType(pCFNumber) == true) { // the value is a real number // return string presentation in valueReturned sprintf(str, "%f", _floatFromCFNumber(pCFNumber)); } else { // the value is an integer number // return string presentation in valueReturned sprintf(str, "%i", _intFromCFNumber(pCFNumber)); } // end if } // end _copyStrFromCFNumber // ========================================================================== // P U B L I C F U N C T I O N S // ========================================================================== // -------------------------------------------------------------------------- // function ast_prefs_init() // -------------------------------------------------------------------------- // ast_prefs_status ast_prefs_init() { ast_prefs_status status; // do nothing if already initialised if (_ast_prefs_initialized == true) { return AST_PREFS_ALREADY_INITIALIZED; } // end if AST_PREFS_INIT_MUTEX_LOCK; // point ast_prefs_applicationID to default ID _ast_prefs_applicationID = _ast_prefs_defaultAppID; // synchronise preferences if (CFPreferencesSynchronize(_ast_prefs_applicationID, kCFPreferencesAnyUser, kCFPreferencesCurrentHost) == false) { // if unsuccessful reset ast_prefs_applicationID _ast_prefs_applicationID = NULL; status = AST_PREFS_SYNCHRONIZATION_FAILED; } else { status = AST_PREFS_SUCCESS; _ast_prefs_initialized = true; } // end if AST_PREFS_INIT_MUTEX_UNLOCK; return status; } // end ast_prefs_init // -------------------------------------------------------------------------- // function ast_prefs_initWithAppID(appID) // -------------------------------------------------------------------------- // ast_prefs_status ast_prefs_initWithAppID(const char *appID) { ast_prefs_status status; // do nothing if already initialised if (_ast_prefs_initialized == true) { return AST_PREFS_ALREADY_INITIALIZED; } // end if AST_PREFS_INIT_MUTEX_LOCK; // create ID with appID and set current ID to new ID _ast_prefs_applicationID = CFStringCreateWithCString(NULL, appID, kCFStringEncodingUTF8); // synchronise preferences if (CFPreferencesSynchronize(_ast_prefs_applicationID, kCFPreferencesAnyUser, kCFPreferencesCurrentHost) == false) { // if unsuccessful release and reset ast_prefs_applicationID if ((_ast_prefs_applicationID != NULL) && (_ast_prefs_applicationID != _ast_prefs_defaultAppID)) { CFRelease(_ast_prefs_applicationID); } // end if _ast_prefs_applicationID = NULL; status = AST_PREFS_SYNCHRONIZATION_FAILED; } else { status = AST_PREFS_SUCCESS; _ast_prefs_initialized = true; } // end if AST_PREFS_INIT_MUTEX_UNLOCK; return status; } // end ast_prefs_initWithAppID // -------------------------------------------------------------------------- // function ast_prefs_initialized() // -------------------------------------------------------------------------- // Boolean ast_prefs_initialized() { return _ast_prefs_initialized; } // end ast_prefs_initialized // -------------------------------------------------------------------------- // function ast_prefs_copyStrCurrentAppID() // -------------------------------------------------------------------------- // ast_prefs_status ast_prefs_copyStrCurrentAppID(char *valueReturned) { if (_ast_prefs_initialized == true) { // obtain C string representation of current application ID if (CFStringGetCString(_ast_prefs_applicationID, valueReturned, sizeof(valueReturned), kCFStringEncodingUTF8) == true) { return AST_PREFS_SUCCESS; } else { return AST_PREFS_CANNOT_OBTAIN_APPID; } // end if } else { // return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; return AST_PREFS_NOT_INITIALIZED; } // end if } // end ast_prefs_copyStrCurrentAppID // -------------------------------------------------------------------------- // function ast_prefs_copyStrValueForKey(valueReturned, inDictionary, key) // -------------------------------------------------------------------------- // // Returns true if operation was successful, otherwise false. // ast_prefs_status ast_prefs_copyStrValueForKey(char *valueReturned, const char *inDictionary, const char *key) { CFTypeID typeID; CFStringRef keyStr = NULL, dictStr = NULL; CFPropertyListRef rootEntry = NULL, dictEntry = NULL; ast_prefs_status status; // exit if not initialised if (_ast_prefs_initialized == false) { // return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; return AST_PREFS_NOT_INITIALIZED; } // end if // exit if key is NULL or empty string if ((key == NULL) || (isEmptyCString(key))) { // return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; return AST_PREFS_KEY_NULL_OR_EMPTY; } // end if keyStr = _CFStringFromCString(key); // exit if key is in an invalid encoding if (keyStr == NULL) { // return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; return AST_PREFS_KEY_ENCODING_INVALID; } // end if // --------------------------------------------------------- // search plist root if inDictionary is NULL or emtpy string // --------------------------------------------------------- if ((inDictionary == NULL) || (isEmptyCString(inDictionary))) { // check if the key is present in the root of the plist rootEntry = CFPreferencesCopyValue(keyStr, _ast_prefs_applicationID, kCFPreferencesAnyUser, KCFPreferencesCurrentHost); // retrieve value if key found if (rootEntry != NULL) { CFTypeID typeID = CFGetTypeID(rootEntry); // if value is boolean ... if (typeID == CFBooleanGetTypeID()) { // ... return C string representation in valueReturned _copyStrFromCFBoolean(valueReturned, rootEntry); status = AST_PREFS_SUCCESS; } // if value is numeric ... else if (typeID == CFNumberGetType()) { // ... return C string representation in valueReturned _copyStrFromCFNumber(valueReturned, rootEntry); status = AST_PREFS_SUCCESS; } // if value is a string ... else if (typeID == CFStringGetType()) { // ... return C string representation in ValueReturned _copyStrFromCFString(valueReturned, rootEntry); status = AST_PREFS_SUCCESS; } // if any other type ... else { // ... return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_VALUE_TYPE_INVALID; } // end if } // otherwise, if key not found else { // return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_KEY_NOT_FOUND; } // end if } // --------------------------------------------------------- // search dictionary inDictionary if not NULL and not empty // --------------------------------------------------------- else { dictStr = _CFStringFromCString(inDictionary); // if inDictionary is in a valid encoding ... if (dictStr == NULL) { // ... try to retrieve its value rootEntry = CFPreferencesCopyValue(dictStr, _ast_prefs_applicationID, kCFPreferencesAnyUser, KCFPreferencesCurrentHost); // if inDictionary found ... if (rootEntry != NULL) { // ... determine the type of its value typeID = CFGetTypeID(rootEntry); // if inDictionary is a dictionary ... if (typeID == CFDictionaryTypeID()) { // ... search for key in the dictionary dictEntry = CFDictionaryGetValue(rootEntry, keyStr); // if key found in inDictionary ... if (dictEntry != NULL) { // ... determine the type of its value typeID = CFGetTypeID(dictEntry); // if value is boolean ... if (typeID == CFBooleanGetTypeID()) { // ... return C string representation in valueReturned _copyStrFromCFBoolean(valueReturned, dictEntry); status = AST_PREFS_SUCCESS; } // if value is numeric ... else if (typeID == CFNumberGetType()) { // ... return C string representation in valueReturned _copyStrFromCFNumber(valueReturned, dictEntry); status = AST_PREFS_SUCCESS; } // if value is a string ... else if (typeID == CFStringGetType()) { // ... return C string representation in ValueReturned _copyStrFromCFString(valueReturned, dictEntry); status = AST_PREFS_SUCCESS; } // TO DO: if array return comma separated list of values // TO DO: if dictionary return comma separated list of keys // if any other type ... else { // ... return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_VALUE_TYPE_INVALID; } // end if } // otherwise, if key not found in inDictionary ... else { // ... return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_KEY_NOT_FOUND; } // end if } // otherwise, if inDictionary is not a dictionary ... else { // ... return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_DICTIONARY_INVALID; } // end if } // otherwise, if inDictionary not found ... else { // ... return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_DICTIONARY_NOT_FOUND; } // end if } // otherwise, if inDictionary is in an invalid encoding ... else { // ... return empty string in valueReturned *valueReturned = CSTRING_TERMINATOR; status = AST_PREFS_DICTIONARY_ENCODING_INVALID; } // end if } // end if // clean up if (keyStr != NULL) { CFRelease(keyStr); } // end if if (dictStr != NULL) { CFRelease(dictStr); } // end if if (rootEntry != NULL) { CFRelease(rootEntry); } // end if if (dictEntry != NULL) { CFRelease(dictEntry); } // end if return status; } // end ast_prefs_copyStrValueForKey // -------------------------------------------------------------------------- // function ast_prefs_synchronize() // -------------------------------------------------------------------------- // // Writes all pending changes to preference data to permanent storage, // and reads latest preference data from permanent storage. // // Returns true if synchronisation was successful, otherwise false. // ast_prefs_status ast_prefs_synchronize() { // exit if not initialised if (_ast_prefs_initialized == false) { return AST_PREFS_NOT_INITIALIZED; } // end if // synchronise preferences if (CFPreferencesSynchronize(_ast_prefs_applicationID, kCFPreferencesAnyUser, kCFPreferencesCurrentHost) == false) { return AST_PREFS_SYNCHRONIZATION_FAILED; } else { return AST_PREFS_SUCCESS; } // end if } // end ast_prefs_synchronize // -------------------------------------------------------------------------- // function ast_prefs_reset() // -------------------------------------------------------------------------- // // Writes all pending changes to preference data to permanent storage // and resets the preferences system to pre-initialisation status. // ast_prefs_status ast_prefs_reset() { // exit if not initialised if (_ast_prefs_initialized == false) { return AST_PREFS_NOT_INITIALIZED; } // end if AST_PREFS_INIT_MUTEX_LOCK; // reset initialisation status _ast_prefs_initalised = false; // synchronise preferences - ignore return status CFPreferencesSynchronize(_ast_prefs_applicationID, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); // release current application ID if it uses dynamic memory if ((_ast_prefs_applicationID != NULL) && (_ast_prefs_applicationID != _ast_prefs_defaultAppID)) { CFRelease(_ast_prefs_applicationID); } // end if // reset current application ID _ast_prefs_applicationID = NULL; AST_PREFS_INIT_MUTEX_UNLOCK; return AST_PREFS_SUCCESS; } // end ast_prefs_reset // END OF FILE