1 /*                    Configure dialog UI                                 */
2 /*             Copyright (C) 2001-2003 William Tompkins                   */
3 
4 /* This plugin is free software, distributed under the GNU General Public */
5 /* License.                                                               */
6 /* Please see the file "COPYING" distributed with this source code        */
7 /* for more details                                                       */
8 /*                                                                        */
9 /*                                                                        */
10 /*    This software 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 GNU    */
13 /*   General Public License for more details.                             */
14 
15 /*   To compile and use:                                                  */
16 /*     See INSTALL file.                                                  */
17 
18 #include "internal.h"
19 
20 #include <string.h>
21 #include <assert.h>
22 
23 #include <gdk/gdk.h>
24 #include <gtk/gtk.h>
25 #include <gtk/gtkplug.h>
26 
27 #include <debug.h>
28 #include <gtkdialogs.h>
29 #include <gtkprefs.h>
30 #include <gtkprefs.h>
31 #include <util.h>
32 
zip(T0 const & t0,T1 const & t1)33 #include "nls.h"
34 #include "cryptproto.h"
35 #include "keys.h"
36 #include "config_ui.h"
37 
38 #ifdef _WIN32
39 #include "win32dep.h"
40 #endif
41 
42 /*Static vars for the config dialog: */
43 static GtkWidget *key_size_entry, *proto_combo;
44 
45 /* static GtkListStore *key_list_store = NULL; */
46 /* static GtkWidget *key_list_view = NULL; */
47 
48 static GtkWidget *regen_err_label;
49 static GtkWidget *regen_window = NULL; /* regenerate key popup */
50 
51 static GtkWidget* config_vbox = NULL;  /* Our main config pane */
52 static GtkWidget* Local_keylist_view = NULL;
53 static GtkWidget* Saved_keylist_view = NULL;
54 static GtkWidget* InMem_keylist_view = NULL;
zip(T0 const & t0,T1 const & t1,T2 const & t2)55 
56 static GtkWidget* Invalid_path_label = NULL;
57 static GtkWidget* Invalid_path_button = NULL;
58 
59 static void create_key_files_cb();
60 
61 /* Callbacks for the Regenerate popup dialog */
62 static void config_cancel_regen() {
63    if (regen_window) {
64       gtk_widget_destroy(regen_window);
65    }
66    regen_window = NULL;
67 }
68 
69 static void config_do_regen(GtkWidget* hitbutton, GtkWidget *key_list_view) {
70    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(key_list_view));
71    GtkListStore *key_list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(key_list_view)));
72 
73    const gchar* bits_string = gtk_entry_get_text(GTK_ENTRY(key_size_entry));
74    const gchar* proto_string =
75       gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(proto_combo)->entry));  // should NOT be freed
76    int bits = 0;
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3)77    GSList *proto = crypt_proto_list;
78    gchar *name;
79    PurpleAccount *acct;
80    gchar key_len[15];
81 
82    GString *key_buf;
83    GtkTreeIter list_store_iter;
84 
85    sscanf(bits_string, "%d", &bits);
86 
87    if (bits == 0) {
88       gtk_label_set_text(GTK_LABEL(regen_err_label),
89                          _("Bad key size"));
90       return;
91    }
92 
93    if (bits < 512) {
94       gtk_label_set_text(GTK_LABEL(regen_err_label),
95                          _("Keys < 512 bits are VERY insecure"));
96       return;
97    }
98 
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4)99    if (bits > 4096) {
100       gtk_label_set_text(GTK_LABEL(regen_err_label),
101                          _("Keys > 4096 bits will cause extreme\n"
102                            "message bloat, causing problems with\n"
103                            "message transmission"));
104       return;
105    }
106 
107    while (proto != NULL &&
108           strcmp(proto_string, ((crypt_proto*)proto->data)->name) != 0) {
109       proto = proto->next;
110    }
111 
112    if (proto == NULL) {
113       purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", "Can't find protocol in list! Aigh!\n");
114       return;
115    }
116 
117    if (gtk_tree_selection_get_selected(selection, NULL, &list_store_iter)) {
118       crypt_key * regenerated_key;
119 
120       gtk_tree_model_get(GTK_TREE_MODEL(key_list_store), &list_store_iter, 0, &name, 4, &acct, -1);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5)121       purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "regen for name: '%s', acct: %p\n", name, acct);
122 
123       PE_make_private_pair((crypt_proto*)proto->data, name, acct, bits);
124 
125       snprintf(key_len, sizeof(key_len), "%d", bits);
126 
127       regenerated_key = PE_find_key_by_name(PE_my_pub_ring, name, acct);
128       if (regenerated_key) {
129          key_buf = g_string_new_len(regenerated_key->fingerprint, KEY_FINGERPRINT_LENGTH);
130       } else {
131          key_buf = g_string_new("--error--");
132       }
133 
134       gtk_list_store_set(key_list_store, &list_store_iter,
135                          1, key_len,
136                          2, key_buf->str,
137                          3, proto_string,
138                          -1);
139 
140       g_string_free(key_buf, TRUE);
141       g_free(name);
142    }
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6)143 
144    config_cancel_regen();
145 
146    hitbutton = hitbutton; /* unused */
147 }
148 
149 /* Display the Regenerate Key popup, and set up the above callbacks */
150 /* (used as a callback from the main Config dialog, below)          */
151 static void config_regen_key(GtkWidget* hitbutton, GtkWidget* key_list_view) {
152    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(key_list_view));
153 
154    GtkWidget *vbox, *hbox, *label, *table, *button;
155    GList *proto_list = NULL;
156    key_ring* iter;
157 
158    if (regen_window != NULL) return;
159 
160    PIDGIN_DIALOG(regen_window);
161    gtk_widget_set_size_request(regen_window, 300, 150);
162    gtk_window_set_title(GTK_WINDOW(regen_window), _("Generate Keys"));
163    g_signal_connect(G_OBJECT(regen_window), "destroy",
164                     GTK_SIGNAL_FUNC(config_cancel_regen), NULL);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7)165 
166    vbox = gtk_vbox_new(0, 2);
167    gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
168    gtk_container_add(GTK_CONTAINER(regen_window), vbox);
169    gtk_widget_show (vbox);
170 
171    if (!gtk_tree_selection_get_selected(selection, NULL, NULL)) {
172       label = gtk_label_new(_("No key selected to re-generate!"));
173       gtk_box_pack_start(GTK_BOX(vbox), label, 0, 0, 0);
174       gtk_widget_show(label);
175 
176       hbox = gtk_hbox_new(FALSE, 2);
177       gtk_box_pack_end(GTK_BOX(vbox), hbox, 0, 0, 0);
178       gtk_widget_show(hbox);
179 
180       button = gtk_button_new_with_label(_("OK"));
181       g_signal_connect(G_OBJECT(button), "clicked",
182                          GTK_SIGNAL_FUNC(config_cancel_regen), NULL);
183       gtk_box_pack_end(GTK_BOX(hbox), button, 0, 0, 0);
184       gtk_widget_set_size_request(button, 100, -1);
185       gtk_widget_show(button);
186       gtk_widget_show(regen_window);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8)187       return;
188    }
189 
190    /* Start 2 x 2 table */
191    table = gtk_table_new(2, 2, FALSE);
192    gtk_box_pack_start(GTK_BOX(vbox), table, 0, 0, 0);
193    gtk_widget_show(table);
194 
195    /* First column */
196    label = gtk_label_new(_("Encryption protocol:"));
197    gtk_widget_set_size_request(label, 150, -1);
198    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
199    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
200                     0, 0, 0, 0);
201    gtk_widget_show(label);
202 
203    label = gtk_label_new(_("Key size:"));
204    gtk_widget_set_size_request(label, 150, -1);
205    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
206    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
207                     0, 0, 0, 0);
208    gtk_widget_show(label);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9)209 
210    /* Second column: */
211    proto_combo = gtk_combo_new();
212    gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(proto_combo)->entry),
213                       ((crypt_proto*)crypt_proto_list->data)->name);
214    gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(proto_combo)->entry),
215                              FALSE);
216    for( iter = crypt_proto_list; iter != NULL; iter = iter->next ) {
217       proto_list = g_list_append(proto_list,
218                                  ((crypt_proto *)iter->data)->name);
219    }
220    gtk_combo_set_popdown_strings(GTK_COMBO (proto_combo), proto_list);
221    g_list_free(proto_list);
222    gtk_table_attach(GTK_TABLE(table), proto_combo, 1, 2, 0, 1,
223                     0, 0, 0, 0);
224 
225    gtk_widget_set_size_request(proto_combo, 85, -1);
226    gtk_widget_show(proto_combo);
227 
228    key_size_entry = gtk_entry_new();
229    gtk_entry_set_max_length(GTK_ENTRY(key_size_entry), 5);
230    gtk_entry_set_text(GTK_ENTRY(key_size_entry), "1024");
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10)231    gtk_table_attach(GTK_TABLE(table), key_size_entry, 1, 2, 1, 2,
232                     0, 0, 0, 0);
233    gtk_widget_set_size_request(key_size_entry, 85, -1);
234    gtk_widget_show(key_size_entry);
235    /* End of 2x2 table */
236 
237    regen_err_label = gtk_label_new("");
238    gtk_box_pack_start(GTK_BOX(vbox), regen_err_label, 0, 0, 0);
239    gtk_widget_show(regen_err_label);
240 
241    hbox = gtk_hbox_new(FALSE, 2);
242    gtk_box_pack_end(GTK_BOX(vbox), hbox, 0, 0, 0);
243    gtk_widget_show(hbox);
244 
245    button = gtk_button_new_with_label(_("Cancel"));
246    g_signal_connect(G_OBJECT(button), "clicked",
247                     GTK_SIGNAL_FUNC(config_cancel_regen), NULL);
248    gtk_box_pack_start(GTK_BOX(hbox), button, 0, 0, 0);
249    gtk_widget_set_size_request(button, 100, -1);
250    gtk_widget_show(button);
251 
252    button = gtk_button_new_with_label(_("Ok"));
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11)253    g_signal_connect(G_OBJECT(button), "clicked",
254                     GTK_SIGNAL_FUNC(config_do_regen), key_list_view);
255    gtk_box_pack_start(GTK_BOX(hbox), button, 0, 0, 0);
256    gtk_widget_set_size_request(button, 100, -1);
257    gtk_widget_show(button);
258 
259    gtk_widget_show(regen_window);
260 
261    hitbutton = hitbutton; /* unused */
262 }
263 
264 /* button handler: */
265 static void delete_local_key(GtkWidget* hitbutton, GtkWidget* key_list_view) {
266    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(key_list_view));
267    GtkListStore *key_list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(key_list_view)));
268    GtkTreeIter list_store_iter;
269 
270    gchar *name;
271    PurpleAccount *acct;
272 
273    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "delete local key\n");
274 
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12)275    if (regen_window != NULL) return;
276 
277    if (gtk_tree_selection_get_selected(selection, NULL, &list_store_iter)) {
278 
279       gtk_tree_model_get(GTK_TREE_MODEL(key_list_store), &list_store_iter, 0, &name, 4, &acct, -1);
280 
281       {
282          GtkWidget * confirm_dialog =
283             gtk_message_dialog_new(0, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
284                                    "%s : %s", _("Delete Key"), name);
285 
286          gint confirm_response = gtk_dialog_run( GTK_DIALOG(confirm_dialog) );
287          gtk_widget_destroy(confirm_dialog);
288 
289          if (confirm_response != GTK_RESPONSE_OK) return;
290       }
291 
292       purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "deleting '%s' : %p\n", name, acct);
293 
294       PE_del_key_from_file(Public_key_file, name, acct);
295       PE_del_key_from_file(Private_key_file, name, acct);
296 
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13)297       PE_del_key_from_ring(PE_my_pub_ring, name, acct);
298       PE_del_key_from_ring(PE_my_priv_ring, name, acct);
299 
300       gtk_list_store_remove(key_list_store, &list_store_iter);
301    }
302 
303    hitbutton = hitbutton; /* unused */
304 }
305 
306 /* button handler: */
307 static void delete_buddy_key(GtkWidget* hitbutton, GtkWidget* key_list_view) {
308    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(key_list_view));
309    GtkListStore *key_list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(key_list_view)));
310    GtkTreeIter list_store_iter;
311 
312    gchar *name;
313    PurpleAccount *acct;
314    gint num;
315 
316    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "delete buddy key\n");
317 
318    if (regen_window != NULL) return;
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14)319 
320    if (gtk_tree_selection_get_selected(selection, NULL, &list_store_iter)) {
321 
322       gtk_tree_model_get(GTK_TREE_MODEL(key_list_store), &list_store_iter, 0,
323                          &name, 4, &acct, 5, &num, -1);
324 
325       {
326          GtkWidget * confirm_dialog =
327             gtk_message_dialog_new(0, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
328                                    "%s %s", _("Delete Key"), name);
329 
330          gint confirm_response = gtk_dialog_run( GTK_DIALOG(confirm_dialog) );
331          gtk_widget_destroy(confirm_dialog);
332 
333          if (confirm_response != GTK_RESPONSE_OK) return;
334       }
335 
336       /* purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "From file: %d : %s\n", num, name); */
337       PE_del_one_key_from_file(Buddy_key_file, num, name);
338       PE_del_key_from_ring(PE_buddy_ring, name, acct);
339 
340       gtk_list_store_remove(key_list_store, &list_store_iter);
341    }
342 
343    hitbutton = hitbutton; /* unused */
344 }
345 
346 /* button handler: */
347 static void copy_fp_to_clipboard(GtkWidget* hitbutton, GtkWidget* key_list_view) {
348    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(key_list_view));
349    GtkListStore *key_list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(key_list_view)));
350    GtkTreeIter list_store_iter;
351 
352    gchar *fptext;
353 
354    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "copy to clipboard\n");
355 
356    if (regen_window != NULL) return;
357 
358    if (gtk_tree_selection_get_selected(selection, NULL, &list_store_iter)) {
359       gtk_tree_model_get(GTK_TREE_MODEL(key_list_store), &list_store_iter, 2, &fptext, -1);
360 
361       /*  purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "copy :%s:\n", fptext); */
362 
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16)363       gtk_clipboard_set_text( gtk_clipboard_get (GDK_SELECTION_PRIMARY), fptext, strlen(fptext) );
364       gtk_clipboard_set_text( gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), fptext, strlen(fptext) );
365       g_free(fptext);
366    }
367 
368    hitbutton = hitbutton; /* unused */
369 }
370 
371 void PE_populate_key_list_view(key_ring *ring, gboolean local, GtkTreeView* key_list_view) {
372    GtkListStore *store;
373    GtkTreeIter store_iter;
374    GtkCellRenderer *renderer;
375    GtkTreeViewColumn *col;
376    key_ring* iter;
377    GString* key_buf;
378    gint num;
379 
380    /* make a list store as a 'model' for the tree view, to store the data in */
381    store = gtk_list_store_new (6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
382                                G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT, -1);
383 
384    gtk_tree_view_set_model(key_list_view, GTK_TREE_MODEL(store));
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17)385 
386    g_object_unref (G_OBJECT(store));
387 
388    /* erase any columns that are in the view from previous populations */
389    while (0 != (col = gtk_tree_view_get_column(key_list_view, 0))) {
390       gtk_tree_view_remove_column(key_list_view, col);
391    }
392 
393    renderer = gtk_cell_renderer_text_new();
394 
395    if (local) {
396       col = gtk_tree_view_column_new_with_attributes(_("Account"), renderer, "text", 0, NULL);
397    } else {
398       col = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 0, NULL);
399    }
400    gtk_tree_view_append_column(key_list_view, col);
401 
402    col = gtk_tree_view_column_new_with_attributes(_("Bits"), renderer, "text", 1, NULL);
403    gtk_tree_view_append_column(key_list_view, col);
404 
405    col = gtk_tree_view_column_new_with_attributes(_("Key Fingerprint"), renderer, "text", 2, NULL);
406    gtk_tree_view_append_column(key_list_view, col);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18)407 
408    num = 0;
409    for( iter = ring; iter != NULL; iter = iter->next ) {
410       key_ring_data * key_iter = (key_ring_data*)(iter->data);
411 
412       gtk_list_store_append(store, &store_iter);
413 
414       if (key_iter && key_iter->key && key_iter->key->fingerprint) {
415          key_buf = g_string_new_len(key_iter->key->fingerprint,
416                                     KEY_FINGERPRINT_LENGTH);
417          purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Set List Item: name: '%s', acct: %p, num: %d\n",
418                     key_iter->name, key_iter->account, num);
419       } else {
420          key_buf = g_string_new("--error--");
421          purple_debug(PURPLE_DEBUG_WARNING, "pidgin-encryption", "Error Setting List Item %p %p\n",
422                     key_iter->key , key_iter->key->fingerprint);
423       }
424 
425 
426       gtk_list_store_set(store, &store_iter,
427                          0, ((key_ring_data *)iter->data)->name,
428                          1, ((key_ring_data *)iter->data)->key->length,
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19)429                          2, key_buf->str,
430                          3, ((key_ring_data *)iter->data)->key->proto->name,
431                          4, ((key_ring_data *)iter->data)->account,
432                          5, num,
433                          -1);
434       g_string_free(key_buf, TRUE);
435       ++num;
436    }
437 }
438 
439 GtkWidget* PE_create_key_vbox(GtkWidget** key_list_view) {
440    GtkWidget *keybox = gtk_vbox_new(FALSE, 10);
441    GtkWidget *keywin = gtk_scrolled_window_new(0, 0);
442 
443 
444    gtk_widget_show(keybox);
445    gtk_box_pack_start(GTK_BOX(keybox), keywin, 0, 0, 0);
446 
447    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (keywin),
448                                   GTK_POLICY_AUTOMATIC,
449                                   GTK_POLICY_ALWAYS);
450    gtk_widget_set_size_request (keywin, -1, 250);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20)451    gtk_widget_show(keywin);
452 
453    *key_list_view = gtk_tree_view_new();
454 
455    gtk_container_add(GTK_CONTAINER(keywin), *key_list_view);
456    gtk_widget_show(*key_list_view);
457 
458    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(*key_list_view), TRUE);
459 
460    return keybox;
461 }
462 
463 
464 /* Todo:  */
465 /* - Make sure we aren't leaking memory on loose widget references */
466 
467 /* Called when Purple wants us to show our config dialog */
468 
469 GtkWidget* PE_get_config_frame(PurplePlugin *plugin) {
470    GtkWidget *hbox;
471    GtkWidget *keybox;
472    GtkWidget *button;
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21)473    GtkWidget *notebook;
474    GtkWidget *checkbox_vbox;
475 
476    config_vbox = gtk_vbox_new(FALSE, 2);
477 
478    gtk_container_set_border_width (GTK_CONTAINER (config_vbox), 12);
479 
480    gtk_widget_show (config_vbox);
481 
482    g_signal_connect(G_OBJECT(config_vbox), "destroy",
483                     GTK_SIGNAL_FUNC(config_cancel_regen), NULL);
484 
485 
486    notebook = gtk_notebook_new();
487    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
488    gtk_box_pack_start(GTK_BOX(config_vbox), notebook, 0, 0, 0);
489    gtk_widget_show(notebook);
490 
491 
492    /* Notebook page 1:  Config */
493 
494    checkbox_vbox = gtk_vbox_new(FALSE, 2);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22)495    gtk_container_set_border_width(GTK_CONTAINER(checkbox_vbox), 2);
496    gtk_widget_show(checkbox_vbox);
497    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), checkbox_vbox,
498                              gtk_label_new(_("Config")));
499 
500    pidgin_prefs_checkbox(_("Accept key automatically if no key on file"),
501                            "/plugins/gtk/encrypt/accept_unknown_key", checkbox_vbox);
502 
503    pidgin_prefs_checkbox(_("Accept conflicting keys automatically (security risk)"),
504                            "/plugins/gtk/encrypt/accept_conflicting_key", checkbox_vbox);
505 
506    pidgin_prefs_checkbox(_("Automatically encrypt if sent an encrypted message"),
507                            "/plugins/gtk/encrypt/encrypt_response", checkbox_vbox);
508 
509    pidgin_prefs_checkbox(_("Broadcast encryption capability"),
510                            "/plugins/gtk/encrypt/broadcast_notify", checkbox_vbox);
511 
512    pidgin_prefs_checkbox(_("Automatically encrypt if buddy has plugin"),
513                            "/plugins/gtk/encrypt/encrypt_if_notified", checkbox_vbox);
514 
515    pidgin_prefs_checkbox(_("Show lock icon for each line of chat"),
516                            "/plugins/gtk/encrypt/show_inline_icons", checkbox_vbox);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23)517 
518    pidgin_prefs_labeled_entry(checkbox_vbox, _("Keyfile location"), "/plugins/gtk/encrypt/key_path_displayed", 0);
519 
520    /* sometime box with message and button for when keyfile location is wrong */
521    hbox = gtk_hbox_new(FALSE, 2);
522    Invalid_path_label = gtk_label_new("");
523    gtk_box_pack_start(GTK_BOX(hbox), Invalid_path_label, 0, 0, 0);
524 
525    Invalid_path_button = gtk_button_new_with_label(_("Create key files"));
526    g_signal_connect(G_OBJECT(Invalid_path_button), "clicked",
527                     GTK_SIGNAL_FUNC(create_key_files_cb), 0);
528    gtk_box_pack_start(GTK_BOX(hbox), Invalid_path_button, 0, 0, 0);
529 
530    gtk_box_pack_start(GTK_BOX(checkbox_vbox), hbox, 0, 0, 0);
531    gtk_widget_show(hbox);
532 
533    gtk_widget_hide(Invalid_path_button);
534    gtk_widget_set_no_show_all(Invalid_path_button, TRUE);
535 
536    /* Notebook page 2: Local keys */
537 
538    /* if this assert fails, then the "add_weak_pointer" calls below are gonna cause trouble */
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24)539    assert(Local_keylist_view == NULL);
540    keybox = PE_create_key_vbox(&Local_keylist_view);
541    PE_populate_key_list_view(PE_my_priv_ring, TRUE, GTK_TREE_VIEW(Local_keylist_view));
542 
543    hbox = gtk_hbox_new(FALSE, 2);
544    gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
545 
546    gtk_box_pack_start(GTK_BOX(keybox), hbox, 0, 0, 0);
547    gtk_widget_show(hbox);
548 
549    button = gtk_button_new_with_label(_("Delete Key"));
550    g_signal_connect(G_OBJECT(button), "clicked",
551                     GTK_SIGNAL_FUNC(delete_local_key), Local_keylist_view);
552    gtk_box_pack_start(GTK_BOX(hbox), button, 0, 0, 0);
553 
554    gtk_widget_show(button);
555 
556    button = gtk_button_new_with_label(_("Regenerate Key"));
557    g_signal_connect(G_OBJECT(button), "clicked",
558                     GTK_SIGNAL_FUNC(config_regen_key), Local_keylist_view);
559    gtk_box_pack_start(GTK_BOX(hbox), button, 0, 0, 0);
560 
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25)561    gtk_widget_show(button);
562 
563    button = gtk_button_new_with_label(_("Copy Fingerprint to Clipboard"));
564    g_signal_connect(G_OBJECT(button), "clicked",
565                     GTK_SIGNAL_FUNC(copy_fp_to_clipboard), Local_keylist_view);
566    gtk_box_pack_end(GTK_BOX(hbox), button, 0, 0, 0);
567 
568    gtk_widget_show(button);
569 
570 
571    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), keybox, gtk_label_new(_("Local Keys")));
572 
573 
574    /* Notebook page 3: Saved Buddy Keys */
575 
576    keybox = PE_create_key_vbox(&Saved_keylist_view);
577    PE_populate_key_list_view(PE_saved_buddy_ring, FALSE, GTK_TREE_VIEW(Saved_keylist_view));
578 
579    hbox = gtk_hbox_new(FALSE, 2);
580    gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
581    gtk_box_pack_start(GTK_BOX(keybox), hbox, 0, 0, 0);
582    gtk_widget_show(hbox);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25,T26 const & t26)583 
584    button = gtk_button_new_with_label(_("Delete Key"));
585    g_signal_connect(G_OBJECT(button), "clicked",
586                     GTK_SIGNAL_FUNC(delete_buddy_key), Saved_keylist_view);
587    gtk_box_pack_start(GTK_BOX(hbox), button, 0, 0, 0);
588 
589    gtk_widget_show(button);
590 
591    button = gtk_button_new_with_label(_("Copy Fingerprint to Clipboard"));
592    g_signal_connect(G_OBJECT(button), "clicked",
593                     GTK_SIGNAL_FUNC(copy_fp_to_clipboard), Saved_keylist_view);
594    gtk_box_pack_end(GTK_BOX(hbox), button, 0, 0, 0);
595 
596    gtk_widget_show(button);
597 
598    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), keybox,
599                              gtk_label_new(_("Trusted Buddy Keys")));
600 
601 
602    /* Notebook page 4: In-Memory Buddy Keys */
603 
604    keybox = PE_create_key_vbox(&InMem_keylist_view);
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25,T26 const & t26,T27 const & t27)605    PE_populate_key_list_view(PE_buddy_ring, FALSE, GTK_TREE_VIEW(InMem_keylist_view));
606 
607    hbox = gtk_hbox_new(FALSE, 2);
608    gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
609    gtk_box_pack_start(GTK_BOX(keybox), hbox, 0, 0, 0);
610    gtk_widget_show(hbox);
611 
612    button = gtk_button_new_with_label(_("Delete Key"));
613    g_signal_connect(G_OBJECT(button), "clicked",
614                     GTK_SIGNAL_FUNC(delete_buddy_key), InMem_keylist_view);
615    gtk_box_pack_start(GTK_BOX(hbox), button, 0, 0, 0);
616 
617    gtk_widget_show(button);
618 
619    button = gtk_button_new_with_label(_("Copy Fingerprint to Clipboard"));
620    g_signal_connect(G_OBJECT(button), "clicked",
621                     GTK_SIGNAL_FUNC(copy_fp_to_clipboard), InMem_keylist_view);
622    gtk_box_pack_end(GTK_BOX(hbox), button, 0, 0, 0);
623 
624    gtk_widget_show(button);
625 
626    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), keybox,
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25,T26 const & t26,T27 const & t27,T28 const & t28)627                              gtk_label_new(_("Recent Buddy Keys")));
628 
629 
630    /* make it so that when the config_vbox object is finalized, our pointer to it is nulled out */
631    g_object_add_weak_pointer(G_OBJECT(config_vbox), (gpointer*) &config_vbox);
632    g_object_add_weak_pointer(G_OBJECT(Local_keylist_view), (gpointer*) &Local_keylist_view);
633    g_object_add_weak_pointer(G_OBJECT(Saved_keylist_view), (gpointer*) &Saved_keylist_view);
634    g_object_add_weak_pointer(G_OBJECT(InMem_keylist_view), (gpointer*) &InMem_keylist_view);
635 
636    g_object_add_weak_pointer(G_OBJECT(Invalid_path_label), (gpointer*) &Invalid_path_label);
637    g_object_add_weak_pointer(G_OBJECT(Invalid_path_button), (gpointer*) &Invalid_path_button);
638 
639    return config_vbox;
640 }
641 
642 void PE_config_update() {
643    if (!Local_keylist_view) return;
644 
645    PE_populate_key_list_view(PE_my_priv_ring, TRUE, GTK_TREE_VIEW(Local_keylist_view));
646    PE_populate_key_list_view(PE_saved_buddy_ring, FALSE, GTK_TREE_VIEW(Saved_keylist_view));
647    PE_populate_key_list_view(PE_buddy_ring, FALSE, GTK_TREE_VIEW(InMem_keylist_view));
648 
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25,T26 const & t26,T27 const & t27,T28 const & t28,T29 const & t29)649    if (!Invalid_path_label) return;
650    gtk_widget_hide(Invalid_path_label);
651    gtk_widget_hide(Invalid_path_button);
652 }
653 
654 void PE_config_show_invalid_keypath() {
655    if (!Invalid_path_label) return;
656 
657    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Showing invalid keypath\n");
658    gtk_label_set(GTK_LABEL(Invalid_path_label), _("No key files found at path"));
659    gtk_widget_show(Invalid_path_label);
660    gtk_widget_show(Invalid_path_button);
661 }
662 
663 void PE_config_show_nonabsolute_keypath() {
664    if (!Invalid_path_label) return;
665 
666    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "Showing non-absolute keypath\n");
667    gtk_label_set(GTK_LABEL(Invalid_path_label), _("Absolute path required"));
668    gtk_widget_show(Invalid_path_label);
669    gtk_widget_hide(Invalid_path_button);
670 }
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25,T26 const & t26,T27 const & t27,T28 const & t28,T29 const & t29,T30 const & t30)671 
672 static void create_key_files_cb( ) {
673    purple_prefs_trigger_callback("/plugins/gtk/encrypt/key_path_displayed");
674    if (PE_check_base_key_path()) {
675       gtk_widget_hide(Invalid_path_label);
676       gtk_widget_hide(Invalid_path_button);
677    } else {
678       gtk_label_set(GTK_LABEL(Invalid_path_label), _("Unable to create key files"));
679       gtk_widget_hide(Invalid_path_button);
680    }
681 }
682 
683 void PE_config_unload() {
684    purple_debug(PURPLE_DEBUG_INFO, "pidgin-encryption", "PE_config_unload: %p\n", config_vbox);
685    if (config_vbox) {
686       /* We don't want our internal static functions getting called after the plugin   */
687       /* has been unloaded, so disconnect the callback that kills the key regen window */
688       /* For good measure, kill the key regen window too                               */
689 
690       g_signal_handlers_disconnect_by_func(GTK_OBJECT(config_vbox),
691                                            GTK_SIGNAL_FUNC(config_cancel_regen), NULL);
692       config_cancel_regen();
zip(T0 const & t0,T1 const & t1,T2 const & t2,T3 const & t3,T4 const & t4,T5 const & t5,T6 const & t6,T7 const & t7,T8 const & t8,T9 const & t9,T10 const & t10,T11 const & t11,T12 const & t12,T13 const & t13,T14 const & t14,T15 const & t15,T16 const & t16,T17 const & t17,T18 const & t18,T19 const & t19,T20 const & t20,T21 const & t21,T22 const & t22,T23 const & t23,T24 const & t24,T25 const & t25,T26 const & t26,T27 const & t27,T28 const & t28,T29 const & t29,T30 const & t30,T31 const & t31)693       config_vbox = NULL;
694    }
695 }
696