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