Fix MailMe being disabled for “incompatibility” (i.e., not instantiating) when the user has not set up any accounts.
authorPeter Hosey <hg@boredzo.org>
Wed Dec 02 17:30:31 2009 -0800 (2009-12-02)
changeset 45634ac369b906c7
parent 4562 07b66c657951
child 4564 9720108dd401
Fix MailMe being disabled for “incompatibility” (i.e., not instantiating) when the user has not set up any accounts.

We now load the accounts on demand, and throw away the cached default-account dictionary whenever Mail quits (in case the user changed the accounts).

Includes a minor change in memory management of one local variable (destAddress), which would otherwise have become a leak, and a fix (by conditionalizing a break statement) for the account scan stopping on the first account it finds an SMTP account for, even if the scan rejects the account for missing or invalid data.

Fixes #73.
Plugins/Displays/MailMe/GrowlMailMeDisplay.m
     1.1 --- a/Plugins/Displays/MailMe/GrowlMailMeDisplay.m	Tue Dec 01 08:46:18 2009 -0800
     1.2 +++ b/Plugins/Displays/MailMe/GrowlMailMeDisplay.m	Wed Dec 02 17:30:31 2009 -0800
     1.3 @@ -17,10 +17,12 @@
     1.4  	@"-- in response to a Growl notification --\r\n"\
     1.5  	@"-- http://growl.info/ --\r\n"
     1.6  
     1.7 +#define MAIL_BUNDLE_IDENTIFIER @"com.apple.mail"
     1.8 +
     1.9  @interface GrowlMailMeDisplay ()
    1.10  
    1.11 -//Intended to be called from -init.
    1.12 -- (BOOL) gatherAccountsFromMail;
    1.13 +- (NSDictionary *) defaultSMTPAccountFromMail;
    1.14 +- (void) workspaceDidTerminateApplication:(NSNotification *)notification;
    1.15  
    1.16  @end
    1.17  
    1.18 @@ -31,16 +33,15 @@
    1.19  	if ((self = [super init])) {
    1.20  		pathToMailSenderProgram = [[[NSBundle bundleForClass:[self class]] pathForResource:@"simple-mailer" ofType:@"py"] copy];
    1.21  
    1.22 -		if (![self gatherAccountsFromMail])
    1.23 -			goto fail;
    1.24 +		NSWorkspace *wksp = [NSWorkspace sharedWorkspace];
    1.25 +		[[wksp notificationCenter] addObserver:self
    1.26 +									  selector:@selector(workspaceDidTerminateApplication:)
    1.27 +										  name:NSWorkspaceDidTerminateApplicationNotification
    1.28 +										object:wksp];
    1.29  
    1.30  		tasks = [[NSMutableArray alloc] init];
    1.31  	}
    1.32  	return self;
    1.33 -
    1.34 -fail:
    1.35 -	[self release];
    1.36 -	return nil;
    1.37  }
    1.38  
    1.39  - (void) dealloc {
    1.40 @@ -62,10 +63,10 @@
    1.41  - (void) displayNotification:(GrowlApplicationNotification *)notification {
    1.42  	NSString *destAddress = nil;
    1.43  	READ_GROWL_PREF_VALUE(destAddressKey, @"com.Growl.MailMe", NSString *, &destAddress);
    1.44 +	[NSMakeCollectable(destAddress) autorelease];
    1.45  	NSDictionary *noteDict = [notification dictionaryRepresentation];
    1.46  
    1.47  	if (destAddress) {
    1.48 -		CFMakeCollectable(destAddress);
    1.49  		if([destAddress length]) {
    1.50  			NSString *title = [noteDict objectForKey:GROWL_NOTIFICATION_TITLE];
    1.51  			NSString *desc = [noteDict objectForKey:GROWL_NOTIFICATION_DESCRIPTION];
    1.52 @@ -73,6 +74,15 @@
    1.53  			//One solution would be an easy way to attach at least one file in the simple-mailer program. Another would be a way to create a MIME multi-part message and to have simple-mailer handle it correctly.
    1.54  			//	NSData *imageData = [noteDict objectForKey:GROWL_NOTIFICATION_ICON];
    1.55  
    1.56 +			if (!defaultSMTPAccount) {
    1.57 +				defaultSMTPAccount = [[self defaultSMTPAccountFromMail] retain];
    1.58 +				if (!defaultSMTPAccount) {
    1.59 +					//We can't do anything without an account.
    1.60 +					NSLog(@"MailMe: No suitable SMTP account found");
    1.61 +					return;
    1.62 +				}
    1.63 +			}
    1.64 +
    1.65  			BOOL useTLS = [[defaultSMTPAccount objectForKey:@"SSLEnabled"] boolValue];
    1.66  			NSString *username = [defaultSMTPAccount objectForKey:@"Username"];
    1.67  			NSString *hostname = [defaultSMTPAccount objectForKey:@"Hostname"];
    1.68 @@ -146,7 +156,6 @@
    1.69  	} else {
    1.70  		NSLog(@"(MailMe) WARNING: No destination address set");
    1.71  	}
    1.72 -	[destAddress release];
    1.73  
    1.74  	id clickContext = [noteDict objectForKey:GROWL_NOTIFICATION_CLICK_CONTEXT];
    1.75  	if (clickContext) {
    1.76 @@ -166,14 +175,16 @@
    1.77  	return NO;
    1.78  }
    1.79  
    1.80 -- (BOOL) gatherAccountsFromMail {
    1.81 +- (NSDictionary *) defaultSMTPAccountFromMail {
    1.82 +	NSDictionary *viableAccount = nil;
    1.83 +
    1.84  	NSArray *deliveryAccounts = [NSMakeCollectable(CFPreferencesCopyAppValue(CFSTR("DeliveryAccounts"), CFSTR("com.apple.Mail"))) autorelease];
    1.85  	if (!deliveryAccounts)
    1.86 -		return NO;
    1.87 +		return viableAccount;
    1.88  
    1.89  	NSArray *mailAccounts = [NSMakeCollectable(CFPreferencesCopyAppValue(CFSTR("MailAccounts"), CFSTR("com.apple.Mail"))) autorelease];
    1.90  	if (!mailAccounts)
    1.91 -		return NO;
    1.92 +		return viableAccount;
    1.93  
    1.94  	NSMutableDictionary *deliveryAccountsBySMTPIdentifier = [NSMutableDictionary dictionaryWithCapacity:[deliveryAccounts count]];
    1.95  	for (NSDictionary *account in deliveryAccounts) {
    1.96 @@ -186,35 +197,39 @@
    1.97  		if (!identifier)
    1.98  			continue;
    1.99  
   1.100 -		defaultSMTPAccount = [[deliveryAccountsBySMTPIdentifier objectForKey:identifier] copy];
   1.101 -		if (defaultSMTPAccount) {
   1.102 +		viableAccount = [deliveryAccountsBySMTPIdentifier objectForKey:identifier];
   1.103 +		if (viableAccount) {
   1.104  			NSString *bareAddress = [[account objectForKey:@"EmailAddresses"] objectAtIndex:0UL];
   1.105  			NSString *name = [account objectForKey:@"FullUserName"];
   1.106  			fromAddress = [(name ? [NSString stringWithFormat:@"%@ <%@>", name, bareAddress] : bareAddress) copy];
   1.107  			if (!fromAddress) {
   1.108 -				[defaultSMTPAccount release];
   1.109 -				defaultSMTPAccount = nil;
   1.110 -			}
   1.111 -
   1.112 -			NSNumber *portNumber = [defaultSMTPAccount objectForKey:@"PortNumber"];
   1.113 +				viableAccount = nil;
   1.114 +			}
   1.115 +
   1.116 +			NSNumber *portNumber = [viableAccount objectForKey:@"PortNumber"];
   1.117  			if (portNumber) {
   1.118  				NSInteger port = [portNumber integerValue];
   1.119  				if (port <= 0 || port > 0xFFFF) {
   1.120 -					[defaultSMTPAccount release];
   1.121 -					defaultSMTPAccount = nil;
   1.122 +					viableAccount = nil;
   1.123  				}
   1.124  			}
   1.125  
   1.126 -			break;
   1.127 +			if (viableAccount) {
   1.128 +				break;
   1.129 +			}
   1.130  		}
   1.131  	}
   1.132  
   1.133 -	if (!defaultSMTPAccount) {
   1.134 -		NSLog(@"MailMe: No suitable SMTP account found");
   1.135 -		return NO;
   1.136 -	}
   1.137 -
   1.138 -	return YES;
   1.139 +	return viableAccount;
   1.140 +}
   1.141 +
   1.142 +- (void) workspaceDidTerminateApplication:(NSNotification *)notification {
   1.143 +	NSString *bundleID = [[notification userInfo] objectForKey:@"NSApplicationBundleIdentifier"];
   1.144 +	if ([bundleID isEqualToString:MAIL_BUNDLE_IDENTIFIER]) {
   1.145 +		//Clear out our knowledge of the default Mail account, in case it's changed.
   1.146 +		[defaultSMTPAccount release];
   1.147 +		defaultSMTPAccount = nil;
   1.148 +	}
   1.149  }
   1.150  
   1.151  @end