Plugins/Purple Service/ESPurpleYahooAccount.m
author Zachary West <zacw@adium.im>
Fri Nov 27 13:16:32 2009 -0500 (2009-11-27)
changeset 2833 fbb560e54233
parent 2570 634e2660696b
permissions -rw-r--r--
Use the account proxy for SSL connections for Yahoo. Fixes #13210.
David@0
     1
/* 
David@0
     2
 * Adium is the legal property of its developers, whose names are listed in the copyright file included
David@0
     3
 * with this source distribution.
David@0
     4
 * 
David@0
     5
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
David@0
     6
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
David@0
     7
 * or (at your option) any later version.
David@0
     8
 * 
David@0
     9
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
David@0
    10
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
David@0
    11
 * Public License for more details.
David@0
    12
 * 
David@0
    13
 * You should have received a copy of the GNU General Public License along with this program; if not,
David@0
    14
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
David@0
    15
 */
David@0
    16
David@0
    17
#import <Adium/AIAccountControllerProtocol.h>
David@0
    18
#import <Adium/AIStatusControllerProtocol.h>
David@0
    19
#import "ESPurpleYahooAccount.h"
David@0
    20
#import "ESPurpleYahooAccountViewController.h"
David@0
    21
#import <AdiumLibpurple/SLPurpleCocoaAdapter.h>
David@0
    22
#import <Adium/AIHTMLDecoder.h>
David@0
    23
#import <Adium/AIListContact.h>
David@0
    24
#import <Adium/AIStatus.h>
David@0
    25
#import <Adium/ESFileTransfer.h>
zacw@2535
    26
#import <libpurple/libymsg.h>
David@0
    27
#import <libpurple/yahoo_friend.h>
David@0
    28
David@0
    29
@implementation ESPurpleYahooAccount
David@0
    30
David@0
    31
- (const char*)protocolPlugin
David@0
    32
{
David@0
    33
    return "prpl-yahoo";
David@0
    34
}
David@0
    35
David@0
    36
- (void)configurePurpleAccount
David@0
    37
{
David@0
    38
	[super configurePurpleAccount];
David@0
    39
David@0
    40
	purple_account_set_string(account, "room_list_locale", [[self preferenceForKey:KEY_YAHOO_ROOM_LIST_LOCALE
David@0
    41
																		   group:GROUP_ACCOUNT_STATUS] UTF8String]);
zacw@2833
    42
	
zacw@2833
    43
	// We only have account proxies; use the account proxy for SSL connections.
zacw@2833
    44
	purple_account_set_bool(account, "proxy_ssl", TRUE);
David@0
    45
}
David@0
    46
David@0
    47
- (NSString *)stringByRemovingYahooSuffix:(NSString *)inString
David@0
    48
{
David@0
    49
	if ((inString && ([inString length] > 0))) {
David@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.
David@0
    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.
David@0
    52
		NSRange yahooRange = [inString rangeOfString:@"@yahoo." 
David@0
    53
		                                     options:NSLiteralSearch];
David@0
    54
		if (yahooRange.location != NSNotFound) {
David@0
    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
David@0
    56
			inString = [inString substringToIndex:yahooRange.location];
David@0
    57
		}
David@0
    58
	}
David@0
    59
	
David@0
    60
	return inString;
David@0
    61
}
David@0
    62
David@0
    63
/*!
David@0
    64
* @brief The UID will be changed. The account has a chance to perform modifications
David@0
    65
 *
David@0
    66
 * Remove @yahoo.com from the proposedUID - a common mistake is to include it in the yahoo ID
David@0
    67
 *
David@0
    68
 * @param proposedUID The proposed, pre-filtered UID (filtered means it has no characters invalid for this servce)
David@0
    69
 * @result The UID to use; the default implementation just returns proposedUID.
David@0
    70
 */
David@0
    71
- (NSString *)accountWillSetUID:(NSString *)proposedUID
David@0
    72
{
David@0
    73
	return [self stringByRemovingYahooSuffix:proposedUID];
David@0
    74
}
David@0
    75
David@0
    76
/*!
David@0
    77
 * @brief Name to use when creating a PurpleAccount for this CBPurpleAccount
David@0
    78
 */
David@0
    79
- (const char *)purpleAccountName
David@0
    80
{
David@427
    81
	return [[self stringByRemovingYahooSuffix:self.formattedUID] UTF8String];
David@0
    82
}
David@0
    83
David@0
    84
- (NSSet *)supportedPropertyKeys
David@0
    85
{
David@0
    86
	static NSMutableSet *supportedPropertyKeys = nil;
David@0
    87
	
David@0
    88
	if (!supportedPropertyKeys) {
David@0
    89
		supportedPropertyKeys = [[NSMutableSet alloc] initWithObjects:
David@0
    90
			@"AvailableMessage",
David@0
    91
			@"Invisible",
David@0
    92
			nil];
David@0
    93
		[supportedPropertyKeys unionSet:[super supportedPropertyKeys]];
David@0
    94
	}
David@0
    95
	
David@0
    96
	return supportedPropertyKeys;
David@0
    97
}
David@0
    98
David@0
    99
/*!
David@0
   100
 * @brief Should set aliases serverside?
David@0
   101
 *
David@0
   102
 * Yahoo supports serverside aliases.
David@0
   103
 */
David@0
   104
- (BOOL)shouldSetAliasesServerside
David@0
   105
{
David@0
   106
	return YES;
David@0
   107
}
David@0
   108
David@0
   109
#pragma mark Connection
David@0
   110
- (NSString *)connectionStringForStep:(int)step
David@0
   111
{
David@0
   112
	switch (step)
David@0
   113
	{
David@0
   114
		case 0:
David@0
   115
			return AILocalizedString(@"Connecting",nil);
David@0
   116
			break;
David@0
   117
	}
David@0
   118
	return nil;
David@0
   119
}
David@0
   120
David@0
   121
#pragma mark Encoding
David@0
   122
- (NSString *)encodedAttributedString:(NSAttributedString *)inAttributedString forListObject:(AIListObject *)inListObject
David@0
   123
{	
David@0
   124
	return [AIHTMLDecoder encodeHTML:inAttributedString
David@0
   125
							 headers:NO
David@0
   126
							fontTags:YES
David@0
   127
				  includingColorTags:YES
David@0
   128
					   closeFontTags:YES
David@0
   129
						   styleTags:YES
David@0
   130
		  closeStyleTagsOnFontChange:YES
David@0
   131
					  encodeNonASCII:NO
David@0
   132
						encodeSpaces:NO
David@0
   133
						  imagesPath:nil
David@0
   134
				   attachmentsAsText:YES
David@0
   135
		   onlyIncludeOutgoingImages:NO
David@0
   136
					  simpleTagsOnly:YES
David@0
   137
					  bodyBackground:NO
David@0
   138
				 allowJavascriptURLs:YES];
David@0
   139
}
David@0
   140
David@0
   141
#pragma mark File transfer
David@0
   142
- (BOOL)canSendFolders
David@0
   143
{
David@0
   144
	return NO;
David@0
   145
}
David@0
   146
David@0
   147
- (void)beginSendOfFileTransfer:(ESFileTransfer *)fileTransfer
David@0
   148
{
David@0
   149
	[super _beginSendOfFileTransfer:fileTransfer];
David@0
   150
}
David@0
   151
David@0
   152
David@0
   153
- (void)acceptFileTransferRequest:(ESFileTransfer *)fileTransfer
David@0
   154
{
David@0
   155
    [super acceptFileTransferRequest:fileTransfer];    
David@0
   156
}
David@0
   157
David@0
   158
- (void)rejectFileReceiveRequest:(ESFileTransfer *)fileTransfer
David@0
   159
{
David@0
   160
    [super rejectFileReceiveRequest:fileTransfer];    
David@0
   161
}
David@0
   162
David@0
   163
- (void)cancelFileTransfer:(ESFileTransfer *)fileTransfer
David@0
   164
{
David@0
   165
	[super cancelFileTransfer:fileTransfer];
David@0
   166
}
David@0
   167
David@0
   168
#pragma mark Status Messages
David@0
   169
David@0
   170
/*!
David@0
   171
 * @brief Status name to use for a Purple buddy
David@0
   172
 */
David@0
   173
- (NSString *)statusNameForPurpleBuddy:(PurpleBuddy *)buddy
David@0
   174
{
David@0
   175
	NSString		*statusName = nil;
David@0
   176
	PurplePresence	*presence = purple_buddy_get_presence(buddy);
David@0
   177
	PurpleStatus		*status = purple_presence_get_active_status(presence);
David@0
   178
	const char		*purpleStatusID = purple_status_get_id(status);
David@0
   179
	
David@0
   180
	if (!purpleStatusID) return nil;
David@0
   181
	
David@0
   182
	if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_BRB)) {
David@0
   183
		statusName = STATUS_NAME_BRB;
David@0
   184
		
David@0
   185
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_BUSY)) {
David@0
   186
		statusName = STATUS_NAME_BUSY;
David@0
   187
		
David@0
   188
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTATHOME)) {
David@0
   189
		statusName = STATUS_NAME_NOT_AT_HOME;
David@0
   190
		
David@0
   191
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTATDESK)) {
David@0
   192
		statusName = STATUS_NAME_NOT_AT_DESK;
David@0
   193
		
David@0
   194
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTINOFFICE)) {
David@0
   195
		statusName = STATUS_NAME_NOT_IN_OFFICE;
David@0
   196
		
David@0
   197
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_ONPHONE)) {
David@0
   198
		statusName = STATUS_NAME_PHONE;
David@0
   199
		
David@0
   200
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_ONVACATION)) {
David@0
   201
		statusName = STATUS_NAME_VACATION;
David@0
   202
		
David@0
   203
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_OUTTOLUNCH)) {
David@0
   204
		statusName = STATUS_NAME_LUNCH;
David@0
   205
		
David@0
   206
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_STEPPEDOUT)) {
David@0
   207
		statusName = STATUS_NAME_STEPPED_OUT;
David@0
   208
		
David@0
   209
	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_INVISIBLE)) {
David@0
   210
		statusName = STATUS_NAME_INVISIBLE;
David@0
   211
	}
David@0
   212
	
David@0
   213
	return statusName;
David@0
   214
}
David@0
   215
David@0
   216
/*!
David@0
   217
 * @brief Update the status message and away state of the contact
David@0
   218
 */
Evan@153
   219
- (void)updateStatusForContact:(AIListContact *)theContact toStatusType:(NSNumber *)statusTypeNumber statusName:(NSString *)statusName statusMessage:(NSAttributedString *)statusMessage isMobile:(BOOL)isMobile
David@0
   220
{
Evan@2570
   221
	NSString	*statusMessageString = [statusMessage string];
Evan@2570
   222
	char		*normalized = g_strdup(purple_normalize(account, [theContact.UID UTF8String]));
Evan@2570
   223
	YahooData	*od;
Evan@2570
   224
	YahooFriend	*f;
David@0
   225
David@0
   226
	/* Grab the idle time while we have a chance */
David@0
   227
	if ((purple_account_is_connected(account)) &&
David@0
   228
		(od = purple_account_get_connection(account)->proto_data) &&
David@0
   229
		(f = g_hash_table_lookup(od->friends, normalized))) {
David@0
   230
David@0
   231
		if (f->status == YAHOO_STATUS_IDLE) {
David@0
   232
			//Now idle
David@0
   233
			int		idle = f->idle;
David@0
   234
			NSDate	*idleSince;
David@0
   235
			
David@0
   236
			if (idle != -1) {
David@0
   237
				idleSince = [NSDate dateWithTimeIntervalSinceNow:-idle];
David@0
   238
			} else {
David@0
   239
				idleSince = [NSDate date];
David@0
   240
			}
David@0
   241
			
David@0
   242
			[theContact setValue:idleSince
David@0
   243
								 forProperty:@"IdleSince"
David@0
   244
								 notify:NotifyLater];
David@0
   245
			
David@0
   246
		} else if (f->status == YAHOO_STATUS_INVISIBLE) {
David@0
   247
			statusTypeNumber = [NSNumber numberWithInt:AIInvisibleStatusType]; /* Invisible has a special status type */
David@0
   248
		}
David@0
   249
	}
David@0
   250
David@0
   251
	g_free(normalized);
David@0
   252
	
David@0
   253
	//Yahoo doesn't have an explicit mobile state; instead the status message is automatically set to indicate mobility.
David@0
   254
	if (statusMessageString && ([statusMessageString isEqualToString:@"I'm on SMS"] ||
David@0
   255
								([statusMessageString rangeOfString:@"I'm mobile"].location != NSNotFound))) {
David@0
   256
		[theContact setIsMobile:YES notify:NotifyLater];
David@0
   257
David@838
   258
	} else if (theContact.isMobile) {
David@0
   259
		[theContact setIsMobile:NO notify:NotifyLater];		
David@0
   260
	}
David@0
   261
	
David@0
   262
	[super updateStatusForContact:theContact
David@0
   263
					 toStatusType:statusTypeNumber
David@0
   264
					   statusName:statusName
Evan@153
   265
					statusMessage:statusMessage
Evan@153
   266
						 isMobile:isMobile];
David@0
   267
}
David@0
   268
David@0
   269
/*!
David@0
   270
 * @brief Return the purple status ID to be used for a status
David@0
   271
 *
David@0
   272
 * Most subclasses should override this method; these generic values may be appropriate for others.
David@0
   273
 *
David@0
   274
 * Active services provided nonlocalized status names.  An AIStatus is passed to this method along with a pointer
David@0
   275
 * to the status message.  This method should handle any status whose statusNname this service set as well as any statusName
David@0
   276
 * defined in  AIStatusController.h (which will correspond to the services handled by Adium by default).
David@0
   277
 * It should also handle a status name not specified in either of these places with a sane default, most likely by loooking at
David@837
   278
 * statusState.statusType for a general idea of the status's type.
David@0
   279
 *
David@0
   280
 * @param statusState The status for which to find the purple status ID
David@0
   281
 * @param arguments Prpl-specific arguments which will be passed with the state. Message is handled automatically.
David@0
   282
 *
David@0
   283
 * @result The purple status ID
David@0
   284
 */
David@0
   285
- (const char *)purpleStatusIDForStatus:(AIStatus *)statusState
David@0
   286
							arguments:(NSMutableDictionary *)arguments
David@0
   287
{
David@0
   288
	const char		*statusID = NULL;
David@837
   289
	NSString		*statusName = statusState.statusName;
David@0
   290
	NSString		*statusMessageString = [statusState statusMessageString];
David@0
   291
David@0
   292
	if (!statusMessageString) statusMessageString = @"";
David@0
   293
David@837
   294
	switch (statusState.statusType) {
David@0
   295
		case AIAvailableStatusType:
David@0
   296
			statusID = YAHOO_STATUS_TYPE_AVAILABLE;
David@0
   297
			break;
David@0
   298
David@0
   299
		case AIAwayStatusType:
David@0
   300
		{
David@0
   301
			if (([statusName isEqualToString:STATUS_NAME_BRB]) ||
David@100
   302
				([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BRB]] == NSOrderedSame))
David@0
   303
				statusID = YAHOO_STATUS_TYPE_BRB;
David@0
   304
David@0
   305
			else if (([statusName isEqualToString:STATUS_NAME_BUSY]) ||
David@100
   306
					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BUSY]] == NSOrderedSame))
David@0
   307
				statusID = YAHOO_STATUS_TYPE_BUSY;
David@0
   308
David@0
   309
			else if (([statusName isEqualToString:STATUS_NAME_NOT_AT_HOME]) ||
David@100
   310
					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_NOT_AT_HOME]] == NSOrderedSame))
David@0
   311
				statusID = YAHOO_STATUS_TYPE_NOTATHOME;
David@0
   312
David@0
   313
			else if (([statusName isEqualToString:STATUS_NAME_NOT_AT_DESK]) ||
David@100
   314
				([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_NOT_AT_DESK]] == NSOrderedSame))
David@0
   315
				statusID = YAHOO_STATUS_TYPE_NOTATDESK;
David@0
   316
			
David@0
   317
			else if (([statusName isEqualToString:STATUS_NAME_PHONE]) ||
David@100
   318
					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_PHONE]] == NSOrderedSame))
David@0
   319
				statusID = YAHOO_STATUS_TYPE_ONPHONE;
David@0
   320
			
David@0
   321
			else if (([statusName isEqualToString:STATUS_NAME_VACATION]) ||
David@100
   322
					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_VACATION]] == NSOrderedSame))
David@0
   323
				statusID = YAHOO_STATUS_TYPE_ONVACATION;
David@0
   324
			
David@0
   325
			else if (([statusName isEqualToString:STATUS_NAME_LUNCH]) ||
David@100
   326
					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_LUNCH]] == NSOrderedSame))
David@0
   327
				statusID = YAHOO_STATUS_TYPE_OUTTOLUNCH;
David@0
   328
			
David@0
   329
			else if (([statusName isEqualToString:STATUS_NAME_STEPPED_OUT]) ||
David@100
   330
					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_STEPPED_OUT]] == NSOrderedSame))
David@0
   331
				statusID = YAHOO_STATUS_TYPE_STEPPEDOUT;
David@0
   332
			
David@0
   333
			
David@0
   334
			break;
David@0
   335
		}
David@0
   336
			
David@0
   337
		case AIInvisibleStatusType:
David@0
   338
			statusID = YAHOO_STATUS_TYPE_INVISIBLE;
David@0
   339
			break;
David@0
   340
		
David@0
   341
		case AIOfflineStatusType:
David@0
   342
			break;
David@0
   343
	}
David@0
   344
	
David@0
   345
	//If we didn't get a purple status ID, request one from super
David@0
   346
	if (statusID == NULL) statusID = [super purpleStatusIDForStatus:statusState arguments:arguments];
David@0
   347
	
David@0
   348
	return statusID;
David@0
   349
}
David@0
   350
David@0
   351
- (BOOL)shouldAddMusicalNoteToNowPlayingStatus
David@0
   352
{
David@0
   353
	return NO;
David@0
   354
}
David@0
   355
David@0
   356
#pragma mark Contact List Menu Items
David@0
   357
- (NSString *)titleForContactMenuLabel:(const char *)label forContact:(AIListContact *)inContact
David@0
   358
{
David@0
   359
	if (!strcmp(label, _("Add Buddy"))) {
David@0
   360
		//We handle Add Buddy ourselves
David@0
   361
		return nil;
David@0
   362
		
David@0
   363
	} else if (!strcmp(label, _("Join in Chat"))) {
David@837
   364
		return [NSString stringWithFormat:AILocalizedString(@"Join %@'s Chat",nil),inContact.formattedUID];
David@0
   365
David@0
   366
	} else if (!strcmp(label, _("Initiate Conference"))) {
David@837
   367
		return [NSString stringWithFormat:AILocalizedString(@"Initiate Conference with %@",nil), inContact.formattedUID];
David@0
   368
David@0
   369
	} else if (!strcmp(label, _("Presence Settings"))) {
David@837
   370
		return [NSString stringWithFormat:AILocalizedString(@"Presence Settings for %@",nil), inContact.formattedUID];
David@0
   371
David@0
   372
	} else if (!strcmp(label, _("Appear Online"))) {
David@837
   373
		return [NSString stringWithFormat:AILocalizedString(@"Appear Online to %@",nil), inContact.formattedUID];
David@0
   374
		
David@0
   375
	} else if (!strcmp(label, _("Appear Offline"))) {
David@837
   376
		return [NSString stringWithFormat:AILocalizedString(@"Appear Offline to %@",nil), inContact.formattedUID];
David@0
   377
		
David@0
   378
	} else if (!strcmp(label, _("Appear Permanently Offline"))) {
David@837
   379
		return [NSString stringWithFormat:AILocalizedString(@"Always Appear Offline to %@",nil), inContact.formattedUID];
David@0
   380
		
David@0
   381
	} else if (!strcmp(label, _("Don't Appear Permanently Offline"))) {
David@837
   382
		return [NSString stringWithFormat:AILocalizedString(@"Don't Always Appear Offline to %@",nil), inContact.formattedUID];
David@0
   383
		
David@0
   384
	} else if (!strcmp(label, _("View Webcam"))) {
David@837
   385
		//return [NSString stringWithFormat:AILocalizedString(@"View %@'s Webcam",nil), inContact.formattedUID];		
David@0
   386
		return nil;
David@0
   387
David@0
   388
	} else if (!strcmp(label, _("Start Doodling"))) {
David@0
   389
		return nil;
David@0
   390
	}
David@0
   391
David@0
   392
	return [super titleForContactMenuLabel:label forContact:inContact];
David@0
   393
}
David@0
   394
David@0
   395
#pragma mark Account Action Menu Items
David@0
   396
- (NSString *)titleForAccountActionMenuLabel:(const char *)label
David@0
   397
{
David@0
   398
	/* The Yahoo actions are "Activate ID" (or perhaps "Active ID," depending on where in the code you look)
David@0
   399
	 * and "Join User in Chat...".  These are dumb. Additionally, Join User in Chat doesn't work as of purple 1.1.4. */
David@0
   400
	return nil;
David@0
   401
}
David@0
   402
David@0
   403
@end