Keep the EKEzvOutgoingFileTransfer.m around so long as it is sending, regardless...
[adiumx.git] / Source / AdiumPreferredAccounts.m
blobcb40c57fadc726674d1ea504d6899f49982a064e
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
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.
8  * 
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.
12  * 
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.
15  */
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
31 /*!
32  * @brief Init
33  */
34 - (id)init
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
43                                                                                  object:nil];           
44         }
45         
46         return self;
49 /*!
50  * @brief Close
51  */
52 - (void)dealloc
54     [[adium notificationCenter] removeObserver:self];
55         [lastAccountIDToSendContent release]; lastAccountIDToSendContent = nil;
56         
57         [super dealloc];
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
72         AIAccount               *account;
73         
74         //If passed a contact, we have a few better ways to determine the account than just using the first
75     if (inContact) {
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];
79                 if (accountID) {
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]];
84                                 } else {
85                                         accountID = nil; //Unrecognizable, ignore
86                                 }
87                                 
88                                 [inContact setPreference:accountID
89                                                                   forKey:KEY_PREFERRED_SOURCE_ACCOUNT
90                                                                    group:PREF_GROUP_PREFERRED_ACCOUNTS];
91                         }
93                         if ((account = [[adium accountController] accountWithInternalObjectID:accountID])) {
94                                 if ([account availableForSendingContentType:inType toContact:inContact]) {
95                                         return account;
96                                 }
97                         }
98                 }
99                 
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]) {
103                                 return account;
104                         }
105                 }
106                 
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) {
111                                 return account;
112                         }
113                 }
114                 
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])) {
118                                 return account;
119                         }
120                 }
121         }
122         
123         //If the previous attempts failed, or we weren't passed a contact, use the first appropraite account
124         return [self firstAccountAvailableForSendingContentType:inType
125                                                                                                   toContact:inContact
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
133         AIAccount               *account;
134         NSEnumerator    *enumerator;
135         
136     if (inContact) {
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)) {
142                                 return account;
143                         }
144                 }
145                 
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)) {
151                                 return account;
152                         }
153                 }
154         } else {
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)) {
160                                 return account;
161                         }
162                 }
163         }
164         
165         
166         //Can't find anything
167         return nil;
170 - (void)didSendContent:(NSNotification *)notification
172         NSDictionary    *userInfo = [notification userInfo];
173     AIChat                      *chat = [userInfo objectForKey:@"AIChat"];
174     AIListContact       *destObject = [chat listObject];
175     
176     if (chat && destObject) {
177         AIContentObject *contentObject = [userInfo objectForKey:@"AIContentObject"];
178         AIAccount               *sourceAccount = (AIAccount *)[contentObject source];
179         
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];
186         }
188         [lastAccountIDToSendContent setObject:[sourceAccount internalObjectID] forKey:[[destObject service] serviceID]];
189     }
192 @end