diff --git a/telegram-base.c b/telegram-base.c index 9f52841..7b87cae 100644 --- a/telegram-base.c +++ b/telegram-base.c @@ -450,3 +450,46 @@ void chat_add_all_users (PurpleConversation *pc, struct tgl_chat *chat) { p2tgl_conv_add_user(pc, *uid, NULL, flags, 0); } } + + +static void pending_reads_cb (struct tgl_state *TLS, void *extra, int success) +{ + debug ("ack state: %d", success); +} + +static gint pending_reads_compare (gconstpointer a, gconstpointer b) +{ + return !memcmp ((tgl_peer_id_t *)a, (tgl_peer_id_t *)b, sizeof(tgl_peer_id_t)); +} + +void pending_reads_send_all (GQueue *queue, struct tgl_state *TLS) +{ + debug ("send all pending ack"); + + tgl_peer_id_t *pending; + + while ((pending = (tgl_peer_id_t*) g_queue_pop_head(queue))) { + tgl_do_mark_read (TLS, *pending, pending_reads_cb, queue); + debug ("tgl_do_mark_read (%d)", pending->id); + free (pending); + } +} + +void pending_reads_add (GQueue *queue, tgl_peer_id_t id) +{ + tgl_peer_id_t *copy = malloc (sizeof(tgl_peer_id_t)); + *copy = id; + if (! g_queue_find_custom (queue, copy, pending_reads_compare)) { + g_queue_push_tail (queue, copy); + } +} + +void pending_reads_clear (GQueue *queue) +{ + tgl_peer_id_t *pending; + + while ((pending = (tgl_peer_id_t*) g_queue_pop_head(queue))) { + free (pending); + } +} + diff --git a/telegram-base.h b/telegram-base.h index 5d6a484..bd0615e 100644 --- a/telegram-base.h +++ b/telegram-base.h @@ -19,6 +19,9 @@ */ #ifndef __TELEGRAM_BASE_H__ #define __TELEGRAM_BASE_H__ + +#include "telegram-purple.h" + void read_state_file (struct tgl_state *TLS); void read_auth_file (struct tgl_state *TLS); void write_auth_file (struct tgl_state *TLS); @@ -29,4 +32,9 @@ PurpleConversation *chat_show (PurpleConnection *gc, int id); int chat_add_message (struct tgl_state *TLS, struct tgl_message *M, char *text); void chat_add_all_users (PurpleConversation *pc, struct tgl_chat *chat); void request_code_entered (gpointer data, const gchar *code); + +void pending_reads_send_all (GQueue *queue, struct tgl_state *TLS); +void pending_reads_add (GQueue *queue, tgl_peer_id_t id); +void pending_reads_clear (GQueue *queue); + #endif diff --git a/telegram-purple.c b/telegram-purple.c index 4972c9c..cc92393 100644 --- a/telegram-purple.c +++ b/telegram-purple.c @@ -331,6 +331,12 @@ static void update_message_received (struct tgl_state *TLS, struct tgl_message * p2tgl_got_im (TLS, M->to_id, text, PURPLE_MESSAGE_SEND, M->date); } else { p2tgl_got_im (TLS, M->from_id, text, PURPLE_MESSAGE_RECV, M->date); + + pending_reads_add (conn->pending_reads, M->from_id); + PurpleStatus *status = purple_account_get_active_status(conn->pa); + if (p2tgl_status_is_present(status)) { + pending_reads_send_all (conn->pending_reads, conn->TLS); + } } } break; @@ -552,16 +558,25 @@ static GList *tgprpl_status_types (PurpleAccount * acct) { debug ("tgprpl_status_types()\n"); GList *types = NULL; PurpleStatusType *type; - type = purple_status_type_new_with_attrs (PURPLE_STATUS_AVAILABLE, NULL, NULL, - 1, 1, 0, "last online", "last online", purple_value_new (PURPLE_TYPE_STRING), NULL); + + type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); - type = purple_status_type_new_with_attrs (PURPLE_STATUS_MOBILE, NULL, NULL, 1, - 1, 0, "last online", "last online", purple_value_new (PURPLE_TYPE_STRING), NULL); + type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, NULL, NULL, FALSE, TRUE, FALSE); + types = g_list_prepend (types, type); + + type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); - type = purple_status_type_new (PURPLE_STATUS_OFFLINE, NULL, NULL, 1); - types = g_list_append (types, type); + /* + The states below are only registered internally so that we get notified about + state changes to away and unavailable. This is useful for deciding when to send + No other peer should ever have those states. + */ + type = purple_status_type_new_full(PURPLE_STATUS_AWAY, NULL, NULL, FALSE, TRUE, FALSE); + types = g_list_prepend (types, type); + type = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); + types = g_list_prepend (types, type); return g_list_reverse (types); } @@ -609,7 +624,8 @@ static void tgprpl_login (PurpleAccount * acct) { conn->gc = gc; conn->pa = acct; conn->new_messages = g_queue_new (); - conn->joining_chats = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + conn->pending_reads = g_queue_new (); + conn->joining_chats = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); purple_connection_set_protocol_data (gc, conn); tgl_set_ev_base (TLS, conn); @@ -628,7 +644,14 @@ static void tgprpl_close (PurpleConnection * gc) { debug ("tgprpl_close()\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); purple_timeout_remove(conn->timer); + + pending_reads_clear (conn->pending_reads); + tgl_free_all (conn->TLS); + g_queue_free (conn->new_messages); + g_queue_free (conn->pending_reads); + g_hash_table_destroy (conn->joining_chats); + } static int tgprpl_send_im (PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) { @@ -685,7 +708,16 @@ static void tgprpl_get_info (PurpleConnection * gc, const char *username) { } static void tgprpl_set_status (PurpleAccount * acct, PurpleStatus * status) { - debug ("tgprpl_set_status()\n"); + debug ("tgprpl_set_status(%s)\n", purple_status_get_name (status)); + debug ("tgprpl_set_status(currstatus=%s)\n", purple_status_get_name(purple_account_get_active_status(acct))); + + PurpleConnection *gc = purple_account_get_connection(acct); + if (!gc) { return; } + telegram_conn *conn = purple_connection_get_protocol_data (gc); + + if (p2tgl_status_is_present(status)) { + pending_reads_send_all (conn->pending_reads, conn->TLS); + } } static void tgprpl_add_buddy (PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) { diff --git a/telegram-purple.h b/telegram-purple.h index 3b36565..c72f638 100644 --- a/telegram-purple.h +++ b/telegram-purple.h @@ -45,6 +45,7 @@ typedef struct { PurpleConnection *gc; int updated; GQueue *new_messages; + GQueue *pending_reads; GHashTable *joining_chats; guint timer; int in_fallback_chat; diff --git a/tgp-2prpl.c b/tgp-2prpl.c index 22bc976..fd29c6f 100644 --- a/tgp-2prpl.c +++ b/tgp-2prpl.c @@ -85,6 +85,12 @@ char *p2tgl_strdup_alias(tgl_peer_t *user) { return g_alias; } +int p2tgl_status_is_present (PurpleStatus *status) +{ + const char *name = purple_status_get_id (status); + return !(strcmp (name, "unavailable") == 0 || strcmp (name, "away") == 0); +} + static PurpleChat *blist_find_chat_by_hasht_cond(PurpleConnection *gc, int (*fn)(GHashTable *hasht, void *data), void *data) { PurpleAccount *account = purple_connection_get_account(gc); diff --git a/tgp-2prpl.h b/tgp-2prpl.h index 319281a..77f04a5 100644 --- a/tgp-2prpl.h +++ b/tgp-2prpl.h @@ -36,6 +36,7 @@ tgl_peer_t *p2tgl_get_peer (tgl_peer_id_t peer); tgl_peer_t *p2tgl_get_peer_by_id (int id); char *p2tgl_strdup_alias(tgl_peer_t *user); +int p2tgl_status_is_present (PurpleStatus *status); PurpleConversation *p2tgl_got_joined_chat (struct tgl_state *TLS, struct tgl_chat *chat); void p2tgl_got_chat_invite (PurpleConnection *gc, tgl_peer_t *chat, tgl_peer_id_t inviter, const char *message);