peer_id_t next_token_peer (void) { int l; char *s = next_token (&l); if (!s) { return PEER_NOT_FOUND; } if (l >= 6 && !memcmp (s, "user#", 5)) { s += 5; l -= 5; int r = atoi (s); if (r >= 0) { return set_peer_id (PEER_USER, r); } else { return PEER_NOT_FOUND; } } if (l >= 6 && !memcmp (s, "chat#", 5)) { s += 5; l -= 5; int r = atoi (s); if (r >= 0) { return set_peer_id (PEER_CHAT, r); } else { return PEER_NOT_FOUND; } } int index = 0; while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name))) { index ++; } if (index < peer_num) { return Peers[index]->id; } else { return PEER_NOT_FOUND; } }
void print_service_message (struct message *M) { assert (M); if (msg_num_mode) { printf ("%lld ", M->id); } print_date (M->date); printf (" "); if (get_peer_type (M->to_id) == PEER_CHAT) { print_chat_name (M->to_id, user_chat_get (M->to_id)); } else { assert (get_peer_type (M->to_id) == PEER_ENCR_CHAT); print_encr_chat_name (M->to_id, user_chat_get (M->to_id)); } printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); switch (M->action.type) { case CODE_message_action_empty: printf ("\n"); break; case CODE_message_action_geo_chat_create: printf ("Created geo chat\n"); break; case CODE_message_action_geo_chat_checkin: printf ("Checkin in geochat\n"); break; case CODE_message_action_chat_create: printf (" created chat %s. %d users\n", M->action.title, M->action.user_num); break; case CODE_message_action_chat_edit_title: printf (" changed title to %s\n", M->action.new_title); break; case CODE_message_action_chat_edit_photo: printf (" changed photo\n"); break; case CODE_message_action_chat_delete_photo: printf (" deleted photo\n"); break; case CODE_message_action_chat_add_user: printf (" added user "); print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); printf ("\n"); break; case CODE_message_action_chat_delete_user: printf (" deleted user "); print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); printf ("\n"); break; case CODE_decrypted_message_action_set_message_t_t_l: printf (" set ttl to %d seconds. Unsupported yet\n", M->action.ttl); break; default: assert (0); } }
void replay_log_event (void) { int *start = rptr; in_replay_log = 1; assert (rptr < wptr); int op = *rptr; if (verbosity >= 2) { logprintf ("log_pos %lld, op 0x%08x\n", binlog_pos, op); } in_ptr = rptr; in_end = wptr; switch (op) { case LOG_START: rptr ++; break; case CODE_binlog_dc_option: in_ptr ++; { int id = fetch_int (); int l1 = prefetch_strlen (); char *name = fetch_str (l1); int l2 = prefetch_strlen (); char *ip = fetch_str (l2); int port = fetch_int (); if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } alloc_dc (id, strndup (ip, l2), port); } rptr = in_ptr; break; case LOG_AUTH_KEY: rptr ++; { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); assert (DC_list[num]); DC_list[num]->auth_key_id = *(long long *)rptr; rptr += 2; memcpy (DC_list[num]->auth_key, rptr, 256); rptr += 64; DC_list[num]->flags |= 1; }; break; case LOG_DEFAULT_DC: rptr ++; { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); DC_working = DC_list[num]; dc_working_num = num; } break; case LOG_OUR_ID: rptr ++; { our_id = *(rptr ++); } break; case LOG_DC_SIGNED: rptr ++; { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); assert (DC_list[num]); DC_list[num]->has_auth = 1; } break; case LOG_DC_SALT: rptr ++; { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); assert (DC_list[num]); DC_list[num]->server_salt = *(long long *)rptr; rptr += 2; }; break; /* case CODE_user_empty: case CODE_user_self: case CODE_user_contact: case CODE_user_request: case CODE_user_foreign: case CODE_user_deleted: fetch_alloc_user (); rptr = in_ptr; break;*/ case LOG_DH_CONFIG: get_dh_config_on_answer (0); rptr = in_ptr; break; case LOG_ENCR_CHAT_KEY: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->key_fingerprint = *(long long *)rptr; rptr += 2; memcpy (U->key, rptr, 256); rptr += 64; }; break; case LOG_ENCR_CHAT_SEND_ACCEPT: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->key_fingerprint = *(long long *)rptr; rptr += 2; memcpy (U->key, rptr, 256); rptr += 64; if (!U->g_key) { U->g_key = malloc (256); } memcpy (U->g_key, rptr, 256); rptr += 64; }; break; case LOG_ENCR_CHAT_SEND_CREATE: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (!U || !(U->flags & FLAG_CREATED)); if (!U) { U = malloc (sizeof (peer_t)); memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); } U->flags |= FLAG_CREATED; U->user_id = *(rptr ++); memcpy (U->key, rptr, 256); rptr += 64; if (!U->print_name) { peer_t *P = user_chat_get (MK_USER (U->user_id)); if (P) { U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); } else { static char buf[100]; sprintf (buf, "user#%d", U->user_id); U->print_name = create_print_name (U->id, "!", buf, 0, 0); } } }; break; case LOG_ENCR_CHAT_DELETED: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); if (!U) { U = malloc (sizeof (peer_t)); memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); } U->flags |= FLAG_CREATED; U->state = sc_deleted; }; break; case LOG_ENCR_CHAT_WAITING: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->state = sc_waiting; U->date = *(rptr ++); U->admin_id = *(rptr ++); U->user_id = *(rptr ++); U->access_hash = *(long long *)rptr; rptr += 2; }; break; case LOG_ENCR_CHAT_REQUESTED: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); if (!U) { U = malloc (sizeof (peer_t)); memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); } U->flags |= FLAG_CREATED; U->state = sc_request; U->date = *(rptr ++); U->admin_id = *(rptr ++); U->user_id = *(rptr ++); U->access_hash = *(long long *)rptr; if (!U->print_name) { peer_t *P = user_chat_get (MK_USER (U->user_id)); if (P) { U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); } else { static char buf[100]; sprintf (buf, "user#%d", U->user_id); U->print_name = create_print_name (U->id, "!", buf, 0, 0); } } rptr += 2; }; break; case LOG_ENCR_CHAT_OK: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->state = sc_ok; } break; case CODE_binlog_new_user: in_ptr ++; { peer_id_t id = MK_USER (fetch_int ()); peer_t *_U = user_chat_get (id); if (!_U) { _U = malloc (sizeof (*_U)); memset (_U, 0, sizeof (*_U)); _U->id = id; insert_user (_U); } else { assert (!(_U->flags & FLAG_CREATED)); } struct user *U = (void *)_U; U->flags |= FLAG_CREATED; if (get_peer_id (id) == our_id) { U->flags |= FLAG_USER_SELF; } U->first_name = fetch_str_dup (); U->last_name = fetch_str_dup (); U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); U->access_hash = fetch_long (); U->phone = fetch_str_dup (); if (fetch_int ()) { U->flags |= FLAG_USER_CONTACT; } } rptr = in_ptr; break; case CODE_binlog_user_delete: rptr ++; { peer_id_t id = MK_USER (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->flags |= FLAG_DELETED; } break; case CODE_binlog_set_user_access_token: rptr ++; { peer_id_t id = MK_USER (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->user.access_hash = *(long long *)rptr; rptr += 2; } break; case CODE_binlog_set_user_phone: in_ptr ++; { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); assert (U); if (U->user.phone) { free (U->user.phone); } U->user.phone = fetch_str_dup (); } rptr = in_ptr; break; case CODE_binlog_set_user_friend: rptr ++; { peer_id_t id = MK_USER (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); int friend = *(rptr ++); if (friend) { U->flags |= FLAG_USER_CONTACT; } else { U->flags &= ~FLAG_USER_CONTACT; } } break; case CODE_binlog_user_full_photo: in_ptr ++; { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); assert (U); if (U->flags & FLAG_HAS_PHOTO) { free_photo (&U->user.photo); } fetch_photo (&U->user.photo); } rptr = in_ptr; break; case CODE_binlog_user_blocked: rptr ++; { peer_id_t id = MK_USER (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->user.blocked = *(rptr ++); } break; case CODE_binlog_set_user_full_name: in_ptr ++; { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); assert (U); if (U->user.real_first_name) { free (U->user.real_first_name); } if (U->user.real_last_name) { free (U->user.real_last_name); } U->user.real_first_name = fetch_str_dup (); U->user.real_last_name = fetch_str_dup (); } rptr = in_ptr; break; case CODE_binlog_encr_chat_delete: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *_U = user_chat_get (id); assert (_U); struct secret_chat *U = &_U->encr_chat; memset (U->key, 0, sizeof (U->key)); U->flags |= FLAG_DELETED; U->state = sc_deleted; if (U->nonce) { memset (U->nonce, 0, 256); free (U->nonce); U->nonce = 0; } if (U->g_key) { memset (U->g_key, 0, 256); free (U->g_key); U->g_key = 0; } } break; case CODE_binlog_encr_chat_requested: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *_U = user_chat_get (id); if (!_U) { _U = malloc (sizeof (*_U)); memset (_U, 0, sizeof (*_U)); _U->id = id; insert_encrypted_chat (_U); } else { assert (!(_U->flags & FLAG_CREATED)); } struct secret_chat *U = (void *)_U; U->access_hash = *(long long *)rptr; rptr += 2; U->date = *(rptr ++); U->admin_id = *(rptr ++); U->user_id = *(rptr ++); peer_t *Us = user_chat_get (MK_USER (U->user_id)); if (Us) { U->print_name = create_print_name (id, "!", Us->user.first_name, Us->user.last_name, 0); } else { static char buf[20]; sprintf (buf, "user#%d", U->user_id); U->print_name = create_print_name (id, "!", buf, 0, 0); } U->g_key = malloc (256); U->nonce = malloc (256); memcpy (U->g_key, rptr, 256); rptr += 64; memcpy (U->nonce, rptr, 256); rptr += 64; U->flags |= FLAG_CREATED; U->state = sc_request; } break; case CODE_binlog_set_encr_chat_access_hash: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->encr_chat.access_hash = *(long long *)rptr; rptr += 2; } break; case CODE_binlog_set_encr_chat_date: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->encr_chat.date = *(rptr ++); } break; case CODE_binlog_set_encr_chat_state: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->encr_chat.state = *(rptr ++); } break; case CODE_binlog_encr_chat_accepted: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *_U = user_chat_get (id); assert (_U); struct secret_chat *U = &_U->encr_chat; if (!U->g_key) { U->g_key = malloc (256); } if (!U->nonce) { U->nonce = malloc (256); } memcpy (U->g_key, rptr, 256); rptr += 64; memcpy (U->nonce, rptr, 256); rptr += 64; U->key_fingerprint = *(long long *)rptr; rptr += 2; if (U->state == sc_waiting) { do_create_keys_end (U); } U->state = sc_ok; } break; case CODE_binlog_set_encr_chat_key: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *_U = user_chat_get (id); assert (_U); struct secret_chat *U = &_U->encr_chat; memcpy (U->key, rptr, 256); rptr += 64; U->key_fingerprint = *(long long *)rptr; rptr += 2; } break; case CODE_binlog_set_dh_params: rptr ++; { if (encr_prime) { free (encr_prime); } encr_root = *(rptr ++); encr_prime = malloc (256); memcpy (encr_prime, rptr, 256); rptr += 64; encr_param_version = *(rptr ++); } break; case CODE_binlog_encr_chat_init: rptr ++; { peer_t *P = malloc (sizeof (*P)); memset (P, 0, sizeof (*P)); P->id = MK_ENCR_CHAT (*(rptr ++)); assert (!user_chat_get (P->id)); P->encr_chat.user_id = *(rptr ++); P->encr_chat.admin_id = our_id; insert_encrypted_chat (P); peer_t *Us = user_chat_get (MK_USER (P->encr_chat.user_id)); assert (Us); P->print_name = create_print_name (P->id, "!", Us->user.first_name, Us->user.last_name, 0); memcpy (P->encr_chat.key, rptr, 256); rptr += 64; P->encr_chat.g_key = malloc (256); memcpy (P->encr_chat.g_key, rptr, 256); rptr += 64; P->flags |= FLAG_CREATED; } break; case CODE_binlog_set_pts: rptr ++; pts = *(rptr ++); break; case CODE_binlog_set_qts: rptr ++; qts = *(rptr ++); break; case CODE_binlog_set_date: rptr ++; last_date = *(rptr ++); break; case CODE_binlog_set_seq: rptr ++; seq = *(rptr ++); break; case CODE_binlog_chat_create: in_ptr ++; { peer_id_t id = MK_CHAT (fetch_int ()); peer_t *_C = user_chat_get (id); if (!_C) { _C = malloc (sizeof (*_C)); memset (_C, 0, sizeof (*_C)); _C->id = id; insert_chat (_C); } else { assert (!(_C->flags & FLAG_CREATED)); } struct chat *C = &_C->chat; C->flags = FLAG_CREATED | fetch_int (); C->title = fetch_str_dup (); C->print_title = create_print_name (id, C->title, 0, 0, 0); C->users_num = fetch_int (); C->date = fetch_int (); C->version = fetch_int (); fetch_data (&C->photo_big, sizeof (struct file_location)); fetch_data (&C->photo_small, sizeof (struct file_location)); }; rptr = in_ptr; break; case CODE_binlog_chat_change_flags: rptr ++; { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->flags |= *(rptr ++); C->flags &= ~*(rptr ++); }; break; case CODE_binlog_set_chat_title: in_ptr ++; { peer_t *_C = user_chat_get (MK_CHAT (fetch_int ())); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; if (C->title) { free (C->title); } C->title = fetch_str_dup (); C->print_title = create_print_name (C->id, C->title, 0, 0, 0); }; rptr = in_ptr; break; case CODE_binlog_set_chat_photo: in_ptr ++; { peer_t *C = user_chat_get (MK_CHAT (fetch_int ())); assert (C && (C->flags & FLAG_CREATED)); fetch_data (&C->photo_big, sizeof (struct file_location)); fetch_data (&C->photo_small, sizeof (struct file_location)); }; rptr = in_ptr; break; case CODE_binlog_set_chat_date: rptr ++; { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.date = *(rptr ++); }; break; case CODE_binlog_set_chat_version: rptr ++; { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.version = *(rptr ++); C->chat.users_num = *(rptr ++); }; break; case CODE_binlog_set_chat_admin: rptr ++; { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.admin_id = *(rptr ++); }; break; case CODE_binlog_set_chat_participants: rptr ++; { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.user_list_version = *(rptr ++); C->chat.user_list_size = *(rptr ++); if (C->chat.user_list) { free (C->chat.user_list); } C->chat.user_list = malloc (12 * C->chat.user_list_size); memcpy (C->chat.user_list, rptr, 12 * C->chat.user_list_size); rptr += 3 * C->chat.user_list_size; }; break; case CODE_binlog_chat_full_photo: in_ptr ++; { peer_id_t id = MK_CHAT (fetch_int ()); peer_t *U = user_chat_get (id); assert (U && (U->flags & FLAG_CREATED)); if (U->flags & FLAG_HAS_PHOTO) { free_photo (&U->chat.photo); } fetch_photo (&U->chat.photo); } rptr = in_ptr; break; case CODE_binlog_add_chat_participant: rptr ++; { peer_id_t id = MK_CHAT (*(rptr ++)); peer_t *_C = user_chat_get (id); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; int version = *(rptr ++); int user = *(rptr ++); int inviter = *(rptr ++); int date = *(rptr ++); assert (C->user_list_version < version); int i; for (i = 0; i < C->user_list_size; i++) { assert (C->user_list[i].user_id != user); } C->user_list_size ++; C->user_list = realloc (C->user_list, 12 * C->user_list_size); C->user_list[C->user_list_size - 1].user_id = user; C->user_list[C->user_list_size - 1].inviter_id = inviter; C->user_list[C->user_list_size - 1].date = date; C->user_list_version = version; } break; case CODE_binlog_del_chat_participant: rptr ++; { peer_id_t id = MK_CHAT (*(rptr ++)); peer_t *_C = user_chat_get (id); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; int version = *(rptr ++); int user = *(rptr ++); assert (C->user_list_version < version); int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { struct chat_user t; t = C->user_list[i]; C->user_list[i] = C->user_list[C->user_list_size - 1]; C->user_list[C->user_list_size - 1] = t; } } assert (C->user_list[C->user_list_size - 1].user_id == user); C->user_list_size --; C->user_list = realloc (C->user_list, 12 * C->user_list_size); C->user_list_version = version; } break; case CODE_binlog_create_message_text: case CODE_binlog_send_message_text: in_ptr ++; { long long id; if (op == CODE_binlog_create_message_text) { id = fetch_int (); } else { id = fetch_long (); } struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); if (t == PEER_ENCR_CHAT) { M->flags |= FLAG_ENCRYPTED; } M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); int l = prefetch_strlen (); M->message = malloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; if (t == PEER_ENCR_CHAT) { M->media.type = CODE_decrypted_message_media_empty; } else { M->media.type = CODE_message_media_empty; } M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); if (op == CODE_binlog_send_message_text) { message_insert_unsent (M); M->flags |= FLAG_PENDING; } } rptr = in_ptr; break; case CODE_binlog_create_message_text_fwd: in_ptr ++; { int id = fetch_int (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); M->fwd_from_id = MK_USER (fetch_int ()); M->fwd_date = fetch_int (); int l = prefetch_strlen (); M->message = malloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; M->media.type = CODE_message_media_empty; M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_create_message_media: in_ptr ++; { int id = fetch_int (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); int l = prefetch_strlen (); M->message = malloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; fetch_message_media (&M->media); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_create_message_media_encr: in_ptr ++; { long long id = fetch_long (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); int l = prefetch_strlen (); M->message = malloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; fetch_message_media_encrypted (&M->media); fetch_encrypted_message_file (&M->media); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_create_message_media_fwd: in_ptr ++; { int id = fetch_int (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); M->fwd_from_id = MK_USER (fetch_int ()); M->fwd_date = fetch_int (); int l = prefetch_strlen (); M->message = malloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; fetch_message_media (&M->media); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_create_message_service: in_ptr ++; { int id = fetch_int (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); fetch_message_action (&M->action); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; M->service = 1; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_create_message_service_encr: in_ptr ++; { long long id = fetch_long (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); fetch_message_action_encrypted (&M->action); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; M->service = 1; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_create_message_service_fwd: in_ptr ++; { int id = fetch_int (); struct message *M = message_get (id); if (!M) { M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; M->from_id = MK_USER (fetch_int ()); int t = fetch_int (); M->to_id = set_peer_id (t, fetch_int ()); M->date = fetch_int (); M->fwd_from_id = MK_USER (fetch_int ()); M->fwd_date = fetch_int (); fetch_message_action (&M->action); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; M->service = 1; message_insert (M); } rptr = in_ptr; break; case CODE_binlog_set_unread: rptr ++; { struct message *M = message_get (*(rptr ++)); assert (M); M->unread = 0; } break; case CODE_binlog_set_message_sent: rptr ++; { struct message *M = message_get (*(long long *)rptr); rptr += 2; assert (M); message_remove_unsent (M); M->flags &= ~FLAG_PENDING; } break; case CODE_binlog_set_msg_id: rptr ++; { struct message *M = message_get (*(long long *)rptr); rptr += 2; assert (M); if (M->flags & FLAG_PENDING) { message_remove_unsent (M); M->flags &= ~FLAG_PENDING; } message_remove_tree (M); message_del_peer (M); M->id = *(rptr ++); if (message_get (M->id)) { free_message (M); free (M); } else { message_insert_tree (M); message_add_peer (M); } } break; case CODE_binlog_delete_msg: rptr ++; { struct message *M = message_get (*(long long *)rptr); rptr += 2; assert (M); if (M->flags & FLAG_PENDING) { message_remove_unsent (M); M->flags &= ~FLAG_PENDING; } message_remove_tree (M); message_del_peer (M); free_message (M); free (M); } break; case CODE_update_user_photo: case CODE_update_user_name: work_update_binlog (); rptr = in_ptr; break; default: logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(rptr - 1), op, *(rptr + 1), binlog_pos); assert (0); }