Add deleted HTTP digest functions to ChangeLog.API.
[pidgin-git.git] / pidgin / gtkprivacy.c
blob0e52e3286a54c9ad853c1f3e93ecab342f3baeed
1 /* pidgin
3 * Pidgin is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 #include "internal.h"
22 #include "pidgin.h"
24 #include "connection.h"
25 #include "debug.h"
26 #include "request.h"
27 #include "util.h"
29 #include "gtkaccount.h"
30 #include "gtkblist.h"
31 #include "gtkprivacy.h"
32 #include "gtkutils.h"
33 #include "pidginaccountchooser.h"
35 #include "gtk3compat.h"
37 typedef struct
39 GtkWidget *win;
41 GtkWidget *type_menu;
43 GtkWidget *add_button;
44 GtkWidget *remove_button;
45 GtkWidget *removeall_button;
46 GtkWidget *close_button;
48 GtkWidget *button_box;
49 GtkWidget *allow_widget;
50 GtkWidget *block_widget;
52 GtkListStore *allow_store;
53 GtkListStore *block_store;
55 GtkWidget *allow_list;
56 GtkWidget *block_list;
58 gboolean in_allow_list;
60 PurpleAccount *account;
62 } PidginPrivacyDialog;
64 typedef struct
66 PurpleAccount *account;
67 char *name;
68 gboolean block;
70 } PidginPrivacyRequestData;
72 static struct
74 const char *text;
75 PurpleAccountPrivacyType type;
77 } const menu_entries[] =
79 { N_("Allow all users to contact me"), PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL },
80 { N_("Allow only the users on my buddy list"), PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST },
81 { N_("Allow only the users below"), PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS },
82 { N_("Block all users"), PURPLE_ACCOUNT_PRIVACY_DENY_ALL },
83 { N_("Block only the users below"), PURPLE_ACCOUNT_PRIVACY_DENY_USERS }
86 static const size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries);
88 static PidginPrivacyDialog *privacy_dialog = NULL;
90 static void
91 rebuild_allow_list(PidginPrivacyDialog *dialog)
93 GSList *l;
94 GtkTreeIter iter;
96 gtk_list_store_clear(dialog->allow_store);
98 for (l = purple_account_privacy_get_permitted(dialog->account); l != NULL; l = l->next) {
99 gtk_list_store_append(dialog->allow_store, &iter);
100 gtk_list_store_set(dialog->allow_store, &iter, 0, l->data, -1);
104 static void
105 rebuild_block_list(PidginPrivacyDialog *dialog)
107 GSList *l;
108 GtkTreeIter iter;
110 gtk_list_store_clear(dialog->block_store);
112 for (l = purple_account_privacy_get_denied(dialog->account); l != NULL; l = l->next) {
113 gtk_list_store_append(dialog->block_store, &iter);
114 gtk_list_store_set(dialog->block_store, &iter, 0, l->data, -1);
118 static void
119 user_selected_cb(GtkTreeSelection *sel, PidginPrivacyDialog *dialog)
121 gtk_widget_set_sensitive(dialog->remove_button, TRUE);
124 static GtkWidget *
125 build_list(PidginPrivacyDialog *dialog, GtkListStore *model,
126 GtkWidget **ret_treeview)
128 GtkWidget *sw;
129 GtkWidget *treeview;
130 GtkCellRenderer *rend;
131 GtkTreeViewColumn *column;
132 GtkTreeSelection *sel;
134 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
135 *ret_treeview = treeview;
137 rend = gtk_cell_renderer_text_new();
139 column = gtk_tree_view_column_new_with_attributes(NULL, rend,
140 "text", 0,
141 NULL);
142 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE);
143 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
144 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
145 sw = pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 200);
147 gtk_widget_show(treeview);
149 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
151 g_signal_connect(G_OBJECT(sel), "changed",
152 G_CALLBACK(user_selected_cb), dialog);
154 return sw;
157 static GtkWidget *
158 build_allow_list(PidginPrivacyDialog *dialog)
160 GtkWidget *widget;
161 GtkWidget *list;
163 dialog->allow_store = gtk_list_store_new(1, G_TYPE_STRING);
165 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->allow_store), 0, GTK_SORT_ASCENDING);
167 widget = build_list(dialog, dialog->allow_store, &list);
169 dialog->allow_list = list;
171 rebuild_allow_list(dialog);
173 return widget;
176 static GtkWidget *
177 build_block_list(PidginPrivacyDialog *dialog)
179 GtkWidget *widget;
180 GtkWidget *list;
182 dialog->block_store = gtk_list_store_new(1, G_TYPE_STRING);
184 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->block_store), 0, GTK_SORT_ASCENDING);
186 widget = build_list(dialog, dialog->block_store, &list);
188 dialog->block_list = list;
190 rebuild_block_list(dialog);
192 return widget;
195 static gint
196 destroy_cb(GtkWidget *w, GdkEvent *event, PidginPrivacyDialog *dialog)
198 pidgin_privacy_dialog_hide();
200 return 0;
203 static void
204 select_account_cb(GtkWidget *chooser, PidginPrivacyDialog *dialog)
206 PurpleAccount *account = pidgin_account_chooser_get_selected(chooser);
207 gsize i;
209 dialog->account = account;
211 for (i = 0; i < menu_entry_count; i++) {
212 if (menu_entries[i].type == purple_account_get_privacy_type(account)) {
213 gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), i);
214 break;
218 rebuild_allow_list(dialog);
219 rebuild_block_list(dialog);
223 * TODO: Setting the permit/deny setting needs to go through privacy.c
224 * Even better: the privacy API needs to not suck.
226 static void
227 type_changed_cb(GtkComboBox *combo, PidginPrivacyDialog *dialog)
229 PurpleAccountPrivacyType new_type =
230 menu_entries[gtk_combo_box_get_active(combo)].type;
232 purple_account_set_privacy_type(dialog->account, new_type);
233 purple_serv_set_permit_deny(purple_account_get_connection(dialog->account));
235 gtk_widget_hide(dialog->allow_widget);
236 gtk_widget_hide(dialog->block_widget);
237 gtk_widget_hide(dialog->button_box);
239 if (new_type == PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS) {
240 gtk_widget_show(dialog->allow_widget);
241 gtk_widget_show_all(dialog->button_box);
242 dialog->in_allow_list = TRUE;
244 else if (new_type == PURPLE_ACCOUNT_PRIVACY_DENY_USERS) {
245 gtk_widget_show(dialog->block_widget);
246 gtk_widget_show_all(dialog->button_box);
247 dialog->in_allow_list = FALSE;
250 gtk_widget_show_all(dialog->close_button);
251 gtk_widget_show(dialog->button_box);
253 purple_blist_schedule_save();
254 pidgin_blist_refresh(purple_blist_get_default());
257 static void
258 add_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
260 if (dialog->in_allow_list)
261 pidgin_request_add_permit(dialog->account, NULL);
262 else
263 pidgin_request_add_block(dialog->account, NULL);
266 static void
267 remove_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
269 GtkTreeIter iter;
270 GtkTreeModel *model;
271 GtkTreeSelection *sel;
272 char *name;
274 if (dialog->in_allow_list && dialog->allow_store == NULL)
275 return;
277 if (!dialog->in_allow_list && dialog->block_store == NULL)
278 return;
280 if (dialog->in_allow_list) {
281 model = GTK_TREE_MODEL(dialog->allow_store);
282 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->allow_list));
284 else {
285 model = GTK_TREE_MODEL(dialog->block_store);
286 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->block_list));
289 if (gtk_tree_selection_get_selected(sel, NULL, &iter))
290 gtk_tree_model_get(model, &iter, 0, &name, -1);
291 else
292 return;
294 if (dialog->in_allow_list)
295 purple_account_privacy_permit_remove(dialog->account, name, FALSE);
296 else
297 purple_account_privacy_deny_remove(dialog->account, name, FALSE);
299 g_free(name);
302 static void
303 removeall_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
305 GSList *l;
306 if (dialog->in_allow_list)
307 l = purple_account_privacy_get_permitted(dialog->account);
308 else
309 l = purple_account_privacy_get_denied(dialog->account);
310 while (l) {
311 char *user;
312 user = l->data;
313 l = l->next;
314 if (dialog->in_allow_list)
315 purple_account_privacy_permit_remove(dialog->account, user, FALSE);
316 else
317 purple_account_privacy_deny_remove(dialog->account, user, FALSE);
321 static void
322 close_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
324 gtk_widget_destroy(dialog->win);
326 pidgin_privacy_dialog_hide();
329 static PidginPrivacyDialog *
330 privacy_dialog_new(void)
332 PidginPrivacyDialog *dialog;
333 GtkWidget *vbox;
334 GtkWidget *button;
335 GtkWidget *dropdown;
336 GtkWidget *label;
337 gssize selected = -1;
338 gsize i;
340 dialog = g_new0(PidginPrivacyDialog, 1);
342 dialog->win = pidgin_create_dialog(_("Privacy"), PIDGIN_HIG_BORDER, "privacy", TRUE);
344 g_signal_connect(G_OBJECT(dialog->win), "delete_event",
345 G_CALLBACK(destroy_cb), dialog);
347 /* Main vbox */
348 vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(dialog->win), FALSE, PIDGIN_HIG_BORDER);
350 /* Description label */
351 label = gtk_label_new(
352 _("Changes to privacy settings take effect immediately."));
354 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
355 gtk_label_set_xalign(GTK_LABEL(label), 0);
356 gtk_widget_show(label);
358 /* Accounts drop-down */
359 dropdown = pidgin_account_chooser_new(NULL, FALSE);
360 pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Set privacy for:"), NULL, dropdown, TRUE, NULL);
361 g_signal_connect(dropdown, "changed", G_CALLBACK(select_account_cb),
362 dialog);
363 dialog->account = pidgin_account_chooser_get_selected(dropdown);
365 /* Add the drop-down list with the allow/block types. */
366 dialog->type_menu = gtk_combo_box_text_new();
367 gtk_box_pack_start(GTK_BOX(vbox), dialog->type_menu, FALSE, FALSE, 0);
368 gtk_widget_show(dialog->type_menu);
370 for (i = 0; i < menu_entry_count; i++) {
371 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(dialog->type_menu),
372 _(menu_entries[i].text));
374 if (menu_entries[i].type == purple_account_get_privacy_type(dialog->account))
375 selected = (gssize)i;
378 gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), selected);
380 g_signal_connect(G_OBJECT(dialog->type_menu), "changed",
381 G_CALLBACK(type_changed_cb), dialog);
383 /* Build the treeview for the allow list. */
384 dialog->allow_widget = build_allow_list(dialog);
385 gtk_box_pack_start(GTK_BOX(vbox), dialog->allow_widget, TRUE, TRUE, 0);
387 /* Build the treeview for the block list. */
388 dialog->block_widget = build_block_list(dialog);
389 gtk_box_pack_start(GTK_BOX(vbox), dialog->block_widget, TRUE, TRUE, 0);
391 /* Add the button box for Add, Remove, Remove All */
392 dialog->button_box = pidgin_dialog_get_action_area(GTK_DIALOG(dialog->win));
394 /* Add button */
395 button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_ADD, G_CALLBACK(add_cb), dialog);
396 dialog->add_button = button;
398 /* Remove button */
399 button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_REMOVE, G_CALLBACK(remove_cb), dialog);
400 dialog->remove_button = button;
401 /* TODO: This button should be sensitive/invisitive more cleverly */
402 gtk_widget_set_sensitive(button, FALSE);
404 /* Remove All button */
405 button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), _("Remove Al_l"), G_CALLBACK(removeall_cb), dialog);
406 dialog->removeall_button = button;
408 /* Close button */
409 button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_CLOSE, G_CALLBACK(close_cb), dialog);
410 dialog->close_button = button;
412 type_changed_cb(GTK_COMBO_BOX(dialog->type_menu), dialog);
413 #if 0
414 if (purple_account_get_privacy_type(dialog->account) == PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS) {
415 gtk_widget_show(dialog->allow_widget);
416 gtk_widget_show(dialog->button_box);
417 dialog->in_allow_list = TRUE;
419 else if (purple_account_get_privacy_type(dialog->account) == PURPLE_ACCOUNT_PRIVACY_DENY_USERS) {
420 gtk_widget_show(dialog->block_widget);
421 gtk_widget_show(dialog->button_box);
422 dialog->in_allow_list = FALSE;
424 #endif
425 return dialog;
428 void
429 pidgin_privacy_dialog_show(void)
431 g_return_if_fail(purple_connections_get_all() != NULL);
433 if (privacy_dialog == NULL)
434 privacy_dialog = privacy_dialog_new();
436 gtk_widget_show(privacy_dialog->win);
437 gdk_window_raise(gtk_widget_get_window(privacy_dialog->win));
440 void
441 pidgin_privacy_dialog_hide(void)
443 if (privacy_dialog == NULL)
444 return;
446 g_object_unref(G_OBJECT(privacy_dialog->allow_store));
447 g_object_unref(G_OBJECT(privacy_dialog->block_store));
448 g_free(privacy_dialog);
449 privacy_dialog = NULL;
452 static void
453 destroy_request_data(PidginPrivacyRequestData *data)
455 g_free(data->name);
456 g_free(data);
459 static void
460 confirm_permit_block_cb(PidginPrivacyRequestData *data, int option)
462 if (data->block)
463 purple_account_privacy_deny(data->account, data->name);
464 else
465 purple_account_privacy_allow(data->account, data->name);
467 destroy_request_data(data);
470 static void
471 add_permit_block_cb(PidginPrivacyRequestData *data, const char *name)
473 data->name = g_strdup(name);
475 confirm_permit_block_cb(data, 0);
478 void
479 pidgin_request_add_permit(PurpleAccount *account, const char *name)
481 PidginPrivacyRequestData *data;
483 g_return_if_fail(account != NULL);
485 data = g_new0(PidginPrivacyRequestData, 1);
486 data->account = account;
487 data->name = g_strdup(name);
488 data->block = FALSE;
490 if (name == NULL) {
491 purple_request_input(account, _("Permit User"),
492 _("Type a user you permit to contact you."),
493 _("Please enter the name of the user you wish to be "
494 "able to contact you."),
495 NULL, FALSE, FALSE, NULL,
496 _("_Permit"), G_CALLBACK(add_permit_block_cb),
497 _("Cancel"), G_CALLBACK(destroy_request_data),
498 purple_request_cpar_from_account(account),
499 data);
501 else {
502 char *primary = g_strdup_printf(_("Allow %s to contact you?"), name);
503 char *secondary =
504 g_strdup_printf(_("Are you sure you wish to allow "
505 "%s to contact you?"), name);
508 purple_request_action(account, _("Permit User"), primary,
509 secondary, 0, purple_request_cpar_from_account(account),
510 data, 2,
511 _("_Permit"), G_CALLBACK(confirm_permit_block_cb),
512 _("Cancel"), G_CALLBACK(destroy_request_data));
514 g_free(primary);
515 g_free(secondary);
519 void
520 pidgin_request_add_block(PurpleAccount *account, const char *name)
522 PidginPrivacyRequestData *data;
524 g_return_if_fail(account != NULL);
526 data = g_new0(PidginPrivacyRequestData, 1);
527 data->account = account;
528 data->name = g_strdup(name);
529 data->block = TRUE;
531 if (name == NULL) {
532 purple_request_input(account, _("Block User"),
533 _("Type a user to block."),
534 _("Please enter the name of the user you wish to block."),
535 NULL, FALSE, FALSE, NULL,
536 _("_Block"), G_CALLBACK(add_permit_block_cb),
537 _("Cancel"), G_CALLBACK(destroy_request_data),
538 purple_request_cpar_from_account(account),
539 data);
541 else {
542 char *primary = g_strdup_printf(_("Block %s?"), name);
543 char *secondary =
544 g_strdup_printf(_("Are you sure you want to block %s?"), name);
546 purple_request_action(account, _("Block User"), primary,
547 secondary, 0, purple_request_cpar_from_account(account),
548 data, 2,
549 _("_Block"), G_CALLBACK(confirm_permit_block_cb),
550 _("Cancel"), G_CALLBACK(destroy_request_data));
552 g_free(primary);
553 g_free(secondary);
557 static void
558 pidgin_permit_added_removed(PurpleAccount *account, const char *name)
560 if (privacy_dialog != NULL)
561 rebuild_allow_list(privacy_dialog);
564 static void
565 pidgin_deny_added_removed(PurpleAccount *account, const char *name)
567 if (privacy_dialog != NULL)
568 rebuild_block_list(privacy_dialog);
571 void
572 pidgin_privacy_init(void)
574 PurpleAccountUiOps *ops = pidgin_accounts_get_ui_ops();
576 ops->permit_added = ops->permit_removed = pidgin_permit_added_removed;
577 ops->deny_added = ops->deny_removed = pidgin_deny_added_removed;