/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if defined(WIN32) || defined(_WIN32) #include #include #include #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #include #include #else #include #include #endif #include #include #include #include #include #include #include #include #include #include #include "tgl-binlog.h" #include "mtproto-common.h" //#include "net.h" #include "mtproto-client.h" #include "mtproto-utils.h" #include "tgl.h" #include "auto.h" #include "auto/auto-types.h" #include "auto/auto-skip.h" #include "auto/auto-store-ds.h" #include "auto/auto-fetch-ds.h" #include "auto/auto-free-ds.h" #include "tgl-structures.h" #include "tgl-methods-in.h" #include #define BINLOG_BUFFER_SIZE (1 << 20) static int binlog_buffer[BINLOG_BUFFER_SIZE]; static int *rptr; static int *wptr; //static int TLS->binlog_fd; static int in_replay_log; // should be used ONLY for DEBUG #define MAX_LOG_EVENT_SIZE (1 << 17) char *get_binlog_file_name (void); static void *alloc_log_event (int l) { return binlog_buffer; } static int mystreq1 (const char *a, const char *b, int l) { if ((int)strlen (a) != l) { return 1; } return memcmp (a, b, l); } static long long binlog_pos; static int fetch_comb_binlog_start (struct tgl_state *TLS, void *extra) { return 0; } /* {{{ DC option */ static int fetch_comb_binlog_dc_option (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { vlogprintf (E_NOTICE, "DC%d '%.*s' update: %.*s:%d\n", DS_LVAL (DS_U->dc), DS_RSTR (DS_U->name), DS_RSTR (DS_U->ip), DS_LVAL (DS_U->port) ); tglmp_alloc_dc (TLS, 0, DS_LVAL (DS_U->dc), DS_STR_DUP (DS_U->ip), DS_LVAL (DS_U->port) ); return 0; } static int fetch_comb_binlog_dc_option_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { vlogprintf (E_NOTICE, "DC%d '%.*s' update: %.*s:%d\n", DS_LVAL (DS_U->dc), DS_RSTR (DS_U->name), DS_RSTR (DS_U->ip), DS_LVAL (DS_U->port) ); tglmp_alloc_dc (TLS, DS_LVAL (DS_U->flags), DS_LVAL (DS_U->dc), DS_STR_DUP (DS_U->ip), DS_LVAL (DS_U->port) ); return 0; } /* }}} */ /* {{{ Auth key */ static int fetch_comb_binlog_auth_key (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { int num = DS_LVAL (DS_U->dc); assert (num > 0 && num <= MAX_DC_ID); assert (TLS->DC_list[num]); tglf_fetch_int_tuple ((void *)TLS->DC_list[num]->auth_key, DS_U->key->key, 64); static unsigned char sha1_buffer[20]; SHA1 ((void *)TLS->DC_list[num]->auth_key, 256, sha1_buffer); TLS->DC_list[num]->auth_key_id = *(long long *)(sha1_buffer + 12); TLS->DC_list[num]->flags |= TGLDCF_AUTHORIZED; return 0; } /* }}} */ /* {{{ Default dc */ static int fetch_comb_binlog_default_dc (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { int num = DS_LVAL (DS_U->dc); assert (num > 0 && num <= MAX_DC_ID); TLS->DC_working = TLS->DC_list[num]; TLS->dc_working_num = num; return 0; } /* }}} */ /* {{{ DC signed */ static int fetch_comb_binlog_dc_signed (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { int num = DS_LVAL (DS_U->dc); assert (num > 0 && num <= MAX_DC_ID); assert (TLS->DC_list[num]); TLS->DC_list[num]->flags |= TGLDCF_LOGGED_IN; return 0; } /* }}} */ /* {{{ our user_id */ static int fetch_comb_binlog_our_id (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { TLS->our_id = DS_LVAL (DS_U->id); assert (TLS->our_id > 0); if (TLS->callback.our_id) { TLS->callback.our_id (TLS, TLS->our_id); } return 0; } /* }}} */ /* {{{ Set DH params */ static int fetch_comb_binlog_set_dh_params (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { if (TLS->encr_prime) { tfree (TLS->encr_prime, 256); BN_free (TLS->encr_prime_bn); } TLS->encr_root = DS_LVAL (DS_U->root); TLS->encr_prime = talloc (256); tglf_fetch_int_tuple ((void *)TLS->encr_prime, DS_U->prime->key, 64); TLS->encr_prime_bn = BN_new (); BN_bin2bn ((void *)TLS->encr_prime, 256, TLS->encr_prime_bn); TLS->encr_param_version = DS_LVAL (DS_U->version); assert (tglmp_check_DH_params (TLS, TLS->encr_prime_bn, TLS->encr_root) >= 0); return 0; } /* }}} */ /* {{{ Set pts, qts, date, seq */ static int fetch_comb_binlog_set_pts (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { TLS->pts = DS_LVAL (DS_U->pts); return 0; } static int fetch_comb_binlog_set_qts (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { TLS->qts = DS_LVAL (DS_U->qts); return 0; } static int fetch_comb_binlog_set_date (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { TLS->date = DS_LVAL (DS_U->date); return 0; } static int fetch_comb_binlog_set_seq (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { TLS->seq = DS_LVAL (DS_U->seq); return 0; } /* }}} */ /* {{{ delete user */ static int fetch_comb_binlog_user_delete (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_USER (DS_LVAL (DS_U->id)); tgl_peer_t *U = tgl_peer_get (TLS, id); assert (U); U->flags |= TGLUF_DELETED; if (TLS->callback.user_update) { TLS->callback.user_update (TLS, (void *)U, TGL_UPDATE_DELETED); } return 0; } /* }}} */ /* {{{ delete secret chat */ static int fetch_comb_binlog_encr_chat_delete (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_U->id)); tgl_peer_t *_U = tgl_peer_get (TLS, id); assert (_U); struct tgl_secret_chat *U = &_U->encr_chat; memset (U->key, 0, sizeof (U->key)); U->flags |= TGLPF_DELETED; U->state = sc_deleted; if (U->g_key) { tfree_secure (U->g_key, 256); U->g_key = 0; } if (TLS->callback.secret_chat_update) { TLS->callback.secret_chat_update (TLS, U, TGL_UPDATE_DELETED); } return 0; } /* }}} */ static int fetch_comb_binlog_user_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_USER (DS_LVAL (DS_U->id)); tgl_peer_t *_U = tgl_peer_get (TLS, id); int flags = DS_LVAL (DS_U->flags); unsigned updates = 0; if (flags & TGLPF_CREATE) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = id; tglp_insert_encrypted_chat (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_user *U = (void *)_U; if ((flags & 0xff) != (U->flags & 0xff)) { updates |= TGL_UPDATE_FLAGS; } U->flags = flags & 0xffff; if (DS_U->access_hash) { U->access_hash = DS_LVAL (DS_U->access_hash); updates |= TGL_UPDATE_ACCESS_HASH; } if (DS_U->first_name) { if (U->first_name) { tfree_str (U->first_name); } U->first_name = DS_STR_DUP (DS_U->first_name); if (U->last_name) { tfree_str (U->last_name); } U->last_name = DS_STR_DUP (DS_U->last_name); updates |= TGL_UPDATE_NAME; if (U->print_name) { tglp_peer_delete_name (TLS, (void *)U); tfree_str (U->print_name); } U->print_name = TLS->callback.create_print_name (TLS, U->id, U->first_name, U->last_name, 0, 0); tglp_peer_insert_name (TLS, (void *)U); } if (DS_U->phone) { if (U->phone) { tfree_str (U->phone); } U->phone = DS_STR_DUP (DS_U->phone); updates |= TGL_UPDATE_PHONE; } if (DS_U->username) { if (U->username) { tfree_str (U->username); } U->username = DS_STR_DUP (DS_U->username); updates |= TGL_UPDATE_USERNAME; } if (DS_U->photo) { if (U->photo) { tgls_free_photo (TLS, U->photo); } U->photo = tglf_fetch_alloc_photo_new (TLS, DS_U->photo); U->flags |= TGLUF_HAS_PHOTO; //updates |= TGL_UPDATE_PHOTO; } if (DS_U->user_photo) { U->photo_id = DS_LVAL (DS_U->user_photo->photo_id); tglf_fetch_file_location_new (TLS, &U->photo_big, DS_U->user_photo->photo_big); tglf_fetch_file_location_new (TLS, &U->photo_small, DS_U->user_photo->photo_small); updates |= TGL_UPDATE_PHOTO; } if (DS_U->real_first_name) { if (U->real_first_name) { tfree_str (U->real_first_name); } U->real_first_name = DS_STR_DUP (DS_U->real_first_name); if (U->real_last_name) { tfree_str (U->real_last_name); } U->real_last_name = DS_STR_DUP (DS_U->real_last_name); updates |= TGL_UPDATE_REAL_NAME; } if (DS_U->last_read_in) { U->last_read_in = DS_LVAL (DS_U->last_read_in); tgls_messages_mark_read (TLS, U->last, 0, U->last_read_in); } if (DS_U->last_read_out) { U->last_read_out = DS_LVAL (DS_U->last_read_out); tgls_messages_mark_read (TLS, U->last, TGLMF_OUT, U->last_read_out); } if (DS_U->bot_info) { if (U->bot_info) { tgls_free_bot_info (TLS, U->bot_info); } U->bot_info = tglf_fetch_alloc_bot_info (TLS, DS_U->bot_info); } if (TLS->callback.user_update && updates) { TLS->callback.user_update (TLS, U, updates); } return 0; } static int fetch_comb_binlog_encr_chat_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_U->id)); tgl_peer_t *_U = tgl_peer_get (TLS, id); int flags = DS_LVAL (DS_U->flags); unsigned updates = 0; if (flags & TGLPF_CREATE) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = id; tglp_insert_encrypted_chat (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_secret_chat *U = (void *)_U; if ((flags & 0xff) != (U->flags & 0xff)) { updates |= TGL_UPDATE_FLAGS; } U->flags = flags & 0xffff; if (DS_U->access_hash) { U->access_hash = DS_LVAL (DS_U->access_hash); updates |= TGL_UPDATE_ACCESS_HASH; } if (DS_U->date) { U->date = DS_LVAL (DS_U->date); } if (DS_U->admin) { U->admin_id = DS_LVAL (DS_U->admin); } if (DS_U->user_id) { U->user_id = DS_LVAL (DS_U->user_id); } if (DS_U->key_fingerprint) { U->key_fingerprint = DS_LVAL (DS_U->key_fingerprint); } if (DS_U->in_seq_no) { U->in_seq_no = DS_LVAL (DS_U->in_seq_no); U->out_seq_no = DS_LVAL (DS_U->out_seq_no); U->last_in_seq_no = DS_LVAL (DS_U->last_in_seq_no); } tgl_peer_t *Us = tgl_peer_get (TLS, TGL_MK_USER (U->user_id)); if (!U->print_name) { if (Us) { U->print_name = TLS->callback.create_print_name (TLS, id, "!", Us->user.first_name, Us->user.last_name, 0); } else { static char buf[100]; tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = TLS->callback.create_print_name (TLS, id, "!", buf, 0, 0); } tglp_peer_insert_name (TLS, (void *)U); } if (DS_U->g_key) { if (!U->g_key) { U->g_key = talloc (256); } tglf_fetch_int_tuple ((void *)U->g_key, DS_U->g_key->key, 64); } if (DS_U->key) { tglf_fetch_int_tuple (U->key, DS_U->key->key, 64); } if (DS_U->state) { if (U->state == sc_waiting && DS_LVAL (DS_U->state) == sc_ok) { tgl_do_create_keys_end (TLS, U); } if ((int)U->state != DS_LVAL (DS_U->state)) { switch (DS_LVAL (DS_U->state)) { case sc_request: updates |= TGL_UPDATE_REQUESTED; break; case sc_ok: updates |= TGL_UPDATE_WORKING; vlogprintf (E_WARNING, "Secret chat in ok state\n"); break; default: break; } } U->state = DS_LVAL (DS_U->state); } if (TLS->callback.secret_chat_update && updates) { TLS->callback.secret_chat_update (TLS, U, updates); } return 0; } static int fetch_comb_binlog_chat_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_CHAT (DS_LVAL (DS_U->id)); tgl_peer_t *_U = tgl_peer_get (TLS, id); int flags = DS_LVAL (DS_U->flags); unsigned updates = 0; if (flags & (1 << 16)) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = id; tglp_insert_chat (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_chat *C = &_U->chat; if ((flags & 0xff) != (C->flags & 0xff)) { updates |= TGL_UPDATE_FLAGS; } C->flags = flags & 0xffff; if (DS_U->title) { if (C->title) { tfree_str (C->title); } C->title = DS_STR_DUP (DS_U->title); if (C->print_title) { tglp_peer_delete_name (TLS, (void *)C); tfree_str (C->print_title); } C->print_title = TLS->callback.create_print_name (TLS, C->id, C->title, 0, 0, 0); tglp_peer_insert_name (TLS, (void *)C); updates |= TGL_UPDATE_TITLE; } if (DS_U->user_num) { C->users_num = DS_LVAL (DS_U->user_num); } if (DS_U->date) { C->date = DS_LVAL (DS_U->date); } if (DS_U->chat_photo) { tglf_fetch_file_location_new (TLS, &C->photo_big, DS_U->chat_photo->photo_big); tglf_fetch_file_location_new (TLS, &C->photo_small, DS_U->chat_photo->photo_small); updates |= TGL_UPDATE_PHOTO; } if (DS_U->photo) { if (C->photo) { tgls_free_photo (TLS, C->photo); } C->photo = tglf_fetch_alloc_photo_new (TLS, DS_U->photo); C->flags |= TGLPF_HAS_PHOTO; updates |= TGL_UPDATE_PHOTO; } if (DS_U->admin) { C->admin_id = DS_LVAL (DS_U->admin); updates |= TGL_UPDATE_ADMIN; } if (DS_U->version) { C->version = DS_LVAL (DS_U->version); if (C->user_list) { tfree (C->user_list, 12 * C->user_list_size); } C->user_list_size = DS_LVAL (DS_U->participants->cnt); C->user_list = talloc (12 * C->user_list_size); int i; for (i = 0; i < C->user_list_size; i++) { C->user_list[i].user_id = DS_LVAL (DS_U->participants->data[i]->user_id); C->user_list[i].inviter_id = DS_LVAL (DS_U->participants->data[i]->inviter_id); C->user_list[i].date = DS_LVAL (DS_U->participants->data[i]->date); } updates |= TGL_UPDATE_MEMBERS; } if (DS_U->last_read_in) { C->last_read_in = DS_LVAL (DS_U->last_read_in); tgls_messages_mark_read (TLS, C->last, 0, C->last_read_in); } if (DS_U->last_read_out) { C->last_read_out = DS_LVAL (DS_U->last_read_out); tgls_messages_mark_read (TLS, C->last, TGLMF_OUT, C->last_read_out); } if (TLS->callback.chat_update && updates) { TLS->callback.chat_update (TLS, C, updates); } return 0; } static int fetch_comb_binlog_chat_add_participant (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_CHAT (DS_LVAL (DS_U->id)); tgl_peer_t *_C = tgl_peer_get (TLS, id); assert (_C && (_C->flags & TGLPF_CREATED)); struct tgl_chat *C = &_C->chat; int version = DS_LVAL (DS_U->version); int user = DS_LVAL (DS_U->user_id); int inviter = DS_LVAL (DS_U->inviter_id); int date = DS_LVAL (DS_U->date); if (C->user_list_version > version) { return 0; } int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { return 0; } } C->user_list_size ++; C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 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; if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS); } return 0; } static int fetch_comb_binlog_chat_del_participant (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_id_t id = TGL_MK_CHAT (DS_LVAL (DS_U->id)); tgl_peer_t *_C = tgl_peer_get (TLS, id); assert (_C && (_C->flags & TGLPF_CREATED)); struct tgl_chat *C = &_C->chat; int version = DS_LVAL (DS_U->version); int user = DS_LVAL (DS_U->user_id); if (C->user_list_version > version) { return 0; } int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { struct tgl_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; } } if (C->user_list[C->user_list_size - 1].user_id != user) { return 0; } assert (C->user_list[C->user_list_size - 1].user_id == user); C->user_list_size --; C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); C->user_list_version = version; if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS); } return 0; } static int fetch_comb_binlog_message_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->lid)); int flags = DS_LVAL (DS_U->flags); if (flags & (1 << 16)) { if (!M) { M = tglm_message_alloc (TLS, DS_LVAL (DS_U->lid)); } assert (!(M->flags & TGLMF_CREATED)); } else { assert (M->flags & TGLMF_CREATED); } assert (flags & TGLMF_CREATED); assert (!(M->flags & TGLMF_ENCRYPTED)); assert (!(flags & TGLMF_ENCRYPTED)); if ((M->flags & TGLMF_PENDING) && !(flags & TGLMF_PENDING)){ tglm_message_remove_unsent (TLS, M); } if (!(M->flags & TGLMF_PENDING) && (flags & TGLMF_PENDING)){ tglm_message_insert_unsent (TLS, M); } if ((M->flags & TGLMF_UNREAD) && !(flags & TGLMF_UNREAD)) { M->flags = (flags & 0xffff) | TGLMF_UNREAD; } else { M->flags = (flags & 0xffff); } if (DS_U->from_id) { M->from_id = TGL_MK_USER (DS_LVAL (DS_U->from_id)); } if (DS_U->to_type) { assert (flags & 0x10000); M->to_id = tgl_set_peer_id (DS_LVAL (DS_U->to_type), DS_LVAL (DS_U->to_id)); assert (DS_LVAL (DS_U->to_type) != TGL_PEER_ENCR_CHAT); } if (DS_U->date) { M->date = DS_LVAL (DS_U->date); } if (DS_U->fwd_from_id) { M->fwd_from_id = TGL_MK_USER (DS_LVAL (DS_U->fwd_from_id)); M->fwd_date = DS_LVAL (DS_U->fwd_date); } if (DS_U->action) { tglf_fetch_message_action_new (TLS, &M->action, DS_U->action); M->flags |= TGLMF_SERVICE; } if (DS_U->message) { M->message_len = DS_U->message->len; M->message = DS_STR_DUP (DS_U->message); assert (!(M->flags & TGLMF_SERVICE)); } if (DS_U->media) { tglf_fetch_message_media_new (TLS, &M->media, DS_U->media); assert (!(M->flags & TGLMF_SERVICE)); } if (DS_U->reply_id) { M->reply_id = DS_LVAL (DS_U->reply_id); } if (flags & 0x10000) { tglm_message_insert (TLS, M); } if (!(flags & TGLMF_UNREAD) && (M->flags & TGLMF_UNREAD)) { tgls_messages_mark_read (TLS, M, M->flags & TGLMF_OUT, M->id); } if (DS_U->reply_markup) { M->reply_markup = tglf_fetch_alloc_reply_markup (TLS, M->next, DS_U->reply_markup); } return 0; } static int fetch_comb_binlog_message_encr_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->lid)); int flags = DS_LVAL (DS_U->flags); if (flags & (1 << 16)) { if (!M) { M = tglm_message_alloc (TLS, DS_LVAL (DS_U->lid)); } else { assert (!(M->flags & TGLMF_CREATED)); } assert (!(M->flags & TGLMF_CREATED)); } else { assert (M->flags & TGLMF_CREATED); } assert (flags & TGLMF_CREATED); assert (flags & TGLMF_ENCRYPTED); if ((M->flags & TGLMF_PENDING) && !(flags & TGLMF_PENDING)){ tglm_message_remove_unsent (TLS, M); } if (!(M->flags & TGLMF_PENDING) && (flags & TGLMF_PENDING)){ tglm_message_insert_unsent (TLS, M); } M->flags = flags & 0xffff; if (DS_U->from_id) { M->from_id = TGL_MK_USER (DS_LVAL (DS_U->from_id)); } if (DS_U->to_type) { assert (flags & 0x10000); M->to_id = tgl_set_peer_id (DS_LVAL (DS_U->to_type), DS_LVAL (DS_U->to_id)); } if (DS_U->date) { M->date = DS_LVAL (DS_U->date); } struct tgl_secret_chat *E = (void *)tgl_peer_get (TLS, M->to_id); assert (E); if (DS_U->message) { M->message_len = DS_U->message->len; M->message = DS_STR_DUP (DS_U->message); assert (!(M->flags & TGLMF_SERVICE)); } if (DS_U->encr_media) { tglf_fetch_message_media_encrypted_new (TLS, &M->media, DS_U->encr_media); assert (!(M->flags & TGLMF_SERVICE)); } if (DS_U->encr_action) { tglf_fetch_message_action_encrypted_new (TLS, &M->action, DS_U->encr_action); M->flags |= TGLMF_SERVICE; } if (DS_U->file) { tglf_fetch_encrypted_message_file_new (TLS, &M->media, DS_U->file); assert (!(M->flags & TGLMF_SERVICE)); } if (DS_U->encr_action && !(M->flags & TGLMF_OUT) && M->action.type == tgl_message_action_notify_layer) { E->layer = M->action.layer; } if ((flags & TGLMF_CREATE) && (flags & TGLMF_OUT)) { E->out_seq_no ++; } if (flags & 0x10000) { tglm_message_insert (TLS, M); } return 0; } static int fetch_comb_binlog_set_msg_id (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->old_id)); assert (M); if (M->flags & TGLMF_PENDING) { tglm_message_remove_unsent (TLS, M); M->flags &= ~TGLMF_PENDING; } tglm_message_remove_tree (TLS, M); tglm_message_del_peer (TLS, M); M->id = DS_LVAL (DS_U->new_id); if (tgl_message_get (TLS, M->id)) { tglm_message_del_use (TLS, M); tgls_free_message (TLS, M); } else { tglm_message_insert_tree (TLS, M); tglm_message_add_peer (TLS, M); } return 0; } static int fetch_comb_binlog_message_delete (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->lid)); assert (M); if (M->flags & TGLMF_PENDING) { tglm_message_remove_unsent (TLS, M); M->flags &= ~TGLMF_PENDING; } tglm_message_remove_tree (TLS, M); tglm_message_del_peer (TLS, M); tglm_message_del_use (TLS, M); tgls_free_message (TLS, M); return 0; } static int fetch_comb_binlog_msg_update (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->lid)); if (!M) { return 0; } assert (M); if (!(M->flags & TGLMF_ENCRYPTED)) { if (TLS->max_msg_id < M->id) { TLS->max_msg_id = M->id; } } if (TLS->callback.msg_receive) { TLS->callback.msg_receive (TLS, M); } return 0; } static int fetch_comb_binlog_reset_authorization (struct tgl_state *TLS, void *extra) { int i; for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) { struct tgl_dc *D = TLS->DC_list[i]; D->flags = 0; D->state = st_init; D->auth_key_id = D->temp_auth_key_id = 0; } TLS->seq = 0; TLS->qts = 0; return 0; } static int fetch_comb_binlog_encr_chat_exchange_new (struct tgl_state *TLS, struct tl_ds_binlog_update *DS_U) { tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (DS_LVAL (DS_U->id))); assert (P); if (DS_U->state) { P->encr_chat.exchange_state = DS_LVAL (DS_U->state); } if (DS_U->exchange_id) { P->encr_chat.exchange_id = DS_LVAL (DS_U->exchange_id); } static unsigned char sha_buffer[20]; switch (P->encr_chat.exchange_state) { case tgl_sce_requested: tglf_fetch_int_tuple (P->encr_chat.exchange_key, DS_U->key->key, 64); break; case tgl_sce_accepted: tglf_fetch_int_tuple (P->encr_chat.exchange_key, DS_U->key->key, 64); SHA1 ((unsigned char *)P->encr_chat.exchange_key, 256, sha_buffer); P->encr_chat.exchange_key_fingerprint = *(long long *)(sha_buffer + 12); break; case tgl_sce_committed: memcpy (P->encr_chat.exchange_key, P->encr_chat.key, 256); P->encr_chat.exchange_key_fingerprint = P->encr_chat.key_fingerprint; tglf_fetch_int_tuple (P->encr_chat.key, DS_U->key->key, 64); SHA1 ((unsigned char *)P->encr_chat.key, 256, sha_buffer); P->encr_chat.key_fingerprint = *(long long *)(sha_buffer + 12); break; case tgl_sce_confirmed: P->encr_chat.exchange_state = tgl_sce_none; if (P->encr_chat.exchange_state != tgl_sce_committed) { memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256); P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint; } break; case tgl_sce_aborted: P->encr_chat.exchange_state = tgl_sce_none; if (P->encr_chat.exchange_state == tgl_sce_committed) { memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256); P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint; } break; default: assert (0); } return 0; } #define FETCH_COMBINATOR_FUNCTION(NAME) \ case CODE_ ## NAME:\ ok = fetch_comb_ ## NAME (TLS, DS_U); \ break; \ static void replay_log_event (struct tgl_state *TLS) { assert (rptr < wptr); int op = *rptr; vlogprintf (E_DEBUG, "replay_log_event: log_pos=%"_PRINTF_INT64_"d, op=0x%08x\n", binlog_pos, op); in_ptr = rptr; in_end = wptr; if (skip_type_any (TYPE_TO_PARAM (binlog_update)) < 0) { vlogprintf (E_ERROR, "Can not replay at %"_PRINTF_INT64_"d (magic = 0x%08x)\n", binlog_pos, *rptr); assert (0); } int *end = in_ptr; in_end = in_ptr; in_ptr = rptr; struct tl_ds_binlog_update *DS_U = fetch_ds_type_binlog_update (TYPE_TO_PARAM (binlog_update)); assert (in_ptr == end); int ok = -1; switch (op) { FETCH_COMBINATOR_FUNCTION (binlog_start) FETCH_COMBINATOR_FUNCTION (binlog_dc_option) FETCH_COMBINATOR_FUNCTION (binlog_dc_option_new) FETCH_COMBINATOR_FUNCTION (binlog_auth_key) FETCH_COMBINATOR_FUNCTION (binlog_default_dc) FETCH_COMBINATOR_FUNCTION (binlog_dc_signed) FETCH_COMBINATOR_FUNCTION (binlog_our_id) FETCH_COMBINATOR_FUNCTION (binlog_set_dh_params) FETCH_COMBINATOR_FUNCTION (binlog_set_pts) FETCH_COMBINATOR_FUNCTION (binlog_set_qts) FETCH_COMBINATOR_FUNCTION (binlog_set_date) FETCH_COMBINATOR_FUNCTION (binlog_set_seq) FETCH_COMBINATOR_FUNCTION (binlog_user_new) FETCH_COMBINATOR_FUNCTION (binlog_user_delete) FETCH_COMBINATOR_FUNCTION (binlog_chat_new) //FETCH_COMBINATOR_FUNCTION (binlog_chat_delete) FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_new) FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_delete) FETCH_COMBINATOR_FUNCTION (binlog_chat_add_participant) FETCH_COMBINATOR_FUNCTION (binlog_chat_del_participant) FETCH_COMBINATOR_FUNCTION (binlog_message_new) FETCH_COMBINATOR_FUNCTION (binlog_message_encr_new) FETCH_COMBINATOR_FUNCTION (binlog_message_delete) FETCH_COMBINATOR_FUNCTION (binlog_set_msg_id) FETCH_COMBINATOR_FUNCTION (binlog_encr_chat_exchange_new) FETCH_COMBINATOR_FUNCTION (binlog_msg_update) FETCH_COMBINATOR_FUNCTION (binlog_reset_authorization) default: vlogprintf (E_ERROR, "Unknown op 0x%08x\n", op); assert (0); } assert (ok >= 0); free_ds_type_binlog_update (DS_U, TYPE_TO_PARAM (binlog_update)); assert (in_ptr == end); //assert (in_ptr == in_end); binlog_pos += (in_ptr - rptr) * 4; rptr = in_ptr; } static void create_new_binlog (struct tgl_state *TLS) { clear_packet (); //static int s[1000]; //packet_ptr = s; out_int (CODE_binlog_start); if (TLS->test_mode) { out_int (CODE_binlog_dc_option); out_int (1); out_string (""); out_string (TG_SERVER_TEST_1); out_int (443); out_int (CODE_binlog_dc_option); out_int (2); out_string (""); out_string (TG_SERVER_TEST_2); out_int (443); out_int (CODE_binlog_dc_option); out_int (3); out_string (""); out_string (TG_SERVER_TEST_3); out_int (443); out_int (CODE_binlog_default_dc); out_int (2); } else { out_int (CODE_binlog_dc_option); out_int (1); out_string (""); out_string (TG_SERVER_1); out_int (443); out_int (CODE_binlog_dc_option); out_int (2); out_string (""); out_string (TG_SERVER_2); out_int (443); out_int (CODE_binlog_dc_option); out_int (3); out_string (""); out_string (TG_SERVER_3); out_int (443); out_int (CODE_binlog_dc_option); out_int (4); out_string (""); out_string (TG_SERVER_4); out_int (443); out_int (CODE_binlog_dc_option); out_int (5); out_string (""); out_string (TG_SERVER_5); out_int (443); out_int (CODE_binlog_default_dc); out_int (2); } #if defined(_MSC_VER) && _MSC_VER >= 1400 int fd = 0; if(_sopen_s (&fd, TLS->binlog_name, _O_WRONLY | _O_EXCL | _O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0 ) { #else int fd = open (TLS->binlog_name, O_WRONLY | O_EXCL | O_CREAT, 0600); if (fd < 0) { #endif perror ("Write new binlog"); exit (2); } assert (write (fd, packet_buffer, (packet_ptr - packet_buffer) * 4) == (packet_ptr - packet_buffer) * 4); close (fd); } void tgl_replay_log (struct tgl_state *TLS) { if (!TLS->binlog_enabled) { return; } #if defined(WIN32) || defined(_WIN32) if (INVALID_FILE_ATTRIBUTES == GetFileAttributesA (TLS->binlog_name) && GetLastError () == ERROR_FILE_NOT_FOUND) { #else if (access (TLS->binlog_name, F_OK) < 0) { #endif printf ("No binlog found. Creating new one\n"); create_new_binlog (TLS); } #if defined(_MSC_VER) && _MSC_VER >= 1400 int fd = 0; if (_sopen_s(&fd, TLS->binlog_name, _O_RDONLY | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0) { #elif defined(WIN32) || defined(_WIN32) int fd = open (TLS->binlog_name, O_RDONLY | O_BINARY); if (fd < 0) { #else int fd = open (TLS->binlog_name, O_RDONLY); if (fd < 0) { #endif perror ("binlog open"); exit (2); } int end = 0; in_replay_log = 1; while (1) { if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) { if (wptr == rptr) { wptr = rptr = binlog_buffer; } else { int x = wptr - rptr; memcpy (binlog_buffer, rptr, 4 * x); wptr -= (rptr - binlog_buffer); rptr = binlog_buffer; } int l = (binlog_buffer + BINLOG_BUFFER_SIZE - wptr) * 4; int k = read (fd, wptr, l); if (k < 0) { perror ("read binlog"); exit (2); } assert (!(k & 3)); if (k < l) { end = 1; } wptr += (k / 4); } if (wptr == rptr) { break; } replay_log_event (TLS); } in_replay_log = 0; close (fd); } //static int b_packet_buffer[PACKET_BUFFER_SIZE]; void tgl_reopen_binlog_for_writing (struct tgl_state *TLS) { #if defined(_MSC_VER) && _MSC_VER >= 1400 if (_sopen_s (&TLS->binlog_fd, TLS->binlog_name, _O_WRONLY | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0) { #elif defined(WIN32) || defined(_WIN32) TLS->binlog_fd = open (TLS->binlog_name, O_WRONLY | _O_BINARY); if (TLS->binlog_fd < 0) { #else TLS->binlog_fd = open (TLS->binlog_name, O_WRONLY); if (TLS->binlog_fd < 0) { #endif perror ("binlog open"); exit (2); } assert (lseek (TLS->binlog_fd, binlog_pos, SEEK_SET) == binlog_pos); #if defined(WIN32) || defined(_WIN32) HANDLE h = INVALID_HANDLE_VALUE; DWORD size_lower, size_upper; DWORD err = 0; OVERLAPPED ovlp; int flags = 0; h = (HANDLE)_get_osfhandle(TLS->binlog_fd); if (h == INVALID_HANDLE_VALUE) { errno = EBADF; goto error; } size_lower = GetFileSize (h, &size_upper); if (size_lower == INVALID_FILE_SIZE) { goto get_err; } memset (&ovlp, 0, sizeof ovlp); flags |= LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY; if (!LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp)) { goto get_err; } return; error: perror ("get lock"); exit(2); get_err: err = GetLastError(); switch (err) { case ERROR_LOCK_VIOLATION: errno = EAGAIN; break; case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; case ERROR_BAD_COMMAND: errno = EINVAL; break; default: errno = err; } goto error; #else if (flock (TLS->binlog_fd, LOCK_EX | LOCK_NB) < 0) { perror ("get lock"); exit (2); } #endif } static void add_log_event (struct tgl_state *TLS, const int *data, int len) { vlogprintf (E_DEBUG, "Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert (!(len & 3)); int *ev = talloc (len); memcpy (ev, data, len); rptr = (void *)ev; wptr = rptr + (len / 4); int *in = in_ptr; int *end = in_end; replay_log_event (TLS); if (rptr != wptr) { vlogprintf (E_ERROR, "Unread %"_PRINTF_INT64_"d ints. Len = %d\n", (long long)(wptr - rptr), len); assert (rptr == wptr); } if (TLS->binlog_enabled) { assert (TLS->binlog_fd > 0); assert (write (TLS->binlog_fd, ev, len) == len); } tfree (ev, len); in_ptr = in; in_end = end; } void bl_do_dc_option_new (struct tgl_state *TLS, int flags, int id, const char *name, int l1, const char *ip, int l2, int port) { struct tgl_dc *DC = TLS->DC_list[id]; if (DC) { struct tgl_dc_option *O = DC->options[flags & 3]; while (O) { if (!strncmp (O->ip, ip, l2)) { return; } O = O->next; } } clear_packet (); out_int (CODE_binlog_dc_option_new); out_int (flags); out_int (id); out_cstring (name, l1); out_cstring (ip, l2); out_int (port); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_dc_option (struct tgl_state *TLS, int id, const char *name, int l1, const char *ip, int l2, int port) { bl_do_dc_option_new (TLS, 0, id, name, l1, ip, l2, port); } void bl_do_set_working_dc (struct tgl_state *TLS, int num) { int *ev = alloc_log_event (8); ev[0] = CODE_binlog_default_dc; ev[1] = num; add_log_event (TLS, ev, 8); } void bl_do_dc_signed (struct tgl_state *TLS, int id) { clear_packet (); out_int (CODE_binlog_dc_signed); out_int (id); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_our_id (struct tgl_state *TLS, int id) { if (TLS->our_id) { assert (TLS->our_id == id); return; } clear_packet (); out_int (CODE_binlog_our_id); out_int (id); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_dh_params (struct tgl_state *TLS, int root, unsigned char prime[], int version) { clear_packet (); out_int (CODE_binlog_set_dh_params); out_int (root); out_ints ((void *)prime, 64); out_int (version); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_pts (struct tgl_state *TLS, int pts) { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (pts <= TLS->pts) { return; } clear_packet (); out_int (CODE_binlog_set_pts); out_int (pts); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_qts (struct tgl_state *TLS, int qts) { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (qts <= TLS->qts) { return; } clear_packet (); out_int (CODE_binlog_set_qts); out_int (qts); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_date (struct tgl_state *TLS, int date) { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (date <= TLS->date) { return; } clear_packet (); out_int (CODE_binlog_set_date); out_int (date); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_seq (struct tgl_state *TLS, int seq) { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (seq <= TLS->seq) { return; } clear_packet (); out_int (CODE_binlog_set_seq); out_int (seq); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_msg_id (struct tgl_state *TLS, struct tgl_message *M, int id) { if (M->id == id) { return; } clear_packet (); out_int (CODE_binlog_set_msg_id); out_long (M->id); out_int (id); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_user_delete (struct tgl_state *TLS, struct tgl_user *U) { if (U->flags & TGLUF_DELETED) { return; } clear_packet (); out_int (CODE_binlog_user_delete); out_int (tgl_get_peer_id (U->id)); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_encr_chat_delete (struct tgl_state *TLS, struct tgl_secret_chat *U) { if (!(U->flags & TGLPF_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } clear_packet (); out_int (CODE_binlog_encr_chat_delete); out_int (tgl_get_peer_id (U->id)); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_chat_add_user (struct tgl_state *TLS, struct tgl_chat *C, int version, int user, int inviter, int date) { if (C->user_list_version >= version || !C->user_list_version) { return; } clear_packet (); out_int (CODE_binlog_chat_add_participant); out_int (tgl_get_peer_id (C->id)); out_int (version); out_int (user); out_int (inviter); out_int (date); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_chat_del_user (struct tgl_state *TLS, struct tgl_chat *C, int version, int user) { if (C->user_list_version >= version || !C->user_list_version) { return; } clear_packet (); out_int (CODE_binlog_chat_del_participant); out_int (tgl_get_peer_id (C->id)); out_int (version); out_int (user); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_create_message_new (struct tgl_state *TLS, long long id, int *from_id, int *to_type, int *to_id, int *fwd_from_id, int *fwd_date, int *date, const char *message, int message_len, struct tl_ds_message_media *media, struct tl_ds_message_action *action, int *reply_id, struct tl_ds_reply_markup *reply_markup, int flags) { clear_packet (); assert (!(flags & 0xfffe0000)); out_int (CODE_binlog_message_new); int *flags_p = packet_ptr; out_int (flags); assert (*flags_p == flags); out_long (id); if (from_id) { assert (to_type); assert (to_id); (*flags_p) |= (1 << 17); out_int (*from_id); out_int (*to_type); out_int (*to_id); } if (fwd_from_id) { assert (fwd_date); (*flags_p) |= (1 << 18); out_int (*fwd_from_id); out_int (*fwd_date); } if (date) { (*flags_p) |= (1 << 19); out_int (*date); } if (message) { (*flags_p) |= (1 << 20); out_cstring (message, message_len); } if (media) { (*flags_p) |= (1 << 21); store_ds_type_message_media (media, TYPE_TO_PARAM (message_media)); } if (action) { (*flags_p) |= (1 << 22); store_ds_type_message_action (action, TYPE_TO_PARAM (message_action)); } if (reply_id) { (*flags_p) |= (1 << 23); out_int (*reply_id); } if (reply_markup) { (*flags_p) |= (1 << 24); store_ds_type_reply_markup (reply_markup, TYPE_TO_PARAM (reply_markup)); } add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_create_message_encr_new (struct tgl_state *TLS, long long id, int *from_id, int *to_type, int *to_id, int *date, const char *message, int message_len, struct tl_ds_decrypted_message_media *media, struct tl_ds_decrypted_message_action *action, struct tl_ds_encrypted_file *file, int flags) { clear_packet (); assert (!(flags & 0xfffe0000)); out_int (CODE_binlog_message_encr_new); int *flags_p = packet_ptr; out_int (flags); assert (flags & TGLMF_ENCRYPTED); assert (*flags_p == flags); out_long (id); if (from_id) { assert (to_id); assert (to_type); (*flags_p) |= (1 << 17); out_int (*from_id); out_int (*to_type); out_int (*to_id); } if (date) { (*flags_p) |= (1 << 19); out_int (*date); } if (message) { (*flags_p) |= (1 << 20); out_cstring (message, message_len); } if (media) { (*flags_p) |= (1 << 21); store_ds_type_decrypted_message_media (media, TYPE_TO_PARAM (decrypted_message_media)); } if (action) { (*flags_p) |= (1 << 22); store_ds_type_decrypted_message_action (action, TYPE_TO_PARAM (decrypted_message_action)); } if (file) { (*flags_p) |= (1 << 23); store_ds_type_encrypted_file (file, TYPE_TO_PARAM (encrypted_file)); } add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_message_delete (struct tgl_state *TLS, struct tgl_message *M) { clear_packet (); out_int (CODE_binlog_message_delete); out_long (M->id); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_msg_update (struct tgl_state *TLS, long long id) { clear_packet (); out_int (CODE_binlog_msg_update); out_long (id); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_reset_authorization (struct tgl_state *TLS) { clear_packet (); out_int (CODE_binlog_reset_authorization); add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_encr_chat_exchange_new (struct tgl_state *TLS, struct tgl_secret_chat *E, long long *exchange_id, const void *key, int *state) { clear_packet (); out_int (CODE_binlog_encr_chat_exchange_new); out_int (tgl_get_peer_id (E->id)); int *flags_p = packet_ptr; out_int (0); if (exchange_id) { *flags_p |= (1 << 17); out_long (*exchange_id); } if (key) { *flags_p |= (1 << 18); out_ints ((void *)key, 64); } if (state) { *flags_p |= (1 << 19); out_int (*state); } add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } void bl_do_set_auth_key (struct tgl_state *TLS, int num, unsigned char *buf) { int *ev = alloc_log_event (8 + 8 + 256); ev[0] = CODE_binlog_auth_key; ev[1] = num; //*(long long *)(ev + 2) = fingerprint; memcpy (ev + 2, buf, 256); add_log_event (TLS, ev, 8 + 256); } void bl_do_user_new (struct tgl_state *TLS, int id, long long *access_hash, const char *first_name, int first_name_len, const char *last_name, int last_name_len, const char *phone, int phone_len, const char *username, int username_len, struct tl_ds_photo *photo, const char *real_first_name, int real_first_name_len, const char *real_last_name, int real_last_name_len, struct tl_ds_user_profile_photo *profile_photo, int *last_read_in, int *last_read_out, struct tl_ds_bot_info *bot_info, int flags) { tgl_peer_t *PP = tgl_peer_get (TLS, TGL_MK_USER (id)); struct tgl_user *P = &PP->user; if (flags == TGL_FLAGS_UNCHANGED) { flags = P->flags & 0xffff; } clear_packet (); out_int (CODE_binlog_user_new); int *flags_p = packet_ptr; assert (!(flags & 0xfffe0000)); out_int (flags); out_int (id); if (access_hash) { if (!P || P->access_hash != *access_hash) { out_long (*access_hash); (*flags_p) |= (1 << 17); } } if (first_name) { if (!P || !P->first_name || !P->last_name || mystreq1 (P->first_name, first_name, first_name_len) || mystreq1 (P->last_name, last_name, last_name_len)) { out_cstring (first_name, first_name_len); out_cstring (last_name, last_name_len); (*flags_p) |= (1 << 18); } } if (phone) { if (!P || !P->phone || mystreq1 (P->phone, phone, phone_len)) { out_cstring (phone, phone_len); (*flags_p) |= (1 << 19); } } if (username) { if (!P || !P->username || mystreq1 (P->username, username, username_len)) { out_cstring (username, username_len); (*flags_p) |= (1 << 20); } } if (photo) { if (!P || !P->photo || P->photo->id != DS_LVAL (photo->id)) { store_ds_type_photo (photo, TYPE_TO_PARAM (photo)); (*flags_p) |= (1 << 21); } } if (real_first_name) { assert (real_last_name); if (!P || !P->real_first_name || !P->real_last_name || mystreq1 (P->real_first_name, real_first_name, real_first_name_len) || mystreq1 (P->real_last_name, real_last_name, real_last_name_len)) { out_cstring (real_first_name, real_first_name_len); out_cstring (real_last_name, real_last_name_len); (*flags_p) |= (1 << 22); } } if (profile_photo) { if (!P || P->photo_id != DS_LVAL (profile_photo->photo_id)) { store_ds_type_user_profile_photo (profile_photo, TYPE_TO_PARAM (user_profile_photo)); (*flags_p) |= (1 << 23); } } if (last_read_in) { if (!P || P->last_read_in < *last_read_in) { out_int (*last_read_in); (*flags_p) |= (1 << 24); } } if (last_read_out) { if (!P || P->last_read_out < *last_read_out) { out_int (*last_read_out); (*flags_p) |= (1 << 25); } } if (bot_info) { if (!P || !P->bot_info || P->bot_info->version != DS_LVAL (bot_info->version)) { store_ds_type_bot_info (bot_info, TYPE_TO_PARAM (bot_info)); (*flags_p) |= (1 << 26); } } if (((*flags_p) & 0xffff0000) || !P || (P->flags & 0xffff) != flags) { add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } } void bl_do_chat_new (struct tgl_state *TLS, int id, const char *title, int title_len, int *user_num, int *date, int *version, struct tl_ds_vector *participants, struct tl_ds_chat_photo *chat_photo, struct tl_ds_photo *photo, int *admin, int *last_read_in, int *last_read_out, int flags) { tgl_peer_t *PP = tgl_peer_get (TLS, TGL_MK_CHAT (id)); struct tgl_chat *P = &PP->chat; if (flags == TGL_FLAGS_UNCHANGED) { flags = P ? (P->flags & 0xffff) : 0; } clear_packet (); out_int (CODE_binlog_chat_new); int *flags_p = packet_ptr; assert (!(flags & 0xfffe0000)); out_int (flags); out_int (id); if (title) { if (!P || !P->title || mystreq1 (P->title, title, title_len)) { out_cstring (title, title_len); (*flags_p) |= (1 << 17); } } if (user_num) { if (!P || P->users_num != *user_num) { out_int (*user_num); (*flags_p) |= (1 << 18); } } if (date) { if (!P || P->date != *date) { out_int (*date); (*flags_p) |= (1 << 19); } } if (version) { assert (participants); if (!P || *version != P->version) { out_int (*version); store_ds_type_vector (participants, TYPE_TO_PARAM_1 (vector, TYPE_TO_PARAM (chat_participant))); (*flags_p) |= (1 << 20); } } if (chat_photo && chat_photo->photo_big) { if (!P || DS_LVAL (chat_photo->photo_big->secret) != P->photo_big.secret) { store_ds_type_chat_photo (chat_photo, TYPE_TO_PARAM (chat_photo)); (*flags_p) |= (1 << 21); } } if (photo) { if (!P || !P->photo || P->photo->id != DS_LVAL (photo->id)) { store_ds_type_photo (photo, TYPE_TO_PARAM (photo)); (*flags_p) |= (1 << 22); } } if (admin) { if (!P || P->admin_id != *admin) { out_int (*admin); (*flags_p) |= (1 << 23); } } if (last_read_in) { if (!P || P->last_read_in < *last_read_in) { out_int (*last_read_in); (*flags_p) |= (1 << 24); } } if (last_read_out) { if (!P || P->last_read_out < *last_read_out) { out_int (*last_read_out); (*flags_p) |= (1 << 25); } } if (((*flags_p) & 0xffff0000) || !P || (P->flags & 0xffff) != flags) { add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } } void bl_do_encr_chat_new (struct tgl_state *TLS, int id, long long *access_hash, int *date, int *admin, int *user_id, void *key, void *g_key, void *first_key_id, int *state, int *ttl, int *layer, int *in_seq_no, int *last_in_seq_no, int *out_seq_no, long long *key_fingerprint, int flags) { tgl_peer_t *PP = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (id)); struct tgl_secret_chat *P = PP ? &PP->encr_chat : NULL; if (flags == TGL_FLAGS_UNCHANGED) { flags = P->flags & 0xffff; } clear_packet (); out_int (CODE_binlog_encr_chat_new); int *flags_p = packet_ptr; assert (!(flags & 0xfffe0000)); out_int (flags); out_int (id); if (access_hash) { if (!P || P->access_hash != *access_hash) { out_long (*access_hash); (*flags_p) |= (1 << 17); } } if (date) { if (!P || P->date != *date) { out_int (*date); (*flags_p) |= (1 << 18); } } if (admin) { if (!P || P->admin_id != *admin) { out_int (*admin); (*flags_p) |= (1 << 19); } } if (user_id) { if (!P || P->user_id != *user_id) { out_int (*user_id); (*flags_p) |= (1 << 20); } } if (key) { if (!P || memcmp (P->key, key, 256)) { out_ints (key, 64); (*flags_p) |= (1 << 21); } } if (g_key) { if (!P || !P->g_key || memcmp (P->g_key, g_key, 256)) { out_ints (g_key, 64); (*flags_p) |= (1 << 22); } } if (state) { if (!P || (int)P->state != *state) { out_int (*state); (*flags_p) |= (1 << 23); } } if (ttl) { if (!P || P->ttl != *ttl) { out_int (*ttl); (*flags_p) |= (1 << 24); } } if (layer) { if (!P || P->layer != *layer) { out_int (*layer); (*flags_p) |= (1 << 25); } } if (in_seq_no || last_in_seq_no || out_seq_no) { if (!P || (in_seq_no && P->in_seq_no != *in_seq_no) || (out_seq_no && P->out_seq_no != *out_seq_no) || (last_in_seq_no && P->last_in_seq_no != *last_in_seq_no)) { out_int (in_seq_no ? *in_seq_no : P ? P->in_seq_no : 0); out_int (last_in_seq_no ? *last_in_seq_no : P ? P->last_in_seq_no : 0); out_int (out_seq_no ? *out_seq_no : P ? P->out_seq_no : 0); (*flags_p) |= (1 << 26); } } if (key_fingerprint) { if (!P || P->key_fingerprint != *key_fingerprint) { out_long (*key_fingerprint); (*flags_p) |= (1 << 27); } } if (((*flags_p) & 0xffff0000) || !P || (P->flags & 0xffff) != flags) { add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer)); } }