cosmetix
[k8lowj.git] / src / security.c
blob19136b344d58ccff518fb11c37572424ba6f3fe9
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
3 */
4 #include "gtk-all.h"
5 #include "util-gtk.h"
7 #include <stdlib.h>
9 #include "conf.h"
10 #include "icons.h"
11 #include "network.h"
12 #include "security.h"
15 struct _SecMgr {
16 GtkOptionMenu omenu;
17 LJSecurity security;
18 GtkWidget *custom;
19 JamAccountLJ *account;
23 static void secmgr_init (SecMgr *sm);
25 static void security_changed (SecMgr *sm);
26 static void secmgr_destroyed_cb (GObject *sm);
29 static const LJSecurity security_private = { LJ_SECURITY_PRIVATE, 0 };
32 /* gtk stuff */
33 GType secmgr_get_type (void) {
34 static GType sm_type = 0;
35 if (!sm_type) {
36 const GTypeInfo sm_info = {
37 sizeof(GtkOptionMenuClass),
38 NULL,
39 NULL,
40 NULL,
41 NULL,
42 NULL,
43 sizeof(SecMgr),
45 (GInstanceInitFunc) secmgr_init,
47 sm_type = g_type_register_static(GTK_TYPE_OPTION_MENU, "SecMgr", &sm_info, 0);
49 return sm_type;
53 static GtkWidget *add_menu_item (GtkMenuShell *ms, const gchar *id, const gchar *text) {
54 GtkWidget *hbox;
55 GtkWidget *item;
57 hbox = gtk_hbox_new(FALSE, 3);
58 gtk_box_pack_start(GTK_BOX(hbox), gtk_image_new_from_stock(id, GTK_ICON_SIZE_MENU), FALSE, FALSE, 0);
59 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(text), FALSE, FALSE, 0);
61 item = gtk_menu_item_new();
62 gtk_container_add(GTK_CONTAINER(item), hbox);
63 gtk_menu_shell_append(ms, item);
64 return item;
68 static void secmgr_init (SecMgr *sm) {
69 GtkWidget *menu;
70 GtkMenuShell *ms;
72 menu = gtk_menu_new();
73 ms = GTK_MENU_SHELL(menu);
75 add_menu_item(ms, "logjam-ljuser", _("Public"));
76 add_menu_item(ms, "logjam-protected", _("Friends"));
77 add_menu_item(ms, "logjam-private", _("Private"));
78 sm->custom = add_menu_item(ms, NULL, _("Custom..."));
79 gtk_widget_set_sensitive(sm->custom, FALSE);
81 gtk_widget_show_all(menu);
82 gtk_option_menu_set_menu(GTK_OPTION_MENU(sm), menu);
84 gtk_option_menu_set_history(GTK_OPTION_MENU(sm), sm->security.type);
86 g_signal_connect(G_OBJECT(sm), "changed", G_CALLBACK(security_changed), NULL);
88 /* register secmgr */
89 app.secmgr_list = g_slist_append(app.secmgr_list, sm);
90 /* g_signal_connect(G_OBJECT(sm), "destroy",
91 G_CALLBACK(g_slist_remove), sm);
93 wouldn't this have been nice? unfortunately, the return value of
94 g_slist_remove must be kept, so we have to wrap this in a function.
96 g_signal_connect(G_OBJECT(sm), "destroy", G_CALLBACK(secmgr_destroyed_cb), NULL);
100 static void secmgr_destroyed_cb (GObject *sm) {
101 app.secmgr_list = g_slist_remove(app.secmgr_list, sm);
105 GtkWidget *secmgr_new (gboolean withcustom) {
106 SecMgr *sm = SECMGR(g_object_new(secmgr_get_type(), NULL));
107 if (!withcustom) gtk_widget_destroy(sm->custom);
108 return GTK_WIDGET(sm);
112 void secmgr_set_account (SecMgr *sm, JamAccountLJ *account) {
113 gtk_widget_set_sensitive(sm->custom, account != NULL);
114 if (account != sm->account) {
115 LJSecurity oldsec;
116 sm->account = account;
117 secmgr_security_get(sm, &oldsec);
118 if (oldsec.type == LJ_SECURITY_CUSTOM) secmgr_security_set(sm, &security_private);
123 void secmgr_security_set (SecMgr *secmgr, const LJSecurity *security) {
124 secmgr->security = *security;
125 gtk_option_menu_set_history(GTK_OPTION_MENU(secmgr), secmgr->security.type);
129 void secmgr_security_get (SecMgr *secmgr, LJSecurity *security) {
130 *security = secmgr->security;
134 /* a version of secmgr_security_set that avoids emitting the "changed"
135 * signal. useful for programmatic adjustments to a SecMgr (such as applying
136 * a user's changes from the Settings dialog), in order to avoid running the
137 * custom security dialog again. It should *only* be used in cases where
138 * the "changed" handler has already dealt with this change, or the input is
139 * known to be good for some other reason. */
140 void secmgr_security_set_force (SecMgr *secmgr, const LJSecurity *security) {
141 g_signal_handlers_block_by_func(G_OBJECT(secmgr), security_changed, NULL);
142 secmgr_security_set(secmgr, security);
143 g_signal_handlers_unblock_by_func(G_OBJECT(secmgr), security_changed, NULL);
147 void security_changed (SecMgr *sm) {
148 sm->security.type = gtk_option_menu_get_history(GTK_OPTION_MENU(sm));
149 if (sm->security.type == LJ_SECURITY_CUSTOM) {
150 sm->security.allowmask = custom_security_dlg_run(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(sm))), sm->security.allowmask, sm->account);
151 } else {
152 sm->security.allowmask = 0; /* reset it. */
154 if (sm->security.type == LJ_SECURITY_CUSTOM && sm->security.allowmask == 0) secmgr_security_set(sm, &security_private);
158 enum {
159 COL_INCLUDED,
160 COL_NAME,
161 COL_FG
165 static void included_toggle_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer data) {
166 GtkTreeModel *model = data;
167 GtkTreeIter iter;
168 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
169 gboolean included;
171 gtk_tree_model_get_iter(model, &iter, path);
172 gtk_tree_model_get(model, &iter, COL_INCLUDED, &included, -1);
174 included = !included;
176 gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_INCLUDED, included, -1);
177 gtk_tree_path_free(path);
181 static GtkTreeModel *build_model (guint32 mask, LJUser *user) {
182 GtkListStore *store;
183 GSList *l;
184 LJFriendGroup *fg;
185 GtkTreeIter iter;
187 store = gtk_list_store_new(3, G_TYPE_BOOLEAN, /* included? */
188 G_TYPE_STRING, /* name */
189 G_TYPE_POINTER /* friendgroup */ );
190 for (l = user->friendgroups; l != NULL; l = l->next) {
191 fg = (LJFriendGroup *) l->data;
192 gtk_list_store_append(store, &iter);
193 gtk_list_store_set(store, &iter, COL_INCLUDED, ((1L << fg->id) & mask) != 0, COL_NAME, fg->name, COL_FG, fg, -1);
195 return GTK_TREE_MODEL(store);
199 static GtkWidget *build_view (GtkTreeModel *model) {
200 GtkWidget *view;
201 GtkCellRenderer *renderer;
202 GtkTreeViewColumn *column;
204 view = gtk_tree_view_new_with_model(model);
205 column = gtk_tree_view_column_new();
206 gtk_tree_view_column_set_title(column, _("Included Groups"));
208 renderer = gtk_cell_renderer_toggle_new();
209 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(included_toggle_cb), model);
210 gtk_tree_view_column_pack_start(column, renderer, FALSE);
211 gtk_tree_view_column_add_attribute(column, renderer, "active", COL_INCLUDED);
213 renderer = gtk_cell_renderer_text_new();
214 gtk_tree_view_column_pack_start(column, renderer, TRUE);
215 gtk_tree_view_column_add_attribute(column, renderer, "text", COL_NAME);
217 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
218 return view;
222 static guint32 get_new_mask (GtkTreeModel *model) {
223 GtkTreeIter iter;
224 gboolean included;
225 LJFriendGroup *fg;
226 guint32 newmask = 0;
228 if (gtk_tree_model_get_iter_first(model, &iter)) {
229 do {
230 gtk_tree_model_get(model, &iter, COL_INCLUDED, &included, COL_FG, &fg, -1);
231 if (included) newmask |= (1L << fg->id);
232 } while (gtk_tree_model_iter_next(model, &iter));
234 return newmask;
238 guint32 custom_security_dlg_run (GtkWindow *parent, guint32 mask, JamAccountLJ *acc) {
239 GtkWidget *dlg;
240 GtkTreeModel *model;
241 GtkWidget *view;
242 LJUser *user = jam_account_lj_get_user(acc);
244 dlg = gtk_dialog_new_with_buttons(_("Select Friend Groups"), parent, GTK_DIALOG_MODAL, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
245 jam_win_set_size(GTK_WINDOW(dlg), 300, -1);
247 model = build_model(mask, user);
248 view = build_view(model);
250 jam_dialog_set_contents(GTK_DIALOG(dlg), scroll_wrap(view));
252 gtk_dialog_run(GTK_DIALOG(dlg));
253 mask = get_new_mask(model);
254 g_object_unref(G_OBJECT(model));
255 gtk_widget_destroy(dlg);
256 return mask;