sync with sylpheed 0.7.0cvs38
[claws.git] / src / addr_compl.c
index f89ac9fb9eb8f9731bb6e931d02c8afa4f129d35..6cfafc5c2a8e2cfd0e4628106db67b674101b68a 100644 (file)
@@ -46,9 +46,6 @@
 #include "addressbook.h"
 #include "main.h"
 
-#define LOG_MESSAGE \
-       debug_mode == 0 ? (debug_mode == debug_mode) : debug_print 
-
 /* How it works:
  *
  * The address book is read into memory. We set up an address list
@@ -158,6 +155,8 @@ static gint add_address(const gchar *name, const gchar *address)
 
        if (!name || !address) return -1;
 
+       debug_print( "completion: add_address: %s - %s\n", name, address );
+
        ae = g_new0(address_entry, 1);
        ce1 = g_new0(completion_entry, 1),
        ce2 = g_new0(completion_entry, 1);
@@ -182,64 +181,10 @@ static gint add_address(const gchar *name, const gchar *address)
        return 0;
 }
 
-static gboolean get_all_addresses(GNode *node, gpointer ae)
-{
-       XMLNode *xmlnode = (XMLNode *)node->data;
-       address_entry *addr = (address_entry *)ae;
-
-       /* this simply checks if tag is "item". in that case, it
-        * verifies it has already seen an item. if it did, an
-        * address retrieval was complete */
-       if (!strcmp(xmlnode->tag->tag, "item")) {
-               /* see if a previous item was complete */
-               /* TODO: does sylpheed address book allow empty names to be entered?
-                * if so, addr->name *AND* addr->address should be checked. */
-               /* add address to our database */
-               add_address(addr->name, addr->address);
-               g_free(addr->name);
-               g_free(addr->address);
-               addr->name = NULL;
-               addr->address = NULL;
-       } else if (!strcmp(xmlnode->tag->tag, "name"))
-               addr->name = g_strdup(xmlnode->element);
-       else if (!strcmp(xmlnode->tag->tag, "address"))
-               addr->address = g_strdup(xmlnode->element);
-
-       return FALSE;
-}
-
 /* read_address_book()
  */ 
-static void read_address_book(void)
-{      
-       gchar *path;
-       GNode *tree; 
-       address_entry ad = {NULL, NULL};
-
-       LOG_MESSAGE( _("%s%d entering read_address_book\n"), __FILE__, __LINE__);
-       path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRESS_BOOK, NULL);
-       tree = xml_parse_file(path);
-       g_free(path);
-       if (!tree) {
-               LOG_MESSAGE( _("%s(%d) no addressbook\n"), __FILE__, __LINE__);
-               return;
-       }
-
-       /* retrieve all addresses */
-       g_node_traverse(tree, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
-                       (GNodeTraverseFunc) get_all_addresses, &ad);
-       /* still one pending? */
-       if (ad.name) {
-               add_address(ad.name, ad.address);
-               if (ad.name)
-                       g_free(ad.name);
-               if (ad.address)
-                       g_free(ad.address);
-       }
-
-       xml_free_tree(tree);
-
-       LOG_MESSAGE(_("%s(%d) leaving read_address_book - OK\n"), __FILE__, __LINE__);
+static void read_address_book(void) {  
+       addressbook_load_completion( add_address );
 }
 
 /* start_address_completion() - returns the number of addresses 
@@ -257,7 +202,7 @@ gint start_address_completion(void)
                        g_completion_add_items(g_completion, g_completion_list);
        }
        g_ref_count++;
-       LOG_MESSAGE("start_address_completion ref count %d\n", g_ref_count);
+       debug_print("start_address_completion ref count %d\n", g_ref_count);
 
        return g_list_length(g_completion_list);
 }
@@ -274,8 +219,15 @@ gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
        wchar_t *wtext;
        wchar_t *wp;
        wchar_t rfc_mail_sep;
+       wchar_t quote;
+       wchar_t lt;
+       gboolean in_quote = FALSE;
        gchar *str;
 
+       if (mbtowc(&rfc_mail_sep, ",", 1) < 0) return NULL;
+       if (mbtowc(&quote, "\"", 1) < 0) return NULL;
+       if (mbtowc(&lt, "<", 1) < 0) return NULL;
+
        edit_text = gtk_entry_get_text(entry);
        if (edit_text == NULL) return NULL;
 
@@ -284,14 +236,13 @@ gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
 
        cur_pos = gtk_editable_get_position(GTK_EDITABLE(entry));
 
-       if (mbtowc(&rfc_mail_sep, ",", 1) < 0) {
-               g_free(wtext);
-               return NULL;
-       }
-
        /* scan for a separator. doesn't matter if walk points at null byte. */
-       for (wp = wtext + cur_pos; wp > wtext && *wp != rfc_mail_sep; wp--)
-               ;
+       for (wp = wtext + cur_pos; wp > wtext; wp--) {
+               if (!in_quote && *wp == rfc_mail_sep)
+                       break;
+               if (*wp == quote)
+                       in_quote ^= TRUE;
+       }
 
        /* have something valid */
        if (wcslen(wp) == 0) {
@@ -299,7 +250,8 @@ gchar *get_address_from_edit(GtkEntry *entry, gint *start_pos)
                return NULL;
        }
 
-#define IS_VALID_CHAR(x)       (iswalnum(x) || ((x) > 0x7f))
+#define IS_VALID_CHAR(x) \
+       (iswalnum(x) || (x) == quote || (x) == lt || ((x) > 0x7f))
 
        /* now scan back until we hit a valid character */
        for (; *wp && !IS_VALID_CHAR(*wp); wp++)
@@ -386,22 +338,29 @@ guint complete_address(const gchar *str)
 gchar *get_complete_address(gint index)
 {
        const address_entry *p;
-       
+       gchar *address = NULL;
+
        if (index < g_completion_count) {
                if (index == 0)
-                       return g_strdup(g_completion_prefix);
+                       address = g_strdup(g_completion_prefix);
                else {
                        /* get something from the unique addresses */
                        p = (address_entry *)g_slist_nth_data
                                (g_completion_addresses, index - 1);
-                       if (p == NULL)
-                               return NULL;
-                       else
-                               return g_strdup_printf
-                                       ("%s <%s>", p->name, p->address);
+                       if (p != NULL) {
+                               if (!p->name || p->name[0] == '\0')
+                                       address = g_strdup_printf(p->address);
+                               else if (strchr_with_skip_quote(p->name, '"', ','))
+                                       address = g_strdup_printf
+                                               ("\"%s\" <%s>", p->name, p->address);
+                               else
+                                       address = g_strdup_printf
+                                               ("%s <%s>", p->name, p->address);
+                       }
                }
-       } else
-               return NULL;
+       }
+
+       return address;
 }
 
 gchar *get_next_complete_address(void)
@@ -474,7 +433,7 @@ gint invalidate_address_completion(void)
 {
        if (g_ref_count) {
                /* simply the same as start_address_completion() */
-               LOG_MESSAGE("Invalidation request for address completion\n");
+               debug_print("Invalidation request for address completion\n");
                free_all();
                init_all();
                read_address_book();
@@ -492,7 +451,7 @@ gint end_address_completion(void)
        if (0 == --g_ref_count)
                free_all();
 
-       LOG_MESSAGE("end_address_completion ref count %d\n", g_ref_count);
+       debug_print("end_address_completion ref count %d\n", g_ref_count);
 
        return g_ref_count; 
 }
@@ -598,6 +557,10 @@ void address_completion_start(GtkWidget *mainwindow)
                           mainwindow);
 }
 
+/* Need unique data to make unregistering signal handler possible for the auto
+ * completed entry */
+#define COMPLETION_UNIQUE_DATA (GINT_TO_POINTER(0xfeefaa))
+
 void address_completion_register_entry(GtkEntry *entry)
 {
        g_return_if_fail(entry != NULL);
@@ -610,14 +573,36 @@ void address_completion_register_entry(GtkEntry *entry)
        gtk_signal_connect_full(GTK_OBJECT(entry), "key_press_event",
                                GTK_SIGNAL_FUNC(address_completion_entry_key_pressed),
                                NULL,
-                               NULL,
+                               COMPLETION_UNIQUE_DATA,
                                NULL,
                                0,
                                0); /* magic */
 }
 
+void address_completion_unregister_entry(GtkEntry *entry)
+{
+       GtkObject *entry_obj;
+
+       g_return_if_fail(entry != NULL);
+       g_return_if_fail(GTK_IS_ENTRY(entry));
+
+       entry_obj = gtk_object_get_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK);
+       g_return_if_fail(entry_obj);
+       g_return_if_fail(entry_obj == GTK_OBJECT(entry));
+
+       /* has the hooked property? */
+       gtk_object_set_data(GTK_OBJECT(entry), ENTRY_DATA_TAB_HOOK, NULL);
+
+       /* remove the hook */
+       gtk_signal_disconnect_by_func(GTK_OBJECT(entry), 
+               GTK_SIGNAL_FUNC(address_completion_entry_key_pressed),
+               COMPLETION_UNIQUE_DATA);
+}
+
 /* should be called when main window with address completion entries
- * terminates */
+ * terminates.
+ * NOTE: this function assumes that it is called upon destruction of
+ * the window */
 void address_completion_end(GtkWidget *mainwindow)
 {
        /* if address_completion_end() is really called on closing the window,