Plugins/Purple Service/ESPurpleYahooAccount.m
branchadium-1.5.10.3
changeset 5957 81732180bddf
parent 5956 297f01718b75
child 5958 0a0f0222bdd4
equal deleted inserted replaced
5956:297f01718b75 5957:81732180bddf
     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  */
       
    16 
       
    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>
       
    28 
       
    29 @implementation ESPurpleYahooAccount
       
    30 
       
    31 - (const char*)protocolPlugin
       
    32 {
       
    33     return "prpl-yahoo";
       
    34 }
       
    35 
       
    36 - (void)configurePurpleAccount
       
    37 {
       
    38 	[super configurePurpleAccount];
       
    39 
       
    40 	purple_account_set_string(account, "room_list_locale", [[self preferenceForKey:KEY_YAHOO_ROOM_LIST_LOCALE
       
    41 																		   group:GROUP_ACCOUNT_STATUS] UTF8String]);
       
    42 	
       
    43 	// We only have account proxies; use the account proxy for SSL connections.
       
    44 	purple_account_set_bool(account, "proxy_ssl", TRUE);
       
    45 }
       
    46 
       
    47 - (NSString *)stringByRemovingYahooSuffix:(NSString *)inString
       
    48 {
       
    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];
       
    57 		}
       
    58 	}
       
    59 	
       
    60 	return inString;
       
    61 }
       
    62 
       
    63 /*!
       
    64 * @brief The UID will be changed. The account has a chance to perform modifications
       
    65  *
       
    66  * Remove @yahoo.com from the proposedUID - a common mistake is to include it in the yahoo ID
       
    67  *
       
    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.
       
    70  */
       
    71 - (NSString *)accountWillSetUID:(NSString *)proposedUID
       
    72 {
       
    73 	return [self stringByRemovingYahooSuffix:proposedUID];
       
    74 }
       
    75 
       
    76 /*!
       
    77  * @brief Name to use when creating a PurpleAccount for this CBPurpleAccount
       
    78  */
       
    79 - (const char *)purpleAccountName
       
    80 {
       
    81 	return [[self stringByRemovingYahooSuffix:self.formattedUID] UTF8String];
       
    82 }
       
    83 
       
    84 - (NSSet *)supportedPropertyKeys
       
    85 {
       
    86 	static NSMutableSet *supportedPropertyKeys = nil;
       
    87 	
       
    88 	if (!supportedPropertyKeys) {
       
    89 		supportedPropertyKeys = [[NSMutableSet alloc] initWithObjects:
       
    90 			@"AvailableMessage",
       
    91 			@"Invisible",
       
    92 			nil];
       
    93 		[supportedPropertyKeys unionSet:[super supportedPropertyKeys]];
       
    94 	}
       
    95 	
       
    96 	return supportedPropertyKeys;
       
    97 }
       
    98 
       
    99 /*!
       
   100  * @brief Should set aliases serverside?
       
   101  *
       
   102  * Yahoo supports serverside aliases.
       
   103  */
       
   104 - (BOOL)shouldSetAliasesServerside
       
   105 {
       
   106 	return YES;
       
   107 }
       
   108 
       
   109 #pragma mark Connection
       
   110 - (NSString *)connectionStringForStep:(NSInteger)step
       
   111 {
       
   112 	switch (step)
       
   113 	{
       
   114 		case 0:
       
   115 			return AILocalizedString(@"Connecting",nil);
       
   116 			break;
       
   117 	}
       
   118 	return nil;
       
   119 }
       
   120 
       
   121 #pragma mark Encoding
       
   122 - (NSString *)encodedAttributedString:(NSAttributedString *)inAttributedString forListObject:(AIListObject *)inListObject
       
   123 {	
       
   124 	return [AIHTMLDecoder encodeHTML:inAttributedString
       
   125 							 headers:NO
       
   126 							fontTags:YES
       
   127 				  includingColorTags:YES
       
   128 					   closeFontTags:YES
       
   129 						   styleTags:YES
       
   130 		  closeStyleTagsOnFontChange:YES
       
   131 					  encodeNonASCII:NO
       
   132 						encodeSpaces:NO
       
   133 						  imagesPath:nil
       
   134 				   attachmentsAsText:YES
       
   135 		   onlyIncludeOutgoingImages:NO
       
   136 					  simpleTagsOnly:YES
       
   137 					  bodyBackground:NO
       
   138 				 allowJavascriptURLs:YES];
       
   139 }
       
   140 
       
   141 #pragma mark File transfer
       
   142 - (BOOL)canSendFolders
       
   143 {
       
   144 	return NO;
       
   145 }
       
   146 
       
   147 - (void)beginSendOfFileTransfer:(ESFileTransfer *)fileTransfer
       
   148 {
       
   149 	[super _beginSendOfFileTransfer:fileTransfer];
       
   150 }
       
   151 
       
   152 
       
   153 - (void)acceptFileTransferRequest:(ESFileTransfer *)fileTransfer
       
   154 {
       
   155     [super acceptFileTransferRequest:fileTransfer];    
       
   156 }
       
   157 
       
   158 - (void)rejectFileReceiveRequest:(ESFileTransfer *)fileTransfer
       
   159 {
       
   160     [super rejectFileReceiveRequest:fileTransfer];    
       
   161 }
       
   162 
       
   163 - (void)cancelFileTransfer:(ESFileTransfer *)fileTransfer
       
   164 {
       
   165 	[super cancelFileTransfer:fileTransfer];
       
   166 }
       
   167 
       
   168 #pragma mark Status Messages
       
   169 
       
   170 /*!
       
   171  * @brief Status name to use for a Purple buddy
       
   172  */
       
   173 - (NSString *)statusNameForPurpleBuddy:(PurpleBuddy *)buddy
       
   174 {
       
   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);
       
   179 	
       
   180 	if (!purpleStatusID) return nil;
       
   181 	
       
   182 	if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_BRB)) {
       
   183 		statusName = STATUS_NAME_BRB;
       
   184 		
       
   185 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_BUSY)) {
       
   186 		statusName = STATUS_NAME_BUSY;
       
   187 		
       
   188 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTATHOME)) {
       
   189 		statusName = STATUS_NAME_NOT_AT_HOME;
       
   190 		
       
   191 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTATDESK)) {
       
   192 		statusName = STATUS_NAME_NOT_AT_DESK;
       
   193 		
       
   194 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_NOTINOFFICE)) {
       
   195 		statusName = STATUS_NAME_NOT_IN_OFFICE;
       
   196 		
       
   197 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_ONPHONE)) {
       
   198 		statusName = STATUS_NAME_PHONE;
       
   199 		
       
   200 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_ONVACATION)) {
       
   201 		statusName = STATUS_NAME_VACATION;
       
   202 		
       
   203 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_OUTTOLUNCH)) {
       
   204 		statusName = STATUS_NAME_LUNCH;
       
   205 		
       
   206 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_STEPPEDOUT)) {
       
   207 		statusName = STATUS_NAME_STEPPED_OUT;
       
   208 		
       
   209 	} else if (!strcmp(purpleStatusID, YAHOO_STATUS_TYPE_INVISIBLE)) {
       
   210 		statusName = STATUS_NAME_INVISIBLE;
       
   211 	}
       
   212 	
       
   213 	return statusName;
       
   214 }
       
   215 
       
   216 /*!
       
   217  * @brief Update the status message and away state of the contact
       
   218  */
       
   219 - (void)updateStatusForContact:(AIListContact *)theContact toStatusType:(NSNumber *)statusTypeNumber statusName:(NSString *)statusName statusMessage:(NSAttributedString *)inStatusMessage isMobile:(BOOL)isMobile
       
   220 {
       
   221 	NSString	*statusMessageString = [inStatusMessage string];
       
   222 	char		*normalized = g_strdup(purple_normalize(account, [theContact.UID UTF8String]));
       
   223 	YahooData	*od;
       
   224 	YahooFriend	*f;
       
   225 
       
   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))) {
       
   230 
       
   231 		if (f->status == YAHOO_STATUS_IDLE) {
       
   232 			//Now idle
       
   233 			NSInteger		idle = f->idle;
       
   234 			NSDate	*idleSince;
       
   235 			
       
   236 			if (idle != -1) {
       
   237 				idleSince = [NSDate dateWithTimeIntervalSinceNow:-idle];
       
   238 			} else {
       
   239 				idleSince = [NSDate date];
       
   240 			}
       
   241 			
       
   242 			[theContact setValue:idleSince
       
   243 								 forProperty:@"idleSince"
       
   244 								 notify:NotifyLater];
       
   245 			
       
   246 		} else if (f->status == YAHOO_STATUS_INVISIBLE) {
       
   247 			statusTypeNumber = [NSNumber numberWithInteger:AIInvisibleStatusType]; /* Invisible has a special status type */
       
   248 		}
       
   249 	}
       
   250 
       
   251 	g_free(normalized);
       
   252 	
       
   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];
       
   257 
       
   258 	} else if (theContact.isMobile) {
       
   259 		[theContact setIsMobile:NO notify:NotifyLater];		
       
   260 	}
       
   261 	
       
   262 	[super updateStatusForContact:theContact
       
   263 					 toStatusType:statusTypeNumber
       
   264 					   statusName:statusName
       
   265 					statusMessage:inStatusMessage
       
   266 						 isMobile:isMobile];
       
   267 }
       
   268 
       
   269 /*!
       
   270  * @brief Return the purple status ID to be used for a status
       
   271  *
       
   272  * Most subclasses should override this method; these generic values may be appropriate for others.
       
   273  *
       
   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.
       
   279  *
       
   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.
       
   282  *
       
   283  * @result The purple status ID
       
   284  */
       
   285 - (const char *)purpleStatusIDForStatus:(AIStatus *)statusState
       
   286 							arguments:(NSMutableDictionary *)arguments
       
   287 {
       
   288 	const char		*statusID = NULL;
       
   289 	NSString		*statusName = statusState.statusName;
       
   290 	NSString		*statusMessageString = [statusState statusMessageString];
       
   291 
       
   292 	if (!statusMessageString) statusMessageString = @"";
       
   293 
       
   294 	switch (statusState.statusType) {
       
   295 		case AIAvailableStatusType:
       
   296 			statusID = YAHOO_STATUS_TYPE_AVAILABLE;
       
   297 			break;
       
   298 
       
   299 		case AIAwayStatusType:
       
   300 		{
       
   301 			if (([statusName isEqualToString:STATUS_NAME_BRB]) ||
       
   302 				([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BRB]] == NSOrderedSame))
       
   303 				statusID = YAHOO_STATUS_TYPE_BRB;
       
   304 
       
   305 			else if (([statusName isEqualToString:STATUS_NAME_BUSY]) ||
       
   306 					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_BUSY]] == NSOrderedSame))
       
   307 				statusID = YAHOO_STATUS_TYPE_BUSY;
       
   308 
       
   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;
       
   312 
       
   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;
       
   316 			
       
   317 			else if (([statusName isEqualToString:STATUS_NAME_PHONE]) ||
       
   318 					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_PHONE]] == NSOrderedSame))
       
   319 				statusID = YAHOO_STATUS_TYPE_ONPHONE;
       
   320 			
       
   321 			else if (([statusName isEqualToString:STATUS_NAME_VACATION]) ||
       
   322 					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_VACATION]] == NSOrderedSame))
       
   323 				statusID = YAHOO_STATUS_TYPE_ONVACATION;
       
   324 			
       
   325 			else if (([statusName isEqualToString:STATUS_NAME_LUNCH]) ||
       
   326 					 ([statusMessageString caseInsensitiveCompare:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_LUNCH]] == NSOrderedSame))
       
   327 				statusID = YAHOO_STATUS_TYPE_OUTTOLUNCH;
       
   328 			
       
   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;
       
   332 			
       
   333 			
       
   334 			break;
       
   335 		}
       
   336 			
       
   337 		case AIInvisibleStatusType:
       
   338 			statusID = YAHOO_STATUS_TYPE_INVISIBLE;
       
   339 			break;
       
   340 		
       
   341 		case AIOfflineStatusType:
       
   342 			break;
       
   343 	}
       
   344 	
       
   345 	//If we didn't get a purple status ID, request one from super
       
   346 	if (statusID == NULL) statusID = [super purpleStatusIDForStatus:statusState arguments:arguments];
       
   347 	
       
   348 	return statusID;
       
   349 }
       
   350 
       
   351 - (BOOL)shouldAddMusicalNoteToNowPlayingStatus
       
   352 {
       
   353 	return NO;
       
   354 }
       
   355 
       
   356 #pragma mark Contact List Menu Items
       
   357 - (NSString *)titleForContactMenuLabel:(const char *)label forContact:(AIListContact *)inContact
       
   358 {
       
   359 	if (!strcmp(label, _("Add Buddy"))) {
       
   360 		//We handle Add Buddy ourselves
       
   361 		return nil;
       
   362 		
       
   363 	} else if (!strcmp(label, _("Join in Chat"))) {
       
   364 		return [NSString stringWithFormat:AILocalizedString(@"Join %@'s Chat",nil),inContact.formattedUID];
       
   365 
       
   366 	} else if (!strcmp(label, _("Initiate Conference"))) {
       
   367 		return [NSString stringWithFormat:AILocalizedString(@"Initiate Conference with %@",nil), inContact.formattedUID];
       
   368 
       
   369 	} else if (!strcmp(label, _("Presence Settings"))) {
       
   370 		return [NSString stringWithFormat:AILocalizedString(@"Presence Settings for %@",nil), inContact.formattedUID];
       
   371 
       
   372 	} else if (!strcmp(label, _("Appear Online"))) {
       
   373 		return [NSString stringWithFormat:AILocalizedString(@"Appear Online to %@",nil), inContact.formattedUID];
       
   374 		
       
   375 	} else if (!strcmp(label, _("Appear Offline"))) {
       
   376 		return [NSString stringWithFormat:AILocalizedString(@"Appear Offline to %@",nil), inContact.formattedUID];
       
   377 		
       
   378 	} else if (!strcmp(label, _("Appear Permanently Offline"))) {
       
   379 		return [NSString stringWithFormat:AILocalizedString(@"Always Appear Offline to %@",nil), inContact.formattedUID];
       
   380 		
       
   381 	} else if (!strcmp(label, _("Don't Appear Permanently Offline"))) {
       
   382 		return [NSString stringWithFormat:AILocalizedString(@"Don't Always Appear Offline to %@",nil), inContact.formattedUID];
       
   383 		
       
   384 	} else if (!strcmp(label, _("View Webcam"))) {
       
   385 		//return [NSString stringWithFormat:AILocalizedString(@"View %@'s Webcam",nil), inContact.formattedUID];		
       
   386 		return nil;
       
   387 
       
   388 	} else if (!strcmp(label, _("Start Doodling"))) {
       
   389 		return nil;
       
   390 	}
       
   391 
       
   392 	return [super titleForContactMenuLabel:label forContact:inContact];
       
   393 }
       
   394 
       
   395 #pragma mark Account Action Menu Items
       
   396 - (NSString *)titleForAccountActionMenuLabel:(const char *)label
       
   397 {
       
   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. */
       
   400 	return nil;
       
   401 }
       
   402 
       
   403 @end