Mon, 15 Aug 2022 22:19:19 -0500
Modernize XMPP discovery plugin
By porting common triggers to actions, dialog buttons to action widgets, `GtkMenu` to `GtkPopoverMenu`, using the `g_rc_box` API, and add braces everywhere. These will mostly make porting to GTK4 easier.
Also, added a default Service name of the JID. Otherwise, looking at `xmpp.org`, you previously got a big list of empty-looking rows (which also warn when the tooltip is shown).
Testing Done:
Opened plugin window, Browsed to `xmpp.org` and `pidgin.im`, checked that the Add button opened the Add-to-chat dialog, checked that double-click did the same, checked that the menu item did the same. I did not check Register in any of its forms as I don't know what server to query that returns something which could be registered on.
Reviewed at https://reviews.imfreedom.org/r/1596/
--- a/pidgin/plugins/disco/gtkdisco.c Mon Aug 15 21:30:26 2022 -0500 +++ b/pidgin/plugins/disco/gtkdisco.c Mon Aug 15 22:19:19 2022 -0500 @@ -1,4 +1,6 @@ -/* pidgin +/* + * Pidgin - Internet Messenger + * Copyright (C) Pidgin Developers <devel@pidgin.im> * * Pidgin is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this @@ -15,8 +17,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * along with this program; if not, see <https://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H @@ -42,61 +43,62 @@ NUM_OF_COLUMNS }; +static PidginDiscoList * +pidgin_disco_list_new(void) { + return g_rc_box_new0(PidginDiscoList); +} + static void pidgin_disco_list_destroy(PidginDiscoList *list) { g_hash_table_destroy(list->services); - if (list->dialog && list->dialog->discolist == list) + if (list->dialog && list->dialog->discolist == list) { list->dialog->discolist = NULL; + } g_free((gchar*)list->server); - g_free(list); } PidginDiscoList *pidgin_disco_list_ref(PidginDiscoList *list) { g_return_val_if_fail(list != NULL, NULL); - ++list->ref; - purple_debug_misc("xmppdisco", "reffing list, ref count now %d\n", list->ref); - - return list; + purple_debug_misc("xmppdisco", "reffing list"); + return g_rc_box_acquire(list); } void pidgin_disco_list_unref(PidginDiscoList *list) { g_return_if_fail(list != NULL); - --list->ref; - - purple_debug_misc("xmppdisco", "unreffing list, ref count now %d\n", list->ref); - if (list->ref == 0) - pidgin_disco_list_destroy(list); + purple_debug_misc("xmppdisco", "unreffing list"); + g_rc_box_release_full(list, (GDestroyNotify)pidgin_disco_list_destroy); } void pidgin_disco_list_set_in_progress(PidginDiscoList *list, gboolean in_progress) { PidginDiscoDialog *dialog = list->dialog; - if (!dialog) + if (!dialog) { return; + } list->in_progress = in_progress; if (in_progress) { gtk_widget_set_sensitive(dialog->account_chooser, FALSE); - gtk_widget_set_sensitive(dialog->stop_button, TRUE); - gtk_widget_set_sensitive(dialog->browse_button, FALSE); + g_simple_action_set_enabled(dialog->stop_action, TRUE); + g_simple_action_set_enabled(dialog->browse_action, FALSE); } else { gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress), 0.0); gtk_widget_set_sensitive(dialog->account_chooser, TRUE); - gtk_widget_set_sensitive(dialog->stop_button, FALSE); - gtk_widget_set_sensitive(dialog->browse_button, TRUE); + g_simple_action_set_enabled(dialog->stop_action, FALSE); + g_simple_action_set_enabled(dialog->browse_action, TRUE); /* - gtk_widget_set_sensitive(dialog->register_button, FALSE); - gtk_widget_set_sensitive(dialog->add_button, FALSE); + g_simple_action_set_enabled(dialog->register_action, FALSE); + g_simple_action_set_enabled(dialog->add_action, FALSE); */ } } @@ -148,16 +150,24 @@ PurpleAccount *account = pidgin_account_chooser_get_selected(PIDGIN_ACCOUNT_CHOOSER(chooser)); gboolean change = (account != dialog->account); dialog->account = account; - gtk_widget_set_sensitive(dialog->browse_button, account != NULL); + g_simple_action_set_enabled(dialog->browse_action, account != NULL); if (change) { g_clear_pointer(&dialog->discolist, pidgin_disco_list_unref); } } -static void register_button_cb(GtkWidget *unused, PidginDiscoDialog *dialog) +static void +activate_register(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + gpointer data) { - xmpp_disco_service_register(dialog->selected); + PidginDiscoDialog *dialog = data; + XmppDiscoService *service = dialog->selected; + + g_return_if_fail(service != NULL); + + xmpp_disco_service_register(service); } static void discolist_cancel_cb(PidginDiscoList *pdl, const char *server) @@ -171,7 +181,7 @@ static void discolist_ok_cb(PidginDiscoList *pdl, const char *server) { pdl->dialog->prompt_handle = NULL; - gtk_widget_set_sensitive(pdl->dialog->browse_button, TRUE); + g_simple_action_set_enabled(pdl->dialog->browse_action, TRUE); if (!server || !*server) { purple_notify_error(my_plugin, _("Invalid Server"), _("Invalid Server"), @@ -187,8 +197,12 @@ xmpp_disco_start(pdl); } -static void browse_button_cb(GtkWidget *button, PidginDiscoDialog *dialog) +static void +activate_browse(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + gpointer data) { + PidginDiscoDialog *dialog = data; PurpleConnection *pc; PidginDiscoList *pdl; const char *username; @@ -196,17 +210,18 @@ char *server = NULL; pc = purple_account_get_connection(dialog->account); - if (!pc) + if (!pc) { return; + } - gtk_widget_set_sensitive(dialog->browse_button, FALSE); - gtk_widget_set_sensitive(dialog->add_button, FALSE); - gtk_widget_set_sensitive(dialog->register_button, FALSE); + g_simple_action_set_enabled(dialog->browse_action, FALSE); + g_simple_action_set_enabled(dialog->add_action, FALSE); + g_simple_action_set_enabled(dialog->register_action, FALSE); g_clear_pointer(&dialog->discolist, pidgin_disco_list_unref); gtk_tree_store_clear(dialog->model); - pdl = dialog->discolist = g_new0(PidginDiscoList, 1); + pdl = dialog->discolist = pidgin_disco_list_new(); pdl->services = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)gtk_tree_row_reference_free); pdl->pc = pc; @@ -226,9 +241,10 @@ server = g_strdup_printf("%.*s", (int)(slash - (at + 1)), at + 1); } - if (server == NULL) + if (server == NULL) { /* This shouldn't ever happen since the account is connected */ server = g_strdup("jabber.org"); + } /* Translators: The string "Enter an XMPP Server" is asking the user to type the name of an XMPP server which will then be queried */ @@ -242,8 +258,12 @@ g_free(server); } -static void add_to_blist_cb(GtkWidget *unused, PidginDiscoDialog *dialog) +static void +activate_add_to_blist(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + gpointer data) { + PidginDiscoDialog *dialog = data; XmppDiscoService *service = dialog->selected; PurpleAccount *account; const char *jid; @@ -253,10 +273,11 @@ account = purple_connection_get_account(service->list->pc); jid = service->jid; - if (service->type == XMPP_DISCO_SERVICE_TYPE_CHAT) + if (service->type == XMPP_DISCO_SERVICE_TYPE_CHAT) { purple_blist_request_add_chat(account, NULL, NULL, jid); - else + } else { purple_blist_request_add_buddy(account, jid, NULL, NULL); + } } static gboolean @@ -264,20 +285,23 @@ { PidginDiscoDialog *dialog = user_data; XmppDiscoService *service; - GtkWidget *menu; - GtkWidget *menuitem = NULL; GtkTreePath *path; GtkTreeIter iter; GValue val; - if (!gdk_event_triggers_context_menu((GdkEvent *)event)) + GdkRectangle rect; + + if (!gdk_event_triggers_context_menu((GdkEvent *)event)) { return FALSE; + } /* Figure out what was clicked */ if (!gtk_tree_view_get_path_at_pos(tree, event->x, event->y, &path, NULL, NULL, NULL)) + { return FALSE; + } gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); gtk_tree_path_free(path); val.g_type = 0; @@ -285,27 +309,19 @@ SERVICE_COLUMN, &val); service = g_value_get_pointer(&val); - if (!service) + if (!service) { return FALSE; - - menu = gtk_menu_new(); - - if (service->flags & XMPP_DISCO_ADD) { - menuitem = gtk_menu_item_new_with_label(_("Add to Buddy List")); - g_signal_connect(G_OBJECT(menuitem), "activate", - G_CALLBACK(add_to_blist_cb), dialog); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } - if (service->flags & XMPP_DISCO_REGISTER) { - menuitem = gtk_menu_item_new_with_label(_("Register")); - g_signal_connect(G_OBJECT(menuitem), "activate", - G_CALLBACK(register_button_cb), dialog); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - } + gtk_tree_view_convert_bin_window_to_widget_coords(dialog->tree, + (gint)event->x, + (gint)event->y, + &rect.x, &rect.y); + rect.width = rect.height = 1; - gtk_widget_show_all(menu); - gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); + gtk_popover_set_pointing_to(GTK_POPOVER(dialog->popover), &rect); + gtk_popover_popup(GTK_POPOVER(dialog->popover)); + return FALSE; } @@ -314,24 +330,21 @@ { GtkTreeIter iter; GValue val; + gboolean allow_add = FALSE, allow_register = FALSE; if (gtk_tree_selection_get_selected(selection, NULL, &iter)) { val.g_type = 0; gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter, SERVICE_COLUMN, &val); dialog->selected = g_value_get_pointer(&val); - if (!dialog->selected) { - gtk_widget_set_sensitive(dialog->add_button, FALSE); - gtk_widget_set_sensitive(dialog->register_button, FALSE); - return; + if (dialog->selected != NULL) { + allow_add = (dialog->selected->flags & XMPP_DISCO_ADD); + allow_register = (dialog->selected->flags & XMPP_DISCO_REGISTER); } + } - gtk_widget_set_sensitive(dialog->add_button, dialog->selected->flags & XMPP_DISCO_ADD); - gtk_widget_set_sensitive(dialog->register_button, dialog->selected->flags & XMPP_DISCO_REGISTER); - } else { - gtk_widget_set_sensitive(dialog->add_button, FALSE); - gtk_widget_set_sensitive(dialog->register_button, FALSE); - } + g_simple_action_set_enabled(dialog->add_action, allow_add); + g_simple_action_set_enabled(dialog->register_action, allow_register); } static void @@ -360,8 +373,7 @@ XmppDiscoService *service; GValue val; - if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, - path)) { + if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path)) { return; } @@ -371,18 +383,15 @@ service = g_value_get_pointer(&val); if (service->flags & XMPP_DISCO_BROWSE) { - if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(dialog->tree), - path)) { - gtk_tree_view_collapse_row(GTK_TREE_VIEW(dialog->tree), - path); + if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(dialog->tree), path)) { + gtk_tree_view_collapse_row(GTK_TREE_VIEW(dialog->tree), path); } else { - gtk_tree_view_expand_row(GTK_TREE_VIEW(dialog->tree), - path, FALSE); + gtk_tree_view_expand_row(GTK_TREE_VIEW(dialog->tree), path, FALSE); } } else if (service->flags & XMPP_DISCO_REGISTER) { - register_button_cb(NULL, dialog); + g_action_activate(G_ACTION(dialog->register_action), NULL); } else if (service->flags & XMPP_DISCO_ADD) { - add_to_blist_cb(NULL, dialog); + g_action_activate(G_ACTION(dialog->add_action), NULL); } } @@ -392,14 +401,16 @@ PidginDiscoDialog *dialog = PIDGIN_DISCO_DIALOG(window); PidginDiscoList *list = dialog->discolist; - if (dialog->prompt_handle) + if (dialog->prompt_handle) { purple_request_close(PURPLE_REQUEST_INPUT, dialog->prompt_handle); + } if (list) { list->dialog = NULL; - if (list->in_progress) + if (list->in_progress) { list->in_progress = FALSE; + } pidgin_disco_list_unref(list); } @@ -407,8 +418,13 @@ dialogs = g_list_remove(dialogs, dialog); } -static void stop_button_cb(GtkButton *button, PidginDiscoDialog *dialog) +static void +activate_stop(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + gpointer data) { + PidginDiscoDialog *dialog = data; + pidgin_disco_list_set_in_progress(dialog->discolist, FALSE); } @@ -491,12 +507,16 @@ break; } + name = g_markup_escape_text(service->name, -1); + jid = g_markup_escape_text(service->jid, -1); + if (service->description != NULL) { + desc = g_markup_escape_text(service->description, -1); + } + markup = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>\n<b>%s:</b> %s%s%s", - name = g_markup_escape_text(service->name, -1), - type, - jid = g_markup_escape_text(service->jid, -1), + name, type, jid, service->description ? _("\n<b>Description:</b> ") : "", - service->description ? desc = g_markup_escape_text(service->description, -1) : ""); + service->description ? desc : ""); gtk_tooltip_set_markup(tooltip, markup); gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, path); @@ -521,8 +541,9 @@ if (list && list->pc == pc) { PurpleAccount *account = NULL; - if (list->in_progress) + if (list->in_progress) { pidgin_disco_list_set_in_progress(list, FALSE); + } gtk_tree_store_clear(dialog->model); @@ -532,12 +553,9 @@ account = pidgin_account_chooser_get_selected( PIDGIN_ACCOUNT_CHOOSER(dialog->account_chooser)); - gtk_widget_set_sensitive( - dialog->browse_button, - account != NULL); - - gtk_widget_set_sensitive(dialog->register_button, FALSE); - gtk_widget_set_sensitive(dialog->add_button, FALSE); + g_simple_action_set_enabled(dialog->browse_action, account != NULL); + g_simple_action_set_enabled(dialog->add_action, FALSE); + g_simple_action_set_enabled(dialog->register_action, FALSE); } } } @@ -571,24 +589,15 @@ gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, progress); gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, - stop_button); - gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, - browse_button); - gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, - register_button); - gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, - add_button); - gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, tree); gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, model); + gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, + popover); + gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog, + popover_menu); gtk_widget_class_bind_template_callback(widget_class, destroy_win_cb); - gtk_widget_class_bind_template_callback(widget_class, stop_button_cb); - gtk_widget_class_bind_template_callback(widget_class, browse_button_cb); - gtk_widget_class_bind_template_callback(widget_class, - register_button_cb); - gtk_widget_class_bind_template_callback(widget_class, add_to_blist_cb); gtk_widget_class_bind_template_callback(widget_class, close_button_cb); gtk_widget_class_bind_template_callback(widget_class, dialog_select_account_cb); @@ -607,6 +616,15 @@ static void pidgin_disco_dialog_init(PidginDiscoDialog *dialog) { + GActionEntry entries[] = { + { .name = "stop", .activate = activate_stop }, + { .name = "browse", .activate = activate_browse }, + { .name = "register", .activate = activate_register }, + { .name = "add", .activate = activate_add_to_blist }, + }; + GSimpleActionGroup *action_group = NULL; + GActionMap *action_map = NULL; + dialogs = g_list_prepend(dialogs, dialog); gtk_widget_init_template(GTK_WIDGET(dialog)); @@ -615,12 +633,36 @@ dialog->account = pidgin_account_chooser_get_selected( PIDGIN_ACCOUNT_CHOOSER(dialog->account_chooser)); - /* browse button */ - gtk_widget_set_sensitive(dialog->browse_button, dialog->account != NULL); - gtk_widget_set_has_tooltip(GTK_WIDGET(dialog->tree), TRUE); g_signal_connect(G_OBJECT(dialog->tree), "query-tooltip", G_CALLBACK(disco_query_tooltip), dialog); + + action_group = g_simple_action_group_new(); + action_map = G_ACTION_MAP(action_group); + g_action_map_add_action_entries(action_map, entries, G_N_ELEMENTS(entries), + dialog); + + dialog->stop_action = G_SIMPLE_ACTION( + g_action_map_lookup_action(action_map, "stop")); + g_simple_action_set_enabled(dialog->stop_action, FALSE); + + dialog->browse_action = G_SIMPLE_ACTION( + g_action_map_lookup_action(action_map, "browse")); + g_simple_action_set_enabled(dialog->browse_action, dialog->account != NULL); + + dialog->register_action = G_SIMPLE_ACTION( + g_action_map_lookup_action(action_map, "register")); + g_simple_action_set_enabled(dialog->register_action, FALSE); + + dialog->add_action = G_SIMPLE_ACTION( + g_action_map_lookup_action(action_map, "add")); + g_simple_action_set_enabled(dialog->add_action, FALSE); + + gtk_widget_insert_action_group(GTK_WIDGET(dialog), "disco", + G_ACTION_GROUP(action_group)); + + gtk_popover_bind_model(GTK_POPOVER(dialog->popover), dialog->popover_menu, + NULL); } /****************************************************************************** @@ -636,8 +678,7 @@ PidginDiscoDialog * pidgin_disco_dialog_new(void) { - PidginDiscoDialog *dialog = - g_object_new(PIDGIN_TYPE_DISCO_DIALOG, NULL); + PidginDiscoDialog *dialog = g_object_new(PIDGIN_TYPE_DISCO_DIALOG, NULL); gtk_widget_show_all(GTK_WIDGET(dialog)); return dialog; } @@ -652,10 +693,12 @@ dialog = pdl->dialog; g_return_if_fail(dialog != NULL); - if (service != NULL) - purple_debug_info("xmppdisco", "Adding service \"%s\"\n", service->name); - else - purple_debug_info("xmppdisco", "Service \"%s\" has no childrens\n", parent->name); + if (service != NULL) { + purple_debug_info("xmppdisco", "Adding service \"%s\"", service->name); + } else { + purple_debug_info("xmppdisco", "Service \"%s\" has no children", + parent->name); + } gtk_progress_bar_pulse(GTK_PROGRESS_BAR(dialog->progress)); @@ -677,15 +720,17 @@ gtk_tree_model_get( GTK_TREE_MODEL(dialog->model), &child, SERVICE_COLUMN, &tmp, -1); - if (!tmp) + if (!tmp) { append = FALSE; + } } } } if (service == NULL) { - if (parent != NULL && !append) + if (parent != NULL && !append) { gtk_tree_store_remove(dialog->model, &child); + } return; } @@ -716,7 +761,8 @@ NAME_COLUMN, service->name, DESCRIPTION_COLUMN, service->description, SERVICE_COLUMN, service, -1); - if (pixbuf) + if (pixbuf) { g_object_unref(pixbuf); + } }
--- a/pidgin/plugins/disco/gtkdisco.h Mon Aug 15 21:30:26 2022 -0500 +++ b/pidgin/plugins/disco/gtkdisco.h Mon Aug 15 22:19:19 2022 -0500 @@ -37,10 +37,10 @@ GtkWidget *progress; - GtkWidget *stop_button; - GtkWidget *browse_button; - GtkWidget *register_button; - GtkWidget *add_button; + GSimpleAction *stop_action; + GSimpleAction *browse_action; + GSimpleAction *register_action; + GSimpleAction *add_action; XmppDiscoService *selected; GtkTreeView *tree; @@ -48,7 +48,10 @@ PurpleAccount *account; PidginDiscoList *discolist; - gpointer *prompt_handle; + GtkPopoverMenu *popover; + GMenuModel *popover_menu; + + gpointer prompt_handle; }; #define PIDGIN_TYPE_DISCO_DIALOG (pidgin_disco_dialog_get_type()) @@ -60,7 +63,6 @@ gboolean in_progress; const gchar *server; - gint ref; guint fetch_count; PidginDiscoDialog *dialog;
--- a/pidgin/plugins/disco/resources/disco.ui Mon Aug 15 21:30:26 2022 -0500 +++ b/pidgin/plugins/disco/resources/disco.ui Mon Aug 15 22:19:19 2022 -0500 @@ -26,6 +26,23 @@ <!-- interface-name Pidgin --> <!-- interface-description Internet Messenger --> <!-- interface-copyright Pidgin Developers <devel@pidgin.im> --> + <menu id="popover_menu"> + <section> + <item> + <attribute name="action">disco.add</attribute> + <attribute name="label" translatable="yes">Add to Buddy List</attribute> + </item> + <item> + <attribute name="action">disco.register</attribute> + <attribute name="label" translatable="yes">Register</attribute> + </item> + </section> + </menu> + <object class="GtkPopoverMenu" id="popover"> + <property name="can_focus">False</property> + <property name="relative-to">tree</property> + <property name="position">bottom</property> + </object> <object class="PidginAccountStore" id="accounts"/> <object class="PidginAccountFilterConnected" id="accounts_connected"> <property name="child_model">accounts</property> @@ -52,102 +69,11 @@ <property name="role">service discovery</property> <property name="type_hint">dialog</property> <signal name="destroy" handler="destroy_win_cb" swapped="no"/> - <child> - <placeholder/> - </child> <child internal-child="vbox"> <object class="GtkBox"> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">2</property> - <child internal-child="action_area"> - <object class="GtkButtonBox"> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="stop_button"> - <property name="label" translatable="yes">_Stop</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="stop_button_cb" object="PidginDiscoDialog" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="browse_button"> - <property name="label" translatable="yes">_Browse</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="browse_button_cb" object="PidginDiscoDialog" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkButton" id="register_button"> - <property name="label" translatable="yes">Register</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="register_button_cb" object="PidginDiscoDialog" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkButton" id="add_button"> - <property name="label" translatable="yes">_Add</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="add_to_blist_cb" object="PidginDiscoDialog" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkButton" id="close_button"> - <property name="label" translatable="yes">_Close</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="close_button_cb" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> <child> <object class="GtkBox"> <property name="visible">True</property> @@ -277,5 +203,61 @@ </child> </object> </child> + <child type="action"> + <object class="GtkButton" id="stop_button"> + <property name="label" translatable="yes">_Stop</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <property name="action-name">disco.stop</property> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="browse_button"> + <property name="label" translatable="yes">_Browse</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <property name="action-name">disco.browse</property> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="register_button"> + <property name="label" translatable="yes">Register</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="action-name">disco.register</property> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="add_button"> + <property name="label" translatable="yes">_Add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <property name="action-name">disco.add</property> + </object> + </child> + <child type="action"> + <object class="GtkButton" id="close_button"> + <property name="label" translatable="yes">_Close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="close_button_cb" swapped="no"/> + </object> + </child> + <action-widgets> + <action-widget response="0">stop_button</action-widget> + <action-widget response="1">browse_button</action-widget> + <action-widget response="2">register_button</action-widget> + <action-widget response="3">add_button</action-widget> + <action-widget response="close">close_button</action-widget> + </action-widgets> </template> </interface>
--- a/pidgin/plugins/disco/xmppdisco.c Mon Aug 15 21:30:26 2022 -0500 +++ b/pidgin/plugins/disco/xmppdisco.c Mon Aug 15 22:19:19 2022 -0500 @@ -1,5 +1,10 @@ /* * Purple - XMPP Service Disco Browser + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * + * Pidgin is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,9 +17,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - * + * along with this program; if not, see <https://www.gnu.org/licenses/>. */ /* TODO list (a little bit of a brain dump): @@ -116,8 +119,9 @@ struct xmpp_iq_cb_data *cb_data; cb_data = g_hash_table_lookup(iq_callbacks, id); - if (!cb_data) + if (!cb_data) { return FALSE; + } cb_data->cb(cb_data->pc, type, id, from, iq, cb_data->context); @@ -170,16 +174,18 @@ query = purple_xmlnode_new_child(iq, "query"); purple_xmlnode_set_namespace(query, NS_DISCO_INFO); - if (node) + if (node) { purple_xmlnode_set_attrib(query, "node", node); + } /* Steals id */ xmpp_iq_register_callback(pc, id, cbdata, cb); purple_signal_emit(purple_connection_get_protocol(pc), "jabber-sending-xmlnode", pc, &iq); - if (iq != NULL) + if (iq != NULL) { purple_xmlnode_free(iq); + } } static void @@ -196,16 +202,18 @@ query = purple_xmlnode_new_child(iq, "query"); purple_xmlnode_set_namespace(query, NS_DISCO_ITEMS); - if (node) + if (node) { purple_xmlnode_set_attrib(query, "node", node); + } /* Steals id */ xmpp_iq_register_callback(pc, id, cbdata, cb); purple_signal_emit(purple_connection_get_protocol(pc), "jabber-sending-xmlnode", pc, &iq); - if (iq != NULL) + if (iq != NULL) { purple_xmlnode_free(iq); + } } static XmppDiscoServiceType @@ -213,29 +221,31 @@ { const char *category, *type; - if (!identity) + if (!identity) { return XMPP_DISCO_SERVICE_TYPE_OTHER; + } category = purple_xmlnode_get_attrib(identity, "category"); type = purple_xmlnode_get_attrib(identity, "type"); - if (!category) + if (!category) { return XMPP_DISCO_SERVICE_TYPE_OTHER; + } - if (purple_strequal(category, "conference")) + if (purple_strequal(category, "conference")) { return XMPP_DISCO_SERVICE_TYPE_CHAT; - else if (purple_strequal(category, "directory")) + } else if (purple_strequal(category, "directory")) { return XMPP_DISCO_SERVICE_TYPE_DIRECTORY; - else if (purple_strequal(category, "gateway")) + } else if (purple_strequal(category, "gateway")) { return XMPP_DISCO_SERVICE_TYPE_GATEWAY; - else if (purple_strequal(category, "pubsub")) { - if (!type || purple_strequal(type, "collection")) + } else if (purple_strequal(category, "pubsub")) { + if (!type || purple_strequal(type, "collection")) { return XMPP_DISCO_SERVICE_TYPE_PUBSUB_COLLECTION; - else if (purple_strequal(type, "leaf")) + } else if (purple_strequal(type, "leaf")) { return XMPP_DISCO_SERVICE_TYPE_PUBSUB_LEAF; - else if (purple_strequal(type, "service")) + } else if (purple_strequal(type, "service")) { return XMPP_DISCO_SERVICE_TYPE_OTHER; - else { + } else { purple_debug_warning("xmppdisco", "Unknown pubsub type '%s'\n", type); return XMPP_DISCO_SERVICE_TYPE_OTHER; } @@ -262,8 +272,9 @@ g_return_val_if_fail(str != NULL, ""); for ( ; disco_type_mappings[i].from; ++i) { - if (!g_ascii_strcasecmp(str, disco_type_mappings[i].from)) + if (!g_ascii_strcasecmp(str, disco_type_mappings[i].from)) { return disco_type_mappings[i].to; + } } /* fallback to the string itself */ @@ -280,8 +291,9 @@ --list->fetch_count; - if (!list->in_progress) + if (!list->in_progress) { goto out; + } if (purple_strequal(type, "result") && (query = purple_xmlnode_get_child(iq, "query"))) { @@ -300,26 +312,31 @@ if (item_data->name) { service->name = item_data->name; item_data->name = NULL; - } else + } else { service->name = g_strdup(item_data->node); + } service->node = item_data->node; item_data->node = NULL; - if (service->type == XMPP_DISCO_SERVICE_TYPE_PUBSUB_COLLECTION) + if (service->type == XMPP_DISCO_SERVICE_TYPE_PUBSUB_COLLECTION) { service->flags |= XMPP_DISCO_BROWSE; - } else + } + } else { service->name = g_strdup(from); + } - if (!service->node) + if (!service->node) { /* Only support adding JIDs, not JID+node combos */ service->flags |= XMPP_DISCO_ADD; + } if (item_data->name) { service->description = item_data->name; item_data->name = NULL; - } else if (identity) + } else if (identity) { service->description = g_strdup(purple_xmlnode_get_attrib(identity, "name")); + } /* TODO: Overlap with service->name a bit */ service->jid = g_strdup(from); @@ -327,29 +344,32 @@ for (feature = purple_xmlnode_get_child(query, "feature"); feature; feature = purple_xmlnode_get_next_twin(feature)) { const char *var; - if (!(var = purple_xmlnode_get_attrib(feature, "var"))) + if (!(var = purple_xmlnode_get_attrib(feature, "var"))) { continue; + } - if (purple_strequal(var, NS_REGISTER)) + if (purple_strequal(var, NS_REGISTER)) { service->flags |= XMPP_DISCO_REGISTER; - else if (purple_strequal(var, NS_DISCO_ITEMS)) + } else if (purple_strequal(var, NS_DISCO_ITEMS)) { service->flags |= XMPP_DISCO_BROWSE; - else if (purple_strequal(var, NS_MUC)) { + } else if (purple_strequal(var, NS_MUC)) { service->flags |= XMPP_DISCO_BROWSE; service->type = XMPP_DISCO_SERVICE_TYPE_CHAT; } } - if (service->type == XMPP_DISCO_SERVICE_TYPE_GATEWAY) + if (service->type == XMPP_DISCO_SERVICE_TYPE_GATEWAY) { service->gateway_type = g_strdup(disco_type_from_string( purple_xmlnode_get_attrib(identity, "type"))); + } pidgin_disco_add_service(list, service, service->parent); } out: - if (list->fetch_count == 0) + if (list->fetch_count == 0) { pidgin_disco_list_set_in_progress(list, FALSE); + } g_free(item_data->name); g_free(item_data->node); @@ -368,8 +388,9 @@ --list->fetch_count; - if (!list->in_progress) + if (!list->in_progress) { goto out; + } if (purple_strequal(type, "result") && (query = purple_xmlnode_get_child(iq, "query"))) { @@ -400,6 +421,9 @@ service->name = g_strdup(name); service->jid = g_strdup(jid); service->node = g_strdup(node); + if (service->name == NULL) { + service->name = g_strdup(jid); + } pidgin_disco_add_service(list, service, item_data->parent); } else { struct item_data *item_data2 = g_new0(struct item_data, 1); @@ -416,12 +440,14 @@ } } - if (!has_items) + if (!has_items) { pidgin_disco_add_service(list, NULL, item_data->parent); + } out: - if (list->fetch_count == 0) + if (list->fetch_count == 0) { pidgin_disco_list_set_in_progress(list, FALSE); + } g_free(item_data); pidgin_disco_list_unref(list); @@ -449,8 +475,9 @@ const char *node = purple_xmlnode_get_attrib(item, "node"); struct item_data *item_data; - if (!jid) + if (!jid) { continue; + } item_data = g_new0(struct item_data, 1); item_data->list = list; @@ -463,8 +490,9 @@ } } - if (list->fetch_count == 0) + if (list->fetch_count == 0) { pidgin_disco_list_set_in_progress(list, FALSE); + } pidgin_disco_list_unref(list); } @@ -511,8 +539,7 @@ purple_notify_error(my_plugin, _("Error"), _("Server does not exist"), NULL, NULL); - } - else { + } else { purple_notify_error(my_plugin, _("Error"), _("Server does not support service discovery"), NULL, NULL); @@ -545,8 +572,9 @@ g_return_if_fail(service != NULL); - if (service->expanded) + if (service->expanded) { return; + } item_data = g_new0(struct item_data, 1); item_data->list = service->list; @@ -577,8 +605,9 @@ purple_signal_emit(purple_connection_get_protocol(service->list->pc), "jabber-sending-xmlnode", service->list->pc, &iq); - if (iq != NULL) + if (iq != NULL) { purple_xmlnode_free(iq); + } g_free(id); }