/** * @file gtkprivacy.c GTK+ Privacy UI * @ingroup gtkui * * gaim * * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "gtkinternal.h" #include "connection.h" #include "debug.h" #include "privacy.h" #include "request.h" #include "util.h" #include "gtkprivacy.h" #include "gtkutils.h" typedef struct { GtkWidget *win; GtkWidget *type_menu; GtkWidget *add_button; GtkWidget *remove_button; GtkWidget *clear_button; GtkWidget *button_box; GtkWidget *allow_widget; GtkWidget *block_widget; GtkListStore *allow_store; GtkListStore *block_store; GtkWidget *allow_list; GtkWidget *block_list; gboolean in_allow_list; GaimAccount *account; } GaimGtkPrivacyDialog; typedef struct { GaimAccount *account; char *name; gboolean block; } GaimGtkPrivacyRequestData; static struct { const char *text; int num; } menu_entries[] = { { N_("Allow all users to contact me"), GAIM_PRIVACY_ALLOW_ALL }, { N_("Allow only the users on my buddy list"), GAIM_PRIVACY_ALLOW_BUDDYLIST }, { N_("Allow only the users below"), GAIM_PRIVACY_ALLOW_USERS }, { N_("Block all users"), GAIM_PRIVACY_DENY_ALL }, { N_("Block only the users below"), GAIM_PRIVACY_DENY_USERS } }; static size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries); static GaimGtkPrivacyDialog *privacy_dialog = NULL; static void rebuild_allow_list(GaimGtkPrivacyDialog *dialog) { GSList *l; GtkTreeIter iter; gtk_list_store_clear(dialog->allow_store); for (l = dialog->account->permit; 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(GaimGtkPrivacyDialog *dialog) { GSList *l; GtkTreeIter iter; gtk_list_store_clear(dialog->block_store); for (l = dialog->account->deny; 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 const char * find_permit_block_by_name(GSList *list, const char *name) { const char *temp_name; GSList *l; for (l = list; l != NULL; l = l->next) { temp_name = (const char *)l->data; if (!gaim_utf8_strcasecmp(name, temp_name)) return temp_name; } return NULL; } static void user_selected_cb(GtkTreeSelection *sel, GaimGtkPrivacyDialog *dialog) { gtk_widget_set_sensitive(dialog->remove_button, TRUE); } static GtkWidget * build_list(GaimGtkPrivacyDialog *dialog, GtkListStore *model, GtkWidget **ret_treeview) { GtkWidget *sw; GtkWidget *treeview; GtkCellRenderer *rend; GtkTreeViewColumn *column; GtkTreeSelection *sel; sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); *ret_treeview = treeview; rend = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(NULL, rend, "text", 0, NULL); gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(user_selected_cb), dialog); gtk_widget_set_size_request(sw, -1, 200); return sw; } static GtkWidget * build_allow_list(GaimGtkPrivacyDialog *dialog) { GtkWidget *widget; GtkWidget *list; dialog->allow_store = gtk_list_store_new(1, G_TYPE_STRING); widget = build_list(dialog, dialog->allow_store, &list); dialog->allow_list = list; rebuild_allow_list(dialog); return widget; } static GtkWidget * build_block_list(GaimGtkPrivacyDialog *dialog) { GtkWidget *widget; GtkWidget *list; dialog->block_store = gtk_list_store_new(1, G_TYPE_STRING); widget = build_list(dialog, dialog->block_store, &list); dialog->block_list = list; rebuild_block_list(dialog); return widget; } static gint destroy_cb(GtkWidget *w, GdkEvent *event, GaimGtkPrivacyDialog *dialog) { gaim_gtk_privacy_dialog_hide(); return 0; } static void select_account_cb(GtkWidget *dropdown, GaimAccount *account, GaimGtkPrivacyDialog *dialog) { int i; dialog->account = account; for (i = 0; i < menu_entry_count; i++) { if (menu_entries[i].num == account->perm_deny) { gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), i); break; } } rebuild_allow_list(dialog); rebuild_block_list(dialog); } static void type_changed_cb(GtkOptionMenu *optmenu, GaimGtkPrivacyDialog *dialog) { int new_type = menu_entries[gtk_option_menu_get_history(optmenu)].num; dialog->account->perm_deny = new_type; serv_set_permit_deny(gaim_account_get_connection(dialog->account)); gtk_widget_hide(dialog->allow_widget); gtk_widget_hide(dialog->block_widget); gtk_widget_hide(dialog->button_box); if (new_type == GAIM_PRIVACY_ALLOW_USERS) { gtk_widget_show(dialog->allow_widget); gtk_widget_show(dialog->button_box); dialog->in_allow_list = TRUE; } else if (new_type == GAIM_PRIVACY_DENY_USERS) { gtk_widget_show(dialog->block_widget); gtk_widget_show(dialog->button_box); dialog->in_allow_list = FALSE; } } static void add_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) { if (dialog->in_allow_list) gaim_gtk_request_add_permit(dialog->account, NULL); else gaim_gtk_request_add_block(dialog->account, NULL); } static void remove_cb(GtkWidget *button, GaimGtkPrivacyDialog *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) { if (find_permit_block_by_name(dialog->account->permit, name)) gaim_privacy_permit_remove(dialog->account, name, FALSE); } else { if (find_permit_block_by_name(dialog->account->deny, name)) gaim_privacy_deny_remove(dialog->account, name, FALSE); } } static void clear_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) { GSList *l; if (dialog->in_allow_list) l = dialog->account->permit; else l = dialog->account->deny; while (l) { char *user; user = l->data; l = l->next; if (dialog->in_allow_list) gaim_privacy_permit_remove(dialog->account, user, FALSE); else gaim_privacy_deny_remove(dialog->account, user, FALSE); } } static void close_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) { gtk_widget_destroy(dialog->win); gaim_gtk_privacy_dialog_hide(); } static gboolean check_account_func(GaimAccount *account) { GaimConnection *gc = gaim_account_get_connection(account); GaimPluginProtocolInfo *prpl_info = NULL; prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); return (prpl_info->set_permit_deny != NULL); } gboolean gaim_gtk_privacy_is_showable() { GList *c; GaimConnection *gc; for (c = gaim_connections_get_all(); c != NULL; c = c->next) { gc = c->data; if (check_account_func(gaim_connection_get_account(gc))) return TRUE; } return FALSE; } static GaimGtkPrivacyDialog * privacy_dialog_new(void) { GaimGtkPrivacyDialog *dialog; GtkWidget *bbox; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *button; GtkWidget *dropdown; GtkWidget *label; GtkWidget *menu; GtkWidget *sep; int selected = 0; int i; dialog = g_new0(GaimGtkPrivacyDialog, 1); dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_resizable(GTK_WINDOW(dialog->win), FALSE); gtk_window_set_role(GTK_WINDOW(dialog->win), "privacy"); gtk_window_set_title(GTK_WINDOW(dialog->win), _("Privacy")); gtk_container_set_border_width(GTK_CONTAINER(dialog->win), 12); g_signal_connect(G_OBJECT(dialog->win), "delete_event", G_CALLBACK(destroy_cb), dialog); /* Main vbox */ vbox = gtk_vbox_new(FALSE, 12); gtk_container_add(GTK_CONTAINER(dialog->win), vbox); gtk_widget_show(vbox); /* Description label */ label = gtk_label_new( _("Changes to privacy settings take effect immediately.")); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_widget_show(label); /* Hbox for the accounts drop-down and label. */ hbox = gtk_hbox_new(FALSE, 12); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); /* "Set privacy for:" label */ label = gtk_label_new(_("Set privacy for:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_widget_show(label); /* Accounts drop-down */ dropdown = gaim_gtk_account_option_menu_new(NULL, FALSE, G_CALLBACK(select_account_cb), check_account_func, dialog); gtk_box_pack_start(GTK_BOX(hbox), dropdown, FALSE, FALSE, 0); gtk_widget_show(dropdown); gaim_set_accessible_label (dropdown, label); dialog->account = gaim_gtk_account_option_menu_get_selected(dropdown); /* Add the drop-down list with the allow/block types. */ dialog->type_menu = gtk_option_menu_new(); gtk_box_pack_start(GTK_BOX(vbox), dialog->type_menu, FALSE, FALSE, 0); gtk_widget_show(dialog->type_menu); /* Build the menu for that. */ menu = gtk_menu_new(); for (i = 0; i < menu_entry_count; i++) { gaim_new_item(menu, _(menu_entries[i].text)); if (menu_entries[i].num == dialog->account->perm_deny) selected = i; } gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->type_menu), menu); gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), selected); g_signal_connect(G_OBJECT(dialog->type_menu), "changed", G_CALLBACK(type_changed_cb), dialog); /* Build the treeview for the allow list. */ dialog->allow_widget = build_allow_list(dialog); gtk_box_pack_start(GTK_BOX(vbox), dialog->allow_widget, TRUE, TRUE, 0); /* Build the treeview for the block list. */ dialog->block_widget = build_block_list(dialog); gtk_box_pack_start(GTK_BOX(vbox), dialog->block_widget, TRUE, TRUE, 0); /* Add the button box for Add, Remove, Clear */ dialog->button_box = bbox = gtk_hbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD); gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); /* Add button */ button = gtk_button_new_from_stock(GTK_STOCK_ADD); dialog->add_button = button; gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(add_cb), dialog); /* Remove button */ button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); dialog->remove_button = button; gtk_widget_set_sensitive(button, FALSE); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(remove_cb), dialog); /* Clear button */ button = gtk_button_new_from_stock(GTK_STOCK_CLEAR); dialog->clear_button = button; gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_cb), dialog); /* Separator */ sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); gtk_widget_show(sep); /* Another button box. */ bbox = gtk_hbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); gtk_widget_show(bbox); /* Close button */ button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(close_cb), dialog); if (dialog->account->perm_deny == GAIM_PRIVACY_ALLOW_USERS) { gtk_widget_show(dialog->allow_widget); gtk_widget_show(dialog->button_box); dialog->in_allow_list = TRUE; } else if (dialog->account->perm_deny == GAIM_PRIVACY_DENY_USERS) { gtk_widget_show(dialog->block_widget); gtk_widget_show(dialog->button_box); dialog->in_allow_list = FALSE; } return dialog; } void gaim_gtk_privacy_dialog_show(void) { if (privacy_dialog == NULL) privacy_dialog = privacy_dialog_new(); gtk_widget_show(privacy_dialog->win); gdk_window_raise(privacy_dialog->win->window); } void gaim_gtk_privacy_dialog_hide(void) { if (privacy_dialog == NULL) return; g_free(privacy_dialog); privacy_dialog = NULL; } static void destroy_request_data(GaimGtkPrivacyRequestData *data) { if (data->name != NULL) g_free(data->name); g_free(data); } static void confirm_permit_block_cb(GaimGtkPrivacyRequestData *data, int option) { if (data->block) gaim_privacy_deny_add(data->account, data->name, FALSE); else gaim_privacy_permit_add(data->account, data->name, FALSE); destroy_request_data(data); } static void add_permit_block_cb(GaimGtkPrivacyRequestData *data, const char *name) { data->name = g_strdup(name); confirm_permit_block_cb(data, 0); } void gaim_gtk_request_add_permit(GaimAccount *account, const char *name) { GaimGtkPrivacyRequestData *data; g_return_if_fail(account != NULL); data = g_new0(GaimGtkPrivacyRequestData, 1); data->account = account; data->name = g_strdup(name); data->block = FALSE; if (name == NULL) { gaim_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), 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); gaim_request_action(account, _("Permit User"), primary, secondary, 0, data, 2, _("Permit"), G_CALLBACK(confirm_permit_block_cb), _("Cancel"), G_CALLBACK(destroy_request_data)); g_free(primary); g_free(secondary); } } void gaim_gtk_request_add_block(GaimAccount *account, const char *name) { GaimGtkPrivacyRequestData *data; g_return_if_fail(account != NULL); data = g_new0(GaimGtkPrivacyRequestData, 1); data->account = account; data->name = g_strdup(name); data->block = TRUE; if (name == NULL) { gaim_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), data); } else { char *primary = g_strdup_printf(_("Block %s?"), name); char *secondary = g_strdup_printf(_("Are you sure you want to block %s?"), name); gaim_request_action(account, _("Block User"), primary, secondary, 0, data, 2, _("Block"), G_CALLBACK(confirm_permit_block_cb), _("Cancel"), G_CALLBACK(destroy_request_data)); g_free(primary); g_free(secondary); } } static void gaim_gtk_permit_added_removed(GaimAccount *account, const char *name) { if (privacy_dialog != NULL) rebuild_allow_list(privacy_dialog); } static void gaim_gtk_deny_added_removed(GaimAccount *account, const char *name) { if (privacy_dialog != NULL) rebuild_block_list(privacy_dialog); } static GaimPrivacyUiOps privacy_ops = { gaim_gtk_permit_added_removed, gaim_gtk_permit_added_removed, gaim_gtk_deny_added_removed, gaim_gtk_deny_added_removed }; GaimPrivacyUiOps * gaim_gtk_privacy_get_ui_ops(void) { return &privacy_ops; } void gaim_gtk_privacy_init(void) { }