fix bug 643638
[claws.git] / src / addrbook.c
index 7db21ab963cf749c202fdc707c4a8ba026df89df..138b9b62e4110bb1ab7c9f430f5a86eb362613f8 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 /*
- * General functions for accessing external address book files.
+ * General functions for accessing address book files.
  */
 
 #include <glib.h>
@@ -56,15 +56,13 @@ AddressBookFile *addrbook_create_book() {
        book = g_new0( AddressBookFile, 1 );
        book->type = ADBOOKTYPE_BOOK;
        book->addressCache = addrcache_create();
-       book->accessFlag = FALSE;
        book->retVal = MGU_SUCCESS;
        book->path = NULL;
        book->fileName = NULL;
        book->maxValue = 0;
        book->tempList = NULL;
        book->tempHash = NULL;
-       book->readFlag = FALSE;
-       book->modifyFlag = TRUE;
+       book->addressCache->modified = TRUE;
        return book;
 }
 
@@ -89,21 +87,29 @@ void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
        book->fileName = mgu_replace_string( book->fileName, value );
        addrcache_set_dirty( book->addressCache, TRUE );
 }
-void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
-       g_return_if_fail( book != NULL );
-       book->accessFlag = value;
-}
 gboolean addrbook_get_modified( AddressBookFile *book ) {
        g_return_val_if_fail( book != NULL, FALSE );
-       return book->modifyFlag;
+       return book->addressCache->modified;
+}
+void addrbook_set_modified( AddressBookFile *book, const gboolean value ) {
+       g_return_if_fail( book != NULL );
+       book->addressCache->modified = value;
 }
 gboolean addrbook_get_accessed( AddressBookFile *book ) {
        g_return_val_if_fail( book != NULL, FALSE );
-       return book->accessFlag;
+       return book->addressCache->accessFlag;
+}
+void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
+       g_return_if_fail( book != NULL );
+       book->addressCache->accessFlag = value;
 }
 gboolean addrbook_get_read_flag( AddressBookFile *book ) {
        g_return_val_if_fail( book != NULL, FALSE );
-       return book->readFlag;
+       return book->addressCache->dataRead;
+}
+void addrbook_set_read_flag( AddressBookFile *book, const gboolean value ) {
+       g_return_if_fail( book != NULL );
+       book->addressCache->dataRead = value;
 }
 gint addrbook_get_status( AddressBookFile *book ) {
        g_return_val_if_fail( book != NULL, -1 );
@@ -144,9 +150,9 @@ void addrbook_empty_book( AddressBookFile *book ) {
        /* Reset to initial state */
        book->tempList = NULL;
        book->tempHash = NULL;
-       book->readFlag = FALSE;
-       book->modifyFlag = FALSE;
-       book->accessFlag = FALSE;
+       book->addressCache->dataRead = FALSE;
+       book->addressCache->modified = FALSE;
+       book->addressCache->accessFlag = FALSE;
        book->retVal = MGU_SUCCESS;
 }
 
@@ -159,7 +165,6 @@ void addrbook_free_book( AddressBookFile *book ) {
        /* Clear cache */
        addrcache_clear( book->addressCache );
        addrcache_free( book->addressCache );
-       addrcache_set_dirty( book->addressCache, FALSE );
 
        /* Free up internal objects */
        g_free( book->path );
@@ -171,12 +176,9 @@ void addrbook_free_book( AddressBookFile *book ) {
        book->maxValue = 0;
        book->tempList = NULL;
        book->tempHash = NULL;
-       book->readFlag = FALSE;
-       book->modifyFlag = FALSE;
 
        book->type = ADBOOKTYPE_NONE;
        book->addressCache = NULL;
-       book->accessFlag = FALSE;
        book->retVal = MGU_SUCCESS;
 
        g_free( book );
@@ -847,10 +849,16 @@ gint addrbook_read_data( AddressBookFile *book ) {
 
        g_return_val_if_fail( book != NULL, -1 );
 
+       /*
+       printf( "...addrbook_read_data :%s:\t:%s:\n", book->fileName,
+               addrcache_get_name( book->addressCache ) );
+       */
+
        fileSpec = g_strconcat( book->path, G_DIR_SEPARATOR_S, book->fileName, NULL );
        book->retVal = MGU_OPEN_FILE;
-       book->accessFlag = FALSE;
-       book->modifyFlag = FALSE;
+       addrcache_clear( book->addressCache );
+       book->addressCache->modified = FALSE;
+       book->addressCache->accessFlag = FALSE;
        file = xml_open_file( fileSpec );
        g_free( fileSpec );
        if( file ) {
@@ -867,7 +875,8 @@ gint addrbook_read_data( AddressBookFile *book ) {
                /* Resolve folder items */
                addrbook_resolve_folder_items( book );
                book->tempList = NULL;
-               book->readFlag = TRUE;
+               book->addressCache->modified = FALSE;
+               book->addressCache->dataRead = TRUE;
                addrcache_set_dirty( book->addressCache, FALSE );
        }
        return book->retVal;
@@ -1171,9 +1180,11 @@ ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
 }
 
 /*
-* Hash table visitor function.
+* Hash table visitor function for deletion of hashtable entries.
 */
-static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, gpointer *data ) {
+static gboolean addrbook_free_simple_hash_vis(
+       gpointer *key, gpointer *value, gpointer *data )
+{
        g_free( key );
        key = NULL;
        value = NULL;
@@ -1184,51 +1195,43 @@ static gboolean addrbook_free_simple_hash_vis( gpointer *key, gpointer *value, g
 * Update address book email list for specified person.
 * Enter: book      Address book.
 *        person    Person to update.
-*        listEMail New list of email addresses.
+*        listEMail List of new email addresses.
 * Note: The existing email addresses are replaced with the new addresses. Any references
 * to old addresses in the groups are re-linked to the new addresses. All old addresses
 * linked to the person are removed.
 */
-void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GList *listEMail ) {
+void addrbook_update_address_list(
+       AddressBookFile *book, ItemPerson *person, GList *listEMail )
+{
        GList *node;
-       GList *oldData;
+       GList *listDelete;
        GList *listGroup;
 
        g_return_if_fail( book != NULL );
        g_return_if_fail( person != NULL );
 
-       /* Remember old list */
-       oldData = person->listEMail;
-
-       /* Attach new address list to person. */
-       node = listEMail;
-       while( node ) {
-               ItemEMail *email = node->data;
-               if( ADDRITEM_ID(email) == NULL ) {
-                       /* Allocate an ID */
-                       addrcache_id_email( book->addressCache, email );
-               }
-               ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
-               node = g_list_next( node );
-       }
-       person->listEMail = listEMail;
-
-       /* Get groups where person's email is listed */
+       /* Get groups where person's existing email addresses are listed */
        listGroup = addrcache_get_group_for_person( book->addressCache, person );
        if( listGroup ) {
                GHashTable *hashEMail;
+               GHashTable *hashEMailAlias;
                GList *nodeGrp;
 
                /* Load hash table with new address entries */
                hashEMail = g_hash_table_new( g_str_hash, g_str_equal );
+               hashEMailAlias = g_hash_table_new( g_str_hash, g_str_equal );
                node = listEMail;
                while( node ) {
                        ItemEMail *email = node->data;
                        gchar *addr = g_strdup( email->address );
+                       gchar *alias = email->obj.name ;
                        g_strdown( addr );
                        if( ! g_hash_table_lookup( hashEMail, addr ) ) {
                                g_hash_table_insert( hashEMail, addr, email );
                        }
+                       if ( *alias != '\0' && ! g_hash_table_lookup( hashEMailAlias, alias ) ) {
+                               g_hash_table_insert( hashEMailAlias, alias, email );
+                       }
                        node = g_list_next( node );
                }
 
@@ -1244,17 +1247,31 @@ void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GL
                        nodeGrpEM = groupEMail;
                        while( nodeGrpEM ) {
                                ItemEMail *emailGrp = ( ItemEMail * ) nodeGrpEM->data;
+
                                if( ADDRITEM_PARENT(emailGrp) == ADDRITEM_OBJECT(person) ) {
                                        /* Found an email address for this person */
                                        ItemEMail *emailNew = NULL;
-                                       gchar *addr = g_strdup( emailGrp->address );
+                                       gchar *addr = g_strdup( emailGrp->address );
+                                       gchar *alias = emailGrp->obj.name;
                                        g_strdown( addr );
-                                       emailNew = ( ItemEMail * ) g_hash_table_lookup( hashEMail, addr );
+                                       emailNew = ( ItemEMail * )
+                                               g_hash_table_lookup( hashEMail, addr );
                                        g_free( addr );
+                                       /* If no match by e-mail, try to match by e-mail alias */
+                                       if( ! emailNew && *alias != '\0' ) {
+                                               emailNew = ( ItemEMail * )
+                                                       g_hash_table_lookup( hashEMailAlias, alias);
+                                       }
+                                       
                                        if( emailNew ) {
                                                /* Point to this entry */
                                                nodeGrpEM->data = emailNew;
                                        }
+                                       else if(g_hash_table_size(hashEMail)==1) {
+                                               /* If the person has just one e-mail address, then 
+                                                  change e-mail address in group list */
+                                               nodeGrpEM->data = listEMail->data;
+                                       } 
                                        else {
                                                /* Mark for removal */
                                                listRemove = g_list_append( listRemove, emailGrp );
@@ -1272,23 +1289,65 @@ void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GL
                                nodeGrpEM = g_list_next( nodeGrpEM );
                        }
 
+                       g_list_free( listRemove );
+
                        /* Move on to next group */
                        nodeGrp = g_list_next( nodeGrp );
 
                }
 
                /* Clear hash table */
-               g_hash_table_foreach_remove( hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
+               g_hash_table_foreach_remove(
+                       hashEMail, ( GHRFunc ) addrbook_free_simple_hash_vis, NULL );
                g_hash_table_destroy( hashEMail );
                hashEMail = NULL;
+               g_hash_table_destroy( hashEMailAlias );
+               hashEMailAlias = NULL;
                g_list_free( listGroup );
                listGroup = NULL;
        }
+
+       /* Remove old addresses from person and cache */
+       listDelete = NULL;
+       node = person->listEMail;
+       while( node ) {
+               ItemEMail *email = node->data;
+
+               if( addrcache_person_remove_email( book->addressCache, person, email ) ) {
+                       addrcache_remove_email( book->addressCache, email );
+               }
+               listDelete = g_list_append( listDelete, email );
+               node = person->listEMail;
+       }
+
+       /* Add new address entries */
+       node = listEMail;
+       while( node ) {
+               ItemEMail *email = node->data;
+
+               if( ADDRITEM_ID(email) == NULL ) {
+                       /* Allocate an ID for new address */
+                       addrcache_id_email( book->addressCache, email );
+               }
+               addrcache_person_add_email( book->addressCache, person, email );
+               node = g_list_next( node );
+       }
+
        addrcache_set_dirty( book->addressCache, TRUE );
 
-       /* Free up old data */
-       addritem_free_list_email( oldData );
-       oldData = NULL;
+       /* Free up memory */
+       g_list_free( listEMail );
+       listEMail = NULL;
+
+       node = listDelete;
+       while( node ) {
+               ItemEMail *email = node->data;
+
+               addritem_free_item_email( email );
+               node = g_list_next( node );
+       }
+       g_list_free( listDelete );
+       listDelete = NULL;
 
 }
 
@@ -1325,31 +1384,6 @@ ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder
        return person;
 }
 
-/*
-* Load hash table visitor function.
-*/
-static void addrbook_load_hash_table_email_vis( gpointer key, gpointer value, gpointer data ) {
-       AddrItemObject *obj = ( AddrItemObject * ) value;
-
-       if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
-               GHashTable *table = ( GHashTable * ) data;
-               gchar *newKey = g_strdup( key );
-               ItemEMail *email = ( ItemEMail * ) obj;
-               if( ! g_hash_table_lookup( table, newKey ) ) {
-                       g_hash_table_insert( table, newKey, email );
-               }
-       }
-}
-
-/*
-* Load hash table with links to email addresses.
-*/
-static void addrbook_load_hash_table_email( AddressBookFile *book, GHashTable *table ) {
-       g_return_if_fail( book != NULL );
-       g_return_if_fail( table != NULL );
-       g_hash_table_foreach( book->addressCache->itemHash, addrbook_load_hash_table_email_vis, table );
-}
-
 /*
 * Build available email list visitor function.
 */
@@ -1709,8 +1743,8 @@ gchar *addrbook_gen_new_file_name( gint fileNum ) {
        if( n < 1 ) n = 1;
        nmax = -1 + (long int) pow( 10, FILE_NUMDIGITS );
        if( fileNum > nmax ) return NULL;
-       sprintf( fmt, "%%s%%0%dd%%s", FILE_NUMDIGITS );
-       sprintf( buf, fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
+       g_snprintf( fmt, sizeof(fmt), "%%s%%0%dd%%s", FILE_NUMDIGITS );
+       g_snprintf( buf, sizeof(buf), fmt, ADDRBOOK_PREFIX, n, ADDRBOOK_SUFFIX );
        return g_strdup( buf );
 }
 
@@ -1719,16 +1753,6 @@ gchar *addrbook_gen_new_file_name( gint fileNum ) {
 * ***********************************************************************
 */
 
-static void addrbook_show_attribs( GList *attr ) {
-       while( attr ) {
-               gchar *name = ((XMLAttr *)attr->data)->name;
-               gchar *value = ((XMLAttr *)attr->data)->value;
-               printf( "\tn/v = %s : %s\n", name, value );
-               attr = g_list_next( attr );
-       }
-       printf( "\t---\n" );
-}
-
 /*
 * Test email address list.
 */
@@ -1987,6 +2011,28 @@ ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, con
        return addrcache_add_contact( book->addressCache, folder, name, address, remarks );
 }
 
+/*
+ * Return file name for next address book file.
+ * Enter:  book Address book.
+ * Return: File name, or NULL if could not create. This should be g_free()
+ *         when done.
+ */
+gchar *addrbook_guess_next_file( AddressBookFile *book ) {
+       gchar *newFile = NULL;
+       GList *fileList = NULL;
+       gint fileNum = 1;
+       fileList = addrbook_get_bookfile_list( book );
+       if( fileList ) {
+               fileNum = 1 + book->maxValue;
+       }
+       newFile = addrbook_gen_new_file_name( fileNum );
+       g_list_free( fileList );
+       fileList = NULL;
+       return newFile;
+}
+
 /*
 * End of Source.
 */
+
+