| |
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 * Some code copyright 2003 Tim Ringenbach <omarvo@hotmail.com> |
| |
9 * (marv on irc.freenode.net) |
| |
10 * Some code borrowed from libyahoo2, copyright (C) 2002, Philip |
| |
11 * S Tellis <philip . tellis AT gmx . net> |
| |
12 * |
| |
13 * This program is free software; you can redistribute it and/or modify |
| |
14 * it under the terms of the GNU General Public License as published by |
| |
15 * the Free Software Foundation; either version 2 of the License, or |
| |
16 * (at your option) any later version. |
| |
17 * |
| |
18 * This program is distributed in the hope that it will be useful, |
| |
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
21 * GNU General Public License for more details. |
| |
22 * |
| |
23 * You should have received a copy of the GNU General Public License |
| |
24 * along with this program; if not, write to the Free Software |
| |
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
26 * |
| |
27 */ |
| |
28 |
| |
29 #ifdef HAVE_CONFIG_H |
| |
30 #include "config.h" |
| |
31 #endif |
| |
32 |
| |
33 #include "debug.h" |
| |
34 #include "privacy.h" |
| |
35 #include "prpl.h" |
| |
36 |
| |
37 #include "conversation.h" |
| |
38 #include "notify.h" |
| |
39 #include "util.h" |
| |
40 #include "internal.h" |
| |
41 |
| |
42 #include "yahoo.h" |
| |
43 #include "yahoo_packet.h" |
| |
44 #include "yahoochat.h" |
| |
45 #include "ycht.h" |
| |
46 |
| |
47 #define YAHOO_CHAT_ID (1) |
| |
48 |
| |
49 /* prototype(s) */ |
| |
50 static void yahoo_chat_leave(GaimConnection *gc, const char *room, const char *dn, gboolean logout); |
| |
51 |
| |
52 /* special function to log us on to the yahoo chat service */ |
| |
53 static void yahoo_chat_online(GaimConnection *gc) |
| |
54 { |
| |
55 struct yahoo_data *yd = gc->proto_data; |
| |
56 struct yahoo_packet *pkt; |
| |
57 |
| |
58 if (yd->wm) { |
| |
59 ycht_connection_open(gc); |
| |
60 return; |
| |
61 } |
| |
62 |
| |
63 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE,0); |
| |
64 yahoo_packet_hash(pkt, "sss", 1, gaim_connection_get_display_name(gc), |
| |
65 109, gaim_connection_get_display_name(gc), 6, "abcde"); |
| |
66 yahoo_packet_send_and_free(pkt, yd); |
| |
67 } |
| |
68 |
| |
69 /* this is slow, and different from the gaim_* version in that it (hopefully) won't add a user twice */ |
| |
70 void yahoo_chat_add_users(GaimConvChat *chat, GList *newusers) |
| |
71 { |
| |
72 GList *i; |
| |
73 |
| |
74 for (i = newusers; i; i = i->next) { |
| |
75 if (gaim_conv_chat_find_user(chat, i->data)) |
| |
76 continue; |
| |
77 gaim_conv_chat_add_user(chat, i->data, NULL, GAIM_CBFLAGS_NONE, TRUE); |
| |
78 } |
| |
79 } |
| |
80 |
| |
81 void yahoo_chat_add_user(GaimConvChat *chat, const char *user, const char *reason) |
| |
82 { |
| |
83 if (gaim_conv_chat_find_user(chat, user)) |
| |
84 return; |
| |
85 |
| |
86 gaim_conv_chat_add_user(chat, user, reason, GAIM_CBFLAGS_NONE, TRUE); |
| |
87 } |
| |
88 |
| |
89 static GaimConversation *yahoo_find_conference(GaimConnection *gc, const char *name) |
| |
90 { |
| |
91 struct yahoo_data *yd; |
| |
92 GSList *l; |
| |
93 |
| |
94 yd = gc->proto_data; |
| |
95 |
| |
96 for (l = yd->confs; l; l = l->next) { |
| |
97 GaimConversation *c = l->data; |
| |
98 if (!gaim_utf8_strcasecmp(gaim_conversation_get_name(c), name)) |
| |
99 return c; |
| |
100 } |
| |
101 return NULL; |
| |
102 } |
| |
103 |
| |
104 |
| |
105 void yahoo_process_conference_invite(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
106 { |
| |
107 GSList *l; |
| |
108 char *room = NULL; |
| |
109 char *who = NULL; |
| |
110 char *msg = NULL; |
| |
111 GString *members = NULL; |
| |
112 GHashTable *components; |
| |
113 |
| |
114 if (pkt->status == 2) |
| |
115 return; /* XXX */ |
| |
116 |
| |
117 members = g_string_sized_new(512); |
| |
118 |
| |
119 for (l = pkt->hash; l; l = l->next) { |
| |
120 struct yahoo_pair *pair = l->data; |
| |
121 |
| |
122 switch (pair->key) { |
| |
123 case 1: /* us, but we already know who we are */ |
| |
124 break; |
| |
125 case 57: |
| |
126 room = yahoo_string_decode(gc, pair->value, FALSE); |
| |
127 break; |
| |
128 case 50: /* inviter */ |
| |
129 who = pair->value; |
| |
130 g_string_append_printf(members, "%s\n", who); |
| |
131 break; |
| |
132 case 52: /* invitee (me) */ |
| |
133 case 53: /* members */ |
| |
134 g_string_append_printf(members, "%s\n", pair->value); |
| |
135 break; |
| |
136 case 58: |
| |
137 msg = yahoo_string_decode(gc, pair->value, FALSE); |
| |
138 break; |
| |
139 case 13: /* ? */ |
| |
140 break; |
| |
141 } |
| |
142 } |
| |
143 |
| |
144 if (!room) { |
| |
145 g_string_free(members, TRUE); |
| |
146 return; |
| |
147 } |
| |
148 |
| |
149 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); |
| |
150 g_hash_table_replace(components, g_strdup("room"), room); |
| |
151 if (msg) |
| |
152 g_hash_table_replace(components, g_strdup("topic"), msg); |
| |
153 g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference")); |
| |
154 if (members) { |
| |
155 g_hash_table_replace(components, g_strdup("members"), g_strdup(members->str)); |
| |
156 } |
| |
157 if (!yahoo_privacy_check(gc, who) || |
| |
158 (gaim_account_get_bool(gaim_connection_get_account(gc), "ignore_invites", FALSE))) { |
| |
159 gaim_debug_info("yahoo", |
| |
160 "Invite to conference %s from %s has been dropped.\n", room, who); |
| |
161 g_string_free(members, TRUE); |
| |
162 return; |
| |
163 } |
| |
164 serv_got_chat_invite(gc, room, who, msg, components); |
| |
165 |
| |
166 g_string_free(members, TRUE); |
| |
167 } |
| |
168 |
| |
169 void yahoo_process_conference_decline(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
170 { |
| |
171 GSList *l; |
| |
172 char *room = NULL; |
| |
173 char *who = NULL; |
| |
174 char *msg = NULL; |
| |
175 |
| |
176 for (l = pkt->hash; l; l = l->next) { |
| |
177 struct yahoo_pair *pair = l->data; |
| |
178 |
| |
179 switch (pair->key) { |
| |
180 case 57: |
| |
181 room = yahoo_string_decode(gc, pair->value, FALSE); |
| |
182 break; |
| |
183 case 54: |
| |
184 who = pair->value; |
| |
185 break; |
| |
186 case 14: |
| |
187 msg = yahoo_string_decode(gc, pair->value, FALSE); |
| |
188 break; |
| |
189 } |
| |
190 } |
| |
191 if (!yahoo_privacy_check(gc, who)) { |
| |
192 g_free(room); |
| |
193 if (msg != NULL) |
| |
194 g_free(msg); |
| |
195 return; |
| |
196 } |
| |
197 |
| |
198 if (who && room) { |
| |
199 /* make sure we're in the room before we process a decline message for it */ |
| |
200 if(yahoo_find_conference(gc, room)) { |
| |
201 char *tmp; |
| |
202 |
| |
203 tmp = g_strdup_printf(_("%s declined your conference invitation to room \"%s\" because \"%s\"."), |
| |
204 who, room, msg?msg:""); |
| |
205 gaim_notify_info(gc, NULL, _("Invitation Rejected"), tmp); |
| |
206 g_free(tmp); |
| |
207 } |
| |
208 |
| |
209 g_free(room); |
| |
210 if (msg) |
| |
211 g_free(msg); |
| |
212 } |
| |
213 } |
| |
214 |
| |
215 void yahoo_process_conference_logon(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
216 { |
| |
217 GSList *l; |
| |
218 char *room = NULL; |
| |
219 char *who = NULL; |
| |
220 GaimConversation *c; |
| |
221 |
| |
222 for (l = pkt->hash; l; l = l->next) { |
| |
223 struct yahoo_pair *pair = l->data; |
| |
224 |
| |
225 switch (pair->key) { |
| |
226 case 57: |
| |
227 room = yahoo_string_decode(gc, pair->value, FALSE); |
| |
228 break; |
| |
229 case 53: |
| |
230 who = pair->value; |
| |
231 break; |
| |
232 } |
| |
233 } |
| |
234 |
| |
235 if (who && room) { |
| |
236 c = yahoo_find_conference(gc, room); |
| |
237 if (c) |
| |
238 yahoo_chat_add_user(GAIM_CONV_CHAT(c), who, NULL); |
| |
239 g_free(room); |
| |
240 } |
| |
241 } |
| |
242 |
| |
243 void yahoo_process_conference_logoff(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
244 { |
| |
245 GSList *l; |
| |
246 char *room = NULL; |
| |
247 char *who = NULL; |
| |
248 GaimConversation *c; |
| |
249 |
| |
250 for (l = pkt->hash; l; l = l->next) { |
| |
251 struct yahoo_pair *pair = l->data; |
| |
252 |
| |
253 switch (pair->key) { |
| |
254 case 57: |
| |
255 room = yahoo_string_decode(gc, pair->value, FALSE); |
| |
256 break; |
| |
257 case 56: |
| |
258 who = pair->value; |
| |
259 break; |
| |
260 } |
| |
261 } |
| |
262 |
| |
263 if (who && room) { |
| |
264 c = yahoo_find_conference(gc, room); |
| |
265 if (c) |
| |
266 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(c), who, NULL); |
| |
267 g_free(room); |
| |
268 } |
| |
269 } |
| |
270 |
| |
271 void yahoo_process_conference_message(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
272 { |
| |
273 GSList *l; |
| |
274 char *room = NULL; |
| |
275 char *who = NULL; |
| |
276 char *msg = NULL; |
| |
277 char *msg2; |
| |
278 int utf8 = 0; |
| |
279 GaimConversation *c; |
| |
280 |
| |
281 for (l = pkt->hash; l; l = l->next) { |
| |
282 struct yahoo_pair *pair = l->data; |
| |
283 |
| |
284 switch (pair->key) { |
| |
285 case 57: |
| |
286 room = yahoo_string_decode(gc, pair->value, FALSE); |
| |
287 break; |
| |
288 case 3: |
| |
289 who = pair->value; |
| |
290 break; |
| |
291 case 14: |
| |
292 msg = pair->value; |
| |
293 break; |
| |
294 case 97: |
| |
295 utf8 = strtol(pair->value, NULL, 10); |
| |
296 break; |
| |
297 } |
| |
298 } |
| |
299 |
| |
300 if (room && who && msg) { |
| |
301 msg2 = yahoo_string_decode(gc, msg, utf8); |
| |
302 c = yahoo_find_conference(gc, room); |
| |
303 if (!c) |
| |
304 return; |
| |
305 msg = yahoo_codes_to_html(msg2); |
| |
306 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(c)), who, 0, msg, time(NULL)); |
| |
307 g_free(msg); |
| |
308 g_free(msg2); |
| |
309 } |
| |
310 if (room) |
| |
311 g_free(room); |
| |
312 } |
| |
313 |
| |
314 |
| |
315 /* this is a confirmation of yahoo_chat_online(); */ |
| |
316 void yahoo_process_chat_online(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
317 { |
| |
318 struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; |
| |
319 |
| |
320 if (pkt->status == 1) |
| |
321 yd->chat_online = 1; |
| |
322 } |
| |
323 |
| |
324 /* this is basicly the opposite of chat_online */ |
| |
325 void yahoo_process_chat_logout(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
326 { |
| |
327 struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; |
| |
328 GSList *l; |
| |
329 |
| |
330 for (l = pkt->hash; l; l = l->next) { |
| |
331 struct yahoo_pair *pair = l->data; |
| |
332 |
| |
333 if (pair->key == 1) |
| |
334 if (g_ascii_strcasecmp(pair->value, |
| |
335 gaim_connection_get_display_name(gc))) |
| |
336 return; |
| |
337 } |
| |
338 |
| |
339 if (pkt->status == 1) { |
| |
340 yd->chat_online = 0; |
| |
341 if (yd->in_chat) |
| |
342 yahoo_c_leave(gc, YAHOO_CHAT_ID); |
| |
343 } |
| |
344 } |
| |
345 |
| |
346 void yahoo_process_chat_join(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
347 { |
| |
348 GaimAccount *account = gaim_connection_get_account(gc); |
| |
349 struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; |
| |
350 GaimConversation *c = NULL; |
| |
351 GSList *l; |
| |
352 GList *members = NULL; |
| |
353 GList *roomies = NULL; |
| |
354 char *room = NULL; |
| |
355 char *topic = NULL; |
| |
356 char *someid, *someotherid, *somebase64orhashosomething, *somenegativenumber; |
| |
357 |
| |
358 if (pkt->status == -1) { |
| |
359 /* We can't join */ |
| |
360 struct yahoo_pair *pair = pkt->hash->data; |
| |
361 gchar const *failed_to_join = _("Failed to join chat"); |
| |
362 switch (atoi(pair->value)) { |
| |
363 case 0xFFFFFFFA: /* -6 */ |
| |
364 gaim_notify_error(gc, NULL, failed_to_join, _("Unknown room")); |
| |
365 break; |
| |
366 case 0xFFFFFFF1: /* -15 */ |
| |
367 gaim_notify_error(gc, NULL, failed_to_join, _("Maybe the room is full")); |
| |
368 break; |
| |
369 case 0xFFFFFFDD: /* -35 */ |
| |
370 gaim_notify_error(gc, NULL, failed_to_join, _("Not available")); |
| |
371 break; |
| |
372 default: |
| |
373 gaim_notify_error(gc, NULL, failed_to_join, |
| |
374 _("Unknown error. You may need to logout and wait five minutes before being able to rejoin a chatroom")); |
| |
375 } |
| |
376 return; |
| |
377 } |
| |
378 |
| |
379 for (l = pkt->hash; l; l = l->next) { |
| |
380 struct yahoo_pair *pair = l->data; |
| |
381 |
| |
382 switch (pair->key) { |
| |
383 |
| |
384 case 104: |
| |
385 room = yahoo_string_decode(gc, pair->value, TRUE); |
| |
386 break; |
| |
387 case 105: |
| |
388 topic = yahoo_string_decode(gc, pair->value, TRUE); |
| |
389 break; |
| |
390 case 128: |
| |
391 someid = pair->value; |
| |
392 break; |
| |
393 case 108: /* number of joiners */ |
| |
394 break; |
| |
395 case 129: |
| |
396 someotherid = pair->value; |
| |
397 break; |
| |
398 case 130: |
| |
399 somebase64orhashosomething = pair->value; |
| |
400 break; |
| |
401 case 126: |
| |
402 somenegativenumber = pair->value; |
| |
403 break; |
| |
404 case 13: /* this is 1. maybe its the type of room? (normal, user created, private, etc?) */ |
| |
405 break; |
| |
406 case 61: /*this looks similar to 130 */ |
| |
407 break; |
| |
408 |
| |
409 /* the previous section was just room info. this next section is |
| |
410 info about individual room members, (including us) */ |
| |
411 |
| |
412 case 109: /* the yahoo id */ |
| |
413 members = g_list_append(members, pair->value); |
| |
414 break; |
| |
415 case 110: /* age */ |
| |
416 break; |
| |
417 case 141: /* nickname */ |
| |
418 break; |
| |
419 case 142: /* location */ |
| |
420 break; |
| |
421 case 113: /* bitmask */ |
| |
422 break; |
| |
423 } |
| |
424 } |
| |
425 |
| |
426 if (room && yd->chat_name && gaim_utf8_strcasecmp(room, yd->chat_name)) |
| |
427 yahoo_chat_leave(gc, room, |
| |
428 gaim_connection_get_display_name(gc), FALSE); |
| |
429 |
| |
430 c = gaim_find_chat(gc, YAHOO_CHAT_ID); |
| |
431 |
| |
432 if (room && (!c || gaim_conv_chat_has_left(GAIM_CONV_CHAT(c))) && members && |
| |
433 ((g_list_length(members) > 1) || |
| |
434 !g_ascii_strcasecmp(members->data, gaim_connection_get_display_name(gc)))) { |
| |
435 int i; |
| |
436 GList *flags = NULL; |
| |
437 for (i = 0; i < g_list_length(members); i++) |
| |
438 flags = g_list_append(flags, GINT_TO_POINTER(GAIM_CBFLAGS_NONE)); |
| |
439 if (c && gaim_conv_chat_has_left(GAIM_CONV_CHAT(c))) { |
| |
440 /* this might be a hack, but oh well, it should nicely */ |
| |
441 char *tmpmsg; |
| |
442 |
| |
443 gaim_conversation_set_name(c, room); |
| |
444 |
| |
445 c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room); |
| |
446 if (topic) |
| |
447 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(c), NULL, topic); |
| |
448 yd->in_chat = 1; |
| |
449 yd->chat_name = g_strdup(room); |
| |
450 gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), members, NULL, flags, FALSE); |
| |
451 |
| |
452 tmpmsg = g_strdup_printf(_("You are now chatting in %s."), room); |
| |
453 gaim_conv_chat_write(GAIM_CONV_CHAT(c), "", tmpmsg, GAIM_MESSAGE_SYSTEM, time(NULL)); |
| |
454 g_free(tmpmsg); |
| |
455 } else { |
| |
456 c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room); |
| |
457 if (topic) |
| |
458 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(c), NULL, topic); |
| |
459 yd->in_chat = 1; |
| |
460 yd->chat_name = g_strdup(room); |
| |
461 gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), members, NULL, flags, FALSE); |
| |
462 } |
| |
463 g_list_free(flags); |
| |
464 } else if (c) { |
| |
465 yahoo_chat_add_users(GAIM_CONV_CHAT(c), members); |
| |
466 } |
| |
467 |
| |
468 if (account->deny && c) { |
| |
469 GaimConversationUiOps *ops = gaim_conversation_get_ui_ops(c); |
| |
470 for (l = account->deny; l != NULL; l = l->next) { |
| |
471 for (roomies = members; roomies; roomies = roomies->next) { |
| |
472 if (!gaim_utf8_strcasecmp((char *)l->data, roomies->data)) { |
| |
473 gaim_debug_info("yahoo", "Ignoring room member %s in room %s\n" , roomies->data, room ? room : ""); |
| |
474 gaim_conv_chat_ignore(GAIM_CONV_CHAT(c),roomies->data); |
| |
475 ops->chat_update_user(c, roomies->data); |
| |
476 } |
| |
477 } |
| |
478 } |
| |
479 } |
| |
480 g_list_free(roomies); |
| |
481 g_list_free(members); |
| |
482 g_free(room); |
| |
483 g_free(topic); |
| |
484 } |
| |
485 |
| |
486 void yahoo_process_chat_exit(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
487 { |
| |
488 char *who = NULL; |
| |
489 char *room = NULL; |
| |
490 GSList *l; |
| |
491 struct yahoo_data *yd; |
| |
492 |
| |
493 yd = gc->proto_data; |
| |
494 |
| |
495 for (l = pkt->hash; l; l = l->next) { |
| |
496 struct yahoo_pair *pair = l->data; |
| |
497 |
| |
498 if (pair->key == 104) |
| |
499 room = yahoo_string_decode(gc, pair->value, TRUE); |
| |
500 if (pair->key == 109) |
| |
501 who = pair->value; |
| |
502 } |
| |
503 |
| |
504 if (who && room) { |
| |
505 GaimConversation *c = gaim_find_chat(gc, YAHOO_CHAT_ID); |
| |
506 if (c && !gaim_utf8_strcasecmp(gaim_conversation_get_name(c), room)) |
| |
507 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(c), who, NULL); |
| |
508 |
| |
509 } |
| |
510 if (room) |
| |
511 g_free(room); |
| |
512 } |
| |
513 |
| |
514 void yahoo_process_chat_message(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
515 { |
| |
516 char *room = NULL, *who = NULL, *msg = NULL, *msg2; |
| |
517 int msgtype = 1, utf8 = 1; /* default to utf8 */ |
| |
518 GaimConversation *c = NULL; |
| |
519 GSList *l; |
| |
520 |
| |
521 for (l = pkt->hash; l; l = l->next) { |
| |
522 struct yahoo_pair *pair = l->data; |
| |
523 |
| |
524 switch (pair->key) { |
| |
525 |
| |
526 case 97: |
| |
527 utf8 = strtol(pair->value, NULL, 10); |
| |
528 break; |
| |
529 case 104: |
| |
530 room = yahoo_string_decode(gc, pair->value, TRUE); |
| |
531 break; |
| |
532 case 109: |
| |
533 who = pair->value; |
| |
534 break; |
| |
535 case 117: |
| |
536 msg = pair->value; |
| |
537 break; |
| |
538 case 124: |
| |
539 msgtype = strtol(pair->value, NULL, 10); |
| |
540 break; |
| |
541 } |
| |
542 } |
| |
543 |
| |
544 c = gaim_find_chat(gc, YAHOO_CHAT_ID); |
| |
545 if (!who || !c) { |
| |
546 if (room) |
| |
547 g_free(room); |
| |
548 /* we still get messages after we part, funny that */ |
| |
549 return; |
| |
550 } |
| |
551 |
| |
552 if (!msg) { |
| |
553 gaim_debug(GAIM_DEBUG_MISC, "yahoo", "Got a message packet with no message.\nThis probably means something important, but we're ignoring it.\n"); |
| |
554 return; |
| |
555 } |
| |
556 msg2 = yahoo_string_decode(gc, msg, utf8); |
| |
557 msg = yahoo_codes_to_html(msg2); |
| |
558 g_free(msg2); |
| |
559 |
| |
560 if (msgtype == 2 || msgtype == 3) { |
| |
561 char *tmp; |
| |
562 tmp = g_strdup_printf("/me %s", msg); |
| |
563 g_free(msg); |
| |
564 msg = tmp; |
| |
565 } |
| |
566 |
| |
567 serv_got_chat_in(gc, YAHOO_CHAT_ID, who, 0, msg, time(NULL)); |
| |
568 g_free(msg); |
| |
569 g_free(room); |
| |
570 } |
| |
571 |
| |
572 void yahoo_process_chat_addinvite(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
573 { |
| |
574 GSList *l; |
| |
575 char *room = NULL; |
| |
576 char *msg = NULL; |
| |
577 char *who = NULL; |
| |
578 |
| |
579 for (l = pkt->hash; l; l = l->next) { |
| |
580 struct yahoo_pair *pair = l->data; |
| |
581 |
| |
582 switch (pair->key) { |
| |
583 case 104: |
| |
584 room = yahoo_string_decode(gc, pair->value, TRUE); |
| |
585 break; |
| |
586 case 129: /* room id? */ |
| |
587 break; |
| |
588 case 126: /* ??? */ |
| |
589 break; |
| |
590 case 117: |
| |
591 msg = yahoo_string_decode(gc, pair->value, FALSE); |
| |
592 break; |
| |
593 case 119: |
| |
594 who = pair->value; |
| |
595 break; |
| |
596 case 118: /* us */ |
| |
597 break; |
| |
598 } |
| |
599 } |
| |
600 |
| |
601 if (room && who) { |
| |
602 GHashTable *components; |
| |
603 |
| |
604 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); |
| |
605 g_hash_table_replace(components, g_strdup("room"), g_strdup(room)); |
| |
606 if (!yahoo_privacy_check(gc, who) || |
| |
607 (gaim_account_get_bool(gaim_connection_get_account(gc), "ignore_invites", FALSE))) { |
| |
608 gaim_debug_info("yahoo", |
| |
609 "Invite to room %s from %s has been dropped.\n", room, who); |
| |
610 if (room != NULL) |
| |
611 g_free(room); |
| |
612 if (msg != NULL) |
| |
613 g_free(msg); |
| |
614 return; |
| |
615 } |
| |
616 serv_got_chat_invite(gc, room, who, msg, components); |
| |
617 } |
| |
618 if (room) |
| |
619 g_free(room); |
| |
620 if (msg) |
| |
621 g_free(msg); |
| |
622 } |
| |
623 |
| |
624 void yahoo_process_chat_goto(GaimConnection *gc, struct yahoo_packet *pkt) |
| |
625 { |
| |
626 if (pkt->status == -1) |
| |
627 gaim_notify_error(gc, NULL, _("Failed to join buddy in chat"), |
| |
628 _("Maybe they're not in a chat?")); |
| |
629 } |
| |
630 |
| |
631 /* |
| |
632 * Functions dealing with conferences |
| |
633 * I think conference names are always ascii. |
| |
634 */ |
| |
635 |
| |
636 void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, GList *who) |
| |
637 { |
| |
638 struct yahoo_packet *pkt; |
| |
639 GList *w; |
| |
640 |
| |
641 gaim_debug_misc("yahoo", "leaving conference %s\n", room); |
| |
642 |
| |
643 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, 0); |
| |
644 |
| |
645 yahoo_packet_hash_str(pkt, 1, dn); |
| |
646 for (w = who; w; w = w->next) { |
| |
647 const char *name = gaim_conv_chat_cb_get_name(w->data); |
| |
648 yahoo_packet_hash_str(pkt, 3, name); |
| |
649 } |
| |
650 |
| |
651 yahoo_packet_hash_str(pkt, 57, room); |
| |
652 yahoo_packet_send_and_free(pkt, yd); |
| |
653 } |
| |
654 |
| |
655 static int yahoo_conf_send(GaimConnection *gc, const char *dn, const char *room, |
| |
656 GList *members, const char *what) |
| |
657 { |
| |
658 struct yahoo_data *yd = gc->proto_data; |
| |
659 struct yahoo_packet *pkt; |
| |
660 GList *who; |
| |
661 char *msg, *msg2; |
| |
662 int utf8 = 1; |
| |
663 |
| |
664 msg = yahoo_html_to_codes(what); |
| |
665 msg2 = yahoo_string_encode(gc, msg, &utf8); |
| |
666 |
| |
667 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, 0); |
| |
668 |
| |
669 yahoo_packet_hash_str(pkt, 1, dn); |
| |
670 for (who = members; who; who = who->next) { |
| |
671 const char *name = gaim_conv_chat_cb_get_name(who->data); |
| |
672 yahoo_packet_hash_str(pkt, 53, name); |
| |
673 } |
| |
674 yahoo_packet_hash(pkt, "ss", 57, room, 14, msg2); |
| |
675 if (utf8) |
| |
676 yahoo_packet_hash_str(pkt, 97, "1"); /* utf-8 */ |
| |
677 |
| |
678 yahoo_packet_send_and_free(pkt, yd); |
| |
679 g_free(msg); |
| |
680 g_free(msg2); |
| |
681 |
| |
682 return 0; |
| |
683 } |
| |
684 |
| |
685 static void yahoo_conf_join(struct yahoo_data *yd, GaimConversation *c, const char *dn, const char *room, |
| |
686 const char *topic, const char *members) |
| |
687 { |
| |
688 struct yahoo_packet *pkt; |
| |
689 char **memarr = NULL; |
| |
690 int i; |
| |
691 |
| |
692 if (members) |
| |
693 memarr = g_strsplit(members, "\n", 0); |
| |
694 |
| |
695 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, 0); |
| |
696 |
| |
697 yahoo_packet_hash(pkt, "sss", 1, dn, 3, dn, 57, room); |
| |
698 if (memarr) { |
| |
699 for(i = 0 ; memarr[i]; i++) { |
| |
700 if (!strcmp(memarr[i], "") || !strcmp(memarr[i], dn)) |
| |
701 continue; |
| |
702 yahoo_packet_hash_str(pkt, 3, memarr[i]); |
| |
703 gaim_conv_chat_add_user(GAIM_CONV_CHAT(c), memarr[i], NULL, GAIM_CBFLAGS_NONE, TRUE); |
| |
704 } |
| |
705 } |
| |
706 yahoo_packet_send_and_free(pkt, yd); |
| |
707 |
| |
708 if (memarr) |
| |
709 g_strfreev(memarr); |
| |
710 } |
| |
711 |
| |
712 static void yahoo_conf_invite(GaimConnection *gc, GaimConversation *c, |
| |
713 const char *dn, const char *buddy, const char *room, const char *msg) |
| |
714 { |
| |
715 struct yahoo_data *yd = gc->proto_data; |
| |
716 struct yahoo_packet *pkt; |
| |
717 GList *members; |
| |
718 char *msg2 = NULL; |
| |
719 |
| |
720 if (msg) |
| |
721 msg2 = yahoo_string_encode(gc, msg, NULL); |
| |
722 |
| |
723 members = gaim_conv_chat_get_users(GAIM_CONV_CHAT(c)); |
| |
724 |
| |
725 pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, 0); |
| |
726 |
| |
727 yahoo_packet_hash(pkt, "sssss", 1, dn, 51, buddy, 57, room, 58, msg?msg2:"", 13, "0"); |
| |
728 for(; members; members = members->next) { |
| |
729 const char *name = gaim_conv_chat_cb_get_name(members->data); |
| |
730 if (!strcmp(name, dn)) |
| |
731 continue; |
| |
732 yahoo_packet_hash(pkt, "ss", 52, name, 53, name); |
| |
733 } |
| |
734 |
| |
735 yahoo_packet_send_and_free(pkt, yd); |
| |
736 g_free(msg2); |
| |
737 } |
| |
738 |
| |
739 /* |
| |
740 * Functions dealing with chats |
| |
741 */ |
| |
742 |
| |
743 static void yahoo_chat_leave(GaimConnection *gc, const char *room, const char *dn, gboolean logout) |
| |
744 { |
| |
745 struct yahoo_data *yd = gc->proto_data; |
| |
746 struct yahoo_packet *pkt; |
| |
747 GaimConversation *c; |
| |
748 |
| |
749 char *eroom; |
| |
750 gboolean utf8 = 1; |
| |
751 |
| |
752 if (yd->wm) { |
| |
753 g_return_if_fail(yd->ycht != NULL); |
| |
754 |
| |
755 ycht_chat_leave(yd->ycht, room, logout); |
| |
756 return; |
| |
757 } |
| |
758 |
| |
759 eroom = yahoo_string_encode(gc, room, &utf8); |
| |
760 |
| |
761 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATEXIT, YAHOO_STATUS_AVAILABLE, 0); |
| |
762 yahoo_packet_hash(pkt, "sss", 104, eroom, 109, dn, 108, "1"); |
| |
763 yahoo_packet_hash_str(pkt, 112, "0"); /* what does this one mean? */ |
| |
764 yahoo_packet_send_and_free(pkt, yd); |
| |
765 |
| |
766 yd->in_chat = 0; |
| |
767 if (yd->chat_name) { |
| |
768 g_free(yd->chat_name); |
| |
769 yd->chat_name = NULL; |
| |
770 } |
| |
771 |
| |
772 if ((c = gaim_find_chat(gc, YAHOO_CHAT_ID))) |
| |
773 serv_got_chat_left(gc, YAHOO_CHAT_ID); |
| |
774 |
| |
775 if (!logout) |
| |
776 return; |
| |
777 |
| |
778 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT, |
| |
779 YAHOO_STATUS_AVAILABLE, 0); |
| |
780 yahoo_packet_hash_str(pkt, 1, dn); |
| |
781 yahoo_packet_send_and_free(pkt, yd); |
| |
782 |
| |
783 yd->chat_online = 0; |
| |
784 g_free(eroom); |
| |
785 } |
| |
786 |
| |
787 /* borrowed from gtkconv.c */ |
| |
788 static gboolean |
| |
789 meify(char *message, size_t len) |
| |
790 { |
| |
791 /* |
| |
792 * Read /me-ify: If the message (post-HTML) starts with /me, |
| |
793 * remove the "/me " part of it (including that space) and return TRUE. |
| |
794 */ |
| |
795 char *c; |
| |
796 gboolean inside_html = 0; |
| |
797 |
| |
798 /* Umm.. this would be very bad if this happens. */ |
| |
799 g_return_val_if_fail(message != NULL, FALSE); |
| |
800 |
| |
801 if (len == -1) |
| |
802 len = strlen(message); |
| |
803 |
| |
804 for (c = message; *c != '\0'; c++, len--) { |
| |
805 if (inside_html) { |
| |
806 if (*c == '>') |
| |
807 inside_html = FALSE; |
| |
808 } |
| |
809 else { |
| |
810 if (*c == '<') |
| |
811 inside_html = TRUE; |
| |
812 else |
| |
813 break; |
| |
814 } |
| |
815 } |
| |
816 |
| |
817 if (*c != '\0' && !g_ascii_strncasecmp(c, "/me ", 4)) { |
| |
818 memmove(c, c + 4, len - 3); |
| |
819 return TRUE; |
| |
820 } |
| |
821 |
| |
822 return FALSE; |
| |
823 } |
| |
824 |
| |
825 static int yahoo_chat_send(GaimConnection *gc, const char *dn, const char *room, const char *what, GaimMessageFlags flags) |
| |
826 { |
| |
827 struct yahoo_data *yd = gc->proto_data; |
| |
828 struct yahoo_packet *pkt; |
| |
829 int me = 0; |
| |
830 char *msg1, *msg2, *room2; |
| |
831 gboolean utf8 = TRUE; |
| |
832 |
| |
833 if (yd->wm) { |
| |
834 g_return_val_if_fail(yd->ycht != NULL, 1); |
| |
835 |
| |
836 return ycht_chat_send(yd->ycht, room, what); |
| |
837 } |
| |
838 |
| |
839 msg1 = g_strdup(what); |
| |
840 |
| |
841 if (meify(msg1, -1)) |
| |
842 me = 1; |
| |
843 |
| |
844 msg2 = yahoo_html_to_codes(msg1); |
| |
845 g_free(msg1); |
| |
846 msg1 = yahoo_string_encode(gc, msg2, &utf8); |
| |
847 g_free(msg2); |
| |
848 room2 = yahoo_string_encode(gc, room, NULL); |
| |
849 |
| |
850 pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, 0); |
| |
851 |
| |
852 yahoo_packet_hash(pkt, "sss", 1, dn, 104, room2, 117, msg1); |
| |
853 if (me) |
| |
854 yahoo_packet_hash_str(pkt, 124, "2"); |
| |
855 else |
| |
856 yahoo_packet_hash_str(pkt, 124, "1"); |
| |
857 /* fixme: what about /think? (124=3) */ |
| |
858 if (utf8) |
| |
859 yahoo_packet_hash_str(pkt, 97, "1"); |
| |
860 |
| |
861 yahoo_packet_send_and_free(pkt, yd); |
| |
862 g_free(msg1); |
| |
863 g_free(room2); |
| |
864 |
| |
865 return 0; |
| |
866 } |
| |
867 |
| |
868 static void yahoo_chat_join(GaimConnection *gc, const char *dn, const char *room, const char *topic) |
| |
869 { |
| |
870 struct yahoo_data *yd = gc->proto_data; |
| |
871 struct yahoo_packet *pkt; |
| |
872 char *room2; |
| |
873 gboolean utf8 = TRUE; |
| |
874 |
| |
875 if (yd->wm) { |
| |
876 g_return_if_fail(yd->ycht != NULL); |
| |
877 ycht_chat_join(yd->ycht, room); |
| |
878 return; |
| |
879 } |
| |
880 |
| |
881 /* apparently room names are always utf8, or else always not utf8, |
| |
882 * so we don't have to actually pass the flag in the packet. Or something. */ |
| |
883 room2 = yahoo_string_encode(gc, room, &utf8); |
| |
884 |
| |
885 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0); |
| |
886 yahoo_packet_hash(pkt, "ssss", 1, gaim_connection_get_display_name(gc), |
| |
887 62, "2", 104, room2, 129, "0"); |
| |
888 yahoo_packet_send_and_free(pkt, yd); |
| |
889 g_free(room2); |
| |
890 } |
| |
891 |
| |
892 static void yahoo_chat_invite(GaimConnection *gc, const char *dn, const char *buddy, |
| |
893 const char *room, const char *msg) |
| |
894 { |
| |
895 struct yahoo_data *yd = gc->proto_data; |
| |
896 struct yahoo_packet *pkt; |
| |
897 char *room2, *msg2 = NULL; |
| |
898 gboolean utf8 = TRUE; |
| |
899 |
| |
900 if (yd->wm) { |
| |
901 g_return_if_fail(yd->ycht != NULL); |
| |
902 ycht_chat_send_invite(yd->ycht, room, buddy, msg); |
| |
903 return; |
| |
904 } |
| |
905 |
| |
906 room2 = yahoo_string_encode(gc, room, &utf8); |
| |
907 if (msg) |
| |
908 msg2 = yahoo_string_encode(gc, msg, NULL); |
| |
909 |
| |
910 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATADDINVITE, YAHOO_STATUS_AVAILABLE, 0); |
| |
911 yahoo_packet_hash(pkt, "sssss", 1, dn, 118, buddy, 104, room2, 117, (msg2?msg2:""), 129, "0"); |
| |
912 yahoo_packet_send_and_free(pkt, yd); |
| |
913 |
| |
914 g_free(room2); |
| |
915 g_free(msg2); |
| |
916 } |
| |
917 |
| |
918 void yahoo_chat_goto(GaimConnection *gc, const char *name) |
| |
919 { |
| |
920 struct yahoo_data *yd; |
| |
921 struct yahoo_packet *pkt; |
| |
922 |
| |
923 yd = gc->proto_data; |
| |
924 |
| |
925 if (yd->wm) { |
| |
926 g_return_if_fail(yd->ycht != NULL); |
| |
927 ycht_chat_goto_user(yd->ycht, name); |
| |
928 return; |
| |
929 } |
| |
930 |
| |
931 if (!yd->chat_online) |
| |
932 yahoo_chat_online(gc); |
| |
933 |
| |
934 pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, 0); |
| |
935 yahoo_packet_hash(pkt, "sss", 109, name, 1, gaim_connection_get_display_name(gc), 62, "2"); |
| |
936 yahoo_packet_send_and_free(pkt, yd); |
| |
937 } |
| |
938 /* |
| |
939 * These are the functions registered with the core |
| |
940 * which get called for both chats and conferences. |
| |
941 */ |
| |
942 |
| |
943 void yahoo_c_leave(GaimConnection *gc, int id) |
| |
944 { |
| |
945 struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; |
| |
946 GaimConversation *c; |
| |
947 |
| |
948 if (!yd) |
| |
949 return; |
| |
950 |
| |
951 c = gaim_find_chat(gc, id); |
| |
952 if (!c) |
| |
953 return; |
| |
954 |
| |
955 if (id != YAHOO_CHAT_ID) { |
| |
956 yahoo_conf_leave(yd, gaim_conversation_get_name(c), |
| |
957 gaim_connection_get_display_name(gc), gaim_conv_chat_get_users(GAIM_CONV_CHAT(c))); |
| |
958 yd->confs = g_slist_remove(yd->confs, c); |
| |
959 } else { |
| |
960 yahoo_chat_leave(gc, gaim_conversation_get_name(c), gaim_connection_get_display_name(gc), TRUE); |
| |
961 } |
| |
962 |
| |
963 serv_got_chat_left(gc, id); |
| |
964 } |
| |
965 |
| |
966 int yahoo_c_send(GaimConnection *gc, int id, const char *what, GaimMessageFlags flags) |
| |
967 { |
| |
968 GaimConversation *c; |
| |
969 int ret; |
| |
970 struct yahoo_data *yd; |
| |
971 |
| |
972 yd = (struct yahoo_data *) gc->proto_data; |
| |
973 if (!yd) |
| |
974 return -1; |
| |
975 |
| |
976 c = gaim_find_chat(gc, id); |
| |
977 if (!c) |
| |
978 return -1; |
| |
979 |
| |
980 if (id != YAHOO_CHAT_ID) { |
| |
981 ret = yahoo_conf_send(gc, gaim_connection_get_display_name(gc), |
| |
982 gaim_conversation_get_name(c), gaim_conv_chat_get_users(GAIM_CONV_CHAT(c)), what); |
| |
983 } else { |
| |
984 ret = yahoo_chat_send(gc, gaim_connection_get_display_name(gc), |
| |
985 gaim_conversation_get_name(c), what, flags); |
| |
986 if (!ret) |
| |
987 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(c)), |
| |
988 gaim_connection_get_display_name(gc), 0, what, time(NULL)); |
| |
989 } |
| |
990 return ret; |
| |
991 } |
| |
992 |
| |
993 GList *yahoo_c_info(GaimConnection *gc) |
| |
994 { |
| |
995 GList *m = NULL; |
| |
996 struct proto_chat_entry *pce; |
| |
997 |
| |
998 pce = g_new0(struct proto_chat_entry, 1); |
| |
999 pce->label = _("_Room:"); |
| |
1000 pce->identifier = "room"; |
| |
1001 pce->required = TRUE; |
| |
1002 m = g_list_append(m, pce); |
| |
1003 |
| |
1004 return m; |
| |
1005 } |
| |
1006 |
| |
1007 GHashTable *yahoo_c_info_defaults(GaimConnection *gc, const char *chat_name) |
| |
1008 { |
| |
1009 GHashTable *defaults; |
| |
1010 |
| |
1011 defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); |
| |
1012 |
| |
1013 if (chat_name != NULL) |
| |
1014 g_hash_table_insert(defaults, "room", g_strdup(chat_name)); |
| |
1015 |
| |
1016 return defaults; |
| |
1017 } |
| |
1018 |
| |
1019 char *yahoo_get_chat_name(GHashTable *data) |
| |
1020 { |
| |
1021 return g_strdup(g_hash_table_lookup(data, "room")); |
| |
1022 } |
| |
1023 |
| |
1024 void yahoo_c_join(GaimConnection *gc, GHashTable *data) |
| |
1025 { |
| |
1026 struct yahoo_data *yd; |
| |
1027 char *room, *topic, *members, *type; |
| |
1028 int id; |
| |
1029 GaimConversation *c; |
| |
1030 |
| |
1031 yd = (struct yahoo_data *) gc->proto_data; |
| |
1032 if (!yd) |
| |
1033 return; |
| |
1034 |
| |
1035 room = g_hash_table_lookup(data, "room"); |
| |
1036 if (!room) |
| |
1037 return; |
| |
1038 |
| |
1039 topic = g_hash_table_lookup(data, "topic"); |
| |
1040 if (!topic) |
| |
1041 topic = ""; |
| |
1042 |
| |
1043 members = g_hash_table_lookup(data, "members"); |
| |
1044 |
| |
1045 if ((type = g_hash_table_lookup(data, "type")) && !strcmp(type, "Conference")) { |
| |
1046 id = yd->conf_id++; |
| |
1047 c = serv_got_joined_chat(gc, id, room); |
| |
1048 yd->confs = g_slist_prepend(yd->confs, c); |
| |
1049 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(c), gaim_connection_get_display_name(gc), topic); |
| |
1050 yahoo_conf_join(yd, c, gaim_connection_get_display_name(gc), room, topic, members); |
| |
1051 return; |
| |
1052 } else { |
| |
1053 if (yd->in_chat) |
| |
1054 yahoo_chat_leave(gc, room, |
| |
1055 gaim_connection_get_display_name(gc), |
| |
1056 FALSE); |
| |
1057 if (!yd->chat_online) |
| |
1058 yahoo_chat_online(gc); |
| |
1059 yahoo_chat_join(gc, gaim_connection_get_display_name(gc), room, topic); |
| |
1060 return; |
| |
1061 } |
| |
1062 } |
| |
1063 |
| |
1064 void yahoo_c_invite(GaimConnection *gc, int id, const char *msg, const char *name) |
| |
1065 { |
| |
1066 GaimConversation *c; |
| |
1067 |
| |
1068 c = gaim_find_chat(gc, id); |
| |
1069 if (!c || !c->name) |
| |
1070 return; |
| |
1071 |
| |
1072 if (id != YAHOO_CHAT_ID) { |
| |
1073 yahoo_conf_invite(gc, c, gaim_connection_get_display_name(gc), name, |
| |
1074 gaim_conversation_get_name(c), msg); |
| |
1075 } else { |
| |
1076 yahoo_chat_invite(gc, gaim_connection_get_display_name(gc), name, |
| |
1077 gaim_conversation_get_name(c), msg); |
| |
1078 } |
| |
1079 } |
| |
1080 |
| |
1081 struct yahoo_roomlist { |
| |
1082 int fd; |
| |
1083 int inpa; |
| |
1084 gchar *txbuf; |
| |
1085 gsize tx_written; |
| |
1086 guchar *rxqueue; |
| |
1087 int rxlen; |
| |
1088 gboolean started; |
| |
1089 char *path; |
| |
1090 char *host; |
| |
1091 GaimRoomlist *list; |
| |
1092 GaimRoomlistRoom *cat; |
| |
1093 GaimRoomlistRoom *ucat; |
| |
1094 GMarkupParseContext *parse; |
| |
1095 }; |
| |
1096 |
| |
1097 static void yahoo_roomlist_destroy(struct yahoo_roomlist *yrl) |
| |
1098 { |
| |
1099 if (yrl->inpa) |
| |
1100 gaim_input_remove(yrl->inpa); |
| |
1101 g_free(yrl->txbuf); |
| |
1102 g_free(yrl->rxqueue); |
| |
1103 g_free(yrl->path); |
| |
1104 g_free(yrl->host); |
| |
1105 if (yrl->parse) |
| |
1106 g_markup_parse_context_free(yrl->parse); |
| |
1107 g_free(yrl); |
| |
1108 } |
| |
1109 |
| |
1110 enum yahoo_room_type { |
| |
1111 yrt_yahoo, |
| |
1112 yrt_user, |
| |
1113 }; |
| |
1114 |
| |
1115 struct yahoo_chatxml_state { |
| |
1116 GaimRoomlist *list; |
| |
1117 struct yahoo_roomlist *yrl; |
| |
1118 GQueue *q; |
| |
1119 struct { |
| |
1120 enum yahoo_room_type type; |
| |
1121 char *name; |
| |
1122 char *topic; |
| |
1123 char *id; |
| |
1124 int users, voices, webcams; |
| |
1125 } room; |
| |
1126 }; |
| |
1127 |
| |
1128 struct yahoo_lobby { |
| |
1129 int count, users, voices, webcams; |
| |
1130 }; |
| |
1131 |
| |
1132 static struct yahoo_chatxml_state *yahoo_chatxml_state_new(GaimRoomlist *list, struct yahoo_roomlist *yrl) |
| |
1133 { |
| |
1134 struct yahoo_chatxml_state *s; |
| |
1135 |
| |
1136 s = g_new0(struct yahoo_chatxml_state, 1); |
| |
1137 s->list = list; |
| |
1138 s->yrl = yrl; |
| |
1139 s->q = g_queue_new(); |
| |
1140 |
| |
1141 return s; |
| |
1142 } |
| |
1143 |
| |
1144 static void yahoo_chatxml_state_destroy(struct yahoo_chatxml_state *s) |
| |
1145 { |
| |
1146 g_queue_free(s->q); |
| |
1147 g_free(s->room.name); |
| |
1148 g_free(s->room.topic); |
| |
1149 g_free(s->room.id); |
| |
1150 g_free(s); |
| |
1151 } |
| |
1152 |
| |
1153 static void yahoo_chatlist_start_element(GMarkupParseContext *context, |
| |
1154 const gchar *ename, const gchar **anames, |
| |
1155 const gchar **avalues, gpointer user_data, |
| |
1156 GError **error) |
| |
1157 { |
| |
1158 struct yahoo_chatxml_state *s = user_data; |
| |
1159 GaimRoomlist *list = s->list; |
| |
1160 GaimRoomlistRoom *r; |
| |
1161 GaimRoomlistRoom *parent; |
| |
1162 int i; |
| |
1163 |
| |
1164 if (!strcmp(ename, "category")) { |
| |
1165 const gchar *name = NULL, *id = NULL; |
| |
1166 |
| |
1167 for (i = 0; anames[i]; i++) { |
| |
1168 if (!strcmp(anames[i], "id")) |
| |
1169 id = avalues[i]; |
| |
1170 if (!strcmp(anames[i], "name")) |
| |
1171 name = avalues[i]; |
| |
1172 } |
| |
1173 if (!name || !id) |
| |
1174 return; |
| |
1175 |
| |
1176 parent = g_queue_peek_head(s->q); |
| |
1177 r = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATEGORY, name, parent); |
| |
1178 gaim_roomlist_room_add_field(list, r, (gpointer)name); |
| |
1179 gaim_roomlist_room_add_field(list, r, (gpointer)id); |
| |
1180 gaim_roomlist_room_add(list, r); |
| |
1181 g_queue_push_head(s->q, r); |
| |
1182 } else if (!strcmp(ename, "room")) { |
| |
1183 s->room.users = s->room.voices = s->room.webcams = 0; |
| |
1184 |
| |
1185 for (i = 0; anames[i]; i++) { |
| |
1186 if (!strcmp(anames[i], "id")) { |
| |
1187 if (s->room.id) |
| |
1188 g_free(s->room.id); |
| |
1189 s->room.id = g_strdup(avalues[i]); |
| |
1190 } else if (!strcmp(anames[i], "name")) { |
| |
1191 if (s->room.name) |
| |
1192 g_free(s->room.name); |
| |
1193 s->room.name = g_strdup(avalues[i]); |
| |
1194 } else if (!strcmp(anames[i], "topic")) { |
| |
1195 if (s->room.topic) |
| |
1196 g_free(s->room.topic); |
| |
1197 s->room.topic = g_strdup(avalues[i]); |
| |
1198 } else if (!strcmp(anames[i], "type")) { |
| |
1199 if (!strcmp("yahoo", avalues[i])) |
| |
1200 s->room.type = yrt_yahoo; |
| |
1201 else |
| |
1202 s->room.type = yrt_user; |
| |
1203 } |
| |
1204 } |
| |
1205 |
| |
1206 } else if (!strcmp(ename, "lobby")) { |
| |
1207 struct yahoo_lobby *lob = g_new0(struct yahoo_lobby, 1); |
| |
1208 |
| |
1209 for (i = 0; anames[i]; i++) { |
| |
1210 if (!strcmp(anames[i], "count")) { |
| |
1211 lob->count = strtol(avalues[i], NULL, 10); |
| |
1212 } else if (!strcmp(anames[i], "users")) { |
| |
1213 s->room.users += lob->users = strtol(avalues[i], NULL, 10); |
| |
1214 } else if (!strcmp(anames[i], "voices")) { |
| |
1215 s->room.voices += lob->voices = strtol(avalues[i], NULL, 10); |
| |
1216 } else if (!strcmp(anames[i], "webcams")) { |
| |
1217 s->room.webcams += lob->webcams = strtol(avalues[i], NULL, 10); |
| |
1218 } |
| |
1219 } |
| |
1220 g_queue_push_head(s->q, lob); |
| |
1221 } |
| |
1222 } |
| |
1223 |
| |
1224 static void yahoo_chatlist_end_element(GMarkupParseContext *context, const gchar *ename, |
| |
1225 gpointer user_data, GError **error) |
| |
1226 { |
| |
1227 struct yahoo_chatxml_state *s = user_data; |
| |
1228 |
| |
1229 if (!strcmp(ename, "category")) { |
| |
1230 g_queue_pop_head(s->q); |
| |
1231 } else if (!strcmp(ename, "room")) { |
| |
1232 struct yahoo_lobby *lob; |
| |
1233 GaimRoomlistRoom *r, *l; |
| |
1234 |
| |
1235 if (s->room.type == yrt_yahoo) |
| |
1236 r = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATEGORY|GAIM_ROOMLIST_ROOMTYPE_ROOM, |
| |
1237 s->room.name, s->yrl->cat); |
| |
1238 else |
| |
1239 r = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATEGORY|GAIM_ROOMLIST_ROOMTYPE_ROOM, |
| |
1240 s->room.name, s->yrl->ucat); |
| |
1241 |
| |
1242 gaim_roomlist_room_add_field(s->list, r, s->room.name); |
| |
1243 gaim_roomlist_room_add_field(s->list, r, s->room.id); |
| |
1244 gaim_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.users)); |
| |
1245 gaim_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.voices)); |
| |
1246 gaim_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.webcams)); |
| |
1247 gaim_roomlist_room_add_field(s->list, r, s->room.topic); |
| |
1248 gaim_roomlist_room_add(s->list, r); |
| |
1249 |
| |
1250 while ((lob = g_queue_pop_head(s->q))) { |
| |
1251 char *name = g_strdup_printf("%s:%d", s->room.name, lob->count); |
| |
1252 l = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, name, r); |
| |
1253 |
| |
1254 gaim_roomlist_room_add_field(s->list, l, name); |
| |
1255 gaim_roomlist_room_add_field(s->list, l, s->room.id); |
| |
1256 gaim_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->users)); |
| |
1257 gaim_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->voices)); |
| |
1258 gaim_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->webcams)); |
| |
1259 gaim_roomlist_room_add_field(s->list, l, s->room.topic); |
| |
1260 gaim_roomlist_room_add(s->list, l); |
| |
1261 |
| |
1262 g_free(name); |
| |
1263 g_free(lob); |
| |
1264 } |
| |
1265 } |
| |
1266 } |
| |
1267 |
| |
1268 static GMarkupParser parser = { |
| |
1269 yahoo_chatlist_start_element, |
| |
1270 yahoo_chatlist_end_element, |
| |
1271 NULL, |
| |
1272 NULL, |
| |
1273 NULL |
| |
1274 }; |
| |
1275 |
| |
1276 static void yahoo_roomlist_cleanup(GaimRoomlist *list, struct yahoo_roomlist *yrl) |
| |
1277 { |
| |
1278 gaim_roomlist_set_in_progress(list, FALSE); |
| |
1279 |
| |
1280 if (yrl) { |
| |
1281 list->proto_data = g_list_remove(list->proto_data, yrl); |
| |
1282 yahoo_roomlist_destroy(yrl); |
| |
1283 } |
| |
1284 |
| |
1285 gaim_roomlist_unref(list); |
| |
1286 } |
| |
1287 |
| |
1288 static void yahoo_roomlist_pending(gpointer data, gint source, GaimInputCondition cond) |
| |
1289 { |
| |
1290 struct yahoo_roomlist *yrl = data; |
| |
1291 GaimRoomlist *list = yrl->list; |
| |
1292 char buf[1024]; |
| |
1293 int len; |
| |
1294 guchar *start; |
| |
1295 struct yahoo_chatxml_state *s; |
| |
1296 |
| |
1297 len = read(yrl->fd, buf, sizeof(buf)); |
| |
1298 |
| |
1299 if (len < 0 && errno == EAGAIN) |
| |
1300 return; |
| |
1301 |
| |
1302 if (len <= 0) { |
| |
1303 if (yrl->parse) |
| |
1304 g_markup_parse_context_end_parse(yrl->parse, NULL); |
| |
1305 yahoo_roomlist_cleanup(list, yrl); |
| |
1306 return; |
| |
1307 } |
| |
1308 |
| |
1309 yrl->rxqueue = g_realloc(yrl->rxqueue, len + yrl->rxlen); |
| |
1310 memcpy(yrl->rxqueue + yrl->rxlen, buf, len); |
| |
1311 yrl->rxlen += len; |
| |
1312 |
| |
1313 if (!yrl->started) { |
| |
1314 yrl->started = TRUE; |
| |
1315 start = (guchar *)g_strstr_len((char *)yrl->rxqueue, yrl->rxlen, "\r\n\r\n"); |
| |
1316 if (!start || (start - yrl->rxqueue + 4) >= yrl->rxlen) |
| |
1317 return; |
| |
1318 start += 4; |
| |
1319 } else { |
| |
1320 start = yrl->rxqueue; |
| |
1321 } |
| |
1322 |
| |
1323 if (yrl->parse == NULL) { |
| |
1324 s = yahoo_chatxml_state_new(list, yrl); |
| |
1325 yrl->parse = g_markup_parse_context_new(&parser, 0, s, |
| |
1326 (GDestroyNotify)yahoo_chatxml_state_destroy); |
| |
1327 } |
| |
1328 |
| |
1329 if (!g_markup_parse_context_parse(yrl->parse, (char *)start, (yrl->rxlen - (start - yrl->rxqueue)), NULL)) { |
| |
1330 |
| |
1331 yahoo_roomlist_cleanup(list, yrl); |
| |
1332 return; |
| |
1333 } |
| |
1334 |
| |
1335 yrl->rxlen = 0; |
| |
1336 } |
| |
1337 |
| |
1338 static void yahoo_roomlist_send_cb(gpointer data, gint source, GaimInputCondition cond) |
| |
1339 { |
| |
1340 struct yahoo_roomlist *yrl; |
| |
1341 GaimRoomlist *list; |
| |
1342 int written, remaining; |
| |
1343 |
| |
1344 yrl = data; |
| |
1345 list = yrl->list; |
| |
1346 |
| |
1347 remaining = strlen(yrl->txbuf) - yrl->tx_written; |
| |
1348 written = write(yrl->fd, yrl->txbuf + yrl->tx_written, remaining); |
| |
1349 |
| |
1350 if (written < 0 && errno == EAGAIN) |
| |
1351 written = 0; |
| |
1352 else if (written <= 0) { |
| |
1353 gaim_input_remove(yrl->inpa); |
| |
1354 yrl->inpa = 0; |
| |
1355 g_free(yrl->txbuf); |
| |
1356 yrl->txbuf = NULL; |
| |
1357 gaim_notify_error(gaim_account_get_connection(list->account), NULL, _("Unable to connect"), _("Fetching the room list failed.")); |
| |
1358 yahoo_roomlist_cleanup(list, yrl); |
| |
1359 return; |
| |
1360 } |
| |
1361 |
| |
1362 if (written < remaining) { |
| |
1363 yrl->tx_written += written; |
| |
1364 return; |
| |
1365 } |
| |
1366 |
| |
1367 g_free(yrl->txbuf); |
| |
1368 yrl->txbuf = NULL; |
| |
1369 |
| |
1370 gaim_input_remove(yrl->inpa); |
| |
1371 yrl->inpa = gaim_input_add(yrl->fd, GAIM_INPUT_READ, |
| |
1372 yahoo_roomlist_pending, yrl); |
| |
1373 |
| |
1374 } |
| |
1375 |
| |
1376 static void yahoo_roomlist_got_connected(gpointer data, gint source, const gchar *error_message) |
| |
1377 { |
| |
1378 struct yahoo_roomlist *yrl = data; |
| |
1379 GaimRoomlist *list = yrl->list; |
| |
1380 struct yahoo_data *yd = gaim_account_get_connection(list->account)->proto_data; |
| |
1381 |
| |
1382 if (source < 0) { |
| |
1383 gaim_notify_error(gaim_account_get_connection(list->account), NULL, _("Unable to connect"), _("Fetching the room list failed.")); |
| |
1384 yahoo_roomlist_cleanup(list, yrl); |
| |
1385 return; |
| |
1386 } |
| |
1387 |
| |
1388 yrl->fd = source; |
| |
1389 |
| |
1390 yrl->txbuf = g_strdup_printf( |
| |
1391 "GET http://%s/%s HTTP/1.0\r\n" |
| |
1392 "Host: %s\r\n" |
| |
1393 "Cookie: Y=%s; T=%s\r\n\r\n", |
| |
1394 yrl->host, yrl->path, yrl->host, yd->cookie_y, |
| |
1395 yd->cookie_t); |
| |
1396 |
| |
1397 |
| |
1398 yrl->inpa = gaim_input_add(yrl->fd, GAIM_INPUT_WRITE, |
| |
1399 yahoo_roomlist_send_cb, yrl); |
| |
1400 yahoo_roomlist_send_cb(yrl, yrl->fd, GAIM_INPUT_WRITE); |
| |
1401 } |
| |
1402 |
| |
1403 GaimRoomlist *yahoo_roomlist_get_list(GaimConnection *gc) |
| |
1404 { |
| |
1405 struct yahoo_roomlist *yrl; |
| |
1406 GaimRoomlist *rl; |
| |
1407 const char *rll; |
| |
1408 char *url; |
| |
1409 GList *fields = NULL; |
| |
1410 GaimRoomlistField *f; |
| |
1411 |
| |
1412 rll = gaim_account_get_string(gaim_connection_get_account(gc), |
| |
1413 "room_list_locale", YAHOO_ROOMLIST_LOCALE); |
| |
1414 |
| |
1415 if (rll != NULL && *rll != '\0') { |
| |
1416 url = g_strdup_printf("%s?chatcat=0&intl=%s", |
| |
1417 gaim_account_get_string(gaim_connection_get_account(gc), |
| |
1418 "room_list", YAHOO_ROOMLIST_URL), rll); |
| |
1419 } else { |
| |
1420 url = g_strdup_printf("%s?chatcat=0", |
| |
1421 gaim_account_get_string(gaim_connection_get_account(gc), |
| |
1422 "room_list", YAHOO_ROOMLIST_URL)); |
| |
1423 } |
| |
1424 |
| |
1425 yrl = g_new0(struct yahoo_roomlist, 1); |
| |
1426 rl = gaim_roomlist_new(gaim_connection_get_account(gc)); |
| |
1427 yrl->list = rl; |
| |
1428 |
| |
1429 gaim_url_parse(url, &(yrl->host), NULL, &(yrl->path), NULL, NULL); |
| |
1430 g_free(url); |
| |
1431 |
| |
1432 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "room", TRUE); |
| |
1433 fields = g_list_append(fields, f); |
| |
1434 |
| |
1435 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "id", TRUE); |
| |
1436 fields = g_list_append(fields, f); |
| |
1437 |
| |
1438 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT, _("Users"), "users", FALSE); |
| |
1439 fields = g_list_append(fields, f); |
| |
1440 |
| |
1441 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT, _("Voices"), "voices", FALSE); |
| |
1442 fields = g_list_append(fields, f); |
| |
1443 |
| |
1444 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT, _("Webcams"), "webcams", FALSE); |
| |
1445 fields = g_list_append(fields, f); |
| |
1446 |
| |
1447 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, _("Topic"), "topic", FALSE); |
| |
1448 fields = g_list_append(fields, f); |
| |
1449 |
| |
1450 gaim_roomlist_set_fields(rl, fields); |
| |
1451 |
| |
1452 if (gaim_proxy_connect(gaim_connection_get_account(gc), yrl->host, 80, |
| |
1453 yahoo_roomlist_got_connected, yrl) == NULL) |
| |
1454 { |
| |
1455 gaim_notify_error(gc, NULL, _("Connection problem"), _("Unable to fetch room list.")); |
| |
1456 yahoo_roomlist_cleanup(rl, yrl); |
| |
1457 return NULL; |
| |
1458 } |
| |
1459 |
| |
1460 rl->proto_data = g_list_append(rl->proto_data, yrl); |
| |
1461 |
| |
1462 gaim_roomlist_set_in_progress(rl, TRUE); |
| |
1463 return rl; |
| |
1464 } |
| |
1465 |
| |
1466 void yahoo_roomlist_cancel(GaimRoomlist *list) |
| |
1467 { |
| |
1468 GList *l, *k; |
| |
1469 |
| |
1470 k = l = list->proto_data; |
| |
1471 list->proto_data = NULL; |
| |
1472 |
| |
1473 gaim_roomlist_set_in_progress(list, FALSE); |
| |
1474 |
| |
1475 for (; l; l = l->next) { |
| |
1476 yahoo_roomlist_destroy(l->data); |
| |
1477 gaim_roomlist_unref(list); |
| |
1478 } |
| |
1479 g_list_free(k); |
| |
1480 } |
| |
1481 |
| |
1482 void yahoo_roomlist_expand_category(GaimRoomlist *list, GaimRoomlistRoom *category) |
| |
1483 { |
| |
1484 struct yahoo_roomlist *yrl; |
| |
1485 char *url; |
| |
1486 char *id; |
| |
1487 const char *rll; |
| |
1488 |
| |
1489 if (category->type != GAIM_ROOMLIST_ROOMTYPE_CATEGORY) |
| |
1490 return; |
| |
1491 |
| |
1492 if (!(id = g_list_nth_data(category->fields, 1))) { |
| |
1493 gaim_roomlist_set_in_progress(list, FALSE); |
| |
1494 return; |
| |
1495 } |
| |
1496 |
| |
1497 rll = gaim_account_get_string(list->account, "room_list_locale", |
| |
1498 YAHOO_ROOMLIST_LOCALE); |
| |
1499 |
| |
1500 if (rll != NULL && *rll != '\0') { |
| |
1501 url = g_strdup_printf("%s?chatroom_%s=0&intl=%s", |
| |
1502 gaim_account_get_string(list->account,"room_list", |
| |
1503 YAHOO_ROOMLIST_URL), id, rll); |
| |
1504 } else { |
| |
1505 url = g_strdup_printf("%s?chatroom_%s=0", |
| |
1506 gaim_account_get_string(list->account,"room_list", |
| |
1507 YAHOO_ROOMLIST_URL), id); |
| |
1508 } |
| |
1509 |
| |
1510 yrl = g_new0(struct yahoo_roomlist, 1); |
| |
1511 yrl->list = list; |
| |
1512 yrl->cat = category; |
| |
1513 list->proto_data = g_list_append(list->proto_data, yrl); |
| |
1514 |
| |
1515 gaim_url_parse(url, &(yrl->host), NULL, &(yrl->path), NULL, NULL); |
| |
1516 g_free(url); |
| |
1517 |
| |
1518 yrl->ucat = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATEGORY, _("User Rooms"), yrl->cat); |
| |
1519 gaim_roomlist_room_add(list, yrl->ucat); |
| |
1520 |
| |
1521 if (gaim_proxy_connect(list->account, yrl->host, 80, |
| |
1522 yahoo_roomlist_got_connected, yrl) == NULL) |
| |
1523 { |
| |
1524 gaim_notify_error(gaim_account_get_connection(list->account), |
| |
1525 NULL, _("Connection problem"), _("Unable to fetch room list.")); |
| |
1526 gaim_roomlist_ref(list); |
| |
1527 yahoo_roomlist_cleanup(list, yrl); |
| |
1528 return; |
| |
1529 } |
| |
1530 |
| |
1531 gaim_roomlist_set_in_progress(list, TRUE); |
| |
1532 gaim_roomlist_ref(list); |
| |
1533 } |