diff --git a/interface.c b/interface.c index e20f90f..bedc835 100644 --- a/interface.c +++ b/interface.c @@ -198,6 +198,18 @@ void interpreter (char *line UU) { static char stat_buf[1 << 15]; print_stat (stat_buf, (1 << 15) - 1); printf ("%s\n", stat_buf); + } else if (!memcmp (line, "msg ", 4)) { + char *q = line + 4; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id < 0)) { + index ++; + } + while (*q && (*q == ' ' || *q == '\t')) { q ++; } + if (*q && index < user_num + chat_num) { + do_send_message (Peers[index], q); + } } } @@ -276,3 +288,14 @@ void logprintf (const char *format, ...) { free(saved_line); } } + +void print_message (struct message *M) { + union user_chat *U = user_chat_get (M->from_id); + if (!M->service) { + if (U && U->id > 0) { + rprintf (COLOR_RED "%s %s " COLOR_GREEN " >>> " COLOR_NORMAL " %s\n", U->user.first_name, U->user.last_name, M->message); + } else { + rprintf (COLOR_RED "User #%d " COLOR_GREEN " >>> " COLOR_NORMAL " %s\n", M->from_id, M->message); + } + } +} diff --git a/interface.h b/interface.h index 949ecdf..29e9e30 100644 --- a/interface.h +++ b/interface.h @@ -5,6 +5,7 @@ #define COLOR_NORMAL "\033[0m" #define COLOR_GREEN "\033[32;1m" #define COLOR_GREY "\033[37;1m" +#define COLOR_YELLOW "\033[33;1m" char *get_default_prompt (void); @@ -16,4 +17,7 @@ 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); + +struct message; +void print_message (struct message *M); #endif diff --git a/mtproto-client.c b/mtproto-client.c index bbfd8ae..6ebcf16 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -23,6 +23,7 @@ #include "queries.h" #include "loop.h" #include "interface.h" +#include "structures.h" #define sha1 SHA1 @@ -611,6 +612,181 @@ int auth_work_start (struct connection *c UU) { } void rpc_execute_answer (struct connection *c, long long msg_id UU); + +void work_update (struct connection *c UU, long long msg_id UU) { + unsigned op = fetch_int (); + switch (op) { + case CODE_update_new_message: + { + struct message *M = fetch_alloc_message (); + print_message (M); + break; + }; + case CODE_update_message_i_d: + { + int id = fetch_int (); // id + int new = fetch_long (); // random_id + struct message *M = message_get (new); + update_message_id (M, id); + } + break; + case CODE_update_read_messages: + { + assert (fetch_int () == (int)CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + int id = fetch_int (); + struct message *M = message_get (id); + if (M) { + M->unread = 0; + } + } + fetch_int (); //pts + } + break; + case CODE_update_user_typing: + { + int id = fetch_int (); + union user_chat *U = user_chat_get (id); + if (U) { + rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name); + } + } + break; + case CODE_update_chat_user_typing: + { + int chat_id = fetch_int (); + int id = fetch_int (); + union user_chat *C = user_chat_get (-chat_id); + union user_chat *U = user_chat_get (id); + if (U && C) { + rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing in chat %s....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, C->chat.title); + } + } + break; + case CODE_update_user_status: + { + int user_id = fetch_int (); + union user_chat *U = user_chat_get (user_id); + if (U) { + fetch_user_status (&U->user.status); + rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is now %s\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, (U->user.status.online > 0) ? "online" : "offline"); + } else { + struct user_status t; + fetch_user_status (&t); + } + } + break; + case CODE_update_user_name: + { + int user_id = fetch_int (); + union user_chat *UC = user_chat_get (user_id); + if (UC) { + struct user *U = &UC->user; + if (U->first_name) { free (U->first_name); } + if (U->last_name) { free (U->first_name); } + if (U->print_name) { free (U->first_name); } + U->first_name = fetch_str_dup (); + U->last_name = fetch_str_dup (); + if (!strlen (U->first_name)) { + if (!strlen (U->last_name)) { + U->print_name = strdup ("none"); + } else { + U->print_name = strdup (U->last_name); + } + } else { + if (!strlen (U->last_name)) { + U->print_name = strdup (U->first_name); + } else { + U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2); + sprintf (U->print_name, "%s_%s", U->first_name, U->last_name); + } + } + } else { + int l; + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + } + } + break; + case CODE_update_user_photo: + { + int user_id = fetch_int (); + union user_chat *UC = user_chat_get (user_id); + if (UC) { + struct user *U = &UC->user; + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + U->photo_big.dc = -2; + U->photo_small.dc = -2; + } else { + assert (y == CODE_user_profile_photo); + fetch_file_location (&U->photo_small); + fetch_file_location (&U->photo_big); + } + } else { + struct file_location t; + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + } else { + assert (y == CODE_user_profile_photo); + fetch_file_location (&t); + fetch_file_location (&t); + } + } + } + break; + default: + logprintf ("Unknown update type %08x\n", op); + } +} + +void work_update_short (struct connection *c, long long msg_id) { + assert (fetch_int () == CODE_update_short); + work_update (c, msg_id); + fetch_int (); // date +} + +void work_updates (struct connection *c, long long msg_id) { + assert (fetch_int () == CODE_updates); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + work_update (c, msg_id); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_user (); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_chat (); + } + fetch_int (); // date + fetch_int (); // seq + +} + +void work_update_short_message (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == (int)CODE_update_short_message); + struct message *M = fetch_alloc_message_short (); + print_message (M); +} + +void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == CODE_update_short_chat_message); + struct message *M = fetch_alloc_message_short_chat (); + print_message (M); +} + void work_container (struct connection *c, long long msg_id UU) { if (verbosity) { logprintf ( "work_container: msg_id = %lld\n", msg_id); @@ -671,6 +847,9 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { } void rpc_execute_answer (struct connection *c, long long msg_id UU) { + if (verbosity >= 5) { + hexdump_in (); + } int op = prefetch_int (); switch (op) { case CODE_msg_container: @@ -685,6 +864,18 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_rpc_result: work_rpc_result (c, msg_id); return; + case CODE_update_short: + work_update_short (c, msg_id); + return; + case CODE_updates: + work_updates (c, msg_id); + return; + case CODE_update_short_message: + work_update_short_message (c, msg_id); + return; + case CODE_update_short_chat_message: + work_update_short_chat_message (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); diff --git a/mtproto-common.h b/mtproto-common.h index b0357c6..be30560 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -255,8 +255,12 @@ static inline int prefetch_strlen (void) { } } - +extern int verbosity; static inline char *fetch_str (int len) { + assert (len >= 0); + if (verbosity > 6) { + logprintf ("fetch_string: len = %d\n", len); + } if (len < 254) { char *str = (char *) in_ptr + 1; in_ptr += 1 + (len >> 2); @@ -289,6 +293,9 @@ static inline long have_prefetch_ints (void) { int fetch_bignum (BIGNUM *x); static inline int fetch_int (void) { + if (verbosity > 6) { + logprintf ("fetch_int: 0x%08x (%d)\n", *in_ptr, *in_ptr); + } return *(in_ptr ++); } diff --git a/net.c b/net.c index ed5a835..8e44e17 100644 --- a/net.c +++ b/net.c @@ -391,6 +391,7 @@ void connections_poll_result (struct pollfd *fds, int max) { int send_all_acks (struct session *S) { clear_packet (); + out_int (CODE_msgs_ack); out_int (tree_count_int (S->ack_tree)); while (S->ack_tree) { int x = tree_get_min_int (S->ack_tree); diff --git a/queries.c b/queries.c index 8742f13..b984e74 100644 --- a/queries.c +++ b/queries.c @@ -46,6 +46,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } struct query *q = malloc (sizeof (*q)); + memset (q, 0, sizeof (*q)); q->data_len = ints; q->data = malloc (4 * ints); memcpy (q->data, data, 4 * ints); @@ -68,7 +69,10 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth void query_ack (long long id) { struct query *q = query_get (id); - if (q) { q->flags |= QUERY_ACK_RECEIVED; } + if (q) { + remove_event_timer (&q->ev); + q->flags |= QUERY_ACK_RECEIVED; + } } void query_error (long long id) { @@ -85,7 +89,9 @@ void query_error (long long id) { logprintf ( "No such query\n"); } } else { - remove_event_timer (&q->ev); + if (!(q->flags & QUERY_ACK_RECEIVED)) { + remove_event_timer (&q->ev); + } queries_tree = tree_delete_query (queries_tree, q); if (q->methods && q->methods->on_error) { q->methods->on_error (q, error_code, error_len, error); @@ -143,7 +149,9 @@ void query_result (long long id UU) { logprintf ( "No such query\n"); } } else { - remove_event_timer (&q->ev); + if (!(q->flags & QUERY_ACK_RECEIVED)) { + remove_event_timer (&q->ev); + } queries_tree = tree_delete_query (queries_tree, q); if (q->methods && q->methods->on_answer) { q->methods->on_answer (q); @@ -191,6 +199,10 @@ void work_timers (void) { assert (ev); if (ev->timeout > t) { break; } remove_event_timer (ev); + assert (ev->alarm); + if (verbosity) { + logprintf ("Alarm\n"); + } ev->alarm (ev->self); } } @@ -405,3 +417,48 @@ void do_update_contact_list (void) { out_string (""); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods); } + + +int msg_send_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_sent_message); + int uid = fetch_int (); // uid + int date = fetch_int (); // date + int ptr = fetch_int (); // ptr + int seq = fetch_int (); // seq + logprintf ("Sent: uid = %d, date = %d, ptr = %d, seq = %d\n", uid, date, ptr, seq); + return 0; +} + +struct query_methods msg_send_methods = { + .on_answer = msg_send_on_answer +}; + +int out_message_num; +void do_send_message (union user_chat *U, const char *msg) { + if (!out_message_num) { + out_message_num = lrand48 (); + } + clear_packet (); + out_int (CODE_messages_send_message); + if (U->id < 0) { + out_int (CODE_input_peer_chat); + out_int (-U->id); + } else { + if (U->user.access_hash) { + out_int (CODE_input_peer_foreign); + out_int (U->id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_peer_contact); + out_int (U->id); + } + } + out_string (msg); + out_long (out_message_num ++); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods); + if (U->id < 0) { + rprintf (COLOR_RED "%s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->chat.title, msg); + } else { + rprintf (COLOR_RED "%s %s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->user.first_name, U->user.last_name, msg); + } +} diff --git a/queries.h b/queries.h index 3f812e2..c13ed76 100644 --- a/queries.h +++ b/queries.h @@ -44,4 +44,6 @@ int do_send_code_result (const char *code); double get_double_time (void); void do_update_contact_list (void); +union user_chat; +void do_send_message (union user_chat *U, const char *msg); #endif diff --git a/structures.c b/structures.c index 87d81fa..bebe2b0 100644 --- a/structures.c +++ b/structures.c @@ -4,6 +4,8 @@ #include "telegram.h" #include "tree.h" +int verbosity; + void fetch_file_location (struct file_location *loc) { int x = fetch_int (); if (x == CODE_file_location_unavailable) { @@ -234,6 +236,28 @@ void fetch_message_action (struct message_action *M) { } } +void fetch_message_short (struct message *M) { + memset (M, 0, sizeof (*M)); + M->id = fetch_int (); + M->from_id = fetch_int (); + M->message = fetch_str_dup (); + fetch_int (); // pts + M->date = fetch_int (); + fetch_int (); // seq +} + +void fetch_message_short_chat (struct message *M) { + memset (M, 0, sizeof (*M)); + M->id = fetch_int (); + M->from_id = fetch_int (); + M->to_id = fetch_int (); + M->message = fetch_str_dup (); + fetch_int (); // pts + M->date = fetch_int (); + fetch_int (); // seq +} + + void fetch_message_media (struct message_media *M) { memset (M, 0, sizeof (*M)); M->type = fetch_int (); @@ -442,6 +466,49 @@ struct message *fetch_alloc_message (void) { } } +struct message *fetch_alloc_message_short (void) { + struct message *M = malloc (sizeof (*M)); + fetch_message_short (M); + struct message *M1 = tree_lookup_message (message_tree, M); + messages_allocated ++; + if (M1) { + message_del_use (M1); + free_message (M1); + memcpy (M1, M, sizeof (*M)); + free (M); + message_add_use (M1); + messages_allocated --; + return M1; + } else { + message_add_use (M); + message_tree = tree_insert_message (message_tree, M, lrand48 ()); + return M; + } +} + +struct message *fetch_alloc_message_short_chat (void) { + struct message *M = malloc (sizeof (*M)); + fetch_message_short_chat (M); + if (verbosity >= 2) { + logprintf ("Read message with id %d\n", M->id); + } + struct message *M1 = tree_lookup_message (message_tree, M); + messages_allocated ++; + if (M1) { + message_del_use (M1); + free_message (M1); + memcpy (M1, M, sizeof (*M)); + free (M); + message_add_use (M1); + messages_allocated --; + return M1; + } else { + message_add_use (M); + message_tree = tree_insert_message (message_tree, M, lrand48 ()); + return M; + } +} + struct chat *fetch_alloc_chat (void) { union user_chat *U = malloc (sizeof (*U)); fetch_chat (&U->chat); @@ -475,3 +542,21 @@ int print_stat (char *s, int len) { messages_allocated ); } + +union user_chat *user_chat_get (int id) { + union user_chat U; + U.id = id; + return tree_lookup_peer (peer_tree, &U); +} + +struct message *message_get (int id) { + struct message M; + M.id = id; + return tree_lookup_message (message_tree, &M); +} + +void update_message_id (struct message *M, int id) { + message_tree = tree_delete_message (message_tree, M); + M->id = id; + message_tree = tree_insert_message (message_tree, M, lrand48 ()); +} diff --git a/structures.h b/structures.h index df89632..2b527c5 100644 --- a/structures.h +++ b/structures.h @@ -142,12 +142,19 @@ struct message { }; void fetch_file_location (struct file_location *loc); +void fetch_user_status (struct user_status *S); void fetch_user (struct user *U); struct user *fetch_alloc_user (void); struct chat *fetch_alloc_chat (void); +struct message *fetch_alloc_message (void); +struct message *fetch_alloc_message_short (void); +struct message *fetch_alloc_message_short_chat (void); void free_user (struct user *U); void free_chat (struct chat *U); int print_stat (char *s, int len); +union user_chat *user_chat_get (int id); +struct message *message_get (int id); +void update_message_id (struct message *M, int id); #endif