diff --git a/Makefile b/Makefile index b57528a..f608ae3 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ LD=cc SRC=main.c loop.c interface.c net.c mtproto-common.c mtproto-client.c queries.c structures.c OBJ=$(SRC:.c=.o) EXE=telegram +HDRS=include.h interface.h loop.h mtproto-client.h mtproto-common.h net.h queries.h structures.h telegram.h tree.h all: $(SRC) $(EXE) diff --git a/interface.c b/interface.c index 472df60..9ad1643 100644 --- a/interface.c +++ b/interface.c @@ -9,6 +9,10 @@ #include #include "include.h" #include "queries.h" + +#include "interface.h" +#include "telegram.h" +#include "structures.h" char *default_prompt = ">"; char *get_default_prompt (void) { @@ -23,16 +27,18 @@ char *commands[] = { "help", "msg", "contact_list", + "stats", 0 }; int commands_flags[] = { 070, 072, - 00, + 07, + 07, }; char *a = 0; -char **user_list = &a; +char *user_list[MAX_USER_NUM + 1]; char **chat_list = &a; int init_token (char **q) { @@ -91,12 +97,27 @@ int get_complete_mode (void) { int s = 0; while (1) { get_token (&q, &l); - if (!*q) { return flags & 7; } + if (!*q) { return flags ? flags & 7 : 7; } s ++; if (s <= 4) { flags >>= 3; } } } +extern int user_num; +extern struct user *Users[]; +int complete_user_list (int index, const char *text, int len, char **R) { + index ++; + while (index < user_num && (!Users[index]->print_name || strncmp (Users[index]->print_name, text, len))) { + index ++; + } + if (index < user_num) { + *R = strdup (Users[index]->print_name); + return index; + } else { + return -1; + } +} + int complete_string_list (char **list, int index, const char *text, int len, char **R) { index ++; while (list[index] && strncmp (list[index], text, len)) { @@ -137,7 +158,7 @@ char *command_generator (const char *text, int state) { index = complete_string_list (commands, index, text, len, &R); return R; case 1: - index = complete_string_list (user_list, index, text, len, &R); + index = complete_user_list (index, text, len, &R); return R; case 2: index = complete_string_list (chat_list, index, text, len, &R); @@ -154,27 +175,90 @@ char **complete_text (char *text, int start UU, int end UU) { } void interpreter (char *line UU) { + if (line && *line) { + add_history (line); + } if (!memcmp (line, "contact_list", 12)) { do_update_contact_list (); + } else if (!memcmp (line, "stats", 5)) { + static char stat_buf[1 << 15]; + print_stat (stat_buf, (1 << 15) - 1); + printf ("%s\n", stat_buf); } } +int readline_active; void rprintf (const char *format, ...) { - - int saved_point = rl_point; - char *saved_line = rl_copy_text(0, rl_end); - rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); + int saved_point = 0; + char *saved_line = 0; + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); - rl_restore_prompt(); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } +} + +void hexdump (int *in_ptr, int *in_end) { + int saved_point = 0; + char *saved_line = 0; + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } + int *ptr = in_ptr; + while (ptr < in_end) { fprintf (stdout, " %08x", *(ptr ++)); } + fprintf (stdout, "\n"); + + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } +} + +void logprintf (const char *format, ...) { + int saved_point = 0; + char *saved_line = 0; + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } + + printf (COLOR_GREY " *** "); + va_list ap; + va_start (ap, format); + vfprintf (stdout, format, ap); + va_end (ap); + printf (COLOR_NORMAL); + + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } } diff --git a/interface.h b/interface.h index a0d2376..949ecdf 100644 --- a/interface.h +++ b/interface.h @@ -1,9 +1,19 @@ #ifndef __INTERFACE_H__ #define __INTERFACE_H__ + +#define COLOR_RED "\033[31;1m" +#define COLOR_NORMAL "\033[0m" +#define COLOR_GREEN "\033[32;1m" +#define COLOR_GREY "\033[37;1m" + + char *get_default_prompt (void); char *complete_none (const char *text, int state); char **complete_text (char *text, int start, int end); void interpreter (char *line); void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void iprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void hexdump (int *in_ptr, int *in_end); #endif diff --git a/loop.c b/loop.c index f5d515a..c91287b 100644 --- a/loop.c +++ b/loop.c @@ -167,6 +167,7 @@ void read_auth_file (void) { close (auth_file_fd); } +int readline_active; int loop (void) { on_start (); read_auth_file (); @@ -216,6 +217,7 @@ int loop (void) { fflush (stdout); fflush (stderr); + readline_active = 1; rl_callback_handler_install (get_default_prompt (), interpreter); rl_attempted_completion_function = (CPPFunction *) complete_text; rl_completion_entry_function = complete_none; diff --git a/mtproto-client.c b/mtproto-client.c index 5a6802b..bbfd8ae 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -22,6 +22,7 @@ #include "include.h" #include "queries.h" #include "loop.h" +#include "interface.h" #define sha1 SHA1 @@ -89,13 +90,13 @@ static int rsa_load_public_key (const char *public_key_name) { pubKey = NULL; FILE *f = fopen (public_key_name, "r"); if (f == NULL) { - fprintf (stderr, "Couldn't open public key file: %s\n", public_key_name); + logprintf ( "Couldn't open public key file: %s\n", public_key_name); return -1; } pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); fclose (f); if (pubKey == NULL) { - fprintf (stderr, "PEM_read_RSAPublicKey returns NULL.\n"); + logprintf ( "PEM_read_RSAPublicKey returns NULL.\n"); return -1; } @@ -205,7 +206,7 @@ unsigned p1, p2; int process_respq_answer (struct connection *c, char *packet, int len) { int i; if (verbosity) { - fprintf (stderr, "process_respq_answer(), len=%d\n", len); + logprintf ( "process_respq_answer(), len=%d\n", len); } assert (len >= 76); assert (!*(long long *) packet); @@ -227,7 +228,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { p1 = 0, p2 = 0; if (verbosity >= 2) { - fprintf (stderr, "%lld received\n", what); + logprintf ( "%lld received\n", what); } int it = 0; @@ -275,7 +276,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { if (verbosity) { - fprintf (stderr, "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); + logprintf ( "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); } /// ++p1; /// @@ -286,12 +287,12 @@ int process_respq_answer (struct connection *c, char *packet, int len) { long long *fingerprints = (long long *) (from + 8); for (i = 0; i < fingerprints_num; i++) { if (fingerprints[i] == pk_fingerprint) { - //fprintf (stderr, "found our public key at position %d\n", i); + //logprintf ( "found our public key at position %d\n", i); break; } } if (i == fingerprints_num) { - fprintf (stderr, "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); + logprintf ( "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); exit (2); } // create inner part (P_Q_inner_data) @@ -378,10 +379,10 @@ int process_respq_answer (struct connection *c, char *packet, int len) { int process_dh_answer (struct connection *c, char *packet, int len) { if (verbosity) { - fprintf (stderr, "process_dh_answer(), len=%d\n", len); + logprintf ( "process_dh_answer(), len=%d\n", len); } if (len < 116) { - fprintf (stderr, "%u * %u = %llu", p1, p2, what); + logprintf ( "%u * %u = %llu", p1, p2, what); } assert (len >= 116); assert (!*(long long *) packet); @@ -418,7 +419,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { GET_DC(c)->server_time_delta = server_time - time (0); GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); - //fprintf (stderr, "server time is %d, delta = %d\n", server_time, server_time_delta); + //logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta); // Build set_client_DH_params answer clear_packet (); @@ -474,7 +475,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { int process_auth_complete (struct connection *c UU, char *packet, int len) { if (verbosity) { - fprintf (stderr, "process_dh_answer(), len=%d\n", len); + logprintf ( "process_dh_answer(), len=%d\n", len); } assert (len == 72); assert (!*(long long *) packet); @@ -493,7 +494,7 @@ 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) { - fprintf (stderr, "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); + logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } //kprintf ("OK\n"); @@ -503,7 +504,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { c_state = st_authorized; //return 1; if (verbosity) { - fprintf (stderr, "Auth success\n"); + logprintf ( "Auth success\n"); } auth_success ++; GET_DC(c)->flags |= 1; @@ -568,7 +569,7 @@ int aes_encrypt_message (struct dc *DC, struct encrypted_message *enc) { sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); //printf ("enc_len is %d\n", enc_len); if (verbosity >= 2) { - fprintf (stderr, "sending message with sha1 %08x\n", *(int *)sha1_buffer); + logprintf ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); } memcpy (enc->msg_key, sha1_buffer + 4, 16); init_aes_auth (DC->auth_key, enc->msg_key, AES_ENCRYPT); @@ -612,7 +613,7 @@ int auth_work_start (struct connection *c UU) { void rpc_execute_answer (struct connection *c, long long msg_id UU); void work_container (struct connection *c, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_container: msg_id = %lld\n", msg_id); + logprintf ( "work_container: msg_id = %lld\n", msg_id); } assert (fetch_int () == CODE_msg_container); int n = fetch_int (); @@ -632,7 +633,7 @@ void work_container (struct connection *c, long long msg_id UU) { void work_new_session_created (struct connection *c, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_new_session_created: msg_id = %lld\n", msg_id); + logprintf ( "work_new_session_created: msg_id = %lld\n", msg_id); } assert (fetch_int () == (int)CODE_new_session_created); fetch_long (); // first message id @@ -643,7 +644,7 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { void work_msgs_ack (struct connection *c UU, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_msgs_ack: msg_id = %lld\n", msg_id); + logprintf ( "work_msgs_ack: msg_id = %lld\n", msg_id); } assert (fetch_int () == CODE_msgs_ack); assert (fetch_int () == CODE_vector); @@ -657,7 +658,7 @@ void work_msgs_ack (struct connection *c UU, long long msg_id UU) { void work_rpc_result (struct connection *c UU, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_rpc_result: msg_id = %lld\n", msg_id); + logprintf ( "work_rpc_result: msg_id = %lld\n", msg_id); } assert (fetch_int () == (int)CODE_rpc_result); long long id = fetch_long (); @@ -685,7 +686,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { work_rpc_result (c, msg_id); return; } - fprintf (stderr, "Unknown message: \n"); + logprintf ( "Unknown message: \n"); hexdump_in (); } @@ -693,7 +694,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (verbosity) { - fprintf (stderr, "process_rpc_message(), len=%d\n", len); + logprintf ( "process_rpc_message(), len=%d\n", len); } assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); struct dc *DC = GET_DC(c); @@ -717,7 +718,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); if (verbosity >= 2) { - fprintf (stderr, "received mesage id %016llx\n", enc->msg_id); + logprintf ( "received mesage id %016llx\n", enc->msg_id); } server_last_msg_id = enc->msg_id; @@ -727,7 +728,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (l >= (MINSZ - UNENCSZ) + 8); //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); if (verbosity >= 2) { - fprintf (stderr, "OK, message is good!\n"); + logprintf ( "OK, message is good!\n"); } ++good_messages; @@ -745,11 +746,11 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int rpc_execute (struct connection *c, int op, int len) { if (verbosity) { - fprintf (stderr, "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); + logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); } if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - fprintf (stderr, "answer too long (%d bytes), skipping\n", len); + logprintf ( "answer too long (%d bytes), skipping\n", len); return 0; } @@ -758,7 +759,7 @@ int rpc_execute (struct connection *c, int op, int len) { assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; if (verbosity >= 2) { - fprintf (stderr, "have %d Response bytes\n", Response_len); + logprintf ( "have %d Response bytes\n", Response_len); } setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); @@ -782,7 +783,7 @@ int rpc_execute (struct connection *c, int op, int len) { setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); return 0; default: - fprintf (stderr, "fatal: cannot receive answer in state %d\n", c_state); + logprintf ( "fatal: cannot receive answer in state %d\n", c_state); exit (2); } @@ -792,14 +793,14 @@ int rpc_execute (struct connection *c, int op, int len) { int tc_close (struct connection *c, int who) { if (verbosity) { - fprintf (stderr, "outbound http connection #%d : closing by %d\n", c->fd, who); + logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); } return 0; } int tc_becomes_ready (struct connection *c) { if (verbosity) { - fprintf (stderr, "outbound connection #%d becomes ready\n", c->fd); + logprintf ( "outbound connection #%d becomes ready\n", c->fd); } char byte = 0xef; assert (write_out (c, &byte, 1) == 1); @@ -816,7 +817,7 @@ int tc_becomes_ready (struct connection *c) { auth_work_start (c); break; default: - fprintf (stderr, "c_state = %d\n", c_state); + logprintf ( "c_state = %d\n", c_state); assert (0); } return 0; @@ -842,7 +843,7 @@ void on_start (void) { exit (1); } if (verbosity) { - fprintf (stderr, "public key '%s' loaded successfully\n", rsa_public_key_name); + logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); } pk_fingerprint = compute_rsa_key_fingerprint (pubKey); } @@ -858,7 +859,7 @@ void dc_authorize (struct dc *DC) { dc_create_session (DC); } if (verbosity) { - fprintf (stderr, "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); + logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); } net_loop (0, auth_ok); } diff --git a/mtproto-common.c b/mtproto-common.c index e00845b..3a0c5a1 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -16,6 +16,7 @@ #include #include "mtproto-common.h" +#include "interface.h" long long rsa_encrypted_chunks, rsa_decrypted_chunks; @@ -28,7 +29,7 @@ int get_random_bytes (void *buf, int n) { r = read (h, buf, n); if (r > 0) { if (verbosity >= 3) { - fprintf (stderr, "added %d bytes of real entropy to secure random numbers seed\n", r); + logprintf ( "added %d bytes of real entropy to secure random numbers seed\n", r); } } close (h); @@ -71,14 +72,14 @@ void prng_seed (const char *password_filename, int password_length) { if (password_filename) { int fd = open (password_filename, O_RDONLY); if (fd < 0) { - fprintf (stderr, "Warning: fail to open password file - \"%s\", %m.\n", password_filename); + logprintf ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename); } else { int l = read (fd, a + s, password_length); if (l < 0) { - fprintf (stderr, "Warning: fail to read password file - \"%s\", %m.\n", password_filename); + logprintf ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); } else { if (verbosity > 0) { - fprintf (stderr, "read %d bytes from password file.\n", l); + logprintf ( "read %d bytes from password file.\n", l); } s += l; } diff --git a/mtproto-common.h b/mtproto-common.h index 808aa89..ac3ffc5 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -7,6 +7,7 @@ #include #include +#include "interface.h" /* DH key exchange protocol data structures */ #define CODE_req_pq 0x60469778 #define CODE_resPQ 0x05162463 @@ -409,8 +410,6 @@ int pad_aes_encrypt (char *from, int from_len, char *to, int size); int pad_aes_decrypt (char *from, int from_len, char *to, int size); static inline void hexdump_in (void) { - int *ptr = in_ptr; - while (ptr < in_end) { fprintf (stderr, " %08x", *(ptr ++)); } - fprintf (stderr, "\n"); + hexdump (in_ptr, in_end); } #endif diff --git a/net.c b/net.c index 69e5c4c..ed5a835 100644 --- a/net.c +++ b/net.c @@ -17,6 +17,7 @@ #include "mtproto-client.h" #include "mtproto-common.h" #include "tree.h" +#include "interface.h" DEFINE_TREE(int,int,int_cmp,0) @@ -156,7 +157,7 @@ struct connection *create_connection (const char *host, int port, struct session if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { if (errno != EINPROGRESS) { - fprintf (stderr, "Can not connect to %s:%d %m\n", host, port); + logprintf ( "Can not connect to %s:%d %m\n", host, port); close (fd); free (c); return 0; @@ -183,7 +184,7 @@ struct connection *create_connection (const char *host, int port, struct session assert (!Connections[fd]); Connections[fd] = c; if (verbosity) { - fprintf (stderr, "connect to %s:%d successful\n", host, port); + logprintf ( "connect to %s:%d successful\n", host, port); } if (c->methods->ready) { c->methods->ready (c); @@ -211,7 +212,7 @@ void fail_connection (struct connection *c) { void try_write (struct connection *c) { if (verbosity) { - fprintf (stderr, "try write: fd = %d\n", c->fd); + logprintf ( "try write: fd = %d\n", c->fd); } int x = 0; while (c->out_head) { @@ -238,12 +239,12 @@ void try_write (struct connection *c) { } } if (verbosity) { - fprintf (stderr, "Sent %d bytes to %d\n", x, c->fd); + logprintf ( "Sent %d bytes to %d\n", x, c->fd); } c->out_bytes -= x; } -void hexdump (struct connection_buffer *b) { +void hexdump_buf (struct connection_buffer *b) { int pos = 0; int rem = 8; while (b) { @@ -270,7 +271,7 @@ void hexdump (struct connection_buffer *b) { void try_rpc_read (struct connection *c) { assert (c->in_head); if (verbosity >= 4) { - hexdump (c->in_head); + hexdump_buf (c->in_head); } while (1) { @@ -307,7 +308,7 @@ void try_rpc_read (struct connection *c) { void try_read (struct connection *c) { if (verbosity) { - fprintf (stderr, "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); @@ -334,7 +335,7 @@ void try_read (struct connection *c) { } } if (verbosity) { - fprintf (stderr, "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) { @@ -356,15 +357,15 @@ int connections_make_poll_array (struct pollfd *fds, int max) { fds ++; max --; } - if (verbosity >= 3) { - fprintf (stderr, "%d connections in poll\n", _max - max); + if (verbosity >= 10) { + logprintf ( "%d connections in poll\n", _max - max); } return _max - max; } void connections_poll_result (struct pollfd *fds, int max) { - if (verbosity >= 2) { - fprintf (stderr, "connections_poll_result: max = %d\n", max); + if (verbosity >= 10) { + logprintf ( "connections_poll_result: max = %d\n", max); } int i; for (i = 0; i < max; i++) { @@ -374,7 +375,7 @@ void connections_poll_result (struct pollfd *fds, int max) { } if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { if (verbosity) { - fprintf (stderr, "fail connection\n"); + logprintf ( "fail connection\n"); } fail_connection (c); } else if (fds[i].revents & POLLOUT) { diff --git a/queries.c b/queries.c index 13b21ca..893ed96 100644 --- a/queries.c +++ b/queries.c @@ -43,7 +43,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth dc_create_session (DC); } if (verbosity) { - fprintf (stderr, "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); + logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } struct query *q = malloc (sizeof (*q)); q->data_len = ints; @@ -51,11 +51,11 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth memcpy (q->data, data, 4 * ints); q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); if (verbosity) { - fprintf (stderr, "Msg_id is %lld\n", q->msg_id); + logprintf ( "Msg_id is %lld\n", q->msg_id); } q->methods = methods; if (queries_tree) { - fprintf (stderr, "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); } queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); @@ -77,12 +77,12 @@ void query_error (long long id) { int error_len = prefetch_strlen (); char *error = fetch_str (error_len); if (verbosity) { - fprintf (stderr, "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) { - fprintf (stderr, "No such query\n"); + logprintf ( "No such query\n"); } } else { remove_event_timer (&q->ev); @@ -100,10 +100,10 @@ static int packed_buffer[MAX_PACKED_SIZE / 4]; void query_result (long long id UU) { if (verbosity) { - fprintf (stderr, "result for query #%lld\n", id); + logprintf ( "result for query #%lld\n", id); } if (verbosity >= 4) { - fprintf (stderr, "result: "); + logprintf ( "result: "); hexdump_in (); } int op = prefetch_int (); @@ -124,8 +124,8 @@ void query_result (long long id UU) { int err = inflate (&strm, Z_FINISH); if (verbosity) { - fprintf (stderr, "inflate error = %d\n", err); - fprintf (stderr, "inflated %d bytes\n", (int)strm.total_out); + logprintf ( "inflate error = %d\n", err); + logprintf ( "inflated %d bytes\n", (int)strm.total_out); } end = in_ptr; eend = in_end; @@ -133,14 +133,14 @@ void query_result (long long id UU) { in_ptr = packed_buffer; in_end = in_ptr + strm.total_out / 4; if (verbosity >= 4) { - fprintf (stderr, "Unzipped data: "); + logprintf ( "Unzipped data: "); hexdump_in (); } } struct query *q = query_get (id); if (!q) { if (verbosity) { - fprintf (stderr, "No such query\n"); + logprintf ( "No such query\n"); } } else { remove_event_timer (&q->ev); @@ -162,16 +162,18 @@ DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) struct tree_timer *timer_tree; void insert_event_timer (struct event_timer *ev) { - return; - fprintf (stderr, "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + if (verbosity > 2) { + logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + } tree_check_timer (timer_tree); timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); tree_check_timer (timer_tree); } void remove_event_timer (struct event_timer *ev) { - return; - fprintf (stderr, "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + if (verbosity > 2) { + logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + } tree_check_timer (timer_tree); timer_tree = tree_delete_timer (timer_tree, ev); tree_check_timer (timer_tree); @@ -207,7 +209,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (test_mode == CODE_bool_false); int this_dc = fetch_int (); if (verbosity) { - fprintf (stderr, "this_dc = %d\n", this_dc); + logprintf ( "this_dc = %d\n", this_dc); } assert (fetch_int () == CODE_vector); int n = fetch_int (); @@ -222,7 +224,7 @@ int help_get_config_on_answer (struct query *q UU) { char *ip = fetch_str (l2); int port = fetch_int (); if (verbosity) { - fprintf (stderr, "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } if (!DC_list[id]) { alloc_dc (id, strndup (ip, l2), port); @@ -230,7 +232,7 @@ int help_get_config_on_answer (struct query *q UU) { } max_chat_size = fetch_int (); if (verbosity >= 2) { - fprintf (stderr, "chat_size = %d\n", max_chat_size); + logprintf ( "chat_size = %d\n", max_chat_size); } return 0; } @@ -259,7 +261,7 @@ int send_code_on_error (struct query *q UU, int error_code, int l, char *error) int i = error[s] - '0'; want_dc_num = i; } else { - fprintf (stderr, "error_code = %d, error = %.*s\n", error_code, l, error); + logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); assert (0); } return 0; @@ -343,13 +345,13 @@ int sign_in_on_answer (struct query *q UU) { fetch_user (&User); sign_in_ok = 1; if (verbosity) { - fprintf (stderr, "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); + logprintf ( "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); } return 0; } int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { - fprintf (stderr, "error_code = %d, error = %.*s\n", error_code, l, error); + logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); sign_in_ok = -1; return 0; } @@ -371,11 +373,13 @@ int do_send_code_result (const char *code) { return sign_in_ok; } +extern char *user_list[]; + int get_contacts_on_answer (struct query *q UU) { + int i; assert (fetch_int () == (int)CODE_contacts_contacts); assert (fetch_int () == CODE_vector); int n = fetch_int (); - int i; for (i = 0; i < n; i++) { assert (fetch_int () == (int)CODE_contact); fetch_int (); // id @@ -384,9 +388,8 @@ int get_contacts_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); n = fetch_int (); for (i = 0; i < n; i++) { - struct user User; - fetch_user (&User); - rprintf ("User: id = %d, first_name = %s, last_name = %s\n", User.id, User.first_name, User.last_name); + struct user *U = fetch_alloc_user (); + rprintf ("User #%d: " COLOR_RED "%s %s" COLOR_NORMAL " (" COLOR_GREEN "%s" COLOR_NORMAL ")\n", U->id, U->first_name, U->last_name, U->print_name); } return 0; } diff --git a/structures.c b/structures.c index aad5eb2..e67770e 100644 --- a/structures.c +++ b/structures.c @@ -1,6 +1,8 @@ #include #include "structures.h" #include "mtproto-common.h" +#include "telegram.h" +#include "tree.h" void fetch_file_location (struct file_location *loc) { int x = fetch_int (); @@ -48,6 +50,25 @@ void fetch_user (struct user *U) { } 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++; + } if (x == CODE_user_deleted) { U->flags = 2; return; @@ -79,3 +100,46 @@ void fetch_user (struct user *U) { U->flags |= 16; } } + + +#define user_cmp(a,b) ((a)->id - (b)->id) + +DEFINE_TREE(user,struct user *,user_cmp,0) +struct tree_user *user_tree; + +int user_num; +struct user *Users[MAX_USER_NUM]; +int users_allocated; + +struct user *fetch_alloc_user (void) { + struct user *U = malloc (sizeof (*U)); + fetch_user (U); + users_allocated ++; + struct user *U1 = tree_lookup_user (user_tree, U); + if (U1) { + free_user (U1); + memcpy (U1, U, sizeof (*U)); + free (U); + users_allocated --; + return U1; + } else { + user_tree = tree_insert_user (user_tree, U, lrand48 ()); + Users[user_num ++] = U; + return U; + } +} + +void free_user (struct user *U) { + if (U->first_name) { free (U->first_name); } + if (U->last_name) { free (U->last_name); } + if (U->print_name) { free (U->print_name); } + if (U->phone) { free (U->phone); } +} + +int print_stat (char *s, int len) { + return snprintf (s, len, + "user_num\t%d\n" + "users_allocated\t%d\n", + user_num, + users_allocated); +} diff --git a/structures.h b/structures.h index bdb34bc..e3d05c1 100644 --- a/structures.h +++ b/structures.h @@ -20,6 +20,7 @@ struct user { char *first_name; char *last_name; char *phone; + char *print_name; long long access_hash; struct file_location photo_big; struct file_location photo_small; @@ -28,4 +29,9 @@ struct user { void fetch_file_location (struct file_location *loc); void fetch_user (struct user *U); +struct user *fetch_alloc_user (void); + +void free_user (struct user *U); + +int print_stat (char *s, int len); #endif diff --git a/telegram.h b/telegram.h index 3958159..30d8f40 100644 --- a/telegram.h +++ b/telegram.h @@ -1 +1,2 @@ #define MAX_DC_NUM 9 +#define MAX_USER_NUM 1000 diff --git a/tree.h b/tree.h index 3145139..250b060 100644 --- a/tree.h +++ b/tree.h @@ -51,7 +51,12 @@ struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYP } else {\ int c = X_CMP (x, T->x);\ assert (c);\ - return tree_insert_ ## X_NAME (c < 0 ? T->left : T->right, x, y);\ + if (c < 0) { \ + T->left = tree_insert_ ## X_NAME (T->left, x, y);\ + } else { \ + T->right = tree_insert_ ## X_NAME (T->right, x, y);\ + } \ + return T; \ }\ }\ }\ @@ -96,6 +101,13 @@ X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ return T ? T->x : X_UNSET;\ }\ \ +void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ + if (!T) { return; } \ + tree_act_ ## X_NAME (T->left, act); \ + act (T->x); \ + tree_act_ ## X_NAME (T->right, act); \ +}\ +\ int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return 0; }\ return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \