Mercurial > pidgin
annotate libgaim/protocols/yahoo/yahoo.c @ 15221:3043806ad900
[gaim-migrate @ 18011]
I think this'll fix an occasional "invalid read of size 1 bytes"
message from valgrind. I'm not sure when it happens... it seems
like it would only happen for invalid packets (ones that don't
end in 0xc0 80 or whatever it is)
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 17 Dec 2006 04:55:12 +0000 |
parents | 4bf7801a2539 |
children |
rev | line source |
---|---|
14192 | 1 /* |
2 * gaim | |
3 * | |
4 * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "debug.h" | |
32 #include "notify.h" | |
33 #include "privacy.h" | |
34 #include "prpl.h" | |
35 #include "proxy.h" | |
36 #include "request.h" | |
37 #include "server.h" | |
38 #include "util.h" | |
39 #include "version.h" | |
40 | |
41 #include "yahoo.h" | |
42 #include "yahoochat.h" | |
43 #include "yahoo_auth.h" | |
44 #include "yahoo_crypt.h" | |
45 #include "yahoo_doodle.h" | |
46 #include "yahoo_filexfer.h" | |
47 #include "yahoo_friend.h" | |
48 #include "yahoo_packet.h" | |
49 #include "yahoo_picture.h" | |
50 #include "ycht.h" | |
51 | |
52 /* #define YAHOO_DEBUG */ | |
53 | |
54 static void yahoo_add_buddy(GaimConnection *gc, GaimBuddy *, GaimGroup *); | |
14354 | 55 static void yahoo_login_page_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message); |
14192 | 56 static void yahoo_set_status(GaimAccount *account, GaimStatus *status); |
57 | |
58 static void | |
59 yahoo_add_permit(GaimConnection *gc, const char *who) | |
60 { | |
61 gaim_debug_info("yahoo", | |
62 "Permitting ID %s local contact rights for account %s\n", who, gc->account); | |
63 gaim_privacy_permit_add(gc->account,who,TRUE); | |
64 } | |
65 | |
66 static void | |
67 yahoo_rem_permit(GaimConnection *gc, const char *who) | |
68 { | |
69 gaim_debug_info("yahoo", | |
70 "Denying ID %s local contact rights for account %s\n", who, gc->account); | |
71 gaim_privacy_permit_remove(gc->account,who,TRUE); | |
72 } | |
73 | |
74 gboolean yahoo_privacy_check(GaimConnection *gc, const char *who) | |
75 { | |
76 /* returns TRUE if allowed through, FALSE otherwise */ | |
77 gboolean permitted; | |
78 | |
79 permitted = gaim_privacy_check(gc->account, who); | |
80 | |
81 /* print some debug info */ | |
82 if (!permitted) { | |
83 char *deb = NULL; | |
84 switch (gc->account->perm_deny) | |
85 { | |
86 case GAIM_PRIVACY_DENY_ALL: | |
87 deb = "GAIM_PRIVACY_DENY_ALL"; | |
88 break; | |
89 case GAIM_PRIVACY_DENY_USERS: | |
90 deb = "GAIM_PRIVACY_DENY_USERS"; | |
91 break; | |
92 case GAIM_PRIVACY_ALLOW_BUDDYLIST: | |
93 deb = "GAIM_PRIVACY_ALLOW_BUDDYLIST"; | |
94 break; | |
95 } | |
96 if(deb) | |
97 gaim_debug_info("yahoo", | |
98 "%s blocked data received from %s (%s)\n", | |
99 gc->account->username,who, deb); | |
100 } else if (gc->account->perm_deny == GAIM_PRIVACY_ALLOW_USERS) { | |
101 gaim_debug_info("yahoo", | |
102 "%s allowed data received from %s (GAIM_PRIVACY_ALLOW_USERS)\n", | |
103 gc->account->username,who); | |
104 } | |
105 | |
106 return permitted; | |
107 } | |
108 | |
109 static void yahoo_update_status(GaimConnection *gc, const char *name, YahooFriend *f) | |
110 { | |
111 char *status = NULL; | |
112 | |
113 if (!gc || !name || !f || !gaim_find_buddy(gaim_connection_get_account(gc), name)) | |
114 return; | |
115 | |
116 if (f->status == YAHOO_STATUS_OFFLINE) | |
117 { | |
118 return; | |
119 } | |
120 | |
121 switch (f->status) { | |
122 case YAHOO_STATUS_AVAILABLE: | |
123 status = YAHOO_STATUS_TYPE_AVAILABLE; | |
124 break; | |
125 case YAHOO_STATUS_BRB: | |
126 status = YAHOO_STATUS_TYPE_BRB; | |
127 break; | |
128 case YAHOO_STATUS_BUSY: | |
129 status = YAHOO_STATUS_TYPE_BUSY; | |
130 break; | |
131 case YAHOO_STATUS_NOTATHOME: | |
132 status = YAHOO_STATUS_TYPE_NOTATHOME; | |
133 break; | |
134 case YAHOO_STATUS_NOTATDESK: | |
135 status = YAHOO_STATUS_TYPE_NOTATDESK; | |
136 break; | |
137 case YAHOO_STATUS_NOTINOFFICE: | |
138 status = YAHOO_STATUS_TYPE_NOTINOFFICE; | |
139 break; | |
140 case YAHOO_STATUS_ONPHONE: | |
141 status = YAHOO_STATUS_TYPE_ONPHONE; | |
142 break; | |
143 case YAHOO_STATUS_ONVACATION: | |
144 status = YAHOO_STATUS_TYPE_ONVACATION; | |
145 break; | |
146 case YAHOO_STATUS_OUTTOLUNCH: | |
147 status = YAHOO_STATUS_TYPE_OUTTOLUNCH; | |
148 break; | |
149 case YAHOO_STATUS_STEPPEDOUT: | |
150 status = YAHOO_STATUS_TYPE_STEPPEDOUT; | |
151 break; | |
152 case YAHOO_STATUS_INVISIBLE: /* this should never happen? */ | |
153 status = YAHOO_STATUS_TYPE_INVISIBLE; | |
154 break; | |
155 case YAHOO_STATUS_CUSTOM: | |
156 case YAHOO_STATUS_IDLE: | |
157 if (!f->away) | |
158 status = YAHOO_STATUS_TYPE_AVAILABLE; | |
159 else | |
160 status = YAHOO_STATUS_TYPE_AWAY; | |
161 break; | |
162 default: | |
163 gaim_debug_warning("yahoo", "Warning, unknown status %d\n", f->status); | |
164 break; | |
165 } | |
166 | |
167 if (status) { | |
168 if (f->status == YAHOO_STATUS_CUSTOM) | |
169 gaim_prpl_got_user_status(gaim_connection_get_account(gc), name, status, "message", | |
170 yahoo_friend_get_status_message(f), NULL); | |
171 else | |
172 gaim_prpl_got_user_status(gaim_connection_get_account(gc), name, status, NULL); | |
173 } | |
174 | |
175 if (f->idle != 0) | |
176 gaim_prpl_got_user_idle(gaim_connection_get_account(gc), name, TRUE, f->idle); | |
177 else | |
178 gaim_prpl_got_user_idle(gaim_connection_get_account(gc), name, FALSE, 0); | |
179 } | |
180 | |
181 static void yahoo_process_status(GaimConnection *gc, struct yahoo_packet *pkt) | |
182 { | |
183 GaimAccount *account = gaim_connection_get_account(gc); | |
184 struct yahoo_data *yd = gc->proto_data; | |
185 GSList *l = pkt->hash; | |
186 YahooFriend *f = NULL; | |
187 char *name = NULL; | |
188 | |
189 if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { | |
190 gc->wants_to_die = TRUE; | |
191 gaim_connection_error(gc, _("You have signed on from another location.")); | |
192 return; | |
193 } | |
194 | |
195 while (l) { | |
196 struct yahoo_pair *pair = l->data; | |
197 | |
198 switch (pair->key) { | |
199 case 0: /* we won't actually do anything with this */ | |
200 break; | |
201 case 1: /* we don't get the full buddy list here. */ | |
202 if (!yd->logged_in) { | |
203 gaim_connection_set_display_name(gc, pair->value); | |
204 gaim_connection_set_state(gc, GAIM_CONNECTED); | |
205 yd->logged_in = TRUE; | |
206 if (yd->picture_upload_todo) { | |
207 yahoo_buddy_icon_upload(gc, yd->picture_upload_todo); | |
208 yd->picture_upload_todo = NULL; | |
209 } | |
210 yahoo_set_status(account, gaim_account_get_active_status(account)); | |
211 | |
212 /* this requests the list. i have a feeling that this is very evil | |
213 * | |
214 * scs.yahoo.com sends you the list before this packet without it being | |
215 * requested | |
216 * | |
217 * do_import(gc, NULL); | |
218 * newpkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_OFFLINE, 0); | |
219 * yahoo_packet_send_and_free(newpkt, yd); | |
220 */ | |
221 | |
222 } | |
223 break; | |
224 case 8: /* how many online buddies we have */ | |
225 break; | |
226 case 7: /* the current buddy */ | |
227 if (name && f) /* update the previous buddy before changing the variables */ | |
228 yahoo_update_status(gc, name, f); | |
229 name = pair->value; | |
230 if (name && g_utf8_validate(name, -1, NULL)) | |
231 f = yahoo_friend_find_or_new(gc, name); | |
232 else { | |
233 f = NULL; | |
234 name = NULL; | |
235 } | |
236 break; | |
237 case 10: /* state */ | |
238 if (!f) | |
239 break; | |
240 | |
241 f->status = strtol(pair->value, NULL, 10); | |
242 if ((f->status >= YAHOO_STATUS_BRB) && (f->status <= YAHOO_STATUS_STEPPEDOUT)) | |
243 f->away = 1; | |
244 else | |
245 f->away = 0; | |
246 | |
247 if (f->status == YAHOO_STATUS_IDLE) { | |
248 /* Idle may have already been set in a more precise way in case 137 */ | |
249 if (f->idle == 0) | |
250 f->idle = time(NULL); | |
251 } else | |
252 f->idle = 0; | |
253 | |
254 if (f->status != YAHOO_STATUS_CUSTOM) | |
255 yahoo_friend_set_status_message(f, NULL); | |
256 | |
257 f->sms = 0; | |
258 break; | |
259 case 19: /* custom message */ | |
260 if (f) | |
261 yahoo_friend_set_status_message(f, yahoo_string_decode(gc, pair->value, FALSE)); | |
262 break; | |
263 case 11: /* this is the buddy's session id */ | |
264 break; | |
265 case 17: /* in chat? */ | |
266 break; | |
267 case 47: /* is custom status away or not? 2=idle*/ | |
268 if (!f) | |
269 break; | |
270 | |
271 /* I have no idea what it means when this is | |
272 * set when someone's available, but it doesn't | |
273 * mean idle. */ | |
274 if (f->status == YAHOO_STATUS_AVAILABLE) | |
275 break; | |
276 | |
277 f->away = strtol(pair->value, NULL, 10); | |
278 if (f->away == 2) { | |
279 /* Idle may have already been set in a more precise way in case 137 */ | |
280 if (f->idle == 0) | |
281 f->idle = time(NULL); | |
282 } | |
283 | |
284 break; | |
285 case 138: /* either we're not idle, or we are but won't say how long */ | |
286 if (!f) | |
287 break; | |
288 | |
289 if (f->idle) | |
290 f->idle = -1; | |
291 break; | |
292 case 137: /* usually idle time in seconds, sometimes login time */ | |
293 if (!f) | |
294 break; | |
295 | |
296 if (f->status != YAHOO_STATUS_AVAILABLE) | |
297 f->idle = time(NULL) - strtol(pair->value, NULL, 10); | |
298 break; | |
299 case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ | |
300 if (strtol(pair->value, NULL, 10) == 0) { | |
301 if (f) | |
302 f->status = YAHOO_STATUS_OFFLINE; | |
14304 | 303 if (name) |
304 gaim_prpl_got_user_status(account, name, "offline", NULL); | |
14192 | 305 break; |
306 } | |
307 break; | |
308 case 60: /* SMS */ | |
309 if (f) { | |
310 f->sms = strtol(pair->value, NULL, 10); | |
311 yahoo_update_status(gc, name, f); | |
312 } | |
313 break; | |
314 case 197: /* Avatars */ | |
315 { | |
316 guchar *decoded; | |
317 char *tmp; | |
318 gsize len; | |
319 | |
320 if (pair->value) { | |
321 decoded = gaim_base64_decode(pair->value, &len); | |
322 if (len) { | |
323 tmp = gaim_str_binary_to_ascii(decoded, len); | |
324 gaim_debug_info("yahoo", "Got key 197, value = %s\n", tmp); | |
325 g_free(tmp); | |
326 } | |
327 g_free(decoded); | |
328 } | |
329 break; | |
330 } | |
331 case 192: /* Pictures, aka Buddy Icons, checksum */ | |
332 { | |
333 int cksum = strtol(pair->value, NULL, 10); | |
334 GaimBuddy *b; | |
335 | |
336 if (!name) | |
337 break; | |
338 | |
339 b = gaim_find_buddy(gc->account, name); | |
340 | |
341 if (!cksum || (cksum == -1)) { | |
342 if (f) | |
343 yahoo_friend_set_buddy_icon_need_request(f, TRUE); | |
344 gaim_buddy_icons_set_for_user(gc->account, name, NULL, 0); | |
345 if (b) | |
346 gaim_blist_node_remove_setting((GaimBlistNode *)b, YAHOO_ICON_CHECKSUM_KEY); | |
347 break; | |
348 } | |
349 | |
350 if (!f) | |
351 break; | |
352 | |
353 yahoo_friend_set_buddy_icon_need_request(f, FALSE); | |
354 if (b && cksum != gaim_blist_node_get_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY)) | |
355 yahoo_send_picture_request(gc, name); | |
356 | |
357 break; | |
358 } | |
359 case 16: /* Custom error message */ | |
360 { | |
361 char *tmp = yahoo_string_decode(gc, pair->value, TRUE); | |
362 gaim_notify_error(gc, NULL, tmp, NULL); | |
363 g_free(tmp); | |
364 } | |
365 break; | |
366 default: | |
367 gaim_debug(GAIM_DEBUG_ERROR, "yahoo", | |
368 "Unknown status key %d\n", pair->key); | |
369 break; | |
370 } | |
371 | |
372 l = l->next; | |
373 } | |
374 | |
375 if (name && f) /* update the last buddy */ | |
376 yahoo_update_status(gc, name, f); | |
377 } | |
378 | |
379 static void yahoo_do_group_check(GaimAccount *account, GHashTable *ht, const char *name, const char *group) | |
380 { | |
381 GaimBuddy *b; | |
382 GaimGroup *g; | |
383 GSList *list, *i; | |
384 gboolean onlist = 0; | |
385 char *oname = NULL; | |
386 char **oname_p = &oname; | |
387 GSList **list_p = &list; | |
388 | |
389 if (!g_hash_table_lookup_extended(ht, gaim_normalize(account, name), (gpointer *) oname_p, (gpointer *) list_p)) | |
390 list = gaim_find_buddies(account, name); | |
391 else | |
392 g_hash_table_steal(ht, name); | |
393 | |
394 for (i = list; i; i = i->next) { | |
395 b = i->data; | |
396 g = gaim_buddy_get_group(b); | |
397 if (!gaim_utf8_strcasecmp(group, g->name)) { | |
398 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
399 "Oh good, %s is in the right group (%s).\n", name, group); | |
400 list = g_slist_delete_link(list, i); | |
401 onlist = 1; | |
402 break; | |
403 } | |
404 } | |
405 | |
406 if (!onlist) { | |
407 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
408 "Uhoh, %s isn't on the list (or not in this group), adding him to group %s.\n", name, group); | |
409 if (!(g = gaim_find_group(group))) { | |
410 g = gaim_group_new(group); | |
411 gaim_blist_add_group(g, NULL); | |
412 } | |
413 b = gaim_buddy_new(account, name, NULL); | |
414 gaim_blist_add_buddy(b, NULL, g, NULL); | |
415 } | |
416 | |
417 if (list) { | |
418 if (!oname) | |
419 oname = g_strdup(gaim_normalize(account, name)); | |
420 g_hash_table_insert(ht, oname, list); | |
421 } else if (oname) | |
422 g_free(oname); | |
423 } | |
424 | |
425 static void yahoo_do_group_cleanup(gpointer key, gpointer value, gpointer user_data) | |
426 { | |
427 char *name = key; | |
428 GSList *list = value, *i; | |
429 GaimBuddy *b; | |
430 GaimGroup *g; | |
431 | |
432 for (i = list; i; i = i->next) { | |
433 b = i->data; | |
434 g = gaim_buddy_get_group(b); | |
435 gaim_debug(GAIM_DEBUG_MISC, "yahoo", "Deleting Buddy %s from group %s.\n", name, g->name); | |
436 gaim_blist_remove_buddy(b); | |
437 } | |
438 } | |
439 | |
440 static char *_getcookie(char *rawcookie) | |
441 { | |
442 char *cookie = NULL; | |
443 char *tmpcookie; | |
444 char *cookieend; | |
445 | |
446 if (strlen(rawcookie) < 2) | |
447 return NULL; | |
448 tmpcookie = g_strdup(rawcookie+2); | |
449 cookieend = strchr(tmpcookie, ';'); | |
450 | |
451 if (cookieend) | |
452 *cookieend = '\0'; | |
453 | |
454 cookie = g_strdup(tmpcookie); | |
455 g_free(tmpcookie); | |
456 | |
457 return cookie; | |
458 } | |
459 | |
460 static void yahoo_process_cookie(struct yahoo_data *yd, char *c) | |
461 { | |
462 if (c[0] == 'Y') { | |
463 if (yd->cookie_y) | |
464 g_free(yd->cookie_y); | |
465 yd->cookie_y = _getcookie(c); | |
466 } else if (c[0] == 'T') { | |
467 if (yd->cookie_t) | |
468 g_free(yd->cookie_t); | |
469 yd->cookie_t = _getcookie(c); | |
470 } | |
471 } | |
472 | |
14258 | 473 static void yahoo_process_list_15(GaimConnection *gc, struct yahoo_packet *pkt) |
474 { | |
475 GSList *l = pkt->hash; | |
476 | |
477 GaimAccount *account = gaim_connection_get_account(gc); | |
478 GHashTable *ht; | |
479 char *grp = NULL; | |
480 char *norm_bud = NULL; | |
14300 | 481 YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */ |
482 /* But what if you had no friends? */ | |
483 GaimBuddy *b; | |
484 GaimGroup *g; | |
485 | |
14258 | 486 |
487 ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free); | |
488 | |
489 while (l) { | |
490 struct yahoo_pair *pair = l->data; | |
491 l = l->next; | |
492 | |
493 switch (pair->key) { | |
14637
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
494 case 302: |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
495 /* This is always 318 before a group, 319 before the first s/n in a group, 320 before any ignored s/n. |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
496 * It is not sent for s/n's in a group after the first. |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
497 * All ignored s/n's are listed last, so when we see a 320 we clear the group and begin marking the |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
498 * s/n's as ignored. It is always followed by an identical 300 key. |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
499 */ |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
500 if (pair->value && !strcmp(pair->value, "320")) { |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
501 /* No longer in any group; this indicates the start of the ignore list. */ |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
502 g_free(grp); |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
503 grp = NULL; |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
504 } |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
505 |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
506 break; |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
507 case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */ |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
508 break; |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
509 case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */ |
14258 | 510 break; |
511 case 65: /* This is the group */ | |
512 g_free(grp); | |
513 grp = yahoo_string_decode(gc, pair->value, FALSE); | |
514 break; | |
515 case 7: /* buddy's s/n */ | |
516 g_free(norm_bud); | |
517 norm_bud = g_strdup(gaim_normalize(account, pair->value)); | |
14637
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
518 |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
519 if (grp) { |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
520 /* This buddy is in a group */ |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
521 f = yahoo_friend_find_or_new(gc, norm_bud); |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
522 if (!(b = gaim_find_buddy(account, norm_bud))) { |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
523 if (!(g = gaim_find_group(grp))) { |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
524 g = gaim_group_new(grp); |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
525 gaim_blist_add_group(g, NULL); |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
526 } |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
527 b = gaim_buddy_new(account, norm_bud, NULL); |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
528 gaim_blist_add_buddy(b, NULL, g, NULL); |
14258 | 529 } |
14637
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
530 yahoo_do_group_check(account, ht, norm_bud, grp); |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
531 |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
532 } else { |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
533 /* This buddy is on the ignore list (and therefore in no group) */ |
c811cfc944d1
[gaim-migrate @ 17383]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14631
diff
changeset
|
534 gaim_privacy_deny_add(account, norm_bud, 1); |
14258 | 535 } |
536 break; | |
14284 | 537 case 241: /* another protocol user */ |
14300 | 538 if (f) { |
14284 | 539 f->protocol = strtol(pair->value, NULL, 10); |
14300 | 540 gaim_debug_info("yahoo", "Setting protocol to %d\n", f->protocol); |
541 } | |
14258 | 542 break; |
543 /* case 242: */ /* this seems related to 241 */ | |
544 /* break; */ | |
545 } | |
546 } | |
547 | |
548 g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); | |
549 g_hash_table_destroy(ht); | |
550 g_free(grp); | |
551 g_free(norm_bud); | |
552 } | |
553 | |
14192 | 554 static void yahoo_process_list(GaimConnection *gc, struct yahoo_packet *pkt) |
555 { | |
556 GSList *l = pkt->hash; | |
557 gboolean export = FALSE; | |
558 gboolean got_serv_list = FALSE; | |
559 GaimBuddy *b; | |
560 GaimGroup *g; | |
561 YahooFriend *f = NULL; | |
562 GaimAccount *account = gaim_connection_get_account(gc); | |
563 struct yahoo_data *yd = gc->proto_data; | |
564 GHashTable *ht; | |
565 | |
566 char **lines; | |
567 char **split; | |
568 char **buddies; | |
569 char **tmp, **bud, *norm_bud; | |
570 char *grp = NULL; | |
571 | |
572 if (pkt->id) | |
573 yd->session_id = pkt->id; | |
574 | |
575 while (l) { | |
576 struct yahoo_pair *pair = l->data; | |
577 l = l->next; | |
578 | |
579 switch (pair->key) { | |
580 case 87: | |
581 if (!yd->tmp_serv_blist) | |
582 yd->tmp_serv_blist = g_string_new(pair->value); | |
583 else | |
584 g_string_append(yd->tmp_serv_blist, pair->value); | |
585 break; | |
586 case 88: | |
587 if (!yd->tmp_serv_ilist) | |
588 yd->tmp_serv_ilist = g_string_new(pair->value); | |
589 else | |
590 g_string_append(yd->tmp_serv_ilist, pair->value); | |
591 break; | |
592 case 59: /* cookies, yum */ | |
593 yahoo_process_cookie(yd, pair->value); | |
594 break; | |
595 case YAHOO_SERVICE_PRESENCE_PERM: | |
596 if (!yd->tmp_serv_plist) | |
597 yd->tmp_serv_plist = g_string_new(pair->value); | |
598 else | |
599 g_string_append(yd->tmp_serv_plist, pair->value); | |
600 break; | |
601 } | |
602 } | |
603 | |
604 if (pkt->status != 0) | |
605 return; | |
606 | |
607 if (yd->tmp_serv_blist) { | |
608 ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free); | |
609 | |
610 lines = g_strsplit(yd->tmp_serv_blist->str, "\n", -1); | |
611 for (tmp = lines; *tmp; tmp++) { | |
612 split = g_strsplit(*tmp, ":", 2); | |
613 if (!split) | |
614 continue; | |
615 if (!split[0] || !split[1]) { | |
616 g_strfreev(split); | |
617 continue; | |
618 } | |
619 grp = yahoo_string_decode(gc, split[0], FALSE); | |
620 buddies = g_strsplit(split[1], ",", -1); | |
621 for (bud = buddies; bud && *bud; bud++) { | |
622 norm_bud = g_strdup(gaim_normalize(account, *bud)); | |
623 f = yahoo_friend_find_or_new(gc, norm_bud); | |
624 | |
625 if (!(b = gaim_find_buddy(account, norm_bud))) { | |
626 if (!(g = gaim_find_group(grp))) { | |
627 g = gaim_group_new(grp); | |
628 gaim_blist_add_group(g, NULL); | |
629 } | |
630 b = gaim_buddy_new(account, norm_bud, NULL); | |
631 gaim_blist_add_buddy(b, NULL, g, NULL); | |
632 export = TRUE; | |
633 } | |
634 | |
635 yahoo_do_group_check(account, ht, norm_bud, grp); | |
636 g_free(norm_bud); | |
637 } | |
638 g_strfreev(buddies); | |
639 g_strfreev(split); | |
640 g_free(grp); | |
641 } | |
642 g_strfreev(lines); | |
643 | |
644 g_string_free(yd->tmp_serv_blist, TRUE); | |
645 yd->tmp_serv_blist = NULL; | |
646 g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); | |
647 g_hash_table_destroy(ht); | |
648 } | |
649 | |
650 if (yd->tmp_serv_ilist) { | |
651 buddies = g_strsplit(yd->tmp_serv_ilist->str, ",", -1); | |
652 for (bud = buddies; bud && *bud; bud++) { | |
653 /* The server is already ignoring the user */ | |
654 got_serv_list = TRUE; | |
655 gaim_privacy_deny_add(gc->account, *bud, 1); | |
656 } | |
657 g_strfreev(buddies); | |
658 | |
659 g_string_free(yd->tmp_serv_ilist, TRUE); | |
660 yd->tmp_serv_ilist = NULL; | |
661 } | |
662 | |
663 if (got_serv_list && | |
664 ((gc->account->perm_deny != GAIM_PRIVACY_ALLOW_BUDDYLIST) && | |
665 (gc->account->perm_deny != GAIM_PRIVACY_DENY_ALL) && | |
666 (gc->account->perm_deny != GAIM_PRIVACY_ALLOW_USERS))) | |
667 { | |
668 gc->account->perm_deny = GAIM_PRIVACY_DENY_USERS; | |
669 gaim_debug_info("yahoo", "%s privacy defaulting to GAIM_PRIVACY_DENY_USERS.\n", | |
670 gc->account->username); | |
671 } | |
672 | |
673 if (yd->tmp_serv_plist) { | |
674 buddies = g_strsplit(yd->tmp_serv_plist->str, ",", -1); | |
675 for (bud = buddies; bud && *bud; bud++) { | |
676 f = yahoo_friend_find(gc, *bud); | |
677 if (f) { | |
678 gaim_debug_info("yahoo", "%s setting presence for %s to PERM_OFFLINE\n", | |
679 gc->account->username, *bud); | |
680 f->presence = YAHOO_PRESENCE_PERM_OFFLINE; | |
681 } | |
682 } | |
683 g_strfreev(buddies); | |
684 g_string_free(yd->tmp_serv_plist, TRUE); | |
685 yd->tmp_serv_plist = NULL; | |
686 | |
687 } | |
688 } | |
689 | |
690 static void yahoo_process_notify(GaimConnection *gc, struct yahoo_packet *pkt) | |
691 { | |
692 char *msg = NULL; | |
693 char *from = NULL; | |
694 char *stat = NULL; | |
695 char *game = NULL; | |
696 YahooFriend *f = NULL; | |
697 GSList *l = pkt->hash; | |
698 | |
699 while (l) { | |
700 struct yahoo_pair *pair = l->data; | |
701 if (pair->key == 4) | |
702 from = pair->value; | |
703 if (pair->key == 49) | |
704 msg = pair->value; | |
705 if (pair->key == 13) | |
706 stat = pair->value; | |
707 if (pair->key == 14) | |
708 game = pair->value; | |
709 l = l->next; | |
710 } | |
711 | |
712 if (!from || !msg) | |
713 return; | |
714 | |
715 if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")) | |
716 && (yahoo_privacy_check(gc, from))) { | |
717 if (*stat == '1') | |
718 serv_got_typing(gc, from, 0, GAIM_TYPING); | |
719 else | |
720 serv_got_typing_stopped(gc, from); | |
721 } else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) { | |
722 GaimBuddy *bud = gaim_find_buddy(gc->account, from); | |
723 | |
724 if (!bud) { | |
725 gaim_debug(GAIM_DEBUG_WARNING, "yahoo", | |
726 "%s is playing a game, and doesn't want " | |
727 "you to know.\n", from); | |
728 } | |
729 | |
730 f = yahoo_friend_find(gc, from); | |
731 if (!f) | |
732 return; /* if they're not on the list, don't bother */ | |
733 | |
734 yahoo_friend_set_game(f, NULL); | |
735 | |
736 if (*stat == '1') { | |
737 yahoo_friend_set_game(f, game); | |
738 if (bud) | |
739 yahoo_update_status(gc, from, f); | |
740 } | |
741 } | |
742 } | |
743 | |
744 | |
745 struct _yahoo_im { | |
746 char *from; | |
747 int time; | |
748 int utf8; | |
749 int buddy_icon; | |
750 char *msg; | |
751 }; | |
752 | |
753 static void yahoo_process_message(GaimConnection *gc, struct yahoo_packet *pkt) | |
754 { | |
755 struct yahoo_data *yd = gc->proto_data; | |
756 GSList *l = pkt->hash; | |
757 GSList *list = NULL; | |
758 struct _yahoo_im *im = NULL; | |
759 | |
760 const char *imv = NULL; | |
761 | |
762 if (pkt->status <= 1 || pkt->status == 5) { | |
763 while (l != NULL) { | |
764 struct yahoo_pair *pair = l->data; | |
765 if (pair->key == 4) { | |
766 im = g_new0(struct _yahoo_im, 1); | |
767 list = g_slist_append(list, im); | |
768 im->from = pair->value; | |
769 im->time = time(NULL); | |
770 } | |
771 if (pair->key == 97) | |
772 if (im) | |
773 im->utf8 = strtol(pair->value, NULL, 10); | |
774 if (pair->key == 15) | |
775 if (im) | |
776 im->time = strtol(pair->value, NULL, 10); | |
777 if (pair->key == 206) | |
778 if (im) | |
779 im->buddy_icon = strtol(pair->value, NULL, 10); | |
780 if (pair->key == 14) { | |
781 if (im) | |
782 im->msg = pair->value; | |
783 } | |
784 /* IMV key */ | |
785 if (pair->key == 63) | |
786 { | |
787 imv = pair->value; | |
788 } | |
789 l = l->next; | |
790 } | |
791 } else if (pkt->status == 2) { | |
792 gaim_notify_error(gc, NULL, | |
793 _("Your Yahoo! message did not get sent."), NULL); | |
794 } | |
795 | |
796 /** TODO: It seems that this check should be per IM, not global */ | |
797 /* Check for the Doodle IMV */ | |
798 if (im != NULL && imv!= NULL && im->from != NULL) | |
799 { | |
800 g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv)); | |
801 | |
802 if (strcmp(imv, "doodle;11") == 0) | |
803 { | |
804 GaimWhiteboard *wb; | |
805 | |
806 if (!yahoo_privacy_check(gc, im->from)) { | |
807 gaim_debug_info("yahoo", "Doodle request from %s dropped.\n", im->from); | |
808 return; | |
809 } | |
810 | |
811 wb = gaim_whiteboard_get_session(gc->account, im->from); | |
812 | |
813 /* If a Doodle session doesn't exist between this user */ | |
814 if(wb == NULL) | |
815 { | |
816 wb = gaim_whiteboard_create(gc->account, im->from, DOODLE_STATE_REQUESTED); | |
817 | |
818 yahoo_doodle_command_send_request(gc, im->from); | |
819 yahoo_doodle_command_send_ready(gc, im->from); | |
820 } | |
821 } | |
822 } | |
823 | |
824 for (l = list; l; l = l->next) { | |
825 YahooFriend *f; | |
826 char *m, *m2; | |
827 im = l->data; | |
828 | |
829 if (!im->from || !im->msg) { | |
830 g_free(im); | |
831 continue; | |
832 } | |
833 | |
834 if (!yahoo_privacy_check(gc, im->from)) { | |
835 gaim_debug_info("yahoo", "Message from %s dropped.\n", im->from); | |
836 return; | |
837 } | |
838 | |
839 m = yahoo_string_decode(gc, im->msg, im->utf8); | |
840 /* This may actually not be necessary, but it appears | |
841 * that at least at one point some clients were sending | |
842 * "\r\n" as line delimiters, so we want to avoid double | |
843 * lines. */ | |
844 m2 = gaim_strreplace(m, "\r\n", "\n"); | |
845 g_free(m); | |
846 m = m2; | |
847 gaim_util_chrreplace(m, '\r', '\n'); | |
848 | |
849 if (!strcmp(m, "<ding>")) { | |
850 GaimConversation *c = gaim_conversation_new(GAIM_CONV_TYPE_IM, | |
851 gaim_connection_get_account(gc), im->from); | |
852 gaim_conv_im_write(GAIM_CONV_IM(c), "", _("Buzz!!"), GAIM_MESSAGE_NICK|GAIM_MESSAGE_RECV, | |
853 im->time); | |
854 g_free(m); | |
855 g_free(im); | |
856 continue; | |
857 } | |
858 | |
859 m2 = yahoo_codes_to_html(m); | |
860 g_free(m); | |
861 serv_got_im(gc, im->from, m2, 0, im->time); | |
862 g_free(m2); | |
863 | |
864 if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) { | |
865 if (yahoo_friend_get_buddy_icon_need_request(f)) { | |
866 yahoo_send_picture_request(gc, im->from); | |
867 yahoo_friend_set_buddy_icon_need_request(f, FALSE); | |
868 } | |
869 } | |
870 | |
871 g_free(im); | |
872 } | |
873 g_slist_free(list); | |
874 } | |
875 | |
876 static void yahoo_process_sysmessage(GaimConnection *gc, struct yahoo_packet *pkt) | |
877 { | |
878 GSList *l = pkt->hash; | |
879 char *prim, *me = NULL, *msg = NULL, *escmsg = NULL; | |
880 | |
881 while (l) { | |
882 struct yahoo_pair *pair = l->data; | |
883 | |
884 if (pair->key == 5) | |
885 me = pair->value; | |
886 if (pair->key == 14) | |
887 msg = pair->value; | |
888 | |
889 l = l->next; | |
890 } | |
891 | |
892 if (!msg || !g_utf8_validate(msg, -1, NULL)) | |
893 return; | |
894 | |
895 /* TODO: Does this really need to be escaped? It seems like it doesn't. */ | |
896 escmsg = g_markup_escape_text(msg, -1); | |
897 | |
898 prim = g_strdup_printf(_("Yahoo! system message for %s:"), | |
899 me?me:gaim_connection_get_display_name(gc)); | |
900 gaim_notify_info(NULL, NULL, prim, escmsg); | |
901 g_free(prim); | |
902 g_free(escmsg); | |
903 } | |
904 | |
905 struct yahoo_add_request { | |
906 GaimConnection *gc; | |
907 char *id; | |
908 char *who; | |
909 char *msg; | |
910 }; | |
911 | |
912 static void | |
15057 | 913 yahoo_buddy_add_authorize_cb(struct yahoo_add_request *add_req) { |
14192 | 914 g_free(add_req->id); |
915 g_free(add_req->who); | |
916 g_free(add_req->msg); | |
917 g_free(add_req); | |
918 } | |
919 | |
920 static void | |
921 yahoo_buddy_add_deny_cb(struct yahoo_add_request *add_req, const char *msg) { | |
922 struct yahoo_packet *pkt; | |
923 char *encoded_msg = NULL; | |
924 struct yahoo_data *yd = add_req->gc->proto_data; | |
925 | |
926 if (msg) | |
927 encoded_msg = yahoo_string_encode(add_req->gc, msg, NULL); | |
928 | |
929 pkt = yahoo_packet_new(YAHOO_SERVICE_REJECTCONTACT, | |
930 YAHOO_STATUS_AVAILABLE, 0); | |
931 | |
932 yahoo_packet_hash(pkt, "sss", | |
933 1, gaim_normalize(add_req->gc->account, | |
934 gaim_account_get_username( | |
935 gaim_connection_get_account( | |
936 add_req->gc))), | |
937 7, add_req->who, | |
938 14, encoded_msg ? encoded_msg : ""); | |
939 | |
940 yahoo_packet_send_and_free(pkt, yd); | |
941 | |
942 g_free(encoded_msg); | |
943 | |
944 g_free(add_req->id); | |
945 g_free(add_req->who); | |
946 g_free(add_req->msg); | |
947 g_free(add_req); | |
948 } | |
949 | |
15057 | 950 static void |
951 yahoo_buddy_add_deny_noreason_cb(struct yahoo_add_request *add_req, const char*msg) | |
952 { | |
953 yahoo_buddy_add_deny_cb(add_req, NULL); | |
954 } | |
955 | |
956 static void | |
957 yahoo_buddy_add_deny_reason_cb(struct yahoo_add_request *add_req) { | |
958 gaim_request_input(add_req->gc, NULL, _("Authorization denied message:"), | |
959 NULL, _("No reason given."), TRUE, FALSE, NULL, | |
960 _("OK"), G_CALLBACK(yahoo_buddy_add_deny_cb), | |
961 _("Cancel"), G_CALLBACK(yahoo_buddy_add_deny_noreason_cb), add_req); | |
962 } | |
963 | |
14192 | 964 static void yahoo_buddy_added_us(GaimConnection *gc, struct yahoo_packet *pkt) { |
965 struct yahoo_add_request *add_req; | |
966 char *msg = NULL; | |
967 GSList *l = pkt->hash; | |
968 | |
969 add_req = g_new0(struct yahoo_add_request, 1); | |
970 add_req->gc = gc; | |
971 | |
972 while (l) { | |
973 struct yahoo_pair *pair = l->data; | |
974 | |
975 switch (pair->key) { | |
976 case 1: | |
977 add_req->id = g_strdup(pair->value); | |
978 break; | |
979 case 3: | |
980 add_req->who = g_strdup(pair->value); | |
981 break; | |
982 case 15: /* time, for when they add us and we're offline */ | |
983 break; | |
984 case 14: | |
985 msg = pair->value; | |
986 break; | |
987 } | |
988 l = l->next; | |
989 } | |
990 | |
991 if (add_req->id) { | |
992 if (msg) | |
993 add_req->msg = yahoo_string_decode(gc, msg, FALSE); | |
994 | |
15057 | 995 /* DONE! this is almost exactly the same as what MSN does, |
14192 | 996 * this should probably be moved to the core. |
997 */ | |
15057 | 998 gaim_account_request_authorization(gaim_connection_get_account(gc), add_req->who, add_req->id, |
15142 | 999 NULL, add_req->msg, gaim_find_buddy(gaim_connection_get_account(gc),add_req->who) != NULL, |
15135 | 1000 G_CALLBACK(yahoo_buddy_add_authorize_cb), |
15057 | 1001 G_CALLBACK(yahoo_buddy_add_deny_reason_cb), |
1002 add_req); | |
14192 | 1003 } else { |
1004 g_free(add_req->id); | |
1005 g_free(add_req->who); | |
1006 /*g_free(add_req->msg);*/ | |
1007 g_free(add_req); | |
1008 } | |
1009 } | |
1010 | |
1011 static void yahoo_buddy_denied_our_add(GaimConnection *gc, struct yahoo_packet *pkt) | |
1012 { | |
1013 char *who = NULL; | |
1014 char *msg = NULL; | |
1015 GSList *l = pkt->hash; | |
1016 GString *buf = NULL; | |
1017 struct yahoo_data *yd = gc->proto_data; | |
1018 | |
1019 while (l) { | |
1020 struct yahoo_pair *pair = l->data; | |
1021 | |
1022 switch (pair->key) { | |
1023 case 3: | |
1024 who = pair->value; | |
1025 break; | |
1026 case 14: | |
1027 msg = pair->value; | |
1028 break; | |
1029 } | |
1030 l = l->next; | |
1031 } | |
1032 | |
1033 if (who) { | |
1034 char *msg2; | |
1035 buf = g_string_sized_new(0); | |
1036 if (!msg) { | |
1037 g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list."), who); | |
1038 } else { | |
1039 msg2 = yahoo_string_decode(gc, msg, FALSE); | |
1040 g_string_printf(buf, _("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg2); | |
1041 g_free(msg2); | |
1042 } | |
1043 gaim_notify_info(gc, NULL, _("Add buddy rejected"), buf->str); | |
1044 g_string_free(buf, TRUE); | |
1045 g_hash_table_remove(yd->friends, who); | |
1046 gaim_prpl_got_user_status(gaim_connection_get_account(gc), who, "offline", NULL); /* FIXME: make this set not on list status instead */ | |
1047 /* TODO: Shouldn't we remove the buddy from our local list? */ | |
1048 } | |
1049 } | |
1050 | |
1051 static void yahoo_process_contact(GaimConnection *gc, struct yahoo_packet *pkt) | |
1052 { | |
1053 switch (pkt->status) { | |
1054 case 1: | |
1055 yahoo_process_status(gc, pkt); | |
1056 return; | |
1057 case 3: | |
1058 yahoo_buddy_added_us(gc, pkt); | |
1059 break; | |
1060 case 7: | |
1061 yahoo_buddy_denied_our_add(gc, pkt); | |
1062 break; | |
1063 default: | |
1064 break; | |
1065 } | |
1066 } | |
1067 | |
1068 #define OUT_CHARSET "utf-8" | |
1069 | |
1070 static char *yahoo_decode(const char *text) | |
1071 { | |
1072 char *converted = NULL; | |
1073 char *n, *new; | |
1074 const char *end, *p; | |
1075 int i, k; | |
1076 | |
1077 n = new = g_malloc(strlen (text) + 1); | |
1078 end = text + strlen(text); | |
1079 | |
1080 for (p = text; p < end; p++, n++) { | |
1081 if (*p == '\\') { | |
1082 if (p[1] >= '0' && p[1] <= '7') { | |
1083 p += 1; | |
1084 for (i = 0, k = 0; k < 3; k += 1) { | |
1085 char c = p[k]; | |
1086 if (c < '0' || c > '7') break; | |
1087 i *= 8; | |
1088 i += c - '0'; | |
1089 } | |
1090 *n = i; | |
1091 p += k - 1; | |
1092 } else { /* bug 959248 */ | |
1093 /* If we see a \ not followed by an octal number, | |
1094 * it means that it is actually a \\ with one \ | |
1095 * already eaten by some unknown function. | |
1096 * This is arguably broken. | |
1097 * | |
1098 * I think wing is wrong here, there is no function | |
1099 * called that I see that could have done it. I guess | |
1100 * it is just really sending single \'s. That's yahoo | |
1101 * for you. | |
1102 */ | |
1103 *n = *p; | |
1104 } | |
1105 } | |
1106 else | |
1107 *n = *p; | |
1108 } | |
1109 | |
1110 *n = '\0'; | |
1111 | |
1112 if (strstr(text, "\033$B")) | |
1113 converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL); | |
1114 if (!converted) | |
1115 converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL); | |
1116 g_free(new); | |
1117 | |
1118 return converted; | |
1119 } | |
1120 | |
1121 static void yahoo_process_mail(GaimConnection *gc, struct yahoo_packet *pkt) | |
1122 { | |
1123 GaimAccount *account = gaim_connection_get_account(gc); | |
1124 struct yahoo_data *yd = gc->proto_data; | |
1125 char *who = NULL; | |
1126 char *email = NULL; | |
1127 char *subj = NULL; | |
1128 char *yahoo_mail_url = (yd->jp? YAHOOJP_MAIL_URL: YAHOO_MAIL_URL); | |
1129 int count = 0; | |
1130 GSList *l = pkt->hash; | |
1131 | |
1132 if (!gaim_account_get_check_mail(account)) | |
1133 return; | |
1134 | |
1135 while (l) { | |
1136 struct yahoo_pair *pair = l->data; | |
1137 if (pair->key == 9) | |
1138 count = strtol(pair->value, NULL, 10); | |
1139 else if (pair->key == 43) | |
1140 who = pair->value; | |
1141 else if (pair->key == 42) | |
1142 email = pair->value; | |
1143 else if (pair->key == 18) | |
1144 subj = pair->value; | |
1145 l = l->next; | |
1146 } | |
1147 | |
1148 if (who && subj && email && *email) { | |
1149 char *dec_who = yahoo_decode(who); | |
1150 char *dec_subj = yahoo_decode(subj); | |
1151 char *from = g_strdup_printf("%s (%s)", dec_who, email); | |
1152 | |
1153 gaim_notify_email(gc, dec_subj, from, gaim_account_get_username(account), | |
1154 yahoo_mail_url, NULL, NULL); | |
1155 | |
1156 g_free(dec_who); | |
1157 g_free(dec_subj); | |
1158 g_free(from); | |
1159 } else if (count > 0) { | |
1160 const char *to = gaim_account_get_username(account); | |
1161 const char *url = yahoo_mail_url; | |
1162 | |
1163 gaim_notify_emails(gc, count, FALSE, NULL, NULL, &to, &url, | |
1164 NULL, NULL); | |
1165 } | |
1166 } | |
1167 /* This is the y64 alphabet... it's like base64, but has a . and a _ */ | |
14842 | 1168 static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; |
14192 | 1169 |
1170 /* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function | |
1171 * in util.c, but it has a bug I don't feel like finding right now ;) */ | |
1172 static void to_y64(char *out, const unsigned char *in, gsize inlen) | |
1173 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ | |
1174 { | |
1175 for (; inlen >= 3; inlen -= 3) | |
1176 { | |
1177 *out++ = base64digits[in[0] >> 2]; | |
1178 *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; | |
1179 *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; | |
1180 *out++ = base64digits[in[2] & 0x3f]; | |
1181 in += 3; | |
1182 } | |
1183 if (inlen > 0) | |
1184 { | |
1185 unsigned char fragment; | |
1186 | |
1187 *out++ = base64digits[in[0] >> 2]; | |
1188 fragment = (in[0] << 4) & 0x30; | |
1189 if (inlen > 1) | |
1190 fragment |= in[1] >> 4; | |
1191 *out++ = base64digits[fragment]; | |
1192 *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c]; | |
1193 *out++ = '-'; | |
1194 } | |
1195 *out = '\0'; | |
1196 } | |
1197 | |
1198 static void yahoo_process_auth_old(GaimConnection *gc, const char *seed) | |
1199 { | |
1200 struct yahoo_packet *pack; | |
1201 GaimAccount *account = gaim_connection_get_account(gc); | |
1202 const char *name = gaim_normalize(account, gaim_account_get_username(account)); | |
1203 const char *pass = gaim_connection_get_password(gc); | |
1204 struct yahoo_data *yd = gc->proto_data; | |
1205 | |
1206 /* So, Yahoo has stopped supporting its older clients in India, and undoubtedly | |
1207 * will soon do so in the rest of the world. | |
1208 * | |
1209 * The new clients use this authentication method. I warn you in advance, it's | |
1210 * bizarre, convoluted, inordinately complicated. It's also no more secure than | |
1211 * crypt() was. The only purpose this scheme could serve is to prevent third | |
1212 * party clients from connecting to their servers. | |
1213 * | |
1214 * Sorry, Yahoo. | |
1215 */ | |
1216 | |
1217 GaimCipher *cipher; | |
1218 GaimCipherContext *context; | |
1219 guchar digest[16]; | |
1220 | |
1221 char *crypt_result; | |
1222 char password_hash[25]; | |
1223 char crypt_hash[25]; | |
1224 char *hash_string_p = g_malloc(50 + strlen(name)); | |
1225 char *hash_string_c = g_malloc(50 + strlen(name)); | |
1226 | |
1227 char checksum; | |
1228 | |
1229 int sv; | |
1230 | |
1231 char result6[25]; | |
1232 char result96[25]; | |
1233 | |
1234 sv = seed[15]; | |
1235 sv = sv % 8; | |
1236 | |
1237 cipher = gaim_ciphers_find_cipher("md5"); | |
1238 context = gaim_cipher_context_new(cipher, NULL); | |
1239 | |
1240 gaim_cipher_context_append(context, (const guchar *)pass, strlen(pass)); | |
1241 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
1242 | |
1243 to_y64(password_hash, digest, 16); | |
1244 | |
1245 crypt_result = yahoo_crypt(pass, "$1$_2S43d5f$"); | |
1246 | |
1247 gaim_cipher_context_reset(context, NULL); | |
1248 gaim_cipher_context_append(context, (const guchar *)crypt_result, strlen(crypt_result)); | |
1249 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
1250 to_y64(crypt_hash, digest, 16); | |
1251 | |
1252 switch (sv) { | |
1253 case 1: | |
1254 case 6: | |
1255 checksum = seed[seed[9] % 16]; | |
1256 g_snprintf(hash_string_p, strlen(name) + 50, | |
1257 "%c%s%s%s", checksum, name, seed, password_hash); | |
1258 g_snprintf(hash_string_c, strlen(name) + 50, | |
1259 "%c%s%s%s", checksum, name, seed, crypt_hash); | |
1260 break; | |
1261 case 2: | |
1262 case 7: | |
1263 checksum = seed[seed[15] % 16]; | |
1264 g_snprintf(hash_string_p, strlen(name) + 50, | |
1265 "%c%s%s%s", checksum, seed, password_hash, name); | |
1266 g_snprintf(hash_string_c, strlen(name) + 50, | |
1267 "%c%s%s%s", checksum, seed, crypt_hash, name); | |
1268 break; | |
1269 case 3: | |
1270 checksum = seed[seed[1] % 16]; | |
1271 g_snprintf(hash_string_p, strlen(name) + 50, | |
1272 "%c%s%s%s", checksum, name, password_hash, seed); | |
1273 g_snprintf(hash_string_c, strlen(name) + 50, | |
1274 "%c%s%s%s", checksum, name, crypt_hash, seed); | |
1275 break; | |
1276 case 4: | |
1277 checksum = seed[seed[3] % 16]; | |
1278 g_snprintf(hash_string_p, strlen(name) + 50, | |
1279 "%c%s%s%s", checksum, password_hash, seed, name); | |
1280 g_snprintf(hash_string_c, strlen(name) + 50, | |
1281 "%c%s%s%s", checksum, crypt_hash, seed, name); | |
1282 break; | |
1283 case 0: | |
1284 case 5: | |
1285 checksum = seed[seed[7] % 16]; | |
1286 g_snprintf(hash_string_p, strlen(name) + 50, | |
1287 "%c%s%s%s", checksum, password_hash, name, seed); | |
1288 g_snprintf(hash_string_c, strlen(name) + 50, | |
1289 "%c%s%s%s", checksum, crypt_hash, name, seed); | |
1290 break; | |
1291 } | |
1292 | |
1293 gaim_cipher_context_reset(context, NULL); | |
1294 gaim_cipher_context_append(context, (const guchar *)hash_string_p, strlen(hash_string_p)); | |
1295 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
1296 to_y64(result6, digest, 16); | |
1297 | |
1298 gaim_cipher_context_reset(context, NULL); | |
1299 gaim_cipher_context_append(context, (const guchar *)hash_string_c, strlen(hash_string_c)); | |
1300 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
1301 gaim_cipher_context_destroy(context); | |
1302 to_y64(result96, digest, 16); | |
1303 | |
1304 pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, YAHOO_STATUS_AVAILABLE, 0); | |
1305 yahoo_packet_hash(pack, "ssss", 0, name, 6, result6, 96, result96, 1, name); | |
1306 yahoo_packet_send_and_free(pack, yd); | |
1307 | |
1308 g_free(hash_string_p); | |
1309 g_free(hash_string_c); | |
1310 } | |
1311 | |
1312 /* I'm dishing out some uber-mad props to Cerulean Studios for cracking this | |
1313 * and sending the fix! Thanks guys. */ | |
1314 | |
1315 static void yahoo_process_auth_new(GaimConnection *gc, const char *seed) | |
1316 { | |
1317 struct yahoo_packet *pack = NULL; | |
1318 GaimAccount *account = gaim_connection_get_account(gc); | |
1319 const char *name = gaim_normalize(account, gaim_account_get_username(account)); | |
1320 const char *pass = gaim_connection_get_password(gc); | |
1321 char *enc_pass; | |
1322 struct yahoo_data *yd = gc->proto_data; | |
1323 | |
1324 GaimCipher *md5_cipher; | |
1325 GaimCipherContext *md5_ctx; | |
1326 guchar md5_digest[16]; | |
1327 | |
1328 GaimCipher *sha1_cipher; | |
1329 GaimCipherContext *sha1_ctx1; | |
1330 GaimCipherContext *sha1_ctx2; | |
1331 | |
1332 char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ"; | |
1333 char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop"; | |
1334 | |
1335 char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5"; | |
1336 char *operand_lookup = "+|&%/*^-"; | |
1337 char *delimit_lookup = ",;"; | |
1338 | |
1339 char *password_hash = (char *)g_malloc(25); | |
1340 char *crypt_hash = (char *)g_malloc(25); | |
1341 char *crypt_result = NULL; | |
1342 | |
1343 unsigned char pass_hash_xor1[64]; | |
1344 unsigned char pass_hash_xor2[64]; | |
1345 unsigned char crypt_hash_xor1[64]; | |
1346 unsigned char crypt_hash_xor2[64]; | |
1347 char resp_6[100]; | |
1348 char resp_96[100]; | |
1349 | |
1350 unsigned char digest1[20]; | |
1351 unsigned char digest2[20]; | |
1352 unsigned char comparison_src[20]; | |
1353 unsigned char magic_key_char[4]; | |
1354 const char *magic_ptr; | |
1355 | |
1356 unsigned int magic[64]; | |
1357 unsigned int magic_work = 0; | |
1358 unsigned int magic_4 = 0; | |
1359 | |
1360 int x; | |
1361 int y; | |
1362 int cnt = 0; | |
1363 int magic_cnt = 0; | |
1364 int magic_len; | |
1365 | |
1366 memset(password_hash, 0, 25); | |
1367 memset(crypt_hash, 0, 25); | |
1368 memset(&pass_hash_xor1, 0, 64); | |
1369 memset(&pass_hash_xor2, 0, 64); | |
1370 memset(&crypt_hash_xor1, 0, 64); | |
1371 memset(&crypt_hash_xor2, 0, 64); | |
1372 memset(&digest1, 0, 20); | |
1373 memset(&digest2, 0, 20); | |
1374 memset(&magic, 0, 64); | |
1375 memset(&resp_6, 0, 100); | |
1376 memset(&resp_96, 0, 100); | |
1377 memset(&magic_key_char, 0, 4); | |
1378 memset(&comparison_src, 0, 20); | |
1379 | |
1380 md5_cipher = gaim_ciphers_find_cipher("md5"); | |
1381 md5_ctx = gaim_cipher_context_new(md5_cipher, NULL); | |
1382 | |
1383 sha1_cipher = gaim_ciphers_find_cipher("sha1"); | |
1384 sha1_ctx1 = gaim_cipher_context_new(sha1_cipher, NULL); | |
1385 sha1_ctx2 = gaim_cipher_context_new(sha1_cipher, NULL); | |
1386 | |
1387 /* | |
1388 * Magic: Phase 1. Generate what seems to be a 30 byte value (could change if base64 | |
1389 * ends up differently? I don't remember and I'm tired, so use a 64 byte buffer. | |
1390 */ | |
1391 | |
1392 magic_ptr = seed; | |
1393 | |
1394 while (*magic_ptr != (int)NULL) { | |
1395 char *loc; | |
1396 | |
1397 /* Ignore parentheses. */ | |
1398 | |
1399 if (*magic_ptr == '(' || *magic_ptr == ')') { | |
1400 magic_ptr++; | |
1401 continue; | |
1402 } | |
1403 | |
1404 /* Characters and digits verify against the challenge lookup. */ | |
1405 | |
1406 if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) { | |
1407 loc = strchr(challenge_lookup, *magic_ptr); | |
1408 if (!loc) { | |
1409 /* SME XXX Error - disconnect here */ | |
1410 } | |
1411 | |
1412 /* Get offset into lookup table and shl 3. */ | |
1413 | |
1414 magic_work = loc - challenge_lookup; | |
1415 magic_work <<= 3; | |
1416 | |
1417 magic_ptr++; | |
1418 continue; | |
1419 } else { | |
1420 unsigned int local_store; | |
1421 | |
1422 loc = strchr(operand_lookup, *magic_ptr); | |
1423 if (!loc) { | |
1424 /* SME XXX Disconnect */ | |
1425 } | |
1426 | |
1427 local_store = loc - operand_lookup; | |
1428 | |
1429 /* Oops; how did this happen? */ | |
1430 | |
1431 if (magic_cnt >= 64) | |
1432 break; | |
1433 | |
1434 magic[magic_cnt++] = magic_work | local_store; | |
1435 magic_ptr++; | |
1436 continue; | |
1437 } | |
1438 } | |
1439 | |
1440 magic_len = magic_cnt; | |
1441 magic_cnt = 0; | |
1442 | |
1443 /* Magic: Phase 2. Take generated magic value and sprinkle fairy | |
1444 * dust on the values. | |
1445 */ | |
1446 | |
1447 for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) { | |
1448 unsigned char byte1; | |
1449 unsigned char byte2; | |
1450 | |
1451 /* Bad. Abort. */ | |
1452 | |
1453 if ((magic_cnt + 1 > magic_len) || (magic_cnt > magic_len)) | |
1454 break; | |
1455 | |
1456 byte1 = magic[magic_cnt]; | |
1457 byte2 = magic[magic_cnt+1]; | |
1458 | |
1459 byte1 *= 0xcd; | |
1460 byte1 ^= byte2; | |
1461 | |
1462 magic[magic_cnt+1] = byte1; | |
1463 } | |
1464 | |
1465 /* | |
1466 * Magic: Phase 3. This computes 20 bytes. The first 4 bytes are used as our magic | |
1467 * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key | |
1468 * plus 3 bytes. The 3 bytes are found by looping, and they represent the offsets | |
1469 * into particular functions we'll later call to potentially alter the magic key. | |
1470 * | |
1471 * %-) | |
1472 */ | |
1473 | |
1474 magic_cnt = 1; | |
1475 x = 0; | |
1476 | |
1477 do { | |
1478 unsigned int bl = 0; | |
1479 unsigned int cl = magic[magic_cnt++]; | |
1480 | |
1481 if (magic_cnt >= magic_len) | |
1482 break; | |
1483 | |
1484 if (cl > 0x7F) { | |
1485 if (cl < 0xe0) | |
1486 bl = cl = (cl & 0x1f) << 6; | |
1487 else { | |
1488 bl = magic[magic_cnt++]; | |
1489 cl = (cl & 0x0f) << 6; | |
1490 bl = ((bl & 0x3f) + cl) << 6; | |
1491 } | |
1492 | |
1493 cl = magic[magic_cnt++]; | |
1494 bl = (cl & 0x3f) + bl; | |
1495 } else | |
1496 bl = cl; | |
1497 | |
1498 comparison_src[x++] = (bl & 0xff00) >> 8; | |
1499 comparison_src[x++] = bl & 0xff; | |
1500 } while (x < 20); | |
1501 | |
1502 /* First four bytes are magic key. */ | |
1503 memcpy(&magic_key_char[0], comparison_src, 4); | |
1504 magic_4 = magic_key_char[0] | (magic_key_char[1]<<8) | (magic_key_char[2]<<16) | (magic_key_char[3]<<24); | |
1505 | |
1506 /* | |
1507 * Magic: Phase 4. Determine what function to use later by getting outside/inside | |
1508 * loop values until we match our previous buffer. | |
1509 */ | |
1510 for (x = 0; x < 65535; x++) { | |
1511 int leave = 0; | |
1512 | |
1513 for (y = 0; y < 5; y++) { | |
1514 unsigned char test[3]; | |
1515 | |
1516 /* Calculate buffer. */ | |
1517 test[0] = x; | |
1518 test[1] = x >> 8; | |
1519 test[2] = y; | |
1520 | |
1521 gaim_cipher_context_reset(md5_ctx, NULL); | |
1522 gaim_cipher_context_append(md5_ctx, magic_key_char, 4); | |
1523 gaim_cipher_context_append(md5_ctx, test, 3); | |
1524 gaim_cipher_context_digest(md5_ctx, sizeof(md5_digest), | |
1525 md5_digest, NULL); | |
1526 | |
1527 if (!memcmp(md5_digest, comparison_src+4, 16)) { | |
1528 leave = 1; | |
1529 break; | |
1530 } | |
1531 } | |
1532 | |
1533 if (leave == 1) | |
1534 break; | |
1535 } | |
1536 | |
1537 /* If y != 0, we need some help. */ | |
1538 if (y != 0) { | |
1539 unsigned int updated_key; | |
1540 | |
1541 /* Update magic stuff. | |
1542 * Call it twice because Yahoo's encryption is super bad ass. | |
1543 */ | |
1544 updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x); | |
1545 updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x); | |
1546 | |
1547 magic_key_char[0] = updated_key & 0xff; | |
1548 magic_key_char[1] = (updated_key >> 8) & 0xff; | |
1549 magic_key_char[2] = (updated_key >> 16) & 0xff; | |
1550 magic_key_char[3] = (updated_key >> 24) & 0xff; | |
1551 } | |
1552 | |
1553 enc_pass = yahoo_string_encode(gc, pass, NULL); | |
1554 | |
1555 /* Get password and crypt hashes as per usual. */ | |
1556 gaim_cipher_context_reset(md5_ctx, NULL); | |
1557 gaim_cipher_context_append(md5_ctx, (const guchar *)enc_pass, strlen(enc_pass)); | |
1558 gaim_cipher_context_digest(md5_ctx, sizeof(md5_digest), | |
1559 md5_digest, NULL); | |
1560 to_y64(password_hash, md5_digest, 16); | |
1561 | |
1562 crypt_result = yahoo_crypt(enc_pass, "$1$_2S43d5f$"); | |
1563 | |
1564 g_free(enc_pass); | |
1565 enc_pass = NULL; | |
1566 | |
1567 gaim_cipher_context_reset(md5_ctx, NULL); | |
1568 gaim_cipher_context_append(md5_ctx, (const guchar *)crypt_result, strlen(crypt_result)); | |
1569 gaim_cipher_context_digest(md5_ctx, sizeof(md5_digest), | |
1570 md5_digest, NULL); | |
1571 to_y64(crypt_hash, md5_digest, 16); | |
1572 | |
1573 /* Our first authentication response is based off of the password hash. */ | |
1574 for (x = 0; x < (int)strlen(password_hash); x++) | |
1575 pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36; | |
1576 | |
1577 if (cnt < 64) | |
1578 memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt); | |
1579 | |
1580 cnt = 0; | |
1581 | |
1582 for (x = 0; x < (int)strlen(password_hash); x++) | |
1583 pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c; | |
1584 | |
1585 if (cnt < 64) | |
1586 memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt); | |
1587 | |
1588 /* | |
1589 * The first context gets the password hash XORed with 0x36 plus a magic value | |
1590 * which we previously extrapolated from our challenge. | |
1591 */ | |
1592 | |
1593 gaim_cipher_context_append(sha1_ctx1, pass_hash_xor1, 64); | |
1594 if (y >= 3) | |
1595 gaim_cipher_context_set_option(sha1_ctx1, "sizeLo", GINT_TO_POINTER(0x1ff)); | |
1596 gaim_cipher_context_append(sha1_ctx1, magic_key_char, 4); | |
1597 gaim_cipher_context_digest(sha1_ctx1, sizeof(digest1), digest1, NULL); | |
1598 | |
1599 /* | |
1600 * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest | |
1601 * of the first context. | |
1602 */ | |
1603 | |
1604 gaim_cipher_context_append(sha1_ctx2, pass_hash_xor2, 64); | |
1605 gaim_cipher_context_append(sha1_ctx2, digest1, 20); | |
1606 gaim_cipher_context_digest(sha1_ctx2, sizeof(digest2), digest2, NULL); | |
1607 | |
1608 /* | |
1609 * Now that we have digest2, use it to fetch characters from an alphabet to construct | |
1610 * our first authentication response. | |
1611 */ | |
1612 | |
1613 for (x = 0; x < 20; x += 2) { | |
1614 unsigned int val = 0; | |
1615 unsigned int lookup = 0; | |
1616 | |
1617 char byte[6]; | |
1618 | |
1619 memset(&byte, 0, 6); | |
1620 | |
1621 /* First two bytes of digest stuffed together. */ | |
1622 | |
1623 val = digest2[x]; | |
1624 val <<= 8; | |
1625 val += digest2[x+1]; | |
1626 | |
1627 lookup = (val >> 0x0b); | |
1628 lookup &= 0x1f; | |
1629 if (lookup >= strlen(alphabet1)) | |
1630 break; | |
1631 sprintf(byte, "%c", alphabet1[lookup]); | |
1632 strcat(resp_6, byte); | |
1633 strcat(resp_6, "="); | |
1634 | |
1635 lookup = (val >> 0x06); | |
1636 lookup &= 0x1f; | |
1637 if (lookup >= strlen(alphabet2)) | |
1638 break; | |
1639 sprintf(byte, "%c", alphabet2[lookup]); | |
1640 strcat(resp_6, byte); | |
1641 | |
1642 lookup = (val >> 0x01); | |
1643 lookup &= 0x1f; | |
1644 if (lookup >= strlen(alphabet2)) | |
1645 break; | |
1646 sprintf(byte, "%c", alphabet2[lookup]); | |
1647 strcat(resp_6, byte); | |
1648 | |
1649 lookup = (val & 0x01); | |
1650 if (lookup >= strlen(delimit_lookup)) | |
1651 break; | |
1652 sprintf(byte, "%c", delimit_lookup[lookup]); | |
1653 strcat(resp_6, byte); | |
1654 } | |
1655 | |
1656 /* Our second authentication response is based off of the crypto hash. */ | |
1657 | |
1658 cnt = 0; | |
1659 memset(&digest1, 0, 20); | |
1660 memset(&digest2, 0, 20); | |
1661 | |
1662 for (x = 0; x < (int)strlen(crypt_hash); x++) | |
1663 crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36; | |
1664 | |
1665 if (cnt < 64) | |
1666 memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt); | |
1667 | |
1668 cnt = 0; | |
1669 | |
1670 for (x = 0; x < (int)strlen(crypt_hash); x++) | |
1671 crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c; | |
1672 | |
1673 if (cnt < 64) | |
1674 memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt); | |
1675 | |
1676 gaim_cipher_context_reset(sha1_ctx1, NULL); | |
1677 gaim_cipher_context_reset(sha1_ctx2, NULL); | |
1678 | |
1679 /* | |
1680 * The first context gets the password hash XORed with 0x36 plus a magic value | |
1681 * which we previously extrapolated from our challenge. | |
1682 */ | |
1683 | |
1684 gaim_cipher_context_append(sha1_ctx1, crypt_hash_xor1, 64); | |
1685 if (y >= 3) { | |
1686 gaim_cipher_context_set_option(sha1_ctx1, "sizeLo", | |
1687 GINT_TO_POINTER(0x1ff)); | |
1688 } | |
1689 gaim_cipher_context_append(sha1_ctx1, magic_key_char, 4); | |
1690 gaim_cipher_context_digest(sha1_ctx1, sizeof(digest1), digest1, NULL); | |
1691 | |
1692 /* | |
1693 * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest | |
1694 * of the first context. | |
1695 */ | |
1696 | |
1697 gaim_cipher_context_append(sha1_ctx2, crypt_hash_xor2, 64); | |
1698 gaim_cipher_context_append(sha1_ctx2, digest1, 20); | |
1699 gaim_cipher_context_digest(sha1_ctx2, sizeof(digest2), digest2, NULL); | |
1700 | |
1701 /* | |
1702 * Now that we have digest2, use it to fetch characters from an alphabet to construct | |
1703 * our first authentication response. | |
1704 */ | |
1705 | |
1706 for (x = 0; x < 20; x += 2) { | |
1707 unsigned int val = 0; | |
1708 unsigned int lookup = 0; | |
1709 | |
1710 char byte[6]; | |
1711 | |
1712 memset(&byte, 0, 6); | |
1713 | |
1714 /* First two bytes of digest stuffed together. */ | |
1715 | |
1716 val = digest2[x]; | |
1717 val <<= 8; | |
1718 val += digest2[x+1]; | |
1719 | |
1720 lookup = (val >> 0x0b); | |
1721 lookup &= 0x1f; | |
1722 if (lookup >= strlen(alphabet1)) | |
1723 break; | |
1724 sprintf(byte, "%c", alphabet1[lookup]); | |
1725 strcat(resp_96, byte); | |
1726 strcat(resp_96, "="); | |
1727 | |
1728 lookup = (val >> 0x06); | |
1729 lookup &= 0x1f; | |
1730 if (lookup >= strlen(alphabet2)) | |
1731 break; | |
1732 sprintf(byte, "%c", alphabet2[lookup]); | |
1733 strcat(resp_96, byte); | |
1734 | |
1735 lookup = (val >> 0x01); | |
1736 lookup &= 0x1f; | |
1737 if (lookup >= strlen(alphabet2)) | |
1738 break; | |
1739 sprintf(byte, "%c", alphabet2[lookup]); | |
1740 strcat(resp_96, byte); | |
1741 | |
1742 lookup = (val & 0x01); | |
1743 if (lookup >= strlen(delimit_lookup)) | |
1744 break; | |
1745 sprintf(byte, "%c", delimit_lookup[lookup]); | |
1746 strcat(resp_96, byte); | |
1747 } | |
1748 gaim_debug_info("yahoo", "yahoo status: %d\n", yd->current_status); | |
1749 pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->current_status, 0); | |
1750 yahoo_packet_hash(pack, "sssss", 0, name, 6, resp_6, 96, resp_96, 1, | |
1751 name, 135, "6,0,0,1710"); | |
1752 if (yd->picture_checksum) | |
1753 yahoo_packet_hash_int(pack, 192, yd->picture_checksum); | |
1754 | |
1755 yahoo_packet_send_and_free(pack, yd); | |
1756 | |
1757 gaim_cipher_context_destroy(md5_ctx); | |
1758 gaim_cipher_context_destroy(sha1_ctx1); | |
1759 gaim_cipher_context_destroy(sha1_ctx2); | |
1760 | |
1761 g_free(password_hash); | |
1762 g_free(crypt_hash); | |
1763 } | |
1764 | |
1765 static void yahoo_process_auth(GaimConnection *gc, struct yahoo_packet *pkt) | |
1766 { | |
1767 char *seed = NULL; | |
1768 char *sn = NULL; | |
1769 GSList *l = pkt->hash; | |
1770 int m = 0; | |
1771 gchar *buf; | |
1772 | |
1773 while (l) { | |
1774 struct yahoo_pair *pair = l->data; | |
1775 if (pair->key == 94) | |
1776 seed = pair->value; | |
1777 if (pair->key == 1) | |
1778 sn = pair->value; | |
1779 if (pair->key == 13) | |
1780 m = atoi(pair->value); | |
1781 l = l->next; | |
1782 } | |
1783 | |
1784 if (seed) { | |
1785 switch (m) { | |
1786 case 0: | |
1787 yahoo_process_auth_old(gc, seed); | |
1788 break; | |
1789 case 1: | |
14258 | 1790 case 2: /* This case seems to work, could probably use testing */ |
14192 | 1791 yahoo_process_auth_new(gc, seed); |
1792 break; | |
1793 default: | |
1794 buf = g_strdup_printf(_("The Yahoo server has requested the use of an unrecognized " | |
1795 "authentication method. This version of Gaim will likely not be able " | |
1796 "to successfully sign on to Yahoo. Check %s for updates."), GAIM_WEBSITE); | |
1797 gaim_notify_error(gc, "", _("Failed Yahoo! Authentication"), | |
1798 buf); | |
1799 g_free(buf); | |
1800 yahoo_process_auth_new(gc, seed); /* Can't hurt to try it anyway. */ | |
1801 } | |
1802 } | |
1803 } | |
1804 | |
1805 static void ignore_buddy(GaimBuddy *buddy) { | |
1806 GaimGroup *group; | |
1807 GaimAccount *account; | |
1808 gchar *name; | |
1809 | |
1810 if (!buddy) | |
1811 return; | |
1812 | |
1813 group = gaim_buddy_get_group(buddy); | |
1814 name = g_strdup(buddy->name); | |
1815 account = buddy->account; | |
1816 | |
1817 gaim_debug(GAIM_DEBUG_INFO, "blist", | |
1818 "Removing '%s' from buddy list.\n", buddy->name); | |
1819 gaim_account_remove_buddy(account, buddy, group); | |
1820 gaim_blist_remove_buddy(buddy); | |
1821 | |
1822 serv_add_deny(account->gc, name); | |
1823 | |
1824 g_free(name); | |
1825 } | |
1826 | |
1827 static void keep_buddy(GaimBuddy *b) { | |
1828 gaim_privacy_deny_remove(b->account, b->name, 1); | |
1829 } | |
1830 | |
1831 static void yahoo_process_ignore(GaimConnection *gc, struct yahoo_packet *pkt) { | |
1832 GaimBuddy *b; | |
1833 GSList *l; | |
1834 gchar *who = NULL; | |
1835 gchar *sn = NULL; | |
1836 gchar buf[BUF_LONG]; | |
1837 gint ignore = 0; | |
1838 gint status = 0; | |
1839 | |
1840 for (l = pkt->hash; l; l = l->next) { | |
1841 struct yahoo_pair *pair = l->data; | |
1842 switch (pair->key) { | |
1843 case 0: | |
1844 who = pair->value; | |
1845 break; | |
1846 case 1: | |
1847 sn = pair->value; | |
1848 break; | |
1849 case 13: | |
1850 ignore = strtol(pair->value, NULL, 10); | |
1851 break; | |
1852 case 66: | |
1853 status = strtol(pair->value, NULL, 10); | |
1854 break; | |
1855 default: | |
1856 break; | |
1857 } | |
1858 } | |
1859 | |
1860 switch (status) { | |
1861 case 12: | |
1862 b = gaim_find_buddy(gc->account, who); | |
1863 g_snprintf(buf, sizeof(buf), _("You have tried to ignore %s, but the " | |
1864 "user is on your buddy list. Clicking \"Yes\" " | |
1865 "will remove and ignore the buddy."), who); | |
1866 gaim_request_yes_no(gc, NULL, _("Ignore buddy?"), buf, 0, b, | |
1867 G_CALLBACK(ignore_buddy), | |
1868 G_CALLBACK(keep_buddy)); | |
1869 break; | |
1870 case 2: | |
1871 case 3: | |
1872 case 0: | |
1873 default: | |
1874 break; | |
1875 } | |
1876 } | |
1877 | |
1878 static void yahoo_process_authresp(GaimConnection *gc, struct yahoo_packet *pkt) | |
1879 { | |
1880 struct yahoo_data *yd = gc->proto_data; | |
1881 GSList *l = pkt->hash; | |
1882 int err = 0; | |
1883 char *msg; | |
1884 char *url = NULL; | |
1885 char *fullmsg; | |
1886 | |
1887 while (l) { | |
1888 struct yahoo_pair *pair = l->data; | |
1889 | |
1890 if (pair->key == 66) | |
1891 err = strtol(pair->value, NULL, 10); | |
1892 if (pair->key == 20) | |
1893 url = pair->value; | |
1894 | |
1895 l = l->next; | |
1896 } | |
1897 | |
1898 switch (err) { | |
1899 case 3: | |
15000
89ae31668a9c
[gaim-migrate @ 17779]
Richard Laager <rlaager@wiktel.com>
parents:
14842
diff
changeset
|
1900 msg = g_strdup(_("Invalid screen name.")); |
14192 | 1901 break; |
1902 case 13: | |
1903 if (!yd->wm) { | |
14354 | 1904 GaimUtilFetchUrlData *url_data; |
14192 | 1905 yd->wm = TRUE; |
1906 if (yd->fd >= 0) | |
1907 close(yd->fd); | |
1908 if (gc->inpa) | |
1909 gaim_input_remove(gc->inpa); | |
14354 | 1910 url_data = gaim_util_fetch_url(WEBMESSENGER_URL, TRUE, |
1911 "Gaim/" VERSION, FALSE, yahoo_login_page_cb, gc); | |
1912 if (url_data != NULL) | |
1913 yd->url_datas = g_slist_prepend(yd->url_datas, url_data); | |
14192 | 1914 gaim_notify_warning(gc, NULL, _("Normal authentication failed!"), |
1915 _("The normal authentication method has failed. " | |
1916 "This means either your password is incorrect, " | |
1917 "or Yahoo!'s authentication scheme has changed. " | |
1918 "Gaim will now attempt to log in using Web " | |
1919 "Messenger authentication, which will result " | |
1920 "in reduced functionality and features.")); | |
1921 return; | |
1922 } | |
1923 msg = g_strdup(_("Incorrect password.")); | |
1924 break; | |
1925 case 14: | |
1926 msg = g_strdup(_("Your account is locked, please log in to the Yahoo! website.")); | |
1927 break; | |
1928 default: | |
1929 msg = g_strdup_printf(_("Unknown error number %d. Logging into the Yahoo! website may fix this."), err); | |
1930 } | |
1931 | |
1932 if (url) | |
1933 fullmsg = g_strdup_printf("%s\n%s", msg, url); | |
1934 else | |
1935 fullmsg = g_strdup(msg); | |
1936 | |
1937 gc->wants_to_die = TRUE; | |
1938 gaim_connection_error(gc, fullmsg); | |
1939 g_free(msg); | |
1940 g_free(fullmsg); | |
1941 } | |
1942 | |
1943 static void yahoo_process_addbuddy(GaimConnection *gc, struct yahoo_packet *pkt) | |
1944 { | |
1945 int err = 0; | |
1946 char *who = NULL; | |
1947 char *group = NULL; | |
1948 char *decoded_group; | |
1949 char *buf; | |
1950 YahooFriend *f; | |
1951 GSList *l = pkt->hash; | |
1952 | |
1953 while (l) { | |
1954 struct yahoo_pair *pair = l->data; | |
1955 | |
1956 switch (pair->key) { | |
1957 case 66: | |
1958 err = strtol(pair->value, NULL, 10); | |
1959 break; | |
1960 case 7: | |
1961 who = pair->value; | |
1962 break; | |
1963 case 65: | |
1964 group = pair->value; | |
1965 break; | |
1966 } | |
1967 | |
1968 l = l->next; | |
1969 } | |
1970 | |
1971 if (!who) | |
1972 return; | |
1973 if (!group) | |
1974 group = ""; | |
1975 | |
1976 if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */ | |
1977 f = yahoo_friend_find_or_new(gc, who); | |
1978 yahoo_update_status(gc, who, f); | |
1979 return; | |
1980 } | |
1981 | |
1982 decoded_group = yahoo_string_decode(gc, group, FALSE); | |
1983 buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."), | |
1984 who, decoded_group, gaim_connection_get_display_name(gc)); | |
1985 if (!gaim_conv_present_error(who, gaim_connection_get_account(gc), buf)) | |
1986 gaim_notify_error(gc, NULL, _("Could not add buddy to server list"), buf); | |
1987 g_free(buf); | |
1988 g_free(decoded_group); | |
1989 } | |
1990 | |
1991 static void yahoo_process_p2p(GaimConnection *gc, struct yahoo_packet *pkt) | |
1992 { | |
1993 GSList *l = pkt->hash; | |
1994 char *who = NULL; | |
1995 char *base64 = NULL; | |
1996 guchar *decoded; | |
1997 gsize len; | |
1998 | |
1999 while (l) { | |
2000 struct yahoo_pair *pair = l->data; | |
2001 | |
2002 switch (pair->key) { | |
2003 case 5: | |
2004 /* our identity */ | |
2005 break; | |
2006 case 4: | |
2007 who = pair->value; | |
2008 break; | |
2009 case 1: | |
2010 /* who again, the master identity this time? */ | |
2011 break; | |
2012 case 12: | |
2013 base64 = pair->value; | |
2014 /* so, this is an ip address. in base64. decoded it's in ascii. | |
2015 after strtol, it's in reversed byte order. Who thought this up?*/ | |
2016 break; | |
2017 /* | |
2018 TODO: figure these out | |
2019 yahoo: Key: 61 Value: 0 | |
2020 yahoo: Key: 2 Value: | |
2021 yahoo: Key: 13 Value: 0 | |
2022 yahoo: Key: 49 Value: PEERTOPEER | |
2023 yahoo: Key: 140 Value: 1 | |
2024 yahoo: Key: 11 Value: -1786225828 | |
2025 */ | |
2026 | |
2027 } | |
2028 | |
2029 l = l->next; | |
2030 } | |
2031 | |
2032 if (base64) { | |
2033 guint32 ip; | |
2034 char *tmp2; | |
2035 YahooFriend *f; | |
2036 | |
2037 decoded = gaim_base64_decode(base64, &len); | |
2038 if (len) { | |
2039 char *tmp = gaim_str_binary_to_ascii(decoded, len); | |
2040 gaim_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp); | |
2041 g_free(tmp); | |
2042 } | |
2043 | |
2044 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/ | |
2045 ip = strtol(tmp2, NULL, 10); | |
2046 g_free(tmp2); | |
2047 g_free(decoded); | |
2048 tmp2 = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, | |
2049 (ip >> 24) & 0xff); | |
2050 f = yahoo_friend_find(gc, who); | |
2051 if (f) | |
2052 yahoo_friend_set_ip(f, tmp2); | |
2053 g_free(tmp2); | |
2054 } | |
2055 } | |
2056 | |
2057 static void yahoo_process_audible(GaimConnection *gc, struct yahoo_packet *pkt) | |
2058 { | |
2059 char *who = NULL, *msg = NULL, *id = NULL; | |
2060 GSList *l = pkt->hash; | |
2061 | |
2062 while (l) { | |
2063 struct yahoo_pair *pair = l->data; | |
2064 | |
2065 switch (pair->key) { | |
2066 case 4: | |
2067 who = pair->value; | |
2068 break; | |
2069 case 5: | |
2070 /* us */ | |
2071 break; | |
2072 case 230: | |
2073 /* the audible, in foo.locale.bar.baz format | |
2074 eg: base.tw.smiley.smiley43 */ | |
2075 id = pair->value; | |
2076 break; | |
2077 case 231: | |
2078 /* the text of the audible */ | |
2079 msg = pair->value; | |
2080 break; | |
2081 case 232: | |
2082 /* weird number (md5 hash?), like 8ebab9094156135f5dcbaccbeee662a5c5fd1420 */ | |
2083 break; | |
2084 } | |
2085 | |
2086 l = l->next; | |
2087 } | |
2088 | |
2089 if (!msg) | |
2090 msg = id; | |
2091 if (!who || !msg) | |
2092 return; | |
2093 if (!g_utf8_validate(msg, -1, NULL)) { | |
2094 gaim_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n"); | |
2095 return; | |
2096 } | |
2097 if (!yahoo_privacy_check(gc, who)) { | |
2098 gaim_debug_misc("yahoo", "Audible message from %s for %s dropped!\n", | |
2099 gc->account->username, who); | |
2100 return; | |
2101 } | |
2102 if (id) { | |
2103 /* "http://us.dl1.yimg.com/download.yahoo.com/dl/aud/"+locale+"/"+id+".swf" */ | |
2104 char **audible_locale = g_strsplit(id, ".", 0); | |
2105 char *buf = g_strdup_printf(_("[ Audible %s/%s/%s.swf ] %s"), YAHOO_AUDIBLE_URL, audible_locale[1], id, msg); | |
2106 g_strfreev(audible_locale); | |
2107 | |
2108 serv_got_im(gc, who, buf, 0, time(NULL)); | |
2109 g_free(buf); | |
2110 } else | |
2111 serv_got_im(gc, who, msg, 0, time(NULL)); | |
2112 } | |
2113 | |
2114 static void yahoo_packet_process(GaimConnection *gc, struct yahoo_packet *pkt) | |
2115 { | |
2116 switch (pkt->service) { | |
2117 case YAHOO_SERVICE_LOGON: | |
2118 case YAHOO_SERVICE_LOGOFF: | |
2119 case YAHOO_SERVICE_ISAWAY: | |
2120 case YAHOO_SERVICE_ISBACK: | |
2121 case YAHOO_SERVICE_GAMELOGON: | |
2122 case YAHOO_SERVICE_GAMELOGOFF: | |
2123 case YAHOO_SERVICE_CHATLOGON: | |
2124 case YAHOO_SERVICE_CHATLOGOFF: | |
2125 case YAHOO_SERVICE_Y6_STATUS_UPDATE: | |
14258 | 2126 case YAHOO_SERVICE_STATUS_15: |
14192 | 2127 yahoo_process_status(gc, pkt); |
2128 break; | |
2129 case YAHOO_SERVICE_NOTIFY: | |
2130 yahoo_process_notify(gc, pkt); | |
2131 break; | |
2132 case YAHOO_SERVICE_MESSAGE: | |
2133 case YAHOO_SERVICE_GAMEMSG: | |
2134 case YAHOO_SERVICE_CHATMSG: | |
2135 yahoo_process_message(gc, pkt); | |
2136 break; | |
2137 case YAHOO_SERVICE_SYSMESSAGE: | |
2138 yahoo_process_sysmessage(gc, pkt); | |
2139 break; | |
2140 case YAHOO_SERVICE_NEWMAIL: | |
2141 yahoo_process_mail(gc, pkt); | |
2142 break; | |
2143 case YAHOO_SERVICE_NEWCONTACT: | |
2144 yahoo_process_contact(gc, pkt); | |
2145 break; | |
2146 case YAHOO_SERVICE_AUTHRESP: | |
2147 yahoo_process_authresp(gc, pkt); | |
2148 break; | |
2149 case YAHOO_SERVICE_LIST: | |
2150 yahoo_process_list(gc, pkt); | |
2151 break; | |
14258 | 2152 case YAHOO_SERVICE_LIST_15: |
2153 yahoo_process_list_15(gc, pkt); | |
2154 break; | |
14192 | 2155 case YAHOO_SERVICE_AUTH: |
2156 yahoo_process_auth(gc, pkt); | |
2157 break; | |
2158 case YAHOO_SERVICE_ADDBUDDY: | |
2159 yahoo_process_addbuddy(gc, pkt); | |
2160 break; | |
2161 case YAHOO_SERVICE_IGNORECONTACT: | |
2162 yahoo_process_ignore(gc, pkt); | |
2163 break; | |
2164 case YAHOO_SERVICE_CONFINVITE: | |
2165 case YAHOO_SERVICE_CONFADDINVITE: | |
2166 yahoo_process_conference_invite(gc, pkt); | |
2167 break; | |
2168 case YAHOO_SERVICE_CONFDECLINE: | |
2169 yahoo_process_conference_decline(gc, pkt); | |
2170 break; | |
2171 case YAHOO_SERVICE_CONFLOGON: | |
2172 yahoo_process_conference_logon(gc, pkt); | |
2173 break; | |
2174 case YAHOO_SERVICE_CONFLOGOFF: | |
2175 yahoo_process_conference_logoff(gc, pkt); | |
2176 break; | |
2177 case YAHOO_SERVICE_CONFMSG: | |
2178 yahoo_process_conference_message(gc, pkt); | |
2179 break; | |
2180 case YAHOO_SERVICE_CHATONLINE: | |
2181 yahoo_process_chat_online(gc, pkt); | |
2182 break; | |
2183 case YAHOO_SERVICE_CHATLOGOUT: | |
2184 yahoo_process_chat_logout(gc, pkt); | |
2185 break; | |
2186 case YAHOO_SERVICE_CHATGOTO: | |
2187 yahoo_process_chat_goto(gc, pkt); | |
2188 break; | |
2189 case YAHOO_SERVICE_CHATJOIN: | |
2190 yahoo_process_chat_join(gc, pkt); | |
2191 break; | |
2192 case YAHOO_SERVICE_CHATLEAVE: /* XXX is this right? */ | |
2193 case YAHOO_SERVICE_CHATEXIT: | |
2194 yahoo_process_chat_exit(gc, pkt); | |
2195 break; | |
2196 case YAHOO_SERVICE_CHATINVITE: /* XXX never seen this one, might not do it right */ | |
2197 case YAHOO_SERVICE_CHATADDINVITE: | |
2198 yahoo_process_chat_addinvite(gc, pkt); | |
2199 break; | |
2200 case YAHOO_SERVICE_COMMENT: | |
2201 yahoo_process_chat_message(gc, pkt); | |
2202 break; | |
2203 case YAHOO_SERVICE_PRESENCE_PERM: | |
2204 case YAHOO_SERVICE_PRESENCE_SESSION: | |
2205 yahoo_process_presence(gc, pkt); | |
2206 break; | |
2207 case YAHOO_SERVICE_P2PFILEXFER: | |
2208 /* This case had no break and continued; thus keeping it this way.*/ | |
2209 yahoo_process_p2pfilexfer(gc, pkt); | |
2210 case YAHOO_SERVICE_FILETRANSFER: | |
2211 yahoo_process_filetransfer(gc, pkt); | |
2212 break; | |
2213 case YAHOO_SERVICE_PEERTOPEER: | |
2214 yahoo_process_p2p(gc, pkt); | |
2215 break; | |
2216 case YAHOO_SERVICE_PICTURE: | |
2217 yahoo_process_picture(gc, pkt); | |
2218 break; | |
2219 case YAHOO_SERVICE_PICTURE_UPDATE: | |
2220 yahoo_process_picture_update(gc, pkt); | |
2221 break; | |
2222 case YAHOO_SERVICE_PICTURE_CHECKSUM: | |
2223 yahoo_process_picture_checksum(gc, pkt); | |
2224 break; | |
2225 case YAHOO_SERVICE_PICTURE_UPLOAD: | |
2226 yahoo_process_picture_upload(gc, pkt); | |
2227 break; | |
2228 case YAHOO_SERVICE_AVATAR_UPDATE: | |
2229 yahoo_process_avatar_update(gc, pkt); | |
2230 break; | |
2231 case YAHOO_SERVICE_AUDIBLE: | |
2232 yahoo_process_audible(gc, pkt); | |
2233 break; | |
2234 default: | |
2235 gaim_debug(GAIM_DEBUG_ERROR, "yahoo", | |
2236 "Unhandled service 0x%02x\n", pkt->service); | |
2237 break; | |
2238 } | |
2239 } | |
2240 | |
2241 static void yahoo_pending(gpointer data, gint source, GaimInputCondition cond) | |
2242 { | |
2243 GaimConnection *gc = data; | |
2244 struct yahoo_data *yd = gc->proto_data; | |
2245 char buf[1024]; | |
2246 int len; | |
2247 | |
2248 len = read(yd->fd, buf, sizeof(buf)); | |
2249 | |
14426 | 2250 if (len < 0) { |
2251 gchar *tmp; | |
2252 | |
2253 if (errno == EAGAIN) | |
2254 /* No worries */ | |
2255 return; | |
2256 | |
2257 tmp = g_strdup_printf(_("Lost connection with server:\n%s"), | |
2258 strerror(errno)); | |
2259 gaim_connection_error(gc, tmp); | |
2260 g_free(tmp); | |
2261 return; | |
2262 } else if (len == 0) { | |
2263 gaim_connection_error(gc, _("Server closed the connection.")); | |
14192 | 2264 return; |
2265 } | |
2266 | |
2267 yd->rxqueue = g_realloc(yd->rxqueue, len + yd->rxlen); | |
2268 memcpy(yd->rxqueue + yd->rxlen, buf, len); | |
2269 yd->rxlen += len; | |
2270 | |
2271 while (1) { | |
2272 struct yahoo_packet *pkt; | |
2273 int pos = 0; | |
2274 int pktlen; | |
2275 | |
2276 if (yd->rxlen < YAHOO_PACKET_HDRLEN) | |
2277 return; | |
2278 | |
2279 if (strncmp((char *)yd->rxqueue, "YMSG", MIN(4, yd->rxlen)) != 0) { | |
2280 /* HEY! This isn't even a YMSG packet. What | |
2281 * are you trying to pull? */ | |
2282 guchar *start; | |
2283 | |
2284 gaim_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!"); | |
2285 | |
2286 start = memchr(yd->rxqueue + 1, 'Y', yd->rxlen - 1); | |
2287 if (start) { | |
2288 g_memmove(yd->rxqueue, start, yd->rxlen - (start - yd->rxqueue)); | |
2289 yd->rxlen -= start - yd->rxqueue; | |
2290 continue; | |
2291 } else { | |
2292 g_free(yd->rxqueue); | |
2293 yd->rxqueue = NULL; | |
2294 yd->rxlen = 0; | |
2295 return; | |
2296 } | |
2297 } | |
2298 | |
2299 pos += 4; /* YMSG */ | |
2300 pos += 2; | |
2301 pos += 2; | |
2302 | |
2303 pktlen = yahoo_get16(yd->rxqueue + pos); pos += 2; | |
2304 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
2305 "%d bytes to read, rxlen is %d\n", pktlen, yd->rxlen); | |
2306 | |
2307 if (yd->rxlen < (YAHOO_PACKET_HDRLEN + pktlen)) | |
2308 return; | |
2309 | |
2310 yahoo_packet_dump(yd->rxqueue, YAHOO_PACKET_HDRLEN + pktlen); | |
2311 | |
2312 pkt = yahoo_packet_new(0, 0, 0); | |
2313 | |
2314 pkt->service = yahoo_get16(yd->rxqueue + pos); pos += 2; | |
2315 pkt->status = yahoo_get32(yd->rxqueue + pos); pos += 4; | |
2316 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
2317 "Yahoo Service: 0x%02x Status: %d\n", | |
2318 pkt->service, pkt->status); | |
2319 pkt->id = yahoo_get32(yd->rxqueue + pos); pos += 4; | |
2320 | |
2321 yahoo_packet_read(pkt, yd->rxqueue + pos, pktlen); | |
2322 | |
2323 yd->rxlen -= YAHOO_PACKET_HDRLEN + pktlen; | |
2324 if (yd->rxlen) { | |
2325 guchar *tmp = g_memdup(yd->rxqueue + YAHOO_PACKET_HDRLEN + pktlen, yd->rxlen); | |
2326 g_free(yd->rxqueue); | |
2327 yd->rxqueue = tmp; | |
2328 } else { | |
2329 g_free(yd->rxqueue); | |
2330 yd->rxqueue = NULL; | |
2331 } | |
2332 | |
2333 yahoo_packet_process(gc, pkt); | |
2334 | |
2335 yahoo_packet_free(pkt); | |
2336 } | |
2337 } | |
2338 | |
2339 static void yahoo_got_connected(gpointer data, gint source, const gchar *error_message) | |
2340 { | |
2341 GaimConnection *gc = data; | |
2342 struct yahoo_data *yd; | |
2343 struct yahoo_packet *pkt; | |
2344 | |
2345 if (!GAIM_CONNECTION_IS_VALID(gc)) { | |
2346 close(source); | |
2347 return; | |
2348 } | |
2349 | |
2350 if (source < 0) { | |
2351 gaim_connection_error(gc, _("Unable to connect.")); | |
2352 return; | |
2353 } | |
2354 | |
2355 yd = gc->proto_data; | |
2356 yd->fd = source; | |
2357 | |
2358 pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, yd->current_status, 0); | |
2359 | |
2360 yahoo_packet_hash_str(pkt, 1, gaim_normalize(gc->account, gaim_account_get_username(gaim_connection_get_account(gc)))); | |
2361 yahoo_packet_send_and_free(pkt, yd); | |
2362 | |
2363 gc->inpa = gaim_input_add(yd->fd, GAIM_INPUT_READ, yahoo_pending, gc); | |
2364 } | |
2365 | |
2366 static void yahoo_got_web_connected(gpointer data, gint source, const gchar *error_message) | |
2367 { | |
2368 GaimConnection *gc = data; | |
2369 struct yahoo_data *yd; | |
2370 struct yahoo_packet *pkt; | |
2371 | |
2372 if (!GAIM_CONNECTION_IS_VALID(gc)) { | |
2373 close(source); | |
2374 return; | |
2375 } | |
2376 | |
2377 if (source < 0) { | |
2378 gaim_connection_error(gc, _("Unable to connect.")); | |
2379 return; | |
2380 } | |
2381 | |
2382 yd = gc->proto_data; | |
2383 yd->fd = source; | |
2384 | |
2385 pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, 0); | |
2386 | |
2387 yahoo_packet_hash(pkt, "sss", 0, | |
2388 gaim_normalize(gc->account, gaim_account_get_username(gaim_connection_get_account(gc))), | |
2389 1, gaim_normalize(gc->account, gaim_account_get_username(gaim_connection_get_account(gc))), | |
2390 6, yd->auth); | |
2391 yahoo_packet_send_and_free(pkt, yd); | |
2392 | |
2393 g_free(yd->auth); | |
2394 gc->inpa = gaim_input_add(yd->fd, GAIM_INPUT_READ, yahoo_pending, gc); | |
2395 } | |
2396 | |
2397 static void yahoo_web_pending(gpointer data, gint source, GaimInputCondition cond) | |
2398 { | |
2399 GaimConnection *gc = data; | |
2400 GaimAccount *account = gaim_connection_get_account(gc); | |
2401 struct yahoo_data *yd = gc->proto_data; | |
2402 char bufread[2048], *i = bufread, *buf = bufread; | |
2403 int len; | |
2404 GString *s; | |
2405 | |
2406 len = read(source, bufread, sizeof(bufread) - 1); | |
14426 | 2407 |
2408 if (len < 0) { | |
2409 gchar *tmp; | |
2410 | |
2411 if (errno == EAGAIN) | |
2412 /* No worries */ | |
2413 return; | |
2414 | |
2415 tmp = g_strdup_printf(_("Lost connection with server:\n%s"), | |
2416 strerror(errno)); | |
2417 gaim_connection_error(gc, tmp); | |
2418 g_free(tmp); | |
14192 | 2419 return; |
14426 | 2420 } else if (len == 0) { |
2421 gaim_connection_error(gc, _("Server closed the connection.")); | |
14192 | 2422 return; |
2423 } | |
2424 | |
2425 if (yd->rxlen > 0 || !g_strstr_len(buf, len, "\r\n\r\n")) { | |
2426 yd->rxqueue = g_realloc(yd->rxqueue, yd->rxlen + len + 1); | |
2427 memcpy(yd->rxqueue + yd->rxlen, buf, len); | |
2428 yd->rxlen += len; | |
14259 | 2429 i = buf = (char *)yd->rxqueue; |
14192 | 2430 len = yd->rxlen; |
2431 } | |
2432 buf[len] = '\0'; | |
2433 | |
2434 if ((strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302")) && | |
2435 strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) { | |
14426 | 2436 gaim_connection_error(gc, _("Received unexpected HTTP response from server.")); |
14192 | 2437 return; |
2438 } | |
2439 | |
2440 s = g_string_sized_new(len); | |
2441 | |
2442 while ((i = strstr(i, "Set-Cookie: "))) { | |
2443 i += strlen("Set-Cookie: "); | |
2444 for (;*i != ';' && *i != '\0'; i++) | |
2445 g_string_append_c(s, *i); | |
2446 | |
2447 g_string_append(s, "; "); | |
2448 } | |
2449 | |
2450 yd->auth = g_string_free(s, FALSE); | |
2451 gaim_input_remove(gc->inpa); | |
2452 close(source); | |
2453 g_free(yd->rxqueue); | |
2454 yd->rxqueue = NULL; | |
2455 yd->rxlen = 0; | |
2456 /* Now we have our cookies to login with. I'll go get the milk. */ | |
14837 | 2457 if (gaim_proxy_connect(gc, account, "wcs2.msg.dcn.yahoo.com", |
14192 | 2458 gaim_account_get_int(account, "port", YAHOO_PAGER_PORT), |
2459 yahoo_got_web_connected, gc) == NULL) { | |
2460 gaim_connection_error(gc, _("Connection problem")); | |
2461 return; | |
2462 } | |
2463 } | |
2464 | |
2465 static void yahoo_got_cookies_send_cb(gpointer data, gint source, GaimInputCondition cond) | |
2466 { | |
2467 GaimConnection *gc; | |
2468 struct yahoo_data *yd; | |
2469 int written, remaining; | |
2470 | |
2471 gc = data; | |
2472 yd = gc->proto_data; | |
2473 | |
2474 remaining = strlen(yd->auth) - yd->auth_written; | |
2475 written = write(source, yd->auth + yd->auth_written, remaining); | |
2476 | |
2477 if (written < 0 && errno == EAGAIN) | |
2478 written = 0; | |
2479 else if (written <= 0) { | |
2480 g_free(yd->auth); | |
2481 yd->auth = NULL; | |
2482 if (gc->inpa) | |
2483 gaim_input_remove(gc->inpa); | |
2484 gc->inpa = 0; | |
2485 gaim_connection_error(gc, _("Unable to connect.")); | |
2486 return; | |
2487 } | |
2488 | |
2489 if (written < remaining) { | |
2490 yd->auth_written += written; | |
2491 return; | |
2492 } | |
2493 | |
2494 g_free(yd->auth); | |
2495 yd->auth = NULL; | |
2496 yd->auth_written = 0; | |
2497 gaim_input_remove(gc->inpa); | |
2498 gc->inpa = gaim_input_add(source, GAIM_INPUT_READ, yahoo_web_pending, gc); | |
2499 } | |
2500 | |
2501 static void yahoo_got_cookies(gpointer data, gint source, const gchar *error_message) | |
2502 { | |
2503 GaimConnection *gc = data; | |
2504 | |
2505 if (source < 0) { | |
2506 gaim_connection_error(gc, _("Unable to connect.")); | |
2507 return; | |
2508 } | |
2509 | |
2510 if (gc->inpa == 0) | |
2511 { | |
2512 gc->inpa = gaim_input_add(source, GAIM_INPUT_WRITE, | |
2513 yahoo_got_cookies_send_cb, gc); | |
2514 yahoo_got_cookies_send_cb(gc, source, GAIM_INPUT_WRITE); | |
2515 } | |
2516 } | |
2517 | |
2518 static void yahoo_login_page_hash_iter(const char *key, const char *val, GString *url) | |
2519 { | |
2520 if (!strcmp(key, "passwd")) | |
2521 return; | |
2522 g_string_append_c(url, '&'); | |
2523 g_string_append(url, key); | |
2524 g_string_append_c(url, '='); | |
2525 if (!strcmp(key, ".save") || !strcmp(key, ".js")) | |
2526 g_string_append_c(url, '1'); | |
2527 else if (!strcmp(key, ".challenge")) | |
2528 g_string_append(url, val); | |
2529 else | |
2530 g_string_append(url, gaim_url_encode(val)); | |
2531 } | |
2532 | |
2533 static GHashTable *yahoo_login_page_hash(const char *buf, size_t len) | |
2534 { | |
2535 GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
2536 const char *c = buf; | |
2537 char *d; | |
2538 char name[64], value[64]; | |
2539 int count; | |
2540 int input_len = strlen("<input "); | |
2541 int name_len = strlen("name=\""); | |
2542 int value_len = strlen("value=\""); | |
2543 while ((len > ((c - buf) + input_len)) | |
2544 && (c = strstr(c, "<input "))) { | |
2545 if (!(c = g_strstr_len(c, len - (c - buf), "name=\""))) | |
2546 continue; | |
2547 c += name_len; | |
2548 count = sizeof(name)-1; | |
2549 for (d = name; (len > ((c - buf) + 1)) && *c!='"' | |
2550 && count; c++, d++, count--) | |
2551 *d = *c; | |
2552 *d = '\0'; | |
2553 count = sizeof(value)-1; | |
2554 if (!(d = g_strstr_len(c, len - (c - buf), "value=\""))) | |
2555 continue; | |
2556 d += value_len; | |
2557 if (strchr(c, '>') < d) | |
2558 break; | |
2559 for (c = d, d = value; (len > ((c - buf) + 1)) | |
2560 && *c!='"' && count; c++, d++, count--) | |
2561 *d = *c; | |
2562 *d = '\0'; | |
2563 g_hash_table_insert(hash, g_strdup(name), g_strdup(value)); | |
2564 } | |
2565 return hash; | |
2566 } | |
2567 | |
14354 | 2568 static void |
2569 yahoo_login_page_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, | |
2570 const gchar *url_text, size_t len, const gchar *error_message) | |
14192 | 2571 { |
2572 GaimConnection *gc = (GaimConnection *)user_data; | |
2573 GaimAccount *account = gaim_connection_get_account(gc); | |
2574 struct yahoo_data *yd = gc->proto_data; | |
2575 const char *sn = gaim_account_get_username(account); | |
2576 const char *pass = gaim_connection_get_password(gc); | |
14354 | 2577 GHashTable *hash = yahoo_login_page_hash(url_text, len); |
14192 | 2578 GString *url = g_string_new("GET http://login.yahoo.com/config/login?login="); |
2579 char md5[33], *hashp = md5, *chal; | |
2580 int i; | |
2581 GaimCipher *cipher; | |
2582 GaimCipherContext *context; | |
2583 guchar digest[16]; | |
2584 | |
14354 | 2585 yd->url_datas = g_slist_remove(yd->url_datas, url_data); |
2586 | |
14192 | 2587 url = g_string_append(url, sn); |
2588 url = g_string_append(url, "&passwd="); | |
2589 | |
2590 cipher = gaim_ciphers_find_cipher("md5"); | |
2591 context = gaim_cipher_context_new(cipher, NULL); | |
2592 | |
2593 gaim_cipher_context_append(context, (const guchar *)pass, strlen(pass)); | |
2594 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
2595 for (i = 0; i < 16; ++i) { | |
2596 g_snprintf(hashp, 3, "%02x", digest[i]); | |
2597 hashp += 2; | |
2598 } | |
2599 | |
2600 chal = g_strconcat(md5, g_hash_table_lookup(hash, ".challenge"), NULL); | |
2601 gaim_cipher_context_reset(context, NULL); | |
2602 gaim_cipher_context_append(context, (const guchar *)chal, strlen(chal)); | |
2603 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
2604 hashp = md5; | |
2605 for (i = 0; i < 16; ++i) { | |
2606 g_snprintf(hashp, 3, "%02x", digest[i]); | |
2607 hashp += 2; | |
2608 } | |
2609 /* | |
2610 * I dunno why this is here and commented out.. but in case it's needed | |
2611 * I updated it.. | |
2612 | |
2613 gaim_cipher_context_reset(context, NULL); | |
2614 gaim_cipher_context_append(context, md5, strlen(md5)); | |
2615 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
2616 hashp = md5; | |
2617 for (i = 0; i < 16; ++i) { | |
2618 g_snprintf(hashp, 3, "%02x", digest[i]); | |
2619 hashp += 2; | |
2620 } | |
2621 */ | |
2622 g_free(chal); | |
2623 | |
2624 url = g_string_append(url, md5); | |
2625 g_hash_table_foreach(hash, (GHFunc)yahoo_login_page_hash_iter, url); | |
2626 | |
2627 url = g_string_append(url, "&.hash=1&.md5=1 HTTP/1.1\r\n" | |
2628 "Host: login.yahoo.com\r\n\r\n"); | |
2629 g_hash_table_destroy(hash); | |
2630 yd->auth = g_string_free(url, FALSE); | |
14837 | 2631 if (gaim_proxy_connect(gc, account, "login.yahoo.com", 80, yahoo_got_cookies, gc) == NULL) { |
14192 | 2632 gaim_connection_error(gc, _("Connection problem")); |
2633 return; | |
2634 } | |
2635 | |
2636 gaim_cipher_context_destroy(context); | |
2637 } | |
2638 | |
2639 static void yahoo_server_check(GaimAccount *account) | |
2640 { | |
2641 const char *server; | |
2642 | |
2643 server = gaim_account_get_string(account, "server", YAHOO_PAGER_HOST); | |
2644 | |
2645 if (strcmp(server, "scs.yahoo.com") == 0) | |
2646 gaim_account_set_string(account, "server", YAHOO_PAGER_HOST); | |
2647 } | |
2648 | |
2649 static void yahoo_picture_check(GaimAccount *account) | |
2650 { | |
2651 GaimConnection *gc = gaim_account_get_connection(account); | |
2652 char *buddyicon; | |
2653 | |
2654 buddyicon = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(account)); | |
2655 yahoo_set_buddy_icon(gc, buddyicon); | |
2656 g_free(buddyicon); | |
2657 } | |
2658 | |
2659 static int get_yahoo_status_from_gaim_status(GaimStatus *status) | |
2660 { | |
2661 GaimPresence *presence; | |
2662 const char *status_id; | |
2663 const char *msg; | |
2664 | |
2665 presence = gaim_status_get_presence(status); | |
2666 status_id = gaim_status_get_id(status); | |
2667 msg = gaim_status_get_attr_string(status, "message"); | |
2668 | |
2669 if (!strcmp(status_id, YAHOO_STATUS_TYPE_AVAILABLE)) { | |
2670 if ((msg != NULL) && (*msg != '\0')) | |
2671 return YAHOO_STATUS_CUSTOM; | |
2672 else | |
2673 return YAHOO_STATUS_AVAILABLE; | |
2674 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BRB)) { | |
2675 return YAHOO_STATUS_BRB; | |
2676 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BUSY)) { | |
2677 return YAHOO_STATUS_BUSY; | |
2678 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATHOME)) { | |
2679 return YAHOO_STATUS_NOTATHOME; | |
2680 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATDESK)) { | |
2681 return YAHOO_STATUS_NOTATDESK; | |
2682 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTINOFFICE)) { | |
2683 return YAHOO_STATUS_NOTINOFFICE; | |
2684 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONPHONE)) { | |
2685 return YAHOO_STATUS_ONPHONE; | |
2686 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONVACATION)) { | |
2687 return YAHOO_STATUS_ONVACATION; | |
2688 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_OUTTOLUNCH)) { | |
2689 return YAHOO_STATUS_OUTTOLUNCH; | |
2690 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_STEPPEDOUT)) { | |
2691 return YAHOO_STATUS_STEPPEDOUT; | |
2692 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_INVISIBLE)) { | |
2693 return YAHOO_STATUS_INVISIBLE; | |
2694 } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_AWAY)) { | |
2695 return YAHOO_STATUS_CUSTOM; | |
2696 } else if (gaim_presence_is_idle(presence)) { | |
2697 return YAHOO_STATUS_IDLE; | |
2698 } else { | |
2699 gaim_debug_error("yahoo", "Unexpected GaimStatus!\n"); | |
2700 return YAHOO_STATUS_AVAILABLE; | |
2701 } | |
2702 } | |
2703 | |
2704 static void yahoo_login(GaimAccount *account) { | |
2705 GaimConnection *gc = gaim_account_get_connection(account); | |
2706 struct yahoo_data *yd = gc->proto_data = g_new0(struct yahoo_data, 1); | |
2707 GaimStatus *status = gaim_account_get_active_status(account); | |
2708 gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_URLDESC; | |
2709 | |
2710 gaim_connection_update_progress(gc, _("Connecting"), 1, 2); | |
2711 | |
2712 gaim_connection_set_display_name(gc, gaim_account_get_username(account)); | |
2713 | |
2714 yd->fd = -1; | |
2715 yd->txhandler = -1; | |
2716 /* TODO: Is there a good grow size for the buffer? */ | |
2717 yd->txbuf = gaim_circ_buffer_new(0); | |
2718 yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free); | |
2719 yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
2720 yd->confs = NULL; | |
2721 yd->conf_id = 2; | |
2722 | |
2723 yd->current_status = get_yahoo_status_from_gaim_status(status); | |
2724 | |
2725 yahoo_server_check(account); | |
2726 yahoo_picture_check(account); | |
2727 | |
2728 if (gaim_account_get_bool(account, "yahoojp", FALSE)) { | |
2729 yd->jp = TRUE; | |
14837 | 2730 if (gaim_proxy_connect(gc, account, |
14192 | 2731 gaim_account_get_string(account, "serverjp", YAHOOJP_PAGER_HOST), |
2732 gaim_account_get_int(account, "port", YAHOO_PAGER_PORT), | |
2733 yahoo_got_connected, gc) == NULL) | |
2734 { | |
2735 gaim_connection_error(gc, _("Connection problem")); | |
2736 return; | |
2737 } | |
2738 } else { | |
2739 yd->jp = FALSE; | |
14837 | 2740 if (gaim_proxy_connect(gc, account, |
14192 | 2741 gaim_account_get_string(account, "server", YAHOO_PAGER_HOST), |
2742 gaim_account_get_int(account, "port", YAHOO_PAGER_PORT), | |
2743 yahoo_got_connected, gc) == NULL) | |
2744 { | |
2745 gaim_connection_error(gc, _("Connection problem")); | |
2746 return; | |
2747 } | |
2748 } | |
2749 } | |
2750 | |
2751 static void yahoo_close(GaimConnection *gc) { | |
2752 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
2753 GSList *l; | |
2754 | |
2755 if (gc->inpa) | |
2756 gaim_input_remove(gc->inpa); | |
2757 | |
14354 | 2758 while (yd->url_datas) { |
2759 gaim_util_fetch_url_cancel(yd->url_datas->data); | |
2760 yd->url_datas = g_slist_delete_link(yd->url_datas, yd->url_datas); | |
2761 } | |
2762 | |
14192 | 2763 for (l = yd->confs; l; l = l->next) { |
2764 GaimConversation *conv = l->data; | |
2765 | |
2766 yahoo_conf_leave(yd, gaim_conversation_get_name(conv), | |
2767 gaim_connection_get_display_name(gc), | |
2768 gaim_conv_chat_get_users(GAIM_CONV_CHAT(conv))); | |
2769 } | |
2770 g_slist_free(yd->confs); | |
2771 | |
2772 yd->chat_online = 0; | |
2773 if (yd->in_chat) | |
2774 yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */ | |
2775 | |
2776 g_hash_table_destroy(yd->friends); | |
2777 g_hash_table_destroy(yd->imvironments); | |
2778 g_free(yd->chat_name); | |
2779 | |
2780 g_free(yd->cookie_y); | |
2781 g_free(yd->cookie_t); | |
2782 | |
2783 if (yd->txhandler) | |
2784 gaim_input_remove(yd->txhandler); | |
2785 | |
2786 gaim_circ_buffer_destroy(yd->txbuf); | |
2787 | |
2788 if (yd->fd >= 0) | |
2789 close(yd->fd); | |
2790 | |
2791 g_free(yd->rxqueue); | |
2792 yd->rxlen = 0; | |
2793 g_free(yd->picture_url); | |
2794 | |
14631
622931ca5622
[gaim-migrate @ 17377]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14542
diff
changeset
|
2795 if (yd->buddy_icon_connect_data) |
622931ca5622
[gaim-migrate @ 17377]
Evan Schoenberg <evan.s@dreskin.net>
parents:
14542
diff
changeset
|
2796 gaim_proxy_connect_cancel(yd->buddy_icon_connect_data); |
14192 | 2797 if (yd->picture_upload_todo) |
2798 yahoo_buddy_icon_upload_data_free(yd->picture_upload_todo); | |
2799 if (yd->ycht) | |
2800 ycht_connection_close(yd->ycht); | |
2801 | |
2802 g_free(yd); | |
2803 gc->proto_data = NULL; | |
2804 } | |
2805 | |
2806 static const char *yahoo_list_icon(GaimAccount *a, GaimBuddy *b) | |
2807 { | |
2808 return "yahoo"; | |
2809 } | |
2810 | |
2811 static void yahoo_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne) | |
2812 { | |
2813 int i = 0; | |
2814 char *emblems[4] = {NULL,NULL,NULL,NULL}; | |
2815 GaimAccount *account; | |
2816 GaimConnection *gc; | |
2817 struct yahoo_data *yd; | |
2818 YahooFriend *f; | |
2819 GaimPresence *presence; | |
2820 | |
2821 if (!b || !(account = b->account) || !(gc = gaim_account_get_connection(account)) || | |
2822 !(yd = gc->proto_data)) | |
2823 return; | |
2824 | |
2825 f = yahoo_friend_find(gc, b->name); | |
2826 if (!f) { | |
2827 *se = "notauthorized"; | |
2828 return; | |
2829 } | |
2830 | |
2831 presence = gaim_buddy_get_presence(b); | |
2832 | |
2833 if (gaim_presence_is_online(presence) == FALSE) { | |
2834 *se = "offline"; | |
2835 return; | |
2836 } else { | |
2837 if (f->away) | |
2838 emblems[i++] = "away"; | |
2839 if (f->sms) | |
2840 emblems[i++] = "wireless"; | |
2841 if (yahoo_friend_get_game(f)) | |
2842 emblems[i++] = "game"; | |
14304 | 2843 if (f->protocol == 2) |
2844 emblems[i] = "msn"; | |
14192 | 2845 } |
2846 *se = emblems[0]; | |
2847 *sw = emblems[1]; | |
2848 *nw = emblems[2]; | |
2849 *ne = emblems[3]; | |
2850 } | |
2851 | |
2852 static const char *yahoo_get_status_string(enum yahoo_status a) | |
2853 { | |
2854 switch (a) { | |
2855 case YAHOO_STATUS_BRB: | |
2856 return _("Be Right Back"); | |
2857 case YAHOO_STATUS_BUSY: | |
2858 return _("Busy"); | |
2859 case YAHOO_STATUS_NOTATHOME: | |
2860 return _("Not at Home"); | |
2861 case YAHOO_STATUS_NOTATDESK: | |
2862 return _("Not at Desk"); | |
2863 case YAHOO_STATUS_NOTINOFFICE: | |
2864 return _("Not in Office"); | |
2865 case YAHOO_STATUS_ONPHONE: | |
2866 return _("On the Phone"); | |
2867 case YAHOO_STATUS_ONVACATION: | |
2868 return _("On Vacation"); | |
2869 case YAHOO_STATUS_OUTTOLUNCH: | |
2870 return _("Out to Lunch"); | |
2871 case YAHOO_STATUS_STEPPEDOUT: | |
2872 return _("Stepped Out"); | |
2873 case YAHOO_STATUS_INVISIBLE: | |
2874 return _("Invisible"); | |
2875 case YAHOO_STATUS_IDLE: | |
2876 return _("Idle"); | |
2877 case YAHOO_STATUS_OFFLINE: | |
2878 return _("Offline"); | |
2879 default: | |
2880 return _("Available"); | |
2881 } | |
2882 } | |
2883 | |
2884 static void yahoo_initiate_conference(GaimBlistNode *node, gpointer data) { | |
2885 | |
2886 GaimBuddy *buddy; | |
2887 GaimConnection *gc; | |
2888 | |
2889 GHashTable *components; | |
2890 struct yahoo_data *yd; | |
2891 int id; | |
2892 | |
2893 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
2894 | |
2895 buddy = (GaimBuddy *) node; | |
2896 gc = gaim_account_get_connection(buddy->account); | |
2897 yd = gc->proto_data; | |
2898 id = yd->conf_id; | |
2899 | |
2900 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
2901 g_hash_table_replace(components, g_strdup("room"), | |
2902 g_strdup_printf("%s-%d", gaim_connection_get_display_name(gc), id)); | |
2903 g_hash_table_replace(components, g_strdup("topic"), g_strdup("Join my conference...")); | |
2904 g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference")); | |
2905 yahoo_c_join(gc, components); | |
2906 g_hash_table_destroy(components); | |
2907 | |
2908 yahoo_c_invite(gc, id, "Join my conference...", buddy->name); | |
2909 } | |
2910 | |
2911 static void yahoo_presence_settings(GaimBlistNode *node, gpointer data) { | |
2912 GaimBuddy *buddy; | |
2913 GaimConnection *gc; | |
2914 int presence_val = GPOINTER_TO_INT(data); | |
2915 | |
2916 buddy = (GaimBuddy *) node; | |
2917 gc = gaim_account_get_connection(buddy->account); | |
2918 | |
2919 yahoo_friend_update_presence(gc, buddy->name, presence_val); | |
2920 } | |
2921 | |
2922 static void yahoo_game(GaimBlistNode *node, gpointer data) { | |
2923 | |
2924 GaimBuddy *buddy; | |
2925 GaimConnection *gc; | |
2926 | |
2927 struct yahoo_data *yd; | |
2928 const char *game; | |
2929 char *game2; | |
2930 char *t; | |
2931 char url[256]; | |
2932 YahooFriend *f; | |
2933 | |
2934 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
2935 | |
2936 buddy = (GaimBuddy *) node; | |
2937 gc = gaim_account_get_connection(buddy->account); | |
2938 yd = (struct yahoo_data *) gc->proto_data; | |
2939 | |
2940 f = yahoo_friend_find(gc, buddy->name); | |
2941 if (!f) | |
2942 return; | |
2943 | |
2944 game = yahoo_friend_get_game(f); | |
2945 if (!game) | |
2946 return; | |
2947 | |
2948 t = game2 = g_strdup(strstr(game, "ante?room=")); | |
2949 while (*t && *t != '\t') | |
2950 t++; | |
2951 *t = 0; | |
2952 g_snprintf(url, sizeof url, "http://games.yahoo.com/games/%s", game2); | |
2953 gaim_notify_uri(gc, url); | |
2954 g_free(game2); | |
2955 } | |
2956 | |
2957 static char *yahoo_status_text(GaimBuddy *b) | |
2958 { | |
2959 YahooFriend *f = NULL; | |
2960 const char *msg; | |
2961 char *msg2; | |
2962 | |
2963 f = yahoo_friend_find(b->account->gc, b->name); | |
2964 if (!f) | |
2965 return g_strdup(_("Not on server list")); | |
2966 | |
2967 switch (f->status) { | |
2968 case YAHOO_STATUS_AVAILABLE: | |
2969 return NULL; | |
2970 case YAHOO_STATUS_IDLE: | |
2971 if (f->idle == -1) | |
2972 return g_strdup(yahoo_get_status_string(f->status)); | |
2973 return NULL; | |
2974 case YAHOO_STATUS_CUSTOM: | |
2975 if (!(msg = yahoo_friend_get_status_message(f))) | |
2976 return NULL; | |
2977 msg2 = g_markup_escape_text(msg, strlen(msg)); | |
2978 gaim_util_chrreplace(msg2, '\n', ' '); | |
2979 return msg2; | |
2980 | |
2981 default: | |
2982 return g_strdup(yahoo_get_status_string(f->status)); | |
2983 } | |
2984 } | |
2985 | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15142
diff
changeset
|
2986 void yahoo_tooltip_text(GaimBuddy *b, GaimNotifyUserInfo *user_info, gboolean full) |
14192 | 2987 { |
2988 YahooFriend *f; | |
2989 char *escaped; | |
2990 char *status = NULL; | |
2991 const char *presence = NULL; | |
2992 | |
2993 f = yahoo_friend_find(b->account->gc, b->name); | |
2994 if (!f) | |
2995 status = g_strdup_printf("\n%s", _("Not on server list")); | |
2996 else { | |
2997 switch (f->status) { | |
2998 case YAHOO_STATUS_CUSTOM: | |
2999 if (!yahoo_friend_get_status_message(f)) | |
3000 return; | |
3001 status = g_strdup(yahoo_friend_get_status_message(f)); | |
3002 break; | |
3003 case YAHOO_STATUS_OFFLINE: | |
3004 break; | |
3005 default: | |
3006 status = g_strdup(yahoo_get_status_string(f->status)); | |
3007 break; | |
3008 } | |
3009 | |
3010 switch (f->presence) { | |
3011 case YAHOO_PRESENCE_ONLINE: | |
3012 presence = _("Appear Online"); | |
3013 break; | |
3014 case YAHOO_PRESENCE_PERM_OFFLINE: | |
3015 presence = _("Appear Permanently Offline"); | |
3016 break; | |
3017 case YAHOO_PRESENCE_DEFAULT: | |
3018 break; | |
3019 default: | |
3020 gaim_debug_error("yahoo", "Unknown presence in yahoo_tooltip_text\n"); | |
3021 break; | |
3022 } | |
3023 } | |
3024 | |
3025 if (status != NULL) { | |
3026 escaped = g_markup_escape_text(status, strlen(status)); | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15142
diff
changeset
|
3027 gaim_notify_user_info_add_pair(user_info, _("Status"), escaped); |
14192 | 3028 g_free(status); |
3029 g_free(escaped); | |
3030 } | |
3031 | |
3032 if (presence != NULL) | |
15143
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15142
diff
changeset
|
3033 gaim_notify_user_info_add_pair(user_info, _("Presence"), presence); |
14192 | 3034 } |
3035 | |
3036 static void yahoo_addbuddyfrommenu_cb(GaimBlistNode *node, gpointer data) | |
3037 { | |
3038 GaimBuddy *buddy; | |
3039 GaimConnection *gc; | |
3040 | |
3041 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
3042 | |
3043 buddy = (GaimBuddy *) node; | |
3044 gc = gaim_account_get_connection(buddy->account); | |
3045 | |
3046 yahoo_add_buddy(gc, buddy, NULL); | |
3047 } | |
3048 | |
3049 | |
3050 static void yahoo_chat_goto_menu(GaimBlistNode *node, gpointer data) | |
3051 { | |
3052 GaimBuddy *buddy; | |
3053 GaimConnection *gc; | |
3054 | |
3055 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
3056 | |
3057 buddy = (GaimBuddy *) node; | |
3058 gc = gaim_account_get_connection(buddy->account); | |
3059 | |
3060 yahoo_chat_goto(gc, buddy->name); | |
3061 } | |
3062 | |
3063 static GList *build_presence_submenu(YahooFriend *f, GaimConnection *gc) { | |
3064 GList *m = NULL; | |
3065 GaimMenuAction *act; | |
3066 struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; | |
3067 | |
3068 if (yd->current_status == YAHOO_STATUS_INVISIBLE) { | |
3069 if (f->presence != YAHOO_PRESENCE_ONLINE) { | |
3070 act = gaim_menu_action_new(_("Appear Online"), | |
3071 GAIM_CALLBACK(yahoo_presence_settings), | |
3072 GINT_TO_POINTER(YAHOO_PRESENCE_ONLINE), | |
3073 NULL); | |
3074 m = g_list_append(m, act); | |
3075 } else if (f->presence != YAHOO_PRESENCE_DEFAULT) { | |
3076 act = gaim_menu_action_new(_("Appear Offline"), | |
3077 GAIM_CALLBACK(yahoo_presence_settings), | |
3078 GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT), | |
3079 NULL); | |
3080 m = g_list_append(m, act); | |
3081 } | |
3082 } | |
3083 | |
3084 if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) { | |
3085 act = gaim_menu_action_new(_("Don't Appear Permanently Offline"), | |
3086 GAIM_CALLBACK(yahoo_presence_settings), | |
3087 GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT), | |
3088 NULL); | |
3089 m = g_list_append(m, act); | |
3090 } else { | |
3091 act = gaim_menu_action_new(_("Appear Permanently Offline"), | |
3092 GAIM_CALLBACK(yahoo_presence_settings), | |
3093 GINT_TO_POINTER(YAHOO_PRESENCE_PERM_OFFLINE), | |
3094 NULL); | |
3095 m = g_list_append(m, act); | |
3096 } | |
3097 | |
3098 return m; | |
3099 } | |
3100 | |
3101 static void yahoo_doodle_blist_node(GaimBlistNode *node, gpointer data) | |
3102 { | |
3103 GaimBuddy *b = (GaimBuddy *)node; | |
3104 GaimConnection *gc = b->account->gc; | |
3105 | |
3106 yahoo_doodle_initiate(gc, b->name); | |
3107 } | |
3108 | |
3109 static GList *yahoo_buddy_menu(GaimBuddy *buddy) | |
3110 { | |
3111 GList *m = NULL; | |
3112 GaimMenuAction *act; | |
3113 | |
3114 GaimConnection *gc = gaim_account_get_connection(buddy->account); | |
3115 struct yahoo_data *yd = gc->proto_data; | |
3116 static char buf2[1024]; | |
3117 YahooFriend *f; | |
3118 | |
3119 f = yahoo_friend_find(gc, buddy->name); | |
3120 | |
3121 if (!f && !yd->wm) { | |
3122 act = gaim_menu_action_new(_("Add Buddy"), | |
3123 GAIM_CALLBACK(yahoo_addbuddyfrommenu_cb), | |
3124 NULL, NULL); | |
3125 m = g_list_append(m, act); | |
3126 | |
3127 return m; | |
3128 | |
3129 } | |
3130 | |
3131 if (f && f->status != YAHOO_STATUS_OFFLINE) { | |
3132 if (!yd->wm) { | |
3133 act = gaim_menu_action_new(_("Join in Chat"), | |
3134 GAIM_CALLBACK(yahoo_chat_goto_menu), | |
3135 NULL, NULL); | |
3136 m = g_list_append(m, act); | |
3137 } | |
3138 | |
3139 act = gaim_menu_action_new(_("Initiate Conference"), | |
3140 GAIM_CALLBACK(yahoo_initiate_conference), | |
3141 NULL, NULL); | |
3142 m = g_list_append(m, act); | |
3143 | |
3144 if (yahoo_friend_get_game(f)) { | |
3145 const char *game = yahoo_friend_get_game(f); | |
3146 char *room; | |
3147 char *t; | |
3148 | |
3149 if ((room = strstr(game, "&follow="))) {/* skip ahead to the url */ | |
3150 while (*room && *room != '\t') /* skip to the tab */ | |
3151 room++; | |
3152 t = room++; /* room as now at the name */ | |
3153 while (*t != '\n') | |
3154 t++; /* replace the \n with a space */ | |
3155 *t = ' '; | |
3156 g_snprintf(buf2, sizeof buf2, "%s", room); | |
3157 | |
3158 act = gaim_menu_action_new(buf2, | |
3159 GAIM_CALLBACK(yahoo_game), | |
3160 NULL, NULL); | |
3161 m = g_list_append(m, act); | |
3162 } | |
3163 } | |
3164 } | |
3165 | |
3166 if (f) { | |
3167 act = gaim_menu_action_new(_("Presence Settings"), NULL, NULL, | |
3168 build_presence_submenu(f, gc)); | |
3169 m = g_list_append(m, act); | |
3170 } | |
3171 | |
3172 if (f) { | |
3173 act = gaim_menu_action_new(_("Start Doodling"), | |
3174 GAIM_CALLBACK(yahoo_doodle_blist_node), | |
3175 NULL, NULL); | |
3176 m = g_list_append(m, act); | |
3177 } | |
3178 | |
3179 return m; | |
3180 } | |
3181 | |
3182 static GList *yahoo_blist_node_menu(GaimBlistNode *node) | |
3183 { | |
3184 if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
3185 return yahoo_buddy_menu((GaimBuddy *) node); | |
3186 } else { | |
3187 return NULL; | |
3188 } | |
3189 } | |
3190 | |
3191 static void yahoo_act_id(GaimConnection *gc, const char *entry) | |
3192 { | |
3193 struct yahoo_data *yd = gc->proto_data; | |
3194 | |
3195 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, 0); | |
3196 yahoo_packet_hash_str(pkt, 3, entry); | |
3197 yahoo_packet_send_and_free(pkt, yd); | |
3198 | |
3199 gaim_connection_set_display_name(gc, entry); | |
3200 } | |
3201 | |
3202 static void yahoo_show_act_id(GaimPluginAction *action) | |
3203 { | |
3204 GaimConnection *gc = (GaimConnection *) action->context; | |
3205 gaim_request_input(gc, NULL, _("Active which ID?"), NULL, | |
3206 gaim_connection_get_display_name(gc), FALSE, FALSE, NULL, | |
3207 _("OK"), G_CALLBACK(yahoo_act_id), | |
3208 _("Cancel"), NULL, gc); | |
3209 } | |
3210 | |
3211 static void yahoo_show_chat_goto(GaimPluginAction *action) | |
3212 { | |
3213 GaimConnection *gc = (GaimConnection *) action->context; | |
3214 gaim_request_input(gc, NULL, _("Join who in chat?"), NULL, | |
3215 "", FALSE, FALSE, NULL, | |
3216 _("OK"), G_CALLBACK(yahoo_chat_goto), | |
3217 _("Cancel"), NULL, gc); | |
3218 } | |
3219 | |
3220 static GList *yahoo_actions(GaimPlugin *plugin, gpointer context) { | |
3221 GList *m = NULL; | |
3222 GaimPluginAction *act; | |
3223 | |
3224 act = gaim_plugin_action_new(_("Activate ID..."), | |
3225 yahoo_show_act_id); | |
3226 m = g_list_append(m, act); | |
3227 | |
3228 act = gaim_plugin_action_new(_("Join User in Chat..."), | |
3229 yahoo_show_chat_goto); | |
3230 m = g_list_append(m, act); | |
3231 | |
3232 return m; | |
3233 } | |
3234 | |
3235 static int yahoo_send_im(GaimConnection *gc, const char *who, const char *what, GaimMessageFlags flags) | |
3236 { | |
3237 struct yahoo_data *yd = gc->proto_data; | |
3238 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0); | |
3239 char *msg = yahoo_html_to_codes(what); | |
3240 char *msg2; | |
3241 gboolean utf8 = TRUE; | |
3242 GaimWhiteboard *wb; | |
3243 int ret = 1; | |
14258 | 3244 YahooFriend *f = NULL; |
14192 | 3245 |
3246 msg2 = yahoo_string_encode(gc, msg, &utf8); | |
3247 | |
3248 yahoo_packet_hash(pkt, "ss", 1, gaim_connection_get_display_name(gc), 5, who); | |
14284 | 3249 if ((f = yahoo_friend_find(gc, who)) && f->protocol) |
3250 yahoo_packet_hash_int(pkt, 241, f->protocol); | |
14258 | 3251 |
14192 | 3252 if (utf8) |
3253 yahoo_packet_hash_str(pkt, 97, "1"); | |
3254 yahoo_packet_hash_str(pkt, 14, msg2); | |
3255 | |
3256 /* | |
3257 * IMVironment. | |
3258 * | |
3259 * If this message is to a user who is also Doodling with the local user, | |
3260 * format the chat packet with the correct IMV information (thanks Yahoo!) | |
3261 * | |
3262 * Otherwise attempt to use the same IMVironment as the remote user, | |
3263 * just so that we don't inadvertantly reset their IMVironment back | |
3264 * to nothing. | |
3265 * | |
3266 * If they have no set an IMVironment, then use the default. | |
3267 */ | |
3268 wb = gaim_whiteboard_get_session(gc->account, who); | |
3269 if (wb) | |
3270 yahoo_packet_hash_str(pkt, 63, "doodle;11"); | |
3271 else | |
3272 { | |
3273 const char *imv; | |
3274 imv = g_hash_table_lookup(yd->imvironments, who); | |
3275 if (imv != NULL) | |
3276 yahoo_packet_hash_str(pkt, 63, imv); | |
3277 else | |
3278 yahoo_packet_hash_str(pkt, 63, ";0"); | |
3279 } | |
3280 | |
3281 yahoo_packet_hash_str(pkt, 64, "0"); /* no idea */ | |
3282 yahoo_packet_hash_str(pkt, 1002, "1"); /* no idea, Yahoo 6 or later only it seems */ | |
3283 if (!yd->picture_url) | |
3284 yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */ | |
3285 else | |
3286 yahoo_packet_hash_str(pkt, 206, "2"); | |
3287 | |
3288 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */ | |
3289 if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) | |
3290 yahoo_packet_send(pkt, yd); | |
3291 else | |
3292 ret = -E2BIG; | |
3293 | |
3294 yahoo_packet_free(pkt); | |
3295 | |
3296 g_free(msg); | |
3297 g_free(msg2); | |
3298 | |
3299 return ret; | |
3300 } | |
3301 | |
3302 static unsigned int yahoo_send_typing(GaimConnection *gc, const char *who, GaimTypingState state) | |
3303 { | |
3304 struct yahoo_data *yd = gc->proto_data; | |
3305 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); | |
3306 yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, gaim_connection_get_display_name(gc), | |
3307 14, " ", 13, state == GAIM_TYPING ? "1" : "0", | |
3308 5, who, 1002, "1"); | |
3309 | |
3310 yahoo_packet_send_and_free(pkt, yd); | |
3311 | |
3312 return 0; | |
3313 } | |
3314 | |
3315 static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data) | |
3316 { | |
3317 YahooFriend *f = value; | |
3318 if (f && f->presence == YAHOO_PRESENCE_ONLINE) | |
3319 f->presence = YAHOO_PRESENCE_DEFAULT; | |
3320 } | |
3321 | |
3322 static void yahoo_set_status(GaimAccount *account, GaimStatus *status) | |
3323 { | |
3324 GaimConnection *gc; | |
3325 GaimPresence *presence; | |
3326 struct yahoo_data *yd; | |
3327 struct yahoo_packet *pkt; | |
3328 int old_status; | |
3329 const char *msg = NULL; | |
3330 char *tmp = NULL; | |
3331 char *conv_msg = NULL; | |
3332 | |
3333 if (!gaim_status_is_active(status)) | |
3334 return; | |
3335 | |
3336 gc = gaim_account_get_connection(account); | |
3337 presence = gaim_status_get_presence(status); | |
3338 yd = (struct yahoo_data *)gc->proto_data; | |
3339 old_status = yd->current_status; | |
3340 | |
3341 yd->current_status = get_yahoo_status_from_gaim_status(status); | |
3342 | |
3343 if (yd->current_status == YAHOO_STATUS_CUSTOM) | |
3344 { | |
3345 msg = gaim_status_get_attr_string(status, "message"); | |
3346 | |
3347 if (gaim_status_is_available(status)) { | |
3348 tmp = yahoo_string_encode(gc, msg, NULL); | |
3349 conv_msg = gaim_markup_strip_html(tmp); | |
3350 g_free(tmp); | |
3351 } else { | |
3352 if ((msg == NULL) || (*msg == '\0')) | |
3353 msg = _("Away"); | |
3354 tmp = yahoo_string_encode(gc, msg, NULL); | |
3355 conv_msg = gaim_markup_strip_html(tmp); | |
3356 g_free(tmp); | |
3357 } | |
3358 } | |
3359 | |
3360 if (yd->current_status == YAHOO_STATUS_INVISIBLE) { | |
3361 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, 0); | |
3362 yahoo_packet_hash_str(pkt, 13, "2"); | |
3363 yahoo_packet_send_and_free(pkt, yd); | |
3364 | |
3365 return; | |
3366 } | |
3367 | |
3368 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0); | |
3369 yahoo_packet_hash_int(pkt, 10, yd->current_status); | |
3370 | |
3371 if (yd->current_status == YAHOO_STATUS_CUSTOM) { | |
3372 yahoo_packet_hash_str(pkt, 19, conv_msg); | |
3373 } else { | |
3374 yahoo_packet_hash_str(pkt, 19, ""); | |
3375 } | |
3376 | |
3377 g_free(conv_msg); | |
3378 | |
3379 if (gaim_presence_is_idle(presence)) | |
3380 yahoo_packet_hash_str(pkt, 47, "2"); | |
3381 else if (!gaim_status_is_available(status)) | |
3382 yahoo_packet_hash_str(pkt, 47, "1"); | |
3383 | |
3384 yahoo_packet_send_and_free(pkt, yd); | |
3385 | |
3386 if (old_status == YAHOO_STATUS_INVISIBLE) { | |
3387 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, 0); | |
3388 yahoo_packet_hash_str(pkt, 13, "1"); | |
3389 yahoo_packet_send_and_free(pkt, yd); | |
3390 | |
3391 /* Any per-session presence settings are removed */ | |
3392 g_hash_table_foreach(yd->friends, yahoo_session_presence_remove, NULL); | |
3393 | |
3394 } | |
3395 } | |
3396 | |
3397 static void yahoo_set_idle(GaimConnection *gc, int idle) | |
3398 { | |
3399 struct yahoo_data *yd = gc->proto_data; | |
3400 struct yahoo_packet *pkt = NULL; | |
3401 char *msg = NULL, *msg2 = NULL; | |
3402 GaimStatus *status = NULL; | |
3403 | |
3404 if (idle && yd->current_status != YAHOO_STATUS_CUSTOM) | |
3405 yd->current_status = YAHOO_STATUS_IDLE; | |
3406 else if (!idle && yd->current_status == YAHOO_STATUS_IDLE) { | |
3407 status = gaim_presence_get_active_status(gaim_account_get_presence(gaim_connection_get_account(gc))); | |
3408 yd->current_status = get_yahoo_status_from_gaim_status(status); | |
3409 } | |
3410 | |
3411 pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0); | |
3412 | |
3413 yahoo_packet_hash_int(pkt, 10, yd->current_status); | |
3414 if (yd->current_status == YAHOO_STATUS_CUSTOM) { | |
3415 const char *tmp; | |
3416 if (status == NULL) | |
3417 status = gaim_presence_get_active_status(gaim_account_get_presence(gaim_connection_get_account(gc))); | |
3418 tmp = gaim_status_get_attr_string(status, "message"); | |
3419 if (tmp != NULL) { | |
3420 msg = yahoo_string_encode(gc, tmp, NULL); | |
3421 msg2 = gaim_markup_strip_html(msg); | |
3422 yahoo_packet_hash_str(pkt, 19, msg2); | |
3423 } else { | |
3424 /* get_yahoo_status_from_gaim_status() returns YAHOO_STATUS_CUSTOM for | |
3425 * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */ | |
3426 yahoo_packet_hash_str(pkt, 19, _("Away")); | |
3427 } | |
3428 } else { | |
3429 yahoo_packet_hash_str(pkt, 19, ""); | |
3430 } | |
3431 | |
3432 if (idle) | |
3433 yahoo_packet_hash_str(pkt, 47, "2"); | |
3434 else if (!gaim_presence_is_available(gaim_account_get_presence(gaim_connection_get_account(gc)))) | |
3435 yahoo_packet_hash_str(pkt, 47, "1"); | |
3436 | |
3437 yahoo_packet_send_and_free(pkt, yd); | |
3438 | |
3439 g_free(msg); | |
3440 g_free(msg2); | |
3441 } | |
3442 | |
3443 static GList *yahoo_status_types(GaimAccount *account) | |
3444 { | |
3445 GaimStatusType *type; | |
3446 GList *types = NULL; | |
3447 | |
3448 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AVAILABLE, YAHOO_STATUS_TYPE_AVAILABLE, | |
3449 NULL, TRUE, TRUE, FALSE, | |
3450 "message", _("Message"), | |
3451 gaim_value_new(GAIM_TYPE_STRING), NULL); | |
3452 types = g_list_append(types, type); | |
3453 | |
3454 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_AWAY, | |
3455 NULL, TRUE, TRUE, FALSE, | |
3456 "message", _("Message"), | |
3457 gaim_value_new(GAIM_TYPE_STRING), NULL); | |
3458 types = g_list_append(types, type); | |
3459 | |
3460 type = gaim_status_type_new(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_BRB, _("Be Right Back"), TRUE); | |
3461 types = g_list_append(types, type); | |
3462 | |
3463 type = gaim_status_type_new(GAIM_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_BUSY, _("Busy"), TRUE); | |
3464 types = g_list_append(types, type); | |
3465 | |
3466 type = gaim_status_type_new(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATHOME, _("Not at Home"), TRUE); | |
3467 types = g_list_append(types, type); | |
3468 | |
3469 type = gaim_status_type_new(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATDESK, _("Not at Desk"), TRUE); | |
3470 types = g_list_append(types, type); | |
3471 | |
3472 type = gaim_status_type_new(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTINOFFICE, _("Not in Office"), TRUE); | |
3473 types = g_list_append(types, type); | |
3474 | |
3475 type = gaim_status_type_new(GAIM_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_ONPHONE, _("On the Phone"), TRUE); | |
3476 types = g_list_append(types, type); | |
3477 | |
3478 type = gaim_status_type_new(GAIM_STATUS_EXTENDED_AWAY, YAHOO_STATUS_TYPE_ONVACATION, _("On Vacation"), TRUE); | |
3479 types = g_list_append(types, type); | |
3480 | |
3481 type = gaim_status_type_new(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_OUTTOLUNCH, _("Out to Lunch"), TRUE); | |
3482 types = g_list_append(types, type); | |
3483 | |
3484 type = gaim_status_type_new(GAIM_STATUS_AWAY, YAHOO_STATUS_TYPE_STEPPEDOUT, _("Stepped Out"), TRUE); | |
3485 types = g_list_append(types, type); | |
3486 | |
3487 | |
3488 type = gaim_status_type_new(GAIM_STATUS_INVISIBLE, YAHOO_STATUS_TYPE_INVISIBLE, NULL, TRUE); | |
3489 types = g_list_append(types, type); | |
3490 | |
3491 type = gaim_status_type_new(GAIM_STATUS_OFFLINE, YAHOO_STATUS_TYPE_OFFLINE, NULL, TRUE); | |
3492 types = g_list_append(types, type); | |
3493 | |
3494 return types; | |
3495 } | |
3496 | |
3497 static void yahoo_keepalive(GaimConnection *gc) | |
3498 { | |
3499 struct yahoo_data *yd = gc->proto_data; | |
3500 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, 0); | |
3501 yahoo_packet_send_and_free(pkt, yd); | |
3502 | |
3503 if (!yd->chat_online) | |
3504 return; | |
3505 | |
3506 if (yd->wm) { | |
3507 ycht_chat_send_keepalive(yd->ycht); | |
3508 return; | |
3509 } | |
3510 | |
3511 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, 0); | |
3512 yahoo_packet_hash_str(pkt, 109, gaim_connection_get_display_name(gc)); | |
3513 yahoo_packet_send_and_free(pkt, yd); | |
3514 } | |
3515 | |
3516 /* XXX - What's the deal with GaimGroup *foo? */ | |
3517 static void yahoo_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *foo) | |
3518 { | |
3519 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
3520 struct yahoo_packet *pkt; | |
3521 GaimGroup *g; | |
3522 char *group = NULL; | |
3523 char *group2 = NULL; | |
3524 | |
3525 if (!yd->logged_in) | |
3526 return; | |
3527 | |
3528 if (!yahoo_privacy_check(gc, gaim_buddy_get_name(buddy))) | |
3529 return; | |
3530 | |
3531 if (foo) | |
3532 group = foo->name; | |
3533 if (!group) { | |
3534 g = gaim_buddy_get_group(buddy); | |
3535 if (g) | |
3536 group = g->name; | |
3537 else | |
3538 group = "Buddies"; | |
3539 } | |
3540 | |
3541 group2 = yahoo_string_encode(gc, group, NULL); | |
3542 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0); | |
3543 yahoo_packet_hash(pkt, "ssss", 1, gaim_connection_get_display_name(gc), | |
3544 7, buddy->name, 65, group2, 14, ""); | |
3545 yahoo_packet_send_and_free(pkt, yd); | |
3546 g_free(group2); | |
3547 } | |
3548 | |
3549 static void yahoo_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) | |
3550 { | |
3551 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
3552 struct yahoo_packet *pkt; | |
3553 GSList *buddies, *l; | |
3554 GaimGroup *g; | |
3555 gboolean remove = TRUE; | |
3556 char *cg; | |
3557 | |
3558 if (!(yahoo_friend_find(gc, buddy->name))) | |
3559 return; | |
3560 | |
3561 buddies = gaim_find_buddies(gaim_connection_get_account(gc), buddy->name); | |
3562 for (l = buddies; l; l = l->next) { | |
3563 g = gaim_buddy_get_group(l->data); | |
3564 if (gaim_utf8_strcasecmp(group->name, g->name)) { | |
3565 remove = FALSE; | |
3566 break; | |
3567 } | |
3568 } | |
3569 | |
3570 g_slist_free(buddies); | |
3571 | |
3572 if (remove) | |
3573 g_hash_table_remove(yd->friends, buddy->name); | |
3574 | |
3575 cg = yahoo_string_encode(gc, group->name, NULL); | |
3576 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); | |
3577 yahoo_packet_hash(pkt, "sss", 1, gaim_connection_get_display_name(gc), | |
3578 7, buddy->name, 65, cg); | |
3579 yahoo_packet_send_and_free(pkt, yd); | |
3580 g_free(cg); | |
3581 } | |
3582 | |
3583 static void yahoo_add_deny(GaimConnection *gc, const char *who) { | |
3584 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
3585 struct yahoo_packet *pkt; | |
3586 | |
3587 if (!yd->logged_in) | |
3588 return; | |
3589 /* It seems to work better without this */ | |
3590 | |
3591 /* if (gc->account->perm_deny != 4) | |
3592 return; */ | |
3593 | |
3594 if (!who || who[0] == '\0') | |
3595 return; | |
3596 | |
3597 pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, 0); | |
3598 yahoo_packet_hash(pkt, "sss", 1, gaim_connection_get_display_name(gc), | |
3599 7, who, 13, "1"); | |
3600 yahoo_packet_send_and_free(pkt, yd); | |
3601 } | |
3602 | |
3603 static void yahoo_rem_deny(GaimConnection *gc, const char *who) { | |
3604 struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; | |
3605 struct yahoo_packet *pkt; | |
3606 | |
3607 if (!yd->logged_in) | |
3608 return; | |
3609 | |
3610 if (!who || who[0] == '\0') | |
3611 return; | |
3612 | |
3613 pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, 0); | |
3614 yahoo_packet_hash(pkt, "sss", 1, gaim_connection_get_display_name(gc), 7, who, 13, "2"); | |
3615 yahoo_packet_send_and_free(pkt, yd); | |
3616 } | |
3617 | |
3618 static void yahoo_set_permit_deny(GaimConnection *gc) { | |
3619 GaimAccount *acct; | |
3620 GSList *deny; | |
3621 | |
3622 acct = gc->account; | |
3623 | |
3624 switch (acct->perm_deny) { | |
3625 /* privacy 1 */ | |
3626 case GAIM_PRIVACY_ALLOW_ALL: | |
3627 for (deny = acct->deny;deny;deny = deny->next) | |
3628 yahoo_rem_deny(gc, deny->data); | |
3629 break; | |
3630 /* privacy 3 */ | |
3631 case GAIM_PRIVACY_ALLOW_USERS: | |
3632 for (deny = acct->deny;deny;deny = deny->next) | |
3633 yahoo_rem_deny(gc, deny->data); | |
3634 break; | |
3635 /* privacy 5 */ | |
3636 case GAIM_PRIVACY_ALLOW_BUDDYLIST: | |
3637 /* privacy 4 */ | |
3638 case GAIM_PRIVACY_DENY_USERS: | |
3639 for (deny = acct->deny;deny;deny = deny->next) | |
3640 yahoo_add_deny(gc, deny->data); | |
3641 break; | |
3642 /* privacy 2 */ | |
3643 case GAIM_PRIVACY_DENY_ALL: | |
3644 default: | |
3645 break; | |
3646 } | |
3647 } | |
3648 | |
3649 static gboolean yahoo_unload_plugin(GaimPlugin *plugin) | |
3650 { | |
3651 yahoo_dest_colorht(); | |
3652 | |
3653 return TRUE; | |
3654 } | |
3655 | |
3656 static void yahoo_change_buddys_group(GaimConnection *gc, const char *who, | |
3657 const char *old_group, const char *new_group) | |
3658 { | |
3659 struct yahoo_data *yd = gc->proto_data; | |
3660 struct yahoo_packet *pkt; | |
3661 char *gpn, *gpo; | |
3662 | |
3663 /* Step 0: If they aren't on the server list anyway, | |
3664 * don't bother letting the server know. | |
3665 */ | |
3666 if (!yahoo_friend_find(gc, who)) | |
3667 return; | |
3668 | |
3669 /* If old and new are the same, we would probably | |
3670 * end up deleting the buddy, which would be bad. | |
3671 * This might happen because of the charset conversation. | |
3672 */ | |
3673 gpn = yahoo_string_encode(gc, new_group, NULL); | |
3674 gpo = yahoo_string_encode(gc, old_group, NULL); | |
3675 if (!strcmp(gpn, gpo)) { | |
3676 g_free(gpn); | |
3677 g_free(gpo); | |
3678 return; | |
3679 } | |
3680 | |
3681 /* Step 1: Add buddy to new group. */ | |
3682 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0); | |
3683 yahoo_packet_hash(pkt, "ssss", 1, gaim_connection_get_display_name(gc), | |
3684 7, who, 65, gpn, 14, ""); | |
3685 yahoo_packet_send_and_free(pkt, yd); | |
3686 | |
3687 /* Step 2: Remove buddy from old group */ | |
3688 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); | |
3689 yahoo_packet_hash(pkt, "sss", 1, gaim_connection_get_display_name(gc), 7, who, 65, gpo); | |
3690 yahoo_packet_send_and_free(pkt, yd); | |
3691 g_free(gpn); | |
3692 g_free(gpo); | |
3693 } | |
3694 | |
3695 static void yahoo_rename_group(GaimConnection *gc, const char *old_name, | |
3696 GaimGroup *group, GList *moved_buddies) | |
3697 { | |
3698 struct yahoo_data *yd = gc->proto_data; | |
3699 struct yahoo_packet *pkt; | |
3700 char *gpn, *gpo; | |
3701 | |
3702 gpn = yahoo_string_encode(gc, group->name, NULL); | |
3703 gpo = yahoo_string_encode(gc, old_name, NULL); | |
3704 if (!strcmp(gpn, gpo)) { | |
3705 g_free(gpn); | |
3706 g_free(gpo); | |
3707 return; | |
3708 } | |
3709 | |
3710 pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, 0); | |
3711 yahoo_packet_hash(pkt, "sss", 1, gaim_connection_get_display_name(gc), | |
3712 65, gpo, 67, gpn); | |
3713 yahoo_packet_send_and_free(pkt, yd); | |
3714 g_free(gpn); | |
3715 g_free(gpo); | |
3716 } | |
3717 | |
3718 /********************************* Commands **********************************/ | |
3719 | |
3720 static GaimCmdRet | |
3721 yahoogaim_cmd_buzz(GaimConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data) { | |
3722 | |
3723 GaimAccount *account = gaim_conversation_get_account(c); | |
3724 const char *username = gaim_account_get_username(account); | |
3725 | |
3726 if (*args && args[0]) | |
3727 return GAIM_CMD_RET_FAILED; | |
3728 | |
3729 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
3730 "Sending <ding> on account %s to buddy %s.\n", username, c->name); | |
3731 gaim_conv_im_send(GAIM_CONV_IM(c), "<ding>"); | |
3732 gaim_conv_im_write(GAIM_CONV_IM(c), "", _("Buzz!!"), GAIM_MESSAGE_NICK|GAIM_MESSAGE_SEND, time(NULL)); | |
3733 return GAIM_CMD_RET_OK; | |
3734 } | |
3735 | |
3736 static GaimPlugin *my_protocol = NULL; | |
3737 | |
3738 static GaimCmdRet | |
3739 yahoogaim_cmd_chat_join(GaimConversation *conv, const char *cmd, | |
3740 char **args, char **error, void *data) | |
3741 { | |
3742 GHashTable *comp; | |
3743 GaimConnection *gc; | |
3744 struct yahoo_data *yd; | |
3745 int id; | |
3746 | |
3747 if (!args || !args[0]) | |
3748 return GAIM_CMD_RET_FAILED; | |
3749 | |
3750 gc = gaim_conversation_get_gc(conv); | |
3751 yd = gc->proto_data; | |
3752 id = yd->conf_id; | |
3753 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
3754 "Trying to join %s \n", args[0]); | |
3755 | |
3756 comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
3757 g_hash_table_replace(comp, g_strdup("room"), | |
3758 g_strdup_printf("%s", g_ascii_strdown(args[0], strlen(args[0])))); | |
3759 g_hash_table_replace(comp, g_strdup("type"), g_strdup("Chat")); | |
3760 | |
3761 yahoo_c_join(gc, comp); | |
3762 | |
3763 g_hash_table_destroy(comp); | |
3764 return GAIM_CMD_RET_OK; | |
3765 } | |
3766 | |
3767 static GaimCmdRet | |
3768 yahoogaim_cmd_chat_list(GaimConversation *conv, const char *cmd, | |
3769 char **args, char **error, void *data) | |
3770 { | |
3771 GaimAccount *account = gaim_conversation_get_account(conv); | |
3772 if (*args && args[0]) | |
3773 return GAIM_CMD_RET_FAILED; | |
3774 gaim_roomlist_show_with_account(account); | |
3775 return GAIM_CMD_RET_OK; | |
3776 } | |
3777 | |
3778 static gboolean yahoo_offline_message(const GaimBuddy *buddy) | |
3779 { | |
3780 return TRUE; | |
3781 } | |
3782 | |
3783 /************************** Plugin Initialization ****************************/ | |
3784 static void | |
3785 yahoogaim_register_commands(void) | |
3786 { | |
3787 gaim_cmd_register("join", "s", GAIM_CMD_P_PRPL, | |
3788 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | | |
3789 GAIM_CMD_FLAG_PRPL_ONLY, | |
3790 "prpl-yahoo", yahoogaim_cmd_chat_join, | |
3791 _("join <room>: Join a chat room on the Yahoo network"), NULL); | |
3792 gaim_cmd_register("list", "", GAIM_CMD_P_PRPL, | |
3793 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | | |
3794 GAIM_CMD_FLAG_PRPL_ONLY, | |
3795 "prpl-yahoo", yahoogaim_cmd_chat_list, | |
3796 _("list: List rooms on the Yahoo network"), NULL); | |
3797 gaim_cmd_register("buzz", "", GAIM_CMD_P_PRPL, | |
3798 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_PRPL_ONLY, | |
3799 "prpl-yahoo", yahoogaim_cmd_buzz, | |
3800 _("buzz: Buzz a user to get their attention"), NULL); | |
3801 gaim_cmd_register("doodle", "", GAIM_CMD_P_PRPL, | |
3802 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_PRPL_ONLY, | |
3803 "prpl-yahoo", yahoo_doodle_gaim_cmd_start, | |
3804 _("doodle: Request user to start a Doodle session"), NULL); | |
3805 } | |
3806 | |
3807 static GaimWhiteboardPrplOps yahoo_whiteboard_prpl_ops = | |
3808 { | |
3809 yahoo_doodle_start, | |
3810 yahoo_doodle_end, | |
3811 yahoo_doodle_get_dimensions, | |
3812 NULL, | |
3813 yahoo_doodle_get_brush, | |
3814 yahoo_doodle_set_brush, | |
3815 yahoo_doodle_send_draw_list, | |
3816 yahoo_doodle_clear | |
3817 }; | |
3818 | |
3819 static GaimPluginProtocolInfo prpl_info = | |
3820 { | |
3821 OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC, | |
3822 NULL, /* user_splits */ | |
3823 NULL, /* protocol_options */ | |
15219 | 3824 {"png,gif,jpeg", 96, 96, 96, 96, 0, GAIM_ICON_SCALE_SEND}, |
14192 | 3825 yahoo_list_icon, |
3826 yahoo_list_emblems, | |
3827 yahoo_status_text, | |
3828 yahoo_tooltip_text, | |
3829 yahoo_status_types, | |
3830 yahoo_blist_node_menu, | |
3831 yahoo_c_info, | |
3832 yahoo_c_info_defaults, | |
3833 yahoo_login, | |
3834 yahoo_close, | |
3835 yahoo_send_im, | |
3836 NULL, /* set info */ | |
3837 yahoo_send_typing, | |
3838 yahoo_get_info, | |
3839 yahoo_set_status, | |
3840 yahoo_set_idle, | |
3841 NULL, /* change_passwd*/ | |
3842 yahoo_add_buddy, | |
3843 NULL, /* add_buddies */ | |
3844 yahoo_remove_buddy, | |
3845 NULL, /*remove_buddies */ | |
3846 yahoo_add_permit, | |
3847 yahoo_add_deny, | |
3848 yahoo_rem_permit, | |
3849 yahoo_rem_deny, | |
3850 yahoo_set_permit_deny, | |
3851 yahoo_c_join, | |
3852 NULL, /* reject chat invite */ | |
3853 yahoo_get_chat_name, | |
3854 yahoo_c_invite, | |
3855 yahoo_c_leave, | |
3856 NULL, /* chat whisper */ | |
3857 yahoo_c_send, | |
3858 yahoo_keepalive, | |
3859 NULL, /* register_user */ | |
3860 NULL, /* get_cb_info */ | |
3861 NULL, /* get_cb_away */ | |
3862 NULL, /* alias_buddy */ | |
3863 yahoo_change_buddys_group, | |
3864 yahoo_rename_group, | |
3865 NULL, /* buddy_free */ | |
3866 NULL, /* convo_closed */ | |
3867 gaim_normalize_nocase, /* normalize */ | |
3868 yahoo_set_buddy_icon, | |
3869 NULL, /* void (*remove_group)(GaimConnection *gc, const char *group);*/ | |
3870 NULL, /* char *(*get_cb_real_name)(GaimConnection *gc, int id, const char *who); */ | |
3871 NULL, /* set_chat_topic */ | |
3872 NULL, /* find_blist_chat */ | |
3873 yahoo_roomlist_get_list, | |
3874 yahoo_roomlist_cancel, | |
3875 yahoo_roomlist_expand_category, | |
3876 NULL, /* can_receive_file */ | |
3877 yahoo_send_file, | |
3878 yahoo_new_xfer, | |
3879 yahoo_offline_message, /* offline_message */ | |
3880 &yahoo_whiteboard_prpl_ops, | |
15123 | 3881 NULL, /* send_raw */ |
3882 NULL, /* roomlist_room_serialize */ | |
14192 | 3883 }; |
3884 | |
3885 static GaimPluginInfo info = | |
3886 { | |
3887 GAIM_PLUGIN_MAGIC, | |
3888 GAIM_MAJOR_VERSION, | |
3889 GAIM_MINOR_VERSION, | |
3890 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
3891 NULL, /**< ui_requirement */ | |
3892 0, /**< flags */ | |
3893 NULL, /**< dependencies */ | |
3894 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
3895 "prpl-yahoo", /**< id */ | |
3896 "Yahoo", /**< name */ | |
3897 VERSION, /**< version */ | |
3898 /** summary */ | |
3899 N_("Yahoo Protocol Plugin"), | |
3900 /** description */ | |
3901 N_("Yahoo Protocol Plugin"), | |
3902 NULL, /**< author */ | |
3903 GAIM_WEBSITE, /**< homepage */ | |
3904 NULL, /**< load */ | |
3905 yahoo_unload_plugin, /**< unload */ | |
3906 NULL, /**< destroy */ | |
3907 NULL, /**< ui_info */ | |
3908 &prpl_info, /**< extra_info */ | |
3909 NULL, | |
3910 yahoo_actions | |
3911 }; | |
3912 | |
3913 static void | |
3914 init_plugin(GaimPlugin *plugin) | |
3915 { | |
3916 GaimAccountOption *option; | |
3917 | |
3918 option = gaim_account_option_bool_new(_("Yahoo Japan"), "yahoojp", FALSE); | |
3919 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3920 | |
3921 option = gaim_account_option_string_new(_("Pager server"), "server", YAHOO_PAGER_HOST); | |
3922 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3923 | |
3924 option = gaim_account_option_string_new(_("Japan Pager server"), "serverjp", YAHOOJP_PAGER_HOST); | |
3925 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3926 | |
3927 option = gaim_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT); | |
3928 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3929 | |
3930 option = gaim_account_option_string_new(_("File transfer server"), "xfer_host", YAHOO_XFER_HOST); | |
3931 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3932 | |
3933 option = gaim_account_option_string_new(_("Japan file transfer server"), "xferjp_host", YAHOOJP_XFER_HOST); | |
3934 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3935 | |
3936 option = gaim_account_option_int_new(_("File transfer port"), "xfer_port", YAHOO_XFER_PORT); | |
3937 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3938 | |
3939 option = gaim_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOO_ROOMLIST_LOCALE); | |
3940 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3941 | |
3942 option = gaim_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE); | |
3943 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3944 | |
14285 | 3945 option = gaim_account_option_string_new(_("Encoding"), "local_charset", "ISO-8859-1"); |
3946 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3947 | |
3948 | |
14192 | 3949 #if 0 |
3950 option = gaim_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL); | |
3951 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3952 | |
3953 option = gaim_account_option_string_new(_("Yahoo Chat server"), "ycht-server", YAHOO_YCHT_HOST); | |
3954 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3955 | |
3956 option = gaim_account_option_int_new(_("Yahoo Chat port"), "ycht-port", YAHOO_YCHT_PORT); | |
3957 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
3958 #endif | |
3959 | |
3960 my_protocol = plugin; | |
3961 yahoogaim_register_commands(); | |
3962 yahoo_init_colorht(); | |
3963 } | |
3964 | |
3965 GAIM_INIT_PLUGIN(yahoo, init_plugin, info); |