libpurple/protocols/gg/lib/handlers.c

changeset 38882
bea4cc95b40f
parent 38881
25cb836b9cec
parent 38182
783878958371
child 38883
90462fef3dd8
equal deleted inserted replaced
38881:25cb836b9cec 38882:bea4cc95b40f
1 /*
2 * (C) Copyright 2001-2011 Wojtek Kaniewski <wojtekka@irc.pl>
3 * Robert J. Woźny <speedy@ziew.org>
4 * Arkadiusz Miśkiewicz <arekm@pld-linux.org>
5 * Tomasz Chiliński <chilek@chilan.com>
6 * Adam Wysocki <gophi@ekg.chmurka.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License Version
10 * 2.1 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
20 * USA.
21 */
22
23 /**
24 * \file handlers.c
25 *
26 * \brief Funkcje obsługi przychodzących pakietów
27 */
28
29 #include <ctype.h>
30
31 #include "fileio.h"
32 #include "network.h"
33 #include "strman.h"
34 #include "libgadu.h"
35 #include "resolver.h"
36 #include "session.h"
37 #include "protocol.h"
38 #include "encoding.h"
39 #include "message.h"
40 #include "internal.h"
41 #include "deflate.h"
42 #include "tvbuff.h"
43 #include "protobuf.h"
44 #include "packets.pb-c.h"
45
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50
51 /* Ograniczenie długości listy kontaktów
52 * z pakietów GG_USERLIST_REPLY do 10MB. */
53 #define GG_USERLIST_REPLY_MAX_LENGTH 10485760
54
55 /**
56 * \internal Struktura opisująca funkcję obsługi pakietu.
57 */
58 typedef struct {
59 /* Typ pakietu */
60 uint32_t type;
61 /* Stan w którym pakiet jest obsługiwany */
62 enum gg_state_t state;
63 /* Minimalny rozmiar danych pakietu */
64 size_t min_length;
65 /* Funkcja obsługująca pakiet. Patrz gg_session_handle_packet(). */
66 int (*handler)(struct gg_session *, uint32_t, const char *, size_t, struct gg_event *);
67 } gg_packet_handler_t;
68
69 static int gg_ack_110(struct gg_session *gs, GG110Ack__Type type, uint32_t seq, struct gg_event *ge)
70 {
71 GG110Ack msg = GG110_ACK__INIT;
72
73 msg.type = type;
74 msg.seq = seq;
75
76 if (!GG_PROTOBUF_SEND(gs, ge, GG_ACK110, gg110_ack, msg))
77 return -1;
78 return 0;
79 }
80
81 static void gg_sync_time(struct gg_session *gs, time_t server_time)
82 {
83 time_t local_time = time(NULL);
84 int time_diff = server_time - local_time;
85
86 if (gs->private_data->time_diff == time_diff)
87 return;
88
89 gs->private_data->time_diff = time_diff;
90 gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_VERBOSE,
91 "// time synchronized (diff = %d)\n", time_diff);
92 }
93
94 static int gg_session_handle_welcome_110(struct gg_session *gs, uint32_t seed,
95 struct gg_event *ge)
96 {
97 GG105Login msg = GG105_LOGIN__INIT;
98 char client_str[1000];
99 uint8_t hash[64];
100 const char *client_name = GG11_VERSION;
101 const char *client_version = GG_DEFAULT_CLIENT_VERSION_110;
102 const char *client_target = GG11_TARGET;
103 uint8_t dummy4[4] = {0, 0, 0, 0};
104
105 if (gs->hash_type != GG_LOGIN_HASH_SHA1) {
106 gg_debug_session(gs, GG_DEBUG_ERROR, "// Unsupported hash type "
107 "for this protocol version\n");
108 gg_connection_failure(gs, ge, GG_FAILURE_INTERNAL);
109 return -1;
110 }
111
112 if (gg_login_hash_sha1_2(gs->password, seed, hash) == -1) {
113 gg_debug_session(gs, GG_DEBUG_ERROR, "// gg_watch_fd() "
114 "gg_login_hash_sha1_2() failed, "
115 "probably out of memory\n");
116 gg_connection_failure(gs, ge, GG_FAILURE_INTERNAL);
117 return -1;
118 }
119
120 if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
121 client_name = "";
122 client_target = "";
123 }
124 if (gs->client_version != NULL)
125 client_version = gs->client_version;
126 snprintf(client_str, sizeof(client_str), "%s%s%s",
127 client_name, client_version, client_target);
128 client_str[sizeof(client_str) - 1] = '\0';
129
130 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() "
131 "sending GG_LOGIN105 packet\n");
132
133 msg.lang = GG8_LANG;
134 gg_protobuf_set_uin(&msg.uin, gs->uin, NULL);
135 msg.hash.len = 20;
136 msg.hash.data = hash;
137 msg.client = client_str;
138
139 /* flagi gg8 są różne od tych dla gg11 */
140 msg.initial_status = gs->initial_status ?
141 (gs->initial_status & 0xFF) : GG_STATUS_AVAIL;
142
143 if (gs->initial_descr != NULL) {
144 msg.initial_descr = gs->initial_descr;
145 }
146
147 /* GG11.0
148 msg.supported_features = "avatar,StatusComments,gg_account_sdp,"
149 "edisc,bot,fanpage,pubdir,botCaps"; */
150 /* GG11.2 */
151 msg.supported_features = "avatar,StatusComments,ggaccount,edisc,"
152 "music_shared,bot,fanpage,pubdir,botCaps,gifts,Gift";
153
154 msg.dummy4.len = sizeof(dummy4);
155 msg.dummy4.data = dummy4;
156
157 msg.has_dummy7 = 1;
158 msg.has_dummy8 = 1;
159 msg.has_dummy10 = 1;
160
161 if (!GG_PROTOBUF_SEND(gs, ge, GG_LOGIN105, gg105_login, msg))
162 return -1;
163
164 gs->state = GG_STATE_READING_REPLY;
165 gs->check = GG_CHECK_READ;
166 return 0;
167 }
168
169 static int gg_session_handle_login110_ok(struct gg_session *gs, uint32_t type,
170 const char *ptr, size_t len, struct gg_event *ge)
171 {
172 GG110LoginOK *msg = gg110_login_ok__unpack(NULL, len, (uint8_t*)ptr);
173
174 if (!GG_PROTOBUF_VALID(gs, "GG110LoginOK", msg))
175 return -1;
176
177 gg_protobuf_expected(gs, "GG110LoginOK.dummy1", msg->dummy1, 1);
178 gg_sync_time(gs, msg->server_time);
179
180 gg_debug_session(gs, GG_DEBUG_MISC, "// login110_ok: "
181 "uin=%u, dummyhash=%s\n", msg->uin, msg->dummyhash);
182
183 gg110_login_ok__free_unpacked(msg, NULL);
184
185 ge->type = GG_EVENT_CONN_SUCCESS;
186 gs->state = GG_STATE_CONNECTED;
187 gs->check = GG_CHECK_READ;
188 gs->timeout = -1;
189 gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL;
190 #if 0
191 free(gs->status_descr);
192 gs->status_descr = gs->initial_descr;
193 #else
194 free(gs->initial_descr);
195 #endif
196 gs->initial_descr = NULL;
197
198 return 0;
199 }
200
201 /**
202 * \internal Obsługuje pakiet GG_WELCOME.
203 *
204 * Patrz gg_packet_handler_t
205 */
206 static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type,
207 const char *ptr, size_t len, struct gg_event *ge)
208 {
209 const struct gg_welcome *w;
210 int ret;
211 uint8_t hash_buf[64];
212 uint32_t local_ip;
213 struct sockaddr_in sin;
214 socklen_t sin_len = sizeof(sin);
215 uint32_t seed;
216
217 struct gg_login80 l80;
218 const char *client_name, *version, *descr;
219 uint32_t client_name_len, version_len, descr_len;
220
221 if (len < sizeof(struct gg_welcome)) {
222 ge->type = GG_EVENT_CONN_FAILED;
223 ge->event.failure = GG_FAILURE_INVALID;
224 gs->state = GG_STATE_IDLE;
225 gg_close(gs);
226 return 0;
227 }
228
229 w = (const struct gg_welcome*) ptr;
230 seed = gg_fix32(w->key);
231
232 if (gs->protocol_version >= GG_PROTOCOL_VERSION_110)
233 return gg_session_handle_welcome_110(gs, seed, ge);
234
235 memset(hash_buf, 0, sizeof(hash_buf));
236
237 switch (gs->hash_type) {
238 case GG_LOGIN_HASH_GG32:
239 {
240 uint32_t hash;
241
242 hash = gg_fix32(gg_login_hash((unsigned char*) gs->password, seed));
243 gg_debug_session(gs, GG_DEBUG_DUMP, "// gg_watch_fd() "
244 "challenge %.4x --> GG32 hash %.8x\n",
245 seed, hash);
246 memcpy(hash_buf, &hash, sizeof(hash));
247
248 break;
249 }
250
251 case GG_LOGIN_HASH_SHA1:
252 {
253 #ifndef GG_DEBUG_DISABLE
254 char tmp[41];
255 int i;
256 #endif
257
258 if (gg_login_hash_sha1_2(gs->password, seed, hash_buf) == -1) {
259 gg_debug_session(gs, GG_DEBUG_MISC,
260 "// gg_watch_fd() gg_login_hash_sha1_2()"
261 " failed, probably out of memory\n");
262 gg_close(gs);
263 ge->type = GG_EVENT_CONN_FAILED;
264 ge->event.failure = GG_FAILURE_INTERNAL;
265 gs->state = GG_STATE_IDLE;
266 return -1;
267 }
268
269 #ifndef GG_DEBUG_DISABLE
270 for (i = 0; i < 40; i += 2)
271 snprintf(tmp + i, sizeof(tmp) - i, "%02x", hash_buf[i / 2]);
272
273 gg_debug_session(gs, GG_DEBUG_DUMP, "// gg_watch_fd() "
274 "challenge %.4x --> SHA1 hash: %s\n",
275 seed, tmp);
276 #endif
277
278 break;
279 }
280
281 default:
282 break;
283 }
284
285 #if 0
286 if (gs->password != NULL && (gs->flags & (1 << GG_SESSION_FLAG_CLEAR_PASSWORD))) {
287 memset(gs->password, 0, strlen(gs->password));
288 free(gs->password);
289 gs->password = NULL;
290 }
291 #endif
292
293 if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
294 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() "
295 "detected address to %s\n", inet_ntoa(sin.sin_addr));
296 local_ip = sin.sin_addr.s_addr;
297 } else {
298 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
299 local_ip = 0;
300 }
301
302 if (gs->external_addr == 0)
303 gs->external_addr = local_ip;
304
305 memset(&l80, 0, sizeof(l80));
306 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN80 packet\n");
307 l80.uin = gg_fix32(gs->uin);
308 memcpy(l80.language, GG8_LANG, sizeof(l80.language));
309 l80.hash_type = gs->hash_type;
310 memcpy(l80.hash, hash_buf, sizeof(l80.hash));
311 l80.status = gg_fix32(gs->initial_status ? gs->initial_status : GG_STATUS_AVAIL);
312 l80.flags = gg_fix32(gs->status_flags);
313 l80.features = gg_fix32(gs->protocol_features);
314 l80.image_size = gs->image_size;
315 l80.dunno2 = 0x64;
316
317 if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
318 client_name = "";
319 client_name_len = 0;
320 } else {
321 client_name = GG8_VERSION;
322 client_name_len = strlen(GG8_VERSION);
323 }
324
325 version = (gs->client_version != NULL) ? gs->client_version : GG_DEFAULT_CLIENT_VERSION_100;
326 version_len = gg_fix32(client_name_len + strlen(version));
327
328 descr = (gs->initial_descr != NULL) ? gs->initial_descr : "";
329 descr_len = (gs->initial_descr != NULL) ? gg_fix32(strlen(gs->initial_descr)) : 0;
330
331 ret = gg_send_packet(gs,
332 GG_LOGIN80,
333 &l80, sizeof(l80),
334 &version_len, sizeof(version_len),
335 client_name, client_name_len,
336 version, strlen(version),
337 &descr_len, sizeof(descr_len),
338 descr, strlen(descr),
339 NULL);
340
341 if (ret == -1) {
342 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() "
343 "sending packet failed. (errno=%d, %s)\n",
344 errno, strerror(errno));
345 gg_close(gs);
346 ge->type = GG_EVENT_CONN_FAILED;
347 ge->event.failure = GG_FAILURE_WRITING;
348 gs->state = GG_STATE_IDLE;
349 return -1;
350 }
351
352 gs->state = GG_STATE_READING_REPLY;
353 gs->check = GG_CHECK_READ;
354
355 return 0;
356 }
357
358 /**
359 * \internal Obsługuje pakiet GG_LOGIN_OK.
360 *
361 * Patrz gg_packet_handler_t
362 */
363 static int gg_session_handle_login_ok(struct gg_session *gs, uint32_t type,
364 const char *ptr, size_t len, struct gg_event *ge)
365 {
366 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
367 ge->type = GG_EVENT_CONN_SUCCESS;
368 gs->state = GG_STATE_CONNECTED;
369 gs->check = GG_CHECK_READ;
370 gs->timeout = -1;
371 gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL;
372 #if 0
373 free(gs->status_descr);
374 gs->status_descr = gs->initial_descr;
375 #else
376 free(gs->initial_descr);
377 #endif
378 gs->initial_descr = NULL;
379
380 return 0;
381 }
382
383 /**
384 * \internal Obsługuje pakiet GG_LOGIN_FAILED.
385 *
386 * Patrz gg_packet_handler_t
387 */
388 static int gg_session_handle_login_failed(struct gg_session *gs, uint32_t type,
389 const char *ptr, size_t len, struct gg_event *ge)
390 {
391 if (type != GG_DISCONNECTING)
392 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login failed\n");
393 else
394 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() too many incorrect password attempts\n");
395 ge->type = GG_EVENT_CONN_FAILED;
396 ge->event.failure = (type != GG_DISCONNECTING) ? GG_FAILURE_PASSWORD : GG_FAILURE_INTRUDER;
397 gs->state = GG_STATE_IDLE;
398 gg_close(gs);
399 errno = EACCES;
400
401 return 0;
402 }
403
404 /**
405 * \internal Obsługuje pakiet GG_SEND_MSG_ACK.
406 *
407 * Patrz gg_packet_handler_t
408 */
409 static int gg_session_handle_send_msg_ack(struct gg_session *gs, uint32_t type,
410 const char *ptr, size_t len, struct gg_event *ge)
411 {
412 struct gg_session_private *p = gs->private_data;
413 const struct gg_send_msg_ack *s = (const struct gg_send_msg_ack*) ptr;
414
415 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n");
416
417 ge->type = GG_EVENT_ACK;
418 ge->event.ack.status = gg_fix32(s->status);
419 ge->event.ack.recipient = gg_fix32(s->recipient);
420 ge->event.ack.seq = gg_fix32(s->seq);
421
422 if (ge->event.ack.seq == 0 && p->imgout_waiting_ack > 0)
423 p->imgout_waiting_ack--;
424 gg_image_sendout(gs);
425
426 return 0;
427 }
428
429 /**
430 * \internal Obsługuje pakiet GG_SEND_MSG_ACK110.
431 */
432 static int gg_session_handle_send_msg_ack_110(struct gg_session *gs,
433 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
434 {
435 struct gg_session_private *p = gs->private_data;
436 GG110MessageAck *msg = gg110_message_ack__unpack(NULL, len, (uint8_t*)ptr);
437 size_t i;
438
439 if (!GG_PROTOBUF_VALID(gs, "GG110MessageAck", msg))
440 return -1;
441
442 if (msg->dummy1 == 0x4000) {
443 /* zaobserwowane w EKG rev2856, po wywołaniu check_conn, czyli
444 * gg_image_request(sess, uin, 0, time(NULL));
445 */
446 gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING,
447 "// gg_session_handle_send_msg_ack_110() magic dummy1 "
448 "value 0x4000\n");
449 } else if (msg->dummy1 != 0) {
450 gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING,
451 "// gg_session_handle_send_msg_ack_110() unknown dummy1 "
452 "value: %x\n", msg->dummy1);
453 }
454
455 gg_debug_session(gs, GG_DEBUG_VERBOSE,
456 "// gg_session_handle_send_msg_ack_110() "
457 "%s=%016" PRIx64 " %s=%016" PRIx64 "\n",
458 msg->has_msg_id ? "msg_id" : "0", msg->msg_id,
459 msg->has_conv_id ? "conv_id" : "0", msg->conv_id);
460
461 for (i = 0; i < msg->n_links; i++) {
462 GG110MessageAckLink *link = msg->links[i];
463 if (!GG_PROTOBUF_VALID(gs, "GG110MessageAckLink", link))
464 continue;
465 gg_debug_session(gs, GG_DEBUG_MISC,
466 "// gg_session_handle_send_msg_ack_110() "
467 "got link (id=%" PRIx64 ") \"%s\"\n", link->id, link->url);
468 }
469
470 ge->type = GG_EVENT_ACK110;
471 ge->event.ack110.msg_type = msg->msg_type;
472 ge->event.ack110.seq = msg->seq;
473 ge->event.ack110.time = msg->time;
474
475 gg_compat_message_ack(gs, msg->seq);
476
477 gg110_message_ack__free_unpacked(msg, NULL);
478
479 if (msg->seq == 0 && p->imgout_waiting_ack > 0)
480 p->imgout_waiting_ack--;
481 gg_image_sendout(gs);
482
483 return 0;
484 }
485
486 /**
487 * \internal Obsługuje pakiet GG_PONG.
488 *
489 * Patrz gg_packet_handler_t
490 */
491 static int gg_session_handle_pong(struct gg_session *gs, uint32_t type,
492 const char *ptr, size_t len, struct gg_event *ge)
493 {
494 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n");
495
496 ge->type = GG_EVENT_PONG;
497
498 gs->last_pong = time(NULL);
499
500 return 0;
501 }
502
503 /**
504 * \internal Obsługuje pakiet GG_DISCONNECTING.
505 *
506 * Patrz gg_packet_handler_t
507 */
508 static int gg_session_handle_disconnecting(struct gg_session *gs, uint32_t type,
509 const char *ptr, size_t len, struct gg_event *ge)
510 {
511 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n");
512
513 ge->type = GG_EVENT_DISCONNECT;
514
515 return 0;
516 }
517
518 /**
519 * \internal Obsługuje pakiet GG_DISCONNECT_ACK.
520 *
521 * Patrz gg_packet_handler_t
522 */
523 static int gg_session_handle_disconnect_ack(struct gg_session *gs,
524 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
525 {
526 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received logoff acknowledge\n");
527
528 ge->type = GG_EVENT_DISCONNECT_ACK;
529
530 return 0;
531 }
532
533 /**
534 * \internal Obsługuje pakiety GG_XML_EVENT i GG_XML_ACTION.
535 *
536 * Patrz gg_packet_handler_t
537 */
538 static int gg_session_handle_xml_event(struct gg_session *gs, uint32_t type,
539 const char *ptr, size_t len, struct gg_event *ge)
540 {
541 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received XML event\n");
542
543 ge->type = GG_EVENT_XML_EVENT;
544 ge->event.xml_event.data = malloc(len + 1);
545
546 if (ge->event.xml_event.data == NULL) {
547 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
548 return -1;
549 }
550
551 memcpy(ge->event.xml_event.data, ptr, len);
552 ge->event.xml_event.data[len] = 0;
553
554 return 0;
555 }
556
557 static int gg_session_handle_event_110(struct gg_session *gs, uint32_t type,
558 const char *ptr, size_t len, struct gg_event *ge)
559 {
560 GG110Event *msg = gg110_event__unpack(NULL, len, (uint8_t*)ptr);
561 int succ = 1;
562
563 if (!GG_PROTOBUF_VALID(gs, "GG110Event", msg))
564 return -1;
565
566 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_event_110: "
567 "received GG11 event (type=%d, id=%" PRIx64 ")\n", msg->type, msg->id);
568
569 if (msg->type == GG110_EVENT__TYPE__XML) {
570 ge->type = GG_EVENT_XML_EVENT;
571 ge->event.xml_event.data = strdup(msg->data);
572 succ = succ && (ge->event.xml_event.data != NULL);
573 } else if (msg->type == GG110_EVENT__TYPE__JSON) {
574 ge->type = GG_EVENT_JSON_EVENT;
575 ge->event.json_event.data = strdup(msg->data);
576 succ = succ && (ge->event.json_event.data != NULL);
577 ge->event.json_event.type = strdup(msg->subtype);
578 succ = succ && (ge->event.json_event.type != NULL);
579 } else {
580 gg_debug_session(gs, GG_DEBUG_WARNING,
581 "// gg_session_handle_event_110: "
582 "unsupported GG11 event type: %d\n", msg->type);
583 succ = 0;
584 }
585
586 if (gg_ack_110(gs, GG110_ACK__TYPE__MPA, msg->seq, ge) != 0) {
587 succ = 0;
588 }
589
590 gg110_event__free_unpacked(msg, NULL);
591
592 return succ ? 0 : -1;
593 }
594
595 /**
596 * \internal Obsługuje pakiet GG_PUBDIR50_REPLY.
597 *
598 * Patrz gg_packet_handler_t
599 */
600 static int gg_session_handle_pubdir50_reply(struct gg_session *gs,
601 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
602 {
603 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n");
604
605 return gg_pubdir50_handle_reply_sess(gs, ge, ptr, len);
606 }
607
608 /**
609 * \internal Obsługuje pakiet GG_USERLIST_REPLY.
610 *
611 * Patrz gg_packet_handler_t
612 */
613 static int gg_session_handle_userlist_reply(struct gg_session *gs,
614 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
615 {
616 char reply_type;
617
618 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n");
619
620 reply_type = ptr[0];
621
622 /* jeśli odpowiedź na eksport, wywołaj zdarzenie tylko
623 * gdy otrzymano wszystkie odpowiedzi */
624 if (reply_type == GG_USERLIST_PUT_REPLY || reply_type == GG_USERLIST_PUT_MORE_REPLY) {
625 if (--gs->userlist_blocks)
626 return 0;
627
628 reply_type = GG_USERLIST_PUT_REPLY;
629 }
630
631 if (len > 1) {
632 unsigned int reply_len = (gs->userlist_reply != NULL) ? strlen(gs->userlist_reply) : 0;
633 char *tmp;
634
635 gg_debug_session(gs, GG_DEBUG_MISC, "userlist_reply=%p, len=%"
636 GG_SIZE_FMT "\n", gs->userlist_reply, len);
637
638 if (reply_len + len > GG_USERLIST_REPLY_MAX_LENGTH) {
639 gg_debug_session(gs, GG_DEBUG_MISC,
640 "// gg_session_handle_userlist_reply() "
641 "too many userlist replies\n");
642 return -1;
643 }
644
645 tmp = realloc(gs->userlist_reply, reply_len + len);
646
647 if (tmp == NULL) {
648 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
649 return -1;
650 }
651
652 gs->userlist_reply = tmp;
653 memcpy(gs->userlist_reply + reply_len, ptr + 1, len - 1);
654 gs->userlist_reply[reply_len + len - 1] = 0;
655 }
656
657 if (reply_type == GG_USERLIST_GET_MORE_REPLY)
658 return 0;
659
660 ge->type = GG_EVENT_USERLIST;
661 ge->event.userlist.type = reply_type;
662 ge->event.userlist.reply = gs->userlist_reply;
663
664 gs->userlist_reply = NULL;
665
666 return 0;
667 }
668
669 /**
670 * \internal Obsługuje pakiet GG_DCC7_ID_REPLY.
671 *
672 * Patrz gg_packet_handler_t
673 */
674 static int gg_session_handle_dcc7_id_reply(struct gg_session *gs, uint32_t type,
675 const char *ptr, size_t len, struct gg_event *ge)
676 {
677 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 id packet\n");
678
679 return gg_dcc7_handle_id(gs, ge, ptr, len);
680 }
681
682 /**
683 * \internal Obsługuje pakiet GG_DCC7_ACCEPT.
684 *
685 * Patrz gg_packet_handler_t
686 */
687 static int gg_session_handle_dcc7_accept(struct gg_session *gs, uint32_t type,
688 const char *ptr, size_t len, struct gg_event *ge)
689 {
690 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 accept\n");
691
692 return gg_dcc7_handle_accept(gs, ge, ptr, len);
693 }
694
695 /**
696 * \internal Obsługuje pakiet GG_DCC7_NEW.
697 *
698 * Patrz gg_packet_handler_t
699 */
700 static int gg_session_handle_dcc7_new(struct gg_session *gs, uint32_t type,
701 const char *ptr, size_t len, struct gg_event *ge)
702 {
703 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 request\n");
704
705 return gg_dcc7_handle_new(gs, ge, ptr, len);
706 }
707
708 /**
709 * \internal Obsługuje pakiet GG_DCC7_REJECT.
710 *
711 * Patrz gg_packet_handler_t
712 */
713 static int gg_session_handle_dcc7_reject(struct gg_session *gs, uint32_t type,
714 const char *ptr, size_t len, struct gg_event *ge)
715 {
716 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 reject\n");
717
718 return gg_dcc7_handle_reject(gs, ge, ptr, len);
719 }
720
721 /**
722 * \internal Obsługuje pakiet GG_DCC7_INFO.
723 *
724 * Patrz gg_packet_handler_t
725 */
726 static int gg_session_handle_dcc7_info(struct gg_session *gs, uint32_t type,
727 const char *ptr, size_t len, struct gg_event *ge)
728 {
729 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 info\n");
730
731 return gg_dcc7_handle_info(gs, ge, ptr, len);
732 }
733
734 /**
735 * \internal Analizuje przychodzący pakiet z obrazkiem.
736 *
737 * \param e Struktura zdarzenia
738 * \param p Bufor z danymi
739 * \param len Długość bufora
740 * \param sess Struktura sesji
741 * \param sender Numer nadawcy
742 * \param type Typ pakietu (NIE typ GG_MSG_OPTION_IMAGE_*)
743 */
744 static void gg_image_queue_parse(struct gg_event *e, const char *p,
745 unsigned int len, struct gg_session *sess, uin_t sender,
746 uint32_t type)
747 {
748 const struct gg_msg_image_reply *i = (const void*) p;
749 struct gg_image_queue *q, *qq;
750
751 gg_debug_session(sess, GG_DEBUG_VERBOSE,
752 "// gg_image_queue_parse(%p, %p, %d, %p, %u, %d)\n",
753 e, p, len, sess, sender, type);
754
755 if (!p || !sess || !e) {
756 errno = EFAULT;
757 return;
758 }
759
760 if (i->flag == GG_MSG_OPTION_IMAGE_REQUEST) {
761 e->type = GG_EVENT_IMAGE_REQUEST;
762 e->event.image_request.sender = sender;
763 e->event.image_reply.size = i->size;
764 e->event.image_request.crc32 = i->crc32;
765 return;
766 }
767
768 /* znajdź dany obrazek w kolejce danej sesji */
769
770 for (qq = sess->images, q = NULL; qq; qq = qq->next) {
771 if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) {
772 q = qq;
773 break;
774 }
775 }
776
777 if (!q) {
778 gg_debug_session(sess, GG_DEBUG_WARNING,
779 "// gg_image_queue_parse() unknown image from %d, "
780 "size=%d, crc32=%.8x\n", sender, i->size, i->crc32);
781 return;
782 }
783
784 if (q->packet_type == 0)
785 q->packet_type = type;
786 if (q->packet_type != type)
787 return;
788
789 if (i->flag == GG_MSG_OPTION_IMAGE_REPLY) {
790 q->done = 0;
791
792 len -= sizeof(struct gg_msg_image_reply);
793 p += sizeof(struct gg_msg_image_reply);
794
795 if (memchr(p, 0, len) == NULL) {
796 gg_debug_session(sess, GG_DEBUG_ERROR,
797 "// gg_image_queue_parse() malformed packet "
798 "from %d, unlimited filename\n", sender);
799 return;
800 }
801
802 if (!(q->filename = strdup(p))) {
803 gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_image_queue_parse() out of memory\n");
804 return;
805 }
806
807 len -= strlen(p) + 1;
808 p += strlen(p) + 1;
809 } else if (i->flag == GG_MSG_OPTION_IMAGE_REPLY_MORE) {
810 len -= sizeof(struct gg_msg_image_reply);
811 p += sizeof(struct gg_msg_image_reply);
812 } else {
813 gg_debug_session(sess, GG_DEBUG_WARNING, "// gg_image_queue_parse() unexpected flag\n");
814 return;
815 }
816
817 if (q->done + len > q->size) {
818 gg_debug_session(sess, GG_DEBUG_ERROR, "// gg_image_queue_parse() got too much\n");
819 len = q->size - q->done;
820 }
821
822 memcpy(q->image + q->done, p, len);
823 q->done += len;
824
825 gg_debug_session(sess, GG_DEBUG_VERBOSE,
826 "// gg_image_queue_parse() got image part (done: %d of %d)\n",
827 q->done, q->size);
828
829 /* jeśli skończono odbierać obrazek, wygeneruj zdarzenie */
830
831 if (q->done >= q->size) {
832 gg_debug_session(sess, GG_DEBUG_VERBOSE,
833 "// gg_image_queue_parse() image ready\n");
834
835 e->type = GG_EVENT_IMAGE_REPLY;
836 e->event.image_reply.sender = sender;
837 e->event.image_reply.size = q->size;
838 e->event.image_reply.crc32 = q->crc32;
839 e->event.image_reply.filename = q->filename;
840 e->event.image_reply.image = q->image;
841
842 gg_image_queue_remove(sess, q, 0);
843
844 free(q);
845 }
846 }
847
848 /**
849 * \internal Analizuje informacje rozszerzone wiadomości.
850 *
851 * \param sess Struktura sesji.
852 * \param e Struktura zdarzenia.
853 * \param sender Numer nadawcy.
854 * \param p Wskaźnik na dane rozszerzone.
855 * \param packet_end Wskaźnik na koniec pakietu.
856 * \param packet_type Typ pakietu, w którym otrzymaliśmy wiadomość.
857 *
858 * \return 0 jeśli się powiodło, -1 jeśli wiadomość obsłużono i wynik ma
859 * zostać przekazany aplikacji, -2 jeśli wystąpił błąd ogólny, -3 jeśli
860 * wiadomość jest niepoprawna.
861 */
862 static int gg_handle_recv_msg_options(struct gg_session *sess,
863 struct gg_event *e, uin_t sender, const char *p, const char *packet_end,
864 uint32_t packet_type)
865 {
866 while (p < packet_end) {
867 switch (*p) {
868 case GG_MSG_OPTION_CONFERENCE:
869 {
870 const struct gg_msg_recipients *m = (const void*) p;
871 uint32_t i, count;
872
873 p += sizeof(*m);
874
875 if (p > packet_end) {
876 gg_debug_session(sess, GG_DEBUG_MISC,
877 "// gg_handle_recv_msg_options()"
878 " packet out of bounds (1)\n");
879 goto malformed;
880 }
881
882 count = gg_fix32(m->count);
883
884 if (p + count * sizeof(uin_t) > packet_end ||
885 p + count * sizeof(uin_t) < p ||
886 count > 0xffff)
887 {
888 gg_debug_session(sess, GG_DEBUG_MISC,
889 "// gg_handle_recv_msg_options()"
890 " packet out of bounds (1.5)\n");
891 goto malformed;
892 }
893
894 if (e->event.msg.recipients != NULL) {
895 gg_debug_session(sess, GG_DEBUG_MISC,
896 "// gg_handle_recv_msg_options()"
897 " e->event.msg.recipients already exist\n");
898 goto malformed;
899 }
900
901 e->event.msg.recipients = malloc(count * sizeof(uin_t));
902
903 if (e->event.msg.recipients == NULL) {
904 gg_debug_session(sess, GG_DEBUG_MISC,
905 "// gg_handle_recv_msg_options()"
906 " not enough memory for recipients data\n");
907 goto fail;
908 }
909
910 memcpy(e->event.msg.recipients, p, count * sizeof(uin_t));
911 p += count * sizeof(uin_t);
912
913 for (i = 0; i < count; i++)
914 e->event.msg.recipients[i] = gg_fix32(e->event.msg.recipients[i]);
915
916 e->event.msg.recipients_count = count;
917
918 break;
919 }
920
921 case GG_MSG_OPTION_ATTRIBUTES:
922 {
923 uint16_t len;
924 char *buf;
925
926 if (p + 3 > packet_end) {
927 gg_debug_session(sess, GG_DEBUG_MISC,
928 "// gg_handle_recv_msg_options()"
929 " packet out of bounds (2)\n");
930 goto malformed;
931 }
932
933 memcpy(&len, p + 1, sizeof(uint16_t));
934 len = gg_fix16(len);
935
936 if (e->event.msg.formats != NULL) {
937 gg_debug_session(sess, GG_DEBUG_MISC,
938 "// gg_handle_recv_msg_options()"
939 " e->event.msg.formats already exist\n");
940 goto malformed;
941 }
942
943 buf = malloc(len);
944
945 if (buf == NULL) {
946 gg_debug_session(sess, GG_DEBUG_MISC,
947 "// gg_handle_recv_msg_options()"
948 " not enough memory for richtext data\n");
949 goto fail;
950 }
951
952 p += 3;
953
954 if (p + len > packet_end) {
955 gg_debug_session(sess, GG_DEBUG_MISC,
956 "// gg_handle_recv_msg_options()"
957 " packet out of bounds (3)\n");
958 free(buf);
959 goto malformed;
960 }
961
962 memcpy(buf, p, len);
963
964 e->event.msg.formats = buf;
965 e->event.msg.formats_length = len;
966
967 p += len;
968
969 break;
970 }
971
972 case GG_MSG_OPTION_IMAGE_REQUEST:
973 {
974 const struct gg_msg_image_request *i = (const void*) p;
975
976 if (p + sizeof(*i) > packet_end) {
977 gg_debug_session(sess, GG_DEBUG_MISC,
978 "// gg_handle_recv_msg() "
979 "packet out of bounds (3)\n");
980 goto malformed;
981 }
982
983 if (e->event.msg.formats != NULL || e->event.msg.recipients != NULL) {
984 gg_debug_session(sess, GG_DEBUG_MISC,
985 "// gg_handle_recv_msg_options()"
986 " mixed options (1)\n");
987 goto malformed;
988 }
989
990 e->event.image_request.sender = sender;
991 e->event.image_request.size = gg_fix32(i->size);
992 e->event.image_request.crc32 = gg_fix32(i->crc32);
993
994 e->type = GG_EVENT_IMAGE_REQUEST;
995
996 goto handled;
997 }
998
999 case GG_MSG_OPTION_IMAGE_REPLY:
1000 case GG_MSG_OPTION_IMAGE_REPLY_MORE:
1001 {
1002 struct gg_msg_image_reply *rep = (void*) p;
1003
1004 if (e->event.msg.formats != NULL || e->event.msg.recipients != NULL) {
1005 gg_debug_session(sess, GG_DEBUG_MISC,
1006 "// gg_handle_recv_msg_options() "
1007 "mixed options (2)\n");
1008 goto malformed;
1009 }
1010
1011 if (p + sizeof(struct gg_msg_image_reply) == packet_end) {
1012
1013 /* pusta odpowiedź - klient po drugiej stronie nie ma żądanego obrazka */
1014
1015 e->type = GG_EVENT_IMAGE_REPLY;
1016 e->event.image_reply.sender = sender;
1017 e->event.image_reply.size = 0;
1018 e->event.image_reply.crc32 = gg_fix32(rep->crc32);
1019 e->event.image_reply.filename = NULL;
1020 e->event.image_reply.image = NULL;
1021 goto handled;
1022
1023 } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) {
1024
1025 gg_debug_session(sess, GG_DEBUG_MISC,
1026 "// gg_handle_recv_msg() "
1027 "packet out of bounds (4)\n");
1028 goto malformed;
1029 }
1030
1031 rep->size = gg_fix32(rep->size);
1032 rep->crc32 = gg_fix32(rep->crc32);
1033 gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, sender, packet_type);
1034
1035 goto handled;
1036 }
1037
1038 default:
1039 {
1040 gg_debug_session(sess, GG_DEBUG_MISC,
1041 "// gg_handle_recv_msg() "
1042 "unknown payload 0x%.2x\n", *p);
1043 p = packet_end;
1044 }
1045 }
1046 }
1047
1048 return 0;
1049
1050 handled:
1051 return -1;
1052
1053 fail:
1054 return -2;
1055
1056 malformed:
1057 return -3;
1058 }
1059
1060 /**
1061 * \internal Wysyła potwierdzenie odebrania wiadomości.
1062 *
1063 * \param gs Struktura sesji
1064 * \param seq Numer sekwencyjny odebranej wiadomości
1065 *
1066 * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
1067 */
1068 static int gg_session_send_msg_ack(struct gg_session *gs, uint32_t seq)
1069 {
1070 struct gg_recv_msg_ack pkt;
1071
1072 gg_debug_session(gs, GG_DEBUG_FUNCTION, "** gg_session_send_msg_ack(%p);\n", gs);
1073
1074 if ((gs->protocol_features & GG_FEATURE_MSG_ACK) == 0)
1075 return 0;
1076
1077 /* Kiedyś zdawało nam się, że mamy wysyłać liczbę odebranych
1078 * wiadomości, ale okazało się, że numer sekwencyjny. */
1079 gs->recv_msg_count++;
1080
1081 pkt.seq = gg_fix32(seq);
1082
1083 return gg_send_packet(gs, GG_RECV_MSG_ACK, &pkt, sizeof(pkt), NULL);
1084 }
1085
1086 /**
1087 * \internal Obsługuje pakiet GG_RECV_MSG.
1088 *
1089 * Patrz gg_packet_handler_t
1090 */
1091 static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type,
1092 const char *packet, size_t length, struct gg_event *e)
1093 {
1094 const struct gg_recv_msg *r = (const struct gg_recv_msg*) packet;
1095 const char *payload = packet + sizeof(struct gg_recv_msg);
1096 const char *payload_end = packet + length;
1097 size_t len;
1098
1099 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %"
1100 GG_SIZE_FMT ", %p);\n", packet, length, e);
1101
1102 if (sess == NULL)
1103 goto fail;
1104
1105 if ((r->seq == 0) && (r->msgclass == 0)) {
1106 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n");
1107 goto malformed;
1108 }
1109
1110 /* jednobajtowa wiadomość o treści \x02 to żądanie połączenia DCC */
1111 if (*payload == GG_MSG_CALLBACK && payload == payload_end - 1) {
1112 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n");
1113 length = 1;
1114 } else {
1115 const char *options;
1116
1117 options = memchr(payload, 0, (size_t) (payload_end - payload));
1118
1119 if (options == NULL) {
1120 gg_debug_session(sess, GG_DEBUG_MISC,
1121 "// gg_handle_recv_msg() malformed packet, "
1122 "message out of bounds (0)\n");
1123 goto malformed;
1124 }
1125
1126 length = (size_t) (options - payload);
1127
1128 switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), options + 1, payload_end, type)) {
1129 case -1: /* handled */
1130 gg_session_send_msg_ack(sess, gg_fix32(r->seq));
1131 return 0;
1132
1133 case -2: /* failed */
1134 goto fail;
1135
1136 case -3: /* malformed */
1137 goto malformed;
1138 }
1139 }
1140
1141 e->type = GG_EVENT_MSG;
1142 e->event.msg.msgclass = gg_fix32(r->msgclass);
1143 e->event.msg.sender = gg_fix32(r->sender);
1144 e->event.msg.time = gg_fix32(r->time);
1145 e->event.msg.seq = gg_fix32(r->seq);
1146
1147 e->event.msg.message = (unsigned char*)gg_encoding_convert(payload,
1148 GG_ENCODING_CP1250, sess->encoding, length, -1);
1149 if (e->event.msg.message == NULL) {
1150 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg() out of memory\n");
1151 goto fail;
1152 }
1153
1154 len = gg_message_text_to_html(NULL, (char*)e->event.msg.message,
1155 sess->encoding, e->event.msg.formats,
1156 e->event.msg.formats_length);
1157 e->event.msg.xhtml_message = malloc(len + 1);
1158
1159 if (e->event.msg.xhtml_message == NULL) {
1160 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg() out of memory\n");
1161 goto fail;
1162 }
1163
1164 gg_message_text_to_html(e->event.msg.xhtml_message,
1165 (char*)e->event.msg.message, sess->encoding,
1166 e->event.msg.formats, e->event.msg.formats_length);
1167
1168 gg_session_send_msg_ack(sess, gg_fix32(r->seq));
1169 return 0;
1170
1171 fail:
1172 free(e->event.msg.message);
1173 free(e->event.msg.xhtml_message);
1174 free(e->event.msg.recipients);
1175 free(e->event.msg.formats);
1176 return -1;
1177
1178 malformed:
1179 e->type = GG_EVENT_NONE;
1180 free(e->event.msg.message);
1181 free(e->event.msg.xhtml_message);
1182 free(e->event.msg.recipients);
1183 free(e->event.msg.formats);
1184 gg_session_send_msg_ack(sess, gg_fix32(r->seq));
1185 return 0;
1186 }
1187
1188 /**
1189 * \internal Obsługuje pakiet GG_RECV_MSG80.
1190 *
1191 * Patrz gg_packet_handler_t
1192 */
1193 static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type,
1194 const char *packet, size_t length, struct gg_event *e)
1195 {
1196 const struct gg_recv_msg80 *r = (const struct gg_recv_msg80*) packet;
1197 uint32_t offset_plain;
1198 uint32_t offset_attr;
1199
1200 gg_debug_session(sess, GG_DEBUG_FUNCTION,
1201 "** gg_handle_recv_msg80(%p, %" GG_SIZE_FMT ", %p);\n",
1202 packet, length, e);
1203
1204 if (sess == NULL)
1205 goto fail;
1206
1207 if (r->seq == 0 && r->msgclass == 0) {
1208 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() oops, silently ignoring the bait\n");
1209 goto malformed;
1210 }
1211
1212 offset_plain = gg_fix32(r->offset_plain);
1213 offset_attr = gg_fix32(r->offset_attr);
1214
1215 if (offset_plain < sizeof(struct gg_recv_msg80) || offset_plain >= length) {
1216 gg_debug_session(sess, GG_DEBUG_MISC,
1217 "// gg_handle_recv_msg80() malformed packet, "
1218 "message out of bounds (0)\n");
1219 goto malformed;
1220 }
1221
1222 if (offset_attr < sizeof(struct gg_recv_msg80) || offset_attr > length) {
1223 gg_debug_session(sess, GG_DEBUG_MISC,
1224 "// gg_handle_recv_msg80() malformed packet, "
1225 "attr out of bounds (1)\n");
1226 offset_attr = 0; /* nie parsuj attr. */
1227 }
1228
1229 /* Normalna sytuacja, więc nie podpada pod powyższy warunek. */
1230 if (offset_attr == length)
1231 offset_attr = 0;
1232
1233 if (memchr(packet + offset_plain, 0, length - offset_plain) == NULL) {
1234 gg_debug_session(sess, GG_DEBUG_MISC,
1235 "// gg_handle_recv_msg80() malformed packet, "
1236 "message out of bounds (2)\n");
1237 goto malformed;
1238 }
1239
1240 if (offset_plain > sizeof(struct gg_recv_msg80) && memchr(packet +
1241 sizeof(struct gg_recv_msg80), 0, offset_plain -
1242 sizeof(struct gg_recv_msg80)) == NULL)
1243 {
1244 gg_debug_session(sess, GG_DEBUG_MISC,
1245 "// gg_handle_recv_msg80() malformed packet, "
1246 "message out of bounds (3)\n");
1247 goto malformed;
1248 }
1249
1250 e->type = (type != GG_RECV_OWN_MSG) ? GG_EVENT_MSG : GG_EVENT_MULTILOGON_MSG;
1251 e->event.msg.msgclass = gg_fix32(r->msgclass);
1252 e->event.msg.sender = gg_fix32(r->sender);
1253 e->event.msg.time = gg_fix32(r->time);
1254 e->event.msg.seq = gg_fix32(r->seq);
1255
1256 if (offset_attr != 0) {
1257 switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender),
1258 packet + offset_attr, packet + length, type))
1259 {
1260 case -1: /* handled */
1261 gg_session_send_msg_ack(sess, gg_fix32(r->seq));
1262 return 0;
1263
1264 case -2: /* failed */
1265 goto fail;
1266
1267 case -3: /* malformed */
1268 goto malformed;
1269 }
1270 }
1271
1272 if (sess->encoding == GG_ENCODING_CP1250) {
1273 e->event.msg.message = (unsigned char*) strdup(packet + offset_plain);
1274
1275 if (e->event.msg.message == NULL) {
1276 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg_80() out of memory\n");
1277 goto fail;
1278 }
1279 } else {
1280 if (offset_plain > sizeof(struct gg_recv_msg80)) {
1281 size_t len, fmt_len;
1282
1283 len = gg_message_html_to_text(NULL, NULL, &fmt_len,
1284 packet + sizeof(struct gg_recv_msg80),
1285 GG_ENCODING_UTF8);
1286 e->event.msg.message = malloc(len + 1);
1287
1288 if (e->event.msg.message == NULL) {
1289 gg_debug_session(sess, GG_DEBUG_MISC,
1290 "// gg_session_handle_recv_msg_80() "
1291 "out of memory\n");
1292 goto fail;
1293 }
1294
1295 free(e->event.msg.formats);
1296 e->event.msg.formats_length = fmt_len;
1297 e->event.msg.formats = malloc(fmt_len);
1298
1299 if (e->event.msg.formats == NULL) {
1300 gg_debug_session(sess, GG_DEBUG_MISC,
1301 "// gg_session_handle_recv_msg_80() "
1302 "out of memory\n");
1303 goto fail;
1304 }
1305
1306 gg_message_html_to_text((char*)e->event.msg.message,
1307 e->event.msg.formats, NULL,
1308 packet + sizeof(struct gg_recv_msg80),
1309 GG_ENCODING_UTF8);
1310 } else {
1311 e->event.msg.message = (unsigned char*)gg_encoding_convert(
1312 packet + offset_plain, GG_ENCODING_CP1250,
1313 sess->encoding, -1, -1);
1314
1315 if (e->event.msg.message == NULL) {
1316 gg_debug_session(sess, GG_DEBUG_MISC,
1317 "// gg_session_handle_recv_msg_80() "
1318 "out of memory\n");
1319 goto fail;
1320 }
1321 }
1322 }
1323
1324 if (offset_plain > sizeof(struct gg_recv_msg80)) {
1325 e->event.msg.xhtml_message = gg_encoding_convert(
1326 packet + sizeof(struct gg_recv_msg80), GG_ENCODING_UTF8,
1327 sess->encoding, -1, -1);
1328
1329 if (e->event.msg.xhtml_message == NULL) {
1330 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg_80() out of memory\n");
1331 goto fail;
1332 }
1333 } else {
1334 size_t len;
1335
1336 len = gg_message_text_to_html(NULL,
1337 (char*)e->event.msg.message, sess->encoding,
1338 e->event.msg.formats, e->event.msg.formats_length);
1339 e->event.msg.xhtml_message = malloc(len + 1);
1340
1341 if (e->event.msg.xhtml_message == NULL) {
1342 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_session_handle_recv_msg_80() out of memory\n");
1343 goto fail;
1344 }
1345
1346 gg_message_text_to_html(e->event.msg.xhtml_message,
1347 (char*)e->event.msg.message, sess->encoding,
1348 e->event.msg.formats, e->event.msg.formats_length);
1349 }
1350
1351 gg_session_send_msg_ack(sess, gg_fix32(r->seq));
1352 return 0;
1353
1354 fail:
1355 free(e->event.msg.message);
1356 free(e->event.msg.xhtml_message);
1357 free(e->event.msg.recipients);
1358 free(e->event.msg.formats);
1359 return -1;
1360
1361 malformed:
1362 e->type = GG_EVENT_NONE;
1363 free(e->event.msg.message);
1364 free(e->event.msg.xhtml_message);
1365 free(e->event.msg.recipients);
1366 free(e->event.msg.formats);
1367 gg_session_send_msg_ack(sess, gg_fix32(r->seq));
1368 return 0;
1369 }
1370
1371 static int gg_session_handle_recv_msg_110(struct gg_session *gs, uint32_t type,
1372 const char *ptr, size_t len, struct gg_event *ge)
1373 {
1374 GG110RecvMessage *msg = gg110_recv_message__unpack(NULL, len, (uint8_t*)ptr);
1375 uint8_t ack_type;
1376 uin_t sender = 0;
1377 uint32_t seq;
1378 int succ = 1;
1379 struct gg_event_msg *ev = &ge->event.msg;
1380
1381 gg_debug_session(gs, GG_DEBUG_FUNCTION,
1382 "** gg_session_handle_recv_msg_110(%p, %" GG_SIZE_FMT
1383 ", %p);\n", ptr, len, ge);
1384
1385 if (!GG_PROTOBUF_VALID(gs, "GG110RecvMessage", msg))
1386 return -1;
1387
1388 seq = msg->seq;
1389 if (type == GG_CHAT_RECV_MSG || type == GG_CHAT_RECV_OWN_MSG)
1390 ack_type = GG110_ACK__TYPE__CHAT;
1391 else
1392 ack_type = GG110_ACK__TYPE__MSG;
1393
1394 if (msg->has_msg_id || msg->has_conv_id) {
1395 msg->msg_id = msg->has_msg_id ? msg->msg_id : 0;
1396 msg->conv_id = msg->has_conv_id ? msg->conv_id : 0;
1397 gg_debug_session(gs, GG_DEBUG_VERBOSE,
1398 "// gg_session_handle_recv_msg_110() "
1399 "msg_id=%016" PRIx64 " conv_id=%016" PRIx64 "\n",
1400 msg->msg_id, msg->conv_id);
1401 }
1402
1403 if (msg->has_sender)
1404 sender = gg_protobuf_get_uin(msg->sender);
1405 else if (type == GG_CHAT_RECV_OWN_MSG)
1406 sender = gs->uin;
1407
1408 if (msg->has_data && msg->msg_plain[0] == '\0') {
1409 if (msg->data.len < sizeof(struct gg_msg_image_reply)) {
1410 gg_debug_session(gs, GG_DEBUG_ERROR,
1411 "// gg_session_handle_recv_msg_110() "
1412 "packet too small (%" GG_SIZE_FMT " < %"
1413 GG_SIZE_FMT ")\n", msg->data.len,
1414 sizeof(struct gg_msg_image_reply));
1415 } else {
1416 gg_image_queue_parse(ge, (char *)msg->data.data,
1417 msg->data.len, gs, sender, type);
1418 }
1419 gg110_recv_message__free_unpacked(msg, NULL);
1420 return gg_ack_110(gs, GG110_ACK__TYPE__MSG, seq, ge);
1421 }
1422
1423 if (type == GG_RECV_OWN_MSG110 || type == GG_CHAT_RECV_OWN_MSG)
1424 ge->type = GG_EVENT_MULTILOGON_MSG;
1425 else
1426 ge->type = GG_EVENT_MSG;
1427 ev->msgclass = GG_CLASS_CHAT;
1428 ev->seq = seq;
1429 ev->sender = sender;
1430 ev->flags = msg->flags;
1431 ev->seq = seq;
1432 ev->time = msg->time;
1433
1434 if (abs(msg->time - gg_server_time(gs)) > 2)
1435 ev->msgclass |= GG_CLASS_QUEUED;
1436
1437 ev->message = NULL;
1438 if (msg->msg_plain[0] != '\0') {
1439 ev->message = (unsigned char*)gg_encoding_convert(
1440 msg->msg_plain, GG_ENCODING_UTF8, gs->encoding, -1, -1);
1441 succ = succ && (ev->message != NULL);
1442 }
1443 ev->xhtml_message = NULL;
1444 if (msg->msg_xhtml != NULL) {
1445 ev->xhtml_message = gg_encoding_convert(
1446 msg->msg_xhtml, GG_ENCODING_UTF8, gs->encoding, -1, -1);
1447 succ = succ && (ev->xhtml_message != NULL);
1448 }
1449
1450 /* wiadomości wysłane z mobilnego gg nie posiadają wersji xhtml */
1451 if (ev->message == NULL && ev->xhtml_message == NULL) {
1452 ev->message = (unsigned char*)strdup("");
1453 succ = succ && (ev->message != NULL);
1454 } else if (ev->message == NULL) {
1455 ev->message = (unsigned char*)gg_message_html_to_text_110(
1456 ev->xhtml_message);
1457 succ = succ && (ev->message != NULL);
1458 } else if (ev->xhtml_message == NULL) {
1459 ev->xhtml_message = gg_message_text_to_html_110(
1460 (char*)ev->message, -1);
1461 succ = succ && (ev->xhtml_message != NULL);
1462 }
1463
1464 /* otrzymywane tylko od gg <= 10.5 */
1465 ev->formats = NULL;
1466 ev->formats_length = 0;
1467 if (msg->has_data && succ) {
1468 ev->formats_length = msg->data.len;
1469 ev->formats = malloc(msg->data.len);
1470 if (ev->formats == NULL)
1471 succ = 0;
1472 else
1473 memcpy(ev->formats, msg->data.data, msg->data.len);
1474 }
1475
1476 if (msg->has_chat_id && succ) {
1477 gg_chat_list_t *chat;
1478
1479 ev->chat_id = msg->chat_id;
1480
1481 chat = gg_chat_find(gs, msg->chat_id);
1482 if (chat) {
1483 size_t rcpt_size = chat->participants_count *
1484 sizeof(uin_t);
1485 ev->recipients = malloc(rcpt_size);
1486 ev->recipients_count = chat->participants_count;
1487 if (ev->recipients == NULL)
1488 succ = 0;
1489 else {
1490 memcpy(ev->recipients, chat->participants,
1491 rcpt_size);
1492 }
1493 }
1494 }
1495
1496 gg110_recv_message__free_unpacked(msg, NULL);
1497
1498 if (gg_ack_110(gs, ack_type, seq, ge) != 0)
1499 succ = 0;
1500
1501 if (succ)
1502 return 0;
1503 else {
1504 free(ev->message);
1505 free(ev->xhtml_message);
1506 free(ev->formats);
1507 free(ev->recipients);
1508 return -1;
1509 }
1510 }
1511
1512 /**
1513 * \internal Obsługuje pakiet GG_STATUS.
1514 *
1515 * Patrz gg_packet_handler_t
1516 */
1517 static int gg_session_handle_status(struct gg_session *gs, uint32_t type,
1518 const char *ptr, size_t len, struct gg_event *ge)
1519 {
1520 const struct gg_status *s = (const void*) ptr;
1521
1522 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
1523
1524 ge->type = GG_EVENT_STATUS;
1525 ge->event.status.uin = gg_fix32(s->uin);
1526 ge->event.status.status = gg_fix32(s->status);
1527 ge->event.status.descr = NULL;
1528
1529 if (len > sizeof(*s)) {
1530 ge->event.status.descr = gg_encoding_convert(ptr + sizeof(*s),
1531 GG_ENCODING_CP1250, gs->encoding, len - sizeof(*s), -1);
1532
1533 if (ge->event.status.descr == NULL) {
1534 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1535 return -1;
1536 }
1537 }
1538
1539 return 0;
1540 }
1541
1542 /**
1543 * \internal Obsługuje pakiety GG_STATUS60, GG_STATUS77 i GG_STATUS80BETA.
1544 *
1545 * Patrz gg_packet_handler_t
1546 */
1547 static int gg_session_handle_status_60_77_80beta(struct gg_session *gs,
1548 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
1549 {
1550 const struct gg_status60 *s60 = (const void*) ptr;
1551 const struct gg_status77 *s77 = (const void*) ptr;
1552 size_t struct_len;
1553 uint32_t uin;
1554
1555 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
1556
1557 ge->type = GG_EVENT_STATUS60;
1558 ge->event.status60.descr = NULL;
1559 ge->event.status60.time = 0;
1560
1561 if (type == GG_STATUS60) {
1562 uin = gg_fix32(s60->uin);
1563 ge->event.status60.status = s60->status;
1564 ge->event.status60.remote_ip = s60->remote_ip;
1565 ge->event.status60.remote_port = gg_fix16(s60->remote_port);
1566 ge->event.status60.version = s60->version;
1567 ge->event.status60.image_size = s60->image_size;
1568 struct_len = sizeof(*s60);
1569 } else {
1570 uin = gg_fix32(s77->uin);
1571 ge->event.status60.status = s77->status;
1572 ge->event.status60.remote_ip = s77->remote_ip;
1573 ge->event.status60.remote_port = gg_fix16(s77->remote_port);
1574 ge->event.status60.version = s77->version;
1575 ge->event.status60.image_size = s77->image_size;
1576 struct_len = sizeof(*s77);
1577 }
1578
1579 ge->event.status60.uin = uin & 0x00ffffff;
1580
1581 if (uin & 0x40000000)
1582 ge->event.status60.version |= GG_HAS_AUDIO_MASK;
1583 if (uin & 0x20000000)
1584 ge->event.status60.version |= GG_HAS_AUDIO7_MASK;
1585 if (uin & 0x08000000)
1586 ge->event.status60.version |= GG_ERA_OMNIX_MASK;
1587
1588 if (len > struct_len) {
1589 size_t descr_len;
1590
1591 descr_len = len - struct_len;
1592
1593 ge->event.status60.descr = gg_encoding_convert(ptr + struct_len,
1594 (type == GG_STATUS80BETA) ? GG_ENCODING_UTF8 : GG_ENCODING_CP1250,
1595 gs->encoding, descr_len, -1);
1596
1597 if (ge->event.status60.descr == NULL) {
1598 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1599 return -1;
1600 }
1601
1602 if (descr_len > 4 && ptr[len - 5] == 0) {
1603 uint32_t t;
1604 memcpy(&t, ptr + len - 4, sizeof(uint32_t));
1605 ge->event.status60.time = gg_fix32(t);
1606 }
1607 }
1608
1609 return 0;
1610 }
1611
1612 /**
1613 * \internal Obsługuje pakiet GG_NOTIFY_REPLY.
1614 *
1615 * Patrz gg_packet_handler_t
1616 */
1617 static int gg_session_handle_notify_reply(struct gg_session *gs, uint32_t type,
1618 const char *ptr, size_t len, struct gg_event *ge)
1619 {
1620 const struct gg_notify_reply *n = (const void*) ptr;
1621 char *descr;
1622
1623 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
1624
1625 if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR ||
1626 gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR ||
1627 gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR)
1628 {
1629 size_t descr_len;
1630
1631 ge->type = GG_EVENT_NOTIFY_DESCR;
1632
1633 if (!(ge->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) {
1634 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1635 return -1;
1636 }
1637 ge->event.notify_descr.notify[1].uin = 0;
1638 memcpy(ge->event.notify_descr.notify, ptr, sizeof(*n));
1639 ge->event.notify_descr.notify[0].uin = gg_fix32(ge->event.notify_descr.notify[0].uin);
1640 ge->event.notify_descr.notify[0].status = gg_fix32(ge->event.notify_descr.notify[0].status);
1641 ge->event.notify_descr.notify[0].remote_port = gg_fix16(ge->event.notify_descr.notify[0].remote_port);
1642 ge->event.notify_descr.notify[0].version = gg_fix32(ge->event.notify_descr.notify[0].version);
1643
1644 descr_len = len - sizeof(*n);
1645
1646 descr = gg_encoding_convert(ptr + sizeof(*n), GG_ENCODING_CP1250, gs->encoding, descr_len, -1);
1647
1648 if (descr == NULL) {
1649 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1650 return -1;
1651 }
1652
1653 ge->event.notify_descr.descr = descr;
1654
1655 } else {
1656 unsigned int i, count;
1657
1658 ge->type = GG_EVENT_NOTIFY;
1659
1660 if (!(ge->event.notify = (void*) malloc(len + 2 * sizeof(*n)))) {
1661 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1662 return -1;
1663 }
1664
1665 memcpy(ge->event.notify, ptr, len);
1666 count = len / sizeof(*n);
1667 ge->event.notify[count].uin = 0;
1668
1669 for (i = 0; i < count; i++) {
1670 ge->event.notify[i].uin = gg_fix32(ge->event.notify[i].uin);
1671 ge->event.notify[i].status = gg_fix32(ge->event.notify[i].status);
1672 ge->event.notify[i].remote_port = gg_fix16(ge->event.notify[i].remote_port);
1673 ge->event.notify[i].version = gg_fix32(ge->event.notify[i].version);
1674 }
1675 }
1676
1677 return 0;
1678 }
1679
1680 /**
1681 * \internal Obsługuje pakiet GG_STATUS80.
1682 *
1683 * Patrz gg_packet_handler_t
1684 */
1685 static int gg_session_handle_status_80(struct gg_session *gs, uint32_t type,
1686 const char *ptr, size_t len, struct gg_event *ge)
1687 {
1688 const struct gg_notify_reply80 *n = (const void*) ptr;
1689 size_t descr_len;
1690
1691 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n");
1692
1693 ge->type = GG_EVENT_STATUS60;
1694 ge->event.status60.uin = gg_fix32(n->uin);
1695 ge->event.status60.status = gg_fix32(n->status);
1696 ge->event.status60.remote_ip = n->remote_ip;
1697 ge->event.status60.remote_port = gg_fix16(n->remote_port);
1698 ge->event.status60.version = 0;
1699 ge->event.status60.image_size = n->image_size;
1700 ge->event.status60.descr = NULL;
1701 ge->event.status60.time = 0;
1702
1703 descr_len = gg_fix32(n->descr_len);
1704
1705 if (descr_len != 0 && sizeof(struct gg_notify_reply80) + descr_len <= len) {
1706 ge->event.status60.descr = gg_encoding_convert(
1707 (const char*) n + sizeof(struct gg_notify_reply80),
1708 GG_ENCODING_UTF8, gs->encoding, descr_len, -1);
1709
1710 if (ge->event.status60.descr == NULL) {
1711 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1712 return -1;
1713 }
1714
1715 /* XXX czas */
1716 }
1717
1718 return 0;
1719 }
1720
1721 /**
1722 * \internal Obsługuje pakiet GG_NOTIFY_REPLY80.
1723 *
1724 * Patrz gg_packet_handler_t
1725 */
1726 static int gg_session_handle_notify_reply_80(struct gg_session *gs,
1727 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
1728 {
1729 const struct gg_notify_reply80 *n = (const void*) ptr;
1730 unsigned int length = len, i = 0;
1731
1732 /* TODO: najpierw przeanalizować strukturę i określić
1733 * liczbę rekordów, żeby obyć się bez realloc()
1734 */
1735
1736 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
1737
1738 ge->type = GG_EVENT_NOTIFY60;
1739 ge->event.notify60 = malloc(sizeof(*ge->event.notify60));
1740
1741 if (!ge->event.notify60) {
1742 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1743 return -1;
1744 }
1745
1746 ge->event.notify60[0].uin = 0;
1747
1748 while (length >= sizeof(struct gg_notify_reply80)) {
1749 uin_t uin = gg_fix32(n->uin);
1750 int descr_len;
1751 void *tmp;
1752
1753 ge->event.notify60[i].uin = uin;
1754 ge->event.notify60[i].status = gg_fix32(n->status);
1755 ge->event.notify60[i].remote_ip = n->remote_ip;
1756 ge->event.notify60[i].remote_port = gg_fix16(n->remote_port);
1757 ge->event.notify60[i].version = 0;
1758 ge->event.notify60[i].image_size = n->image_size;
1759 ge->event.notify60[i].descr = NULL;
1760 ge->event.notify60[i].time = 0;
1761
1762 descr_len = gg_fix32(n->descr_len);
1763
1764 if (descr_len != 0) {
1765 if (sizeof(struct gg_notify_reply80) + descr_len <= length) {
1766 ge->event.notify60[i].descr = gg_encoding_convert(
1767 (const char*) n + sizeof(struct gg_notify_reply80),
1768 GG_ENCODING_UTF8, gs->encoding, descr_len, -1);
1769
1770 if (ge->event.notify60[i].descr == NULL) {
1771 gg_debug_session(gs, GG_DEBUG_MISC,
1772 "// gg_watch_fd_connected() "
1773 "out of memory\n");
1774 return -1;
1775 }
1776
1777 /* XXX czas */
1778
1779 length -= sizeof(struct gg_notify_reply80) + descr_len;
1780 n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply80) + descr_len);
1781 } else {
1782 length = 0;
1783 }
1784
1785 } else {
1786 length -= sizeof(struct gg_notify_reply80);
1787 n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply80));
1788 }
1789
1790 if (!(tmp = realloc(ge->event.notify60, (i + 2) * sizeof(*ge->event.notify60)))) {
1791 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1792 free(ge->event.notify60);
1793 return -1;
1794 }
1795
1796 ge->event.notify60 = tmp;
1797 ge->event.notify60[++i].uin = 0;
1798 }
1799
1800 return 0;
1801 }
1802
1803 /**
1804 * \internal Obsługuje pakiety GG_NOTIFY_REPLY77 i GG_NOTIFY_REPLY80BETA.
1805 *
1806 * Patrz gg_packet_handler_t
1807 */
1808 static int gg_session_handle_notify_reply_77_80beta(struct gg_session *gs,
1809 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
1810 {
1811 const struct gg_notify_reply77 *n = (const void*) ptr;
1812 unsigned int length = len, i = 0;
1813
1814 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
1815
1816 ge->type = GG_EVENT_NOTIFY60;
1817 ge->event.notify60 = malloc(sizeof(*ge->event.notify60));
1818
1819 if (ge->event.notify60 == NULL) {
1820 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1821 return -1;
1822 }
1823
1824 ge->event.notify60[0].uin = 0;
1825
1826 while (length >= sizeof(struct gg_notify_reply77)) {
1827 uin_t uin = gg_fix32(n->uin);
1828 void *tmp;
1829
1830 ge->event.notify60[i].uin = uin & 0x00ffffff;
1831 ge->event.notify60[i].status = n->status;
1832 ge->event.notify60[i].remote_ip = n->remote_ip;
1833 ge->event.notify60[i].remote_port = gg_fix16(n->remote_port);
1834 ge->event.notify60[i].version = n->version;
1835 ge->event.notify60[i].image_size = n->image_size;
1836 ge->event.notify60[i].descr = NULL;
1837 ge->event.notify60[i].time = 0;
1838
1839 if (uin & 0x40000000)
1840 ge->event.notify60[i].version |= GG_HAS_AUDIO_MASK;
1841 if (uin & 0x20000000)
1842 ge->event.notify60[i].version |= GG_HAS_AUDIO7_MASK;
1843 if (uin & 0x08000000)
1844 ge->event.notify60[i].version |= GG_ERA_OMNIX_MASK;
1845
1846 if (GG_S_D(n->status)) {
1847 unsigned char descr_len = *((const char*) n + sizeof(struct gg_notify_reply77));
1848
1849 if (sizeof(struct gg_notify_reply77) + descr_len <= length) {
1850 ge->event.notify60[i].descr = gg_encoding_convert(
1851 (const char*) n + sizeof(struct gg_notify_reply77) + 1,
1852 (type == GG_NOTIFY_REPLY80BETA) ? GG_ENCODING_UTF8 : GG_ENCODING_CP1250,
1853 gs->encoding, descr_len, -1);
1854
1855 if (ge->event.notify60[i].descr == NULL) {
1856 gg_debug_session(gs, GG_DEBUG_MISC,
1857 "// gg_watch_fd_connected() "
1858 "out of memory\n");
1859 return -1;
1860 }
1861
1862 /* XXX czas */
1863
1864 length -= sizeof(struct gg_notify_reply77) + descr_len + 1;
1865 n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1);
1866 } else {
1867 length = 0;
1868 }
1869
1870 } else {
1871 length -= sizeof(struct gg_notify_reply77);
1872 n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply77));
1873 }
1874
1875 if (!(tmp = realloc(ge->event.notify60, (i + 2) * sizeof(*ge->event.notify60)))) {
1876 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1877 free(ge->event.notify60);
1878 return -1;
1879 }
1880
1881 ge->event.notify60 = tmp;
1882 ge->event.notify60[++i].uin = 0;
1883 }
1884
1885 return 0;
1886 }
1887
1888 /**
1889 * \internal Obsługuje pakiet GG_NOTIFY_REPLY60.
1890 *
1891 * Patrz gg_packet_handler_t
1892 */
1893 static int gg_session_handle_notify_reply_60(struct gg_session *gs,
1894 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
1895 {
1896 const struct gg_notify_reply60 *n = (const void*) ptr;
1897 unsigned int length = len, i = 0;
1898
1899 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
1900
1901 ge->type = GG_EVENT_NOTIFY60;
1902 ge->event.notify60 = malloc(sizeof(*ge->event.notify60));
1903
1904 if (ge->event.notify60 == NULL) {
1905 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1906 return -1;
1907 }
1908
1909 ge->event.notify60[0].uin = 0;
1910
1911 while (length >= sizeof(struct gg_notify_reply60)) {
1912 uin_t uin = gg_fix32(n->uin);
1913 void *tmp;
1914
1915 ge->event.notify60[i].uin = uin & 0x00ffffff;
1916 ge->event.notify60[i].status = n->status;
1917 ge->event.notify60[i].remote_ip = n->remote_ip;
1918 ge->event.notify60[i].remote_port = gg_fix16(n->remote_port);
1919 ge->event.notify60[i].version = n->version;
1920 ge->event.notify60[i].image_size = n->image_size;
1921 ge->event.notify60[i].descr = NULL;
1922 ge->event.notify60[i].time = 0;
1923
1924 if (uin & 0x40000000)
1925 ge->event.notify60[i].version |= GG_HAS_AUDIO_MASK;
1926 if (uin & 0x08000000)
1927 ge->event.notify60[i].version |= GG_ERA_OMNIX_MASK;
1928
1929 if (GG_S_D(n->status)) {
1930 unsigned char descr_len = *((const char*) n + sizeof(struct gg_notify_reply60));
1931
1932 if (sizeof(struct gg_notify_reply60) + descr_len <= length) {
1933 char *descr;
1934
1935 descr = gg_encoding_convert((const char*) n +
1936 sizeof(struct gg_notify_reply60) + 1,
1937 GG_ENCODING_CP1250, gs->encoding,
1938 descr_len, -1);
1939
1940 if (descr == NULL) {
1941 gg_debug_session(gs, GG_DEBUG_MISC,
1942 "// gg_watch_fd_connected() "
1943 "out of memory\n");
1944 return -1;
1945 }
1946
1947 ge->event.notify60[i].descr = descr;
1948
1949 /* XXX czas */
1950
1951 length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
1952 n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
1953 } else {
1954 length = 0;
1955 }
1956
1957 } else {
1958 length -= sizeof(struct gg_notify_reply60);
1959 n = (const void*) ((const char*) n + sizeof(struct gg_notify_reply60));
1960 }
1961
1962 if (!(tmp = realloc(ge->event.notify60, (i + 2) * sizeof(*ge->event.notify60)))) {
1963 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() out of memory\n");
1964 free(ge->event.notify60);
1965 return -1;
1966 }
1967
1968 ge->event.notify60 = tmp;
1969 ge->event.notify60[++i].uin = 0;
1970 }
1971
1972 return 0;
1973 }
1974
1975 /**
1976 * \internal Obsługuje pakiet GG_USER_DATA.
1977 *
1978 * Patrz gg_packet_handler_t
1979 */
1980 static int gg_session_handle_user_data(struct gg_session *gs, uint32_t type,
1981 const char *ptr, size_t len, struct gg_event *ge)
1982 {
1983 struct gg_user_data d;
1984 const char *p = (const char*) ptr;
1985 const char *packet_end = (const char*) ptr + len;
1986 struct gg_event_user_data_user *users;
1987 unsigned int i, j;
1988 int res = 0;
1989
1990 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received user data\n");
1991
1992 ge->event.user_data.user_count = 0;
1993 ge->event.user_data.users = NULL;
1994
1995 if (ptr + sizeof(d) > packet_end)
1996 goto malformed;
1997
1998 memcpy(&d, p, sizeof(d));
1999 p += sizeof(d);
2000
2001 d.type = gg_fix32(d.type);
2002 d.user_count = gg_fix32(d.user_count);
2003
2004 if (d.user_count > 0xffff) {
2005 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_user_data() malformed packet (1)\n");
2006 goto malformed;
2007 }
2008
2009 if (d.user_count > 0) {
2010 users = calloc(d.user_count, sizeof(struct gg_event_user_data_user));
2011
2012 if (users == NULL) {
2013 gg_debug_session(gs, GG_DEBUG_MISC,
2014 "// gg_session_handle_user_data() out of memory"
2015 " (%d*%" GG_SIZE_FMT ")\n", d.user_count,
2016 sizeof(struct gg_event_user_data_user));
2017 goto fail;
2018 }
2019 } else {
2020 users = NULL;
2021 }
2022
2023 ge->type = GG_EVENT_USER_DATA;
2024 ge->event.user_data.type = d.type;
2025 ge->event.user_data.user_count = d.user_count;
2026 ge->event.user_data.users = users;
2027
2028 gg_debug_session(gs, GG_DEBUG_DUMP, "type=%d, count=%d\n", d.type, d.user_count);
2029
2030 for (i = 0; i < d.user_count; i++) {
2031 struct gg_user_data_user u;
2032 struct gg_event_user_data_attr *attrs;
2033
2034 if (p + sizeof(u) > packet_end) {
2035 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_user_data() malformed packet (2)\n");
2036 goto malformed;
2037 }
2038
2039 memcpy(&u, p, sizeof(u));
2040 p += sizeof(u);
2041
2042 u.uin = gg_fix32(u.uin);
2043 u.attr_count = gg_fix32(u.attr_count);
2044
2045 if (u.attr_count > 0xffff) {
2046 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_user_data() malformed packet (2)\n");
2047 goto malformed;
2048 }
2049
2050 if (u.attr_count > 0) {
2051 attrs = calloc(u.attr_count, sizeof(struct gg_event_user_data_attr));
2052
2053 if (attrs == NULL) {
2054 gg_debug_session(gs, GG_DEBUG_MISC,
2055 "// gg_session_handle_user_data() "
2056 "out of memory (%d*%" GG_SIZE_FMT
2057 ")\n", u.attr_count,
2058 sizeof(struct gg_event_user_data_attr));
2059 goto fail;
2060 }
2061 } else {
2062 attrs = NULL;
2063 }
2064
2065 users[i].uin = u.uin;
2066 users[i].attr_count = u.attr_count;
2067 users[i].attrs = attrs;
2068
2069 gg_debug_session(gs, GG_DEBUG_DUMP, " uin=%d, count=%d\n", u.uin, u.attr_count);
2070
2071 for (j = 0; j < u.attr_count; j++) {
2072 uint32_t key_size;
2073 uint32_t attr_type;
2074 uint32_t value_size;
2075 char *key;
2076 char *value;
2077
2078 if (p + sizeof(key_size) > packet_end) {
2079 gg_debug_session(gs, GG_DEBUG_MISC,
2080 "// gg_session_handle_user_data()"
2081 "malformed packet (3)\n");
2082 goto malformed;
2083 }
2084
2085 memcpy(&key_size, p, sizeof(key_size));
2086 p += sizeof(key_size);
2087
2088 key_size = gg_fix32(key_size);
2089
2090 if (key_size > 0xffff || p + key_size > packet_end) {
2091 gg_debug_session(gs, GG_DEBUG_MISC,
2092 "// gg_session_handle_user_data() "
2093 "malformed packet (3)\n");
2094 goto malformed;
2095 }
2096
2097 key = malloc(key_size + 1);
2098
2099 if (key == NULL) {
2100 gg_debug_session(gs, GG_DEBUG_MISC,
2101 "// gg_session_handle_user_data() "
2102 "out of memory (%d)\n", key_size + 1);
2103 goto fail;
2104 }
2105
2106 memcpy(key, p, key_size);
2107 p += key_size;
2108
2109 key[key_size] = 0;
2110
2111 attrs[j].key = key;
2112
2113 if (p + sizeof(attr_type) + sizeof(value_size) > packet_end) {
2114 gg_debug_session(gs, GG_DEBUG_MISC,
2115 "// gg_session_handle_user_data() "
2116 "malformed packet (4)\n");
2117 goto malformed;
2118 }
2119
2120 memcpy(&attr_type, p, sizeof(attr_type));
2121 p += sizeof(attr_type);
2122 memcpy(&value_size, p, sizeof(value_size));
2123 p += sizeof(value_size);
2124
2125 attrs[j].type = gg_fix32(attr_type);
2126 value_size = gg_fix32(value_size);
2127
2128 if (value_size > 0xffff || p + value_size > packet_end) {
2129 gg_debug_session(gs, GG_DEBUG_MISC,
2130 "// gg_session_handle_user_data() "
2131 "malformed packet (5)\n");
2132 goto malformed;
2133 }
2134
2135 value = malloc(value_size + 1);
2136
2137 if (value == NULL) {
2138 gg_debug_session(gs, GG_DEBUG_MISC,
2139 "// gg_session_handle_user_data() "
2140 "out of memory (%d)\n", value_size + 1);
2141 goto fail;
2142 }
2143
2144 memcpy(value, p, value_size);
2145 p += value_size;
2146
2147 value[value_size] = 0;
2148
2149 attrs[j].value = value;
2150
2151 gg_debug_session(gs, GG_DEBUG_DUMP, " key=\"%s\", "
2152 "type=%d, value=\"%s\"\n", key, attr_type, value);
2153 }
2154 }
2155
2156 return 0;
2157
2158 fail:
2159 res = -1;
2160
2161 malformed:
2162 ge->type = GG_EVENT_NONE;
2163
2164 for (i = 0; i < ge->event.user_data.user_count; i++) {
2165 for (j = 0; j < ge->event.user_data.users[i].attr_count; j++) {
2166 free(ge->event.user_data.users[i].attrs[j].key);
2167 free(ge->event.user_data.users[i].attrs[j].value);
2168 }
2169
2170 free(ge->event.user_data.users[i].attrs);
2171 }
2172
2173 free(ge->event.user_data.users);
2174
2175 return res;
2176 }
2177
2178 /**
2179 * \internal Obsługuje pakiet GG_TYPING_NOTIFICATION.
2180 *
2181 * Patrz gg_packet_handler_t
2182 */
2183 static int gg_session_handle_typing_notification(struct gg_session *gs,
2184 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2185 {
2186 const struct gg_typing_notification *n = (const void*) ptr;
2187 uin_t uin;
2188
2189 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received typing notification\n");
2190
2191 memcpy(&uin, &n->uin, sizeof(uin_t));
2192
2193 ge->type = GG_EVENT_TYPING_NOTIFICATION;
2194 ge->event.typing_notification.uin = gg_fix32(uin);
2195 ge->event.typing_notification.length = gg_fix16(n->length);
2196
2197 return 0;
2198 }
2199
2200 /**
2201 * \internal Obsługuje pakiet GG_MULTILOGON_INFO.
2202 *
2203 * Patrz gg_packet_handler_t
2204 */
2205 static int gg_session_handle_multilogon_info(struct gg_session *gs,
2206 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2207 {
2208 const char *packet_end = (const char*) ptr + len;
2209 const struct gg_multilogon_info *info = (const struct gg_multilogon_info*) ptr;
2210 const char *p = (const char*) ptr + sizeof(*info);
2211 struct gg_multilogon_session *sessions = NULL;
2212 size_t count;
2213 size_t i;
2214 int res = 0;
2215
2216 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received multilogon info\n");
2217
2218 count = gg_fix32(info->count);
2219
2220 if (count > 0xffff) {
2221 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() malformed packet (1)\n");
2222 goto malformed;
2223 }
2224
2225 sessions = calloc(count, sizeof(struct gg_multilogon_session));
2226
2227 if (sessions == NULL) {
2228 gg_debug_session(gs, GG_DEBUG_MISC, "// "
2229 "gg_handle_multilogon_info() out of memory (%"
2230 GG_SIZE_FMT "*%" GG_SIZE_FMT ")\n",
2231 count, sizeof(struct gg_multilogon_session));
2232 return -1;
2233 }
2234
2235 ge->type = GG_EVENT_MULTILOGON_INFO;
2236 ge->event.multilogon_info.count = count;
2237 ge->event.multilogon_info.sessions = sessions;
2238
2239 for (i = 0; i < count; i++) {
2240 struct gg_multilogon_info_item item;
2241 size_t name_size;
2242
2243 if (p + sizeof(item) > packet_end) {
2244 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() malformed packet (2)\n");
2245 goto malformed;
2246 }
2247
2248 memcpy(&item, p, sizeof(item));
2249
2250 sessions[i].id = item.conn_id;
2251 sessions[i].remote_addr = item.addr;
2252 sessions[i].status_flags = gg_fix32(item.flags);
2253 sessions[i].protocol_features = gg_fix32(item.features);
2254 sessions[i].logon_time = gg_fix32(item.logon_time);
2255
2256 p += sizeof(item);
2257
2258 name_size = gg_fix32(item.name_size);
2259
2260 if (name_size > 0xffff || p + name_size > packet_end) {
2261 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() malformed packet (3)\n");
2262 goto malformed;
2263 }
2264
2265 sessions[i].name = malloc(name_size + 1);
2266
2267 if (sessions[i].name == NULL) {
2268 gg_debug_session(gs, GG_DEBUG_MISC,
2269 "// gg_handle_multilogon_info() out of "
2270 "memory (%" GG_SIZE_FMT ")\n", name_size);
2271 goto fail;
2272 }
2273
2274 memcpy(sessions[i].name, p, name_size);
2275 sessions[i].name[name_size] = 0;
2276
2277 p += name_size;
2278 }
2279
2280 return 0;
2281
2282 fail:
2283 res = -1;
2284
2285 malformed:
2286 ge->type = GG_EVENT_NONE;
2287
2288 for (i = 0; (int) i < ge->event.multilogon_info.count; i++)
2289 free(ge->event.multilogon_info.sessions[i].name);
2290
2291 free(ge->event.multilogon_info.sessions);
2292
2293 return res;
2294 }
2295
2296 /**
2297 * \internal Obsługuje pakiet GG_USERLIST100_VERSION.
2298 *
2299 * Patrz gg_packet_handler_t
2300 */
2301 static int gg_session_handle_userlist_100_version(struct gg_session *gs,
2302 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2303 {
2304 const struct gg_userlist100_version *version = (const struct gg_userlist100_version*) ptr;
2305
2306 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 version\n");
2307
2308 ge->type = GG_EVENT_USERLIST100_VERSION;
2309 ge->event.userlist100_version.version = gg_fix32(version->version);
2310
2311 return 0;
2312 }
2313
2314 /**
2315 * \internal Obsługuje pakiet GG_USERLIST100_REPLY.
2316 *
2317 * Patrz gg_packet_handler_t
2318 */
2319 static int gg_session_handle_userlist_100_reply(struct gg_session *gs,
2320 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2321 {
2322 const struct gg_userlist100_reply *reply = (const struct gg_userlist100_reply*) ptr;
2323 char *data = NULL;
2324
2325 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 reply\n");
2326
2327 if (len > sizeof(*reply)) {
2328 data = gg_inflate((const unsigned char*) ptr + sizeof(*reply), len - sizeof(*reply));
2329
2330 if (data == NULL) {
2331 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_userlist_100_reply() gg_inflate() failed\n");
2332 return -1;
2333 }
2334 }
2335
2336 ge->type = GG_EVENT_USERLIST100_REPLY;
2337 ge->event.userlist100_reply.type = reply->type;
2338 ge->event.userlist100_reply.version = gg_fix32(reply->version);
2339 ge->event.userlist100_reply.format_type = reply->format_type;
2340 ge->event.userlist100_reply.reply = data;
2341
2342 return 0;
2343 }
2344
2345 static int gg_session_handle_imtoken(struct gg_session *gs, uint32_t type,
2346 const char *ptr, size_t len, struct gg_event *ge)
2347 {
2348 GG110Imtoken *msg = gg110_imtoken__unpack(NULL, len, (uint8_t*)ptr);
2349 char *imtoken = NULL;
2350 int succ = 1;
2351
2352 if (!GG_PROTOBUF_VALID(gs, "GG110Imtoken", msg))
2353 return -1;
2354
2355 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() "
2356 "received imtoken\n");
2357
2358 if (msg->imtoken[0] != '\0') {
2359 imtoken = strdup(msg->imtoken);
2360 succ = succ && (imtoken != NULL);
2361 }
2362
2363 gg110_imtoken__free_unpacked(msg, NULL);
2364
2365 ge->type = GG_EVENT_IMTOKEN;
2366 ge->event.imtoken.imtoken = imtoken;
2367
2368 return succ ? 0 : -1;
2369 }
2370
2371 static int gg_session_handle_pong_110(struct gg_session *gs, uint32_t type,
2372 const char *ptr, size_t len, struct gg_event *ge)
2373 {
2374 GG110Pong *msg = gg110_pong__unpack(NULL, len, (uint8_t*)ptr);
2375
2376 if (!GG_PROTOBUF_VALID(gs, "GG110Pong", msg))
2377 return -1;
2378
2379 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() "
2380 "received pong110\n");
2381
2382 ge->type = GG_EVENT_PONG110;
2383 ge->event.pong110.time = msg->server_time;
2384
2385 gg_sync_time(gs, msg->server_time);
2386
2387 gg110_pong__free_unpacked(msg, NULL);
2388
2389 return 0;
2390 }
2391
2392 static int gg_session_handle_chat_info(struct gg_session *gs, uint32_t type,
2393 const char *ptr, size_t len, struct gg_event *ge)
2394 {
2395 gg_tvbuff_t *tvb;
2396 uint32_t i;
2397
2398 uint64_t id;
2399 uint32_t version;
2400 uint32_t dummy1;
2401 uint32_t participants_count;
2402 uin_t *participants = NULL;
2403
2404 tvb = gg_tvbuff_new(ptr, len);
2405
2406 id = gg_tvbuff_read_uint64(tvb);
2407 gg_tvbuff_expected_uint32(tvb, 0); /* unknown */
2408 version = gg_tvbuff_read_uint32(tvb);
2409 dummy1 = gg_tvbuff_read_uint32(tvb);
2410 if (gg_tvbuff_is_valid(tvb) && dummy1 == 1) {
2411 uint32_t name_length;
2412
2413 name_length = gg_tvbuff_read_uint32(tvb);
2414 gg_tvbuff_skip(tvb, name_length);
2415
2416 gg_tvbuff_expected_uint32(tvb, 0); /* unknown */
2417 gg_tvbuff_expected_uint32(tvb, 2); /* unknown */
2418 }
2419 participants_count = gg_tvbuff_read_uint32(tvb);
2420 if (id == 0 && participants_count > 0) {
2421 gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING,
2422 "// gg_session_handle_chat_info() terminating packet "
2423 "shouldn't contain participants\n");
2424 participants_count = 0;
2425 }
2426
2427 if (participants_count > 0) {
2428 participants = malloc(sizeof(uin_t) * participants_count);
2429 if (participants == NULL) {
2430 gg_tvbuff_close(tvb);
2431 return -1;
2432 }
2433 }
2434
2435 for (i = 0; i < participants_count && gg_tvbuff_is_valid(tvb); i++) {
2436 participants[i] = gg_tvbuff_read_uint32(tvb);
2437 gg_tvbuff_read_uint32(tvb); /* 0x1e lub 0x18 */
2438 }
2439
2440 if (!gg_tvbuff_close(tvb)) {
2441 free(participants);
2442 return -1;
2443 }
2444
2445 if (id == 0) {
2446 ge->type = GG_EVENT_CHAT_INFO_GOT_ALL;
2447 return 0;
2448 }
2449
2450 if (0 != gg_chat_update(gs, id, version, participants,
2451 participants_count))
2452 {
2453 free(participants);
2454 return -1;
2455 }
2456
2457 ge->type = GG_EVENT_CHAT_INFO;
2458 ge->event.chat_info.id = id;
2459 ge->event.chat_info.version = version;
2460 ge->event.chat_info.participants_count = participants_count;
2461 ge->event.chat_info.participants = participants;
2462
2463 return 0;
2464 }
2465
2466 static int gg_session_handle_chat_info_update(struct gg_session *gs,
2467 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2468 {
2469 GG110ChatInfoUpdate *msg = gg110_chat_info_update__unpack(NULL, len, (uint8_t*)ptr);
2470 gg_chat_list_t *chat;
2471 uin_t participant;
2472
2473 if (!GG_PROTOBUF_VALID(gs, "GG110ChatInfoUpdate", msg))
2474 return -1;
2475
2476 gg_debug_session(gs, GG_DEBUG_VERBOSE,
2477 "// gg_session_handle_chat_info_update() "
2478 "msg_id=%016" PRIx64 " conv_id=%016" PRIx64 "\n",
2479 msg->msg_id, msg->conv_id);
2480
2481 ge->type = GG_EVENT_CHAT_INFO_UPDATE;
2482 ge->event.chat_info_update.id = msg->chat_id;
2483 ge->event.chat_info_update.type = msg->update_type;
2484 ge->event.chat_info_update.participant = participant = gg_protobuf_get_uin(msg->participant);
2485 ge->event.chat_info_update.inviter = gg_protobuf_get_uin(msg->inviter);
2486 ge->event.chat_info_update.version = msg->version;
2487 ge->event.chat_info_update.time = msg->time;
2488
2489 chat = gg_chat_find(gs, msg->chat_id);
2490 if (!chat) {
2491 gg110_chat_info_update__free_unpacked(msg, NULL);
2492 return 0;
2493 }
2494
2495 chat->version = msg->version;
2496 if (msg->update_type == GG_CHAT_INFO_UPDATE_ENTERED) {
2497 uin_t *old_part = chat->participants;
2498 chat->participants = realloc(chat->participants,
2499 sizeof(uin_t) * chat->participants_count);
2500 if (chat->participants == NULL) {
2501 chat->participants = old_part;
2502 gg_debug_session(gs, GG_DEBUG_ERROR,
2503 "// gg_session_handle_chat_info_update() "
2504 "out of memory (count=%u)\n",
2505 chat->participants_count);
2506 return -1;
2507 }
2508 chat->participants_count++;
2509 chat->participants[chat->participants_count - 1] = participant;
2510 } else if (msg->update_type == GG_CHAT_INFO_UPDATE_EXITED) {
2511 uint32_t idx;
2512 for (idx = 0; idx < chat->participants_count; idx++)
2513 if (chat->participants[idx] == participant)
2514 break;
2515 if (chat->participants_count > 1 &&
2516 idx < chat->participants_count)
2517 chat->participants[idx] = chat->participants[chat->participants_count - 1];
2518 if (idx < chat->participants_count) {
2519 chat->participants_count--;
2520 if (chat->participants_count == 0) {
2521 free(chat->participants);
2522 chat->participants = NULL;
2523 } else {
2524 chat->participants = realloc(chat->participants,
2525 sizeof(uin_t)*chat->participants_count);
2526 }
2527 }
2528 }
2529
2530 gg110_chat_info_update__free_unpacked(msg, NULL);
2531 return 0;
2532 }
2533
2534 static int gg_session_handle_chat_created(struct gg_session *gs, uint32_t type,
2535 const char *ptr, size_t len, struct gg_event *ge)
2536 {
2537 const struct gg_chat_created *p = (const struct gg_chat_created *)ptr;
2538
2539 if (0 != gg_chat_update(gs, gg_fix64(p->id), 0, &gs->uin, 1))
2540 return -1;
2541
2542 ge->type = GG_EVENT_CHAT_CREATED;
2543 ge->event.chat_created.id = gg_fix64(p->id);
2544 ge->event.chat_created.seq = gg_fix32(p->seq);
2545 return 0;
2546 }
2547
2548 static int gg_session_handle_chat_invite_ack(struct gg_session *gs,
2549 uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2550 {
2551 const struct gg_chat_invite_ack *p =
2552 (const struct gg_chat_invite_ack *)ptr;
2553
2554 ge->type = GG_EVENT_CHAT_INVITE_ACK;
2555 ge->event.chat_invite_ack.id = gg_fix64(p->id);
2556 ge->event.chat_invite_ack.seq = gg_fix32(p->seq);
2557
2558 return 0;
2559 }
2560
2561 static int gg_session_handle_chat_left(struct gg_session *gs, uint32_t type,
2562 const char *ptr, size_t len, struct gg_event *ge)
2563 {
2564 const struct gg_chat_left *p = (const struct gg_chat_left *)ptr;
2565
2566 ge->type = GG_EVENT_CHAT_INFO_UPDATE;
2567 ge->event.chat_info_update.id = gg_fix64(p->id);
2568 ge->event.chat_info_update.type = GG_CHAT_INFO_UPDATE_EXITED;
2569 /* Właściwie, to nie wiadomo, czy to jest "osoba wychodząca", czy
2570 * "osoba wyrzucająca nas" z konferencji. */
2571 ge->event.chat_info_update.participant = gg_fix32(p->uin);
2572 ge->event.chat_info_update.inviter = gg_fix32(p->uin);
2573 ge->event.chat_info_update.version = 0;
2574 ge->event.chat_info_update.time = time(NULL);
2575
2576 return 0;
2577 }
2578
2579 static int gg_session_handle_options(struct gg_session *gs, uint32_t type,
2580 const char *ptr, size_t len, struct gg_event *ge)
2581 {
2582 GG110Options *msg = gg110_options__unpack(NULL, len, (uint8_t*)ptr);
2583 size_t i;
2584
2585 if (!GG_PROTOBUF_VALID(gs, "GG110Options", msg))
2586 return -1;
2587
2588 gg_protobuf_expected(gs, "GG110Options.dummy1", msg->dummy1, 0);
2589
2590 for (i = 0; i < msg->n_options; i++) {
2591 ProtobufKVP *kvp = msg->options[i];
2592 if (!GG_PROTOBUF_VALID(gs, "ProtobufKVP", kvp))
2593 continue;
2594 gg_debug_session(gs, GG_DEBUG_MISC,
2595 "// gg_session_handle_options[%s] = \"%s\"\n",
2596 kvp->key, kvp->value);
2597 }
2598
2599 gg110_options__free_unpacked(msg, NULL);
2600
2601 return 0;
2602 }
2603
2604 static int gg_session_handle_access_info(struct gg_session *gs, uint32_t type,
2605 const char *ptr, size_t len, struct gg_event *ge)
2606 {
2607 GG110AccessInfo *msg = gg110_access_info__unpack(NULL, len, (uint8_t*)ptr);
2608
2609 if (!GG_PROTOBUF_VALID(gs, "GG110AccessInfo", msg))
2610 return -1;
2611
2612 gg_debug_session(gs, GG_DEBUG_MISC,
2613 "// gg_session_handle_access_info: dummy[%02x, %02x], "
2614 "last[message=%u, file_transfer=%u, conference_ch=%u]\n",
2615 msg->dummy1, msg->dummy2, msg->last_message,
2616 msg->last_file_transfer, msg->last_conference_ch);
2617
2618 gg110_access_info__free_unpacked(msg, NULL);
2619
2620 return 0;
2621 }
2622
2623 /* ten pakiet jest odbierany tylko, jeżeli przy logowaniu użyliśmy identyfikatora typu 0x01 */
2624 static int gg_session_handle_uin_info(struct gg_session *gs, uint32_t type,
2625 const char *ptr, size_t len, struct gg_event *ge)
2626 {
2627 gg_tvbuff_t *tvb;
2628 char *uin1 = NULL, *uin2 = NULL;
2629
2630 tvb = gg_tvbuff_new(ptr, len);
2631
2632 gg_tvbuff_expected_uint32(tvb, 1); /* unknown */
2633 gg_tvbuff_expected_uint32(tvb, 2); /* unknown */
2634
2635 /* podstawowy identyfikator (numer GG) */
2636 gg_tvbuff_expected_uint8(tvb, 0);
2637 gg_tvbuff_read_str_dup(tvb, &uin1);
2638
2639 /* identyfikator użyty przy logowaniu (numer GG lub email) */
2640 gg_tvbuff_expected_uint8(tvb, 1);
2641 gg_tvbuff_read_str_dup(tvb, &uin2);
2642
2643 if (!gg_tvbuff_close(tvb)) {
2644 free(uin1);
2645 free(uin2);
2646 return -1;
2647 }
2648
2649 gg_debug_session(gs, GG_DEBUG_MISC, "// gg_session_handle_uin_info: "
2650 "uin1=\"%s\", uin2=\"%s\"\n", uin1, uin2);
2651
2652 free(uin1);
2653 free(uin2);
2654
2655 return 0;
2656 }
2657
2658 static int gg_session_handle_transfer_info(struct gg_session *gs, uint32_t type,
2659 const char *ptr, size_t len, struct gg_event *ge)
2660 {
2661 GG112TransferInfo *msg = gg112_transfer_info__unpack(NULL, len, (uint8_t*)ptr);
2662 int succ = 1;
2663 size_t i;
2664 uin_t peer = 0, sender = 0;
2665
2666 if (!GG_PROTOBUF_VALID(gs, "GG112TransferInfo", msg))
2667 return -1;
2668
2669 /* see packets.proto */
2670 if (msg->dummy1 != 5 && msg->dummy1 != 6) {
2671 gg_debug_session(gs, GG_DEBUG_MISC | GG_DEBUG_WARNING,
2672 "// gg_session_handle_transfer_info: "
2673 "unknown dummy1 value: %d\n", msg->dummy1);
2674 }
2675
2676 if (GG_PROTOBUF_VALID(gs, "GG112TransferInfoUin", msg->peer)) {
2677 gg_protobuf_expected(gs, "GG112TransferInfoUin.dummy1",
2678 msg->peer->dummy1, 1);
2679 peer = gg_protobuf_get_uin(msg->peer->uin);
2680 }
2681 if (GG_PROTOBUF_VALID(gs, "GG112TransferInfoUin", msg->sender)) {
2682 gg_protobuf_expected(gs, "GG112TransferInfoUin.dummy1",
2683 msg->sender->dummy1, 1);
2684 sender = gg_protobuf_get_uin(msg->sender->uin);
2685 }
2686
2687 gg_debug_session(gs, GG_DEBUG_MISC,
2688 "// gg_session_handle_transfer_info: dummy1=%#x, time=%u, "
2689 "sender=%u, peer=%u, msg_id=%#016" PRIx64 ", "
2690 "conv_id=%#016" PRIx64 "\n",
2691 msg->dummy1, msg->time, sender, peer, msg->msg_id,
2692 msg->conv_id);
2693
2694 for (i = 0; i < msg->n_data; i++) {
2695 ProtobufKVP *kvp = msg->data[i];
2696 if (!GG_PROTOBUF_VALID(gs, "ProtobufKVP", kvp))
2697 continue;
2698 gg_debug_session(gs, GG_DEBUG_MISC,
2699 "// gg_session_handle_transfer_info[%s] = \"%s\"\n",
2700 kvp->key, kvp->value);
2701 }
2702
2703 if (msg->file && GG_PROTOBUF_VALID(gs, "GG112TransferInfoFile", msg->file)) {
2704 GG112TransferInfoFile *file = msg->file;
2705 gg_debug_session(gs, GG_DEBUG_MISC,
2706 "// gg_session_handle_transfer_info file: "
2707 "type=\"%s\", content_type=\"%s\", filename=\"%s\", "
2708 "filesize=%u, msg_id=%#016" PRIx64 " url=\"%s\"\n",
2709 file->type, file->content_type, file->filename,
2710 file->filesize, file->msg_id, file->url);
2711 }
2712
2713 succ = (gg_ack_110(gs, GG110_ACK__TYPE__TRANSFER_INFO,
2714 msg->seq, ge) == 0);
2715
2716 gg112_transfer_info__free_unpacked(msg, NULL);
2717
2718 return succ ? 0 : -1;
2719 }
2720
2721 static int gg_session_handle_magic_notification(struct gg_session *gs, uint32_t type,
2722 const char *ptr, size_t len, struct gg_event *ge)
2723 {
2724 GG110MagicNotification *msg = gg110_magic_notification__unpack(NULL, len, (uint8_t*)ptr);
2725 int succ = 1;
2726
2727 if (!GG_PROTOBUF_VALID(gs, "GG110MagicNotification", msg))
2728 return -1;
2729
2730 gg_debug_session(gs, GG_DEBUG_MISC,
2731 "// gg_session_handle_magic_notification \n");
2732
2733 gg_protobuf_expected(gs, "GG110MagicNotification.dummy1", msg->dummy1, 2);
2734 gg_protobuf_expected(gs, "GG110MagicNotification.dummy2", msg->dummy2, 1);
2735 gg_protobuf_expected(gs, "GG110MagicNotification.dummy3", msg->dummy3, 1);
2736
2737 succ = (gg_ack_110(gs, GG110_ACK__TYPE__MAGIC_NOTIFICATION, msg->seq, ge) == 0);
2738
2739 gg110_magic_notification__free_unpacked(msg, NULL);
2740
2741 return succ ? 0 : -1;
2742 }
2743
2744 /**
2745 * \internal Tablica obsługiwanych pakietów
2746 */
2747 static const gg_packet_handler_t handlers[] =
2748 {
2749 /* style:maxlinelength:start-ignore */
2750 { GG_WELCOME, GG_STATE_READING_KEY, 0, gg_session_handle_welcome },
2751 { GG_LOGIN_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
2752 { GG_LOGIN80_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
2753 { GG_LOGIN110_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login110_ok },
2754 { GG_NEED_EMAIL, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
2755 { GG_LOGIN_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
2756 { GG_LOGIN80_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
2757 { GG_SEND_MSG_ACK, GG_STATE_CONNECTED, sizeof(struct gg_send_msg_ack), gg_session_handle_send_msg_ack },
2758 { GG_SEND_MSG_ACK110, GG_STATE_CONNECTED, 0, gg_session_handle_send_msg_ack_110 },
2759 { GG_PONG, GG_STATE_CONNECTED, 0, gg_session_handle_pong },
2760 { GG_DISCONNECTING, GG_STATE_CONNECTED, 0, gg_session_handle_disconnecting },
2761 { GG_DISCONNECT_ACK, GG_STATE_DISCONNECTING, 0, gg_session_handle_disconnect_ack },
2762 { GG_XML_EVENT, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
2763 { GG_EVENT110, GG_STATE_CONNECTED, 0, gg_session_handle_event_110 },
2764 { GG_PUBDIR50_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_pubdir50_reply },
2765 { GG_USERLIST_REPLY, GG_STATE_CONNECTED, sizeof(char), gg_session_handle_userlist_reply },
2766 { GG_DCC7_ID_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_id_reply), gg_session_handle_dcc7_id_reply },
2767 { GG_DCC7_ACCEPT, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_accept), gg_session_handle_dcc7_accept },
2768 { GG_DCC7_NEW, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_new), gg_session_handle_dcc7_new },
2769 { GG_DCC7_REJECT, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_reject), gg_session_handle_dcc7_reject },
2770 { GG_DCC7_INFO, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_info), gg_session_handle_dcc7_info },
2771 { GG_RECV_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg), gg_session_handle_recv_msg },
2772 { GG_RECV_MSG80, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
2773 { GG_RECV_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
2774 { GG_RECV_OWN_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
2775 { GG_STATUS, GG_STATE_CONNECTED, sizeof(struct gg_status), gg_session_handle_status },
2776 { GG_STATUS60, GG_STATE_CONNECTED, sizeof(struct gg_status60), gg_session_handle_status_60_77_80beta },
2777 { GG_STATUS77, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta },
2778 { GG_STATUS80BETA, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta },
2779 { GG_STATUS80, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply80), gg_session_handle_status_80 },
2780 { GG_NOTIFY_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply), gg_session_handle_notify_reply },
2781 { GG_NOTIFY_REPLY60, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply60), gg_session_handle_notify_reply_60 },
2782 { GG_NOTIFY_REPLY77, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply77), gg_session_handle_notify_reply_77_80beta },
2783 { GG_NOTIFY_REPLY80BETA, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply77), gg_session_handle_notify_reply_77_80beta },
2784 { GG_NOTIFY_REPLY80, GG_STATE_CONNECTED, sizeof(struct gg_notify_reply80), gg_session_handle_notify_reply_80 },
2785 { GG_USER_DATA, GG_STATE_CONNECTED, sizeof(struct gg_user_data), gg_session_handle_user_data },
2786 { GG_TYPING_NOTIFICATION, GG_STATE_CONNECTED, sizeof(struct gg_typing_notification), gg_session_handle_typing_notification },
2787 { GG_MULTILOGON_INFO, GG_STATE_CONNECTED, sizeof(struct gg_multilogon_info), gg_session_handle_multilogon_info },
2788 { GG_XML_ACTION, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
2789 { GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
2790 { GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version },
2791 { GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply },
2792 { GG_IMTOKEN, GG_STATE_CONNECTED, 0, gg_session_handle_imtoken },
2793 { GG_PONG110, GG_STATE_CONNECTED, 0, gg_session_handle_pong_110 },
2794 { GG_CHAT_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info },
2795 { GG_CHAT_INFO_UPDATE, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info_update },
2796 { GG_CHAT_CREATED, GG_STATE_CONNECTED, sizeof(struct gg_chat_created), gg_session_handle_chat_created },
2797 { GG_CHAT_INVITE_ACK, GG_STATE_CONNECTED, sizeof(struct gg_chat_invite_ack), gg_session_handle_chat_invite_ack },
2798 { GG_CHAT_RECV_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
2799 { GG_CHAT_RECV_OWN_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
2800 { GG_CHAT_LEFT, GG_STATE_CONNECTED, sizeof(struct gg_chat_left), gg_session_handle_chat_left },
2801 { GG_OPTIONS, GG_STATE_CONNECTED, 0, gg_session_handle_options },
2802 { GG_ACCESS_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_access_info },
2803 { GG_UIN_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_uin_info },
2804 { GG_TRANSFER_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_transfer_info },
2805 { GG_MAGIC_NOTIFICATION, GG_STATE_CONNECTED, 0, gg_session_handle_magic_notification }
2806 /* style:maxlinelength:end-ignore */
2807 };
2808
2809 /**
2810 * \internal Obsługuje przychodzący pakiet danych.
2811 *
2812 * \param gs Struktura sesji
2813 * \param type Typ pakietu
2814 * \param ptr Wskaźnik do bufora pakietu
2815 * \param len Długość bufora pakietu
2816 * \param[out] ge Struktura zdarzenia
2817 *
2818 * \return 0 jeśli się powiodło, -1 w przypadku błędu
2819 */
2820 int gg_session_handle_packet(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
2821 {
2822 unsigned int i;
2823
2824 gg_debug_session(gs, GG_DEBUG_FUNCTION,
2825 "// gg_session_handle_packet(%d, %p, %" GG_SIZE_FMT ")\n",
2826 type, ptr, len);
2827
2828 gs->last_event = time(NULL);
2829
2830 #if 0
2831 if ((gs->flags & (1 << GG_SESSION_FLAG_RAW_PACKET)) != 0) {
2832 char *tmp;
2833
2834 tmp = malloc(len);
2835
2836 if (tmp == NULL) {
2837 gg_debug_session(gs, GG_DEBUG_ERROR,
2838 "// gg_session_handle_packet() out of memory "
2839 "(%d bytes)\n", len);
2840 return -1;
2841 }
2842
2843 memcpy(tmp, ptr, len);
2844
2845 ge->type = GG_EVENT_RAW_PACKET;
2846 ge->event.raw_packet.type = type;
2847 ge->event.raw_packet.length = len;
2848 ge->event.raw_packet.data = tmp;
2849
2850 return 0;
2851 }
2852 #endif
2853
2854 for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) {
2855 if (handlers[i].type != 0 && handlers[i].type != type)
2856 continue;
2857
2858 if (handlers[i].state != 0 && handlers[i].state != (enum gg_state_t) gs->state) {
2859 gg_debug_session(gs, GG_DEBUG_WARNING,
2860 "// gg_session_handle_packet() packet 0x%02x "
2861 "unexpected in state %d\n", type, gs->state);
2862 continue;
2863 }
2864
2865 if (len < handlers[i].min_length) {
2866 gg_debug_session(gs, GG_DEBUG_ERROR,
2867 "// gg_session_handle_packet() packet 0x%02x "
2868 "too short (%" GG_SIZE_FMT " bytes)\n",
2869 type, len);
2870 continue;
2871 }
2872
2873 return (*handlers[i].handler)(gs, type, ptr, len, ge);
2874 }
2875
2876 gg_debug_session(gs, GG_DEBUG_WARNING, "// gg_session_handle_packet() "
2877 "unhandled packet 0x%02x, len %" GG_SIZE_FMT ", state %d\n",
2878 type, len, gs->state);
2879
2880 return 0;
2881 }

mercurial