diff --git a/telegram-adium/TelegramJoinChatViewController.m b/telegram-adium/TelegramJoinChatViewController.m index 65e70c3..20a1d52 100644 --- a/telegram-adium/TelegramJoinChatViewController.m +++ b/telegram-adium/TelegramJoinChatViewController.m @@ -37,10 +37,12 @@ @implementation TelegramJoinChatViewController -static void tgl_peer_iterator_cb (tgl_peer_t *peer, void *extra) { +static void tgl_chat_iterator_cb (tgl_peer_t *peer, void *extra) { NSMutableArray *A = (__bridge NSMutableArray *)(extra); - if (tgl_get_peer_type (peer->id) == TGL_PEER_CHAT) { - [A addObject: [NSValue valueWithPointer: peer]]; + + // chats with 0 participants were deleted or left by the user + if (tgl_get_peer_type (peer->id) == TGL_PEER_CHAT && peer->chat.users_num > 0) { + [A addObject: [NSString stringWithUTF8String: peer->print_name]]; } } @@ -53,33 +55,12 @@ static void tgl_peer_iterator_cb (tgl_peer_t *peer, void *extra) { if (gc && PURPLE_CONNECTION_IS_CONNECTED(gc)) { connection_data *conn = purple_connection_get_protocol_data (gc); + // fetch all active chats and put them into the select box [popupButton_existingChat removeAllItems]; - - NSMutableArray *a = [NSMutableArray new]; - tgl_peer_iterator_ex (conn->TLS, tgl_peer_iterator_cb, (__bridge void *)(a)); - NSMutableArray *chats = [NSMutableArray new]; - NSMutableArray *leftChats = [NSMutableArray new]; - for (NSValue *V in a) { - tgl_peer_t *P = [V pointerValue]; - NSString *name = [[NSString alloc] initWithUTF8String:P->print_name]; - if (chat_is_member (conn->TLS->our_id, &P->chat)) { - [chats addObject: name]; - } - else { - [leftChats addObject: name]; - } - } - - NSArray *sortedChats = [chats sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { - return [(NSString*)a - compare:b - options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch]; - }]; - [popupButton_existingChat addItemsWithTitles: sortedChats]; - // TODO: Display left chats with a grey font to indicate that those are no - // longer, but still allow the user to view the history - // [popupButton_existingChat addItemsWithTitles: leftChats]; + tgl_peer_iterator_ex (conn->TLS, tgl_chat_iterator_cb, (__bridge void *)(chats)); + [popupButton_existingChat + addItemsWithTitles: [chats sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]]; // provide the current TLS instance for access by the autocompletion TelegramAutocompletionDelegate *D = [tokenField_createChatUsers delegate]; diff --git a/telegram-base.c b/telegram-base.c index a369d43..9aafa63 100644 --- a/telegram-base.c +++ b/telegram-base.c @@ -620,10 +620,9 @@ void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat * void create_group_chat_done_cb (struct tgl_state *TLS, void *title, int success) { if (success) { - tgl_peer_t *t = tgl_peer_get_by_name(TLS, title); - if (t) { - connection_data *conn = TLS->ev_base; - chat_show (conn->gc, tgl_get_peer_id(t->id)); + tgl_peer_t *P = tgl_peer_get_by_name (TLS, title); + if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { + tgp_chat_show (TLS, &P->chat); } } tgp_notify_on_error_gw (TLS, NULL, success); @@ -645,7 +644,7 @@ void tgp_create_group_chat_by_usernames (struct tgl_state *TLS, const char *titl if (P && tgl_get_peer_id (P->id) != TLS->our_id) { ids[j++] = P->id; } else { - debug("User %s not found in peer list", users[j]); + debug ("User %s not found in peer list", users[j]); } } if (i > 0) { @@ -662,9 +661,9 @@ static void create_group_chat_cb (void *_data, PurpleRequestFields* fields) { debug ("create_group_chat_cb()"); struct accept_create_chat_data *data = _data; const char *users[3] = { - purple_request_fields_get_string(fields, "user1"), - purple_request_fields_get_string(fields, "user2"), - purple_request_fields_get_string(fields, "user3") + purple_request_fields_get_string (fields, "user1"), + purple_request_fields_get_string (fields, "user2"), + purple_request_fields_get_string (fields, "user3") }; tgp_create_group_chat_by_usernames (data->TLS, data->title, users, 3, FALSE); diff --git a/telegram-purple.c b/telegram-purple.c index cdcbf81..e7473c8 100755 --- a/telegram-purple.c +++ b/telegram-purple.c @@ -83,7 +83,6 @@ static void update_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum static void update_marked_read (struct tgl_state *TLS, int num, struct tgl_message *list[]); static char *format_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, struct tgl_user *U); -void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); PurpleGroup *tggroup; const char *config_dir = "telegram-purple"; @@ -141,12 +140,6 @@ static void update_user_handler (struct tgl_state *TLS, struct tgl_user *user, u static void update_message_handler (struct tgl_state *TLS, struct tgl_message *M) { write_files_schedule (TLS); tgp_msg_recv (TLS, M); - - if (M->flags & TGLMF_SERVICE && - (M->action.type == tgl_message_action_chat_add_user || - M->action.type == tgl_message_action_chat_delete_user)) { - tgl_do_get_chat_info (TLS, M->to_id, FALSE, on_chat_get_info, NULL); - } } static void update_user_status_handler (struct tgl_state *TLS, struct tgl_user *U) { @@ -191,15 +184,17 @@ static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret } static void update_chat_handler (struct tgl_state *TLS, struct tgl_chat *chat, unsigned flags) { - PurpleChat *ch = p2tgl_chat_find (TLS, chat->id); - if (! (flags & TGL_UPDATE_CREATED)) { + PurpleChat *ch = p2tgl_chat_find (TLS, chat->id); + if (flags & TGL_UPDATE_TITLE && ch) { purple_blist_alias_chat (ch, chat->print_title); } + /* if (flags & (TGL_UPDATE_MEMBERS | TGL_UPDATE_ADMIN) && ch) { - chat_users_update (TLS, chat); + tgp_chat_users_update (TLS, chat); } + */ if (flags & TGL_UPDATE_DELETED && ch) { purple_blist_remove_chat (ch); } @@ -325,33 +320,26 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, free (dld); } -static void on_get_dialog_list_done (struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) { - int i; - for (i = size - 1; i >= 0; i--) { - tgl_peer_t *UC; - switch (tgl_get_peer_type (peers[i])) { - - case TGL_PEER_USER: { - PurpleBuddy *buddy = p2tgl_buddy_find (TLS, peers[i]); - UC = tgl_peer_get (TLS, peers[i]); - if (tgl_get_peer_id (peers[i]) != TLS->our_id) { - if (! buddy) { - buddy = p2tgl_buddy_new (TLS, UC); - purple_blist_add_buddy (buddy, NULL, tggroup, NULL); - tgl_do_get_user_info (TLS, UC->id, 0, on_user_get_info, get_user_info_data_new (0, UC->id)); - } - p2tgl_prpl_got_user_status (TLS, UC->id, &UC->user.status); - p2tgl_prpl_got_set_status_mobile (TLS, UC->id); - } else { - p2tgl_connection_set_display_name (TLS, UC); - } - break; +static void on_get_dialog_list_done (struct tgl_state *TLS, void *callback_extra, int success, int size, + tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) { + int i = size - 1; + for (; i >= 0; i--) if (tgl_get_peer_type (peers[i]) == TGL_PEER_USER) { + tgl_peer_t *UC = tgl_peer_get (TLS, peers[i]); + + if (tgl_get_peer_id (peers[i]) != TLS->our_id) { + PurpleBuddy *buddy = p2tgl_buddy_find (TLS, peers[i]); + if (! buddy) { + buddy = p2tgl_buddy_new (TLS, UC); + purple_blist_add_buddy (buddy, NULL, tggroup, NULL); + tgl_do_get_user_info (TLS, UC->id, 0, on_user_get_info, get_user_info_data_new (0, UC->id)); } - - case TGL_PEER_CHAT: - tgl_do_get_chat_info (TLS, peers[i], FALSE, on_chat_get_info, NULL); - break; + + p2tgl_prpl_got_user_status (TLS, UC->id, &UC->user.status); + p2tgl_prpl_got_set_status_mobile (TLS, UC->id); + } else { + p2tgl_connection_set_display_name (TLS, UC); } + break; } } @@ -379,21 +367,6 @@ void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, stru } } -void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C) { - if (!success) { - failure ("chat_get_info FAILED"); - return; - } - - PurpleChat *PC = p2tgl_chat_find (TLS, C->id); - if (!PC) { - PC = p2tgl_chat_new (TLS, C); - purple_blist_add_chat (PC, NULL, NULL); - } - - chat_users_update (TLS, C); -} - void on_ready (struct tgl_state *TLS) { debug ("on_ready()."); connection_data *conn = TLS->ev_base; @@ -479,8 +452,10 @@ static void create_chat_link_done (struct tgl_state *TLS, void *extra, int succe tgl_peer_t *C = extra; if (success) { - chat_show (conn->gc, tgl_get_peer_id (C->id)); - char *msg = g_strdup_printf("Invite link: %s", url); + assert (tgl_get_peer_type (C->id) == TGL_PEER_CHAT); + tgp_chat_show (TLS, &C->chat); + + char *msg = g_strdup_printf ("Invite link: %s", url); serv_got_chat_in (conn->gc, tgl_get_peer_id(C->id), "WebPage", PURPLE_MESSAGE_SYSTEM, msg, time(NULL)); g_free (msg); @@ -561,23 +536,6 @@ static GList* tgprpl_blist_node_menu (PurpleBlistNode *node) { return menu; } -static GList *tgprpl_chat_join_info (PurpleConnection * gc) { - debug ("tgprpl_chat_join_info()"); - - struct proto_chat_entry *pce; - pce = g_new0(struct proto_chat_entry, 1); - pce->label = "_Subject:"; - pce->identifier = "subject"; - pce->required = FALSE; - GList *info = g_list_append (NULL, pce); - - pce = g_new0(struct proto_chat_entry, 1); - pce->label = "_Join by Link:"; - pce->identifier = "link"; - pce->required = FALSE; - return g_list_append (info, pce); -} - static void tgprpl_login (PurpleAccount * acct) { debug ("tgprpl_login()"); @@ -741,50 +699,6 @@ static void tgprpl_remove_buddy (PurpleConnection * gc, PurpleBuddy * buddy, Pur } } -static void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) { - debug ("tgprpl_chat_join()"); - const char *subject = NULL, *link = NULL; - gpointer value; - connection_data *conn = purple_connection_get_protocol_data (gc); - - value = g_hash_table_lookup (data, "id"); - if (value && atoi (value)) { - chat_show (conn->gc, atoi (value)); - return; - } - - link = g_hash_table_lookup(data, "link"); - if (str_not_empty (link)) { - tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL); - return; - } - - subject = g_hash_table_lookup (data, "subject"); - if (str_not_empty (subject)) { - tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject); - if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { - chat_show (conn->gc, tgl_get_peer_id (P->id)); - return; - } - request_create_chat (conn->TLS, subject); - } -} - -static char *tgprpl_get_chat_name (GHashTable * data) { - return g_strdup(g_hash_table_lookup(data, "subject")); -} - -static void add_user_to_chat_done_cb (struct tgl_state *TLS, void *callback_extra, int success) { - tgl_peer_t *C = callback_extra; - - if (success) { - // update users - tgl_do_get_chat_info (TLS, C->id, FALSE, on_chat_get_info, NULL); - } else { - tgp_notify_on_error_gw (TLS, NULL, success); - } -} - static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *message, const char *name) { debug ("tgprpl_chat_invite()"); @@ -797,7 +711,7 @@ static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *messa return; } - tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, add_user_to_chat_done_cb, chat); + tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, tgp_notify_on_error_gw, chat); } static int tgprpl_send_chat (PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) { diff --git a/telegram-purple.h b/telegram-purple.h index d844078..cacf779 100644 --- a/telegram-purple.h +++ b/telegram-purple.h @@ -59,7 +59,6 @@ #define TGP_DEFAULT_SEND_READ_NOTIFICATIONS TRUE #define TGP_KEY_SEND_READ_NOTIFICATIONS "send-read-notifications" -void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); void on_ready (struct tgl_state *TLS); extern const char *pk_path; extern const char *config_dir; diff --git a/tgp-2prpl.c b/tgp-2prpl.c index a5e1f3b..c373f87 100644 --- a/tgp-2prpl.c +++ b/tgp-2prpl.c @@ -294,6 +294,14 @@ PurpleChat *p2tgl_chat_new (struct tgl_state *TLS, struct tgl_chat *chat) { return C; } +void p2tgl_chat_update (PurpleChat *chat, tgl_peer_id_t id, int admin_id, const char *subject) { + GHashTable *ht = purple_chat_get_components (chat); + + g_hash_table_replace (ht, g_strdup ("id"), g_strdup_printf ("%d", tgl_get_peer_id (id))); + g_hash_table_replace (ht, g_strdup ("owner"), g_strdup_printf ("%d", admin_id)); + g_hash_table_replace (ht, g_strdup ("subject"), g_strdup (subject)); +} + tgl_chat_id_t p2tgl_chat_get_id (PurpleChat *PC) { char *name = g_hash_table_lookup (purple_chat_get_components (PC), "id"); if (! atoi (name)) { @@ -310,17 +318,17 @@ PurpleChat *p2tgl_chat_find (struct tgl_state *TLS, tgl_peer_id_t id) { } void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, - struct tgl_chat_user user, char *message, int flags, int new_arrival) { + int user, char *message, int flags, int new_arrival) { PurpleConvChat *cdata = purple_conversation_get_chat_data(conv); - char *name = g_strdup_printf("%d", user.user_id); + char *name = g_strdup_printf ("%d", user); purple_conv_chat_add_user (cdata, name, message, flags, new_arrival); // inject print_name into chat buddies to display a human-readable name // for buddies not in the buddy list instead of the user id - tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER(user.user_id)); + tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER(user)); if (U) { PurpleConvChatBuddy *cbuddy = purple_conv_chat_cb_find (PURPLE_CONV_CHAT(conv), name); - PurpleConversationUiOps *uiops = purple_conversation_get_ui_ops (conv);; + PurpleConversationUiOps *uiops = purple_conversation_get_ui_ops (conv); if (cbuddy && cbuddy->alias) { g_free (cbuddy->alias); cbuddy->alias = g_strdup (U->print_name); @@ -337,6 +345,14 @@ void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, g_free(name); } +void p2tgl_conv_del_user (struct tgl_state *TLS, PurpleConversation *conv, const char *message, int userid) { + char *name = g_strdup_printf("%d", userid); + + purple_conv_chat_remove_user (purple_conversation_get_chat_data (conv), name, message); + + g_free (name); +} + void p2tgl_connection_set_display_name(struct tgl_state *TLS, tgl_peer_t *user) { char *name = p2tgl_strdup_alias (user); purple_connection_set_display_name (tg_get_conn(TLS), name); diff --git a/tgp-2prpl.h b/tgp-2prpl.h index 9a0f8b2..a644383 100644 --- a/tgp-2prpl.h +++ b/tgp-2prpl.h @@ -60,14 +60,15 @@ void p2tgl_prpl_got_set_status_mobile (struct tgl_state *TLS, tgl_peer_id_t user void p2tgl_prpl_got_set_status_offline (struct tgl_state *TLS, tgl_peer_id_t user); void p2tgl_connection_set_display_name(struct tgl_state *TLS, tgl_peer_t *user); -void p2tgl_conv_del_user (PurpleConversation *conv, tgl_peer_id_t user); +void p2tgl_conv_del_user (struct tgl_state *TLS, PurpleConversation *conv, const char *message, int userid); void p2tgl_conv_add_users (PurpleConversation *conv, struct tgl_chat_user *list); -void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, struct tgl_chat_user user, char *message, int flags, int new_arrival); +void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, int user, char *message, int flags, int new_arrival); PurpleConversation *p2tgl_find_conversation_with_account (struct tgl_state *TLS, tgl_peer_id_t peer); void p2tgl_conversation_write (PurpleConversation *conv, tgl_peer_id_t who, const char *message, int flags, int date); PurpleConversation *p2tgl_conversation_new (struct tgl_state *TLS, tgl_peer_id_t who); PurpleChat *p2tgl_chat_new (struct tgl_state *TLS, struct tgl_chat *chat); +void p2tgl_chat_update (PurpleChat *chat, tgl_peer_id_t id, int admin_id, const char *subject); PurpleChat *p2tgl_chat_find (struct tgl_state *TLS, tgl_peer_id_t chat); void *p2tgl_notify_userinfo(struct tgl_state *TLS, tgl_peer_id_t user, PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb, gpointer user_data); diff --git a/tgp-chat.c b/tgp-chat.c index ea330de..55b0c07 100644 --- a/tgp-chat.c +++ b/tgp-chat.c @@ -20,45 +20,125 @@ #include "tgp-chat.h" #include "msglog.h" +#include "tgp-utils.h" +#include "telegram-base.h" -void chat_add_all_users (struct tgl_state *TLS, PurpleConversation *pc, struct tgl_chat *chat) { - int i; - for (i = 0; i < chat->user_list_size; i++) { - struct tgl_chat_user *uid = (chat->user_list + i); - int flags = (chat->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE); - p2tgl_conv_add_user (TLS, pc, *uid, NULL, flags, FALSE); +#include +#include + +void tgp_chat_on_loaded_chat_full (struct tgl_state *TLS, struct tgl_chat *C) { + PurpleChat *PC = p2tgl_chat_find (TLS, C->id); + if (!PC) { + PC = p2tgl_chat_new (TLS, C); + purple_blist_add_chat (PC, NULL, NULL); } + p2tgl_chat_update (PC, C->id, C->admin_id, C->print_title); } -void chat_users_update (struct tgl_state *TLS, struct tgl_chat *chat) { - PurpleConversation *pc = purple_find_chat(tg_get_conn(TLS), tgl_get_peer_id(chat->id)); - if (pc) { - purple_conv_chat_clear_users (purple_conversation_get_chat_data(pc)); - chat_add_all_users (TLS, pc, chat); +static void tgp_chat_on_loaded_chat_full_joining (struct tgl_state *TLS, void *_, + int success, struct tgl_chat *C) { + if (! success) { + tgp_notify_on_error_gw (TLS, NULL, success); + return; } -} - -PurpleConversation *chat_show (PurpleConnection *gc, int id) { - connection_data *conn = purple_connection_get_protocol_data(gc); - PurpleConversation *convo = purple_find_chat (gc, id); - PurpleConvChat *chat = purple_conversation_get_chat_data (convo); - tgl_peer_t *P = tgl_peer_get (conn->TLS, TGL_MK_CHAT(id)); - if (! P) { - warning ("Chat %d not existing, not showing...", id); - return NULL; + tgp_chat_on_loaded_chat_full (TLS, C); + tgp_chat_show (TLS, C); + + // Check if the users attempts to join an empty chat + if (! C->user_list_size) { + p2tgl_got_chat_in (TLS, C->id, C->id, "You have already left this chat.", + PURPLE_MESSAGE_SYSTEM, time (NULL)); } +} + +static void tgp_chat_add_all_users (struct tgl_state *TLS, PurpleConversation *pc, struct tgl_chat *C) { + int i = 0; + for (; i < C->user_list_size; i++) { + struct tgl_chat_user *uid = (C->user_list + i); + int flags = (C->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE); + p2tgl_conv_add_user (TLS, pc, uid->user_id, NULL, flags, FALSE); + } +} + +void tgp_chat_users_update (struct tgl_state *TLS, struct tgl_chat *C) { + PurpleConversation *pc = purple_find_chat (tg_get_conn (TLS), tgl_get_peer_id (C->id)); + if (pc) { + purple_conv_chat_clear_users (purple_conversation_get_chat_data (pc)); + tgp_chat_add_all_users (TLS, pc, C); + } +} + +PurpleConversation *tgp_chat_show (struct tgl_state *TLS, struct tgl_chat *C) { + connection_data *conn = TLS->ev_base; + + PurpleConversation *convo = purple_find_chat (conn->gc, tgl_get_peer_id (C->id)); + PurpleConvChat *chat = purple_conversation_get_chat_data (convo); + if (! convo || (chat && purple_conv_chat_has_left (chat))) { - convo = p2tgl_got_joined_chat (conn->TLS, &P->chat); - chat_users_update (conn->TLS, &P->chat); + convo = p2tgl_got_joined_chat (conn->TLS, C); + tgp_chat_users_update (conn->TLS, C); } return convo; } -int chat_is_member (int who, struct tgl_chat *chat) { - int i; - for (i = 0; i < chat->user_list_size; i++) if ((chat->user_list + i)->user_id == who) { - return TRUE; - } - return FALSE; +GList *tgprpl_chat_join_info (PurpleConnection * gc) { + struct proto_chat_entry *pce; + pce = g_new0 (struct proto_chat_entry, 1); + pce->label = "_Subject:"; + pce->identifier = "subject"; + pce->required = FALSE; + GList *info = g_list_append (NULL, pce); + + pce = g_new0 (struct proto_chat_entry, 1); + pce->label = "_Join by Link:"; + pce->identifier = "link"; + pce->required = FALSE; + return g_list_append (info, pce); +} + +void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) { + debug ("tgprpl_chat_join()"); + connection_data *conn = purple_connection_get_protocol_data (gc); + + // join existing chat by id when the user clicks on a chat in the buddy list + void *value = g_hash_table_lookup (data, "id"); + if (value && atoi (value)) { + tgl_peer_id_t cid = TGL_MK_CHAT(atoi (value)); + tgl_peer_t *P = tgl_peer_get (conn->TLS, cid); + if (P) { + tgl_do_get_chat_info (conn->TLS, cid, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); + } else { + warning ("Cannot join chat %d, peer not found...", tgl_get_peer_id (cid)); + } + return; + } + + // join chat by invite link provided in the chat join window + const char *link = g_hash_table_lookup (data, "link"); + if (str_not_empty (link)) { + tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL); + return; + } + + // if a chat with this name doesn't exist yet, prompt to create one + const char *subject = g_hash_table_lookup (data, "subject"); + if (str_not_empty (subject)) { + tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject); + + // handle joining chats by print_names as used by the Adium plugin + if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { + tgl_do_get_chat_info (conn->TLS, P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); + return; + } else { + warning ("Cannot join chat %s, peer not found...", subject); + } + + // user creates a new chat by providing its subject the chat join window + request_create_chat (conn->TLS, subject); + } +} + +char *tgprpl_get_chat_name (GHashTable * data) { + return g_strdup (g_hash_table_lookup (data, "subject")); } diff --git a/tgp-chat.h b/tgp-chat.h index cf418f0..83c7ddc 100644 --- a/tgp-chat.h +++ b/tgp-chat.h @@ -26,9 +26,13 @@ #include "tgp-2prpl.h" #include -PurpleConversation *chat_show (PurpleConnection *gc, int id); -void chat_users_update (struct tgl_state *TLS, struct tgl_chat *chat); +void tgp_chat_on_loaded_chat_full (struct tgl_state *TLS, struct tgl_chat *C); +PurpleConversation *tgp_chat_show (struct tgl_state *TLS, struct tgl_chat *C); +void tgp_chat_users_update (struct tgl_state *TLS, struct tgl_chat *C); int chat_add_message (struct tgl_state *TLS, struct tgl_message *M, char *text); -int chat_is_member (int who, struct tgl_chat *chat); + +char *tgprpl_get_chat_name (GHashTable *data); +void tgprpl_chat_join (PurpleConnection *gc, GHashTable *data); +GList *tgprpl_chat_join_info (PurpleConnection *gc); #endif diff --git a/tgp-msg.c b/tgp-msg.c index 1634a74..99e5263 100644 --- a/tgp-msg.c +++ b/tgp-msg.c @@ -43,6 +43,7 @@ static void tgp_msg_err_out (struct tgl_state *TLS, const char *error, tgl_peer_ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) { assert (M && M->flags & TGLMF_SERVICE); + connection_data *conn = TLS->ev_base; char *txt_user = NULL; char *txt_action = NULL; char *txt = NULL; @@ -52,6 +53,7 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) { return NULL; } txt_user = p2tgl_strdup_alias (peer); + switch (M->action.type) { case tgl_message_action_chat_create: txt_action = g_strdup_printf ("created chat %s", M->action.title); @@ -65,20 +67,65 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) { case tgl_message_action_chat_delete_photo: txt_action = g_strdup ("deleted photo"); break; - case tgl_message_action_chat_add_user: - { + case tgl_message_action_chat_add_user_by_link: { + tgl_peer_t *actionPeer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); + if (actionPeer) { + char *alias = p2tgl_strdup_alias (actionPeer); + + PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id)); + txt_action = g_strdup_printf ("%s added user %s by link.", alias, txt_user); + if (conv) { + p2tgl_conv_add_user (TLS, conv, tgl_get_peer_id (peer->id), NULL, 0, FALSE); + } + + g_free (alias); + g_free (txt_user); + return txt_action; + } + break; + } + case tgl_message_action_chat_add_user: { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); if (peer) { char *alias = p2tgl_strdup_alias (peer); txt_action = g_strdup_printf ("added user %s", alias); + + PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id)); + if (conv) { + p2tgl_conv_add_user (TLS, conv, M->action.user, NULL, 0, FALSE); + } g_free (alias); } break; } - case tgl_message_action_chat_delete_user: - { + case tgl_message_action_chat_delete_user: { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); if (peer) { + + tgl_peer_t *chatPeer = tgl_peer_get (TLS, M->to_id); + assert (tgl_get_peer_type(chatPeer->id) == TGL_PEER_CHAT); + + // make sure that the chat is showing before deleting the user, otherwise the + // chat will be initialised after removing the chat and the chat will still contain + // the deleted user + PurpleConversation *conv = tgp_chat_show (TLS, &chatPeer->chat); + if (conv) { + char *alias = p2tgl_strdup_alias (peer); + txt_action = g_strdup_printf ("%s deleted user %s.", txt_user, alias); + g_free (alias); + + p2tgl_conv_del_user (TLS, conv, txt_action, M->action.user); + if (M->action.user == TLS->our_id) { + purple_conv_chat_left (purple_conversation_get_chat_data (conv)); + } + + // conv_del_user already printed a message, prevent a redundant message + // from being printed by returning NULL + g_free (txt_user); + g_free (txt_action); + return NULL; + } + char *alias = p2tgl_strdup_alias (peer); txt_action = g_strdup_printf ("deleted user %s", alias); g_free (alias); @@ -117,7 +164,6 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) { break; } if (txt_action) { - debug ("SERVICE MESSAGE: %s", txt_action); txt = g_strdup_printf ("%s %s.", txt_user, txt_action); g_free (txt_action); } @@ -454,15 +500,17 @@ static void tgp_msg_display (struct tgl_state *TLS, struct tgp_msg_loading *C) { flags |= PURPLE_MESSAGE_DELAYED; } + // some service messages (like removing/adding users from chats) might print the message + // text through other means and leave the text empty if (! str_not_empty (text)) { - warning ("No text to display"); return; } // display the message to the user switch (tgl_get_peer_type (M->to_id)) { case TGL_PEER_CHAT: { - if (chat_show (conn->gc, tgl_get_peer_id (M->to_id))) { + tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); + if (tgp_chat_show (TLS, &P->chat)) { p2tgl_got_chat_in (TLS, M->to_id, M->from_id, text, flags, M->date); } pending_reads_add (conn->pending_reads, M->to_id); @@ -505,7 +553,7 @@ static void tgp_msg_process_in_ready (struct tgl_state *TLS) { struct tgp_msg_loading *C; while ((C = g_queue_peek_head (conn->new_messages))) { - if (! C->done) { + if (C->pending) { break; } g_queue_pop_head (conn->new_messages); @@ -518,10 +566,23 @@ static void tgp_msg_process_in_ready (struct tgl_state *TLS) { } static void tgp_msg_on_loaded_document (struct tgl_state *TLS, void *extra, int success, const char *filename) { + debug ("tgp_msg_on_loaded_document()"); assert (success); + struct tgp_msg_loading *C = extra; C->data = (void *) g_strdup (filename); - C->done = TRUE; + -- C->pending; + tgp_msg_process_in_ready (TLS); +} + +static void tgp_msg_on_loaded_chat_full (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *chat) { + debug ("tgp_msg_on_loaded_chat()"); + assert (success); + + tgp_chat_on_loaded_chat_full (TLS, chat); + + struct tgp_msg_loading *C = extra; + -- C->pending; tgp_msg_process_in_ready (TLS); } @@ -538,29 +599,31 @@ void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M) { return; } - struct tgp_msg_loading *C = tgp_msg_loading_init (TRUE, M); + struct tgp_msg_loading *C = tgp_msg_loading_init (M); + if (! (M->flags & TGLMF_SERVICE)) { + // handle all messages that need to load content before they can be displayed if (M->media.type != tgl_message_media_none) { switch (M->media.type) { case tgl_message_media_photo: - C->done = FALSE; + ++ C->pending; tgl_do_load_photo (TLS, M->media.photo, tgp_msg_on_loaded_document, C); break; - // documents that are stickers or images will be displayed just like regular photo messages - // and need to be lodaed beforehand + // documents that are stickers or images will be displayed just like regular photo messages + // and need to be lodaed beforehand case tgl_message_media_document: case tgl_message_media_video: case tgl_message_media_audio: if (M->media.document->flags & TGLDF_STICKER || M->media.document->flags & TGLDF_IMAGE) { - C->done = FALSE; + ++ C->pending; tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C); } break; case tgl_message_media_document_encr: if (M->media.encr_document->flags & TGLDF_STICKER || M->media.encr_document->flags & TGLDF_IMAGE) { - C->done = FALSE; + ++ C->pending; tgl_do_load_encr_document (TLS, M->media.encr_document, tgp_msg_on_loaded_document, C); } break; @@ -569,12 +632,25 @@ void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M) { // TODO: load geo thumbnail break; - default: + default: // prevent Clang warnings ... break; } } } + if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) { + + tgl_peer_t *peer = tgl_peer_get (TLS, M->to_id); + assert (peer); + + if (! peer->chat.user_list_size) { + // we receive messages even though the user list is empty, this means that we still + // haven't fetched the full chat information + ++ C->pending; + tgl_do_get_chat_info (TLS, M->to_id, FALSE, tgp_msg_on_loaded_chat_full, C); + } + } + g_queue_push_tail (conn->new_messages, C); tgp_msg_process_in_ready (TLS); } diff --git a/tgp-structs.c b/tgp-structs.c index 78396bf..e16495b 100644 --- a/tgp-structs.c +++ b/tgp-structs.c @@ -70,9 +70,9 @@ void tgp_msg_loading_free (gpointer data) { free (C); } -struct tgp_msg_loading *tgp_msg_loading_init (int done, struct tgl_message *M) { +struct tgp_msg_loading *tgp_msg_loading_init (struct tgl_message *M) { struct tgp_msg_loading *C = malloc (sizeof (struct tgp_msg_loading)); - C->done = done; + C->pending = 0; C->msg = M; C->data = NULL; return C; diff --git a/tgp-structs.h b/tgp-structs.h index 81c35f2..a5a0d7c 100755 --- a/tgp-structs.h +++ b/tgp-structs.h @@ -62,7 +62,7 @@ struct download_desc { }; struct tgp_msg_loading { - int done; + int pending; struct tgl_message *msg; void *data; }; @@ -91,7 +91,7 @@ void used_images_add (connection_data *data, gint imgid); void *connection_data_free (connection_data *conn); connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *gc, PurpleAccount *pa); get_user_info_data* get_user_info_data_new (int show_info, tgl_peer_id_t peer); -struct tgp_msg_loading *tgp_msg_loading_init (int done, struct tgl_message *M); +struct tgp_msg_loading *tgp_msg_loading_init (struct tgl_message *M); struct tgp_msg_sending *tgp_msg_sending_init (struct tgl_state *TLS, char *M, tgl_peer_id_t to); void tgp_msg_loading_free (gpointer data); void tgp_msg_sending_free (gpointer data);