2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import <Adium/AIAccountControllerProtocol.h>
18 #import "AdiumPreferredAccounts.h"
19 #import <Adium/AIAccount.h>
20 #import <Adium/AIChat.h>
21 #import <Adium/AIService.h>
22 #import <Adium/AIContentObject.h>
23 #import <Adium/AIListObject.h>
24 #import <Adium/AIListContact.h>
26 #define PREF_GROUP_PREFERRED_ACCOUNTS @"Preferred Accounts"
27 #define KEY_PREFERRED_SOURCE_ACCOUNT @"Preferred Account"
29 @implementation AdiumPreferredAccounts
36 if ((self = [super init])) {
37 lastAccountIDToSendContent = [[NSMutableDictionary alloc] init];
39 //Observe content (for accountForSendingContentToContact)
40 [[adium notificationCenter] addObserver:self
41 selector:@selector(didSendContent:)
42 name:CONTENT_MESSAGE_SENT
54 [[adium notificationCenter] removeObserver:self];
55 [lastAccountIDToSendContent release]; lastAccountIDToSendContent = nil;
61 //XXX - Why is code calling these with a nil contact?
62 //XXX - This method is being misused all over the place as a means to pick the inner contact of a meta?
63 //XXX - Who wants an offline account for sending content, do we absolutely need to do that in the core?
64 //XXX - Why is the method for determining which account to use so complicated?
65 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact
67 return ([self preferredAccountForSendingContentType:inType toContact:inContact includeOffline:NO]);
70 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline
74 //If passed a contact, we have a few better ways to determine the account than just using the first
76 //If we've messaged this object previously, and the account we used to message it is online, return that account
77 NSString *accountID = [inContact preferenceForKey:KEY_PREFERRED_SOURCE_ACCOUNT
78 group:PREF_GROUP_PREFERRED_ACCOUNTS];
80 if (![accountID isKindOfClass:[NSString class]]) {
81 //Old code stored this as an NSNumber; upgrade.
82 if ([accountID isKindOfClass:[NSNumber class]]) {
83 accountID = [NSString stringWithFormat:@"%i",[(NSNumber *)accountID intValue]];
85 accountID = nil; //Unrecognizable, ignore
88 [inContact setPreference:accountID
89 forKey:KEY_PREFERRED_SOURCE_ACCOUNT
90 group:PREF_GROUP_PREFERRED_ACCOUNTS];
93 if ((account = [[adium accountController] accountWithInternalObjectID:accountID])) {
94 if ([account availableForSendingContentType:inType toContact:inContact]) {
100 //If inObject is an AIListContact return the account the object is on
101 if ((account = [inContact account])) {
102 if ([account availableForSendingContentType:inType toContact:inContact]) {
107 //Return the last account used to message someone on this service
108 NSString *lastAccountID = [lastAccountIDToSendContent objectForKey:[[inContact service] serviceID]];
109 if (lastAccountID && (account = [[adium accountController] accountWithInternalObjectID:lastAccountID])) {
110 if ([account availableForSendingContentType:inType toContact:nil] || includeOffline) {
115 if (includeOffline) {
116 //If inObject is an AIListContact return the account the object is on even if the account is offline
117 if ((account = [inContact account])) {
123 //If the previous attempts failed, or we weren't passed a contact, use the first appropraite account
124 return [self firstAccountAvailableForSendingContentType:inType
126 includeOffline:includeOffline];
129 //XXX - This seems awfully complex for code that is only run the first time we talk to a contact
130 //XXX - Why isn't this private?
131 - (AIAccount *)firstAccountAvailableForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline
134 NSEnumerator *enumerator;
137 //First available account in our list of the correct service type
138 enumerator = [[[adium accountController] accounts] objectEnumerator];
139 while ((account = [enumerator nextObject])) {
140 if ([inContact service] == [account service] &&
141 ([account availableForSendingContentType:inType toContact:nil] || includeOffline)) {
146 //First available account in our list of a compatible service type
147 enumerator = [[[adium accountController] accounts] objectEnumerator];
148 while ((account = [enumerator nextObject])) {
149 if ([[inContact serviceClass] isEqualToString:[account serviceClass]] &&
150 ([account availableForSendingContentType:inType toContact:nil] || includeOffline)) {
155 //First available account in our list
156 enumerator = [[[adium accountController] accounts] objectEnumerator];
157 while ((account = [enumerator nextObject])) {
158 if ([account enabled] &&
159 ([account availableForSendingContentType:inType toContact:nil] || includeOffline)) {
166 //Can't find anything
170 - (void)didSendContent:(NSNotification *)notification
172 NSDictionary *userInfo = [notification userInfo];
173 AIChat *chat = [userInfo objectForKey:@"AIChat"];
174 AIListContact *destObject = [chat listObject];
176 if (chat && destObject) {
177 AIContentObject *contentObject = [userInfo objectForKey:@"AIContentObject"];
178 AIAccount *sourceAccount = (AIAccount *)[contentObject source];
180 if (![[destObject preferenceForKey:KEY_PREFERRED_SOURCE_ACCOUNT
181 group:PREF_GROUP_PREFERRED_ACCOUNTS
182 ignoreInheritedValues:YES] isEqualToString:[sourceAccount internalObjectID]]) {
183 [destObject setPreference:[sourceAccount internalObjectID]
184 forKey:KEY_PREFERRED_SOURCE_ACCOUNT
185 group:PREF_GROUP_PREFERRED_ACCOUNTS];
188 [lastAccountIDToSendContent setObject:[sourceAccount internalObjectID] forKey:[[destObject service] serviceID]];