Partial support for binlog. It now can track user, secret chat and auth updates.

This commit is contained in:
Vysheng 2013-11-15 04:08:24 +04:00
parent 0d99482877
commit 8ad5053c66
11 changed files with 589 additions and 96 deletions

View File

@ -7,7 +7,7 @@ DEFS=-DHAVE_CONFIG_H
COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb
EXTRA_LIBS= -lreadline -lrt -lconfig
LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS}
LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS}
LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS}
HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h

View File

@ -7,7 +7,7 @@ DEFS=@DEFS@
COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb
EXTRA_LIBS=@EXTRA_LIBS@
LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS}
LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS}
LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS}
HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h

220
binlog.c
View File

@ -11,10 +11,7 @@
#include "binlog.h"
#include "mtproto-common.h"
#include "net.h"
#define LOG_START 0x8948329a
#define LOG_AUTH_KEY 0x984932aa
#define LOG_DEFAULT_DC 0x95382908
#include "include.h"
#define BINLOG_BUFFER_SIZE (1 << 20)
int binlog_buffer[BINLOG_BUFFER_SIZE];
@ -28,6 +25,14 @@ char *get_binlog_file_name (void);
extern struct dc *DC_list[];
extern struct dc *DC_working;
extern int dc_working_num;
extern int our_id;
extern int binlog_enabled;
int in_replay_log;
void *alloc_log_event (int l UU) {
return binlog_buffer;
}
void replay_log_event (void) {
assert (rptr < wptr);
@ -41,6 +46,7 @@ void replay_log_event (void) {
return;
case CODE_dc_option:
fetch_dc_option ();
rptr = in_ptr;
return;
case LOG_AUTH_KEY:
rptr ++;
@ -52,6 +58,7 @@ void replay_log_event (void) {
rptr += 2;
memcpy (DC_list[num]->auth_key, rptr, 256);
rptr += 64;
DC_list[num]->flags |= 1;
};
return;
case LOG_DEFAULT_DC:
@ -63,6 +70,180 @@ void replay_log_event (void) {
dc_working_num = num;
}
return;
case LOG_OUR_ID:
rptr ++;
{
our_id = *(rptr ++);
}
break;
case LOG_DC_SIGNED:
rptr ++;
{
int num = *(rptr ++);
assert (num >= 0 && num <= MAX_DC_ID);
assert (DC_list[num]);
DC_list[num]->has_auth = 1;
}
break;
case LOG_DC_SALT:
rptr ++;
{
int num = *(rptr ++);
assert (num >= 0 && num <= MAX_DC_ID);
assert (DC_list[num]);
DC_list[num]->server_salt = *(long long *)rptr;
rptr += 2;
};
break;
case CODE_user_empty:
case CODE_user_self:
case CODE_user_contact:
case CODE_user_request:
case CODE_user_foreign:
case CODE_user_deleted:
fetch_alloc_user ();
rptr = in_ptr;
return;
case LOG_DH_CONFIG:
get_dh_config_on_answer (0);
rptr = in_ptr;
return;
case LOG_ENCR_CHAT_KEY:
rptr ++;
{
peer_id_t id = MK_ENCR_CHAT (*(rptr ++));
struct secret_chat *U = (void *)user_chat_get (id);
assert (U);
U->key_fingerprint = *(long long *)rptr;
rptr += 2;
memcpy (U->key, rptr, 256);
rptr += 64;
};
return;
case LOG_ENCR_CHAT_SEND_ACCEPT:
rptr ++;
{
peer_id_t id = MK_ENCR_CHAT (*(rptr ++));
struct secret_chat *U = (void *)user_chat_get (id);
assert (U);
U->key_fingerprint = *(long long *)rptr;
rptr += 2;
memcpy (U->key, rptr, 256);
rptr += 64;
if (!U->g_key) {
U->g_key = malloc (256);
}
memcpy (U->g_key, rptr, 256);
rptr += 64;
};
return;
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));
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 ++);
memcpy (U->key, rptr, 256);
rptr += 64;
if (!U->print_name) {
peer_t *P = user_chat_get (MK_USER (U->user_id));
if (P) {
U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0);
} else {
static char buf[100];
sprintf (buf, "user#%d", U->user_id);
U->print_name = create_print_name (U->id, "!", buf, 0, 0);
}
}
};
return;
case LOG_ENCR_CHAT_DELETED:
rptr ++;
{
peer_id_t id = MK_ENCR_CHAT (*(rptr ++));
struct secret_chat *U = (void *)user_chat_get (id);
if (!U) {
U = malloc (sizeof (peer_t));
memset (U, 0, sizeof (peer_t));
U->id = id;
insert_encrypted_chat ((void *)U);
} else {
U->flags &= ~FLAG_EMPTY;
}
U->flags |= FLAG_CREATED;
U->state = sc_deleted;
};
return;
case LOG_ENCR_CHAT_WAITING:
rptr ++;
{
peer_id_t id = MK_ENCR_CHAT (*(rptr ++));
struct secret_chat *U = (void *)user_chat_get (id);
assert (U);
U->state = sc_waiting;
U->date = *(rptr ++);
U->admin_id = *(rptr ++);
U->user_id = *(rptr ++);
U->access_hash = *(long long *)rptr;
rptr += 2;
};
return;
case LOG_ENCR_CHAT_REQUESTED:
rptr ++;
{
peer_id_t id = MK_ENCR_CHAT (*(rptr ++));
struct secret_chat *U = (void *)user_chat_get (id);
if (!U) {
U = malloc (sizeof (peer_t));
memset (U, 0, sizeof (peer_t));
U->id = id;
insert_encrypted_chat ((void *)U);
} else {
U->flags &= ~FLAG_EMPTY;
}
U->flags |= FLAG_CREATED;
U->state = sc_request;
U->date = *(rptr ++);
U->admin_id = *(rptr ++);
U->user_id = *(rptr ++);
U->access_hash = *(long long *)rptr;
if (!U->print_name) {
peer_t *P = user_chat_get (MK_USER (U->user_id));
if (P) {
U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0);
} else {
static char buf[100];
sprintf (buf, "user#%d", U->user_id);
U->print_name = create_print_name (U->id, "!", buf, 0, 0);
}
}
rptr += 2;
};
return;
case LOG_ENCR_CHAT_OK:
rptr ++;
{
peer_id_t id = MK_ENCR_CHAT (*(rptr ++));
struct secret_chat *U = (void *)user_chat_get (id);
assert (U);
U->state = sc_ok;
}
return;
default:
logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x]\n", *(rptr - 1), op, *(rptr + 1));
assert (0);
}
}
@ -71,20 +252,27 @@ void create_new_binlog (void) {
packet_ptr = s;
out_int (LOG_START);
out_int (CODE_dc_option);
out_int (0);
out_int (1);
out_string ("");
out_string (test_dc ? TG_SERVER_TEST : TG_SERVER);
out_int (443);
out_int (LOG_DEFAULT_DC);
out_int (1);
int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL);
int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL | O_CREAT, 0600);
if (fd < 0) {
perror ("Write new binlog");
exit (2);
}
assert (write (fd, s, (packet_ptr - s) * 4) == (packet_ptr - s) * 4);
close (fd);
}
void replay_log (void) {
in_replay_log = 1;
if (access (get_binlog_file_name (), F_OK) < 0) {
printf ("No binlog found. Creating new one");
printf ("No binlog found. Creating new one\n");
create_new_binlog ();
}
int fd = open (get_binlog_file_name (), O_RDONLY);
@ -92,7 +280,7 @@ void replay_log (void) {
perror ("binlog open");
exit (2);
}
int end;
int end = 0;
while (1) {
if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) {
if (wptr == rptr) {
@ -119,4 +307,20 @@ void replay_log (void) {
replay_log_event ();
}
close (fd);
in_replay_log = 0;
}
int binlog_fd;
void write_binlog (void) {
binlog_fd = open (get_binlog_file_name (), O_WRONLY);
if (binlog_fd < 0) {
perror ("binlog open");
exit (2);
}
lseek (binlog_fd, 0, SEEK_END);
}
void add_log_event (const int *data, int len) {
if (in_replay_log) { return; }
assert (write (binlog_fd, data, len) == len);
}

View File

@ -1,6 +1,23 @@
#ifndef __BINLOG_H__
#define __BINLOG_H__
#define LOG_START 0x8948329a
#define LOG_AUTH_KEY 0x984932aa
#define LOG_DEFAULT_DC 0x95382908
#define LOG_OUR_ID 0x8943211a
#define LOG_DC_SIGNED 0x234f9893
#define LOG_DC_SALT 0x92192ffa
#define LOG_DH_CONFIG 0x8983402b
#define LOG_ENCR_CHAT_KEY 0x894320aa
#define LOG_ENCR_CHAT_SEND_ACCEPT 0x12ab01c4
#define LOG_ENCR_CHAT_SEND_CREATE 0xab091e24
#define LOG_ENCR_CHAT_DELETED 0x99481230
#define LOG_ENCR_CHAT_WAITING 0x7102100a
#define LOG_ENCR_CHAT_REQUESTED 0x9011011a
#define LOG_ENCR_CHAT_OK 0x7612ce13
void *alloc_log_event (int l);
void replay_log (void);
void add_log_event (const int *data, int l);
void write_binlog (void);
#endif

19
loop.c
View File

@ -160,6 +160,7 @@ void write_dc (int auth_file_fd, struct dc *DC) {
int our_id;
void write_auth_file (void) {
if (binlog_enabled) { return; }
int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600);
assert (auth_file_fd >= 0);
int x = DC_SERIALIZED_MAGIC_V2;
@ -216,6 +217,7 @@ void empty_auth_file (void) {
int need_dc_list_update;
void read_auth_file (void) {
if (binlog_enabled) { return; }
int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600);
if (auth_file_fd < 0) {
empty_auth_file ();
@ -308,6 +310,7 @@ extern unsigned char *encr_prime;
extern int encr_param_version;
void read_secret_chat_file (void) {
if (binlog_enabled) { return; }
int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600);
if (fd < 0) {
return;
@ -364,6 +367,7 @@ void read_secret_chat_file (void) {
}
void write_secret_chat_file (void) {
if (binlog_enabled) { return; }
int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600);
if (fd < 0) {
return;
@ -430,12 +434,15 @@ int loop (void) {
on_start ();
if (binlog_enabled) {
replay_log ();
write_binlog ();
} else {
read_auth_file ();
}
read_auth_file ();
update_prompt ();
assert (DC_list[dc_working_num]);
if (auth_state == 0) {
if (!DC_working || !DC_working->auth_key_id) {
// if (auth_state == 0) {
DC_working = DC_list[dc_working_num];
assert (!DC_working->auth_key_id);
dc_authorize (DC_working);
@ -459,7 +466,7 @@ int loop (void) {
write_auth_file ();
}
if (auth_state == 100) {
if (auth_state == 100 || !(DC_working->has_auth)) {
if (!default_username) {
size_t size = 0;
char *user = 0;
@ -546,6 +553,12 @@ int loop (void) {
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);
}
write_auth_file ();
}
write_auth_file ();

View File

@ -44,6 +44,7 @@
#include "loop.h"
#include "interface.h"
#include "structures.h"
#include "binlog.h"
#define sha1 SHA1
@ -57,6 +58,7 @@ enum dc_state c_state;
char nonce[256];
char new_nonce[256];
char server_nonce[256];
extern int binlog_enabled;
int rpc_execute (struct connection *c, int op, int len);
int rpc_becomes_ready (struct connection *c);
@ -509,6 +511,13 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) {
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);
}
@ -525,6 +534,15 @@ 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;
}
@ -559,7 +577,7 @@ void init_enc_msg (struct session *S, int useful) {
struct dc *DC = S->dc;
assert (DC->auth_key_id);
enc_msg.auth_key_id = DC->auth_key_id;
assert (DC->server_salt);
// assert (DC->server_salt);
enc_msg.server_salt = DC->server_salt;
if (!S->session_id) {
assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0);
@ -1213,6 +1231,14 @@ void work_new_session_created (struct connection *c, long long msg_id UU) {
//DC->session_id = fetch_long ();
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) {
@ -1294,6 +1320,13 @@ 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) {
@ -1389,6 +1422,13 @@ 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;
@ -1475,7 +1515,11 @@ int rpc_execute (struct connection *c, int op, int len) {
#endif
return 0;
case st_authorized:
process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/);
if (op < 0 && op >= -999) {
logprintf ("Server error %d\n", op);
} else {
process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/);
}
#ifndef __MACH__
setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
#endif

View File

@ -307,6 +307,53 @@ static inline char *fetch_str_dup (void) {
return s;
}
static inline int fetch_update_str (char **s) {
if (!*s) {
*s = fetch_str_dup ();
return 1;
}
int l = prefetch_strlen ();
char *r = fetch_str (l);
if (memcmp (*s, r, l) || (*s)[l]) {
free (*s);
*s = malloc (l + 1);
memcpy (*s, r, l);
(*s)[l] = 0;
return 1;
}
return 0;
}
static inline int fetch_update_int (int *value) {
if (*value == *in_ptr) {
in_ptr ++;
return 0;
} else {
*value = *(in_ptr ++);
return 1;
}
}
static inline int fetch_update_long (long long *value) {
if (*value == *(long long *)in_ptr) {
in_ptr += 2;
return 0;
} else {
*value = *(long long *)(in_ptr);
in_ptr += 2;
return 1;
}
}
static inline int set_update_int (int *value, int new_value) {
if (*value == new_value) {
return 0;
} else {
*value = new_value;
return 1;
}
}
static inline void fetch_skip (int n) {
in_ptr += n;
}

111
queries.c
View File

@ -44,6 +44,7 @@
#include <openssl/md5.h>
#include "no-preview.h"
#include "binlog.h"
#define sha1 SHA1
@ -55,6 +56,8 @@ long long cur_uploaded_bytes;
long long cur_downloading_bytes;
long long cur_downloaded_bytes;
extern int binlog_enabled;
void out_peer_id (peer_id_t id);
#define QUERY_TIMEOUT 6.0
@ -303,6 +306,7 @@ void out_random (int n) {
/* {{{ 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 ();
@ -316,6 +320,9 @@ void fetch_dc_option (void) {
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));
}
}
}
@ -424,6 +431,13 @@ 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);
}
logprintf ("send_code: dc_num = %d\n", dc_working_num);
want_dc_num = 0;
clear_packet ();
@ -463,11 +477,27 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error
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);
}
check_phone_result = 1;
} else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) {
int i = error[s2] - '0';
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);
}
DC_working = DC_list[i];
write_auth_file ();
check_phone_result = 1;
@ -536,6 +566,7 @@ int do_get_nearest_dc (void) {
/* {{{ Sign in / Sign up */
int sign_in_ok;
int our_id;
int sign_in_is_ok (void) {
return sign_in_ok;
}
@ -546,11 +577,28 @@ int sign_in_on_answer (struct query *q UU) {
assert (fetch_int () == (int)CODE_auth_authorization);
int expires = fetch_int ();
fetch_user (&User);
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);
}
}
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);
}
return 0;
}
@ -734,7 +782,7 @@ void encr_finish (struct secret_chat *E) {
/* {{{ Seng msg (plain text) */
int msg_send_encr_on_answer (struct query *q UU) {
assert (fetch_int () == CODE_messages_sent_encrypted_message);
logprintf ("Sent\n");
rprintf ("Sent\n");
struct message *M = q->extra;
M->date = fetch_int ();
message_insert (M);
@ -790,7 +838,7 @@ int msg_send_on_answer (struct query *q UU) {
print_end ();
}
}
logprintf ("Sent: id = %d\n", id);
rprintf ("Sent: id = %d\n", id);
return 0;
}
@ -2113,6 +2161,8 @@ int send_encr_request_on_answer (struct query *q UU) {
printf ("\n");
pop_color ();
print_end ();
assert (E->state == sc_waiting);
}
return 0;
}
@ -2156,10 +2206,18 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
sha1 ((void *)E->key, 256, sha_buffer);
E->key_fingerprint = *(long long *)(sha_buffer + 12);
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);
}
clear_packet ();
out_int (CODE_messages_accept_encryption);
out_int (CODE_input_encrypted_chat);
logprintf ("id = %d\n", get_peer_id (E->id));
out_int (get_peer_id (E->id));
out_long (E->access_hash);
@ -2175,15 +2233,22 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
BN_clear_free (g_a);
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);
}
void do_create_keys_end (struct secret_chat *U) {
if (!encr_prime) {
rprintf (COLOR_YELLOW "Something failed in bad moment. Did not fail\n"COLOR_NORMAL);
return;
}
assert (encr_prime);
BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0);
assert (g_b);
if (!ctx) {
@ -2212,6 +2277,15 @@ 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) {
@ -2264,20 +2338,36 @@ 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);
if (x == CODE_messages_dh_config) {
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 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;
}
}
if (x == LOG_DH_CONFIG) { return 0; }
int l = prefetch_strlen ();
assert (l == 256);
unsigned char *random = (void *)fetch_str_dup ();
@ -2411,7 +2501,7 @@ struct query_methods get_difference_methods = {
void do_get_difference (void) {
difference_got = 0;
clear_packet ();
out_int (CODE_invoke_with_layer10);
out_int (CODE_invoke_with_layer9);
out_int (CODE_init_connection);
out_int (TG_APP_ID);
if (allow_send_linux_version) {
@ -2568,6 +2658,7 @@ void do_create_secret_chat (peer_id_t id) {
peer_t *U = user_chat_get (id);
if (!U) {
rprintf ("Can not create chat with unknown user\n");
return;
}
peer_t *P = malloc (sizeof (*P));

View File

@ -111,5 +111,6 @@ void do_contacts_search (int limit, const char *s);
// For binlog
int get_dh_config_on_answer (struct query *q);
void fetch_dc_option (void);
#endif

View File

@ -30,6 +30,7 @@
#include <openssl/aes.h>
#include <openssl/sha.h>
#include "queries.h"
#include "binlog.h"
#define sha1 SHA1
@ -40,24 +41,37 @@ int peer_num;
int encr_chats_allocated;
int geo_chats_allocated;
void fetch_file_location (struct file_location *loc) {
int x = fetch_int ();
if (x == CODE_file_location_unavailable) {
loc->dc = -1;
loc->volume = fetch_long ();
loc->local_id = fetch_int ();
loc->secret = fetch_long ();
} else {
assert (x == CODE_file_location);
loc->dc = fetch_int ();;
loc->volume = fetch_long ();
loc->local_id = fetch_int ();
loc->secret = fetch_long ();
extern int binlog_enabled;
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));
}
}
void fetch_user_status (struct user_status *S) {
int fetch_file_location (struct file_location *loc) {
int x = fetch_int ();
int new = 0;
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);
} 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);
}
return new;
}
int fetch_user_status (struct user_status *S) {
int x = fetch_int ();
int old = S->online;
switch (x) {
case CODE_user_status_empty:
S->online = 0;
@ -73,6 +87,7 @@ void fetch_user_status (struct user_status *S) {
default:
assert (0);
}
return (old == S->online);
}
int our_id;
@ -134,72 +149,83 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha
return strdup (s);
}
void fetch_user (struct user *U) {
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);
U->id = MK_USER (fetch_int ());
U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT);
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;
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);
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);
}
}
}
if (U->first_name) { free (U->first_name); }
if (U->last_name) { free (U->last_name); }
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);
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);
}
if (x == CODE_user_deleted) {
U->flags |= FLAG_DELETED;
return;
}
if (x == CODE_user_self) {
U->flags |= FLAG_USER_SELF;
} else {
U->access_hash = fetch_long ();
}
if (x == CODE_user_foreign) {
U->flags |= FLAG_USER_FOREIGN;
U->phone = 0;
} else {
if (U->phone) { free (U->phone); }
U->phone = fetch_str_dup ();
}
//logprintf ("name = %s, surname = %s, phone = %s\n", U->first_name, U->last_name, U->phone);
unsigned y = fetch_int ();
//fprintf (stderr, "y = 0x%08x\n", y);
if (y == CODE_user_profile_photo_empty) {
U->photo_small.dc = -2;
U->photo_big.dc = -2;
} else {
assert (y == CODE_user_profile_photo || y == 0x990d1493);
if (y == CODE_user_profile_photo) {
fetch_long ();
if (x == CODE_user_self) {
U->flags |= FLAG_USER_SELF;
} else {
need_update |= fetch_update_long (&U->access_hash);
}
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);
fetch_long ();
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;
}
fetch_file_location (&U->photo_small);
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;
}
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) {
@ -210,11 +236,18 @@ void fetch_encrypted_chat (struct secret_chat *U) {
}
return;
}
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);
}
}
return;
}
@ -222,19 +255,31 @@ void fetch_encrypted_chat (struct secret_chat *U) {
U->date = fetch_int ();
U->admin_id = fetch_int ();
U->user_id = fetch_int () + U->admin_id - our_id;
if (U->print_name) { free (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 (!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);
}
}
} else if (x == CODE_encrypted_chat_requested) {
U->state = sc_request;
if (!U->g_key) {
@ -259,6 +304,18 @@ void fetch_encrypted_chat (struct secret_chat *U) {
} else {
memcpy (U->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);
}
}
} else {
U->state = sc_ok;
if (!U->g_key) {
@ -291,6 +348,18 @@ void fetch_encrypted_chat (struct secret_chat *U) {
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) {
write_secret_chat_file ();
@ -941,13 +1010,13 @@ struct user *fetch_alloc_user (void) {
prefetch_data (data, 8);
peer_t *U = user_chat_get (MK_USER (data[1]));
if (U) {
fetch_user (&U->user);
fetch_add_alloc_log_event (&U->user, (void *)fetch_user);
return &U->user;
} else {
users_allocated ++;
U = malloc (sizeof (*U));
memset (U, 0, sizeof (*U));
fetch_user (&U->user);
fetch_add_alloc_log_event (&U->user, (void *)fetch_user);
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
Peers[peer_num ++] = U;
return &U->user;
@ -1343,7 +1412,7 @@ int print_stat (char *s, int len) {
}
peer_t *user_chat_get (peer_id_t id) {
peer_t U;
static peer_t U;
U.id = id;
return tree_lookup_peer (peer_tree, &U);
}

View File

@ -26,6 +26,7 @@ typedef struct { int type; int id; } peer_id_t;
#define FLAG_DELETED 2
#define FLAG_FORBIDDEN 4
#define FLAG_HAS_PHOTO 8
#define FLAG_CREATED 16
#define FLAG_USER_SELF 128
#define FLAG_USER_FOREIGN 256
@ -113,6 +114,7 @@ struct user {
int flags;
struct message *last;
char *print_name;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
@ -137,6 +139,7 @@ struct chat {
int flags;
struct message *last;
char *print_title;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
@ -161,6 +164,7 @@ struct secret_chat {
int flags;
struct message *last;
char *print_name;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
@ -183,6 +187,7 @@ typedef union peer {
int flags;
struct message *last;
char *print_name;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
@ -262,9 +267,9 @@ struct message {
};
};
void fetch_file_location (struct file_location *loc);
void fetch_user_status (struct user_status *S);
void fetch_user (struct user *U);
int fetch_file_location (struct file_location *loc);
int fetch_user_status (struct user_status *S);
int fetch_user (struct user *U);
struct user *fetch_alloc_user (void);
struct user *fetch_alloc_user_full (void);
struct chat *fetch_alloc_chat (void);
@ -281,6 +286,8 @@ peer_id_t fetch_peer_id (void);
void free_user (struct user *U);
void free_chat (struct chat *U);
char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4);
int print_stat (char *s, int len);
peer_t *user_chat_get (peer_id_t id);
struct message *message_get (long long id);