1 /*
2 *
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10 * for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program; if not, see <http://www.gnu.org/licenses/>.
14 *
15 *
16 * Authors:
17 * Michael Zucchi <notzed@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #include "evolution-config.h"
24
25 #include <glib/gi18n.h>
26
27 #include "nss.h"
28 #include "pk11func.h"
29 #include "certdb.h"
30 #include "cert.h"
31
32 #include "e-cert-selector.h"
33
34 #include "e-util/e-util.h"
35 #include "e-util/e-util-private.h"
36
37 /* XXX Hack to disable p11-kit's pkcs11.h header, since
38 * NSS headers supply the same PKCS #11 definitions. */
39 #define PKCS11_H 1
40
41 #define GCR_API_SUBJECT_TO_CHANGE
42 #include "gcr/gcr.h"
43
44 #include "smime/lib/e-cert.h"
45
46 #define E_CERT_SELECTOR_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE \
48 ((obj), E_TYPE_CERT_SELECTOR, ECertSelectorPrivate))
49
50 struct _ECertSelectorPrivate {
51 CERTCertList *certlist;
52
53 GtkWidget *combobox;
54 GcrCertificateWidget *cert_widget;
55 };
56
57 enum {
58 ECS_SELECTED,
59 ECS_LAST_SIGNAL
60 };
61
62 static guint ecs_signals[ECS_LAST_SIGNAL];
63
G_DEFINE_TYPE(ECertSelector,e_cert_selector,GTK_TYPE_DIALOG)64 G_DEFINE_TYPE (ECertSelector, e_cert_selector, GTK_TYPE_DIALOG)
65
66 /* (this is what mozilla shows)
67 * Issued to:
68 * Subject: E=notzed@ximian.com, CN=notzed@ximian.com, O=My Company Ltd, L=Adelaide, ST=SA, C=AU
69 * Serial Number: 03
70 * Valid from 23/10/03 06:35:29 to 22/10/04 06:35:29
71 * Purposes: Sign,Encrypt
72 * Issued by:
73 * Subject: E=notzed@ximian.com, O=company, L=there, ST=Here, C=AU
74 */
75
76 static CERTCertListNode *
77 ecs_find_current (ECertSelector *ecs)
78 {
79 struct _ECertSelectorPrivate *p = ecs->priv;
80 CERTCertListNode *node;
81 gint n;
82
83 if (p->certlist == NULL || CERT_LIST_EMPTY (p->certlist))
84 return NULL;
85
86 n = gtk_combo_box_get_active (GTK_COMBO_BOX (p->combobox));
87 node = CERT_LIST_HEAD (p->certlist);
88 while (n > 0 && !CERT_LIST_END (node, p->certlist)) {
89 n--;
90 node = CERT_LIST_NEXT (node);
91 }
92
93 g_return_val_if_fail (!CERT_LIST_END (node, p->certlist), NULL);
94
95 return node;
96 }
97
98 static void
e_cert_selector_response(GtkDialog * dialog,gint button)99 e_cert_selector_response (GtkDialog *dialog,
100 gint button)
101 {
102 CERTCertListNode *node;
103
104 switch (button) {
105 case GTK_RESPONSE_OK:
106 node = ecs_find_current ((ECertSelector *) dialog);
107 break;
108 default:
109 node = NULL;
110 break;
111 }
112
113 g_signal_emit (dialog, ecs_signals[ECS_SELECTED], 0, node ? node->cert->nickname : NULL);
114 }
115
116 static void
ecs_cert_changed(GtkWidget * w,ECertSelector * ecs)117 ecs_cert_changed (GtkWidget *w,
118 ECertSelector *ecs)
119 {
120 struct _ECertSelectorPrivate *p = ecs->priv;
121 CERTCertListNode *node;
122
123 node = ecs_find_current (ecs);
124 if (node) {
125 ECert *ecert = e_cert_new (CERT_DupCertificate ((CERTCertificate *) node->cert));
126 gcr_certificate_widget_set_certificate (p->cert_widget, GCR_CERTIFICATE (ecert));
127 g_object_unref (ecert);
128 }
129 }
130
131 /**
132 * e_cert_selector_new:
133 * @type:
134 * @currentid:
135 *
136 * Create a new ECertSelector dialog. @type specifies which type of cert to
137 * be selected, E_CERT_SELECTOR_SIGNER for signing certs, and
138 * E_CERT_SELECTOR_RECIPIENT for encrypting certs.
139 *
140 * @currentid is the nickname of the cert currently selected for this user.
141 *
142 * You only need to connect to a single signal "selected" which will
143 * be called with either a NULL nickname if cancelled, or the newly
144 * selected nickname otherwise.
145 *
146 * Return value: A dialogue to be shown.
147 **/
148 GtkWidget *
e_cert_selector_new(gint type,const gchar * currentid)149 e_cert_selector_new (gint type,
150 const gchar *currentid)
151 {
152 ECertSelector *ecs;
153 struct _ECertSelectorPrivate *p;
154 SECCertUsage usage;
155 CERTCertList *certlist;
156 CERTCertListNode *node;
157 GtkBuilder *builder;
158 GtkWidget *content_area;
159 GtkWidget *w;
160 GtkListStore *store;
161 GtkTreeIter iter;
162 gint n = 0, active = 0;
163
164 ecs = g_object_new (e_cert_selector_get_type (), NULL);
165 p = ecs->priv;
166
167 builder = gtk_builder_new ();
168 e_load_ui_builder_definition (builder, "smime-ui.ui");
169
170 p->combobox = e_builder_get_widget (builder, "cert_combobox");
171 p->cert_widget = gcr_certificate_widget_new (NULL);
172
173 w = e_builder_get_widget (builder, "cert_selector_vbox");
174 content_area = gtk_dialog_get_content_area (GTK_DIALOG (ecs));
175 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (p->cert_widget));
176 gtk_widget_show (GTK_WIDGET (p->cert_widget));
177 gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 3);
178 gtk_window_set_title (GTK_WINDOW (ecs), _("Select certificate"));
179
180 switch (type) {
181 case E_CERT_SELECTOR_SIGNER:
182 default:
183 usage = certUsageEmailSigner;
184 break;
185 case E_CERT_SELECTOR_RECIPIENT:
186 usage = certUsageEmailRecipient;
187 break;
188 }
189
190 store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (p->combobox)));
191 gtk_list_store_clear (store);
192
193 certlist = CERT_FindUserCertsByUsage (CERT_GetDefaultCertDB (), usage, FALSE, TRUE, NULL);
194 ecs->priv->certlist = certlist;
195 if (certlist != NULL) {
196 node = CERT_LIST_HEAD (certlist);
197 while (!CERT_LIST_END (node, certlist)) {
198 if (node->cert->nickname || node->cert->emailAddr) {
199 gtk_list_store_append (store, &iter);
200 gtk_list_store_set (
201 store, &iter,
202 0, node->cert->nickname ? node->cert->nickname : node->cert->emailAddr,
203 -1);
204
205 if (currentid != NULL
206 && ((node->cert->nickname != NULL && strcmp (node->cert->nickname, currentid) == 0)
207 || (node->cert->emailAddr != NULL && strcmp (node->cert->emailAddr, currentid) == 0)))
208 active = n;
209
210 n++;
211 }
212
213 node = CERT_LIST_NEXT (node);
214 }
215 }
216
217 gtk_combo_box_set_active (GTK_COMBO_BOX (p->combobox), active);
218
219 g_signal_connect (
220 p->combobox, "changed",
221 G_CALLBACK (ecs_cert_changed), ecs);
222
223 g_object_unref (builder);
224
225 ecs_cert_changed (p->combobox, ecs);
226
227 return GTK_WIDGET (ecs);
228 }
229
230 static void
e_cert_selector_init(ECertSelector * ecs)231 e_cert_selector_init (ECertSelector *ecs)
232 {
233 gtk_dialog_add_buttons (
234 GTK_DIALOG (ecs),
235 _("_Cancel"), GTK_RESPONSE_CANCEL,
236 _("_OK"), GTK_RESPONSE_OK, NULL);
237
238 ecs->priv = E_CERT_SELECTOR_GET_PRIVATE (ecs);
239 }
240
241 static void
e_cert_selector_finalize(GObject * object)242 e_cert_selector_finalize (GObject *object)
243 {
244 ECertSelectorPrivate *priv;
245
246 priv = E_CERT_SELECTOR_GET_PRIVATE (object);
247
248 if (priv->certlist)
249 CERT_DestroyCertList (priv->certlist);
250
251 /* Chain up to parent's finalize() method. */
252 G_OBJECT_CLASS (e_cert_selector_parent_class)->finalize (object);
253 }
254
255 static void
e_cert_selector_class_init(ECertSelectorClass * class)256 e_cert_selector_class_init (ECertSelectorClass *class)
257 {
258 GObjectClass *object_class;
259 GtkDialogClass *dialog_class;
260
261 g_type_class_add_private (class, sizeof (ECertSelectorPrivate));
262
263 object_class = G_OBJECT_CLASS (class);
264 object_class->finalize = e_cert_selector_finalize;
265
266 dialog_class = GTK_DIALOG_CLASS (class);
267 dialog_class->response = e_cert_selector_response;
268
269 ecs_signals[ECS_SELECTED] = g_signal_new (
270 "selected",
271 G_OBJECT_CLASS_TYPE (class),
272 G_SIGNAL_RUN_LAST,
273 G_STRUCT_OFFSET (ECertSelectorClass, selected),
274 NULL, NULL,
275 g_cclosure_marshal_VOID__POINTER,
276 G_TYPE_NONE, 1,
277 G_TYPE_POINTER);
278 }
279
280