Adium

Changeset 23929

Show
Ignore:
Timestamp:
06/11/2008 08:08:55 PM (6 months ago)
Author:
evands
Message:

Fixed and simplified determination of preferred accounts for messaging contacts. Removed a couple public methods which shouldn't exist in the process. Fixes opening message windows for offline contacts on accounts which don't support offline messaging, among other problems. Fixes #9970

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Frameworks/Adium Framework/Source/AIAccountControllerProtocol.h

    r22850 r23929  
    156156//Preferred Accounts 
    157157- (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact; 
    158 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline; 
    159 - (AIAccount *)firstAccountAvailableForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline; 
    160158 
    161159//Connection convenience methods 
  • trunk/Frameworks/Adium Framework/Source/AIAccountPlusFieldPromptController.m

    r22098 r23929  
    212212- (void)_selectLastUsedAccountInAccountMenu:(AIAccountMenu *)inAccountMenu 
    213213{ 
    214         AIAccount   *preferredAccount = [[adium accountController] preferredAccountForSendingContentType:CONTENT_MESSAGE_TYPE 
    215                                                                                                                                                                                    toContact:nil]; 
     214        //First online account in our list 
     215        NSEnumerator *enumerator = [[[adium accountController] accounts] objectEnumerator]; 
     216        AIAccount    *preferredAccount; 
     217        while ((preferredAccount = [enumerator nextObject])) { 
     218                if ([preferredAccount online]) 
     219                        break; 
     220        } 
     221         
    216222        NSMenuItem      *menuItem = [inAccountMenu menuItemForAccount:preferredAccount]; 
    217223         
  • trunk/Frameworks/Adium Framework/Source/DCJoinChatWindowController.m

    r22747 r23929  
    195195{ 
    196196        if ([popUp_service numberOfItems]) { 
    197                 AIAccount   *preferredAccount = [[adium accountController] preferredAccountForSendingContentType:CONTENT_MESSAGE_TYPE 
    198                                                                                                                                                                                            toContact:nil]; 
     197                //First online account in our list 
     198                NSEnumerator *enumerator = [[[adium accountController] accounts] objectEnumerator]; 
     199                AIAccount    *preferredAccount; 
     200                while ((preferredAccount = [enumerator nextObject])) { 
     201                        if ([preferredAccount online]) 
     202                                break; 
     203                } 
     204                 
    199205                NSMenuItem      *menuItem = [inAccountMenu menuItemForAccount:preferredAccount]; 
    200206 
  • trunk/Source/AdiumPreferredAccounts.h

    r17127 r23929  
    2424 
    2525- (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact; 
    26 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline; 
    27 - (AIAccount *)firstAccountAvailableForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline; 
    2826 
    2927@end 
  • trunk/Source/AdiumPreferredAccounts.m

    r23379 r23929  
    6060} 
    6161 
    62  
    63 //XXX - Why is code calling these with a nil contact? 
    64 //XXX - This method is being misused all over the place as a means to pick the inner contact of a meta? 
    65 //XXX - Who wants an offline account for sending content, do we absolutely need to do that in the core? 
    66 //XXX - Why is the method for determining which account to use so complicated? 
    67 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact  
    68 
    69         return ([self preferredAccountForSendingContentType:inType toContact:inContact includeOffline:NO]); 
    70 
    71  
    72 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline 
     62- (AIAccount *)fallbackAccountForSendingToContact:(AIListContact *)inContact strictChecking:(BOOL)strictChecking 
    7363{ 
    7464        AIAccount               *account; 
    75  
    76         //If passed a contact, we have a few better ways to determine the account than just using the first 
    77     if (inContact) { 
    78                 //If we've messaged this object previously, and the account we used to message it is online, return that account 
    79         NSString *accountID = [inContact preferenceForKey:KEY_PREFERRED_SOURCE_ACCOUNT 
    80                                                                                                         group:PREF_GROUP_PREFERRED_ACCOUNTS]; 
    81                 if (accountID) { 
    82                         if (![accountID isKindOfClass:[NSString class]]) { 
    83                                 //Old code stored this as an NSNumber; upgrade. 
    84                                 accountID = ([accountID isKindOfClass:[NSNumber class]] ? 
    85                                                          [NSString stringWithFormat:@"%i",[(NSNumber *)accountID intValue]] : 
    86                                                          nil); 
    87                                  
    88                                 [inContact setPreference:accountID 
    89                                                                   forKey:KEY_PREFERRED_SOURCE_ACCOUNT 
    90                                                                    group:PREF_GROUP_PREFERRED_ACCOUNTS]; 
    91                         } 
    92  
     65        NSEnumerator    *enumerator; 
     66         
     67        //First available account in our list of the correct service type 
     68        enumerator = [[[adium accountController] accounts] objectEnumerator]; 
     69        while ((account = [enumerator nextObject])) { 
     70                if ([inContact service] == [account service] && 
     71                        ([account online] || ([account enabled] && !strictChecking))) { 
     72                        return account; 
     73                } 
     74        } 
     75         
     76        //First available account in our list of a compatible service type 
     77        enumerator = [[[adium accountController] accounts] objectEnumerator]; 
     78        while ((account = [enumerator nextObject])) { 
     79                if ([[inContact serviceClass] isEqualToString:[account serviceClass]] && 
     80                        ([account online] || ([account enabled] && !strictChecking))) { 
     81                        return account; 
     82                } 
     83        } 
     84 
     85        //Can't find anything 
     86        return nil; 
     87
     88 
     89- (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact strictChecking:(BOOL)strictChecking 
     90{        
     91        AIAccount               *account; 
     92 
     93        NSParameterAssert(inContact != nil); 
     94 
     95        //If we've messaged this object previously, and the account we used to message it is online, return that account 
     96        NSString *accountID = [inContact preferenceForKey:KEY_PREFERRED_SOURCE_ACCOUNT 
     97                                                                                                group:PREF_GROUP_PREFERRED_ACCOUNTS]; 
     98        if (accountID) { 
     99                if (![accountID isKindOfClass:[NSString class]]) { 
     100                        //Old code stored this as an NSNumber; upgrade. 
     101                        accountID = ([accountID isKindOfClass:[NSNumber class]] ? 
     102                                                 [NSString stringWithFormat:@"%i",[(NSNumber *)accountID intValue]] : 
     103                                                 nil); 
    93104                         
    94                         if ((account = [[adium accountController] accountWithInternalObjectID:accountID])) { 
    95                                 if ([account availableForSendingContentType:inType toContact:inContact] || includeOffline) { 
    96                                         return account; 
    97                                 } 
    98                         } 
     105                        [inContact setPreference:accountID 
     106                                                          forKey:KEY_PREFERRED_SOURCE_ACCOUNT 
     107                                                           group:PREF_GROUP_PREFERRED_ACCOUNTS]; 
    99108                } 
    100109                 
    101                 /* We don't have a known previously used account for this contact. */ 
    102  
    103                 //Get the last account used to message someone on this service, and check if the contact is on that account 
    104                 NSString                *lastAccountID = [lastAccountIDToSendContent objectForKey:[[inContact service] serviceID]]; 
    105                 AIAccount               *lastUsedAccount = (lastAccountID ? [[adium accountController] accountWithInternalObjectID:lastAccountID] : nil); 
    106                 AIListContact   *possibleContact = [[adium contactController] existingContactWithService:[lastUsedAccount service] 
    107                                                                                                                                                                            account:lastUsedAccount 
    108                                                                                                                                                                                    UID:[inContact UID]]; 
    109                 if (possibleContact && ![possibleContact isStranger] && 
    110                         ([lastUsedAccount availableForSendingContentType:inType toContact:inContact] || includeOffline)) { 
    111                         return lastUsedAccount; 
    112                 } 
    113  
    114                 //Use the current account if and only if the contact is not a stranger on that account. 
    115                 if ((account = [inContact account]) && 
    116                         ![inContact isStranger] && 
    117                         ([account availableForSendingContentType:inType toContact:inContact] || includeOffline)) { 
    118                         return account; 
    119                 } 
    120110                 
    121                 //Now check compatible accounts, looking for one that knows about the contact 
    122                 NSEnumerator    *enumerator = [[[adium accountController] accountsCompatibleWithService:[inContact service]] objectEnumerator]; 
    123                 while ((account = [enumerator nextObject])) { 
    124                         AIListContact *possibleContact = [[adium contactController] existingContactWithService:[account service] 
    125                                                                                                                                                                                    account:account 
    126                                                                                                                                                                                            UID:[inContact UID]]; 
    127                         if ((possibleContact && ![possibleContact isStranger]) && 
    128                                 ([account availableForSendingContentType:inType toContact:inContact] || includeOffline)) { 
    129                                 //If a contact with this account already exists and isn't a stranger, we've found a good possible choice. 
     111                if ((account = [[adium accountController] accountWithInternalObjectID:accountID])) { 
     112                        if ([account availableForSendingContentType:inType toContact:inContact] || !strictChecking) { 
    130113                                return account; 
    131114                        } 
    132115                } 
    133  
    134                 /* Now, just look for any account which could send to this contact. 
    135                  * We no longer care if the contact is not a stranger, as we exchausted all those possibilities. 
    136                  * 
    137                  * First, check to see if the last account used on this service will work. 
    138                  */ 
    139                 if ([lastUsedAccount availableForSendingContentType:inType toContact:inContact] || includeOffline) { 
    140                         return lastUsedAccount; 
    141                 } 
    142  
    143                 //If inObject is an AIListContact return the account the object is on even if the account is offline 
    144                 if (includeOffline && (account = [inContact account])) { 
     116        } 
     117         
     118        /* We don't have a known previously used account for this contact. */ 
     119         
     120        //Get the last account used to message someone on this service, and check if the contact is on that account 
     121        NSString                *lastAccountID = [lastAccountIDToSendContent objectForKey:[[inContact service] serviceID]]; 
     122        AIAccount               *lastUsedAccount = (lastAccountID ? [[adium accountController] accountWithInternalObjectID:lastAccountID] : nil); 
     123        AIListContact   *possibleContact = [[adium contactController] existingContactWithService:[lastUsedAccount service] 
     124                                                                                                                                                                   account:lastUsedAccount 
     125                                                                                                                                                                           UID:[inContact UID]]; 
     126        if (possibleContact && ![possibleContact isStranger] && 
     127                ([lastUsedAccount availableForSendingContentType:inType toContact:inContact] || !strictChecking)) { 
     128                return lastUsedAccount; 
     129        } 
     130         
     131        //Use the current account if and only if the contact is not a stranger on that account. 
     132        if ((account = [inContact account]) && 
     133                ![inContact isStranger] && 
     134                ([account availableForSendingContentType:inType toContact:inContact] || !strictChecking)) { 
     135                return account; 
     136        } 
     137         
     138        //Now check compatible accounts, looking for one that knows about the contact 
     139        NSEnumerator    *enumerator = [[[adium accountController] accountsCompatibleWithService:[inContact service]] objectEnumerator]; 
     140        while ((account = [enumerator nextObject])) { 
     141                AIListContact *possibleContact = [[adium contactController] existingContactWithService:[account service] 
     142                                                                                                                                                                           account:account 
     143                                                                                                                                                                                   UID:[inContact UID]]; 
     144                if ((possibleContact && ![possibleContact isStranger]) && 
     145                        ([account availableForSendingContentType:inType toContact:inContact] || !strictChecking)) { 
     146                        //If a contact with this account already exists and isn't a stranger, we've found a good possible choice. 
    145147                        return account; 
    146148                } 
    147149        } 
    148  
    149         AILogWithSignature(@"Could not find a good choice to talk to %@; will return first available account", inContact); 
    150  
    151         //If the previous attempts failed, or we weren't passed a contact, use the first appropriate account 
    152         return [self firstAccountAvailableForSendingContentType:inType 
    153                                                                                                   toContact:inContact 
    154                                                                                          includeOffline:includeOffline]; 
    155 
    156  
    157 //XXX - This seems awfully complex for code that is only run the first time we talk to a contact 
    158 //XXX - Why isn't this private? 
    159 - (AIAccount *)firstAccountAvailableForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline 
    160 
    161         AIAccount               *account; 
    162         NSEnumerator    *enumerator; 
    163          
    164     if (inContact) { 
    165                 //First available account in our list of the correct service type 
    166                 enumerator = [[[adium accountController] accounts] objectEnumerator]; 
    167                 while ((account = [enumerator nextObject])) { 
    168                         if ([inContact service] == [account service] && 
    169                                 ([account availableForSendingContentType:inType toContact:inContact] || includeOffline)) { 
    170                                 return account; 
     150         
     151        /* Now, just look for any account which could send to this contact. 
     152         * We no longer care if the contact is not a stranger, as we exchausted all those possibilities. 
     153         * 
     154         * First, check to see if the last account used on this service will work. 
     155         */ 
     156        if ([lastUsedAccount availableForSendingContentType:inType toContact:inContact] || !strictChecking) { 
     157                return lastUsedAccount; 
     158        } 
     159         
     160        //If inObject is an AIListContact return the account the object is on even if the account is offline 
     161        if (!strictChecking && (account = [inContact account])) { 
     162                return account; 
     163        } 
     164 
     165        return nil; 
     166
     167 
     168- (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact  
     169
     170        AIAccount *account; 
     171         
     172        account = [self preferredAccountForSendingContentType:inType toContact:inContact strictChecking:YES]; 
     173        if (!account) { 
     174                AILogWithSignature(@"Could not find an online choice to talk to %@; will include offline accounts", inContact); 
     175                account = [self preferredAccountForSendingContentType:inType toContact:inContact strictChecking:NO]; 
     176         
     177                if (!account) { 
     178                        AILogWithSignature(@"Could not find a good choice to talk to %@; will return first available account", inContact); 
     179                        account = [self fallbackAccountForSendingToContact:inContact strictChecking:YES]; 
     180                 
     181                        if (!account) { 
     182                                account = [self fallbackAccountForSendingToContact:inContact strictChecking:NO]; 
    171183                        } 
    172184                } 
    173                  
    174                 //First available account in our list of a compatible service type 
    175                 enumerator = [[[adium accountController] accounts] objectEnumerator]; 
    176                 while ((account = [enumerator nextObject])) { 
    177                         if ([[inContact serviceClass] isEqualToString:[account serviceClass]] && 
    178                                 ([account availableForSendingContentType:inType toContact:inContact] || includeOffline)) { 
    179                                 return account; 
    180                         } 
    181                 } 
    182         } else { 
    183                 //First available account in our list 
    184                 enumerator = [[[adium accountController] accounts] objectEnumerator]; 
    185                 while ((account = [enumerator nextObject])) { 
    186                         if ([account enabled] &&  
    187                                 ([account availableForSendingContentType:inType toContact:inContact] || includeOffline)) { 
    188                                 return account; 
    189                         } 
    190                 } 
    191         } 
    192          
    193          
    194         //Can't find anything 
    195         return nil; 
     185        } 
     186 
     187        return account; 
    196188} 
    197189 
  • trunk/Source/AIAccountController.m

    r23556 r23929  
    175175        return [adiumPreferredAccounts preferredAccountForSendingContentType:inType toContact:inContact]; 
    176176} 
    177 - (AIAccount *)preferredAccountForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline { 
    178         return [adiumPreferredAccounts preferredAccountForSendingContentType:inType toContact:inContact includeOffline:includeOffline]; 
    179 } 
    180 - (AIAccount *)firstAccountAvailableForSendingContentType:(NSString *)inType toContact:(AIListContact *)inContact includeOffline:(BOOL)includeOffline { 
    181         return [adiumPreferredAccounts firstAccountAvailableForSendingContentType:inType toContact:inContact includeOffline:includeOffline]; 
    182 } 
    183177 
    184178- (void)disconnectAllAccounts 
  • trunk/Source/AIContactController.m

    r23746 r23929  
    17311731                                                                                                                                service:theService]; 
    17321732        AIAccount               *account = [[adium accountController] preferredAccountForSendingContentType:CONTENT_MESSAGE_TYPE 
    1733                                                                                                                                                                  toContact:tempListContact 
    1734                                                                                                                                                         includeOffline:YES]; 
     1733                                                                                                                                                                 toContact:tempListContact]; 
    17351734        [tempListContact release]; 
    1736          
     1735 
    17371736        return [self contactWithService:theService account:account UID:inUID]; 
    17381737}