File nm-certificate-formats.patch of Package NetworkManager

From 7ae5c9af1dde0845271b76adeb4c383aa3c49359 Mon Sep 17 00:00:00 2001
From: Tambet Ingo <tambet@gmail.com>
Date: Wed, 3 Dec 2008 12:11:09 +0200
Subject: [PATCH] nm-certificate-formats


diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c
index 062cb7a..cf11e2a 100644
--- a/libnm-util/nm-setting-8021x.c
+++ b/libnm-util/nm-setting-8021x.c
@@ -717,6 +717,9 @@ need_private_key_password (GByteArray *key, const char *password)
 	GError *error = NULL;
 	gboolean needed = TRUE;
 
+	if (key && key->data && g_str_has_prefix ((char *) key->data, NM_SETTING_802_1X_CK_FORMAT_FILE))
+		return FALSE;
+
 	/* See if a private key password is needed, which basically is whether
 	 * or not the private key is a PKCS#12 file or not, since PKCS#1 files
 	 * are decrypted by the settings service.
@@ -1384,7 +1387,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 							   "CA certificate",
 							   "CA certificate",
 							   DBUS_TYPE_G_UCHAR_ARRAY,
-							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
 
 	g_object_class_install_property
 		(object_class, PROP_CA_PATH,
@@ -1400,7 +1403,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 							   "Client certificate",
 							   "Client certificate",
 							   DBUS_TYPE_G_UCHAR_ARRAY,
-							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
 
 	g_object_class_install_property
 		(object_class, PROP_PHASE1_PEAPVER,
@@ -1448,7 +1451,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 							   "Phase2 CA certificate",
 							   "Phase2 CA certificate",
 							   DBUS_TYPE_G_UCHAR_ARRAY,
-							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
 
 	g_object_class_install_property
 		(object_class, PROP_PHASE2_CA_PATH,
@@ -1464,7 +1467,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 							   "Phase2 client certificate",
 							   "Phase2 client certificate",
 							   DBUS_TYPE_G_UCHAR_ARRAY,
-							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
 
 	g_object_class_install_property
 		(object_class, PROP_PASSWORD,
@@ -1480,7 +1483,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 							   "Private key",
 							   "Private key",
 							   DBUS_TYPE_G_UCHAR_ARRAY,
-							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_CERTIFICATE));
 
 	g_object_class_install_property
 		(object_class, PROP_PRIVATE_KEY_PASSWORD,
@@ -1496,7 +1499,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 							   "Phase2 private key",
 							   "Phase2 private key",
 							   DBUS_TYPE_G_UCHAR_ARRAY,
-							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_CERTIFICATE));
 
 	g_object_class_install_property
 		(object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD,
diff --git a/libnm-util/nm-setting-8021x.h b/libnm-util/nm-setting-8021x.h
index e956e68..d170e4e 100644
--- a/libnm-util/nm-setting-8021x.h
+++ b/libnm-util/nm-setting-8021x.h
@@ -83,6 +83,9 @@ GQuark nm_setting_802_1x_error_quark (void);
 #define NM_SETTING_802_1X_PSK "psk"
 #define NM_SETTING_802_1X_SYSTEM_CA_CERTS "system-ca-certs"
 
+#define NM_SETTING_802_1X_CK_FORMAT_ID   "id:"
+#define NM_SETTING_802_1X_CK_FORMAT_FILE "file:"
+
 typedef struct {
 	NMSetting parent;
 } NMSetting8021x;
diff --git a/libnm-util/nm-setting.h b/libnm-util/nm-setting.h
index 474d3f6..84a9140 100644
--- a/libnm-util/nm-setting.h
+++ b/libnm-util/nm-setting.h
@@ -81,6 +81,8 @@ GQuark nm_setting_error_quark (void);
  */
 #define NM_SETTING_PARAM_FUZZY_IGNORE (1 << (3 + G_PARAM_USER_SHIFT))
 
+#define NM_SETTING_PARAM_CERTIFICATE  (1 << (4 + G_PARAM_USER_SHIFT))
+
 #define NM_SETTING_NAME "name"
 
 /**
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 2918504..da90f00 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -558,6 +558,174 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 	return TRUE;
 }
 
+static gboolean
+add_certificates (NMSupplicantConfig *self, NMSetting8021x *setting, const char *connection_uid)
+{
+	const GByteArray *array;
+	const char *str;
+	char *value;
+	gboolean use_system_ca;
+	gboolean send_private_key_passwd;
+	gboolean send_client_cert;
+	gboolean success;
+
+	use_system_ca = nm_setting_802_1x_get_system_ca_certs (setting) || nm_setting_802_1x_get_ca_cert (setting) == NULL;
+
+	if (use_system_ca) {
+		ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path", FALSE, FALSE, FALSE);
+	} else {
+		array = nm_setting_802_1x_get_ca_cert (setting);
+		if (array && array->data) {
+			str = (char *) array->data;
+
+			if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID))
+				nm_supplicant_config_add_option (self, "ca_cert_id",
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+												 -1, FALSE);
+			else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE))
+				nm_supplicant_config_add_option (self, "ca_cert",
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+												 -1, FALSE);
+			else {
+				ADD_BLOB_VAL (array, "ca_cert", connection_uid);
+			}
+		}
+	}
+
+	array = nm_setting_802_1x_get_private_key (setting);
+	if (array && array->data) {
+		str = (char *) array->data;
+
+		if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+			nm_supplicant_config_add_option (self, "key_id",
+											 str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+											 -1, FALSE);
+
+			send_private_key_passwd = FALSE;
+			send_client_cert = TRUE;
+		} else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+			nm_supplicant_config_add_option (self, "private_key",
+											 str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+											 -1, FALSE);
+
+			send_private_key_passwd = TRUE;
+			send_client_cert = TRUE;
+		} else {
+			ADD_BLOB_VAL (array, "private_key", connection_uid);
+
+			if (nm_setting_802_1x_get_private_key_type (setting) == NM_SETTING_802_1X_CK_TYPE_PKCS12) {
+				send_private_key_passwd = TRUE;
+				send_client_cert = FALSE;
+			} else {
+				send_private_key_passwd = FALSE;
+				send_client_cert = TRUE;
+			}
+		}
+	}
+
+	if (send_private_key_passwd) {
+		ADD_STRING_VAL (nm_setting_802_1x_get_private_key_password (setting),
+						"private_key_passwd", FALSE, FALSE, TRUE);
+	} 
+
+	if (send_client_cert) {
+		array = nm_setting_802_1x_get_client_cert (setting);
+		if (array && array->data) {
+			str = (char *) array->data;
+
+			if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID))
+				nm_supplicant_config_add_option (self, "cert_id", 
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+												 -1, FALSE);
+			else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE))
+				nm_supplicant_config_add_option (self, "client_cert",
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+												 -1, FALSE);
+			else {
+				ADD_BLOB_VAL (array, "client_cert", connection_uid);
+			}
+		}
+	}
+
+	/* phase 2 */
+
+	if (!use_system_ca) {
+		array = nm_setting_802_1x_get_phase2_ca_cert (setting);
+		if (array && array->data) {
+			str = (char *) array->data;
+
+			if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+				nm_supplicant_config_add_option (self, "ca_cert2_id",
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+												 -1, FALSE);
+			} else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+				nm_supplicant_config_add_option (self, "ca_cert2",
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+												 -1, FALSE);
+			} else {
+				ADD_BLOB_VAL (array, "ca_cert", connection_uid);
+			}
+		}
+	}
+
+	array = nm_setting_802_1x_get_phase2_private_key (setting);
+	if (array && array->data) {
+		str = (char *) array->data;
+
+		if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+			nm_supplicant_config_add_option (self, "key2_id",
+											 str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+											 -1, FALSE);
+
+			send_private_key_passwd = FALSE;
+			send_client_cert = TRUE;
+		} else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+			nm_supplicant_config_add_option (self, "private_key2",
+											 str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+											 -1, FALSE);
+
+			send_private_key_passwd = TRUE;
+			send_client_cert = TRUE;
+		} else {
+			ADD_BLOB_VAL (array, "private_key2", connection_uid);
+
+			if (nm_setting_802_1x_get_phase2_private_key_type (setting) == NM_SETTING_802_1X_CK_TYPE_PKCS12) {
+				send_private_key_passwd = TRUE;
+				send_client_cert = FALSE;
+			} else {
+				send_private_key_passwd = FALSE;
+				send_client_cert = TRUE;
+			}
+		}
+	}
+
+	if (send_private_key_passwd) {
+		ADD_STRING_VAL (nm_setting_802_1x_get_phase2_private_key_password (setting),
+						"private_key2_passwd", FALSE, FALSE, TRUE);
+	} 
+
+	if (send_client_cert) {
+		array = nm_setting_802_1x_get_phase2_client_cert (setting);
+		if (array && array->data) {
+			str = (char *) array->data;
+
+			if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+				nm_supplicant_config_add_option (self, "cert2_id", 
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+												 -1, FALSE);
+			} else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+				nm_supplicant_config_add_option (self, "client_cert2",
+												 str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+												 -1, FALSE);
+			} else {
+				ADD_BLOB_VAL (array, "client_cert2", connection_uid);
+			}
+		}
+	}
+
+	return TRUE;
+}
+
 gboolean
 nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                         NMSetting8021x *setting,
@@ -568,7 +736,6 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	char *value, *tmp;
 	gboolean success;
 	GString *phase1, *phase2;
-	const GByteArray *array;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
@@ -624,53 +791,11 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		ADD_STRING_VAL (phase2->str, "phase2", FALSE, FALSE, FALSE);
 	g_string_free (phase2, TRUE);
 
-	if (nm_setting_802_1x_get_system_ca_certs (setting)) {
-		ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path", FALSE, FALSE, FALSE);
-	} else {
-		ADD_BLOB_VAL (nm_setting_802_1x_get_ca_cert (setting), "ca_cert", connection_uid);
-	}
-
-	array = nm_setting_802_1x_get_private_key (setting);
-	if (array) {
-		ADD_BLOB_VAL (array, "private_key", connection_uid);
-
-		switch (nm_setting_802_1x_get_private_key_type (setting)) {
-		case NM_SETTING_802_1X_CK_TYPE_PKCS12:
-			/* Only add the private key password for PKCS#12 keys */
-			ADD_STRING_VAL (nm_setting_802_1x_get_private_key_password (setting), "private_key_passwd", FALSE, FALSE, TRUE);
-			break;
-		default:
-			/* Only add the client cert if the private key is not PKCS#12 */
-			ADD_BLOB_VAL (nm_setting_802_1x_get_client_cert (setting), "client_cert", connection_uid);
-			break;
-		}
-	}
-
-	if (nm_setting_802_1x_get_system_ca_certs (setting)) {
-		ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path2", FALSE, FALSE, FALSE);
-	} else {
-		ADD_BLOB_VAL (nm_setting_802_1x_get_phase2_ca_cert (setting), "ca_cert2", connection_uid);
-	}
-
-	array = nm_setting_802_1x_get_phase2_private_key (setting);
-	if (array) {
-		ADD_BLOB_VAL (array, "private_key2", connection_uid);
-
-		switch (nm_setting_802_1x_get_phase2_private_key_type (setting)) {
-		case NM_SETTING_802_1X_CK_TYPE_PKCS12:
-			/* Only add the private key password for PKCS#12 keys */
-			ADD_STRING_VAL (nm_setting_802_1x_get_phase2_private_key_password (setting), "private_key2_passwd", FALSE, FALSE, TRUE);
-			break;
-		default:
-			/* Only add the client cert if the private key is not PKCS#12 */
-			ADD_BLOB_VAL (nm_setting_802_1x_get_phase2_client_cert (setting), "client_cert2", connection_uid);
-			break;
-		}
-	}
-
 	ADD_STRING_VAL (nm_setting_802_1x_get_identity (setting), "identity", FALSE, FALSE, FALSE);
 	ADD_STRING_VAL (nm_setting_802_1x_get_anonymous_identity (setting), "anonymous_identity", FALSE, FALSE, FALSE);
 
+	add_certificates (self, setting, connection_uid);
+
 	return TRUE;
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c
index 5e30795..2c70d22 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.c
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.c
@@ -103,16 +103,22 @@ static const struct Opt opt_table[] = {
 	{ "password",           TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "ca_path",            TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "ca_cert",            TYPE_BYTES,   0, 65536, FALSE,  NULL },
+	{ "ca_cert_id",         TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "client_cert",        TYPE_BYTES,   0, 65536, FALSE,  NULL },
+	{ "cert_id",            TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "private_key",        TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "private_key_passwd", TYPE_BYTES,   0, 1024, FALSE,  NULL },
+	{ "key_id",             TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "phase1",             TYPE_KEYWORD, 0, 0, TRUE, phase1_allowed },
 	{ "phase2",             TYPE_KEYWORD, 0, 0, TRUE, phase2_allowed },
 	{ "anonymous_identity", TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "ca_cert2",           TYPE_BYTES,   0, 65536, FALSE,  NULL },
+	{ "ca_cert2_id",        TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "client_cert2",       TYPE_BYTES,   0, 65536, FALSE,  NULL },
+	{ "cert2_id",           TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "private_key2",       TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "private_key2_passwd",TYPE_BYTES,   0, 1024, FALSE,  NULL },
+	{ "key2_id",            TYPE_BYTES,   0, 65536, FALSE,  NULL },
 	{ "pin",                TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "pcsc",               TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "nai",                TYPE_BYTES,   0, 0, FALSE,  NULL },
diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.c b/system-settings/plugins/keyfile/nm-keyfile-connection.c
index 0e4031b..2f4ded7 100644
--- a/system-settings/plugins/keyfile/nm-keyfile-connection.c
+++ b/system-settings/plugins/keyfile/nm-keyfile-connection.c
@@ -114,6 +114,18 @@ add_secrets (NMSetting *setting,
 	} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
 		/* Flatten the string hash by pulling its keys/values out */
 		g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets);
+	} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY)) {
+		const GByteArray *array;
+
+		array = (GByteArray *) g_value_get_boxed (value);
+		if (array && array->len > 0) {
+			GValue *v;
+
+			v = g_slice_new0 (GValue);
+			g_value_init (v, DBUS_TYPE_G_UCHAR_ARRAY);
+			g_value_copy (value, v);
+			g_hash_table_insert (secrets, g_strdup (key), v);
+		}
 	} else
 		g_message ("%s: unhandled secret %s type %s", __func__, key, G_VALUE_TYPE_NAME (value));
 }
diff --git a/system-settings/plugins/keyfile/reader.c b/system-settings/plugins/keyfile/reader.c
index 9efd130..b8c4099 100644
--- a/system-settings/plugins/keyfile/reader.c
+++ b/system-settings/plugins/keyfile/reader.c
@@ -29,6 +29,7 @@
 #include <nm-setting-ip4-config.h>
 #include <nm-setting-vpn.h>
 #include <nm-setting-connection.h>
+#include <nm-setting-8021x.h>
 #include <arpa/inet.h>
 #include <string.h>
 
@@ -337,6 +338,56 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
 	g_strfreev (keys);
 }
 
+static void
+read_guchar_array (GKeyFile *file, NMSetting *setting, const char *key)
+{
+	gint *tmp;
+	GByteArray *array;
+	gsize length;
+	int i;
+
+	tmp = g_key_file_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
+	array = g_byte_array_sized_new (length);
+	for (i = 0; i < length; i++) {
+		int val = tmp[i];
+		unsigned char v = (unsigned char) (val & 0xFF);
+
+		if (val < 0 || val > 255)
+			g_warning ("Value out of range for a byte value");
+		else
+			g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
+	}
+
+	g_object_set (setting, key, array, NULL);
+	g_byte_array_free (array, TRUE);
+	g_free (tmp);
+}
+
+static void
+read_certificate (NMSetting *setting, GKeyFile *file, const char *key)
+{
+	char *value;
+
+	value = g_key_file_get_value (file, nm_setting_get_name (setting), key, NULL);
+	if (!value)
+		return;
+
+	if (g_str_has_prefix (value, NM_SETTING_802_1X_CK_FORMAT_ID) || 
+		g_str_has_prefix (value, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+		GByteArray *array;
+		gsize len;
+
+		len = strlen (value);
+		array = g_byte_array_sized_new (len);
+		g_byte_array_append (array, (guint8 *) value, len);
+		g_object_set (setting, key, array, NULL);
+		g_byte_array_free (array, TRUE);
+	} else
+		read_guchar_array (file, setting, key);
+
+	g_free (value);
+}
+
 typedef struct {
 	GKeyFile *keyfile;
 	gboolean secrets;
@@ -390,6 +441,12 @@ read_one_setting_value (NMSetting *setting,
 		return;
 	}
 
+	/* Certificates are handled differently */
+	if (flags & NM_SETTING_PARAM_CERTIFICATE) {
+		read_certificate (setting, file, key);
+		return;
+	}
+
 	type = G_VALUE_TYPE (value);
 
 	if (type == G_TYPE_STRING) {
@@ -432,27 +489,7 @@ read_one_setting_value (NMSetting *setting,
 		g_free (tmp_str);
 		g_object_set (setting, key, uint_val, NULL);
  	} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
-		gint *tmp;
-		GByteArray *array;
-		gsize length;
-		int i;
-
-		tmp = g_key_file_get_integer_list (file, setting_name, key, &length, NULL);
-
-		array = g_byte_array_sized_new (length);
-		for (i = 0; i < length; i++) {
-			int val = tmp[i];
-			unsigned char v = (unsigned char) (val & 0xFF);
-
-			if (val < 0 || val > 255)
-				g_warning ("Value out of range for a byte value");
-			else
-				g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
-		}
-
-		g_object_set (setting, key, array, NULL);
-		g_byte_array_free (array, TRUE);
-		g_free (tmp);
+		read_guchar_array (file, setting, key);
  	} else if (type == DBUS_TYPE_G_LIST_OF_STRING) {
 		gchar **sa;
 		gsize length;
-- 
1.6.0.2

openSUSE Build Service is sponsored by