music.c: cosmetix
[k8lowj.git] / src / security.c
blob591615ef30bcc1c9f97c6c3c36ba721cfb334077
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #include "gtk-all.h"
8 #include "util-gtk.h"
10 #include <stdlib.h>
12 #include "security.h"
13 #include "conf.h"
14 #include "network.h"
15 #include "icons.h"
17 struct _SecMgr {
18 GtkOptionMenu omenu;
19 LJSecurity security;
20 GtkWidget *custom;
21 JamAccountLJ *account;
24 static void secmgr_init(SecMgr *sm);
26 static void security_changed(SecMgr *sm);
27 static void secmgr_destroyed_cb(GObject* sm);
29 static const LJSecurity security_private = { LJ_SECURITY_PRIVATE, 0 };
31 /* gtk stuff */
32 GType
33 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,
48 "SecMgr", &sm_info, 0);
50 return sm_type;
53 static GtkWidget*
54 add_menu_item(GtkMenuShell *ms, const gchar *id, const gchar *text) {
55 GtkWidget *hbox;
56 GtkWidget *item;
58 hbox = gtk_hbox_new(FALSE, 3);
59 gtk_box_pack_start(GTK_BOX(hbox),
60 gtk_image_new_from_stock(id, GTK_ICON_SIZE_MENU),
61 FALSE, FALSE, 0);
62 gtk_box_pack_start(GTK_BOX(hbox),
63 gtk_label_new(text), FALSE, FALSE, 0);
65 item = gtk_menu_item_new();
66 gtk_container_add(GTK_CONTAINER(item), hbox);
67 gtk_menu_shell_append(ms, item);
68 return item;
71 static void
72 secmgr_init(SecMgr *sm) {
73 GtkWidget *menu;
74 GtkMenuShell *ms;
76 menu = gtk_menu_new();
77 ms = GTK_MENU_SHELL(menu);
79 add_menu_item(ms, "logjam-ljuser", _("Public"));
80 add_menu_item(ms, "logjam-protected", _("Friends"));
81 add_menu_item(ms, "logjam-private", _("Private"));
82 sm->custom = add_menu_item(ms, NULL, _("Custom..."));
83 gtk_widget_set_sensitive(sm->custom, FALSE);
85 gtk_widget_show_all(menu);
86 gtk_option_menu_set_menu(GTK_OPTION_MENU(sm), menu);
88 gtk_option_menu_set_history(GTK_OPTION_MENU(sm), sm->security.type);
90 g_signal_connect(G_OBJECT(sm), "changed",
91 G_CALLBACK(security_changed), NULL);
93 /* register secmgr */
94 app.secmgr_list = g_slist_append(app.secmgr_list, sm);
95 /* g_signal_connect(G_OBJECT(sm), "destroy",
96 G_CALLBACK(g_slist_remove), sm);
98 wouldn't this have been nice? unfortunately, the return value of
99 g_slist_remove must be kept, so we have to wrap this in a function.
101 g_signal_connect(G_OBJECT(sm), "destroy",
102 G_CALLBACK(secmgr_destroyed_cb), NULL);
105 static void
106 secmgr_destroyed_cb(GObject* sm) {
107 app.secmgr_list = g_slist_remove(app.secmgr_list, sm);
110 GtkWidget*
111 secmgr_new(gboolean withcustom) {
112 SecMgr *sm = SECMGR(g_object_new(secmgr_get_type(), NULL));
113 if (!withcustom)
114 gtk_widget_destroy(sm->custom);
115 return GTK_WIDGET(sm);
118 void
119 secmgr_set_account(SecMgr *sm, JamAccountLJ *account) {
120 gtk_widget_set_sensitive(sm->custom, account != NULL);
121 if (account != sm->account) {
122 LJSecurity oldsec;
124 sm->account = account;
126 secmgr_security_get(sm, &oldsec);
127 if (oldsec.type == LJ_SECURITY_CUSTOM)
128 secmgr_security_set(sm, &security_private);
132 void
133 secmgr_security_set(SecMgr *secmgr, const LJSecurity *security) {
134 secmgr->security = *security;
135 gtk_option_menu_set_history(GTK_OPTION_MENU(secmgr), secmgr->security.type);
137 void
138 secmgr_security_get(SecMgr *secmgr, LJSecurity *security) {
139 *security = secmgr->security;
142 /* a version of secmgr_security_set that avoids emitting the "changed"
143 * signal. useful for programmatic adjustments to a SecMgr (such as applying
144 * a user's changes from the Settings dialog), in order to avoid running the
145 * custom security dialog again. It should *only* be used in cases where
146 * the "changed" handler has already dealt with this change, or the input is
147 * known to be good for some other reason. */
148 void
149 secmgr_security_set_force(SecMgr *secmgr, const LJSecurity *security) {
150 g_signal_handlers_block_by_func(G_OBJECT(secmgr),
151 security_changed, NULL);
152 secmgr_security_set(secmgr, security);
153 g_signal_handlers_unblock_by_func(G_OBJECT(secmgr),
154 security_changed, NULL);
157 void
158 security_changed(SecMgr *sm) {
159 sm->security.type = gtk_option_menu_get_history(GTK_OPTION_MENU(sm));
160 if (sm->security.type == LJ_SECURITY_CUSTOM) {
161 sm->security.allowmask =
162 custom_security_dlg_run(
163 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(sm))),
164 sm->security.allowmask,
165 sm->account);
166 } else {
167 sm->security.allowmask = 0; /* reset it. */
170 if (sm->security.type == LJ_SECURITY_CUSTOM
171 && sm->security.allowmask == 0) {
172 secmgr_security_set(sm, &security_private);
176 enum {
177 COL_INCLUDED,
178 COL_NAME,
179 COL_FG
182 static void
183 included_toggle_cb(GtkCellRendererToggle *cell,
184 gchar *path_str, gpointer data) {
185 GtkTreeModel *model = data;
186 GtkTreeIter iter;
187 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
188 gboolean included;
190 gtk_tree_model_get_iter(model, &iter, path);
191 gtk_tree_model_get(model, &iter,
192 COL_INCLUDED, &included,
193 -1);
195 included = !included;
197 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
198 COL_INCLUDED, included,
199 -1);
200 gtk_tree_path_free(path);
203 static GtkTreeModel*
204 build_model(guint32 mask, LJUser *user) {
205 GtkListStore *store;
206 GSList *l;
207 LJFriendGroup *fg;
208 GtkTreeIter iter;
210 store = gtk_list_store_new(3,
211 G_TYPE_BOOLEAN, /* included? */
212 G_TYPE_STRING, /* name */
213 G_TYPE_POINTER /* friendgroup */);
214 for (l = user->friendgroups; l != NULL; l = l->next) {
215 fg = (LJFriendGroup*)l->data;
216 gtk_list_store_append(store, &iter);
217 gtk_list_store_set(store, &iter,
218 COL_INCLUDED, ((1L << fg->id) & mask) != 0,
219 COL_NAME, fg->name,
220 COL_FG, fg,
221 -1);
223 return GTK_TREE_MODEL(store);
226 static GtkWidget*
227 build_view(GtkTreeModel *model) {
228 GtkWidget *view;
229 GtkCellRenderer *renderer;
230 GtkTreeViewColumn *column;
232 view = gtk_tree_view_new_with_model(model);
233 column = gtk_tree_view_column_new();
234 gtk_tree_view_column_set_title(column, _("Included Groups"));
236 renderer = gtk_cell_renderer_toggle_new();
237 g_signal_connect(G_OBJECT(renderer), "toggled",
238 G_CALLBACK(included_toggle_cb), model);
239 gtk_tree_view_column_pack_start(column, renderer, FALSE);
240 gtk_tree_view_column_add_attribute(column, renderer,
241 "active", COL_INCLUDED);
243 renderer = gtk_cell_renderer_text_new();
244 gtk_tree_view_column_pack_start(column, renderer, TRUE);
245 gtk_tree_view_column_add_attribute(column, renderer,
246 "text", COL_NAME);
248 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
249 return view;
252 static guint32
253 get_new_mask(GtkTreeModel *model) {
254 GtkTreeIter iter;
255 gboolean included;
256 LJFriendGroup *fg;
257 guint32 newmask = 0;
259 if (gtk_tree_model_get_iter_first(model, &iter)) {
260 do {
261 gtk_tree_model_get(model, &iter,
262 COL_INCLUDED, &included,
263 COL_FG, &fg,
264 -1);
265 if (included)
266 newmask |= (1L << fg->id);
267 } while (gtk_tree_model_iter_next(model, &iter));
269 return newmask;
272 guint32
273 custom_security_dlg_run(GtkWindow *parent, guint32 mask, JamAccountLJ *acc) {
274 GtkWidget *dlg;
275 GtkTreeModel *model;
276 GtkWidget *view;
277 LJUser *user = jam_account_lj_get_user(acc);
279 dlg = gtk_dialog_new_with_buttons(_("Select Friend Groups"),
280 parent, GTK_DIALOG_MODAL,
281 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
282 NULL);
283 jam_win_set_size(GTK_WINDOW(dlg), 300, -1);
285 model = build_model(mask, user);
286 view = build_view(model);
288 jam_dialog_set_contents(GTK_DIALOG(dlg), scroll_wrap(view));
290 gtk_dialog_run(GTK_DIALOG(dlg));
291 mask = get_new_mask(model);
292 g_object_unref(G_OBJECT(model));
293 gtk_widget_destroy(dlg);
294 return mask;