From 06dee8bdbdc9b8a362cc6f6d69a9d0a336d7ba51 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 21 Nov 2013 23:35:49 +0400 Subject: [PATCH] Sometimes new binlog works --- binlog.c | 636 +++++++++++++++++++++++++++++++++++++++++++++-- binlog.h | 49 ++++ interface.c | 16 +- loop.c | 11 +- main.c | 6 +- mtproto-client.c | 76 ++---- queries.c | 160 ++++-------- queries.h | 2 +- structures.c | 494 +++++++++++++++++++----------------- structures.h | 7 +- 10 files changed, 1023 insertions(+), 434 deletions(-) diff --git a/binlog.c b/binlog.c index 73d543c..ef46b8b 100644 --- a/binlog.c +++ b/binlog.c @@ -12,6 +12,9 @@ #include "mtproto-common.h" #include "net.h" #include "include.h" +#include "mtproto-client.h" + +#include #define BINLOG_BUFFER_SIZE (1 << 20) int binlog_buffer[BINLOG_BUFFER_SIZE]; @@ -27,6 +30,9 @@ extern struct dc *DC_working; extern int dc_working_num; extern int our_id; extern int binlog_enabled; +extern int encr_root; +extern unsigned char *encr_prime; +extern int encr_param_version; int in_replay_log; @@ -34,20 +40,39 @@ void *alloc_log_event (int l UU) { return binlog_buffer; } +long long binlog_pos; + void replay_log_event (void) { + int *start = rptr; + in_replay_log = 1; assert (rptr < wptr); int op = *rptr; in_ptr = rptr; in_end = wptr; + if (verbosity >= 2) { + logprintf ("event = 0x%08x. pos = %lld\n", op, binlog_pos); + } switch (op) { case LOG_START: rptr ++; - return; - case CODE_dc_option: - fetch_dc_option (); + 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; - return; + break; case LOG_AUTH_KEY: rptr ++; { @@ -60,7 +85,7 @@ void replay_log_event (void) { rptr += 64; DC_list[num]->flags |= 1; }; - return; + break; case LOG_DEFAULT_DC: rptr ++; { @@ -69,7 +94,7 @@ void replay_log_event (void) { DC_working = DC_list[num]; dc_working_num = num; } - return; + break; case LOG_OUR_ID: rptr ++; { @@ -95,7 +120,7 @@ void replay_log_event (void) { rptr += 2; }; break; - case CODE_user_empty: +/* case CODE_user_empty: case CODE_user_self: case CODE_user_contact: case CODE_user_request: @@ -103,11 +128,11 @@ void replay_log_event (void) { case CODE_user_deleted: fetch_alloc_user (); rptr = in_ptr; - return; + break;*/ case LOG_DH_CONFIG: get_dh_config_on_answer (0); rptr = in_ptr; - return; + break; case LOG_ENCR_CHAT_KEY: rptr ++; { @@ -119,7 +144,7 @@ void replay_log_event (void) { memcpy (U->key, rptr, 256); rptr += 64; }; - return; + break; case LOG_ENCR_CHAT_SEND_ACCEPT: rptr ++; { @@ -136,20 +161,18 @@ void replay_log_event (void) { memcpy (U->g_key, rptr, 256); rptr += 64; }; - return; + 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_EMPTY)); + 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); - } else { - U->flags &= ~FLAG_EMPTY; } U->flags |= FLAG_CREATED; U->user_id = *(rptr ++); @@ -166,7 +189,7 @@ void replay_log_event (void) { } } }; - return; + break; case LOG_ENCR_CHAT_DELETED: rptr ++; { @@ -177,13 +200,11 @@ void replay_log_event (void) { memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); - } else { - U->flags &= ~FLAG_EMPTY; } U->flags |= FLAG_CREATED; U->state = sc_deleted; }; - return; + break; case LOG_ENCR_CHAT_WAITING: rptr ++; { @@ -197,7 +218,7 @@ void replay_log_event (void) { U->access_hash = *(long long *)rptr; rptr += 2; }; - return; + break; case LOG_ENCR_CHAT_REQUESTED: rptr ++; { @@ -208,8 +229,6 @@ void replay_log_event (void) { memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); - } else { - U->flags &= ~FLAG_EMPTY; } U->flags |= FLAG_CREATED; U->state = sc_request; @@ -229,7 +248,7 @@ void replay_log_event (void) { } rptr += 2; }; - return; + break; case LOG_ENCR_CHAT_OK: rptr ++; { @@ -238,20 +257,293 @@ void replay_log_event (void) { assert (U); U->state = sc_ok; } - return; + 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 (rptr, U->g_key, 256); + rptr += 64; + memcpy (rptr, U->nonce, 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_update_user_photo: + case CODE_update_user_name: + work_update (0, 0); + rptr = in_ptr; + break; default: logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x]\n", *(rptr - 1), op, *(rptr + 1)); assert (0); } + if (verbosity >= 2) { + logprintf ("Event end\n"); + } + in_replay_log = 0; + binlog_pos += (rptr - start) * 4; } void create_new_binlog (void) { static int s[1000]; packet_ptr = s; out_int (LOG_START); - out_int (CODE_dc_option); + out_int (CODE_binlog_dc_option); out_int (1); out_string (""); out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); @@ -270,7 +562,6 @@ void create_new_binlog (void) { void replay_log (void) { - in_replay_log = 1; if (access (get_binlog_file_name (), F_OK) < 0) { printf ("No binlog found. Creating new one\n"); create_new_binlog (); @@ -307,7 +598,6 @@ void replay_log (void) { replay_log_event (); } close (fd); - in_replay_log = 0; } int binlog_fd; @@ -321,6 +611,298 @@ void write_binlog (void) { } void add_log_event (const int *data, int len) { + if (verbosity) { + logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); + } + assert (!(len & 3)); if (in_replay_log) { return; } - assert (write (binlog_fd, data, len) == len); + rptr = (void *)data; + wptr = rptr + (len / 4); + int *in = in_ptr; + int *end = in_end; + replay_log_event (); + if (rptr != wptr) { + logprintf ("Unread %ld ints. Len = %d\n", wptr - rptr, len); + assert (rptr == wptr); + } + if (binlog_enabled) { + assert (write (binlog_fd, data, len) == len); + } + in_ptr = in; + in_end = end; +} + +void bl_do_set_auth_key_id (int num, unsigned char *buf) { + static unsigned char sha1_buffer[20]; + SHA1 (buf, 256, sha1_buffer); + long long fingerprint = *(long long *)(sha1_buffer + 12); + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_AUTH_KEY; + ev[1] = num; + *(long long *)(ev + 2) = fingerprint; + memcpy (ev + 4, buf, 256); + add_log_event (ev, 8 + 8 + 256); +} + +void bl_do_set_our_id (int id) { + int *ev = alloc_log_event (8); + ev[0] = LOG_OUR_ID; + ev[1] = id; + add_log_event (ev, 8); +} + +void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact) { + clear_packet (); + out_int (CODE_binlog_new_user); + out_int (id); + out_cstring (f ? f : "", fl); + out_cstring (l ? l : "", ll); + out_long (access_token); + out_cstring (p ? p : "", pl); + out_int (contact); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_user_delete (struct user *U) { + if (U->flags & FLAG_DELETED) { return; } + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_user_delete; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); +} + +extern int last_date; +void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct file_location *big, struct file_location *small) { + if (photo_id == U->photo_id) { return; } + if (!photo_id) { + int *ev = alloc_log_event (20); + ev[0] = CODE_update_user_photo; + ev[1] = get_peer_id (U->id); + ev[2] = last_date; + ev[3] = CODE_user_profile_photo_empty; + ev[4] = CODE_bool_false; + add_log_event (ev, 20); + } else { + clear_packet (); + out_int (CODE_update_user_photo); + out_int (get_peer_id (U->id)); + out_int (last_date); + out_int (CODE_user_profile_photo); + out_long (photo_id); + if (small->dc >= 0) { + out_int (CODE_file_location); + out_int (small->dc); + out_long (small->volume); + out_int (small->local_id); + out_long (small->secret); + } else { + out_int (CODE_file_location_unavailable); + out_long (small->volume); + out_int (small->local_id); + out_long (small->secret); + } + if (big->dc >= 0) { + out_int (CODE_file_location); + out_int (big->dc); + out_long (big->volume); + out_int (big->local_id); + out_long (big->secret); + } else { + out_int (CODE_file_location_unavailable); + out_long (big->volume); + out_int (big->local_id); + out_long (big->secret); + } + out_int (CODE_bool_false); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + } +} + +void bl_do_set_user_name (struct user *U, const char *f, int fl, const char *l, int ll) { + if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && + (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { + return; + } + clear_packet (); + out_int (CODE_update_user_name); + out_int (get_peer_id (U->id)); + out_cstring (f, fl); + out_cstring (l, ll); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_user_access_token (struct user *U, long long access_token) { + if (U->access_hash == access_token) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_set_user_access_token; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = access_token; + add_log_event (ev, 16); +} + +void bl_do_set_user_phone (struct user *U, const char *p, int pl) { + if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { + return; + } + clear_packet (); + out_int (CODE_binlog_set_user_phone); + out_int (get_peer_id (U->id)); + out_cstring (p, pl); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_user_friend (struct user *U, int friend) { + if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_user_friend; + ev[1] = get_peer_id (U->id); + ev[2] = friend; + add_log_event (ev, 12); +} + +void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port) { + struct dc *DC = DC_list[id]; + if (DC) { return; } + + clear_packet (); + out_int (CODE_binlog_dc_option); + out_int (id); + out_cstring (name, l1); + out_cstring (ip, l2); + out_int (port); + + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_dc_signed (int id) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DC_SIGNED; + ev[1] = id; + add_log_event (ev, 8); +} + +void bl_do_set_working_dc (int num) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = num; + add_log_event (ev, 8); +} + +void bl_do_set_user_full_photo (struct user *U, const int *start, int len) { + if (U->photo.id == *(long long *)(start + 1)) { return; } + int *ev = alloc_log_event (len + 8); + ev[0] = CODE_binlog_user_full_photo; + ev[1] = get_peer_id (U->id); + memcpy (ev + 2, start, len); + add_log_event (ev, len + 8); +} + +void bl_do_set_user_blocked (struct user *U, int blocked) { + if (U->blocked == blocked) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_user_blocked; + ev[1] = get_peer_id (U->id); + ev[2] = blocked; + add_log_event (ev, 12); +} + +void bl_do_set_user_real_name (struct user *U, const char *f, int fl, const char *l, int ll) { + if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && + (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { + return; + } + clear_packet (); + out_int (CODE_binlog_set_user_full_name); + out_int (get_peer_id (U->id)); + out_cstring (f, fl); + out_cstring (l, ll); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_encr_chat_delete (struct secret_chat *U) { + if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_encr_chat_delete; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); +} + +void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]) { + int *ev = alloc_log_event (540); + ev[0] = CODE_binlog_encr_chat_requested; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = access_hash; + ev[4] = date; + ev[5] = admin_id; + ev[6] = user_id; + logprintf ("user_id = %d, admin_id = %d, our_id = %d\n", user_id, admin_id, our_id); + memcpy (ev + 7, g_key, 256); + memcpy (ev + 7 + 64, nonce, 256); + add_log_event (ev, 540); +} + +void bl_do_set_encr_chat_access_hash (struct secret_chat *U, long long access_hash) { + if (U->access_hash == access_hash) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_set_encr_chat_access_hash; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = access_hash; + add_log_event (ev, 16); +} + +void bl_do_set_encr_chat_date (struct secret_chat *U, int date) { + if (U->date == date) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_encr_chat_date; + ev[1] = get_peer_id (U->id); + ev[2] = date; + add_log_event (ev, 12); +} + +void bl_do_set_encr_chat_state (struct secret_chat *U, enum secret_chat_state state) { + if (U->state == state) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_encr_chat_state; + ev[1] = get_peer_id (U->id); + ev[2] = state; + add_log_event (ev, 12); +} + +void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { + if (U->state != sc_waiting && U->state != sc_request) { return; } + int *ev = alloc_log_event (528); + ev[0] = CODE_binlog_encr_chat_accepted; + ev[1] = get_peer_id (U->id); + memcpy (ev + 2, g_key, 256); + memcpy (ev + 66, nonce, 256); + *(long long *)(ev + 130) = key_fingerprint; + add_log_event (ev, 528); +} + +void bl_do_set_encr_chat_key (struct secret_chat *E, unsigned char key[], long long key_fingerprint) { + int *ev = alloc_log_event (272); + ev[0] = CODE_binlog_set_encr_chat_key; + ev[1] = get_peer_id (E->id); + memcpy (ev + 2, key, 256); + *(long long *)(ev + 66) = key_fingerprint; + add_log_event (ev, 272); +} + +void bl_do_set_dh_params (int root, unsigned char prime[], int version) { + int *ev = alloc_log_event (268); + ev[0] = CODE_binlog_set_dh_params; + ev[1] = root; + memcpy (ev + 2, prime, 256); + ev[66] = version; + add_log_event (ev, 268); +} + +void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned char g_a[]) { + int *ev = alloc_log_event (524); + ev[0] = CODE_binlog_encr_chat_init; + ev[1] = id; + ev[2] = user_id; + memcpy (ev + 3, random, 256); + memcpy (ev + 67, g_a, 256); + add_log_event (ev, 524); } diff --git a/binlog.h b/binlog.h index 9c77d78..1ce2a37 100644 --- a/binlog.h +++ b/binlog.h @@ -1,6 +1,8 @@ #ifndef __BINLOG_H__ #define __BINLOG_H__ +#include "structures.h" + #define LOG_START 0x8948329a #define LOG_AUTH_KEY 0x984932aa #define LOG_DEFAULT_DC 0x95382908 @@ -16,8 +18,55 @@ #define LOG_ENCR_CHAT_REQUESTED 0x9011011a #define LOG_ENCR_CHAT_OK 0x7612ce13 +#define CODE_binlog_new_user 0xe04f30de +#define CODE_binlog_user_delete 0xf7a27c79 +#define CODE_binlog_set_user_access_token 0x1349f615 +#define CODE_binlog_set_user_phone 0x5d3afde2 +#define CODE_binlog_set_user_friend 0x75a7ec5a +#define CODE_binlog_dc_option 0x08c0ef19 +#define CODE_binlog_user_full_photo 0xfaa35824 +#define CODE_binlog_user_blocked 0xb2dea7cd +#define CODE_binlog_set_user_full_name 0x4ceb4cf0 +#define CODE_binlog_encr_chat_delete 0xb9d33f87 +#define CODE_binlog_encr_chat_requested 0xf57d1ea2 +#define CODE_binlog_set_encr_chat_access_hash 0xe5612bb3 +#define CODE_binlog_set_encr_chat_date 0x54f16911 +#define CODE_binlog_set_encr_chat_state 0x76a6e45b +#define CODE_binlog_encr_chat_accepted 0x4627e926 +#define CODE_binlog_set_encr_chat_key 0x179df2d4 +#define CODE_binlog_set_dh_params 0x20ba46bc +#define CODE_binlog_encr_chat_init 0x939cd1c7 + void *alloc_log_event (int l); void replay_log (void); void add_log_event (const int *data, int l); void write_binlog (void); +void bl_do_set_auth_key_id (int num, unsigned char *buf); + +void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port); + +void bl_do_set_our_id (int id); +void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); +void bl_do_user_delete (struct user *U); +void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct file_location *big, struct file_location *small); +void bl_do_set_user_name (struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_user_access_token (struct user *U, long long access_token); +void bl_do_set_user_phone (struct user *U, const char *p, int pl); +void bl_do_set_user_friend (struct user *U, int friend); +void bl_do_set_user_full_photo (struct user *U, const int *start, int len); +void bl_do_set_user_blocked (struct user *U, int blocked); +void bl_do_set_user_real_name (struct user *U, const char *f, int fl, const char *l, int ll); + +void bl_do_encr_chat_delete (struct secret_chat *U); +void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); +void bl_do_set_encr_chat_access_hash (struct secret_chat *U, long long access_hash); +void bl_do_set_encr_chat_date (struct secret_chat *U, int date); +void bl_do_set_encr_chat_state (struct secret_chat *U, enum secret_chat_state state); +void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); +void bl_do_set_encr_chat_key (struct secret_chat *E, unsigned char key[], long long key_fingerprint); +void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned char g_a[]); + +void bl_do_dc_signed (int id); +void bl_do_set_working_dc (int num); +void bl_do_set_dh_params (int root, unsigned char prime[], int version); #endif diff --git a/interface.c b/interface.c index 1663669..a089988 100644 --- a/interface.c +++ b/interface.c @@ -916,14 +916,20 @@ void hexdump (int *in_ptr, int *in_end) { } void logprintf (const char *format, ...) { - print_start (); + int x = 0; + if (!prompt_was) { + x = 1; + print_start (); + } printf (COLOR_GREY " *** "); va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); printf (COLOR_NORMAL); - print_end (); + if (x) { + print_end (); + } } int color_stack_pos; @@ -1007,8 +1013,10 @@ void print_user_name (peer_id_t id, peer_t *U) { if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { push_color (COLOR_REDB); } - if ((U->flags & FLAG_DELETED) || (U->flags & FLAG_EMPTY)) { + if ((U->flags & FLAG_DELETED)) { printf ("deleted user#%d", get_peer_id (id)); + } else if (!(U->flags & FLAG_CREATED)) { + printf ("empty user#%d", get_peer_id (id)); } else if (!U->user.first_name || !strlen (U->user.first_name)) { printf ("%s", U->user.last_name); } else if (!U->user.last_name || !strlen (U->user.last_name)) { @@ -1123,7 +1131,7 @@ peer_id_t last_from_id; peer_id_t last_to_id; void print_message (struct message *M) { - if (M->flags & (FLAG_EMPTY | FLAG_DELETED)) { + if (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) { return; } if (M->service) { diff --git a/loop.c b/loop.c index fa93451..8680850 100644 --- a/loop.c +++ b/loop.c @@ -57,6 +57,7 @@ extern int binlog_enabled; extern int unknown_user_list_pos; extern int unknown_user_list[]; +int register_mode; int unread_messages; void got_it (char *line, int len); @@ -483,7 +484,7 @@ int loop (void) { int res = do_auth_check_phone (default_username); assert (res >= 0); logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); - if (res > 0) { + if (res > 0 && !register_mode) { do_send_code (default_username); char *code = 0; size_t size = 0; @@ -552,13 +553,7 @@ int loop (void) { for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->has_auth) { do_export_auth (i); do_import_auth (i); - DC_list[i]->has_auth = 1; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DC_SIGNED; - ev[1] = i; - add_log_event (ev, 8); - } + bl_do_dc_signed (i); write_auth_file (); } write_auth_file (); diff --git a/main.c b/main.c index b17410e..3d9c4a1 100644 --- a/main.c +++ b/main.c @@ -312,9 +312,10 @@ extern char *rsa_public_key_name; extern int verbosity; extern int default_dc_num; +int register_mode; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:R")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -338,6 +339,9 @@ void args_parse (int argc, char **argv) { case 'l': log_level = atoi (optarg); break; + case 'R': + register_mode = 1; + break; case 'h': default: usage (); diff --git a/mtproto-client.c b/mtproto-client.c index 91f0404..da1ca8a 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -61,6 +61,11 @@ char new_nonce[256]; char server_nonce[256]; extern int binlog_enabled; + +int total_packets_sent; +long long total_data_sent; + + int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); int rpc_close (struct connection *c); @@ -183,6 +188,9 @@ int rpc_send_packet (struct connection *c) { write_out (c, &unenc_msg_header, 20); write_out (c, packet_buffer, len); flush_out (c); + + total_packets_sent ++; + total_data_sent += total_len; return 1; } @@ -198,6 +206,9 @@ int rpc_send_message (struct connection *c, void *data, int len) { c->out_packet_num ++; write_out (c, data, len); flush_out (c); + + total_packets_sent ++; + total_data_sent += total_len; return 1; } @@ -506,19 +517,16 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { static unsigned char tmp[44], sha1_buffer[20]; memcpy (tmp, new_nonce, 32); tmp[32] = 1; + //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); + + bl_do_set_auth_key_id (GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); - GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); + memcpy (tmp + 33, sha1_buffer, 8); sha1 (tmp, 41, sha1_buffer); assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->server_salt; - add_log_event (ev, 16); - }*/ + if (verbosity >= 3) { logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } @@ -535,14 +543,6 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { auth_success ++; GET_DC(c)->flags |= 1; write_auth_file (); - if (binlog_enabled) { - int *ev = alloc_log_event (8 + 8 + 256); - ev[0] = LOG_AUTH_KEY; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->auth_key_id; - memcpy (ev + 4, GET_DC(c)->auth_key, 256); - add_log_event (ev, 8 + 8 + 256); - } return 1; } @@ -825,25 +825,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { if (U->print_name) { free (U->print_name); } 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); printf (" changed name to "); print_user_name (user_id, UC); printf ("\n"); pop_color (); print_end (); - if (!strlen (U->first_name)) { - if (!strlen (U->last_name)) { - U->print_name = strdup ("none"); - } else { - U->print_name = strdup (U->last_name); - } - } else { - if (!strlen (U->last_name)) { - U->print_name = strdup (U->first_name); - } else { - U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2); - sprintf (U->print_name, "%s_%s", U->first_name, U->last_name); - } - } } else { int l; l = prefetch_strlen (); @@ -871,11 +858,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { print_end (); unsigned y = fetch_int (); if (y == CODE_user_profile_photo_empty) { + U->photo_id = 0; U->photo_big.dc = -2; U->photo_small.dc = -2; } else { assert (y == CODE_user_profile_photo); - fetch_long (); // photo_id + U->photo_id = fetch_long (); fetch_file_location (&U->photo_small); fetch_file_location (&U->photo_big); } @@ -1031,12 +1019,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { case CODE_update_encryption: { struct secret_chat *E = fetch_alloc_encrypted_chat (); + if (verbosity >= 2) { + logprintf ("Secret chat state = %d\n", E->state); + } print_start (); push_color (COLOR_YELLOW); print_date (time (0)); switch (E->state) { case sc_none: - assert (0); break; case sc_waiting: printf (" Encrypted chat "); @@ -1159,6 +1149,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; default: logprintf ("Unknown update type %08x\n", op); + ; } } @@ -1244,13 +1235,6 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { fetch_long (); // unique_id GET_DC(c)->server_salt = fetch_long (); -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->server_salt; - add_log_event (ev, 16); - }*/ } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1332,13 +1316,6 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { fetch_int (); // error_code long long new_server_salt = fetch_long (); GET_DC(c)->server_salt = new_server_salt; -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->server_salt; - add_log_event (ev, 16); - }*/ } void work_pong (struct connection *c UU, long long msg_id UU) { @@ -1434,13 +1411,6 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, if (DC->server_salt != enc->server_salt) { DC->server_salt = enc->server_salt; write_auth_file (); -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = DC->id; - *(long long *)(ev + 2) = DC->server_salt; - add_log_event (ev, 16); - }*/ } int this_server_time = enc->msg_id >> 32LL; diff --git a/queries.c b/queries.c index 429f04c..1fb4d82 100644 --- a/queries.c +++ b/queries.c @@ -328,7 +328,6 @@ void do_insert_header (void) { /* {{{ Get config */ void fetch_dc_option (void) { - int *start = in_ptr; assert (fetch_int () == CODE_dc_option); int id = fetch_int (); int l1 = prefetch_strlen (); @@ -339,13 +338,8 @@ void fetch_dc_option (void) { if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } - if (!DC_list[id]) { - alloc_dc (id, strndup (ip, l2), port); - new_dc_num ++; - if (binlog_enabled) { - add_log_event (start, 4 * (in_ptr - start)); - } - } + + bl_do_dc_option (id, l1, name, l2, ip, port); } int help_get_config_on_answer (struct query *q UU) { @@ -453,12 +447,8 @@ void do_send_code (const char *user) { dc_create_session (DC_working); } dc_working_num = want_dc_num; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = dc_working_num; - add_log_event (ev, 8); - } + + bl_do_set_working_dc (dc_working_num); logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; @@ -496,16 +486,12 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { int i = error[s] - '0'; assert (DC_list[i]); + dc_working_num = i; DC_working = DC_list[i]; write_auth_file (); - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = i; - add_log_event (ev, 8); - } + bl_do_set_working_dc (i); check_phone_result = 1; } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { @@ -513,12 +499,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error assert (DC_list[i]); dc_working_num = i; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = i; - add_log_event (ev, 8); - } + bl_do_set_working_dc (i); DC_working = DC_list[i]; write_auth_file (); @@ -602,24 +583,15 @@ int sign_in_on_answer (struct query *q UU) { if (!our_id) { our_id = get_peer_id (User.id); - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_OUR_ID; - ev[1] = our_id; - add_log_event (ev, 8); - } + bl_do_set_our_id (our_id); } sign_in_ok = 1; if (verbosity) { logprintf ( "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); } DC_working->has_auth = 1; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DC_SIGNED; - ev[1] = DC_working->id; - add_log_event (ev, 8); - } + + bl_do_dc_signed (DC_working->id); return 0; } @@ -2219,23 +2191,16 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { BIGNUM *r = BN_new (); BN_init (r); BN_mod_exp (r, g_a, b, p, ctx); - memset (E->key, 0, sizeof (E->key)); - BN_bn2bin (r, (void *)E->key); - for (i = 0; i < 64; i++) { - E->key[i] ^= *(((int *)E->nonce) + i); + static unsigned char kk[256]; + memset (kk, 0, sizeof (kk)); + BN_bn2bin (r, kk); + for (i = 0; i < 256; i++) { + kk[i] ^= E->nonce[i]; } static unsigned char sha_buffer[20]; - sha1 ((void *)E->key, 256, sha_buffer); - E->key_fingerprint = *(long long *)(sha_buffer + 12); + sha1 (kk, 256, sha_buffer); - if (binlog_enabled) { - int *ev = alloc_log_event (8 + 8 + 256); - ev[0] = LOG_ENCR_CHAT_KEY; - ev[1] = get_peer_id (E->id); - *(long long *)(ev + 2) = E->key_fingerprint; - memcpy (ev + 4, E->key, 256); - add_log_event (ev, 8 + 8 + 256); - } + bl_do_set_encr_chat_key (E, kk, *(long long *)(sha_buffer + 12)); clear_packet (); out_int (CODE_messages_accept_encryption); @@ -2256,16 +2221,6 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (p); BN_clear_free (r); - if (binlog_enabled) { - int *ev = alloc_log_event (16 + 512); - ev[0] = LOG_ENCR_CHAT_SEND_ACCEPT; - ev[1] = get_peer_id (E->id); - *(long long *)(ev + 2) = E->key_fingerprint; - memcpy (ev + 4, E->key, 256); - memcpy (ev + 68, buf, 256); - add_log_event (ev, 16 + 512); - } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); } @@ -2299,18 +2254,10 @@ void do_create_keys_end (struct secret_chat *U) { BN_clear_free (g_b); BN_clear_free (r); BN_clear_free (a); - - if (binlog_enabled) { - int *ev = alloc_log_event (8 + 8 + 256); - ev[0] = LOG_ENCR_CHAT_KEY; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = U->key_fingerprint; - memcpy (ev + 4, U->key, 256); - add_log_event (ev, 8 + 8 + 256); - } } -void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { +void do_send_create_encr_chat (void *x, unsigned char *random) { + int user_id = (long)x; int i; for (i = 0; i < 64; i++) { *(((int *)random) + i) ^= mrand48 (); @@ -2333,13 +2280,21 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { BN_mod_exp (r, g, a, p, ctx); - memcpy (E->key, random, 256); - static char g_a[256]; memset (g_a, 0, 256); BN_bn2bin (r, (void *)g_a); + int t = lrand48 (); + while (user_chat_get (MK_ENCR_CHAT (t))) { + t = lrand48 (); + } + + bl_do_encr_chat_init (t, user_id, (void *)random, (void *)g_a); + peer_t *_E = user_chat_get (MK_ENCR_CHAT (t)); + assert (_E); + struct secret_chat *E = &_E->encr_chat; + clear_packet (); out_int (CODE_messages_request_encryption); peer_t *U = user_chat_get (MK_USER (E->user_id)); @@ -2360,46 +2315,28 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (p); BN_clear_free (r); - if (binlog_enabled) { - int *ev = alloc_log_event (12 + 256); - ev[0] = LOG_ENCR_CHAT_SEND_CREATE; - ev[1] = get_peer_id (E->id); - ev[2] = E->user_id; - memcpy (ev + 3, E->key, 256); - add_log_event (ev, 12 + 256); - } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); } int get_dh_config_on_answer (struct query *q UU) { - int *start = in_ptr; unsigned x = fetch_int (); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { - encr_root = fetch_int (); - if (encr_prime) { free (encr_prime); } + int a = fetch_int (); int l = prefetch_strlen (); assert (l == 256); - encr_prime = (void *)fetch_str_dup (); - encr_param_version = fetch_int (); - if (binlog_enabled) { - *start = LOG_DH_CONFIG; - add_log_event (start, 4 * (in_ptr - start)); - *start = CODE_messages_dh_config; - } + char *s = fetch_str (l); + int v = fetch_int (); + bl_do_set_dh_params (a, (void *)s, v); } if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); assert (l == 256); unsigned char *random = (void *)fetch_str_dup (); if (q->extra) { - struct secret_chat *E = q->extra; - if (E->state == sc_request) { - do_send_accept_encr_chat (q->extra, random); - } else if (E->state == sc_none) { - do_send_create_encr_chat (q->extra, random); - } + void **x = q->extra; + ((void (*)(void *, void *))(*x))(x[1], random); + free (x); free (random); } else { free (random); @@ -2418,17 +2355,21 @@ void do_accept_encr_chat_request (struct secret_chat *E) { out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); + void **x = malloc (2 * sizeof (void *)); + x[0] = do_send_accept_encr_chat; + x[1] = E; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); } -void do_create_encr_chat_request (struct secret_chat *E) { - assert (E->state == sc_none); - +void do_create_encr_chat_request (int user_id) { clear_packet (); out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); + void **x = malloc (2 * sizeof (void *)); + x[0] = do_send_create_encr_chat; + x[1] = (void *)(long)(user_id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); } /* }}} */ @@ -2666,16 +2607,7 @@ void do_create_secret_chat (peer_id_t id) { return; } - peer_t *P = malloc (sizeof (*P)); - memset (P, 0, sizeof (*P)); - P->id = MK_ENCR_CHAT (lrand48 ()); - - P->encr_chat.user_id = get_peer_id (id); - - insert_encrypted_chat (P); - P->print_name = create_print_name (P->id, "!", U->user.first_name, U->user.last_name, 0); - - do_create_encr_chat_request (&P->encr_chat); + do_create_encr_chat_request (get_peer_id (id)); } /* }}} */ diff --git a/queries.h b/queries.h index 20015ca..e377a0a 100644 --- a/queries.h +++ b/queries.h @@ -81,7 +81,7 @@ void do_get_user_info (peer_id_t id); void do_forward_message (peer_id_t id, int n); void do_rename_chat (peer_id_t id, char *name); void do_load_encr_video (struct encr_video *V, int next); -void do_create_encr_chat_request (struct secret_chat *E); +void do_create_encr_chat_request (int user_id); void do_create_secret_chat (peer_id_t id); void do_get_suggested (void); diff --git a/structures.c b/structures.c index 9a48a42..4eab03f 100644 --- a/structures.c +++ b/structures.c @@ -42,39 +42,47 @@ int encr_chats_allocated; int geo_chats_allocated; extern int binlog_enabled; +void fetch_skip_photo (void); -void fetch_add_alloc_log_event (void *obj, int (*f)(void *)) { - int *start = in_ptr; - int r = f (obj); - if (binlog_enabled && r) { - add_log_event (start, 4 * (in_ptr - start)); - } -} +#define code_assert(x) if (!(x)) { logprintf ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } int fetch_file_location (struct file_location *loc) { int x = fetch_int (); - int new = 0; + code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); + if (x == CODE_file_location_unavailable) { - new |= set_update_int (&loc->dc, -1); - new |= fetch_update_long (&loc->volume); - new |= fetch_update_int (&loc->local_id); - new |= fetch_update_long (&loc->secret); + loc->dc = -1; + loc->volume = fetch_long (); + loc->local_id = fetch_int (); + loc->secret = fetch_long (); } else { - assert (x == CODE_file_location); - new |= fetch_update_int (&loc->dc); - new |= fetch_update_long (&loc->volume); - new |= fetch_update_int (&loc->local_id); - new |= fetch_update_long (&loc->secret); + loc->dc = fetch_int (); + loc->volume = fetch_long (); + loc->local_id = fetch_int (); + loc->secret = fetch_long (); } - return new; + return 0; +} + +int fetch_skip_file_location (void) { + int x = fetch_int (); + code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); + + if (x == CODE_file_location_unavailable) { + in_ptr += 5; + } else { + in_ptr += 6; + } + return 0; } int fetch_user_status (struct user_status *S) { - int x = fetch_int (); - int old = S->online; + unsigned x = fetch_int (); + code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); switch (x) { case CODE_user_status_empty: S->online = 0; + S->when = 0; break; case CODE_user_status_online: S->online = 1; @@ -87,7 +95,7 @@ int fetch_user_status (struct user_status *S) { default: assert (0); } - return (old == S->online); + return 0; } int our_id; @@ -149,223 +157,222 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha return strdup (s); } +long long fetch_user_photo (struct user *U) { + unsigned x = fetch_int (); + code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); + if (x == CODE_user_profile_photo_empty) { + bl_do_set_user_profile_photo (U, 0, 0, 0); + return 0; + } + long long photo_id = 1; + if (x == CODE_user_profile_photo) { + photo_id = fetch_long (); + } + struct file_location big; + struct file_location small; + if (fetch_file_location (&small) < 0) { return -1; } + if (fetch_file_location (&big) < 0) { return -1; } + + bl_do_set_user_profile_photo (U, photo_id, &big, &small); + return 0; +} + int fetch_user (struct user *U) { unsigned x = fetch_int (); - assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted); + code_assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted); U->id = MK_USER (fetch_int ()); if ((U->flags & FLAG_CREATED) && x == CODE_user_empty) { return 0; } - int old_flags = U->flags; - U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT | FLAG_CREATED); if (x == CODE_user_empty) { - U->flags |= FLAG_EMPTY; return 0; } - U->flags |= FLAG_CREATED; + if (x == CODE_user_self) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { - our_id = get_peer_id (U->id); + bl_do_set_our_id (get_peer_id (U->id)); write_auth_file (); - - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_OUR_ID; - ev[1] = our_id; - add_log_event (ev, 8); - } } } - int need_update = 0; - need_update |= fetch_update_str (&U->first_name); - need_update |= fetch_update_str (&U->last_name); - if (need_update) { - if (U->print_name) { free (U->print_name); } - U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); + + int new = 0; + if (!(U->flags & FLAG_CREATED)) { + new = 1; } - if (x == CODE_user_deleted) { - U->flags |= FLAG_DELETED; + if (new) { + int l1 = prefetch_strlen (); + char *s1 = fetch_str (l1); + int l2 = prefetch_strlen (); + char *s2 = fetch_str (l2); + + if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { + bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); + bl_do_user_delete (U); + } + if (x != CODE_user_deleted) { + long long access_token = 0; + if (x != CODE_user_self) { + access_token = fetch_long (); + } + int phone_len = 0; + char *phone = 0; + if (x != CODE_user_foreign) { + phone_len = prefetch_strlen (); + phone = fetch_str (phone_len); + } + bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); + if (fetch_user_photo (U) < 0) { return -1; } + + if (fetch_user_status (&U->status) < 0) { return -1; } + if (x == CODE_user_self) { + fetch_bool (); + } + } } else { - if (x == CODE_user_self) { - U->flags |= FLAG_USER_SELF; - } else { - need_update |= fetch_update_long (&U->access_hash); + int l1 = prefetch_strlen (); + char *s1 = fetch_str (l1); + int l2 = prefetch_strlen (); + char *s2 = fetch_str (l2); + + bl_do_set_user_name (U, s1, l1, s2, l2); + + if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { + bl_do_user_delete (U); } - if (x == CODE_user_foreign) { - U->flags |= FLAG_USER_FOREIGN; - } else { - need_update |= fetch_update_str (&U->phone); - } - unsigned y = fetch_int (); - if (y == CODE_user_profile_photo_empty) { - need_update |= set_update_int (&U->photo_small.dc, -2); - need_update |= set_update_int (&U->photo_big.dc, -2); - } else { - assert (y == CODE_user_profile_photo || y == CODE_user_profile_photo_old); - if (y == CODE_user_profile_photo) { - fetch_long (); + if (x != CODE_user_deleted) { + if (x != CODE_user_self) { + bl_do_set_user_access_token (U, fetch_long ()); + } + if (x != CODE_user_foreign) { + int l = prefetch_strlen (); + char *s = fetch_str (l); + bl_do_set_user_phone (U, s, l); + } + if (fetch_user_photo (U) < 0) { return -1; } + + fetch_user_status (&U->status); + if (x == CODE_user_self) { + fetch_bool (); + } + + if (x == CODE_user_contact) { + bl_do_set_user_friend (U, 1); + } else { + bl_do_set_user_friend (U, 0); } - need_update |= fetch_file_location (&U->photo_small); - need_update |= fetch_file_location (&U->photo_big); - } - fetch_user_status (&U->status); - if (x == CODE_user_self) { - fetch_bool (); - } - if (x == CODE_user_contact) { - U->flags |= FLAG_USER_CONTACT; } } - need_update |= (old_flags != U->flags); - return need_update; + return 0; } void fetch_encrypted_chat (struct secret_chat *U) { unsigned x = fetch_int (); assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); U->id = MK_ENCR_CHAT (fetch_int ()); - if ((U->flags & FLAG_CREATED) && x == CODE_encrypted_chat_empty) { - return; - } - U->flags &= ~(FLAG_EMPTY | FLAG_DELETED); - enum secret_chat_state old_state = U->state; if (x == CODE_encrypted_chat_empty) { - U->state = sc_none; - U->flags |= FLAG_EMPTY; - if (U->state != old_state) { - write_secret_chat_file (); - } return; } - U->flags |= FLAG_CREATED; + int new = !(U->flags & FLAG_CREATED); + if (x == CODE_encrypted_chat_discarded) { - U->state = sc_deleted; - U->flags |= FLAG_DELETED; - if (U->state != old_state) { - write_secret_chat_file (); - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_ENCR_CHAT_DELETED; - ev[1] = get_peer_id (U->id); - add_log_event (ev, 8); - } + if (new) { + logprintf ("Unknown chat in deleted state. May be we forgot something...\n"); + return; } + bl_do_encr_chat_delete (U); + write_secret_chat_file (); return; } - U->access_hash = fetch_long (); - U->date = fetch_int (); - U->admin_id = fetch_int (); - U->user_id = fetch_int () + U->admin_id - our_id; - 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); - } - } - if (x == CODE_encrypted_chat_waiting) { - U->state = sc_waiting; - if (old_state != sc_waiting) { - if (binlog_enabled) { - int *ev = alloc_log_event (28); - ev[0] = LOG_ENCR_CHAT_WAITING; - ev[1] = get_peer_id (U->id); - ev[2] = U->date; - ev[3] = U->admin_id; - ev[4] = U->user_id; - *(long long *)(ev + 5) = U->access_hash; - add_log_event (ev, 28); - } + static char g_key[256]; + static char nonce[256]; + if (new) { + long long access_hash = fetch_long (); + int date = fetch_int (); + int admin_id = fetch_int (); + int user_id = fetch_int () + admin_id - our_id; + + if (x == CODE_encrypted_chat_waiting) { + logprintf ("Unknown chat in waiting state. May be we forgot something...\n"); + return; } - } else if (x == CODE_encrypted_chat_requested) { - U->state = sc_request; - if (!U->g_key) { - U->g_key = malloc (256); + if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { + memset (g_key, 0, sizeof (g_key)); + memset (nonce, 0, sizeof (nonce)); } - memset (U->g_key, 0, 256); - if (!U->nonce) { - U->nonce = malloc (256); - } - memset (U->nonce, 0, 256); + int l = prefetch_strlen (); char *s = fetch_str (l); if (l < 256) { - memcpy (U->g_key + 256 - l, s, l); + memcpy (g_key + 256 - l, s, l); } else { - memcpy (U->g_key, s + (l - 256), 256); + memcpy (g_key, s + (l - 256), 256); } + l = prefetch_strlen (); s = fetch_str (l); if (l < 256) { - memcpy (U->nonce + 256 - l, s, l); + memcpy (nonce + 256 - l, s, l); } else { - memcpy (U->nonce, s + (l - 256), 256); + memcpy (nonce, s + (l - 256), 256); } - if (old_state != sc_request) { - if (binlog_enabled) { - int *ev = alloc_log_event (28); - ev[0] = LOG_ENCR_CHAT_REQUESTED; - ev[1] = get_peer_id (U->id); - ev[2] = U->date; - ev[3] = U->admin_id; - ev[4] = U->user_id; - *(long long *)(ev + 5) = U->access_hash; - add_log_event (ev, 28); - } + + if (x == CODE_encrypted_chat) { + fetch_long (); // fingerprint } - } else { - U->state = sc_ok; - if (!U->g_key) { - U->g_key = malloc (256); + + if (x == CODE_encrypted_chat) { + logprintf ("Unknown chat in ok state. May be we forgot something...\n"); + return; } - memset (U->g_key, 0, 256); - if (!U->nonce) { - U->nonce = malloc (256); - } - memset (U->nonce, 0, 256); - int l = prefetch_strlen (); - char *s = fetch_str (l); - if (l < 256) { - memcpy (U->g_key + 256 - l, s, l); - } else { - memcpy (U->g_key, s + (l - 256), 256); - } - l = prefetch_strlen (); - s = fetch_str (l); - if (l < 256) { - memcpy (U->nonce + 256 - l, s, l); - } else { - memcpy (U->nonce, s + (l - 256), 256); - } - if (!U->key_fingerprint) { - U->key_fingerprint = fetch_long (); - } else { - assert (U->key_fingerprint == fetch_long ()); - } - if (old_state == sc_waiting) { - do_create_keys_end (U); - } - free (U->g_key); - U->g_key = 0; - free (U->nonce); - U->nonce = 0; - if (old_state != sc_ok) { - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_ENCR_CHAT_OK; - ev[1] = get_peer_id (U->id); - add_log_event (ev, 8); - } - } - } - if (U->state != old_state) { + + bl_do_encr_chat_requested (U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); write_secret_chat_file (); + } else { + bl_do_set_encr_chat_access_hash (U, fetch_long ()); + bl_do_set_encr_chat_date (U, fetch_int ()); + if (fetch_int () != U->admin_id) { + logprintf ("Changed admin in secret chat. WTF?\n"); + return; + } + if (U->user_id != U->admin_id + fetch_int () - our_id) { + logprintf ("Changed partner in secret chat. WTF?\n"); + return; + } + if (x == CODE_encrypted_chat_waiting) { + bl_do_set_encr_chat_state (U, sc_waiting); + write_secret_chat_file (); + return; // We needed only access hash from here + } + + if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { + memset (g_key, 0, sizeof (g_key)); + memset (nonce, 0, sizeof (nonce)); + } + + int l = prefetch_strlen (); + char *s = fetch_str (l); + if (l < 256) { + memcpy (g_key + 256 - l, s, l); + } else { + memcpy (g_key, s + (l - 256), 256); + } + + l = prefetch_strlen (); + s = fetch_str (l); + if (l < 256) { + memcpy (nonce + 256 - l, s, l); + } else { + memcpy (nonce, s + (l - 256), 256); + } + + if (x == CODE_encrypted_chat_requested) { + return; // Duplicate? + } + bl_do_encr_chat_accepted (U, (void *)g_key, (void *)nonce, fetch_long ()); } + write_secret_chat_file (); } void fetch_notify_settings (void); @@ -376,46 +383,39 @@ void fetch_user_full (struct user *U) { assert (fetch_int () == (int)CODE_contacts_link); x = fetch_int (); assert (x == CODE_contacts_my_link_empty || x == CODE_contacts_my_link_requested || x == CODE_contacts_my_link_contact); - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (x == CODE_contacts_my_link_contact) { - U->flags |= FLAG_USER_IN_CONTACT; - } if (x == CODE_contacts_my_link_requested) { fetch_bool (); } x = fetch_int (); assert (x == CODE_contacts_foreign_link_unknown || x == CODE_contacts_foreign_link_requested || x == CODE_contacts_foreign_link_mutual); - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (x == CODE_contacts_foreign_link_mutual) { - U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; - } if (x == CODE_contacts_foreign_link_requested) { - U->flags |= FLAG_USER_OUT_CONTACT; fetch_bool (); } fetch_alloc_user (); - if (U->flags & FLAG_HAS_PHOTO) { - free_photo (&U->photo); - } - fetch_photo (&U->photo); - U->flags |= FLAG_HAS_PHOTO; + + int *start = in_ptr; + fetch_skip_photo (); + bl_do_set_user_full_photo (U, start, 4 * (in_ptr - start)); + fetch_notify_settings (); - U->blocked = fetch_int (); - if (U->real_first_name) { free (U->real_first_name); } - if (U->real_last_name) { free (U->real_last_name); } - U->real_first_name = fetch_str_dup (); - U->real_last_name = fetch_str_dup (); + + bl_do_set_user_blocked (U, fetch_bool ()); + int l1 = prefetch_strlen (); + char *s1 = fetch_str (l1); + int l2 = prefetch_strlen (); + char *s2 = fetch_str (l2); + bl_do_set_user_real_name (U, s1, l1, s2, l2); } void fetch_chat (struct chat *C) { unsigned x = fetch_int (); assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); C->id = MK_CHAT (fetch_int ()); - C->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); if (x == CODE_chat_empty) { - C->flags |= FLAG_EMPTY; return; } + C->flags |= FLAG_CREATED; + C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); if (x == CODE_chat_forbidden) { C->flags |= FLAG_FORBIDDEN; } @@ -472,7 +472,8 @@ void fetch_chat_full (struct chat *C) { assert (x == CODE_messages_chat_full); assert (fetch_int () == CODE_chat_full); C->id = MK_CHAT (fetch_int ()); - C->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); + C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); + C->flags |= FLAG_CREATED; x = fetch_int (); if (x == CODE_chat_participants) { assert (fetch_int () == get_peer_id (C->id)); @@ -536,6 +537,23 @@ void fetch_photo_size (struct photo_size *S) { } } +void fetch_skip_photo_size (void) { + unsigned x = fetch_int (); + assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); + int l = prefetch_strlen (); + fetch_str (l); // type + if (x != CODE_photo_size_empty) { + fetch_skip_file_location (); + in_ptr += 2; // w, h + if (x == CODE_photo_size) { + in_ptr ++; + } else { + l = prefetch_strlen (); + fetch_str (l); + } + } +} + void fetch_geo (struct geo *G) { unsigned x = fetch_int (); if (x == CODE_geo_point) { @@ -548,6 +566,14 @@ void fetch_geo (struct geo *G) { } } +void fetch_skip_geo (void) { + unsigned x = fetch_int (); + assert (x == CODE_geo_point || x == CODE_geo_point_empty); + if (x == CODE_geo_point) { + in_ptr += 2; + } +} + void fetch_photo (struct photo *P) { memset (P, 0, sizeof (*P)); unsigned x = fetch_int (); @@ -568,6 +594,23 @@ void fetch_photo (struct photo *P) { } } +void fetch_skip_photo (void) { + unsigned x = fetch_int (); + assert (x == CODE_photo_empty || x == CODE_photo); + in_ptr += 2; // id + if (x == CODE_photo_empty) { return; } + in_ptr += 2 +1 + 1; // access_hash, user_id, date + int l = prefetch_strlen (); + fetch_str (l); // caption + fetch_skip_geo (); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + fetch_skip_photo_size (); + } +} + void fetch_video (struct video *V) { memset (V, 0, sizeof (*V)); unsigned x = fetch_int (); @@ -902,11 +945,11 @@ void fetch_encrypted_message (struct message *M) { peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); M->to_id = chat; peer_t *P = user_chat_get (chat); - M->flags &= ~(FLAG_EMPTY | FLAG_DELETED); + M->flags &= ~(FLAG_MESSAGE_EMPTY | FLAG_DELETED); M->flags |= FLAG_ENCRYPTED; if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); - M->flags |= FLAG_EMPTY; + M->flags |= FLAG_MESSAGE_EMPTY; } M->date = fetch_int (); @@ -1012,36 +1055,32 @@ struct user *fetch_alloc_user (void) { int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); - if (U) { - fetch_add_alloc_log_event (&U->user, (void *)fetch_user); - return &U->user; - } else { + if (!U) { users_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_add_alloc_log_event (&U->user, (void *)fetch_user); + U->id = MK_USER (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; - return &U->user; } + fetch_user (&U->user); + return &U->user; } struct secret_chat *fetch_alloc_encrypted_chat (void) { int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); - if (U) { - fetch_encrypted_chat (&U->encr_chat); - return &U->encr_chat; - } else { - encr_chats_allocated ++; + if (!U) { U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_encrypted_chat (&U->encr_chat); + U->id = MK_ENCR_CHAT (data[1]); + encr_chats_allocated ++; peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; - return &U->encr_chat; } + fetch_encrypted_chat (&U->encr_chat); + return &U->encr_chat; } void insert_encrypted_chat (peer_t *P) { @@ -1050,6 +1089,12 @@ void insert_encrypted_chat (peer_t *P) { Peers[peer_num ++] = P; } +void insert_user (peer_t *P) { + users_allocated ++; + peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + Peers[peer_num ++] = P; +} + struct user *fetch_alloc_user_full (void) { int data[3]; prefetch_data (data, 12); @@ -1196,7 +1241,6 @@ void message_add_peer (struct message *M) { P = malloc (sizeof (*P)); memset (P, 0, sizeof (*P)); P->id = id; - P->flags = FLAG_EMPTY; switch (get_peer_type (id)) { case PEER_USER: users_allocated ++; diff --git a/structures.h b/structures.h index a06627a..3e3daf3 100644 --- a/structures.h +++ b/structures.h @@ -22,7 +22,8 @@ #include typedef struct { int type; int id; } peer_id_t; -#define FLAG_EMPTY 1 +//#define FLAG_EMPTY 1 +#define FLAG_MESSAGE_EMPTY 1 #define FLAG_DELETED 2 #define FLAG_FORBIDDEN 4 #define FLAG_HAS_PHOTO 8 @@ -117,6 +118,7 @@ struct user { int structure_version; struct file_location photo_big; struct file_location photo_small; + long long photo_id; struct photo photo; char *first_name; char *last_name; @@ -296,6 +298,9 @@ void message_insert (struct message *M); void free_photo (struct photo *P); void fetch_photo (struct photo *P); void insert_encrypted_chat (peer_t *P); +void insert_user (peer_t *P); +void fetch_photo (struct photo *P); +void free_photo (struct photo *P); #define PEER_USER 1 #define PEER_CHAT 2