Use the account proxy for SSL connections for Yahoo. Fixes #13210.
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 <Adium/AIStatusControllerProtocol.h>
19 #import "ESPurpleYahooAccount.h"
20 #import "ESPurpleYahooAccountViewController.h"
21 #import <AdiumLibpurple/SLPurpleCocoaAdapter.h>
22 #import <Adium/AIHTMLDecoder.h>
23 #import <Adium/AIListContact.h>
24 #import <Adium/AIStatus.h>
25 #import <Adium/ESFileTransfer.h>
26 #import <libpurple/libymsg.h>
27 #import <libpurple/yahoo_friend.h>
29 @implementation ESPurpleYahooAccount
31 - (const char*)protocolPlugin
36 - (void)configurePurpleAccount
38 [super configurePurpleAccount];
40 purple_account_set_string(account, "room_list_locale", [[self preferenceForKey:KEY_YAHOO_ROOM_LIST_LOCALE
41 group:GROUP_ACCOUNT_STATUS] UTF8String]);
43 // We only have account proxies; use the account proxy for SSL connections.
44 purple_account_set_bool(account, "proxy_ssl", TRUE);
47 - (NSString *)stringByRemovingYahooSuffix:(NSString *)inString
49 if ((inString && ([inString length] > 0))) {
50 //If inString contains @yahoo., we consider this to be an email address suffix such as @yahoo.com or @yahoo.it, and delete it and everything after it. Thus, jdoe@yahoo.com becomes simply jdoe.
51 //However, we must leave other suffixes, such as sbcglobal.net, alone. We can't simply match @, or we would delete the @sbcglobal.net suffix and leave the user unable to connect with it.
52 NSRange yahooRange = [inString rangeOfString:@"@yahoo."
53 options:NSLiteralSearch];
54 if (yahooRange.location != NSNotFound) {
55 //Future expansion: Only delete if “@yahoo.” is followed by a known TLD and (if appropriate) 2LD, in order to support oddball suffixes such as “@yahoo.example.com”. I don't know whether any such suffixes exist. —boredzo
56 inString = [inString substringToIndex:yahooRange.location];
64 * @brief The UID will be changed. The account has a chance to perform modifications
66 * Remove @yahoo.com from the proposedUID - a common mistake is to include it in the yahoo ID
68 * @param proposedUID The proposed, pre-filtered UID (filtered means it has no characters invalid for this servce)
69 * @result The UID to use; the default implementation just returns proposedUID.
71 - (NSString *)accountWillSetUID:(NSString *)proposedUID
73 return [self stringByRemovingYahooSuffix:proposedUID];
77 * @brief Name to use when creating a PurpleAccount for this CBPurpleAccount
79 - (const char *)purpleAccountName
81 return [[self stringByRemovingYahooSuffix:self.formattedUID] UTF8String];
84 - (NSSet *)supportedPropertyKeys
86 static NSMutableSet *supportedPropertyKeys = nil;
88 if (!supportedPropertyKeys) {
89 supportedPropertyKeys = [[NSMutableSet alloc] initWithObjects:
93 [supportedPropertyKeys unionSet:[super supportedPropertyKeys]];
96 return supportedPropertyKeys;
100 * @brief Should set aliases serverside?
102 * Yahoo supports serverside aliases.
104 - (BOOL)shouldSetAliasesServerside
109 #pragma mark Connection
110 - (NSString *)connectionStringForStep:(int)step
115 return AILocalizedString(@"Connecting",nil);
121 #pragma mark Encoding
122 - (NSString *)encodedAttributedString:(NSAttributedString *)inAttributedString forListObject:(AIListObject *)inListObject
124 return [AIHTMLDecoder encodeHTML:inAttributedString
127 includingColorTags:YES
130 closeStyleTagsOnFontChange:YES
134 attachmentsAsText:YES
135 onlyIncludeOutgoingImages:NO
138 allowJavascriptURLs:YES];
141 #pragma mark File transfer
142 - (BOOL)canSendFolders
147 - (void)beginSendOfFileTransfer:(ESFileTransfer *)fileTransfer
149 [super _beginSendOfFileTransfer:fileTransfer];
153 - (void)acceptFileTransferRequest:(ESFileTransfer *)fileTransfer
155 [super acceptFileTransferRequest:fileTransfer];
158 - (void)rejectFileReceiveRequest:(ESFileTransfer *)fileTransfer
160 [super rejectFileReceiveRequest:fileTransfer];
163 - (void)cancelFileTransfer:(ESFileTransfer *)fileTransfer
165 [super cancelFileTransfer:fileTransfer];
168 #pragma mark Status Messages
171 * @brief Status name to use for a Purple buddy
173 - (NSString *)statusNameForPurpleBuddy:(PurpleBuddy *)buddy
175 NSString *statusName = nil;
176 PurplePresence *presence = purple_buddy_get_presence(buddy);
177 PurpleStatus *status = purple_presence_get_active_status(presence);
178 const char *purpleStatusID = purple_status_get_id(status);
180 if (!purpleStatusID) return nil;
182 if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_BRB)) {
183 statusName = STATUS_NAME_BRB;
185 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_BUSY)) {
186 statusName = STATUS_NAME_BUSY;
188 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTATHOME)) {
189 statusName = STATUS_NAME_NOT_AT_HOME;
191 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTATDESK)) {
192 statusName = STATUS_NAME_NOT_AT_DESK;
194 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTINOFFICE)) {
195 statusName = STATUS_NAME_NOT_IN_OFFICE;
197 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_ONPHONE)) {
198 statusName = STATUS_NAME_PHONE;
200 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_ONVACATION)) {
201 statusName = STATUS_NAME_VACATION;
203 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_OUTTOLUNCH)) {
204 statusName = STATUS_NAME_LUNCH;
206 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_STEPPEDOUT)) {
207 statusName = STATUS_NAME_STEPPED_OUT;
209 } else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_INVISIBLE)) {
210 statusName = STATUS_NAME_INVISIBLE;
217 * @brief Update the status message and away state of the contact
219 - (void)updateStatusForContact:(AIListContact *)theContact toStatusType:(NSNumber *)statusTypeNumber statusName:(NSString *)statusName statusMessage:(NSAttributedString *)statusMessage isMobile:(BOOL)isMobile
221 NSString *statusMessageString = [statusMessage string];
222 char *normalized = g_strdup(purple_normalize(account, [theContact.UID UTF8String]));
226 /* Grab the idle time while we have a chance */
227 if ((purple_account_is_connected(account)) &&
228 (od = purple_account_get_connection(account)->proto_data) &&
229 (f = g_hash_table_lookup(od->friends, normalized))) {
231 if (f->status == YAHOO_STATUS_IDLE) {
237 idleSince = [NSDate dateWithTimeIntervalSinceNow:-idle];
239 idleSince = [NSDate date];
242 [theContact setValue:idleSince
243 forProperty:@"IdleSince"
246 } else if (f->status == YAHOO_STATUS_INVISIBLE) {
247 statusTypeNumber = [NSNumber numberWithInt:AIInvisibleStatusType]; /* Invisible has a special status type */
253 //Yahoo doesn't have an explicit mobile state; instead the status message is automatically set to indicate mobility.
254 if (statusMessageString && ([statusMessageString isEqualToString:@"I'm on SMS"] ||
255 ([statusMessageString rangeOfString:@"I'm mobile"].location != NSNotFound))) {
256 [theContact setIsMobile:YES notify:NotifyLater];
258 } else if (theContact.isMobile) {
259 [theContact setIsMobile:NO notify:NotifyLater];
262 [super updateStatusForContact:theContact
263 toStatusType:statusTypeNumber
264 statusName:statusName
265 statusMessage:statusMessage
270 * @brief Return the purple status ID to be used for a status
272 * Most subclasses should override this method; these generic values may be appropriate for others.
274 * Active services provided nonlocalized status names. An AIStatus is passed to this method along with a pointer
275 * to the status message. This method should handle any status whose statusNname this service set as well as any statusName
276 * defined in AIStatusController.h (which will correspond to the services handled by Adium by default).
277 * It should also handle a status name not specified in either of these places with a sane default, most likely by loooking at
278 * statusState.statusType for a general idea of the status's type.
280 * @param statusState The status for which to find the purple status ID
281 * @param arguments Prpl-specific arguments which will be passed with the state. Message is handled automatically.
283 * @result The purple status ID
285 - (const char *)purpleStatusIDForStatus:(AIStatus *)statusState
286 arguments:(NSMutableDictionary *)arguments
288 const char *statusID = NULL;
289 NSString *statusName = statusState.statusName;
290 NSString *statusMessageString = [statusState statusMessageString];
292 if (!statusMessageString) statusMessageString = @"";
294 switch (statusState.statusType) {
295 case AIAvailableStatusType:
296 statusID = YAHOO_STATUS_TYPE_AVAILABLE;
299 case AIAwayStatusType:
301 if (([statusName isEqualToString:STATUS_NAME_BRB]) ||
302 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BRB]] == NSOrderedSame))
303 statusID = YAHOO_STATUS_TYPE_BRB;
305 else if (([statusName isEqualToString:STATUS_NAME_BUSY]) ||
306 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BUSY]] == NSOrderedSame))
307 statusID = YAHOO_STATUS_TYPE_BUSY;
309 else if (([statusName isEqualToString:STATUS_NAME_NOT_AT_HOME]) ||
310 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_NOT_AT_HOME]] == NSOrderedSame))
311 statusID = YAHOO_STATUS_TYPE_NOTATHOME;
313 else if (([statusName isEqualToString:STATUS_NAME_NOT_AT_DESK]) ||
314 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_NOT_AT_DESK]] == NSOrderedSame))
315 statusID = YAHOO_STATUS_TYPE_NOTATDESK;
317 else if (([statusName isEqualToString:STATUS_NAME_PHONE]) ||
318 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_PHONE]] == NSOrderedSame))
319 statusID = YAHOO_STATUS_TYPE_ONPHONE;
321 else if (([statusName isEqualToString:STATUS_NAME_VACATION]) ||
322 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_VACATION]] == NSOrderedSame))
323 statusID = YAHOO_STATUS_TYPE_ONVACATION;
325 else if (([statusName isEqualToString:STATUS_NAME_LUNCH]) ||
326 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_LUNCH]] == NSOrderedSame))
327 statusID = YAHOO_STATUS_TYPE_OUTTOLUNCH;
329 else if (([statusName isEqualToString:STATUS_NAME_STEPPED_OUT]) ||
330 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_STEPPED_OUT]] == NSOrderedSame))
331 statusID = YAHOO_STATUS_TYPE_STEPPEDOUT;
337 case AIInvisibleStatusType:
338 statusID = YAHOO_STATUS_TYPE_INVISIBLE;
341 case AIOfflineStatusType:
345 //If we didn't get a purple status ID, request one from super
346 if (statusID == NULL) statusID = [super purpleStatusIDForStatus:statusState arguments:arguments];
351 - (BOOL)shouldAddMusicalNoteToNowPlayingStatus
356 #pragma mark Contact List Menu Items
357 - (NSString *)titleForContactMenuLabel:(const char *)label forContact:(AIListContact *)inContact
359 if (!strcmp(label, _("Add Buddy"))) {
360 //We handle Add Buddy ourselves
363 } else if (!strcmp(label, _("Join in Chat"))) {
364 return [NSString stringWithFormat:AILocalizedString(@"Join %@'s Chat",nil),inContact.formattedUID];
366 } else if (!strcmp(label, _("Initiate Conference"))) {
367 return [NSString stringWithFormat:AILocalizedString(@"Initiate Conference with %@",nil), inContact.formattedUID];
369 } else if (!strcmp(label, _("Presence Settings"))) {
370 return [NSString stringWithFormat:AILocalizedString(@"Presence Settings for %@",nil), inContact.formattedUID];
372 } else if (!strcmp(label, _("Appear Online"))) {
373 return [NSString stringWithFormat:AILocalizedString(@"Appear Online to %@",nil), inContact.formattedUID];
375 } else if (!strcmp(label, _("Appear Offline"))) {
376 return [NSString stringWithFormat:AILocalizedString(@"Appear Offline to %@",nil), inContact.formattedUID];
378 } else if (!strcmp(label, _("Appear Permanently Offline"))) {
379 return [NSString stringWithFormat:AILocalizedString(@"Always Appear Offline to %@",nil), inContact.formattedUID];
381 } else if (!strcmp(label, _("Don't Appear Permanently Offline"))) {
382 return [NSString stringWithFormat:AILocalizedString(@"Don't Always Appear Offline to %@",nil), inContact.formattedUID];
384 } else if (!strcmp(label, _("View Webcam"))) {
385 //return [NSString stringWithFormat:AILocalizedString(@"View %@'s Webcam",nil), inContact.formattedUID];
388 } else if (!strcmp(label, _("Start Doodling"))) {
392 return [super titleForContactMenuLabel:label forContact:inContact];
395 #pragma mark Account Action Menu Items
396 - (NSString *)titleForAccountActionMenuLabel:(const char *)label
398 /* The Yahoo actions are "Activate ID" (or perhaps "Active ID," depending on where in the code you look)
399 * and "Join User in Chat...". These are dumb. Additionally, Join User in Chat doesn't work as of purple 1.1.4. */