From 16ba82555ba829616214400817e3f77a5647f52c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Mar 2018 21:24:02 +0000 Subject: [PATCH 1/7] Add PURPLE_BLIST_NODE_FLAG_INVISIBLE to avoid showing nodes in UI This allows a PRPL to create hidden buddies, which are used for providing presence and full name (alias) information for IM peers who *aren't* buddies. It works for chat room members too, although there may be a way to handle those with lower overhead. Fixes #17295 --- libpurple/blist.c | 9 ++++++--- libpurple/blist.h | 4 +++- pidgin/gtkblist.c | 7 ++++--- pidgin/gtkconv.c | 26 ++++++++++++++++---------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/libpurple/blist.c b/libpurple/blist.c index 2233835..3a7e36e 100644 --- a/libpurple/blist.c +++ b/libpurple/blist.c @@ -2431,7 +2431,7 @@ const char *purple_chat_get_name(PurpleChat *chat) PurpleBuddy *purple_find_buddy(PurpleAccount *account, const char *name) { - PurpleBuddy *buddy; + PurpleBuddy *buddy, *fallback_buddy = NULL; struct _purple_hbuddy hb; PurpleBlistNode *group; @@ -2448,11 +2448,14 @@ PurpleBuddy *purple_find_buddy(PurpleAccount *account, const char *name) hb.group = group; if ((buddy = g_hash_table_lookup(purplebuddylist->buddies, &hb))) { - return buddy; + if (PURPLE_BLIST_NODE_IS_VISIBLE(buddy)) + return buddy; + /* Only return invisible buddies if there are no visible ones */ + fallback_buddy = buddy; } } - return NULL; + return fallback_buddy; } PurpleBuddy *purple_find_buddy_in_group(PurpleAccount *account, const char *name, diff --git a/libpurple/blist.h b/libpurple/blist.h index d3cae7a..9db9fb3 100644 --- a/libpurple/blist.h +++ b/libpurple/blist.h @@ -71,7 +71,8 @@ typedef enum typedef enum { - PURPLE_BLIST_NODE_FLAG_NO_SAVE = 1 << 0 /**< node should not be saved with the buddy list */ + PURPLE_BLIST_NODE_FLAG_NO_SAVE = 1 << 0, /**< node should not be saved with the buddy list */ + PURPLE_BLIST_NODE_FLAG_INVISIBLE = 1 << 1, /**< node should not be displayed */ } PurpleBlistNodeFlags; @@ -82,6 +83,7 @@ typedef enum #define PURPLE_BLIST_NODE_HAS_FLAG(b, f) (purple_blist_node_get_flags((PurpleBlistNode*)(b)) & (f)) #define PURPLE_BLIST_NODE_SHOULD_SAVE(b) (! PURPLE_BLIST_NODE_HAS_FLAG(b, PURPLE_BLIST_NODE_FLAG_NO_SAVE)) +#define PURPLE_BLIST_NODE_IS_VISIBLE(b) (! PURPLE_BLIST_NODE_HAS_FLAG(b, PURPLE_BLIST_NODE_FLAG_INVISIBLE)) #define PURPLE_BLIST_NODE_NAME(n) (purple_blist_node_get_type(n) == PURPLE_BLIST_CHAT_NODE ? purple_chat_get_name((PurpleChat*)n) : \ purple_blist_node_get_type(n) == PURPLE_BLIST_BUDDY_NODE ? purple_buddy_get_name((PurpleBuddy*)n) : NULL) diff --git a/pidgin/gtkblist.c b/pidgin/gtkblist.c index f200eb4..71361f7 100644 --- a/pidgin/gtkblist.c +++ b/pidgin/gtkblist.c @@ -3202,7 +3202,7 @@ static gboolean buddy_is_displayable(PurpleBuddy *buddy) { struct _pidgin_blist_node *gtknode; - if(!buddy) + if(!buddy || !PURPLE_BLIST_NODE_IS_VISIBLE(buddy)) return FALSE; gtknode = ((PurpleBlistNode*)buddy)->ui_data; @@ -6386,14 +6386,15 @@ static void pidgin_blist_update_group(PurpleBuddyList *list, else count = purple_blist_get_group_online_count(group); - if (count > 0 || purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups")) + if (!PURPLE_BLIST_NODE_IS_VISIBLE(gnode) || !PURPLE_BLIST_NODE_IS_VISIBLE(node)) + show = FALSE; + else if (count > 0 || purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups")) show = TRUE; else if (PURPLE_BLIST_NODE_IS_BUDDY(node) && buddy_is_displayable((PurpleBuddy*)node)) { /* Or chat? */ show = TRUE; } else if (!show_offline) { show = pidgin_blist_group_has_show_offline_buddy(group); } - if (show) { gchar *title; gboolean biglist; diff --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c index 5c3e2d5..74dbe69 100644 --- a/pidgin/gtkconv.c +++ b/pidgin/gtkconv.c @@ -632,7 +632,7 @@ add_remove_cb(GtkWidget *widget, PidginConversation *gtkconv) PurpleBuddy *b; b = purple_find_buddy(account, name); - if (b != NULL) + if (b != NULL && PURPLE_BLIST_NODE_IS_VISIBLE(b)) pidgin_dialogs_remove_buddy(b); else if (account != NULL && purple_account_is_connected(account)) purple_blist_request_add_buddy(account, (char *)name, NULL, NULL); @@ -1686,7 +1686,8 @@ create_chat_menu(PurpleConversation *conv, const char *who, PurpleConnection *gc } if (!is_me && prpl_info && !(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME) && (prpl_info->add_buddy != NULL)) { - if ((buddy = purple_find_buddy(conv->account, who)) != NULL) + if ((buddy = purple_find_buddy(conv->account, who)) != NULL && + PURPLE_BLIST_NODE_IS_VISIBLE(buddy)) button = pidgin_new_item_from_stock(menu, _("Remove"), GTK_STOCK_REMOVE, G_CALLBACK(menu_chat_add_remove_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL); else @@ -4542,7 +4543,7 @@ buddy_cb_common(PurpleBuddy *buddy, PurpleConversation *conv, gboolean is_buddy) static void buddy_added_cb(PurpleBlistNode *node, PurpleConversation *conv) { - if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) + if (!PURPLE_BLIST_NODE_IS_BUDDY(node) || !PURPLE_BLIST_NODE_IS_VISIBLE(node)) return; buddy_cb_common(PURPLE_BUDDY(node), conv, TRUE); @@ -4551,12 +4552,15 @@ buddy_added_cb(PurpleBlistNode *node, PurpleConversation *conv) static void buddy_removed_cb(PurpleBlistNode *node, PurpleConversation *conv) { + PurpleBuddy *buddy; + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) return; - /* If there's another buddy for the same "dude" on the list, do nothing. */ - if (purple_find_buddy(purple_buddy_get_account(PURPLE_BUDDY(node)), - purple_buddy_get_name(PURPLE_BUDDY(node))) != NULL) + /* If there's another real buddy for the same "dude" on the list, do nothing. */ + buddy = purple_find_buddy(purple_buddy_get_account(PURPLE_BUDDY(node)), + purple_buddy_get_name(PURPLE_BUDDY(node))); + if (buddy && PURPLE_BLIST_NODE_IS_VISIBLE(buddy)) return; buddy_cb_common(PURPLE_BUDDY(node), conv, FALSE); @@ -6544,6 +6548,7 @@ gray_stuff_out(PidginConversation *gtkconv) * is sensitive or not. */ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { + PurpleBuddy *buddy; /* Show stuff that applies to IMs, hide stuff that applies to chats */ /* Deal with menu items */ @@ -6562,12 +6567,13 @@ gray_stuff_out(PidginConversation *gtkconv) gtk_widget_show(win->menu.unblock); } - if (purple_find_buddy(account, purple_conversation_get_name(conv)) == NULL) { - gtk_widget_show(win->menu.add); - gtk_widget_hide(win->menu.remove); - } else { + buddy = purple_find_buddy(account, purple_conversation_get_name(conv)); + if (buddy && PURPLE_BLIST_NODE_IS_VISIBLE(buddy)) { gtk_widget_show(win->menu.remove); gtk_widget_hide(win->menu.add); + } else { + gtk_widget_show(win->menu.add); + gtk_widget_hide(win->menu.remove); } gtk_widget_show(win->menu.insert_link); -- 2.7.4