Implemented Smartcard support in NetworkManager frontend
[strongswan.git] / src / libcharon / plugins / nm / gnome / properties / nm-strongswan.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2005 David Zeuthen
5 * Copyright (C) 2005-2008 Dan Williams
6 *
7 * Based on NetworkManager's vpnc plugin
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <glib.h>
25 #include <glib/gi18n-lib.h>
26 #include <gtk/gtk.h>
27 #include <glade/glade.h>
28
29 #define NM_VPN_API_SUBJECT_TO_CHANGE
30
31 #include <nm-vpn-plugin-ui-interface.h>
32 #include <nm-setting-vpn.h>
33 #include <nm-setting-connection.h>
34 #include <nm-setting-ip4-config.h>
35
36 #include "nm-strongswan.h"
37
38 #define STRONGSWAN_PLUGIN_NAME _("IPsec/IKEv2 (strongswan)")
39 #define STRONGSWAN_PLUGIN_DESC _("IPsec with the IKEv2 key exchange protocol.")
40 #define STRONGSWAN_PLUGIN_SERVICE "org.freedesktop.NetworkManager.strongswan"
41 #define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan"
42
43 /************** plugin class **************/
44
45 static void strongswan_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class);
46
47 G_DEFINE_TYPE_EXTENDED (StrongswanPluginUi, strongswan_plugin_ui, G_TYPE_OBJECT, 0,
48 G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_INTERFACE,
49 strongswan_plugin_ui_interface_init))
50
51 /************** UI widget class **************/
52
53 static void strongswan_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class);
54
55 G_DEFINE_TYPE_EXTENDED (StrongswanPluginUiWidget, strongswan_plugin_ui_widget, G_TYPE_OBJECT, 0,
56 G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_WIDGET_INTERFACE,
57 strongswan_plugin_ui_widget_interface_init))
58
59 #define STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), STRONGSWAN_TYPE_PLUGIN_UI_WIDGET, StrongswanPluginUiWidgetPrivate))
60
61 typedef struct {
62 GladeXML *xml;
63 GtkWidget *widget;
64 } StrongswanPluginUiWidgetPrivate;
65
66
67 #define STRONGSWAN_PLUGIN_UI_ERROR strongswan_plugin_ui_error_quark ()
68
69 static GQuark
70 strongswan_plugin_ui_error_quark (void)
71 {
72 static GQuark error_quark = 0;
73
74 if (G_UNLIKELY (error_quark == 0))
75 error_quark = g_quark_from_static_string ("strongswan-plugin-ui-error-quark");
76
77 return error_quark;
78 }
79
80 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
81
82 GType
83 strongswan_plugin_ui_error_get_type (void)
84 {
85 static GType etype = 0;
86
87 if (etype == 0) {
88 static const GEnumValue values[] = {
89 /* Unknown error. */
90 ENUM_ENTRY (STRONGSWAN_PLUGIN_UI_ERROR_UNKNOWN, "UnknownError"),
91 /* The specified property was invalid. */
92 ENUM_ENTRY (STRONGSWAN_PLUGIN_UI_ERROR_INVALID_PROPERTY, "InvalidProperty"),
93 /* The specified property was missing and is required. */
94 ENUM_ENTRY (STRONGSWAN_PLUGIN_UI_ERROR_MISSING_PROPERTY, "MissingProperty"),
95 { 0, 0, 0 }
96 };
97 etype = g_enum_register_static ("StrongswanPluginUiError", values);
98 }
99 return etype;
100 }
101
102 static gboolean
103 check_validity (StrongswanPluginUiWidget *self, GError **error)
104 {
105 StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
106 GtkWidget *widget;
107 char *str;
108
109 widget = glade_xml_get_widget (priv->xml, "address-entry");
110 str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
111 if (!str || !strlen (str)) {
112 g_set_error (error,
113 STRONGSWAN_PLUGIN_UI_ERROR,
114 STRONGSWAN_PLUGIN_UI_ERROR_INVALID_PROPERTY,
115 "address");
116 return FALSE;
117 }
118 return TRUE;
119 }
120
121 static void update_layout (GtkWidget *widget, StrongswanPluginUiWidgetPrivate *priv)
122 {
123 switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)))
124 {
125 default:
126 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
127 /* FALL */
128 case 0:
129 gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-label"));
130 gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-button"));
131 gtk_widget_show (glade_xml_get_widget (priv->xml, "userkey-label"));
132 gtk_widget_show (glade_xml_get_widget (priv->xml, "userkey-button"));
133 gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label"));
134 gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry"));
135 break;
136 case 1:
137 gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-label"));
138 gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-button"));
139 gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label"));
140 gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry"));
141 gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-label"));
142 gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-button"));
143 break;
144 case 2:
145 gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label"));
146 gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button"));
147 gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label"));
148 gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry"));
149 gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-label"));
150 gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-button"));
151 break;
152 case 3:
153 gtk_widget_show (glade_xml_get_widget (priv->xml, "user-label"));
154 gtk_widget_show (glade_xml_get_widget (priv->xml, "user-entry"));
155 gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label"));
156 gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button"));
157 gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-label"));
158 gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-button"));
159 break;
160 }
161
162 }
163
164 static void
165 settings_changed_cb (GtkWidget *widget, gpointer user_data)
166 {
167 StrongswanPluginUiWidget *self = STRONGSWAN_PLUGIN_UI_WIDGET (user_data);
168 StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
169
170 if (widget == glade_xml_get_widget (priv->xml, "method-combo"))
171 {
172 update_layout(glade_xml_get_widget (priv->xml, "method-combo"), priv);
173 }
174 g_signal_emit_by_name (STRONGSWAN_PLUGIN_UI_WIDGET (user_data), "changed");
175 }
176
177 static gboolean
178 init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError **error)
179 {
180 StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
181 NMSettingVPN *settings;
182 GtkWidget *widget;
183 const char *value;
184
185 settings = NM_SETTING_VPN(nm_connection_get_setting(connection, NM_TYPE_SETTING_VPN));
186 widget = glade_xml_get_widget (priv->xml, "address-entry");
187 value = nm_setting_vpn_get_data_item (settings, "address");
188 if (value)
189 gtk_entry_set_text (GTK_ENTRY (widget), value);
190 g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self);
191
192 widget = glade_xml_get_widget (priv->xml, "certificate-button");
193 value = nm_setting_vpn_get_data_item (settings, "certificate");
194 if (value)
195 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
196 g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self);
197
198 widget = glade_xml_get_widget (priv->xml, "user-label");
199 gtk_widget_set_no_show_all (widget, TRUE);
200 widget = glade_xml_get_widget (priv->xml, "user-entry");
201 gtk_widget_set_no_show_all (widget, TRUE);
202 value = nm_setting_vpn_get_data_item (settings, "user");
203 if (value)
204 gtk_entry_set_text (GTK_ENTRY (widget), value);
205 g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self);
206
207 widget = glade_xml_get_widget (priv->xml, "method-combo");
208 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Certificate/private key"));
209 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Certificate/ssh-agent"));
210 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Smartcard"));
211 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("EAP"));
212 value = nm_setting_vpn_get_data_item (settings, "method");
213 if (value) {
214 if (g_strcmp0 (value, "key") == 0) {
215 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
216 }
217 if (g_strcmp0 (value, "agent") == 0) {
218 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
219 }
220 if (g_strcmp0 (value, "smartcard") == 0) {
221 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
222 }
223 if (g_strcmp0 (value, "eap") == 0) {
224 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 3);
225 }
226 }
227 if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1)
228 {
229 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
230 }
231 update_layout (widget, priv);
232 g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self);
233
234 widget = glade_xml_get_widget (priv->xml, "usercert-label");
235 gtk_widget_set_no_show_all (widget, TRUE);
236 widget = glade_xml_get_widget (priv->xml, "usercert-button");
237 gtk_widget_set_no_show_all (widget, TRUE);
238 value = nm_setting_vpn_get_data_item (settings, "usercert");
239 if (value)
240 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
241 g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self);
242
243 widget = glade_xml_get_widget (priv->xml, "userkey-label");
244 gtk_widget_set_no_show_all (widget, TRUE);
245 widget = glade_xml_get_widget (priv->xml, "userkey-button");
246 gtk_widget_set_no_show_all (widget, TRUE);
247 value = nm_setting_vpn_get_data_item (settings, "userkey");
248 if (value)
249 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
250 g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self);
251
252 widget = glade_xml_get_widget (priv->xml, "virtual-check");
253 value = nm_setting_vpn_get_data_item (settings, "virtual");
254 if (value && strcmp(value, "yes") == 0)
255 {
256 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
257 }
258 g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (settings_changed_cb), self);
259
260 widget = glade_xml_get_widget (priv->xml, "encap-check");
261 value = nm_setting_vpn_get_data_item (settings, "encap");
262 if (value && strcmp(value, "yes") == 0)
263 {
264 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
265 }
266 g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (settings_changed_cb), self);
267
268 widget = glade_xml_get_widget (priv->xml, "ipcomp-check");
269 value = nm_setting_vpn_get_data_item (settings, "ipcomp");
270 if (value && strcmp(value, "yes") == 0)
271 {
272 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
273 }
274 g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (settings_changed_cb), self);
275
276 return TRUE;
277 }
278
279 static GObject *
280 get_widget (NMVpnPluginUiWidgetInterface *iface)
281 {
282 StrongswanPluginUiWidget *self = STRONGSWAN_PLUGIN_UI_WIDGET (iface);
283 StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
284
285 return G_OBJECT (priv->widget);
286 }
287
288 static gboolean
289 update_connection (NMVpnPluginUiWidgetInterface *iface,
290 NMConnection *connection,
291 GError **error)
292 {
293 StrongswanPluginUiWidget *self = STRONGSWAN_PLUGIN_UI_WIDGET (iface);
294 StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
295 NMSettingVPN *settings;
296 GtkWidget *widget;
297 gboolean active;
298 char *str;
299
300 if (!check_validity (self, error))
301 return FALSE;
302 settings = NM_SETTING_VPN (nm_setting_vpn_new ());
303
304 g_object_set (settings, NM_SETTING_VPN_SERVICE_TYPE,
305 NM_DBUS_SERVICE_STRONGSWAN, NULL);
306
307 widget = glade_xml_get_widget (priv->xml, "address-entry");
308 str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
309 if (str && strlen (str)) {
310 nm_setting_vpn_add_data_item (settings, "address", str);
311 }
312
313 widget = glade_xml_get_widget (priv->xml, "certificate-button");
314 str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
315 if (str) {
316 nm_setting_vpn_add_data_item (settings, "certificate", str);
317 }
318
319 widget = glade_xml_get_widget (priv->xml, "method-combo");
320 switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)))
321 {
322 default:
323 case 0:
324 widget = glade_xml_get_widget (priv->xml, "userkey-button");
325 str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
326 if (str) {
327 nm_setting_vpn_add_data_item (settings, "userkey", str);
328 }
329 widget = glade_xml_get_widget (priv->xml, "usercert-button");
330 str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
331 if (str) {
332 nm_setting_vpn_add_data_item (settings, "usercert", str);
333 }
334 str = "key";
335 break;
336 case 1:
337 widget = glade_xml_get_widget (priv->xml, "usercert-button");
338 str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
339 if (str) {
340 nm_setting_vpn_add_data_item (settings, "usercert", str);
341 }
342 str = "agent";
343 break;
344 case 2:
345 str = "smartcard";
346 break;
347 case 3:
348 widget = glade_xml_get_widget (priv->xml, "user-entry");
349 str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
350 if (str && strlen (str)) {
351 nm_setting_vpn_add_data_item (settings, "user", str);
352 }
353 str = "eap";
354 break;
355 }
356 nm_setting_vpn_add_data_item (settings, "method", str);
357
358 widget = glade_xml_get_widget (priv->xml, "virtual-check");
359 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
360 nm_setting_vpn_add_data_item (settings, "virtual", active ? "yes" : "no");
361
362 widget = glade_xml_get_widget (priv->xml, "encap-check");
363 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
364 nm_setting_vpn_add_data_item (settings, "encap", active ? "yes" : "no");
365
366 widget = glade_xml_get_widget (priv->xml, "ipcomp-check");
367 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
368 nm_setting_vpn_add_data_item (settings, "ipcomp", active ? "yes" : "no");
369
370 nm_connection_add_setting (connection, NM_SETTING (settings));
371 return TRUE;
372 }
373
374 static gboolean
375 save_secrets (NMVpnPluginUiWidgetInterface *iface,
376 NMConnection *connection, GError **error)
377 {
378 /* no secrets to save */
379 return TRUE;
380 }
381
382 static NMVpnPluginUiWidgetInterface *
383 nm_vpn_plugin_ui_widget_interface_new (NMConnection *connection, GError **error)
384 {
385 NMVpnPluginUiWidgetInterface *object;
386 StrongswanPluginUiWidgetPrivate *priv;
387 char *glade_file;
388
389 if (error)
390 g_return_val_if_fail (*error == NULL, NULL);
391
392 object = NM_VPN_PLUGIN_UI_WIDGET_INTERFACE (g_object_new (STRONGSWAN_TYPE_PLUGIN_UI_WIDGET, NULL));
393 if (!object) {
394 g_set_error (error, STRONGSWAN_PLUGIN_UI_ERROR, 0, "could not create strongswan object");
395 return NULL;
396 }
397
398 priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (object);
399
400 glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-strongswan-dialog.glade");
401 priv->xml = glade_xml_new (glade_file, "strongswan-vbox", GETTEXT_PACKAGE);
402 if (priv->xml == NULL) {
403 g_set_error (error, STRONGSWAN_PLUGIN_UI_ERROR, 0,
404 "could not load required resources at %s", glade_file);
405 g_free (glade_file);
406 g_object_unref (object);
407 return NULL;
408 }
409 g_free (glade_file);
410
411 priv->widget = glade_xml_get_widget (priv->xml, "strongswan-vbox");
412 if (!priv->widget) {
413 g_set_error (error, STRONGSWAN_PLUGIN_UI_ERROR, 0, "could not load UI widget");
414 g_object_unref (object);
415 return NULL;
416 }
417 g_object_ref_sink (priv->widget);
418
419 if (!init_plugin_ui (STRONGSWAN_PLUGIN_UI_WIDGET (object), connection, error)) {
420 g_object_unref (object);
421 return NULL;
422 }
423
424 return object;
425 }
426
427 static void
428 dispose (GObject *object)
429 {
430 StrongswanPluginUiWidget *plugin = STRONGSWAN_PLUGIN_UI_WIDGET (object);
431 StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (plugin);
432
433 if (priv->widget)
434 g_object_unref (priv->widget);
435
436 if (priv->xml)
437 g_object_unref (priv->xml);
438
439 G_OBJECT_CLASS (strongswan_plugin_ui_widget_parent_class)->dispose (object);
440 }
441
442 static void
443 strongswan_plugin_ui_widget_class_init (StrongswanPluginUiWidgetClass *req_class)
444 {
445 GObjectClass *object_class = G_OBJECT_CLASS (req_class);
446
447 g_type_class_add_private (req_class, sizeof (StrongswanPluginUiWidgetPrivate));
448
449 object_class->dispose = dispose;
450 }
451
452 static void
453 strongswan_plugin_ui_widget_init (StrongswanPluginUiWidget *plugin)
454 {
455 }
456
457 static void
458 strongswan_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class)
459 {
460 /* interface implementation */
461 iface_class->get_widget = get_widget;
462 iface_class->update_connection = update_connection;
463 iface_class->save_secrets = save_secrets;
464 }
465
466 static guint32
467 get_capabilities (NMVpnPluginUiInterface *iface)
468 {
469 return 0;
470 }
471
472 static NMVpnPluginUiWidgetInterface *
473 ui_factory (NMVpnPluginUiInterface *iface, NMConnection *connection, GError **error)
474 {
475 return nm_vpn_plugin_ui_widget_interface_new (connection, error);
476 }
477
478 static void
479 get_property (GObject *object, guint prop_id,
480 GValue *value, GParamSpec *pspec)
481 {
482 switch (prop_id) {
483 case NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME:
484 g_value_set_string (value, STRONGSWAN_PLUGIN_NAME);
485 break;
486 case NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC:
487 g_value_set_string (value, STRONGSWAN_PLUGIN_DESC);
488 break;
489 case NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE:
490 g_value_set_string (value, STRONGSWAN_PLUGIN_SERVICE);
491 break;
492 default:
493 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
494 break;
495 }
496 }
497
498 static void
499 strongswan_plugin_ui_class_init (StrongswanPluginUiClass *req_class)
500 {
501 GObjectClass *object_class = G_OBJECT_CLASS (req_class);
502
503 object_class->get_property = get_property;
504
505 g_object_class_override_property (object_class,
506 NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME,
507 NM_VPN_PLUGIN_UI_INTERFACE_NAME);
508
509 g_object_class_override_property (object_class,
510 NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC,
511 NM_VPN_PLUGIN_UI_INTERFACE_DESC);
512
513 g_object_class_override_property (object_class,
514 NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE,
515 NM_VPN_PLUGIN_UI_INTERFACE_SERVICE);
516 }
517
518 static void
519 strongswan_plugin_ui_init (StrongswanPluginUi *plugin)
520 {
521 }
522
523 static void
524 strongswan_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class)
525 {
526 /* interface implementation */
527 iface_class->ui_factory = ui_factory;
528 iface_class->get_capabilities = get_capabilities;
529 /* TODO: implement delete_connection to purge associated secrets */
530 }
531
532
533 G_MODULE_EXPORT NMVpnPluginUiInterface *
534 nm_vpn_plugin_ui_factory (GError **error)
535 {
536 if (error)
537 g_return_val_if_fail (*error == NULL, NULL);
538
539 return NM_VPN_PLUGIN_UI_INTERFACE (g_object_new (STRONGSWAN_TYPE_PLUGIN_UI, NULL));
540 }
541