pidgin/gtkprivacy.c

Fri, 26 Aug 2022 00:13:48 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 26 Aug 2022 00:13:48 -0500
branch
gtk4
changeset 41599
450080e4726a
parent 41528
4160c570866d
child 41643
f7af70658fe5
permissions
-rw-r--r--

Fix up the roomlist to work in GTK4

Testing Done:
Opened the room list and verified it functioned as intended.

Reviewed at https://reviews.imfreedom.org/r/1648/

/* pidgin
 *
 * 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * 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
 */

#include <glib/gi18n-lib.h>

#include <purple.h>

#include "gtkaccount.h"
#include "gtkblist.h"
#include "gtkprivacy.h"
#include "gtkutils.h"
#include "pidginaccountchooser.h"
#include "pidginaccountstore.h"

#define PIDGIN_TYPE_PRIVACY_DIALOG (pidgin_privacy_dialog_get_type())
G_DECLARE_FINAL_TYPE(PidginPrivacyDialog, pidgin_privacy_dialog, PIDGIN,
                     PRIVACY_DIALOG, GtkDialog)

struct _PidginPrivacyDialog {
	GtkDialog parent;

	GtkWidget *type_menu;

	GtkWidget *add_button;
	GtkWidget *remove_button;
	GtkWidget *removeall_button;
	GtkWidget *close_button;

	GtkWidget *allow_widget;
	GtkWidget *block_widget;

	GtkListStore *allow_store;
	GtkListStore *block_store;

	GtkWidget *allow_list;
	GtkWidget *block_list;

	gboolean in_allow_list;

	GtkWidget *account_chooser;
	PurpleAccount *account;
};

typedef struct
{
	PurpleAccount *account;
	char *name;
	gboolean block;

} PidginPrivacyRequestData;

static struct
{
	const char *text;
	PurpleAccountPrivacyType type;

} const menu_entries[] =
{
	{ N_("Allow all users to contact me"),         PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL },
	{ N_("Allow only the users on my buddy list"), PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST },
	{ N_("Allow only the users below"),            PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS },
	{ N_("Block all users"),                       PURPLE_ACCOUNT_PRIVACY_DENY_ALL },
	{ N_("Block only the users below"),            PURPLE_ACCOUNT_PRIVACY_DENY_USERS }
};

static const size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries);

static PidginPrivacyDialog *privacy_dialog = NULL;

static void
rebuild_allow_list(PidginPrivacyDialog *dialog)
{
	GSList *l;
	GtkTreeIter iter;

	gtk_list_store_clear(dialog->allow_store);

	for (l = purple_account_privacy_get_permitted(dialog->account); l != NULL; l = l->next) {
		gtk_list_store_append(dialog->allow_store, &iter);
		gtk_list_store_set(dialog->allow_store, &iter, 0, l->data, -1);
	}
}

static void
rebuild_block_list(PidginPrivacyDialog *dialog)
{
	GSList *l;
	GtkTreeIter iter;

	gtk_list_store_clear(dialog->block_store);

	for (l = purple_account_privacy_get_denied(dialog->account); l != NULL; l = l->next) {
		gtk_list_store_append(dialog->block_store, &iter);
		gtk_list_store_set(dialog->block_store, &iter, 0, l->data, -1);
	}
}

static void
user_selected_cb(GtkTreeSelection *sel, PidginPrivacyDialog *dialog)
{
	gtk_widget_set_sensitive(dialog->remove_button, TRUE);
}

static void
select_account_cb(GtkWidget *w, PidginPrivacyDialog *dialog) {
	PidginAccountChooser *chooser = PIDGIN_ACCOUNT_CHOOSER(w);
	PurpleAccount *account = pidgin_account_chooser_get_selected(chooser);
	gsize i;

	dialog->account = account;

	if (account) {
		gtk_widget_set_sensitive(dialog->type_menu, TRUE);
		gtk_widget_set_sensitive(dialog->add_button, TRUE);
		/* dialog->remove_button is enabled when a user is selected. */
		gtk_widget_set_sensitive(dialog->removeall_button, TRUE);
	} else {
		gtk_widget_set_sensitive(dialog->type_menu, FALSE);
		gtk_widget_set_sensitive(dialog->add_button, FALSE);
		gtk_widget_set_sensitive(dialog->remove_button, FALSE);
		gtk_widget_set_sensitive(dialog->removeall_button, FALSE);
		gtk_list_store_clear(dialog->allow_store);
		gtk_list_store_clear(dialog->block_store);
		return;
	}

	for (i = 0; i < menu_entry_count; i++) {
		if (menu_entries[i].type == purple_account_get_privacy_type(account)) {
			gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), i);
			break;
		}
	}

	rebuild_allow_list(dialog);
	rebuild_block_list(dialog);
}

/*
 * TODO: Setting the permit/deny setting needs to go through privacy.c
 *       Even better: the privacy API needs to not suck.
 */
static void
type_changed_cb(GtkComboBox *combo, PidginPrivacyDialog *dialog)
{
	PurpleAccountPrivacyType new_type =
		menu_entries[gtk_combo_box_get_active(combo)].type;
	gboolean buttons_sensitive;

	purple_account_set_privacy_type(dialog->account, new_type);
	purple_serv_set_permit_deny(purple_account_get_connection(dialog->account));

	gtk_widget_hide(dialog->allow_widget);
	gtk_widget_hide(dialog->block_widget);
	buttons_sensitive = FALSE;

	if (new_type == PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS) {
		gtk_widget_show(dialog->allow_widget);
		buttons_sensitive = TRUE;
		dialog->in_allow_list = TRUE;
	}
	else if (new_type == PURPLE_ACCOUNT_PRIVACY_DENY_USERS) {
		gtk_widget_show(dialog->block_widget);
		buttons_sensitive = TRUE;
		dialog->in_allow_list = FALSE;
	}

	gtk_widget_set_sensitive(dialog->add_button, buttons_sensitive);
	/* dialog->remove_button is enabled when a user is selected. */
	gtk_widget_set_sensitive(dialog->remove_button, FALSE);
	gtk_widget_set_sensitive(dialog->removeall_button, buttons_sensitive);

	purple_blist_schedule_save();
	pidgin_blist_refresh(purple_blist_get_default());
}

static void
add_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
{
	if (dialog->in_allow_list)
		pidgin_request_add_permit(dialog->account, NULL);
	else
		pidgin_request_add_block(dialog->account, NULL);
}

static void
remove_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	GtkTreeSelection *sel;
	char *name;

	if (dialog->in_allow_list && dialog->allow_store == NULL)
		return;

	if (!dialog->in_allow_list && dialog->block_store == NULL)
		return;

	if (dialog->in_allow_list) {
		model = GTK_TREE_MODEL(dialog->allow_store);
		sel   = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->allow_list));
	}
	else {
		model = GTK_TREE_MODEL(dialog->block_store);
		sel   = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->block_list));
	}

	if (gtk_tree_selection_get_selected(sel, NULL, &iter))
		gtk_tree_model_get(model, &iter, 0, &name, -1);
	else
		return;

	if (dialog->in_allow_list)
		purple_account_privacy_permit_remove(dialog->account, name, FALSE);
	else
		purple_account_privacy_deny_remove(dialog->account, name, FALSE);

	g_free(name);
}

static void
removeall_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
{
	GSList *l;
	if (dialog->in_allow_list)
		l = purple_account_privacy_get_permitted(dialog->account);
	else
		l = purple_account_privacy_get_denied(dialog->account);
	while (l) {
		char *user;
		user = l->data;
		l = l->next;
		if (dialog->in_allow_list)
			purple_account_privacy_permit_remove(dialog->account, user, FALSE);
		else
			purple_account_privacy_deny_remove(dialog->account, user, FALSE);
	}
}

G_DEFINE_TYPE(PidginPrivacyDialog, pidgin_privacy_dialog, GTK_TYPE_DIALOG)

static void
pidgin_privacy_dialog_class_init(PidginPrivacyDialogClass *klass)
{
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);

	gtk_widget_class_set_template_from_resource(
	        widget_class, "/im/pidgin/Pidgin3/Privacy/dialog.ui");

	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     account_chooser);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     add_button);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     allow_list);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     allow_store);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     allow_widget);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     block_list);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     block_store);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     block_widget);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     close_button);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     remove_button);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     removeall_button);
	gtk_widget_class_bind_template_child(widget_class, PidginPrivacyDialog,
	                                     type_menu);

	gtk_widget_class_bind_template_callback(widget_class, add_cb);
	gtk_widget_class_bind_template_callback(widget_class, remove_cb);
	gtk_widget_class_bind_template_callback(widget_class, removeall_cb);
	gtk_widget_class_bind_template_callback(widget_class, select_account_cb);
	gtk_widget_class_bind_template_callback(widget_class, type_changed_cb);
	gtk_widget_class_bind_template_callback(widget_class, user_selected_cb);
}

static void
pidgin_privacy_dialog_init(PidginPrivacyDialog *dialog) {
	PidginAccountChooser *chooser = NULL;
	gssize selected = -1;
	gsize i;

	gtk_widget_init_template(GTK_WIDGET(dialog));

	chooser = PIDGIN_ACCOUNT_CHOOSER(dialog->account_chooser);
	dialog->account = pidgin_account_chooser_get_selected(chooser);

	/* Add the drop-down list with the allow/block types. */
	for (i = 0; i < menu_entry_count; i++) {
		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(dialog->type_menu),
		                          _(menu_entries[i].text));

		if (menu_entries[i].type == purple_account_get_privacy_type(dialog->account))
			selected = (gssize)i;
	}
	gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), selected);

	/* Rebuild the allow and block lists views. */
	rebuild_allow_list(dialog);
	rebuild_block_list(dialog);

	type_changed_cb(GTK_COMBO_BOX(dialog->type_menu), dialog);
}

void
pidgin_privacy_dialog_show(void)
{
	g_return_if_fail(purple_connections_get_all() != NULL);

	if (privacy_dialog == NULL) {
		privacy_dialog = g_object_new(PIDGIN_TYPE_PRIVACY_DIALOG, NULL);
		g_object_add_weak_pointer(G_OBJECT(privacy_dialog),
		                          (gpointer)&privacy_dialog);
	}

	gtk_widget_show(GTK_WIDGET(privacy_dialog));
}

void
pidgin_privacy_dialog_hide(void)
{
	if(GTK_IS_WIDGET(privacy_dialog)) {
		gtk_window_destroy(GTK_WINDOW(privacy_dialog));
	}
}

static void
destroy_request_data(PidginPrivacyRequestData *data)
{
	g_free(data->name);
	g_free(data);
}

static void
confirm_permit_block_cb(PidginPrivacyRequestData *data, int option)
{
	if (data->block)
		purple_account_privacy_deny(data->account, data->name);
	else
		purple_account_privacy_allow(data->account, data->name);

	destroy_request_data(data);
}

static void
add_permit_block_cb(PidginPrivacyRequestData *data, const char *name)
{
	data->name = g_strdup(name);

	confirm_permit_block_cb(data, 0);
}

void
pidgin_request_add_permit(PurpleAccount *account, const char *name)
{
	PidginPrivacyRequestData *data;

	g_return_if_fail(account != NULL);

	data = g_new0(PidginPrivacyRequestData, 1);
	data->account = account;
	data->name    = g_strdup(name);
	data->block   = FALSE;

	if (name == NULL) {
		purple_request_input(account, _("Permit User"),
			_("Type a user you permit to contact you."),
			_("Please enter the name of the user you wish to be "
			  "able to contact you."),
			NULL, FALSE, FALSE, NULL,
			_("_Permit"), G_CALLBACK(add_permit_block_cb),
			_("Cancel"), G_CALLBACK(destroy_request_data),
			purple_request_cpar_from_account(account),
			data);
	}
	else {
		char *primary = g_strdup_printf(_("Allow %s to contact you?"), name);
		char *secondary =
			g_strdup_printf(_("Are you sure you wish to allow "
							  "%s to contact you?"), name);


		purple_request_action(account, _("Permit User"), primary,
			secondary, 0, purple_request_cpar_from_account(account),
			data, 2,
			_("_Permit"), G_CALLBACK(confirm_permit_block_cb),
			_("Cancel"), G_CALLBACK(destroy_request_data));

		g_free(primary);
		g_free(secondary);
	}
}

void
pidgin_request_add_block(PurpleAccount *account, const char *name)
{
	PidginPrivacyRequestData *data;

	g_return_if_fail(account != NULL);

	data = g_new0(PidginPrivacyRequestData, 1);
	data->account = account;
	data->name    = g_strdup(name);
	data->block   = TRUE;

	if (name == NULL) {
		purple_request_input(account, _("Block User"),
			_("Type a user to block."),
			_("Please enter the name of the user you wish to block."),
			NULL, FALSE, FALSE, NULL,
			_("_Block"), G_CALLBACK(add_permit_block_cb),
			_("Cancel"), G_CALLBACK(destroy_request_data),
			purple_request_cpar_from_account(account),
			data);
	}
	else {
		char *primary = g_strdup_printf(_("Block %s?"), name);
		char *secondary =
			g_strdup_printf(_("Are you sure you want to block %s?"), name);

		purple_request_action(account, _("Block User"), primary,
			secondary, 0, purple_request_cpar_from_account(account),
			data, 2,
			_("_Block"), G_CALLBACK(confirm_permit_block_cb),
			_("Cancel"), G_CALLBACK(destroy_request_data));

		g_free(primary);
		g_free(secondary);
	}
}

static void
pidgin_permit_added_removed(PurpleAccount *account, const char *name)
{
	if (privacy_dialog != NULL)
		rebuild_allow_list(privacy_dialog);
}

static void
pidgin_deny_added_removed(PurpleAccount *account, const char *name)
{
	if (privacy_dialog != NULL)
		rebuild_block_list(privacy_dialog);
}

void
pidgin_privacy_init(void)
{
	PurpleAccountUiOps *ops = pidgin_accounts_get_ui_ops();

	ops->permit_added = ops->permit_removed = pidgin_permit_added_removed;
	ops->deny_added = ops->deny_removed = pidgin_deny_added_removed;
}

mercurial