4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 * Note: When handling the list of struct yahoo_pair's from an incoming
26 * packet the value might not be UTF-8. You should either validate that
27 * it is UTF-8 using g_utf8_validate() or use yahoo_string_decode().
33 #include "accountopt.h"
34 #include "buddylist.h"
35 #include "ciphers/md5hash.h"
51 #include "yahoochat.h"
52 #include "yahoo_aliases.h"
53 #include "yahoo_doodle.h"
54 #include "yahoo_filexfer.h"
55 #include "yahoo_friend.h"
56 #include "yahoo_packet.h"
57 #include "yahoo_picture.h"
60 /* #define YAHOO_DEBUG */
62 /* It doesn't look like it is working (the previously used host is down, another
63 * one doesn't send us back cookies).
65 #define TRY_WEBMESSENGER_LOGIN 0
68 #define PING_TIMEOUT 3600
71 #define KEEPALIVE_TIMEOUT 60
73 #if TRY_WEBMESSENGER_LOGIN
75 yahoo_login_page_cb(PurpleHttpConnection
*http_conn
,
76 PurpleHttpResponse
*response
, gpointer _unused
);
77 #endif /* TRY_WEBMESSENGER_LOGIN */
79 static void yahoo_update_status(PurpleConnection
*gc
, const char *name
, YahooFriend
*f
)
83 if (!gc
|| !name
|| !f
|| !purple_blist_find_buddy(purple_connection_get_account(gc
), name
))
87 case YAHOO_STATUS_OFFLINE
:
88 status
= YAHOO_STATUS_TYPE_OFFLINE
;
90 case YAHOO_STATUS_AVAILABLE
:
91 status
= YAHOO_STATUS_TYPE_AVAILABLE
;
93 case YAHOO_STATUS_BRB
:
94 status
= YAHOO_STATUS_TYPE_BRB
;
96 case YAHOO_STATUS_BUSY
:
97 status
= YAHOO_STATUS_TYPE_BUSY
;
99 case YAHOO_STATUS_NOTATHOME
:
100 status
= YAHOO_STATUS_TYPE_NOTATHOME
;
102 case YAHOO_STATUS_NOTATDESK
:
103 status
= YAHOO_STATUS_TYPE_NOTATDESK
;
105 case YAHOO_STATUS_NOTINOFFICE
:
106 status
= YAHOO_STATUS_TYPE_NOTINOFFICE
;
108 case YAHOO_STATUS_ONPHONE
:
109 status
= YAHOO_STATUS_TYPE_ONPHONE
;
111 case YAHOO_STATUS_ONVACATION
:
112 status
= YAHOO_STATUS_TYPE_ONVACATION
;
114 case YAHOO_STATUS_OUTTOLUNCH
:
115 status
= YAHOO_STATUS_TYPE_OUTTOLUNCH
;
117 case YAHOO_STATUS_STEPPEDOUT
:
118 status
= YAHOO_STATUS_TYPE_STEPPEDOUT
;
120 case YAHOO_STATUS_INVISIBLE
: /* this should never happen? */
121 status
= YAHOO_STATUS_TYPE_INVISIBLE
;
123 case YAHOO_STATUS_CUSTOM
:
124 case YAHOO_STATUS_IDLE
:
126 status
= YAHOO_STATUS_TYPE_AVAILABLE
;
128 status
= YAHOO_STATUS_TYPE_AWAY
;
131 purple_debug_warning("yahoo", "Warning, unknown status %d\n", f
->status
);
136 if (f
->status
== YAHOO_STATUS_CUSTOM
)
137 purple_protocol_got_user_status(purple_connection_get_account(gc
), name
, status
, "message",
138 yahoo_friend_get_status_message(f
), NULL
);
140 purple_protocol_got_user_status(purple_connection_get_account(gc
), name
, status
, NULL
);
144 purple_protocol_got_user_idle(purple_connection_get_account(gc
), name
, TRUE
, f
->idle
);
146 purple_protocol_got_user_idle(purple_connection_get_account(gc
), name
, FALSE
, 0);
149 purple_protocol_got_user_status(purple_connection_get_account(gc
), name
, YAHOO_STATUS_TYPE_MOBILE
, NULL
);
151 purple_protocol_got_user_status_deactive(purple_connection_get_account(gc
), name
, YAHOO_STATUS_TYPE_MOBILE
);
154 static void yahoo_process_status(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
156 PurpleAccount
*account
= purple_connection_get_account(gc
);
157 GSList
*l
= pkt
->hash
;
158 YahooFriend
*f
= NULL
;
160 gboolean unicode
= FALSE
;
161 char *message
= NULL
;
163 if (pkt
->service
== YAHOO_SERVICE_LOGOFF
&& pkt
->status
== -1) {
164 if (!purple_account_get_remember_password(account
))
165 purple_account_set_password(account
, NULL
, NULL
, NULL
);
166 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NAME_IN_USE
,
167 _("You have signed on from another location"));
172 struct yahoo_pair
*pair
= l
->data
;
175 case 0: /* we won't actually do anything with this */
176 case 1: /* we won't actually do anything with this */
178 case 8: /* how many online buddies we have */
180 case 7: /* the current buddy */
181 /* update the previous buddy before changing the variables */
184 yahoo_friend_set_status_message(f
, yahoo_string_decode(gc
, message
, unicode
));
186 yahoo_update_status(gc
, name
, f
);
188 name
= message
= NULL
;
190 if (pair
->value
&& g_utf8_validate(pair
->value
, -1, NULL
)) {
192 f
= yahoo_friend_find_or_new(gc
, name
);
199 f
->status
= strtol(pair
->value
, NULL
, 10);
200 if ((f
->status
>= YAHOO_STATUS_BRB
) && (f
->status
<= YAHOO_STATUS_STEPPEDOUT
))
205 if (f
->status
== YAHOO_STATUS_IDLE
) {
206 /* Idle may have already been set in a more precise way in case 137 */
209 if(pkt
->service
== YAHOO_SERVICE_STATUS_15
)
212 f
->idle
= time(NULL
);
217 if (f
->status
!= YAHOO_STATUS_CUSTOM
)
218 yahoo_friend_set_status_message(f
, NULL
);
222 case 19: /* custom message */
224 message
= pair
->value
;
226 case 11: /* this is the buddy's session id */
228 f
->session_id
= strtol(pair
->value
, NULL
, 10);
230 case 17: /* in chat? */
232 case 47: /* is custom status away or not? 2=idle*/
236 /* I have no idea what it means when this is
237 * set when someone's available, but it doesn't
239 if (f
->status
== YAHOO_STATUS_AVAILABLE
)
242 f
->away
= strtol(pair
->value
, NULL
, 10);
244 /* Idle may have already been set in a more precise way in case 137 */
247 if(pkt
->service
== YAHOO_SERVICE_STATUS_15
)
250 f
->idle
= time(NULL
);
255 case 138: /* when value is 1, either we're not idle, or we are but won't say how long */
259 if( (strtol(pair
->value
, NULL
, 10) == 1) && (f
->idle
) )
262 case 137: /* usually idle time in seconds, sometimes login time */
266 if (f
->status
!= YAHOO_STATUS_AVAILABLE
)
267 f
->idle
= time(NULL
) - strtol(pair
->value
, NULL
, 10);
269 case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
270 if (strtol(pair
->value
, NULL
, 10) == 0) {
272 f
->status
= YAHOO_STATUS_OFFLINE
;
274 purple_protocol_got_user_status(account
, name
, "offline", NULL
);
275 purple_protocol_got_user_status_deactive(account
, name
, YAHOO_STATUS_TYPE_MOBILE
);
282 f
->sms
= strtol(pair
->value
, NULL
, 10);
283 yahoo_update_status(gc
, name
, f
);
286 case 197: /* Avatars */
293 decoded
= purple_base64_decode(pair
->value
, &len
);
294 if (decoded
&& len
> 0) {
295 tmp
= purple_str_binary_to_ascii(decoded
, len
);
296 purple_debug_info("yahoo", "Got key 197, value = %s\n", tmp
);
303 case 192: /* Pictures, aka Buddy Icons, checksum */
305 /* FIXME: Please, if you know this protocol,
306 * FIXME: fix up the strtol() stuff if possible. */
307 int cksum
= strtol(pair
->value
, NULL
, 10);
308 const char *locksum
= NULL
;
314 b
= purple_blist_find_buddy(purple_connection_get_account(gc
), name
);
316 if (!cksum
|| (cksum
== -1)) {
318 yahoo_friend_set_buddy_icon_need_request(f
, TRUE
);
319 purple_buddy_icons_set_for_user(purple_connection_get_account(gc
), name
, NULL
, 0, NULL
);
326 yahoo_friend_set_buddy_icon_need_request(f
, FALSE
);
328 locksum
= purple_buddy_icons_get_checksum_for_user(b
);
329 if (!locksum
|| (cksum
!= strtol(locksum
, NULL
, 10)))
330 yahoo_send_picture_request(gc
, name
);
335 case 16: /* Custom error message */
337 char *tmp
= yahoo_string_decode(gc
, pair
->value
, TRUE
);
338 purple_notify_error(gc
, NULL
, tmp
, NULL
,
339 purple_request_cpar_from_connection(gc
));
343 case 97: /* Unicode status message */
344 unicode
= !strcmp(pair
->value
, "1");
346 case 244: /* client version number. Yahoo Client Detection */
347 if(f
&& strtol(pair
->value
, NULL
, 10))
348 f
->version_id
= strtol(pair
->value
, NULL
, 10);
351 purple_debug_warning("yahoo",
352 "Unknown status key %d\n", pair
->key
);
360 if (pkt
->service
== YAHOO_SERVICE_LOGOFF
)
361 f
->status
= YAHOO_STATUS_OFFLINE
;
363 yahoo_friend_set_status_message(f
, yahoo_string_decode(gc
, message
, unicode
));
365 if (name
) /* update the last buddy */
366 yahoo_update_status(gc
, name
, f
);
370 static void yahoo_do_group_check(PurpleAccount
*account
, GHashTable
*ht
, const char *name
, const char *group
)
375 gboolean onlist
= FALSE
;
378 if (g_hash_table_lookup_extended(ht
, name
, (gpointer
*)&oname
, (gpointer
*)&list
))
379 g_hash_table_steal(ht
, oname
);
381 list
= purple_blist_find_buddies(account
, name
);
383 for (i
= list
; i
; i
= i
->next
) {
385 g
= purple_buddy_get_group(b
);
386 if (!purple_utf8_strcasecmp(group
, purple_group_get_name(g
))) {
387 purple_debug_misc("yahoo",
388 "Oh good, %s is in the right group (%s).\n", name
, group
);
389 list
= g_slist_delete_link(list
, i
);
396 purple_debug_misc("yahoo",
397 "Uhoh, %s isn't on the list (or not in this group), adding him to group %s.\n", name
, group
);
398 if (!(g
= purple_blist_find_group(group
))) {
399 g
= purple_group_new(group
);
400 purple_blist_add_group(g
, NULL
);
402 b
= purple_buddy_new(account
, name
, NULL
);
403 purple_blist_add_buddy(b
, NULL
, g
, NULL
);
408 oname
= g_strdup(name
);
409 g_hash_table_insert(ht
, oname
, list
);
414 static void yahoo_do_group_cleanup(gpointer key
, gpointer value
, gpointer user_data
)
417 GSList
*list
= value
, *i
;
421 for (i
= list
; i
; i
= i
->next
) {
423 g
= purple_buddy_get_group(b
);
424 purple_debug_misc("yahoo", "Deleting Buddy %s from group %s.\n", name
,
425 purple_group_get_name(g
));
426 purple_blist_remove_buddy(b
);
430 static char *_getcookie(char *rawcookie
)
436 if (strlen(rawcookie
) < 2)
438 tmpcookie
= g_strdup(rawcookie
+2);
439 cookieend
= strchr(tmpcookie
, ';');
444 cookie
= g_strdup(tmpcookie
);
450 static void yahoo_process_cookie(YahooData
*yd
, char *c
)
453 g_free(yd
->cookie_y
);
454 yd
->cookie_y
= _getcookie(c
);
455 } else if (c
[0] == 'T') {
456 g_free(yd
->cookie_t
);
457 yd
->cookie_t
= _getcookie(c
);
459 purple_debug_info("yahoo", "Unrecognized cookie '%c'\n", c
[0]);
460 yd
->cookies
= g_slist_prepend(yd
->cookies
, g_strdup(c
));
463 static void yahoo_process_list_15(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
465 GSList
*l
= pkt
->hash
;
467 PurpleAccount
*account
= purple_connection_get_account(gc
);
468 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
470 char *norm_bud
= NULL
;
472 YahooFriend
*f
= NULL
; /* It's your friends. They're going to want you to share your StarBursts. */
473 /* But what if you had no friends? */
476 ht
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_slist_free
);
479 struct yahoo_pair
*pair
= l
->data
;
484 /* This is always 318 before a group, 319 before the first s/n in a group, 320 before any ignored s/n.
485 * It is not sent for s/n's in a group after the first.
486 * All ignored s/n's are listed last, so when we see a 320 we clear the group and begin marking the
487 * s/n's as ignored. It is always followed by an identical 300 key.
489 if (pair
->value
&& !strcmp(pair
->value
, "320")) {
490 /* No longer in any group; this indicates the start of the ignore list. */
491 g_free(yd
->current_list15_grp
);
492 yd
->current_list15_grp
= NULL
;
496 case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */
498 norm_bud
= g_strdup(temp
);
500 if (yd
->current_list15_grp
) {
501 /* This buddy is in a group */
502 f
= yahoo_friend_find_or_new(gc
, norm_bud
);
503 if (!purple_blist_find_buddy(account
, norm_bud
)) {
506 if (!(g
= purple_blist_find_group(yd
->current_list15_grp
))) {
507 g
= purple_group_new(yd
->current_list15_grp
);
508 purple_blist_add_group(g
, NULL
);
510 b
= purple_buddy_new(account
, norm_bud
, NULL
);
511 purple_blist_add_buddy(b
, NULL
, g
, NULL
);
513 yahoo_do_group_check(account
, ht
, norm_bud
, yd
->current_list15_grp
);
516 f
->presence
= YAHOO_PRESENCE_PERM_OFFLINE
;
518 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_NOT_CONNECTED
);
519 f
->p2p_packet_sent
= 0;
521 /* This buddy is on the ignore list (and therefore in no group) */
522 purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n", purple_account_get_username(account
), norm_bud
);
523 purple_account_privacy_deny_add(account
, norm_bud
, 1);
533 case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */
535 case 65: /* This is the group */
536 g_free(yd
->current_list15_grp
);
537 yd
->current_list15_grp
= yahoo_string_decode(gc
, pair
->value
, FALSE
);
539 case 7: /* buddy's s/n */
540 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
542 temp
= g_strdup(purple_normalize(account
, pair
->value
));
544 purple_debug_warning("yahoo", "yahoo_process_list_15 "
545 "got non-UTF-8 string for key %d\n", pair
->key
);
548 case 59: /* somebody told cookies come here too, but im not sure */
549 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
550 yahoo_process_cookie(yd
, pair
->value
);
552 purple_debug_warning("yahoo", "yahoo_process_list_15 "
553 "got non-UTF-8 string for key %d\n", pair
->key
);
556 case 317: /* Stealth Setting */
557 stealth
= strtol(pair
->value
, NULL
, 10);
562 g_hash_table_foreach(ht
, yahoo_do_group_cleanup
, NULL
);
564 /* The reporter of ticket #9745 determined that we weren't retrieving the
565 * aliases during buddy list retrieval, so we never updated aliases that
566 * changed while we were signed off. */
567 yahoo_fetch_aliases(gc
);
569 /* Now that we have processed the buddy list, we can say yahoo has connected */
570 purple_connection_set_display_name(gc
, purple_normalize(account
, purple_account_get_username(account
)));
571 yd
->logged_in
= TRUE
;
572 purple_debug_info("yahoo","Authentication: Connection established\n");
573 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTED
);
574 if (yd
->picture_upload_todo
) {
575 yahoo_buddy_icon_upload(gc
, yd
->picture_upload_todo
);
576 yd
->picture_upload_todo
= NULL
;
578 yahoo_set_status(account
, purple_account_get_active_status(account
));
580 g_hash_table_destroy(ht
);
584 static void yahoo_process_list(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
586 GSList
*l
= pkt
->hash
;
587 gboolean got_serv_list
= FALSE
;
588 YahooFriend
*f
= NULL
;
589 PurpleAccount
*account
= purple_connection_get_account(gc
);
590 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
596 char **tmp
, **bud
, *norm_bud
;
600 yd
->session_id
= pkt
->id
;
603 struct yahoo_pair
*pair
= l
->data
;
608 if (!yd
->tmp_serv_blist
)
609 yd
->tmp_serv_blist
= g_string_new(pair
->value
);
611 g_string_append(yd
->tmp_serv_blist
, pair
->value
);
614 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
615 if (!yd
->tmp_serv_ilist
)
616 yd
->tmp_serv_ilist
= g_string_new(pair
->value
);
618 g_string_append(yd
->tmp_serv_ilist
, pair
->value
);
620 purple_debug_warning("yahoo", "yahoo_process_list "
621 "got non-UTF-8 string for key %d\n", pair
->key
);
625 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
626 yd
->profiles
= g_strsplit(pair
->value
, ",", -1);
628 purple_debug_warning("yahoo", "yahoo_process_list "
629 "got non-UTF-8 string for key %d\n", pair
->key
);
632 case 59: /* cookies, yum */
633 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
634 yahoo_process_cookie(yd
, pair
->value
);
636 purple_debug_warning("yahoo", "yahoo_process_list "
637 "got non-UTF-8 string for key %d\n", pair
->key
);
640 case YAHOO_SERVICE_PRESENCE_PERM
:
641 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
642 if (!yd
->tmp_serv_plist
)
643 yd
->tmp_serv_plist
= g_string_new(pair
->value
);
645 g_string_append(yd
->tmp_serv_plist
, pair
->value
);
647 purple_debug_warning("yahoo", "yahoo_process_list "
648 "got non-UTF-8 string for key %d\n", pair
->key
);
654 if (pkt
->status
!= 0)
657 if (yd
->tmp_serv_blist
) {
658 ht
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_slist_free
);
660 lines
= g_strsplit(yd
->tmp_serv_blist
->str
, "\n", -1);
661 for (tmp
= lines
; *tmp
; tmp
++) {
662 split
= g_strsplit(*tmp
, ":", 2);
665 if (!split
[0] || !split
[1]) {
669 grp
= yahoo_string_decode(gc
, split
[0], FALSE
);
670 buddies
= g_strsplit(split
[1], ",", -1);
671 for (bud
= buddies
; bud
&& *bud
; bud
++) {
672 if (!g_utf8_validate(*bud
, -1, NULL
)) {
673 purple_debug_warning("yahoo", "yahoo_process_list "
674 "got non-UTF-8 string for bud\n");
678 norm_bud
= g_strdup(purple_normalize(account
, *bud
));
679 f
= yahoo_friend_find_or_new(gc
, norm_bud
);
681 if (!purple_blist_find_buddy(account
, norm_bud
)) {
684 if (!(g
= purple_blist_find_group(grp
))) {
685 g
= purple_group_new(grp
);
686 purple_blist_add_group(g
, NULL
);
688 b
= purple_buddy_new(account
, norm_bud
, NULL
);
689 purple_blist_add_buddy(b
, NULL
, g
, NULL
);
692 yahoo_do_group_check(account
, ht
, norm_bud
, grp
);
693 /* set p2p status not connected and no p2p packet sent */
694 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_NOT_CONNECTED
);
695 f
->p2p_packet_sent
= 0;
705 g_string_free(yd
->tmp_serv_blist
, TRUE
);
706 yd
->tmp_serv_blist
= NULL
;
707 g_hash_table_foreach(ht
, yahoo_do_group_cleanup
, NULL
);
708 g_hash_table_destroy(ht
);
711 if (yd
->tmp_serv_ilist
) {
712 buddies
= g_strsplit(yd
->tmp_serv_ilist
->str
, ",", -1);
713 for (bud
= buddies
; bud
&& *bud
; bud
++) {
714 /* The server is already ignoring the user */
715 got_serv_list
= TRUE
;
716 purple_account_privacy_deny_add(account
, *bud
, 1);
720 g_string_free(yd
->tmp_serv_ilist
, TRUE
);
721 yd
->tmp_serv_ilist
= NULL
;
725 ((purple_account_get_privacy_type(account
) != PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST
) &&
726 (purple_account_get_privacy_type(account
) != PURPLE_ACCOUNT_PRIVACY_DENY_ALL
) &&
727 (purple_account_get_privacy_type(account
) != PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS
)))
729 purple_account_set_privacy_type(account
, PURPLE_ACCOUNT_PRIVACY_DENY_USERS
);
730 purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_ACCOUNT_PRIVACY_DENY_USERS.\n",
731 purple_account_get_username(account
));
734 if (yd
->tmp_serv_plist
) {
735 buddies
= g_strsplit(yd
->tmp_serv_plist
->str
, ",", -1);
736 for (bud
= buddies
; bud
&& *bud
; bud
++) {
737 f
= yahoo_friend_find(gc
, *bud
);
739 purple_debug_info("yahoo", "%s setting presence for %s to PERM_OFFLINE\n",
740 purple_account_get_username(account
), *bud
);
741 f
->presence
= YAHOO_PRESENCE_PERM_OFFLINE
;
745 g_string_free(yd
->tmp_serv_plist
, TRUE
);
746 yd
->tmp_serv_plist
= NULL
;
749 /* Now that we've got the list, request aliases */
750 yahoo_fetch_aliases(gc
);
753 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
754 static void yahoo_process_notify(PurpleConnection
*gc
, struct yahoo_packet
*pkt
, yahoo_pkt_type pkt_type
)
756 PurpleAccount
*account
;
761 YahooFriend
*f
= NULL
;
762 GSList
*l
= pkt
->hash
;
764 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
766 account
= purple_connection_get_account(gc
);
769 struct yahoo_pair
*pair
= l
->data
;
770 if (pair
->key
== 4 || pair
->key
== 1) {
771 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
774 purple_debug_warning("yahoo", "yahoo_process_notify "
775 "got non-UTF-8 string for key %d\n", pair
->key
);
777 } else if (pair
->key
== 49) {
779 } else if (pair
->key
== 13) {
781 } else if (pair
->key
== 14) {
782 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
785 purple_debug_warning("yahoo", "yahoo_process_notify "
786 "got non-UTF-8 string for key %d\n", pair
->key
);
788 } else if (pair
->key
== 11) {
789 val_11
= strtol(pair
->value
, NULL
, 10);
797 /* disconnect the peer if connected through p2p and sends wrong value for session id */
798 if ((pkt_type
== YAHOO_PKT_TYPE_P2P
) && (val_11
!= yd
->session_id
)) {
799 purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from
);
800 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
801 g_hash_table_remove(yd
->peers
, from
);
805 if (!g_ascii_strncasecmp(msg
, "TYPING", strlen("TYPING"))
806 && (purple_account_privacy_check(account
, from
)))
809 if (stat
&& *stat
== '1')
810 purple_serv_got_typing(gc
, from
, 0, PURPLE_IM_TYPING
);
812 purple_serv_got_typing_stopped(gc
, from
);
814 } else if (!g_ascii_strncasecmp(msg
, "GAME", strlen("GAME"))) {
815 PurpleBuddy
*bud
= purple_blist_find_buddy(account
, from
);
818 purple_debug_warning("yahoo",
819 "%s is playing a game, and doesn't want you to know.\n", from
);
822 f
= yahoo_friend_find(gc
, from
);
824 return; /* if they're not on the list, don't bother */
826 yahoo_friend_set_game(f
, NULL
);
828 if (stat
&& *stat
== '1') {
829 yahoo_friend_set_game(f
, game
);
831 yahoo_update_status(gc
, from
, f
);
833 } else if (!g_ascii_strncasecmp(msg
, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) {
834 PurpleIMConversation
*im
= purple_conversations_find_im_with_account(from
, account
);
835 char *buf
= g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from
);
836 purple_conversation_write_system_message(PURPLE_CONVERSATION(im
),
837 buf
, PURPLE_MESSAGE_NOTIFY
);
853 static void yahoo_process_sms_message(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
855 PurpleAccount
*account
;
856 GSList
*l
= pkt
->hash
;
857 struct _yahoo_im
*sms
= NULL
;
859 char *server_msg
= NULL
;
862 yd
= purple_connection_get_protocol_data(gc
);
863 account
= purple_connection_get_account(gc
);
866 struct yahoo_pair
*pair
= l
->data
;
867 if (pair
->key
== 4) {
868 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
869 sms
= g_new0(struct _yahoo_im
, 1);
870 sms
->from
= g_strdup_printf("+%s", pair
->value
);
871 sms
->time
= time(NULL
);
874 purple_debug_warning("yahoo", "yahoo_process_sms_message "
875 "got non-UTF-8 string for key %d\n", pair
->key
);
877 } else if (pair
->key
== 14) {
879 sms
->msg
= pair
->value
;
880 } else if (pair
->key
== 68) {
882 g_hash_table_insert(yd
->sms_carrier
, g_strdup(sms
->from
), g_strdup(pair
->value
));
883 } else if (pair
->key
== 16) {
884 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
885 server_msg
= pair
->value
;
887 purple_debug_warning("yahoo", "yahoo_process_sms_message "
888 "got non-UTF-8 string for key %d\n", pair
->key
);
895 purple_debug_info("yahoo", "Received a malformed SMS packet!\n");
899 if ((int)pkt
->status
< 0)
900 pkt
->status
= YAHOO_STATUS_DISCONNECTED
;
901 if (pkt
->status
== YAHOO_STATUS_DISCONNECTED
) {
903 PurpleIMConversation
*im
;
904 im
= purple_conversations_find_im_with_account(sms
->from
, account
);
906 im
= purple_im_conversation_new(account
, sms
->from
);
907 purple_conversation_write_system_message(PURPLE_CONVERSATION(im
),
911 purple_notify_error(gc
, NULL
,
912 _("Your SMS was not delivered"), NULL
,
913 purple_request_cpar_from_connection(gc
));
921 if (!sms
->from
|| !sms
->msg
) {
926 m
= yahoo_string_decode(gc
, sms
->msg
, sms
->utf8
);
927 purple_serv_got_im(gc
, sms
->from
, m
, 0, sms
->time
);
934 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
935 static void yahoo_process_message(PurpleConnection
*gc
, struct yahoo_packet
*pkt
, yahoo_pkt_type pkt_type
)
937 PurpleAccount
*account
;
938 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
939 GSList
*l
= pkt
->hash
;
941 struct _yahoo_im
*im
= NULL
;
943 account
= purple_connection_get_account(gc
);
945 if (pkt
->status
<= 1 || pkt
->status
== 5 || pkt
->status
== YAHOO_STATUS_OFFLINE
) {
946 /* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */
948 struct yahoo_pair
*pair
= l
->data
;
949 if (pair
->key
== 4 || pair
->key
== 1) {
950 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
951 im
= g_new0(struct _yahoo_im
, 1);
952 list
= g_slist_append(list
, im
);
953 im
->from
= pair
->value
;
954 im
->time
= time(NULL
);
957 purple_debug_warning("yahoo", "yahoo_process_message "
958 "got non-UTF-8 string for key %d\n", pair
->key
);
960 } else if (im
&& pair
->key
== 5) {
961 im
->active_id
= pair
->value
;
962 } else if (pair
->key
== 97) {
964 im
->utf8
= strtol(pair
->value
, NULL
, 10);
965 } else if (pair
->key
== 15) {
967 im
->time
= strtol(pair
->value
, NULL
, 10);
968 } else if (pair
->key
== 206) {
970 im
->buddy_icon
= strtol(pair
->value
, NULL
, 10);
971 } else if (pair
->key
== 14) {
973 im
->msg
= pair
->value
;
974 } else if (im
&& (pair
->key
== 11)) {
975 /* peer session id */
976 /* disconnect the peer if connected through p2p and sends wrong value for session id */
977 if( (pkt_type
== YAHOO_PKT_TYPE_P2P
)
978 && (yd
->session_id
!= strtol(pair
->value
, NULL
, 10)) )
980 purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im
->from
);
981 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
982 g_hash_table_remove(yd
->peers
, im
->from
);
984 return; /* Not sure whether we should process remaining IMs in this packet */
987 } else if (im
&& pair
->key
== 63 && g_utf8_validate(pair
->value
, -1, NULL
)) {
989 /* Check for the Doodle IMV */
990 if (im
->from
!= NULL
)
992 g_hash_table_replace(yd
->imvironments
, g_strdup(im
->from
), g_strdup(pair
->value
));
994 if (strstr(pair
->value
, "doodle;") != NULL
)
996 PurpleWhiteboard
*wb
;
998 if (!purple_account_privacy_check(account
, im
->from
)) {
999 purple_debug_info("yahoo", "Doodle request from %s dropped.\n",
1004 /* I'm not sure the following ever happens -DAA */
1005 wb
= purple_whiteboard_get_session(account
, im
->from
);
1007 /* If a Doodle session doesn't exist between this user */
1011 wb
= purple_whiteboard_new(account
, im
->from
,
1012 DOODLE_STATE_REQUESTED
);
1013 ds
= purple_whiteboard_get_protocol_data(wb
);
1014 ds
->imv_key
= g_strdup(pair
->value
);
1016 yahoo_doodle_command_send_request(gc
, im
->from
, pair
->value
);
1017 yahoo_doodle_command_send_ready(gc
, im
->from
, pair
->value
);
1021 } else if (pair
->key
== 429) {
1023 im
->id
= pair
->value
;
1027 } else if (pkt
->status
== 2) {
1028 purple_notify_error(gc
, NULL
,
1029 _("Your Yahoo! message did not get sent."), NULL
,
1030 purple_request_cpar_from_connection(gc
));
1033 for (l
= list
; l
; l
= l
->next
) {
1042 if (!purple_account_privacy_check(account
, im
->from
)) {
1043 purple_debug_info("yahoo", "Message from %s dropped.\n", im
->from
);
1048 * TODO: Is there anything else we should check when determining whether
1049 * we should send an acknowledgement?
1051 if (im
->id
!= NULL
) {
1052 /* Send acknowledgement. If we don't do this then the official
1053 * Yahoo Messenger client for Windows will send us the same
1054 * message 7 seconds later as an offline message. This is true
1055 * for at least version 9.0.0.2162 on Windows XP. */
1056 struct yahoo_packet
*pkt2
;
1057 pkt2
= yahoo_packet_new(YAHOO_SERVICE_MESSAGE_ACK
,
1058 YAHOO_STATUS_AVAILABLE
, pkt
->id
);
1059 yahoo_packet_hash(pkt2
, "ssisii",
1060 1, im
->active_id
, /* May not always be the connection's display name */
1066 yahoo_packet_send_and_free(pkt2
, yd
);
1069 m
= yahoo_string_decode(gc
, im
->msg
, im
->utf8
);
1070 /* This may actually not be necessary, but it appears
1071 * that at least at one point some clients were sending
1072 * "\r\n" as line delimiters, so we want to avoid double
1074 m2
= purple_strreplace(m
, "\r\n", "\n");
1077 purple_util_chrreplace(m
, '\r', '\n');
1078 if (!strcmp(m
, "<ding>")) {
1081 username
= g_markup_escape_text(im
->from
, -1);
1082 purple_protocol_got_attention(gc
, username
, YAHOO_BUZZ
);
1089 m2
= yahoo_codes_to_html(m
);
1092 purple_serv_got_im(gc
, im
->from
, m2
, 0, im
->time
);
1100 static void yahoo_process_sysmessage(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
1102 GSList
*l
= pkt
->hash
;
1103 char *prim
, *me
= NULL
, *msg
= NULL
;
1106 struct yahoo_pair
*pair
= l
->data
;
1108 if (pair
->key
== 5) {
1109 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1112 purple_debug_warning("yahoo", "yahoo_process_sysmessage "
1113 "got non-UTF-8 string for key %d\n", pair
->key
);
1115 } else if (pair
->key
== 14) {
1116 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1119 purple_debug_warning("yahoo", "yahoo_process_sysmessage "
1120 "got non-UTF-8 string for key %d\n", pair
->key
);
1127 if (!msg
|| !g_utf8_validate(msg
, -1, NULL
))
1130 prim
= g_strdup_printf(_("Yahoo! system message for %s:"),
1131 me
?me
:purple_connection_get_display_name(gc
));
1132 purple_notify_info(NULL
, NULL
, prim
, msg
,
1133 purple_request_cpar_from_connection(gc
));
1137 struct yahoo_add_request
{
1138 PurpleConnection
*gc
;
1144 yahoo_buddy_add_authorize_cb(const char *message
, gpointer data
)
1146 struct yahoo_add_request
*add_req
= data
;
1147 struct yahoo_packet
*pkt
;
1148 YahooData
*yd
= purple_connection_get_protocol_data(add_req
->gc
);
1149 const char *who
= add_req
->who
;
1151 pkt
= yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
1152 yahoo_packet_hash(pkt
, "ssii",
1158 yahoo_packet_send_and_free(pkt
, yd
);
1160 g_free(add_req
->id
);
1161 g_free(add_req
->who
);
1166 yahoo_buddy_add_deny_cb(const char *msg
, gpointer data
)
1168 struct yahoo_add_request
*add_req
= data
;
1169 YahooData
*yd
= purple_connection_get_protocol_data(add_req
->gc
);
1170 struct yahoo_packet
*pkt
;
1171 char *encoded_msg
= NULL
;
1172 const char *who
= add_req
->who
;
1175 encoded_msg
= yahoo_string_encode(add_req
->gc
, msg
, FALSE
);
1177 pkt
= yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15
,
1178 YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
1180 yahoo_packet_hash(pkt
, "ssiiis",
1186 14, encoded_msg
? encoded_msg
: "");
1189 yahoo_packet_send_and_free(pkt
, yd
);
1191 g_free(encoded_msg
);
1193 g_free(add_req
->id
);
1194 g_free(add_req
->who
);
1198 static void yahoo_buddy_denied_our_add(PurpleConnection
*gc
, const char *who
, const char *reason
)
1201 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
1206 if (reason
!= NULL
) {
1207 char *msg2
= yahoo_string_decode(gc
, reason
, FALSE
);
1208 notify_msg
= g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who
, msg2
);
1211 notify_msg
= g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list."), who
);
1213 purple_notify_info(gc
, NULL
, _("Add buddy rejected"), notify_msg
,
1214 purple_request_cpar_from_connection(gc
));
1217 g_hash_table_remove(yd
->friends
, who
);
1218 purple_protocol_got_user_status(purple_connection_get_account(gc
), who
, "offline", NULL
); /* FIXME: make this set not on list status instead */
1219 /* TODO: Shouldn't we remove the buddy from our local list? */
1222 static void yahoo_buddy_auth_req_15(PurpleConnection
*gc
, struct yahoo_packet
*pkt
) {
1223 PurpleAccount
*account
;
1224 GSList
*l
= pkt
->hash
;
1225 const char *msg
= NULL
;
1227 account
= purple_connection_get_account(gc
);
1229 /* Buddy authorized/declined our addition */
1230 if (pkt
->status
== 1) {
1235 struct yahoo_pair
*pair
= l
->data
;
1237 switch (pair
->key
) {
1241 response
= strtol(pair
->value
, NULL
, 10);
1250 if (response
== 1) /* Authorized */
1251 purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who
? who
: "(Unknown Buddy)");
1252 else if (response
== 2) { /* Declined */
1253 purple_debug_info("yahoo", "Received authorization decline from buddy '%s'.\n", who
? who
: "(Unknown Buddy)");
1254 yahoo_buddy_denied_our_add(gc
, who
, msg
);
1256 purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response
, who
? who
: "(Unknown Buddy)");
1259 /* Buddy requested authorization to add us. */
1260 else if (pkt
->status
== 3) {
1261 struct yahoo_add_request
*add_req
;
1262 const char *firstname
= NULL
, *lastname
= NULL
;
1264 add_req
= g_new0(struct yahoo_add_request
, 1);
1268 struct yahoo_pair
*pair
= l
->data
;
1270 switch (pair
->key
) {
1274 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1275 add_req
->id
= g_strdup(pair
->value
);
1277 purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
1278 "got non-UTF-8 string for key %d\n", pair
->key
);
1285 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1286 firstname
= pair
->value
;
1288 purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
1289 "got non-UTF-8 string for key %d\n", pair
->key
);
1293 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1294 lastname
= pair
->value
;
1296 purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
1297 "got non-UTF-8 string for key %d\n", pair
->key
);
1305 if (add_req
->id
&& add_req
->who
) {
1306 char *alias
= NULL
, *dec_msg
= NULL
;
1308 if (!purple_account_privacy_check(account
, add_req
->who
))
1310 purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
1312 yahoo_buddy_add_deny_cb(NULL
, add_req
);
1317 dec_msg
= yahoo_string_decode(gc
, msg
, FALSE
);
1319 if (firstname
&& lastname
)
1320 alias
= g_strdup_printf("%s %s", firstname
, lastname
);
1322 alias
= g_strdup(firstname
);
1324 alias
= g_strdup(lastname
);
1326 /* DONE! this is almost exactly the same as what MSN does,
1327 * this should probably be moved to the core.
1329 purple_account_request_authorization(account
, add_req
->who
, add_req
->id
,
1331 purple_blist_find_buddy(account
, add_req
->who
) != NULL
,
1332 yahoo_buddy_add_authorize_cb
,
1333 yahoo_buddy_add_deny_cb
,
1338 g_free(add_req
->id
);
1339 g_free(add_req
->who
);
1343 purple_debug_error("yahoo", "Received authorization of unknown status (%d).\n", pkt
->status
);
1347 /* I don't think this happens anymore in Version 15 */
1348 static void yahoo_buddy_added_us(PurpleConnection
*gc
, struct yahoo_packet
*pkt
) {
1349 PurpleAccount
*account
;
1350 struct yahoo_add_request
*add_req
;
1352 GSList
*l
= pkt
->hash
;
1354 account
= purple_connection_get_account(gc
);
1356 add_req
= g_new0(struct yahoo_add_request
, 1);
1360 struct yahoo_pair
*pair
= l
->data
;
1362 switch (pair
->key
) {
1364 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1365 add_req
->id
= g_strdup(pair
->value
);
1367 purple_debug_warning("yahoo", "yahoo_buddy_added_us "
1368 "got non-UTF-8 string for key %d\n", pair
->key
);
1372 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1373 add_req
->who
= g_strdup(pair
->value
);
1375 purple_debug_warning("yahoo", "yahoo_buddy_added_us "
1376 "got non-UTF-8 string for key %d\n", pair
->key
);
1379 case 15: /* time, for when they add us and we're offline */
1388 if (add_req
->id
&& add_req
->who
) {
1389 char *dec_msg
= NULL
;
1391 if (!purple_account_privacy_check(account
, add_req
->who
)) {
1392 purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
1394 yahoo_buddy_add_deny_cb(NULL
, add_req
);
1399 dec_msg
= yahoo_string_decode(gc
, msg
, FALSE
);
1401 /* DONE! this is almost exactly the same as what MSN does,
1402 * this should probably be moved to the core.
1404 purple_account_request_authorization(account
, add_req
->who
, add_req
->id
,
1406 purple_blist_find_buddy(account
,add_req
->who
) != NULL
,
1407 yahoo_buddy_add_authorize_cb
,
1408 yahoo_buddy_add_deny_cb
, add_req
);
1411 g_free(add_req
->id
);
1412 g_free(add_req
->who
);
1417 /* I have no idea if this every gets called in version 15 */
1418 static void yahoo_buddy_denied_our_add_old(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
1422 GSList
*l
= pkt
->hash
;
1425 struct yahoo_pair
*pair
= l
->data
;
1427 switch (pair
->key
) {
1429 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1432 purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
1433 "got non-UTF-8 string for key %d\n", pair
->key
);
1437 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1440 purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
1441 "got non-UTF-8 string for key %d\n", pair
->key
);
1448 yahoo_buddy_denied_our_add(gc
, who
, msg
);
1451 static void yahoo_process_contact(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
1453 switch (pkt
->status
) {
1455 yahoo_process_status(gc
, pkt
);
1458 yahoo_buddy_added_us(gc
, pkt
);
1461 yahoo_buddy_denied_our_add_old(gc
, pkt
);
1468 #define OUT_CHARSET "utf-8"
1470 static char *yahoo_decode(const char *text
)
1472 char *converted
= NULL
;
1474 const char *end
, *p
;
1477 n
= new = g_malloc(strlen (text
) + 1);
1478 end
= text
+ strlen(text
);
1480 for (p
= text
; p
< end
; p
++, n
++) {
1482 if (p
[1] >= '0' && p
[1] <= '7') {
1484 for (i
= 0, k
= 0; k
< 3; k
+= 1) {
1486 if (c
< '0' || c
> '7') break;
1492 } else { /* bug 959248 */
1493 /* If we see a \ not followed by an octal number,
1494 * it means that it is actually a \\ with one \
1495 * already eaten by some unknown function.
1496 * This is arguably broken.
1498 * I think wing is wrong here, there is no function
1499 * called that I see that could have done it. I guess
1500 * it is just really sending single \'s. That's yahoo
1512 /* XXX: Is this related to Yahoo! Japan? If so, it should be removed. -mmcco */
1513 if (strstr(text
, "\033$B"))
1514 converted
= g_convert(new, n
- new, OUT_CHARSET
, "iso-2022-jp", NULL
, NULL
, NULL
);
1516 converted
= g_convert(new, n
- new, OUT_CHARSET
, "iso-8859-1", NULL
, NULL
, NULL
);
1522 static void yahoo_process_mail(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
1524 PurpleAccount
*account
= purple_connection_get_account(gc
);
1525 const char *who
= NULL
;
1526 const char *email
= NULL
;
1527 const char *subj
= NULL
;
1528 const char *yahoo_mail_url
= YAHOO_MAIL_URL
;
1530 GSList
*l
= pkt
->hash
;
1532 if (!purple_account_get_check_mail(account
))
1536 struct yahoo_pair
*pair
= l
->data
;
1537 if (pair
->key
== 9) {
1538 count
= strtol(pair
->value
, NULL
, 10);
1539 } else if (pair
->key
== 43) {
1540 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1543 purple_debug_warning("yahoo", "yahoo_process_mail "
1544 "got non-UTF-8 string for key %d\n", pair
->key
);
1546 } else if (pair
->key
== 42) {
1547 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1548 email
= pair
->value
;
1550 purple_debug_warning("yahoo", "yahoo_process_mail "
1551 "got non-UTF-8 string for key %d\n", pair
->key
);
1553 } else if (pair
->key
== 18) {
1554 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1557 purple_debug_warning("yahoo", "yahoo_process_mail "
1558 "got non-UTF-8 string for key %d\n", pair
->key
);
1564 if (who
&& subj
&& email
&& *email
) {
1565 char *dec_who
= yahoo_decode(who
);
1566 char *dec_subj
= yahoo_decode(subj
);
1567 char *from
= g_strdup_printf("%s (%s)", dec_who
, email
);
1569 purple_notify_email(gc
, dec_subj
, from
, purple_account_get_username(account
),
1570 yahoo_mail_url
, NULL
, NULL
);
1575 } else if (count
> 0) {
1576 const char *tos
[2] = { purple_account_get_username(account
) };
1577 const char *urls
[2] = { yahoo_mail_url
};
1579 purple_notify_emails(gc
, count
, FALSE
, NULL
, NULL
, tos
, urls
,
1584 /* We use this structure once while we authenticate */
1585 struct yahoo_auth_data
1587 PurpleConnection
*gc
;
1591 /* This is the y64 alphabet... it's like base64, but has a . and a _ */
1592 static const char base64digits
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
1594 /* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function
1595 * in util.c, but it is different from the one yahoo uses */
1596 static void to_y64(char *out
, const unsigned char *in
, gsize inlen
)
1597 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
1599 for (; inlen
>= 3; inlen
-= 3)
1601 *out
++ = base64digits
[in
[0] >> 2];
1602 *out
++ = base64digits
[((in
[0] << 4) & 0x30) | (in
[1] >> 4)];
1603 *out
++ = base64digits
[((in
[1] << 2) & 0x3c) | (in
[2] >> 6)];
1604 *out
++ = base64digits
[in
[2] & 0x3f];
1609 unsigned char fragment
;
1611 *out
++ = base64digits
[in
[0] >> 2];
1612 fragment
= (in
[0] << 4) & 0x30;
1614 fragment
|= in
[1] >> 4;
1615 *out
++ = base64digits
[fragment
];
1616 *out
++ = (inlen
< 2) ? '-' : base64digits
[(in
[1] << 2) & 0x3c];
1622 static void yahoo_auth16_stage3(PurpleConnection
*gc
, const char *crypt
)
1624 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
1625 PurpleAccount
*account
= purple_connection_get_account(gc
);
1626 const char *name
= purple_normalize(account
, purple_account_get_username(account
));
1627 PurpleHash
*md5_hash
;
1628 guchar md5_digest
[16];
1629 gchar base64_string
[25];
1630 struct yahoo_packet
*pkt
;
1632 purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n");
1634 g_return_if_fail(crypt
!= NULL
);
1636 md5_hash
= purple_md5_hash_new();
1637 purple_hash_append(md5_hash
, (guchar
*)crypt
, strlen(crypt
));
1638 purple_hash_digest(md5_hash
, md5_digest
, sizeof(md5_digest
));
1640 to_y64(base64_string
, md5_digest
, 16);
1642 purple_debug_info("yahoo", "yahoo status: %d\n", yd
->current_status
);
1643 pkt
= yahoo_packet_new(YAHOO_SERVICE_AUTHRESP
, yd
->current_status
, yd
->session_id
);
1645 if(yd
->cookie_b
) { /* send B cookie if we have it */
1646 yahoo_packet_hash(pkt
, "ssssssssss",
1652 244, YAHOO_CLIENT_VERSION_ID
,
1656 98, purple_account_get_string(account
, "room_list_locale", "us"),
1657 135, YAHOO_CLIENT_VERSION
);
1658 } else { /* don't try to send an empty B cookie - the server will be mad */
1659 yahoo_packet_hash(pkt
, "sssssssss",
1665 244, YAHOO_CLIENT_VERSION_ID
,
1668 98, purple_account_get_string(account
, "room_list_locale", "us"),
1669 135, YAHOO_CLIENT_VERSION
);
1672 if (yd
->picture_checksum
)
1673 yahoo_packet_hash_int(pkt
, 192, yd
->picture_checksum
);
1674 yahoo_packet_send_and_free(pkt
, yd
);
1676 g_object_unref(md5_hash
);
1679 static void yahoo_auth16_stage2(PurpleHttpConnection
*http_conn
,
1680 PurpleHttpResponse
*response
, gpointer _auth_data
)
1682 struct yahoo_auth_data
*auth_data
= _auth_data
;
1683 PurpleConnection
*gc
= auth_data
->gc
;
1684 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
1688 int response_no
= -1;
1691 PurpleHttpCookieJar
*cookiejar
;
1693 purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n");
1695 if (!purple_http_response_is_successful(response
)) {
1696 const gchar
*error_message
= purple_http_response_get_error(response
);
1697 purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message
);
1698 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
, error_message
);
1699 g_free(auth_data
->seed
);
1704 splits
= g_strsplit(purple_http_response_get_data(response
, NULL
),
1707 cookiejar
= purple_http_conn_get_cookie_jar(http_conn
);
1708 yd
->cookie_b
= purple_http_cookie_jar_get(cookiejar
, "B");
1709 yd
->cookie_t
= purple_http_cookie_jar_get(cookiejar
, "T");
1710 yd
->cookie_y
= purple_http_cookie_jar_get(cookiejar
, "Y");
1714 /* I'm not exactly a fan of the magic numbers, but it's obvious,
1715 * so no sense in wasting a bajillion vars or calls to strlen */
1717 if (i
== 0 && g_ascii_isdigit(splits
[i
][0])) {
1718 response_no
= strtol(splits
[i
], NULL
, 10);
1719 purple_debug_info("yahoo", "Got auth16 stage 2 response code: %d\n",
1721 } else if (strncmp(splits
[i
], "crumb=", 6) == 0) {
1722 crumb
= g_strdup(&splits
[i
][6]);
1724 if (purple_debug_is_unsafe())
1725 purple_debug_info("yahoo", "Got crumb: %s\n", crumb
);
1735 if(response_no
!= 0) {
1736 /* Some error in the login process */
1737 PurpleConnectionError error
;
1738 char *error_reason
= NULL
;
1740 switch (response_no
) {
1742 /* Some error in the received stream */
1743 error_reason
= g_strdup(_("Received invalid data"));
1744 error
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
1748 error_reason
= g_strdup(_("Unknown error"));
1749 error
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
1752 /* if we have everything we need, why not try to login irrespective of response */
1753 if ((crumb
!= NULL
) && (yd
->cookie_y
!= NULL
) && (yd
->cookie_t
!= NULL
)) {
1755 try_login_on_error
= TRUE
;
1759 error_reason
= g_strdup(_("Unknown error"));
1760 error
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
1764 purple_debug_error("yahoo", "Authentication error: %s. "
1765 "Code %d\n", error_reason
, response_no
);
1766 purple_connection_error(gc
, error
, error_reason
);
1767 g_free(error_reason
);
1769 g_free(auth_data
->seed
);
1775 crypt
= g_strconcat(crumb
, auth_data
->seed
, NULL
);
1776 yahoo_auth16_stage3(gc
, crypt
);
1779 g_free(auth_data
->seed
);
1783 static void yahoo_auth16_stage1_cb(PurpleHttpConnection
*http_conn
,
1784 PurpleHttpResponse
*response
, gpointer _auth_data
)
1786 struct yahoo_auth_data
*auth_data
= _auth_data
;
1787 PurpleConnection
*gc
= auth_data
->gc
;
1788 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
1790 purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n");
1792 if (!purple_http_response_is_successful(response
)) {
1793 const gchar
*error_message
= purple_http_response_get_error(response
);
1794 purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message
);
1795 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
, error_message
);
1796 g_free(auth_data
->seed
);
1800 PurpleAccount
*account
= purple_connection_get_account(gc
);
1801 gchar
**split_data
= g_strsplit(purple_http_response_get_data(
1802 response
, NULL
), "\r\n", -1);
1803 int totalelements
= 0;
1804 int response_no
= -1;
1807 totalelements
= g_strv_length(split_data
);
1809 if(totalelements
== 1) { /* Received an error code */
1810 response_no
= strtol(split_data
[0], NULL
, 10);
1811 } else if(totalelements
== 2 || totalelements
== 3 ) { /* received valid data */
1812 response_no
= strtol(split_data
[0], NULL
, 10);
1813 token
= g_strdup(split_data
[1] + strlen("ymsgr="));
1814 } else { /* It looks like a transparent proxy has returned a document we don't want */
1818 g_strfreev(split_data
);
1820 if(response_no
!= 0) {
1821 /* Some error in the login process */
1822 PurpleConnectionError error
;
1825 switch(response_no
) {
1827 /* Some error in the received stream */
1828 error_reason
= g_strdup(_("Received invalid data"));
1829 error
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
1832 /* Password incorrect */
1833 /* Set password to NULL. Avoids account locking. Brings dialog to enter password if clicked on Re-enable account */
1834 if (!purple_account_get_remember_password(account
))
1835 purple_account_set_password(account
, NULL
, NULL
, NULL
);
1836 error_reason
= g_strdup(_("Incorrect password"));
1837 error
= PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
1840 /* security lock from too many failed login attempts */
1841 error_reason
= g_strdup(_("Account locked: Too many failed login "
1842 "attempts. Logging into the Yahoo! website may fix this."));
1843 error
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
1846 /* the username does not exist */
1847 error_reason
= g_strdup(_("Username does not exist"));
1848 error
= PURPLE_CONNECTION_ERROR_INVALID_USERNAME
;
1851 /* indicates a lock of some description */
1852 error_reason
= g_strdup(_("Account locked: Unknown reason. Logging "
1853 "into the Yahoo! website may fix this."));
1854 error
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
1857 /* indicates a lock due to logging in too frequently */
1858 error_reason
= g_strdup(_("Account locked: You have been logging in too "
1859 "frequently. Wait a few minutes before trying to connect "
1860 "again. Logging into the Yahoo! website may help."));
1861 error
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
1864 /* username or password missing */
1865 error_reason
= g_strdup(_("Username or password missing"));
1866 error
= PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
1869 /* Unknown error! */
1870 error_reason
= g_strdup_printf(_("Unknown error (%d)"), response_no
);
1871 error
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
1874 purple_debug_error("yahoo", "Authentication error: %s. Code %d\n",
1875 error_reason
, response_no
);
1876 purple_connection_error(gc
, error
, error_reason
);
1877 g_free(error_reason
);
1878 g_free(auth_data
->seed
);
1883 PurpleHttpRequest
*req
;
1885 req
= purple_http_request_new(NULL
);
1886 purple_http_request_set_url_printf(req
, YAHOO_LOGIN_URL
, token
);
1887 purple_http_request_header_set(req
, "User-Agent",
1888 YAHOO_CLIENT_USERAGENT
);
1889 purple_http_connection_set_add(yd
->http_reqs
,
1890 purple_http_request(gc
, req
,
1891 yahoo_auth16_stage2
, auth_data
));
1892 purple_http_request_unref(req
);
1899 static void yahoo_auth16_stage1(PurpleConnection
*gc
, const char *seed
)
1901 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
1902 PurpleHttpRequest
*req
;
1903 struct yahoo_auth_data
*auth_data
= NULL
;
1904 char *encoded_username
;
1905 char *encoded_password
;
1907 purple_debug_info("yahoo", "Authentication: In yahoo_auth16_stage1\n");
1909 auth_data
= g_new0(struct yahoo_auth_data
, 1);
1911 auth_data
->seed
= g_strdup(seed
);
1913 encoded_username
= g_strdup(purple_url_encode(purple_account_get_username(purple_connection_get_account(gc
))));
1914 encoded_password
= g_strdup(purple_url_encode(purple_connection_get_password(gc
)));
1916 req
= purple_http_request_new(NULL
);
1917 purple_http_request_set_url_printf(req
, YAHOO_TOKEN_URL
,
1918 encoded_username
, encoded_password
, purple_url_encode(seed
));
1919 purple_http_request_header_set(req
, "User-Agent", YAHOO_CLIENT_USERAGENT
);
1920 purple_http_connection_set_add(yd
->http_reqs
, purple_http_request(gc
,
1921 req
, yahoo_auth16_stage1_cb
, auth_data
));
1922 purple_http_request_unref(req
);
1924 purple_str_wipe(encoded_password
);
1925 g_free(encoded_username
);
1928 static void yahoo_process_auth(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
1931 GSList
*l
= pkt
->hash
;
1936 struct yahoo_pair
*pair
= l
->data
;
1937 /* (pair->key == 1) -> sn */
1938 if (pair
->key
== 94) {
1939 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
1942 purple_debug_warning("yahoo", "yahoo_process_auth "
1943 "got non-UTF-8 string for key %d\n", pair
->key
);
1945 } else if (pair
->key
== 13) {
1946 m
= atoi(pair
->value
);
1954 /* used to be for really old auth routine, dont support now */
1956 case 2: /* Yahoo ver 16 authentication */
1957 yahoo_auth16_stage1(gc
, seed
);
1961 GHashTable
*ui_info
= purple_core_get_ui_info();
1963 buf
= g_strdup_printf(_("The Yahoo server has requested the use of an unrecognized "
1964 "authentication method. You will probably not be able "
1965 "to successfully sign on to Yahoo. Check %s for updates."),
1966 ((ui_info
&& g_hash_table_lookup(ui_info
, "website")) ? (char *)g_hash_table_lookup(ui_info
, "website") : PURPLE_WEBSITE
));
1967 purple_notify_error(gc
, "",
1968 _("Failed Yahoo! Authentication"), buf
,
1969 purple_request_cpar_from_connection(gc
));
1971 yahoo_auth16_stage1(gc
, seed
); /* Can't hurt to try it anyway. */
1978 static void ignore_buddy(PurpleBuddy
*buddy
) {
1980 PurpleAccount
*account
;
1986 group
= purple_buddy_get_group(buddy
);
1987 name
= g_strdup(purple_buddy_get_name(buddy
));
1988 account
= purple_buddy_get_account(buddy
);
1990 purple_debug_info("yahoo", "blist: Removing '%s' from buddy list.\n", name
);
1991 purple_account_remove_buddy(account
, buddy
, group
);
1992 purple_blist_remove_buddy(buddy
);
1994 purple_serv_add_deny(purple_account_get_connection(account
), name
);
1999 static void keep_buddy(PurpleBuddy
*b
)
2001 purple_account_privacy_deny_remove(purple_buddy_get_account(b
),
2002 purple_buddy_get_name(b
), 1);
2005 static void yahoo_process_ignore(PurpleConnection
*gc
, struct yahoo_packet
*pkt
) {
2009 gchar buf
[BUF_LONG
];
2010 gboolean ignore
= TRUE
;
2013 for (l
= pkt
->hash
; l
; l
= l
->next
) {
2014 struct yahoo_pair
*pair
= l
->data
;
2015 switch (pair
->key
) {
2017 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2020 purple_debug_warning("yahoo", "yahoo_process_ignore "
2021 "got non-UTF-8 string for key %d\n", pair
->key
);
2026 /* 1 == ignore, 2 == unignore */
2027 ignore
= (strtol(pair
->value
, NULL
, 10) == 1);
2030 status
= strtol(pair
->value
, NULL
, 10);
2040 * 2 - already in ignore list, could not add
2041 * 3 - not in ignore list, could not delete
2042 * 12 - is a buddy, could not add (and possibly also a not-in-ignore list condition?)
2046 purple_debug_info("yahoo", "Server reported \"is a buddy\" for %s while %s",
2047 who
, (ignore
? "ignoring" : "unignoring"));
2050 b
= purple_blist_find_buddy(purple_connection_get_account(gc
), who
);
2051 g_snprintf(buf
, sizeof(buf
), _("You have tried to ignore %s, but the "
2052 "user is on your buddy list. Clicking \"Yes\" "
2053 "will remove and ignore the buddy."), who
);
2054 purple_request_yes_no(gc
, NULL
,
2055 _("Ignore buddy?"), buf
, 0,
2056 purple_request_cpar_from_connection(gc
),
2057 b
, G_CALLBACK(ignore_buddy
),
2058 G_CALLBACK(keep_buddy
));
2062 purple_debug_info("yahoo", "Server reported that %s is already in the ignore list.\n",
2066 purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete\n",
2074 #if TRY_WEBMESSENGER_LOGIN
2077 yahoo_try_webmessenger_login(PurpleConnection
*gc
)
2079 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
2080 PurpleHttpRequest
*req
;
2089 purple_input_remove(yd
->inpa
);
2093 req
= purple_http_request_new(WEBMESSENGER_URL
);
2094 purple_http_request_header_set(req
, "User-Agent", "Purple/" VERSION
);
2095 purple_http_connection_set_add(yd
->http_reqs
, purple_http_request(gc
,
2096 req
, yahoo_login_page_cb
, NULL
));
2097 purple_http_request_unref(req
);
2102 #endif /* TRY_WEBMESSENGER_LOGIN */
2104 static void yahoo_process_authresp(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
2106 GSList
*l
= pkt
->hash
;
2111 PurpleAccount
*account
= purple_connection_get_account(gc
);
2112 PurpleConnectionError reason
= PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
2115 struct yahoo_pair
*pair
= l
->data
;
2117 if (pair
->key
== 66) {
2118 err
= strtol(pair
->value
, NULL
, 10);
2119 } else if (pair
->key
== 20) {
2120 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2123 purple_debug_warning("yahoo", "yahoo_process_authresp "
2124 "got non-UTF-8 string for key %d\n", pair
->key
);
2133 msg
= g_strdup(_("Unknown error"));
2134 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
2137 msg
= g_strdup(_("Username does not exist"));
2138 reason
= PURPLE_CONNECTION_ERROR_INVALID_USERNAME
;
2141 #if TRY_WEBMESSENGER_LOGIN
2142 if (yahoo_try_webmessenger_login(gc
))
2145 purple_debug_info("yahoo", "Web messenger login is disabled\n");
2146 #endif /* TRY_WEBMESSENGER_LOGIN */
2147 if (!purple_account_get_remember_password(account
))
2148 purple_account_set_password(account
, NULL
, NULL
, NULL
);
2150 msg
= g_strdup(_("Invalid username or password"));
2151 reason
= PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
2154 msg
= g_strdup(_("Your account has been locked due to too many failed login attempts."
2155 " Please try logging into the Yahoo! website."));
2156 reason
= PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED
;
2159 /* See #9660. As much as we know, reconnecting shouldn't hurt */
2160 purple_debug_info("yahoo", "Got error 52, Set to autoreconnect\n");
2161 msg
= g_strdup(_("Unknown error 52. Reconnecting should fix this."));
2162 reason
= PURPLE_CONNECTION_ERROR_NETWORK_ERROR
;
2165 msg
= g_strdup(_("Error 1013: The username you have entered is invalid."
2166 " The most common cause of this error is entering your email"
2167 " address instead of your Yahoo! ID."));
2168 reason
= PURPLE_CONNECTION_ERROR_INVALID_USERNAME
;
2171 msg
= g_strdup_printf(_("Unknown error number %d. Logging into the Yahoo! website may fix this."), err
);
2175 fullmsg
= g_strdup_printf("%s\n%s", msg
, url
);
2177 fullmsg
= g_strdup(msg
);
2179 purple_connection_error(gc
, reason
, fullmsg
);
2184 static void yahoo_process_addbuddy(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
2190 char *decoded_group
;
2193 GSList
*l
= pkt
->hash
;
2194 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
2197 struct yahoo_pair
*pair
= l
->data
;
2199 switch (pair
->key
) {
2201 err
= strtol(pair
->value
, NULL
, 10);
2204 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2207 purple_debug_warning("yahoo", "yahoo_process_addbuddy "
2208 "got non-UTF-8 string for key %d\n", pair
->key
);
2212 group
= pair
->value
;
2224 who
= g_strdup(temp
);
2226 if (!err
|| (err
== 2)) { /* 0 = ok, 2 = already on serv list */
2227 f
= yahoo_friend_find_or_new(gc
, who
);
2228 yahoo_update_status(gc
, who
, f
);
2230 if( !g_hash_table_lookup(yd
->peers
, who
) ) {
2231 /* we are not connected as client, so set friend to not connected */
2232 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_NOT_CONNECTED
);
2233 f
->p2p_packet_sent
= 0;
2235 else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */
2236 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_WE_ARE_CLIENT
);
2241 decoded_group
= yahoo_string_decode(gc
, group
, FALSE
);
2242 buf
= g_strdup_printf(_("Unable to add buddy %s to group %s to the server list on account %s."),
2243 who
, decoded_group
, purple_connection_get_display_name(gc
));
2244 if (!purple_conversation_present_error(who
, purple_connection_get_account(gc
), buf
))
2245 purple_notify_error(gc
, NULL
, _("Unable to add buddy to server list"), buf
,
2246 purple_request_cpar_from_connection(gc
));
2248 g_free(decoded_group
);
2252 /* write pkt to the source */
2253 static void yahoo_p2p_write_pkt(gint source
, struct yahoo_packet
*pkt
)
2259 /*build the raw packet and send it to the host*/
2260 pkt_len
= yahoo_packet_build(pkt
, 0, 0, &raw_packet
);
2261 written
= write(source
, raw_packet
, pkt_len
);
2262 if (written
< 0 || (gsize
)written
!= pkt_len
)
2263 purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
2267 static void yahoo_p2p_keepalive_cb(gpointer key
, gpointer value
, gpointer user_data
)
2269 struct yahoo_p2p_data
*p2p_data
= value
;
2270 PurpleConnection
*gc
= user_data
;
2271 struct yahoo_packet
*pkt_to_send
;
2272 PurpleAccount
*account
;
2273 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
2275 account
= purple_connection_get_account(gc
);
2277 pkt_to_send
= yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
2278 yahoo_packet_hash(pkt_to_send
, "ssisi",
2279 4, purple_normalize(account
, purple_account_get_username(account
)),
2280 5, p2p_data
->host_username
,
2281 241, 0, /* Protocol identifier */
2284 yahoo_p2p_write_pkt(p2p_data
->source
, pkt_to_send
);
2286 yahoo_packet_free(pkt_to_send
);
2289 static gboolean
yahoo_p2p_keepalive(gpointer data
)
2291 PurpleConnection
*gc
= data
;
2292 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
2294 g_hash_table_foreach(yd
->peers
, yahoo_p2p_keepalive_cb
, gc
);
2299 /* destroy p2p_data associated with a peer and close p2p connection.
2300 * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer,
2301 * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */
2302 static void yahoo_p2p_disconnect_destroy_data(gpointer data
)
2304 struct yahoo_p2p_data
*p2p_data
;
2307 if(!(p2p_data
= data
))
2310 /* If friend, set him not connected */
2311 f
= yahoo_friend_find(p2p_data
->gc
, p2p_data
->host_username
);
2313 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_NOT_CONNECTED
);
2315 if(p2p_data
->source
>= 0)
2316 close(p2p_data
->source
);
2317 if (p2p_data
->input_event
> 0)
2318 purple_input_remove(p2p_data
->input_event
);
2319 g_free(p2p_data
->host_ip
);
2320 g_free(p2p_data
->host_username
);
2324 /* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */
2325 static void yahoo_p2p_process_p2pfilexfer(gpointer data
, gint source
, struct yahoo_packet
*pkt
)
2327 struct yahoo_p2p_data
*p2p_data
;
2329 GSList
*l
= pkt
->hash
;
2330 struct yahoo_packet
*pkt_to_send
;
2331 PurpleAccount
*account
;
2332 int val_13_to_send
= 0;
2336 if(!(p2p_data
= data
))
2339 yd
= purple_connection_get_protocol_data(p2p_data
->gc
);
2341 /* lets see whats in the packet */
2343 struct yahoo_pair
*pair
= l
->data
;
2345 switch (pair
->key
) {
2347 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2349 if(strncmp(who
, p2p_data
->host_username
, strlen(p2p_data
->host_username
)) != 0) {
2350 /* from whom are we receiving the packets ?? */
2351 purple_debug_warning("yahoo","p2p: received data from wrong user\n");
2355 purple_debug_warning("yahoo", "yahoo_p2p_process_p2pfilexfer "
2356 "got non-UTF-8 string for key %d\n", pair
->key
);
2360 p2p_data
->val_13
= strtol(pair
->value
, NULL
, 10); /* Value should be 5-7 */
2362 /* case 5, 49 look laters, no use right now */
2367 account
= purple_connection_get_account(p2p_data
->gc
);
2369 /* key_13: sort of a counter.
2370 * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5,
2371 * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive.
2372 * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5,
2373 * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */
2375 switch(p2p_data
->val_13
) {
2376 case 1 : val_13_to_send
= 5; break;
2377 case 5 : val_13_to_send
= 6; break;
2378 case 6 : val_13_to_send
= 7; break;
2379 case 7 : if( g_hash_table_lookup(yd
->peers
, p2p_data
->host_username
) )
2381 val_13_to_send
= 7; break;
2382 default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n");
2386 /* Build the yahoo packet */
2387 pkt_to_send
= yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
2388 yahoo_packet_hash(pkt_to_send
, "ssisi",
2389 4, purple_normalize(account
, purple_account_get_username(account
)),
2390 5, p2p_data
->host_username
,
2391 241, 0, /* Protocol identifier */
2393 13, val_13_to_send
);
2395 /* build the raw packet and send it to the host */
2396 yahoo_p2p_write_pkt(source
, pkt_to_send
);
2397 yahoo_packet_free(pkt_to_send
);
2399 if( val_13_to_send
== 7 )
2400 if( !g_hash_table_lookup(yd
->peers
, p2p_data
->host_username
) ) {
2401 g_hash_table_insert(yd
->peers
, g_strdup(p2p_data
->host_username
), p2p_data
);
2402 /* If the peer is a friend, set him connected */
2403 f
= yahoo_friend_find(p2p_data
->gc
, p2p_data
->host_username
);
2405 if(p2p_data
->connection_type
== YAHOO_P2P_WE_ARE_SERVER
) {
2406 p2p_data
->session_id
= f
->session_id
;
2407 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_WE_ARE_SERVER
);
2410 yahoo_friend_set_p2p_status(f
, YAHOO_P2PSTATUS_WE_ARE_CLIENT
);
2415 /* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */
2416 static void yahoo_p2p_read_pkt_cb(gpointer data
, gint source
, PurpleInputCondition cond
)
2418 guchar buf
[1024]; /* is it safe to assume a fixed array length of 1024 ?? */
2422 struct yahoo_packet
*pkt
;
2424 struct yahoo_p2p_data
*p2p_data
;
2427 if(!(p2p_data
= data
))
2429 yd
= purple_connection_get_protocol_data(p2p_data
->gc
);
2431 len
= read(source
, buf
, sizeof(buf
));
2432 if ((len
< 0) && ((errno
== EAGAIN
) || (errno
== EWOULDBLOCK
)))
2433 return ; /* No Worries*/
2436 purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n");
2437 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
2438 if( g_hash_table_lookup(yd
->peers
, p2p_data
->host_username
) )
2439 g_hash_table_remove(yd
->peers
,p2p_data
->host_username
);
2441 yahoo_p2p_disconnect_destroy_data(data
);
2445 /* TODO: It looks like there's a bug here (and above) where an incorrect
2446 * assumtion is being made that the buffer will be added to when this
2447 * is next called, but that's not really the case! */
2448 if(len
< YAHOO_PACKET_HDRLEN
)
2451 if(strncmp((char *)buf
, "YMSG", 4) != 0) {
2452 /* Not a YMSG packet */
2453 purple_debug_warning("yahoo", "p2p: Got something other than YMSG packet\n");
2455 start
= (guchar
*) g_strstr_len((char *) buf
+ 1, len
- 1 ,"YMSG");
2456 if (start
== NULL
) {
2457 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
2458 if (g_hash_table_lookup(yd
->peers
, p2p_data
->host_username
))
2459 g_hash_table_remove(yd
->peers
, p2p_data
->host_username
);
2461 yahoo_p2p_disconnect_destroy_data(data
);
2464 purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
2466 len
-= (start
- buf
);
2467 g_memmove(buf
, start
, len
);
2470 pos
+= 4; /* YMSG */
2474 pktlen
= yahoo_get16(buf
+ pos
); pos
+= 2;
2475 if (len
< (YAHOO_PACKET_HDRLEN
+ pktlen
)) {
2476 purple_debug_error("yahoo", "p2p: packet length(%d) > buffer length(%d)\n",
2477 pktlen
, (len
- pos
));
2478 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
2479 if (g_hash_table_lookup(yd
->peers
, p2p_data
->host_username
))
2480 g_hash_table_remove(yd
->peers
, p2p_data
->host_username
);
2482 yahoo_p2p_disconnect_destroy_data(data
);
2485 purple_debug_misc("yahoo", "p2p: %d bytes to read\n", pktlen
);
2487 pkt
= yahoo_packet_new(0, 0, 0);
2488 pkt
->service
= yahoo_get16(buf
+ pos
); pos
+= 2;
2489 pkt
->status
= yahoo_get32(buf
+ pos
); pos
+= 4;
2490 pkt
->id
= yahoo_get32(buf
+ pos
); pos
+= 4;
2492 purple_debug_misc("yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt
->service
, pkt
->status
);
2493 yahoo_packet_read(pkt
, buf
+ pos
, pktlen
);
2495 /* packet processing */
2496 switch(pkt
->service
) {
2497 case YAHOO_SERVICE_P2PFILEXFER
:
2498 yahoo_p2p_process_p2pfilexfer(data
, source
, pkt
);
2500 case YAHOO_SERVICE_MESSAGE
:
2501 yahoo_process_message(p2p_data
->gc
, pkt
, YAHOO_PKT_TYPE_P2P
);
2503 case YAHOO_SERVICE_NOTIFY
:
2504 yahoo_process_notify(p2p_data
->gc
, pkt
, YAHOO_PKT_TYPE_P2P
);
2507 purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt
->service
);
2510 yahoo_packet_free(pkt
);
2513 static void yahoo_p2p_server_send_connected_cb(gpointer data
, gint source
, PurpleInputCondition cond
)
2516 struct yahoo_p2p_data
*p2p_data
;
2519 if(!(p2p_data
= data
))
2521 yd
= purple_connection_get_protocol_data(p2p_data
->gc
);
2523 acceptfd
= accept(source
, NULL
, 0);
2524 if(acceptfd
== -1 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
))
2526 else if(acceptfd
== -1) {
2527 purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno
));
2528 yahoo_p2p_disconnect_destroy_data(data
);
2532 /* remove timeout */
2533 if (yd
->yahoo_p2p_server_timeout_handle
) {
2534 purple_timeout_remove(yd
->yahoo_p2p_server_timeout_handle
);
2535 yd
->yahoo_p2p_server_timeout_handle
= 0;
2538 /* remove watcher and close p2p server */
2539 if (yd
->yahoo_p2p_server_watcher
) {
2540 purple_input_remove(yd
->yahoo_p2p_server_watcher
);
2541 yd
->yahoo_p2p_server_watcher
= 0;
2543 if (yd
->yahoo_local_p2p_server_fd
>= 0) {
2544 close(yd
->yahoo_local_p2p_server_fd
);
2545 yd
->yahoo_local_p2p_server_fd
= -1;
2548 /* Add an Input Read event to the file descriptor */
2549 p2p_data
->input_event
= purple_input_add(acceptfd
, PURPLE_INPUT_READ
, yahoo_p2p_read_pkt_cb
, data
);
2550 p2p_data
->source
= acceptfd
;
2553 static gboolean
yahoo_cancel_p2p_server_listen_cb(gpointer data
)
2555 struct yahoo_p2p_data
*p2p_data
;
2558 if(!(p2p_data
= data
))
2561 yd
= purple_connection_get_protocol_data(p2p_data
->gc
);
2563 purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect\n");
2564 yahoo_p2p_disconnect_destroy_data(data
);
2565 purple_input_remove(yd
->yahoo_p2p_server_watcher
);
2566 yd
->yahoo_p2p_server_watcher
= 0;
2567 close(yd
->yahoo_local_p2p_server_fd
);
2568 yd
->yahoo_local_p2p_server_fd
= -1;
2569 yd
->yahoo_p2p_server_timeout_handle
= 0;
2574 static void yahoo_p2p_server_listen_cb(int listenfd
, gpointer data
)
2576 struct yahoo_p2p_data
*p2p_data
;
2579 if(!(p2p_data
= data
))
2582 yd
= purple_connection_get_protocol_data(p2p_data
->gc
);
2583 yd
->listen_data
= NULL
;
2585 if(listenfd
== -1) {
2586 purple_debug_warning("yahoo","p2p: error starting p2p server\n");
2587 yahoo_p2p_disconnect_destroy_data(data
);
2591 /* Add an Input Read event to the file descriptor */
2592 yd
->yahoo_local_p2p_server_fd
= listenfd
;
2593 yd
->yahoo_p2p_server_watcher
= purple_input_add(listenfd
, PURPLE_INPUT_READ
, yahoo_p2p_server_send_connected_cb
,data
);
2596 yd
->yahoo_p2p_server_timeout_handle
= purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT
, yahoo_cancel_p2p_server_listen_cb
, data
);
2599 /* send p2p pkt containing our encoded ip, asking peer to connect to us */
2600 void yahoo_send_p2p_pkt(PurpleConnection
*gc
, const char *who
, int val_13
)
2602 const char *public_ip
;
2606 gchar
*base64_ip
= NULL
;
2608 struct yahoo_packet
*pkt
;
2609 PurpleAccount
*account
;
2610 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
2611 struct yahoo_p2p_data
*p2p_data
;
2612 const char *norm_username
;
2614 f
= yahoo_friend_find(gc
, who
);
2615 account
= purple_connection_get_account(gc
);
2617 /* Do not send invitation if already listening for other connection */
2618 if(yd
->yahoo_local_p2p_server_fd
>= 0)
2621 /* One shouldn't try to connect to self */
2622 if( strcmp(purple_normalize(account
, purple_account_get_username(account
)), who
) == 0)
2625 /* send packet to only those friends who arent p2p connected and to whom we havent already sent. Do not send if this condition doesn't hold good */
2626 if( !( f
&& (yahoo_friend_get_p2p_status(f
) == YAHOO_P2PSTATUS_NOT_CONNECTED
) && (f
->p2p_packet_sent
== 0)) )
2629 /* Finally, don't try to connect to buddies not online or on sms */
2630 if( (f
->status
== YAHOO_STATUS_OFFLINE
) || f
->sms
)
2633 public_ip
= purple_network_get_public_ip();
2634 if( (sscanf(public_ip
, "%u.%u.%u.%u", &temp
[0], &temp
[1], &temp
[2], &temp
[3])) !=4 )
2637 ip
= (temp
[3] << 24) | (temp
[2] <<16) | (temp
[1] << 8) | temp
[0];
2638 sprintf(temp_str
, "%d", ip
);
2639 base64_ip
= purple_base64_encode( (guchar
*)temp_str
, strlen(temp_str
) );
2641 norm_username
= purple_normalize(account
, purple_account_get_username(account
));
2642 pkt
= yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER
, YAHOO_STATUS_AVAILABLE
, 0);
2643 yahoo_packet_hash(pkt
, "sssissis",
2646 12, base64_ip
, /* base64 encode ip */
2647 61, 0, /* To-do : figure out what is 61 for?? */
2652 yahoo_packet_send_and_free(pkt
, yd
);
2654 f
->p2p_packet_sent
= 1; /* set p2p_packet_sent to sent */
2656 p2p_data
= g_new0(struct yahoo_p2p_data
, 1);
2659 p2p_data
->host_ip
= NULL
;
2660 p2p_data
->host_username
= g_strdup(who
);
2661 p2p_data
->val_13
= val_13
;
2662 p2p_data
->connection_type
= YAHOO_P2P_WE_ARE_SERVER
;
2663 p2p_data
->source
= -1;
2665 /* FIXME: If the port is already used, purple_network_listener returns NULL and old listener won't be canceled
2666 * in yahoo_close function. */
2667 if (yd
->listen_data
)
2668 purple_debug_warning("yahoo","p2p: Failed to create p2p server - server already exists\n");
2670 yd
->listen_data
= purple_network_listen(YAHOO_PAGER_PORT_P2P
, AF_UNSPEC
, SOCK_STREAM
, TRUE
, yahoo_p2p_server_listen_cb
, p2p_data
);
2671 if (yd
->listen_data
== NULL
)
2672 purple_debug_warning("yahoo","p2p: Failed to created p2p server\n");
2678 /* function called when connection to p2p host is setup */
2679 static void yahoo_p2p_init_cb(gpointer data
, gint source
, const gchar
*error_message
)
2681 struct yahoo_p2p_data
*p2p_data
;
2682 struct yahoo_packet
*pkt_to_send
;
2683 PurpleAccount
*account
;
2687 yd
= purple_connection_get_protocol_data(p2p_data
->gc
);
2689 if(error_message
!= NULL
) {
2690 purple_debug_warning("yahoo","p2p: %s\n",error_message
);
2691 yahoo_send_p2p_pkt(p2p_data
->gc
, p2p_data
->host_username
, 2);/* send p2p init packet with val_13=2 */
2693 yahoo_p2p_disconnect_destroy_data(p2p_data
);
2697 /* Add an Input Read event to the file descriptor */
2698 p2p_data
->input_event
= purple_input_add(source
, PURPLE_INPUT_READ
, yahoo_p2p_read_pkt_cb
, data
);
2699 p2p_data
->source
= source
;
2701 account
= purple_connection_get_account(p2p_data
->gc
);
2703 /* Build the yahoo packet */
2704 pkt_to_send
= yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
2705 yahoo_packet_hash(pkt_to_send
, "ssisi",
2706 4, purple_normalize(account
, purple_account_get_username(account
)),
2707 5, p2p_data
->host_username
,
2708 241, 0, /* Protocol identifier */
2710 13, 1); /* we receive key13= 0 or 2, we send key13=1 */
2712 yahoo_p2p_write_pkt(source
, pkt_to_send
); /* build raw packet and send */
2713 yahoo_packet_free(pkt_to_send
);
2716 static void yahoo_process_p2p(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
2718 GSList
*l
= pkt
->hash
;
2720 char *base64
= NULL
;
2725 PurpleAccount
*account
;
2728 /* if status is not YAHOO_STATUS_BRB or YAHOO_STATUS_P2P, the packet bounced back,
2729 * so it contains our own ip */
2730 if(pkt
->status
!= YAHOO_STATUS_BRB
&& pkt
->status
!= YAHOO_STATUS_P2P
)
2734 struct yahoo_pair
*pair
= l
->data
;
2736 switch (pair
->key
) {
2741 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2744 purple_debug_warning("yahoo", "yahoo_process_p2p "
2745 "got non-UTF-8 string for key %d\n", pair
->key
);
2749 /* who again, the master identity this time? */
2752 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2753 base64
= pair
->value
;
2754 /* so, this is an ip address. in base64. decoded it's in ascii.
2755 after strtol, it's in reversed byte order. Who thought this up?*/
2757 purple_debug_warning("yahoo", "yahoo_process_p2p "
2758 "got non-UTF-8 string for key %d\n", pair
->key
);
2762 val_13
= strtol(pair
->value
, NULL
, 10);
2765 val_11
= strtol(pair
->value
, NULL
, 10); /* session id of peer */
2766 if( (f
= yahoo_friend_find(gc
, who
)) )
2767 f
->session_id
= val_11
;
2770 TODO: figure these out
2771 yahoo: Key: 61 Value: 0
2772 yahoo: Key: 2 Value:
2773 yahoo: Key: 13 Value: 0 packet count ??
2774 yahoo: Key: 49 Value: PEERTOPEER
2775 yahoo: Key: 140 Value: 1
2786 char *host_ip
, *tmp
;
2787 struct yahoo_p2p_data
*p2p_data
;
2789 decoded
= purple_base64_decode(base64
, &len
);
2790 if (decoded
== NULL
) {
2791 purple_debug_info("yahoo","p2p: Unable to decode base64 IP (%s) \n", base64
);
2794 tmp
= purple_str_binary_to_ascii(decoded
, len
);
2795 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who
, tmp
);
2798 ip
= strtol((gchar
*)decoded
, NULL
, 10);
2800 host_ip
= g_strdup_printf("%u.%u.%u.%u", ip
& 0xff, (ip
>> 8) & 0xff, (ip
>> 16) & 0xff,
2802 f
= yahoo_friend_find(gc
, who
);
2804 yahoo_friend_set_ip(f
, host_ip
);
2805 purple_debug_info("yahoo", "IP : %s\n", host_ip
);
2807 account
= purple_connection_get_account(gc
);
2813 val_11
= f
->session_id
;
2816 p2p_data
= g_new0(struct yahoo_p2p_data
, 1);
2817 p2p_data
->host_username
= g_strdup(who
);
2818 p2p_data
->val_13
= val_13
;
2819 p2p_data
->session_id
= val_11
;
2820 p2p_data
->host_ip
= host_ip
;
2822 p2p_data
->connection_type
= YAHOO_P2P_WE_ARE_CLIENT
;
2823 p2p_data
->source
= -1;
2825 /* connect to host */
2826 if((purple_proxy_connect(gc
, account
, host_ip
, YAHOO_PAGER_PORT_P2P
, yahoo_p2p_init_cb
, p2p_data
))==NULL
) {
2827 purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip
);
2828 g_free(p2p_data
->host_ip
);
2829 g_free(p2p_data
->host_username
);
2835 static void yahoo_process_audible(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
2837 PurpleAccount
*account
;
2838 char *who
= NULL
, *msg
= NULL
, *id
= NULL
;
2839 GSList
*l
= pkt
->hash
;
2841 account
= purple_connection_get_account(gc
);
2844 struct yahoo_pair
*pair
= l
->data
;
2846 switch (pair
->key
) {
2848 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2851 purple_debug_warning("yahoo", "yahoo_process_audible "
2852 "got non-UTF-8 string for key %d\n", pair
->key
);
2859 /* the audible, in foo.locale.bar.baz format
2860 eg: base.tw.smiley.smiley43 */
2861 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2864 purple_debug_warning("yahoo", "yahoo_process_audible "
2865 "got non-UTF-8 string for key %d\n", pair
->key
);
2869 /* the text of the audible */
2870 if (g_utf8_validate(pair
->value
, -1, NULL
)) {
2873 purple_debug_warning("yahoo", "yahoo_process_audible "
2874 "got non-UTF-8 string for key %d\n", pair
->key
);
2878 /* SHA-1 hash of audible SWF file (eg: 4e8691499d9c0fb8374478ff9720f4a9ea4a4915) */
2889 if (!g_utf8_validate(msg
, -1, NULL
)) {
2890 purple_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n");
2893 if (!purple_account_privacy_check(account
, who
)) {
2894 purple_debug_misc("yahoo", "Audible message from %s for %s dropped!\n",
2895 purple_account_get_username(account
), who
);
2899 /* "http://l.yimg.com/pu/dl/aud/"+locale+"/"+id+".swf" */
2900 char **audible_locale
= g_strsplit(id
, ".", 0);
2901 char *buf
= g_strdup_printf(_("[ Audible %s/%s/%s.swf ] %s"), YAHOO_AUDIBLE_URL
, audible_locale
[1], id
, msg
);
2902 g_strfreev(audible_locale
);
2904 purple_serv_got_im(gc
, who
, buf
, 0, time(NULL
));
2907 purple_serv_got_im(gc
, who
, msg
, 0, time(NULL
));
2910 static void yahoo_packet_process(PurpleConnection
*gc
, struct yahoo_packet
*pkt
)
2912 switch (pkt
->service
) {
2913 case YAHOO_SERVICE_LOGON
:
2914 case YAHOO_SERVICE_LOGOFF
:
2915 case YAHOO_SERVICE_ISAWAY
:
2916 case YAHOO_SERVICE_ISBACK
:
2917 case YAHOO_SERVICE_GAMELOGON
:
2918 case YAHOO_SERVICE_GAMELOGOFF
:
2919 case YAHOO_SERVICE_CHATLOGON
:
2920 case YAHOO_SERVICE_CHATLOGOFF
:
2921 case YAHOO_SERVICE_Y6_STATUS_UPDATE
:
2922 case YAHOO_SERVICE_STATUS_15
:
2923 yahoo_process_status(gc
, pkt
);
2925 case YAHOO_SERVICE_NOTIFY
:
2926 yahoo_process_notify(gc
, pkt
, YAHOO_PKT_TYPE_SERVER
);
2928 case YAHOO_SERVICE_MESSAGE
:
2929 case YAHOO_SERVICE_GAMEMSG
:
2930 case YAHOO_SERVICE_CHATMSG
:
2931 yahoo_process_message(gc
, pkt
, YAHOO_PKT_TYPE_SERVER
);
2933 case YAHOO_SERVICE_SYSMESSAGE
:
2934 yahoo_process_sysmessage(gc
, pkt
);
2936 case YAHOO_SERVICE_NEWMAIL
:
2937 yahoo_process_mail(gc
, pkt
);
2939 case YAHOO_SERVICE_NEWCONTACT
:
2940 yahoo_process_contact(gc
, pkt
);
2942 case YAHOO_SERVICE_AUTHRESP
:
2943 yahoo_process_authresp(gc
, pkt
);
2945 case YAHOO_SERVICE_LIST
:
2946 yahoo_process_list(gc
, pkt
);
2948 case YAHOO_SERVICE_LIST_15
:
2949 yahoo_process_list_15(gc
, pkt
);
2951 case YAHOO_SERVICE_AUTH
:
2952 yahoo_process_auth(gc
, pkt
);
2954 case YAHOO_SERVICE_AUTH_REQ_15
:
2955 yahoo_buddy_auth_req_15(gc
, pkt
);
2957 case YAHOO_SERVICE_ADDBUDDY
:
2958 yahoo_process_addbuddy(gc
, pkt
);
2960 case YAHOO_SERVICE_IGNORECONTACT
:
2961 yahoo_process_ignore(gc
, pkt
);
2963 case YAHOO_SERVICE_CONFINVITE
:
2964 case YAHOO_SERVICE_CONFADDINVITE
:
2965 yahoo_process_conference_invite(gc
, pkt
);
2967 case YAHOO_SERVICE_CONFDECLINE
:
2968 yahoo_process_conference_decline(gc
, pkt
);
2970 case YAHOO_SERVICE_CONFLOGON
:
2971 yahoo_process_conference_logon(gc
, pkt
);
2973 case YAHOO_SERVICE_CONFLOGOFF
:
2974 yahoo_process_conference_logoff(gc
, pkt
);
2976 case YAHOO_SERVICE_CONFMSG
:
2977 yahoo_process_conference_message(gc
, pkt
);
2979 case YAHOO_SERVICE_CHATONLINE
:
2980 yahoo_process_chat_online(gc
, pkt
);
2982 case YAHOO_SERVICE_CHATLOGOUT
:
2983 yahoo_process_chat_logout(gc
, pkt
);
2985 case YAHOO_SERVICE_CHATGOTO
:
2986 yahoo_process_chat_goto(gc
, pkt
);
2988 case YAHOO_SERVICE_CHATJOIN
:
2989 yahoo_process_chat_join(gc
, pkt
);
2991 case YAHOO_SERVICE_CHATLEAVE
: /* XXX is this right? */
2992 case YAHOO_SERVICE_CHATEXIT
:
2993 yahoo_process_chat_exit(gc
, pkt
);
2995 case YAHOO_SERVICE_CHATINVITE
: /* XXX never seen this one, might not do it right */
2996 case YAHOO_SERVICE_CHATADDINVITE
:
2997 yahoo_process_chat_addinvite(gc
, pkt
);
2999 case YAHOO_SERVICE_COMMENT
:
3000 yahoo_process_chat_message(gc
, pkt
);
3002 case YAHOO_SERVICE_PRESENCE_PERM
:
3003 case YAHOO_SERVICE_PRESENCE_SESSION
:
3004 yahoo_process_presence(gc
, pkt
);
3006 case YAHOO_SERVICE_P2PFILEXFER
:
3007 /* This case had no break and continued; thus keeping it this way.*/
3008 yahoo_process_p2p(gc
, pkt
); /* P2PFILEXFER handled the same way as process_p2p */
3009 yahoo_process_p2pfilexfer(gc
, pkt
); /* redundant ??, need to have a break now */
3010 case YAHOO_SERVICE_FILETRANSFER
:
3011 purple_debug_error("yahoo", "Legacy file transfers are not "
3012 "supported anymore.\n");
3014 case YAHOO_SERVICE_PEERTOPEER
:
3015 yahoo_process_p2p(gc
, pkt
);
3017 case YAHOO_SERVICE_PICTURE
:
3018 yahoo_process_picture(gc
, pkt
);
3020 case YAHOO_SERVICE_PICTURE_CHECKSUM
:
3021 yahoo_process_picture_checksum(gc
, pkt
);
3023 case YAHOO_SERVICE_PICTURE_UPLOAD
:
3024 yahoo_process_picture_upload(gc
, pkt
);
3026 case YAHOO_SERVICE_PICTURE_UPDATE
:
3027 case YAHOO_SERVICE_AVATAR_UPDATE
:
3028 yahoo_process_avatar_update(gc
, pkt
);
3030 case YAHOO_SERVICE_AUDIBLE
:
3031 yahoo_process_audible(gc
, pkt
);
3033 case YAHOO_SERVICE_CONTACT_DETAILS
:
3034 yahoo_process_contact_details(gc
, pkt
);
3036 case YAHOO_SERVICE_FILETRANS_15
:
3037 yahoo_process_filetrans_15(gc
, pkt
);
3039 case YAHOO_SERVICE_FILETRANS_INFO_15
:
3040 yahoo_process_filetrans_info_15(gc
, pkt
);
3042 case YAHOO_SERVICE_FILETRANS_ACC_15
:
3043 yahoo_process_filetrans_acc_15(gc
, pkt
);
3045 case YAHOO_SERVICE_SMS_MSG
:
3046 yahoo_process_sms_message(gc
, pkt
);
3050 purple_debug_error("yahoo", "Unhandled service 0x%02x\n", pkt
->service
);
3055 static void yahoo_pending(gpointer data
, gint source
, PurpleInputCondition cond
)
3057 PurpleConnection
*gc
= data
;
3058 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
3062 len
= read(yd
->fd
, buf
, sizeof(buf
));
3067 if (errno
== EAGAIN
)
3071 tmp
= g_strdup_printf(_("Lost connection with server: %s"),
3073 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
, tmp
);
3076 } else if (len
== 0) {
3077 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3078 _("Server closed the connection"));
3081 purple_connection_update_last_received(gc
);
3082 yd
->rxqueue
= g_realloc(yd
->rxqueue
, len
+ yd
->rxlen
);
3083 memcpy(yd
->rxqueue
+ yd
->rxlen
, buf
, len
);
3087 struct yahoo_packet
*pkt
;
3091 if (yd
->rxlen
< YAHOO_PACKET_HDRLEN
)
3094 if (strncmp((char *)yd
->rxqueue
, "YMSG", MIN(4, yd
->rxlen
)) != 0) {
3095 /* HEY! This isn't even a YMSG packet. What
3096 * are you trying to pull? */
3099 purple_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!\n");
3101 start
= memchr(yd
->rxqueue
+ 1, 'Y', yd
->rxlen
- 1);
3103 g_memmove(yd
->rxqueue
, start
, yd
->rxlen
- (start
- yd
->rxqueue
));
3104 yd
->rxlen
-= start
- yd
->rxqueue
;
3107 g_free(yd
->rxqueue
);
3114 pos
+= 4; /* YMSG */
3118 pktlen
= yahoo_get16(yd
->rxqueue
+ pos
); pos
+= 2;
3119 purple_debug_misc("yahoo", "%d bytes to read, rxlen is %d\n", pktlen
, yd
->rxlen
);
3121 if (yd
->rxlen
< (YAHOO_PACKET_HDRLEN
+ pktlen
))
3124 yahoo_packet_dump(yd
->rxqueue
, YAHOO_PACKET_HDRLEN
+ pktlen
);
3126 pkt
= yahoo_packet_new(0, 0, 0);
3128 pkt
->service
= yahoo_get16(yd
->rxqueue
+ pos
); pos
+= 2;
3129 pkt
->status
= yahoo_get32(yd
->rxqueue
+ pos
); pos
+= 4;
3130 purple_debug_misc("yahoo", "Yahoo Service: 0x%02x Status: %d\n",
3131 pkt
->service
, pkt
->status
);
3132 pkt
->id
= yahoo_get32(yd
->rxqueue
+ pos
); pos
+= 4;
3134 yahoo_packet_read(pkt
, yd
->rxqueue
+ pos
, pktlen
);
3136 yd
->rxlen
-= YAHOO_PACKET_HDRLEN
+ pktlen
;
3138 guchar
*tmp
= g_memdup(yd
->rxqueue
+ YAHOO_PACKET_HDRLEN
+ pktlen
, yd
->rxlen
);
3139 g_free(yd
->rxqueue
);
3142 g_free(yd
->rxqueue
);
3146 yahoo_packet_process(gc
, pkt
);
3148 yahoo_packet_free(pkt
);
3152 static void yahoo_got_connected(gpointer data
, gint source
, const gchar
*error_message
)
3154 PurpleConnection
*gc
= data
;
3156 struct yahoo_packet
*pkt
;
3160 tmp
= g_strdup_printf(_("Unable to connect: %s"), error_message
);
3161 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
, tmp
);
3166 yd
= purple_connection_get_protocol_data(gc
);
3169 pkt
= yahoo_packet_new(YAHOO_SERVICE_AUTH
, yd
->current_status
, yd
->session_id
);
3171 yahoo_packet_hash_str(pkt
, 1, purple_normalize(purple_connection_get_account(gc
), purple_account_get_username(purple_connection_get_account(gc
))));
3172 yahoo_packet_send_and_free(pkt
, yd
);
3174 yd
->inpa
= purple_input_add(yd
->fd
, PURPLE_INPUT_READ
, yahoo_pending
, gc
);
3177 #if TRY_WEBMESSENGER_LOGIN
3179 static void yahoo_got_web_connected(gpointer data
, gint source
, const gchar
*error_message
)
3181 PurpleConnection
*gc
= data
;
3183 struct yahoo_packet
*pkt
;
3187 tmp
= g_strdup_printf(_("Unable to connect: %s"), error_message
);
3188 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
, tmp
);
3193 yd
= purple_connection_get_protocol_data(gc
);
3196 pkt
= yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN
, YAHOO_STATUS_WEBLOGIN
, yd
->session_id
);
3198 yahoo_packet_hash(pkt
, "sss", 0,
3199 purple_normalize(purple_connection_get_account(gc
), purple_account_get_username(purple_connection_get_account(gc
))),
3200 1, purple_normalize(purple_connection_get_account(gc
), purple_account_get_username(purple_connection_get_account(gc
))),
3202 yahoo_packet_send_and_free(pkt
, yd
);
3205 yd
->inpa
= purple_input_add(yd
->fd
, PURPLE_INPUT_READ
, yahoo_pending
, gc
);
3209 yahoo_login_page_got(PurpleHttpConnection
*hc
, PurpleHttpResponse
*resp
,
3212 PurpleConnection
*gc
= purple_http_conn_get_purple_connection(hc
);
3213 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
3214 PurpleAccount
*account
= purple_connection_get_account(gc
);
3215 PurpleHttpCookieJar
*cjar
;
3219 if (purple_http_response_get_code(resp
) != 302) {
3220 purple_connection_error(gc
,
3221 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3222 _("Unable to connect"));
3226 auth_s
= g_string_new(NULL
);
3227 cjar
= purple_http_conn_get_cookie_jar(hc
);
3228 cookie
= purple_http_cookie_jar_get(cjar
, "B");
3230 g_string_append_printf(auth_s
, "B=%s; ", cookie
);
3233 cookie
= purple_http_cookie_jar_get(cjar
, "T");
3235 g_string_append_printf(auth_s
, "T=%s; ", cookie
);
3238 cookie
= purple_http_cookie_jar_get(cjar
, "Y");
3240 g_string_append_printf(auth_s
, "Y=%s; ", cookie
);
3244 yd
->auth
= g_string_free(auth_s
, FALSE
);
3245 /* Now we have our cookies to login with. I'll go get the milk. */
3247 /* XXX: wcs2.msg.dcn.yahoo.com is down, so I used
3248 * YAHOO_PAGER_HOST_FALLBACK, but I'm not sure, if it is the correct
3251 if (purple_proxy_connect(gc
, account
, YAHOO_PAGER_HOST_FALLBACK
,
3252 purple_account_get_int(account
, "port", YAHOO_PAGER_PORT
),
3253 yahoo_got_web_connected
, gc
) == NULL
)
3255 purple_connection_error(gc
,
3256 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3257 _("Unable to connect"));
3262 static void yahoo_login_page_hash_iter(const char *key
, const char *val
, GString
*url
)
3264 if (!strcmp(key
, "passwd") || !strcmp(key
, "login"))
3266 g_string_append_c(url
, '&');
3267 g_string_append(url
, key
);
3268 g_string_append_c(url
, '=');
3269 if (!strcmp(key
, ".save") || !strcmp(key
, ".js"))
3270 g_string_append_c(url
, '1');
3271 else if (!strcmp(key
, ".challenge"))
3272 g_string_append(url
, val
);
3274 g_string_append(url
, purple_url_encode(val
));
3277 static GHashTable
*yahoo_login_page_hash(const char *buf
, size_t len
)
3279 GHashTable
*hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
3280 const char *c
= buf
;
3282 char name
[64], value
[64];
3284 int input_len
= strlen("<input ");
3285 int name_len
= strlen("name=\"");
3286 int value_len
= strlen("value=\"");
3287 while ((len
> ((c
- buf
) + input_len
))
3288 && (c
= strstr(c
, "<input "))) {
3289 if (!(c
= g_strstr_len(c
, len
- (c
- buf
), "name=\"")))
3292 count
= sizeof(name
)-1;
3293 for (d
= name
; (len
> ((c
- buf
) + 1)) && *c
!='"'
3294 && count
; c
++, d
++, count
--)
3297 count
= sizeof(value
)-1;
3298 if (!(d
= g_strstr_len(c
, len
- (c
- buf
), "value=\"")))
3301 if (strchr(c
, '>') < d
)
3303 for (c
= d
, d
= value
; (len
> ((c
- buf
) + 1))
3304 && *c
!='"' && count
; c
++, d
++, count
--)
3307 g_hash_table_insert(hash
, g_strdup(name
), g_strdup(value
));
3313 yahoo_login_page_cb(PurpleHttpConnection
*http_conn
,
3314 PurpleHttpResponse
*response
, gpointer _unused
)
3316 PurpleConnection
*gc
= purple_http_conn_get_purple_connection(http_conn
);
3317 PurpleAccount
*account
= purple_connection_get_account(gc
);
3318 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
3319 const char *pass
= purple_connection_get_password(gc
);
3321 const gchar
*got_data
;
3324 char md5
[33], *hashp
= md5
, *chal
;
3326 PurpleCipher
*cipher
;
3328 PurpleHttpRequest
*req
;
3330 if (!purple_http_response_is_successful(response
))
3332 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3333 purple_http_response_get_error(response
));
3337 got_data
= purple_http_response_get_data(response
, &len
);
3338 hash
= yahoo_login_page_hash(got_data
, len
);
3340 cipher
= purple_md5_cipher_new();
3342 purple_cipher_append(cipher
, (const guchar
*)pass
, strlen(pass
));
3343 purple_cipher_digest(cipher
, digest
, sizeof(digest
));
3344 for (i
= 0; i
< 16; ++i
) {
3345 g_snprintf(hashp
, 3, "%02x", digest
[i
]);
3349 chal
= g_strconcat(md5
, g_hash_table_lookup(hash
, ".challenge"), NULL
);
3350 purple_cipher_reset(cipher
);
3351 purple_cipher_append(cipher
, (const guchar
*)chal
, strlen(chal
));
3352 purple_cipher_digest(cipher
, digest
, sizeof(digest
));
3354 for (i
= 0; i
< 16; ++i
) {
3355 g_snprintf(hashp
, 3, "%02x", digest
[i
]);
3359 * I dunno why this is here and commented out.. but in case it's needed
3362 purple_cipher_reset(cipher);
3363 purple_cipher_append(cipher, md5, strlen(md5));
3364 purple_cipher_digest(cipher, sizeof(digest), digest, NULL);
3366 for (i = 0; i < 16; ++i) {
3367 g_snprintf(hashp, 3, "%02x", digest[i]);
3373 url
= g_string_new(NULL
);
3374 g_string_printf(url
, "http://login.yahoo.com/config/login?login=%s&passwd=%s", purple_account_get_username(account
), md5
);
3375 g_hash_table_foreach(hash
, (GHFunc
)yahoo_login_page_hash_iter
, url
);
3376 url
= g_string_append(url
, "&.hash=1&.md5=1");
3378 g_hash_table_destroy(hash
);
3379 g_object_unref(cipher
);
3381 req
= purple_http_request_new(g_string_free(url
, FALSE
));
3382 purple_http_request_set_max_redirects(req
, 0);
3383 purple_http_connection_set_add(yd
->http_reqs
,
3384 purple_http_request(gc
, req
, yahoo_login_page_got
, NULL
));
3385 purple_http_request_unref(req
);
3388 #endif /* TRY_WEBMESSENGER_LOGIN */
3390 static void yahoo_picture_check(PurpleAccount
*account
)
3392 PurpleConnection
*gc
= purple_account_get_connection(account
);
3393 PurpleImage
*img
= purple_buddy_icons_find_account_icon(account
);
3395 yahoo_set_buddy_icon(gc
, img
);
3398 g_object_unref(img
);
3401 static int get_yahoo_status_from_purple_status(PurpleStatus
*status
)
3403 PurplePresence
*presence
;
3404 const char *status_id
;
3407 presence
= purple_status_get_presence(status
);
3408 status_id
= purple_status_get_id(status
);
3409 msg
= purple_status_get_attr_string(status
, "message");
3411 if ((msg
!= NULL
) && (*msg
!= '\0')) {
3412 return YAHOO_STATUS_CUSTOM
;
3413 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_AVAILABLE
)) {
3414 return YAHOO_STATUS_AVAILABLE
;
3415 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_BRB
)) {
3416 return YAHOO_STATUS_BRB
;
3417 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_BUSY
)) {
3418 return YAHOO_STATUS_BUSY
;
3419 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_NOTATHOME
)) {
3420 return YAHOO_STATUS_NOTATHOME
;
3421 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_NOTATDESK
)) {
3422 return YAHOO_STATUS_NOTATDESK
;
3423 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_NOTINOFFICE
)) {
3424 return YAHOO_STATUS_NOTINOFFICE
;
3425 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_ONPHONE
)) {
3426 return YAHOO_STATUS_ONPHONE
;
3427 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_ONVACATION
)) {
3428 return YAHOO_STATUS_ONVACATION
;
3429 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_OUTTOLUNCH
)) {
3430 return YAHOO_STATUS_OUTTOLUNCH
;
3431 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_STEPPEDOUT
)) {
3432 return YAHOO_STATUS_STEPPEDOUT
;
3433 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_INVISIBLE
)) {
3434 return YAHOO_STATUS_INVISIBLE
;
3435 } else if (!strcmp(status_id
, YAHOO_STATUS_TYPE_AWAY
)) {
3436 return YAHOO_STATUS_CUSTOM
;
3437 } else if (purple_presence_is_idle(presence
)) {
3438 return YAHOO_STATUS_IDLE
;
3440 purple_debug_error("yahoo", "Unexpected PurpleStatus!\n");
3441 return YAHOO_STATUS_AVAILABLE
;
3445 static void yahoo_got_pager_server(PurpleHttpConnection
*http_conn
,
3446 PurpleHttpResponse
*response
, gpointer _yd
)
3448 YahooData
*yd
= _yd
;
3449 PurpleConnection
*gc
= yd
->gc
;
3450 PurpleAccount
*a
= purple_connection_get_account(gc
);
3451 gchar
**strings
= NULL
, *cs_server
= NULL
;
3452 int port
= purple_account_get_int(a
, "port", YAHOO_PAGER_PORT
);
3454 const gchar
*got_data
;
3456 if (!purple_http_response_is_successful(response
)) {
3457 purple_debug_error("yahoo", "Unable to retrieve server info: %s\n",
3458 purple_http_response_get_error(response
));
3460 if(purple_proxy_connect(gc
, a
, YAHOO_PAGER_HOST_FALLBACK
, port
,
3461 yahoo_got_connected
, gc
) == NULL
) {
3462 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3463 _("Unable to connect"));
3466 got_data
= purple_http_response_get_data(response
, NULL
);
3467 strings
= g_strsplit(got_data
, "\r\n", -1);
3469 if((stringslen
= g_strv_length(strings
)) > 1) {
3472 for(i
= 0; i
< stringslen
; i
++) {
3473 if(g_ascii_strncasecmp(strings
[i
], "COLO_CAPACITY=", 14) == 0) {
3474 purple_debug_info("yahoo", "Got COLO Capacity: %s\n", &(strings
[i
][14]));
3475 } else if(g_ascii_strncasecmp(strings
[i
], "CS_IP_ADDRESS=", 14) == 0) {
3476 cs_server
= g_strdup(&strings
[i
][14]);
3477 purple_debug_info("yahoo", "Got CS IP address: %s\n", cs_server
);
3482 if(cs_server
) { /* got an address; get on with connecting */
3483 if(purple_proxy_connect(gc
, a
, cs_server
, port
, yahoo_got_connected
, gc
) == NULL
)
3484 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3485 _("Unable to connect"));
3487 purple_debug_error("yahoo", "No CS address retrieved! Server "
3488 "response:\n%s\n", got_data
);
3490 if(purple_proxy_connect(gc
, a
, YAHOO_PAGER_HOST_FALLBACK
, port
,
3491 yahoo_got_connected
, gc
) == NULL
) {
3492 purple_connection_error(gc
, PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
3493 _("Unable to connect"));
3498 g_strfreev(strings
);
3502 void yahoo_login(PurpleAccount
*account
) {
3503 PurpleConnection
*gc
= purple_account_get_connection(account
);
3504 PurpleHttpRequest
*req
;
3505 YahooData
*yd
= g_new0(YahooData
, 1);
3506 PurpleStatus
*status
= purple_account_get_active_status(account
);
3508 purple_connection_set_protocol_data(gc
, yd
);
3509 purple_connection_set_flags(gc
, PURPLE_CONNECTION_FLAG_HTML
|
3510 PURPLE_CONNECTION_FLAG_NO_BGCOLOR
|
3511 PURPLE_CONNECTION_FLAG_NO_URLDESC
|
3512 PURPLE_CONNECTION_FLAG_NO_IMAGES
);
3514 purple_connection_update_progress(gc
, _("Connecting"), 1, 2);
3516 purple_connection_set_display_name(gc
, purple_account_get_username(account
));
3519 yd
->yahoo_local_p2p_server_fd
= -1;
3522 /* TODO: Is there a good grow size for the buffer? */
3523 yd
->txbuf
= purple_circular_buffer_new(0);
3524 yd
->http_reqs
= purple_http_connection_set_new();
3525 yd
->friends
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, yahoo_friend_free
);
3526 yd
->imvironments
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
3527 yd
->xfer_peer_idstring_map
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, NULL
);
3528 yd
->peers
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
,
3529 yahoo_p2p_disconnect_destroy_data
);
3530 yd
->sms_carrier
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
3531 yd
->yahoo_p2p_timer
= purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS
,
3532 yahoo_p2p_keepalive
, gc
);
3535 yd
->last_keepalive
= yd
->last_ping
= time(NULL
);
3537 yd
->current_status
= get_yahoo_status_from_purple_status(status
);
3539 yahoo_picture_check(account
);
3541 /* Get the pager server. Actually start connecting in the callback since we
3542 * must have the contents of the HTTP response to proceed. */
3543 req
= purple_http_request_new(YAHOO_PAGER_HOST_REQ_URL
);
3544 purple_http_request_header_set(req
, "User-Agent", YAHOO_CLIENT_USERAGENT
);
3545 purple_http_connection_set_add(yd
->http_reqs
, purple_http_request(gc
,
3546 req
, yahoo_got_pager_server
, yd
));
3547 purple_http_request_unref(req
);
3552 void yahoo_close(PurpleConnection
*gc
) {
3553 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
3557 purple_input_remove(yd
->inpa
);
3561 purple_http_connection_set_destroy(yd
->http_reqs
);
3562 yd
->http_reqs
= NULL
;
3564 for (l
= yd
->confs
; l
; l
= l
->next
) {
3565 PurpleChatConversation
*conv
= l
->data
;
3568 users
= purple_chat_conversation_get_users(conv
);
3569 yahoo_conf_leave(yd
,
3570 purple_conversation_get_name(PURPLE_CONVERSATION(conv
)),
3571 purple_connection_get_display_name(gc
), users
);
3574 g_slist_free(yd
->confs
);
3576 g_slist_free_full(yd
->cookies
, g_free
);
3578 yd
->chat_online
= FALSE
;
3580 yahoo_c_leave(gc
, 1); /* 1 = YAHOO_CHAT_ID */
3582 purple_timeout_remove(yd
->yahoo_p2p_timer
);
3583 if(yd
->yahoo_p2p_server_timeout_handle
!= 0) {
3584 purple_timeout_remove(yd
->yahoo_p2p_server_timeout_handle
);
3585 yd
->yahoo_p2p_server_timeout_handle
= 0;
3588 /* close p2p server if it is waiting for a peer to connect */
3589 if (yd
->yahoo_p2p_server_watcher
) {
3590 purple_input_remove(yd
->yahoo_p2p_server_watcher
);
3591 yd
->yahoo_p2p_server_watcher
= 0;
3593 if (yd
->yahoo_local_p2p_server_fd
>= 0) {
3594 close(yd
->yahoo_local_p2p_server_fd
);
3595 yd
->yahoo_local_p2p_server_fd
= -1;
3598 g_hash_table_destroy(yd
->sms_carrier
);
3599 g_hash_table_destroy(yd
->peers
);
3600 g_hash_table_destroy(yd
->friends
);
3601 g_hash_table_destroy(yd
->imvironments
);
3602 g_hash_table_destroy(yd
->xfer_peer_idstring_map
);
3603 g_free(yd
->chat_name
);
3605 g_free(yd
->cookie_y
);
3606 g_free(yd
->cookie_t
);
3607 g_free(yd
->cookie_b
);
3610 purple_input_remove(yd
->txhandler
);
3612 g_object_unref(G_OBJECT(yd
->txbuf
));
3617 g_free(yd
->rxqueue
);
3619 g_free(yd
->picture_url
);
3621 purple_http_conn_cancel(yd
->picture_upload_hc
);
3622 if (yd
->picture_upload_todo
)
3623 yahoo_buddy_icon_upload_data_free(yd
->picture_upload_todo
);
3625 ycht_connection_close(yd
->ycht
);
3626 if (yd
->listen_data
!= NULL
)
3627 purple_network_listen_cancel(yd
->listen_data
);
3629 g_free(yd
->pending_chat_room
);
3630 g_free(yd
->pending_chat_id
);
3631 g_free(yd
->pending_chat_topic
);
3632 g_free(yd
->pending_chat_goto
);
3633 g_strfreev(yd
->profiles
);
3635 yahoo_personal_details_reset(&yd
->ypd
, TRUE
);
3637 g_free(yd
->current_list15_grp
);
3640 purple_connection_set_protocol_data(gc
, NULL
);
3643 const char *yahoo_list_icon(PurpleAccount
*a
, PurpleBuddy
*b
)
3648 const char *yahoo_list_emblem(PurpleBuddy
*b
)
3650 PurpleAccount
*account
;
3651 PurpleConnection
*gc
;
3653 PurplePresence
*presence
;
3655 if (!b
|| !(account
= purple_buddy_get_account(b
)) ||
3656 !(gc
= purple_account_get_connection(account
)) ||
3657 !purple_connection_get_protocol_data(gc
))
3660 f
= yahoo_friend_find(gc
, purple_buddy_get_name(b
));
3662 return "not-authorized";
3665 presence
= purple_buddy_get_presence(b
);
3667 if (purple_presence_is_online(presence
)) {
3668 if (yahoo_friend_get_game(f
))
3674 static const char *yahoo_get_status_string(enum yahoo_status a
)
3677 case YAHOO_STATUS_BRB
:
3678 return _("Be Right Back");
3679 case YAHOO_STATUS_BUSY
:
3681 case YAHOO_STATUS_NOTATHOME
:
3682 return _("Not at Home");
3683 case YAHOO_STATUS_NOTATDESK
:
3684 return _("Not at Desk");
3685 case YAHOO_STATUS_NOTINOFFICE
:
3686 return _("Not in Office");
3687 case YAHOO_STATUS_ONPHONE
:
3688 return _("On the Phone");
3689 case YAHOO_STATUS_ONVACATION
:
3690 return _("On Vacation");
3691 case YAHOO_STATUS_OUTTOLUNCH
:
3692 return _("Out to Lunch");
3693 case YAHOO_STATUS_STEPPEDOUT
:
3694 return _("Stepped Out");
3695 case YAHOO_STATUS_INVISIBLE
:
3696 return _("Invisible");
3697 case YAHOO_STATUS_IDLE
:
3699 case YAHOO_STATUS_OFFLINE
:
3700 return _("Offline");
3702 return _("Available");
3706 static void yahoo_initiate_conference(PurpleBlistNode
*node
, gpointer data
) {
3709 PurpleConnection
*gc
;
3711 GHashTable
*components
;
3715 g_return_if_fail(PURPLE_IS_BUDDY(node
));
3717 buddy
= (PurpleBuddy
*) node
;
3718 gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
3719 yd
= purple_connection_get_protocol_data(gc
);
3722 components
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
3723 g_hash_table_replace(components
, g_strdup("room"),
3724 g_strdup_printf("%s-%d", purple_connection_get_display_name(gc
), id
));
3725 g_hash_table_replace(components
, g_strdup("topic"), g_strdup("Join my conference..."));
3726 g_hash_table_replace(components
, g_strdup("type"), g_strdup("Conference"));
3727 yahoo_c_join(gc
, components
);
3728 g_hash_table_destroy(components
);
3730 yahoo_c_invite(gc
, id
, "Join my conference...", purple_buddy_get_name(buddy
));
3733 static void yahoo_presence_settings(PurpleBlistNode
*node
, gpointer data
) {
3735 PurpleConnection
*gc
;
3736 int presence_val
= GPOINTER_TO_INT(data
);
3738 buddy
= (PurpleBuddy
*) node
;
3739 gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
3741 yahoo_friend_update_presence(gc
, purple_buddy_get_name(buddy
), presence_val
);
3744 static void yahoo_game(PurpleBlistNode
*node
, gpointer data
) {
3747 PurpleConnection
*gc
;
3755 g_return_if_fail(PURPLE_IS_BUDDY(node
));
3757 buddy
= (PurpleBuddy
*) node
;
3758 gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
3760 f
= yahoo_friend_find(gc
, purple_buddy_get_name(buddy
));
3764 game
= yahoo_friend_get_game(f
);
3768 t
= game2
= g_strdup(strstr(game
, "ante?room="));
3769 while (*t
&& *t
!= '\t')
3772 g_snprintf(url
, sizeof url
, "http://games.yahoo.com/games/%s", game2
);
3773 purple_notify_uri(gc
, url
);
3777 char *yahoo_status_text(PurpleBuddy
*b
)
3779 YahooFriend
*f
= NULL
;
3782 PurpleAccount
*account
;
3783 PurpleConnection
*gc
;
3785 account
= purple_buddy_get_account(b
);
3786 gc
= purple_account_get_connection(account
);
3787 if (!gc
|| !purple_connection_get_protocol_data(gc
))
3790 f
= yahoo_friend_find(gc
, purple_buddy_get_name(b
));
3792 return g_strdup(_("Not on server list"));
3794 switch (f
->status
) {
3795 case YAHOO_STATUS_AVAILABLE
:
3797 case YAHOO_STATUS_IDLE
:
3799 return g_strdup(yahoo_get_status_string(f
->status
));
3801 case YAHOO_STATUS_CUSTOM
:
3802 if (!(msg
= yahoo_friend_get_status_message(f
)))
3804 msg2
= g_markup_escape_text(msg
, strlen(msg
));
3805 purple_util_chrreplace(msg2
, '\n', ' ');
3809 return g_strdup(yahoo_get_status_string(f
->status
));
3813 void yahoo_tooltip_text(PurpleBuddy
*b
, PurpleNotifyUserInfo
*user_info
, gboolean full
)
3816 char *status
= NULL
;
3817 const char *presence
= NULL
;
3818 PurpleAccount
*account
;
3820 account
= purple_buddy_get_account(b
);
3821 f
= yahoo_friend_find(purple_account_get_connection(account
), purple_buddy_get_name(b
));
3823 status
= g_strdup_printf("\n%s", _("Not on server list"));
3825 switch (f
->status
) {
3826 case YAHOO_STATUS_CUSTOM
:
3827 if (!yahoo_friend_get_status_message(f
))
3829 status
= g_strdup(yahoo_friend_get_status_message(f
));
3831 case YAHOO_STATUS_OFFLINE
:
3834 status
= g_strdup(yahoo_get_status_string(f
->status
));
3838 switch (f
->presence
) {
3839 case YAHOO_PRESENCE_ONLINE
:
3840 presence
= _("Appear Online");
3842 case YAHOO_PRESENCE_PERM_OFFLINE
:
3843 presence
= _("Appear Permanently Offline");
3845 case YAHOO_PRESENCE_DEFAULT
:
3848 purple_debug_error("yahoo", "Unknown presence in yahoo_tooltip_text\n");
3853 if (status
!= NULL
) {
3854 purple_notify_user_info_add_pair_plaintext(user_info
, _("Status"), status
);
3858 if (presence
!= NULL
)
3859 purple_notify_user_info_add_pair_plaintext(user_info
, _("Presence"), presence
);
3862 YahooPersonalDetails
*ypd
= &f
->ypd
;
3863 if (ypd
->phone
.home
&& *ypd
->phone
.home
)
3864 purple_notify_user_info_add_pair_plaintext(user_info
, _("Home Phone Number"), ypd
->phone
.home
);
3865 if (ypd
->phone
.work
&& *ypd
->phone
.work
)
3866 purple_notify_user_info_add_pair_plaintext(user_info
, _("Work Phone Number"), ypd
->phone
.work
);
3867 if (ypd
->phone
.mobile
&& *ypd
->phone
.mobile
)
3868 purple_notify_user_info_add_pair_plaintext(user_info
, _("Mobile Phone Number"), ypd
->phone
.mobile
);
3872 static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode
*node
, gpointer data
)
3875 PurpleConnection
*gc
;
3877 g_return_if_fail(PURPLE_IS_BUDDY(node
));
3879 buddy
= (PurpleBuddy
*) node
;
3880 gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
3882 yahoo_add_buddy(gc
, buddy
, NULL
, NULL
);
3886 static void yahoo_chat_goto_menu(PurpleBlistNode
*node
, gpointer data
)
3889 PurpleConnection
*gc
;
3891 g_return_if_fail(PURPLE_IS_BUDDY(node
));
3893 buddy
= (PurpleBuddy
*) node
;
3894 gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
3896 yahoo_chat_goto(gc
, purple_buddy_get_name(buddy
));
3899 static GList
*build_presence_submenu(YahooFriend
*f
, PurpleConnection
*gc
) {
3901 PurpleMenuAction
*act
;
3902 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
3904 if (yd
->current_status
== YAHOO_STATUS_INVISIBLE
) {
3905 if (f
->presence
!= YAHOO_PRESENCE_ONLINE
) {
3906 act
= purple_menu_action_new(_("Appear Online"),
3907 PURPLE_CALLBACK(yahoo_presence_settings
),
3908 GINT_TO_POINTER(YAHOO_PRESENCE_ONLINE
),
3910 m
= g_list_append(m
, act
);
3911 } else if (f
->presence
!= YAHOO_PRESENCE_DEFAULT
) {
3912 act
= purple_menu_action_new(_("Appear Offline"),
3913 PURPLE_CALLBACK(yahoo_presence_settings
),
3914 GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT
),
3916 m
= g_list_append(m
, act
);
3920 if (f
->presence
== YAHOO_PRESENCE_PERM_OFFLINE
) {
3921 act
= purple_menu_action_new(_("Don't Appear Permanently Offline"),
3922 PURPLE_CALLBACK(yahoo_presence_settings
),
3923 GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT
),
3925 m
= g_list_append(m
, act
);
3927 act
= purple_menu_action_new(_("Appear Permanently Offline"),
3928 PURPLE_CALLBACK(yahoo_presence_settings
),
3929 GINT_TO_POINTER(YAHOO_PRESENCE_PERM_OFFLINE
),
3931 m
= g_list_append(m
, act
);
3937 static void yahoo_doodle_blist_node(PurpleBlistNode
*node
, gpointer data
)
3939 PurpleBuddy
*b
= (PurpleBuddy
*)node
;
3940 PurpleAccount
*account
= purple_buddy_get_account(b
);
3941 PurpleConnection
*gc
= purple_account_get_connection(account
);
3943 yahoo_doodle_initiate(gc
, purple_buddy_get_name(b
));
3947 /* XXX: it doesn't seems to work */
3949 yahoo_userinfo_blist_node(PurpleBlistNode
*node
, gpointer data
)
3951 PurpleBuddy
*b
= (PurpleBuddy
*)node
;
3952 PurpleAccount
*account
= purple_buddy_get_account(b
);
3953 PurpleConnection
*gc
= purple_account_get_connection(account
);
3955 yahoo_set_userinfo_for_buddy(gc
, b
);
3959 static GList
*yahoo_buddy_menu(PurpleBuddy
*buddy
)
3962 PurpleMenuAction
*act
;
3964 PurpleConnection
*gc
= purple_account_get_connection(purple_buddy_get_account(buddy
));
3965 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
3966 static char buf2
[1024];
3969 f
= yahoo_friend_find(gc
, purple_buddy_get_name(buddy
));
3971 if (!f
&& !yd
->wm
) {
3972 act
= purple_menu_action_new(_("Add Buddy"),
3973 PURPLE_CALLBACK(yahoo_addbuddyfrommenu_cb
),
3975 m
= g_list_append(m
, act
);
3981 if (f
&& f
->status
!= YAHOO_STATUS_OFFLINE
) {
3983 act
= purple_menu_action_new(_("Join in Chat"),
3984 PURPLE_CALLBACK(yahoo_chat_goto_menu
),
3986 m
= g_list_append(m
, act
);
3989 act
= purple_menu_action_new(_("Initiate Conference"),
3990 PURPLE_CALLBACK(yahoo_initiate_conference
),
3992 m
= g_list_append(m
, act
);
3994 if (yahoo_friend_get_game(f
)) {
3995 const char *game
= yahoo_friend_get_game(f
);
3999 if ((room
= strstr(game
, "&follow="))) {/* skip ahead to the url */
4000 while (*room
&& *room
!= '\t') /* skip to the tab */
4002 t
= room
++; /* room as now at the name */
4004 t
++; /* replace the \n with a space */
4006 g_snprintf(buf2
, sizeof buf2
, "%s", room
);
4008 act
= purple_menu_action_new(buf2
,
4009 PURPLE_CALLBACK(yahoo_game
),
4011 m
= g_list_append(m
, act
);
4017 act
= purple_menu_action_new(_("Presence Settings"), NULL
, NULL
,
4018 build_presence_submenu(f
, gc
));
4019 m
= g_list_append(m
, act
);
4021 act
= purple_menu_action_new(_("Start Doodling"),
4022 PURPLE_CALLBACK(yahoo_doodle_blist_node
),
4024 m
= g_list_append(m
, act
);
4027 /* XXX: it doesn't seems to work */
4028 act
= purple_menu_action_new(_("Set User Info..."),
4029 PURPLE_CALLBACK(yahoo_userinfo_blist_node
),
4031 m
= g_list_append(m
, act
);
4038 GList
*yahoo_blist_node_menu(PurpleBlistNode
*node
)
4040 if(PURPLE_IS_BUDDY(node
)) {
4041 return yahoo_buddy_menu((PurpleBuddy
*) node
);
4047 static void yahoo_act_id(PurpleConnection
*gc
, PurpleRequestFields
*fields
)
4049 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4050 const char *name
= yd
->profiles
[GPOINTER_TO_INT(purple_request_fields_get_choice(fields
, "id"))];
4052 struct yahoo_packet
*pkt
= yahoo_packet_new(YAHOO_SERVICE_IDACT
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4053 yahoo_packet_hash_str(pkt
, 3, name
);
4054 yahoo_packet_send_and_free(pkt
, yd
);
4056 purple_connection_set_display_name(gc
, name
);
4060 yahoo_get_inbox_token_cb(PurpleHttpConnection
*http_conn
,
4061 PurpleHttpResponse
*response
, gpointer _unused
)
4063 PurpleConnection
*gc
=
4064 purple_http_conn_get_purple_connection(http_conn
);
4067 PURPLE_ASSERT_CONNECTION_IS_VALID(gc
);
4069 if (!purple_http_response_is_successful(response
)) {
4070 purple_debug_error("yahoo",
4071 "Requesting mail login token failed: %s\n",
4072 purple_http_response_get_error(response
));
4073 url
= g_strdup(YAHOO_MAIL_URL
);
4075 /* Should we not be hardcoding the rd url? */
4077 token
= g_strdup(purple_http_response_get_data(response
, NULL
));
4079 url
= g_strdup_printf(
4080 "http://login.yahoo.com/config/reset_cookies_token?"
4082 "&.done=http://us.rd.yahoo.com/messenger/client/%%3f"
4083 "http://mail.yahoo.com/", token
);
4084 purple_str_wipe(token
);
4087 /* Open the mailbox with the parsed url data */
4088 purple_notify_uri(gc
, url
);
4094 static void yahoo_show_inbox(PurpleProtocolAction
*action
)
4096 /* Setup a cookie that can be used by the browser */
4098 PurpleConnection
*gc
= action
->connection
;
4099 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4100 PurpleHttpRequest
*req
;
4101 PurpleHttpCookieJar
*cookiejar
;
4103 req
= purple_http_request_new(
4104 "https://login.yahoo.com/config/cookie_token");
4105 purple_http_request_set_method(req
, "POST");
4106 purple_http_request_header_set(req
, "User-Agent",
4107 YAHOO_CLIENT_USERAGENT
);
4108 cookiejar
= purple_http_request_get_cookie_jar(req
);
4109 purple_http_cookie_jar_set(cookiejar
, "T", yd
->cookie_t
);
4110 purple_http_cookie_jar_set(cookiejar
, "Y", yd
->cookie_y
);
4111 purple_http_connection_set_add(yd
->http_reqs
, purple_http_request(gc
,
4112 req
, yahoo_get_inbox_token_cb
, NULL
));
4113 purple_http_request_unref(req
);
4117 /* XXX: it doesn't seems to work */
4119 yahoo_set_userinfo_fn(PurpleProtocolAction
*action
)
4121 yahoo_set_userinfo(action
->connection
);
4125 static void yahoo_show_act_id(PurpleProtocolAction
*action
)
4127 PurpleRequestFields
*fields
;
4128 PurpleRequestFieldGroup
*group
;
4129 PurpleRequestField
*field
;
4130 PurpleConnection
*gc
= (PurpleConnection
*) action
->connection
;
4131 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4132 const char *name
= purple_connection_get_display_name(gc
);
4135 fields
= purple_request_fields_new();
4136 group
= purple_request_field_group_new(NULL
);
4137 purple_request_fields_add_group(fields
, group
);
4138 field
= purple_request_field_choice_new("id", _("Activate which ID?"), 0);
4139 purple_request_field_group_add_field(group
, field
);
4141 for (iter
= 0; yd
->profiles
[iter
]; iter
++) {
4142 purple_request_field_choice_add(field
, yd
->profiles
[iter
], GINT_TO_POINTER(iter
));
4143 if (purple_strequal(yd
->profiles
[iter
], name
))
4144 purple_request_field_choice_set_default_value(field
, GINT_TO_POINTER(iter
));
4147 purple_request_fields(gc
, NULL
, _("Select the ID you want to activate"), NULL
,
4149 _("OK"), G_CALLBACK(yahoo_act_id
),
4151 purple_request_cpar_from_connection(gc
), gc
);
4154 static void yahoo_show_chat_goto(PurpleProtocolAction
*action
)
4156 PurpleConnection
*gc
= action
->connection
;
4157 purple_request_input(gc
, NULL
, _("Join whom in chat?"), NULL
,
4158 "", FALSE
, FALSE
, NULL
,
4159 _("OK"), G_CALLBACK(yahoo_chat_goto
),
4161 purple_request_cpar_from_connection(gc
),
4165 GList
*yahoo_get_actions(PurpleConnection
*gc
) {
4167 PurpleProtocolAction
*act
;
4170 /* XXX: it doesn't seems to work */
4171 act
= purple_protocol_action_new(_("Set User Info..."),
4172 yahoo_set_userinfo_fn
);
4173 m
= g_list_append(m
, act
);
4176 act
= purple_protocol_action_new(_("Activate ID..."),
4178 m
= g_list_append(m
, act
);
4180 act
= purple_protocol_action_new(_("Join User in Chat..."),
4181 yahoo_show_chat_goto
);
4182 m
= g_list_append(m
, act
);
4184 m
= g_list_append(m
, NULL
);
4185 act
= purple_protocol_action_new(_("Open Inbox"),
4187 m
= g_list_append(m
, act
);
4192 struct yahoo_sms_carrier_cb_data
{
4193 PurpleConnection
*gc
;
4198 static void yahoo_get_sms_carrier_cb(PurpleHttpConnection
*http_conn
,
4199 PurpleHttpResponse
*response
, gpointer _sms_cb_data
)
4201 struct yahoo_sms_carrier_cb_data
*sms_cb_data
= _sms_cb_data
;
4202 PurpleConnection
*gc
= sms_cb_data
->gc
;
4203 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4204 char *status
= NULL
;
4205 char *carrier
= NULL
;
4206 PurpleAccount
*account
= purple_connection_get_account(gc
);
4207 PurpleIMConversation
*im
= purple_conversations_find_im_with_account(sms_cb_data
->who
, account
);
4209 if (!purple_http_response_is_successful(response
)) {
4210 purple_conversation_write_system_message(PURPLE_CONVERSATION(im
),
4211 _("Can't send SMS. Unable to obtain mobile carrier."), 0);
4213 g_free(sms_cb_data
->who
);
4214 g_free(sms_cb_data
->what
);
4215 g_free(sms_cb_data
);
4218 const gchar
*got_data
= purple_http_response_get_data(response
, NULL
);
4219 PurpleXmlNode
*validate_data_root
= purple_xmlnode_from_str(got_data
, -1);
4220 PurpleXmlNode
*validate_data_child
= purple_xmlnode_get_child(validate_data_root
, "mobile_no");
4221 const char *mobile_no
= purple_xmlnode_get_attrib(validate_data_child
, "msisdn");
4223 validate_data_root
= purple_xmlnode_copy(validate_data_child
);
4224 validate_data_child
= purple_xmlnode_get_child(validate_data_root
, "status");
4225 status
= purple_xmlnode_get_data(validate_data_child
);
4227 validate_data_child
= purple_xmlnode_get_child(validate_data_root
, "carrier");
4228 carrier
= purple_xmlnode_get_data(validate_data_child
);
4230 purple_debug_info("yahoo", "SMS validate data: %s\n", got_data
);
4232 if (status
&& g_str_equal(status
, "Valid")) {
4233 g_hash_table_insert(yd
->sms_carrier
,
4234 g_strdup_printf("+%s", mobile_no
), g_strdup(carrier
));
4235 yahoo_send_im(sms_cb_data
->gc
, purple_message_new_outgoing(
4236 sms_cb_data
->who
, sms_cb_data
->what
, 0));
4238 g_hash_table_insert(yd
->sms_carrier
,
4239 g_strdup_printf("+%s", mobile_no
), g_strdup("Unknown"));
4240 purple_conversation_write_system_message(PURPLE_CONVERSATION(im
),
4241 _("Can't send SMS. Unknown mobile carrier."), 0);
4244 purple_xmlnode_free(validate_data_child
);
4245 purple_xmlnode_free(validate_data_root
);
4246 g_free(sms_cb_data
->who
);
4247 g_free(sms_cb_data
->what
);
4248 g_free(sms_cb_data
);
4254 static void yahoo_get_sms_carrier(PurpleConnection
*gc
, gpointer data
)
4256 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4257 PurpleHttpRequest
*req
;
4258 PurpleHttpCookieJar
*cookiejar
;
4259 struct yahoo_sms_carrier_cb_data
*sms_cb_data
;
4260 char *validate_request_str
= NULL
;
4261 PurpleXmlNode
*validate_request_root
= NULL
;
4262 PurpleXmlNode
*validate_request_child
= NULL
;
4264 if(!(sms_cb_data
= data
))
4267 validate_request_root
= purple_xmlnode_new("validate");
4268 purple_xmlnode_set_attrib(validate_request_root
, "intl", "us");
4269 purple_xmlnode_set_attrib(validate_request_root
, "version", YAHOO_CLIENT_VERSION
);
4270 purple_xmlnode_set_attrib(validate_request_root
, "qos", "0");
4272 validate_request_child
= purple_xmlnode_new_child(validate_request_root
, "mobile_no");
4273 purple_xmlnode_set_attrib(validate_request_child
, "msisdn", sms_cb_data
->who
+ 1);
4275 validate_request_str
= purple_xmlnode_to_str(validate_request_root
, NULL
);
4277 purple_xmlnode_free(validate_request_child
);
4278 purple_xmlnode_free(validate_request_root
);
4280 req
= purple_http_request_new(NULL
);
4281 purple_http_request_set_url_printf(req
, "http://validate.msg.yahoo.com"
4282 "/mobileno?intl=us&version=%s", YAHOO_CLIENT_VERSION
);
4283 purple_http_request_set_method(req
, "POST");
4284 purple_http_request_header_set(req
, "User-Agent",
4285 YAHOO_CLIENT_USERAGENT
);
4286 cookiejar
= purple_http_request_get_cookie_jar(req
);
4287 purple_http_cookie_jar_set(cookiejar
, "T", yd
->cookie_t
);
4288 purple_http_cookie_jar_set(cookiejar
, "Y", yd
->cookie_y
);
4289 purple_http_request_set_contents(req
, validate_request_str
, -1);
4290 purple_http_connection_set_add(yd
->http_reqs
, purple_http_request(gc
,
4291 req
, yahoo_get_sms_carrier_cb
, data
));
4292 purple_http_request_unref(req
);
4294 g_free(validate_request_str
);
4297 int yahoo_send_im(PurpleConnection
*gc
, PurpleMessage
*pmsg
)
4299 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4300 struct yahoo_packet
*pkt
= NULL
;
4301 char *msg
= yahoo_html_to_codes(purple_message_get_contents(pmsg
));
4303 PurpleWhiteboard
*wb
;
4307 struct yahoo_p2p_data
*p2p_data
;
4308 const gchar
*rcpt
= purple_message_get_recipient(pmsg
);
4310 msg2
= yahoo_string_encode(gc
, msg
, TRUE
);
4313 lenb
= strlen(msg2
);
4314 lenc
= g_utf8_strlen(msg2
, -1);
4316 if(lenb
> YAHOO_MAX_MESSAGE_LENGTH_BYTES
|| lenc
> YAHOO_MAX_MESSAGE_LENGTH_CHARS
) {
4317 purple_debug_info("yahoo", "Message too big. Length is %" G_GSIZE_FORMAT
4318 " bytes, %ld characters. Max is %d bytes, %d chars."
4319 " Message is '%s'.\n", lenb
, lenc
, YAHOO_MAX_MESSAGE_LENGTH_BYTES
,
4320 YAHOO_MAX_MESSAGE_LENGTH_CHARS
, msg2
);
4327 if (rcpt
[0] == '+') {
4328 /* we have an sms to be sent */
4329 gchar
*carrier
= NULL
;
4330 const char *alias
= NULL
;
4331 PurpleAccount
*account
= purple_connection_get_account(gc
);
4332 PurpleIMConversation
*im
= purple_conversations_find_im_with_account(rcpt
, account
);
4334 carrier
= g_hash_table_lookup(yd
->sms_carrier
, rcpt
);
4336 struct yahoo_sms_carrier_cb_data
*sms_cb_data
;
4337 sms_cb_data
= g_malloc(sizeof(struct yahoo_sms_carrier_cb_data
));
4338 sms_cb_data
->gc
= gc
;
4339 sms_cb_data
->who
= g_strdup(rcpt
);
4340 sms_cb_data
->what
= g_strdup(purple_message_get_contents(pmsg
));
4342 purple_conversation_write_system_message(PURPLE_CONVERSATION(im
),
4343 _("Getting mobile carrier to send the SMS."), 0);
4345 yahoo_get_sms_carrier(gc
, sms_cb_data
);
4351 else if( strcmp(carrier
,"Unknown") == 0 ) {
4352 purple_conversation_write_system_message(PURPLE_CONVERSATION(im
),
4353 _("Can't send SMS. Unknown mobile carrier."), 0);
4360 alias
= purple_account_get_private_alias(account
);
4361 pkt
= yahoo_packet_new(YAHOO_SERVICE_SMS_MSG
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4362 yahoo_packet_hash(pkt
, "sssss",
4363 1, purple_connection_get_display_name(gc
),
4368 yahoo_packet_send_and_free(pkt
, yd
);
4376 pkt
= yahoo_packet_new(YAHOO_SERVICE_MESSAGE
, YAHOO_STATUS_OFFLINE
, yd
->session_id
);
4377 yahoo_packet_hash(pkt
, "ss", 1, purple_connection_get_display_name(gc
), 5, rcpt
);
4379 yahoo_packet_hash_str(pkt
, 97, "1"); /* UTF-8 */
4380 yahoo_packet_hash_str(pkt
, 14, msg2
);
4385 * If this message is to a user who is also Doodling with the local user,
4386 * format the chat packet with the correct IMV information (thanks Yahoo!)
4388 * Otherwise attempt to use the same IMVironment as the remote user,
4389 * just so that we don't inadvertantly reset their IMVironment back
4392 * If they have not set an IMVironment, then use the default.
4394 wb
= purple_whiteboard_get_session(purple_connection_get_account(gc
), rcpt
);
4396 yahoo_packet_hash_str(pkt
, 63, DOODLE_IMV_KEY
);
4400 imv
= g_hash_table_lookup(yd
->imvironments
, rcpt
);
4402 yahoo_packet_hash_str(pkt
, 63, imv
);
4404 yahoo_packet_hash_str(pkt
, 63, ";0");
4407 yahoo_packet_hash_str(pkt
, 64, "0"); /* no idea */
4408 yahoo_packet_hash_str(pkt
, 1002, "1"); /* no idea, Yahoo 6 or later only it seems */
4409 if (!yd
->picture_url
)
4410 yahoo_packet_hash_str(pkt
, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */
4412 yahoo_packet_hash_str(pkt
, 206, "2");
4414 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */
4415 if ((YAHOO_PACKET_HDRLEN
+ yahoo_packet_length(pkt
)) <= 2000) {
4416 /* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */
4417 if( (p2p_data
= g_hash_table_lookup(yd
->peers
, rcpt
))) {
4418 yahoo_packet_hash_int(pkt
, 11, p2p_data
->session_id
);
4419 yahoo_p2p_write_pkt(p2p_data
->source
, pkt
);
4422 yahoo_packet_send(pkt
, yd
);
4423 yahoo_send_p2p_pkt(gc
, rcpt
, 0); /* send p2p packet, with val_13=0 */
4429 yahoo_packet_free(pkt
);
4437 unsigned int yahoo_send_typing(PurpleConnection
*gc
, const char *who
, PurpleIMTypingState state
)
4439 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4440 struct yahoo_p2p_data
*p2p_data
;
4441 struct yahoo_packet
*pkt
= NULL
;
4443 /* Don't do anything if sms is being typed */
4444 if( strncmp(who
, "+", 1) == 0 )
4447 pkt
= yahoo_packet_new(YAHOO_SERVICE_NOTIFY
, YAHOO_STATUS_TYPING
, yd
->session_id
);
4449 /* check to see if p2p link exists, send through it */
4450 if( (p2p_data
= g_hash_table_lookup(yd
->peers
, who
))) {
4451 yahoo_packet_hash(pkt
, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc
),
4452 14, " ", 13, state
== PURPLE_IM_TYPING
? "1" : "0",
4453 5, who
, 11, p2p_data
->session_id
, 1002, "1"); /* To-do: key 15 to be sent in case of p2p */
4454 yahoo_p2p_write_pkt(p2p_data
->source
, pkt
);
4455 yahoo_packet_free(pkt
);
4457 else { /* send through yahoo server */
4459 yahoo_packet_hash(pkt
, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc
),
4460 14, " ", 13, state
== PURPLE_IM_TYPING
? "1" : "0",
4462 yahoo_packet_send_and_free(pkt
, yd
);
4468 static void yahoo_session_presence_remove(gpointer key
, gpointer value
, gpointer data
)
4470 YahooFriend
*f
= value
;
4471 if (f
&& f
->presence
== YAHOO_PRESENCE_ONLINE
)
4472 f
->presence
= YAHOO_PRESENCE_DEFAULT
;
4475 void yahoo_set_status(PurpleAccount
*account
, PurpleStatus
*status
)
4477 PurpleConnection
*gc
;
4478 PurplePresence
*presence
;
4480 struct yahoo_packet
*pkt
;
4482 const char *msg
= NULL
;
4484 char *conv_msg
= NULL
;
4486 if (!purple_status_is_active(status
))
4489 gc
= purple_account_get_connection(account
);
4490 presence
= purple_status_get_presence(status
);
4491 yd
= purple_connection_get_protocol_data(gc
);
4492 old_status
= yd
->current_status
;
4494 yd
->current_status
= get_yahoo_status_from_purple_status(status
);
4496 if (yd
->current_status
== YAHOO_STATUS_CUSTOM
)
4498 msg
= purple_status_get_attr_string(status
, "message");
4500 if (purple_status_is_available(status
)) {
4501 tmp
= yahoo_string_encode(gc
, msg
, TRUE
);
4502 conv_msg
= purple_markup_strip_html(tmp
);
4505 if ((msg
== NULL
) || (*msg
== '\0'))
4507 tmp
= yahoo_string_encode(gc
, msg
, TRUE
);
4508 conv_msg
= purple_markup_strip_html(tmp
);
4513 if (yd
->current_status
== YAHOO_STATUS_INVISIBLE
) {
4514 pkt
= yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4515 yahoo_packet_hash_str(pkt
, 13, "2");
4516 yahoo_packet_send_and_free(pkt
, yd
);
4521 pkt
= yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4522 yahoo_packet_hash_int(pkt
, 10, yd
->current_status
);
4524 if (yd
->current_status
== YAHOO_STATUS_CUSTOM
) {
4525 yahoo_packet_hash_str(pkt
, 97, "1"); /* UTF-8 */
4526 yahoo_packet_hash_str(pkt
, 19, conv_msg
);
4528 yahoo_packet_hash_str(pkt
, 19, "");
4533 if (purple_presence_is_idle(presence
))
4534 yahoo_packet_hash_str(pkt
, 47, "2");
4536 if (!purple_status_is_available(status
))
4537 yahoo_packet_hash_str(pkt
, 47, "1");
4539 yahoo_packet_hash_str(pkt
, 47, "0");
4542 yahoo_packet_send_and_free(pkt
, yd
);
4544 if (old_status
== YAHOO_STATUS_INVISIBLE
) {
4545 pkt
= yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4546 yahoo_packet_hash_str(pkt
, 13, "1");
4547 yahoo_packet_send_and_free(pkt
, yd
);
4549 /* Any per-session presence settings are removed */
4550 g_hash_table_foreach(yd
->friends
, yahoo_session_presence_remove
, NULL
);
4555 void yahoo_set_idle(PurpleConnection
*gc
, int idle
)
4557 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4558 struct yahoo_packet
*pkt
= NULL
;
4559 char *msg
= NULL
, *msg2
= NULL
;
4560 PurpleStatus
*status
= NULL
;
4561 gboolean invisible
= FALSE
;
4563 if (idle
&& yd
->current_status
!= YAHOO_STATUS_CUSTOM
)
4564 yd
->current_status
= YAHOO_STATUS_IDLE
;
4565 else if (!idle
&& yd
->current_status
== YAHOO_STATUS_IDLE
) {
4566 status
= purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc
)));
4567 yd
->current_status
= get_yahoo_status_from_purple_status(status
);
4570 invisible
= (yd
->current_status
== YAHOO_STATUS_INVISIBLE
);
4572 pkt
= yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4574 if (!idle
&& invisible
)
4575 yahoo_packet_hash_int(pkt
, 10, YAHOO_STATUS_AVAILABLE
);
4577 yahoo_packet_hash_int(pkt
, 10, yd
->current_status
);
4579 if (yd
->current_status
== YAHOO_STATUS_CUSTOM
) {
4582 status
= purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc
)));
4583 tmp
= purple_status_get_attr_string(status
, "message");
4585 msg
= yahoo_string_encode(gc
, tmp
, TRUE
);
4586 msg2
= purple_markup_strip_html(msg
);
4587 yahoo_packet_hash_str(pkt
, 97, "1"); /* UTF-8 */
4588 yahoo_packet_hash_str(pkt
, 19, msg2
);
4590 /* get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
4591 * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */
4592 yahoo_packet_hash_str(pkt
, 19, _("Away"));
4595 yahoo_packet_hash_str(pkt
, 19, "");
4599 yahoo_packet_hash_str(pkt
, 47, "2");
4600 else if (yd
->current_status
== YAHOO_STATUS_CUSTOM
&&
4601 !purple_status_is_available(status
))
4602 /* We are still unavailable in this case.
4603 * Make sure Yahoo knows that */
4604 yahoo_packet_hash_str(pkt
, 47, "1");
4606 yahoo_packet_send_and_free(pkt
, yd
);
4612 GList
*yahoo_status_types(PurpleAccount
*account
)
4614 PurpleStatusType
*type
;
4615 GList
*types
= NULL
;
4617 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE
, YAHOO_STATUS_TYPE_AVAILABLE
,
4618 NULL
, TRUE
, TRUE
, FALSE
,
4619 "message", _("Message"),
4620 purple_value_new(G_TYPE_STRING
), NULL
);
4621 types
= g_list_append(types
, type
);
4623 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_AWAY
,
4624 NULL
, TRUE
, TRUE
, FALSE
,
4625 "message", _("Message"),
4626 purple_value_new(G_TYPE_STRING
), NULL
);
4627 types
= g_list_append(types
, type
);
4629 type
= purple_status_type_new(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_BRB
, _("Be Right Back"), TRUE
);
4630 types
= g_list_append(types
, type
);
4632 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE
, YAHOO_STATUS_TYPE_BUSY
,
4633 _("Busy"), TRUE
, TRUE
, FALSE
,
4634 "message", _("Message"),
4635 purple_value_new(G_TYPE_STRING
), NULL
);
4636 types
= g_list_append(types
, type
);
4638 type
= purple_status_type_new(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_NOTATHOME
, _("Not at Home"), TRUE
);
4639 types
= g_list_append(types
, type
);
4641 type
= purple_status_type_new(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_NOTATDESK
, _("Not at Desk"), TRUE
);
4642 types
= g_list_append(types
, type
);
4644 type
= purple_status_type_new(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_NOTINOFFICE
, _("Not in Office"), TRUE
);
4645 types
= g_list_append(types
, type
);
4647 type
= purple_status_type_new(PURPLE_STATUS_UNAVAILABLE
, YAHOO_STATUS_TYPE_ONPHONE
, _("On the Phone"), TRUE
);
4648 types
= g_list_append(types
, type
);
4650 type
= purple_status_type_new(PURPLE_STATUS_EXTENDED_AWAY
, YAHOO_STATUS_TYPE_ONVACATION
, _("On Vacation"), TRUE
);
4651 types
= g_list_append(types
, type
);
4653 type
= purple_status_type_new(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_OUTTOLUNCH
, _("Out to Lunch"), TRUE
);
4654 types
= g_list_append(types
, type
);
4656 type
= purple_status_type_new(PURPLE_STATUS_AWAY
, YAHOO_STATUS_TYPE_STEPPEDOUT
, _("Stepped Out"), TRUE
);
4657 types
= g_list_append(types
, type
);
4660 type
= purple_status_type_new(PURPLE_STATUS_INVISIBLE
, YAHOO_STATUS_TYPE_INVISIBLE
, NULL
, TRUE
);
4661 types
= g_list_append(types
, type
);
4663 type
= purple_status_type_new(PURPLE_STATUS_OFFLINE
, YAHOO_STATUS_TYPE_OFFLINE
, NULL
, TRUE
);
4664 types
= g_list_append(types
, type
);
4666 type
= purple_status_type_new_full(PURPLE_STATUS_MOBILE
, YAHOO_STATUS_TYPE_MOBILE
, NULL
, FALSE
, FALSE
, TRUE
);
4667 types
= g_list_append(types
, type
);
4672 void yahoo_keepalive(PurpleConnection
*gc
)
4674 struct yahoo_packet
*pkt
;
4675 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4676 time_t now
= time(NULL
);
4678 /* We're only allowed to send a ping once an hour or the servers will boot us */
4679 if ((now
- yd
->last_ping
) >= PING_TIMEOUT
) {
4680 yd
->last_ping
= now
;
4682 /* The native client will only send PING or CHATPING */
4683 if (yd
->chat_online
) {
4685 ycht_chat_send_keepalive(yd
->ycht
);
4687 pkt
= yahoo_packet_new(YAHOO_SERVICE_CHATPING
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4688 yahoo_packet_hash_str(pkt
, 109, purple_connection_get_display_name(gc
));
4689 yahoo_packet_send_and_free(pkt
, yd
);
4692 pkt
= yahoo_packet_new(YAHOO_SERVICE_PING
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4693 yahoo_packet_send_and_free(pkt
, yd
);
4697 if ((now
- yd
->last_keepalive
) >= KEEPALIVE_TIMEOUT
) {
4698 yd
->last_keepalive
= now
;
4699 pkt
= yahoo_packet_new(YAHOO_SERVICE_KEEPALIVE
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4700 yahoo_packet_hash_str(pkt
, 0, purple_connection_get_display_name(gc
));
4701 yahoo_packet_send_and_free(pkt
, yd
);
4706 void yahoo_add_buddy(PurpleConnection
*gc
, PurpleBuddy
*buddy
, PurpleGroup
*g
, const char *message
)
4708 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4709 struct yahoo_packet
*pkt
;
4710 const char *group
= NULL
;
4712 const char *bname
= purple_buddy_get_name(buddy
);
4717 if (!purple_account_privacy_check(purple_connection_get_account(gc
), bname
))
4720 group
= purple_group_get_name(purple_buddy_get_group(buddy
));
4722 group2
= yahoo_string_encode(gc
, group
, FALSE
);
4723 pkt
= yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4724 yahoo_packet_hash(pkt
, "ssssssssss",
4727 97, "1", /* UTF-8 */
4728 1, purple_connection_get_display_name(gc
),
4736 yahoo_packet_send_and_free(pkt
, yd
);
4740 void yahoo_remove_buddy(PurpleConnection
*gc
, PurpleBuddy
*buddy
, PurpleGroup
*group
)
4742 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4743 struct yahoo_packet
*pkt
;
4744 GSList
*buddies
, *l
;
4746 gboolean remove
= TRUE
;
4748 const char *bname
, *gname
;
4749 YahooFriend
*f
= NULL
;
4751 bname
= purple_buddy_get_name(buddy
);
4752 f
= yahoo_friend_find(gc
, bname
);
4756 gname
= purple_group_get_name(group
);
4757 buddies
= purple_blist_find_buddies(purple_connection_get_account(gc
), bname
);
4758 for (l
= buddies
; l
; l
= l
->next
) {
4759 g
= purple_buddy_get_group(l
->data
);
4760 if (purple_utf8_strcasecmp(gname
, purple_group_get_name(g
))) {
4766 g_slist_free(buddies
);
4769 g_hash_table_remove(yd
->friends
, bname
);
4770 f
= NULL
; /* f no longer valid - Just making it clear */
4773 cg
= yahoo_string_encode(gc
, gname
, FALSE
);
4774 pkt
= yahoo_packet_new(YAHOO_SERVICE_REMBUDDY
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4776 yahoo_packet_hash(pkt
, "sss", 1, purple_connection_get_display_name(gc
),
4778 yahoo_packet_send_and_free(pkt
, yd
);
4782 void yahoo_add_deny(PurpleConnection
*gc
, const char *who
) {
4783 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4784 struct yahoo_packet
*pkt
;
4789 if (!who
|| who
[0] == '\0')
4792 pkt
= yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4794 yahoo_packet_hash(pkt
, "sss", 1, purple_connection_get_display_name(gc
), 7, who
, 13, "1");
4796 yahoo_packet_send_and_free(pkt
, yd
);
4799 void yahoo_rem_deny(PurpleConnection
*gc
, const char *who
) {
4800 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4801 struct yahoo_packet
*pkt
;
4806 if (!who
|| who
[0] == '\0')
4809 pkt
= yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4811 yahoo_packet_hash(pkt
, "sss", 1, purple_connection_get_display_name(gc
), 7, who
, 13, "2");
4813 yahoo_packet_send_and_free(pkt
, yd
);
4816 void yahoo_set_permit_deny(PurpleConnection
*gc
)
4818 PurpleAccount
*account
;
4821 account
= purple_connection_get_account(gc
);
4823 switch (purple_account_get_privacy_type(account
))
4825 case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL
:
4826 for (deny
= purple_account_privacy_get_denied(account
); deny
; deny
= deny
->next
)
4827 yahoo_rem_deny(gc
, deny
->data
);
4830 case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST
:
4831 case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS
:
4832 case PURPLE_ACCOUNT_PRIVACY_DENY_USERS
:
4833 case PURPLE_ACCOUNT_PRIVACY_DENY_ALL
:
4834 for (deny
= purple_account_privacy_get_denied(account
); deny
; deny
= deny
->next
)
4835 yahoo_add_deny(gc
, deny
->data
);
4840 void yahoo_change_buddys_group(PurpleConnection
*gc
, const char *who
,
4841 const char *old_group
, const char *new_group
)
4843 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4844 struct yahoo_packet
*pkt
;
4846 YahooFriend
*f
= yahoo_friend_find(gc
, who
);
4847 const char *temp
= NULL
;
4849 /* Step 0: If they aren't on the server list anyway,
4850 * don't bother letting the server know.
4857 /* If old and new are the same, we would probably
4858 * end up deleting the buddy, which would be bad.
4859 * This might happen because of the charset conversation.
4861 gpn
= yahoo_string_encode(gc
, new_group
, FALSE
);
4862 gpo
= yahoo_string_encode(gc
, old_group
, FALSE
);
4863 if (!strcmp(gpn
, gpo
)) {
4869 pkt
= yahoo_packet_new(YAHOO_SERVICE_CHGRP_15
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4870 yahoo_packet_hash(pkt
, "ssssssss", 1, purple_connection_get_display_name(gc
),
4871 302, "240", 300, "240", 7, temp
, 224, gpo
, 264, gpn
, 301,
4873 yahoo_packet_send_and_free(pkt
, yd
);
4879 void yahoo_rename_group(PurpleConnection
*gc
, const char *old_name
,
4880 PurpleGroup
*group
, GList
*moved_buddies
)
4882 YahooData
*yd
= purple_connection_get_protocol_data(gc
);
4883 struct yahoo_packet
*pkt
;
4886 gpn
= yahoo_string_encode(gc
, purple_group_get_name(group
), FALSE
);
4887 gpo
= yahoo_string_encode(gc
, old_name
, FALSE
);
4888 if (!strcmp(gpn
, gpo
)) {
4894 pkt
= yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME
, YAHOO_STATUS_AVAILABLE
, yd
->session_id
);
4895 yahoo_packet_hash(pkt
, "sss", 1, purple_connection_get_display_name(gc
),
4897 yahoo_packet_send_and_free(pkt
, yd
);
4902 /********************************* Commands **********************************/
4905 yahoopurple_cmd_buzz(PurpleConversation
*c
, const gchar
*cmd
, gchar
**args
, gchar
**error
, void *data
) {
4906 PurpleAccount
*account
= purple_conversation_get_account(c
);
4908 if (*args
&& args
[0])
4909 return PURPLE_CMD_RET_FAILED
;
4911 purple_protocol_send_attention(purple_account_get_connection(account
), purple_conversation_get_name(c
), YAHOO_BUZZ
);
4913 return PURPLE_CMD_RET_OK
;
4917 yahoopurple_cmd_chat_join(PurpleConversation
*conv
, const char *cmd
,
4918 char **args
, char **error
, void *data
)
4921 PurpleConnection
*gc
;
4923 if (!args
|| !args
[0])
4924 return PURPLE_CMD_RET_FAILED
;
4926 gc
= purple_conversation_get_connection(conv
);
4927 purple_debug_info("yahoo", "Trying to join %s \n", args
[0]);
4929 comp
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
4930 g_hash_table_replace(comp
, g_strdup("room"), g_ascii_strdown(args
[0], -1));
4931 g_hash_table_replace(comp
, g_strdup("type"), g_strdup("Chat"));
4933 yahoo_c_join(gc
, comp
);
4935 g_hash_table_destroy(comp
);
4936 return PURPLE_CMD_RET_OK
;
4940 yahoopurple_cmd_chat_list(PurpleConversation
*conv
, const char *cmd
,
4941 char **args
, char **error
, void *data
)
4943 PurpleAccount
*account
= purple_conversation_get_account(conv
);
4944 if (*args
&& args
[0])
4945 return PURPLE_CMD_RET_FAILED
;
4946 purple_roomlist_show_with_account(account
);
4947 return PURPLE_CMD_RET_OK
;
4950 gboolean
yahoo_offline_message(const PurpleBuddy
*buddy
)
4955 gboolean
yahoo_send_attention(PurpleConnection
*gc
, const char *username
, guint type
)
4957 PurpleIMConversation
*im
;
4959 im
= purple_conversations_find_im_with_account(username
,
4960 purple_connection_get_account(gc
));
4962 g_return_val_if_fail(im
!= NULL
, FALSE
);
4964 purple_debug_info("yahoo", "Sending <ding> on account %s to buddy %s.\n",
4965 username
, purple_conversation_get_name(PURPLE_CONVERSATION(im
)));
4966 purple_conversation_send_with_flags(PURPLE_CONVERSATION(im
), "<ding>", PURPLE_MESSAGE_INVISIBLE
);
4971 GList
*yahoo_attention_types(PurpleAccount
*account
)
4973 static GList
*list
= NULL
;
4976 /* Yahoo only supports one attention command: the 'buzz'. */
4977 /* This is index number YAHOO_BUZZ. */
4978 list
= g_list_append(list
, purple_attention_type_new("Buzz", _("Buzz"),
4979 _("%s has buzzed you!"), _("Buzzing %s...")));
4986 yahoo_get_max_message_size(PurpleConversation
*conv
)
4988 return YAHOO_MAX_MESSAGE_LENGTH_CHARS
;