[Commits] Makefile.am 1.1 1.2 callbacks.c 1.5 1.6 contactwindow.c 1.3 1.4 mainwindow.c 1.3 1.4 plugin-loader.c 1.6 1.7 plugin-loader.h 1.4 1.5 plugin.h 1.5 1.6 utils.c 1.4 1.5 utils.h 1.4 1.5

miras at claws-mail.org miras at claws-mail.org
Mon Nov 14 23:06:46 CET 2011


Update of /home/claws-mail/contacts/src
In directory claws-mail:/tmp/cvs-serv18563/src

Modified Files:
	Makefile.am callbacks.c contactwindow.c mainwindow.c 
	plugin-loader.c plugin-loader.h plugin.h utils.c utils.h 
Log Message:
Lots of bug fixes and read-only support for LDAP. No searching implemented though

Index: contactwindow.c
===================================================================
RCS file: /home/claws-mail/contacts/src/contactwindow.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- contactwindow.c	4 Oct 2011 20:21:40 -0000	1.3
+++ contactwindow.c	14 Nov 2011 22:06:43 -0000	1.4
@@ -895,6 +895,7 @@
 	g_signal_connect(GTK_TREE_MODEL(list), "row-deleted",
 			G_CALLBACK(row_deleted_cb), cw);
 	cw->email_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list));
+    g_object_unref(list);
     gtk_widget_set_tooltip_text(GTK_WIDGET(cw->email_list),
         _("Double-click, enter, or space on cell will activate edit mode\n"
           "Mouse-Left-click to drag and drop for reordering email list\n"

Index: utils.h
===================================================================
RCS file: /home/claws-mail/contacts/src/utils.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- utils.h	4 Oct 2011 20:21:40 -0000	1.4
+++ utils.h	14 Nov 2011 22:06:44 -0000	1.5
@@ -125,6 +125,13 @@
 gint gslist_compare_gchar(gconstpointer a, gconstpointer b);
 GPtrArray* g_value_email_new();
 void dbus_contact_print(DBusContact* contact, FILE* f);
+gchar* aes256_encrypt(const gchar* plain, gboolean base64_enc);
+gchar* aes256_decrypt(const gchar* cipher_text, gboolean base64_enc);
+gchar* sha256(const gchar* plain);
+void extra_config_free(gpointer data);
+gpointer extra_config_copy(gpointer data);
+ExtraConfig* get_extra_config(GSList* list, const gchar* name);
+GSList* find_name(GtkContainer* container, const gchar* name);
 
 G_END_DECLS
 

Index: plugin-loader.h
===================================================================
RCS file: /home/claws-mail/contacts/src/plugin-loader.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- plugin-loader.h	4 Oct 2011 20:21:40 -0000	1.4
+++ plugin-loader.h	14 Nov 2011 22:06:43 -0000	1.5
@@ -46,14 +46,16 @@
 	gchar* id;
 	//gchar* addrbook_name;
 	GModule	*module;
-	gboolean (*init) (gchar** error);
+	gboolean (*init) (gpointer self, gchar** error);
 	void (*reset) (gchar** error);
 	const gchar* (*name) (void);
 	const gchar* (*desc) (void);
 	const gchar* (*version) (void);
-	const gchar* (*type) (void);
+	PluginType (*type) (void);
 	const gchar* (*license) (void);
-	const gchar* (*filter) (void);
+	const gchar* (*file_filter) (void);
+	gboolean (*need_credentials) (void);
+	GSList* (*extra_config) (void);
 	gchar* (*default_url) (const gchar* name);
 	GSList* (*remaining_attribs) (void);
 	GSList* (*inactive_attribs) (void);

Index: plugin.h
===================================================================
RCS file: /home/claws-mail/contacts/src/plugin.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- plugin.h	4 Oct 2011 20:21:40 -0000	1.5
+++ plugin.h	14 Nov 2011 22:06:43 -0000	1.6
@@ -48,6 +48,50 @@
 #define IS_READ_WRITE(X) ((X & PLUGIN_READ_WRITE) == PLUGIN_READ_WRITE)
 #define HAS_ADV_SEARCH(X) ((X & PLUGIN_ADVANCED_SEARCH) == PLUGIN_ADVANCED_SEARCH)
 
+typedef enum {
+	PLUGIN_CONFIG_EXTRA_ENTRY,
+	PLUGIN_CONFIG_EXTRA_CHECKBOX,
+	PLUGIN_CONFIG_EXTRA_SPINBUTTON
+} ExtraConfigType;
+
+typedef struct {
+	ExtraConfigType	type;
+	gchar*			label;
+	gchar*			tooltip;
+	union {
+		gchar*		entry;
+		gboolean	check_btn;
+		gint		spin_btn;
+	} value;
+	union {
+		gchar*		entry;
+		gboolean	check_btn;
+		gint		spin_btn;
+	} default_value;
+} ExtraConfig;
+
+typedef enum {
+	/*
+	 * Address books configured with this plugin only requires
+	 * the following input to function
+	 * Name: Address book name (Name must be uniq within this plugin)
+	 * (URI|URL): Reference to storage (URI => File in local file system,
+	 * URL => TCP based reference). If 'plugin_file_filter' returns NULL
+	 * then this plugin uses URL type storage reference.
+	 * 
+	 * Optional
+	 * - Username
+	 * - Password
+	 */
+	PLUGIN_TYPE_SIMPLE,
+	/*
+	 * Address books configured with this plugin requires additional
+	 * input to function in which case the function 'plugin_extra_config'
+	 * MUST return a GSList of ExtraConfig
+	 */
+	PLUGIN_TYPE_ADVANCED
+} PluginType;
+
 typedef struct {
 	guint			support; /* One or more of the plugin features or'ed */
 	const gchar*	subtype;
@@ -92,6 +136,8 @@
 	GList*		contacts; /* contacts is expected to be a list of Contact */
 	gboolean	dirty;
 	gulong		next_uid;
+	gboolean	open;
+	GSList*		extra_config; /* List of ExtraConfig */
 } AddressBook;
 
 typedef struct {
@@ -122,16 +168,20 @@
 
 
 /* Functions which must be implemented by any plugin */
-gboolean plugin_init(gchar** error);
+gboolean plugin_init(gpointer self, gchar** error);
 void plugin_reset(gchar** error);
 gboolean plugin_done(void);
 const PluginFeature* plugin_provides(void);
 const gchar* plugin_name(void);
 const gchar* plugin_desc(void);
 const gchar* plugin_version(void);
-const gchar* plugin_type(void);
+PluginType plugin_type(void);
+const gchar* plugin_file_filter(void);
 const gchar* plugin_license(void);
+gboolean plugin_need_credentials(void);
 gchar* plugin_default_url(const gchar* name);
+GSList* plugin_extra_config(void);
+
 /* 
  * Returning NULL means list of supported attributes are infinite
  * Returning an empty list means that no more supported attributes

Index: plugin-loader.c
===================================================================
RCS file: /home/claws-mail/contacts/src/plugin-loader.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- plugin-loader.c	4 Oct 2011 20:21:40 -0000	1.6
+++ plugin-loader.c	14 Nov 2011 22:06:43 -0000	1.7
@@ -402,22 +402,7 @@
 	g_free(plugin);
 }
 
-static gchar* format_hash(const guchar* md_string) {
-    int len = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
-    int i;
-    gchar* hex = g_new0(gchar, 2 * len + 1);
-
-	for (i = 0; i < len; i++)
-        sprintf(hex + 2 * i, "%02x", md_string[i]);
-	
-	return hex;
-}
-
-#define key "claws-mail address book"
 static void compute_hash(Plugin* plugin) {
-    gcry_error_t err = 0;
-    gcry_md_hd_t digest = NULL;
-    guchar* md_string = NULL;
     gchar* cipher;
 
 	gchar* plain = g_strconcat(
@@ -425,30 +410,12 @@
 			plugin->desc(), " ",
 			plugin->version(), NULL);
 
-    err = gcry_md_open(
-                &digest, GCRY_MD_SHA256,
-                GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC);
-    if (err) {
-        g_printerr("%s\n", gcry_strerror(err));
-        goto done;
-    }
-    err = gcry_md_setkey(digest, key, strlen(key));
-    if (err) {
-        g_printerr("%s\n", gcry_strerror(err));
-        goto done;
-    }
-
-    gcry_md_write(digest, plain, strlen(plain));
-
-    md_string = gcry_md_read(digest, 0);
-    cipher = format_hash(md_string);
+	cipher = sha256(plain);
+    g_free(plain);
     debug_print("Computed hash: %s\n", cipher);
+
     plugin->id = g_strdup(cipher);
 	g_free(cipher);
-	
-    done:
-    gcry_md_close(digest);
-    g_free(plain);
 }
 
 static Plugin* plugin_allready_loaded(Plugin* plugin, gchar** error) {
@@ -479,7 +446,7 @@
 		if (found) {
 			g_free(found->error);
 			found->error = NULL;
-			if (found->init(error)) {
+			if (found->init(found, error)) {
 				if (*error)
 					found->error = g_strdup(*error);
 				else
@@ -637,9 +604,9 @@
 			 get_contact, set_contact, delete_contact, search_contact, update_contact,
 			 plugin_abook_open, plugin_abook_close, plugin_abook_delete,
 			 plugin_addrbook_all_get, plugin_abook_set_config, plugin_type,
-			 plugin_url, plugin_attribs_set, plugin_commit_all,
+			 plugin_file_filter, plugin_url, plugin_attribs_set, plugin_commit_all,
 			 plugin_remaining_attribs, plugin_inactive_attribs,
-			 plugin_closed_books_get;
+			 plugin_closed_books_get, plugin_need_credentials, plugin_extra_config;
 
 	plugin = g_new0(Plugin, 1);
 	if (plugin == NULL) {
@@ -659,6 +626,7 @@
 		!g_module_symbol(plugin->module, "plugin_desc", &plugin_desc) ||
 		!g_module_symbol(plugin->module, "plugin_default_url", &plugin_url) ||
 		!g_module_symbol(plugin->module, "plugin_type", &plugin_type) ||
+		!g_module_symbol(plugin->module, "plugin_file_filter", &plugin_file_filter) ||
 		!g_module_symbol(plugin->module, "plugin_version", &plugin_version) ||
 		!g_module_symbol(plugin->module, "plugin_provides", &plugin_provides) ||
 		!g_module_symbol(plugin->module, "plugin_license", &plugin_license) ||
@@ -672,6 +640,8 @@
 		!g_module_symbol(plugin->module, "plugin_abook_set_config", &plugin_abook_set_config) ||
 		!g_module_symbol(plugin->module, "plugin_commit_all", &plugin_commit_all) ||
 		!g_module_symbol(plugin->module, "plugin_init", &plugin_init) ||
+		!g_module_symbol(plugin->module, "plugin_need_credentials", &plugin_need_credentials) ||
+		!g_module_symbol(plugin->module, "plugin_extra_config", &plugin_extra_config) ||
 		!g_module_symbol(plugin->module, "plugin_closed_books_get", &plugin_closed_books_get) ||
 		!g_module_symbol(plugin->module, "plugin_remaining_attribs", &plugin_remaining_attribs) ||
 		!g_module_symbol(plugin->module, "plugin_inactive_attribs", &plugin_inactive_attribs)) {
@@ -728,7 +698,7 @@
 	}
 	
 	plugin->init = plugin_init;
-	plugin->filter = plugin_type;
+	plugin->file_filter = plugin_file_filter;
 	plugin->reset = plugin_reset;
 	plugin->name = plugin_name;
 	plugin->desc = plugin_desc;
@@ -736,6 +706,8 @@
 	plugin->type = plugin_type;
 	plugin->license = plugin_license;
 	plugin->filename = g_strdup(filename);
+	plugin->need_credentials = plugin_need_credentials;
+	plugin->extra_config = plugin_extra_config;
 	plugin->error = NULL;
 	plugin->abook_open = plugin_abook_open;
 	plugin->abook_close = plugin_abook_close;
@@ -773,7 +745,7 @@
 		}
 	}
 	else {
-		if (plugin->init(error)) {
+		if (plugin->init(plugin, error)) {
 			if (*error)
 				plugin->error = g_strdup(*error);
 			else

Index: mainwindow.c
===================================================================
RCS file: /home/claws-mail/contacts/src/mainwindow.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- mainwindow.c	4 Oct 2011 20:21:40 -0000	1.3
+++ mainwindow.c	14 Nov 2011 22:06:43 -0000	1.4
@@ -360,6 +360,7 @@
 
     mainwindow->abook_list = 
         gtk_tree_view_new_with_model(GTK_TREE_MODEL(list));
+    g_object_unref(list);
     gtk_widget_set_name(mainwindow->abook_list, "abook_list");
     gtk_widget_set_tooltip_text(mainwindow->abook_list,
         _("Address book in BOLD is the default address book"));
@@ -412,6 +413,7 @@
 
     mainwindow->contact_list = 
         gtk_tree_view_new_with_model(GTK_TREE_MODEL(list));
+    g_object_unref(list);
     gtk_widget_set_tooltip_text(GTK_WIDGET(mainwindow->contact_list),
         _("Double-click, enter, or space on cell will activate edit mode"));
     gtk_tree_view_set_rules_hint(

Index: utils.c
===================================================================
RCS file: /home/claws-mail/contacts/src/utils.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- utils.c	4 Oct 2011 20:21:40 -0000	1.4
+++ utils.c	14 Nov 2011 22:06:44 -0000	1.5
@@ -44,6 +44,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <gcrypt.h>
 
 #include "utils.h"
 #include "gtk-utils.h"
@@ -66,6 +67,11 @@
 } CompareSListData;
 */
 
+typedef struct {
+	size_t		size;
+	guchar*		block;
+} NormBlock;
+
 #define ERRBUFSIZ 255
 
 /* Forward declarations */
@@ -352,6 +358,9 @@
 void attrib_def_free(gpointer attrdef) {
 	AttribDef* a = (AttribDef *) attrdef;
 	
+	if (! a)
+		return;
+		
 	if (a->attrib_name) {
 		g_free(a->attrib_name);
 		a->attrib_name = NULL;
@@ -415,24 +424,28 @@
 	cl_books = config->closed_books;
 	
 	if (cf_books && cf_books->group) {
-		if (cf_books->books)
+		if (cf_books->books) {
 			list = gslist_to_array(cf_books->books, &num);
+			g_key_file_set_string_list(config->key_file, cf_books->group,
+				"books", (const gchar* const *) list, num);
+			g_strfreev(list);
+		}
 		else {
-			list = g_new0(gchar *, 1);
+			g_key_file_set_string(config->key_file, cf_books->group,
+				"books", "");
 		}
-		g_key_file_set_string_list(config->key_file, cf_books->group,
-				"books", (const gchar* const *) list, num);
-		g_strfreev(list);
 	}
 	if (cl_books && cl_books->group) {
-		if (cl_books->books)
+		if (cl_books->books) {
 			list = gslist_to_array(cl_books->books, &num);
+			g_key_file_set_string_list(config->key_file, cl_books->group,
+				"books", (const gchar* const *) list, num);
+			g_strfreev(list);
+		}
 		else {
-			list = g_new0(gchar *, 1);
+			g_key_file_set_string(config->key_file, cl_books->group,
+				"books", "");
 		}
-		g_key_file_set_string_list(config->key_file, cl_books->group,
-				"books", (const gchar* const *) list, num);
-		g_strfreev(list);
 	}
 }
 
@@ -497,7 +510,7 @@
 }
 
 static void config_close(ConfigFile* config, gchar** error) {
-	gchar* data;
+	gchar *data, *dir;
 	GError* err = NULL;
 	FILE* fp;
 	gsize len;
@@ -510,13 +523,30 @@
 			g_clear_error(&err);
 		}
 		else {
-			gchar* old = g_strconcat(config->path, ".bak", NULL);
-			g_rename(config->path, old);
-			g_free(old);
+			dir = g_path_get_dirname(config->path);
+			if (strcmp(".", dir) != 0) {
+				if (!g_file_test(dir, G_FILE_TEST_EXISTS)) {
+					if (g_mkdir(dir, 0700)) {
+						*error = g_strconcat(dir, ": Could not create", NULL);
+						goto end;
+					}
+				}
+			}
+			g_free(dir);
+			if (g_file_test(config->path, G_FILE_TEST_EXISTS)) {
+				gchar* old = g_strconcat(config->path, ".bak", NULL);
+				g_rename(config->path, old);
+				g_free(old);
+			}
 			fp = g_fopen(config->path, "w");
-			fwrite(data, len, 1, fp);
-			fclose(fp);
+			if (fp) {
+				fwrite(data, len, 1, fp);
+				fclose(fp);
+			}
+			else
+				*error = g_strconcat(config->path, ": Could not create", NULL);
 		}
+end:
 		g_free(data);
 		g_key_file_free(config->key_file);
 		config->key_file = NULL;
@@ -536,9 +566,9 @@
 	if (g_file_test(config->path, G_FILE_TEST_EXISTS)) {
 		g_key_file_load_from_file(
 			config->key_file, config->path, G_KEY_FILE_KEEP_COMMENTS, &err);
-		if (err) {
+		if (err && err->code > 1) {
 			config_close(config, error);
-			g_free(error);
+			g_free(*error);
 			if (error)
 				*error = g_strdup(err->message);
 			g_clear_error(&err);
@@ -564,7 +594,7 @@
 	}
 	g_strfreev(str);
 			
-	return TRUE;
+	return (len > 0);
 }
 
 gboolean config_set_value(ConfigFile* config, const gchar* group,
@@ -585,13 +615,14 @@
 }
 
 void plugin_config_free(ConfigFile** config_file) {
-	ConfigFile* config = *config_file;
+	ConfigFile* config;
 	ConfiguredBooks* cf_books;
 	ClosedBooks* cl_books;
 	
-	if (config == NULL)
+	if (! config_file || ! *config_file)
 		return;
 	
+	config = *config_file;
 	cf_books = config->configured_books;
 	cl_books = config->closed_books;
 
@@ -629,7 +660,9 @@
 	}
 	gchar* str = g_string_free(buf, FALSE);
 	gchar* tmp = str;
-	tmp[strlen(tmp) - 1] = 0;
+	if (strlen(str) > 0 && str[strlen(str) - 1] == '|') {
+		tmp[strlen(tmp) - 1] = 0;
+	}
 	array = g_strsplit_set(tmp, "|", 0);
 	g_free(str);
 	
@@ -776,6 +809,9 @@
 void address_book_contacts_free(AddressBook* address_book) {
 	GList* cur;
 
+	if (! address_book)
+		return;
+		
 	for (cur = address_book->contacts; cur; cur = g_list_next(cur)) {
 		Contact* c = (Contact *) cur->data;
 		contact_free(c);
@@ -787,16 +823,18 @@
 }
 
 void address_book_free(AddressBook** address_book) {
-	AddressBook* a = *address_book;
+	AddressBook* a;
 	
-	if (! a)
+	if (! address_book || ! *address_book)
 		return;
-		
+	
+	a  = *address_book;
 	g_free(a->abook_name);
 	g_free(a->URL);
 	g_free(a->username);
 	g_free(a->password);
 	address_book_contacts_free(a);
+	gslist_free(&a->extra_config, extra_config_free);
 	*address_book = NULL;
 }
 
@@ -854,6 +892,7 @@
 	b->password = g_strdup(a->password);
 	b->next_uid = a->next_uid;
 	b->dirty = a->dirty;
+
 	if (deep) {
 		for (cur = a->contacts; cur; cur = g_list_next(cur)) {
 			b->contacts = g_list_prepend(
@@ -862,6 +901,9 @@
 	}
 	else
 		b->contacts = g_list_copy(a->contacts);
+
+	b->extra_config = g_slist_reverse(gslist_deep_copy(
+		a->extra_config, extra_config_copy));
 	
 	debug_print("from: %d contacts to: %d contacts\n",
 		g_list_length(a->contacts), g_list_length(b->contacts));
@@ -969,6 +1011,9 @@
 	GValue* email_member;
 	guint i;
 	
+	if (! email)
+		return;
+	
 	for (i = 0; i < email->n_values; i++) {
 		email_member = g_value_array_get_nth(email, i);
 		g_value_unset(email_member);
@@ -1269,4 +1314,251 @@
 		index = g_slist_index(list, data);
 
 	return index;
+}
+
+#define KEY "This is abook I1"
+static gboolean aes_init(gcry_cipher_hd_t* digest) {
+    gcry_error_t err = 0;
+    const gchar iv[] = "AbC1234567890xYz";
+
+	err = gcry_cipher_open(digest, GCRY_CIPHER_AES256,
+		GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE | GCRY_CIPHER_CBC_MAC);
+    if (err) {
+        g_printerr("%s\n", gcry_strerror(err));
+    	gcry_cipher_close(*digest);
+    	return FALSE;
+    }
+
+	err = gcry_cipher_setkey(*digest, KEY, strlen(KEY));
+    if (err) {
+        g_printerr("%s\n", gcry_strerror(err));
+    	gcry_cipher_close(*digest);
+    	return FALSE;
+    }
+
+	err = gcry_cipher_setiv(*digest, iv, gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES256));
+    if (err) {
+        g_printerr("%s\n", gcry_strerror(err));
+    	gcry_cipher_close(*digest);
+    	return FALSE;
+    }
+    
+    return TRUE;
+}
+
+static NormBlock* normalize(const gchar* text) {
+	size_t blk_size = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES256);
+	gint passes = strlen(text) / blk_size;
+	gint rest = strlen(text) % blk_size;
+	NormBlock* norm_block = g_new0(NormBlock, 1);
+	norm_block->size = (passes * blk_size) + (rest) ? blk_size : 0;
+	gint i;
+	
+	norm_block->block = g_new0(guchar, norm_block->size);
+	for (i = 0; i < strlen(text); i++) {
+		norm_block->block[i] = text[i];
+	}
+	
+	return norm_block;
+}
+
+gchar* aes256_encrypt(const gchar* plain, gboolean base64_enc) {
+    gcry_error_t err = 0;
+    gcry_cipher_hd_t digest = NULL;
+	guchar *cipher;
+	NormBlock* text;
+	gchar* base64 = NULL;
+	
+	if (! plain)
+		return NULL;
+
+	if (aes_init(&digest)) {
+		text = normalize(plain);
+		cipher = g_new0(guchar, text->size);
+		err = gcry_cipher_encrypt(digest, cipher, text->size, text->block, text->size);
+	    if (err) {
+	        g_printerr("%s\n", gcry_strerror(err));
+	    }
+	    else {
+			if (base64_enc)
+				base64 = g_base64_encode(cipher, text->size);
+			else
+				base64 = g_memdup(cipher, text->size);	
+		}
+		
+		g_free(cipher);
+		g_free(text->block);
+		g_free(text);
+		gcry_cipher_close(digest);
+	}
+	
+	return base64;
+}
+
+gchar* aes256_decrypt(const gchar* cipher_text, gboolean base64_enc) {
+    gcry_error_t err = 0;
+    gcry_cipher_hd_t digest = NULL;
+	size_t size;
+	guchar* cipher;
+	guchar* plain = NULL;
+
+	if (! cipher_text)
+		return NULL;
+
+	if (base64_enc)
+		cipher = g_base64_decode(cipher_text, &size);
+	else
+		cipher = (guchar *) g_strdup(cipher_text);
+
+	if (aes_init(&digest)) {
+		plain = g_new0(guchar, size + 1);
+		err = gcry_cipher_decrypt(digest, plain, size + 1, cipher, size);
+	    if (err) {
+	        g_printerr("%s\n", gcry_strerror(err));
+	        g_free(plain);
+	        plain = NULL;
+	    }
+		
+		g_free(cipher);
+		gcry_cipher_close(digest);
+	}
+	
+	return (gchar *) plain;
+}
+
+static gchar* format_hash(const guchar* md_string) {
+    int len = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
+    int i;
+    gchar* hex = g_new0(gchar, 2 * len + 1);
+
+	for (i = 0; i < len; i++)
+        sprintf(hex + 2 * i, "%02x", md_string[i]);
+	
+	return hex;
+}
+
+#define key "claws-mail address book"
+gchar* sha256(const gchar* plain) {
+    gcry_error_t err = 0;
+    gcry_md_hd_t digest = NULL;
+    guchar* md_string = NULL;
+    gchar* cipher;
+
+	if (! plain)
+		return NULL;
+
+    err = gcry_md_open(
+                &digest, GCRY_MD_SHA256,
+                GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC);
+    if (err) {
+        g_printerr("%s\n", gcry_strerror(err));
+        gcry_md_close(digest);
+    }
+
+    err = gcry_md_setkey(digest, key, strlen(key));
+    if (err) {
+        g_printerr("%s\n", gcry_strerror(err));
+        gcry_md_close(digest);
+    }
+
+    gcry_md_write(digest, plain, strlen(plain));
+
+    md_string = gcry_md_read(digest, 0);
+    cipher = format_hash(md_string);
+    gcry_md_close(digest);
+    
+    return cipher;
+}
+
+void extra_config_free(gpointer data) {
+    ExtraConfig* ec;
+    
+    if (! data)
+        return;
+        
+    ec = (ExtraConfig *) data;
+    g_free(ec->label);
+    g_free(ec->tooltip);
+	if (ec->type == PLUGIN_CONFIG_EXTRA_ENTRY) {
+		g_free(ec->value.entry);
+		g_free(ec->default_value.entry);
+	}
+    g_free(ec);
+    ec = NULL;
+}
+
+gpointer extra_config_copy(gpointer data) {
+	ExtraConfig *a, *b;
+	
+	if (! data)
+		return NULL;
+		
+	a = (ExtraConfig *) data;
+	b = g_new0(ExtraConfig, 1);
+	
+	b->label = g_strdup(a->label);
+	b->tooltip = g_strdup(a->tooltip);
+	b->type = a->type;
+	if (a->type == PLUGIN_CONFIG_EXTRA_ENTRY) {
+		b->value.entry = g_strdup(a->value.entry);
+		b->default_value.entry = g_strdup(a->default_value.entry);
+	}
+	else {
+		b->value = a->value;
+		b->default_value = a->default_value;
+	}
+	
+	return b; 
+}
+
+typedef struct {
+	GSList* list;
+	const gchar* name;
+} GtkIteratorData;
+
+static void gtk_iterator(GtkWidget* widget, gpointer data) {
+	GtkIteratorData* iter_data = (GtkIteratorData *) data;
+	const gchar* name;
+	
+	if (GTK_IS_CONTAINER(widget))
+		gtk_container_foreach(GTK_CONTAINER(widget), gtk_iterator, iter_data);
+	name = gtk_widget_get_name(widget);
+	if (name && strcmp(name, iter_data->name) == 0)
+		iter_data->list = g_slist_prepend(iter_data->list, widget);
+}
+
+GSList* find_name(GtkContainer* container, const gchar* name) {
+	GSList* list = NULL;
+	GtkIteratorData* data;
+	
+	if (! container || ! name)
+		return list;
+	
+	data = g_new0(GtkIteratorData, 1);
+	data->name = name;
+	
+	gtk_container_foreach(container, gtk_iterator, data);
+	list = data->list;
+	g_free(data);
+	
+	return list;
+}
+
+ExtraConfig* get_extra_config(GSList* list, const gchar* name) {
+	GSList* cur;
+	ExtraConfig* conf = NULL;
+	gboolean found = FALSE;
+	
+	if (! list || ! name)
+		return conf;
+		
+	for (cur = list; cur && !found; cur = g_slist_next(cur)) {
+		conf = (ExtraConfig *) cur->data;
+		if (conf->label && strcmp(conf->label, name) == 0)
+			found = TRUE;
+		else
+			conf = NULL;
+	}
+	
+	return extra_config_copy(conf);
 }
\ No newline at end of file

Index: Makefile.am
===================================================================
RCS file: /home/claws-mail/contacts/src/Makefile.am,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- Makefile.am	7 Sep 2011 17:35:29 -0000	1.1
+++ Makefile.am	14 Nov 2011 22:06:43 -0000	1.2
@@ -16,7 +16,8 @@
 
 AM_CPPFLAGS = \
 		-DG_LOG_DOMAIN=\"Claws-Contacts\" \
-		-DPLUGINDIR=\"@PLUGINDIR@\"
+		-DPLUGINDIR=\"@PLUGINDIR@\" \
+		$(LIBGCRYPT_CFLAGS)
 
 claws_contacts_SOURCES = \
 		    claws-contacts.c \
@@ -48,7 +49,7 @@
 claws_contacts_LDADD= \
 		   @GLIB_LIBS@ \
 		   @GTK_LIBS@ \
-		   @GCRYPT_LIBS@ \
+		   $(LIBGCRYPT_LIBS) \
 		   @LIBXML_LIBS@ \
 		   ${top_builddir}/xmllib/libcontactxml.la \
 		   ${top_builddir}/src/dbus/libdbus.la

Index: callbacks.c
===================================================================
RCS file: /home/claws-mail/contacts/src/callbacks.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- callbacks.c	4 Oct 2011 20:21:40 -0000	1.5
+++ callbacks.c	14 Nov 2011 22:06:43 -0000	1.6
@@ -185,7 +185,7 @@
 	GtkFileFilter* filter;
 	gchar* home;
 	
-	file_filter = cur.plugin->filter();
+	file_filter = cur.plugin->file_filter();
 	if (file_filter) {
 		gchar* f = g_strconcat("*.", file_filter, NULL);
 		filter = gtk_file_filter_new();
@@ -204,8 +204,10 @@
 		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
 	gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
 	home = cur.plugin->default_url(NULL);
-	gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), home);
-	g_free(home);
+	if (home) {
+		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), home);
+		g_free(home);
+	}
 	
 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
 		file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
@@ -669,7 +671,7 @@
 	}
 	else {
 		show_message(win->window, GTK_UTIL_MESSAGE_INFO,
-		_("Please highlight desired address book for deletion"));
+		_("Please highlight desired address book to edit"));
 	}
 }
 
@@ -851,7 +853,8 @@
 		plugin = plugin_get_plugin(plugin_name);
 		if (plugin) {
 			if (address_book_edit(win->window, plugin, &book)) {
-				if (g_file_test(book->URL, G_FILE_TEST_EXISTS)) {
+				if (plugin->file_filter() && strcmp("xml", plugin->file_filter()) == 0 &&
+						g_file_test(book->URL, G_FILE_TEST_EXISTS)) {
 					AddressBook* abook =
 							address_book_get(plugin, book->abook_name);
 					if (abook) {
@@ -874,7 +877,8 @@
 						}
 					}
 				}
-				if (! addr_book_set_config(book, &error)) {
+				if (! plugin->abook_set_config(book, NULL, &error)) {
+				/*if (! addr_book_set_config(book, &error)) {*/
 					if (plugin->abook_open(book, &error)) 
 						update_abook_list(win);
 				}
@@ -990,19 +994,188 @@
 	}
 }
 
+static void add_advanced_page(GtkNotebook* notebook,
+							  Plugin* plugin,
+							  AddressBook* address_book) {
+	GSList *cur, *extra;
+	GtkWidget *widget, *hbox, *vbox, *label;
+	gboolean new;
+	
+	if (address_book->extra_config) {
+		extra = address_book->extra_config;
+		new = FALSE;
+	}
+	else {
+		extra = plugin->extra_config();
+		new = TRUE;
+	}
+
+	if (extra) {
+		vbox = gtk_vbox_new(FALSE, 0);
+		for (cur = extra; cur; cur = g_slist_next(cur)) {
+			ExtraConfig* ec = (ExtraConfig *) cur->data;
+			hbox = gtk_hbox_new(FALSE, 5);
+			switch (ec->type) {
+				case PLUGIN_CONFIG_EXTRA_CHECKBOX:
+					widget = gtk_check_button_new();
+					if (ec->label)
+						gtk_button_set_label(GTK_BUTTON(widget), ec->label);
+					if (ec->tooltip)
+						gtk_widget_set_tooltip_text(widget, ec->tooltip);
+					if (new)
+						gtk_toggle_button_set_active(
+							GTK_TOGGLE_BUTTON(widget), ec->default_value.check_btn);
+					else
+						gtk_toggle_button_set_active(
+							GTK_TOGGLE_BUTTON(widget), ec->value.check_btn);
+					label = gtk_label_new("");
+					break;
+				case PLUGIN_CONFIG_EXTRA_ENTRY:
+					widget = gtk_entry_new();
+					if (ec->label)
+						label = gtk_label_new(ec->label);
+					else
+						label = gtk_label_new("");
+					if (ec->tooltip)
+						gtk_widget_set_tooltip_text(widget, ec->tooltip);
+					if (ec->value.entry)
+						gtk_entry_set_text(GTK_ENTRY(widget), ec->value.entry);
+					else if (ec->default_value.entry)
+						gtk_entry_set_text(GTK_ENTRY(widget), ec->default_value.entry);
+					break;
+				case PLUGIN_CONFIG_EXTRA_SPINBUTTON:
+					widget = gtk_spin_button_new_with_range(0.0, 100.0, 1.0);
+					if (ec->label)
+						label = gtk_label_new(ec->label);
+					else
+						label = gtk_label_new("");
+					if (ec->tooltip)
+						gtk_widget_set_tooltip_text(widget, ec->tooltip);
+					if (new)
+						gtk_spin_button_set_value(
+							GTK_SPIN_BUTTON(widget), ec->default_value.spin_btn);
+					else		
+						gtk_spin_button_set_value(
+							GTK_SPIN_BUTTON(widget), ec->value.spin_btn);		
+					break;
+			}
+			gtk_widget_set_name(widget, ec->label);
+			gtk_widget_set_size_request(label, 100, -1);
+			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+			gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
+			if (ec->type == PLUGIN_CONFIG_EXTRA_SPINBUTTON)
+				gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 2);
+			else
+				gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
+			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
+		}
+		label = gtk_label_new(_("Advanced settings"));
+		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
+		if (! address_book->extra_config)
+			gslist_free(&extra, extra_config_free);
+	}
+}
+
+static void set_advanced_config(Plugin* plugin,
+								AddressBook* address_book,
+								GtkNotebook* notebook) {
+	GtkWidget *page, *widget;
+	GSList *config, *cur, *widgets = NULL, *ptr;
+	gboolean found;
+	
+	config = plugin->extra_config();
+	page = gtk_notebook_get_nth_page(notebook, 1);
+	
+	if (config && page) {
+		for (cur = config; cur; cur = g_slist_next(cur)) {
+			ExtraConfig* ec = (ExtraConfig *) cur->data;
+			gslist_free(&widgets, NULL);
+			widgets = find_name(GTK_CONTAINER(notebook), ec->label);
+			if (! widgets)
+				continue;
+			
+			switch (ec->type) {
+				case PLUGIN_CONFIG_EXTRA_CHECKBOX:
+					found = FALSE;
+					for (ptr = widgets; ptr && !found; ptr = g_slist_next(ptr)) {
+						widget = (GtkWidget *) widgets->data;
+						if (debug_get_mode()) {
+							gchar* text = gtk_widget_get_tooltip_text(widget);
+							debug_print("%s\n", (text) ? text: "(NULL)");
+							g_free(text);
+						}
+						if (GTK_IS_CHECK_BUTTON(widget))
+							found = TRUE;
+						else
+							widget = NULL;
+					}
+					if (widget) {
+						ec->value.check_btn = 
+							gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+					}
+					break;
+				case PLUGIN_CONFIG_EXTRA_ENTRY:
+					found = FALSE;
+					for (ptr = widgets; ptr && !found; ptr = g_slist_next(ptr)) {
+						widget = (GtkWidget *) widgets->data;
+						if (debug_get_mode()) {
+							gchar* text = gtk_widget_get_tooltip_text(widget);
+							debug_print("%s\n", (text) ? text: "(NULL)");
+							g_free(text);
+						}
+						if (GTK_IS_ENTRY(widget))
+							found = TRUE;
+						else
+							widget = NULL;
+					}
+					if (widget) {
+						g_free(ec->value.entry);
+						ec->value.entry = 
+							gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
+					}
+					break;
+				case PLUGIN_CONFIG_EXTRA_SPINBUTTON:
+					found = FALSE;
+					for (ptr = widgets; ptr && !found; ptr = g_slist_next(ptr)) {
+						widget = (GtkWidget *) widgets->data;
+						if (debug_get_mode()) {
+							gchar* text = gtk_widget_get_tooltip_text(widget);
+							debug_print("%s\n", (text) ? text: "(NULL)");
+							g_free(text);
+						}
+						if (GTK_IS_SPIN_BUTTON(widget))
+							found = TRUE;
+						else
+							widget = NULL;
+					}
+					if (widget) {
+						ec->value.spin_btn = 
+							gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+					}
+					break;
+			}
+		}
+		address_book->extra_config = config;
+	}
+	else	
+		gslist_free(&config, extra_config_free);
+}
+
 #define GTK_ENTRIES 4
-gboolean address_book_edit(
-		GtkWidget* parent, Plugin* plugin, AddressBook** address_book) {
+gboolean address_book_edit(GtkWidget* parent,
+						   Plugin* plugin,
+						   AddressBook** address_book) {
 	GtkWidget* dialog;
 	GtkWidget* file_btn;
 	AddressBook* book;
 	GtkWidget* input[GTK_ENTRIES] = {NULL, NULL, NULL, NULL};
-	GtkWidget *hbox, *vbox, *label = NULL, *frame;
+	GtkWidget *hbox, *vbox, *label = NULL, *frame, *notebook;
 	int i;
 	gboolean response = FALSE;
 	gboolean use_button = FALSE;
 	struct DataContainer data;
 	gboolean show_url = TRUE;
+	gchar* title = NULL;
 	
 	for (i = 0; i < GTK_ENTRIES; i++) {
 		input[i] = gtk_entry_new();
@@ -1019,19 +1192,23 @@
 		if (book->password)
 			gtk_entry_set_text(GTK_ENTRY(input[3]), book->password);
 		gtk_entry_set_visibility(GTK_ENTRY(input[3]), FALSE);
+		title = g_strdup(_("Edit address book"));
 	}
 	else {
 		book = *address_book = address_book_new();
-		show_url = FALSE;
+		title = g_strdup(_("New address book"));
+		/*if (! plugin->file_filter())
+			show_url = FALSE;*/
 	}
 	
 	dialog = gtk_dialog_new_with_buttons(
-                _("Edit address book"), 
+                title, 
                 GTK_WINDOW(parent),
                 GTK_DIALOG_DESTROY_WITH_PARENT,
                 GTK_STOCK_OK, GTK_RESPONSE_OK,
                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                 NULL);
+    g_free(title);
     gtk_widget_set_size_request(dialog, 360, -1);
 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
 	
@@ -1048,16 +1225,19 @@
 				if (show_url) { 
 					label = gtk_label_new(_("URL"));
 					gtk_widget_set_tooltip_text(
-						input[i], _("URL or path to this address book"));
-					file_btn = gtk_button_new_from_stock(GTK_STOCK_OPEN);
-					gtk_widget_set_tooltip_text(
-						file_btn, _("Open file dialog"));
-					data.plugin = plugin;
-					data.addressbook = address_book;
-					data.widget = input[i];
-					g_signal_connect(file_btn, "clicked",
-						G_CALLBACK(select_addr_book_cb), &data);
-					use_button = TRUE;
+						input[i], _("URL or path to this address book\n"
+									"Must conform to plugin requirements."));
+					if (plugin->file_filter()) {
+						file_btn = gtk_button_new_from_stock(GTK_STOCK_OPEN);
+						gtk_widget_set_tooltip_text(
+							file_btn, _("Open file dialog"));
+						data.plugin = plugin;
+						data.addressbook = address_book;
+						data.widget = input[i];
+						g_signal_connect(file_btn, "clicked",
+							G_CALLBACK(select_addr_book_cb), &data);
+						use_button = TRUE;
+					}
 				}
 				else {
 					gtk_widget_destroy(input[i]);
@@ -1068,15 +1248,20 @@
 				label = gtk_label_new(_("Username"));
 				gtk_widget_set_tooltip_text(
 					input[i], _("And optional username"));
+				if (!plugin->need_credentials())
+					gtk_widget_set_sensitive(input[i], FALSE);
 				break;
 			case 3:
 				label = gtk_label_new(_("Password"));
 				gtk_widget_set_tooltip_text(
 					input[i], _("And optional password"));
+				gtk_entry_set_visibility(GTK_ENTRY(input[i]), FALSE);
+				if (!plugin->need_credentials())
+					gtk_widget_set_sensitive(input[i], FALSE);
 				break;
 		}
 		if (input[i]) {
-			gtk_widget_set_size_request(label, 60, -1);
+			gtk_widget_set_size_request(label, 100, -1);
 			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 			gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
 			gtk_box_pack_start(GTK_BOX(hbox), input[i], TRUE, TRUE, 2);
@@ -1087,10 +1272,20 @@
 			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
 		}
 	}
-	frame = gtk_frame_new(_("Address book settings"));
-	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
-	gtk_widget_show_all(frame);
+	if (plugin->extra_config()) {
+		notebook = gtk_notebook_new();
+		label = gtk_label_new(_("Basic settings"));
+		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
+		add_advanced_page(GTK_NOTEBOOK(notebook), plugin, book);
+		gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), notebook);
+		gtk_widget_show_all(notebook);
+	}
+	else {
+		frame = gtk_frame_new(_("Address book settings"));
+		gtk_container_add(GTK_CONTAINER(frame), vbox);
+		gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
+		gtk_widget_show_all(frame);
+	}
 	dialog_set_focus(GTK_DIALOG(dialog), GTK_STOCK_CANCEL);
 	
 	gint result = gtk_dialog_run(GTK_DIALOG(dialog));
@@ -1119,6 +1314,10 @@
 			book->password = 
 				gtk_editable_get_chars(GTK_EDITABLE(input[3]), 0, -1);
 			response = TRUE;
+			if (plugin->extra_config()) {
+				//gslist_free(&book->extra_config, extra_config_free);
+				set_advanced_config(plugin, book, GTK_NOTEBOOK(notebook));
+			}
 			break;
 		case GTK_RESPONSE_CANCEL:
 			break;



More information about the Commits mailing list