telegram-purple/loop.c

351 lines
11 KiB
C
Raw Permalink Normal View History

2013-10-23 18:26:17 +04:00
/*
This file is part of telegram-client.
Telegram-client is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Telegram-client is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#define _GNU_SOURCE
#define READLINE_CALLBACKS
2013-10-03 16:38:25 +04:00
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2013-10-03 20:09:06 +04:00
#include <errno.h>
2013-10-12 00:52:20 +04:00
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
2013-10-03 20:09:06 +04:00
2013-10-12 00:52:20 +04:00
#include "net.h"
#include "mtproto-client.h"
#include "queries.h"
#include "telegram.h"
2013-11-04 21:34:27 +04:00
#include "loop.h"
2013-11-13 04:11:25 +04:00
#include "binlog.h"
2013-10-12 00:52:20 +04:00
//
#include "purple-plugin/telegram-purple.h"
//
2013-10-12 00:52:20 +04:00
char *get_auth_key_filename (void);
2013-11-04 21:34:27 +04:00
char *get_state_filename (void);
2013-10-12 00:52:20 +04:00
int zero[512];
void write_dc (int auth_file_fd, struct dc *DC) {
2014-10-03 14:23:15 +02:00
debug("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip);
2013-10-12 00:52:20 +04:00
assert (write (auth_file_fd, &DC->port, 4) == 4);
int l = strlen (DC->ip);
assert (write (auth_file_fd, &l, 4) == 4);
assert (write (auth_file_fd, DC->ip, l) == l);
if (DC->flags & 1) {
assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (write (auth_file_fd, DC->auth_key, 256) == 256);
} else {
assert (write (auth_file_fd, zero, 256 + 8) == 256 + 8);
}
2013-10-12 00:52:20 +04:00
assert (write (auth_file_fd, &DC->server_salt, 8) == 8);
assert (write (auth_file_fd, &DC->has_auth, 4) == 4);
2013-10-12 00:52:20 +04:00
}
2014-07-29 15:28:04 +02:00
void write_auth_file (struct authorization_state *state, const char *filename) {
2014-10-03 14:23:15 +02:00
debug("Writing to auth_file: %s\n", filename);
2014-07-29 15:28:04 +02:00
int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
2013-10-12 00:52:20 +04:00
assert (auth_file_fd >= 0);
int x = DC_SERIALIZED_MAGIC_V2;
2013-10-12 00:52:20 +04:00
assert (write (auth_file_fd, &x, 4) == 4);
x = MAX_DC_ID;
assert (write (auth_file_fd, &x, 4) == 4);
2014-07-29 15:28:04 +02:00
assert (write (auth_file_fd, &state->dc_working_num, 4) == 4);
assert (write (auth_file_fd, &state->auth_state, 4) == 4);
2013-10-12 00:52:20 +04:00
int i;
for (i = 0; i <= MAX_DC_ID; i++) {
2014-07-29 15:28:04 +02:00
if (state->DC_list[i]) {
2013-10-12 00:52:20 +04:00
x = 1;
assert (write (auth_file_fd, &x, 4) == 4);
2014-07-29 15:28:04 +02:00
write_dc (auth_file_fd, state->DC_list[i]);
2013-10-12 00:52:20 +04:00
} else {
x = 0;
assert (write (auth_file_fd, &x, 4) == 4);
}
}
2014-07-29 15:28:04 +02:00
assert (write (auth_file_fd, &state->our_id, 4) == 4);
2013-10-12 00:52:20 +04:00
close (auth_file_fd);
}
2014-07-26 11:55:45 +02:00
void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) {
2013-10-12 00:52:20 +04:00
int port = 0;
assert (read (auth_file_fd, &port, 4) == 4);
int l = 0;
assert (read (auth_file_fd, &l, 4) == 4);
assert (l >= 0);
char *ip = talloc (l + 1);
2013-10-12 00:52:20 +04:00
assert (read (auth_file_fd, ip, l) == l);
ip[l] = 0;
2014-07-26 11:55:45 +02:00
struct dc *DC = alloc_dc (DC_list, id, ip, port);
2013-10-12 00:52:20 +04:00
assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (read (auth_file_fd, &DC->auth_key, 256) == 256);
assert (read (auth_file_fd, &DC->server_salt, 8) == 8);
if (DC->auth_key_id) {
DC->flags |= 1;
}
if (ver != DC_SERIALIZED_MAGIC) {
assert (read (auth_file_fd, &DC->has_auth, 4) == 4);
} else {
DC->has_auth = 0;
}
2013-10-12 00:52:20 +04:00
}
2014-07-26 11:55:45 +02:00
2014-08-06 19:45:46 +02:00
void empty_auth_file (const char *filename) {
struct authorization_state state;
memset(state.DC_list, 0, 11 * sizeof(void *));
2014-10-03 14:23:15 +02:00
debug("empty_auth_file()\n");
alloc_dc (state.DC_list, TG_DC_NUM, tstrdup (TG_SERVER), TG_PORT);
state.dc_working_num = TG_DC_NUM;
2014-08-06 19:45:46 +02:00
state.auth_state = 0;
write_auth_file (&state, filename);
2013-10-12 00:52:20 +04:00
}
2014-07-29 15:28:04 +02:00
/**
* Read the auth-file and return the read authorization state
*
* When the given file doesn't exist, create a new empty
* file containing the default authorization state at this
* path
*/
2014-07-26 11:55:45 +02:00
struct authorization_state read_auth_file (const char *filename) {
2014-10-03 14:23:15 +02:00
debug("read_auth_file()\n");
2014-07-29 15:28:04 +02:00
2014-07-26 11:55:45 +02:00
struct authorization_state state;
2014-07-29 15:28:04 +02:00
memset(state.DC_list, 0, 11 * sizeof(void *));
2014-07-26 11:55:45 +02:00
2014-07-29 15:28:04 +02:00
int auth_file_fd = open (filename, O_RDWR, 0600);
2014-10-03 14:23:15 +02:00
debug("fd: %d\n", auth_file_fd);
2013-10-12 00:52:20 +04:00
if (auth_file_fd < 0) {
2014-10-03 14:23:15 +02:00
debug("auth_file does not exist, creating empty...\n");
2014-08-06 19:45:46 +02:00
empty_auth_file (filename);
2013-10-12 00:52:20 +04:00
}
2014-07-29 15:28:04 +02:00
auth_file_fd = open (filename, O_RDWR, 0600);
2013-10-12 00:52:20 +04:00
assert (auth_file_fd >= 0);
// amount of data centers
unsigned x;
// magic number of file
unsigned m;
if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) {
2014-10-03 14:23:15 +02:00
debug("Invalid File content, wrong Magic numebr\n");
2013-10-12 00:52:20 +04:00
close (auth_file_fd);
2014-08-06 19:45:46 +02:00
empty_auth_file (filename);
2014-07-26 11:55:45 +02:00
return state;
2013-10-12 00:52:20 +04:00
}
assert (read (auth_file_fd, &x, 4) == 4);
assert (x <= MAX_DC_ID);
2014-07-26 11:55:45 +02:00
assert (read (auth_file_fd, &state.dc_working_num, 4) == 4);
assert (read (auth_file_fd, &state.auth_state, 4) == 4);
debug ("dc_working_num=%d, auth_state=%d \n", state.dc_working_num, state.auth_state);
if (m == DC_SERIALIZED_MAGIC) {
2014-07-26 11:55:45 +02:00
state.auth_state = 700;
}
2013-10-12 00:52:20 +04:00
int i;
for (i = 0; i <= (int)x; i++) {
2013-10-12 00:52:20 +04:00
int y;
assert (read (auth_file_fd, &y, 4) == 4);
if (y) {
2014-07-26 11:55:45 +02:00
read_dc (auth_file_fd, i, m, state.DC_list);
2014-10-03 14:23:15 +02:00
debug("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n",
2014-08-06 19:45:46 +02:00
i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id,
state.DC_list[i]->server_salt, state.DC_list[i]->has_auth);
2014-07-29 15:28:04 +02:00
} else {
2014-10-03 14:23:15 +02:00
debug("loaded dc[%d] - NULL\n", i);
2013-10-12 00:52:20 +04:00
}
}
2014-07-26 11:55:45 +02:00
int l = read (auth_file_fd, &state.our_id, 4);
2013-10-18 23:30:24 +04:00
if (l < 4) {
assert (!l);
}
2013-10-12 00:52:20 +04:00
close (auth_file_fd);
2014-07-26 11:55:45 +02:00
struct dc *DC_working = state.DC_list[state.dc_working_num];
if (m == DC_SERIALIZED_MAGIC) {
DC_working->has_auth = 1;
}
2014-10-03 14:23:15 +02:00
debug("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num);
2014-07-26 11:55:45 +02:00
return state;
}
2014-07-26 11:55:45 +02:00
struct protocol_state read_state_file (const char *filename) {
2014-10-03 14:23:15 +02:00
debug("read_state_file()\n");
2014-07-29 15:28:04 +02:00
struct protocol_state state = {0, 0, 0, 0};
int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
2013-11-04 21:34:27 +04:00
if (state_file_fd < 0) {
2014-07-26 11:55:45 +02:00
return state;
2013-11-04 21:34:27 +04:00
}
int version, magic;
2014-07-26 11:55:45 +02:00
if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return state; }
if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return state; }
if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return state; }
2013-11-04 21:34:27 +04:00
assert (version >= 0);
int x[4];
if (read (state_file_fd, x, 16) < 16) {
close (state_file_fd);
2014-07-26 11:55:45 +02:00
return state;
2013-11-04 21:34:27 +04:00
}
2014-07-26 11:55:45 +02:00
state.pts = x[0];
state.qts = x[1];
state.seq = x[2];
state.last_date = x[3];
close (state_file_fd);
2014-10-03 14:23:15 +02:00
debug("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts,
2014-07-29 15:28:04 +02:00
state.qts, state.seq, state.last_date);
2014-07-26 11:55:45 +02:00
return state;
2013-11-04 21:34:27 +04:00
}
2014-07-29 15:28:04 +02:00
void write_state_file (struct protocol_state *state, const char* filename) {
2014-09-01 21:59:23 +02:00
int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
2013-11-04 21:34:27 +04:00
if (state_file_fd < 0) {
return;
}
int x[6];
x[0] = STATE_FILE_MAGIC;
x[1] = 0;
2014-07-29 15:28:04 +02:00
x[2] = state->pts;
x[3] = state->qts;
x[4] = state->seq;
x[5] = state->last_date;
2013-11-04 21:34:27 +04:00
assert (write (state_file_fd, x, 24) == 24);
close (state_file_fd);
2013-11-04 21:34:27 +04:00
}
2014-09-01 21:25:41 +02:00
void read_secret_chat_file (struct telegram *instance, const char *file) {
struct binlog *bl = instance->bl;
2014-07-26 11:55:45 +02:00
int fd = open (file, O_CREAT | O_RDWR, 0600);
2013-11-04 21:34:27 +04:00
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 = talloc0 (sizeof (*P));
2013-11-04 21:34:27 +04:00
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 = talloc (t + 1);
2013-11-04 21:34:27 +04:00
assert (read (fd, P->print_name, t) == t);
P->print_name[t] = 0;
2014-09-01 21:25:41 +02:00
peer_insert_name (bl, P);
2013-11-04 21:34:27 +04:00
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 = talloc (256);
2013-11-04 21:34:27 +04:00
assert (read (fd, E->g_key, 256) == 256);
E->nonce = talloc (256);
2013-11-06 02:24:26 +04:00
assert (read (fd, E->nonce, 256) == 256);
2013-11-04 21:34:27 +04:00
}
assert (read (fd, E->key, 256) == 256);
assert (read (fd, &E->key_fingerprint, 8) == 8);
2014-09-01 21:25:41 +02:00
insert_encrypted_chat (bl, P);
2013-11-04 21:34:27 +04:00
}
if (version >= 1) {
2014-09-01 21:25:41 +02:00
assert (read (fd, &instance->encr_root, 4) == 4);
if (instance->encr_root) {
assert (read (fd, &instance->encr_param_version, 4) == 4);
instance->encr_prime = talloc (256);
assert (read (fd, instance->encr_prime, 256) == 256);
}
}
2013-11-04 21:34:27 +04:00
close (fd);
}
2014-07-26 11:55:45 +02:00
// TODO: Refactor
2014-09-01 21:25:41 +02:00
void write_secret_chat_file (struct telegram *instance, const char *filename) {
struct binlog *bl = instance->bl;
2014-07-26 11:55:45 +02:00
int fd = open (filename, O_CREAT | O_RDWR, 0600);
2013-11-04 21:34:27 +04:00
if (fd < 0) {
return;
}
int x[2];
x[0] = SECRET_CHAT_FILE_MAGIC;
x[1] = 1;
2013-11-04 21:34:27 +04:00
assert (write (fd, x, 8) == 8);
int i;
int cc = 0;
2014-09-01 21:25:41 +02:00
for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) {
if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) {
2013-11-04 21:34:27 +04:00
cc ++;
}
}
assert (write (fd, &cc, 4) == 4);
2014-09-01 21:25:41 +02:00
for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) {
if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) {
int t = get_peer_id (bl->Peers[i]->id);
2013-11-04 21:34:27 +04:00
assert (write (fd, &t, 4) == 4);
2014-09-01 21:25:41 +02:00
t = bl->Peers[i]->flags;
2013-11-04 21:34:27 +04:00
assert (write (fd, &t, 4) == 4);
2014-09-01 21:25:41 +02:00
t = strlen (bl->Peers[i]->print_name);
2013-11-04 21:34:27 +04:00
assert (write (fd, &t, 4) == 4);
2014-09-01 21:25:41 +02:00
assert (write (fd, bl->Peers[i]->print_name, t) == t);
2014-09-01 21:25:41 +02:00
assert (write (fd, &bl->Peers[i]->encr_chat.state, 4) == 4);
2013-11-04 21:34:27 +04:00
2014-09-01 21:25:41 +02:00
assert (write (fd, &bl->Peers[i]->encr_chat.user_id, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.admin_id, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.ttl, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.access_hash, 8) == 8);
if (bl->Peers[i]->encr_chat.state != sc_waiting) {
assert (write (fd, bl->Peers[i]->encr_chat.g_key, 256) == 256);
2013-11-04 21:34:27 +04:00
}
2014-09-01 21:25:41 +02:00
if (bl->Peers[i]->encr_chat.state != sc_waiting) {
assert (write (fd, bl->Peers[i]->encr_chat.nonce, 256) == 256);
2013-11-06 02:24:26 +04:00
}
2014-09-01 21:25:41 +02:00
assert (write (fd, bl->Peers[i]->encr_chat.key, 256) == 256);
assert (write (fd, &bl->Peers[i]->encr_chat.key_fingerprint, 8) == 8);
2013-11-04 21:34:27 +04:00
}
}
2014-09-01 21:25:41 +02:00
assert (write (fd, &instance->encr_root, 4) == 4);
if (instance->encr_root) {
assert (write (fd, &instance->encr_param_version, 4) == 4);
assert (write (fd, instance->encr_prime, 256) == 256);
}
2013-11-04 21:34:27 +04:00
close (fd);
}