| 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 } |
|