Partial support for encrypted chats.
This commit is contained in:
parent
9dd3627afa
commit
923845d668
102
interface.c
102
interface.c
@ -48,9 +48,8 @@ long long cur_downloading_bytes;
|
||||
long long cur_downloaded_bytes;
|
||||
|
||||
char *line_ptr;
|
||||
extern int user_num;
|
||||
extern int chat_num;
|
||||
extern peer_t *Peers[];
|
||||
extern int peer_num;
|
||||
|
||||
int is_same_word (const char *s, size_t l, const char *word) {
|
||||
return s && word && strlen (word) == l && !memcmp (s, word, l);
|
||||
@ -106,10 +105,10 @@ peer_id_t next_token_user (void) {
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) {
|
||||
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) {
|
||||
index ++;
|
||||
}
|
||||
if (index < user_num + chat_num) {
|
||||
if (index < peer_num) {
|
||||
return Peers[index]->id;
|
||||
} else {
|
||||
return PEER_NOT_FOUND;
|
||||
@ -130,10 +129,10 @@ peer_id_t next_token_chat (void) {
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
|
||||
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
|
||||
index ++;
|
||||
}
|
||||
if (index < user_num + chat_num) {
|
||||
if (index < peer_num) {
|
||||
return Peers[index]->id;
|
||||
} else {
|
||||
return PEER_NOT_FOUND;
|
||||
@ -161,10 +160,10 @@ peer_id_t next_token_peer (void) {
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name))) {
|
||||
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name))) {
|
||||
index ++;
|
||||
}
|
||||
if (index < user_num + chat_num) {
|
||||
if (index < peer_num) {
|
||||
return Peers[index]->id;
|
||||
} else {
|
||||
return PEER_NOT_FOUND;
|
||||
@ -232,6 +231,7 @@ char *commands[] = {
|
||||
"rename_contact",
|
||||
"show_license",
|
||||
"search",
|
||||
"mark_read",
|
||||
0 };
|
||||
|
||||
int commands_flags[] = {
|
||||
@ -258,6 +258,7 @@ int commands_flags[] = {
|
||||
071,
|
||||
07,
|
||||
072,
|
||||
072,
|
||||
};
|
||||
|
||||
int get_complete_mode (void) {
|
||||
@ -297,10 +298,10 @@ int get_complete_mode (void) {
|
||||
|
||||
int complete_user_list (int index, const char *text, int len, char **R) {
|
||||
index ++;
|
||||
while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) {
|
||||
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) {
|
||||
index ++;
|
||||
}
|
||||
if (index < user_num + chat_num) {
|
||||
if (index < peer_num) {
|
||||
*R = strdup (Peers[index]->print_name);
|
||||
return index;
|
||||
} else {
|
||||
@ -310,10 +311,10 @@ int complete_user_list (int index, const char *text, int len, char **R) {
|
||||
|
||||
int complete_chat_list (int index, const char *text, int len, char **R) {
|
||||
index ++;
|
||||
while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
|
||||
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
|
||||
index ++;
|
||||
}
|
||||
if (index < user_num + chat_num) {
|
||||
if (index < peer_num) {
|
||||
*R = strdup (Peers[index]->print_name);
|
||||
return index;
|
||||
} else {
|
||||
@ -323,10 +324,10 @@ int complete_chat_list (int index, const char *text, int len, char **R) {
|
||||
|
||||
int complete_user_chat_list (int index, const char *text, int len, char **R) {
|
||||
index ++;
|
||||
while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) {
|
||||
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) {
|
||||
index ++;
|
||||
}
|
||||
if (index < user_num + chat_num) {
|
||||
if (index < peer_num) {
|
||||
*R = strdup (Peers[index]->print_name);
|
||||
return index;
|
||||
} else {
|
||||
@ -663,6 +664,8 @@ void interpreter (char *line UU) {
|
||||
"load_photo/load_video/load_video_thumb <msg-seqno> - loads photo/video to download dir\n"
|
||||
"view_photo/view_video/view_video_thumb <msg-seqno> - loads photo/video to download dir and starts system default viewer\n"
|
||||
"show_license - prints contents of GPLv2\n"
|
||||
"search <peer> pattern - searches pattern in messages with peer\n"
|
||||
"mark_read <peer> - mark read all received messages with peer\n"
|
||||
);
|
||||
pop_color ();
|
||||
rl_on_new_line ();
|
||||
@ -685,6 +688,9 @@ void interpreter (char *line UU) {
|
||||
RET;
|
||||
}
|
||||
do_msg_search (id, from, to, limit, s);
|
||||
} else if (IS_WORD ("mark_read")) {
|
||||
GET_PEER;
|
||||
do_mark_read (id);
|
||||
}
|
||||
#undef IS_WORD
|
||||
#undef RET
|
||||
@ -796,30 +802,6 @@ void logprintf (const char *format, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *message_media_type_str (struct message_media *M) {
|
||||
static char buf[1000];
|
||||
switch (M->type) {
|
||||
case CODE_message_media_empty:
|
||||
return "";
|
||||
case CODE_message_media_photo:
|
||||
return "[photo]";
|
||||
case CODE_message_media_video:
|
||||
return "[video]";
|
||||
case CODE_message_media_geo:
|
||||
sprintf (buf, "[geo] https://maps.google.com/maps?ll=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude);
|
||||
return buf;
|
||||
case CODE_message_media_contact:
|
||||
snprintf (buf, 999, "[contact] " COLOR_RED "%s %s" COLOR_NORMAL " %s", M->first_name, M->last_name, M->phone);
|
||||
return buf;
|
||||
case CODE_message_media_unsupported:
|
||||
return "[unsupported]";
|
||||
default:
|
||||
assert (0);
|
||||
return "";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int color_stack_pos;
|
||||
const char *color_stack[10];
|
||||
|
||||
@ -853,6 +835,12 @@ void print_media (struct message_media *M) {
|
||||
case CODE_message_media_video:
|
||||
printf ("[video]");
|
||||
return;
|
||||
case CODE_decrypted_message_media_photo:
|
||||
printf ("[photo]");
|
||||
return;
|
||||
case CODE_decrypted_message_media_video:
|
||||
printf ("[video]");
|
||||
return;
|
||||
case CODE_message_media_geo:
|
||||
printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude);
|
||||
return;
|
||||
@ -1009,6 +997,9 @@ 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)) {
|
||||
return;
|
||||
}
|
||||
if (M->service) {
|
||||
print_service_message (M);
|
||||
return;
|
||||
@ -1050,7 +1041,42 @@ void print_message (struct message *M) {
|
||||
printf (" »»» ");
|
||||
}
|
||||
}
|
||||
} else if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) {
|
||||
peer_t *P = user_chat_get (M->to_id);
|
||||
assert (P);
|
||||
if (M->out) {
|
||||
push_color (COLOR_GREEN);
|
||||
if (msg_num_mode) {
|
||||
printf ("%lld ", M->id);
|
||||
}
|
||||
print_date (M->date);
|
||||
printf (" ");
|
||||
push_color (COLOR_CYAN);
|
||||
printf (" %s", P->print_name);
|
||||
pop_color ();
|
||||
if (M->unread) {
|
||||
printf (" <<< ");
|
||||
} else {
|
||||
printf (" ««« ");
|
||||
}
|
||||
} else {
|
||||
push_color (COLOR_BLUE);
|
||||
if (msg_num_mode) {
|
||||
printf ("%lld ", M->id);
|
||||
}
|
||||
print_date (M->date);
|
||||
push_color (COLOR_CYAN);
|
||||
printf (" %s", P->print_name);
|
||||
pop_color ();
|
||||
if (M->unread) {
|
||||
printf (" >>> ");
|
||||
} else {
|
||||
printf (" »»» ");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
assert (get_peer_type (M->to_id) == PEER_CHAT);
|
||||
push_color (COLOR_MAGENTA);
|
||||
if (msg_num_mode) {
|
||||
printf ("%lld ", M->id);
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define COLOR_YELLOW "\033[33;1m"
|
||||
#define COLOR_BLUE "\033[34;1m"
|
||||
#define COLOR_MAGENTA "\033[35;1m"
|
||||
|
||||
#define COLOR_CYAN "\033[36;1m"
|
||||
|
||||
char *get_default_prompt (void);
|
||||
char *complete_none (const char *text, int state);
|
||||
|
156
loop.c
156
loop.c
@ -39,6 +39,7 @@
|
||||
#include "mtproto-common.h"
|
||||
#include "queries.h"
|
||||
#include "telegram.h"
|
||||
#include "loop.h"
|
||||
|
||||
extern char *default_username;
|
||||
extern char *auth_token;
|
||||
@ -59,6 +60,7 @@ void net_loop (int flags, int (*is_end)(void)) {
|
||||
cc ++;
|
||||
}
|
||||
|
||||
write_state_file ();
|
||||
int x = connections_make_poll_array (fds + cc, 101 - cc) + cc;
|
||||
double timer = next_timer_in ();
|
||||
if (timer > 1000) { timer = 1000; }
|
||||
@ -116,6 +118,8 @@ struct dc *DC_working;
|
||||
int dc_working_num;
|
||||
int auth_state;
|
||||
char *get_auth_key_filename (void);
|
||||
char *get_state_filename (void);
|
||||
char *get_secret_chat_filename (void);
|
||||
int zero[512];
|
||||
|
||||
|
||||
@ -231,11 +235,157 @@ void read_auth_file (void) {
|
||||
}
|
||||
}
|
||||
|
||||
int pts, qts, seq, last_date;
|
||||
|
||||
void read_state_file (void) {
|
||||
int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600);
|
||||
if (state_file_fd < 0) {
|
||||
return;
|
||||
}
|
||||
int version, magic;
|
||||
if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; }
|
||||
if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; }
|
||||
if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return; }
|
||||
assert (version >= 0);
|
||||
int x[4];
|
||||
if (read (state_file_fd, x, 16) < 16) {
|
||||
close (state_file_fd);
|
||||
return;
|
||||
}
|
||||
pts = x[0];
|
||||
qts = x[1];
|
||||
seq = x[2];
|
||||
last_date = x[3];
|
||||
close (state_file_fd);
|
||||
}
|
||||
|
||||
void write_state_file (void) {
|
||||
static int wseq;
|
||||
static int wpts;
|
||||
static int wqts;
|
||||
static int wdate;
|
||||
if (wseq >= seq && wpts >= pts && wqts >= qts && wdate >= last_date) { return; }
|
||||
int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600);
|
||||
if (state_file_fd < 0) {
|
||||
return;
|
||||
}
|
||||
int x[6];
|
||||
x[0] = STATE_FILE_MAGIC;
|
||||
x[1] = 0;
|
||||
x[2] = pts;
|
||||
x[3] = qts;
|
||||
x[4] = seq;
|
||||
x[5] = last_date;
|
||||
assert (write (state_file_fd, x, 24) == 24);
|
||||
close (state_file_fd);
|
||||
wseq = seq; wpts = pts; wqts = qts; wdate = last_date;
|
||||
}
|
||||
|
||||
extern peer_t *Peers[];
|
||||
extern int peer_num;
|
||||
|
||||
void read_secret_chat_file (void) {
|
||||
int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600);
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
int x[2];
|
||||
if (read (fd, x, 8) < 8) {
|
||||
close (fd); return;
|
||||
}
|
||||
if (x[0] != (int)SECRET_CHAT_FILE_MAGIC) { close (fd); return; }
|
||||
int version = x[1];
|
||||
assert (version >= 0);
|
||||
int cc;
|
||||
assert (read (fd, &cc, 4) == 4);
|
||||
int i;
|
||||
for (i = 0; i < cc; i++) {
|
||||
peer_t *P = malloc (sizeof (*P));
|
||||
memset (P, 0, sizeof (*P));
|
||||
struct secret_chat *E = &P->encr_chat;
|
||||
int t;
|
||||
assert (read (fd, &t, 4) == 4);
|
||||
P->id = MK_ENCR_CHAT (t);
|
||||
assert (read (fd, &P->flags, 4) == 4);
|
||||
assert (read (fd, &t, 4) == 4);
|
||||
assert (t > 0);
|
||||
P->print_name = malloc (t + 1);
|
||||
assert (read (fd, P->print_name, t) == t);
|
||||
P->print_name[t] = 0;
|
||||
|
||||
assert (read (fd, &E->state, 4) == 4);
|
||||
assert (read (fd, &E->user_id, 4) == 4);
|
||||
assert (read (fd, &E->admin_id, 4) == 4);
|
||||
assert (read (fd, &E->ttl, 4) == 4);
|
||||
assert (read (fd, &E->access_hash, 8) == 8);
|
||||
|
||||
if (E->state != sc_waiting) {
|
||||
E->g_key = malloc (256);
|
||||
assert (read (fd, E->g_key, 256) == 256);
|
||||
}
|
||||
E->nonce = malloc (256);
|
||||
assert (read (fd, E->nonce, 256) == 256);
|
||||
assert (read (fd, E->key, 256) == 256);
|
||||
assert (read (fd, &E->key_fingerprint, 8) == 8);
|
||||
insert_encrypted_chat (P);
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
void write_secret_chat_file (void) {
|
||||
int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600);
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
int x[2];
|
||||
x[0] = SECRET_CHAT_FILE_MAGIC;
|
||||
x[1] = 0;
|
||||
assert (write (fd, x, 8) == 8);
|
||||
int i;
|
||||
int cc = 0;
|
||||
for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) {
|
||||
if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) {
|
||||
cc ++;
|
||||
}
|
||||
}
|
||||
assert (write (fd, &cc, 4) == 4);
|
||||
for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) {
|
||||
if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) {
|
||||
int t = get_peer_id (Peers[i]->id);
|
||||
assert (write (fd, &t, 4) == 4);
|
||||
t = Peers[i]->flags;
|
||||
assert (write (fd, &t, 4) == 4);
|
||||
t = strlen (Peers[i]->print_name);
|
||||
assert (write (fd, &t, 4) == 4);
|
||||
assert (write (fd, Peers[i]->print_name, t) == t);
|
||||
|
||||
assert (write (fd, &Peers[i]->encr_chat.state, 4) == 4);
|
||||
|
||||
assert (write (fd, &Peers[i]->encr_chat.user_id, 4) == 4);
|
||||
assert (write (fd, &Peers[i]->encr_chat.admin_id, 4) == 4);
|
||||
assert (write (fd, &Peers[i]->encr_chat.ttl, 4) == 4);
|
||||
assert (write (fd, &Peers[i]->encr_chat.access_hash, 8) == 8);
|
||||
if (Peers[i]->encr_chat.state != sc_waiting) {
|
||||
assert (write (fd, Peers[i]->encr_chat.g_key, 256) == 256);
|
||||
}
|
||||
assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256);
|
||||
assert (write (fd, Peers[i]->encr_chat.key, 256) == 256);
|
||||
assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8);
|
||||
}
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
extern int max_chat_size;
|
||||
int mcs (void) {
|
||||
return max_chat_size;
|
||||
}
|
||||
|
||||
extern int difference_got;
|
||||
int dgot (void) {
|
||||
return !difference_got;
|
||||
}
|
||||
|
||||
int readline_active;
|
||||
int new_dc_num;
|
||||
int loop (void) {
|
||||
@ -368,7 +518,11 @@ int loop (void) {
|
||||
rl_attempted_completion_function = (CPPFunction *) complete_text;
|
||||
rl_completion_entry_function = complete_none;
|
||||
|
||||
do_get_dialog_list_ex ();
|
||||
read_state_file ();
|
||||
read_secret_chat_file ();
|
||||
do_get_difference ();
|
||||
net_loop (0, dgot);
|
||||
do_get_dialog_list ();
|
||||
|
||||
return main_loop ();
|
||||
}
|
||||
|
2
loop.h
2
loop.h
@ -21,4 +21,6 @@
|
||||
int loop (void);
|
||||
void net_loop (int flags, int (*end)(void));
|
||||
void write_auth_file (void);
|
||||
void write_state_file (void);
|
||||
void write_secret_chat_file (void);
|
||||
#endif
|
||||
|
20
main.c
20
main.c
@ -41,6 +41,8 @@
|
||||
#define CONFIG_DIRECTORY ".telegram/"
|
||||
#define CONFIG_FILE CONFIG_DIRECTORY "config"
|
||||
#define AUTH_KEY_FILE CONFIG_DIRECTORY "auth"
|
||||
#define STATE_FILE CONFIG_DIRECTORY "state"
|
||||
#define SECRET_CHAT_FILE CONFIG_DIRECTORY "secret"
|
||||
#define DOWNLOADS_DIRECTORY "downloads/"
|
||||
|
||||
#define CONFIG_DIRECTORY_MODE 0700
|
||||
@ -130,6 +132,24 @@ char *get_auth_key_filename (void) {
|
||||
return auth_key_filename;
|
||||
}
|
||||
|
||||
char *get_state_filename (void) {
|
||||
char *state_filename;
|
||||
int length = strlen (get_home_directory ()) + strlen (STATE_FILE) + 2;
|
||||
|
||||
state_filename = (char *) calloc (length, sizeof (char));
|
||||
sprintf (state_filename, "%s/" STATE_FILE, get_home_directory ());
|
||||
return state_filename;
|
||||
}
|
||||
|
||||
char *get_secret_chat_filename (void) {
|
||||
char *secret_chat_filename;
|
||||
int length = strlen (get_home_directory ()) + strlen (SECRET_CHAT_FILE) + 2;
|
||||
|
||||
secret_chat_filename = (char *) calloc (length, sizeof (char));
|
||||
sprintf (secret_chat_filename, "%s/" SECRET_CHAT_FILE, get_home_directory ());
|
||||
return secret_chat_filename;
|
||||
}
|
||||
|
||||
char *get_downloads_directory (void)
|
||||
{
|
||||
char *downloads_directory;
|
||||
|
@ -637,14 +637,18 @@ int unread_messages;
|
||||
int our_id;
|
||||
int pts;
|
||||
int qts;
|
||||
int last_date;
|
||||
int seq;
|
||||
|
||||
void fetch_pts (void) {
|
||||
int p = fetch_int ();
|
||||
if (p <= pts) { return; }
|
||||
if (p != pts + 1) {
|
||||
if (pts) {
|
||||
logprintf ("Hole in pts p = %d, pts = %d\n", p, pts);
|
||||
//logprintf ("Hole in pts p = %d, pts = %d\n", p, pts);
|
||||
|
||||
// get difference should be here
|
||||
pts = p;
|
||||
} else {
|
||||
pts = p;
|
||||
}
|
||||
@ -655,10 +659,12 @@ void fetch_pts (void) {
|
||||
|
||||
void fetch_qts (void) {
|
||||
int p = fetch_int ();
|
||||
if (p <= qts) { return; }
|
||||
if (p != qts + 1) {
|
||||
if (qts) {
|
||||
logprintf ("Hole in qts\n");
|
||||
//logprintf ("Hole in qts\n");
|
||||
// get difference should be here
|
||||
qts = p;
|
||||
} else {
|
||||
qts = p;
|
||||
}
|
||||
@ -667,6 +673,24 @@ void fetch_qts (void) {
|
||||
}
|
||||
}
|
||||
|
||||
void fetch_date (void) {
|
||||
int p = fetch_int ();
|
||||
if (p > last_date) {
|
||||
last_date = p;
|
||||
}
|
||||
}
|
||||
|
||||
void fetch_seq (void) {
|
||||
int x = fetch_int ();
|
||||
if (x > seq + 1) {
|
||||
logprintf ("Hole in seq: seq = %d, x = %d\n", seq, x);
|
||||
//do_get_difference ();
|
||||
seq = x;
|
||||
} else if (x >= seq + 1) {
|
||||
seq = x;
|
||||
}
|
||||
}
|
||||
|
||||
void work_update (struct connection *c UU, long long msg_id UU) {
|
||||
unsigned op = fetch_int ();
|
||||
switch (op) {
|
||||
@ -993,9 +1017,11 @@ void work_update (struct connection *c UU, long long msg_id UU) {
|
||||
printf (" is now in deleted state\n");
|
||||
break;
|
||||
}
|
||||
/*if (E->state == state_requested) {
|
||||
pop_color ();
|
||||
print_end ();
|
||||
if (E->state == sc_request) {
|
||||
do_accept_encr_chat_request (E);
|
||||
}*/
|
||||
}
|
||||
fetch_int (); // date
|
||||
}
|
||||
break;
|
||||
@ -1041,7 +1067,7 @@ void work_update (struct connection *c UU, long long msg_id UU) {
|
||||
void work_update_short (struct connection *c, long long msg_id) {
|
||||
assert (fetch_int () == CODE_update_short);
|
||||
work_update (c, msg_id);
|
||||
fetch_int (); // date
|
||||
fetch_date ();
|
||||
}
|
||||
|
||||
void work_updates (struct connection *c, long long msg_id) {
|
||||
@ -1062,9 +1088,8 @@ void work_updates (struct connection *c, long long msg_id) {
|
||||
for (i = 0; i < n; i++) {
|
||||
fetch_alloc_chat ();
|
||||
}
|
||||
fetch_int (); // date
|
||||
fetch_int (); // seq
|
||||
|
||||
fetch_date (); // date
|
||||
fetch_seq (); // seq
|
||||
}
|
||||
|
||||
void work_update_short_message (struct connection *c UU, long long msg_id UU) {
|
||||
@ -1073,6 +1098,9 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) {
|
||||
unread_messages ++;
|
||||
print_message (M);
|
||||
update_prompt ();
|
||||
if (M->date > last_date) {
|
||||
last_date = M->date;
|
||||
}
|
||||
}
|
||||
|
||||
void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) {
|
||||
@ -1081,6 +1109,9 @@ void work_update_short_chat_message (struct connection *c UU, long long msg_id U
|
||||
unread_messages ++;
|
||||
print_message (M);
|
||||
update_prompt ();
|
||||
if (M->date > last_date) {
|
||||
last_date = M->date;
|
||||
}
|
||||
}
|
||||
|
||||
void work_container (struct connection *c, long long msg_id UU) {
|
||||
@ -1211,6 +1242,10 @@ void work_detained_info (struct connection *c UU, long long msg_id UU) {
|
||||
fetch_int (); // status
|
||||
}
|
||||
|
||||
void work_updates_to_long (struct connection *c UU, long long msg_id UU) {
|
||||
assert (fetch_int () == (int)CODE_updates_too_long);
|
||||
do_get_difference ();
|
||||
}
|
||||
void rpc_execute_answer (struct connection *c, long long msg_id UU) {
|
||||
if (verbosity >= 5) {
|
||||
logprintf ("rpc_execute_answer: fd=%d\n", c->fd);
|
||||
@ -1254,6 +1289,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) {
|
||||
case CODE_msg_detained_info:
|
||||
work_detained_info (c, msg_id);
|
||||
return;
|
||||
case CODE_updates_too_long:
|
||||
work_updates_to_long (c, msg_id);
|
||||
return;
|
||||
}
|
||||
logprintf ( "Unknown message: \n");
|
||||
hexdump_in ();
|
||||
|
@ -23,4 +23,5 @@
|
||||
void on_start (void);
|
||||
long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful);
|
||||
void dc_authorize (struct dc *DC);
|
||||
void work_update (struct connection *c, long long msg_id);
|
||||
#endif
|
||||
|
@ -37,6 +37,9 @@
|
||||
#include "mtproto-common.h"
|
||||
#include "interface.h"
|
||||
|
||||
int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr;
|
||||
int *packet_buffer = __packet_buffer + 16;
|
||||
|
||||
long long rsa_encrypted_chunks, rsa_decrypted_chunks;
|
||||
|
||||
BN_CTX *BN_ctx;
|
||||
|
@ -83,6 +83,7 @@
|
||||
#define MAX_MESSAGE_INTS 1048576
|
||||
#define MAX_PROTO_MESSAGE_INTS 1048576
|
||||
|
||||
#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix
|
||||
#pragma pack(push,4)
|
||||
struct encrypted_message {
|
||||
// unencrypted header
|
||||
@ -219,8 +220,8 @@ void prng_seed (const char *password_filename, int password_length);
|
||||
int serialize_bignum (BIGNUM *b, char *buffer, int maxlen);
|
||||
long long compute_rsa_key_fingerprint (RSA *key);
|
||||
|
||||
#define PACKET_BUFFER_SIZE (16384 * 100) // temp fix
|
||||
int packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr;
|
||||
extern int *packet_buffer;
|
||||
extern int *packet_ptr;
|
||||
|
||||
static inline void out_ints (int *what, int len) {
|
||||
assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE);
|
||||
@ -262,6 +263,9 @@ static inline void out_bignum (BIGNUM *n) {
|
||||
extern int *in_ptr, *in_end;
|
||||
|
||||
void fetch_pts (void);
|
||||
void fetch_qts (void);
|
||||
void fetch_date (void);
|
||||
void fetch_seq (void);
|
||||
static inline int prefetch_strlen (void) {
|
||||
if (in_ptr >= in_end) {
|
||||
return -1;
|
||||
|
5
net.h
5
net.h
@ -26,7 +26,7 @@ struct dc;
|
||||
//#define TG_SERVER "95.142.192.66"
|
||||
#define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74"
|
||||
#define TG_APP_ID 2899
|
||||
#define TG_BUILD "200"
|
||||
#define TG_BUILD "203"
|
||||
|
||||
#define TG_VERSION "0.01-beta"
|
||||
|
||||
@ -79,6 +79,9 @@ struct dc {
|
||||
|
||||
#define DC_SERIALIZED_MAGIC 0x64582faa
|
||||
#define DC_SERIALIZED_MAGIC_V2 0x94032abb
|
||||
#define STATE_FILE_MAGIC 0x84217a0d
|
||||
#define SECRET_CHAT_FILE_MAGIC 0xa9840add
|
||||
|
||||
struct dc_serialized {
|
||||
int magic;
|
||||
int port;
|
||||
|
470
queries.c
470
queries.c
@ -37,6 +37,12 @@
|
||||
#include "structures.h"
|
||||
#include "interface.h"
|
||||
#include "net.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#define sha1 SHA1
|
||||
|
||||
char *get_downloads_directory (void);
|
||||
int verbosity;
|
||||
@ -276,6 +282,8 @@ int new_dc_num;
|
||||
extern struct dc *DC_list[];
|
||||
extern struct dc *DC_working;
|
||||
|
||||
/* {{{ Get config */
|
||||
|
||||
int help_get_config_on_answer (struct query *q UU) {
|
||||
assert (fetch_int () == CODE_config);
|
||||
fetch_int ();
|
||||
@ -323,7 +331,9 @@ void do_help_get_config (void) {
|
||||
out_int (CODE_help_get_config);
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Send code */
|
||||
char *phone_code_hash;
|
||||
int send_code_on_answer (struct query *q UU) {
|
||||
assert (fetch_int () == CODE_auth_sent_code);
|
||||
@ -407,8 +417,9 @@ void do_send_code (const char *user) {
|
||||
net_loop (0, code_is_sent);
|
||||
assert (want_dc_num == -1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ Check phone */
|
||||
int check_phone_result;
|
||||
int cr_f (void) {
|
||||
return check_phone_result >= 0;
|
||||
@ -460,7 +471,9 @@ int do_auth_check_phone (const char *user) {
|
||||
net_loop (0, cr_f);
|
||||
return check_phone_result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Nearest DC */
|
||||
int nearest_dc_num;
|
||||
int nr_f (void) {
|
||||
return nearest_dc_num >= 0;
|
||||
@ -497,7 +510,9 @@ int do_get_nearest_dc (void) {
|
||||
net_loop (0, nr_f);
|
||||
return nearest_dc_num;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Sign in / Sign up */
|
||||
int sign_in_ok;
|
||||
int sign_in_is_ok (void) {
|
||||
return sign_in_ok;
|
||||
@ -554,7 +569,9 @@ int do_send_code_result_auth (const char *code, const char *first_name, const ch
|
||||
net_loop (0, sign_in_is_ok);
|
||||
return sign_in_ok;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Get contacts */
|
||||
extern char *user_list[];
|
||||
|
||||
int get_contacts_on_answer (struct query *q UU) {
|
||||
@ -612,18 +629,106 @@ void do_update_contact_list (void) {
|
||||
out_string ("");
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Encrypt decrypted */
|
||||
int *encr_extra;
|
||||
int *encr_ptr;
|
||||
int *encr_end;
|
||||
|
||||
char *encrypt_decrypted_message (struct secret_chat *E) {
|
||||
static int msg_key[4];
|
||||
static unsigned char sha1a_buffer[20];
|
||||
static unsigned char sha1b_buffer[20];
|
||||
static unsigned char sha1c_buffer[20];
|
||||
static unsigned char sha1d_buffer[20];
|
||||
int x = *(encr_ptr);
|
||||
assert (x >= 0 && !(x & 3));
|
||||
sha1 ((void *)encr_ptr, 4 + x, sha1a_buffer);
|
||||
memcpy (msg_key, sha1a_buffer + 4, 16);
|
||||
|
||||
static unsigned char buf[64];
|
||||
memcpy (buf, msg_key, 16);
|
||||
memcpy (buf + 16, E->key, 32);
|
||||
sha1 (buf, 48, sha1a_buffer);
|
||||
|
||||
memcpy (buf, E->key + 8, 16);
|
||||
memcpy (buf + 16, msg_key, 16);
|
||||
memcpy (buf + 32, E->key + 12, 16);
|
||||
sha1 (buf, 48, sha1b_buffer);
|
||||
|
||||
memcpy (buf, E->key + 16, 32);
|
||||
memcpy (buf + 32, msg_key, 16);
|
||||
sha1 (buf, 48, sha1c_buffer);
|
||||
|
||||
memcpy (buf, msg_key, 16);
|
||||
memcpy (buf + 16, E->key + 24, 32);
|
||||
sha1 (buf, 48, sha1d_buffer);
|
||||
|
||||
static unsigned char key[32];
|
||||
memcpy (key, sha1a_buffer + 0, 8);
|
||||
memcpy (key + 8, sha1b_buffer + 8, 12);
|
||||
memcpy (key + 20, sha1c_buffer + 4, 12);
|
||||
|
||||
static unsigned char iv[32];
|
||||
memcpy (iv, sha1a_buffer + 8, 12);
|
||||
memcpy (iv + 12, sha1b_buffer + 0, 8);
|
||||
memcpy (iv + 20, sha1c_buffer + 16, 4);
|
||||
memcpy (iv + 24, sha1d_buffer + 0, 8);
|
||||
|
||||
AES_KEY aes_key;
|
||||
AES_set_encrypt_key (key, 256, &aes_key);
|
||||
AES_ige_encrypt ((void *)encr_ptr, (void *)encr_ptr, 4 * (encr_end - encr_ptr), &aes_key, iv, 1);
|
||||
|
||||
return (void *)msg_key;
|
||||
}
|
||||
|
||||
void encr_start (void) {
|
||||
encr_extra = packet_ptr;
|
||||
packet_ptr += 1; // str len
|
||||
packet_ptr += 2; // fingerprint
|
||||
packet_ptr += 4; // msg_key
|
||||
packet_ptr += 1; // len
|
||||
}
|
||||
|
||||
|
||||
void encr_finish (struct secret_chat *E) {
|
||||
int l = packet_ptr - (encr_extra + 8);
|
||||
while (((packet_ptr - encr_extra) - 3) & 3) {
|
||||
out_int (mrand48 ());
|
||||
}
|
||||
|
||||
*encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe;
|
||||
encr_extra ++;
|
||||
*(long long *)encr_extra = E->key_fingerprint;
|
||||
encr_extra += 2;
|
||||
encr_extra[4] = l * 4;
|
||||
encr_ptr = encr_extra + 4;
|
||||
encr_end = packet_ptr;
|
||||
memcpy (encr_extra, encrypt_decrypted_message (E), 16);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ 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");
|
||||
struct message *M = q->extra;
|
||||
M->date = fetch_int ();
|
||||
message_insert (M);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msg_send_on_answer (struct query *q UU) {
|
||||
assert (fetch_int () == (int)CODE_messages_sent_message);
|
||||
int id = fetch_int (); // id
|
||||
int date = fetch_int (); // date
|
||||
fetch_date ();
|
||||
fetch_pts ();
|
||||
int seq = fetch_int (); // seq
|
||||
fetch_seq ();
|
||||
struct message *M = q->extra;
|
||||
M->id = id;
|
||||
message_insert (M);
|
||||
logprintf ("Sent: id = %d, date = %d, seq = %d\n", id, date, seq);
|
||||
logprintf ("Sent: id = %d\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -631,10 +736,71 @@ struct query_methods msg_send_methods = {
|
||||
.on_answer = msg_send_on_answer
|
||||
};
|
||||
|
||||
struct query_methods msg_send_encr_methods = {
|
||||
.on_answer = msg_send_encr_on_answer
|
||||
};
|
||||
|
||||
int out_message_num;
|
||||
int our_id;
|
||||
void out_peer_id (peer_id_t id);
|
||||
|
||||
void do_send_encr_message (peer_id_t id, const char *msg, int len) {
|
||||
peer_t *P = user_chat_get (id);
|
||||
if (!P) {
|
||||
logprintf ("Can not send to unknown encrypted chat\n");
|
||||
return;
|
||||
}
|
||||
if (P->encr_chat.state != sc_ok) {
|
||||
logprintf ("Chat is not yet initialized\n");
|
||||
return;
|
||||
}
|
||||
clear_packet ();
|
||||
out_int (CODE_messages_send_encrypted);
|
||||
out_int (CODE_input_encrypted_chat);
|
||||
out_int (get_peer_id (id));
|
||||
out_long (P->encr_chat.access_hash);
|
||||
if (!out_message_num) {
|
||||
out_message_num = -lrand48 ();
|
||||
}
|
||||
out_long ((--out_message_num) - (4ll << 32));
|
||||
encr_start ();
|
||||
//out_int (CODE_decrypted_message_layer);
|
||||
//out_int (8);
|
||||
out_int (CODE_decrypted_message);
|
||||
out_long ((out_message_num) - (4ll << 32));
|
||||
static int buf[4];
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
buf[i] = mrand48 ();
|
||||
}
|
||||
out_cstring ((void *)buf, 16);
|
||||
out_cstring ((void *)msg, len);
|
||||
out_int (CODE_decrypted_message_media_empty);
|
||||
encr_finish (&P->encr_chat);
|
||||
|
||||
struct message *M = malloc (sizeof (*M));
|
||||
memset (M, 0, sizeof (*M));
|
||||
M->from_id = MK_USER (our_id);
|
||||
M->to_id = id;
|
||||
M->unread = 1;
|
||||
M->message = malloc (len + 1);
|
||||
memcpy (M->message, msg, len);
|
||||
M->message[len] = 0;
|
||||
M->message_len = len;
|
||||
M->out = 1;
|
||||
M->media.type = CODE_message_media_empty;
|
||||
M->id = (out_message_num) - (4ll << 32);
|
||||
M->date = time (0);
|
||||
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M);
|
||||
print_message (M);
|
||||
}
|
||||
|
||||
void do_send_message (peer_id_t id, const char *msg, int len) {
|
||||
if (get_peer_type (id) == PEER_ENCR_CHAT) {
|
||||
do_send_encr_message (id, msg, len);
|
||||
return;
|
||||
}
|
||||
if (!out_message_num) {
|
||||
out_message_num = -lrand48 ();
|
||||
}
|
||||
@ -659,7 +825,9 @@ void do_send_message (peer_id_t id, const char *msg, int len) {
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M);
|
||||
print_message (M);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Send text file */
|
||||
void do_send_text (peer_id_t id, char *file_name) {
|
||||
int fd = open (file_name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
@ -681,19 +849,29 @@ void do_send_text (peer_id_t id, char *file_name) {
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int mark_read_on_receive (struct query *q UU) {
|
||||
assert (fetch_int () == (int)CODE_messages_affected_history);
|
||||
fetch_int (); // pts
|
||||
fetch_int (); // seq
|
||||
fetch_pts ();
|
||||
fetch_seq ();
|
||||
fetch_int (); // offset
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mark_read_encr_on_receive (struct query *q UU) {
|
||||
fetch_bool ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct query_methods mark_read_methods = {
|
||||
.on_answer = mark_read_on_receive
|
||||
};
|
||||
|
||||
struct query_methods mark_read_encr_methods = {
|
||||
.on_answer = mark_read_encr_on_receive
|
||||
};
|
||||
|
||||
void do_messages_mark_read (peer_id_t id, int max_id) {
|
||||
clear_packet ();
|
||||
out_int (CODE_messages_read_history);
|
||||
@ -703,6 +881,34 @@ void do_messages_mark_read (peer_id_t id, int max_id) {
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0);
|
||||
}
|
||||
|
||||
void do_messages_mark_read_encr (peer_id_t id, long long access_hash, int last_time) {
|
||||
clear_packet ();
|
||||
out_int (CODE_messages_read_encrypted_history);
|
||||
out_int (CODE_input_encrypted_chat);
|
||||
out_int (get_peer_id (id));
|
||||
out_long (access_hash);
|
||||
out_int (last_time);
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, 0);
|
||||
}
|
||||
|
||||
void do_mark_read (peer_id_t id) {
|
||||
peer_t *P = user_chat_get (id);
|
||||
if (!P) {
|
||||
rprintf ("Unknown peer\n");
|
||||
return;
|
||||
}
|
||||
if (!P->last) {
|
||||
rprintf ("Unknown last peer message\n");
|
||||
return;
|
||||
}
|
||||
if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) {
|
||||
do_messages_mark_read (id, P->last->id);
|
||||
return;
|
||||
}
|
||||
assert (get_peer_type (id) == PEER_ENCR_CHAT);
|
||||
do_messages_mark_read_encr (id, P->encr_chat.access_hash, P->last->date);
|
||||
}
|
||||
|
||||
int get_history_on_answer (struct query *q UU) {
|
||||
static struct message *ML[10000];
|
||||
int i;
|
||||
@ -919,8 +1125,8 @@ int send_file_on_answer (struct query *q UU) {
|
||||
for (i = 0; i < n; i++) {
|
||||
fetch_alloc_user ();
|
||||
}
|
||||
fetch_int (); // pts
|
||||
fetch_int (); // seq
|
||||
fetch_pts ();
|
||||
fetch_seq ();
|
||||
print_message (M);
|
||||
return 0;
|
||||
}
|
||||
@ -1029,8 +1235,8 @@ int fwd_msg_on_answer (struct query *q UU) {
|
||||
for (i = 0; i < n; i++) {
|
||||
fetch_alloc_user ();
|
||||
}
|
||||
fetch_int (); // pts
|
||||
fetch_int (); // seq
|
||||
fetch_pts ();
|
||||
fetch_seq ();
|
||||
print_message (M);
|
||||
return 0;
|
||||
}
|
||||
@ -1041,7 +1247,7 @@ struct query_methods fwd_msg_methods = {
|
||||
|
||||
void do_forward_message (peer_id_t id, int n) {
|
||||
clear_packet ();
|
||||
out_int (CODE_invoke_with_layer3);
|
||||
out_int (CODE_invoke_with_layer9);
|
||||
out_int (CODE_messages_forward_message);
|
||||
out_peer_id (id);
|
||||
out_int (n);
|
||||
@ -1063,8 +1269,8 @@ int rename_chat_on_answer (struct query *q UU) {
|
||||
for (i = 0; i < n; i++) {
|
||||
fetch_alloc_user ();
|
||||
}
|
||||
fetch_int (); // pts
|
||||
fetch_int (); // seq
|
||||
fetch_pts ();
|
||||
fetch_seq ();
|
||||
print_message (M);
|
||||
return 0;
|
||||
}
|
||||
@ -1509,3 +1715,241 @@ void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) {
|
||||
out_int (limit);
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, 0);
|
||||
}
|
||||
|
||||
int send_encr_accept_on_answer (struct query *q UU) {
|
||||
struct secret_chat *E = fetch_alloc_encrypted_chat ();
|
||||
|
||||
if (E->state == sc_ok) {
|
||||
print_start ();
|
||||
push_color (COLOR_YELLOW);
|
||||
printf ("Encrypted connection with ");
|
||||
print_encr_chat_name (E->id, (void *)E);
|
||||
printf (" established\n");
|
||||
pop_color ();
|
||||
print_end ();
|
||||
} else {
|
||||
print_start ();
|
||||
push_color (COLOR_YELLOW);
|
||||
printf ("Encrypted connection with ");
|
||||
print_encr_chat_name (E->id, (void *)E);
|
||||
printf (" failed\n");
|
||||
pop_color ();
|
||||
print_end ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct query_methods send_encr_accept_methods = {
|
||||
.on_answer = send_encr_accept_on_answer
|
||||
};
|
||||
|
||||
int encr_root;
|
||||
unsigned char *encr_prime;
|
||||
int encr_param_version;
|
||||
BN_CTX *ctx;
|
||||
|
||||
void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
|
||||
int i;
|
||||
for (i = 0; i < 64; i++) {
|
||||
*(((int *)random) + i) ^= mrand48 ();
|
||||
}
|
||||
BIGNUM *b = BN_bin2bn (random, 256, 0);
|
||||
assert (b);
|
||||
BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0);
|
||||
assert (g_a);
|
||||
if (!ctx) {
|
||||
ctx = BN_CTX_new ();
|
||||
BN_CTX_init (ctx);
|
||||
}
|
||||
BIGNUM *p = BN_bin2bn (encr_prime, 256, 0);
|
||||
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 sha_buffer[20];
|
||||
sha1 ((void *)E->key, 256, sha_buffer);
|
||||
E->key_fingerprint = *(long long *)(sha_buffer + 12);
|
||||
|
||||
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);
|
||||
|
||||
BN_set_word (g_a, encr_root);
|
||||
BN_mod_exp (r, g_a, b, p, ctx);
|
||||
static unsigned char buf[256];
|
||||
memset (buf, 0, sizeof (buf));
|
||||
BN_bn2bin (r, buf);
|
||||
out_cstring ((void *)buf, 256);
|
||||
|
||||
out_long (E->key_fingerprint);
|
||||
BN_clear_free (b);
|
||||
BN_clear_free (g_a);
|
||||
BN_clear_free (p);
|
||||
BN_clear_free (r);
|
||||
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E);
|
||||
}
|
||||
|
||||
int get_dh_config_on_answer (struct query *q UU) {
|
||||
unsigned x = fetch_int ();
|
||||
assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified);
|
||||
if (x == CODE_messages_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 ();
|
||||
}
|
||||
int l = prefetch_strlen ();
|
||||
assert (l == 256);
|
||||
unsigned char *random = (void *)fetch_str_dup ();
|
||||
if (q->extra) {
|
||||
do_send_accept_encr_chat (q->extra, random);
|
||||
free (random);
|
||||
} else {
|
||||
free (random);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct query_methods get_dh_config_methods = {
|
||||
.on_answer = get_dh_config_on_answer
|
||||
};
|
||||
|
||||
void do_accept_encr_chat_request (struct secret_chat *E) {
|
||||
assert (E->state == sc_request);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int unread_messages;
|
||||
int difference_got;
|
||||
int seq, pts, qts, last_date;
|
||||
int get_state_on_answer (struct query *q UU) {
|
||||
assert (fetch_int () == (int)CODE_updates_state);
|
||||
pts = fetch_int ();
|
||||
qts = fetch_int ();
|
||||
last_date = fetch_int ();
|
||||
seq = fetch_int ();
|
||||
unread_messages = fetch_int ();
|
||||
write_state_file ();
|
||||
difference_got = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_difference_on_answer (struct query *q UU) {
|
||||
unsigned x = fetch_int ();
|
||||
if (x == CODE_updates_difference_empty) {
|
||||
fetch_date ();
|
||||
fetch_seq ();
|
||||
difference_got = 1;
|
||||
} else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) {
|
||||
int n, i;
|
||||
assert (fetch_int () == CODE_vector);
|
||||
n = fetch_int ();
|
||||
static struct message *ML[10000];
|
||||
int ml_pos = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (ml_pos < 10000) {
|
||||
ML[ml_pos ++] = fetch_alloc_message ();
|
||||
} else {
|
||||
fetch_alloc_message ();
|
||||
}
|
||||
}
|
||||
assert (fetch_int () == CODE_vector);
|
||||
n = fetch_int ();
|
||||
for (i = 0; i < n; i++) {
|
||||
if (ml_pos < 10000) {
|
||||
ML[ml_pos ++] = fetch_alloc_encrypted_message ();
|
||||
} else {
|
||||
fetch_alloc_encrypted_message ();
|
||||
}
|
||||
}
|
||||
assert (fetch_int () == CODE_vector);
|
||||
n = fetch_int ();
|
||||
for (i = 0; i < n; i++) {
|
||||
work_update (0, 0);
|
||||
}
|
||||
assert (fetch_int () == CODE_vector);
|
||||
n = fetch_int ();
|
||||
for (i = 0; i < n; i++) {
|
||||
fetch_alloc_chat ();
|
||||
}
|
||||
assert (fetch_int () == CODE_vector);
|
||||
n = fetch_int ();
|
||||
for (i = 0; i < n; i++) {
|
||||
fetch_alloc_user ();
|
||||
}
|
||||
assert (fetch_int () == (int)CODE_updates_state);
|
||||
pts = fetch_int ();
|
||||
qts = fetch_int ();
|
||||
last_date = fetch_int ();
|
||||
seq = fetch_int ();
|
||||
unread_messages = fetch_int ();
|
||||
write_state_file ();
|
||||
for (i = 0; i < ml_pos; i++) {
|
||||
print_message (ML[i]);
|
||||
}
|
||||
if (x == CODE_updates_difference_slice) {
|
||||
do_get_difference ();
|
||||
} else {
|
||||
difference_got = 1;
|
||||
}
|
||||
} else {
|
||||
assert (0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct query_methods get_state_methods = {
|
||||
.on_answer = get_state_on_answer
|
||||
};
|
||||
|
||||
struct query_methods get_difference_methods = {
|
||||
.on_answer = get_difference_on_answer
|
||||
};
|
||||
|
||||
void do_get_difference (void) {
|
||||
difference_got = 0;
|
||||
clear_packet ();
|
||||
out_int (CODE_invoke_with_layer9);
|
||||
out_int (CODE_init_connection);
|
||||
out_int (TG_APP_ID);
|
||||
if (allow_send_linux_version) {
|
||||
struct utsname st;
|
||||
uname (&st);
|
||||
out_string (st.machine);
|
||||
static char buf[1000000];
|
||||
sprintf (buf, "%s %s %s", st.sysname, st.release, st.version);
|
||||
out_string (buf);
|
||||
out_string (TG_VERSION " (build " TG_BUILD ")");
|
||||
out_string ("En");
|
||||
} else {
|
||||
out_string ("x86");
|
||||
out_string ("Linux");
|
||||
out_string (TG_VERSION);
|
||||
out_string ("en");
|
||||
}
|
||||
if (seq > 0) {
|
||||
out_int (CODE_updates_get_difference);
|
||||
out_int (pts);
|
||||
out_int (last_date);
|
||||
out_int (qts);
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, 0);
|
||||
} else {
|
||||
out_int (CODE_updates_get_state);
|
||||
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0);
|
||||
}
|
||||
}
|
||||
|
@ -94,5 +94,8 @@ void do_import_auth (int num);
|
||||
void do_export_auth (int num);
|
||||
void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force);
|
||||
void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s);
|
||||
void do_accept_encr_chat_request (struct secret_chat *E);
|
||||
void do_get_difference (void);
|
||||
void do_mark_read (peer_id_t id);
|
||||
|
||||
#endif
|
||||
|
434
structures.c
434
structures.c
@ -32,6 +32,10 @@
|
||||
int verbosity;
|
||||
peer_t *Peers[MAX_USER_NUM];
|
||||
|
||||
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) {
|
||||
@ -68,8 +72,63 @@ void fetch_user_status (struct user_status *S) {
|
||||
}
|
||||
|
||||
int our_id;
|
||||
int user_num;
|
||||
int chat_num;
|
||||
|
||||
char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) {
|
||||
const char *d[4];
|
||||
d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4;
|
||||
static char buf[10000];
|
||||
int i;
|
||||
int p = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (d[i] && strlen (d[i])) {
|
||||
p += snprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]);
|
||||
assert (p < 9990);
|
||||
}
|
||||
}
|
||||
char *s = buf;
|
||||
while (*s) {
|
||||
if (*s == ' ') { *s = '_'; }
|
||||
s++;
|
||||
}
|
||||
s = buf;
|
||||
int cc = 0;
|
||||
while (1) {
|
||||
int ok = 1;
|
||||
int i;
|
||||
for (i = 0; i < peer_num; i++) {
|
||||
if (cmp_peer_id (Peers[i]->id, id) && Peers[i]->print_name && !strcmp (Peers[i]->print_name, s)) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
cc ++;
|
||||
assert (cc <= 99);
|
||||
if (cc == 1) {
|
||||
int l = strlen (s);
|
||||
s[l + 2] = 0;
|
||||
s[l] = '#';
|
||||
s[l + 1] = '1';
|
||||
} else if (cc == 10) {
|
||||
int l = strlen (s);
|
||||
s[l + 1] = 0;
|
||||
s[l] = '0';
|
||||
s[l - 1] = '1';
|
||||
} else {
|
||||
int l = strlen (s);
|
||||
s[l - 1] ++;
|
||||
int cc = l - 1;
|
||||
while (s[cc] > '9') {
|
||||
s[cc] = '0';
|
||||
s[cc - 1] ++;
|
||||
cc --;
|
||||
}
|
||||
}
|
||||
}
|
||||
return strdup (s);
|
||||
}
|
||||
|
||||
void fetch_user (struct user *U) {
|
||||
unsigned x = fetch_int ();
|
||||
@ -92,67 +151,8 @@ void fetch_user (struct user *U) {
|
||||
if (U->print_name) { free (U->print_name); }
|
||||
U->first_name = fetch_str_dup ();
|
||||
U->last_name = fetch_str_dup ();
|
||||
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);
|
||||
}
|
||||
}
|
||||
char *s = U->print_name;
|
||||
while (*s) {
|
||||
if (*s == ' ') { *s = '_'; }
|
||||
s++;
|
||||
}
|
||||
int cc = 0;
|
||||
while (1) {
|
||||
int ok = 1;
|
||||
int i;
|
||||
for (i = 0; i < user_num + chat_num; i++) {
|
||||
if (Peers[i] != (void *)U && Peers[i]->print_name && !strcmp (Peers[i]->print_name, U->print_name)) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
cc ++;
|
||||
assert (cc <= 99);
|
||||
if (cc == 1) {
|
||||
int l = strlen (U->print_name);
|
||||
char *s = malloc (l + 3);
|
||||
memcpy (s, U->print_name, l);
|
||||
s[l + 2] = 0;
|
||||
s[l] = '#';
|
||||
s[l + 1] = '1';
|
||||
free (U->print_name);
|
||||
U->print_name = s;
|
||||
} else if (cc == 10) {
|
||||
int l = strlen (U->print_name);
|
||||
char *s = malloc (l + 2);
|
||||
memcpy (s, U->print_name, l);
|
||||
s[l + 1] = 0;
|
||||
s[l] = '0';
|
||||
s[l - 1] = '1';
|
||||
free (U->print_name);
|
||||
U->print_name = s;
|
||||
} else {
|
||||
int l = strlen (U->print_name);
|
||||
U->print_name[l - 1] ++;
|
||||
if (U->print_name[l - 1] > '9') {
|
||||
U->print_name[l - 1] = '0';
|
||||
U->print_name[l - 2] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -197,47 +197,96 @@ void fetch_encrypted_chat (struct secret_chat *U) {
|
||||
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 ());
|
||||
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;
|
||||
}
|
||||
if (x == CODE_encrypted_chat_discarded) {
|
||||
U->state = sc_deleted;
|
||||
U->flags |= FLAG_DELETED;
|
||||
if (U->state != old_state) {
|
||||
write_secret_chat_file ();
|
||||
}
|
||||
return;
|
||||
}
|
||||
U->access_hash = fetch_long ();
|
||||
U->date = fetch_int ();
|
||||
U->admin_id = fetch_int ();
|
||||
U->user_id = fetch_int () + U->admin_id - our_id;
|
||||
if (U->print_name) { 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 (x == CODE_encrypted_chat_waiting) {
|
||||
U->state = sc_waiting;
|
||||
} else if (x == CODE_encrypted_chat_requested) {
|
||||
U->state = sc_request;
|
||||
if (!U->g_key) {
|
||||
U->g_key = malloc (256);
|
||||
U->g_key = malloc (256);
|
||||
}
|
||||
memset (U->g_key, 0, 256);
|
||||
if (!U->nonce) {
|
||||
U->nonce = malloc (256);
|
||||
}
|
||||
assert (prefetch_strlen () == 256);
|
||||
memcpy (U->g_key, fetch_str (256), 256);
|
||||
assert (prefetch_strlen () == 256);
|
||||
memcpy (U->nonce, fetch_str (256), 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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
assert (prefetch_strlen () == 256);
|
||||
memcpy (U->g_key, fetch_str (256), 256);
|
||||
assert (prefetch_strlen () == 256);
|
||||
memcpy (U->nonce, fetch_str (256), 256);
|
||||
U->key_fingerprint = fetch_long ();
|
||||
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 (U->state != old_state) {
|
||||
write_secret_chat_file ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,12 +343,7 @@ void fetch_chat (struct chat *C) {
|
||||
if (C->title) { free (C->title); }
|
||||
if (C->print_title) { free (C->print_title); }
|
||||
C->title = fetch_str_dup ();
|
||||
C->print_title = strdup (C->title);
|
||||
char *s = C->print_title;
|
||||
while (*s) {
|
||||
if (*s == ' ') { *s = '_'; }
|
||||
s ++;
|
||||
}
|
||||
C->print_title = create_print_name (C->id, C->title, 0, 0, 0);
|
||||
if (x == CODE_chat) {
|
||||
unsigned y = fetch_int ();
|
||||
if (y == CODE_chat_photo_empty) {
|
||||
@ -499,9 +543,9 @@ void fetch_message_short (struct message *M) {
|
||||
M->to_id = MK_USER (our_id);
|
||||
M->from_id = MK_USER (fetch_int ());
|
||||
M->message = fetch_str_dup ();
|
||||
fetch_int (); // pts
|
||||
fetch_pts ();
|
||||
M->date = fetch_int ();
|
||||
fetch_int (); // seq
|
||||
fetch_seq ();
|
||||
M->media.type = CODE_message_media_empty;
|
||||
M->unread = 1;
|
||||
}
|
||||
@ -512,9 +556,9 @@ void fetch_message_short_chat (struct message *M) {
|
||||
M->from_id = MK_USER (fetch_int ());
|
||||
M->to_id = MK_CHAT (fetch_int ());
|
||||
M->message = fetch_str_dup ();
|
||||
fetch_int (); // pts
|
||||
fetch_pts ();
|
||||
M->date = fetch_int ();
|
||||
fetch_int (); // seq
|
||||
fetch_seq ();
|
||||
M->media.type = CODE_message_media_empty;
|
||||
M->unread = 1;
|
||||
}
|
||||
@ -554,7 +598,7 @@ void fetch_message_media_encrypted (struct message_media *M) {
|
||||
memset (M, 0, sizeof (*M));
|
||||
unsigned x = fetch_int ();
|
||||
int l;
|
||||
switch (M->type) {
|
||||
switch (x) {
|
||||
case CODE_decrypted_message_media_empty:
|
||||
M->type = CODE_message_media_empty;
|
||||
break;
|
||||
@ -567,15 +611,25 @@ void fetch_message_media_encrypted (struct message_media *M) {
|
||||
M->encr_photo.w = fetch_int ();
|
||||
M->encr_photo.h = fetch_int ();
|
||||
M->encr_photo.size = fetch_int ();
|
||||
l = fetch_int ();
|
||||
assert (l > 0);
|
||||
M->encr_photo.key = malloc (l);
|
||||
memcpy (M->encr_photo.key, fetch_str (l), l);
|
||||
|
||||
l = fetch_int ();
|
||||
l = prefetch_strlen ();
|
||||
assert (l > 0);
|
||||
M->encr_photo.iv = malloc (l);
|
||||
memcpy (M->encr_photo.iv, fetch_str (l), l);
|
||||
M->encr_photo.key = malloc (32);
|
||||
memset (M->encr_photo.key, 0, 32);
|
||||
if (l <= 32) {
|
||||
memcpy (M->encr_photo.key + (32 - l), fetch_str (l), l);
|
||||
} else {
|
||||
memcpy (M->encr_photo.key, fetch_str (l) + (l - 32), 32);
|
||||
}
|
||||
M->encr_photo.iv = malloc (32);
|
||||
l = prefetch_strlen ();
|
||||
assert (l > 0);
|
||||
memset (M->encr_photo.iv, 0, 32);
|
||||
if (l <= 32) {
|
||||
memcpy (M->encr_photo.iv + (32 - l), fetch_str (l), l);
|
||||
} else {
|
||||
memcpy (M->encr_photo.iv, fetch_str (l) + (l - 32), 32);
|
||||
}
|
||||
break;
|
||||
case CODE_decrypted_message_media_video:
|
||||
M->type = x;
|
||||
@ -587,15 +641,25 @@ void fetch_message_media_encrypted (struct message_media *M) {
|
||||
M->encr_video.h = fetch_int ();
|
||||
M->encr_video.size = fetch_int ();
|
||||
M->encr_video.duration = fetch_int ();
|
||||
l = fetch_int ();
|
||||
assert (l > 0);
|
||||
M->encr_video.key = malloc (l);
|
||||
memcpy (M->encr_video.key, fetch_str (l), l);
|
||||
|
||||
l = fetch_int ();
|
||||
l = prefetch_strlen ();
|
||||
assert (l > 0);
|
||||
M->encr_video.iv = malloc (l);
|
||||
memcpy (M->encr_video.iv, fetch_str (l), l);
|
||||
M->encr_video.key = malloc (32);
|
||||
memset (M->encr_photo.key, 0, 32);
|
||||
if (l <= 32) {
|
||||
memcpy (M->encr_video.key + (32 - l), fetch_str (l), l);
|
||||
} else {
|
||||
memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32);
|
||||
}
|
||||
M->encr_video.iv = malloc (32);
|
||||
l = prefetch_strlen ();
|
||||
assert (l > 0);
|
||||
memset (M->encr_video.iv, 0, 32);
|
||||
if (l <= 32) {
|
||||
memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l);
|
||||
} else {
|
||||
memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32);
|
||||
}
|
||||
break;
|
||||
/* case CODE_decrypted_message_media_file:
|
||||
M->type = x;
|
||||
@ -719,24 +783,26 @@ int decrypt_encrypted_message (struct secret_chat *E) {
|
||||
memcpy (buf + 16, E->key + 24, 32);
|
||||
sha1 (buf, 48, sha1d_buffer);
|
||||
|
||||
static unsigned char iv[32];
|
||||
memcpy (iv, sha1a_buffer + 0, 8);
|
||||
memcpy (iv + 8, sha1b_buffer + 8, 12);
|
||||
memcpy (iv + 20, sha1c_buffer + 4, 12);
|
||||
|
||||
static unsigned char key[32];
|
||||
memcpy (key, sha1a_buffer + 8, 12);
|
||||
memcpy (key + 12, sha1b_buffer + 0, 8);
|
||||
memcpy (key + 20, sha1c_buffer + 16, 4);
|
||||
memcpy (key + 24, sha1d_buffer + 0, 8);
|
||||
memcpy (key, sha1a_buffer + 0, 8);
|
||||
memcpy (key + 8, sha1b_buffer + 8, 12);
|
||||
memcpy (key + 20, sha1c_buffer + 4, 12);
|
||||
|
||||
static unsigned char iv[32];
|
||||
memcpy (iv, sha1a_buffer + 8, 12);
|
||||
memcpy (iv + 12, sha1b_buffer + 0, 8);
|
||||
memcpy (iv + 20, sha1c_buffer + 16, 4);
|
||||
memcpy (iv + 24, sha1d_buffer + 0, 8);
|
||||
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key (key, 256, &aes_key);
|
||||
AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0);
|
||||
|
||||
sha1 ((void *)decr_ptr, 4 * (decr_end - decr_ptr), sha1a_buffer);
|
||||
int x = *(decr_ptr);
|
||||
assert (x >= 0 && !(x & 3));
|
||||
sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer);
|
||||
|
||||
if (memcmp (sha1a_buffer, msg_key, 16)) {
|
||||
if (memcmp (sha1a_buffer + 4, msg_key, 16)) {
|
||||
logprintf ("Sha1 mismatch\n");
|
||||
return -1;
|
||||
}
|
||||
@ -747,40 +813,72 @@ void fetch_encrypted_message (struct message *M) {
|
||||
memset (M, 0, sizeof (*M));
|
||||
unsigned x = fetch_int ();
|
||||
assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service);
|
||||
peer_id_t chat = MK_ENCR_CHAT (fetch_int ());
|
||||
unsigned sx = x;
|
||||
M->id = fetch_long ();
|
||||
peer_id_t chat = MK_ENCR_CHAT (fetch_int ());
|
||||
M->to_id = chat;
|
||||
peer_t *P = user_chat_get (chat);
|
||||
if (!P) {
|
||||
logprintf ("Encrypted message to unknown chat. Dropping\n");
|
||||
M->flags |= FLAG_EMPTY;
|
||||
}
|
||||
M->date = fetch_int ();
|
||||
|
||||
|
||||
int len = prefetch_strlen ();
|
||||
assert (!(len & 15));
|
||||
assert ((len & 15) == 8);
|
||||
decr_ptr = (void *)fetch_str (len);
|
||||
decr_end = in_ptr;
|
||||
decr_end = decr_ptr + (len / 4);
|
||||
M->flags |= FLAG_ENCRYPTED;
|
||||
int ok = 0;
|
||||
if (P) {
|
||||
if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) {
|
||||
logprintf ("Encrypted message with bad fingerprint to chat %s\n", P->print_name);
|
||||
P = 0;
|
||||
}
|
||||
decr_ptr += 2;
|
||||
}
|
||||
if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) {
|
||||
ok = 1;
|
||||
int *save_in_ptr = in_ptr;
|
||||
int *save_in_end = in_end;
|
||||
in_ptr = decr_ptr;
|
||||
int l = fetch_int ();
|
||||
in_end = in_ptr + l;
|
||||
unsigned x = fetch_int ();
|
||||
if (x == CODE_decrypted_message_layer) {
|
||||
int layer = fetch_int ();
|
||||
assert (layer >= 0);
|
||||
x = fetch_int ();
|
||||
}
|
||||
assert (x == CODE_decrypted_message);
|
||||
assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service);
|
||||
assert (M->id = fetch_long ());
|
||||
int l = prefetch_strlen ();
|
||||
l = prefetch_strlen ();
|
||||
fetch_str (l); // random_bytes
|
||||
M->from_id = MK_USER (fetch_int ());
|
||||
M->date = fetch_int ();
|
||||
if (x == CODE_decrypted_message) {
|
||||
M->message = fetch_str_dup ();
|
||||
fetch_encrypted_message_file (&M->media);
|
||||
fetch_message_media_encrypted (&M->media);
|
||||
} else {
|
||||
assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l);
|
||||
P->encr_chat.ttl = fetch_int ();
|
||||
M->service = 1;
|
||||
}
|
||||
in_ptr = save_in_ptr;
|
||||
in_end = save_in_end;
|
||||
}
|
||||
|
||||
if (sx == CODE_encrypted_message) {
|
||||
if (ok) {
|
||||
fetch_encrypted_message_file (&M->media);
|
||||
} else {
|
||||
x = fetch_int ();
|
||||
if (x == CODE_encrypted_file) {
|
||||
fetch_skip (7);
|
||||
} else {
|
||||
assert (x == CODE_encrypted_file_empty);
|
||||
}
|
||||
M->media.type = CODE_message_media_empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -793,7 +891,8 @@ void fetch_encrypted_message_file (struct message_media *M) {
|
||||
assert (M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video);
|
||||
M->encr_photo.id = fetch_long ();
|
||||
M->encr_photo.access_hash = fetch_long ();
|
||||
assert (M->encr_photo.size == fetch_int ());
|
||||
//assert (M->encr_photo.size == fetch_int ());
|
||||
M->encr_photo.size = fetch_int (); // Why it is not the same?
|
||||
M->encr_photo.dc_id = fetch_int ();
|
||||
M->encr_photo.key_fingerprint = fetch_int ();
|
||||
|
||||
@ -813,8 +912,6 @@ DEFINE_TREE(message,struct message *,id_cmp,0)
|
||||
struct tree_peer *peer_tree;
|
||||
struct tree_message *message_tree;
|
||||
|
||||
int chat_num;
|
||||
int user_num;
|
||||
int users_allocated;
|
||||
int chats_allocated;
|
||||
int messages_allocated;
|
||||
@ -837,7 +934,7 @@ struct user *fetch_alloc_user (void) {
|
||||
memset (U, 0, sizeof (*U));
|
||||
fetch_user (&U->user);
|
||||
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
|
||||
Peers[chat_num + (user_num ++)] = U;
|
||||
Peers[peer_num ++] = U;
|
||||
return &U->user;
|
||||
}
|
||||
}
|
||||
@ -850,16 +947,22 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) {
|
||||
fetch_encrypted_chat (&U->encr_chat);
|
||||
return &U->encr_chat;
|
||||
} else {
|
||||
chats_allocated ++;
|
||||
encr_chats_allocated ++;
|
||||
U = malloc (sizeof (*U));
|
||||
memset (U, 0, sizeof (*U));
|
||||
fetch_encrypted_chat (&U->encr_chat);
|
||||
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
|
||||
Peers[(chat_num ++) + user_num] = U;
|
||||
Peers[peer_num ++] = U;
|
||||
return &U->encr_chat;
|
||||
}
|
||||
}
|
||||
|
||||
void insert_encrypted_chat (peer_t *P) {
|
||||
encr_chats_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);
|
||||
@ -874,7 +977,7 @@ struct user *fetch_alloc_user_full (void) {
|
||||
U->id = MK_USER (data[2]);
|
||||
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
|
||||
fetch_user_full (&U->user);
|
||||
Peers[chat_num + (user_num ++ )] = U;
|
||||
Peers[peer_num ++] = U;
|
||||
return &U->user;
|
||||
}
|
||||
}
|
||||
@ -938,6 +1041,8 @@ void free_message_media (struct message_media *M) {
|
||||
free (M->encr_video.key);
|
||||
free (M->encr_video.iv);
|
||||
return;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
logprintf ("%08x\n", M->type);
|
||||
assert (0);
|
||||
@ -964,6 +1069,8 @@ void free_message_action (struct message_action *M) {
|
||||
break;
|
||||
case CODE_message_action_chat_delete_user:
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
assert (0);
|
||||
}
|
||||
@ -990,6 +1097,61 @@ void message_add_use (struct message *M) {
|
||||
M->prev_use->next_use = M;
|
||||
}
|
||||
|
||||
void message_add_peer (struct message *M) {
|
||||
peer_id_t id;
|
||||
if (!cmp_peer_id (M->to_id, MK_USER (our_id))) {
|
||||
id = M->from_id;
|
||||
} else {
|
||||
id = M->to_id;
|
||||
}
|
||||
peer_t *P = user_chat_get (id);
|
||||
if (!P) {
|
||||
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 ++;
|
||||
break;
|
||||
case PEER_CHAT:
|
||||
chats_allocated ++;
|
||||
break;
|
||||
case PEER_GEO_CHAT:
|
||||
geo_chats_allocated ++;
|
||||
break;
|
||||
case PEER_ENCR_CHAT:
|
||||
encr_chats_allocated ++;
|
||||
break;
|
||||
}
|
||||
peer_tree = tree_insert_peer (peer_tree, P, lrand48 ());
|
||||
Peers[peer_num ++] = P;
|
||||
}
|
||||
M->next = P->last;
|
||||
if (M->next) { M->next->prev = M; }
|
||||
M->prev = 0;
|
||||
P->last = M;
|
||||
}
|
||||
|
||||
void message_del_peer (struct message *M) {
|
||||
peer_id_t id;
|
||||
if (!cmp_peer_id (M->to_id, MK_USER (our_id))) {
|
||||
id = M->from_id;
|
||||
} else {
|
||||
id = M->to_id;
|
||||
}
|
||||
peer_t *P = user_chat_get (id);
|
||||
if (M->prev) {
|
||||
M->prev->next = M->next;
|
||||
}
|
||||
if (M->next) {
|
||||
M->next->prev = M->prev;
|
||||
}
|
||||
if (P && P->last == M) {
|
||||
P->last = M->next;
|
||||
}
|
||||
}
|
||||
|
||||
struct message *fetch_alloc_message (void) {
|
||||
struct message *M = malloc (sizeof (*M));
|
||||
fetch_message (M);
|
||||
@ -997,14 +1159,17 @@ struct message *fetch_alloc_message (void) {
|
||||
messages_allocated ++;
|
||||
if (M1) {
|
||||
message_del_use (M1);
|
||||
message_del_peer (M1);
|
||||
free_message (M1);
|
||||
memcpy (M1, M, sizeof (*M));
|
||||
free (M);
|
||||
message_add_use (M1);
|
||||
message_add_peer (M1);
|
||||
messages_allocated --;
|
||||
return M1;
|
||||
} else {
|
||||
message_add_use (M);
|
||||
message_add_peer (M);
|
||||
message_tree = tree_insert_message (message_tree, M, lrand48 ());
|
||||
return M;
|
||||
}
|
||||
@ -1017,14 +1182,17 @@ struct message *fetch_alloc_geo_message (void) {
|
||||
messages_allocated ++;
|
||||
if (M1) {
|
||||
message_del_use (M1);
|
||||
message_del_peer (M1);
|
||||
free_message (M1);
|
||||
memcpy (M1, M, sizeof (*M));
|
||||
free (M);
|
||||
message_add_use (M1);
|
||||
message_add_peer (M1);
|
||||
messages_allocated --;
|
||||
return M1;
|
||||
} else {
|
||||
message_add_use (M);
|
||||
message_add_peer (M);
|
||||
message_tree = tree_insert_message (message_tree, M, lrand48 ());
|
||||
return M;
|
||||
}
|
||||
@ -1037,14 +1205,17 @@ struct message *fetch_alloc_encrypted_message (void) {
|
||||
messages_allocated ++;
|
||||
if (M1) {
|
||||
message_del_use (M1);
|
||||
message_del_peer (M1);
|
||||
free_message (M1);
|
||||
memcpy (M1, M, sizeof (*M));
|
||||
free (M);
|
||||
message_add_use (M1);
|
||||
message_add_peer (M1);
|
||||
messages_allocated --;
|
||||
return M1;
|
||||
} else {
|
||||
message_add_use (M);
|
||||
message_add_peer (M);
|
||||
message_tree = tree_insert_message (message_tree, M, lrand48 ());
|
||||
return M;
|
||||
}
|
||||
@ -1057,14 +1228,17 @@ struct message *fetch_alloc_message_short (void) {
|
||||
messages_allocated ++;
|
||||
if (M1) {
|
||||
message_del_use (M1);
|
||||
message_del_peer (M1);
|
||||
free_message (M1);
|
||||
memcpy (M1, M, sizeof (*M));
|
||||
free (M);
|
||||
message_add_use (M1);
|
||||
message_add_peer (M1);
|
||||
messages_allocated --;
|
||||
return M1;
|
||||
} else {
|
||||
message_add_use (M);
|
||||
message_add_peer (M);
|
||||
message_tree = tree_insert_message (message_tree, M, lrand48 ());
|
||||
return M;
|
||||
}
|
||||
@ -1080,14 +1254,17 @@ struct message *fetch_alloc_message_short_chat (void) {
|
||||
messages_allocated ++;
|
||||
if (M1) {
|
||||
message_del_use (M1);
|
||||
message_del_peer (M1);
|
||||
free_message (M1);
|
||||
memcpy (M1, M, sizeof (*M));
|
||||
free (M);
|
||||
message_add_use (M1);
|
||||
message_add_peer (M1);
|
||||
messages_allocated --;
|
||||
return M1;
|
||||
} else {
|
||||
message_add_use (M);
|
||||
message_add_peer (M);
|
||||
message_tree = tree_insert_message (message_tree, M, lrand48 ());
|
||||
return M;
|
||||
}
|
||||
@ -1106,7 +1283,7 @@ struct chat *fetch_alloc_chat (void) {
|
||||
memset (U, 0, sizeof (*U));
|
||||
fetch_chat (&U->chat);
|
||||
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
|
||||
Peers[(chat_num ++) + user_num] = U;
|
||||
Peers[peer_num ++] = U;
|
||||
return &U->chat;
|
||||
}
|
||||
}
|
||||
@ -1125,7 +1302,7 @@ struct chat *fetch_alloc_chat_full (void) {
|
||||
U->id = MK_CHAT (data[2]);
|
||||
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
|
||||
fetch_chat_full (&U->chat);
|
||||
Peers[(chat_num ++) + user_num] = U;
|
||||
Peers[peer_num ++] = U;
|
||||
return &U->chat;
|
||||
}
|
||||
}
|
||||
@ -1139,9 +1316,13 @@ int print_stat (char *s, int len) {
|
||||
return snprintf (s, len,
|
||||
"users_allocated\t%d\n"
|
||||
"chats_allocated\t%d\n"
|
||||
"secret_chats_allocated\t%d\n"
|
||||
"peer_num\t%d\n"
|
||||
"messages_allocated\t%d\n",
|
||||
users_allocated,
|
||||
chats_allocated,
|
||||
encr_chats_allocated,
|
||||
peer_num,
|
||||
messages_allocated
|
||||
);
|
||||
}
|
||||
@ -1166,5 +1347,6 @@ void update_message_id (struct message *M, long long id) {
|
||||
|
||||
void message_insert (struct message *M) {
|
||||
message_add_use (M);
|
||||
message_add_peer (M);
|
||||
message_tree = tree_insert_message (message_tree, M, lrand48 ());
|
||||
}
|
||||
|
55
structures.h
55
structures.h
@ -20,7 +20,7 @@
|
||||
#define __STRUCTURES_H__
|
||||
|
||||
#include <assert.h>
|
||||
typedef struct { int id; } peer_id_t;
|
||||
typedef struct { int type; int id; } peer_id_t;
|
||||
|
||||
#define FLAG_EMPTY 1
|
||||
#define FLAG_DELETED 2
|
||||
@ -111,6 +111,7 @@ struct user_status {
|
||||
struct user {
|
||||
peer_id_t id;
|
||||
int flags;
|
||||
struct message *last;
|
||||
char *print_name;
|
||||
struct file_location photo_big;
|
||||
struct file_location photo_small;
|
||||
@ -134,6 +135,7 @@ struct chat_user {
|
||||
struct chat {
|
||||
peer_id_t id;
|
||||
int flags;
|
||||
struct message *last;
|
||||
char *print_title;
|
||||
struct file_location photo_big;
|
||||
struct file_location photo_small;
|
||||
@ -157,6 +159,7 @@ enum secret_chat_state {
|
||||
struct secret_chat {
|
||||
peer_id_t id;
|
||||
int flags;
|
||||
struct message *last;
|
||||
char *print_name;
|
||||
struct file_location photo_big;
|
||||
struct file_location photo_small;
|
||||
@ -178,6 +181,7 @@ typedef union peer {
|
||||
struct {
|
||||
peer_id_t id;
|
||||
int flags;
|
||||
struct message *last;
|
||||
char *print_name;
|
||||
struct file_location photo_big;
|
||||
struct file_location photo_small;
|
||||
@ -237,6 +241,7 @@ struct message_media {
|
||||
|
||||
struct message {
|
||||
struct message *next_use, *prev_use;
|
||||
struct message *next, *prev;
|
||||
long long id;
|
||||
int flags;
|
||||
peer_id_t fwd_from_id;
|
||||
@ -283,6 +288,7 @@ void update_message_id (struct message *M, long long id);
|
||||
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);
|
||||
|
||||
#define PEER_USER 1
|
||||
#define PEER_CHAT 2
|
||||
@ -296,55 +302,18 @@ void fetch_photo (struct photo *P);
|
||||
#define MK_ENCR_CHAT(id) set_peer_id (PEER_ENCR_CHAT,id)
|
||||
|
||||
static inline int get_peer_type (peer_id_t id) {
|
||||
if (id.id > 1000000000) {
|
||||
return PEER_ENCR_CHAT;
|
||||
}
|
||||
if (id.id > 0) {
|
||||
return PEER_USER;
|
||||
}
|
||||
if (id.id < -1000000000) {
|
||||
return PEER_GEO_CHAT;
|
||||
}
|
||||
if (id.id < 0) {
|
||||
return PEER_CHAT;
|
||||
}
|
||||
return PEER_UNKNOWN;
|
||||
return id.type;
|
||||
}
|
||||
|
||||
static inline int get_peer_id (peer_id_t id) {
|
||||
switch (get_peer_type (id)) {
|
||||
case PEER_USER:
|
||||
return id.id;
|
||||
case PEER_CHAT:
|
||||
return -id.id;
|
||||
case PEER_GEO_CHAT:
|
||||
return -id.id - 1000000000;
|
||||
case PEER_ENCR_CHAT:
|
||||
return id.id - 1000000000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return id.id;
|
||||
}
|
||||
|
||||
static inline peer_id_t set_peer_id (int type, int id) {
|
||||
peer_id_t ID;
|
||||
switch (type) {
|
||||
case PEER_USER:
|
||||
ID.id = id;
|
||||
return ID;
|
||||
case PEER_CHAT:
|
||||
ID.id = -id;
|
||||
return ID;
|
||||
case PEER_GEO_CHAT:
|
||||
ID.id = -id - 1000000000;
|
||||
return ID;
|
||||
case PEER_ENCR_CHAT:
|
||||
ID.id = id + 1000000000;
|
||||
return ID;
|
||||
default:
|
||||
assert (0);
|
||||
return ID;
|
||||
}
|
||||
ID.id = id;
|
||||
ID.type = type;
|
||||
return ID;
|
||||
}
|
||||
|
||||
static inline int cmp_peer_id (peer_id_t a, peer_id_t b) {
|
||||
|
Loading…
Reference in New Issue
Block a user