Core/Source/GrowlPreferencesController.m
author Rudy Richter
Sat Aug 01 20:50:32 2009 -0400 (2009-08-01)
changeset 4261 48b7c994f6c8
parent 4246 4f52d1d98978
child 4270 5c1d8f5e64c2
permissions -rw-r--r--
PrefPane: clang warnings and setup for Sparkle
boredzo@2434
     1
//
boredzo@2434
     2
//  GrowlPreferencesController.m
boredzo@2434
     3
//  Growl
boredzo@2434
     4
//
boredzo@2434
     5
//  Created by Nelson Elhage on 8/24/04.
boredzo@2434
     6
//  Renamed from GrowlPreferences.m by Mac-arena the Bored Zo on 2005-06-27.
ingmarstein@3040
     7
//  Copyright 2004-2006 The Growl Project. All rights reserved.
boredzo@2434
     8
//
boredzo@2434
     9
// This file is under the BSD License, refer to License.txt for details
boredzo@2434
    10
boredzo@2434
    11
boredzo@2434
    12
#import "GrowlPreferencesController.h"
boredzo@2434
    13
#import "GrowlDefinesInternal.h"
boredzo@2434
    14
#import "GrowlDefines.h"
boredzo@2461
    15
#import "GrowlPathUtilities.h"
ingmarstein@2517
    16
#import "NSStringAdditions.h"
ingmarstein@2639
    17
#include "CFURLAdditions.h"
ingmarstein@2641
    18
#include "CFDictionaryAdditions.h"
ingmarstein@2721
    19
#include "LoginItemsAE.h"
ingmarstein@2639
    20
#include <Security/SecKeychain.h>
ingmarstein@2639
    21
#include <Security/SecKeychainItem.h>
boredzo@2434
    22
ingmarstein@2517
    23
#define keychainServiceName "Growl"
ingmarstein@2517
    24
#define keychainAccountName "Growl"
ingmarstein@2517
    25
ingmarstein@2602
    26
CFTypeRef GrowlPreferencesController_objectForKey(CFTypeRef key) {
ingmarstein@2602
    27
	return [[GrowlPreferencesController sharedController] objectForKey:(id)key];
ingmarstein@2602
    28
}
ingmarstein@2602
    29
Rudy@4246
    30
CFIndex GrowlPreferencesController_integerForKey(CFTypeRef key) {
ingmarstein@2646
    31
	Boolean keyExistsAndHasValidFormat;
boredzo@4041
    32
	return CFPreferencesGetAppIntegerValue((CFStringRef)key, (CFStringRef)GROWL_HELPERAPP_BUNDLE_IDENTIFIER, &keyExistsAndHasValidFormat);
ingmarstein@2602
    33
}
ingmarstein@2602
    34
ingmarstein@2602
    35
Boolean GrowlPreferencesController_boolForKey(CFTypeRef key) {
ingmarstein@2646
    36
	Boolean keyExistsAndHasValidFormat;
boredzo@4041
    37
	return CFPreferencesGetAppBooleanValue((CFStringRef)key, (CFStringRef)GROWL_HELPERAPP_BUNDLE_IDENTIFIER, &keyExistsAndHasValidFormat);
ingmarstein@2602
    38
}
ingmarstein@2602
    39
Rudy@4246
    40
unsigned short GrowlPreferencesController_unsignedShortForKey(CFTypeRef key)
Rudy@4246
    41
{
Rudy@4246
    42
	CFIndex theIndex = GrowlPreferencesController_integerForKey(key);
Rudy@4246
    43
	
Rudy@4246
    44
	if (theIndex > USHRT_MAX)
Rudy@4246
    45
		return USHRT_MAX;
Rudy@4246
    46
	else if (theIndex < 0)
Rudy@4246
    47
		return 0;
Rudy@4246
    48
	return (unsigned short)index;
Rudy@4246
    49
}
Rudy@4246
    50
boredzo@2434
    51
@implementation GrowlPreferencesController
boredzo@2434
    52
boredzo@2496
    53
+ (GrowlPreferencesController *) sharedController {
ofri@2581
    54
	return [self sharedInstance];
ofri@2581
    55
}
ofri@2581
    56
ofri@2581
    57
- (id) initSingleton {
ofri@2581
    58
	if ((self = [super initSingleton])) {
evands@2514
    59
		[[NSDistributedNotificationCenter defaultCenter] addObserver:self
evands@2514
    60
															selector:@selector(growlPreferencesChanged:)
evands@2514
    61
																name:GrowlPreferencesChanged
ingmarstein@2591
    62
															  object:nil];
boredzo@2434
    63
	}
boredzo@2434
    64
	return self;
boredzo@2434
    65
}
boredzo@2434
    66
ofri@2581
    67
- (void) destroy {
evands@2514
    68
	[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
ingmarstein@2591
    69
ofri@2581
    70
	[super destroy];
boredzo@2434
    71
}
boredzo@2434
    72
boredzo@2434
    73
#pragma mark -
boredzo@2434
    74
boredzo@2434
    75
- (void) registerDefaults:(NSDictionary *)inDefaults {
ingmarstein@2561
    76
	NSUserDefaults *helperAppDefaults = [[NSUserDefaults alloc] init];
boredzo@4041
    77
	[helperAppDefaults addSuiteNamed:GROWL_HELPERAPP_BUNDLE_IDENTIFIER];
boredzo@4041
    78
	NSDictionary *existing = [helperAppDefaults persistentDomainForName:GROWL_HELPERAPP_BUNDLE_IDENTIFIER];
boredzo@2434
    79
	if (existing) {
boredzo@2434
    80
		NSMutableDictionary *domain = [inDefaults mutableCopy];
boredzo@2434
    81
		[domain addEntriesFromDictionary:existing];
boredzo@4041
    82
		[helperAppDefaults setPersistentDomain:domain forName:GROWL_HELPERAPP_BUNDLE_IDENTIFIER];
boredzo@2434
    83
		[domain release];
boredzo@2434
    84
	} else {
boredzo@4041
    85
		[helperAppDefaults setPersistentDomain:inDefaults forName:GROWL_HELPERAPP_BUNDLE_IDENTIFIER];
boredzo@2434
    86
	}
ingmarstein@2561
    87
	[helperAppDefaults release];
ingmarstein@2561
    88
	SYNCHRONIZE_GROWL_PREFS();
boredzo@2434
    89
}
boredzo@2434
    90
boredzo@2434
    91
- (id) objectForKey:(NSString *)key {
boredzo@4041
    92
	id value = (id)CFPreferencesCopyAppValue((CFStringRef)key, (CFStringRef)GROWL_HELPERAPP_BUNDLE_IDENTIFIER);
Rudy@4261
    93
	if(value)
Rudy@4261
    94
		CFMakeCollectable(value);
ingmarstein@2561
    95
	return [value autorelease];
boredzo@2434
    96
}
boredzo@2434
    97
boredzo@2434
    98
- (void) setObject:(id)object forKey:(NSString *)key {
boredzo@2494
    99
	CFPreferencesSetAppValue((CFStringRef)key,
boredzo@2494
   100
							 (CFPropertyListRef)object,
boredzo@4041
   101
							 (CFStringRef)GROWL_HELPERAPP_BUNDLE_IDENTIFIER);
boredzo@2434
   102
ingmarstein@2561
   103
	SYNCHRONIZE_GROWL_PREFS();
boredzo@2434
   104
ingmarstein@2672
   105
	int pid = getpid();
ingmarstein@2672
   106
	CFNumberRef pidValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
ingmarstein@2672
   107
	CFStringRef pidKey = CFSTR("pid");
ingmarstein@2672
   108
	CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&pidKey, (const void **)&pidValue, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
ingmarstein@2672
   109
	CFRelease(pidValue);
ingmarstein@2672
   110
	CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
ingmarstein@2672
   111
										 (CFStringRef)GrowlPreferencesChanged,
ingmarstein@2672
   112
										 /*object*/ key,
ingmarstein@2672
   113
										 /*userInfo*/ userInfo,
ingmarstein@2672
   114
										 /*deliverImmediately*/ false);
ingmarstein@2672
   115
	CFRelease(userInfo);
boredzo@2434
   116
}
boredzo@2434
   117
boredzo@2434
   118
- (BOOL) boolForKey:(NSString *)key {
ingmarstein@2646
   119
	return GrowlPreferencesController_boolForKey((CFTypeRef)key);
boredzo@2434
   120
}
boredzo@2434
   121
boredzo@2434
   122
- (void) setBool:(BOOL)value forKey:(NSString *)key {
boredzo@2434
   123
	NSNumber *object = [[NSNumber alloc] initWithBool:value];
boredzo@2434
   124
	[self setObject:object forKey:key];
boredzo@2434
   125
	[object release];
boredzo@2434
   126
}
boredzo@2434
   127
Rudy@4246
   128
- (CFIndex) integerForKey:(NSString *)key {
ingmarstein@2646
   129
	return GrowlPreferencesController_integerForKey((CFTypeRef)key);
boredzo@2434
   130
}
boredzo@2434
   131
Rudy@4246
   132
- (void) setInteger:(CFIndex)value forKey:(NSString *)key {
Rudy@4246
   133
#ifdef __LP64__
Rudy@4246
   134
	NSNumber *object = [[NSNumber alloc] initWithInteger:value];
Rudy@4246
   135
#else
boredzo@2434
   136
	NSNumber *object = [[NSNumber alloc] initWithInt:value];
Rudy@4246
   137
#endif
boredzo@2434
   138
	[self setObject:object forKey:key];
boredzo@2434
   139
	[object release];
boredzo@2434
   140
}
boredzo@2434
   141
Rudy@4246
   142
- (unsigned short)unsignedShortForKey:(NSString *)key
Rudy@4246
   143
{
Rudy@4246
   144
	return GrowlPreferencesController_unsignedShortForKey((CFTypeRef)key);
Rudy@4246
   145
}
Rudy@4246
   146
Rudy@4246
   147
Rudy@4246
   148
- (void)setUnsignedShort:(unsigned short)theShort forKey:(NSString *)key
Rudy@4246
   149
{
Rudy@4246
   150
	[self setObject:[NSNumber numberWithUnsignedShort:theShort] forKey:key];
Rudy@4246
   151
}
Rudy@4246
   152
boredzo@2434
   153
- (void) synchronize {
boredzo@2434
   154
	SYNCHRONIZE_GROWL_PREFS();
boredzo@2434
   155
}
boredzo@2434
   156
boredzo@2434
   157
#pragma mark -
boredzo@2434
   158
#pragma mark Start-at-login control
boredzo@2434
   159
boredzo@2496
   160
- (BOOL) shouldStartGrowlAtLogin {
ingmarstein@2721
   161
	OSStatus   status;
ingmarstein@3011
   162
	Boolean    foundIt = false;
ingmarstein@2721
   163
	CFArrayRef loginItems = NULL;
boredzo@2434
   164
boredzo@2434
   165
	//get the prefpane bundle and find GHA within it.
evands@3619
   166
	NSString *pathToGHA      = [[NSBundle bundleWithIdentifier:GROWL_PREFPANE_BUNDLE_IDENTIFIER] pathForResource:@"GrowlHelperApp" ofType:@"app"];
ingmarstein@2721
   167
	//get the file url to GHA.
ingmarstein@2721
   168
	CFURLRef urlToGHA = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)pathToGHA, kCFURLPOSIXPathStyle, true);
ingmarstein@2721
   169
ingmarstein@2721
   170
	status = LIAECopyLoginItems(&loginItems);
ingmarstein@3011
   171
	if (status == noErr) {
boredzo@3994
   172
		for (CFIndex i=0, count=CFArrayGetCount(loginItems); i<count; ++i) {
ingmarstein@3011
   173
			CFDictionaryRef loginItem = CFArrayGetValueAtIndex(loginItems, i);
ingmarstein@3011
   174
			foundIt = CFEqual(CFDictionaryGetValue(loginItem, kLIAEURL), urlToGHA);
ingmarstein@3011
   175
			if (foundIt)
ingmarstein@3011
   176
				break;
ingmarstein@3011
   177
		}
ingmarstein@3011
   178
		CFRelease(loginItems);
ingmarstein@3011
   179
	}
ingmarstein@2721
   180
ingmarstein@2721
   181
	CFRelease(urlToGHA);
boredzo@2434
   182
boredzo@2434
   183
	return foundIt;
boredzo@2434
   184
}
boredzo@2434
   185
boredzo@2496
   186
- (void) setShouldStartGrowlAtLogin:(BOOL)flag {
boredzo@2434
   187
	//get the prefpane bundle and find GHA within it.
evands@3619
   188
	NSString *pathToGHA = [[NSBundle bundleWithIdentifier:GROWL_PREFPANE_BUNDLE_IDENTIFIER] pathForResource:@"GrowlHelperApp" ofType:@"app"];
boredzo@2434
   189
	[self setStartAtLogin:pathToGHA enabled:flag];
boredzo@2434
   190
}
boredzo@2434
   191
evands@3616
   192
- (void) setStartAtLogin:(NSString *)path enabled:(BOOL)enabled {
ingmarstein@2721
   193
	OSStatus status;
ingmarstein@2721
   194
	CFArrayRef loginItems = NULL;
evands@3616
   195
	NSURL *url = [NSURL fileURLWithPath:path];
Rudy@4246
   196
	NSInteger existingLoginItemIndex = -1;
evands@3616
   197
ingmarstein@2721
   198
	status = LIAECopyLoginItems(&loginItems);
evands@3616
   199
ingmarstein@2721
   200
	if (status == noErr) {
evands@3616
   201
		NSEnumerator *enumerator = [(NSArray *)loginItems objectEnumerator];
evands@3616
   202
		NSDictionary *loginItemDict;
evands@3616
   203
evands@3616
   204
		while ((loginItemDict = [enumerator nextObject])) {
evands@3616
   205
			if ([[loginItemDict objectForKey:(NSString *)kLIAEURL] isEqual:url]) {
evands@3616
   206
				existingLoginItemIndex = [(NSArray *)loginItems indexOfObjectIdenticalTo:loginItemDict];
evands@3616
   207
				break;
evands@3616
   208
			}
evands@3616
   209
		}
evands@3616
   210
	}
evands@3616
   211
evands@3616
   212
	if (enabled && (existingLoginItemIndex == -1))
evands@3616
   213
		LIAEAddURLAtEnd((CFURLRef)url, false);
evands@3616
   214
	else if (!enabled && (existingLoginItemIndex != -1))
evands@3616
   215
		LIAERemove(existingLoginItemIndex);
evands@3616
   216
bgannin@3654
   217
	if(loginItems)
bgannin@3654
   218
		CFRelease(loginItems);
boredzo@2434
   219
}
boredzo@2434
   220
boredzo@2434
   221
#pragma mark -
boredzo@2496
   222
#pragma mark GrowlMenu running state
boredzo@2496
   223
boredzo@2496
   224
- (void) enableGrowlMenu {
ingmarstein@2517
   225
	NSBundle *bundle = [NSBundle bundleForClass:[GrowlPreferencesController class]];
ingmarstein@2517
   226
	NSString *growlMenuPath = [bundle pathForResource:@"GrowlMenu" ofType:@"app"];
boredzo@2496
   227
	NSURL *growlMenuURL = [NSURL fileURLWithPath:growlMenuPath];
boredzo@2496
   228
	[[NSWorkspace sharedWorkspace] openURLs:[NSArray arrayWithObject:growlMenuURL]
boredzo@2496
   229
	                withAppBundleIdentifier:nil
boredzo@2496
   230
	                                options:NSWorkspaceLaunchWithoutAddingToRecents | NSWorkspaceLaunchWithoutActivation | NSWorkspaceLaunchAsync
boredzo@2496
   231
	         additionalEventParamDescriptor:nil
boredzo@2496
   232
	                      launchIdentifiers:NULL];
boredzo@2496
   233
}
boredzo@2496
   234
boredzo@2496
   235
- (void) disableGrowlMenu {
boredzo@2496
   236
	// Ask GrowlMenu to shutdown via the DNC
ingmarstein@2672
   237
	CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
ingmarstein@2672
   238
										 CFSTR("GrowlMenuShutdown"),
ingmarstein@2672
   239
										 /*object*/ NULL,
ingmarstein@2672
   240
										 /*userInfo*/ NULL,
ingmarstein@2672
   241
										 /*deliverImmediately*/ false);
boredzo@2496
   242
}
boredzo@2496
   243
boredzo@2496
   244
#pragma mark -
boredzo@2434
   245
#pragma mark Growl running state
boredzo@2434
   246
boredzo@2434
   247
- (void) setGrowlRunning:(BOOL)flag noMatterWhat:(BOOL)nmw {
boredzo@2434
   248
	// Store the desired running-state of the helper app for use by GHA.
boredzo@2434
   249
	[self setBool:flag forKey:GrowlEnabledKey];
boredzo@2434
   250
boredzo@2434
   251
	//now launch or terminate as appropriate.
boredzo@2434
   252
	if (flag)
boredzo@2434
   253
		[self launchGrowl:nmw];
boredzo@2434
   254
	else
boredzo@2434
   255
		[self terminateGrowl];
boredzo@2434
   256
}
boredzo@2434
   257
boredzo@2434
   258
- (BOOL) isRunning:(NSString *)theBundleIdentifier {
boredzo@2434
   259
	BOOL isRunning = NO;
boredzo@2434
   260
	ProcessSerialNumber PSN = { kNoProcess, kNoProcess };
boredzo@2434
   261
boredzo@2434
   262
	while (GetNextProcess(&PSN) == noErr) {
boredzo@2434
   263
		NSDictionary *infoDict = (NSDictionary *)ProcessInformationCopyDictionary(&PSN, kProcessDictionaryIncludeAllInformationMask);
Rudy@4261
   264
		if(infoDict) {
Rudy@4261
   265
			NSString *bundleID = [infoDict objectForKey:(NSString *)kCFBundleIdentifierKey];
Rudy@4261
   266
			isRunning = bundleID && [bundleID isEqualToString:theBundleIdentifier];
Rudy@4261
   267
			CFMakeCollectable(infoDict);
Rudy@4261
   268
			[infoDict release];
Rudy@4261
   269
		}
boredzo@2434
   270
		if (isRunning)
boredzo@2434
   271
			break;
boredzo@2434
   272
	}
boredzo@2434
   273
boredzo@2434
   274
	return isRunning;
boredzo@2434
   275
}
boredzo@2434
   276
boredzo@2434
   277
- (BOOL) isGrowlRunning {
boredzo@2434
   278
	return [self isRunning:@"com.Growl.GrowlHelperApp"];
boredzo@2434
   279
}
boredzo@2434
   280
boredzo@2434
   281
- (void) launchGrowl:(BOOL)noMatterWhat {
boredzo@2677
   282
	NSString *helperPath = [[GrowlPathUtilities helperAppBundle] bundlePath];
boredzo@2496
   283
	NSURL *helperURL = [NSURL fileURLWithPath:helperPath];
boredzo@2496
   284
boredzo@2496
   285
	unsigned options = NSWorkspaceLaunchWithoutAddingToRecents | NSWorkspaceLaunchWithoutActivation | NSWorkspaceLaunchAsync;
boredzo@2496
   286
	if (noMatterWhat)
boredzo@2496
   287
		options |= NSWorkspaceLaunchNewInstance;
boredzo@2496
   288
	[[NSWorkspace sharedWorkspace] openURLs:[NSArray arrayWithObject:helperURL]
boredzo@2496
   289
	                withAppBundleIdentifier:nil
boredzo@2496
   290
	                                options:options
boredzo@2496
   291
	         additionalEventParamDescriptor:nil
boredzo@2496
   292
	                      launchIdentifiers:NULL];
boredzo@2434
   293
}
boredzo@2434
   294
boredzo@2434
   295
- (void) terminateGrowl {
boredzo@2434
   296
	// Ask the Growl Helper App to shutdown via the DNC
ingmarstein@2672
   297
	CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
ingmarstein@2672
   298
										 (CFStringRef)GROWL_SHUTDOWN,
ingmarstein@2672
   299
										 /*object*/ NULL,
ingmarstein@2672
   300
										 /*userInfo*/ NULL,
ingmarstein@2672
   301
										 /*deliverImmediately*/ false);
boredzo@2434
   302
}
boredzo@2434
   303
boredzo@2496
   304
#pragma mark -
boredzo@2496
   305
//Simplified accessors
boredzo@2496
   306
boredzo@2496
   307
#pragma mark UI
boredzo@2496
   308
Rudy@4246
   309
- (CFIndex)selectedPosition {
bgannin@3317
   310
	return [self integerForKey:GROWL_POSITION_PREFERENCE_KEY];
bgannin@3317
   311
}
bgannin@3317
   312
boredzo@2496
   313
- (BOOL) isBackgroundUpdateCheckEnabled {
boredzo@2496
   314
	return [self boolForKey:GrowlUpdateCheckKey];
boredzo@2496
   315
}
boredzo@2496
   316
- (void) setIsBackgroundUpdateCheckEnabled:(BOOL)flag {
boredzo@2496
   317
	[self setBool:flag forKey:GrowlUpdateCheckKey];
boredzo@2496
   318
}
boredzo@2496
   319
boredzo@2496
   320
- (NSString *) defaultDisplayPluginName {
boredzo@2496
   321
	return [self objectForKey:GrowlDisplayPluginKey];
boredzo@2496
   322
}
boredzo@2496
   323
- (void) setDefaultDisplayPluginName:(NSString *)name {
boredzo@2496
   324
	[self setObject:name forKey:GrowlDisplayPluginKey];
boredzo@2496
   325
}
boredzo@2496
   326
boredzo@2496
   327
- (BOOL) squelchMode {
boredzo@2496
   328
	return [self boolForKey:GrowlSquelchModeKey];
boredzo@2496
   329
}
boredzo@2496
   330
- (void) setSquelchMode:(BOOL)flag {
boredzo@2496
   331
	[self setBool:flag forKey:GrowlSquelchModeKey];
boredzo@2496
   332
}
boredzo@2496
   333
boredzo@2496
   334
- (BOOL) stickyWhenAway {
boredzo@2496
   335
	return [self boolForKey:GrowlStickyWhenAwayKey];
boredzo@2496
   336
}
boredzo@2496
   337
- (void) setStickyWhenAway:(BOOL)flag {
boredzo@2496
   338
	[self setBool:flag forKey:GrowlStickyWhenAwayKey];
boredzo@2496
   339
}
boredzo@2496
   340
rudy@2968
   341
- (NSNumber*) idleThreshold {
Rudy@4246
   342
#ifdef __LP64__
Rudy@4246
   343
	return [NSNumber numberWithInteger:[self integerForKey:GrowlStickyIdleThresholdKey]];
Rudy@4246
   344
#else
rudy@2968
   345
	return [NSNumber numberWithInt:[self integerForKey:GrowlStickyIdleThresholdKey]];
Rudy@4246
   346
#endif
rudy@2968
   347
}
rudy@2968
   348
rudy@2968
   349
- (void) setIdleThreshold:(NSNumber*)value {
rudy@2968
   350
	[self setInteger:[value intValue] forKey:GrowlStickyIdleThresholdKey];
rudy@2968
   351
}
boredzo@2496
   352
#pragma mark Status Item
boredzo@2496
   353
ingmarstein@2540
   354
- (BOOL) isGrowlMenuEnabled {
boredzo@2496
   355
	return [self boolForKey:GrowlMenuExtraKey];
boredzo@2496
   356
}
boredzo@2496
   357
boredzo@2496
   358
- (void) setGrowlMenuEnabled:(BOOL)state {
ingmarstein@2540
   359
	if (state != [self isGrowlMenuEnabled]) {
boredzo@2496
   360
		[self setBool:state forKey:GrowlMenuExtraKey];
boredzo@2496
   361
		if (state)
boredzo@2496
   362
			[self enableGrowlMenu];
boredzo@2496
   363
		else
boredzo@2496
   364
			[self disableGrowlMenu];
boredzo@2496
   365
	}
boredzo@2496
   366
}
boredzo@2496
   367
boredzo@2496
   368
#pragma mark Logging
boredzo@2496
   369
boredzo@2496
   370
- (BOOL) loggingEnabled {
ingmarstein@2635
   371
	return [self boolForKey:GrowlLoggingEnabledKey];
boredzo@2496
   372
}
boredzo@2496
   373
boredzo@2496
   374
- (void) setLoggingEnabled:(BOOL)flag {
ingmarstein@2635
   375
	[self setBool:flag forKey:GrowlLoggingEnabledKey];
ingmarstein@2635
   376
}
boredzo@2496
   377
boredzo@2496
   378
- (BOOL) isGrowlServerEnabled {
ingmarstein@2635
   379
	return [self boolForKey:GrowlStartServerKey];
boredzo@2496
   380
}
boredzo@2496
   381
boredzo@2496
   382
- (void) setGrowlServerEnabled:(BOOL)enabled {
ingmarstein@2635
   383
	[self setBool:enabled forKey:GrowlStartServerKey];
boredzo@2496
   384
}
boredzo@2496
   385
boredzo@2496
   386
#pragma mark Remote Growling
boredzo@2496
   387
boredzo@2496
   388
- (BOOL) isRemoteRegistrationAllowed {
ingmarstein@2635
   389
	return [self boolForKey:GrowlRemoteRegistrationKey];
boredzo@2496
   390
}
boredzo@2496
   391
boredzo@2496
   392
- (void) setRemoteRegistrationAllowed:(BOOL)flag {
ingmarstein@2635
   393
	[self setBool:flag forKey:GrowlRemoteRegistrationKey];
boredzo@2496
   394
}
boredzo@2496
   395
boredzo@2496
   396
- (NSString *) remotePassword {
ingmarstein@2634
   397
	unsigned char *password;
boredzo@2496
   398
	UInt32 passwordLength;
boredzo@2496
   399
	OSStatus status;
boredzo@2496
   400
	status = SecKeychainFindGenericPassword(NULL,
Rudy@4246
   401
											(UInt32)strlen(keychainServiceName), keychainServiceName,
Rudy@4246
   402
											(UInt32)strlen(keychainAccountName), keychainAccountName,
boredzo@2496
   403
											&passwordLength, (void **)&password, NULL);
boredzo@2496
   404
boredzo@2496
   405
	NSString *passwordString;
boredzo@2496
   406
	if (status == noErr) {
ingmarstein@2634
   407
		passwordString = (NSString *)CFStringCreateWithBytes(kCFAllocatorDefault, password, passwordLength, kCFStringEncodingUTF8, false);
Rudy@4261
   408
		if(passwordString) {
Rudy@4261
   409
			CFMakeCollectable(passwordString);
Rudy@4261
   410
			[passwordString autorelease];
Rudy@4261
   411
			SecKeychainItemFreeContent(NULL, password);
Rudy@4261
   412
		}
boredzo@2496
   413
	} else {
boredzo@2496
   414
		if (status != errSecItemNotFound)
boredzo@2496
   415
			NSLog(@"Failed to retrieve password from keychain. Error: %d", status);
boredzo@2496
   416
		passwordString = @"";
boredzo@2496
   417
	}
boredzo@2496
   418
boredzo@2496
   419
	return passwordString;
boredzo@2496
   420
}
boredzo@2496
   421
boredzo@2496
   422
- (void) setRemotePassword:(NSString *)value {
boredzo@2496
   423
	const char *password = value ? [value UTF8String] : "";
Rudy@4246
   424
	size_t length = strlen(password);
boredzo@2496
   425
	OSStatus status;
boredzo@2496
   426
	SecKeychainItemRef itemRef = nil;
boredzo@2496
   427
	status = SecKeychainFindGenericPassword(NULL,
Rudy@4246
   428
											(UInt32)strlen(keychainServiceName), keychainServiceName,
Rudy@4246
   429
											(UInt32)strlen(keychainAccountName), keychainAccountName,
boredzo@2496
   430
											NULL, NULL, &itemRef);
boredzo@2496
   431
	if (status == errSecItemNotFound) {
boredzo@2496
   432
		// add new item
boredzo@2496
   433
		status = SecKeychainAddGenericPassword(NULL,
Rudy@4246
   434
											   (UInt32)strlen(keychainServiceName), keychainServiceName,
Rudy@4246
   435
											   (UInt32)strlen(keychainAccountName), keychainAccountName,
Rudy@4246
   436
											   (UInt32)length, password, NULL);
boredzo@2496
   437
		if (status)
boredzo@2496
   438
			NSLog(@"Failed to add password to keychain.");
boredzo@2496
   439
	} else {
boredzo@2496
   440
		// change existing password
boredzo@2496
   441
		SecKeychainAttribute attrs[] = {
Rudy@4246
   442
			{ kSecAccountItemAttr, (UInt32)strlen(keychainAccountName), (char *)keychainAccountName },
Rudy@4246
   443
			{ kSecServiceItemAttr, (UInt32)strlen(keychainServiceName), (char *)keychainServiceName }
boredzo@2496
   444
		};
Rudy@4246
   445
		const SecKeychainAttributeList attributes = { (UInt32)sizeof(attrs) / (UInt32)sizeof(attrs[0]), attrs };
boredzo@2496
   446
		status = SecKeychainItemModifyAttributesAndData(itemRef,		// the item reference
boredzo@2496
   447
														&attributes,	// no change to attributes
Rudy@4246
   448
														(UInt32)length,			// length of password
boredzo@2496
   449
														password		// pointer to password data
boredzo@2496
   450
														);
boredzo@2496
   451
		if (itemRef)
boredzo@2496
   452
			CFRelease(itemRef);
boredzo@2496
   453
		if (status)
boredzo@2496
   454
			NSLog(@"Failed to change password in keychain.");
boredzo@2496
   455
	}
boredzo@2496
   456
}
boredzo@2496
   457
Rudy@4246
   458
- (unsigned short) UDPPort {
Rudy@4246
   459
	return [self unsignedShortForKey:GrowlUDPPortKey];
Rudy@4246
   460
}
Rudy@4246
   461
- (void) setUDPPort:(unsigned short)value {
Rudy@4246
   462
	[self setUnsignedShort:value forKey:GrowlUDPPortKey];
boredzo@2496
   463
}
boredzo@2496
   464
boredzo@2496
   465
- (BOOL) isForwardingEnabled {
ingmarstein@2635
   466
	return [self boolForKey:GrowlEnableForwardKey];
boredzo@2496
   467
}
boredzo@2496
   468
- (void) setForwardingEnabled:(BOOL)enabled {
ingmarstein@2635
   469
	[self setBool:enabled forKey:GrowlEnableForwardKey];
boredzo@2496
   470
}
boredzo@2496
   471
evands@2514
   472
#pragma mark -
evands@2514
   473
/*
evands@2514
   474
 * @brief Growl preferences changed
evands@2514
   475
 *
evands@2514
   476
 * Synchronize our NSUserDefaults to immediately get any changes from the disk
evands@2514
   477
 */
ingmarstein@2517
   478
- (void) growlPreferencesChanged:(NSNotification *)notification {
evands@4016
   479
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
evands@4016
   480
ingmarstein@2672
   481
	NSString *object = [notification object];
ingmarstein@2672
   482
//	NSLog(@"%s: %@\n", __func__, object);
ingmarstein@2672
   483
	SYNCHRONIZE_GROWL_PREFS();
ingmarstein@2672
   484
	if (!object || [object isEqualToString:GrowlDisplayPluginKey]) {
ingmarstein@2672
   485
		[self willChangeValueForKey:@"defaultDisplayPluginName"];
ingmarstein@2672
   486
		[self didChangeValueForKey:@"defaultDisplayPluginName"];
ingmarstein@2672
   487
	}
ingmarstein@2672
   488
	if (!object || [object isEqualToString:GrowlSquelchModeKey]) {
ingmarstein@2672
   489
		[self willChangeValueForKey:@"squelchMode"];
ingmarstein@2672
   490
		[self didChangeValueForKey:@"squelchMode"];
ingmarstein@2672
   491
	}
ingmarstein@2672
   492
	if (!object || [object isEqualToString:GrowlMenuExtraKey]) {
ingmarstein@2672
   493
		[self willChangeValueForKey:@"growlMenuEnabled"];
ingmarstein@2672
   494
		[self didChangeValueForKey:@"growlMenuEnabled"];
ingmarstein@2672
   495
	}
ingmarstein@2672
   496
	if (!object || [object isEqualToString:GrowlEnableForwardKey]) {
ingmarstein@2672
   497
		[self willChangeValueForKey:@"forwardingEnabled"];
ingmarstein@2672
   498
		[self didChangeValueForKey:@"forwardingEnabled"];
ingmarstein@2672
   499
	}
ingmarstein@2672
   500
	if (!object || [object isEqualToString:GrowlUpdateCheckKey]) {
ingmarstein@2672
   501
		[self willChangeValueForKey:@"backgroundUpdateCheckEnabled"];
ingmarstein@2672
   502
		[self didChangeValueForKey:@"backgroundUpdateCheckEnabled"];
ingmarstein@2672
   503
	}
ingmarstein@2672
   504
	if (!object || [object isEqualToString:GrowlStickyWhenAwayKey]) {
ingmarstein@2672
   505
		[self willChangeValueForKey:@"stickyWhenAway"];
ingmarstein@2672
   506
		[self didChangeValueForKey:@"stickyWhenAway"];
ingmarstein@2672
   507
	}
rudy@2968
   508
	if (!object || [object isEqualToString:GrowlStickyIdleThresholdKey]) {
rudy@2968
   509
		[self willChangeValueForKey:@"idleThreshold"];
rudy@2968
   510
		[self didChangeValueForKey:@"idleThreshold"];
rudy@2968
   511
	}
ingmarstein@2672
   512
	if (!object || [object isEqualToString:GrowlRemoteRegistrationKey]) {
ingmarstein@2672
   513
		[self willChangeValueForKey:@"remoteRegistrationAllowed"];
ingmarstein@2672
   514
		[self didChangeValueForKey:@"remoteRegistrationAllowed"];
ingmarstein@2672
   515
	}
evands@4016
   516
	
evands@4016
   517
	[pool release];
evands@2514
   518
}
boredzo@2496
   519
boredzo@2434
   520
@end