Sometimes new binlog works
This commit is contained in:
parent
fe0e4fed8f
commit
06dee8bdbd
634
binlog.c
634
binlog.c
@ -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);
|
||||
}
|
||||
|
49
binlog.h
49
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
|
||||
|
12
interface.c
12
interface.c
@ -916,15 +916,21 @@ 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;
|
||||
const char *color_stack[10];
|
||||
@ -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
11
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 ();
|
||||
|
6
main.c
6
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 ();
|
||||
|
@ -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
160
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));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
474
structures.c
474
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 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 ++;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user