diff --git a/loop.c b/loop.c index 30fa263..b51a71d 100644 --- a/loop.c +++ b/loop.c @@ -536,6 +536,10 @@ void network_connect (void) { write_auth_file (); logprintf("DataCentre start_loopd, key id: %lld\n", DC_list[i]->auth_key_id); } + + // read saved connection state + read_state_file (); + read_secret_chat_file (); } /** @@ -625,6 +629,25 @@ void network_export_registration() fflush (stderr); } +/** + * Fetch all unknown messages of the current session + */ +void session_get_difference() +{ + do_get_difference(); + net_loop (0, dgot); +} + +extern int contacts_got; +int cupdate_got() { + return contacts_got; +} +void session_update_contact_list() +{ + do_update_contact_list(); + net_loop(0, cupdate_got); +} + int start_loop (char* code, char* auth_mode) { logprintf("Calling start_loop()\n"); logprintf("auth_state %i\n", auth_state); @@ -722,9 +745,11 @@ int start_loop (char* code, char* auth_mode) { fflush (stdout); fflush (stderr); + // read saved connection state read_state_file (); read_secret_chat_file (); - + + // callbacks for interface functions set_interface_callbacks (); do_get_difference (); diff --git a/mtproto-client.c b/mtproto-client.c index 442e4c2..675cb5b 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -66,6 +66,8 @@ #include "mtproto-common.h" +#include "tg-cli.h" + #define MAX_NET_RES (1L << 16) extern int log_level; @@ -906,6 +908,7 @@ void work_update_binlog (void) { void work_update (struct connection *c UU, long long msg_id UU) { unsigned op = fetch_int (); + logprintf("work_update(): OP:%d\n", op); switch (op) { case CODE_update_new_message: { @@ -913,7 +916,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { assert (M); fetch_pts (); unread_messages ++; - print_message (M); + event_update_new_message(M); + //print_message (M); update_prompt (); break; }; @@ -1717,10 +1721,12 @@ int rpc_execute (struct connection *c, int op, int len) { if (verbosity) { logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); } -/* if (op < 0) { + /* + if (op < 0) { assert (read_in (c, Response, Response_len) == Response_len); return 0; - }*/ + } + */ if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); diff --git a/net.c b/net.c index db2b474..fe88e11 100644 --- a/net.c +++ b/net.c @@ -59,6 +59,43 @@ extern FILE *log_net_f; void fail_connection (struct connection *c); +/* + * Delegate the read-oprations to external function + */ +ssize_t (*netread)(int fd, void *buff, size_t size) = read; +void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)) { + netread = cb; +} + +/* + * Delegate the write operations to external function + */ +ssize_t (*netwrite)(int fd, const void *buff, size_t size) = write; +void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)) { + netwrite = cb; +} + +/* + * Delegate the session creation to an external callback + * + * TODO: use dc_ensure_session instead of dc_create_session to create sessions, + * to make this actually work + */ +void dc_create_session (struct dc *DC); +void dc_ensure_session_local (struct dc *DC, void (*on_session_ready)(void)) { + dc_create_session(DC); + on_session_ready(); +} +void (*dc_ensure_session)(struct dc *DC, void (*on_session_ready)(void)); +void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))) +{ + dc_ensure_session = dc_ens_sess; +} + +/* + * + */ + #define PING_TIMEOUT 10 void start_ping_timer (struct connection *c); @@ -386,22 +423,29 @@ void try_write (struct connection *c) { } int x = 0; while (c->out_head) { - int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + + // Log all written packages if (r > 0 && log_net_f) { 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"); fflush (log_net_f); } + if (r >= 0) { x += r; c->out_head->rptr += r; if (c->out_head->rptr != c->out_head->wptr) { + // Inhalt des Buffers nicht komplett abgeschickt, + // es geht nichts mehr in den Socket break; } + // buffer ausgelesen, alten buffer löschen struct connection_buffer *b = c->out_head; c->out_head = b->next; if (!c->out_head) { @@ -497,11 +541,12 @@ void try_read (struct connection *c) { } int x = 0; while (1) { - int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + int r = netread (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); if (r > 0 && log_net_f) { fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { + // print all writte bits fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); } fprintf (log_net_f, "\n"); @@ -509,13 +554,17 @@ void try_read (struct connection *c) { } if (r > 0) { c->last_receive_time = get_double_time (); + // reset ping timer stop_ping_timer (c); start_ping_timer (c); } if (r >= 0) { + // write pointer nach vorne setzen c->in_tail->wptr += r; x += r; + if (c->in_tail->wptr != c->in_tail->end) { + // Paket nicht komplett beschrieben, keine neuen Daten liegen an. break; } struct connection_buffer *b = new_connection_buffer (1 << 20); @@ -646,3 +695,4 @@ void dc_create_session (struct dc *DC) { assert (!DC->sessions[0]); DC->sessions[0] = S; } + diff --git a/queries.c b/queries.c index 10b450d..5a4129b 100644 --- a/queries.c +++ b/queries.c @@ -53,6 +53,7 @@ #include "no-preview.h" #include "binlog.h" +#include "tg-cli.h" #define sha1 SHA1 @@ -132,7 +133,6 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth if (!DC->sessions[0]) { dc_create_session (DC); } - logprintf("telegram: verbosity: %d\n", verbosity); if (verbosity) { logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } @@ -695,6 +695,7 @@ int do_send_code_result_auth (const char *code, const char *sms_hash, const char /* {{{ Get contacts */ extern char *user_list[]; +int contacts_got = 0; int get_contacts_on_answer (struct query *q UU) { int i; assert (fetch_int () == (int)CODE_contacts_contacts); @@ -708,7 +709,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 *U = fetch_alloc_user (); + fetch_alloc_user (); + /* print_start (); push_color (COLOR_YELLOW); logprintf ("User #%d: ", get_peer_id (U->id)); @@ -735,7 +737,9 @@ int get_contacts_on_answer (struct query *q UU) { } pop_color (); print_end (); + */ } + contacts_got = 1; return 0; } @@ -745,11 +749,14 @@ struct query_methods get_contacts_methods = { void do_update_contact_list (void) { + contacts_got = 0; clear_packet (); out_int (CODE_contacts_get_contacts); out_string (""); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0); } + + /* }}} */ /* {{{ Encrypt decrypted */ @@ -2565,6 +2572,7 @@ int unread_messages; int difference_got; int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { + logprintf("get_state_on_answer()\n"); assert (fetch_int () == (int)CODE_updates_state); bl_do_set_pts (fetch_int ()); bl_do_set_qts (fetch_int ()); @@ -2578,6 +2586,7 @@ int get_state_on_answer (struct query *q UU) { int get_difference_active; int get_difference_on_answer (struct query *q UU) { + logprintf("get_difference_on_answer()\n"); get_difference_active = 0; unsigned x = fetch_int (); if (x == CODE_updates_difference_empty) { @@ -2629,7 +2638,8 @@ int get_difference_on_answer (struct query *q UU) { unread_messages = fetch_int (); write_state_file (); for (i = 0; i < ml_pos; i++) { - print_message (ML[i]); + event_update_new_message(ML[i]); + //print_message (ML[i]); } if (x == CODE_updates_difference_slice) { do_get_difference (); @@ -2651,6 +2661,7 @@ struct query_methods get_difference_methods = { }; void do_get_difference (void) { + logprintf("do_get_difference()\n"); get_difference_active = 1; difference_got = 0; clear_packet (); diff --git a/structures.c b/structures.c index 687155e..d8a5887 100644 --- a/structures.c +++ b/structures.c @@ -33,6 +33,8 @@ #include "queries.h" #include "binlog.h" +#include "tg-cli.h" + #define sha1 SHA1 static int id_cmp (struct message *M1, struct message *M2); @@ -204,6 +206,21 @@ long long fetch_user_photo (struct user *U) { return 0; } +int user_get_printname(peer_t *user, char *buffer, int maxlen) +{ + char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; + char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; + if (strlen(first_name) && strlen(last_name)) { + return snprintf(buffer, maxlen, "%s %s", first_name, last_name); + } else if (strlen(first_name)) { + return snprintf(buffer, maxlen, "%s", first_name); + } else if (strlen(last_name)) { + return snprintf(buffer, maxlen, "%s", last_name); + } else { + return snprintf(buffer, maxlen, "%d", get_peer_id(user->id)); + } +} + int fetch_user (struct user *U) { unsigned x = fetch_int (); code_assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted); @@ -1512,10 +1529,12 @@ static int id_cmp (struct message *M1, struct message *M2) { } struct user *fetch_alloc_user (void) { + int send_event = 0; int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); if (!U) { + send_event = 1; users_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_USER (data[1]); @@ -1524,6 +1543,9 @@ struct user *fetch_alloc_user (void) { Peers[peer_num ++] = U; } fetch_user (&U->user); + if (send_event) { + event_user_allocated(U); + } return &U->user; } @@ -1871,10 +1893,12 @@ struct message *fetch_alloc_message_short_chat (void) { } struct chat *fetch_alloc_chat (void) { + int send_event = 0; int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_CHAT (data[1])); if (!U) { + send_event = 1; chats_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[1]); @@ -1883,6 +1907,9 @@ struct chat *fetch_alloc_chat (void) { Peers[peer_num ++] = U; } fetch_chat (&U->chat); + if (send_event) { + event_chat_allocated(U); + } return &U->chat; } diff --git a/structures.h b/structures.h index ad4360f..686e4ee 100644 --- a/structures.h +++ b/structures.h @@ -156,6 +156,7 @@ struct user { char *real_last_name; }; + struct chat_user { int user_id; int inviter_id; @@ -380,6 +381,8 @@ void peer_insert_name (peer_t *P); void peer_delete_name (peer_t *P); peer_t *peer_lookup_name (const char *s); +int user_get_printname(peer_t *user, char *buffer, int maxlen); + #define PEER_USER 1 #define PEER_CHAT 2 #define PEER_GEO_CHAT 3 diff --git a/tg-cli.h b/tg-cli.h index 1989dfd..bb2ddf8 100755 --- a/tg-cli.h +++ b/tg-cli.h @@ -1,12 +1,15 @@ +#include +#include "net.h" +#include "mtproto-common.h" +#include "structures.h" + // Export functions for plugins int tg_login (); void running_for_first_time (); - void parse_config (); void store_config (); - void read_auth_file (); /** @@ -40,6 +43,72 @@ int network_phone_is_registered(); */ int network_client_is_registered(); +/** + * Export the current registration to all available data centers + */ +void network_export_registration(); + +/** + * Fetch all unknown messages of the current session + */ +void session_get_difference(); + +/** + * Fetch all known contacts + */ +void session_update_contact_list(); + +/* + * Events + */ +void on_update_new_message(void (*on_msg)(struct message *M)); +void event_update_new_message(struct message *M); + +void on_update_user_typing(); +void on_update_chat_user_typing(); +void on_update_user_status(); +void on_update_user_name(); +void on_update_user_photo(); +void on_update_chat_participants(); + +/* + * Load known users and chats on connect + */ +void on_user_allocated(); + +void on_user_allocated(void (*handler)(peer_t *user)); +void event_user_allocated(peer_t *user); + +void on_chat_allocated(void (*handler)(peer_t *chat)); +void event_chat_allocated(peer_t *chat); + +// template +//void on_blarg(void (*on_msg)(struct message *M)); +//void event_blarg(struct message *M); + +void on_chat_allocated(); + +/** + * Set a function to use as a handle to read from a network resource + * instead of the regular socket read function + */ +void set_net_read_cb(int (*cb)(int fd, void *buff, size_t size)); + +/** + * Set a function to use as handle to write to a newtork resource + * instead of the regular socket write function + */ +void set_net_write_cb(int (*cb)(int fd, const void *buff, size_t size)); + +/** + * Set a function to use as handle to create new connections instead of the regular + * socket write function + */ +void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))); + +/** + * ? + */ void set_default_username (); // Settings #define AUTH_MODE_SMS "sms"