diff --git a/Makefile.in b/Makefile.in index 865eb7f..aec2ce2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,6 +53,7 @@ PRPL_CFLAGS = \ -fPIC \ -DPURPLE_PLUGINS \ -DPIC \ + -DDEBUG \ -g \ $(CFLAGS_PURPLE) @@ -84,10 +85,6 @@ plugin: $(PRPL_LIBNAME) strip: $(PRPL_LIBNAME) $(STRIP) --strip-unneeded $(PRPL_LIBNAME) -debug: PRPL_CFLAGS += -g -DDEBUG -debug: $(PRPL_LIBNAME) - gdb -tui -ex 'break telegram-purple.c:tgprpl_login' pidgin - # TODO: Find a better place for server.pub install: $(PRPL_LIBNAME) install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) @@ -108,6 +105,10 @@ uninstall: $(PRPL_LIBNAME) run: install pidgin -d | grep 'telegram\|plugin\|proxy' +.PHONY: debug +debug: install + gdb -tui -ex "$(shell echo $$GDB_BPOINTS )" pidgin + clean: rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" diff --git a/binlog.c b/binlog.c index 13dd663..58d85c1 100644 --- a/binlog.c +++ b/binlog.c @@ -56,7 +56,13 @@ extern int seq; #define MAX_LOG_EVENT_SIZE (1 << 17) +// TODO: remove this completely char *get_binlog_file_name (void); +char *get_binlog_file_name() +{ + return "/home/dev-jessie/.telegram/binlog"; +} + //extern struct dc *DC_list[]; //extern int dc_working_num; extern int our_id; @@ -1162,9 +1168,9 @@ 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); - } + logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); + assert(0); + // TODO: Mit add_log_event_i austauschen assert (!(len & 3)); if (in_replay_log) { return; } rptr = (void *)data; @@ -1185,7 +1191,29 @@ void add_log_event (const int *data, int len) { in_end = end; } -void bl_do_set_auth_key_id (int num, unsigned char *buf) { +void add_log_event_i (struct telegram *instance, const int *data, int len) { + 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; + // TODO: + replay_log_event (instance); + if (rptr != wptr) { + logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); + assert (rptr == wptr); + } + if (binlog_enabled) { + assert (binlog_fd > 0); + assert (write (binlog_fd, data, len) == len); + } + in_ptr = in; + in_end = end; +} + +void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf) { static unsigned char sha1_buffer[20]; SHA1 (buf, 256, sha1_buffer); long long fingerprint = *(long long *)(sha1_buffer + 12); @@ -1194,7 +1222,7 @@ void bl_do_set_auth_key_id (int num, unsigned char *buf) { ev[1] = num; *(long long *)(ev + 2) = fingerprint; memcpy (ev + 4, buf, 256); - add_log_event (ev, 8 + 8 + 256); + add_log_event_i (instance, ev, 8 + 8 + 256); } void bl_do_set_our_id (int id) { diff --git a/binlog.h b/binlog.h index c72699a..370ea55 100644 --- a/binlog.h +++ b/binlog.h @@ -87,8 +87,9 @@ void *alloc_log_event (int l); void replay_log (struct telegram *instance); void add_log_event (const int *data, int l); +void add_log_event_i (struct telegram *instance, const int *data, int l); void write_binlog (void); -void bl_do_set_auth_key_id (int num, unsigned char *buf); +void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf); void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); diff --git a/loop.c b/loop.c index fd29ca3..e3d20ef 100644 --- a/loop.c +++ b/loop.c @@ -148,6 +148,7 @@ int is_got_it (void) { return got_it_ok; } +/* int net_getline (char **s, size_t *l) { fflush (stdout); // rl_already_prompted = 1; @@ -155,16 +156,19 @@ int net_getline (char **s, size_t *l) { _s = s; _l = l; // rl_callback_handler_install (0, got_it); - net_loop (2, is_got_it); + //net_loop (2, is_got_it); return 0; } +*/ int ret1 (void) { return 0; } +/* int main_loop (void) { net_loop (1, ret1); return 0; } +*/ //struct dc *DC_list[MAX_DC_ID + 1]; @@ -177,6 +181,7 @@ int zero[512]; void write_dc (int auth_file_fd, struct dc *DC) { + logprintf("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip); assert (write (auth_file_fd, &DC->port, 4) == 4); int l = strlen (DC->ip); assert (write (auth_file_fd, &l, 4) == 4); @@ -194,28 +199,28 @@ void write_dc (int auth_file_fd, struct dc *DC) { int our_id; -void write_auth_file (struct authorization_state state, const char *filename) { - if (binlog_enabled) { return; } - int auth_file_fd = open (filename /*get_auth_key_filename ()*/, O_CREAT | O_RDWR, 0600); +void write_auth_file (struct authorization_state *state, const char *filename) { + logprintf("Writing to auth_file: %s\n", filename); + int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); int x = DC_SERIALIZED_MAGIC_V2; assert (write (auth_file_fd, &x, 4) == 4); x = MAX_DC_ID; assert (write (auth_file_fd, &x, 4) == 4); - assert (write (auth_file_fd, &state.dc_working_num, 4) == 4); - assert (write (auth_file_fd, &state.auth_state, 4) == 4); + assert (write (auth_file_fd, &state->dc_working_num, 4) == 4); + assert (write (auth_file_fd, &state->auth_state, 4) == 4); int i; for (i = 0; i <= MAX_DC_ID; i++) { - if (state.DC_list[i]) { + if (state->DC_list[i]) { x = 1; assert (write (auth_file_fd, &x, 4) == 4); - write_dc (auth_file_fd, state.DC_list[i]); + write_dc (auth_file_fd, state->DC_list[i]); } else { x = 0; assert (write (auth_file_fd, &x, 4) == 4); } } - assert (write (auth_file_fd, &state.our_id, 4) == 4); + assert (write (auth_file_fd, &state->our_id, 4) == 4); close (auth_file_fd); } @@ -232,9 +237,6 @@ void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { 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); - logprintf("auth_key_id: %lli \n", DC->auth_key_id); - logprintf("auth_key_id: ?"); - logprintf("server_salt: %lli \n", DC->server_salt); if (DC->auth_key_id) { DC->flags |= 1; } @@ -247,23 +249,33 @@ void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { void empty_auth_file (struct authorization_state *state, const char *filename) { + logprintf("empty_auth_file()\n"); alloc_dc (state->DC_list, 1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); state->dc_working_num = 1; state->auth_state = 0; - write_auth_file (*state, filename); + write_auth_file (state, filename); } +/** + * 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 + */ struct authorization_state read_auth_file (const char *filename) { - struct authorization_state state; - state.dc_working_num = 0; - state.auth_state = 0; - state.our_id = 0; + logprintf("read_auth_file()\n"); - if (binlog_enabled) { return state; } - int auth_file_fd = open (filename /*get_auth_key_filename ()*/, O_CREAT | O_RDWR, 0600); + struct authorization_state state; + memset(state.DC_list, 0, 11 * sizeof(void *)); + + int auth_file_fd = open (filename, O_RDWR, 0600); + logprintf("fd: %d\n", auth_file_fd); if (auth_file_fd < 0) { + logprintf("auth_file does not exist, creating empty...\n"); empty_auth_file (&state, filename); } + auth_file_fd = open (filename, O_RDWR, 0600); assert (auth_file_fd >= 0); // amount of data centers @@ -271,6 +283,7 @@ struct authorization_state read_auth_file (const char *filename) { // magic number of file unsigned m; if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { + logprintf("Invalid File content, wrong Magic numebr\n"); close (auth_file_fd); empty_auth_file (&state, filename); return state; @@ -288,6 +301,10 @@ struct authorization_state read_auth_file (const char *filename) { assert (read (auth_file_fd, &y, 4) == 4); if (y) { read_dc (auth_file_fd, i, m, state.DC_list); + logprintf("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n", + 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); + } else { + logprintf("loaded dc[%d] - NULL\n", i); } } int l = read (auth_file_fd, &state.our_id, 4); @@ -299,20 +316,17 @@ struct authorization_state read_auth_file (const char *filename) { if (m == DC_SERIALIZED_MAGIC) { DC_working->has_auth = 1; } + logprintf("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num); return state; } int pts, qts, seq, last_date; struct protocol_state read_state_file (const char *filename) { - struct protocol_state state; - state.last_date = 0; - state.qts = 0; - state.pts = 0; - state.seq = 0; + logprintf("read_state_file()\n"); + struct protocol_state state = {0, 0, 0, 0}; - if (binlog_enabled) { return state; } - int state_file_fd = open (filename/*get_state_filename ()*/, O_CREAT | O_RDWR, 0600); + int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600); if (state_file_fd < 0) { return state; } @@ -331,11 +345,12 @@ struct protocol_state read_state_file (const char *filename) { state.seq = x[2]; state.last_date = x[3]; close (state_file_fd); + logprintf("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts, + state.qts, state.seq, state.last_date); return state; } -void write_state_file (struct protocol_state state, const char* filename) { - if (binlog_enabled) { return; } +void write_state_file (struct protocol_state *state, const char* filename) { /* static int wseq; static int wpts; @@ -350,10 +365,10 @@ void write_state_file (struct protocol_state state, const char* filename) { int x[6]; x[0] = STATE_FILE_MAGIC; x[1] = 0; - x[2] = state.pts; - x[3] = state.qts; - x[4] = state.seq; - x[5] = state.last_date; + x[2] = state->pts; + x[3] = state->qts; + x[4] = state->seq; + x[5] = state->last_date; assert (write (state_file_fd, x, 24) == 24); close (state_file_fd); //wseq = seq; wpts = pts; wqts = qts; wdate = last_date; @@ -569,32 +584,10 @@ int network_verify_phone_registration(const char* code, const char *sms_hash, { logprintf("Registering with code:%s, hash:%s, first:%s, last:%s\n", code, sms_hash, first, last); - if (do_send_code_result_auth (code, sms_hash, first, last) >= 0) { - logprintf ("Authentication successfull, state = 300\n"); - auth_state = 300; - return 1; - } return 0; } */ -/** - * Verify the current client by providing the given code - */ - /* -int network_verify_registration(const char *code, const char *sms_hash) -{ - logprintf("Verifying with hash:%s, code:%s\n", code, sms_hash); - int state; - if ((state = do_send_code_result (code, sms_hash)) >= 0) { - logprintf ("Authentication successfull, state = 300\n"); - auth_state = 300; - return 1; - } - return 0; -} -*/ - /** * Export current authentication state to all known data centers. */ diff --git a/loop.h b/loop.h index 467b454..12a56a5 100644 --- a/loop.h +++ b/loop.h @@ -24,7 +24,6 @@ #ifndef __LOOP_H__ #define __LOOP_H__ int loop(); -void net_loop (int flags, int (*end)(void)); void write_secret_chat_file (const char *filename); #endif @@ -38,14 +37,14 @@ struct protocol_state { struct authorization_state { int dc_working_num; int auth_state; - struct dc *DC_list[11]; + struct dc* DC_list[11]; int our_id; }; -void write_auth_file (struct authorization_state state, const char *filename); +void write_auth_file (struct authorization_state *state, const char *filename); struct authorization_state read_auth_file (const char *filename); -void write_state_file (struct protocol_state state, const char *filename); +void write_state_file (struct protocol_state *state, const char *filename); struct protocol_state read_state_file (const char *filename); void on_start(); diff --git a/mtproto-client.c b/mtproto-client.c index bda8bf7..00aed25 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -85,6 +85,8 @@ int allow_weak_random = 0; int total_packets_sent; long long total_data_sent; +extern int queries_num; + /* int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); @@ -224,6 +226,8 @@ int rpc_send_packet (struct connection *c) { //flush_out (c); total_packets_sent ++; + queries_num++; + logprintf("pending queries: %d\n", queries_num); total_data_sent += total_len; return 1; } @@ -248,6 +252,9 @@ int rpc_send_message (struct connection *c, void *data, int len) { } int send_req_pq_packet (struct connection *c) { + char byte = 0xef; + assert (write_out (c, &byte, 1) == 1); + assert (c_state == st_init); secure_random (nonce, 16); unenc_msg_header.out_msg_id = 0; @@ -255,6 +262,7 @@ int send_req_pq_packet (struct connection *c) { out_int (CODE_req_pq); out_ints ((int *)nonce, 4); rpc_send_packet (c); + c_state = st_reqpq_sent; return 1; } @@ -539,9 +547,7 @@ int check_g_bn (BIGNUM *p, BIGNUM *g) { } int process_dh_answer (struct connection *c, char *packet, int len) { - if (verbosity) { - logprintf ( "process_dh_answer(), len=%d\n", len); - } + logprintf ( "process_dh_answer(), len=%d\n", len); if (len < 116) { logprintf ( "%u * %u = %llu", p1, p2, what); } @@ -633,15 +639,13 @@ int process_dh_answer (struct connection *c, char *packet, int len) { out_cstring ((char *) encrypt_buffer, l); c_state = st_client_dh_sent; - return rpc_send_packet (c); } int process_auth_complete (struct connection *c UU, char *packet, int len) { - if (verbosity) { - logprintf ( "process_dh_answer(), len=%d\n", len); - } + + logprintf ( "process_dh_answer(), len=%d\n", len); assert (len == 72); assert (!*(long long *) packet); assert (*(int *) (packet + 16) == len - 20); @@ -654,7 +658,8 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { 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); + bl_do_set_auth_key_id (c->instance, GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); + sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); memcpy (tmp + 33, sha1_buffer, 8); @@ -662,9 +667,8 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; - if (verbosity >= 3) { - logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); - } + logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); + //logprintf ( "auth_key=%s\n", GET_DC(c)->auth_key); //kprintf ("OK\n"); //c->status = conn_error; @@ -672,9 +676,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { c_state = st_authorized; //return 1; - if (verbosity) { - logprintf ( "Auth success\n"); - } + logprintf ( "Auth success\n"); auth_success ++; GET_DC(c)->flags |= 1; @@ -804,7 +806,7 @@ void fetch_pts (void) { } else { pts ++; } - bl_do_set_pts (pts); + //bl_do_set_pts (pts); } void fetch_qts (void) { @@ -821,14 +823,14 @@ void fetch_qts (void) { } else { qts ++; } - bl_do_set_qts (qts); + //bl_do_set_qts (qts); } void fetch_date (void) { int p = fetch_int (); if (p > last_date) { last_date = p; - bl_do_set_date (last_date); + //bl_do_set_date (last_date); } } @@ -1252,9 +1254,7 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram case CODE_update_encryption: { struct secret_chat *E = fetch_alloc_encrypted_chat (); - if (verbosity >= 2) { - logprintf ("Secret chat state = %d\n", E->state); - } + logprintf ("Secret chat state = %d\n", E->state); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1776,48 +1776,59 @@ int process_rpc_message (struct telegram *instance, struct encrypted_message *en //} int rpc_execute_req_pq (struct telegram *instance, int len) { + logprintf("rpc_execute_rq_dh()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); + queries_num--; return 0; } int rpc_execute_rq_dh (struct telegram *instance, int len) { + logprintf("rpc_execute_rq_dh()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); + queries_num--; return 0; } int rpc_execute_cdh_sent (struct telegram *instance, int len) { + logprintf("rpc_execute_cdh()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); + queries_num--; return 0; } int rpc_execute_authorized (struct telegram *instance, int op, int len) { + logprintf("rpc_execute_authorized()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; @@ -1828,11 +1839,10 @@ int rpc_execute_authorized (struct telegram *instance, int op, int len) { } else { process_rpc_message (instance, (void *)(Response/* + 8*/), Response_len/* - 12*/); } + queries_num--; return 0; } - - int tc_close (struct connection *c, int who) { if (verbosity) { logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); @@ -1900,11 +1910,13 @@ int auth_ok (void) { return auth_success; } +/* void dc_authorize (struct dc *DC) { c_state = 0; auth_success = 0; if (verbosity) { logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); } - net_loop (0, auth_ok); + //net_loop (0, auth_ok); } +*/ diff --git a/mtproto-client.h b/mtproto-client.h index 49f8891..d5a581f 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -23,7 +23,7 @@ #include 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 dc_authorize (struct dc *DC); void work_update (struct connection *c, long long msg_id); void work_update_binlog (void); int check_g (unsigned char p[256], BIGNUM *g); @@ -32,7 +32,7 @@ int check_DH_params (BIGNUM *p, int g); void secure_random (void *s, int l); -int send_req_pq_packet (struct telegram *instance); +int send_req_pq_packet (struct connection *c); int rpc_execute_req_pq (struct telegram *instance, int len); int rpc_execute_rq_dh (struct telegram *instance, int len); diff --git a/mtproto-common.h b/mtproto-common.h index 0dbf71d..da8c49f 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -20,6 +20,7 @@ #ifndef __MTPROTO_COMMON_H__ #define __MTPROTO_COMMON_H__ +#include #include #include #include diff --git a/net.c b/net.c index 0570d65..d42cc6a 100644 --- a/net.c +++ b/net.c @@ -113,10 +113,11 @@ void start_ping_timer (struct connection *c) { insert_event_timer (&c->ev); } -void restart_connection (struct connection *c); int fail_alarm (void *ev) { - ((struct connection *)ev)->in_fail_timer = 0; - restart_connection (ev); + struct connection *c = ev; + c->in_fail_timer = 0; + logprintf("Connection %d FAILED.", c->fd); + telegram_change_state(c->instance, STATE_ERROR, NULL); return 0; } void start_fail_timer (struct connection *c) { @@ -251,13 +252,14 @@ void rotate_port (struct connection *c) { } } -struct connection *create_connection (const char *host, int port, int fd) { +struct connection *create_connection (const char *host, int port, int fd, struct telegram *instance) { struct connection *c = talloc0 (sizeof (*c)); c->fd = fd; c->ip = tstrdup (host); c->flags = 0; c->state = conn_ready; c->port = port; + c->instance = instance; if (verbosity) { logprintf ( "connect to %s:%d successful\n", host, port); } @@ -316,12 +318,11 @@ void restart_connection (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); } - +*/ void fail_connection (struct connection *c) { if (c->state == conn_ready || c->state == conn_connecting) { stop_ping_timer (c); } - rotate_port (c); struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; @@ -338,18 +339,15 @@ void fail_connection (struct connection *c) { c->state = conn_failed; c->out_bytes = c->in_bytes = 0; close (c->fd); - Connections[c->fd] = 0; logprintf ("Lost connection to server... %s:%d\n", c->ip, c->port); - restart_connection (c); + telegram_change_state(c->instance, STATE_ERROR, NULL); } -*/ extern FILE *log_net_f; -void try_write (struct telegram *instance) { +int try_write (struct telegram *instance) { struct connection *c = telegram_get_connection(instance); - if (verbosity) { - logprintf ( "try write: fd = %d\n", c->fd); - } + logprintf ("try write: fd = %d\n", c->fd); + int x = 0; while (c->out_head) { int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); @@ -359,7 +357,6 @@ void try_write (struct telegram *instance) { fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { - fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); } fprintf (log_net_f, "\n"); @@ -387,16 +384,15 @@ void try_write (struct telegram *instance) { logprintf ("fail_connection: write_error %m\n"); } fail_connection (c); - return; + return 0; } else { break; } } } - if (verbosity) { - logprintf ( "Sent %d bytes to %d\n", x, c->fd); - } + logprintf ( "Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; + return x; } void hexdump_buf (struct connection_buffer *b) { @@ -423,6 +419,9 @@ void hexdump_buf (struct connection_buffer *b) { } +/** + * Read all rpc responses from the current connection + */ void try_rpc_read (struct telegram *instance) { struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; @@ -467,10 +466,7 @@ void try_rpc_read (struct telegram *instance) { void try_read (struct telegram *instance) { struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; - - if (verbosity) { - logprintf ( "try read: fd = %d\n", c->fd); - } + logprintf ( "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } @@ -489,9 +485,11 @@ void try_read (struct telegram *instance) { } if (r > 0) { c->last_receive_time = get_double_time (); + + // TODO: Implement the Ping-Timer // reset ping timer - stop_ping_timer (c); - start_ping_timer (c); + //stop_ping_timer (c); + //start_ping_timer (c); } if (r >= 0) { // write pointer nach vorne setzen @@ -507,9 +505,7 @@ void try_read (struct telegram *instance) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - if (verbosity) { - logprintf ("fail_connection: read_error %m\n"); - } + logprintf ("fail_connection: read_error %m\n"); fail_connection (c); return; } else { @@ -517,9 +513,7 @@ void try_read (struct telegram *instance) { } } } - if (verbosity) { - logprintf ( "Received %d bytes from %d\n", x, c->fd); - } + logprintf ( "Received %d bytes from %d\n", x, c->fd); c->in_bytes += x; if (x) { try_rpc_read (instance); @@ -609,10 +603,7 @@ void insert_msg_id (struct session *S, long long id) { } } -extern struct dc *DC_list[]; - struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { - assert (!DC_list[id]); struct dc *DC = talloc0 (sizeof (*DC)); DC->id = id; DC->ip = ip; diff --git a/net.h b/net.h index 10ec628..7725222 100644 --- a/net.h +++ b/net.h @@ -130,6 +130,7 @@ struct connection { void *extra; struct event_timer ev; double last_receive_time; + struct telegram *instance; }; extern struct connection *Connections[]; @@ -140,7 +141,7 @@ int read_in (struct connection *c, void *data, int len); void create_all_outbound_connections (void); -struct connection *create_connection (const char *host, int port, int fd); +struct connection *create_connection (const char *host, int port, int fd, struct telegram *instance); int connections_make_poll_array (struct pollfd *fds, int max); void connections_poll_result (struct pollfd *fds, int max); void insert_msg_id (struct session *S, long long id); @@ -151,8 +152,8 @@ void dc_create_session (struct dc *DC, struct connection *c); void try_read (struct telegram *instance); void try_rpc_read (struct telegram *instance); -void try_write (struct telegram *instance); +int try_write (struct telegram *instance); -#define GET_DC(c) (c->session->dc) +#define GET_DC(c) (telegram_get_working_dc(c->instance)) #endif diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 4cf58c9..cb09b16 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -20,6 +20,7 @@ #include #include #include +#include // test @@ -42,6 +43,7 @@ #include "prpl.h" #include "prefs.h" #include "util.h" +#include "eventloop.h" // struct telegram Includes #include "telegram.h" @@ -105,7 +107,6 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info /** * Request a verification key, save the returned verification_hash in the account settings * for later usage and inform the user. - */ static void login_request_verification(PurpleAccount *acct) { // TODO: we should find a way to request the key @@ -119,6 +120,7 @@ static void login_request_verification(PurpleAccount *acct) "You need to verify this device, please enter the code struct telegram has sent to you by SMS.", NULL, NULL, NULL); } + */ /** * Handle a failed verification, by removing the invalid sms code and @@ -135,25 +137,52 @@ static void login_verification_fail(PurpleAccount *acct) static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) { logprintf("tgprpl_output_cb()\n"); - PurpleConnection *c = data; - telegram_conn *conn = purple_connection_get_protocol_data(c); - telegram_write_output(conn->tg); + struct telegram *tg = data; + telegram_conn *conn = tg->extra; + + int written = telegram_write_output(tg); + logprintf("written(%d): %d.\n", telegram_get_connection(tg)->fd, written); + if (written == 0) { + logprintf("no output, removing output...\n"); + purple_input_remove(conn->wh); + conn->wh = 0; + } +} + +static void tgprpl_has_output(struct telegram *tg) +{ + logprintf("tgprpl_has_output()\n"); + telegram_conn *conn = tg->extra; + if (! conn->wh) { + conn->wh = purple_input_add(telegram_get_connection(tg)->fd, PURPLE_INPUT_WRITE, + tgprpl_output_cb, tg); + logprintf("Attached write handle: %u ", conn->wh); + } } static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) { + struct telegram *tg = data; + //telegram_conn *conn = tg->extra; logprintf("tgprpl_input_cb()\n"); - PurpleConnection *c = data; - telegram_conn *conn = purple_connection_get_protocol_data(c); - telegram_read_input(conn->tg); + + // TODO: remove input handler when no more input + telegram_read_input(tg); + if (telegram_has_output(tg)) { + tgprpl_has_output(tg); + } } -/* -static void tgprpl_on_input(struct telegram *tg) +static void tgprpl_has_input(struct telegram *tg) { - PurpleConnection *c = data; + logprintf("tgprpl_has_input()\n"); + telegram_conn *conn = tg->extra; + if (! conn->rh) { + conn->rh = purple_input_add(telegram_get_connection(tg)->fd, PURPLE_INPUT_READ, + tgprpl_input_cb, tg); + logprintf("Attached read handle: %u ", conn->rh); + } } -*/ static void tgprpl_on_state_change(struct telegram *instance, int state, void *data) { @@ -175,7 +204,8 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d NULL, NULL, NULL); return; } - network_verify_phone_registration(code, hash, first_name, last_name); + + do_send_code_result_auth (instance, code, hash, first_name, last_name); break; case STATE_PHONE_CODE_NOT_ENTERED: @@ -190,7 +220,7 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d case STATE_CLIENT_CODE_NOT_ENTERED: { const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); - network_verify_registration(code, hash); + do_send_code_result(instance, code, hash); // enter SMS code } break; @@ -270,14 +300,13 @@ static void tgprpl_login(PurpleAccount * acct) purple_connection_set_state(gc, PURPLE_CONNECTING); purple_proxy_connect(gc, acct, DC.ip, DC.port, tgprpl_login_on_connected, tg); - purple_debug_info(PLUGIN_ID, "username: %s\n", username); - purple_debug_info(PLUGIN_ID, "hostname: %s\n", DC.ip); } void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) { purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); struct telegram *tg = (struct telegram*) data; + telegram_conn *conn = tg->extra; //running_for_first_time(); if (fd == -1) { @@ -286,9 +315,10 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa return; } - purple_debug_info(PLUGIN_ID, "Connecting to the struct telegram network...\n"); - purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, telegram_get_connection(tg)); - purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, telegram_get_connection(tg)); + + purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n"); + conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg); + conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); telegram_network_connect(tg, fd); // // load all settings: the known network topology, secret keys, logs and configuration file paths @@ -896,10 +926,10 @@ static PurplePluginInfo info = { NULL, PURPLE_PRIORITY_DEFAULT, PLUGIN_ID, - "struct telegram", + "Telegram", "0.1", - "struct telegram integration.", - "Adds support for the struct telegram protocol to libpurple.", + "Telegram protocol", + "Adds support for the telegram protocol to libpurple.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", NULL, // on load diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 433e7f3..24536d8 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -39,4 +39,14 @@ typedef struct { struct telegram *tg; PurpleAccount *pa; PurpleConnection *gc; + + /** + * Write handler returned by purple_input_add + */ + guint wh; + + /** + * Read handler returned by purple_input_add + */ + guint rh; } telegram_conn; diff --git a/queries.c b/queries.c index 3f07807..db61e6e 100644 --- a/queries.c +++ b/queries.c @@ -196,14 +196,10 @@ void query_error (long long id) { int error_code = fetch_int (); int error_len = prefetch_strlen (); char *error = fetch_str (error_len); - if (verbosity) { - logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); - } + logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); struct query *q = query_get (id); if (!q) { - if (verbosity) { - logprintf ( "No such query\n"); - } + logprintf ( "No such query\n"); } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (&q->ev); @@ -281,16 +277,12 @@ DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) struct tree_timer *timer_tree; void insert_event_timer (struct event_timer *ev) { - if (verbosity > 2) { - logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - } + logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); } void remove_event_timer (struct event_timer *ev) { - if (verbosity > 2) { - logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - } + logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); timer_tree = tree_delete_timer (timer_tree, ev); } @@ -641,14 +633,14 @@ struct query_methods nearest_dc_methods = { .on_error = fail_on_error }; -int do_get_nearest_dc (struct telegram *instance) { +void do_get_nearest_dc (struct telegram *instance) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_help_get_nearest_dc); nearest_dc_num = -1; send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &nearest_dc_methods, 0); - net_loop (0, nr_f); - return nearest_dc_num; + //net_loop (0, nr_f); + //return nearest_dc_num; } /* }}} */ @@ -702,7 +694,7 @@ struct query_methods sign_in_methods = { .on_error = sign_in_on_error }; -int do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { +void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_auth_sign_in); @@ -710,12 +702,14 @@ int do_send_code_result (struct telegram *instance, const char *code, const char out_string(sms_hash); out_string (code); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); + /* sign_in_ok = 0; - net_loop (0, sign_in_is_ok); + //net_loop (0, sign_in_is_ok); return sign_in_ok; + */ } -int do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { +void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_auth_sign_up); @@ -725,9 +719,11 @@ int do_send_code_result_auth (struct telegram *instance, const char *code, const out_string (first_name); out_string (last_name); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); + /* sign_in_ok = 0; net_loop (0, sign_in_is_ok); return sign_in_ok; + */ } /* }}} */ @@ -1987,9 +1983,9 @@ void load_next_part (struct telegram *instance, struct download *D) { static char buf[PATH_MAX]; int l; if (!D->id) { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); + l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", instance->download_path, D->volume, D->local_id); } else { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", get_downloads_directory (), D->id); + l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", instance->download_path, D->id); } if (l >= (int) sizeof (buf)) { logprintf ("Download filename is too long"); @@ -2195,7 +2191,6 @@ void do_export_auth (struct telegram *instance, int num) { out_int (CODE_auth_export_authorization); out_int (num); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &export_auth_methods, 0); - net_loop (0, is_export_auth_str); } /* }}} */ @@ -2220,7 +2215,6 @@ void do_import_auth (struct telegram *instance, int num) { out_int (our_id); out_cstring (export_auth_str, export_auth_str_len); send_query (instance->auth.DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); - net_loop (0, isn_export_auth_str); } /* }}} */ diff --git a/queries.h b/queries.h index dd6588e..a7730fa 100644 --- a/queries.h +++ b/queries.h @@ -69,7 +69,7 @@ extern struct query_methods help_get_config_methods; void do_send_code (struct telegram *instance, const char *user); void do_phone_call (struct telegram *instance, const char *user); -int do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash); +void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash); double get_double_time (void); void do_update_contact_list (struct telegram *instance); @@ -101,8 +101,8 @@ void do_load_document (struct telegram *instance, struct document *V, int next); void do_load_document_thumb (struct telegram *instance, struct document *video, int next); void do_help_get_config (struct telegram *instance); int do_auth_check_phone (struct telegram *instance, const char *user); -int do_get_nearest_dc (struct telegram*); -int do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); +void do_get_nearest_dc (struct telegram*); +void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); void do_import_auth (struct telegram *instance, int num); void do_export_auth (struct telegram *instance, int num); void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); @@ -127,3 +127,5 @@ void fetch_dc_option (struct telegram *instance); #endif const char *get_last_err(); + +int all_queries_done(); diff --git a/telegram.c b/telegram.c index f712483..ba51d03 100755 --- a/telegram.c +++ b/telegram.c @@ -4,17 +4,15 @@ #include #include #include +#include #include "mtproto-common.h" #include "telegram.h" #include "msglog.h" #include "glib.h" +#include "tools.h" #include "mtproto-client.h" -/* - * Events - */ - /* * New message received */ @@ -55,7 +53,7 @@ void telegram_add_state_change_listener(struct telegram *instance, state_listene } void telegram_change_state(struct telegram *instance, int state, void *data) { - logprintf("Changing struct telegram state %d\n", state); + logprintf("telegram connection state changed to: %d\n", state); instance->session_state = state; GList *curr = instance->change_state_listeners; while ((curr = g_list_next(change_listeners)) != NULL) { @@ -65,22 +63,40 @@ void telegram_change_state(struct telegram *instance, int state, void *data) struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path) { + on_start (); struct telegram *this = malloc(sizeof(struct telegram)); this->protocol_data = NULL; this->curr_dc = 0; this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; - this->config_path = config_path; - strcpy(this->login, malloc(strlen(login) + 1)); + + this->login = g_strdup(login); + this->config_path = g_strdup_printf("%s/%s", config_path, login); + this->download_path = telegram_get_config(this, "downloads"); + this->auth_path = telegram_get_config(this, "auth"); + this->state_path = telegram_get_config(this, "state"); + this->secret_path = telegram_get_config(this, "secret"); + + logprintf("%s\n", this->login); + logprintf("%s\n", this->config_path); + logprintf("%s\n", this->download_path); + logprintf("%s\n", this->auth_path); + logprintf("%s\n", this->state_path); + telegram_change_state(this, STATE_INITIALISED, NULL); return this; } -void telegram_free(struct telegram *instance) +void telegram_free(struct telegram *this) { - g_list_free(instance->change_state_listeners); - free(instance->login); - free(instance); + g_list_free(this->change_state_listeners); + g_free(this->login); + g_free(this->config_path); + g_free(this->download_path); + g_free(this->auth_path); + g_free(this->state_path); + g_free(this->secret_path); + free(this); } void assert_file_usable(const char *file) @@ -90,56 +106,80 @@ void assert_file_usable(const char *file) void assure_file_exists(const char *dir, const char *file) { - char f[256]; g_mkdir_with_parents(dir, 0700); - sprintf(f, "%s/%s", dir, file); + char *f = g_strdup_printf("%s/%s", dir, file); close(open(f, O_RDWR | O_CREAT, S_IRUSR, S_IWUSR)); assert_file_usable(f); + g_free(f); } +/** + * Get the currently used connection + * + * Will only work after telegram_connect has been called and the connection has + * not errored. + */ struct connection *telegram_get_connection(struct telegram *instance) { - struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; + assert(instance->session_state != STATE_ERROR); + + struct dc *DC = telegram_get_working_dc(instance); + assert(DC); + assert(DC->sessions[0]); + assert(DC->sessions[0]->c); + //logprintf("get_connection() -> fd: %d\n", DC->sessions[0]->c->fd); return DC->sessions[0]->c; } +/** + * Get the currently used DC + * + * Will only work after restore_session has been called and the data center configuration + * was properly loaded + */ struct dc *telegram_get_working_dc(struct telegram *instance) { + assert(instance->session_state != STATE_ERROR); + + assert(instance->auth.DC_list); + assert(instance->auth.dc_working_num > 0); struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; return DC; } +/** + * Store the current session state to a file + */ void telegram_restore_session(struct telegram *instance) { - char file[256]; - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "auth"); - instance->auth = read_auth_file(file); - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "state"); - instance->proto = read_state_file(file); + g_mkdir_with_parents(instance->config_path, 0700); + instance->auth = read_auth_file(instance->auth_path); + instance->proto = read_state_file(instance->state_path); } +/** + * Load the current session state from a file + */ void telegram_store_session(struct telegram *instance) { - char file[256]; - sprintf(file, "%s/%s", instance->config_path, instance->login); - assure_file_exists(file, "auth"); - assure_file_exists(file, "state"); - - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "auth"); - write_auth_file(instance->auth, file); - - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "state"); - write_state_file(instance->proto, file); + assure_file_exists(instance->config_path, "auth"); + assure_file_exists(instance->config_path, "state"); + write_auth_file(&instance->auth, instance->auth_path); + write_state_file(&instance->proto, instance->state_path); } -void telegram_get_downloads_dir(struct telegram *instance) +char *telegram_get_config(struct telegram *instance, char *config) { - + return g_strdup_printf("%s/%s", instance->config_path, config); } void telegram_network_connect(struct telegram *instance, int fd) { - on_start (); + logprintf("telegram_network_connect()\n"); + if (!instance->auth.DC_list) { + logprintf("telegram_network_connect(): cannot connect, restore / initialise a session first.\n"); + assert(0); + } struct dc *DC_working = telegram_get_working_dc(instance); // check whether authentication is needed @@ -147,14 +187,12 @@ void telegram_network_connect(struct telegram *instance, int fd) logprintf("No working DC, authenticating.\n"); // init a new connection - struct connection *c = create_connection (DC_working->ip, DC_working->port, fd); + struct connection *c = create_connection (DC_working->ip, DC_working->port, fd, instance); // init a new session with random session id dc_create_session(DC_working, c); // Request PQ - char byte = 0xef; - assert (write_out (c, &byte, 1) == 1); - send_req_pq_packet (instance); + send_req_pq_packet (c); telegram_change_state(instance, STATE_PQ_REQUESTED, NULL); } else { logprintf("Already working session, setting state to connected.\n"); @@ -175,11 +213,23 @@ void on_state_change(struct telegram *instance, int state, void *data) case STATE_CONNECTED: on_connected(instance); break; + case STATE_ERROR: { const char* err = data; logprintf("Telegram errored: %s \n", err); - break; } + break; + + case STATE_AUTH_DONE: + logprintf("requesting configuration"); + telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); + do_help_get_config (instance); + break; + + case STATE_CONFIG_REQUESTED: + logprintf("switch: config_requested\n"); + telegram_store_session(instance); + break; } } @@ -191,31 +241,39 @@ void try_rpc_interpret(struct telegram *instance, int op, int len) { switch (instance->session_state) { case STATE_PQ_REQUESTED: + logprintf("switch: pq_requested\n"); rpc_execute_req_pq(instance, len); telegram_change_state(instance, STATE_DH_REQUESTED, NULL); break; case STATE_DH_REQUESTED: + logprintf("switch: dh_requested\n"); rpc_execute_rq_dh(instance, len); telegram_change_state(instance, STATE_CDH_REQUESTED, NULL); break; case STATE_CDH_REQUESTED: + logprintf("switch: cdh_requested\n"); rpc_execute_cdh_sent(instance, len); telegram_change_state(instance, STATE_AUTH_DONE, NULL); break; case STATE_AUTH_DONE: + logprintf("switch: auth_done\n"); rpc_execute_authorized(instance, op, len); - telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); - do_help_get_config (instance); - break; - case STATE_CONFIG_REQUESTED: - // ? - telegram_store_session(instance); break; } } void telegram_read_input (struct telegram *instance) { - try_read(instance); + return try_read(instance); +} + +int telegram_write_output (struct telegram *instance) +{ + return try_write(instance); +} + +int telegram_has_output (struct telegram *instance) +{ + return !all_queries_done(); } diff --git a/telegram.h b/telegram.h index 77ac0c5..e5cda6a 100644 --- a/telegram.h +++ b/telegram.h @@ -70,8 +70,14 @@ struct telegram { void *protocol_data; int curr_dc; + char *login; - const char *config_path; + char *config_path; + char *download_path; + char *auth_path; + char *state_path; + char *secret_path; + int session_state; /* @@ -81,6 +87,10 @@ struct telegram { struct authorization_state auth; GList *change_state_listeners; + + /* + * Callbacks + */ void (*on_output)(struct telegram *instance); void *extra; @@ -89,13 +99,16 @@ struct telegram { /** * Constructor */ -struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path); +struct telegram *telegram_new(struct dc *DC, const char* login, + const char* config_path); /** * Resume the session to */ void telegram_restore_session(struct telegram *instance); +char *telegram_get_config(struct telegram *instance, char *config); + /** * Store */ @@ -176,7 +189,12 @@ void telegram_read_input (struct telegram *instance); /** * Write all available output to the network */ -void telegram_write_output (struct telegram *instance); +int telegram_write_output (struct telegram *instance); + +/** + * Return whether there is pending output. + */ +int telegram_has_output (struct telegram *instance); /** * Try to interpret RPC calls and apply the changes to the current telegram state diff --git a/tools.c b/tools.c index c9c4255..5dcc439 100644 --- a/tools.c +++ b/tools.c @@ -105,6 +105,32 @@ void tfree (void *ptr, int size __attribute__ ((unused))) { #endif } +/** + * Add a variable amount of strings together + */ +//char *stradd(const char *strs, ...) +//{ +// va_list args; +// size_t size = 0; +// char *result; +// +// // count strlen +// va_start(args, strs); +// for (int i = 0; strs[i] != '\0'; i++) { +// size += strlen(va_arg(args, char*)); +// } +// va_end(args); +// +// // create the new string +// result = talloc0(size + 1); +// va_start(args, strs); +// for (int i = 0; strs[i] != '\0'; i++) { +// strcat(result, va_arg(args, char*)); +// } +// va_end(args); +// return result; +//} + void tfree_str (void *ptr) { if (!ptr) { return; } tfree (ptr, strlen (ptr) + 1); diff --git a/tools.h b/tools.h index e63b133..dc8bfd9 100644 --- a/tools.h +++ b/tools.h @@ -25,6 +25,7 @@ void *trealloc (void *ptr, size_t old_size, size_t size); void *talloc0 (size_t size); char *tstrdup (const char *s); char *tstrndup (const char *s, size_t n); +//char *stradd(const char *, ...); int tinflate (void *input, int ilen, void *output, int olen); void ensure (int r); void ensure_ptr (void *p);