Mercurial > pidgin.yaz
annotate libgaim/protocols/yahoo/yahoo.c @ 15154:38cdfbb371b1
[gaim-migrate @ 17939]
Compile warning fixes
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 10 Dec 2006 08:29:03 +0000 |
parents | b81e4e44b509 |
children | 4bf7801a2539 |
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 | |
15058 | 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 | |
15058 | 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 | |
15058 | 995 /* DONE! this is almost exactly the same as what MSN does, |
14192 | 996 * this should probably be moved to the core. |
997 */ | |
15058 | 998 gaim_account_request_authorization(gaim_connection_get_account(gc), add_req->who, add_req->id, |
15143 | 999 NULL, add_req->msg, gaim_find_buddy(gaim_connection_get_account(gc),add_req->who) != NULL, |
15136 | 1000 G_CALLBACK(yahoo_buddy_add_authorize_cb), |
15058 | 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: | |
15001
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 | |
15144
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15143
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)); | |
15144
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15143
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) | |
15144
b81e4e44b509
[gaim-migrate @ 17929]
Evan Schoenberg <evan.s@dreskin.net>
parents:
15143
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 */ | |
15120 | 3824 {"png,gif,jpeg", 96, 96, 96, 96, 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, | |
15124 | 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); |