2 * @file gtkprivacy.c GTK+ Privacy UI
8 * Pidgin is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 #include "connection.h"
36 #include "gtkprivacy.h"
45 GtkWidget
*add_button
;
46 GtkWidget
*remove_button
;
47 GtkWidget
*removeall_button
;
48 GtkWidget
*close_button
;
50 GtkWidget
*button_box
;
51 GtkWidget
*allow_widget
;
52 GtkWidget
*block_widget
;
54 GtkListStore
*allow_store
;
55 GtkListStore
*block_store
;
57 GtkWidget
*allow_list
;
58 GtkWidget
*block_list
;
60 gboolean in_allow_list
;
62 PurpleAccount
*account
;
64 } PidginPrivacyDialog
;
68 PurpleAccount
*account
;
72 } PidginPrivacyRequestData
;
77 PurplePrivacyType type
;
79 } const menu_entries
[] =
81 { N_("Allow all users to contact me"), PURPLE_PRIVACY_ALLOW_ALL
},
82 { N_("Allow only the users on my buddy list"), PURPLE_PRIVACY_ALLOW_BUDDYLIST
},
83 { N_("Allow only the users below"), PURPLE_PRIVACY_ALLOW_USERS
},
84 { N_("Block all users"), PURPLE_PRIVACY_DENY_ALL
},
85 { N_("Block only the users below"), PURPLE_PRIVACY_DENY_USERS
}
88 static const size_t menu_entry_count
= sizeof(menu_entries
) / sizeof(*menu_entries
);
90 static PidginPrivacyDialog
*privacy_dialog
= NULL
;
93 rebuild_allow_list(PidginPrivacyDialog
*dialog
)
98 gtk_list_store_clear(dialog
->allow_store
);
100 for (l
= dialog
->account
->permit
; l
!= NULL
; l
= l
->next
) {
101 gtk_list_store_append(dialog
->allow_store
, &iter
);
102 gtk_list_store_set(dialog
->allow_store
, &iter
, 0, l
->data
, -1);
107 rebuild_block_list(PidginPrivacyDialog
*dialog
)
112 gtk_list_store_clear(dialog
->block_store
);
114 for (l
= dialog
->account
->deny
; l
!= NULL
; l
= l
->next
) {
115 gtk_list_store_append(dialog
->block_store
, &iter
);
116 gtk_list_store_set(dialog
->block_store
, &iter
, 0, l
->data
, -1);
121 user_selected_cb(GtkTreeSelection
*sel
, PidginPrivacyDialog
*dialog
)
123 gtk_widget_set_sensitive(dialog
->remove_button
, TRUE
);
127 build_list(PidginPrivacyDialog
*dialog
, GtkListStore
*model
,
128 GtkWidget
**ret_treeview
)
132 GtkCellRenderer
*rend
;
133 GtkTreeViewColumn
*column
;
134 GtkTreeSelection
*sel
;
136 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(model
));
137 *ret_treeview
= treeview
;
139 rend
= gtk_cell_renderer_text_new();
141 column
= gtk_tree_view_column_new_with_attributes(NULL
, rend
,
144 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column
), TRUE
);
145 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview
), column
);
146 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview
), FALSE
);
147 sw
= pidgin_make_scrollable(treeview
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
, GTK_SHADOW_IN
, -1, 200);
149 gtk_widget_show(treeview
);
151 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
));
153 g_signal_connect(G_OBJECT(sel
), "changed",
154 G_CALLBACK(user_selected_cb
), dialog
);
160 build_allow_list(PidginPrivacyDialog
*dialog
)
165 dialog
->allow_store
= gtk_list_store_new(1, G_TYPE_STRING
);
167 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog
->allow_store
), 0, GTK_SORT_ASCENDING
);
169 widget
= build_list(dialog
, dialog
->allow_store
, &list
);
171 dialog
->allow_list
= list
;
173 rebuild_allow_list(dialog
);
179 build_block_list(PidginPrivacyDialog
*dialog
)
184 dialog
->block_store
= gtk_list_store_new(1, G_TYPE_STRING
);
186 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog
->block_store
), 0, GTK_SORT_ASCENDING
);
188 widget
= build_list(dialog
, dialog
->block_store
, &list
);
190 dialog
->block_list
= list
;
192 rebuild_block_list(dialog
);
198 destroy_cb(GtkWidget
*w
, GdkEvent
*event
, PidginPrivacyDialog
*dialog
)
200 pidgin_privacy_dialog_hide();
206 select_account_cb(GtkWidget
*dropdown
, PurpleAccount
*account
,
207 PidginPrivacyDialog
*dialog
)
211 dialog
->account
= account
;
213 for (i
= 0; i
< menu_entry_count
; i
++) {
214 if (menu_entries
[i
].type
== account
->perm_deny
) {
215 gtk_combo_box_set_active(GTK_COMBO_BOX(dialog
->type_menu
), i
);
220 rebuild_allow_list(dialog
);
221 rebuild_block_list(dialog
);
225 * TODO: Setting the permit/deny setting needs to go through privacy.c
226 * Even better: the privacy API needs to not suck.
229 type_changed_cb(GtkComboBox
*combo
, PidginPrivacyDialog
*dialog
)
231 PurplePrivacyType new_type
=
232 menu_entries
[gtk_combo_box_get_active(combo
)].type
;
234 dialog
->account
->perm_deny
= new_type
;
235 serv_set_permit_deny(purple_account_get_connection(dialog
->account
));
237 gtk_widget_hide(dialog
->allow_widget
);
238 gtk_widget_hide(dialog
->block_widget
);
239 gtk_widget_hide_all(dialog
->button_box
);
241 if (new_type
== PURPLE_PRIVACY_ALLOW_USERS
) {
242 gtk_widget_show(dialog
->allow_widget
);
243 gtk_widget_show_all(dialog
->button_box
);
244 dialog
->in_allow_list
= TRUE
;
246 else if (new_type
== PURPLE_PRIVACY_DENY_USERS
) {
247 gtk_widget_show(dialog
->block_widget
);
248 gtk_widget_show_all(dialog
->button_box
);
249 dialog
->in_allow_list
= FALSE
;
252 gtk_widget_show_all(dialog
->close_button
);
253 gtk_widget_show(dialog
->button_box
);
255 purple_blist_schedule_save();
256 pidgin_blist_refresh(purple_get_blist());
260 add_cb(GtkWidget
*button
, PidginPrivacyDialog
*dialog
)
262 if (dialog
->in_allow_list
)
263 pidgin_request_add_permit(dialog
->account
, NULL
);
265 pidgin_request_add_block(dialog
->account
, NULL
);
269 remove_cb(GtkWidget
*button
, PidginPrivacyDialog
*dialog
)
273 GtkTreeSelection
*sel
;
276 if (dialog
->in_allow_list
&& dialog
->allow_store
== NULL
)
279 if (!dialog
->in_allow_list
&& dialog
->block_store
== NULL
)
282 if (dialog
->in_allow_list
) {
283 model
= GTK_TREE_MODEL(dialog
->allow_store
);
284 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog
->allow_list
));
287 model
= GTK_TREE_MODEL(dialog
->block_store
);
288 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog
->block_list
));
291 if (gtk_tree_selection_get_selected(sel
, NULL
, &iter
))
292 gtk_tree_model_get(model
, &iter
, 0, &name
, -1);
296 if (dialog
->in_allow_list
)
297 purple_privacy_permit_remove(dialog
->account
, name
, FALSE
);
299 purple_privacy_deny_remove(dialog
->account
, name
, FALSE
);
305 removeall_cb(GtkWidget
*button
, PidginPrivacyDialog
*dialog
)
308 if (dialog
->in_allow_list
)
309 l
= dialog
->account
->permit
;
311 l
= dialog
->account
->deny
;
316 if (dialog
->in_allow_list
)
317 purple_privacy_permit_remove(dialog
->account
, user
, FALSE
);
319 purple_privacy_deny_remove(dialog
->account
, user
, FALSE
);
324 close_cb(GtkWidget
*button
, PidginPrivacyDialog
*dialog
)
326 gtk_widget_destroy(dialog
->win
);
328 pidgin_privacy_dialog_hide();
331 static PidginPrivacyDialog
*
332 privacy_dialog_new(void)
334 PidginPrivacyDialog
*dialog
;
339 gssize selected
= -1;
342 dialog
= g_new0(PidginPrivacyDialog
, 1);
344 dialog
->win
= pidgin_create_dialog(_("Privacy"), PIDGIN_HIG_BORDER
, "privacy", TRUE
);
346 g_signal_connect(G_OBJECT(dialog
->win
), "delete_event",
347 G_CALLBACK(destroy_cb
), dialog
);
350 vbox
= pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(dialog
->win
), FALSE
, PIDGIN_HIG_BORDER
);
352 /* Description label */
353 label
= gtk_label_new(
354 _("Changes to privacy settings take effect immediately."));
356 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, FALSE
, 0);
357 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
358 gtk_widget_show(label
);
360 /* Accounts drop-down */
361 dropdown
= pidgin_account_option_menu_new(NULL
, FALSE
,
362 G_CALLBACK(select_account_cb
), NULL
, dialog
);
363 pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("Set privacy for:"), NULL
, dropdown
, TRUE
, NULL
);
364 dialog
->account
= pidgin_account_option_menu_get_selected(dropdown
);
366 /* Add the drop-down list with the allow/block types. */
367 dialog
->type_menu
= gtk_combo_box_new_text();
368 gtk_box_pack_start(GTK_BOX(vbox
), dialog
->type_menu
, FALSE
, FALSE
, 0);
369 gtk_widget_show(dialog
->type_menu
);
371 for (i
= 0; i
< menu_entry_count
; i
++) {
372 gtk_combo_box_append_text(GTK_COMBO_BOX(dialog
->type_menu
),
373 _(menu_entries
[i
].text
));
375 if (menu_entries
[i
].type
== dialog
->account
->perm_deny
)
376 selected
= (gssize
)i
;
379 gtk_combo_box_set_active(GTK_COMBO_BOX(dialog
->type_menu
), selected
);
381 g_signal_connect(G_OBJECT(dialog
->type_menu
), "changed",
382 G_CALLBACK(type_changed_cb
), dialog
);
384 /* Build the treeview for the allow list. */
385 dialog
->allow_widget
= build_allow_list(dialog
);
386 gtk_box_pack_start(GTK_BOX(vbox
), dialog
->allow_widget
, TRUE
, TRUE
, 0);
388 /* Build the treeview for the block list. */
389 dialog
->block_widget
= build_block_list(dialog
);
390 gtk_box_pack_start(GTK_BOX(vbox
), dialog
->block_widget
, TRUE
, TRUE
, 0);
392 /* Add the button box for Add, Remove, Remove All */
393 dialog
->button_box
= pidgin_dialog_get_action_area(GTK_DIALOG(dialog
->win
));
396 button
= pidgin_dialog_add_button(GTK_DIALOG(dialog
->win
), GTK_STOCK_ADD
, G_CALLBACK(add_cb
), dialog
);
397 dialog
->add_button
= button
;
400 button
= pidgin_dialog_add_button(GTK_DIALOG(dialog
->win
), GTK_STOCK_REMOVE
, G_CALLBACK(remove_cb
), dialog
);
401 dialog
->remove_button
= button
;
402 /* TODO: This button should be sensitive/invisitive more cleverly */
403 gtk_widget_set_sensitive(button
, FALSE
);
405 /* Remove All button */
406 button
= pidgin_dialog_add_button(GTK_DIALOG(dialog
->win
), _("Remove Al_l"), G_CALLBACK(removeall_cb
), dialog
);
407 dialog
->removeall_button
= button
;
410 button
= pidgin_dialog_add_button(GTK_DIALOG(dialog
->win
), GTK_STOCK_CLOSE
, G_CALLBACK(close_cb
), dialog
);
411 dialog
->close_button
= button
;
413 type_changed_cb(GTK_COMBO_BOX(dialog
->type_menu
), dialog
);
415 if (dialog
->account
->perm_deny
== PURPLE_PRIVACY_ALLOW_USERS
) {
416 gtk_widget_show(dialog
->allow_widget
);
417 gtk_widget_show(dialog
->button_box
);
418 dialog
->in_allow_list
= TRUE
;
420 else if (dialog
->account
->perm_deny
== PURPLE_PRIVACY_DENY_USERS
) {
421 gtk_widget_show(dialog
->block_widget
);
422 gtk_widget_show(dialog
->button_box
);
423 dialog
->in_allow_list
= FALSE
;
430 pidgin_privacy_dialog_show(void)
432 g_return_if_fail(purple_connections_get_all() != NULL
);
434 if (privacy_dialog
== NULL
)
435 privacy_dialog
= privacy_dialog_new();
437 gtk_widget_show(privacy_dialog
->win
);
438 gdk_window_raise(privacy_dialog
->win
->window
);
442 pidgin_privacy_dialog_hide(void)
444 if (privacy_dialog
== NULL
)
447 g_object_unref(G_OBJECT(privacy_dialog
->allow_store
));
448 g_object_unref(G_OBJECT(privacy_dialog
->block_store
));
449 g_free(privacy_dialog
);
450 privacy_dialog
= NULL
;
454 destroy_request_data(PidginPrivacyRequestData
*data
)
461 confirm_permit_block_cb(PidginPrivacyRequestData
*data
, int option
)
464 purple_privacy_deny(data
->account
, data
->name
, FALSE
, FALSE
);
466 purple_privacy_allow(data
->account
, data
->name
, FALSE
, FALSE
);
468 destroy_request_data(data
);
472 add_permit_block_cb(PidginPrivacyRequestData
*data
, const char *name
)
474 data
->name
= g_strdup(name
);
476 confirm_permit_block_cb(data
, 0);
480 pidgin_request_add_permit(PurpleAccount
*account
, const char *name
)
482 PidginPrivacyRequestData
*data
;
484 g_return_if_fail(account
!= NULL
);
486 data
= g_new0(PidginPrivacyRequestData
, 1);
487 data
->account
= account
;
488 data
->name
= g_strdup(name
);
492 purple_request_input(account
, _("Permit User"),
493 _("Type a user you permit to contact you."),
494 _("Please enter the name of the user you wish to be "
495 "able to contact you."),
496 NULL
, FALSE
, FALSE
, NULL
,
497 _("_Permit"), G_CALLBACK(add_permit_block_cb
),
498 _("Cancel"), G_CALLBACK(destroy_request_data
),
503 char *primary
= g_strdup_printf(_("Allow %s to contact you?"), name
);
505 g_strdup_printf(_("Are you sure you wish to allow "
506 "%s to contact you?"), name
);
509 purple_request_action(account
, _("Permit User"), primary
, secondary
,
513 _("_Permit"), G_CALLBACK(confirm_permit_block_cb
),
514 _("Cancel"), G_CALLBACK(destroy_request_data
));
522 pidgin_request_add_block(PurpleAccount
*account
, const char *name
)
524 PidginPrivacyRequestData
*data
;
526 g_return_if_fail(account
!= NULL
);
528 data
= g_new0(PidginPrivacyRequestData
, 1);
529 data
->account
= account
;
530 data
->name
= g_strdup(name
);
534 purple_request_input(account
, _("Block User"),
535 _("Type a user to block."),
536 _("Please enter the name of the user you wish to block."),
537 NULL
, FALSE
, FALSE
, NULL
,
538 _("_Block"), G_CALLBACK(add_permit_block_cb
),
539 _("Cancel"), G_CALLBACK(destroy_request_data
),
544 char *primary
= g_strdup_printf(_("Block %s?"), name
);
546 g_strdup_printf(_("Are you sure you want to block %s?"), name
);
548 purple_request_action(account
, _("Block User"), primary
, secondary
,
552 _("_Block"), G_CALLBACK(confirm_permit_block_cb
),
553 _("Cancel"), G_CALLBACK(destroy_request_data
));
561 pidgin_permit_added_removed(PurpleAccount
*account
, const char *name
)
563 if (privacy_dialog
!= NULL
)
564 rebuild_allow_list(privacy_dialog
);
568 pidgin_deny_added_removed(PurpleAccount
*account
, const char *name
)
570 if (privacy_dialog
!= NULL
)
571 rebuild_block_list(privacy_dialog
);
574 static PurplePrivacyUiOps privacy_ops
=
576 pidgin_permit_added_removed
,
577 pidgin_permit_added_removed
,
578 pidgin_deny_added_removed
,
579 pidgin_deny_added_removed
,
587 pidgin_privacy_get_ui_ops(void)
593 pidgin_privacy_init(void)