Mercurial > pidgin.yaz
comparison libpurple/protocols/yahoo/libymsg.c @ 27394:16ef6a9e7acd
Start of splitting yahoo into two separate prpls. Not sure if this even comes
close to building yet.
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Sun, 05 Jul 2009 04:37:33 +0000 |
parents | |
children | ef5f0cde8d74 |
comparison
equal
deleted
inserted
replaced
27393:319b0f3dd2d0 | 27394:16ef6a9e7acd |
---|---|
1 /* | |
2 * purple | |
3 * | |
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 | |
6 * source distribution. | |
7 * | |
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. | |
12 * | |
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. | |
17 * | |
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 | |
21 * | |
22 */ | |
23 | |
24 #include "internal.h" | |
25 | |
26 #include "account.h" | |
27 #include "accountopt.h" | |
28 #include "blist.h" | |
29 #include "cipher.h" | |
30 #include "cmds.h" | |
31 #include "core.h" | |
32 #include "debug.h" | |
33 #include "network.h" | |
34 #include "notify.h" | |
35 #include "privacy.h" | |
36 #include "prpl.h" | |
37 #include "proxy.h" | |
38 #include "request.h" | |
39 #include "server.h" | |
40 #include "util.h" | |
41 #include "version.h" | |
42 #include "xmlnode.h" | |
43 | |
44 #include "yahoo.h" | |
45 #include "yahoochat.h" | |
46 #include "yahoo_aliases.h" | |
47 #include "yahoo_doodle.h" | |
48 #include "yahoo_filexfer.h" | |
49 #include "yahoo_friend.h" | |
50 #include "yahoo_packet.h" | |
51 #include "yahoo_picture.h" | |
52 #include "ycht.h" | |
53 | |
54 /* #define YAHOO_DEBUG */ | |
55 | |
56 /* #define TRY_WEBMESSENGER_LOGIN 0 */ | |
57 | |
58 /* One hour */ | |
59 #define PING_TIMEOUT 3600 | |
60 | |
61 /* One minute */ | |
62 #define KEEPALIVE_TIMEOUT 60 | |
63 | |
64 static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *, PurpleGroup *); | |
65 #ifdef TRY_WEBMESSENGER_LOGIN | |
66 static void yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message); | |
67 #endif /* TRY_WEBMESSENGER_LOGIN */ | |
68 static void yahoo_set_status(PurpleAccount *account, PurpleStatus *status); | |
69 | |
70 static void yahoo_update_status(PurpleConnection *gc, const char *name, YahooFriend *f) | |
71 { | |
72 char *status = NULL; | |
73 | |
74 if (!gc || !name || !f || !purple_find_buddy(purple_connection_get_account(gc), name)) | |
75 return; | |
76 | |
77 switch (f->status) { | |
78 case YAHOO_STATUS_OFFLINE: | |
79 status = YAHOO_STATUS_TYPE_OFFLINE; | |
80 break; | |
81 case YAHOO_STATUS_AVAILABLE: | |
82 status = YAHOO_STATUS_TYPE_AVAILABLE; | |
83 break; | |
84 case YAHOO_STATUS_BRB: | |
85 status = YAHOO_STATUS_TYPE_BRB; | |
86 break; | |
87 case YAHOO_STATUS_BUSY: | |
88 status = YAHOO_STATUS_TYPE_BUSY; | |
89 break; | |
90 case YAHOO_STATUS_NOTATHOME: | |
91 status = YAHOO_STATUS_TYPE_NOTATHOME; | |
92 break; | |
93 case YAHOO_STATUS_NOTATDESK: | |
94 status = YAHOO_STATUS_TYPE_NOTATDESK; | |
95 break; | |
96 case YAHOO_STATUS_NOTINOFFICE: | |
97 status = YAHOO_STATUS_TYPE_NOTINOFFICE; | |
98 break; | |
99 case YAHOO_STATUS_ONPHONE: | |
100 status = YAHOO_STATUS_TYPE_ONPHONE; | |
101 break; | |
102 case YAHOO_STATUS_ONVACATION: | |
103 status = YAHOO_STATUS_TYPE_ONVACATION; | |
104 break; | |
105 case YAHOO_STATUS_OUTTOLUNCH: | |
106 status = YAHOO_STATUS_TYPE_OUTTOLUNCH; | |
107 break; | |
108 case YAHOO_STATUS_STEPPEDOUT: | |
109 status = YAHOO_STATUS_TYPE_STEPPEDOUT; | |
110 break; | |
111 case YAHOO_STATUS_INVISIBLE: /* this should never happen? */ | |
112 status = YAHOO_STATUS_TYPE_INVISIBLE; | |
113 break; | |
114 case YAHOO_STATUS_CUSTOM: | |
115 case YAHOO_STATUS_IDLE: | |
116 if (!f->away) | |
117 status = YAHOO_STATUS_TYPE_AVAILABLE; | |
118 else | |
119 status = YAHOO_STATUS_TYPE_AWAY; | |
120 break; | |
121 default: | |
122 purple_debug_warning("yahoo", "Warning, unknown status %d\n", f->status); | |
123 break; | |
124 } | |
125 | |
126 if (status) { | |
127 if (f->status == YAHOO_STATUS_CUSTOM) | |
128 purple_prpl_got_user_status(purple_connection_get_account(gc), name, status, "message", | |
129 yahoo_friend_get_status_message(f), NULL); | |
130 else | |
131 purple_prpl_got_user_status(purple_connection_get_account(gc), name, status, NULL); | |
132 } | |
133 | |
134 if (f->idle != 0) | |
135 purple_prpl_got_user_idle(purple_connection_get_account(gc), name, TRUE, f->idle); | |
136 else | |
137 purple_prpl_got_user_idle(purple_connection_get_account(gc), name, FALSE, 0); | |
138 | |
139 if (f->sms) | |
140 purple_prpl_got_user_status(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE, NULL); | |
141 else | |
142 purple_prpl_got_user_status_deactive(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE); | |
143 } | |
144 | |
145 static void yahoo_process_status(PurpleConnection *gc, struct yahoo_packet *pkt) | |
146 { | |
147 PurpleAccount *account = purple_connection_get_account(gc); | |
148 GSList *l = pkt->hash; | |
149 YahooFriend *f = NULL; | |
150 char *name = NULL; | |
151 gboolean unicode = FALSE; | |
152 char *message = NULL; | |
153 char *msn_name = NULL; | |
154 | |
155 if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { | |
156 if (!purple_account_get_remember_password(account)) | |
157 purple_account_set_password(account, NULL); | |
158 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NAME_IN_USE, | |
159 _("You have signed on from another location.")); | |
160 return; | |
161 } | |
162 | |
163 while (l) { | |
164 struct yahoo_pair *pair = l->data; | |
165 | |
166 switch (pair->key) { | |
167 case 0: /* we won't actually do anything with this */ | |
168 case 1: /* we won't actually do anything with this */ | |
169 break; | |
170 case 8: /* how many online buddies we have */ | |
171 break; | |
172 case 7: /* the current buddy */ | |
173 /* update the previous buddy before changing the variables */ | |
174 if (f) { | |
175 if (message) | |
176 yahoo_friend_set_status_message(f, yahoo_string_decode(gc, message, unicode)); | |
177 if (name) | |
178 yahoo_update_status(gc, name, f); | |
179 } | |
180 name = message = NULL; | |
181 f = NULL; | |
182 if (pair->value && g_utf8_validate(pair->value, -1, NULL)) { | |
183 GSList *tmplist; | |
184 int protocol = 0; | |
185 | |
186 name = pair->value; | |
187 | |
188 /* Look ahead to see if we have the protocol info about the buddy */ | |
189 for (tmplist = l->next; tmplist; tmplist = tmplist->next) { | |
190 struct yahoo_pair *p = tmplist->data; | |
191 if (p->key == 7) | |
192 break; | |
193 if (p->key == 241) { | |
194 if(strtol(p->value, NULL, 10) == 2) { | |
195 g_free(msn_name); | |
196 msn_name = g_strconcat("msn/", name, NULL); | |
197 name = msn_name; | |
198 protocol = 2; | |
199 } | |
200 break; | |
201 } | |
202 } | |
203 f = yahoo_friend_find_or_new(gc, name); | |
204 f->protocol = protocol; | |
205 } | |
206 break; | |
207 case 10: /* state */ | |
208 if (!f) | |
209 break; | |
210 | |
211 f->status = strtol(pair->value, NULL, 10); | |
212 if ((f->status >= YAHOO_STATUS_BRB) && (f->status <= YAHOO_STATUS_STEPPEDOUT)) | |
213 f->away = 1; | |
214 else | |
215 f->away = 0; | |
216 | |
217 if (f->status == YAHOO_STATUS_IDLE) { | |
218 /* Idle may have already been set in a more precise way in case 137 */ | |
219 if (f->idle == 0) | |
220 f->idle = time(NULL); | |
221 } else | |
222 f->idle = 0; | |
223 | |
224 if (f->status != YAHOO_STATUS_CUSTOM) | |
225 yahoo_friend_set_status_message(f, NULL); | |
226 | |
227 f->sms = 0; | |
228 break; | |
229 case 19: /* custom message */ | |
230 if (f) | |
231 message = pair->value; | |
232 break; | |
233 case 11: /* this is the buddy's session id */ | |
234 if (f) | |
235 f->session_id = strtol(pair->value, NULL, 10); | |
236 break; | |
237 case 17: /* in chat? */ | |
238 break; | |
239 case 47: /* is custom status away or not? 2=idle*/ | |
240 if (!f) | |
241 break; | |
242 | |
243 /* I have no idea what it means when this is | |
244 * set when someone's available, but it doesn't | |
245 * mean idle. */ | |
246 if (f->status == YAHOO_STATUS_AVAILABLE) | |
247 break; | |
248 | |
249 f->away = strtol(pair->value, NULL, 10); | |
250 if (f->away == 2) { | |
251 /* Idle may have already been set in a more precise way in case 137 */ | |
252 if (f->idle == 0) | |
253 f->idle = time(NULL); | |
254 } | |
255 | |
256 break; | |
257 case 138: /* either we're not idle, or we are but won't say how long */ | |
258 if (!f) | |
259 break; | |
260 | |
261 if (f->idle) | |
262 f->idle = -1; | |
263 break; | |
264 case 137: /* usually idle time in seconds, sometimes login time */ | |
265 if (!f) | |
266 break; | |
267 | |
268 if (f->status != YAHOO_STATUS_AVAILABLE) | |
269 f->idle = time(NULL) - strtol(pair->value, NULL, 10); | |
270 break; | |
271 case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ | |
272 if (strtol(pair->value, NULL, 10) == 0) { | |
273 if (f) | |
274 f->status = YAHOO_STATUS_OFFLINE; | |
275 if (name) { | |
276 purple_prpl_got_user_status(account, name, "offline", NULL); | |
277 purple_prpl_got_user_status_deactive(account, name, YAHOO_STATUS_TYPE_MOBILE); | |
278 } | |
279 break; | |
280 } | |
281 break; | |
282 case 60: /* SMS */ | |
283 if (f) { | |
284 f->sms = strtol(pair->value, NULL, 10); | |
285 yahoo_update_status(gc, name, f); | |
286 } | |
287 break; | |
288 case 197: /* Avatars */ | |
289 { | |
290 guchar *decoded; | |
291 char *tmp; | |
292 gsize len; | |
293 | |
294 if (pair->value) { | |
295 decoded = purple_base64_decode(pair->value, &len); | |
296 if (len) { | |
297 tmp = purple_str_binary_to_ascii(decoded, len); | |
298 purple_debug_info("yahoo", "Got key 197, value = %s\n", tmp); | |
299 g_free(tmp); | |
300 } | |
301 g_free(decoded); | |
302 } | |
303 break; | |
304 } | |
305 case 192: /* Pictures, aka Buddy Icons, checksum */ | |
306 { | |
307 /* FIXME: Please, if you know this protocol, | |
308 * FIXME: fix up the strtol() stuff if possible. */ | |
309 int cksum = strtol(pair->value, NULL, 10); | |
310 const char *locksum = NULL; | |
311 PurpleBuddy *b; | |
312 | |
313 if (!name) | |
314 break; | |
315 | |
316 b = purple_find_buddy(gc->account, name); | |
317 | |
318 if (!cksum || (cksum == -1)) { | |
319 if (f) | |
320 yahoo_friend_set_buddy_icon_need_request(f, TRUE); | |
321 purple_buddy_icons_set_for_user(gc->account, name, NULL, 0, NULL); | |
322 break; | |
323 } | |
324 | |
325 if (!f) | |
326 break; | |
327 | |
328 yahoo_friend_set_buddy_icon_need_request(f, FALSE); | |
329 if (b) { | |
330 locksum = purple_buddy_icons_get_checksum_for_user(b); | |
331 if (!locksum || (cksum != strtol(locksum, NULL, 10))) | |
332 yahoo_send_picture_request(gc, name); | |
333 } | |
334 | |
335 break; | |
336 } | |
337 case 16: /* Custom error message */ | |
338 { | |
339 char *tmp = yahoo_string_decode(gc, pair->value, TRUE); | |
340 purple_notify_error(gc, NULL, tmp, NULL); | |
341 g_free(tmp); | |
342 } | |
343 break; | |
344 case 97: /* Unicode status message */ | |
345 unicode = !strcmp(pair->value, "1"); | |
346 break; | |
347 case 244: /* client version number. Yahoo Client Detection */ | |
348 if(f && strtol(pair->value, NULL, 10)) | |
349 f->version_id = strtol(pair->value, NULL, 10); | |
350 break; | |
351 case 241: /* protocol buddy belongs to */ | |
352 break; /* We process this when get '7' */ | |
353 default: | |
354 purple_debug_warning("yahoo", | |
355 "Unknown status key %d\n", pair->key); | |
356 break; | |
357 } | |
358 | |
359 l = l->next; | |
360 } | |
361 | |
362 if (f) { | |
363 if (pkt->service == YAHOO_SERVICE_LOGOFF) | |
364 f->status = YAHOO_STATUS_OFFLINE; | |
365 if (message) | |
366 yahoo_friend_set_status_message(f, yahoo_string_decode(gc, message, unicode)); | |
367 | |
368 if (name) /* update the last buddy */ | |
369 yahoo_update_status(gc, name, f); | |
370 } | |
371 g_free(msn_name); | |
372 } | |
373 | |
374 static void yahoo_do_group_check(PurpleAccount *account, GHashTable *ht, const char *name, const char *group) | |
375 { | |
376 PurpleBuddy *b; | |
377 PurpleGroup *g; | |
378 GSList *list, *i; | |
379 gboolean onlist = 0; | |
380 char *oname = NULL; | |
381 char **oname_p = &oname; | |
382 GSList **list_p = &list; | |
383 | |
384 if (!g_hash_table_lookup_extended(ht, purple_normalize(account, name), (gpointer *) oname_p, (gpointer *) list_p)) | |
385 list = purple_find_buddies(account, name); | |
386 else | |
387 g_hash_table_steal(ht, name); | |
388 | |
389 for (i = list; i; i = i->next) { | |
390 b = i->data; | |
391 g = purple_buddy_get_group(b); | |
392 if (!purple_utf8_strcasecmp(group, purple_group_get_name(g))) { | |
393 purple_debug_misc("yahoo", | |
394 "Oh good, %s is in the right group (%s).\n", name, group); | |
395 list = g_slist_delete_link(list, i); | |
396 onlist = 1; | |
397 break; | |
398 } | |
399 } | |
400 | |
401 if (!onlist) { | |
402 purple_debug_misc("yahoo", | |
403 "Uhoh, %s isn't on the list (or not in this group), adding him to group %s.\n", name, group); | |
404 if (!(g = purple_find_group(group))) { | |
405 g = purple_group_new(group); | |
406 purple_blist_add_group(g, NULL); | |
407 } | |
408 b = purple_buddy_new(account, name, NULL); | |
409 purple_blist_add_buddy(b, NULL, g, NULL); | |
410 } | |
411 | |
412 if (list) { | |
413 if (!oname) | |
414 oname = g_strdup(purple_normalize(account, name)); | |
415 g_hash_table_insert(ht, oname, list); | |
416 } else if (oname) | |
417 g_free(oname); | |
418 } | |
419 | |
420 static void yahoo_do_group_cleanup(gpointer key, gpointer value, gpointer user_data) | |
421 { | |
422 char *name = key; | |
423 GSList *list = value, *i; | |
424 PurpleBuddy *b; | |
425 PurpleGroup *g; | |
426 | |
427 for (i = list; i; i = i->next) { | |
428 b = i->data; | |
429 g = purple_buddy_get_group(b); | |
430 purple_debug_misc("yahoo", "Deleting Buddy %s from group %s.\n", name, | |
431 purple_group_get_name(g)); | |
432 purple_blist_remove_buddy(b); | |
433 } | |
434 } | |
435 | |
436 static char *_getcookie(char *rawcookie) | |
437 { | |
438 char *cookie = NULL; | |
439 char *tmpcookie; | |
440 char *cookieend; | |
441 | |
442 if (strlen(rawcookie) < 2) | |
443 return NULL; | |
444 tmpcookie = g_strdup(rawcookie+2); | |
445 cookieend = strchr(tmpcookie, ';'); | |
446 | |
447 if (cookieend) | |
448 *cookieend = '\0'; | |
449 | |
450 cookie = g_strdup(tmpcookie); | |
451 g_free(tmpcookie); | |
452 | |
453 return cookie; | |
454 } | |
455 | |
456 static void yahoo_process_cookie(struct yahoo_data *yd, char *c) | |
457 { | |
458 if (c[0] == 'Y') { | |
459 if (yd->cookie_y) | |
460 g_free(yd->cookie_y); | |
461 yd->cookie_y = _getcookie(c); | |
462 } else if (c[0] == 'T') { | |
463 if (yd->cookie_t) | |
464 g_free(yd->cookie_t); | |
465 yd->cookie_t = _getcookie(c); | |
466 } else | |
467 purple_debug_info("yahoo", "Unrecognized cookie '%c'\n", c[0]); | |
468 yd->cookies = g_slist_prepend(yd->cookies, g_strdup(c)); | |
469 } | |
470 | |
471 static void yahoo_process_list_15(PurpleConnection *gc, struct yahoo_packet *pkt) | |
472 { | |
473 GSList *l = pkt->hash; | |
474 | |
475 PurpleAccount *account = purple_connection_get_account(gc); | |
476 struct yahoo_data *yd = gc->proto_data; | |
477 GHashTable *ht; | |
478 char *norm_bud = NULL; | |
479 char *temp = NULL; | |
480 YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */ | |
481 /* But what if you had no friends? */ | |
482 PurpleBuddy *b; | |
483 PurpleGroup *g; | |
484 int protocol = 0; | |
485 int stealth = 0; | |
486 | |
487 | |
488 ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free); | |
489 | |
490 while (l) { | |
491 struct yahoo_pair *pair = l->data; | |
492 l = l->next; | |
493 | |
494 switch (pair->key) { | |
495 case 302: | |
496 /* This is always 318 before a group, 319 before the first s/n in a group, 320 before any ignored s/n. | |
497 * It is not sent for s/n's in a group after the first. | |
498 * All ignored s/n's are listed last, so when we see a 320 we clear the group and begin marking the | |
499 * s/n's as ignored. It is always followed by an identical 300 key. | |
500 */ | |
501 if (pair->value && !strcmp(pair->value, "320")) { | |
502 /* No longer in any group; this indicates the start of the ignore list. */ | |
503 g_free(yd->current_list15_grp); | |
504 yd->current_list15_grp = NULL; | |
505 } | |
506 | |
507 break; | |
508 case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */ | |
509 if(temp != NULL) { | |
510 if(protocol == 2) | |
511 norm_bud = g_strconcat("msn/", temp, NULL); | |
512 else | |
513 norm_bud = g_strdup(temp); | |
514 | |
515 if (yd->current_list15_grp) { | |
516 /* This buddy is in a group */ | |
517 f = yahoo_friend_find_or_new(gc, norm_bud); | |
518 if (!(b = purple_find_buddy(account, norm_bud))) { | |
519 if (!(g = purple_find_group(yd->current_list15_grp))) { | |
520 g = purple_group_new(yd->current_list15_grp); | |
521 purple_blist_add_group(g, NULL); | |
522 } | |
523 b = purple_buddy_new(account, norm_bud, NULL); | |
524 purple_blist_add_buddy(b, NULL, g, NULL); | |
525 } | |
526 yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); | |
527 if(protocol != 0) { | |
528 f->protocol = protocol; | |
529 purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol); | |
530 } | |
531 if(stealth == 2) | |
532 f->presence = YAHOO_PRESENCE_PERM_OFFLINE; | |
533 | |
534 /* set p2p status not connected and no p2p packet sent */ | |
535 if(protocol == 0) { | |
536 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); | |
537 f->p2p_packet_sent = 0; | |
538 } else | |
539 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT); | |
540 } else { | |
541 /* This buddy is on the ignore list (and therefore in no group) */ | |
542 purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n",account->username, norm_bud); | |
543 purple_privacy_deny_add(account, norm_bud, 1); | |
544 } | |
545 | |
546 protocol = 0; | |
547 stealth = 0; | |
548 norm_bud = NULL; | |
549 temp = NULL; | |
550 } | |
551 break; | |
552 case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */ | |
553 break; | |
554 case 65: /* This is the group */ | |
555 g_free(yd->current_list15_grp); | |
556 yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE); | |
557 break; | |
558 case 7: /* buddy's s/n */ | |
559 temp = g_strdup(purple_normalize(account, pair->value)); | |
560 break; | |
561 case 241: /* another protocol user */ | |
562 protocol = strtol(pair->value, NULL, 10); | |
563 break; | |
564 case 59: /* somebody told cookies come here too, but im not sure */ | |
565 yahoo_process_cookie(yd, pair->value); | |
566 break; | |
567 case 317: /* Stealth Setting */ | |
568 stealth = strtol(pair->value, NULL, 10); | |
569 break; | |
570 /* case 242: */ /* this seems related to 241 */ | |
571 /* break; */ | |
572 } | |
573 } | |
574 | |
575 g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); | |
576 | |
577 /* Now that we have processed the buddy list, we can say yahoo has connected */ | |
578 purple_connection_set_display_name(gc, purple_normalize(account, purple_account_get_username(account))); | |
579 purple_connection_set_state(gc, PURPLE_CONNECTED); | |
580 yd->logged_in = TRUE; | |
581 if (yd->picture_upload_todo) { | |
582 yahoo_buddy_icon_upload(gc, yd->picture_upload_todo); | |
583 yd->picture_upload_todo = NULL; | |
584 } | |
585 yahoo_set_status(account, purple_account_get_active_status(account)); | |
586 purple_debug_info("yahoo","Authentication: Connection established\n"); | |
587 | |
588 g_hash_table_destroy(ht); | |
589 g_free(norm_bud); | |
590 g_free(temp); | |
591 } | |
592 | |
593 static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt) | |
594 { | |
595 GSList *l = pkt->hash; | |
596 gboolean export = FALSE; | |
597 gboolean got_serv_list = FALSE; | |
598 PurpleBuddy *b; | |
599 PurpleGroup *g; | |
600 YahooFriend *f = NULL; | |
601 PurpleAccount *account = purple_connection_get_account(gc); | |
602 struct yahoo_data *yd = gc->proto_data; | |
603 GHashTable *ht; | |
604 | |
605 char **lines; | |
606 char **split; | |
607 char **buddies; | |
608 char **tmp, **bud, *norm_bud; | |
609 char *grp = NULL; | |
610 | |
611 if (pkt->id) | |
612 yd->session_id = pkt->id; | |
613 | |
614 while (l) { | |
615 struct yahoo_pair *pair = l->data; | |
616 l = l->next; | |
617 | |
618 switch (pair->key) { | |
619 case 87: | |
620 if (!yd->tmp_serv_blist) | |
621 yd->tmp_serv_blist = g_string_new(pair->value); | |
622 else | |
623 g_string_append(yd->tmp_serv_blist, pair->value); | |
624 break; | |
625 case 88: | |
626 if (!yd->tmp_serv_ilist) | |
627 yd->tmp_serv_ilist = g_string_new(pair->value); | |
628 else | |
629 g_string_append(yd->tmp_serv_ilist, pair->value); | |
630 break; | |
631 case 89: | |
632 yd->profiles = g_strsplit(pair->value, ",", -1); | |
633 break; | |
634 case 59: /* cookies, yum */ | |
635 yahoo_process_cookie(yd, pair->value); | |
636 break; | |
637 case YAHOO_SERVICE_PRESENCE_PERM: | |
638 if (!yd->tmp_serv_plist) | |
639 yd->tmp_serv_plist = g_string_new(pair->value); | |
640 else | |
641 g_string_append(yd->tmp_serv_plist, pair->value); | |
642 break; | |
643 } | |
644 } | |
645 | |
646 if (pkt->status != 0) | |
647 return; | |
648 | |
649 if (yd->tmp_serv_blist) { | |
650 ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free); | |
651 | |
652 lines = g_strsplit(yd->tmp_serv_blist->str, "\n", -1); | |
653 for (tmp = lines; *tmp; tmp++) { | |
654 split = g_strsplit(*tmp, ":", 2); | |
655 if (!split) | |
656 continue; | |
657 if (!split[0] || !split[1]) { | |
658 g_strfreev(split); | |
659 continue; | |
660 } | |
661 grp = yahoo_string_decode(gc, split[0], FALSE); | |
662 buddies = g_strsplit(split[1], ",", -1); | |
663 for (bud = buddies; bud && *bud; bud++) { | |
664 norm_bud = g_strdup(purple_normalize(account, *bud)); | |
665 f = yahoo_friend_find_or_new(gc, norm_bud); | |
666 | |
667 if (!(b = purple_find_buddy(account, norm_bud))) { | |
668 if (!(g = purple_find_group(grp))) { | |
669 g = purple_group_new(grp); | |
670 purple_blist_add_group(g, NULL); | |
671 } | |
672 b = purple_buddy_new(account, norm_bud, NULL); | |
673 purple_blist_add_buddy(b, NULL, g, NULL); | |
674 export = TRUE; | |
675 } | |
676 | |
677 yahoo_do_group_check(account, ht, norm_bud, grp); | |
678 /* set p2p status not connected and no p2p packet sent */ | |
679 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); | |
680 f->p2p_packet_sent = 0; | |
681 | |
682 g_free(norm_bud); | |
683 } | |
684 g_strfreev(buddies); | |
685 g_strfreev(split); | |
686 g_free(grp); | |
687 } | |
688 g_strfreev(lines); | |
689 | |
690 g_string_free(yd->tmp_serv_blist, TRUE); | |
691 yd->tmp_serv_blist = NULL; | |
692 g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); | |
693 g_hash_table_destroy(ht); | |
694 } | |
695 | |
696 if (yd->tmp_serv_ilist) { | |
697 buddies = g_strsplit(yd->tmp_serv_ilist->str, ",", -1); | |
698 for (bud = buddies; bud && *bud; bud++) { | |
699 /* The server is already ignoring the user */ | |
700 got_serv_list = TRUE; | |
701 purple_privacy_deny_add(account, *bud, 1); | |
702 } | |
703 g_strfreev(buddies); | |
704 | |
705 g_string_free(yd->tmp_serv_ilist, TRUE); | |
706 yd->tmp_serv_ilist = NULL; | |
707 } | |
708 | |
709 if (got_serv_list && | |
710 ((account->perm_deny != PURPLE_PRIVACY_ALLOW_BUDDYLIST) && | |
711 (account->perm_deny != PURPLE_PRIVACY_DENY_ALL) && | |
712 (account->perm_deny != PURPLE_PRIVACY_ALLOW_USERS))) | |
713 { | |
714 account->perm_deny = PURPLE_PRIVACY_DENY_USERS; | |
715 purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_PRIVACY_DENY_USERS.\n", | |
716 account->username); | |
717 } | |
718 | |
719 if (yd->tmp_serv_plist) { | |
720 buddies = g_strsplit(yd->tmp_serv_plist->str, ",", -1); | |
721 for (bud = buddies; bud && *bud; bud++) { | |
722 f = yahoo_friend_find(gc, *bud); | |
723 if (f) { | |
724 purple_debug_info("yahoo", "%s setting presence for %s to PERM_OFFLINE\n", | |
725 account->username, *bud); | |
726 f->presence = YAHOO_PRESENCE_PERM_OFFLINE; | |
727 } | |
728 } | |
729 g_strfreev(buddies); | |
730 g_string_free(yd->tmp_serv_plist, TRUE); | |
731 yd->tmp_serv_plist = NULL; | |
732 | |
733 } | |
734 /* Now that we've got the list, request aliases */ | |
735 yahoo_fetch_aliases(gc); | |
736 } | |
737 | |
738 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */ | |
739 static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type) | |
740 { | |
741 PurpleAccount *account; | |
742 char *msg = NULL; | |
743 char *from = NULL; | |
744 char *stat = NULL; | |
745 char *game = NULL; | |
746 YahooFriend *f = NULL; | |
747 GSList *l = pkt->hash; | |
748 gint val_11 = 0; | |
749 struct yahoo_data *yd = gc->proto_data; | |
750 gboolean msn = FALSE; | |
751 | |
752 account = purple_connection_get_account(gc); | |
753 | |
754 while (l) { | |
755 struct yahoo_pair *pair = l->data; | |
756 if (pair->key == 4 || pair->key == 1) | |
757 from = pair->value; | |
758 if (pair->key == 49) | |
759 msg = pair->value; | |
760 if (pair->key == 13) | |
761 stat = pair->value; | |
762 if (pair->key == 14) | |
763 game = pair->value; | |
764 if (pair->key == 11) | |
765 val_11 = strtol(pair->value, NULL, 10); | |
766 if (pair->key == 241) | |
767 if(strtol(pair->value, NULL, 10) == 2) | |
768 msn = TRUE; | |
769 l = l->next; | |
770 } | |
771 | |
772 if (!from || !msg) | |
773 return; | |
774 | |
775 /* disconnect the peer if connected through p2p and sends wrong value for session id */ | |
776 if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) { | |
777 purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from); | |
778 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ | |
779 g_hash_table_remove(yd->peers, from); | |
780 return; | |
781 } | |
782 | |
783 if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")) | |
784 && (purple_privacy_check(account, from))) | |
785 { | |
786 if(msn) { | |
787 char *msn_from = g_strconcat("msn/", from, NULL); | |
788 if (*stat == '1') | |
789 serv_got_typing(gc, msn_from, 0, PURPLE_TYPING); | |
790 else | |
791 serv_got_typing_stopped(gc, msn_from); | |
792 g_free(msn_from); | |
793 } | |
794 else { | |
795 if (*stat == '1') | |
796 serv_got_typing(gc, from, 0, PURPLE_TYPING); | |
797 else | |
798 serv_got_typing_stopped(gc, from); | |
799 } | |
800 } else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) { | |
801 PurpleBuddy *bud = purple_find_buddy(account, from); | |
802 | |
803 if (!bud) { | |
804 purple_debug_warning("yahoo", | |
805 "%s is playing a game, and doesn't want you to know.\n", from); | |
806 } | |
807 | |
808 f = yahoo_friend_find(gc, from); | |
809 if (!f) | |
810 return; /* if they're not on the list, don't bother */ | |
811 | |
812 yahoo_friend_set_game(f, NULL); | |
813 | |
814 if (*stat == '1') { | |
815 yahoo_friend_set_game(f, game); | |
816 if (bud) | |
817 yahoo_update_status(gc, from, f); | |
818 } | |
819 } else if (!g_ascii_strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) { | |
820 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account); | |
821 char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from); | |
822 purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL)); | |
823 g_free(buf); | |
824 } | |
825 } | |
826 | |
827 | |
828 struct _yahoo_im { | |
829 char *from; | |
830 char *active_id; | |
831 int time; | |
832 int utf8; | |
833 int buddy_icon; | |
834 char *id; | |
835 char *msg; | |
836 gboolean msn; | |
837 }; | |
838 | |
839 static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt) | |
840 { | |
841 PurpleAccount *account; | |
842 GSList *l = pkt->hash; | |
843 struct _yahoo_im *sms = NULL; | |
844 struct yahoo_data *yd; | |
845 char *server_msg = NULL; | |
846 char *m; | |
847 | |
848 yd = gc->proto_data; | |
849 account = purple_connection_get_account(gc); | |
850 | |
851 while (l != NULL) { | |
852 struct yahoo_pair *pair = l->data; | |
853 if (pair->key == 4) { | |
854 sms = g_new0(struct _yahoo_im, 1); | |
855 sms->from = g_strdup_printf("+%s", pair->value); | |
856 sms->time = time(NULL); | |
857 sms->utf8 = TRUE; | |
858 } | |
859 if (pair->key == 14) { | |
860 if (sms) | |
861 sms->msg = pair->value; | |
862 } | |
863 if (pair->key == 68) | |
864 if(sms) | |
865 g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value)); | |
866 if (pair->key == 16) | |
867 server_msg = pair->value; | |
868 l = l->next; | |
869 } | |
870 | |
871 if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) { | |
872 if (server_msg) { | |
873 PurpleConversation *c; | |
874 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account); | |
875 if (c == NULL) | |
876 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from); | |
877 purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
878 } | |
879 else | |
880 purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL); | |
881 | |
882 g_free(sms->from); | |
883 g_free(sms); | |
884 return ; | |
885 } | |
886 | |
887 if (!sms->from || !sms->msg) { | |
888 g_free(sms); | |
889 return; | |
890 } | |
891 | |
892 m = yahoo_string_decode(gc, sms->msg, sms->utf8); | |
893 serv_got_im(gc, sms->from, m, 0, sms->time); | |
894 | |
895 g_free(m); | |
896 g_free(sms->from); | |
897 g_free(sms); | |
898 } | |
899 | |
900 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */ | |
901 static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type) | |
902 { | |
903 PurpleAccount *account; | |
904 struct yahoo_data *yd = gc->proto_data; | |
905 GSList *l = pkt->hash; | |
906 GSList *list = NULL; | |
907 struct _yahoo_im *im = NULL; | |
908 const char *imv = NULL; | |
909 gint val_11 = 0; | |
910 | |
911 account = purple_connection_get_account(gc); | |
912 | |
913 if (pkt->status <= 1 || pkt->status == 5 || pkt->status == YAHOO_STATUS_OFFLINE) { | |
914 /* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */ | |
915 while (l != NULL) { | |
916 struct yahoo_pair *pair = l->data; | |
917 if (pair->key == 4 || pair->key == 1) { | |
918 im = g_new0(struct _yahoo_im, 1); | |
919 list = g_slist_append(list, im); | |
920 im->from = pair->value; | |
921 im->time = time(NULL); | |
922 im->utf8 = TRUE; | |
923 } | |
924 if (im && pair->key == 5) | |
925 im->active_id = pair->value; | |
926 if (pair->key == 97) | |
927 if (im) | |
928 im->utf8 = strtol(pair->value, NULL, 10); | |
929 if (pair->key == 15) | |
930 if (im) | |
931 im->time = strtol(pair->value, NULL, 10); | |
932 if (pair->key == 206) | |
933 if (im) | |
934 im->buddy_icon = strtol(pair->value, NULL, 10); | |
935 if (pair->key == 14) { | |
936 if (im) | |
937 im->msg = pair->value; | |
938 } | |
939 if (im && pair->key == 241) { | |
940 if(strtol(pair->value, NULL, 10) == 2) | |
941 im->msn = TRUE; | |
942 } | |
943 /* peer session id */ | |
944 if (pair->key == 11) { | |
945 if (im) | |
946 val_11 = strtol(pair->value, NULL, 10); | |
947 } | |
948 /* IMV key */ | |
949 if (pair->key == 63) | |
950 { | |
951 imv = pair->value; | |
952 } | |
953 if (pair->key == 429) | |
954 if (im) | |
955 im->id = pair->value; | |
956 l = l->next; | |
957 } | |
958 } else if (pkt->status == 2) { | |
959 purple_notify_error(gc, NULL, | |
960 _("Your Yahoo! message did not get sent."), NULL); | |
961 } | |
962 | |
963 /* disconnect the peer if connected through p2p and sends wrong value for session id */ | |
964 if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) { | |
965 purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->from); | |
966 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ | |
967 g_hash_table_remove(yd->peers, im->from); | |
968 return; | |
969 } | |
970 | |
971 /** TODO: It seems that this check should be per IM, not global */ | |
972 /* Check for the Doodle IMV */ | |
973 if (im != NULL && imv!= NULL && im->from != NULL) | |
974 { | |
975 g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv)); | |
976 | |
977 if (strstr(imv, "doodle;") != NULL) | |
978 { | |
979 PurpleWhiteboard *wb; | |
980 | |
981 if (!purple_privacy_check(account, im->from)) { | |
982 purple_debug_info("yahoo", "Doodle request from %s dropped.\n", im->from); | |
983 return; | |
984 } | |
985 | |
986 /* I'm not sure the following ever happens -DAA */ | |
987 | |
988 wb = purple_whiteboard_get_session(account, im->from); | |
989 | |
990 /* If a Doodle session doesn't exist between this user */ | |
991 if(wb == NULL) | |
992 { | |
993 doodle_session *ds; | |
994 wb = purple_whiteboard_create(account, im->from, DOODLE_STATE_REQUESTED); | |
995 ds = wb->proto_data; | |
996 ds->imv_key = g_strdup(imv); | |
997 | |
998 yahoo_doodle_command_send_request(gc, im->from, imv); | |
999 yahoo_doodle_command_send_ready(gc, im->from, imv); | |
1000 } | |
1001 } | |
1002 } | |
1003 | |
1004 for (l = list; l; l = l->next) { | |
1005 YahooFriend *f; | |
1006 char *m, *m2; | |
1007 char *msn_from = NULL; | |
1008 const char *from; | |
1009 PurpleConversation *c; | |
1010 im = l->data; | |
1011 | |
1012 if (!im->from || !im->msg) { | |
1013 g_free(im); | |
1014 continue; | |
1015 } | |
1016 | |
1017 if (!purple_privacy_check(account, im->from)) { | |
1018 purple_debug_info("yahoo", "Message from %s dropped.\n", im->from); | |
1019 return; | |
1020 } | |
1021 | |
1022 /* | |
1023 * TODO: Is there anything else we should check when determining whether | |
1024 * we should send an acknowledgement? | |
1025 */ | |
1026 if (im->id != NULL) { | |
1027 /* Send acknowledgement. If we don't do this then the official | |
1028 * Yahoo Messenger client for Windows will send us the same | |
1029 * message 7 seconds later as an offline message. This is true | |
1030 * for at least version 9.0.0.2162 on Windows XP. */ | |
1031 struct yahoo_packet *pkt2; | |
1032 pkt2 = yahoo_packet_new(YAHOO_SERVICE_MESSAGE_ACK, | |
1033 YAHOO_STATUS_AVAILABLE, pkt->id); | |
1034 yahoo_packet_hash(pkt2, "ssisii", | |
1035 1, im->active_id, /* May not always be the connection's display name */ | |
1036 5, im->from, | |
1037 302, 430, | |
1038 430, im->id, | |
1039 303, 430, | |
1040 450, 0); | |
1041 yahoo_packet_send_and_free(pkt2, yd); | |
1042 } | |
1043 | |
1044 m = yahoo_string_decode(gc, im->msg, im->utf8); | |
1045 /* This may actually not be necessary, but it appears | |
1046 * that at least at one point some clients were sending | |
1047 * "\r\n" as line delimiters, so we want to avoid double | |
1048 * lines. */ | |
1049 m2 = purple_strreplace(m, "\r\n", "\n"); | |
1050 g_free(m); | |
1051 m = m2; | |
1052 purple_util_chrreplace(m, '\r', '\n'); | |
1053 | |
1054 if (im->msn) { | |
1055 msn_from = g_strconcat("msn/", im->from, NULL); | |
1056 from = msn_from; | |
1057 } else { | |
1058 from = im->from; | |
1059 } | |
1060 | |
1061 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account); | |
1062 | |
1063 if (!strcmp(m, "<ding>")) { | |
1064 char *username; | |
1065 | |
1066 if (c == NULL) { | |
1067 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, from); | |
1068 } | |
1069 username = g_markup_escape_text(from, -1); | |
1070 purple_prpl_got_attention(gc, username, YAHOO_BUZZ); | |
1071 g_free(username); | |
1072 g_free(m); | |
1073 g_free(im); | |
1074 g_free(msn_from); | |
1075 continue; | |
1076 } | |
1077 | |
1078 m2 = yahoo_codes_to_html(m); | |
1079 g_free(m); | |
1080 | |
1081 serv_got_im(gc, from, m2, 0, im->time); | |
1082 g_free(m2); | |
1083 | |
1084 /* laters : implement buddy icon for msn friends */ | |
1085 if (!im->msn) { | |
1086 if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) { | |
1087 if (yahoo_friend_get_buddy_icon_need_request(f)) { | |
1088 yahoo_send_picture_request(gc, im->from); | |
1089 yahoo_friend_set_buddy_icon_need_request(f, FALSE); | |
1090 } | |
1091 } | |
1092 } | |
1093 | |
1094 g_free(im); | |
1095 g_free(msn_from); | |
1096 } | |
1097 g_slist_free(list); | |
1098 } | |
1099 | |
1100 static void yahoo_process_sysmessage(PurpleConnection *gc, struct yahoo_packet *pkt) | |
1101 { | |
1102 GSList *l = pkt->hash; | |
1103 char *prim, *me = NULL, *msg = NULL; | |
1104 | |
1105 while (l) { | |
1106 struct yahoo_pair *pair = l->data; | |
1107 | |
1108 if (pair->key == 5) | |
1109 me = pair->value; | |
1110 if (pair->key == 14) | |
1111 msg = pair->value; | |
1112 | |
1113 l = l->next; | |
1114 } | |
1115 | |
1116 if (!msg || !g_utf8_validate(msg, -1, NULL)) | |
1117 return; | |
1118 | |
1119 prim = g_strdup_printf(_("Yahoo! system message for %s:"), | |
1120 me?me:purple_connection_get_display_name(gc)); | |
1121 purple_notify_info(NULL, NULL, prim, msg); | |
1122 g_free(prim); | |
1123 } | |
1124 | |
1125 struct yahoo_add_request { | |
1126 PurpleConnection *gc; | |
1127 char *id; | |
1128 char *who; | |
1129 int protocol; | |
1130 }; | |
1131 | |
1132 static void | |
1133 yahoo_buddy_add_authorize_cb(gpointer data) | |
1134 { | |
1135 struct yahoo_add_request *add_req = data; | |
1136 struct yahoo_packet *pkt; | |
1137 struct yahoo_data *yd = add_req->gc->proto_data; | |
1138 const char *who = add_req->who; | |
1139 | |
1140 if (add_req->protocol == 2) | |
1141 who += 4; | |
1142 | |
1143 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, 0); | |
1144 yahoo_packet_hash(pkt, "ssiii", | |
1145 1, add_req->id, | |
1146 5, who, | |
1147 241, add_req->protocol, | |
1148 13, 1, | |
1149 334, 0); | |
1150 yahoo_packet_send_and_free(pkt, yd); | |
1151 | |
1152 g_free(add_req->id); | |
1153 g_free(add_req->who); | |
1154 g_free(add_req); | |
1155 } | |
1156 | |
1157 static void | |
1158 yahoo_buddy_add_deny_cb(struct yahoo_add_request *add_req, const char *msg) | |
1159 { | |
1160 struct yahoo_data *yd = add_req->gc->proto_data; | |
1161 struct yahoo_packet *pkt; | |
1162 char *encoded_msg = NULL; | |
1163 PurpleAccount *account = purple_connection_get_account(add_req->gc); | |
1164 | |
1165 if (msg && *msg) | |
1166 encoded_msg = yahoo_string_encode(add_req->gc, msg, NULL); | |
1167 | |
1168 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, | |
1169 YAHOO_STATUS_AVAILABLE, 0); | |
1170 | |
1171 yahoo_packet_hash(pkt, "ssiiis", | |
1172 1, purple_normalize(account, purple_account_get_username(account)), | |
1173 5, add_req->who, | |
1174 13, 2, | |
1175 334, 0, | |
1176 97, 1, | |
1177 14, encoded_msg ? encoded_msg : ""); | |
1178 | |
1179 yahoo_packet_send_and_free(pkt, yd); | |
1180 | |
1181 g_free(encoded_msg); | |
1182 | |
1183 g_free(add_req->id); | |
1184 g_free(add_req->who); | |
1185 g_free(add_req); | |
1186 } | |
1187 | |
1188 static void | |
1189 yahoo_buddy_add_deny_noreason_cb(struct yahoo_add_request *add_req, const char*msg) | |
1190 { | |
1191 yahoo_buddy_add_deny_cb(add_req, NULL); | |
1192 } | |
1193 | |
1194 static void | |
1195 yahoo_buddy_add_deny_reason_cb(gpointer data) { | |
1196 struct yahoo_add_request *add_req = data; | |
1197 purple_request_input(add_req->gc, NULL, _("Authorization denied message:"), | |
1198 NULL, _("No reason given."), TRUE, FALSE, NULL, | |
1199 _("OK"), G_CALLBACK(yahoo_buddy_add_deny_cb), | |
1200 _("Cancel"), G_CALLBACK(yahoo_buddy_add_deny_noreason_cb), | |
1201 purple_connection_get_account(add_req->gc), add_req->who, NULL, | |
1202 add_req); | |
1203 } | |
1204 | |
1205 static void yahoo_buddy_denied_our_add(PurpleConnection *gc, const char *who, const char *reason) | |
1206 { | |
1207 char *notify_msg; | |
1208 struct yahoo_data *yd = gc->proto_data; | |
1209 | |
1210 if (who == NULL) | |
1211 return; | |
1212 | |
1213 if (reason != NULL) { | |
1214 char *msg2 = yahoo_string_decode(gc, reason, FALSE); | |
1215 notify_msg = g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg2); | |
1216 g_free(msg2); | |
1217 } else | |
1218 notify_msg = g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list."), who); | |
1219 | |
1220 purple_notify_info(gc, NULL, _("Add buddy rejected"), notify_msg); | |
1221 g_free(notify_msg); | |
1222 | |
1223 g_hash_table_remove(yd->friends, who); | |
1224 purple_prpl_got_user_status(purple_connection_get_account(gc), who, "offline", NULL); /* FIXME: make this set not on list status instead */ | |
1225 /* TODO: Shouldn't we remove the buddy from our local list? */ | |
1226 } | |
1227 | |
1228 static void yahoo_buddy_auth_req_15(PurpleConnection *gc, struct yahoo_packet *pkt) { | |
1229 PurpleAccount *account; | |
1230 GSList *l = pkt->hash; | |
1231 const char *msg = NULL; | |
1232 int protocol = 0; | |
1233 | |
1234 account = purple_connection_get_account(gc); | |
1235 | |
1236 /* Buddy authorized/declined our addition */ | |
1237 if (pkt->status == 1) { | |
1238 char *temp = NULL; | |
1239 char *who = NULL; | |
1240 int response = 0; | |
1241 | |
1242 while (l) { | |
1243 struct yahoo_pair *pair = l->data; | |
1244 | |
1245 switch (pair->key) { | |
1246 case 4: | |
1247 temp = pair->value; | |
1248 break; | |
1249 case 13: | |
1250 response = strtol(pair->value, NULL, 10); | |
1251 break; | |
1252 case 14: | |
1253 msg = pair->value; | |
1254 break; | |
1255 case 241: | |
1256 protocol = strtol(pair->value, NULL, 10); | |
1257 break; | |
1258 } | |
1259 l = l->next; | |
1260 } | |
1261 | |
1262 if(protocol == 0) | |
1263 who = g_strdup(temp); | |
1264 else if(protocol == 2) | |
1265 who = g_strconcat("msn/", temp, NULL); | |
1266 | |
1267 if (response == 1) /* Authorized */ | |
1268 purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)"); | |
1269 else if (response == 2) { /* Declined */ | |
1270 purple_debug_info("yahoo", "Received authorization decline from buddy '%s'.\n", who ? who : "(Unknown Buddy)"); | |
1271 yahoo_buddy_denied_our_add(gc, who, msg); | |
1272 } else | |
1273 purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)"); | |
1274 g_free(who); | |
1275 } | |
1276 /* Buddy requested authorization to add us. */ | |
1277 else if (pkt->status == 3) { | |
1278 struct yahoo_add_request *add_req; | |
1279 const char *firstname = NULL, *lastname = NULL; | |
1280 char *temp = NULL; | |
1281 | |
1282 add_req = g_new0(struct yahoo_add_request, 1); | |
1283 add_req->gc = gc; | |
1284 | |
1285 while (l) { | |
1286 struct yahoo_pair *pair = l->data; | |
1287 | |
1288 switch (pair->key) { | |
1289 case 4: | |
1290 temp = pair->value; | |
1291 add_req->who = g_strdup(pair->value); | |
1292 break; | |
1293 case 5: | |
1294 add_req->id = g_strdup(pair->value); | |
1295 break; | |
1296 case 14: | |
1297 msg = pair->value; | |
1298 break; | |
1299 case 216: | |
1300 firstname = pair->value; | |
1301 break; | |
1302 case 241: | |
1303 add_req->protocol = strtol(pair->value, NULL, 10); | |
1304 break; | |
1305 case 254: | |
1306 lastname = pair->value; | |
1307 break; | |
1308 | |
1309 } | |
1310 l = l->next; | |
1311 } | |
1312 if(add_req->protocol == 2) | |
1313 add_req->who = g_strconcat("msn/", temp, NULL); | |
1314 else | |
1315 add_req->who = g_strdup(temp); | |
1316 | |
1317 if (add_req->id && add_req->who) { | |
1318 char *alias = NULL, *dec_msg = NULL; | |
1319 | |
1320 if (!purple_privacy_check(account, add_req->who)) | |
1321 { | |
1322 purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n", | |
1323 add_req->who); | |
1324 yahoo_buddy_add_deny_cb(add_req, NULL); | |
1325 return; | |
1326 } | |
1327 | |
1328 if (msg) | |
1329 dec_msg = yahoo_string_decode(gc, msg, FALSE); | |
1330 | |
1331 if (firstname && lastname) | |
1332 alias = g_strdup_printf("%s %s", firstname, lastname); | |
1333 else if (firstname) | |
1334 alias = g_strdup(firstname); | |
1335 else if (lastname) | |
1336 alias = g_strdup(lastname); | |
1337 | |
1338 /* DONE! this is almost exactly the same as what MSN does, | |
1339 * this should probably be moved to the core. | |
1340 */ | |
1341 purple_account_request_authorization(account, add_req->who, add_req->id, | |
1342 alias, dec_msg, | |
1343 purple_find_buddy(account, add_req->who) != NULL, | |
1344 yahoo_buddy_add_authorize_cb, | |
1345 yahoo_buddy_add_deny_reason_cb, | |
1346 add_req); | |
1347 g_free(alias); | |
1348 g_free(dec_msg); | |
1349 } else { | |
1350 g_free(add_req->id); | |
1351 g_free(add_req->who); | |
1352 g_free(add_req); | |
1353 } | |
1354 } else { | |
1355 purple_debug_error("yahoo", "Received authorization of unknown status (%d).\n", pkt->status); | |
1356 } | |
1357 } | |
1358 | |
1359 /* I don't think this happens anymore in Version 15 */ | |
1360 static void yahoo_buddy_added_us(PurpleConnection *gc, struct yahoo_packet *pkt) { | |
1361 PurpleAccount *account; | |
1362 struct yahoo_add_request *add_req; | |
1363 char *msg = NULL; | |
1364 GSList *l = pkt->hash; | |
1365 | |
1366 account = purple_connection_get_account(gc); | |
1367 | |
1368 add_req = g_new0(struct yahoo_add_request, 1); | |
1369 add_req->gc = gc; | |
1370 | |
1371 while (l) { | |
1372 struct yahoo_pair *pair = l->data; | |
1373 | |
1374 switch (pair->key) { | |
1375 case 1: | |
1376 add_req->id = g_strdup(pair->value); | |
1377 break; | |
1378 case 3: | |
1379 add_req->who = g_strdup(pair->value); | |
1380 break; | |
1381 case 15: /* time, for when they add us and we're offline */ | |
1382 break; | |
1383 case 14: | |
1384 msg = pair->value; | |
1385 break; | |
1386 } | |
1387 l = l->next; | |
1388 } | |
1389 | |
1390 if (add_req->id && add_req->who) { | |
1391 char *dec_msg = NULL; | |
1392 | |
1393 if (!purple_privacy_check(account, add_req->who)) { | |
1394 purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n", | |
1395 add_req->who); | |
1396 yahoo_buddy_add_deny_cb(add_req, NULL); | |
1397 return; | |
1398 } | |
1399 | |
1400 if (msg) | |
1401 dec_msg = yahoo_string_decode(gc, msg, FALSE); | |
1402 | |
1403 /* DONE! this is almost exactly the same as what MSN does, | |
1404 * this should probably be moved to the core. | |
1405 */ | |
1406 purple_account_request_authorization(account, add_req->who, add_req->id, | |
1407 NULL, dec_msg, | |
1408 purple_find_buddy(account,add_req->who) != NULL, | |
1409 yahoo_buddy_add_authorize_cb, | |
1410 yahoo_buddy_add_deny_reason_cb, add_req); | |
1411 g_free(dec_msg); | |
1412 } else { | |
1413 g_free(add_req->id); | |
1414 g_free(add_req->who); | |
1415 g_free(add_req); | |
1416 } | |
1417 } | |
1418 | |
1419 /* I have no idea if this every gets called in version 15 */ | |
1420 static void yahoo_buddy_denied_our_add_old(PurpleConnection *gc, struct yahoo_packet *pkt) | |
1421 { | |
1422 char *who = NULL; | |
1423 char *msg = NULL; | |
1424 GSList *l = pkt->hash; | |
1425 | |
1426 while (l) { | |
1427 struct yahoo_pair *pair = l->data; | |
1428 | |
1429 switch (pair->key) { | |
1430 case 3: | |
1431 who = pair->value; | |
1432 break; | |
1433 case 14: | |
1434 msg = pair->value; | |
1435 break; | |
1436 } | |
1437 l = l->next; | |
1438 } | |
1439 | |
1440 yahoo_buddy_denied_our_add(gc, who, msg); | |
1441 } | |
1442 | |
1443 static void yahoo_process_contact(PurpleConnection *gc, struct yahoo_packet *pkt) | |
1444 { | |
1445 switch (pkt->status) { | |
1446 case 1: | |
1447 yahoo_process_status(gc, pkt); | |
1448 return; | |
1449 case 3: | |
1450 yahoo_buddy_added_us(gc, pkt); | |
1451 break; | |
1452 case 7: | |
1453 yahoo_buddy_denied_our_add_old(gc, pkt); | |
1454 break; | |
1455 default: | |
1456 break; | |
1457 } | |
1458 } | |
1459 | |
1460 #define OUT_CHARSET "utf-8" | |
1461 | |
1462 static char *yahoo_decode(const char *text) | |
1463 { | |
1464 char *converted = NULL; | |
1465 char *n, *new; | |
1466 const char *end, *p; | |
1467 int i, k; | |
1468 | |
1469 n = new = g_malloc(strlen (text) + 1); | |
1470 end = text + strlen(text); | |
1471 | |
1472 for (p = text; p < end; p++, n++) { | |
1473 if (*p == '\\') { | |
1474 if (p[1] >= '0' && p[1] <= '7') { | |
1475 p += 1; | |
1476 for (i = 0, k = 0; k < 3; k += 1) { | |
1477 char c = p[k]; | |
1478 if (c < '0' || c > '7') break; | |
1479 i *= 8; | |
1480 i += c - '0'; | |
1481 } | |
1482 *n = i; | |
1483 p += k - 1; | |
1484 } else { /* bug 959248 */ | |
1485 /* If we see a \ not followed by an octal number, | |
1486 * it means that it is actually a \\ with one \ | |
1487 * already eaten by some unknown function. | |
1488 * This is arguably broken. | |
1489 * | |
1490 * I think wing is wrong here, there is no function | |
1491 * called that I see that could have done it. I guess | |
1492 * it is just really sending single \'s. That's yahoo | |
1493 * for you. | |
1494 */ | |
1495 *n = *p; | |
1496 } | |
1497 } | |
1498 else | |
1499 *n = *p; | |
1500 } | |
1501 | |
1502 *n = '\0'; | |
1503 | |
1504 if (strstr(text, "\033$B")) | |
1505 converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL); | |
1506 if (!converted) | |
1507 converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL); | |
1508 g_free(new); | |
1509 | |
1510 return converted; | |
1511 } | |
1512 | |
1513 static void yahoo_process_mail(PurpleConnection *gc, struct yahoo_packet *pkt) | |
1514 { | |
1515 PurpleAccount *account = purple_connection_get_account(gc); | |
1516 struct yahoo_data *yd = gc->proto_data; | |
1517 const char *who = NULL; | |
1518 const char *email = NULL; | |
1519 const char *subj = NULL; | |
1520 const char *yahoo_mail_url = (yd->jp? YAHOOJP_MAIL_URL: YAHOO_MAIL_URL); | |
1521 int count = 0; | |
1522 GSList *l = pkt->hash; | |
1523 | |
1524 if (!purple_account_get_check_mail(account)) | |
1525 return; | |
1526 | |
1527 while (l) { | |
1528 struct yahoo_pair *pair = l->data; | |
1529 if (pair->key == 9) | |
1530 count = strtol(pair->value, NULL, 10); | |
1531 else if (pair->key == 43) | |
1532 who = pair->value; | |
1533 else if (pair->key == 42) | |
1534 email = pair->value; | |
1535 else if (pair->key == 18) | |
1536 subj = pair->value; | |
1537 l = l->next; | |
1538 } | |
1539 | |
1540 if (who && subj && email && *email) { | |
1541 char *dec_who = yahoo_decode(who); | |
1542 char *dec_subj = yahoo_decode(subj); | |
1543 char *from = g_strdup_printf("%s (%s)", dec_who, email); | |
1544 | |
1545 purple_notify_email(gc, dec_subj, from, purple_account_get_username(account), | |
1546 yahoo_mail_url, NULL, NULL); | |
1547 | |
1548 g_free(dec_who); | |
1549 g_free(dec_subj); | |
1550 g_free(from); | |
1551 } else if (count > 0) { | |
1552 const char *tos[2] = { purple_account_get_username(account) }; | |
1553 const char *urls[2] = { yahoo_mail_url }; | |
1554 | |
1555 purple_notify_emails(gc, count, FALSE, NULL, NULL, tos, urls, | |
1556 NULL, NULL); | |
1557 } | |
1558 } | |
1559 | |
1560 /* We use this structure once while we authenticate */ | |
1561 struct yahoo_auth_data | |
1562 { | |
1563 PurpleConnection *gc; | |
1564 char *seed; | |
1565 }; | |
1566 | |
1567 /* This is the y64 alphabet... it's like base64, but has a . and a _ */ | |
1568 static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; | |
1569 | |
1570 /* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function | |
1571 * in util.c, but it is different from the one yahoo uses */ | |
1572 static void to_y64(char *out, const unsigned char *in, gsize inlen) | |
1573 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ | |
1574 { | |
1575 for (; inlen >= 3; inlen -= 3) | |
1576 { | |
1577 *out++ = base64digits[in[0] >> 2]; | |
1578 *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; | |
1579 *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; | |
1580 *out++ = base64digits[in[2] & 0x3f]; | |
1581 in += 3; | |
1582 } | |
1583 if (inlen > 0) | |
1584 { | |
1585 unsigned char fragment; | |
1586 | |
1587 *out++ = base64digits[in[0] >> 2]; | |
1588 fragment = (in[0] << 4) & 0x30; | |
1589 if (inlen > 1) | |
1590 fragment |= in[1] >> 4; | |
1591 *out++ = base64digits[fragment]; | |
1592 *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c]; | |
1593 *out++ = '-'; | |
1594 } | |
1595 *out = '\0'; | |
1596 } | |
1597 | |
1598 static void yahoo_auth16_stage3(PurpleConnection *gc, const char *crypt) | |
1599 { | |
1600 struct yahoo_data *yd = gc->proto_data; | |
1601 PurpleAccount *account = purple_connection_get_account(gc); | |
1602 const char *name = purple_normalize(account, purple_account_get_username(account)); | |
1603 PurpleCipher *md5_cipher; | |
1604 PurpleCipherContext *md5_ctx; | |
1605 guchar md5_digest[16]; | |
1606 gchar base64_string[25]; | |
1607 struct yahoo_packet *pkt; | |
1608 | |
1609 purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n"); | |
1610 | |
1611 md5_cipher = purple_ciphers_find_cipher("md5"); | |
1612 md5_ctx = purple_cipher_context_new(md5_cipher, NULL); | |
1613 purple_cipher_context_append(md5_ctx, (guchar *)crypt, strlen(crypt)); | |
1614 purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL); | |
1615 | |
1616 to_y64(base64_string, md5_digest, 16); | |
1617 | |
1618 purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status); | |
1619 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->current_status, yd->session_id); | |
1620 if(yd->jp) { | |
1621 yahoo_packet_hash(pkt, "ssssssss", | |
1622 1, name, | |
1623 0, name, | |
1624 277, yd->cookie_y, | |
1625 278, yd->cookie_t, | |
1626 307, base64_string, | |
1627 2, name, | |
1628 2, "1", | |
1629 135, YAHOOJP_CLIENT_VERSION); | |
1630 } else { | |
1631 yahoo_packet_hash(pkt, "sssssssss", | |
1632 1, name, | |
1633 0, name, | |
1634 277, yd->cookie_y, | |
1635 278, yd->cookie_t, | |
1636 307, base64_string, | |
1637 244, YAHOO_CLIENT_VERSION_ID, | |
1638 2, name, | |
1639 2, "1", | |
1640 135, YAHOO_CLIENT_VERSION); | |
1641 } | |
1642 if (yd->picture_checksum) | |
1643 yahoo_packet_hash_int(pkt, 192, yd->picture_checksum); | |
1644 yahoo_packet_send_and_free(pkt, yd); | |
1645 | |
1646 purple_cipher_context_destroy(md5_ctx); | |
1647 } | |
1648 | |
1649 static void yahoo_auth16_stage2(PurpleUtilFetchUrlData *unused, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message) | |
1650 { | |
1651 struct yahoo_auth_data *auth_data = user_data; | |
1652 PurpleConnection *gc = auth_data->gc; | |
1653 struct yahoo_data *yd; | |
1654 gboolean try_login_on_error = FALSE; | |
1655 | |
1656 purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n"); | |
1657 | |
1658 if (!PURPLE_CONNECTION_IS_VALID(gc)) { | |
1659 g_free(auth_data->seed); | |
1660 g_free(auth_data); | |
1661 g_return_if_reached(); | |
1662 } | |
1663 | |
1664 yd = (struct yahoo_data *)gc->proto_data; | |
1665 | |
1666 if (error_message != NULL) { | |
1667 purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message); | |
1668 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message); | |
1669 g_free(auth_data->seed); | |
1670 g_free(auth_data); | |
1671 return; | |
1672 } | |
1673 else if (len > 0 && ret_data && *ret_data) { | |
1674 gchar **split_data = g_strsplit(ret_data, "\r\n", -1); | |
1675 int totalelements = 0; | |
1676 int response_no = -1; | |
1677 char *crumb = NULL; | |
1678 char *crypt = NULL; | |
1679 | |
1680 #if GLIB_CHECK_VERSION(2,6,0) | |
1681 totalelements = g_strv_length(split_data); | |
1682 #else | |
1683 while (split_data[++totalelements] != NULL); | |
1684 #endif | |
1685 if (totalelements >= 4) { | |
1686 response_no = strtol(split_data[0], NULL, 10); | |
1687 crumb = g_strdup(split_data[1] + strlen("crumb=")); | |
1688 yd->cookie_y = g_strdup(split_data[2] + strlen("Y=")); | |
1689 yd->cookie_t = g_strdup(split_data[3] + strlen("T=")); | |
1690 } | |
1691 | |
1692 g_strfreev(split_data); | |
1693 | |
1694 if(response_no != 0) { | |
1695 /* Some error in the login process */ | |
1696 PurpleConnectionError error; | |
1697 char *error_reason = NULL; | |
1698 | |
1699 switch(response_no) { | |
1700 case -1: | |
1701 /* Some error in the received stream */ | |
1702 error_reason = g_strdup(_("Received invalid data")); | |
1703 error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; | |
1704 break; | |
1705 case 100: | |
1706 /* Unknown error */ | |
1707 error_reason = g_strdup(_("Unknown error")); | |
1708 error = PURPLE_CONNECTION_ERROR_OTHER_ERROR; | |
1709 break; | |
1710 default: | |
1711 /* if we have everything we need, why not try to login irrespective of response */ | |
1712 if((crumb != NULL) && (yd->cookie_y != NULL) && (yd->cookie_t != NULL)) { | |
1713 try_login_on_error = TRUE; | |
1714 break; | |
1715 } | |
1716 error_reason = g_strdup(_("Unknown error")); | |
1717 error = PURPLE_CONNECTION_ERROR_OTHER_ERROR; | |
1718 break; | |
1719 } | |
1720 if(error_reason) { | |
1721 purple_debug_error("yahoo", "Authentication error: %s\n", | |
1722 error_reason); | |
1723 purple_connection_error_reason(gc, error, error_reason); | |
1724 g_free(error_reason); | |
1725 g_free(auth_data->seed); | |
1726 g_free(auth_data); | |
1727 return; | |
1728 } | |
1729 } | |
1730 | |
1731 crypt = g_strconcat(crumb, auth_data->seed, NULL); | |
1732 yahoo_auth16_stage3(gc, crypt); | |
1733 g_free(crypt); | |
1734 g_free(crumb); | |
1735 } | |
1736 g_free(auth_data->seed); | |
1737 g_free(auth_data); | |
1738 } | |
1739 | |
1740 static void yahoo_auth16_stage1_cb(PurpleUtilFetchUrlData *unused, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message) | |
1741 { | |
1742 struct yahoo_auth_data *auth_data = user_data; | |
1743 PurpleConnection *gc = auth_data->gc; | |
1744 | |
1745 purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n"); | |
1746 | |
1747 if (!PURPLE_CONNECTION_IS_VALID(gc)) { | |
1748 g_free(auth_data->seed); | |
1749 g_free(auth_data); | |
1750 g_return_if_reached(); | |
1751 } | |
1752 | |
1753 if (error_message != NULL) { | |
1754 purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message); | |
1755 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message); | |
1756 g_free(auth_data->seed); | |
1757 g_free(auth_data); | |
1758 return; | |
1759 } | |
1760 else if (len > 0 && ret_data && *ret_data) { | |
1761 gchar **split_data = g_strsplit(ret_data, "\r\n", -1); | |
1762 int totalelements = 0; | |
1763 int response_no = -1; | |
1764 char *token = NULL; | |
1765 | |
1766 #if GLIB_CHECK_VERSION(2,6,0) | |
1767 totalelements = g_strv_length(split_data); | |
1768 #else | |
1769 while (split_data[++totalelements] != NULL); | |
1770 #endif | |
1771 if(totalelements == 1) | |
1772 response_no = strtol(split_data[0], NULL, 10); | |
1773 else if(totalelements >= 2) { | |
1774 response_no = strtol(split_data[0], NULL, 10); | |
1775 token = g_strdup(split_data[1] + strlen("ymsgr=")); | |
1776 } | |
1777 | |
1778 g_strfreev(split_data); | |
1779 | |
1780 if(response_no != 0) { | |
1781 /* Some error in the login process */ | |
1782 PurpleConnectionError error; | |
1783 char *error_reason; | |
1784 | |
1785 switch(response_no) { | |
1786 case -1: | |
1787 /* Some error in the received stream */ | |
1788 error_reason = g_strdup(_("Received invalid data")); | |
1789 error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; | |
1790 break; | |
1791 case 1212: | |
1792 /* Password incorrect */ | |
1793 /* Set password to NULL. Avoids account locking. Brings dialog to enter password if clicked on Re-enable account */ | |
1794 if (!purple_account_get_remember_password(purple_connection_get_account(gc))) | |
1795 purple_account_set_password(purple_connection_get_account(gc), NULL); | |
1796 error_reason = g_strdup(_("Incorrect Password")); | |
1797 error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; | |
1798 break; | |
1799 case 1213: | |
1800 /* security lock from too many failed login attempts */ | |
1801 error_reason = g_strdup(_("Account locked: Too many failed login attempts.\nLogging into the Yahoo! website may fix this.")); | |
1802 error = PURPLE_CONNECTION_ERROR_OTHER_ERROR; | |
1803 break; | |
1804 case 1235: | |
1805 /* the username does not exist */ | |
1806 error_reason = g_strdup(_("Username does not exist")); | |
1807 error = PURPLE_CONNECTION_ERROR_INVALID_USERNAME; | |
1808 break; | |
1809 case 1214: | |
1810 case 1236: | |
1811 /* indicates a lock of some description */ | |
1812 error_reason = g_strdup(_("Account locked: Unknown reason.\nLogging into the Yahoo! website may fix this.")); | |
1813 error = PURPLE_CONNECTION_ERROR_OTHER_ERROR; | |
1814 break; | |
1815 case 100: | |
1816 /* username or password missing */ | |
1817 error_reason = g_strdup(_("Username or password missing")); | |
1818 error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; | |
1819 break; | |
1820 default: | |
1821 /* Unknown error! */ | |
1822 error_reason = g_strdup(_("Unknown error")); | |
1823 error = PURPLE_CONNECTION_ERROR_OTHER_ERROR; | |
1824 break; | |
1825 } | |
1826 purple_debug_error("yahoo", "Authentication error: %s\n", | |
1827 error_reason); | |
1828 purple_connection_error_reason(gc, error, error_reason); | |
1829 g_free(error_reason); | |
1830 g_free(auth_data->seed); | |
1831 g_free(auth_data); | |
1832 } | |
1833 else { | |
1834 /* OK to login, correct information provided */ | |
1835 PurpleUtilFetchUrlData *url_data = NULL; | |
1836 char *url = NULL; | |
1837 gboolean yahoojp = purple_account_get_bool(purple_connection_get_account(gc), | |
1838 "yahoojp", 0); | |
1839 | |
1840 url = g_strdup_printf(yahoojp ? YAHOOJP_LOGIN_URL : YAHOO_LOGIN_URL, token); | |
1841 url_data = purple_util_fetch_url_request_len_with_account( | |
1842 purple_connection_get_account(gc), url, TRUE, | |
1843 YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1, | |
1844 yahoo_auth16_stage2, auth_data); | |
1845 g_free(url); | |
1846 g_free(token); | |
1847 } | |
1848 } | |
1849 } | |
1850 | |
1851 static void yahoo_auth16_stage1(PurpleConnection *gc, const char *seed) | |
1852 { | |
1853 PurpleUtilFetchUrlData *url_data = NULL; | |
1854 struct yahoo_auth_data *auth_data = NULL; | |
1855 char *url = NULL; | |
1856 char *encoded_username; | |
1857 char *encoded_password; | |
1858 gboolean yahoojp; | |
1859 | |
1860 purple_debug_info("yahoo", "Authentication: In yahoo_auth16_stage1\n"); | |
1861 | |
1862 if(!purple_ssl_is_supported()) { | |
1863 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("SSL support unavailable")); | |
1864 return; | |
1865 } | |
1866 | |
1867 yahoojp = purple_account_get_bool(purple_connection_get_account(gc), | |
1868 "yahoojp", 0); | |
1869 auth_data = g_new0(struct yahoo_auth_data, 1); | |
1870 auth_data->gc = gc; | |
1871 auth_data->seed = g_strdup(seed); | |
1872 | |
1873 encoded_username = g_strdup(purple_url_encode(purple_account_get_username(purple_connection_get_account(gc)))); | |
1874 encoded_password = g_strdup(purple_url_encode(purple_connection_get_password(gc))); | |
1875 url = g_strdup_printf(yahoojp ? YAHOOJP_TOKEN_URL : YAHOO_TOKEN_URL, | |
1876 encoded_username, encoded_password, purple_url_encode(seed)); | |
1877 g_free(encoded_password); | |
1878 g_free(encoded_username); | |
1879 | |
1880 url_data = purple_util_fetch_url_request_len_with_account( | |
1881 purple_connection_get_account(gc), url, TRUE, | |
1882 YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1, | |
1883 yahoo_auth16_stage1_cb, auth_data); | |
1884 | |
1885 g_free(url); | |
1886 } | |
1887 | |
1888 static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt) | |
1889 { | |
1890 char *seed = NULL; | |
1891 char *sn = NULL; | |
1892 GSList *l = pkt->hash; | |
1893 int m = 0; | |
1894 gchar *buf; | |
1895 | |
1896 while (l) { | |
1897 struct yahoo_pair *pair = l->data; | |
1898 if (pair->key == 94) | |
1899 seed = pair->value; | |
1900 if (pair->key == 1) | |
1901 sn = pair->value; | |
1902 if (pair->key == 13) | |
1903 m = atoi(pair->value); | |
1904 l = l->next; | |
1905 } | |
1906 | |
1907 if (seed) { | |
1908 switch (m) { | |
1909 case 0: | |
1910 /* used to be for really old auth routine, dont support now */ | |
1911 case 1: | |
1912 case 2: /* Yahoo ver 16 authentication */ | |
1913 yahoo_auth16_stage1(gc, seed); | |
1914 break; | |
1915 default: | |
1916 { | |
1917 GHashTable *ui_info = purple_core_get_ui_info(); | |
1918 | |
1919 buf = g_strdup_printf(_("The Yahoo server has requested the use of an unrecognized " | |
1920 "authentication method. You will probably not be able " | |
1921 "to successfully sign on to Yahoo. Check %s for updates."), | |
1922 ((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE)); | |
1923 purple_notify_error(gc, "", _("Failed Yahoo! Authentication"), | |
1924 buf); | |
1925 g_free(buf); | |
1926 yahoo_auth16_stage1(gc, seed); /* Can't hurt to try it anyway. */ | |
1927 break; | |
1928 } | |
1929 } | |
1930 } | |
1931 } | |
1932 | |
1933 static void ignore_buddy(PurpleBuddy *buddy) { | |
1934 PurpleGroup *group; | |
1935 PurpleAccount *account; | |
1936 gchar *name; | |
1937 | |
1938 if (!buddy) | |
1939 return; | |
1940 | |
1941 group = purple_buddy_get_group(buddy); | |
1942 name = g_strdup(purple_buddy_get_name(buddy)); | |
1943 account = purple_buddy_get_account(buddy); | |
1944 | |
1945 purple_debug_info("yahoo", "blist: Removing '%s' from buddy list.\n", name); | |
1946 purple_account_remove_buddy(account, buddy, group); | |
1947 purple_blist_remove_buddy(buddy); | |
1948 | |
1949 serv_add_deny(purple_account_get_connection(account), name); | |
1950 | |
1951 g_free(name); | |
1952 } | |
1953 | |
1954 static void keep_buddy(PurpleBuddy *b) | |
1955 { | |
1956 purple_privacy_deny_remove(purple_buddy_get_account(b), | |
1957 purple_buddy_get_name(b), 1); | |
1958 } | |
1959 | |
1960 static void yahoo_process_ignore(PurpleConnection *gc, struct yahoo_packet *pkt) { | |
1961 PurpleBuddy *b; | |
1962 GSList *l; | |
1963 gchar *who = NULL; | |
1964 gchar *me = NULL; | |
1965 gchar buf[BUF_LONG]; | |
1966 gboolean ignore = TRUE; | |
1967 gint status = 0; | |
1968 | |
1969 for (l = pkt->hash; l; l = l->next) { | |
1970 struct yahoo_pair *pair = l->data; | |
1971 switch (pair->key) { | |
1972 case 0: | |
1973 who = pair->value; | |
1974 break; | |
1975 case 1: | |
1976 me = pair->value; | |
1977 break; | |
1978 case 13: | |
1979 /* 1 == ignore, 2 == unignore */ | |
1980 ignore = (strtol(pair->value, NULL, 10) == 1); | |
1981 break; | |
1982 case 66: | |
1983 status = strtol(pair->value, NULL, 10); | |
1984 break; | |
1985 default: | |
1986 break; | |
1987 } | |
1988 } | |
1989 | |
1990 /* | |
1991 * status | |
1992 * 0 - ok | |
1993 * 2 - already in ignore list, could not add | |
1994 * 3 - not in ignore list, could not delete | |
1995 * 12 - is a buddy, could not add (and possibly also a not-in-ignore list condition?) | |
1996 */ | |
1997 switch (status) { | |
1998 case 12: | |
1999 purple_debug_info("yahoo", "Server reported \"is a buddy\" for %s while %s", | |
2000 who, (ignore ? "ignoring" : "unignoring")); | |
2001 | |
2002 if (ignore) { | |
2003 b = purple_find_buddy(gc->account, who); | |
2004 g_snprintf(buf, sizeof(buf), _("You have tried to ignore %s, but the " | |
2005 "user is on your buddy list. Clicking \"Yes\" " | |
2006 "will remove and ignore the buddy."), who); | |
2007 purple_request_yes_no(gc, NULL, _("Ignore buddy?"), buf, 0, | |
2008 gc->account, who, NULL, | |
2009 b, | |
2010 G_CALLBACK(ignore_buddy), | |
2011 G_CALLBACK(keep_buddy)); | |
2012 break; | |
2013 } | |
2014 case 2: | |
2015 purple_debug_info("yahoo", "Server reported that %s is already in the ignore list.", | |
2016 who); | |
2017 break; | |
2018 case 3: | |
2019 purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete", | |
2020 who); | |
2021 case 0: | |
2022 default: | |
2023 break; | |
2024 } | |
2025 } | |
2026 | |
2027 static void yahoo_process_authresp(PurpleConnection *gc, struct yahoo_packet *pkt) | |
2028 { | |
2029 #ifdef TRY_WEBMESSENGER_LOGIN | |
2030 struct yahoo_data *yd = gc->proto_data; | |
2031 #endif /* TRY_WEBMESSENGER_LOGIN */ | |
2032 GSList *l = pkt->hash; | |
2033 int err = 0; | |
2034 char *msg; | |
2035 char *url = NULL; | |
2036 char *fullmsg; | |
2037 PurpleAccount *account = gc->account; | |
2038 PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; | |
2039 | |
2040 while (l) { | |
2041 struct yahoo_pair *pair = l->data; | |
2042 | |
2043 if (pair->key == 66) | |
2044 err = strtol(pair->value, NULL, 10); | |
2045 else if (pair->key == 20) | |
2046 url = pair->value; | |
2047 | |
2048 l = l->next; | |
2049 } | |
2050 | |
2051 switch (err) { | |
2052 case 0: | |
2053 msg = g_strdup(_("Unknown error.")); | |
2054 reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; | |
2055 break; | |
2056 case 3: | |
2057 msg = g_strdup(_("Invalid username.")); | |
2058 reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME; | |
2059 break; | |
2060 case 13: | |
2061 #ifdef TRY_WEBMESSENGER_LOGIN | |
2062 if (!yd->wm) { | |
2063 PurpleUtilFetchUrlData *url_data; | |
2064 yd->wm = TRUE; | |
2065 if (yd->fd >= 0) | |
2066 close(yd->fd); | |
2067 if (gc->inpa) | |
2068 purple_input_remove(gc->inpa); | |
2069 url_data = purple_util_fetch_url(WEBMESSENGER_URL, TRUE, | |
2070 "Purple/" VERSION, FALSE, yahoo_login_page_cb, gc); | |
2071 if (url_data != NULL) | |
2072 yd->url_datas = g_slist_prepend(yd->url_datas, url_data); | |
2073 return; | |
2074 } | |
2075 #endif /* TRY_WEBMESSENGER_LOGIN */ | |
2076 if (!purple_account_get_remember_password(account)) | |
2077 purple_account_set_password(account, NULL); | |
2078 | |
2079 msg = g_strdup(_("Incorrect password.")); | |
2080 reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; | |
2081 break; | |
2082 case 14: | |
2083 msg = g_strdup(_("Your account is locked, please log in to the Yahoo! website.")); | |
2084 reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; | |
2085 break; | |
2086 default: | |
2087 msg = g_strdup_printf(_("Unknown error number %d. Logging into the Yahoo! website may fix this."), err); | |
2088 } | |
2089 | |
2090 if (url) | |
2091 fullmsg = g_strdup_printf("%s\n%s", msg, url); | |
2092 else | |
2093 fullmsg = g_strdup(msg); | |
2094 | |
2095 purple_connection_error_reason(gc, reason, fullmsg); | |
2096 g_free(msg); | |
2097 g_free(fullmsg); | |
2098 } | |
2099 | |
2100 static void yahoo_process_addbuddy(PurpleConnection *gc, struct yahoo_packet *pkt) | |
2101 { | |
2102 int err = 0; | |
2103 char *who = NULL; | |
2104 char *temp = NULL; | |
2105 char *group = NULL; | |
2106 char *decoded_group; | |
2107 char *buf; | |
2108 YahooFriend *f; | |
2109 GSList *l = pkt->hash; | |
2110 struct yahoo_data *yd = gc->proto_data; | |
2111 int protocol = 0; | |
2112 gboolean msn = FALSE; | |
2113 | |
2114 while (l) { | |
2115 struct yahoo_pair *pair = l->data; | |
2116 | |
2117 switch (pair->key) { | |
2118 case 66: | |
2119 err = strtol(pair->value, NULL, 10); | |
2120 break; | |
2121 case 7: | |
2122 temp = pair->value; | |
2123 break; | |
2124 case 65: | |
2125 group = pair->value; | |
2126 break; | |
2127 case 241: | |
2128 protocol = strtol(pair->value, NULL, 10); | |
2129 if(protocol == 2) | |
2130 msn = TRUE; | |
2131 break; | |
2132 } | |
2133 | |
2134 l = l->next; | |
2135 } | |
2136 | |
2137 if (!temp) | |
2138 return; | |
2139 if (!group) | |
2140 group = ""; | |
2141 | |
2142 if(msn) | |
2143 who = g_strconcat("msn/", temp, NULL); | |
2144 else | |
2145 who = g_strdup(temp); | |
2146 | |
2147 if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */ | |
2148 f = yahoo_friend_find_or_new(gc, who); | |
2149 yahoo_update_status(gc, who, f); | |
2150 if(protocol) | |
2151 f->protocol = protocol; | |
2152 | |
2153 if( !g_hash_table_lookup(yd->peers, who) ) { | |
2154 /* we are not connected as client, so set friend to not connected */ | |
2155 if(msn) | |
2156 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT); | |
2157 else { | |
2158 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); | |
2159 f->p2p_packet_sent = 0; | |
2160 } | |
2161 } | |
2162 else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */ | |
2163 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT); | |
2164 g_free(who); | |
2165 return; | |
2166 } | |
2167 | |
2168 decoded_group = yahoo_string_decode(gc, group, FALSE); | |
2169 buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."), | |
2170 who, decoded_group, purple_connection_get_display_name(gc)); | |
2171 if (!purple_conv_present_error(who, purple_connection_get_account(gc), buf)) | |
2172 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf); | |
2173 g_free(buf); | |
2174 g_free(decoded_group); | |
2175 g_free(who); | |
2176 } | |
2177 | |
2178 /* write pkt to the source */ | |
2179 static void yahoo_p2p_write_pkt(gint source, struct yahoo_packet *pkt) | |
2180 { | |
2181 size_t pkt_len; | |
2182 guchar *raw_packet; | |
2183 | |
2184 /*build the raw packet and send it to the host*/ | |
2185 pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet); | |
2186 if(write(source, raw_packet, pkt_len) != pkt_len) | |
2187 purple_debug_warning("yahoo","p2p: couldn't write to the source\n"); | |
2188 g_free(raw_packet); | |
2189 } | |
2190 | |
2191 static void yahoo_p2p_keepalive_cb(gpointer key, gpointer value, gpointer user_data) | |
2192 { | |
2193 struct yahoo_p2p_data *p2p_data = value; | |
2194 PurpleConnection *gc = user_data; | |
2195 struct yahoo_packet *pkt_to_send; | |
2196 PurpleAccount *account; | |
2197 struct yahoo_data *yd = gc->proto_data; | |
2198 | |
2199 account = purple_connection_get_account(gc); | |
2200 | |
2201 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
2202 yahoo_packet_hash(pkt_to_send, "ssisi", | |
2203 4, purple_normalize(account, purple_account_get_username(account)), | |
2204 5, p2p_data->host_username, | |
2205 241, 0, /* Protocol identifier */ | |
2206 49, "PEERTOPEER", | |
2207 13, 7); | |
2208 yahoo_p2p_write_pkt(p2p_data->source, pkt_to_send); | |
2209 | |
2210 yahoo_packet_free(pkt_to_send); | |
2211 } | |
2212 | |
2213 static gboolean yahoo_p2p_keepalive(gpointer data) | |
2214 { | |
2215 PurpleConnection *gc = data; | |
2216 struct yahoo_data *yd = gc->proto_data; | |
2217 | |
2218 g_hash_table_foreach(yd->peers, yahoo_p2p_keepalive_cb, gc); | |
2219 | |
2220 return TRUE; | |
2221 } | |
2222 | |
2223 /* destroy p2p_data associated with a peer and close p2p connection. | |
2224 * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer, | |
2225 * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */ | |
2226 static void yahoo_p2p_disconnect_destroy_data(gpointer data) | |
2227 { | |
2228 struct yahoo_p2p_data *p2p_data; | |
2229 YahooFriend *f; | |
2230 | |
2231 if(!(p2p_data = data)) | |
2232 return ; | |
2233 | |
2234 /* If friend, set him not connected */ | |
2235 f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username); | |
2236 if (f) | |
2237 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED); | |
2238 | |
2239 if(p2p_data->source >= 0) | |
2240 close(p2p_data->source); | |
2241 purple_input_remove(p2p_data->input_event); | |
2242 g_free(p2p_data->host_ip); | |
2243 g_free(p2p_data->host_username); | |
2244 g_free(p2p_data); | |
2245 } | |
2246 | |
2247 /* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */ | |
2248 static void yahoo_p2p_process_p2pfilexfer(gpointer data, gint source, struct yahoo_packet *pkt) | |
2249 { | |
2250 struct yahoo_p2p_data *p2p_data; | |
2251 char *who = NULL; | |
2252 GSList *l = pkt->hash; | |
2253 struct yahoo_packet *pkt_to_send; | |
2254 PurpleAccount *account; | |
2255 int val_13_to_send = 0; | |
2256 struct yahoo_data *yd; | |
2257 YahooFriend *f; | |
2258 | |
2259 if(!(p2p_data = data)) | |
2260 return ; | |
2261 | |
2262 yd = p2p_data->gc->proto_data; | |
2263 | |
2264 /* lets see whats in the packet */ | |
2265 while (l) { | |
2266 struct yahoo_pair *pair = l->data; | |
2267 | |
2268 switch (pair->key) { | |
2269 case 4: | |
2270 who = pair->value; | |
2271 if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) { | |
2272 /* from whom are we receiving the packets ?? */ | |
2273 purple_debug_warning("yahoo","p2p: received data from wrong user\n"); | |
2274 return; | |
2275 } | |
2276 break; | |
2277 case 13: | |
2278 p2p_data->val_13 = strtol(pair->value, NULL, 10); /* Value should be 5-7 */ | |
2279 break; | |
2280 /* case 5, 49 look laters, no use right now */ | |
2281 } | |
2282 l = l->next; | |
2283 } | |
2284 | |
2285 account = purple_connection_get_account(p2p_data->gc); | |
2286 | |
2287 /* key_13: sort of a counter. | |
2288 * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5, | |
2289 * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive. | |
2290 * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5, | |
2291 * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */ | |
2292 | |
2293 switch(p2p_data->val_13) { | |
2294 case 1 : val_13_to_send = 5; break; | |
2295 case 5 : val_13_to_send = 6; break; | |
2296 case 6 : val_13_to_send = 7; break; | |
2297 case 7 : if( g_hash_table_lookup(yd->peers, p2p_data->host_username) ) | |
2298 return; | |
2299 val_13_to_send = 7; break; | |
2300 default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n"); | |
2301 return; | |
2302 } | |
2303 | |
2304 /* Build the yahoo packet */ | |
2305 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
2306 yahoo_packet_hash(pkt_to_send, "ssisi", | |
2307 4, purple_normalize(account, purple_account_get_username(account)), | |
2308 5, p2p_data->host_username, | |
2309 241, 0, /* Protocol identifier */ | |
2310 49, "PEERTOPEER", | |
2311 13, val_13_to_send); | |
2312 | |
2313 /* build the raw packet and send it to the host */ | |
2314 yahoo_p2p_write_pkt(source, pkt_to_send); | |
2315 yahoo_packet_free(pkt_to_send); | |
2316 | |
2317 if( val_13_to_send == 7 ) | |
2318 if( !g_hash_table_lookup(yd->peers, p2p_data->host_username) ) { | |
2319 g_hash_table_insert(yd->peers, g_strdup(p2p_data->host_username), p2p_data); | |
2320 /* If the peer is a friend, set him connected */ | |
2321 f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username); | |
2322 if (f) { | |
2323 if(p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) { | |
2324 p2p_data->session_id = f->session_id; | |
2325 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_SERVER); | |
2326 } | |
2327 else | |
2328 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT); | |
2329 } | |
2330 } | |
2331 } | |
2332 | |
2333 /* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */ | |
2334 static void yahoo_p2p_read_pkt_cb(gpointer data, gint source, PurpleInputCondition cond) | |
2335 { | |
2336 guchar buf[1024]; /* is it safe to assume a fixed array length of 1024 ?? */ | |
2337 int len; | |
2338 int pos = 0; | |
2339 int pktlen; | |
2340 struct yahoo_packet *pkt; | |
2341 guchar *start = NULL; | |
2342 struct yahoo_p2p_data *p2p_data; | |
2343 struct yahoo_data *yd; | |
2344 | |
2345 if(!(p2p_data = data)) | |
2346 return ; | |
2347 yd = p2p_data->gc->proto_data; | |
2348 | |
2349 len = read(source, buf, sizeof(buf)); | |
2350 if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) | |
2351 return ; /* No Worries*/ | |
2352 else if (len <= 0) | |
2353 { | |
2354 purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n"); | |
2355 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ | |
2356 if( g_hash_table_lookup(yd->peers, p2p_data->host_username) ) | |
2357 g_hash_table_remove(yd->peers,p2p_data->host_username); | |
2358 else | |
2359 yahoo_p2p_disconnect_destroy_data(data); | |
2360 return; | |
2361 } | |
2362 | |
2363 if(len < YAHOO_PACKET_HDRLEN) | |
2364 return; | |
2365 | |
2366 if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) { | |
2367 /* Not a YMSG packet */ | |
2368 purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n"); | |
2369 | |
2370 start = memchr(buf + 1, 'Y', len - 1); | |
2371 if (start == NULL) | |
2372 return; | |
2373 | |
2374 g_memmove(buf, start, len - (start - buf)); | |
2375 len -= start - buf; | |
2376 } | |
2377 | |
2378 pos += 4; /* YMSG */ | |
2379 pos += 2; | |
2380 pos += 2; | |
2381 | |
2382 pktlen = yahoo_get16(buf + pos); pos += 2; | |
2383 purple_debug_misc("yahoo", "p2p: %d bytes to read\n", len); | |
2384 | |
2385 pkt = yahoo_packet_new(0, 0, 0); | |
2386 pkt->service = yahoo_get16(buf + pos); pos += 2; | |
2387 pkt->status = yahoo_get32(buf + pos); pos += 4; | |
2388 pkt->id = yahoo_get32(buf + pos); pos += 4; | |
2389 | |
2390 purple_debug_misc("yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt->service, pkt->status); | |
2391 yahoo_packet_read(pkt, buf + pos, pktlen); | |
2392 | |
2393 /* packet processing */ | |
2394 switch(pkt->service) { | |
2395 case YAHOO_SERVICE_P2PFILEXFER: | |
2396 yahoo_p2p_process_p2pfilexfer(data, source, pkt); | |
2397 break; | |
2398 case YAHOO_SERVICE_MESSAGE: | |
2399 yahoo_process_message(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P); | |
2400 break; | |
2401 case YAHOO_SERVICE_NOTIFY: | |
2402 yahoo_process_notify(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P); | |
2403 break; | |
2404 default: | |
2405 purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt->service); | |
2406 } | |
2407 | |
2408 yahoo_packet_free(pkt); | |
2409 } | |
2410 | |
2411 static void yahoo_p2p_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond) | |
2412 { | |
2413 int acceptfd; | |
2414 struct yahoo_p2p_data *p2p_data; | |
2415 struct yahoo_data *yd; | |
2416 | |
2417 if(!(p2p_data = data)) | |
2418 return ; | |
2419 yd = p2p_data->gc->proto_data; | |
2420 | |
2421 acceptfd = accept(source, NULL, 0); | |
2422 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) | |
2423 return; | |
2424 else if(acceptfd == -1) { | |
2425 purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno)); | |
2426 yahoo_p2p_disconnect_destroy_data(data); | |
2427 return; | |
2428 } | |
2429 | |
2430 /* remove timeout */ | |
2431 if (yd->yahoo_p2p_server_timeout_handle) { | |
2432 purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle); | |
2433 yd->yahoo_p2p_server_timeout_handle = 0; | |
2434 } | |
2435 | |
2436 /* remove watcher and close p2p server */ | |
2437 if (yd->yahoo_p2p_server_watcher) { | |
2438 purple_input_remove(yd->yahoo_p2p_server_watcher); | |
2439 yd->yahoo_p2p_server_watcher = 0; | |
2440 } | |
2441 if (yd->yahoo_local_p2p_server_fd >= 0) { | |
2442 close(yd->yahoo_local_p2p_server_fd); | |
2443 yd->yahoo_local_p2p_server_fd = -1; | |
2444 } | |
2445 | |
2446 /* Add an Input Read event to the file descriptor */ | |
2447 p2p_data->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data); | |
2448 p2p_data->source = acceptfd; | |
2449 } | |
2450 | |
2451 static gboolean yahoo_cancel_p2p_server_listen_cb(gpointer data) | |
2452 { | |
2453 struct yahoo_p2p_data *p2p_data; | |
2454 struct yahoo_data *yd; | |
2455 | |
2456 if(!(p2p_data = data)) | |
2457 return FALSE; | |
2458 | |
2459 yd = p2p_data->gc->proto_data; | |
2460 | |
2461 purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect"); | |
2462 yahoo_p2p_disconnect_destroy_data(data); | |
2463 purple_input_remove(yd->yahoo_p2p_server_watcher); | |
2464 yd->yahoo_p2p_server_watcher = 0; | |
2465 close(yd->yahoo_local_p2p_server_fd); | |
2466 yd->yahoo_local_p2p_server_fd = -1; | |
2467 yd->yahoo_p2p_server_timeout_handle = 0; | |
2468 | |
2469 return FALSE; | |
2470 } | |
2471 | |
2472 static void yahoo_p2p_server_listen_cb(int listenfd, gpointer data) | |
2473 { | |
2474 struct yahoo_p2p_data *p2p_data; | |
2475 struct yahoo_data *yd; | |
2476 | |
2477 if(!(p2p_data = data)) | |
2478 return ; | |
2479 | |
2480 if(listenfd == -1) { | |
2481 purple_debug_warning("yahoo","p2p: error starting p2p server\n"); | |
2482 yahoo_p2p_disconnect_destroy_data(data); | |
2483 return; | |
2484 } | |
2485 | |
2486 yd = p2p_data->gc->proto_data; | |
2487 | |
2488 /* Add an Input Read event to the file descriptor */ | |
2489 yd->yahoo_local_p2p_server_fd = listenfd; | |
2490 yd->yahoo_p2p_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_server_send_connected_cb,data); | |
2491 | |
2492 /* add timeout */ | |
2493 yd->yahoo_p2p_server_timeout_handle = purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT, yahoo_cancel_p2p_server_listen_cb, data); | |
2494 } | |
2495 | |
2496 /* send p2p pkt containing our encoded ip, asking peer to connect to us */ | |
2497 void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13) | |
2498 { | |
2499 const char *public_ip; | |
2500 guint32 temp[4]; | |
2501 guint32 ip; | |
2502 char temp_str[100]; | |
2503 gchar *base64_ip = NULL; | |
2504 YahooFriend *f; | |
2505 struct yahoo_packet *pkt; | |
2506 PurpleAccount *account; | |
2507 struct yahoo_data *yd = gc->proto_data; | |
2508 struct yahoo_p2p_data *p2p_data; | |
2509 | |
2510 f = yahoo_friend_find(gc, who); | |
2511 account = purple_connection_get_account(gc); | |
2512 | |
2513 /* Do not send invitation if already listening for other connection */ | |
2514 if(yd->yahoo_local_p2p_server_fd >= 0) | |
2515 return; | |
2516 | |
2517 /* One shouldn't try to connect to self */ | |
2518 if( strcmp(purple_normalize(account, purple_account_get_username(account)), who) == 0) | |
2519 return; | |
2520 | |
2521 /* 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 */ | |
2522 if( !( f && (yahoo_friend_get_p2p_status(f) == YAHOO_P2PSTATUS_NOT_CONNECTED) && (f->p2p_packet_sent == 0)) ) | |
2523 return; | |
2524 | |
2525 /* Dont send p2p packet to buddies of other protocols */ | |
2526 if(f->protocol) | |
2527 return; | |
2528 | |
2529 /* Finally, don't try to connect to buddies not online or on sms */ | |
2530 if( (f->status == YAHOO_STATUS_OFFLINE) || f->sms ) | |
2531 return; | |
2532 | |
2533 public_ip = purple_network_get_public_ip(); | |
2534 if( (sscanf(public_ip, "%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3])) !=4 ) | |
2535 return ; | |
2536 | |
2537 ip = (temp[3] << 24) | (temp[2] <<16) | (temp[1] << 8) | temp[0]; | |
2538 sprintf(temp_str, "%d", ip); | |
2539 base64_ip = purple_base64_encode( (guchar *)temp_str, strlen(temp_str) ); | |
2540 | |
2541 pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0); | |
2542 yahoo_packet_hash(pkt, "sssissis", | |
2543 1, purple_normalize(account, purple_account_get_username(account)), | |
2544 4, purple_normalize(account, purple_account_get_username(account)), | |
2545 12, base64_ip, /* base64 encode ip */ | |
2546 61, 0, /* To-do : figure out what is 61 for?? */ | |
2547 2, "", | |
2548 5, who, | |
2549 13, val_13, | |
2550 49, "PEERTOPEER"); | |
2551 yahoo_packet_send_and_free(pkt, yd); | |
2552 | |
2553 f->p2p_packet_sent = 1; /* set p2p_packet_sent to sent */ | |
2554 | |
2555 p2p_data = g_new0(struct yahoo_p2p_data, 1); | |
2556 | |
2557 p2p_data->gc = gc; | |
2558 p2p_data->host_ip = NULL; | |
2559 p2p_data->host_username = g_strdup(who); | |
2560 p2p_data->val_13 = val_13; | |
2561 p2p_data->connection_type = YAHOO_P2P_WE_ARE_SERVER; | |
2562 p2p_data->source = -1; | |
2563 | |
2564 purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data); | |
2565 | |
2566 g_free(base64_ip); | |
2567 } | |
2568 | |
2569 /* function called when connection to p2p host is setup */ | |
2570 static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message) | |
2571 { | |
2572 struct yahoo_p2p_data *p2p_data; | |
2573 struct yahoo_packet *pkt_to_send; | |
2574 PurpleAccount *account; | |
2575 struct yahoo_data *yd; | |
2576 | |
2577 if(!(p2p_data = data)) | |
2578 return ; | |
2579 yd = p2p_data->gc->proto_data; | |
2580 | |
2581 if(error_message != NULL) { | |
2582 purple_debug_warning("yahoo","p2p: %s\n",error_message); | |
2583 yahoo_send_p2p_pkt(p2p_data->gc, p2p_data->host_username, 2);/* send p2p init packet with val_13=2 */ | |
2584 | |
2585 yahoo_p2p_disconnect_destroy_data(p2p_data); | |
2586 return; | |
2587 } | |
2588 | |
2589 /* Add an Input Read event to the file descriptor */ | |
2590 p2p_data->input_event = purple_input_add(source, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data); | |
2591 p2p_data->source = source; | |
2592 | |
2593 account = purple_connection_get_account(p2p_data->gc); | |
2594 | |
2595 /* Build the yahoo packet */ | |
2596 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
2597 yahoo_packet_hash(pkt_to_send, "ssisi", | |
2598 4, purple_normalize(account, purple_account_get_username(account)), | |
2599 5, p2p_data->host_username, | |
2600 241, 0, /* Protocol identifier */ | |
2601 49, "PEERTOPEER", | |
2602 13, 1); /* we receive key13= 0 or 2, we send key13=1 */ | |
2603 | |
2604 yahoo_p2p_write_pkt(source, pkt_to_send); /* build raw packet and send */ | |
2605 yahoo_packet_free(pkt_to_send); | |
2606 } | |
2607 | |
2608 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt) | |
2609 { | |
2610 GSList *l = pkt->hash; | |
2611 char *who = NULL; | |
2612 char *base64 = NULL; | |
2613 guchar *decoded; | |
2614 gsize len; | |
2615 gint val_13 = 0; | |
2616 gint val_11 = 0; | |
2617 PurpleAccount *account; | |
2618 YahooFriend *f; | |
2619 | |
2620 /* if status is not 1 ie YAHOO_STATUS_BRB, the packet bounced back, so contains our own ip */ | |
2621 if(!(pkt->status == YAHOO_STATUS_BRB)) | |
2622 return ; | |
2623 | |
2624 while (l) { | |
2625 struct yahoo_pair *pair = l->data; | |
2626 | |
2627 switch (pair->key) { | |
2628 case 5: | |
2629 /* our identity */ | |
2630 break; | |
2631 case 4: | |
2632 who = pair->value; | |
2633 break; | |
2634 case 1: | |
2635 /* who again, the master identity this time? */ | |
2636 break; | |
2637 case 12: | |
2638 base64 = pair->value; | |
2639 /* so, this is an ip address. in base64. decoded it's in ascii. | |
2640 after strtol, it's in reversed byte order. Who thought this up?*/ | |
2641 break; | |
2642 case 13: | |
2643 val_13 = strtol(pair->value, NULL, 10); | |
2644 break; | |
2645 case 11: | |
2646 val_11 = strtol(pair->value, NULL, 10); /* session id of peer */ | |
2647 if( (f = yahoo_friend_find(gc, who)) ) | |
2648 f->session_id = val_11; | |
2649 break; | |
2650 /* | |
2651 TODO: figure these out | |
2652 yahoo: Key: 61 Value: 0 | |
2653 yahoo: Key: 2 Value: | |
2654 yahoo: Key: 13 Value: 0 packet count ?? | |
2655 yahoo: Key: 49 Value: PEERTOPEER | |
2656 yahoo: Key: 140 Value: 1 | |
2657 */ | |
2658 | |
2659 } | |
2660 | |
2661 l = l->next; | |
2662 } | |
2663 | |
2664 if (base64) { | |
2665 guint32 ip; | |
2666 YahooFriend *f; | |
2667 char *host_ip; | |
2668 struct yahoo_p2p_data *p2p_data; | |
2669 | |
2670 decoded = purple_base64_decode(base64, &len); | |
2671 if (len) { | |
2672 char *tmp = purple_str_binary_to_ascii(decoded, len); | |
2673 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp); | |
2674 g_free(tmp); | |
2675 } | |
2676 | |
2677 ip = strtol((gchar *)decoded, NULL, 10); | |
2678 g_free(decoded); | |
2679 host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, | |
2680 (ip >> 24) & 0xff); | |
2681 f = yahoo_friend_find(gc, who); | |
2682 if (f) | |
2683 yahoo_friend_set_ip(f, host_ip); | |
2684 purple_debug_info("yahoo", "IP : %s\n", host_ip); | |
2685 | |
2686 account = purple_connection_get_account(gc); | |
2687 | |
2688 if(val_11==0) { | |
2689 if(!f) | |
2690 return; | |
2691 else | |
2692 val_11 = f->session_id; | |
2693 } | |
2694 | |
2695 p2p_data = g_new0(struct yahoo_p2p_data, 1); | |
2696 p2p_data->host_username = g_strdup(who); | |
2697 p2p_data->val_13 = val_13; | |
2698 p2p_data->session_id = val_11; | |
2699 p2p_data->host_ip = host_ip; | |
2700 p2p_data->gc = gc; | |
2701 p2p_data->connection_type = YAHOO_P2P_WE_ARE_CLIENT; | |
2702 p2p_data->source = -1; | |
2703 | |
2704 /* connect to host */ | |
2705 if((purple_proxy_connect(gc, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, p2p_data))==NULL) { | |
2706 purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip); | |
2707 g_free(p2p_data->host_ip); | |
2708 g_free(p2p_data->host_username); | |
2709 g_free(p2p_data); | |
2710 } | |
2711 } | |
2712 } | |
2713 | |
2714 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt) | |
2715 { | |
2716 PurpleAccount *account; | |
2717 char *who = NULL, *msg = NULL, *id = NULL; | |
2718 GSList *l = pkt->hash; | |
2719 | |
2720 account = purple_connection_get_account(gc); | |
2721 | |
2722 while (l) { | |
2723 struct yahoo_pair *pair = l->data; | |
2724 | |
2725 switch (pair->key) { | |
2726 case 4: | |
2727 who = pair->value; | |
2728 break; | |
2729 case 5: | |
2730 /* us */ | |
2731 break; | |
2732 case 230: | |
2733 /* the audible, in foo.locale.bar.baz format | |
2734 eg: base.tw.smiley.smiley43 */ | |
2735 id = pair->value; | |
2736 break; | |
2737 case 231: | |
2738 /* the text of the audible */ | |
2739 msg = pair->value; | |
2740 break; | |
2741 case 232: | |
2742 /* weird number (md5 hash?), like 8ebab9094156135f5dcbaccbeee662a5c5fd1420 */ | |
2743 break; | |
2744 } | |
2745 | |
2746 l = l->next; | |
2747 } | |
2748 | |
2749 if (!msg) | |
2750 msg = id; | |
2751 if (!who || !msg) | |
2752 return; | |
2753 if (!g_utf8_validate(msg, -1, NULL)) { | |
2754 purple_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n"); | |
2755 return; | |
2756 } | |
2757 if (!purple_privacy_check(account, who)) { | |
2758 purple_debug_misc("yahoo", "Audible message from %s for %s dropped!\n", | |
2759 purple_account_get_username(account), who); | |
2760 return; | |
2761 } | |
2762 if (id) { | |
2763 /* "http://us.dl1.yimg.com/download.yahoo.com/dl/aud/"+locale+"/"+id+".swf" */ | |
2764 char **audible_locale = g_strsplit(id, ".", 0); | |
2765 char *buf = g_strdup_printf(_("[ Audible %s/%s/%s.swf ] %s"), YAHOO_AUDIBLE_URL, audible_locale[1], id, msg); | |
2766 g_strfreev(audible_locale); | |
2767 | |
2768 serv_got_im(gc, who, buf, 0, time(NULL)); | |
2769 g_free(buf); | |
2770 } else | |
2771 serv_got_im(gc, who, msg, 0, time(NULL)); | |
2772 } | |
2773 | |
2774 static void yahoo_packet_process(PurpleConnection *gc, struct yahoo_packet *pkt) | |
2775 { | |
2776 switch (pkt->service) { | |
2777 case YAHOO_SERVICE_LOGON: | |
2778 case YAHOO_SERVICE_LOGOFF: | |
2779 case YAHOO_SERVICE_ISAWAY: | |
2780 case YAHOO_SERVICE_ISBACK: | |
2781 case YAHOO_SERVICE_GAMELOGON: | |
2782 case YAHOO_SERVICE_GAMELOGOFF: | |
2783 case YAHOO_SERVICE_CHATLOGON: | |
2784 case YAHOO_SERVICE_CHATLOGOFF: | |
2785 case YAHOO_SERVICE_Y6_STATUS_UPDATE: | |
2786 case YAHOO_SERVICE_STATUS_15: | |
2787 yahoo_process_status(gc, pkt); | |
2788 break; | |
2789 case YAHOO_SERVICE_NOTIFY: | |
2790 yahoo_process_notify(gc, pkt, YAHOO_PKT_TYPE_SERVER); | |
2791 break; | |
2792 case YAHOO_SERVICE_MESSAGE: | |
2793 case YAHOO_SERVICE_GAMEMSG: | |
2794 case YAHOO_SERVICE_CHATMSG: | |
2795 yahoo_process_message(gc, pkt, YAHOO_PKT_TYPE_SERVER); | |
2796 break; | |
2797 case YAHOO_SERVICE_SYSMESSAGE: | |
2798 yahoo_process_sysmessage(gc, pkt); | |
2799 break; | |
2800 case YAHOO_SERVICE_NEWMAIL: | |
2801 yahoo_process_mail(gc, pkt); | |
2802 break; | |
2803 case YAHOO_SERVICE_NEWCONTACT: | |
2804 yahoo_process_contact(gc, pkt); | |
2805 break; | |
2806 case YAHOO_SERVICE_AUTHRESP: | |
2807 yahoo_process_authresp(gc, pkt); | |
2808 break; | |
2809 case YAHOO_SERVICE_LIST: | |
2810 yahoo_process_list(gc, pkt); | |
2811 break; | |
2812 case YAHOO_SERVICE_LIST_15: | |
2813 yahoo_process_list_15(gc, pkt); | |
2814 break; | |
2815 case YAHOO_SERVICE_AUTH: | |
2816 yahoo_process_auth(gc, pkt); | |
2817 break; | |
2818 case YAHOO_SERVICE_AUTH_REQ_15: | |
2819 yahoo_buddy_auth_req_15(gc, pkt); | |
2820 break; | |
2821 case YAHOO_SERVICE_ADDBUDDY: | |
2822 yahoo_process_addbuddy(gc, pkt); | |
2823 break; | |
2824 case YAHOO_SERVICE_IGNORECONTACT: | |
2825 yahoo_process_ignore(gc, pkt); | |
2826 break; | |
2827 case YAHOO_SERVICE_CONFINVITE: | |
2828 case YAHOO_SERVICE_CONFADDINVITE: | |
2829 yahoo_process_conference_invite(gc, pkt); | |
2830 break; | |
2831 case YAHOO_SERVICE_CONFDECLINE: | |
2832 yahoo_process_conference_decline(gc, pkt); | |
2833 break; | |
2834 case YAHOO_SERVICE_CONFLOGON: | |
2835 yahoo_process_conference_logon(gc, pkt); | |
2836 break; | |
2837 case YAHOO_SERVICE_CONFLOGOFF: | |
2838 yahoo_process_conference_logoff(gc, pkt); | |
2839 break; | |
2840 case YAHOO_SERVICE_CONFMSG: | |
2841 yahoo_process_conference_message(gc, pkt); | |
2842 break; | |
2843 case YAHOO_SERVICE_CHATONLINE: | |
2844 yahoo_process_chat_online(gc, pkt); | |
2845 break; | |
2846 case YAHOO_SERVICE_CHATLOGOUT: | |
2847 yahoo_process_chat_logout(gc, pkt); | |
2848 break; | |
2849 case YAHOO_SERVICE_CHATGOTO: | |
2850 yahoo_process_chat_goto(gc, pkt); | |
2851 break; | |
2852 case YAHOO_SERVICE_CHATJOIN: | |
2853 yahoo_process_chat_join(gc, pkt); | |
2854 break; | |
2855 case YAHOO_SERVICE_CHATLEAVE: /* XXX is this right? */ | |
2856 case YAHOO_SERVICE_CHATEXIT: | |
2857 yahoo_process_chat_exit(gc, pkt); | |
2858 break; | |
2859 case YAHOO_SERVICE_CHATINVITE: /* XXX never seen this one, might not do it right */ | |
2860 case YAHOO_SERVICE_CHATADDINVITE: | |
2861 yahoo_process_chat_addinvite(gc, pkt); | |
2862 break; | |
2863 case YAHOO_SERVICE_COMMENT: | |
2864 yahoo_process_chat_message(gc, pkt); | |
2865 break; | |
2866 case YAHOO_SERVICE_PRESENCE_PERM: | |
2867 case YAHOO_SERVICE_PRESENCE_SESSION: | |
2868 yahoo_process_presence(gc, pkt); | |
2869 break; | |
2870 case YAHOO_SERVICE_P2PFILEXFER: | |
2871 /* This case had no break and continued; thus keeping it this way.*/ | |
2872 yahoo_process_p2p(gc, pkt); /* P2PFILEXFER handled the same way as process_p2p */ | |
2873 yahoo_process_p2pfilexfer(gc, pkt); /* redundant ??, need to have a break now */ | |
2874 case YAHOO_SERVICE_FILETRANSFER: | |
2875 yahoo_process_filetransfer(gc, pkt); | |
2876 break; | |
2877 case YAHOO_SERVICE_PEERTOPEER: | |
2878 yahoo_process_p2p(gc, pkt); | |
2879 break; | |
2880 case YAHOO_SERVICE_PICTURE: | |
2881 yahoo_process_picture(gc, pkt); | |
2882 break; | |
2883 case YAHOO_SERVICE_PICTURE_CHECKSUM: | |
2884 yahoo_process_picture_checksum(gc, pkt); | |
2885 break; | |
2886 case YAHOO_SERVICE_PICTURE_UPLOAD: | |
2887 yahoo_process_picture_upload(gc, pkt); | |
2888 break; | |
2889 case YAHOO_SERVICE_PICTURE_UPDATE: | |
2890 case YAHOO_SERVICE_AVATAR_UPDATE: | |
2891 yahoo_process_avatar_update(gc, pkt); | |
2892 break; | |
2893 case YAHOO_SERVICE_AUDIBLE: | |
2894 yahoo_process_audible(gc, pkt); | |
2895 break; | |
2896 case YAHOO_SERVICE_FILETRANS_15: | |
2897 yahoo_process_filetrans_15(gc, pkt); | |
2898 break; | |
2899 case YAHOO_SERVICE_FILETRANS_INFO_15: | |
2900 yahoo_process_filetrans_info_15(gc, pkt); | |
2901 break; | |
2902 case YAHOO_SERVICE_FILETRANS_ACC_15: | |
2903 yahoo_process_filetrans_acc_15(gc, pkt); | |
2904 break; | |
2905 case YAHOO_SERVICE_SMS_MSG: | |
2906 yahoo_process_sms_message(gc, pkt); | |
2907 break; | |
2908 | |
2909 default: | |
2910 purple_debug_error("yahoo", "Unhandled service 0x%02x\n", pkt->service); | |
2911 break; | |
2912 } | |
2913 } | |
2914 | |
2915 static void yahoo_pending(gpointer data, gint source, PurpleInputCondition cond) | |
2916 { | |
2917 PurpleConnection *gc = data; | |
2918 struct yahoo_data *yd = gc->proto_data; | |
2919 char buf[1024]; | |
2920 int len; | |
2921 | |
2922 len = read(yd->fd, buf, sizeof(buf)); | |
2923 | |
2924 if (len < 0) { | |
2925 gchar *tmp; | |
2926 | |
2927 if (errno == EAGAIN) | |
2928 /* No worries */ | |
2929 return; | |
2930 | |
2931 tmp = g_strdup_printf(_("Lost connection with server:\n%s"), | |
2932 g_strerror(errno)); | |
2933 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
2934 g_free(tmp); | |
2935 return; | |
2936 } else if (len == 0) { | |
2937 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
2938 _("Server closed the connection.")); | |
2939 return; | |
2940 } | |
2941 gc->last_received = time(NULL); | |
2942 yd->rxqueue = g_realloc(yd->rxqueue, len + yd->rxlen); | |
2943 memcpy(yd->rxqueue + yd->rxlen, buf, len); | |
2944 yd->rxlen += len; | |
2945 | |
2946 while (1) { | |
2947 struct yahoo_packet *pkt; | |
2948 int pos = 0; | |
2949 int pktlen; | |
2950 | |
2951 if (yd->rxlen < YAHOO_PACKET_HDRLEN) | |
2952 return; | |
2953 | |
2954 if (strncmp((char *)yd->rxqueue, "YMSG", MIN(4, yd->rxlen)) != 0) { | |
2955 /* HEY! This isn't even a YMSG packet. What | |
2956 * are you trying to pull? */ | |
2957 guchar *start; | |
2958 | |
2959 purple_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!\n"); | |
2960 | |
2961 start = memchr(yd->rxqueue + 1, 'Y', yd->rxlen - 1); | |
2962 if (start) { | |
2963 g_memmove(yd->rxqueue, start, yd->rxlen - (start - yd->rxqueue)); | |
2964 yd->rxlen -= start - yd->rxqueue; | |
2965 continue; | |
2966 } else { | |
2967 g_free(yd->rxqueue); | |
2968 yd->rxqueue = NULL; | |
2969 yd->rxlen = 0; | |
2970 return; | |
2971 } | |
2972 } | |
2973 | |
2974 pos += 4; /* YMSG */ | |
2975 pos += 2; | |
2976 pos += 2; | |
2977 | |
2978 pktlen = yahoo_get16(yd->rxqueue + pos); pos += 2; | |
2979 purple_debug_misc("yahoo", "%d bytes to read, rxlen is %d\n", pktlen, yd->rxlen); | |
2980 | |
2981 if (yd->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) | |
2982 return; | |
2983 | |
2984 yahoo_packet_dump(yd->rxqueue, YAHOO_PACKET_HDRLEN + pktlen); | |
2985 | |
2986 pkt = yahoo_packet_new(0, 0, 0); | |
2987 | |
2988 pkt->service = yahoo_get16(yd->rxqueue + pos); pos += 2; | |
2989 pkt->status = yahoo_get32(yd->rxqueue + pos); pos += 4; | |
2990 purple_debug_misc("yahoo", "Yahoo Service: 0x%02x Status: %d\n", | |
2991 pkt->service, pkt->status); | |
2992 pkt->id = yahoo_get32(yd->rxqueue + pos); pos += 4; | |
2993 | |
2994 yahoo_packet_read(pkt, yd->rxqueue + pos, pktlen); | |
2995 | |
2996 yd->rxlen -= YAHOO_PACKET_HDRLEN + pktlen; | |
2997 if (yd->rxlen) { | |
2998 guchar *tmp = g_memdup(yd->rxqueue + YAHOO_PACKET_HDRLEN + pktlen, yd->rxlen); | |
2999 g_free(yd->rxqueue); | |
3000 yd->rxqueue = tmp; | |
3001 } else { | |
3002 g_free(yd->rxqueue); | |
3003 yd->rxqueue = NULL; | |
3004 } | |
3005 | |
3006 yahoo_packet_process(gc, pkt); | |
3007 | |
3008 yahoo_packet_free(pkt); | |
3009 } | |
3010 } | |
3011 | |
3012 static void yahoo_got_connected(gpointer data, gint source, const gchar *error_message) | |
3013 { | |
3014 PurpleConnection *gc = data; | |
3015 struct yahoo_data *yd; | |
3016 struct yahoo_packet *pkt; | |
3017 | |
3018 if (source < 0) { | |
3019 gchar *tmp; | |
3020 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), | |
3021 error_message); | |
3022 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
3023 g_free(tmp); | |
3024 return; | |
3025 } | |
3026 | |
3027 yd = gc->proto_data; | |
3028 yd->fd = source; | |
3029 | |
3030 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, yd->current_status, 0); | |
3031 | |
3032 yahoo_packet_hash_str(pkt, 1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc)))); | |
3033 yahoo_packet_send_and_free(pkt, yd); | |
3034 | |
3035 gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc); | |
3036 } | |
3037 | |
3038 #ifdef TRY_WEBMESSENGER_LOGIN | |
3039 static void yahoo_got_web_connected(gpointer data, gint source, const gchar *error_message) | |
3040 { | |
3041 PurpleConnection *gc = data; | |
3042 struct yahoo_data *yd; | |
3043 struct yahoo_packet *pkt; | |
3044 | |
3045 if (source < 0) { | |
3046 gchar *tmp; | |
3047 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), | |
3048 error_message); | |
3049 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
3050 g_free(tmp); | |
3051 return; | |
3052 } | |
3053 | |
3054 yd = gc->proto_data; | |
3055 yd->fd = source; | |
3056 | |
3057 pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, 0); | |
3058 | |
3059 yahoo_packet_hash(pkt, "sss", 0, | |
3060 purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))), | |
3061 1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))), | |
3062 6, yd->auth); | |
3063 yahoo_packet_send_and_free(pkt, yd); | |
3064 | |
3065 g_free(yd->auth); | |
3066 gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc); | |
3067 } | |
3068 | |
3069 static void yahoo_web_pending(gpointer data, gint source, PurpleInputCondition cond) | |
3070 { | |
3071 PurpleConnection *gc = data; | |
3072 PurpleAccount *account = purple_connection_get_account(gc); | |
3073 struct yahoo_data *yd = gc->proto_data; | |
3074 char bufread[2048], *i = bufread, *buf = bufread; | |
3075 int len; | |
3076 GString *s; | |
3077 | |
3078 len = read(source, bufread, sizeof(bufread) - 1); | |
3079 | |
3080 if (len < 0) { | |
3081 gchar *tmp; | |
3082 | |
3083 if (errno == EAGAIN) | |
3084 /* No worries */ | |
3085 return; | |
3086 | |
3087 tmp = g_strdup_printf(_("Lost connection with server:\n%s"), | |
3088 g_strerror(errno)); | |
3089 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
3090 g_free(tmp); | |
3091 return; | |
3092 } else if (len == 0) { | |
3093 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3094 _("Server closed the connection.")); | |
3095 return; | |
3096 } | |
3097 | |
3098 if (yd->rxlen > 0 || !g_strstr_len(buf, len, "\r\n\r\n")) { | |
3099 yd->rxqueue = g_realloc(yd->rxqueue, yd->rxlen + len + 1); | |
3100 memcpy(yd->rxqueue + yd->rxlen, buf, len); | |
3101 yd->rxlen += len; | |
3102 i = buf = (char *)yd->rxqueue; | |
3103 len = yd->rxlen; | |
3104 } | |
3105 buf[len] = '\0'; | |
3106 | |
3107 if ((strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302")) && | |
3108 strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) { | |
3109 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3110 _("Received unexpected HTTP response from server.")); | |
3111 purple_debug_misc("yahoo", "Unexpected HTTP response: %s\n", buf); | |
3112 return; | |
3113 } | |
3114 | |
3115 s = g_string_sized_new(len); | |
3116 | |
3117 while ((i = strstr(i, "Set-Cookie: "))) { | |
3118 | |
3119 i += strlen("Set-Cookie: "); | |
3120 for (;*i != ';' && *i != '\0'; i++) | |
3121 g_string_append_c(s, *i); | |
3122 | |
3123 g_string_append(s, "; "); | |
3124 /* Should these cookies be included too when trying for xfer? | |
3125 * It seems to work without these | |
3126 */ | |
3127 } | |
3128 | |
3129 yd->auth = g_string_free(s, FALSE); | |
3130 purple_input_remove(gc->inpa); | |
3131 close(source); | |
3132 g_free(yd->rxqueue); | |
3133 yd->rxqueue = NULL; | |
3134 yd->rxlen = 0; | |
3135 /* Now we have our cookies to login with. I'll go get the milk. */ | |
3136 if (purple_proxy_connect(gc, account, "wcs2.msg.dcn.yahoo.com", | |
3137 purple_account_get_int(account, "port", YAHOO_PAGER_PORT), | |
3138 yahoo_got_web_connected, gc) == NULL) { | |
3139 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3140 _("Connection problem")); | |
3141 return; | |
3142 } | |
3143 } | |
3144 | |
3145 static void yahoo_got_cookies_send_cb(gpointer data, gint source, PurpleInputCondition cond) | |
3146 { | |
3147 PurpleConnection *gc; | |
3148 struct yahoo_data *yd; | |
3149 int written, remaining; | |
3150 | |
3151 gc = data; | |
3152 yd = gc->proto_data; | |
3153 | |
3154 remaining = strlen(yd->auth) - yd->auth_written; | |
3155 written = write(source, yd->auth + yd->auth_written, remaining); | |
3156 | |
3157 if (written < 0 && errno == EAGAIN) | |
3158 written = 0; | |
3159 else if (written <= 0) { | |
3160 gchar *tmp; | |
3161 g_free(yd->auth); | |
3162 yd->auth = NULL; | |
3163 if (gc->inpa) | |
3164 purple_input_remove(gc->inpa); | |
3165 gc->inpa = 0; | |
3166 tmp = g_strdup_printf(_("Lost connection with %s:\n%s"), | |
3167 "login.yahoo.com:80", g_strerror(errno)); | |
3168 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
3169 g_free(tmp); | |
3170 return; | |
3171 } | |
3172 | |
3173 if (written < remaining) { | |
3174 yd->auth_written += written; | |
3175 return; | |
3176 } | |
3177 | |
3178 g_free(yd->auth); | |
3179 yd->auth = NULL; | |
3180 yd->auth_written = 0; | |
3181 purple_input_remove(gc->inpa); | |
3182 gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, yahoo_web_pending, gc); | |
3183 } | |
3184 | |
3185 static void yahoo_got_cookies(gpointer data, gint source, const gchar *error_message) | |
3186 { | |
3187 PurpleConnection *gc = data; | |
3188 | |
3189 if (source < 0) { | |
3190 gchar *tmp; | |
3191 tmp = g_strdup_printf(_("Could not establish a connection with %s:\n%s"), | |
3192 "login.yahoo.com:80", error_message); | |
3193 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
3194 g_free(tmp); | |
3195 return; | |
3196 } | |
3197 | |
3198 if (gc->inpa == 0) | |
3199 { | |
3200 gc->inpa = purple_input_add(source, PURPLE_INPUT_WRITE, | |
3201 yahoo_got_cookies_send_cb, gc); | |
3202 yahoo_got_cookies_send_cb(gc, source, PURPLE_INPUT_WRITE); | |
3203 } | |
3204 } | |
3205 | |
3206 static void yahoo_login_page_hash_iter(const char *key, const char *val, GString *url) | |
3207 { | |
3208 if (!strcmp(key, "passwd") || !strcmp(key, "login")) | |
3209 return; | |
3210 g_string_append_c(url, '&'); | |
3211 g_string_append(url, key); | |
3212 g_string_append_c(url, '='); | |
3213 if (!strcmp(key, ".save") || !strcmp(key, ".js")) | |
3214 g_string_append_c(url, '1'); | |
3215 else if (!strcmp(key, ".challenge")) | |
3216 g_string_append(url, val); | |
3217 else | |
3218 g_string_append(url, purple_url_encode(val)); | |
3219 } | |
3220 | |
3221 static GHashTable *yahoo_login_page_hash(const char *buf, size_t len) | |
3222 { | |
3223 GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
3224 const char *c = buf; | |
3225 char *d; | |
3226 char name[64], value[64]; | |
3227 int count; | |
3228 int input_len = strlen("<input "); | |
3229 int name_len = strlen("name=\""); | |
3230 int value_len = strlen("value=\""); | |
3231 while ((len > ((c - buf) + input_len)) | |
3232 && (c = strstr(c, "<input "))) { | |
3233 if (!(c = g_strstr_len(c, len - (c - buf), "name=\""))) | |
3234 continue; | |
3235 c += name_len; | |
3236 count = sizeof(name)-1; | |
3237 for (d = name; (len > ((c - buf) + 1)) && *c!='"' | |
3238 && count; c++, d++, count--) | |
3239 *d = *c; | |
3240 *d = '\0'; | |
3241 count = sizeof(value)-1; | |
3242 if (!(d = g_strstr_len(c, len - (c - buf), "value=\""))) | |
3243 continue; | |
3244 d += value_len; | |
3245 if (strchr(c, '>') < d) | |
3246 break; | |
3247 for (c = d, d = value; (len > ((c - buf) + 1)) | |
3248 && *c!='"' && count; c++, d++, count--) | |
3249 *d = *c; | |
3250 *d = '\0'; | |
3251 g_hash_table_insert(hash, g_strdup(name), g_strdup(value)); | |
3252 } | |
3253 return hash; | |
3254 } | |
3255 | |
3256 static void | |
3257 yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, | |
3258 const gchar *url_text, size_t len, const gchar *error_message) | |
3259 { | |
3260 PurpleConnection *gc = (PurpleConnection *)user_data; | |
3261 PurpleAccount *account = purple_connection_get_account(gc); | |
3262 struct yahoo_data *yd = gc->proto_data; | |
3263 const char *sn = purple_account_get_username(account); | |
3264 const char *pass = purple_connection_get_password(gc); | |
3265 GHashTable *hash = yahoo_login_page_hash(url_text, len); | |
3266 GString *url = g_string_new("GET http://login.yahoo.com/config/login?login="); | |
3267 char md5[33], *hashp = md5, *chal; | |
3268 int i; | |
3269 PurpleCipher *cipher; | |
3270 PurpleCipherContext *context; | |
3271 guchar digest[16]; | |
3272 | |
3273 yd->url_datas = g_slist_remove(yd->url_datas, url_data); | |
3274 | |
3275 if (error_message != NULL) | |
3276 { | |
3277 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3278 error_message); | |
3279 return; | |
3280 } | |
3281 | |
3282 url = g_string_append(url, sn); | |
3283 url = g_string_append(url, "&passwd="); | |
3284 | |
3285 cipher = purple_ciphers_find_cipher("md5"); | |
3286 context = purple_cipher_context_new(cipher, NULL); | |
3287 | |
3288 purple_cipher_context_append(context, (const guchar *)pass, strlen(pass)); | |
3289 purple_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
3290 for (i = 0; i < 16; ++i) { | |
3291 g_snprintf(hashp, 3, "%02x", digest[i]); | |
3292 hashp += 2; | |
3293 } | |
3294 | |
3295 chal = g_strconcat(md5, g_hash_table_lookup(hash, ".challenge"), NULL); | |
3296 purple_cipher_context_reset(context, NULL); | |
3297 purple_cipher_context_append(context, (const guchar *)chal, strlen(chal)); | |
3298 purple_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
3299 hashp = md5; | |
3300 for (i = 0; i < 16; ++i) { | |
3301 g_snprintf(hashp, 3, "%02x", digest[i]); | |
3302 hashp += 2; | |
3303 } | |
3304 /* | |
3305 * I dunno why this is here and commented out.. but in case it's needed | |
3306 * I updated it.. | |
3307 | |
3308 purple_cipher_context_reset(context, NULL); | |
3309 purple_cipher_context_append(context, md5, strlen(md5)); | |
3310 purple_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
3311 hashp = md5; | |
3312 for (i = 0; i < 16; ++i) { | |
3313 g_snprintf(hashp, 3, "%02x", digest[i]); | |
3314 hashp += 2; | |
3315 } | |
3316 */ | |
3317 g_free(chal); | |
3318 | |
3319 url = g_string_append(url, md5); | |
3320 g_hash_table_foreach(hash, (GHFunc)yahoo_login_page_hash_iter, url); | |
3321 | |
3322 url = g_string_append(url, "&.hash=1&.md5=1 HTTP/1.1\r\n" | |
3323 "Host: login.yahoo.com\r\n\r\n"); | |
3324 g_hash_table_destroy(hash); | |
3325 yd->auth = g_string_free(url, FALSE); | |
3326 if (purple_proxy_connect(gc, account, "login.yahoo.com", 80, yahoo_got_cookies, gc) == NULL) { | |
3327 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3328 _("Connection problem")); | |
3329 return; | |
3330 } | |
3331 | |
3332 purple_cipher_context_destroy(context); | |
3333 } | |
3334 #endif /* TRY_WEBMESSENGER_LOGIN */ | |
3335 | |
3336 static void yahoo_server_check(PurpleAccount *account) | |
3337 { | |
3338 const char *server; | |
3339 | |
3340 server = purple_account_get_string(account, "server", YAHOO_PAGER_HOST); | |
3341 | |
3342 if (*server == '\0' || g_str_equal(server, "scs.yahoo.com") || | |
3343 g_str_equal(server, "scs.msg.yahoo.com")) | |
3344 purple_account_set_string(account, "server", YAHOO_PAGER_HOST); | |
3345 } | |
3346 | |
3347 static void yahoo_picture_check(PurpleAccount *account) | |
3348 { | |
3349 PurpleConnection *gc = purple_account_get_connection(account); | |
3350 PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account); | |
3351 | |
3352 yahoo_set_buddy_icon(gc, img); | |
3353 purple_imgstore_unref(img); | |
3354 } | |
3355 | |
3356 static int get_yahoo_status_from_purple_status(PurpleStatus *status) | |
3357 { | |
3358 PurplePresence *presence; | |
3359 const char *status_id; | |
3360 const char *msg; | |
3361 | |
3362 presence = purple_status_get_presence(status); | |
3363 status_id = purple_status_get_id(status); | |
3364 msg = purple_status_get_attr_string(status, "message"); | |
3365 | |
3366 if (!strcmp(status_id, YAHOO_STATUS_TYPE_AVAILABLE)) { | |
3367 if ((msg != NULL) && (*msg != '\0')) | |
3368 return YAHOO_STATUS_CUSTOM; | |
3369 else | |
3370 return YAHOO_STATUS_AVAILABLE; | |
3371 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BRB)) { | |
3372 return YAHOO_STATUS_BRB; | |
3373 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BUSY)) { | |
3374 return YAHOO_STATUS_BUSY; | |
3375 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATHOME)) { | |
3376 return YAHOO_STATUS_NOTATHOME; | |
3377 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATDESK)) { | |
3378 return YAHOO_STATUS_NOTATDESK; | |
3379 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTINOFFICE)) { | |
3380 return YAHOO_STATUS_NOTINOFFICE; | |
3381 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONPHONE)) { | |
3382 return YAHOO_STATUS_ONPHONE; | |
3383 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONVACATION)) { | |
3384 return YAHOO_STATUS_ONVACATION; | |
3385 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_OUTTOLUNCH)) { | |
3386 return YAHOO_STATUS_OUTTOLUNCH; | |
3387 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_STEPPEDOUT)) { | |
3388 return YAHOO_STATUS_STEPPEDOUT; | |
3389 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_INVISIBLE)) { | |
3390 return YAHOO_STATUS_INVISIBLE; | |
3391 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_AWAY)) { | |
3392 return YAHOO_STATUS_CUSTOM; | |
3393 } else if (purple_presence_is_idle(presence)) { | |
3394 return YAHOO_STATUS_IDLE; | |
3395 } else { | |
3396 purple_debug_error("yahoo", "Unexpected PurpleStatus!\n"); | |
3397 return YAHOO_STATUS_AVAILABLE; | |
3398 } | |
3399 } | |
3400 | |
3401 static void yahoo_login(PurpleAccount *account) { | |
3402 PurpleConnection *gc = purple_account_get_connection(account); | |
3403 struct yahoo_data *yd = gc->proto_data = g_new0(struct yahoo_data, 1); | |
3404 PurpleStatus *status = purple_account_get_active_status(account); | |
3405 gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC; | |
3406 | |
3407 purple_connection_update_progress(gc, _("Connecting"), 1, 2); | |
3408 | |
3409 purple_connection_set_display_name(gc, purple_account_get_username(account)); | |
3410 | |
3411 yd->yahoo_local_p2p_server_fd = -1; | |
3412 yd->fd = -1; | |
3413 yd->txhandler = 0; | |
3414 /* TODO: Is there a good grow size for the buffer? */ | |
3415 yd->txbuf = purple_circ_buffer_new(0); | |
3416 yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free); | |
3417 yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
3418 yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); | |
3419 yd->peers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_p2p_disconnect_destroy_data); | |
3420 yd->sms_carrier = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
3421 yd->yahoo_p2p_timer = purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS, yahoo_p2p_keepalive, gc); | |
3422 yd->confs = NULL; | |
3423 yd->conf_id = 2; | |
3424 yd->last_keepalive = yd->last_ping = time(NULL); | |
3425 | |
3426 yd->current_status = get_yahoo_status_from_purple_status(status); | |
3427 | |
3428 yahoo_server_check(account); | |
3429 yahoo_picture_check(account); | |
3430 | |
3431 if (purple_account_get_bool(account, "yahoojp", FALSE)) { | |
3432 yd->jp = TRUE; | |
3433 if (purple_proxy_connect(gc, account, | |
3434 purple_account_get_string(account, "serverjp", YAHOOJP_PAGER_HOST), | |
3435 purple_account_get_int(account, "port", YAHOO_PAGER_PORT), | |
3436 yahoo_got_connected, gc) == NULL) | |
3437 { | |
3438 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3439 _("Connection problem")); | |
3440 return; | |
3441 } | |
3442 } else { | |
3443 yd->jp = FALSE; | |
3444 if (purple_proxy_connect(gc, account, | |
3445 purple_account_get_string(account, "server", YAHOO_PAGER_HOST), | |
3446 purple_account_get_int(account, "port", YAHOO_PAGER_PORT), | |
3447 yahoo_got_connected, gc) == NULL) | |
3448 { | |
3449 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | |
3450 _("Connection problem")); | |
3451 return; | |
3452 } | |
3453 } | |
3454 } | |
3455 | |
3456 static void yahoo_close(PurpleConnection *gc) { | |
3457 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
3458 GSList *l; | |
3459 | |
3460 if (gc->inpa) | |
3461 purple_input_remove(gc->inpa); | |
3462 | |
3463 while (yd->url_datas) { | |
3464 purple_util_fetch_url_cancel(yd->url_datas->data); | |
3465 yd->url_datas = g_slist_delete_link(yd->url_datas, yd->url_datas); | |
3466 } | |
3467 | |
3468 for (l = yd->confs; l; l = l->next) { | |
3469 PurpleConversation *conv = l->data; | |
3470 | |
3471 yahoo_conf_leave(yd, purple_conversation_get_name(conv), | |
3472 purple_connection_get_display_name(gc), | |
3473 purple_conv_chat_get_users(PURPLE_CONV_CHAT(conv))); | |
3474 } | |
3475 g_slist_free(yd->confs); | |
3476 | |
3477 for (l = yd->cookies; l; l = l->next) { | |
3478 g_free(l->data); | |
3479 l->data=NULL; | |
3480 } | |
3481 g_slist_free(yd->cookies); | |
3482 | |
3483 yd->chat_online = FALSE; | |
3484 if (yd->in_chat) | |
3485 yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */ | |
3486 | |
3487 purple_timeout_remove(yd->yahoo_p2p_timer); | |
3488 if(yd->yahoo_p2p_server_timeout_handle != 0) { | |
3489 purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle); | |
3490 yd->yahoo_p2p_server_timeout_handle = 0; | |
3491 } | |
3492 | |
3493 /* close p2p server if it is waiting for a peer to connect */ | |
3494 if (yd->yahoo_p2p_server_watcher) { | |
3495 purple_input_remove(yd->yahoo_p2p_server_watcher); | |
3496 yd->yahoo_p2p_server_watcher = 0; | |
3497 } | |
3498 if (yd->yahoo_local_p2p_server_fd >= 0) { | |
3499 close(yd->yahoo_local_p2p_server_fd); | |
3500 yd->yahoo_local_p2p_server_fd = -1; | |
3501 } | |
3502 | |
3503 g_hash_table_destroy(yd->sms_carrier); | |
3504 g_hash_table_destroy(yd->peers); | |
3505 g_hash_table_destroy(yd->friends); | |
3506 g_hash_table_destroy(yd->imvironments); | |
3507 g_hash_table_destroy(yd->xfer_peer_idstring_map); | |
3508 g_free(yd->chat_name); | |
3509 | |
3510 g_free(yd->cookie_y); | |
3511 g_free(yd->cookie_t); | |
3512 | |
3513 if (yd->txhandler) | |
3514 purple_input_remove(yd->txhandler); | |
3515 | |
3516 purple_circ_buffer_destroy(yd->txbuf); | |
3517 | |
3518 if (yd->fd >= 0) | |
3519 close(yd->fd); | |
3520 | |
3521 g_free(yd->rxqueue); | |
3522 yd->rxlen = 0; | |
3523 g_free(yd->picture_url); | |
3524 | |
3525 if (yd->buddy_icon_connect_data) | |
3526 purple_proxy_connect_cancel(yd->buddy_icon_connect_data); | |
3527 if (yd->picture_upload_todo) | |
3528 yahoo_buddy_icon_upload_data_free(yd->picture_upload_todo); | |
3529 if (yd->ycht) | |
3530 ycht_connection_close(yd->ycht); | |
3531 | |
3532 g_free(yd->pending_chat_room); | |
3533 g_free(yd->pending_chat_id); | |
3534 g_free(yd->pending_chat_topic); | |
3535 g_free(yd->pending_chat_goto); | |
3536 g_strfreev(yd->profiles); | |
3537 | |
3538 g_free(yd->current_list15_grp); | |
3539 | |
3540 g_free(yd); | |
3541 gc->proto_data = NULL; | |
3542 } | |
3543 | |
3544 static const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b) | |
3545 { | |
3546 return "yahoo"; | |
3547 } | |
3548 | |
3549 static const char *yahoo_list_emblem(PurpleBuddy *b) | |
3550 { | |
3551 PurpleAccount *account; | |
3552 PurpleConnection *gc; | |
3553 struct yahoo_data *yd; | |
3554 YahooFriend *f; | |
3555 PurplePresence *presence; | |
3556 | |
3557 if (!b || !(account = purple_buddy_get_account(b)) || | |
3558 !(gc = purple_account_get_connection(account)) || | |
3559 !(yd = gc->proto_data)) | |
3560 return NULL; | |
3561 | |
3562 f = yahoo_friend_find(gc, purple_buddy_get_name(b)); | |
3563 if (!f) { | |
3564 return "not-authorized"; | |
3565 } | |
3566 | |
3567 presence = purple_buddy_get_presence(b); | |
3568 | |
3569 if (purple_presence_is_online(presence)) { | |
3570 if (yahoo_friend_get_game(f)) | |
3571 return "game"; | |
3572 if (f->protocol == 2) | |
3573 return "msn"; | |
3574 } | |
3575 return NULL; | |
3576 } | |
3577 | |
3578 static const char *yahoo_get_status_string(enum yahoo_status a) | |
3579 { | |
3580 switch (a) { | |
3581 case YAHOO_STATUS_BRB: | |
3582 return _("Be Right Back"); | |
3583 case YAHOO_STATUS_BUSY: | |
3584 return _("Busy"); | |
3585 case YAHOO_STATUS_NOTATHOME: | |
3586 return _("Not at Home"); | |
3587 case YAHOO_STATUS_NOTATDESK: | |
3588 return _("Not at Desk"); | |
3589 case YAHOO_STATUS_NOTINOFFICE: | |
3590 return _("Not in Office"); | |
3591 case YAHOO_STATUS_ONPHONE: | |
3592 return _("On the Phone"); | |
3593 case YAHOO_STATUS_ONVACATION: | |
3594 return _("On Vacation"); | |
3595 case YAHOO_STATUS_OUTTOLUNCH: | |
3596 return _("Out to Lunch"); | |
3597 case YAHOO_STATUS_STEPPEDOUT: | |
3598 return _("Stepped Out"); | |
3599 case YAHOO_STATUS_INVISIBLE: | |
3600 return _("Invisible"); | |
3601 case YAHOO_STATUS_IDLE: | |
3602 return _("Idle"); | |
3603 case YAHOO_STATUS_OFFLINE: | |
3604 return _("Offline"); | |
3605 default: | |
3606 return _("Available"); | |
3607 } | |
3608 } | |
3609 | |
3610 static void yahoo_initiate_conference(PurpleBlistNode *node, gpointer data) { | |
3611 | |
3612 PurpleBuddy *buddy; | |
3613 PurpleConnection *gc; | |
3614 | |
3615 GHashTable *components; | |
3616 struct yahoo_data *yd; | |
3617 int id; | |
3618 | |
3619 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); | |
3620 | |
3621 buddy = (PurpleBuddy *) node; | |
3622 gc = purple_account_get_connection(purple_buddy_get_account(buddy)); | |
3623 yd = gc->proto_data; | |
3624 id = yd->conf_id; | |
3625 | |
3626 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
3627 g_hash_table_replace(components, g_strdup("room"), | |
3628 g_strdup_printf("%s-%d", purple_connection_get_display_name(gc), id)); | |
3629 g_hash_table_replace(components, g_strdup("topic"), g_strdup("Join my conference...")); | |
3630 g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference")); | |
3631 yahoo_c_join(gc, components); | |
3632 g_hash_table_destroy(components); | |
3633 | |
3634 yahoo_c_invite(gc, id, "Join my conference...", purple_buddy_get_name(buddy)); | |
3635 } | |
3636 | |
3637 static void yahoo_presence_settings(PurpleBlistNode *node, gpointer data) { | |
3638 PurpleBuddy *buddy; | |
3639 PurpleConnection *gc; | |
3640 int presence_val = GPOINTER_TO_INT(data); | |
3641 | |
3642 buddy = (PurpleBuddy *) node; | |
3643 gc = purple_account_get_connection(purple_buddy_get_account(buddy)); | |
3644 | |
3645 yahoo_friend_update_presence(gc, purple_buddy_get_name(buddy), presence_val); | |
3646 } | |
3647 | |
3648 static void yahoo_game(PurpleBlistNode *node, gpointer data) { | |
3649 | |
3650 PurpleBuddy *buddy; | |
3651 PurpleConnection *gc; | |
3652 | |
3653 struct yahoo_data *yd; | |
3654 const char *game; | |
3655 char *game2; | |
3656 char *t; | |
3657 char url[256]; | |
3658 YahooFriend *f; | |
3659 | |
3660 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); | |
3661 | |
3662 buddy = (PurpleBuddy *) node; | |
3663 gc = purple_account_get_connection(purple_buddy_get_account(buddy)); | |
3664 yd = (struct yahoo_data *) gc->proto_data; | |
3665 | |
3666 f = yahoo_friend_find(gc, purple_buddy_get_name(buddy)); | |
3667 if (!f) | |
3668 return; | |
3669 | |
3670 game = yahoo_friend_get_game(f); | |
3671 if (!game) | |
3672 return; | |
3673 | |
3674 t = game2 = g_strdup(strstr(game, "ante?room=")); | |
3675 while (*t && *t != '\t') | |
3676 t++; | |
3677 *t = 0; | |
3678 g_snprintf(url, sizeof url, "http://games.yahoo.com/games/%s", game2); | |
3679 purple_notify_uri(gc, url); | |
3680 g_free(game2); | |
3681 } | |
3682 | |
3683 static char *yahoo_status_text(PurpleBuddy *b) | |
3684 { | |
3685 YahooFriend *f = NULL; | |
3686 const char *msg; | |
3687 char *msg2; | |
3688 PurpleAccount *account; | |
3689 | |
3690 account = purple_buddy_get_account(b); | |
3691 f = yahoo_friend_find(purple_account_get_connection(account), purple_buddy_get_name(b)); | |
3692 if (!f) | |
3693 return g_strdup(_("Not on server list")); | |
3694 | |
3695 switch (f->status) { | |
3696 case YAHOO_STATUS_AVAILABLE: | |
3697 return NULL; | |
3698 case YAHOO_STATUS_IDLE: | |
3699 if (f->idle == -1) | |
3700 return g_strdup(yahoo_get_status_string(f->status)); | |
3701 return NULL; | |
3702 case YAHOO_STATUS_CUSTOM: | |
3703 if (!(msg = yahoo_friend_get_status_message(f))) | |
3704 return NULL; | |
3705 msg2 = g_markup_escape_text(msg, strlen(msg)); | |
3706 purple_util_chrreplace(msg2, '\n', ' '); | |
3707 return msg2; | |
3708 | |
3709 default: | |
3710 return g_strdup(yahoo_get_status_string(f->status)); | |
3711 } | |
3712 } | |
3713 | |
3714 void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) | |
3715 { | |
3716 YahooFriend *f; | |
3717 char *escaped; | |
3718 char *status = NULL; | |
3719 const char *presence = NULL; | |
3720 PurpleAccount *account; | |
3721 | |
3722 account = purple_buddy_get_account(b); | |
3723 f = yahoo_friend_find(purple_account_get_connection(account), purple_buddy_get_name(b)); | |
3724 if (!f) | |
3725 status = g_strdup_printf("\n%s", _("Not on server list")); | |
3726 else { | |
3727 switch (f->status) { | |
3728 case YAHOO_STATUS_CUSTOM: | |
3729 if (!yahoo_friend_get_status_message(f)) | |
3730 return; | |
3731 status = g_strdup(yahoo_friend_get_status_message(f)); | |
3732 break; | |
3733 case YAHOO_STATUS_OFFLINE: | |
3734 break; | |
3735 default: | |
3736 status = g_strdup(yahoo_get_status_string(f->status)); | |
3737 break; | |
3738 } | |
3739 | |
3740 switch (f->presence) { | |
3741 case YAHOO_PRESENCE_ONLINE: | |
3742 presence = _("Appear Online"); | |
3743 break; | |
3744 case YAHOO_PRESENCE_PERM_OFFLINE: | |
3745 presence = _("Appear Permanently Offline"); | |
3746 break; | |
3747 case YAHOO_PRESENCE_DEFAULT: | |
3748 break; | |
3749 default: | |
3750 purple_debug_error("yahoo", "Unknown presence in yahoo_tooltip_text\n"); | |
3751 break; | |
3752 } | |
3753 } | |
3754 | |
3755 if (status != NULL) { | |
3756 escaped = g_markup_escape_text(status, strlen(status)); | |
3757 purple_notify_user_info_add_pair(user_info, _("Status"), escaped); | |
3758 g_free(status); | |
3759 g_free(escaped); | |
3760 } | |
3761 | |
3762 if (presence != NULL) | |
3763 purple_notify_user_info_add_pair(user_info, _("Presence"), presence); | |
3764 } | |
3765 | |
3766 static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode *node, gpointer data) | |
3767 { | |
3768 PurpleBuddy *buddy; | |
3769 PurpleConnection *gc; | |
3770 | |
3771 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); | |
3772 | |
3773 buddy = (PurpleBuddy *) node; | |
3774 gc = purple_account_get_connection(purple_buddy_get_account(buddy)); | |
3775 | |
3776 yahoo_add_buddy(gc, buddy, NULL); | |
3777 } | |
3778 | |
3779 | |
3780 static void yahoo_chat_goto_menu(PurpleBlistNode *node, gpointer data) | |
3781 { | |
3782 PurpleBuddy *buddy; | |
3783 PurpleConnection *gc; | |
3784 | |
3785 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); | |
3786 | |
3787 buddy = (PurpleBuddy *) node; | |
3788 gc = purple_account_get_connection(purple_buddy_get_account(buddy)); | |
3789 | |
3790 yahoo_chat_goto(gc, purple_buddy_get_name(buddy)); | |
3791 } | |
3792 | |
3793 static GList *build_presence_submenu(YahooFriend *f, PurpleConnection *gc) { | |
3794 GList *m = NULL; | |
3795 PurpleMenuAction *act; | |
3796 struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; | |
3797 | |
3798 if (yd->current_status == YAHOO_STATUS_INVISIBLE) { | |
3799 if (f->presence != YAHOO_PRESENCE_ONLINE) { | |
3800 act = purple_menu_action_new(_("Appear Online"), | |
3801 PURPLE_CALLBACK(yahoo_presence_settings), | |
3802 GINT_TO_POINTER(YAHOO_PRESENCE_ONLINE), | |
3803 NULL); | |
3804 m = g_list_append(m, act); | |
3805 } else if (f->presence != YAHOO_PRESENCE_DEFAULT) { | |
3806 act = purple_menu_action_new(_("Appear Offline"), | |
3807 PURPLE_CALLBACK(yahoo_presence_settings), | |
3808 GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT), | |
3809 NULL); | |
3810 m = g_list_append(m, act); | |
3811 } | |
3812 } | |
3813 | |
3814 if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) { | |
3815 act = purple_menu_action_new(_("Don't Appear Permanently Offline"), | |
3816 PURPLE_CALLBACK(yahoo_presence_settings), | |
3817 GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT), | |
3818 NULL); | |
3819 m = g_list_append(m, act); | |
3820 } else { | |
3821 act = purple_menu_action_new(_("Appear Permanently Offline"), | |
3822 PURPLE_CALLBACK(yahoo_presence_settings), | |
3823 GINT_TO_POINTER(YAHOO_PRESENCE_PERM_OFFLINE), | |
3824 NULL); | |
3825 m = g_list_append(m, act); | |
3826 } | |
3827 | |
3828 return m; | |
3829 } | |
3830 | |
3831 static void yahoo_doodle_blist_node(PurpleBlistNode *node, gpointer data) | |
3832 { | |
3833 PurpleBuddy *b = (PurpleBuddy *)node; | |
3834 PurpleAccount *account = purple_buddy_get_account(b); | |
3835 PurpleConnection *gc = purple_account_get_connection(account); | |
3836 | |
3837 yahoo_doodle_initiate(gc, purple_buddy_get_name(b)); | |
3838 } | |
3839 | |
3840 static GList *yahoo_buddy_menu(PurpleBuddy *buddy) | |
3841 { | |
3842 GList *m = NULL; | |
3843 PurpleMenuAction *act; | |
3844 | |
3845 PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy)); | |
3846 struct yahoo_data *yd = gc->proto_data; | |
3847 static char buf2[1024]; | |
3848 YahooFriend *f; | |
3849 | |
3850 f = yahoo_friend_find(gc, purple_buddy_get_name(buddy)); | |
3851 | |
3852 if (!f && !yd->wm) { | |
3853 act = purple_menu_action_new(_("Add Buddy"), | |
3854 PURPLE_CALLBACK(yahoo_addbuddyfrommenu_cb), | |
3855 NULL, NULL); | |
3856 m = g_list_append(m, act); | |
3857 | |
3858 return m; | |
3859 | |
3860 } | |
3861 | |
3862 if (f && f->status != YAHOO_STATUS_OFFLINE) { | |
3863 if (!yd->wm) { | |
3864 act = purple_menu_action_new(_("Join in Chat"), | |
3865 PURPLE_CALLBACK(yahoo_chat_goto_menu), | |
3866 NULL, NULL); | |
3867 m = g_list_append(m, act); | |
3868 } | |
3869 | |
3870 act = purple_menu_action_new(_("Initiate Conference"), | |
3871 PURPLE_CALLBACK(yahoo_initiate_conference), | |
3872 NULL, NULL); | |
3873 m = g_list_append(m, act); | |
3874 | |
3875 if (yahoo_friend_get_game(f)) { | |
3876 const char *game = yahoo_friend_get_game(f); | |
3877 char *room; | |
3878 char *t; | |
3879 | |
3880 if ((room = strstr(game, "&follow="))) {/* skip ahead to the url */ | |
3881 while (*room && *room != '\t') /* skip to the tab */ | |
3882 room++; | |
3883 t = room++; /* room as now at the name */ | |
3884 while (*t != '\n') | |
3885 t++; /* replace the \n with a space */ | |
3886 *t = ' '; | |
3887 g_snprintf(buf2, sizeof buf2, "%s", room); | |
3888 | |
3889 act = purple_menu_action_new(buf2, | |
3890 PURPLE_CALLBACK(yahoo_game), | |
3891 NULL, NULL); | |
3892 m = g_list_append(m, act); | |
3893 } | |
3894 } | |
3895 } | |
3896 | |
3897 if (f) { | |
3898 act = purple_menu_action_new(_("Presence Settings"), NULL, NULL, | |
3899 build_presence_submenu(f, gc)); | |
3900 m = g_list_append(m, act); | |
3901 } | |
3902 | |
3903 if (f) { | |
3904 act = purple_menu_action_new(_("Start Doodling"), | |
3905 PURPLE_CALLBACK(yahoo_doodle_blist_node), | |
3906 NULL, NULL); | |
3907 m = g_list_append(m, act); | |
3908 } | |
3909 | |
3910 return m; | |
3911 } | |
3912 | |
3913 static GList *yahoo_blist_node_menu(PurpleBlistNode *node) | |
3914 { | |
3915 if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { | |
3916 return yahoo_buddy_menu((PurpleBuddy *) node); | |
3917 } else { | |
3918 return NULL; | |
3919 } | |
3920 } | |
3921 | |
3922 static void yahoo_act_id(PurpleConnection *gc, PurpleRequestFields *fields) | |
3923 { | |
3924 struct yahoo_data *yd = gc->proto_data; | |
3925 const char *name = yd->profiles[purple_request_fields_get_choice(fields, "id")]; | |
3926 | |
3927 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, 0); | |
3928 yahoo_packet_hash_str(pkt, 3, name); | |
3929 yahoo_packet_send_and_free(pkt, yd); | |
3930 | |
3931 purple_connection_set_display_name(gc, name); | |
3932 } | |
3933 | |
3934 static void | |
3935 yahoo_get_inbox_token_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, | |
3936 const gchar *token, size_t len, const gchar *error_message) | |
3937 { | |
3938 PurpleConnection *gc = user_data; | |
3939 gboolean set_cookie = FALSE; | |
3940 gchar *url; | |
3941 struct yahoo_data *yd = gc->proto_data; | |
3942 | |
3943 g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc)); | |
3944 | |
3945 yd->url_datas = g_slist_remove(yd->url_datas, url_data); | |
3946 | |
3947 if (error_message != NULL) | |
3948 purple_debug_error("yahoo", "Requesting mail login token failed: %s\n", error_message); | |
3949 else if (len > 0 && token && *token) { | |
3950 /* Should we not be hardcoding the rd url? */ | |
3951 url = g_strdup_printf( | |
3952 "http://login.yahoo.com/config/reset_cookies_token?" | |
3953 ".token=%s" | |
3954 "&.done=http://us.rd.yahoo.com/messenger/client/%%3fhttp://mail.yahoo.com/", | |
3955 token); | |
3956 set_cookie = TRUE; | |
3957 } | |
3958 | |
3959 if (!set_cookie) { | |
3960 purple_debug_error("yahoo", "No mail login token; forwarding to login screen.\n"); | |
3961 url = g_strdup(yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL); | |
3962 } | |
3963 | |
3964 /* Open the mailbox with the parsed url data */ | |
3965 purple_notify_uri(gc, url); | |
3966 | |
3967 g_free(url); | |
3968 } | |
3969 | |
3970 | |
3971 static void yahoo_show_inbox(PurplePluginAction *action) | |
3972 { | |
3973 /* Setup a cookie that can be used by the browser */ | |
3974 /* XXX I have no idea how this will work with Yahoo! Japan. */ | |
3975 | |
3976 PurpleConnection *gc = action->context; | |
3977 struct yahoo_data *yd = gc->proto_data; | |
3978 | |
3979 PurpleUtilFetchUrlData *url_data; | |
3980 const char* base_url = "http://login.yahoo.com"; | |
3981 /* use whole URL if using HTTP Proxy */ | |
3982 gboolean use_whole_url = yahoo_account_use_http_proxy(gc); | |
3983 gchar *request = g_strdup_printf( | |
3984 "POST %s/config/cookie_token HTTP/1.0\r\n" | |
3985 "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s;\r\n" | |
3986 "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n" | |
3987 "Host: login.yahoo.com\r\n" | |
3988 "Content-Length: 0\r\n\r\n", | |
3989 use_whole_url ? base_url : "", | |
3990 yd->cookie_t, yd->cookie_y); | |
3991 | |
3992 url_data = purple_util_fetch_url_request_len_with_account( | |
3993 purple_connection_get_account(gc), base_url, use_whole_url, | |
3994 YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1, | |
3995 yahoo_get_inbox_token_cb, gc); | |
3996 | |
3997 g_free(request); | |
3998 | |
3999 if (url_data != NULL) | |
4000 yd->url_datas = g_slist_prepend(yd->url_datas, url_data); | |
4001 else { | |
4002 const char *yahoo_mail_url = (yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL); | |
4003 purple_debug_error("yahoo", | |
4004 "Unable to request mail login token; forwarding to login screen."); | |
4005 purple_notify_uri(gc, yahoo_mail_url); | |
4006 } | |
4007 | |
4008 } | |
4009 | |
4010 | |
4011 static void yahoo_show_act_id(PurplePluginAction *action) | |
4012 { | |
4013 PurpleRequestFields *fields; | |
4014 PurpleRequestFieldGroup *group; | |
4015 PurpleRequestField *field; | |
4016 PurpleConnection *gc = (PurpleConnection *) action->context; | |
4017 struct yahoo_data *yd = purple_connection_get_protocol_data(gc); | |
4018 const char *name = purple_connection_get_display_name(gc); | |
4019 int iter; | |
4020 | |
4021 fields = purple_request_fields_new(); | |
4022 group = purple_request_field_group_new(NULL); | |
4023 purple_request_fields_add_group(fields, group); | |
4024 field = purple_request_field_choice_new("id", "Activate which ID?", 0); | |
4025 purple_request_field_group_add_field(group, field); | |
4026 | |
4027 for (iter = 0; yd->profiles[iter]; iter++) { | |
4028 purple_request_field_choice_add(field, yd->profiles[iter]); | |
4029 if (purple_strequal(yd->profiles[iter], name)) | |
4030 purple_request_field_choice_set_default_value(field, iter); | |
4031 } | |
4032 | |
4033 purple_request_fields(gc, NULL, _("Select the ID you want to activate"), NULL, | |
4034 fields, | |
4035 _("OK"), G_CALLBACK(yahoo_act_id), | |
4036 _("Cancel"), NULL, | |
4037 purple_connection_get_account(gc), NULL, NULL, | |
4038 gc); | |
4039 } | |
4040 | |
4041 static void yahoo_show_chat_goto(PurplePluginAction *action) | |
4042 { | |
4043 PurpleConnection *gc = (PurpleConnection *) action->context; | |
4044 purple_request_input(gc, NULL, _("Join whom in chat?"), NULL, | |
4045 "", FALSE, FALSE, NULL, | |
4046 _("OK"), G_CALLBACK(yahoo_chat_goto), | |
4047 _("Cancel"), NULL, | |
4048 purple_connection_get_account(gc), NULL, NULL, | |
4049 gc); | |
4050 } | |
4051 | |
4052 static GList *yahoo_actions(PurplePlugin *plugin, gpointer context) { | |
4053 GList *m = NULL; | |
4054 PurplePluginAction *act; | |
4055 | |
4056 act = purple_plugin_action_new(_("Activate ID..."), | |
4057 yahoo_show_act_id); | |
4058 m = g_list_append(m, act); | |
4059 | |
4060 act = purple_plugin_action_new(_("Join User in Chat..."), | |
4061 yahoo_show_chat_goto); | |
4062 m = g_list_append(m, act); | |
4063 | |
4064 m = g_list_append(m, NULL); | |
4065 act = purple_plugin_action_new(_("Open Inbox"), | |
4066 yahoo_show_inbox); | |
4067 m = g_list_append(m, act); | |
4068 | |
4069 return m; | |
4070 } | |
4071 | |
4072 struct yahoo_sms_carrier_cb_data { | |
4073 PurpleConnection *gc; | |
4074 char *who; | |
4075 char *what; | |
4076 }; | |
4077 | |
4078 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags); | |
4079 | |
4080 static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, | |
4081 const gchar *webdata, size_t len, const gchar *error_message) | |
4082 { | |
4083 struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data; | |
4084 PurpleConnection *gc = sms_cb_data->gc; | |
4085 struct yahoo_data *yd = gc->proto_data; | |
4086 char *mobile_no = NULL; | |
4087 char *status = NULL; | |
4088 char *carrier = NULL; | |
4089 PurpleAccount *account = purple_connection_get_account(gc); | |
4090 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account); | |
4091 | |
4092 if (error_message != NULL) { | |
4093 purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
4094 | |
4095 g_free(sms_cb_data->who); | |
4096 g_free(sms_cb_data->what); | |
4097 g_free(sms_cb_data); | |
4098 return ; | |
4099 } | |
4100 else if (len > 0 && webdata && *webdata) { | |
4101 xmlnode *validate_data_root = xmlnode_from_str(webdata, -1); | |
4102 xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no"); | |
4103 mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn"); | |
4104 | |
4105 validate_data_root = xmlnode_copy(validate_data_child); | |
4106 validate_data_child = xmlnode_get_child(validate_data_root, "status"); | |
4107 status = xmlnode_get_data(validate_data_child); | |
4108 | |
4109 validate_data_child = xmlnode_get_child(validate_data_root, "carrier"); | |
4110 carrier = xmlnode_get_data(validate_data_child); | |
4111 | |
4112 purple_debug_info("yahoo","SMS validate data: Mobile:%s, Status:%s, Carrier:%s\n", mobile_no, status, carrier); | |
4113 | |
4114 if( strcmp(status, "Valid") == 0) { | |
4115 g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup(carrier)); | |
4116 yahoo_send_im(sms_cb_data->gc, sms_cb_data->who, sms_cb_data->what, PURPLE_MESSAGE_SEND); | |
4117 } | |
4118 else { | |
4119 g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown")); | |
4120 purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
4121 } | |
4122 | |
4123 xmlnode_free(validate_data_child); | |
4124 xmlnode_free(validate_data_root); | |
4125 g_free(sms_cb_data->who); | |
4126 g_free(sms_cb_data->what); | |
4127 g_free(sms_cb_data); | |
4128 g_free(mobile_no); | |
4129 g_free(status); | |
4130 g_free(carrier); | |
4131 } | |
4132 } | |
4133 | |
4134 static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data) | |
4135 { | |
4136 struct yahoo_data *yd = gc->proto_data; | |
4137 PurpleUtilFetchUrlData *url_data; | |
4138 struct yahoo_sms_carrier_cb_data *sms_cb_data; | |
4139 char *validate_request_str = NULL; | |
4140 char *request = NULL; | |
4141 gboolean use_whole_url = FALSE; | |
4142 xmlnode *validate_request_root = NULL; | |
4143 xmlnode *validate_request_child = NULL; | |
4144 | |
4145 if(!(sms_cb_data = data)) | |
4146 return; | |
4147 | |
4148 validate_request_root = xmlnode_new("validate"); | |
4149 xmlnode_set_attrib(validate_request_root, "intl", "us"); | |
4150 xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION); | |
4151 xmlnode_set_attrib(validate_request_root, "qos", "0"); | |
4152 | |
4153 validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no"); | |
4154 xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1); | |
4155 | |
4156 validate_request_str = xmlnode_to_str(validate_request_root, NULL); | |
4157 | |
4158 xmlnode_free(validate_request_child); | |
4159 xmlnode_free(validate_request_root); | |
4160 | |
4161 request = g_strdup_printf( | |
4162 "POST /mobileno?intl=us&version=%s HTTP/1.1\r\n" | |
4163 "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n" | |
4164 "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n" | |
4165 "Host: validate.msg.yahoo.com\r\n" | |
4166 "Content-Length: %" G_GSIZE_FORMAT "\r\n" | |
4167 "Cache-Control: no-cache\r\n\r\n%s", | |
4168 YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str); | |
4169 | |
4170 /* use whole URL if using HTTP Proxy */ | |
4171 if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) | |
4172 use_whole_url = TRUE; | |
4173 | |
4174 url_data = purple_util_fetch_url_request_len_with_account( | |
4175 purple_connection_get_account(gc), YAHOO_SMS_CARRIER_URL, use_whole_url, | |
4176 YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1, | |
4177 yahoo_get_sms_carrier_cb, data); | |
4178 | |
4179 g_free(request); | |
4180 g_free(validate_request_str); | |
4181 | |
4182 if (!url_data) { | |
4183 PurpleAccount *account = purple_connection_get_account(gc); | |
4184 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account); | |
4185 purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
4186 g_free(sms_cb_data->who); | |
4187 g_free(sms_cb_data->what); | |
4188 g_free(sms_cb_data); | |
4189 } | |
4190 } | |
4191 | |
4192 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags) | |
4193 { | |
4194 struct yahoo_data *yd = gc->proto_data; | |
4195 struct yahoo_packet *pkt = NULL; | |
4196 char *msg = yahoo_html_to_codes(what); | |
4197 char *msg2; | |
4198 gboolean utf8 = TRUE; | |
4199 PurpleWhiteboard *wb; | |
4200 int ret = 1; | |
4201 YahooFriend *f = NULL; | |
4202 gsize lenb = 0; | |
4203 glong lenc = 0; | |
4204 struct yahoo_p2p_data *p2p_data; | |
4205 gboolean msn = FALSE; | |
4206 msg2 = yahoo_string_encode(gc, msg, &utf8); | |
4207 | |
4208 if(msg2) { | |
4209 lenb = strlen(msg2); | |
4210 lenc = g_utf8_strlen(msg2, -1); | |
4211 | |
4212 if(lenb > YAHOO_MAX_MESSAGE_LENGTH_BYTES || lenc > YAHOO_MAX_MESSAGE_LENGTH_CHARS) { | |
4213 purple_debug_info("yahoo", "Message too big. Length is %" G_GSIZE_FORMAT | |
4214 " bytes, %ld characters. Max is %d bytes, %d chars." | |
4215 " Message is '%s'.\n", lenb, lenc, YAHOO_MAX_MESSAGE_LENGTH_BYTES, | |
4216 YAHOO_MAX_MESSAGE_LENGTH_CHARS, msg2); | |
4217 g_free(msg); | |
4218 g_free(msg2); | |
4219 return -E2BIG; | |
4220 } | |
4221 } | |
4222 | |
4223 msn = !g_strncasecmp(who, "msn/", 4); | |
4224 | |
4225 if( strncmp(who, "+", 1) == 0 ) { | |
4226 /* we have an sms to be sent */ | |
4227 gchar *carrier = NULL; | |
4228 const char *alias = NULL; | |
4229 PurpleAccount *account = purple_connection_get_account(gc); | |
4230 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account); | |
4231 | |
4232 carrier = g_hash_table_lookup(yd->sms_carrier, who); | |
4233 if (!carrier) { | |
4234 struct yahoo_sms_carrier_cb_data *sms_cb_data; | |
4235 sms_cb_data = g_malloc(sizeof(struct yahoo_sms_carrier_cb_data)); | |
4236 sms_cb_data->gc = gc; | |
4237 sms_cb_data->who = g_strdup(who); | |
4238 sms_cb_data->what = g_strdup(what); | |
4239 | |
4240 purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
4241 | |
4242 yahoo_get_sms_carrier(gc, sms_cb_data); | |
4243 | |
4244 g_free(msg); | |
4245 g_free(msg2); | |
4246 return ret; | |
4247 } | |
4248 else if( strcmp(carrier,"Unknown") == 0 ) { | |
4249 purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
4250 | |
4251 g_free(msg); | |
4252 g_free(msg2); | |
4253 return -1; | |
4254 } | |
4255 | |
4256 alias = purple_account_get_alias(account); | |
4257 pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, 0); | |
4258 yahoo_packet_hash(pkt, "sssss", | |
4259 1, purple_connection_get_display_name(gc), | |
4260 69, alias, | |
4261 5, who + 1, | |
4262 68, carrier, | |
4263 14, msg2); | |
4264 yahoo_packet_send_and_free(pkt, yd); | |
4265 | |
4266 g_free(msg); | |
4267 g_free(msg2); | |
4268 | |
4269 return ret; | |
4270 } | |
4271 | |
4272 pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0); | |
4273 if(msn) { | |
4274 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who+4); | |
4275 yahoo_packet_hash_int(pkt, 241, 2); | |
4276 } | |
4277 else { | |
4278 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who); | |
4279 if ((f = yahoo_friend_find(gc, who)) && f->protocol) | |
4280 yahoo_packet_hash_int(pkt, 241, f->protocol); | |
4281 } | |
4282 | |
4283 if (utf8) | |
4284 yahoo_packet_hash_str(pkt, 97, "1"); | |
4285 yahoo_packet_hash_str(pkt, 14, msg2); | |
4286 | |
4287 /* | |
4288 * IMVironment. | |
4289 * | |
4290 * If this message is to a user who is also Doodling with the local user, | |
4291 * format the chat packet with the correct IMV information (thanks Yahoo!) | |
4292 * | |
4293 * Otherwise attempt to use the same IMVironment as the remote user, | |
4294 * just so that we don't inadvertantly reset their IMVironment back | |
4295 * to nothing. | |
4296 * | |
4297 * If they have no set an IMVironment, then use the default. | |
4298 */ | |
4299 wb = purple_whiteboard_get_session(gc->account, who); | |
4300 if (wb) | |
4301 yahoo_packet_hash_str(pkt, 63, DOODLE_IMV_KEY); | |
4302 else | |
4303 { | |
4304 const char *imv; | |
4305 imv = g_hash_table_lookup(yd->imvironments, who); | |
4306 if (imv != NULL) | |
4307 yahoo_packet_hash_str(pkt, 63, imv); | |
4308 else | |
4309 yahoo_packet_hash_str(pkt, 63, ";0"); | |
4310 } | |
4311 | |
4312 yahoo_packet_hash_str(pkt, 64, "0"); /* no idea */ | |
4313 yahoo_packet_hash_str(pkt, 1002, "1"); /* no idea, Yahoo 6 or later only it seems */ | |
4314 if (!yd->picture_url) | |
4315 yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */ | |
4316 else | |
4317 yahoo_packet_hash_str(pkt, 206, "2"); | |
4318 | |
4319 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */ | |
4320 if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) { | |
4321 /* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */ | |
4322 if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) { | |
4323 yahoo_packet_hash_int(pkt, 11, p2p_data->session_id); | |
4324 yahoo_p2p_write_pkt(p2p_data->source, pkt); | |
4325 } | |
4326 else { | |
4327 yahoo_packet_send(pkt, yd); | |
4328 if(!msn) | |
4329 yahoo_send_p2p_pkt(gc, who, 0); /* send p2p packet, with val_13=0 */ | |
4330 } | |
4331 } | |
4332 else | |
4333 ret = -E2BIG; | |
4334 | |
4335 yahoo_packet_free(pkt); | |
4336 | |
4337 g_free(msg); | |
4338 g_free(msg2); | |
4339 | |
4340 return ret; | |
4341 } | |
4342 | |
4343 static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) | |
4344 { | |
4345 struct yahoo_data *yd = gc->proto_data; | |
4346 struct yahoo_p2p_data *p2p_data; | |
4347 gboolean msn = !g_strncasecmp(who, "msn/", 4); | |
4348 struct yahoo_packet *pkt = NULL; | |
4349 | |
4350 /* Don't do anything if sms is being typed */ | |
4351 if( strncmp(who, "+", 1) == 0 ) | |
4352 return 0; | |
4353 | |
4354 pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); | |
4355 | |
4356 /* check to see if p2p link exists, send through it */ | |
4357 if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) { | |
4358 yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc), | |
4359 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", | |
4360 5, who, 11, p2p_data->session_id, 1002, "1"); /* To-do: key 15 to be sent in case of p2p */ | |
4361 yahoo_p2p_write_pkt(p2p_data->source, pkt); | |
4362 yahoo_packet_free(pkt); | |
4363 } | |
4364 else { /* send through yahoo server */ | |
4365 if(msn) | |
4366 yahoo_packet_hash(pkt, "sssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), | |
4367 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", | |
4368 5, who+4, 1002, "1", 241, "2"); | |
4369 else | |
4370 yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), | |
4371 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", | |
4372 5, who+4, 1002, "1"); | |
4373 yahoo_packet_send_and_free(pkt, yd); | |
4374 } | |
4375 | |
4376 return 0; | |
4377 } | |
4378 | |
4379 static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data) | |
4380 { | |
4381 YahooFriend *f = value; | |
4382 if (f && f->presence == YAHOO_PRESENCE_ONLINE) | |
4383 f->presence = YAHOO_PRESENCE_DEFAULT; | |
4384 } | |
4385 | |
4386 static void yahoo_set_status(PurpleAccount *account, PurpleStatus *status) | |
4387 { | |
4388 PurpleConnection *gc; | |
4389 PurplePresence *presence; | |
4390 struct yahoo_data *yd; | |
4391 struct yahoo_packet *pkt; | |
4392 int old_status; | |
4393 const char *msg = NULL; | |
4394 char *tmp = NULL; | |
4395 char *conv_msg = NULL; | |
4396 gboolean utf8 = TRUE; | |
4397 | |
4398 if (!purple_status_is_active(status)) | |
4399 return; | |
4400 | |
4401 gc = purple_account_get_connection(account); | |
4402 presence = purple_status_get_presence(status); | |
4403 yd = (struct yahoo_data *)gc->proto_data; | |
4404 old_status = yd->current_status; | |
4405 | |
4406 yd->current_status = get_yahoo_status_from_purple_status(status); | |
4407 | |
4408 if (yd->current_status == YAHOO_STATUS_CUSTOM) | |
4409 { | |
4410 msg = purple_status_get_attr_string(status, "message"); | |
4411 | |
4412 if (purple_status_is_available(status)) { | |
4413 tmp = yahoo_string_encode(gc, msg, &utf8); | |
4414 conv_msg = purple_markup_strip_html(tmp); | |
4415 g_free(tmp); | |
4416 } else { | |
4417 if ((msg == NULL) || (*msg == '\0')) | |
4418 msg = _("Away"); | |
4419 tmp = yahoo_string_encode(gc, msg, &utf8); | |
4420 conv_msg = purple_markup_strip_html(tmp); | |
4421 g_free(tmp); | |
4422 } | |
4423 } | |
4424 | |
4425 if (yd->current_status == YAHOO_STATUS_INVISIBLE) { | |
4426 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, 0); | |
4427 yahoo_packet_hash_str(pkt, 13, "2"); | |
4428 yahoo_packet_send_and_free(pkt, yd); | |
4429 | |
4430 return; | |
4431 } | |
4432 | |
4433 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0); | |
4434 yahoo_packet_hash_int(pkt, 10, yd->current_status); | |
4435 | |
4436 if (yd->current_status == YAHOO_STATUS_CUSTOM) { | |
4437 yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0); | |
4438 yahoo_packet_hash_str(pkt, 19, conv_msg); | |
4439 } else { | |
4440 yahoo_packet_hash_str(pkt, 19, ""); | |
4441 } | |
4442 | |
4443 g_free(conv_msg); | |
4444 | |
4445 if (purple_presence_is_idle(presence)) | |
4446 yahoo_packet_hash_str(pkt, 47, "2"); | |
4447 else if (!purple_status_is_available(status)) | |
4448 yahoo_packet_hash_str(pkt, 47, "1"); | |
4449 | |
4450 yahoo_packet_send_and_free(pkt, yd); | |
4451 | |
4452 if (old_status == YAHOO_STATUS_INVISIBLE) { | |
4453 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, 0); | |
4454 yahoo_packet_hash_str(pkt, 13, "1"); | |
4455 yahoo_packet_send_and_free(pkt, yd); | |
4456 | |
4457 /* Any per-session presence settings are removed */ | |
4458 g_hash_table_foreach(yd->friends, yahoo_session_presence_remove, NULL); | |
4459 | |
4460 } | |
4461 } | |
4462 | |
4463 static void yahoo_set_idle(PurpleConnection *gc, int idle) | |
4464 { | |
4465 struct yahoo_data *yd = gc->proto_data; | |
4466 struct yahoo_packet *pkt = NULL; | |
4467 char *msg = NULL, *msg2 = NULL; | |
4468 PurpleStatus *status = NULL; | |
4469 | |
4470 if (idle && yd->current_status != YAHOO_STATUS_CUSTOM) | |
4471 yd->current_status = YAHOO_STATUS_IDLE; | |
4472 else if (!idle && yd->current_status == YAHOO_STATUS_IDLE) { | |
4473 status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc))); | |
4474 yd->current_status = get_yahoo_status_from_purple_status(status); | |
4475 } | |
4476 | |
4477 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0); | |
4478 | |
4479 yahoo_packet_hash_int(pkt, 10, yd->current_status); | |
4480 if (yd->current_status == YAHOO_STATUS_CUSTOM) { | |
4481 const char *tmp; | |
4482 if (status == NULL) | |
4483 status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc))); | |
4484 tmp = purple_status_get_attr_string(status, "message"); | |
4485 if (tmp != NULL) { | |
4486 gboolean utf8 = TRUE; | |
4487 msg = yahoo_string_encode(gc, tmp, &utf8); | |
4488 msg2 = purple_markup_strip_html(msg); | |
4489 yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0); | |
4490 yahoo_packet_hash_str(pkt, 19, msg2); | |
4491 } else { | |
4492 /* get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for | |
4493 * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */ | |
4494 yahoo_packet_hash_str(pkt, 19, _("Away")); | |
4495 } | |
4496 } else { | |
4497 yahoo_packet_hash_str(pkt, 19, ""); | |
4498 } | |
4499 | |
4500 if (idle) | |
4501 yahoo_packet_hash_str(pkt, 47, "2"); | |
4502 else if (!purple_presence_is_available(purple_account_get_presence(purple_connection_get_account(gc)))) | |
4503 yahoo_packet_hash_str(pkt, 47, "1"); | |
4504 | |
4505 yahoo_packet_send_and_free(pkt, yd); | |
4506 | |
4507 g_free(msg); | |
4508 g_free(msg2); | |
4509 } | |
4510 | |
4511 static GList *yahoo_status_types(PurpleAccount *account) | |
4512 { | |
4513 PurpleStatusType *type; | |
4514 GList *types = NULL; | |
4515 | |
4516 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, YAHOO_STATUS_TYPE_AVAILABLE, | |
4517 NULL, TRUE, TRUE, FALSE, | |
4518 "message", _("Message"), | |
4519 purple_value_new(PURPLE_TYPE_STRING), NULL); | |
4520 types = g_list_append(types, type); | |
4521 | |
4522 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_AWAY, | |
4523 NULL, TRUE, TRUE, FALSE, | |
4524 "message", _("Message"), | |
4525 purple_value_new(PURPLE_TYPE_STRING), NULL); | |
4526 types = g_list_append(types, type); | |
4527 | |
4528 type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_BRB, _("Be Right Back"), TRUE); | |
4529 types = g_list_append(types, type); | |
4530 | |
4531 type = purple_status_type_new(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_BUSY, _("Busy"), TRUE); | |
4532 types = g_list_append(types, type); | |
4533 | |
4534 type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATHOME, _("Not at Home"), TRUE); | |
4535 types = g_list_append(types, type); | |
4536 | |
4537 type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATDESK, _("Not at Desk"), TRUE); | |
4538 types = g_list_append(types, type); | |
4539 | |
4540 type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTINOFFICE, _("Not in Office"), TRUE); | |
4541 types = g_list_append(types, type); | |
4542 | |
4543 type = purple_status_type_new(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_ONPHONE, _("On the Phone"), TRUE); | |
4544 types = g_list_append(types, type); | |
4545 | |
4546 type = purple_status_type_new(PURPLE_STATUS_EXTENDED_AWAY, YAHOO_STATUS_TYPE_ONVACATION, _("On Vacation"), TRUE); | |
4547 types = g_list_append(types, type); | |
4548 | |
4549 type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_OUTTOLUNCH, _("Out to Lunch"), TRUE); | |
4550 types = g_list_append(types, type); | |
4551 | |
4552 type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_STEPPEDOUT, _("Stepped Out"), TRUE); | |
4553 types = g_list_append(types, type); | |
4554 | |
4555 | |
4556 type = purple_status_type_new(PURPLE_STATUS_INVISIBLE, YAHOO_STATUS_TYPE_INVISIBLE, NULL, TRUE); | |
4557 types = g_list_append(types, type); | |
4558 | |
4559 type = purple_status_type_new(PURPLE_STATUS_OFFLINE, YAHOO_STATUS_TYPE_OFFLINE, NULL, TRUE); | |
4560 types = g_list_append(types, type); | |
4561 | |
4562 type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, YAHOO_STATUS_TYPE_MOBILE, NULL, FALSE, FALSE, TRUE); | |
4563 types = g_list_append(types, type); | |
4564 | |
4565 return types; | |
4566 } | |
4567 | |
4568 static void yahoo_keepalive(PurpleConnection *gc) | |
4569 { | |
4570 struct yahoo_packet *pkt; | |
4571 struct yahoo_data *yd = gc->proto_data; | |
4572 time_t now = time(NULL); | |
4573 | |
4574 /* We're only allowed to send a ping once an hour or the servers will boot us */ | |
4575 if ((now - yd->last_ping) >= PING_TIMEOUT) { | |
4576 yd->last_ping = now; | |
4577 | |
4578 /* The native client will only send PING or CHATPING */ | |
4579 if (yd->chat_online) { | |
4580 if (yd->wm) { | |
4581 ycht_chat_send_keepalive(yd->ycht); | |
4582 } else { | |
4583 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, 0); | |
4584 yahoo_packet_hash_str(pkt, 109, purple_connection_get_display_name(gc)); | |
4585 yahoo_packet_send_and_free(pkt, yd); | |
4586 } | |
4587 } else { | |
4588 pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, 0); | |
4589 yahoo_packet_send_and_free(pkt, yd); | |
4590 } | |
4591 } | |
4592 | |
4593 if ((now - yd->last_keepalive) >= KEEPALIVE_TIMEOUT) { | |
4594 yd->last_keepalive = now; | |
4595 pkt = yahoo_packet_new(YAHOO_SERVICE_KEEPALIVE, YAHOO_STATUS_AVAILABLE, 0); | |
4596 yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc)); | |
4597 yahoo_packet_send_and_free(pkt, yd); | |
4598 } | |
4599 | |
4600 } | |
4601 | |
4602 static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g) | |
4603 { | |
4604 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
4605 struct yahoo_packet *pkt; | |
4606 const char *group = NULL; | |
4607 char *group2; | |
4608 YahooFriend *f; | |
4609 const char *bname; | |
4610 gboolean msn = FALSE; | |
4611 | |
4612 if (!yd->logged_in) | |
4613 return; | |
4614 | |
4615 bname = purple_buddy_get_name(buddy); | |
4616 if (!purple_privacy_check(purple_connection_get_account(gc), bname)) | |
4617 return; | |
4618 | |
4619 f = yahoo_friend_find(gc, bname); | |
4620 msn = !g_strncasecmp(bname, "msn/", 4); | |
4621 | |
4622 g = purple_buddy_get_group(buddy); | |
4623 if (g) | |
4624 group = purple_group_get_name(g); | |
4625 else | |
4626 group = "Buddies"; | |
4627 | |
4628 group2 = yahoo_string_encode(gc, group, NULL); | |
4629 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0); | |
4630 if(msn) { | |
4631 yahoo_packet_hash(pkt, "sssssssssss", | |
4632 14, "", | |
4633 65, group2, | |
4634 97, "1", | |
4635 1, purple_connection_get_display_name(gc), | |
4636 302, "319", | |
4637 300, "319", | |
4638 7, bname + 4, | |
4639 241, "2", | |
4640 334, "0", | |
4641 301, "319", | |
4642 303, "319" | |
4643 ); | |
4644 } | |
4645 else { | |
4646 yahoo_packet_hash(pkt, "ssssssssss", | |
4647 14, "", | |
4648 65, group2, | |
4649 97, "1", | |
4650 1, purple_connection_get_display_name(gc), | |
4651 302, "319", | |
4652 300, "319", | |
4653 7, bname, | |
4654 334, "0", | |
4655 301, "319", | |
4656 303, "319" | |
4657 ); | |
4658 } | |
4659 if (f && f->protocol && !msn) | |
4660 yahoo_packet_hash_int(pkt, 241, f->protocol); | |
4661 | |
4662 yahoo_packet_send_and_free(pkt, yd); | |
4663 g_free(group2); | |
4664 } | |
4665 | |
4666 static void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) | |
4667 { | |
4668 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
4669 struct yahoo_packet *pkt; | |
4670 GSList *buddies, *l; | |
4671 PurpleGroup *g; | |
4672 gboolean remove = TRUE; | |
4673 char *cg; | |
4674 const char *bname, *gname; | |
4675 YahooFriend *f = NULL; | |
4676 gboolean msn = FALSE; | |
4677 | |
4678 bname = purple_buddy_get_name(buddy); | |
4679 f = yahoo_friend_find(gc, bname); | |
4680 if (!f) | |
4681 return; | |
4682 | |
4683 gname = purple_group_get_name(group); | |
4684 buddies = purple_find_buddies(purple_connection_get_account(gc), bname); | |
4685 if(f->protocol == 2) | |
4686 msn = TRUE; | |
4687 for (l = buddies; l; l = l->next) { | |
4688 g = purple_buddy_get_group(l->data); | |
4689 if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) { | |
4690 remove = FALSE; | |
4691 break; | |
4692 } | |
4693 } | |
4694 | |
4695 g_slist_free(buddies); | |
4696 | |
4697 if (remove) | |
4698 g_hash_table_remove(yd->friends, bname); | |
4699 | |
4700 cg = yahoo_string_encode(gc, gname, NULL); | |
4701 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); | |
4702 | |
4703 if(msn) | |
4704 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), | |
4705 7, bname+4, 65, cg); | |
4706 else | |
4707 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), | |
4708 7, bname, 65, cg); | |
4709 if(f->protocol) | |
4710 yahoo_packet_hash_int(pkt, 241, f->protocol); | |
4711 yahoo_packet_send_and_free(pkt, yd); | |
4712 g_free(cg); | |
4713 } | |
4714 | |
4715 static void yahoo_add_deny(PurpleConnection *gc, const char *who) { | |
4716 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
4717 struct yahoo_packet *pkt; | |
4718 | |
4719 if (!yd->logged_in) | |
4720 return; | |
4721 | |
4722 if (!who || who[0] == '\0') | |
4723 return; | |
4724 | |
4725 pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, 0); | |
4726 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), | |
4727 7, who, 13, "1"); | |
4728 yahoo_packet_send_and_free(pkt, yd); | |
4729 } | |
4730 | |
4731 static void yahoo_rem_deny(PurpleConnection *gc, const char *who) { | |
4732 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
4733 struct yahoo_packet *pkt; | |
4734 | |
4735 if (!yd->logged_in) | |
4736 return; | |
4737 | |
4738 if (!who || who[0] == '\0') | |
4739 return; | |
4740 | |
4741 pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, 0); | |
4742 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "2"); | |
4743 yahoo_packet_send_and_free(pkt, yd); | |
4744 } | |
4745 | |
4746 static void yahoo_set_permit_deny(PurpleConnection *gc) | |
4747 { | |
4748 PurpleAccount *account; | |
4749 GSList *deny; | |
4750 | |
4751 account = purple_connection_get_account(gc); | |
4752 | |
4753 switch (account->perm_deny) | |
4754 { | |
4755 case PURPLE_PRIVACY_ALLOW_ALL: | |
4756 for (deny = account->deny; deny; deny = deny->next) | |
4757 yahoo_rem_deny(gc, deny->data); | |
4758 break; | |
4759 | |
4760 case PURPLE_PRIVACY_ALLOW_BUDDYLIST: | |
4761 case PURPLE_PRIVACY_ALLOW_USERS: | |
4762 case PURPLE_PRIVACY_DENY_USERS: | |
4763 case PURPLE_PRIVACY_DENY_ALL: | |
4764 for (deny = account->deny; deny; deny = deny->next) | |
4765 yahoo_add_deny(gc, deny->data); | |
4766 break; | |
4767 } | |
4768 } | |
4769 | |
4770 static gboolean yahoo_unload_plugin(PurplePlugin *plugin) | |
4771 { | |
4772 yahoo_dest_colorht(); | |
4773 | |
4774 return TRUE; | |
4775 } | |
4776 | |
4777 static void yahoo_change_buddys_group(PurpleConnection *gc, const char *who, | |
4778 const char *old_group, const char *new_group) | |
4779 { | |
4780 struct yahoo_data *yd = gc->proto_data; | |
4781 struct yahoo_packet *pkt; | |
4782 char *gpn, *gpo; | |
4783 YahooFriend *f = yahoo_friend_find(gc, who); | |
4784 gboolean msn = FALSE; | |
4785 const char *temp = NULL; | |
4786 | |
4787 /* Step 0: If they aren't on the server list anyway, | |
4788 * don't bother letting the server know. | |
4789 */ | |
4790 if (!f) | |
4791 return; | |
4792 | |
4793 if(f->protocol == 2) { | |
4794 msn = TRUE; | |
4795 temp = who+4; | |
4796 } else | |
4797 temp = who; | |
4798 | |
4799 /* If old and new are the same, we would probably | |
4800 * end up deleting the buddy, which would be bad. | |
4801 * This might happen because of the charset conversation. | |
4802 */ | |
4803 gpn = yahoo_string_encode(gc, new_group, NULL); | |
4804 gpo = yahoo_string_encode(gc, old_group, NULL); | |
4805 if (!strcmp(gpn, gpo)) { | |
4806 g_free(gpn); | |
4807 g_free(gpo); | |
4808 return; | |
4809 } | |
4810 | |
4811 pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0); | |
4812 if(f->protocol) | |
4813 yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc), | |
4814 302, "240", 300, "240", 7, temp, 241, f->protocol, 224, gpo, 264, gpn, 301, | |
4815 "240", 303, "240"); | |
4816 else | |
4817 yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc), | |
4818 302, "240", 300, "240", 7, temp, 224, gpo, 264, gpn, 301, | |
4819 "240", 303, "240"); | |
4820 yahoo_packet_send_and_free(pkt, yd); | |
4821 | |
4822 g_free(gpn); | |
4823 g_free(gpo); | |
4824 } | |
4825 | |
4826 static void yahoo_rename_group(PurpleConnection *gc, const char *old_name, | |
4827 PurpleGroup *group, GList *moved_buddies) | |
4828 { | |
4829 struct yahoo_data *yd = gc->proto_data; | |
4830 struct yahoo_packet *pkt; | |
4831 char *gpn, *gpo; | |
4832 | |
4833 gpn = yahoo_string_encode(gc, purple_group_get_name(group), NULL); | |
4834 gpo = yahoo_string_encode(gc, old_name, NULL); | |
4835 if (!strcmp(gpn, gpo)) { | |
4836 g_free(gpn); | |
4837 g_free(gpo); | |
4838 return; | |
4839 } | |
4840 | |
4841 pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, 0); | |
4842 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), | |
4843 65, gpo, 67, gpn); | |
4844 yahoo_packet_send_and_free(pkt, yd); | |
4845 g_free(gpn); | |
4846 g_free(gpo); | |
4847 } | |
4848 | |
4849 /********************************* Commands **********************************/ | |
4850 | |
4851 static PurpleCmdRet | |
4852 yahoopurple_cmd_buzz(PurpleConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data) { | |
4853 PurpleAccount *account = purple_conversation_get_account(c); | |
4854 | |
4855 if (*args && args[0]) | |
4856 return PURPLE_CMD_RET_FAILED; | |
4857 | |
4858 purple_prpl_send_attention(account->gc, c->name, YAHOO_BUZZ); | |
4859 | |
4860 return PURPLE_CMD_RET_OK; | |
4861 } | |
4862 | |
4863 static PurplePlugin *my_protocol = NULL; | |
4864 | |
4865 static PurpleCmdRet | |
4866 yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd, | |
4867 char **args, char **error, void *data) | |
4868 { | |
4869 GHashTable *comp; | |
4870 PurpleConnection *gc; | |
4871 struct yahoo_data *yd; | |
4872 int id; | |
4873 | |
4874 if (!args || !args[0]) | |
4875 return PURPLE_CMD_RET_FAILED; | |
4876 | |
4877 gc = purple_conversation_get_gc(conv); | |
4878 yd = gc->proto_data; | |
4879 id = yd->conf_id; | |
4880 purple_debug_info("yahoo", "Trying to join %s \n", args[0]); | |
4881 | |
4882 comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
4883 g_hash_table_replace(comp, g_strdup("room"), g_ascii_strdown(args[0], -1)); | |
4884 g_hash_table_replace(comp, g_strdup("type"), g_strdup("Chat")); | |
4885 | |
4886 yahoo_c_join(gc, comp); | |
4887 | |
4888 g_hash_table_destroy(comp); | |
4889 return PURPLE_CMD_RET_OK; | |
4890 } | |
4891 | |
4892 static PurpleCmdRet | |
4893 yahoopurple_cmd_chat_list(PurpleConversation *conv, const char *cmd, | |
4894 char **args, char **error, void *data) | |
4895 { | |
4896 PurpleAccount *account = purple_conversation_get_account(conv); | |
4897 if (*args && args[0]) | |
4898 return PURPLE_CMD_RET_FAILED; | |
4899 purple_roomlist_show_with_account(account); | |
4900 return PURPLE_CMD_RET_OK; | |
4901 } | |
4902 | |
4903 static gboolean yahoo_offline_message(const PurpleBuddy *buddy) | |
4904 { | |
4905 return TRUE; | |
4906 } | |
4907 | |
4908 gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type) | |
4909 { | |
4910 PurpleConversation *c; | |
4911 | |
4912 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, | |
4913 username, gc->account); | |
4914 | |
4915 g_return_val_if_fail(c != NULL, FALSE); | |
4916 | |
4917 purple_debug_info("yahoo", "Sending <ding> on account %s to buddy %s.\n", | |
4918 username, c->name); | |
4919 purple_conv_im_send_with_flags(PURPLE_CONV_IM(c), "<ding>", PURPLE_MESSAGE_INVISIBLE); | |
4920 | |
4921 return TRUE; | |
4922 } | |
4923 | |
4924 GList *yahoo_attention_types(PurpleAccount *account) | |
4925 { | |
4926 static GList *list = NULL; | |
4927 | |
4928 if (!list) { | |
4929 /* Yahoo only supports one attention command: the 'buzz'. */ | |
4930 /* This is index number YAHOO_BUZZ. */ | |
4931 list = g_list_append(list, purple_attention_type_new("Buzz", _("Buzz"), | |
4932 _("%s has buzzed you!"), _("Buzzing %s..."))); | |
4933 } | |
4934 | |
4935 return list; | |
4936 } | |
4937 | |
4938 /************************** Plugin Initialization ****************************/ | |
4939 static void | |
4940 yahoopurple_register_commands(void) | |
4941 { | |
4942 purple_cmd_register("join", "s", PURPLE_CMD_P_PRPL, | |
4943 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | | |
4944 PURPLE_CMD_FLAG_PRPL_ONLY, | |
4945 "prpl-yahoo", yahoopurple_cmd_chat_join, | |
4946 _("join <room>: Join a chat room on the Yahoo network"), NULL); | |
4947 purple_cmd_register("list", "", PURPLE_CMD_P_PRPL, | |
4948 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | | |
4949 PURPLE_CMD_FLAG_PRPL_ONLY, | |
4950 "prpl-yahoo", yahoopurple_cmd_chat_list, | |
4951 _("list: List rooms on the Yahoo network"), NULL); | |
4952 purple_cmd_register("buzz", "", PURPLE_CMD_P_PRPL, | |
4953 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY, | |
4954 "prpl-yahoo", yahoopurple_cmd_buzz, | |
4955 _("buzz: Buzz a user to get their attention"), NULL); | |
4956 purple_cmd_register("doodle", "", PURPLE_CMD_P_PRPL, | |
4957 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY, | |
4958 "prpl-yahoo", yahoo_doodle_purple_cmd_start, | |
4959 _("doodle: Request user to start a Doodle session"), NULL); | |
4960 } | |
4961 | |
4962 static PurpleAccount *find_acct(const char *prpl, const char *acct_id) | |
4963 { | |
4964 PurpleAccount *acct = NULL; | |
4965 | |
4966 /* If we have a specific acct, use it */ | |
4967 if (acct_id) { | |
4968 acct = purple_accounts_find(acct_id, prpl); | |
4969 if (acct && !purple_account_is_connected(acct)) | |
4970 acct = NULL; | |
4971 } else { /* Otherwise find an active account for the protocol */ | |
4972 GList *l = purple_accounts_get_all(); | |
4973 while (l) { | |
4974 if (!strcmp(prpl, purple_account_get_protocol_id(l->data)) | |
4975 && purple_account_is_connected(l->data)) { | |
4976 acct = l->data; | |
4977 break; | |
4978 } | |
4979 l = l->next; | |
4980 } | |
4981 } | |
4982 | |
4983 return acct; | |
4984 } | |
4985 | |
4986 /* This may not be the best way to do this, but we find the first key w/o a value | |
4987 * and assume it is the buddy name */ | |
4988 static void yahoo_find_uri_novalue_param(gpointer key, gpointer value, gpointer user_data) | |
4989 { | |
4990 char **retval = user_data; | |
4991 | |
4992 if (value == NULL && *retval == NULL) { | |
4993 *retval = key; | |
4994 } | |
4995 } | |
4996 | |
4997 static gboolean yahoo_uri_handler(const char *proto, const char *cmd, GHashTable *params) | |
4998 { | |
4999 char *acct_id = g_hash_table_lookup(params, "account"); | |
5000 PurpleAccount *acct; | |
5001 | |
5002 if (g_ascii_strcasecmp(proto, "ymsgr")) | |
5003 return FALSE; | |
5004 | |
5005 acct = find_acct(purple_plugin_get_id(my_protocol), acct_id); | |
5006 | |
5007 if (!acct) | |
5008 return FALSE; | |
5009 | |
5010 /* ymsgr:SendIM?screename&m=The+Message */ | |
5011 if (!g_ascii_strcasecmp(cmd, "SendIM")) { | |
5012 char *sname = NULL; | |
5013 g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &sname); | |
5014 if (sname) { | |
5015 char *message = g_hash_table_lookup(params, "m"); | |
5016 | |
5017 PurpleConversation *conv = purple_find_conversation_with_account( | |
5018 PURPLE_CONV_TYPE_IM, sname, acct); | |
5019 if (conv == NULL) | |
5020 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, sname); | |
5021 purple_conversation_present(conv); | |
5022 | |
5023 if (message) { | |
5024 /* Spaces are encoded as '+' */ | |
5025 g_strdelimit(message, "+", ' '); | |
5026 purple_conv_send_confirm(conv, message); | |
5027 } | |
5028 } | |
5029 /* else | |
5030 **If pidgindialogs_im() was in the core, we could use it here. | |
5031 * It is all purple_request_* based, but I'm not sure it really belongs in the core | |
5032 pidgindialogs_im(); */ | |
5033 | |
5034 return TRUE; | |
5035 } | |
5036 /* ymsgr:Chat?roomname */ | |
5037 else if (!g_ascii_strcasecmp(cmd, "Chat")) { | |
5038 char *rname = NULL; | |
5039 g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &rname); | |
5040 if (rname) { | |
5041 /* This is somewhat hacky, but the params aren't useful after this command */ | |
5042 g_hash_table_insert(params, g_strdup("room"), g_strdup(rname)); | |
5043 g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat")); | |
5044 serv_join_chat(purple_account_get_connection(acct), params); | |
5045 } | |
5046 /* else | |
5047 ** Same as above (except that this would have to be re-written using purple_request_*) | |
5048 pidgin_blist_joinchat_show(); */ | |
5049 | |
5050 return TRUE; | |
5051 } | |
5052 /* ymsgr:AddFriend?name */ | |
5053 else if (!g_ascii_strcasecmp(cmd, "AddFriend")) { | |
5054 char *name = NULL; | |
5055 g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &name); | |
5056 purple_blist_request_add_buddy(acct, name, NULL, NULL); | |
5057 return TRUE; | |
5058 } | |
5059 | |
5060 return FALSE; | |
5061 } | |
5062 | |
5063 static GHashTable * | |
5064 yahoo_get_account_text_table(PurpleAccount *account) | |
5065 { | |
5066 GHashTable *table; | |
5067 table = g_hash_table_new(g_str_hash, g_str_equal); | |
5068 g_hash_table_insert(table, "login_label", (gpointer)_("Yahoo ID...")); | |
5069 return table; | |
5070 } | |
5071 | |
5072 static PurpleWhiteboardPrplOps yahoo_whiteboard_prpl_ops = | |
5073 { | |
5074 yahoo_doodle_start, | |
5075 yahoo_doodle_end, | |
5076 yahoo_doodle_get_dimensions, | |
5077 NULL, | |
5078 yahoo_doodle_get_brush, | |
5079 yahoo_doodle_set_brush, | |
5080 yahoo_doodle_send_draw_list, | |
5081 yahoo_doodle_clear, | |
5082 | |
5083 /* padding */ | |
5084 NULL, | |
5085 NULL, | |
5086 NULL, | |
5087 NULL | |
5088 }; | |
5089 | |
5090 static PurplePluginProtocolInfo prpl_info = | |
5091 { | |
5092 OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC, | |
5093 NULL, /* user_splits */ | |
5094 NULL, /* protocol_options */ | |
5095 {"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND}, | |
5096 yahoo_list_icon, | |
5097 yahoo_list_emblem, | |
5098 yahoo_status_text, | |
5099 yahoo_tooltip_text, | |
5100 yahoo_status_types, | |
5101 yahoo_blist_node_menu, | |
5102 yahoo_c_info, | |
5103 yahoo_c_info_defaults, | |
5104 yahoo_login, | |
5105 yahoo_close, | |
5106 yahoo_send_im, | |
5107 NULL, /* set info */ | |
5108 yahoo_send_typing, | |
5109 yahoo_get_info, | |
5110 yahoo_set_status, | |
5111 yahoo_set_idle, | |
5112 NULL, /* change_passwd*/ | |
5113 yahoo_add_buddy, | |
5114 NULL, /* add_buddies */ | |
5115 yahoo_remove_buddy, | |
5116 NULL, /* remove_buddies */ | |
5117 NULL, /* add_permit */ | |
5118 yahoo_add_deny, | |
5119 NULL, /* rem_permit */ | |
5120 yahoo_rem_deny, | |
5121 yahoo_set_permit_deny, | |
5122 yahoo_c_join, | |
5123 NULL, /* reject chat invite */ | |
5124 yahoo_get_chat_name, | |
5125 yahoo_c_invite, | |
5126 yahoo_c_leave, | |
5127 NULL, /* chat whisper */ | |
5128 yahoo_c_send, | |
5129 yahoo_keepalive, | |
5130 NULL, /* register_user */ | |
5131 NULL, /* get_cb_info */ | |
5132 NULL, /* get_cb_away */ | |
5133 yahoo_update_alias, /* alias_buddy */ | |
5134 yahoo_change_buddys_group, | |
5135 yahoo_rename_group, | |
5136 NULL, /* buddy_free */ | |
5137 NULL, /* convo_closed */ | |
5138 purple_normalize_nocase, /* normalize */ | |
5139 yahoo_set_buddy_icon, | |
5140 NULL, /* void (*remove_group)(PurpleConnection *gc, const char *group);*/ | |
5141 NULL, /* char *(*get_cb_real_name)(PurpleConnection *gc, int id, const char *who); */ | |
5142 NULL, /* set_chat_topic */ | |
5143 NULL, /* find_blist_chat */ | |
5144 yahoo_roomlist_get_list, | |
5145 yahoo_roomlist_cancel, | |
5146 yahoo_roomlist_expand_category, | |
5147 NULL, /* can_receive_file */ | |
5148 yahoo_send_file, | |
5149 yahoo_new_xfer, | |
5150 yahoo_offline_message, /* offline_message */ | |
5151 &yahoo_whiteboard_prpl_ops, | |
5152 NULL, /* send_raw */ | |
5153 NULL, /* roomlist_room_serialize */ | |
5154 NULL, /* unregister_user */ | |
5155 | |
5156 yahoo_send_attention, | |
5157 yahoo_attention_types, | |
5158 | |
5159 sizeof(PurplePluginProtocolInfo), /* struct_size */ | |
5160 yahoo_get_account_text_table, /* get_account_text_table */ | |
5161 NULL, /* initiate_media */ | |
5162 NULL /* can_do_media */ | |
5163 }; | |
5164 | |
5165 static PurplePluginInfo info = | |
5166 { | |
5167 PURPLE_PLUGIN_MAGIC, | |
5168 PURPLE_MAJOR_VERSION, | |
5169 PURPLE_MINOR_VERSION, | |
5170 PURPLE_PLUGIN_PROTOCOL, /**< type */ | |
5171 NULL, /**< ui_requirement */ | |
5172 0, /**< flags */ | |
5173 NULL, /**< dependencies */ | |
5174 PURPLE_PRIORITY_DEFAULT, /**< priority */ | |
5175 "prpl-yahoo", /**< id */ | |
5176 "Yahoo", /**< name */ | |
5177 DISPLAY_VERSION, /**< version */ | |
5178 /** summary */ | |
5179 N_("Yahoo Protocol Plugin"), | |
5180 /** description */ | |
5181 N_("Yahoo Protocol Plugin"), | |
5182 NULL, /**< author */ | |
5183 PURPLE_WEBSITE, /**< homepage */ | |
5184 NULL, /**< load */ | |
5185 yahoo_unload_plugin, /**< unload */ | |
5186 NULL, /**< destroy */ | |
5187 NULL, /**< ui_info */ | |
5188 &prpl_info, /**< extra_info */ | |
5189 NULL, | |
5190 yahoo_actions, | |
5191 | |
5192 /* padding */ | |
5193 NULL, | |
5194 NULL, | |
5195 NULL, | |
5196 NULL | |
5197 }; | |
5198 | |
5199 static void | |
5200 init_plugin(PurplePlugin *plugin) | |
5201 { | |
5202 PurpleAccountOption *option; | |
5203 | |
5204 option = purple_account_option_bool_new(_("Yahoo Japan"), "yahoojp", FALSE); | |
5205 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5206 | |
5207 option = purple_account_option_string_new(_("Pager server"), "server", YAHOO_PAGER_HOST); | |
5208 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5209 | |
5210 option = purple_account_option_string_new(_("Japan Pager server"), "serverjp", YAHOOJP_PAGER_HOST); | |
5211 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5212 | |
5213 option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT); | |
5214 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5215 | |
5216 option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOO_XFER_HOST); | |
5217 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5218 | |
5219 option = purple_account_option_string_new(_("Japan file transfer server"), "xferjp_host", YAHOOJP_XFER_HOST); | |
5220 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5221 | |
5222 option = purple_account_option_int_new(_("File transfer port"), "xfer_port", YAHOO_XFER_PORT); | |
5223 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5224 | |
5225 option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOO_ROOMLIST_LOCALE); | |
5226 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5227 | |
5228 option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE); | |
5229 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5230 | |
5231 option = purple_account_option_string_new(_("Encoding"), "local_charset", "ISO-8859-1"); | |
5232 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5233 | |
5234 | |
5235 #if 0 | |
5236 option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL); | |
5237 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5238 | |
5239 option = purple_account_option_string_new(_("Yahoo Chat server"), "ycht-server", YAHOO_YCHT_HOST); | |
5240 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5241 | |
5242 option = purple_account_option_int_new(_("Yahoo Chat port"), "ycht-port", YAHOO_YCHT_PORT); | |
5243 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
5244 #endif | |
5245 | |
5246 my_protocol = plugin; | |
5247 yahoopurple_register_commands(); | |
5248 yahoo_init_colorht(); | |
5249 | |
5250 purple_signal_connect(purple_get_core(), "uri-handler", plugin, | |
5251 PURPLE_CALLBACK(yahoo_uri_handler), NULL); | |
5252 } | |
5253 | |
5254 PURPLE_INIT_PLUGIN(yahoo, init_plugin, info); |