diff --git a/Makefile.in b/Makefile.in index 1255097..9e0183a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,7 +108,7 @@ run: install .PHONY: debug debug: install - gdb -tui -ex "$(shell echo $$GDB_BPOINTS )" pidgin + ddd 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/mtproto-client.c b/mtproto-client.c index b7fcfee..e787362 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -914,6 +914,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (id); + event_update_user_typing (tg, U); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -932,6 +933,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t id = MK_USER (fetch_int (self)); peer_t *C UU = user_chat_get (chat_id); peer_t *U UU = user_chat_get (id); + event_update_user_typing(tg, U); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -952,6 +954,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *U = user_chat_get (user_id); if (U) { fetch_user_status (self, &U->user.status); + event_update_user_status(tg, U); if (log_level >= 3) { //print_start (); //push_color (COLOR_YELLOW); @@ -1252,6 +1255,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); + event_update_user_typing(tg, P); if (P) { printf (" User "); peer_id_t user_id UU = MK_USER (P->encr_chat.user_id); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 0931fdf..f545aae 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -73,6 +73,8 @@ void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); void telegram_on_phone_registration (struct telegram *instance); void elegram_on_client_registration (struct telegram *instance); +void on_new_user_status(struct telegram *instance, void *user); +void on_user_typing(struct telegram *instance, void *user); /** * Returns the base icon name for the given buddy and account. @@ -94,8 +96,24 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); + const char *status; + peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + peer_t *P = user_chat_get (*peer); + + if (P->user.status.online == 1) + status = "Online"; + else + status = "Offline"; + + purple_notify_user_info_add_pair_plaintext(info, "Status", status); + + struct tm *tm = localtime ((void *)&P->user.status.when); + char buffer [21]; + sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); } + /** * Handle a failed verification by removing the invalid sms code and notifying the user */ @@ -318,9 +336,26 @@ struct telegram_config tgconf = { telegram_on_disconnected, message_allocated_handler, - peer_allocated_handler + peer_allocated_handler, + on_new_user_status, + on_user_typing }; +gboolean queries_timerfunc (gpointer data) { + logprintf ("queries_timerfunc()\n"); + telegram_conn *conn = data; + work_timers (); + // TODO: work pending timers + + if (conn->updated) { + logprintf ("State updated, storing current session...\n"); + conn->updated = 0; + telegram_store_session (conn->tg); + } + return 1; +} + + /** * This must be implemented. */ @@ -346,7 +381,9 @@ static void tgprpl_login(PurpleAccount * acct) tg->extra = conn; purple_connection_set_state (conn->gc, PURPLE_CONNECTING); - telegram_network_connect(tg); + telegram_network_connect (tg); + + purple_timeout_add (2000, queries_timerfunc, conn); } void message_allocated_handler(struct telegram *tg, struct message *M) @@ -367,11 +404,40 @@ void message_allocated_handler(struct telegram *tg, struct message *M) logprintf ("service message, skipping...\n"); return; } - serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); + logprintf ("fwd_date: %d\n", M->date); + serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); g_free(who); } + + conn->updated = 1; } +void on_new_user_status(struct telegram *tg, void *peer) +{ + telegram_conn *conn = tg->extra; + peer_t *p = peer; + + // purple_debug_info(PLUGIN_ID, "New User Status: %s\n", peer->user.status.online); + // TODO: this should probably be freed again somwhere + char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + + PurpleAccount *account = purple_connection_get_account(conn->gc); + if (p->user.status.online == 1) + purple_prpl_got_user_status(account, who, "available", "message", "", NULL); + else + purple_prpl_got_user_status(account, who, "unavailable", "message", "", NULL); + g_free(who); +} + +void on_user_typing(struct telegram *tg, void *peer) +{ + telegram_conn *conn = tg->extra; + peer_t *p = peer; + + char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + serv_got_typing(conn->gc, who, 2, PURPLE_TYPING); + g_free(who); +} /* * Search chats in hash table @@ -415,7 +481,6 @@ void peer_allocated_handler(struct telegram *tg, void *usr) peer_t *user = usr; gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); logprintf("Allocated peer: %s\n", name); - switch (user->id.type) { case PEER_USER: { logprintf("Peer type: user.\n"); @@ -433,6 +498,13 @@ void peer_allocated_handler(struct telegram *tg, void *usr) purple_blist_add_buddy(buddy, NULL, tggroup, NULL); } purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); + + PurpleAccount *account = purple_connection_get_account(gc); + if (user->user.status.online == 1) + purple_prpl_got_user_status(account, name, "available", "message", "", NULL); + else + purple_prpl_got_user_status(account, name, "unavailable", "message", "", NULL); + g_free(name); } break; @@ -508,10 +580,11 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me telegram_conn *conn = purple_connection_get_protocol_data(gc); PurpleAccount *pa = conn->pa; - purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); - PurpleBuddy *b = purple_find_buddy(pa, who); - peer_id_t *peer = purple_buddy_get_protocol_data(b); - do_send_message(conn->tg, *peer, message, strlen(message)); + purple_debug_info (PLUGIN_ID, "tgprpl_send_im()\n"); + PurpleBuddy *b = purple_find_buddy (pa, who); + peer_id_t *peer = purple_buddy_get_protocol_data (b); + do_send_message (conn->tg, *peer, message, strlen(message)); + tgprpl_has_output (conn->tg); return 1; } @@ -596,7 +669,14 @@ static void tgprpl_rem_deny(PurpleConnection * gc, const char *name) */ static unsigned int tgprpl_send_typing(PurpleConnection * gc, const char *who, PurpleTypingState typing) { + telegram_conn *conn = purple_connection_get_protocol_data(gc); + purple_debug_info(PLUGIN_ID, "tgprpl_send_typing()\n"); + PurpleBuddy *b = purple_find_buddy(conn->pa, who); + if (b) { + peer_id_t *peer = purple_buddy_get_protocol_data(b); + do_update_typing (conn->tg, *peer); + } return 0; } @@ -932,8 +1012,8 @@ static PurplePluginInfo info = { "Adds support for the telegram protocol to libpurple.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", - NULL, // on load - NULL, // on unload + NULL, // on load + NULL, // on unload NULL, // on destroy NULL, // ui specific struct &prpl_info, // plugin info struct diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 3df5749..761377c 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -40,6 +40,8 @@ typedef struct { PurpleAccount *pa; PurpleConnection *gc; + int updated; + /** * Write handler returned by purple_input_add */ diff --git a/queries.c b/queries.c index 1cd8bee..6389dac 100644 --- a/queries.c +++ b/queries.c @@ -276,6 +276,7 @@ double next_timer_in (void) { } void work_timers (void) { + logprintf ("work_timers ()\n"); double t = get_double_time (); while (timer_tree) { struct event_timer *ev = tree_get_min_timer (timer_tree); @@ -710,7 +711,6 @@ struct query_methods get_contacts_methods = { .on_answer = get_contacts_on_answer, }; - void do_update_contact_list (struct telegram *instance) { struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); @@ -2699,6 +2699,7 @@ int difference_got; int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); + struct telegram *instance = q->extra; logprintf("get_state_on_answer()\n"); assert (fetch_int (mtp) == (int)CODE_updates_state); @@ -2709,6 +2710,7 @@ int get_state_on_answer (struct query *q UU) { unread_messages = fetch_int (mtp); //write_state_file (); difference_got = 1; + telegram_store_session (instance); return 0; } @@ -2771,7 +2773,7 @@ int get_difference_on_answer (struct query *q UU) { unread_messages = fetch_int (mtp); //write_state_file (); for (i = 0; i < ml_pos; i++) { - event_update_new_message (instance, ML[i]); + event_update_new_message (instance, ML[i]); ////print_message (ML[i]); } if (x == CODE_updates_difference_slice) { @@ -2782,6 +2784,7 @@ int get_difference_on_answer (struct query *q UU) { } else { assert (0); } + telegram_store_session (instance); return 0; } @@ -2813,7 +2816,7 @@ void do_get_difference (struct telegram *instance) { send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); } else { out_int (mtp, CODE_updates_get_state); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); } } /* }}} */ @@ -3065,4 +3068,23 @@ void do_update_status (struct telegram *instance, int online UU) { send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); } +int update_typing_on_answer (struct query *q UU) { + fetch_bool (query_get_mtproto (q)); + return 0; +} + +struct query_methods update_typing_methods = { + .on_answer = update_typing_on_answer +}; + +void do_update_typing (struct telegram *instance, peer_id_t id) { + struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_messages_set_typing); + out_peer_id (mtp, id); + out_int (mtp, CODE_bool_true); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); +} diff --git a/queries.h b/queries.h index 516b0e2..8587d67 100644 --- a/queries.h +++ b/queries.h @@ -115,6 +115,7 @@ void do_get_difference (struct telegram*); void do_mark_read (struct telegram *instance, peer_id_t id); void do_visualize_key (peer_id_t id); void do_create_keys_end (struct secret_chat *U); + void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit); void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id); void do_update_status (struct telegram *instance, int online); diff --git a/structures.c b/structures.c index cf7ad1c..8b36ab1 100644 --- a/structures.c +++ b/structures.c @@ -1531,22 +1531,22 @@ static int id_cmp (struct message *M1, struct message *M2) { struct user *fetch_alloc_user (struct mtproto_connection *mtp) { logprintf("fetch_alloc_user()\n"); - int send_event = 0; int data[2]; prefetch_data (mtp, 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]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; - } - fetch_user (mtp, &U->user); - if (send_event) { + fetch_user (mtp, &U->user); + event_update_user_status(mtp->connection->instance, U); event_peer_allocated(mtp->connection->instance, U); + } else { + fetch_user (mtp, &U->user); + event_update_user_status(mtp->connection->instance, U); } return &U->user; } diff --git a/telegram.c b/telegram.c index f23b230..40332ff 100755 --- a/telegram.c +++ b/telegram.c @@ -21,7 +21,7 @@ void event_update_new_message(struct telegram *instance, struct message *M) { if (instance->config->on_msg_handler) { - instance->config->on_msg_handler(instance, M); + instance->config->on_msg_handler (instance, M); } } @@ -31,10 +31,32 @@ void event_update_new_message(struct telegram *instance, struct message *M) void event_peer_allocated(struct telegram *instance, void *peer) { if (instance->config->on_peer_allocated_handler) { - instance->config->on_peer_allocated_handler(instance, peer); + instance->config->on_peer_allocated_handler (instance, peer); } } +/* + * User status changed + */ +void event_update_user_status (struct telegram *instance, void *peer) +{ + if (instance->config->on_update_user_status_handler) { + instance->config->on_update_user_status_handler (instance, peer); + } +} + +/* + * User typing changed + */ +void event_update_user_typing (struct telegram *instance, void *peer) +{ + if (instance->config->on_update_uesr_typing_handler) { + instance->config->on_update_uesr_typing_handler (instance, peer); + } +} + + + /** * Calculate the configuration path for the given config file and the given instance * @@ -319,3 +341,4 @@ int telegram_has_output (struct telegram *instance) { return instance->connection->queries_num > 0; } + diff --git a/telegram.h b/telegram.h index fff1a45..f1b85b9 100644 --- a/telegram.h +++ b/telegram.h @@ -150,6 +150,16 @@ struct telegram_config { * for populating the GUI with new peers. */ void (*on_peer_allocated_handler)(struct telegram *instance, void *peer); + + /** + * A callback function that is called when a user's status has changed + */ + void (*on_update_user_status_handler) (struct telegram *instance, void *peer); + + /** + * A callback function that is called when a user starts or stops typing + */ + void (*on_update_uesr_typing_handler) (struct telegram *instance, void *peer); }; /** @@ -325,6 +335,8 @@ void session_update_contact_list(); * Events */ void event_update_new_message(struct telegram *instance, struct message *M); +void event_update_user_status(struct telegram *instance, void *peer); +void event_update_user_typing(struct telegram *instance, void *peer); /* * Load known users and chats on connect