Sometimes new binlog works

This commit is contained in:
Vysheng 2013-11-21 23:35:49 +04:00
parent fe0e4fed8f
commit 06dee8bdbd
10 changed files with 1023 additions and 434 deletions

634
binlog.c
View File

@ -12,6 +12,9 @@
#include "mtproto-common.h"
#include "net.h"
#include "include.h"
#include "mtproto-client.h"
#include <openssl/sha.h>
#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; }
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);
}

View File

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

View File

@ -916,14 +916,20 @@ void hexdump (int *in_ptr, int *in_end) {
}
void logprintf (const char *format, ...) {
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);
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) {

11
loop.c
View File

@ -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 ();

6
main.c
View File

@ -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 ();

View File

@ -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;

160
queries.c
View File

@ -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));
}
/* }}} */

View File

@ -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);

View File

@ -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 new = 0;
if (!(U->flags & FLAG_CREATED)) {
new = 1;
}
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 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 phone_len = 0;
char *phone = 0;
if (x != CODE_user_foreign) {
phone_len = prefetch_strlen ();
phone = fetch_str (phone_len);
}
if (x == CODE_user_deleted) {
U->flags |= FLAG_DELETED;
} else {
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) {
U->flags |= FLAG_USER_SELF;
fetch_bool ();
}
}
} 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);
if (x != CODE_user_deleted) {
if (x != CODE_user_self) {
bl_do_set_user_access_token (U, fetch_long ());
}
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 ();
}
need_update |= fetch_file_location (&U->photo_small);
need_update |= fetch_file_location (&U->photo_big);
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) {
U->flags |= FLAG_USER_CONTACT;
bl_do_set_user_friend (U, 1);
} else {
bl_do_set_user_friend (U, 0);
}
}
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;
}
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);
}
bl_do_encr_chat_delete (U);
write_secret_chat_file ();
return;
}
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) {
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);
logprintf ("Unknown chat in waiting state. May be we forgot something...\n");
return;
}
if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) {
memset (g_key, 0, sizeof (g_key));
memset (nonce, 0, sizeof (nonce));
}
} else if (x == CODE_encrypted_chat_requested) {
U->state = sc_request;
if (!U->g_key) {
U->g_key = malloc (256);
}
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
}
if (x == CODE_encrypted_chat) {
logprintf ("Unknown chat in ok state. May be we forgot something...\n");
return;
}
} else {
U->state = sc_ok;
if (!U->g_key) {
U->g_key = malloc (256);
}
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 ++;

View File

@ -22,7 +22,8 @@
#include <assert.h>
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