Mercurial > pidgin.yaz
comparison src/protocols/yahoo/ycht.c @ 9376:3aa848ccf986
[gaim-migrate @ 10184]
*** Danger Will Robinson!!!
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Thu, 24 Jun 2004 07:08:33 +0000 |
parents | |
children | 3b0c6255033e |
comparison
equal
deleted
inserted
replaced
9375:49b7b30f6e4e | 9376:3aa848ccf986 |
---|---|
1 /** | |
2 * @file ycht.c The Yahoo! protocol plugin, YCHT protocol stuff. | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2004 Timothy Ringenbach <omarvo@hotmail.com> | |
7 * Liberal amounts of code borrowed from the rest of the Yahoo! prpl. | |
8 * | |
9 * Gaim is the legal property of its developers, whose names are too numerous | |
10 * to list here. Please refer to the COPYRIGHT file distributed with this | |
11 * source distribution. | |
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 #include <string.h> | |
29 | |
30 #include "internal.h" | |
31 #include "prpl.h" | |
32 #include "notify.h" | |
33 #include "account.h" | |
34 #include "proxy.h" | |
35 #include "debug.h" | |
36 #include "conversation.h" | |
37 #include "util.h" | |
38 | |
39 #include "yahoo.h" | |
40 #include "ycht.h" | |
41 #include "yahoochat.h" | |
42 | |
43 /* | |
44 * dword: YCHT | |
45 * dword: 0x000000AE | |
46 * dword: service | |
47 * word: status | |
48 * word: size | |
49 */ | |
50 #define YAHOO_CHAT_ID (1) | |
51 /************************************************************************************ | |
52 * Functions to process various kinds of packets. | |
53 ************************************************************************************/ | |
54 static void ycht_process_login(YchtConn *ycht, YchtPkt *pkt) | |
55 { | |
56 GaimConnection *gc = ycht->gc; | |
57 struct yahoo_data *yd = gc->proto_data; | |
58 | |
59 if (ycht->logged_in) | |
60 return; | |
61 | |
62 yd->chat_online = TRUE; | |
63 ycht->logged_in = TRUE; | |
64 | |
65 if (ycht->room) | |
66 ycht_chat_join(ycht, ycht->room); | |
67 } | |
68 | |
69 static void ycht_process_logout(YchtConn *ycht, YchtPkt *pkt) | |
70 { | |
71 GaimConnection *gc = ycht->gc; | |
72 struct yahoo_data *yd = gc->proto_data; | |
73 | |
74 yd->chat_online = FALSE; | |
75 ycht->logged_in = FALSE; | |
76 } | |
77 | |
78 static void ycht_process_chatjoin(YchtConn *ycht, YchtPkt *pkt) | |
79 { | |
80 char *room, *topic; | |
81 GaimConnection *gc = ycht->gc; | |
82 GaimConversation *c = NULL; | |
83 gboolean new_room = FALSE; | |
84 char **members; | |
85 int i; | |
86 | |
87 room = g_list_nth_data(pkt->data, 0); | |
88 topic = g_list_nth_data(pkt->data, 1); | |
89 if (!g_list_nth_data(pkt->data, 4)) | |
90 return; | |
91 if (!room) | |
92 return; | |
93 | |
94 members = g_strsplit(g_list_nth_data(pkt->data, 4), "\001", 0); | |
95 for (i = 0; members[i]; i++) { | |
96 char *tmp = strchr(members[i], '\002'); | |
97 if (tmp) | |
98 *tmp = '\0'; | |
99 } | |
100 | |
101 | |
102 if (g_list_length(pkt->data) > 5) | |
103 new_room = TRUE; | |
104 | |
105 if (new_room && ycht->changing_rooms) { | |
106 serv_got_chat_left(gc, YAHOO_CHAT_ID); | |
107 ycht->changing_rooms = FALSE; | |
108 c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room); | |
109 } else { | |
110 c = gaim_find_chat(gc, YAHOO_CHAT_ID); | |
111 } | |
112 | |
113 | |
114 if (topic) | |
115 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(c), NULL, topic); | |
116 | |
117 for (i = 0; members[i]; i++) { | |
118 if (new_room) { | |
119 GList l; | |
120 /*if (!strcmp(members[i], gaim_connection_get_display_name(ycht->gc))) | |
121 continue;*/ | |
122 l.data = members[i]; | |
123 l.next = l.prev = NULL; | |
124 gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), &l); | |
125 } else { | |
126 yahoo_chat_add_user(GAIM_CONV_CHAT(c), members[i], NULL); | |
127 } | |
128 } | |
129 | |
130 g_strfreev(members); | |
131 } | |
132 | |
133 static void ycht_process_chatpart(YchtConn *ycht, YchtPkt *pkt) | |
134 { | |
135 char *room, *who; | |
136 | |
137 room = g_list_nth_data(pkt->data, 0); | |
138 who = g_list_nth_data(pkt->data, 1); | |
139 | |
140 if (who && room) { | |
141 GaimConversation *c = gaim_find_chat(ycht->gc, YAHOO_CHAT_ID); | |
142 if (c && !gaim_utf8_strcasecmp(gaim_conversation_get_name(c), room)) | |
143 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(c), who, NULL); | |
144 | |
145 } | |
146 } | |
147 | |
148 static void ycht_progress_chatmsg(YchtConn *ycht, YchtPkt *pkt) | |
149 { | |
150 char *who, *what, *msg; | |
151 GaimConversation *c; | |
152 GaimConnection *gc = ycht->gc; | |
153 | |
154 who = g_list_nth_data(pkt->data, 1); | |
155 what = g_list_nth_data(pkt->data, 2); | |
156 | |
157 if (!who || !what) | |
158 return; | |
159 | |
160 c = gaim_find_chat(gc, YAHOO_CHAT_ID); | |
161 if (!c) | |
162 return; | |
163 | |
164 msg = yahoo_string_decode(gc, what, 1); | |
165 what = yahoo_codes_to_html(msg); | |
166 g_free(msg); | |
167 | |
168 if (pkt->service == YCHT_SERVICE_CHATMSG_EMOTE) { | |
169 char *tmp = g_strdup_printf("/me %s", what); | |
170 g_free(what); | |
171 what = tmp; | |
172 } | |
173 | |
174 serv_got_chat_in(gc, YAHOO_CHAT_ID, who, 0, what, time(NULL)); | |
175 g_free(what); | |
176 } | |
177 | |
178 static void ycht_progress_online_friends(YchtConn *ycht, YchtPkt *pkt) | |
179 { | |
180 #if 0 | |
181 GaimConnection *gc = ycht->gc; | |
182 struct yahoo_data *yd = gc->proto_data; | |
183 | |
184 if (ycht->logged_in) | |
185 return; | |
186 | |
187 yd->chat_online = TRUE; | |
188 ycht->logged_in = TRUE; | |
189 | |
190 if (ycht->room) | |
191 ycht_chat_join(ycht, ycht->room); | |
192 #endif | |
193 } | |
194 | |
195 /***************************************************************************** | |
196 * Functions dealing with YCHT packets and their contents directly. | |
197 *****************************************************************************/ | |
198 static void ycht_packet_dump(const char *data, int len) | |
199 { | |
200 #ifdef YAHOO_YCHT_DEBUG | |
201 int i; | |
202 | |
203 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
204 | |
205 for (i = 0; i + 1 < len; i += 2) { | |
206 if ((i % 16 == 0) && i) { | |
207 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
208 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
209 } | |
210 | |
211 gaim_debug(GAIM_DEBUG_MISC, NULL, "%02hhx%02hhx ", data[i], data[i + 1]); | |
212 } | |
213 if (i < len) | |
214 gaim_debug(GAIM_DEBUG_MISC, NULL, "%02hhx", data[i]); | |
215 | |
216 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
217 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
218 | |
219 for (i = 0; i < len; i++) { | |
220 if ((i % 16 == 0) && i) { | |
221 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
222 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
223 } | |
224 | |
225 if (g_ascii_isprint(data[i])) | |
226 gaim_debug(GAIM_DEBUG_MISC, NULL, "%c ", data[i]); | |
227 else | |
228 gaim_debug(GAIM_DEBUG_MISC, NULL, ". "); | |
229 } | |
230 | |
231 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
232 #endif | |
233 } | |
234 | |
235 static YchtPkt *ycht_packet_new(guint version, guint service, int status) | |
236 { | |
237 YchtPkt *ret; | |
238 | |
239 ret = g_new0(YchtPkt, 1); | |
240 | |
241 ret->version = version; | |
242 ret->service = service; | |
243 ret->status = status; | |
244 | |
245 return ret; | |
246 } | |
247 | |
248 static void ycht_packet_append(YchtPkt *pkt, const char *str) | |
249 { | |
250 g_return_if_fail(pkt != NULL); | |
251 g_return_if_fail(str != NULL); | |
252 | |
253 pkt->data = g_list_append(pkt->data, g_strdup(str)); | |
254 } | |
255 | |
256 static int ycht_packet_length(YchtPkt *pkt) | |
257 { | |
258 int ret; | |
259 GList *l; | |
260 | |
261 ret = YCHT_HEADER_LEN; | |
262 | |
263 for (l = pkt->data; l; l = l->next) { | |
264 ret += strlen(l->data); | |
265 if (l->next) | |
266 ret += strlen(YCHT_SEP); | |
267 } | |
268 | |
269 return ret; | |
270 } | |
271 | |
272 static void ycht_packet_send(YchtConn *ycht, YchtPkt *pkt) | |
273 { | |
274 int len, pos; | |
275 char *buf; | |
276 GList *l; | |
277 | |
278 g_return_if_fail(ycht != NULL); | |
279 g_return_if_fail(pkt != NULL); | |
280 g_return_if_fail(ycht->fd != -1); | |
281 | |
282 pos = 0; | |
283 len = ycht_packet_length(pkt); | |
284 buf = g_malloc(len); | |
285 | |
286 memcpy(buf + pos, "YCHT", 4); pos += 4; | |
287 pos += yahoo_put32(buf + pos, pkt->version); | |
288 pos += yahoo_put32(buf + pos, pkt->service); | |
289 pos += yahoo_put16(buf + pos, pkt->status); | |
290 pos += yahoo_put16(buf + pos, len - YCHT_HEADER_LEN); | |
291 | |
292 for (l = pkt->data; l; l = l->next) { | |
293 int slen = strlen(l->data); | |
294 memcpy(buf + pos, l->data, slen); pos += slen; | |
295 | |
296 if (l->next) { | |
297 memcpy(buf + pos, YCHT_SEP, strlen(YCHT_SEP)); | |
298 pos += strlen(YCHT_SEP); | |
299 } | |
300 } | |
301 | |
302 write(ycht->fd, buf, len); | |
303 g_free(buf); | |
304 } | |
305 | |
306 static void ycht_packet_read(YchtPkt *pkt, const char *buf, int len) | |
307 { | |
308 const char *pos = buf; | |
309 const char *needle; | |
310 char *tmp, *tmp2; | |
311 int i = 0; | |
312 | |
313 while (len > 0 && (needle = g_strstr_len(pos, len, YCHT_SEP))) { | |
314 tmp = g_strndup(pos, needle - pos); | |
315 pkt->data = g_list_append(pkt->data, tmp); | |
316 len -= needle - pos + strlen(YCHT_SEP); | |
317 pos = needle + strlen(YCHT_SEP); | |
318 tmp2 = g_strescape(tmp, NULL); | |
319 gaim_debug_misc("yahoo", "Data[%d]:\t%s\n", i++, tmp2); | |
320 g_free(tmp2); | |
321 } | |
322 | |
323 if (len) { | |
324 tmp = g_strndup(pos, len); | |
325 pkt->data = g_list_append(pkt->data, tmp); | |
326 tmp2 = g_strescape(tmp, NULL); | |
327 gaim_debug_misc("yahoo", "Data[%d]:\t%s\n", i, tmp2); | |
328 g_free(tmp2); | |
329 }; | |
330 | |
331 gaim_debug_misc("yahoo", "--==End of incoming YCHT packet==--\n"); | |
332 } | |
333 | |
334 static void ycht_packet_process(YchtConn *ycht, YchtPkt *pkt) | |
335 { | |
336 if (pkt->data && !strncmp(pkt->data->data, "*** Danger Will Robinson!!!", strlen("*** Danger Will Robinson!!!"))) | |
337 return; | |
338 | |
339 switch (pkt->service) { | |
340 case YCHT_SERVICE_LOGIN: | |
341 ycht_process_login(ycht, pkt); | |
342 break; | |
343 case YCHT_SERVICE_LOGOUT: | |
344 ycht_process_logout(ycht, pkt); | |
345 break; | |
346 case YCHT_SERVICE_CHATJOIN: | |
347 ycht_process_chatjoin(ycht, pkt); | |
348 break; | |
349 case YCHT_SERVICE_CHATPART: | |
350 ycht_process_chatpart(ycht, pkt); | |
351 break; | |
352 case YCHT_SERVICE_CHATMSG: | |
353 case YCHT_SERVICE_CHATMSG_EMOTE: | |
354 ycht_progress_chatmsg(ycht, pkt); | |
355 break; | |
356 case YCHT_SERVICE_ONLINE_FRIENDS: | |
357 ycht_progress_online_friends(ycht, pkt); | |
358 break; | |
359 default: | |
360 gaim_debug_warning("yahoo", "YCHT: warning, unhandled service 0x%02x\n", pkt->service); | |
361 } | |
362 } | |
363 | |
364 static void ycht_packet_free(YchtPkt *pkt) | |
365 { | |
366 GList *l; | |
367 | |
368 g_return_if_fail(pkt != NULL); | |
369 | |
370 for (l = pkt->data; l; l = l->next) | |
371 g_free(l->data); | |
372 g_list_free(pkt->data); | |
373 g_free(pkt); | |
374 } | |
375 | |
376 /************************************************************************************ | |
377 * Functions dealing with connecting and disconnecting and reading data into YchtPkt | |
378 * structs, and all that stuff. | |
379 ************************************************************************************/ | |
380 | |
381 void ycht_connection_close(YchtConn *ycht) | |
382 { | |
383 struct yahoo_data *yd = ycht->gc->proto_data; | |
384 | |
385 if (yd) { | |
386 yd->ycht = NULL; | |
387 yd->chat_online = FALSE; | |
388 } | |
389 | |
390 if (ycht->fd > 0) | |
391 close(ycht->fd); | |
392 if (ycht->inpa) | |
393 gaim_input_remove(ycht->inpa); | |
394 | |
395 if (ycht->rxqueue) | |
396 g_free(ycht->rxqueue); | |
397 | |
398 g_free(ycht); | |
399 } | |
400 | |
401 static void ycht_connection_error(YchtConn *ycht, const gchar *error) | |
402 { | |
403 #if 0 | |
404 /* string freeze */ | |
405 gaim_notify_info(ycht->gc, NULL, _("Connection problem with the YCHT server."), error); | |
406 #endif | |
407 ycht_connection_close(ycht); | |
408 } | |
409 | |
410 static void ycht_pending(gpointer data, gint source, GaimInputCondition cond) | |
411 { | |
412 YchtConn *ycht = data; | |
413 char buf[1024]; | |
414 int len; | |
415 | |
416 len = read(ycht->fd, buf, sizeof(buf)); | |
417 | |
418 if (len <= 0) { | |
419 /*ycht_connection_error(ycht, _("Unable to read"));*/ | |
420 ycht_connection_error(ycht, NULL); | |
421 return; | |
422 } | |
423 | |
424 ycht->rxqueue = g_realloc(ycht->rxqueue, len + ycht->rxlen); | |
425 memcpy(ycht->rxqueue + ycht->rxlen, buf, len); | |
426 ycht->rxlen += len; | |
427 | |
428 while (1) { | |
429 YchtPkt *pkt; | |
430 int pos = 0; | |
431 int pktlen; | |
432 guint service; | |
433 guint version; | |
434 gint status; | |
435 | |
436 if (ycht->rxlen < YCHT_HEADER_LEN) | |
437 return; | |
438 | |
439 if (strncmp("YCHT", ycht->rxqueue, 4) != 0) | |
440 gaim_debug_error("yahoo", "YCHT: protocol error.\n"); | |
441 | |
442 pos += 4; /* YCHT */ | |
443 | |
444 version = yahoo_get32(ycht->rxqueue + pos); pos += 4; | |
445 service = yahoo_get32(ycht->rxqueue + pos); pos += 4; | |
446 status = yahoo_get16(ycht->rxqueue + pos); pos += 2; | |
447 pktlen = yahoo_get16(ycht->rxqueue + pos); pos += 2; | |
448 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
449 "ycht: %d bytes to read, rxlen is %d\n", pktlen, ycht->rxlen); | |
450 | |
451 if (ycht->rxlen < (YCHT_HEADER_LEN + pktlen)) | |
452 return; | |
453 | |
454 gaim_debug_misc("yahoo", "--==Incoming YCHT packet==--\n"); | |
455 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
456 "YCHT Service: 0x%02x Version: 0x%02x Status: 0x%02x\n", | |
457 service, version, status); | |
458 ycht_packet_dump(ycht->rxqueue, YCHT_HEADER_LEN + pktlen); | |
459 | |
460 pkt = ycht_packet_new(version, service, status); | |
461 ycht_packet_read(pkt, ycht->rxqueue + pos, pktlen); | |
462 | |
463 ycht->rxlen -= YCHT_HEADER_LEN + pktlen; | |
464 if (ycht->rxlen) { | |
465 char *tmp = g_memdup(ycht->rxqueue + YCHT_HEADER_LEN + pktlen, ycht->rxlen); | |
466 g_free(ycht->rxqueue); | |
467 ycht->rxqueue = tmp; | |
468 } else { | |
469 g_free(ycht->rxqueue); | |
470 ycht->rxqueue = NULL; | |
471 } | |
472 | |
473 ycht_packet_process(ycht, pkt); | |
474 | |
475 ycht_packet_free(pkt); | |
476 } | |
477 } | |
478 | |
479 static void ycht_got_connected(gpointer data, gint source, GaimInputCondition cond) | |
480 { | |
481 YchtConn *ycht = data; | |
482 GaimConnection *gc = ycht->gc; | |
483 struct yahoo_data *yd = gc->proto_data; | |
484 YchtPkt *pkt; | |
485 char *buf; | |
486 | |
487 if (source < 0) { | |
488 /*ycht_connection_error(ycht, _("Unable to connect."));*/ | |
489 ycht_connection_error(ycht, NULL); | |
490 return; | |
491 } | |
492 | |
493 ycht->fd = source; | |
494 | |
495 pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_LOGIN, 0); | |
496 | |
497 buf = g_strdup_printf("%s\001Y=%s; T=%s", gaim_connection_get_display_name(gc), yd->cookie_y, yd->cookie_t); | |
498 ycht_packet_append(pkt, buf); | |
499 g_free(buf); | |
500 | |
501 ycht_packet_send(ycht, pkt); | |
502 | |
503 ycht_packet_free(pkt); | |
504 | |
505 ycht->inpa = gaim_input_add(ycht->fd, GAIM_INPUT_READ, ycht_pending, ycht); | |
506 } | |
507 | |
508 void ycht_connection_open(GaimConnection *gc) | |
509 { | |
510 YchtConn *ycht; | |
511 struct yahoo_data *yd = gc->proto_data; | |
512 GaimAccount *account = gaim_connection_get_account(gc); | |
513 | |
514 ycht = g_new0(YchtConn, 1); | |
515 ycht->gc = gc; | |
516 ycht->fd = -1; | |
517 | |
518 yd->ycht = ycht; | |
519 | |
520 if (gaim_proxy_connect(account, | |
521 gaim_account_get_string(account, "ycht-server", YAHOO_YCHT_HOST), | |
522 gaim_account_get_int(account, "ycht-port", YAHOO_YCHT_PORT), | |
523 ycht_got_connected, ycht) != 0) | |
524 { | |
525 /*ycht_connection_error(ycht, _("Connection problem"));*/ | |
526 ycht_connection_error(ycht, NULL); | |
527 return; | |
528 } | |
529 } | |
530 | |
531 /******************************************************************************************* | |
532 * These are functions called because the user did something. | |
533 *******************************************************************************************/ | |
534 | |
535 void ycht_chat_join(YchtConn *ycht, const char *room) | |
536 { | |
537 YchtPkt *pkt; | |
538 char *tmp; | |
539 | |
540 tmp = g_strdup(room); | |
541 if (ycht->room) | |
542 g_free(ycht->room); | |
543 ycht->room = tmp; | |
544 | |
545 if (!ycht->logged_in) | |
546 return; | |
547 | |
548 ycht->changing_rooms = TRUE; | |
549 pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_CHATJOIN, 0); | |
550 ycht_packet_append(pkt, ycht->room); | |
551 ycht_packet_send(ycht, pkt); | |
552 ycht_packet_free(pkt); | |
553 } | |
554 | |
555 int ycht_chat_send(YchtConn *ycht, const char *room, const char *what) | |
556 { | |
557 YchtPkt *pkt; | |
558 char *msg1, *msg2, *buf; | |
559 | |
560 if (strcmp(room, ycht->room)) | |
561 gaim_debug_warning("yahoo", "uhoh, sending to the wrong room!\n"); | |
562 | |
563 pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_CHATMSG, 0); | |
564 | |
565 msg1 = yahoo_html_to_codes(what); | |
566 msg2 = yahoo_string_encode(ycht->gc, msg1, NULL); | |
567 g_free(msg1); | |
568 | |
569 buf = g_strdup_printf("%s\001%s", ycht->room, msg2); | |
570 ycht_packet_append(pkt, buf); | |
571 g_free(msg2); | |
572 g_free(buf); | |
573 | |
574 ycht_packet_send(ycht, pkt); | |
575 ycht_packet_free(pkt); | |
576 return 1; | |
577 } | |
578 | |
579 void ycht_chat_leave(YchtConn *ycht, const char *room, gboolean logout) | |
580 { | |
581 if (logout) | |
582 ycht_connection_close(ycht); | |
583 } | |
584 | |
585 void ycht_chat_send_invite(YchtConn *ycht, const char *room, const char *buddy, const char *msg) | |
586 { | |
587 } | |
588 | |
589 void ycht_chat_goto_user(YchtConn *ycht, const char *name) | |
590 { | |
591 } | |
592 | |
593 void ycht_chat_send_keepalive(YchtConn *ycht) | |
594 { | |
595 YchtPkt *pkt; | |
596 | |
597 pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_PING, 0); | |
598 ycht_packet_send(ycht, pkt); | |
599 ycht_packet_free(pkt); | |
600 } |