2011-09-20 [mir] 0.6.0cvs17
authorMichael Rasmussen <mir@datanom.net>
Tue, 20 Sep 2011 21:58:44 +0000 (21:58 +0000)
committerMichael Rasmussen <mir@datanom.net>
Tue, 20 Sep 2011 21:58:44 +0000 (21:58 +0000)
* dbus-client/.cvsignore
* dbus-client/client.c
* plugins/xml/plugin-init.c
* plugins/xml/xml-plugin.c
* src/callbacks.c
* src/contactwindow.c
* src/gtk-utils.c
* src/gtk-utils.h
* src/plugin-loader.c
* src/plugin-loader.h
* src/plugin.h
* src/printing.c
* src/settings.c
* src/utils.c
* src/utils.h
* src/dbus/server-object.c
* xmllib/parser.c
    Extended attribute support to use all available
    supported attributes defined in AttribType.
    Fix a lot of bugs and potential memory leaks.

20 files changed:
ChangeLog
PATCHSETS
configure.ac
dbus-client/.cvsignore
dbus-client/client.c
plugins/xml/plugin-init.c
plugins/xml/xml-plugin.c
src/callbacks.c
src/contactwindow.c
src/dbus/server-object.c
src/gtk-utils.c
src/gtk-utils.h
src/plugin-loader.c
src/plugin-loader.h
src/plugin.h
src/printing.c
src/settings.c
src/utils.c
src/utils.h
xmllib/parser.c

index 95ab66f17af2e2bbc8196bb168596b1a175cc778..bc68ae71e8a4f34ca38db2d5541ac51e3c83834d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2011-09-20 [mir]       0.6.0cvs17
+
+       * dbus-client/.cvsignore
+       * dbus-client/client.c
+       * plugins/xml/plugin-init.c
+       * plugins/xml/xml-plugin.c
+       * src/callbacks.c
+       * src/contactwindow.c
+       * src/gtk-utils.c
+       * src/gtk-utils.h
+       * src/plugin-loader.c
+       * src/plugin-loader.h
+       * src/plugin.h
+       * src/printing.c
+       * src/settings.c
+       * src/utils.c
+       * src/utils.h
+       * src/dbus/server-object.c
+       * xmllib/parser.c
+           Extended attribute support to use all available
+           supported attributes defined in AttribType.
+           Fix a lot of bugs and potential memory leaks.
+
+
 2011-09-17 [mir]       0.6.0cvs16
 
        * xmllib/parser.c
index 9fd7e52a6611f24515cb8ffba2cb7ff5b18ee55c..4f30a25d691148e914a6afde2d530460ca36b0de 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
@@ -14,3 +14,4 @@
 ( cvs diff -u -r 1.1 -r 1.2 plugins/Makefile.am;  diff -u /dev/null plugins/ldap/Makefile.am;  diff -u /dev/null plugins/ldap/ldap-plugin.c;  ) > 0.6.0cvs14.patchset
 ( diff -u /dev/null plugins/ldap/.cvsignore;  ) > 0.6.0cvs15.patchset
 ( cvs diff -u -r 1.2 -r 1.3 xmllib/parser.c;  ) > 0.6.0cvs16.patchset
+( cvs diff -u -r 1.1 -r 1.2 dbus-client/.cvsignore;  cvs diff -u -r 1.1 -r 1.2 dbus-client/client.c;  cvs diff -u -r 1.1 -r 1.2 plugins/xml/plugin-init.c;  cvs diff -u -r 1.2 -r 1.3 plugins/xml/xml-plugin.c;  cvs diff -u -r 1.2 -r 1.3 src/callbacks.c;  cvs diff -u -r 1.1 -r 1.2 src/contactwindow.c;  cvs diff -u -r 1.1 -r 1.2 src/gtk-utils.c;  cvs diff -u -r 1.1 -r 1.2 src/gtk-utils.h;  cvs diff -u -r 1.3 -r 1.4 src/plugin-loader.c;  cvs diff -u -r 1.2 -r 1.3 src/plugin-loader.h;  cvs diff -u -r 1.2 -r 1.3 src/plugin.h;  cvs diff -u -r 1.1 -r 1.2 src/printing.c;  cvs diff -u -r 1.1 -r 1.2 src/settings.c;  cvs diff -u -r 1.1 -r 1.2 src/utils.c;  cvs diff -u -r 1.1 -r 1.2 src/utils.h;  cvs diff -u -r 1.1 -r 1.2 src/dbus/server-object.c;  cvs diff -u -r 1.3 -r 1.4 xmllib/parser.c;  ) > 0.6.0cvs17.patchset
index ec707e90daea5d491f105ce0362eba0c3de1cc28..3a1cbf1944e869d1546c9e8cf471b71734ccc40a 100644 (file)
@@ -12,7 +12,7 @@ MINOR_VERSION=6
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=16
+EXTRA_VERSION=17
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index 3fe74e72408d3783b283faf4078e649edf10e06e..133304b41059b1e64959a8e9235feb3b0bc50365 100644 (file)
@@ -23,4 +23,6 @@ org.clawsmail.ClawsContact.service
 *.la
 claws-contacts
 server-bindings.h
+client-bindings.h
+dbus-client
 
index 4ef59aa19c91f2542f4602cffc3a85b41cbf7fb5..2c3f2cc2e78c58da6369cbdf292153687a10fcc6 100644 (file)
@@ -125,7 +125,7 @@ static void format_contact(DBusContact* contact, ContactInfo* c) {
     GValue email_member = {0};
     gchar* str;   
     
-    contact->data = hash_table_new();
+    contact->data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
     contact->emails = g_value_email_new();
     firstname = lastname = NULL;
     
index 59afbe2dacefa9fce9e7e7717ec0e1dfc235e65a..0fe8d49cd2549fe34465728ed8f24e75800e1876 100644 (file)
@@ -121,19 +121,24 @@ static gboolean has_old_claws_native_abook(gchar** path, gchar** error) {
 static GHashTable* get_attributes(
                const gchar* path, gboolean old_abook, gchar** error) {
        const gchar* header;
-       const gchar **attribs;
-       
+       AttribContainer* attribs;
+       GHashTable* result;
+
+       attribs = g_new0(AttribContainer, 1);
        if (old_abook) {
                header = native_header;
                scanned_attribs = scan_existing_addrbooks(path, error);
-               attribs = (const gchar**) scanned_attribs;
+               attribs->existing_attribs = (const gchar**) scanned_attribs;
        }
        else {
                header = standard_header;
-               attribs = standard_attribs;
+               attribs->existing_attribs = standard_attribs;
        }
-
-       return get_attrib_list(NULL, attribs, header, TRUE, error, add_attrib_btn_cb);
+       
+       result = get_attrib_list(NULL, attribs, header, TRUE, error, add_attrib_btn_cb);
+       g_free(attribs);
+       
+       return result;
 }
 
 GHashTable* plugin_get_attribs(gboolean* old_abook, gchar** error) {
index c85df802eef0fd9e7c42315283f756f8e39b0745..819c3d20a176e3131403d885c8b3da6e705beaa1 100644 (file)
@@ -67,6 +67,7 @@ static GList* abooks = NULL;
 static gchar self_home[] = "xml";
 static gchar configrc[] = "xmlrc";
 static ConfigFile* config = NULL;
+static GSList* inactive_attribs = NULL;
 
 static void contact_set_uid(AddressBook* abook, Contact* contact) {
        GHashTable* data = contact->data;
@@ -74,7 +75,7 @@ static void contact_set_uid(AddressBook* abook, Contact* contact) {
        if (data) {
                gchar* uid = g_strdup_printf("%ld", abook->next_uid);
                abook->next_uid++;
-               g_hash_table_replace(data, g_strdup("uid"), g_strdup(uid));
+               swap_data(data, "uid", uid);
                g_free(uid);
        }
 }
@@ -82,12 +83,14 @@ static void contact_set_uid(AddressBook* abook, Contact* contact) {
 static void abook_set_next_uid(AddressBook* abook) {
        GList* cur;
        gulong uid = 0;
+       gchar* id = NULL;
        
        for (cur = abook->contacts; cur; cur = g_list_next(cur)) {
                Contact* contact = (Contact *) cur->data;
                if (contact && contact->data) {
-                       gchar* id = g_hash_table_lookup(contact->data, "uid");
+                       extract_data(contact->data, "uid", (void **) &id);
                        gulong n = strtol(id, NULL, 10);
+                       g_free(id);
                        uid = (n > uid) ? n : uid;
                }       
        }
@@ -137,6 +140,7 @@ static void abook_get_images(AddressBook* abook) {
        Image* image;
        GSList* images = NULL, *cur1;
        gboolean found;
+       gchar* uid = NULL;
        
        dir = g_dir_open(dir_path, 0, &error);
        if (!dir || error) {
@@ -164,11 +168,12 @@ static void abook_get_images(AddressBook* abook) {
                for (cur2 = abook->contacts; !found && cur2; cur2 = g_list_next(cur2)) {
                        Contact* contact = (Contact *) cur2->data;
                        if (contact && contact->data) {
-                               gchar* uid = g_hash_table_lookup(contact->data, "uid");
+                               extract_data(contact->data, "uid", (void **) &uid);
                                if (uid && strcmp(uid, image->uid) == 0) {
-                                       g_hash_table_replace(contact->data,
-                                                                                g_strdup("image"),
-                                                                                g_strdup(image->image));
+                                       g_free(uid);
+                                       AttribDef* attr = 
+                                               pack_data(ATTRIB_TYPE_STRING, "image", image->image);
+                                       g_hash_table_replace(contact->data, g_strdup("image"), attr);
                                        found = TRUE;
                                }
                                uid = NULL;
@@ -178,7 +183,7 @@ static void abook_get_images(AddressBook* abook) {
                g_free(image->image);
                g_free(image);
        }
-       gslist_free(images, NULL);
+       gslist_free(&images, NULL);
 }
 
 static void abooks_free() {
@@ -203,7 +208,7 @@ static void open_addr_book(AddressBook* abook, gchar** error) {
        }
 }
 
-static gboolean person_attrib(gchar** str, gchar* key, gchar* value) {
+static gboolean person_attrib(gchar** str, gchar* key, AttribDef* attr) {
        gchar *tmp, *k, *v;
        
        if (strcasecmp("uid", key) == 0 ||
@@ -213,7 +218,7 @@ static gboolean person_attrib(gchar** str, gchar* key, gchar* value) {
                strcasecmp("cn", key) == 0) {
                
                k = g_markup_escape_text(key, -1);
-               v = g_markup_escape_text(value, -1);
+               v = g_markup_escape_text(attr->value.string, -1);
                if (*str) {
                        tmp = g_strdup(*str);
                        g_free(*str);
@@ -228,11 +233,36 @@ static gboolean person_attrib(gchar** str, gchar* key, gchar* value) {
        return FALSE;
 }
 
-static void attributes_attrib(gchar** str, gchar* key, gchar* value) {
+static void attributes_attrib(gchar** str, gchar* key, AttribDef* attr) {
        gchar *tmp, *k, *v;
+       void* value = NULL;
+       AttribType type;
+       gboolean bool;
+       gchar ch;
+       gint i;
        
+       type = get_data(attr, &value);
+       switch (type) {
+               case ATTRIB_TYPE_BOOLEAN:
+                       bool = *(gboolean *) value;
+                       tmp = (bool) ? g_strdup("true") : g_strdup("false");
+                       break;
+               case ATTRIB_TYPE_CHAR:
+                       ch = *(gchar *) value;
+                       tmp = g_strdup_printf("%c", ch);
+                       break;
+               case ATTRIB_TYPE_INT:
+                       i = *(gint *) value;
+                       tmp = g_strdup_printf("%i", i);
+                       break;
+               case ATTRIB_TYPE_STRING:
+                       tmp = g_strdup((gchar *) value);
+                       break;
+       }
+       g_free(value);
        k = g_markup_escape_text(key, -1);
-       v = g_markup_escape_text(value, -1);
+       v = g_markup_escape_text(tmp, -1);
+       g_free(tmp);
        if (*str) {
                tmp = g_strdup(*str);
                g_free(*str);
@@ -256,12 +286,12 @@ static gchar* serialize(GHashTable* hash, GSList* emails) {
        g_hash_table_foreach(hash, hash_table_keys_to_slist, &attr);
        for (cur = attr; cur; cur = g_slist_next(cur)) {
                AttribDef* attrdef = (AttribDef *) cur->data;
-               gchar* value = g_hash_table_lookup(hash, attrdef->attrib_name);
-               if (person_attrib(&person, attrdef->attrib_name, value))
+               AttribDef* attr = g_hash_table_lookup(hash, attrdef->attrib_name);
+               if (person_attrib(&person, attrdef->attrib_name, attr))
                        continue;
-               attributes_attrib(&attributes, attrdef->attrib_name, value);
+               attributes_attrib(&attributes, attrdef->attrib_name, attr);
        }
-       gslist_free(attr, attrib_def_free);
+       gslist_free(&attr, attrib_def_free);
        for (mail = emails; mail; mail = g_slist_next(mail)) {
                Email* email = (Email *) mail->data;
                alias = g_markup_escape_text(email->alias, -1);
@@ -362,7 +392,7 @@ static void merge_file(const gchar* path) {
 }
 
 static void write_config_file(GSList** books) {
-       GSList *cur, *tmp;
+       GSList *cur, *tmp, *cur_attribs;
        gchar* error = NULL;
        gchar* path = NULL;
        
@@ -388,7 +418,7 @@ static void write_config_file(GSList** books) {
                        g_slist_prepend(config->configured_books->books, g_strdup(book));
                g_free(book);
        }
-       gslist_free(*books, NULL);
+       gslist_free(books, NULL);
        *books = NULL;
        
        plugin_config_set(config, &error);
@@ -398,15 +428,24 @@ static void write_config_file(GSList** books) {
        }
 
        cur = NULL;
-       GSList* attribs = plugin_attrib_list();
-       for (tmp = attribs; tmp; tmp = g_slist_next(tmp)) {
+       cur_attribs = plugin_attrib_list();
+       for (tmp = cur_attribs; tmp; tmp = g_slist_next(tmp)) {
                AttribDef* attrdef = (AttribDef *) tmp->data;
                cur = g_slist_prepend(cur, g_strdup(attrdef->attrib_name));
        }
-       gslist_free(attribs, attrib_def_free);
-
+       gslist_free(&cur_attribs, attrib_def_free);
        config_set_value(config, "supported attributes", "attributes", cur);
-       gslist_free(cur, g_free);
+       gslist_free(&cur, g_free);
+
+       cur = NULL;
+       cur_attribs = plugin_inactive_attribs();
+       for (tmp = cur_attribs; tmp; tmp = g_slist_next(tmp)) {
+               AttribDef* attrdef = (AttribDef *) tmp->data;
+               cur = g_slist_prepend(cur, g_strdup(attrdef->attrib_name));
+       }
+       gslist_free(&cur_attribs, attrib_def_free);
+       config_set_value(config, "deactivated attributes", "attributes", cur);
+       gslist_free(&cur, g_free);
 }
 
 static gint compare_book_names(gconstpointer a, gconstpointer b) {
@@ -534,15 +573,20 @@ static void write_config() {
 
 static GSList* get_basic_attributes(Contact* contact) {
        GSList *list = NULL, *cur;
+       gchar* value;
        
-       list = g_slist_prepend(list,
-                       g_strdup(g_hash_table_lookup(contact->data, "nick-name")));
-       list = g_slist_prepend(list,
-                       g_strdup(g_hash_table_lookup(contact->data, "first-name")));
-       list = g_slist_prepend(list,
-                       g_strdup(g_hash_table_lookup(contact->data, "last-name")));
-       list = g_slist_prepend(list,
-                       g_strdup(g_hash_table_lookup(contact->data, "cn")));
+       extract_data(contact->data, "nick-name", (void **) &value);
+       list = g_slist_prepend(list, g_strdup(value));
+       g_free(value);
+       extract_data(contact->data, "first-name", (void **) &value);
+       list = g_slist_prepend(list, g_strdup(value));
+       g_free(value);
+       extract_data(contact->data, "last-name", (void **) &value);
+       list = g_slist_prepend(list, g_strdup(value));
+       g_free(value);
+       extract_data(contact->data, "cn", (void **) &value);
+       list = g_slist_prepend(list, g_strdup(value));
+       g_free(value);
        
        for (cur = contact->emails; cur; cur = g_slist_next(cur)) {
                Email* e = (Email *) cur->data;
@@ -647,7 +691,7 @@ static gboolean match_string_pattern(const gchar* pattern,
 
 static void contact_compare_values(gpointer key, gpointer value, gpointer data) {
        Compare* comp = (Compare *) data;
-       gchar* cvalue;
+       AttribDef* attr;
        
        if (debug_get_mode()) {
                Contact* c = g_new0(Contact, 1);
@@ -658,9 +702,25 @@ static void contact_compare_values(gpointer key, gpointer value, gpointer data)
        }
        if ((comp->is_and && comp->equal) ||
                (!comp->is_and && (comp->equal < 0 || comp->equal == 0))) {
-               cvalue = g_hash_table_lookup(comp->hash, key);
-               comp->equal = match_string_pattern(value, cvalue, TRUE);
+               attr = g_hash_table_lookup(comp->hash, key);
+               if (attr) {
+                       if (attr->type == ATTRIB_TYPE_STRING) {
+                               comp->equal = match_string_pattern(
+                                       value, attr->value.string, TRUE);
+                       }
+                       else if (attr->type == ATTRIB_TYPE_CHAR) {
+                               gchar* ch = g_strdup_printf("%c", attr->value.character);
+                               comp->equal = match_string_pattern(value, ch, TRUE);
+                               g_free(ch);
+                       }
+                       else {
+                               /* TODO. How to compare int and boolean */
+                               comp->equal = FALSE;
+                       }
+               }
        }
+       else
+               comp->equal = FALSE;
 }
 
 static gboolean email_compare_values(GSList* a, GSList* b, gboolean is_and) {
@@ -691,6 +751,30 @@ static gboolean email_compare_values(GSList* a, GSList* b, gboolean is_and) {
        return equal;
 }
 
+static void reactivate_attribs(gpointer key, gpointer value, gpointer data) {
+       GSList** new_list = (GSList**) data;
+       GSList *cur;
+       gboolean more = TRUE;
+
+       for (cur = inactive_attribs; cur && more; cur = g_slist_next(cur)) {
+               AttribDef* attr = (AttribDef *) cur->data;
+               if (utf8_collate(attr->attrib_name, (gchar *) key) == 0) {
+                       *new_list = g_slist_remove(*new_list, attr);
+                       attrib_def_free(attr);
+                       more = FALSE;
+               }
+       }
+}
+
+static void deactivate_attribs(gpointer key, gpointer value, gpointer data) {
+       GHashTable* new_attr = (GHashTable *) data;
+       
+       //hash_table_dump(new_attr, stderr);
+       if (! g_hash_table_lookup_extended(new_attr, key, NULL, NULL)) {
+               inactive_attribs = g_slist_prepend(inactive_attribs, attrib_def_copy(value));
+       }
+}
+
 gboolean plugin_init(gchar** error) {
        gchar *basedir, *path;
        GSList *list = NULL, *cur, *found;
@@ -750,9 +834,25 @@ gboolean plugin_init(gchar** error) {
                                for (cur = list; cur; cur = g_slist_next(cur)) {
                                        gchar* key = (gchar *) cur->data;
                                        debug_print("Adding '%s' to attributes\n", key);
-                                       g_hash_table_replace(attribs, g_strdup(key), NULL);
+                                       AttribDef* attr = g_new0(AttribDef, 1);
+                                       attr->attrib_name = g_strdup(key);
+                                       attr->type = ATTRIB_TYPE_STRING;
+                                       g_hash_table_replace(attribs, g_strdup(key), attr);
                                }
-                               gslist_free(list, g_free);
+                               gslist_free(&list, g_free);
+
+                               config_get_value(config, "deactivated attributes", "attributes", &list);                                
+                               for (cur = list; cur; cur = g_slist_next(cur)) {
+                                       gchar* key = (gchar *) cur->data;
+                                       debug_print("Adding '%s' to deactivated attributes\n", key);
+                                       AttribDef* attr = g_new0(AttribDef, 1);
+                                       attr->attrib_name = g_strdup(key);
+                                       attr->type = ATTRIB_TYPE_STRING;
+                                       inactive_attribs = g_slist_prepend(inactive_attribs, attr);
+                               }
+                               gslist_free(&list, g_free);
+
+                               //hash_table_dump(attribs, stderr);
                        }
                }
                g_free(basedir);
@@ -777,6 +877,7 @@ gboolean plugin_done(void) {
        hash_table_free(&attribs);
        abooks_free();
        old_abook_free_dir();
+       gslist_free(&inactive_attribs, attrib_def_free);
        
        return TRUE;
 }
@@ -831,6 +932,14 @@ GSList* plugin_attrib_list(void) {
 }
 
 void plugin_attribs_set(GHashTable* attributes) {
+       GSList* new_list = gslist_deep_copy(inactive_attribs, attrib_def_copy);
+
+       //hash_table_dump(attributes, stderr);  
+       g_hash_table_foreach(attributes, reactivate_attribs, &new_list);
+       gslist_free(&inactive_attribs, attrib_def_free);
+       inactive_attribs = gslist_deep_copy(new_list, attrib_def_copy);
+       gslist_free(&new_list, attrib_def_free);
+       g_hash_table_foreach(attribs, deactivate_attribs, attributes);
        hash_table_free(&attribs);
        attribs = hash_table_copy(attributes);
 }
@@ -855,7 +964,7 @@ GSList* plugin_get_contact(
                                        found = match_string_pattern(search_token, attr, FALSE);
                                }
                        }
-                       gslist_free(list, g_free);
+                       gslist_free(&list, g_free);
                        if (found) {
                                contacts = g_slist_prepend(contacts, contact);
                                found = FALSE;
@@ -868,10 +977,14 @@ GSList* plugin_get_contact(
 
 gboolean plugin_set_contact(
                AddressBook* abook, const Contact* contact, gchar** error) {
+       gchar* uid = NULL;
        
-       gchar* uid = g_hash_table_lookup(contact->data, "uid");
-       if (! uid)
+       if (debug_get_mode())
+               contact_dump(contact, stderr);
+       extract_data(contact->data, "uid", (void **) &uid);
+       if (! uid || strlen(uid) < 1)
                contact_set_uid(abook, (Contact *) contact);
+       g_free(uid);
 
        addr_book_set_contact(abook, (Contact *) contact, error);
        if (*error)
@@ -897,10 +1010,11 @@ gboolean plugin_delete_contact(
 gboolean plugin_update_contact(
                AddressBook* abook, const Contact* contact, gchar** error) {
        
+       if (debug_get_mode())
+               contact_dump(contact, stderr);
        plugin_delete_contact(abook, contact, error);
        if (*error)
                return TRUE;
-               
        plugin_set_contact(abook, contact, error);
        if (*error)
                return TRUE;
@@ -1060,3 +1174,11 @@ gchar* plugin_default_url(const gchar* name) {
 gboolean plugin_commit_all(gchar** error) {
        return TRUE;
 }
+
+GSList* plugin_remaining_attribs(void) {
+       return NULL;
+}
+
+GSList* plugin_inactive_attribs(void) {
+       return gslist_deep_copy(inactive_attribs, attrib_def_copy);
+}
\ No newline at end of file
index 5903d2f87f2b81e443df3bba4c8f95abfa42a8bd..df99398309f98535bccc3d9c85a96e5636f14b54 100644 (file)
@@ -126,7 +126,7 @@ static void write_config() {
        g_key_file_set_string_list(config->key_file, PLUGINGROUP,
                        "plugins", (const gchar**) list, num);
        g_strfreev(list);
-       gslist_free(plugins, g_free);
+       gslist_free(&plugins, g_free);
        
        data = g_key_file_to_data(config->key_file, &len, &err);
        if (! err) {
@@ -425,8 +425,8 @@ void read_config(MainWindow* mainwindow) {
        }       
 
        plugin_load_all(window, plugins);
-       gslist_free(plugins, g_free);
-       gslist_free(book, g_free);
+       gslist_free(&plugins, g_free);
+       gslist_free(&book, g_free);
        
        g_free(configrc);
        if (mainwindow)
@@ -466,9 +466,9 @@ void list_view_append_contact(GtkTreeView* view, Contact* contact) {
                Email* email = (Email *) contact->emails->data;
                mail = email->email;
        }
-       first = g_hash_table_lookup(contact->data, "first-name");
-       last = g_hash_table_lookup(contact->data, "last-name");
-       cn = g_hash_table_lookup(contact->data, "cn");
+       extract_data(contact->data, "first-name", (void *) &first);
+       extract_data(contact->data, "last-name", (void *) &last);
+       extract_data(contact->data, "cn", (void *) &cn);
 
        gtk_list_store_append(store, &iter);
        gtk_list_store_set(store, &iter,
@@ -478,6 +478,9 @@ void list_view_append_contact(GtkTreeView* view, Contact* contact) {
                        CONTACT_EMAIL_COLUMN, mail,
                        CONTACT_DATA_COLUMN, contact,
        -1);
+       g_free(first);
+       g_free(last);
+       g_free(cn);
 }
 
 gchar* contact_write_to_backend(Plugin* plugin,
@@ -716,7 +719,7 @@ void abook_open_cb(GtkWidget* widget, gpointer data) {
        gboolean response = show_choice_list(win->window,
                        "[Open book] Select plugin to use",
                        plugins, &plugin_name);
-       gslist_free(plugins, NULL);
+       gslist_free(&plugins, NULL);
 
        if (response) {
                plugin = plugin_get_plugin(plugin_name);
@@ -792,7 +795,7 @@ void abook_new_cb(GtkWidget* widget, gpointer data) {
        gboolean response = show_choice_list(win->window,
                        "[New book] Select plugin to use",
                        plugins, &plugin_name);
-       gslist_free(plugins, NULL);
+       gslist_free(&plugins, NULL);
 
        if (response) {
                plugin = plugin_get_plugin(plugin_name);
@@ -901,14 +904,14 @@ void update_abook_list(MainWindow* mainwindow) {
                                        BOOK_DATA_COLUMN, book,
                                        BOOK_PLUGIN_COLUMN, reference->plugin, -1);
                }
-               gslist_free(reference->abooks, NULL);
+               gslist_free(&reference->abooks, NULL);
        }
        if (! ref) {
                gtk_widget_set_sensitive(mainwindow->search_btn, FALSE);
                gtk_widget_set_sensitive(mainwindow->adv_search_btn, FALSE);
                gtk_widget_set_sensitive(mainwindow->new_btn, FALSE);
        }
-       gslist_free(ref, NULL);
+       gslist_free(&ref, NULL);
 }
 
 void abook_list_cursor_changed_cb(GtkTreeView* tree_view, gpointer data) {
@@ -1504,21 +1507,24 @@ void tools_attribs_cb(GtkWidget* widget, gpointer data) {
        GSList* attribs = NULL;
        gchar* error = NULL;
        GHashTable* new_attribs = NULL;
+       AttribContainer* attr_container;
        gint i;
 
        plugins = plugin_get_name_all();
        gboolean response = show_choice_list(win->window,
                        "[Attributes] Select plugin to use",
                        plugins, &plugin_name);
-       gslist_free(plugins, NULL);
+       gslist_free(&plugins, NULL);
        if (response) {
                plugin = plugin_get_plugin(plugin_name);
 
+/*
                if (plugin->readonly) {
                        show_message(win->window, GTK_UTIL_MESSAGE_INFO,
                                        _("Plugin does not support updates"));
                        return;
                }
+*/
        
                if (plugin) {
                        attribs = plugin->attrib_list();
@@ -1527,16 +1533,28 @@ void tools_attribs_cb(GtkWidget* widget, gpointer data) {
                                AttribDef* attrdef = (AttribDef *) cur->data;
                                attr[i] = g_strdup(attrdef->attrib_name);
                        }
-                       gslist_free(attribs, attrib_def_free);
-                       new_attribs = get_attrib_list(win->window, (const gchar**) attr,
-                                       "Supported Attributes",
-                                       TRUE, &error, add_attrib_btn_cb);
+                       gslist_free(&attribs, attrib_def_free);
+                       attribs = plugin->inactive_attribs();
+                       gchar** inactive_attr = g_new0(gchar *, g_slist_length(attribs) + 1);
+                       for (cur = attribs, i = 0; cur; i++, cur = g_slist_next(cur)) {
+                               AttribDef* attrdef = (AttribDef *) cur->data;
+                               inactive_attr[i] = g_strdup(attrdef->attrib_name);
+                       }
+                       gslist_free(&attribs, attrib_def_free);
+                       attr_container = g_new0(AttribContainer, 1);
+                       attr_container->existing_attribs = (const gchar**) attr;
+                       attr_container->inactive_attribs = (const gchar **) inactive_attr;
+                       new_attribs = get_attrib_list(win->window, attr_container,
+                                       "Supported Attributes", TRUE, &error, add_attrib_btn_cb);
                        g_strfreev(attr);
+                       g_strfreev(inactive_attr);
+                       g_free(attr_container);
                        if (error) {
                                show_message(win->window, GTK_UTIL_MESSAGE_ERROR, "%s", error);
                                g_free(error);
                        }
                        else {
+                               //hash_table_dump(new_attribs, stderr);
                                plugin->attribs_set(new_attribs);
                        }
                        hash_table_free(&new_attribs);
@@ -1588,7 +1606,7 @@ void contact_basic_search_cb(GtkWidget* widget, gpointer data) {
                                list_view_append_contact(view, contact);
                        }
                }               
-               gslist_free(contacts, NULL);
+               gslist_free(&contacts, NULL);
        }
 }
 
@@ -1652,7 +1670,7 @@ void contact_advanced_search_cb(GtkWidget* widget, gpointer data) {
                                }
                                gtk_widget_set_sensitive(win->clear_btn, TRUE);
                        }               
-                       gslist_free(contacts, NULL);
+                       gslist_free(&contacts, NULL);
                        
                }
                else
index dc96a7df717e74f58a56e65ae04b4b7d6cfb965a..b5e87dcacd0266322daf057ac57490e1728286ec 100644 (file)
@@ -83,6 +83,7 @@ static gint contact_entry_data_size = 0;
 static gboolean contact_is_new = FALSE;
 
 static void email_list_add(GtkTreeView* view, ContactWindow* cw);
+static gchar* hash_table_get_entry(GHashTable* hash, const gchar* key);
 
 static void contact_entry_data_update(ContactWindow* cw) {
        gint i;
@@ -110,10 +111,14 @@ static void contact_entry_data_free(ContactEntryData** data) {
 static gboolean entry_dirty(GHashTable* hash,
                                                        const gchar* key,
                                                        const gchar* new_data) {
-       gchar* old_data =
-               g_hash_table_lookup(hash, key);
+       gchar* value = NULL;
        
-       return (xor(old_data, new_data));
+       value = hash_table_get_entry(hash, key);        
+       gboolean res = xor(value, new_data);
+       
+       g_free(value);
+       
+       return res;
 }
 
 static gboolean contact_dirty(ContactEntryData** data) {
@@ -183,23 +188,50 @@ static void save_contact(ContactWindow* cw, gchar** error) {
        gboolean changed = FALSE;
        Contact *contact, *cur = NULL;
        const gchar* new_data;
+       void* value = NULL;
+       AttribDef* attr;
+       gchar* tmp = NULL;
+       gboolean bool;
+       gchar ch;
+       gint num;
        
        contact = cw->contact;
                
        for (i = 0; i < contact_entry_data_size; i++) {
                cur = cw->data[i]->contact;
                if (cur && cur->data && cw->data[i]->key) {
-                       gchar* old_data =
-                               g_hash_table_lookup(cur->data, cw->data[i]->key);
+                       attr = g_hash_table_lookup(cur->data, cw->data[i]->key);
+                       if (attr) {
+                               AttribType type = get_data(attr, &value);
+                               switch (type) {
+                                       case ATTRIB_TYPE_BOOLEAN:
+                                               bool = *(gboolean *) value;
+                                               tmp = (bool) ? g_strdup("true") : g_strdup("false");
+                                               break;
+                                       case ATTRIB_TYPE_CHAR:
+                                               ch = *(gchar *) value;
+                                               tmp = g_strdup_printf("%c", ch);
+                                               break;
+                                       case ATTRIB_TYPE_INT:
+                                               num = *(gint *) value;
+                                               tmp = g_strdup_printf("%i", num);
+                                               break;
+                                       case ATTRIB_TYPE_STRING:
+                                               tmp = g_strdup((gchar *) value);
+                                               break;
+                               }
+                               g_free(value);
+                       }
                        if (cw->data[i]->entry)
                                new_data = gtk_entry_get_text(GTK_ENTRY(cw->data[i]->entry));
                        else
                                new_data = NULL;
-                       if (xor(old_data, new_data)) {
-                               g_hash_table_replace(contact->data,
-                                       g_strdup(cw->data[i]->key), g_strdup(new_data));
+                       if (xor(tmp, new_data)) {
+                               swap_data(contact->data, cw->data[i]->key, new_data);
                                changed = TRUE;
                        }
+                       g_free(tmp);
+                       tmp = NULL;
                }
        }
        
@@ -361,7 +393,7 @@ static void email_delete_cb(GtkWidget* widget, gpointer data) {
                                        email_list_add(GTK_TREE_VIEW(cw->email_list), cw);
                                        cur = NULL;
                                        cur = g_slist_prepend(cur, remove);
-                                       gslist_free(cur, g_free);
+                                       gslist_free(&cur, g_free);
                                }
                        }
                }
@@ -427,11 +459,30 @@ static void contact_set_attr(Contact* contact,
 }
 
 static gchar* hash_table_get_entry(GHashTable* hash, const gchar* key) {
-       gchar* value;
+       AttribDef* attr;
+       gchar* value = NULL;
        
-       value = g_hash_table_lookup(hash, key);
+       attr = g_hash_table_lookup(hash, key);
        
-       return (value) ? value : "";
+       if (attr) {
+               switch (attr->type) {
+                       case ATTRIB_TYPE_BOOLEAN:
+                               value = (attr->value.boolean) ? g_strdup("true") : g_strdup("false");
+                               break;
+                       case ATTRIB_TYPE_INT:
+                               value = g_new0(gchar, 5);
+                               sprintf(value, "%i", attr->value.number);
+                               break;
+                       case ATTRIB_TYPE_CHAR:
+                               value = g_new0(gchar, 1);
+                               sprintf(value, "%c", attr->value.character);
+                               break;
+                       case ATTRIB_TYPE_STRING:
+                               value = g_strdup(attr->value.string);
+                               break;
+               }
+       }
+       return (value) ? value : g_strdup("");
 }
 
 static void contact_image_change(gpointer data) {
@@ -475,8 +526,7 @@ static void contact_image_change(gpointer data) {
                
                if (pixbuf) {
                        gchar* image = base64_encode_data(file);
-                       g_hash_table_replace(cw->contact->data,
-                                       g_strdup("image"), g_strdup(image));
+                       swap_data(cw->contact->data, "image", image);
                        g_free(image);
                        GtkWidget* parent = gtk_widget_get_parent(cw->image);
                        gtk_widget_destroy(cw->image);
@@ -609,9 +659,10 @@ static GtkWidget* create_entry_row(GHashTable* hash,
                if (hash)
                        value = hash_table_get_entry(hash, data->key);
                else
-                       value = "";
+                       value = g_strdup("");
        
                gtk_entry_set_text(GTK_ENTRY(entry), value);
+               g_free(value);
                hbox = gtk_hbox_new(FALSE, 5);
                gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
                gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
@@ -745,7 +796,7 @@ static void row_deleted_cb(GtkTreeModel *tree_model,
        gchar* s = gtk_tree_path_to_string(path);
        debug_print("deleted: %s\n", s);
        g_free(s);
-       gslist_free(cw->contact->emails, email_free);
+       gslist_free(&cw->contact->emails, email_free);
        cw->contact->emails = NULL;
        gtk_tree_model_foreach(tree_model, contact_reorder_emails, cw);
        contact_update(cw, cw->contact);
@@ -797,11 +848,16 @@ static void contact_widget(ContactWindow* cw) {
        gtk_frame_set_label_widget(GTK_FRAME(frame), label_photo);
        
        if (cw->contact->data) {
-               photo = g_hash_table_lookup(cw->contact->data, "image");
-               if (photo) {
-                       pixbuf = contact_load_image(cw->main->window, photo);
-                       if (! pixbuf)
-                               photo = NULL;
+               if (debug_get_mode())
+                       contact_dump(cw->contact, stderr);
+               AttribDef* attr = g_hash_table_lookup(cw->contact->data, "image");
+               if (attr) {
+                       photo = attr->value.string;
+                       if (photo) {
+                               pixbuf = contact_load_image(cw->main->window, photo);
+                               if (! pixbuf)
+                                       photo = NULL;
+                       }
                }
        }
        
@@ -981,8 +1037,7 @@ static void contact_search_get(ContactEntryData** data, Contact* contact) {
                                                email->remarks = g_strdup(value);
                                }
                                else
-                                       g_hash_table_replace(
-                                               contact->data, g_strdup(data[i]->key), g_strdup(value));
+                                       swap_data(contact->data, data[i]->key, value);
                        }
                }
        }
@@ -1025,7 +1080,7 @@ gboolean contact_show(MainWindow* main, Contact* contact, gchar** error) {
                        AttribDef* attrdef = g_slist_nth_data(attr, i);
                        dialog->data[i]->key = g_strdup(attrdef->attrib_name);
                }                               
-               gslist_free(attr, attrib_def_free);
+               gslist_free(&attr, attrib_def_free);
 
                if (! dialog->contact) {
                        contact_is_new = TRUE;
@@ -1111,7 +1166,7 @@ Contact* contact_search_show(MainWindow* main, gboolean* is_and, gchar** error)
                        gtk_widget_set_tooltip_text(row, tooltip);
                        gtk_box_pack_start(vbox, row, FALSE, TRUE, 0);
                }                               
-               gslist_free(attr, attrib_def_free);
+               gslist_free(&attr, attrib_def_free);
 
                data[pos] = g_new0(ContactEntryData, 1);
                data[pos]->key = g_strdup("alias");
index 6dd17f17e8f9d50da34bf4ed2056fba7feba6556..744be1e8bd0db33f604ec89869f11bc551aa1594 100644 (file)
@@ -282,8 +282,7 @@ static void get_emails(GPtrArray* array,
         g_message("%s", err);
         g_free(err);
         err = NULL;
-        gslist_free(result, NULL);
-        result = NULL;
+        gslist_free(&result, NULL);
         return;
     }
     for (contacts = result; contacts; contacts = g_slist_next(contacts)) {
@@ -294,7 +293,7 @@ static void get_emails(GPtrArray* array,
             g_ptr_array_add(array, g_strdup(text[i]));
         g_strfreev(text);
     }
-    gslist_free(result, NULL);
+    gslist_free(&result, NULL);
     plugin->abook_close(abook, &err);
 }
 
@@ -573,10 +572,10 @@ gboolean abook_book_list(ServerObject*  server,
             list = g_slist_prepend(list, g_strdup(ab->abook_name));
         }
     }
-    gslist_free(abooks, NULL);
+    gslist_free(&abooks, NULL);
 
     *books = gslist_to_array(list, NULL);
-    gslist_free(list, g_free);
+    gslist_free(&list, g_free);
         
     return response;
 }
@@ -654,7 +653,7 @@ gboolean abook_search_addressbook(ServerObject* server,
         debug_print("%s", *reply);
     g_message("End receive");
 
-    gslist_free(abooks, NULL);    
+    gslist_free(&abooks, NULL);    
     return response;
 }
 
@@ -689,7 +688,7 @@ gboolean abook_add_contact(ServerObject*   server,
         g_free(config);
         if (default_book) {
             search_book = g_strdup((gchar *) default_book->data);
-            gslist_free(default_book, g_free);
+            gslist_free(&default_book, g_free);
         }
         if (! search_book) {
             g_set_error(error,
index 87cf9c1de068380414b1e71f9198d46f1dc675c2..9497337554449791bfc2dd332793eaa27b1e4d86 100644 (file)
 #include "gtk-utils.h"
 #include "utils.h"
 #include "plugin-loader.h"
+#include "plugin.h"
 
 typedef struct {
        GHashTable*     hash_table;
        gchar*          error;
 } CallbackData;
 
+typedef struct {
+       GtkWidget*      parent;
+       GtkWidget*      vbox;
+} ButtonCB;
+
+
 static void callback_data_free(CallbackData* data) {
        hash_table_free(&data->hash_table);
        g_free(data->error);
@@ -57,14 +64,18 @@ static void collect_attribs_cb(GtkWidget* widget, gpointer data) {
        GtkWidget* btn;
        const gchar* label;
        gboolean use;
+       AttribDef* attr;
        
        btn = gtk_bin_get_child(GTK_BIN(widget));
        if (btn) {
                use = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn));
                if (use) {
                        label = gtk_button_get_label(GTK_BUTTON(btn));
+                       attr = g_new0(AttribDef, 1);
+                       attr->attrib_name = g_strdup(label);
+                       attr->type = ATTRIB_TYPE_STRING;
                        g_hash_table_replace(
-                               callback_data->hash_table, g_strdup(label), NULL);
+                               callback_data->hash_table, g_strdup(label), attr);
                }
        }
 }
@@ -164,7 +175,7 @@ gboolean show_input(GtkWidget* parent, const gchar* title, gchar** reply,
 }
 
 GHashTable* get_attrib_list(GtkWidget* parent, 
-                                                       const gchar **existing_attribs,
+                                                       AttribContainer* attrib_lists,
                                                        const gchar* info_text, gboolean can_delete,
                                                        gchar** error, AddAttribCallback callback) {
        GtkWidget *header, *dialog, *window, *vbox1, *attrib_box,
@@ -172,7 +183,12 @@ GHashTable* get_attrib_list(GtkWidget* parent,
        gint i;
        GHashTable*     hash_table = NULL;
        CallbackData* callback_data;
+       ButtonCB* button_cb;
        
+       if (! attrib_lists || 
+                       (! attrib_lists->existing_attribs && ! attrib_lists->inactive_attribs))
+               return NULL;
+
        callback_data = g_new0(CallbackData, 1);
        callback_data->hash_table = hash_table_new();
        callback_data->error = NULL;
@@ -195,8 +211,9 @@ GHashTable* get_attrib_list(GtkWidget* parent,
        gtk_scrolled_window_add_with_viewport(
                        GTK_SCROLLED_WINDOW(window), attrib_box);
        
-       for(i = 0; existing_attribs[i]; i++) {
-               GtkWidget* check_btn = gtk_check_button_new_with_label(existing_attribs[i]);
+       for(i = 0; attrib_lists->existing_attribs[i]; i++) {
+               GtkWidget* check_btn = gtk_check_button_new_with_label(
+                               attrib_lists->existing_attribs[i]);
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_btn), TRUE);
                gtk_widget_set_sensitive(check_btn, can_delete);
                GtkWidget* frame = gtk_frame_new(NULL);
@@ -204,14 +221,29 @@ GHashTable* get_attrib_list(GtkWidget* parent,
                gtk_box_pack_start(GTK_BOX(attrib_box), frame, FALSE, TRUE, 0);
        }
        
+       if (attrib_lists->inactive_attribs && *attrib_lists->inactive_attribs) {
+               for(i = 0; attrib_lists->inactive_attribs[i]; i++) {
+                       GtkWidget* check_btn = gtk_check_button_new_with_label(
+                                       attrib_lists->inactive_attribs[i]);
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_btn), FALSE);
+                       gtk_widget_set_sensitive(check_btn, can_delete);
+                       GtkWidget* frame = gtk_frame_new(NULL);
+                       gtk_container_add(GTK_CONTAINER(frame), check_btn);
+                       gtk_box_pack_start(GTK_BOX(attrib_box), frame, FALSE, TRUE, 0);
+               }
+       }
+       
        gtk_box_pack_start(GTK_BOX(vbox1), frame2, TRUE, TRUE, 0);
 
        hbtnbox = gtk_hbutton_box_new();
        gtk_button_box_set_layout(GTK_BUTTON_BOX(hbtnbox), GTK_BUTTONBOX_CENTER);
        add_attrib_btn = gtk_button_new_with_mnemonic("_Add attribute");
        gtk_box_pack_start_defaults(GTK_BOX(hbtnbox), add_attrib_btn);
+       button_cb = g_new0(ButtonCB, 1);
+       button_cb->parent = parent;
+       button_cb->vbox = attrib_box;
        g_signal_connect(
-                       add_attrib_btn, "clicked", G_CALLBACK(callback), attrib_box);
+                       add_attrib_btn, "clicked", G_CALLBACK(callback), button_cb);
        gtk_box_pack_start(GTK_BOX(vbox1), hbtnbox, FALSE, TRUE, 0);
        
        gtk_widget_show_all(vbox1);
@@ -239,14 +271,18 @@ GHashTable* get_attrib_list(GtkWidget* parent,
                        }
                        break;
                default:
-                       for(i = 0; existing_attribs[i]; i++) {
+                       for(i = 0; attrib_lists->existing_attribs[i]; i++) {
+                               AttribDef* attr = g_new0(AttribDef, 1);
+                               attr->attrib_name = g_strdup(attrib_lists->existing_attribs[i]);
+                               attr->type = ATTRIB_TYPE_STRING;
                                g_hash_table_replace(callback_data->hash_table,
-                                               g_strdup(existing_attribs[i]), NULL);
+                                       g_strdup(attrib_lists->existing_attribs[i]), attr);
                        }
                        hash_table = hash_table_copy(callback_data->hash_table);
                        break;
        }
        gtk_widget_destroy(dialog);
+       g_free(button_cb);
        callback_data_free(callback_data);
 
        return hash_table;
@@ -260,17 +296,18 @@ void add_widget_attrib_list(GtkWidget* vbox, GtkWidget* check_btn) {
                gtk_box_reorder_child(GTK_BOX(vbox), frame, 0);
 }
 
-void add_attrib_btn_cb(GtkWidget* parent, GtkWidget* widget, gpointer data) {
-       GtkWidget* vbox = (GtkWidget *) data;
+void add_attrib_btn_cb(GtkWidget* widget, gpointer data) {
+       ButtonCB* button_cb = (ButtonCB *) data;
        gchar* reply = NULL;
        
        if (show_input(
-               parent, "Define new attribute", &reply, "Enter name for new attribute")) {
+               button_cb->parent, "Define new attribute",
+                               &reply, "Enter name for new attribute")) {
                GtkWidget* check_btn = gtk_check_button_new_with_label(reply);
                g_free(reply);
                gtk_widget_show(check_btn);
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_btn), TRUE);
-               add_widget_attrib_list(vbox, check_btn);
+               add_widget_attrib_list(button_cb->vbox, check_btn);
        }
 }
 
index 2f0200da1760f1acc63568f20d1800af21ed17d9..73eaa22037de921bca8fe0c1ede3cfab35597f8b 100644 (file)
@@ -58,22 +58,30 @@ typedef struct {
        gchar* name;
 } RowData;
 
+/*
 struct RowContainer {
        GSList* rows;
 };
+*/
+
+typedef struct {
+       const gchar **existing_attribs;
+       const gchar **inactive_attribs;
+       const gchar **remaining_attribs;
+} AttribContainer;
 
-typedef void (*AddAttribCallback) (GtkWidget* parent, GtkWidget* widget, gpointer data);
+typedef void (*AddAttribCallback) (GtkWidget* widget, gpointer data);
 
 void show_message(GtkWidget* parent, MessageType type, const gchar* format, ...);
 gboolean show_question(GtkWidget* parent, const gchar* format, ...);
 gboolean show_input(GtkWidget* parent, const gchar* title,
                                        gchar** reply, const gchar* format, ...);
 GHashTable* get_attrib_list(GtkWidget* parent,
-                                                       const gchar **existing_attribs,
+                                                       AttribContainer* attrib_lists,
                                                        const gchar* info_text, gboolean can_delete,
                                                        gchar** error, AddAttribCallback callback);
 void add_widget_attrib_list(GtkWidget* vbox, GtkWidget* check_btn);
-void add_attrib_btn_cb(GtkWidget* parent, GtkWidget* widget, gpointer data);
+void add_attrib_btn_cb(GtkWidget* widget, gpointer data);
 gboolean show_choice_list(GtkWidget* parent,
                                                  const gchar* title,
                                                  GSList* choices,
index f600b98fc67d12c58cc08e7a7362daf15e3914ef..bbfbb25263e038f6e7b77d6763213b7bd3857254 100644 (file)
@@ -183,8 +183,8 @@ static void set_plugin_list(PluginWindow* pluginwindow) {
        if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
                gtk_tree_selection_select_iter(selection, &iter);
                
-       gslist_free(loaded, NULL);
-       gslist_free(unloaded, NULL);
+       gslist_free(&loaded, NULL);
+       gslist_free(&unloaded, NULL);
 }
 
 static void load_plugin_cb(GtkWidget* widget, gpointer data) {
@@ -232,7 +232,7 @@ static void load_plugin_cb(GtkWidget* widget, gpointer data) {
                                set_plugin_list(pluginwindow);
                                g_free(file);
                        }
-                       gslist_free(files, NULL);
+                       gslist_free(&files, NULL);
                }
        }
        else
@@ -441,7 +441,7 @@ static Plugin* plugin_allready_loaded(Plugin* plugin, gchar** error) {
                        break;
                }
        }
-       gslist_free(plugins, NULL);
+       gslist_free(&plugins, NULL);
 
        if (! found) {
                plugins = plugin_get_unloaded_list();
@@ -452,7 +452,7 @@ static Plugin* plugin_allready_loaded(Plugin* plugin, gchar** error) {
                                break;
                        }
                }
-               gslist_free(plugins, NULL);
+               gslist_free(&plugins, NULL);
                
                if (found) {
                        g_free(found->error);
@@ -615,7 +615,8 @@ Plugin* plugin_load(const gchar* filename, gchar** error) {
                         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_url, plugin_attribs_set, plugin_commit_all,
+                        plugin_remaining_attribs, plugin_inactive_attribs;
 
        plugin = g_new0(Plugin, 1);
        if (plugin == NULL) {
@@ -647,7 +648,9 @@ Plugin* plugin_load(const gchar* filename, gchar** error) {
                !g_module_symbol(plugin->module, "plugin_abook_delete", &plugin_abook_delete) ||
                !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_init", &plugin_init) ||
+               !g_module_symbol(plugin->module, "plugin_remaining_attribs", &plugin_remaining_attribs) ||
+               !g_module_symbol(plugin->module, "plugin_inactive_attribs", &plugin_inactive_attribs)) {
                *error = g_strdup(g_module_error());
                g_module_close(plugin->module);
                g_free(plugin);
@@ -724,6 +727,8 @@ Plugin* plugin_load(const gchar* filename, gchar** error) {
        plugin->abook_set_config = plugin_abook_set_config;
        plugin->default_url = plugin_url;
        plugin->abooks_commit_all = plugin_commit_all;
+       plugin->remaining_attribs = plugin_remaining_attribs;
+       plugin->inactive_attribs = plugin_inactive_attribs;
        
        compute_hash(plugin);
 
@@ -831,10 +836,10 @@ void plugin_unload_all() {
                plugin_unload(plugin);
        }
                
-       gslist_free(plugins, NULL);
-       gslist_free(unloaded_plugins, NULL);
-       gslist_free(loaded, NULL);
-       gslist_free(unloaded, NULL);
+       gslist_free(&plugins, NULL);
+       gslist_free(&unloaded_plugins, NULL);
+       gslist_free(&loaded, NULL);
+       gslist_free(&unloaded, NULL);
 }
 
 GSList* plugin_get_name_all() {
@@ -846,7 +851,7 @@ GSList* plugin_get_name_all() {
                Plugin *plugin = (Plugin *) cur->data;
                names = g_slist_prepend(names, g_strdup(plugin->name()));
        }
-       gslist_free(loaded, NULL);
+       gslist_free(&loaded, NULL);
 
        return names;
 }
@@ -860,7 +865,7 @@ GSList* plugin_get_path_all() {
                Plugin *plugin = (Plugin *) cur->data;
                names = g_slist_prepend(names, g_strdup(plugin->filename));
        }
-       gslist_free(loaded, NULL);
+       gslist_free(&loaded, NULL);
 
        return names;
 }
@@ -877,7 +882,7 @@ GSList* address_books_get() {
                ref->abooks = ref->plugin->addrbook_all_get();
                addr_books = g_slist_prepend(addr_books, ref);
        }
-       gslist_free(loaded, NULL);
+       gslist_free(&loaded, NULL);
        
        return addr_books;
 }
@@ -894,7 +899,7 @@ Plugin* plugin_get_plugin(const gchar* name) {
                        break;
                plugin = NULL;
        }
-       gslist_free(loaded, NULL);
+       gslist_free(&loaded, NULL);
        
        return plugin;
 }
@@ -914,7 +919,7 @@ Reference* address_book_reference_get(const gchar* name) {
                                found_book = TRUE;
                }
        }
-       gslist_free(books, NULL);
+       gslist_free(&books, NULL);
        
        return (found_book) ? ref : NULL;
 }
index fd48a7841e2fff877fb9824d73060b46673e9fee..070f382d537eeef340575a2e92afa4e60b719e69 100644 (file)
@@ -55,6 +55,8 @@ typedef struct {
        const gchar* (*license) (void);
        const gchar* (*filter) (void);
        gchar* (*default_url) (const gchar* name);
+       GSList* (*remaining_attribs) (void);
+       GSList* (*inactive_attribs) (void);
        PluginFeature* (*provides) (void);
        GSList* (*attrib_list) (void);
        void (*attribs_set) (GHashTable* attributes);
index 99cdb8cb242d2993ff7645b6e14bb0414cb66cec..e6264b1b36066729f7403b8f680d46b39c8a464f 100644 (file)
@@ -55,14 +55,22 @@ typedef struct {
 
 typedef enum {
        ATTRIB_TYPE_INT,
-       ATTRIB_TYPE_CHAR,
        ATTRIB_TYPE_BOOLEAN,
+       ATTRIB_TYPE_CHAR,
        ATTRIB_TYPE_STRING
 } AttribType;
 
+typedef union {
+               gint            number;
+               gboolean        boolean;
+               gchar           character;
+               gchar*          string;
+} Value;
+
 typedef struct {
-       gchar*          attrib_name;
        AttribType      type;
+       gchar*          attrib_name;
+       Value           value;
 } AttribDef;
 
 typedef struct {
@@ -115,6 +123,9 @@ const gchar* plugin_version(void);
 const gchar* plugin_type(void);
 const gchar* plugin_license(void);
 gchar* plugin_default_url(const gchar* name);
+GSList* plugin_remaining_attribs(void);
+GSList* plugin_inactive_attribs(void);
+
 gboolean plugin_abook_open(AddressBook* abook, gchar** error);
 gboolean plugin_abook_close(AddressBook* abook, gchar** error);
 gboolean plugin_abook_delete(AddressBook* abook, gchar** error);
index a41c4af393ab13b51496008229642fd444dd54f9..db11b825023d1d73726cd24e92f8b65a6c8f938a 100644 (file)
@@ -63,15 +63,39 @@ static GtkPrintSettings* settings = NULL;
 static void contact_get_data(gpointer key, gpointer value, gpointer data) {
        PrintData* pd = (PrintData *) data;
        gchar *k, *v;
+       void* val = NULL;
+       gboolean bool;
+       gchar ch;
+       gint i;
        
        k = (gchar *) key;
-       v = (gchar *) value;
+       AttribType type = get_data((AttribDef *) value, &val);
+       switch (type) {
+               case ATTRIB_TYPE_BOOLEAN:
+                       bool = *(gboolean *) val;
+                       v = (bool) ? g_strdup("true") : g_strdup("false");
+                       break;
+               case ATTRIB_TYPE_CHAR:
+                       ch = *(gchar *) val;
+                       v = g_strdup_printf("%c", ch);
+                       break;
+               case ATTRIB_TYPE_INT:
+                       i = *(gint *) val;
+                       v = g_strdup_printf("%i", i);
+                       break;
+               case ATTRIB_TYPE_STRING:
+                       v = g_strdup((gchar *) val);
+                       break;
+       }
+       g_free(val);
+       
        if (strcmp(k, "uid") != 0 && strcmp(k, "image") != 0 &&
                                strlen(k) > 0 && strlen(v) > 0) {
                pd->lines[pd->total_lines++] = g_strdup_printf("%s: %s", k, v);
                pd->lines = g_renew(gchar *, pd->lines, pd->total_lines + 1);
                pd->lines[pd->total_lines] = NULL;
        }
+       g_free(v);
 }
 
 static void email_get_data(GSList* emails, PrintData* pd) {
@@ -99,7 +123,7 @@ static void end_print(GtkPrintOperation *operation,
        PrintData* pd = (PrintData *) data;
 
        g_strfreev(pd->lines);
-       gslist_free(pd->contacts, NULL);
+       gslist_free(&pd->contacts, NULL);
        g_free(pd);
 }
 
index 9dd77eca6dbf59adb240cc7afa6a340c35d697e0..1f1dab74a018dced9ea0d1d1dd0b550c95bf6c48 100644 (file)
@@ -65,7 +65,7 @@ static void set_default_abook(MainWindow* win,
        
        g_free(name);
        config_set_value(config, "Settings", "default book", list);
-       gslist_free(list, g_free);
+       gslist_free(&list, g_free);
        update_abook_list(win);
 }
 
index d6b6fc51e90051afcf7d65fe75d1ec6f5caaa60c..a6b28ab5cc02952fe18731c2c5f61a9b59d06b8b 100644 (file)
@@ -86,8 +86,8 @@ static void hash_table_copy_entry(gpointer key,
                                                                  gpointer user_data) {
     GHashTable* hash = (GHashTable *) user_data;
 
-       debug_print("Key: %s - Value: %s\n", key, value);
-    g_hash_table_replace(hash, g_strdup(key), g_strdup(value));
+       debug_print("Key: %s - Value: %p\n", key, value);
+    g_hash_table_replace(hash, g_strdup(key), attrib_def_copy(value));
 }
 
 /*
@@ -226,18 +226,20 @@ gchar* get_self_home() {
        return g_strconcat(get_home(), G_DIR_SEPARATOR_S, self_home, NULL);
 }
 
-void gslist_free(GSList* list, void (*elem_free) (gpointer data)) {
+void gslist_free(GSList** list, void (*elem_free) (gpointer data)) {
        GSList* cur;
        
-       if (list == NULL)
+       if (!list || !*list)
                return;
 
        if (elem_free) {
-               for (cur = list; cur; cur = g_slist_next(cur)) {
+               for (cur = *list; cur; cur = g_slist_next(cur)) {
                        elem_free(cur->data);
+                       cur->data = NULL;
                }
        }
-       g_slist_free(list);     
+       g_slist_free(*list);
+       *list = NULL;
 }
 
 void hash_table_free(GHashTable** hash_table) {
@@ -253,7 +255,8 @@ void hash_table_free(GHashTable** hash_table) {
 GHashTable* hash_table_new(void) {
        GHashTable* hash_table;
        
-       hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+       hash_table = g_hash_table_new_full(
+                       g_str_hash, g_str_equal, g_free, attrib_def_free);
                
        return hash_table;
 }
@@ -333,8 +336,37 @@ gboolean first_time(const gchar* subpath, const gchar* config, gchar** error) {
 void attrib_def_free(gpointer attrdef) {
        AttribDef* a = (AttribDef *) attrdef;
        
-       g_free(a->attrib_name);
+       if (a->attrib_name) {
+               g_free(a->attrib_name);
+               a->attrib_name = NULL;
+       }
+       if (a->type == ATTRIB_TYPE_STRING && a->value.string) {
+               g_free(a->value.string);
+               a->value.string = NULL;
+       }
        g_free(a);
+       a = NULL;
+}
+
+gpointer attrib_def_copy(gpointer a) {
+       AttribDef* a1;
+       AttribDef* a2;
+       
+       if (!a)
+               return NULL;
+
+       a1 = g_new0(AttribDef, 1);
+       a2 = (AttribDef *) a;
+               
+       if (a2->attrib_name)
+               a1->attrib_name = g_strdup(a2->attrib_name);
+       a1->type = a2->type;
+       if (a2->type == ATTRIB_TYPE_STRING)
+               a1->value.string = g_strdup(a2->value.string);
+       else
+               a1->value = a2->value;
+       
+       return (gpointer) a1;
 }
 
 void hash_table_keys_to_slist(gpointer key, gpointer value, gpointer slist) {
@@ -542,13 +574,13 @@ void plugin_config_free(ConfigFile** config_file) {
        g_free(config->comment);
        if (cf_books) {
                g_free(cf_books->group);
-               gslist_free(cf_books->books, g_free);
+               gslist_free(&cf_books->books, g_free);
                g_free(cf_books);
                cf_books = NULL;
        }
        if (cl_books) {
                g_free(cl_books->group);
-               gslist_free(cl_books->books, g_free);
+               gslist_free(&cl_books->books, g_free);
                g_free(cl_books);
                cl_books = NULL;
        }
@@ -631,7 +663,7 @@ void contact_free(gpointer contact) {
        if (debug_get_mode())
                contact_dump(c, stderr);        
        hash_table_free(&c->data);
-       gslist_free(c->emails, email_free);
+       gslist_free(&c->emails, email_free);
 }
 
 AddressBook* address_book_get(Plugin* plugin, const gchar* name) {
@@ -649,7 +681,7 @@ AddressBook* address_book_get(Plugin* plugin, const gchar* name) {
                abook = NULL;
        }
        
-       gslist_free(books, NULL);
+       gslist_free(&books, NULL);
        
        return abook;
 }
@@ -688,27 +720,29 @@ gboolean contact_compare(Contact* a, Contact* b, gboolean is_and) {
 
 gboolean contact_compare_attrib(Contact* a, Contact* b, const AttribDef* compare) {
        gboolean result = FALSE;
-       gpointer a_id, b_id;
+       AttribDef *a_id, *b_id;
        gint res;
        
        if (!a || !a->data || !b || !b->data || !compare || !compare->attrib_name)
                return result;
                
-       a_id = g_hash_table_lookup(a->data, compare->attrib_name);
-       b_id = g_hash_table_lookup(b->data, compare->attrib_name);
+       a_id = (AttribDef *) g_hash_table_lookup(a->data, compare->attrib_name);
+       b_id = (AttribDef *) g_hash_table_lookup(b->data, compare->attrib_name);
        if (!a_id || !b_id)
                return result;
        
        switch (compare->type) {
                case ATTRIB_TYPE_BOOLEAN:
+                       result = a_id->value.boolean == b_id->value.boolean;
+                       break;
                case ATTRIB_TYPE_INT:
-                       result = GPOINTER_TO_INT(a_id) == GPOINTER_TO_INT(b_id);
+                       result = a_id->value.number == b_id->value.number;
                        break;
                case ATTRIB_TYPE_CHAR:
-                       result = (gchar *) a_id == (gchar *) b_id;
+                       result = a_id->value.character == b_id->value.character;
                        break;
                case ATTRIB_TYPE_STRING:
-                       res = g_utf8_collate((gchar *) a_id, (gchar *) b_id);
+                       res = g_utf8_collate(a_id->value.string, b_id->value.string);
                        result = (res == 0);
        }
        
@@ -811,11 +845,32 @@ AddressBook* address_book_copy(AddressBook* a, gboolean deep) {
 
 void contact_data_print(gpointer key, gpointer value, gpointer data) {
        FILE* f = (FILE *) data;
-       
+       AttribDef* attr = (AttribDef *) value;
+       gchar* val = NULL;
+       
+       if (attr) {
+               switch (attr->type) {
+                       case ATTRIB_TYPE_BOOLEAN:
+                               val = (attr->value.boolean) ? g_strdup("true") : g_strdup("false");
+                               break;
+                       case ATTRIB_TYPE_INT:
+                               val = g_strdup_printf("%i", attr->value.number);
+                               break;
+                       case ATTRIB_TYPE_CHAR:
+                               val = g_strdup_printf("%c", attr->value.character);
+                               break;
+                       case ATTRIB_TYPE_STRING:
+                               val = g_strdup(attr->value.string);
+                               break;
+               }
+       }
+               
        if (f)
-               fprintf(f, "Key: %s - Value: %s\n", (gchar *) key, (gchar *) value);
+               fprintf(f, "Key: %s - Value: %s\n", (gchar *) key, val);
        else
-               g_message("Key: %s - Value: %s", (gchar *) key, (gchar *) value);
+               g_message("Key: %s - Value: %s", (gchar *) key, val);
+       
+       g_free(val);
 }
 
 void contact_dump(Contact* contact, FILE* f) {
@@ -973,7 +1028,132 @@ gboolean attribute_supported(Plugin* plugin, const gchar* attribute) {
                if (utf8_collate(def->attrib_name, (gchar *) attribute) == 0)
                        found = TRUE;
        }
-       gslist_free(attribs, attrib_def_free);
+       gslist_free(&attribs, attrib_def_free);
        
        return found;
 }
+
+GSList* gslist_deep_copy(GSList* list, COPYFUNC copy_func) {
+       GSList *new = NULL, *cur;
+       
+       if (!copy_func || !list)
+               return new;
+       
+       for (cur = list; cur; cur = g_slist_next(cur)) {
+               new = g_slist_prepend(new, copy_func(cur->data));
+       }
+       
+       return new;
+}
+
+static void hash_print(gpointer key, gpointer value, gpointer data) {
+       FILE* f = (FILE *) data;
+       AttribDef* attr = (AttribDef *) value;
+       const gchar* type;
+       
+       switch (attr->type) {
+               case ATTRIB_TYPE_INT: type = "INT"; break;
+               case ATTRIB_TYPE_CHAR: type = "CHAR"; break;
+               case ATTRIB_TYPE_BOOLEAN: type = "BOOLEAN"; break;
+               case ATTRIB_TYPE_STRING: type = "STRING"; break;
+       }
+       
+       fprintf(f, "key: %s\n\tname: %s\n\ttype: %s\n",
+               (gchar *) key, attr->attrib_name, type);
+}
+
+void hash_table_dump(GHashTable* hash, FILE* f) {
+       if (!hash || !f)
+               return;
+               
+       g_hash_table_foreach(hash, hash_print, (gpointer) f);
+}
+
+AttribDef* pack_data(AttribType type, const gchar* name, const void* value) {
+       AttribDef* data;
+       
+       data = g_new0(AttribDef, 1);
+       data->type = type;
+       if (name)
+               data->attrib_name = g_strdup(name);
+       switch (type) {
+               case ATTRIB_TYPE_INT:
+                       data->value.number = *(gint *) value;
+                       break;
+               case ATTRIB_TYPE_BOOLEAN:
+                       data->value.boolean = *(gboolean *) value;
+                       break;
+               case ATTRIB_TYPE_CHAR:
+                       data->value.character = *(char *) value;
+                       break;
+               case ATTRIB_TYPE_STRING:
+                       data->value.string = g_strdup((const gchar *) value);
+                       break;
+       }
+       
+       return data;
+}
+
+void extract_data(GHashTable* data, const gchar* key, void** value) {
+       AttribDef* attr;
+       
+       if (! data || ! key || ! value)
+               return;
+               
+       attr = g_hash_table_lookup(data, key);
+       if (attr) {
+               get_data(attr, value);
+       }
+}
+
+void swap_data(GHashTable* data, const gchar* key, void* value) {
+       AttribDef* attr;
+       
+       if (! data || ! key || ! value)
+               return;
+               
+       attr = g_hash_table_lookup(data, key);
+
+       if (attr) {
+               switch (attr->type) {
+                       case ATTRIB_TYPE_INT:
+                               attr->value.number = *(gint *) value;
+                               break;
+                       case ATTRIB_TYPE_BOOLEAN:
+                               attr->value.boolean = *(gboolean *) value;
+                               break;
+                       case ATTRIB_TYPE_CHAR:
+                               attr->value.character = *(char *) value;
+                               break;
+                       case ATTRIB_TYPE_STRING:
+                               g_free(attr->value.string);
+                               attr->value.string = g_strdup(value);
+                               break;
+               }
+       }
+       else {
+               attr = pack_data(ATTRIB_TYPE_STRING, key, (gchar *) value);
+               g_hash_table_replace(data, g_strdup(key), attr);
+       }
+}
+
+AttribType get_data(AttribDef* attrib_def, void** value) {
+       if (attrib_def && value) {
+               switch (attrib_def->type) {
+                       case ATTRIB_TYPE_INT:
+                               *value = &attrib_def->value.number;
+                               break;
+                       case ATTRIB_TYPE_BOOLEAN:
+                               *value = &attrib_def->value.boolean;
+                               break;
+                       case ATTRIB_TYPE_CHAR:
+                               *value = &attrib_def->value.character;
+                               break;
+                       case ATTRIB_TYPE_STRING:
+                               *value = g_strdup(attrib_def->value.string);
+                               break;
+               }
+       }
+       
+       return attrib_def->type;
+}
\ No newline at end of file
index df113ecbedf3c36d379119de7f6e59e8f1d589d2..5a49a6947803d415be600df49b0f622b7a3b372f 100644 (file)
@@ -53,6 +53,8 @@ G_BEGIN_DECLS
        debug_print_real("%s:%d:[%s]: ", debug_srcname(__FILE__), __LINE__, ___FUNC___), \
        debug_print_real
 
+typedef gpointer (*COPYFUNC) (gpointer);
+
 void debug_print_real(const gchar *format, ...);
 const char* debug_srcname(const char *file);
 gboolean debug_get_mode();
@@ -63,10 +65,17 @@ gboolean create_file(const gchar* path, gchar** error);
 gboolean first_time(const gchar* subpath, const gchar* config, gchar** error);
 void close_log_file();
 
+void swap_data(GHashTable* data, const gchar* key, void* value);
+AttribDef* pack_data(AttribType type, const gchar* name, const void* value);
+void extract_data(GHashTable* data, const gchar* key, void** value);
+AttribType get_data(AttribDef* attrib_def, void** value); 
 void attrib_def_free(gpointer attrdef);
-void gslist_free(GSList* list, void (*elem_free) (gpointer data));
+gpointer attrib_def_copy(gpointer attrdef);
+GSList* gslist_deep_copy(GSList* list, COPYFUNC copy_func);
+void gslist_free(GSList** list, void (*elem_free) (gpointer data));
 GHashTable* hash_table_new(void);
 GHashTable * hash_table_copy(GHashTable* hash);
+void hash_table_dump(GHashTable* hash, FILE* f);
 void hash_table_free(GHashTable** hash_table);
 void hash_table_keys_to_slist(gpointer key, gpointer value, gpointer slist);
 
index d5f552d521143d1e28e16a65318ab91f2dc7086b..818607936d4a101179c05dd29e44a38b47ace029 100644 (file)
@@ -102,16 +102,17 @@ static gboolean init_document(DOCTYPE type,
 
 static void parse_attribute(GHashTable* person, xmlDocPtr doc, xmlAttr* attribs) {
     xmlChar *str;
-    gchar *attr, *value;
+    gchar *attr;
+    AttribDef* data;
 
        while (person && attribs) {
                if (g_hash_table_lookup(person, "uid") == NULL ||
-                       strcasecmp("uid", (const gchar *) attribs->name) != 0) {
+                               strcasecmp("uid", (const gchar *) attribs->name) != 0) {
                        str = xmlNodeListGetString(doc, attribs->children, 1);
                        attr = (const gchar *) attribs->name;
-                       value = (const gchar *) str;
-                       debug_print("\tAttribute: %s->%s\n", attr, value);
-                       g_hash_table_replace(person, g_strdup(attr), g_strdup(value));
+                       debug_print("\tAttribute: %s->%s\n", attr, (const gchar *) str);
+                       data = pack_data(ATTRIB_TYPE_STRING, attr, (const gchar *) str);
+                       g_hash_table_replace(person, g_strdup(attr), data);
                        xmlFree(str);
                }
                attribs = attribs->next;
@@ -164,6 +165,7 @@ static void parse_attributes(GHashTable* person, xmlDocPtr doc, xmlNodePtr cur)
     xmlAttr* attribs;
     xmlChar *xvalue, *xkey;
     gchar *key = NULL, *value = NULL;
+    AttribDef* data;
 
     cur = cur->xmlChildrenNode;
     while (cur != NULL) {
@@ -182,19 +184,18 @@ static void parse_attributes(GHashTable* person, xmlDocPtr doc, xmlNodePtr cur)
                                }
                                attribs = attribs->next;
                        }
-                       debug_print("\tAttribute: %s->%s\n", key, value);
                        if (person && key && value) {
-                               g_hash_table_replace(person, key, value);
+                               debug_print("\tAttribute: %s->%s\n", key, value);
+                               data = pack_data(ATTRIB_TYPE_STRING, key, value);
+                               g_hash_table_replace(person, g_strdup(key), data);
                        }
-                       else {
-                               if (key) {
-                                       g_free(key);
-                                       key = NULL;
-                               }
-                               if (value) {
-                                       g_free(value);
-                                       value = NULL;
-                               }
+                       if (key) {
+                               g_free(key);
+                               key = NULL;
+                       }
+                       if (value) {
+                               g_free(value);
+                               value = NULL;
                        }
                }
         cur = cur->next;
@@ -309,14 +310,14 @@ static GSList* parse_book(xmlDocPtr doc, xmlNodePtr cur) {
 }
 
 static gchar* hash_table_get_entry(GHashTable* hash, const gchar* key) {
-       gchar* value;
+       AttribDef* attr;
        
        if (! hash || ! key)
                return "";
                
-       value = g_hash_table_lookup(hash, key);
+       attr = g_hash_table_lookup(hash, key);
        
-       return (value) ? value : "";
+       return (attr) ? attr->value.string : "";
 }
 
 static void hash_table_get_entries(gpointer key,
@@ -324,7 +325,7 @@ static void hash_table_get_entries(gpointer key,
                                                                   gpointer data) {
        xmlNodePtr attribute;
        xmlNodePtr parent = (xmlNodePtr) data;
-       gchar* val = (value) ? value : "";
+       AttribDef* attr = (AttribDef *) value;
        const gchar** reserved = RESERVED;
        
        while (key && *reserved) {
@@ -332,7 +333,8 @@ static void hash_table_get_entries(gpointer key,
                        return;
                }
        }
-
+       
+       gchar* val = (attr) ? attr->value.string : "";
        attribute = xmlNewNode(NULL, (const xmlChar *) "attribute");
        xmlSetProp(attribute, (xmlChar *) "name", (xmlChar *) g_strdup(key));
        xmlNodeAddContent(attribute, (const xmlChar *) g_strdup(val));
@@ -578,7 +580,7 @@ void addr_book_delete_contact(AddressBook* abook,
        xmlNodePtr cur;
        GList* head;
        Contact* remove = NULL;
-       AttribDef compare;
+       AttribDef* compare;
        gchar* value;
        int bytes;
 
@@ -593,31 +595,43 @@ void addr_book_delete_contact(AddressBook* abook,
 
        xmlThrDefIndentTreeOutput(1);
 
-       compare.type = ATTRIB_TYPE_STRING;
-       compare.attrib_name = "uid";
+       compare = g_new0(AttribDef, 1);
+       compare->type = ATTRIB_TYPE_STRING;
+       compare->attrib_name = g_strdup("uid");
        
        for (head = abook->contacts; head; head = g_list_next(head)) {
                remove = (Contact *) head->data;
-               if (contact_compare_attrib(contact, remove, &compare))
+               if (contact_compare_attrib(contact, remove, compare))
                        break;
        }       
        
-       value = (gchar *) g_hash_table_lookup(remove->data, compare.attrib_name);
-       cur = cur->xmlChildrenNode;
-       while (cur != NULL) {
-               if (cur->name && !xmlStrcmp(cur->name, (const xmlChar *) "person")) {
-                       debug_print("Parsing: %s\n", cur->name);
-                       if (value && has_attribute(doc, cur, compare.attrib_name, value)) {
-                               xmlUnlinkNode(cur);
-                               xmlFreeNode(cur);
-                               bytes = xmlSaveFormatFileEnc(abook->URL, doc, "UTF-8", 1);
-                               if (bytes == -1) {
-                                       *error = g_strdup_printf(_("%s: Not saved"), abook->URL);
+       if (debug_get_mode())
+               contact_dump(contact, stderr);
+       value = g_strdup(compare->attrib_name);
+       attrib_def_free(compare);
+       
+       compare = g_hash_table_lookup(remove->data, value);
+       g_free(value);
+       
+       value = compare->value.string;
+       
+       if (value) {
+               cur = cur->xmlChildrenNode;
+               while (cur != NULL) {
+                       if (cur->name && !xmlStrcmp(cur->name, (const xmlChar *) "person")) {
+                               debug_print("Parsing: %s\n", cur->name);
+                               if (has_attribute(doc, cur, compare->attrib_name, value)) {
+                                       xmlUnlinkNode(cur);
+                                       xmlFreeNode(cur);
+                                       bytes = xmlSaveFormatFileEnc(abook->URL, doc, "UTF-8", 1);
+                                       if (bytes == -1) {
+                                               *error = g_strdup_printf(_("%s: Not saved"), abook->URL);
+                                       }
+                                       break;
                                }
-                               break;
                        }
+                       cur = cur->next;
                }
-               cur = cur->next;
        }
        
        xmlFreeDoc(doc);