1 /* key_selection_dialog.c
2 *
3 * Copyright 2011 Hans Alves <alves.h88@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21 /* something about premature optimization, it still needs to be done */
22
23 #include "geanypg.h"
24
25 enum
26 {
27 TOGGLE_COLUMN,
28 RECIPIENT_COLUMN,
29 KEYID_COLUMN,
30 N_COLUMNS
31 };
32
33 typedef struct
34 {
35 GtkListStore * store;
36 gint column;
37 } listdata;
38
geanypg_toggled_cb(GtkCellRendererToggle * cell_renderer,gchar * path,listdata * udata)39 static void geanypg_toggled_cb(GtkCellRendererToggle * cell_renderer,
40 gchar * path,
41 listdata * udata)
42 {
43 GtkTreeIter iter;
44 gboolean value;
45 if (!udata) return;
46 if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(udata->store), &iter, path))
47 {
48 gtk_tree_model_get(GTK_TREE_MODEL(udata->store), &iter, udata->column, &value, -1);
49 value = !value;
50 gtk_list_store_set(udata->store, &iter, udata->column, value, -1);
51 }
52 }
53
geanypg_makelist(gpgme_key_t * key_array,unsigned long nkeys,int addnone)54 static GtkListStore * geanypg_makelist(gpgme_key_t * key_array, unsigned long nkeys, int addnone)
55 {
56 GtkTreeIter iter;
57 unsigned long idx;
58 char empty_string = '\0';
59 GtkListStore * list = gtk_list_store_new(N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING);
60 if (addnone)
61 {
62 gtk_list_store_append(list, &iter);
63 gtk_list_store_set(list, &iter,
64 TOGGLE_COLUMN, FALSE,
65 RECIPIENT_COLUMN, "None",
66 KEYID_COLUMN, "",
67 -1);
68 }
69 for (idx = 0; idx < nkeys; ++idx)
70 {
71 char * name = (key_array[idx]->uids && key_array[idx]->uids->name) ? key_array[idx]->uids->name : &empty_string;
72 char * email = (key_array[idx]->uids && key_array[idx]->uids->email) ? key_array[idx]->uids->email : &empty_string;
73 gchar * buffer = g_strdup_printf("%s <%s>", name, email);
74 gtk_list_store_append(list, &iter);
75 gtk_list_store_set(list, &iter,
76 TOGGLE_COLUMN, FALSE,
77 RECIPIENT_COLUMN, buffer,
78 KEYID_COLUMN, key_array[idx]->subkeys->keyid,
79 -1);
80 g_free(buffer);
81 }
82 return list;
83 }
84
geanypg_combobox(GtkListStore * list)85 static GtkWidget * geanypg_combobox(GtkListStore * list)
86 {
87 GtkWidget * combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list));
88 GtkCellRenderer * cell1 = gtk_cell_renderer_text_new();
89 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), cell1, FALSE);
90 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combobox), cell1,
91 "text", RECIPIENT_COLUMN);
92 return combobox;
93 }
94
geanypg_listview(GtkListStore * list,listdata * data)95 static GtkWidget * geanypg_listview(GtkListStore * list, listdata * data)
96 {
97 GtkTreeViewColumn * column;
98 GtkCellRenderer * togglerenderer, * textrenderer;
99 GtkWidget * listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list));
100 /* checkbox column */
101 togglerenderer = gtk_cell_renderer_toggle_new();
102 g_signal_connect(G_OBJECT(togglerenderer), "toggled", G_CALLBACK(geanypg_toggled_cb), NULL);
103 column = gtk_tree_view_column_new_with_attributes("?",
104 togglerenderer,
105 "active", TOGGLE_COLUMN,
106 NULL);
107 gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
108 data->store = list;
109 data->column = TOGGLE_COLUMN;
110 g_signal_connect(G_OBJECT(togglerenderer), "toggled", G_CALLBACK(geanypg_toggled_cb), (gpointer) data);
111 /* recipient column */
112 textrenderer = gtk_cell_renderer_text_new();
113 column = gtk_tree_view_column_new_with_attributes("recipient",
114 textrenderer,
115 "text", RECIPIENT_COLUMN,
116 NULL);
117 gtk_tree_view_column_set_resizable(column, TRUE);
118 gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
119 /* keyid column */
120 column = gtk_tree_view_column_new_with_attributes("keyid",
121 textrenderer,
122 "text", KEYID_COLUMN,
123 NULL);
124 gtk_tree_view_column_set_resizable(column, TRUE);
125 gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
126 return listview;
127 }
128
geanypg_encrypt_selection_dialog(encrypt_data * ed,gpgme_key_t ** selected,int * sign)129 int geanypg_encrypt_selection_dialog(encrypt_data * ed, gpgme_key_t ** selected, int * sign)
130 {
131 GtkWidget * dialog = gtk_dialog_new();
132 unsigned long idx, sidx, capacity;
133 int response;
134 GtkWidget * contentarea, * listview, * scrollwin, * combobox;
135 GtkTreeIter iter;
136 listdata data;
137 gboolean active;
138 GtkListStore * list;
139
140 *sign = 0;
141
142 list = geanypg_makelist(ed->key_array, ed->nkeys, 0);
143 listview = geanypg_listview(list, &data);
144 scrollwin = gtk_scrolled_window_new(NULL, NULL);
145 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwin),
146 listview);
147 gtk_widget_set_size_request(scrollwin, 500, 160);
148 combobox = geanypg_combobox(geanypg_makelist(ed->skey_array, ed->nskeys, 1));
149
150
151 contentarea = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
152 gtk_box_pack_start(GTK_BOX(contentarea), gtk_label_new(_("Please select any recipients")), FALSE, FALSE, 5);
153 gtk_box_pack_start(GTK_BOX(contentarea), scrollwin, TRUE, TRUE, 0);
154 gtk_box_pack_start(GTK_BOX(contentarea), gtk_label_new(_("Sign the message as:")), FALSE, FALSE, 5);
155 gtk_box_pack_start(GTK_BOX(contentarea), combobox, FALSE, FALSE, 0);
156
157
158 /* add ok and cancel buttons */
159 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
160 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
161
162 gtk_window_set_title(GTK_WINDOW(dialog), _("Select recipients"));
163 gtk_widget_show_all(dialog);
164 /* make sure dialog is destroyed when user responds */
165 response = gtk_dialog_run(GTK_DIALOG(dialog));
166 if (response == GTK_RESPONSE_CANCEL)
167 {
168 gtk_widget_destroy(dialog);
169 return 0;
170 }
171 idx = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
172 if (idx && idx <= ed->nskeys)
173 {
174 *sign = 1;
175 gpgme_signers_add(ed->ctx, ed->skey_array[idx - 1]); /* -1 because the first option is `None' */
176 }
177 /* try to loop all the keys in the list
178 * if they are active (the user checked the checkbox in front of the key)
179 * add it to the selected array, finaly make sure that the array
180 * is NULL terminated */
181 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), &iter))
182 {
183 capacity = SIZE;
184 *selected = (gpgme_key_t*) malloc(SIZE * sizeof(gpgme_key_t));
185 idx = 0;
186 sidx = 0;
187 gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, TOGGLE_COLUMN, &active, -1);
188 if (active)
189 (*selected)[sidx++] = ed->key_array[idx];
190
191 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter))
192 {
193 ++idx;
194 gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, TOGGLE_COLUMN, &active, -1);
195 if (active)
196 (*selected)[sidx++] = ed->key_array[idx];
197 if (sidx >= capacity - 1)
198 {
199 capacity += SIZE;
200 *selected = (gpgme_key_t*) realloc(*selected, capacity * sizeof(gpgme_key_t));
201 }
202 }
203 (*selected)[sidx] = NULL;
204 }
205 else
206 {
207 gtk_widget_destroy(dialog);
208 return 0;
209 }
210
211 gtk_widget_destroy(dialog);
212 return 1;
213 }
214
geanypg_sign_selection_dialog(encrypt_data * ed)215 int geanypg_sign_selection_dialog(encrypt_data * ed)
216 {
217 GtkWidget * dialog = gtk_dialog_new();
218 unsigned long idx;
219 int response;
220 GtkWidget * contentarea = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
221 GtkWidget * combobox = geanypg_combobox(
222 geanypg_makelist(ed->skey_array, ed->nskeys, 0));
223
224 gtk_box_pack_start(GTK_BOX(contentarea), gtk_label_new(_("Choose a key to sign with:")), FALSE, FALSE, 5);
225 gtk_box_pack_start(GTK_BOX(contentarea), combobox, TRUE, TRUE, 0);
226
227 /* add ok and cancel buttons */
228 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
229 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
230
231 gtk_widget_show_all(dialog);
232 gtk_window_set_title(GTK_WINDOW(dialog), _("Select signer"));
233 /* make sure dialog is destroyed when user responds */
234 response = gtk_dialog_run(GTK_DIALOG(dialog));
235 if (response == GTK_RESPONSE_CANCEL)
236 {
237 gtk_widget_destroy(dialog);
238 return 0;
239 }
240 idx = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
241 gpgme_signers_clear(ed->ctx);
242 if (idx < ed->nskeys)
243 gpgme_signers_add(ed->ctx, ed->skey_array[idx]);
244
245 gtk_widget_destroy(dialog);
246 return 1;
247 }
248