1/* 2 * Copyright (C) 2009-2012 by Matthias Ringwald 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at [email protected] 34 * 35 */ 36 37#define __BTSTACK_FILE__ "btstack_device_name_db_corefoundation.c" 38 39#include "btstack_device_name_db_corefoundation.h" 40#include "btstack_debug.h" 41 42#import <Foundation/Foundation.h> 43 44#define BTdaemonID "ch.ringwald.btdaemon" 45#define BTDaemonPrefsPath "Library/Preferences/ch.ringwald.btdaemon.plist" 46 47#define DEVICES_KEY "devices" 48#define PREFS_REMOTE_NAME @"RemoteName" 49#define PREFS_LINK_KEY @"LinkKey" 50 51static void put_name(bd_addr_t bd_addr, device_name_t *device_name); 52 53static NSMutableDictionary *remote_devices = nil; 54 55// Device info 56static void db_open(void){ 57 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 58 59 // NSUserDefaults didn't work 60 // 61 // NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 62 // NSDictionary * dict = [defaults persistentDomainForName:BTdaemonID]; 63 64 // NSDictionary * dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID)); 65 NSDictionary * dict; 66 dict = (NSDictionary*) CFPreferencesCopyAppValue(CFSTR(DEVICES_KEY), CFSTR(BTdaemonID)); 67 remote_devices = [[NSMutableDictionary alloc] initWithCapacity:([dict count]+5)]; 68 69 // copy entries 70 for (id key in dict) { 71 NSDictionary *value = [dict objectForKey:key]; 72 NSMutableDictionary *deviceEntry = [NSMutableDictionary dictionaryWithCapacity:[value count]]; 73 [deviceEntry addEntriesFromDictionary:value]; 74 [remote_devices setObject:deviceEntry forKey:key]; 75 } 76 77 log_info("read prefs for %u devices\n", (unsigned int) [dict count]); 78 79 [pool release]; 80} 81 82static void db_synchronize(void){ 83 log_info("stored prefs for %u devices\n", (unsigned int) [remote_devices count]); 84 85 // 3 different ways 86 87 // Core Foundation 88 CFPreferencesSetValue(CFSTR(DEVICES_KEY), (CFPropertyListRef) remote_devices, CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); 89 CFPreferencesSynchronize(CFSTR(BTdaemonID), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); 90 91 // NSUserDefaults didn't work 92 // 93 // NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 94 // [defaults setPersistentDomain:remote_devices forName:BTdaemonID]; 95 // [defaults synchronize]; 96} 97 98static void db_close(void){ 99 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 100 101 // don't call db_synchronize(); 102 // a) we're calling db_synchronize() after each change already 103 // b) db_close is called during the SIGINT handler which causes a corrupt prefs file 104 105 [remote_devices release]; 106 remote_devices = nil; 107 [pool release]; 108} 109 110static NSString * stringForAddress(bd_addr_t addr) { 111 return [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], 112 addr[3], addr[4], addr[5]]; 113} 114 115static void set_value(bd_addr_t bd_addr, NSString *key, id value){ 116 NSString *devAddress = stringForAddress(bd_addr); 117 NSMutableDictionary * deviceDict = [remote_devices objectForKey:devAddress]; 118 if (!deviceDict){ 119 deviceDict = [NSMutableDictionary dictionaryWithCapacity:3]; 120 [remote_devices setObject:deviceDict forKey:devAddress]; 121 } 122 [deviceDict setObject:value forKey:key]; 123 db_synchronize(); 124} 125 126static void delete_value(bd_addr_t bd_addr, NSString *key){ 127 NSString *devAddress = stringForAddress(bd_addr); 128 NSMutableDictionary * deviceDict = [remote_devices objectForKey:devAddress]; 129 [deviceDict removeObjectForKey:key]; 130 db_synchronize(); 131 132} 133 134static id get_value(bd_addr_t bd_addr, NSString *key){ 135 NSString *devAddress = stringForAddress(bd_addr); 136 NSMutableDictionary * deviceDict = [remote_devices objectForKey:devAddress]; 137 if (!deviceDict) return nil; 138 return [deviceDict objectForKey:key]; 139} 140 141static void put_name(bd_addr_t bd_addr, device_name_t *device_name){ 142 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 143 NSString *remoteName = [NSString stringWithUTF8String:(char*)device_name]; 144 if (!remoteName){ 145 remoteName = [NSString stringWithCString:(char*)device_name encoding:NSISOLatin1StringEncoding]; 146 } 147 if (remoteName) { 148 set_value(bd_addr, PREFS_REMOTE_NAME, remoteName); 149 } 150 [pool release]; 151} 152 153static void delete_name(bd_addr_t bd_addr){ 154 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 155 delete_value(bd_addr, PREFS_REMOTE_NAME); 156 [pool release]; 157} 158 159static int get_name(bd_addr_t bd_addr, device_name_t *device_name) { 160 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 161 NSString *remoteName = get_value(bd_addr, PREFS_REMOTE_NAME); 162 if (remoteName){ 163 memset(device_name, 0, sizeof(device_name_t)); 164 strncpy((char*) device_name, [remoteName UTF8String], sizeof(device_name_t)-1); 165 } 166 [pool release]; 167 return (remoteName != nil); 168} 169 170btstack_device_name_db_t btstack_device_name_db_corefounation = { 171 db_open, 172 db_close, 173 get_name, 174 put_name, 175 delete_name, 176}; 177 178const btstack_device_name_db_t * btstack_device_name_db_corefoundation_instance(void) { 179 return &btstack_device_name_db_corefounation; 180} 181 182