Addressbook cut, copy and paste. Sort user attributes. Tidy up
authorMatch Grun <match@dimensional.com>
Sat, 19 Jan 2002 06:25:11 +0000 (06:25 +0000)
committerMatch Grun <match@dimensional.com>
Sat, 19 Jan 2002 06:25:11 +0000 (06:25 +0000)
addressbook menus.

24 files changed:
src/Makefile.am
src/addrbook.c
src/addrbook.h
src/addrcache.c
src/addrcache.h
src/addressbook.c
src/addressitem.h
src/addrindex.c
src/addrindex.h
src/addritem.c
src/addritem.h
src/editaddress.c
src/editbook.c
src/editjpilot.c
src/editldap.c
src/editvcard.c
src/importldif.c
src/importmutt.c
src/jpilot.c
src/jpilot.h
src/syldap.c
src/syldap.h
src/vcard.c
src/vcard.h

index dcfea69958e3fb1820b2ef965b232713d25bda7b..afe428a96cfa70b9f1bf68637933fdb917e1674b 100644 (file)
@@ -40,8 +40,11 @@ sylpheed_SOURCES = \
        addressbook.c addressbook.h \
        addr_compl.c addr_compl.h \
        addressitem.h \
+       adbookbase.h \
        addritem.c addritem.h \
        addrcache.c addrcache.h \
+       addrclip.c addrclip.h \
+       addrselect.c addrselect.h \
        addrbook.c addrbook.h \
        addrindex.c addrindex.h \
        mgutils.c mgutils.h \
index 1fd03670320a0a6336927cf0a9727fc8a4728828..70f8579432756c1fae7b6623ed09a0cfd9d24278 100644 (file)
@@ -34,6 +34,7 @@
 #include "addritem.h"
 #include "addrcache.h"
 #include "addrbook.h"
+#include "adbookbase.h"
 
 #ifndef DEV_STANDALONE
 #include "prefs.h"
@@ -53,18 +54,17 @@ AddressBookFile *addrbook_create_book() {
        AddressBookFile *book;
 
        book = g_new0( AddressBookFile, 1 );
-       book->name = NULL;
+       book->type = ADBOOKTYPE_BOOK;
+       book->addressCache = addrcache_create();
+       book->accessFlag = FALSE;
+       book->retVal = MGU_SUCCESS;
        book->path = NULL;
        book->fileName = NULL;
-       book->retVal = MGU_SUCCESS;
-       book->addressCache = addrcache_create();
-
+       book->maxValue = 0;
        book->tempList = NULL;
+       book->tempHash = NULL;
        book->readFlag = FALSE;
-       book->dirtyFlag = FALSE;
        book->modifyFlag = TRUE;
-       book->accessFlag = FALSE;
-       book->tempHash = NULL;
        return book;
 }
 
@@ -73,17 +73,21 @@ AddressBookFile *addrbook_create_book() {
 */
 void addrbook_set_name( AddressBookFile *book, const gchar *value ) {
        g_return_if_fail( book != NULL );
-       book->name = mgu_replace_string( book->name, value );
+       addrcache_set_name( book->addressCache, value );
+}
+gchar *addrbook_get_name( AddressBookFile *book ) {
+       g_return_val_if_fail( book != NULL, NULL );
+       return addrcache_get_name( book->addressCache );
 }
 void addrbook_set_path( AddressBookFile *book, const gchar *value ) {
        g_return_if_fail( book != NULL );
        book->path = mgu_replace_string( book->path, value );
-       book->dirtyFlag = TRUE;
+       addrcache_set_dirty( book->addressCache, TRUE );
 }
 void addrbook_set_file( AddressBookFile *book, const gchar *value ) {
        g_return_if_fail( book != NULL );
        book->fileName = mgu_replace_string( book->fileName, value );
-       book->dirtyFlag = TRUE;
+       addrcache_set_dirty( book->addressCache, TRUE );
 }
 void addrbook_set_accessed( AddressBookFile *book, const gboolean value ) {
        g_return_if_fail( book != NULL );
@@ -117,37 +121,13 @@ GList *addrbook_get_list_person( AddressBookFile *book ) {
        g_return_val_if_fail( book != NULL, NULL );
        return addrcache_get_list_person( book->addressCache );
 }
-gchar *addrbook_get_name( AddressBookFile *book ) {
-       g_return_val_if_fail( book != NULL, NULL );
-       return book->name;
-}
-
-static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
-       AddrItemObject *obj = ( AddrItemObject * ) value;
-
-       if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
-               addritem_free_item_person( ( ItemPerson * ) obj );
-       }
-       else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
-               addritem_free_item_group( ( ItemGroup * ) obj );
-       }
-       else if( ADDRITEM_TYPE(obj) == ITEMTYPE_FOLDER ) {
-               addritem_free_item_folder( ( ItemFolder * ) obj );
-       }
-       key = NULL;
-       value = NULL;
-       return 0;
+gboolean addrbook_get_dirty( AddressBookFile *book ) {
+       g_return_val_if_fail( book != NULL, FALSE );
+       return addrcache_get_dirty( book->addressCache );
 }
-
-/*
-* Free hash table of address book items.
-*/
-static void addrcache_free_item_hash( GHashTable *table ) {
-       g_return_if_fail( table != NULL );
-       g_hash_table_freeze( table );
-       g_hash_table_foreach_remove( table, addrcache_free_item_vis, NULL );
-       g_hash_table_thaw( table );
-       g_hash_table_destroy( table );
+void addrbook_set_dirty( AddressBookFile *book, const gboolean value ) {
+       g_return_if_fail( book != NULL );
+       addrcache_set_dirty( book->addressCache, value );
 }
 
 /*
@@ -156,19 +136,18 @@ static void addrcache_free_item_hash( GHashTable *table ) {
 void addrbook_empty_book( AddressBookFile *book ) {
        g_return_if_fail( book != NULL );
 
-       /* Free up folders and hash table */
+       /* Free up internal objects */
        addrcache_clear( book->addressCache );
-
+       addrcache_set_dirty( book->addressCache, FALSE );
        g_list_free( book->tempList );
-       book->tempList = NULL;
 
        /* Reset to initial state */
-       book->retVal = MGU_SUCCESS;
+       book->tempList = NULL;
        book->tempHash = NULL;
        book->readFlag = FALSE;
-       book->dirtyFlag = FALSE;
        book->modifyFlag = FALSE;
        book->accessFlag = FALSE;
+       book->retVal = MGU_SUCCESS;
 }
 
 /*
@@ -177,26 +156,28 @@ void addrbook_empty_book( AddressBookFile *book ) {
 void addrbook_free_book( AddressBookFile *book ) {
        g_return_if_fail( book != NULL );
 
-       g_free( book->name );
+       /* Clear cache */
+       addrcache_clear( book->addressCache );
+       addrcache_free( book->addressCache );
+       addrcache_set_dirty( book->addressCache, FALSE );
+
+       /* Free up internal objects */
        g_free( book->path );
        g_free( book->fileName );
-       book->name = NULL;
+       g_list_free( book->tempList );
+
        book->path = NULL;
        book->fileName = NULL;
-
-       /* Free up folders and hash table */
-       addrcache_free( book->addressCache );
-       book->addressCache = NULL;
-
-       g_list_free( book->tempList );
+       book->maxValue = 0;
        book->tempList = NULL;
-
-       book->retVal = MGU_SUCCESS;
        book->tempHash = NULL;
        book->readFlag = FALSE;
-       book->dirtyFlag = FALSE;
        book->modifyFlag = FALSE;
+
+       book->type = ADBOOKTYPE_NONE;
+       book->addressCache = NULL;
        book->accessFlag = FALSE;
+       book->retVal = MGU_SUCCESS;
 
        g_free( book );
 }
@@ -230,7 +211,6 @@ void addrbook_print_book( AddressBookFile *book, FILE *stream ) {
        g_return_if_fail( book != NULL );
 
        fprintf( stream, "AddressBook:\n" );
-       fprintf( stream, "\tname  : '%s'\n", book->name );
        fprintf( stream, "\tpath  : '%s'\n", book->path );
        fprintf( stream, "\tfile  : '%s'\n", book->fileName );
        fprintf( stream, "\tstatus: %d : '%s'\n", book->retVal, mgu_error2string( book->retVal ) );
@@ -256,13 +236,8 @@ void addrbook_dump_book( AddressBookFile *book, FILE *stream ) {
 * return: Group, or NULL if not found. Note that object should still be freed.
 */
 ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
-       ItemGroup *item;
-
        g_return_val_if_fail( book != NULL, NULL );
-
-       item = addrcache_remove_group( book->addressCache, group );
-       if( item ) book->dirtyFlag = TRUE;
-       return item;
+       return addrcache_remove_group( book->addressCache, group );
 }
 
 /*
@@ -271,13 +246,8 @@ ItemGroup *addrbook_remove_group( AddressBookFile *book, ItemGroup *group ) {
 * return: Person, or NULL if not found. Note that object should still be freed.
 */
 ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person ) {
-       ItemPerson *item;
-
        g_return_val_if_fail( book != NULL, NULL );
-
-       item = addrcache_remove_person( book->addressCache, person );
-       if( item ) book->dirtyFlag = TRUE;
-       return item;
+       return addrcache_remove_person( book->addressCache, person );
 }
 
 /*
@@ -287,13 +257,8 @@ ItemPerson *addrbook_remove_person( AddressBookFile *book, ItemPerson *person )
 * return: EMail object, or NULL if not found. Note that object should still be freed.
 */
 ItemEMail *addrbook_person_remove_email( AddressBookFile *book, ItemPerson *person, ItemEMail *email ) {
-       ItemEMail *item;
-
        g_return_val_if_fail( book != NULL, NULL );
-
-       item = addrcache_person_remove_email( book->addressCache, person, email );
-       if( item ); book->dirtyFlag = TRUE;
-       return item;
+       return addrcache_person_remove_email( book->addressCache, person, email );
 }
 
 /* **********************************************************************
@@ -546,7 +511,8 @@ static void addrbook_parse_member( AddressBookFile *book, XMLFile *file, ItemGro
                }
                attr = g_list_next( attr );
        }
-       email = addrcache_get_email( book->addressCache, pid, eid );
+       /* email = addrcache_get_email( book->addressCache, pid, eid ); */
+       email = addrcache_get_email( book->addressCache, eid );
        if( email ) {
                if( group ) {
                        addrcache_group_add_email( book->addressCache, group, email );
@@ -902,7 +868,7 @@ gint addrbook_read_data( AddressBookFile *book ) {
                addrbook_resolve_folder_items( book );
                book->tempList = NULL;
                book->readFlag = TRUE;
-               book->dirtyFlag = FALSE;
+               addrcache_set_dirty( book->addressCache, FALSE );
        }
        return book->retVal;
 }
@@ -1112,7 +1078,7 @@ gint addrbook_write_to( AddressBookFile *book, gchar *newFile ) {
                                conv_get_current_charset_str() );
 #endif
                addrbook_write_elem_s( fp, 0, AB_ELTAG_ADDRESS_BOOK );
-               addrbook_write_attr( fp, AB_ATTAG_NAME, book->name );
+               addrbook_write_attr( fp, AB_ATTAG_NAME, addrcache_get_name( book->addressCache ) );
                fputs( " >\n", fp );
 
                /* Output all persons */
@@ -1152,7 +1118,7 @@ gint addrbook_save_data( AddressBookFile *book ) {
 
        addrbook_write_to( book, book->fileName );
        if( book->retVal == MGU_SUCCESS ) {
-               book->dirtyFlag = FALSE;
+               addrcache_set_dirty( book->addressCache, FALSE );
        }
        return book->retVal;
 }
@@ -1178,7 +1144,7 @@ ItemEMail *addrbook_move_email_before( AddressBookFile *book, ItemPerson *person
 
        email = addritem_move_email_before( person, itemMove, itemTarget );
        if( email ) {
-               book->dirtyFlag = TRUE;
+               addrcache_set_dirty( book->addressCache, TRUE );
        }
        return email;
 }
@@ -1199,7 +1165,7 @@ ItemEMail *addrbook_move_email_after( AddressBookFile *book, ItemPerson *person,
 
        email = addritem_move_email_after( person, itemMove, itemTarget );
        if( email ) {
-               book->dirtyFlag = TRUE;
+               addrcache_set_dirty( book->addressCache, TRUE );
        }
        return email;
 }
@@ -1318,11 +1284,11 @@ void addrbook_update_address_list( AddressBookFile *book, ItemPerson *person, GL
                g_list_free( listGroup );
                listGroup = NULL;
        }
+       addrcache_set_dirty( book->addressCache, TRUE );
 
        /* Free up old data */
        addritem_free_list_email( oldData );
        oldData = NULL;
-       book->dirtyFlag = TRUE;
 
 }
 
@@ -1356,7 +1322,6 @@ ItemPerson *addrbook_add_address_list( AddressBookFile *book, ItemFolder *folder
                addrcache_person_add_email( book->addressCache, person, email );
                node = g_list_next( node );
        }
-       book->dirtyFlag = TRUE;
        return person;
 }
 
@@ -1461,12 +1426,13 @@ void addrbook_update_group_list( AddressBookFile *book, ItemGroup *group, GList
        g_return_if_fail( book != NULL );
        g_return_if_fail( group != NULL );
 
+       addrcache_set_dirty( book->addressCache, TRUE );
+
        /* Remember old list */
        oldData = group->listEMail;
        group->listEMail = listEMail;
        mgu_clear_list( oldData );
        oldData = NULL;
-       book->dirtyFlag = TRUE;
 }
 
 /*
@@ -1490,7 +1456,6 @@ ItemGroup *addrbook_add_group_list( AddressBookFile *book, ItemFolder *folder, G
        addrcache_id_group( book->addressCache, group );
        addrcache_folder_add_group( book->addressCache, f, group );
        group->listEMail = listEMail;
-       book->dirtyFlag = TRUE;
        return group;
 }
 
@@ -1512,7 +1477,7 @@ ItemFolder *addrbook_add_new_folder( AddressBookFile *book, ItemFolder *parent )
        if( addrcache_hash_add_folder( book->addressCache, folder ) ) {
                p->listFolder = g_list_append( p->listFolder, folder );
                ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(p);
-               book->dirtyFlag = TRUE;
+               addrcache_set_dirty( book->addressCache, TRUE );
        }
        else {
                addritem_free_item_folder( folder );
@@ -1550,11 +1515,11 @@ void addrbook_update_attrib_list( AddressBookFile *book, ItemPerson *person, GLi
                node = g_list_next( node );
        }
        person->listAttrib = listAttrib;
+       addrcache_set_dirty( book->addressCache, TRUE );
 
        /* Free up old data */
        addritem_free_list_attribute( oldData );
        oldData = NULL;
-       book->dirtyFlag = TRUE;
 
 }
 
@@ -1580,7 +1545,7 @@ void addrbook_add_attrib_list( AddressBookFile *book, ItemPerson *person, GList
                addritem_person_add_attribute( person, attrib );
                node = g_list_next( node );
        }
-       book->dirtyFlag = TRUE;
+       addrcache_set_dirty( book->addressCache, TRUE );
 }
 
 /*
@@ -1624,7 +1589,6 @@ ItemFolder *addrbook_remove_folder( AddressBookFile *book, ItemFolder *folder )
        g_return_val_if_fail( book != NULL, NULL );
 
        f = addrcache_remove_folder( book->addressCache, folder );
-       if( f ) book->dirtyFlag = TRUE;
        return f;
 }
 
@@ -1639,7 +1603,6 @@ ItemFolder *addrbook_remove_folder_delete( AddressBookFile *book, ItemFolder *fo
        g_return_val_if_fail( book != NULL, NULL );
 
        f = addrcache_remove_folder_delete( book->addressCache, folder );
-       if( f ) book->dirtyFlag = TRUE;
        return f;
 }
 
@@ -2020,13 +1983,8 @@ GList *addrbook_get_all_persons( AddressBookFile *book ) {
 ItemPerson *addrbook_add_contact( AddressBookFile *book, ItemFolder *folder, const gchar *name,
                const gchar *address, const gchar *remarks )
 {
-       ItemPerson *person = NULL;
-
        g_return_val_if_fail( book != NULL, NULL );
-
-       person = addrcache_add_contact( book->addressCache, folder, name, address, remarks );
-       if( person ) book->dirtyFlag = TRUE;
-       return person;
+       return addrcache_add_contact( book->addressCache, folder, name, address, remarks );
 }
 
 /*
index 1902be5d1b37fa3e5d0f067424aa74204e3e4702..c5841002148f12e3c722c12571255c7d11928cef 100644 (file)
 
 #include "addritem.h"
 #include "addrcache.h"
+#include "adbookbase.h"
 
 /* Address book file */
 typedef struct _AddressBookFile AddressBookFile;
 
 struct _AddressBookFile {
-       gchar *name;
-       gchar *path;
-       gchar *fileName;
+       AddressBookType type;
        AddressCache *addressCache;
-       gint  retVal;
-       gint  maxValue;
-       GList *tempList;
+       gboolean   accessFlag;
+       gint       retVal;
+       gchar      *path;
+       gchar      *fileName;
+       gint       maxValue;
+       GList      *tempList;
        GHashTable *tempHash;
-       gboolean readFlag;
-       gboolean dirtyFlag;
-       gboolean modifyFlag;
-       gboolean accessFlag;
-       jmp_buf jumper;
+       gboolean   readFlag;
+       gboolean   modifyFlag;
+       jmp_buf    jumper;
 };
 
 /* Function prototypes */
@@ -70,6 +70,8 @@ ItemFolder *addrbook_get_root_folder  ( AddressBookFile *book );
 GList *addrbook_get_list_folder                ( AddressBookFile *book );
 GList *addrbook_get_list_person                ( AddressBookFile *book );
 gchar *addrbook_get_name               ( AddressBookFile *book );
+gboolean addrbook_get_dirty            ( AddressBookFile *book );
+void addrbook_set_dirty                        ( AddressBookFile *book, const gboolean value );
 
 ItemPerson *addrbook_remove_person     ( AddressBookFile *book, ItemPerson *person );
 ItemGroup *addrbook_remove_group       ( AddressBookFile *book, ItemGroup *group );
index 04b16705fb5355654b27841593b2a351343f1755..dad38740695851d4e2145450b42b6b463d73cc36 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <sys/stat.h>
 #include <glib.h>
 
-/* #include "mgutils.h" */
+#include "mgutils.h"
 #include "addritem.h"
 #include "addrcache.h"
 
 #define ID_TIME_OFFSET             998000000
 #define ADDRCACHE_MAX_SEARCH_COUNT 1000
 
+static int _nextCacheID__ = 0;
+
+/*
+ * Generate next cache ID.
+ */
+static int addrcache_next_cache_id() {
+       int retVal;
+
+       if( _nextCacheID__ == 0 ) {
+               _nextCacheID__ = 1;
+       }
+       retVal = _nextCacheID__;
+       ++_nextCacheID__;
+       return retVal;
+}
+
 /*
 * Create new address cache.
 */
@@ -41,9 +57,12 @@ AddressCache *addrcache_create() {
 
        cache = g_new0( AddressCache, 1 );
        cache->itemHash = g_hash_table_new( g_str_hash, g_str_equal );
+       cache->cacheID = g_strdup_printf( "%d", addrcache_next_cache_id() );
 
        cache->dataRead = FALSE;
        cache->modified = FALSE;
+       cache->dirtyFlag = FALSE;
+       cache->name = NULL;
        cache->modifyTime = 0;
 
        /* Generate the next ID using system time */
@@ -75,6 +94,24 @@ GList *addrcache_get_list_person( AddressCache *cache ) {
        g_return_val_if_fail( cache != NULL, NULL );
        return cache->rootFolder->listPerson;
 }
+gboolean addrcache_get_dirty( AddressCache *cache ) {
+       g_return_val_if_fail( cache != NULL, FALSE );
+       return cache->dirtyFlag;
+}
+void addrcache_set_dirty( AddressCache *cache, const gboolean value ) {
+       g_return_if_fail( cache != NULL );
+       cache->dirtyFlag = value;
+}
+gchar *addrcache_get_name( AddressCache *cache ) {
+       g_return_val_if_fail( cache != NULL, NULL );
+       return cache->name;
+}
+void addrcache_set_name( AddressCache *cache, const gchar *value ) {
+       g_return_if_fail( cache != NULL );
+       cache->name = mgu_replace_string( cache->name, value );
+       g_strstrip( cache->name );
+       cache->dirtyFlag = TRUE;
+}
 
 /*
 * Generate next ID.
@@ -99,6 +136,7 @@ void addrcache_refresh( AddressCache *cache ) {
 static gint addrcache_free_item_vis( gpointer key, gpointer value, gpointer data ) {
        AddrItemObject *obj = ( AddrItemObject * ) value;
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
+               /* Free person and their email */
                addritem_free_item_person( ( ItemPerson * ) obj );
        }
        else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
@@ -173,6 +211,7 @@ void addrcache_clear( AddressCache *cache ) {
 void addrcache_free( AddressCache *cache ) {
        g_return_if_fail( cache != NULL );
 
+       cache->dirtyFlag = FALSE;
        addrcache_free_all_folders( cache->rootFolder );
        addrcache_free_item_hash( cache->itemHash );
        cache->itemHash = NULL;
@@ -181,6 +220,10 @@ void addrcache_free( AddressCache *cache ) {
        cache->rootFolder = NULL;
        g_list_free( cache->tempList );
        cache->tempList = NULL;
+       g_free( cache->cacheID );
+       cache->cacheID = NULL;
+       g_free( cache->name );
+       cache->name = NULL;
        g_free( cache );
 }
 
@@ -246,6 +289,9 @@ static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer dat
        if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
                addritem_print_item_person( ( ItemPerson * ) obj, stream );
        }
+       else if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
+               printf( "addrcache: print email\n" );
+       }
        else if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
                addritem_print_item_group( ( ItemGroup * ) obj, stream );
        }
@@ -260,7 +306,9 @@ static void addrcache_print_item_vis( gpointer key, gpointer value, gpointer dat
 void addrcache_print( AddressCache *cache, FILE *stream ) {
        g_return_if_fail( cache != NULL );
        fprintf( stream, "AddressCache:\n" );
+       fprintf( stream, "cache id : %s\n",  cache->cacheID );
        fprintf( stream, "next id  : %d\n",  cache->nextID );
+       fprintf( stream, "name     : %s\n",  cache->name );
        fprintf( stream, "mod time : %ld\n", cache->modifyTime );
        fprintf( stream, "modified : %s\n",  cache->modified ? "yes" : "no" );
        fprintf( stream, "data read: %s\n",  cache->dataRead ? "yes" : "no" );
@@ -342,6 +390,18 @@ gboolean addrcache_hash_add_person( AddressCache *cache, ItemPerson *person ) {
        return TRUE;
 }
 
+/*
+* Add email to hash table.
+* return: TRUE if item added.
+*/
+gboolean addrcache_hash_add_email( AddressCache *cache, ItemEMail *email ) {
+       if( g_hash_table_lookup( cache->itemHash, ADDRITEM_ID(email) ) ) {
+               return FALSE;
+       }
+       g_hash_table_insert( cache->itemHash, ADDRITEM_ID(email), email );
+       return TRUE;
+}
+
 /*
 * Add group to hash table.
 * return: TRUE if item added.
@@ -385,6 +445,7 @@ gboolean addrcache_folder_add_person( AddressCache *cache, ItemFolder *folder, I
        retVal = addrcache_hash_add_person( cache, item );
        if( retVal ) {
                addritem_folder_add_person( folder, item );
+               cache->dirtyFlag = TRUE;
        }
        return retVal;
 }
@@ -402,6 +463,7 @@ gboolean addrcache_folder_add_folder( AddressCache *cache, ItemFolder *folder, I
        retVal = addrcache_hash_add_folder( cache, item );
        if( retVal ) {
                addritem_folder_add_folder( folder, item );
+               cache->dirtyFlag = TRUE;
        }
        return TRUE;
 }
@@ -419,6 +481,7 @@ gboolean addrcache_folder_add_group( AddressCache *cache, ItemFolder *folder, It
        retVal = addrcache_hash_add_group( cache, item );
        if( retVal ) {
                addritem_folder_add_group( folder, item );
+               cache->dirtyFlag = TRUE;
        }
        return retVal;
 }
@@ -436,6 +499,7 @@ gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
        retVal = addrcache_hash_add_person( cache, person );
        if( retVal ) {
                addritem_folder_add_person( cache->rootFolder, person );
+               cache->dirtyFlag = TRUE;
        }
        return retVal;
 }
@@ -445,12 +509,18 @@ gboolean addrcache_add_person( AddressCache *cache, ItemPerson *person ) {
 * return: TRUE if item added.
 */
 gboolean addrcache_person_add_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
+       gboolean retVal = FALSE;
+
        g_return_val_if_fail( cache != NULL, FALSE );
        g_return_val_if_fail( person != NULL, FALSE );
        g_return_val_if_fail( email != NULL, FALSE );
 
-       addritem_person_add_email( person, email );
-       return TRUE;
+       retVal = addrcache_hash_add_email( cache, email );
+       if( retVal ) {
+               addritem_person_add_email( person, email );
+               cache->dirtyFlag = TRUE;
+       }
+       return retVal;
 }
 
 /*
@@ -466,6 +536,7 @@ gboolean addrcache_add_group( AddressCache *cache, ItemGroup *group ) {
        retVal = addrcache_hash_add_group( cache, group );
        if( retVal ) {
                addritem_folder_add_group( cache->rootFolder, group );
+               cache->dirtyFlag = TRUE;
        }
        return retVal;
 }
@@ -480,6 +551,7 @@ gboolean addrcache_group_add_email( AddressCache *cache, ItemGroup *group, ItemE
        g_return_val_if_fail( email != NULL, FALSE );
 
        addritem_group_add_email( group, email );
+       cache->dirtyFlag = TRUE;
        return TRUE;
 }
 
@@ -496,10 +568,77 @@ gboolean addrcache_add_folder( AddressCache *cache, ItemFolder *folder ) {
        retVal = addrcache_hash_add_folder( cache, folder );
        if( retVal ) {
                addritem_folder_add_folder( cache->rootFolder, folder );
+               cache->dirtyFlag = TRUE;
        }
        return retVal;
 }
 
+/*
+* Move person to destination folder.
+* Enter: cache  Cache.
+*        person Person to move.
+*        target Target folder.
+*/
+void addrcache_folder_move_person(
+       AddressCache *cache, ItemPerson *person, ItemFolder *target )
+{
+       ItemFolder *parent;
+
+       g_return_if_fail( cache != NULL );
+       g_return_if_fail( person != NULL );
+
+       parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
+       if( ! parent ) parent = cache->rootFolder;
+       parent->listPerson = g_list_remove( parent->listPerson, person );
+       target->listPerson = g_list_append( target->listPerson, person );
+       ADDRITEM_PARENT(person) = ADDRITEM_OBJECT(target);
+       cache->dirtyFlag = TRUE;
+}
+
+/*
+* Move group to destination folder.
+* Enter: cache  Cache.
+*        group  Group to move.
+*        target Target folder.
+*/
+void addrcache_folder_move_group(
+       AddressCache *cache, ItemGroup *group, ItemFolder *target )
+{
+       ItemFolder *parent;
+
+       g_return_if_fail( cache != NULL );
+       g_return_if_fail( group != NULL );
+
+       parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
+       if( ! parent ) parent = cache->rootFolder;
+       parent->listGroup = g_list_remove( parent->listGroup, group );
+       target->listGroup = g_list_append( target->listGroup, group );
+       ADDRITEM_PARENT(group) = ADDRITEM_OBJECT(target);
+       cache->dirtyFlag = TRUE;
+}
+
+/*
+* Move folder to destination folder.
+* Enter: cache  Cache.
+*        folder Folder to move.
+*        target Target folder.
+*/
+void addrcache_folder_move_folder(
+       AddressCache *cache, ItemFolder *folder, ItemFolder *target )
+{
+       ItemFolder *parent;
+
+       g_return_if_fail( cache != NULL );
+       g_return_if_fail( folder != NULL );
+
+       parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
+       if( ! parent ) parent = cache->rootFolder;
+       parent->listFolder = g_list_remove( parent->listFolder, folder );
+       target->listFolder = g_list_append( target->listFolder, folder );
+       ADDRITEM_PARENT(folder) = ADDRITEM_OBJECT(target);
+       cache->dirtyFlag = TRUE;
+}
+
 /*
 * Return pointer to object (either person or group) for specified ID.
 * param: uid Object ID.
@@ -559,34 +698,19 @@ ItemGroup *addrcache_get_group( AddressCache *cache, const gchar *uid ) {
 
 /*
 * Find email address in address cache.
-* param: uid   Object ID for person.
-*        eid   EMail ID.
+* param: eid   EMail ID.
 * return: email object for specified object ID and email ID, or NULL if not found.
 */
-ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *uid, const gchar *eid ) {
-       AddrItemObject *objP;
-
-       if( eid == NULL || *eid == '\0' ) return NULL;
-
-       objP = addrcache_get_object( cache, uid );
-       if( objP ) {
-               if( ADDRITEM_TYPE(objP) == ITEMTYPE_PERSON ) {
-                       /* Sequential search through email addresses */
-                       ItemPerson *person = ( ItemPerson * ) objP;
-                       GList *nodeMail = person->listEMail;
-                       while( nodeMail ) {
-                               AddrItemObject *objE = nodeMail->data;
-                               gchar *ide = ADDRITEM_ID(objE);
-                               if( ide ) {
-                                       if( strcmp( ide, eid ) == 0 ) {
-                                               return ( ItemEMail * ) objE;
-                                       }
-                               }
-                               nodeMail = g_list_next( nodeMail );
-                       }
+ItemEMail *addrcache_get_email( AddressCache *cache, const gchar *eid ) {
+       ItemEMail *email = NULL;
+       AddrItemObject *obj = addrcache_get_object( cache, eid );
+
+       if( obj ) {
+               if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
+                       email = ( ItemEMail * ) obj;
                }
        }
-       return NULL;
+       return email;
 }
 
 /*
@@ -604,6 +728,7 @@ UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache, const gch
        person = addrcache_get_person( cache, uid );
        if( person ) {
                attrib = addritem_person_remove_attrib_id( person, aid );
+               cache->dirtyFlag = TRUE;
        }
        return attrib;
 }
@@ -621,36 +746,11 @@ UserAttribute *addrcache_person_remove_attribute( AddressCache *cache, ItemPerso
 
        if( person && attrib ) {
                found = addritem_person_remove_attribute( person, attrib );
+               cache->dirtyFlag = TRUE;
        }
        return found;
 }
 
-/*
-* Remove group from address cache for specified ID.
-* param: uid Object ID.
-* return: Group, or NULL if not found. Note that object should still be freed.
-*/
-ItemGroup *addrcache_remove_group_id( AddressCache *cache, const gchar *uid ) {
-       AddrItemObject *obj = NULL;
-
-       g_return_val_if_fail( cache != NULL, NULL );
-
-       if( uid == NULL || *uid == '\0' ) return NULL;
-       obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
-       if( obj ) {
-               if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
-                       ItemGroup *group = ( ItemGroup * ) obj;
-                       ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(group);
-                       if( ! parent ) parent = cache->rootFolder;
-                       /* Remove group from parent's list and hash table */
-                       parent->listGroup = g_list_remove( parent->listGroup, group );
-                       g_hash_table_remove( cache->itemHash, uid );
-                       return ( ItemGroup * ) obj;
-               }
-       }
-       return NULL;
-}
-
 /*
 * Remove group from address cache.
 * param: group Group to remove.
@@ -672,6 +772,7 @@ ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
                        /* Remove group from parent's list and hash table */
                        parent->listGroup = g_list_remove( parent->listGroup, obj );
                        g_hash_table_remove( cache->itemHash, uid );
+                       cache->dirtyFlag = TRUE;
                        return group;
                }
        }
@@ -679,55 +780,47 @@ ItemGroup *addrcache_remove_group( AddressCache *cache, ItemGroup *group ) {
 }
 
 /*
-* Remove person's email address from all groups in folder.
+* Remove specified email from address cache. Note that object is only
+* removed from cache and not parent objects.
+* param: email EMail to remove.
+* return: EMail, or NULL if not found. Note that object should still be freed.
 */
-static void addrcache_foldergrp_rem_person( ItemFolder *folder, ItemPerson *person ) {
-       GList *nodeGrp = folder->listGroup;
+ItemEMail *addrcache_remove_email( AddressCache *cache, ItemEMail *email ) {
+       AddrItemObject *obj = NULL;
 
-       while( nodeGrp ) {
-               ItemGroup *group = nodeGrp->data;
-               if( group ) {
-                       /* Remove each email address that belongs to the person from the list */
-                       GList *node = person->listEMail;
-                       while( node ) {
-                               group->listEMail = g_list_remove( group->listEMail, node->data );
-                               node = g_list_next( node );
+       g_return_val_if_fail( cache != NULL, NULL );
+
+       if( email ) {
+               gchar *eid = ADDRITEM_ID(email);
+               if( eid == NULL || *eid == '\0' ) return NULL;
+               obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, eid );
+               if( obj ) {
+                       if( ADDRITEM_TYPE(obj) == ITEMTYPE_EMAIL ) {
+                               /* Remove email addresses from hash table. */
+                               g_hash_table_remove( cache->itemHash, eid );
+                               cache->dirtyFlag = TRUE;
+                               return email;
                        }
                }
-               nodeGrp = g_list_next( nodeGrp );
        }
+       return NULL;
 }
 
 /*
-* Remove person from address cache for specified ID. Note that person still retains
-* their EMail addresses. Also, links to these email addresses will be severed from
-* the group.
-* param: uid Object ID.
-* return: Person, or NULL if not found. Note that object should still be freed.
+* Hash table visitor function to remove email from group.
 */
-ItemPerson *addrcache_remove_person_id( AddressCache *cache, const gchar *uid ) {
-       AddrItemObject *obj = NULL;
-
-       g_return_val_if_fail( cache != NULL, NULL );
+static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
+       AddrItemObject *obj = ( AddrItemObject * ) value;
+       ItemEMail *email = ( ItemEMail * ) data;
 
-       if( uid == NULL || *uid == '\0' ) return NULL;
-       obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
-       if( obj ) {
-               if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
-                       /* Remove person's email addresses from all groups where */
-                       /* referenced and from hash table. */
-                       ItemPerson *person = ( ItemPerson * ) obj;
-                       ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
-                       if( ! parent ) parent = cache->rootFolder;
-                       /* Remove emails from groups, remove from parent's list */
-                       /* and hash table */
-                       addrcache_foldergrp_rem_person( parent, person );
-                       parent->listPerson = g_list_remove( parent->listPerson, person );
-                       g_hash_table_remove( cache->itemHash, uid );
-                       return person;
+       if( ! email ) return;
+       if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
+               ItemGroup *group = ( ItemGroup * ) value;
+               if( group ) {
+                       /* Remove each email address that belongs to the person from the list */
+                       group->listEMail = g_list_remove( group->listEMail, email );
                }
        }
-       return NULL;
 }
 
 /*
@@ -737,22 +830,40 @@ ItemPerson *addrcache_remove_person_id( AddressCache *cache, const gchar *uid )
 */
 ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
        AddrItemObject *obj = NULL;
+       gchar *uid;
 
        g_return_val_if_fail( cache != NULL, NULL );
 
        if( person ) {
-               gchar *uid = ADDRITEM_ID(person);
+               uid = ADDRITEM_ID(person);
                if( uid == NULL || *uid == '\0' ) return NULL;
                obj = ( AddrItemObject * ) g_hash_table_lookup( cache->itemHash, uid );
                if( obj ) {
                        if( ADDRITEM_TYPE(obj) == ITEMTYPE_PERSON ) {
-                               /* Remove person's email addresses from all groups where */
-                               /* referenced and from hash table. */
-                               ItemFolder *parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
+                               ItemFolder *parent;
+                               GList *node;
+
+                               /* Remove all email addresses for person */
+                               /* from groups and from hash table */
+                               node = person->listEMail;
+                               while( node ) {
+                                       ItemEMail *email;
+                                       gchar *eid;
+
+                                       email = node->data;
+                                       g_hash_table_foreach( cache->itemHash,
+                                               addrcache_allgrp_rem_email_vis, email );
+                                       eid = ADDRITEM_ID( email );
+                                       g_hash_table_remove( cache->itemHash, eid );
+                                       node = g_list_next( node );
+                               }
+
+                               /* Remove person from owning folder */
+                               parent = ( ItemFolder * ) ADDRITEM_PARENT(person);
                                if( ! parent ) parent = cache->rootFolder;
-                               addrcache_foldergrp_rem_person( parent, person );
                                parent->listPerson = g_list_remove( parent->listPerson, person );
                                g_hash_table_remove( cache->itemHash, uid );
+                               cache->dirtyFlag = TRUE;
                                return person;
                        }
                }
@@ -761,38 +872,19 @@ ItemPerson *addrcache_remove_person( AddressCache *cache, ItemPerson *person ) {
 }
 
 /*
-* Remove email from group item hash table visitor function.
-*/
-static void addrcache_allgrp_rem_email_vis( gpointer key, gpointer value, gpointer data ) {
-       AddrItemObject *obj = ( AddrItemObject * ) value;
-       ItemEMail *email = ( ItemEMail * ) data;
-
-       if( !email ) return;
-       if( ADDRITEM_TYPE(obj) == ITEMTYPE_GROUP ) {
-               ItemGroup *group = ( ItemGroup * ) value;
-               if( group ) {
-                       /* Remove each email address that belongs to the person from the list */
-                       group->listEMail = g_list_remove( group->listEMail, email );
-               }
-       }
-}
-
-/*
-* Remove email address in address cache for specified ID.
-* param: uid   Object ID for person.
-*        eid   EMail ID.
+* Remove email address in address cache for specified person.
+* param: person        Person.
+*        email EMail to remove.
 * return: EMail object, or NULL if not found. Note that object should still be freed.
 */
-ItemEMail *addrcache_person_remove_email_id( AddressCache *cache, const gchar *uid, const gchar *eid ) {
-       ItemEMail *email = NULL;
-       ItemPerson *person;
+ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
+       ItemEMail *found = NULL;
 
-       if( eid == NULL || *eid == '\0' ) return NULL;
+       g_return_val_if_fail( cache != NULL, NULL );
 
-       person = addrcache_get_person( cache, uid );
-       if( person ) {
-               email = addritem_person_remove_email_id( person, eid );
-               if( email ) {
+       if( person && email ) {
+               found = addritem_person_remove_email( person, email );
+               if( found ) {
                        /* Remove email from all groups. */
                        g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
 
@@ -802,37 +894,42 @@ ItemEMail *addrcache_person_remove_email_id( AddressCache *cache, const gchar *u
                        }
                        /* Unlink reference to person. */
                        ADDRITEM_PARENT(email) = NULL;
+                       cache->dirtyFlag = TRUE;
                }
        }
-       return email;
+       return found;
 }
 
 /*
-* Remove email address in address cache for specified person.
-* param: person        Person.
-*        email EMail to remove.
+* Move email address in address cache to new person. If member of group, address
+* remains in group.
+* param: cache  Cache.
+*        email  EMail to remove.
+*        target Target person.
 * return: EMail object, or NULL if not found. Note that object should still be freed.
 */
-ItemEMail *addrcache_person_remove_email( AddressCache *cache, ItemPerson *person, ItemEMail *email ) {
-       ItemEMail *found = NULL;
+void addrcache_person_move_email(
+       AddressCache *cache, ItemEMail *email, ItemPerson *target )
+{
+       ItemPerson *person;
 
-       g_return_val_if_fail( cache != NULL, NULL );
+       g_return_if_fail( cache != NULL );
 
-       if( person && email ) {
+       if( email == NULL ) return;
+       if( target == NULL ) return;
+
+       person = ( ItemPerson * ) ADDRITEM_PARENT(email);
+       if( person ) {
+               ItemEMail *found;
                found = addritem_person_remove_email( person, email );
                if( found ) {
-                       /* Remove email from all groups. */
-                       g_hash_table_foreach( cache->itemHash, addrcache_allgrp_rem_email_vis, email );
-
-                       /* Remove email from person's address list */
                        if( person->listEMail ) {
-                               person->listEMail = g_list_remove( person->listEMail, email );
+                               person->listEMail = g_list_remove( person->listEMail, found );
+                               addritem_person_add_email( target, found );
+                               cache->dirtyFlag = TRUE;
                        }
-                       /* Unlink reference to person. */
-                       ADDRITEM_PARENT(email) = NULL;
                }
        }
-       return found;
 }
 
 /*
@@ -982,7 +1079,7 @@ static void addrcache_get_grp_person_vis( gpointer key, gpointer value, gpointer
 }
 
 /*
-* Return link list of groups which contain a reference to specified person's email
+* Return linked list of groups which contain a reference to specified person's email
 * address.
 */
 GList *addrcache_get_group_for_person( AddressCache *cache, ItemPerson *person ) {
@@ -1126,6 +1223,7 @@ ItemFolder *addrcache_remove_folder( AddressCache *cache, ItemFolder *folder ) {
                        parent->listFolder = g_list_remove( parent->listFolder, folder );
                        ADDRITEM_PARENT(folder) = NULL;
                        g_hash_table_remove( cache->itemHash, uid );
+                       cache->dirtyFlag = TRUE;
                        return folder;
                }
        }
@@ -1183,6 +1281,7 @@ ItemFolder *addrcache_remove_folder_delete( AddressCache *cache, ItemFolder *fol
                        parent->listFolder = g_list_remove( parent->listFolder, folder );
                        ADDRITEM_PARENT(folder) = NULL;
                        g_hash_table_remove( cache->itemHash, uid );
+                       cache->dirtyFlag = TRUE;
                        return folder;
                }
        }
@@ -1222,6 +1321,7 @@ ItemPerson *addrcache_add_contact( AddressCache *cache, ItemFolder *folder, cons
        addritem_email_set_remarks( email, remarks );
        addrcache_id_email( cache, email );
        addritem_person_add_email( person, email );
+       cache->dirtyFlag = TRUE;
 
        return person;
 }
index 46a0264f9ae70e3f58e1212dc6c71181be9caa67..cfb7877d18e8a660927ce49049520ba3ae0cbff8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,6 +40,9 @@ struct _AddressCache {
        GHashTable *itemHash;
        GList      *tempList;
        ItemFolder *rootFolder;
+       gchar      *cacheID;
+       gboolean   dirtyFlag;
+       gchar      *name;
 };
 
 /* Function prototypes */
@@ -47,9 +50,14 @@ AddressCache *addrcache_create();
 ItemFolder *addrcache_get_root_folder  ( AddressCache *cache );
 GList *addrcache_get_list_folder       ( AddressCache *cache );
 GList *addrcache_get_list_person       ( AddressCache *cache );
+gboolean addrcache_get_dirty           ( AddressCache *cache );
+void addrcache_set_dirty               ( AddressCache *cache,
+                                         const gboolean value );
+gchar *addrcache_get_name              ( AddressCache *cache );
+void addrcache_set_name                        ( AddressCache *cache,
+                                         const gchar *value );
 
 void addrcache_refresh                 ( AddressCache *cache );
-/* void addrcache_empty                        ( AddressCache *cache ); */
 void addrcache_clear                   ( AddressCache *cache );
 void addrcache_free                    ( AddressCache *cache );
 gboolean addrcache_check_file          ( AddressCache *cache, gchar *path );
@@ -69,55 +77,87 @@ gboolean addrcache_hash_add_person  ( AddressCache *cache, ItemPerson *person );
 gboolean addrcache_hash_add_group      ( AddressCache *cache, ItemGroup *group );
 gboolean addrcache_hash_add_folder     ( AddressCache *cache, ItemFolder *folder );
 
-gboolean addrcache_folder_add_person   ( AddressCache *cache, ItemFolder *folder, ItemPerson *item );
-gboolean addrcache_folder_add_folder   ( AddressCache *cache, ItemFolder *folder, ItemFolder *item );
-gboolean addrcache_folder_add_group    ( AddressCache *cache, ItemFolder *folder, ItemGroup *item );
-
-gboolean addrcache_add_person          ( AddressCache *cache, ItemPerson *person );
-gboolean addrcache_add_group           ( AddressCache *cache, ItemGroup *group );
-gboolean addrcache_person_add_email    ( AddressCache *cache, ItemPerson *person, ItemEMail *email );
-gboolean addrcache_group_add_email     ( AddressCache *cache, ItemGroup *group, ItemEMail *email );
-gboolean addrcache_add_folder          ( AddressCache *cache, ItemFolder *folder );
+gboolean addrcache_folder_add_person   ( AddressCache *cache,
+                                         ItemFolder *folder,
+                                         ItemPerson *item );
+gboolean addrcache_folder_add_folder   ( AddressCache *cache,
+                                         ItemFolder *folder,
+                                         ItemFolder *item );
+gboolean addrcache_folder_add_group    ( AddressCache *cache,
+                                         ItemFolder *folder,
+                                         ItemGroup *item );
+
+gboolean addrcache_add_person          ( AddressCache *cache,
+                                         ItemPerson *person );
+gboolean addrcache_add_group           ( AddressCache *cache,
+                                         ItemGroup *group );
+gboolean addrcache_person_add_email    ( AddressCache *cache,
+                                         ItemPerson *person,
+                                         ItemEMail *email );
+gboolean addrcache_group_add_email     ( AddressCache *cache,
+                                         ItemGroup *group,
+                                         ItemEMail *email );
+gboolean addrcache_add_folder          ( AddressCache *cache,
+                                         ItemFolder *folder );
+
+void addrcache_folder_move_person      ( AddressCache *cache,
+                                         ItemPerson *person,
+                                         ItemFolder *target );
+void addrcache_folder_move_group       ( AddressCache *cache,
+                                         ItemGroup *group,
+                                         ItemFolder *target );
+void addrcache_folder_move_folder      ( AddressCache *cache,
+                                         ItemFolder *folder,
+                                         ItemFolder *target );
 
 AddrItemObject *addrcache_get_object   ( AddressCache *cache, const gchar *uid );
 ItemPerson *addrcache_get_person       ( AddressCache *cache, const gchar *uid );
 ItemGroup *addrcache_get_group         ( AddressCache *cache, const gchar *uid );
-ItemEMail *addrcache_get_email         ( AddressCache *cache, const gchar *uid, const gchar *eid );
-
-UserAttribute *addrcache_person_remove_attrib_id       ( AddressCache *cache, const gchar *uid,
-                                                         const gchar *aid );
-UserAttribute *addrcache_person_remove_attribute       ( AddressCache *cache, ItemPerson *person,
-                                                         UserAttribute *attrib );
-
-ItemGroup *addrcache_remove_group_id           ( AddressCache *cache, const gchar *uid );
-ItemGroup *addrcache_remove_group              ( AddressCache *cache, ItemGroup *group );
-
-ItemPerson *addrcache_remove_person_id         ( AddressCache *cache, const gchar *uid );
-ItemPerson *addrcache_remove_person            ( AddressCache *cache, ItemPerson *person );
-ItemEMail *addrcache_person_remove_email_id    ( AddressCache *cache, const gchar *uid, const gchar *eid );
-ItemEMail *addrcache_person_remove_email       ( AddressCache *cache, ItemPerson *person, ItemEMail *email );
-
-GList *addrcache_folder_get_address_list       ( AddressCache *cache, ItemFolder *folder );
-GList *addrcache_folder_get_person_list                ( AddressCache *cache, ItemFolder *folder );
-GList *addrcache_folder_get_group_list         ( AddressCache *cache, ItemFolder *folder );
-GList *addrcache_folder_get_folder_list                ( AddressCache *cache, ItemFolder *folder );
-
-GList *addrcache_get_address_list              ( AddressCache *cache );
-GList *addrcache_get_person_list               ( AddressCache *cache );
-GList *addrcache_get_group_list                        ( AddressCache *cache );
-GList *addrcache_get_folder_list               ( AddressCache *cache );
-
-GList *addrcache_get_group_for_person          ( AddressCache *cache, ItemPerson *person );
-
-ItemFolder *addrcache_find_root_folder         ( ItemFolder *folder );
-GList *addrcache_get_all_persons               ( AddressCache *cache );
-GList *addrcache_get_all_groups                        ( AddressCache *cache );
-
-ItemFolder *addrcache_remove_folder            ( AddressCache *cache, ItemFolder *folder );
-ItemFolder *addrcache_remove_folder_delete     ( AddressCache *cache, ItemFolder *folder );
-
-ItemPerson *addrcache_add_contact              ( AddressCache *cache, ItemFolder *folder,
-                                                 const gchar *name, const gchar *address,
-                                                 const gchar *remarks ); 
+ItemEMail *addrcache_get_email         ( AddressCache *cache, const gchar *eid );
+
+UserAttribute *addrcache_person_remove_attrib_id( AddressCache *cache,
+                                                 const gchar *uid,
+                                                 const gchar *aid );
+UserAttribute *addrcache_person_remove_attribute( AddressCache *cache,
+                                                 ItemPerson *person,
+                                                 UserAttribute *attrib );
+
+ItemGroup *addrcache_remove_group      ( AddressCache *cache, ItemGroup *group );
+ItemPerson *addrcache_remove_person    ( AddressCache *cache, ItemPerson *person );
+ItemEMail *addrcache_remove_email      ( AddressCache *cache, ItemEMail *email );
+
+ItemEMail *addrcache_person_remove_email( AddressCache *cache,
+                                         ItemPerson *person, 
+                                         ItemEMail *email );
+void addrcache_person_move_email       ( AddressCache *cache,
+                                         ItemEMail *email,
+                                         ItemPerson *target );
+
+GList *addrcache_folder_get_address_list( AddressCache *cache, ItemFolder *folder );
+GList *addrcache_folder_get_person_list        ( AddressCache *cache, ItemFolder *folder );
+GList *addrcache_folder_get_group_list ( AddressCache *cache, ItemFolder *folder );
+GList *addrcache_folder_get_folder_list        ( AddressCache *cache, ItemFolder *folder );
+
+GList *addrcache_get_address_list      ( AddressCache *cache );
+GList *addrcache_get_person_list       ( AddressCache *cache );
+GList *addrcache_get_group_list                ( AddressCache *cache );
+GList *addrcache_get_folder_list       ( AddressCache *cache );
+
+GList *addrcache_get_group_for_person  ( AddressCache *cache, ItemPerson *person );
+
+ItemFolder *addrcache_find_root_folder ( ItemFolder *folder );
+GList *addrcache_get_all_persons       ( AddressCache *cache );
+GList *addrcache_get_all_groups                ( AddressCache *cache );
+
+ItemFolder *addrcache_remove_folder            ( AddressCache *cache,
+                                                 ItemFolder *folder );
+ItemFolder *addrcache_remove_folder_delete     ( AddressCache *cache,
+                                                 ItemFolder *folder );
+
+ItemPerson *addrcache_add_contact      ( AddressCache *cache,
+                                         ItemFolder *folder,
+                                         const gchar *name,
+                                         const gchar *address,
+                                         const gchar *remarks ); 
 
 #endif /* __ADDRCACHE_H__ */
index 93b809a61ca7689e4dae20122ebb228f40d62b96..bf3a1f5a0163f5f0e675b3a51c3b1824fdf7019b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2001 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2002 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
 #endif
 
+#include "addrselect.h"
+#include "addrclip.h"
+
+/*
+#include "pixmaps/dir-close.xpm"
+#include "pixmaps/dir-open.xpm"
+#include "pixmaps/group.xpm"
+#include "pixmaps/interface.xpm"
+#include "pixmaps/book.xpm"
+#include "pixmaps/address.xpm"
+#include "pixmaps/vcard.xpm"
+#include "pixmaps/jpilot.xpm"
+#include "pixmaps/category.xpm"
+#include "pixmaps/ldap.xpm"
+*/
+
 typedef enum
 {
        COL_NAME        = 0,
@@ -134,7 +150,8 @@ static GdkBitmap *ldapxpmmask;
 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
 
 /* Address list selection */
-static GList *_addressListSelection_ = NULL;
+static AddrSelectList *_addressSelect_ = NULL;
+static AddressClipboard *_clipBoard_ = NULL;
 
 /* Address index file and interfaces */
 static AddressIndex *_addressIndex_ = NULL;
@@ -265,10 +282,12 @@ void addressbook_read_file                        (void);
 
 static GtkCTreeNode *addressbook_add_object    (GtkCTreeNode   *node,
                                                 AddressObject  *obj);
+static void addressbook_treenode_remove_item   ( void );
+
 static AddressDataSource *addressbook_find_datasource
                                                (GtkCTreeNode   *node );
 
-static AddressBookFile *addressbook_get_book_file();
+static AddressBookFile *addressbook_get_book_file(void);
 
 static GtkCTreeNode *addressbook_node_add_folder
                                                (GtkCTreeNode   *node,
@@ -278,40 +297,33 @@ static GtkCTreeNode *addressbook_node_add_folder
 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode  *node,
                                                AddressDataSource *ds,
                                                ItemGroup       *itemGroup);
-/* static GtkCTreeNode *addressbook_node_add_category */
-/*                                             (GtkCTreeNode   *node, */
-/*                                              AddressDataSource *ds, */
-/*                                              ItemFolder     *itemFolder); */
 static void addressbook_tree_remove_children   (GtkCTree       *ctree,
                                                GtkCTreeNode    *parent);
 static void addressbook_move_nodes_up          (GtkCTree       *ctree,
                                                GtkCTreeNode    *node);
 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
-                                               ItemGroup       *group);
+                                                  ItemGroup    *group);
+static GtkCTreeNode *addressbook_find_folder_node( GtkCTreeNode        *parent,
+                                                  ItemFolder   *folder );
 
 static void addressbook_delete_object          (AddressObject  *obj);
 
 static void key_pressed                                (GtkWidget      *widget,
                                                 GdkEventKey    *event,
                                                 gpointer        data);
+static gint addressbook_treenode_compare_func  (GtkCList       *clist,
+                                                gconstpointer   ptr1,
+                                                gconstpointer   ptr2);
 static gint addressbook_list_compare_func      (GtkCList       *clist,
                                                 gconstpointer   ptr1,
                                                 gconstpointer   ptr2);
-/* static gint addressbook_obj_name_compare    (gconstpointer   a, */
-/*                                              gconstpointer   b); */
 
-static void addressbook_book_show_message      (AddressBookFile *book);
-static void addressbook_vcard_show_message     (VCardFile *vcf);
-#ifdef USE_JPILOT
-static void addressbook_jpilot_show_message    (JPilotFile *jpf);
-#endif
 #ifdef USE_LDAP
 static void addressbook_ldap_show_message      (SyldapServer *server);
 #endif
 
 /* LUT's and IF stuff */
-static void addressbook_free_adapter           (GtkCTreeNode   *node);
-static void addressbook_free_child_adapters    (GtkCTreeNode   *node);
+static void addressbook_free_treenode          ( gpointer data );
 AddressTypeControlItem *addrbookctl_lookup     (gint            ot);
 AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType  ifType);
 
@@ -325,12 +337,20 @@ static void addrbookctl_free_datasource           (AdapterDSource   *adapter);
 static void addrbookctl_free_folder            (AdapterFolder    *adapter);
 static void addrbookctl_free_group             (AdapterGroup     *adapter);
 
-static void addressbook_list_select_clear      (void);
-static void addressbook_list_select_add                (AddressObject *obj);
-static void addressbook_list_select_remove     (AddressObject *obj);
-
-static void addressbook_import_ldif_cb         (void);
-static void addressbook_import_mutt_cb         (void);
+static void addressbook_list_select_clear      ( void );
+static void addressbook_list_select_add                ( AddrItemObject    *aio,
+                                                 AddressDataSource *ds );
+static void addressbook_list_select_remove     ( AddrItemObject    *aio );
+
+static void addressbook_import_ldif_cb         ( void );
+static void addressbook_import_mutt_cb         ( void );
+static void addressbook_clip_cut_cb            ( void );
+static void addressbook_clip_copy_cb           ( void );
+static void addressbook_clip_paste_cb          ( void );
+static void addressbook_clip_paste_address_cb  ( void );
+static void addressbook_treenode_cut_cb                ( void );
+static void addressbook_treenode_copy_cb       ( void );
+static void addressbook_treenode_paste_cb      ( void );
 
 static GtkItemFactoryEntry addressbook_entries[] =
 {
@@ -348,7 +368,13 @@ static GtkItemFactoryEntry addressbook_entries[] =
        {N_("/_File/_Delete"),          NULL,           addressbook_treenode_delete_cb, 0, NULL},
        {N_("/_File/---"),              NULL,           NULL, 0, "<Separator>"},
        {N_("/_File/_Save"),            "<alt>S",       addressbook_file_save_cb,       0, NULL},
-       {N_("/_File/_Close"),           "<alt>W",       close_cb, 0, NULL},
+       {N_("/_File/_Close"),           "<alt>W",       close_cb,                       0, NULL},
+       {N_("/_Edit"),                  NULL,           NULL, 0, "<Branch>"},
+       {N_("/_Edit/C_ut"),             "<ctl>X",       addressbook_clip_cut_cb,        0, NULL},
+       {N_("/_Edit/_Copy"),            "<ctl>C",       addressbook_clip_copy_cb,       0, NULL},
+       {N_("/_Edit/_Paste"),           "<ctl>V",       addressbook_clip_paste_cb,      0, NULL},
+       {N_("/_Edit/---"),              NULL,           NULL, 0, "<Separator>"},
+       {N_("/_Edit/Pa_ste Address"),   NULL,           addressbook_clip_paste_address_cb, 0, NULL},
        {N_("/_Address"),               NULL,           NULL, 0, "<Branch>"},
        {N_("/_Address/New _Address"),  "<alt>N",       addressbook_new_address_cb,     0, NULL},
        {N_("/_Address/New _Group"),    "<alt>G",       addressbook_new_group_cb,       0, NULL},
@@ -357,7 +383,7 @@ static GtkItemFactoryEntry addressbook_entries[] =
        {N_("/_Address/_Edit"),         "<alt>Return",  addressbook_edit_address_cb,    0, NULL},
        {N_("/_Address/_Delete"),       NULL,           addressbook_delete_address_cb,  0, NULL},
        {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
-       {N_("/_Tools/Import _LDIF file"), NULL,         addressbook_import_ldif_cb,     0, NULL},
+       {N_("/_Tools/Import _LDIF"),    NULL,           addressbook_import_ldif_cb,     0, NULL},
        {N_("/_Tools/Import M_utt"),    NULL,           addressbook_import_mutt_cb,     0, NULL},
        {N_("/_Help"),                  NULL,           NULL, 0, "<LastBranch>"},
        {N_("/_Help/_About"),           NULL,           about_show, 0, NULL}
@@ -365,15 +391,11 @@ static GtkItemFactoryEntry addressbook_entries[] =
 
 /* New options to be added. */
 /*
-       {N_("/_Edit"),                  NULL,           NULL, 0, "<Branch>"},
-       {N_("/_Edit/C_ut"),             "<ctl>X",       NULL,                           0, NULL},
-       {N_("/_Edit/_Copy"),            "<ctl>C",       NULL,                           0, NULL},
-       {N_("/_Edit/_Paste"),           "<ctl>V",       NULL,                           0, NULL},
        {N_("/_Tools"),                 NULL,           NULL, 0, "<Branch>"},
        {N_("/_Tools/Import _Mozilla"), NULL,           NULL,                           0, NULL},
        {N_("/_Tools/Import _vCard"),   NULL,           NULL,                           0, NULL},
        {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
-       {N_("/_Tools/Export _LDIF file"), NULL,         NULL,                           0, NULL},
+       {N_("/_Tools/Export _LDIF"),    NULL,           NULL,                           0, NULL},
        {N_("/_Tools/Export v_Card"),   NULL,           NULL,                           0, NULL},
 */
 
@@ -384,39 +406,59 @@ static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
        {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,  0, NULL},
        {N_("/---"),            NULL, NULL, 0, "<Separator>"},
        {N_("/_Edit"),          NULL, addressbook_treenode_edit_cb,   0, NULL},
-       {N_("/_Delete"),        NULL, addressbook_treenode_delete_cb, 0, NULL}
+       {N_("/_Delete"),        NULL, addressbook_treenode_delete_cb, 0, NULL},
+       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
+       {N_("/C_ut"),           NULL, addressbook_treenode_cut_cb,    0, NULL},
+       {N_("/_Copy"),          NULL, addressbook_treenode_copy_cb,   0, NULL},
+       {N_("/_Paste"),         NULL, addressbook_treenode_paste_cb,  0, NULL}
 };
 
 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
 {
-       {N_("/New _Address"),   NULL, addressbook_new_address_cb,  0, NULL},
-       {N_("/New _Group"),     NULL, addressbook_new_group_cb,    0, NULL},
-       {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,   0, NULL},
+       {N_("/New _Address"),   NULL, addressbook_new_address_cb,    0, NULL},
+       {N_("/New _Group"),     NULL, addressbook_new_group_cb,      0, NULL},
+       {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,     0, NULL},
        {N_("/---"),            NULL, NULL, 0, "<Separator>"},
        {N_("/_Edit"),          NULL, addressbook_edit_address_cb,   0, NULL},
-       {N_("/_Delete"),        NULL, addressbook_delete_address_cb, 0, NULL}
+       {N_("/_Delete"),        NULL, addressbook_delete_address_cb, 0, NULL},
+       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
+       {N_("/C_ut"),           NULL, addressbook_clip_cut_cb,       0, NULL},
+       {N_("/_Copy"),          NULL, addressbook_clip_copy_cb,      0, NULL},
+       {N_("/_Paste"),         NULL, addressbook_clip_paste_cb,     0, NULL},
+       {N_("/---"),            NULL, NULL, 0, "<Separator>"},
+       {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb,     0, NULL}
 };
 
 void addressbook_open(Compose *target)
 {
+       /* Initialize all static members */
+       if( _clipBoard_ == NULL ) {
+               _clipBoard_ = addrclip_create();
+       }
+       if( _addressIndex_ != NULL ) {
+               addrclip_set_index( _clipBoard_, _addressIndex_ );
+       }
+       if( _addressSelect_ == NULL ) {
+               _addressSelect_ = addrselect_list_create();
+       }
        if (!addrbook.window) {
                addressbook_read_file();
                addressbook_create();
                addressbook_load_tree();
                gtk_ctree_select(GTK_CTREE(addrbook.ctree),
                                 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
-       } else
+       }
+       else {
                gtk_widget_hide(addrbook.window);
+       }
 
        gtk_widget_show_all(addrbook.window);
-
        addressbook_set_target_compose(target);
 }
 
 void addressbook_set_target_compose(Compose *target)
 {
        addrbook.target_compose = target;
-
        addressbook_button_set_sensitive();
 }
 
@@ -535,7 +577,7 @@ static void addressbook_create(void)
                                     GTK_CTREE_EXPANDER_SQUARE);
        gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
        gtk_clist_set_compare_func(GTK_CLIST(ctree),
-                                  addressbook_list_compare_func);
+                                  addressbook_treenode_compare_func);
 
        gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
                           GTK_SIGNAL_FUNC(addressbook_tree_selected), NULL);
@@ -690,7 +732,9 @@ static void addressbook_create(void)
                                        interfacexpm, interfacexpmmask,
                                        FALSE, FALSE );
                        menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
-                       gtk_ctree_node_set_row_data( GTK_CTREE(ctree), adapter->treeNode, adapter );
+                       gtk_ctree_node_set_row_data_full(
+                               GTK_CTREE(ctree), adapter->treeNode, adapter,
+                               addressbook_free_treenode );
                }
        }
 
@@ -716,7 +760,8 @@ static void addressbook_create(void)
        addrbook.clist   = clist;
        addrbook.entry   = entry;
        addrbook.statusbar = statusbar;
-       addrbook.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Addressbook Window" );
+       addrbook.status_cid = gtk_statusbar_get_context_id(
+                       GTK_STATUSBAR(statusbar), "Addressbook Window" );
 
        addrbook.del_btn = del_btn;
        addrbook.reg_btn = reg_btn;
@@ -746,13 +791,31 @@ static gint addressbook_close(void)
 
 static void addressbook_status_show( gchar *msg ) {
        if( addrbook.statusbar != NULL ) {
-               gtk_statusbar_pop( GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid );
+               gtk_statusbar_pop(
+                       GTK_STATUSBAR(addrbook.statusbar),
+                       addrbook.status_cid );
                if( msg ) {
-                       gtk_statusbar_push( GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid, msg );
+                       gtk_statusbar_push(
+                               GTK_STATUSBAR(addrbook.statusbar),
+                               addrbook.status_cid, msg );
                }
        }
 }
 
+static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
+       *addressbook_msgbuf = '\0';
+       if( ds ) {
+               gchar *name;
+
+               name = addrindex_ds_get_name( ds );
+               sprintf( addressbook_msgbuf, "%s: %s", name, msg );
+       }
+       else {
+               sprintf( addressbook_msgbuf, "%s", msg );
+       }
+       addressbook_status_show( addressbook_msgbuf );
+}
+
 static void addressbook_ds_show_message( AddressDataSource *ds ) {
        gint retVal;
        gchar *name;
@@ -761,17 +824,11 @@ static void addressbook_ds_show_message( AddressDataSource *ds ) {
                name = addrindex_ds_get_name( ds );
                retVal = addrindex_ds_get_status_code( ds );
                if( retVal == MGU_SUCCESS ) {
-                       if( ds ) {
-                               sprintf( addressbook_msgbuf, "%s", name );
-                       }
+                       sprintf( addressbook_msgbuf, "%s", name );
                }
                else {
-                       if( ds == NULL ) {
-                               sprintf( addressbook_msgbuf, "%s", mgu_error2string( retVal ) );
-                       }
-                       else {
-                               sprintf( addressbook_msgbuf, "%s: %s", name, mgu_error2string( retVal ) );
-                       }
+                       sprintf( addressbook_msgbuf, "%s: %s", name,
+                               mgu_error2string( retVal ) );
                }
        }
        addressbook_status_show( addressbook_msgbuf );
@@ -804,23 +861,38 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
 {
        GtkCTree *clist = GTK_CTREE(addrbook.clist);
        GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
-       AddressObject *pobj, *obj;
+       AddressObject *pobj;
        AdapterDSource *ads = NULL;
        GtkCTreeNode *nodeList;
        gboolean procFlag;
        AlertValue aval;
        AddressBookFile *abf = NULL;
        AddressDataSource *ds = NULL;
+       AddressInterface *iface;
+       AddrItemObject *aio;
+       AddrSelectItem *item;
+       GList *list, *node;
 
        pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
        g_return_if_fail(pobj != NULL);
 
+       /* Test whether anything selected for deletion */
        nodeList = addrbook.listSelected;
-       obj = gtk_ctree_node_get_row_data( clist, nodeList );
-       if( obj == NULL) return;
+       aio = gtk_ctree_node_get_row_data( clist, nodeList );
+       if( aio == NULL) return;
        ds = addressbook_find_datasource( addrbook.treeSelected );
        if( ds == NULL ) return;
 
+       /* Test for read only */
+       iface = ds->interface;
+       if( iface->readOnly ) {
+               aval = alertpanel( _("Delete address(es)"),
+                       _("This address data is readonly and cannot be deleted."),
+                       _("Close"), NULL, NULL );
+               return;
+       }
+
+       /* Test whether Ok to proceed */
        procFlag = FALSE;
        if( pobj->type == ADDR_DATASOURCE ) {
                ads = ADAPTER_DSOURCE(pobj);
@@ -845,11 +917,12 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
        /* Process deletions */
        if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
                /* Items inside folders */
-               GList *node;
-               node = _addressListSelection_;
+               list = addrselect_get_list( _addressSelect_ );
+               node = list;
                while( node ) {
-                       AddrItemObject *aio = node->data;
+                       item = node->data;
                        node = g_list_next( node );
+                       aio = ( AddrItemObject * ) item->addressItem;
                        if( aio->type == ADDR_ITEM_GROUP ) {
                                ItemGroup *item = ( ItemGroup * ) aio;
                                GtkCTreeNode *nd = NULL;
@@ -858,7 +931,6 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                                item = addrbook_remove_group( abf, item );
                                if( item ) {
                                        addritem_free_item_group( item );
-                                       item = NULL;
                                }
                                /* Remove group from parent node */
                                gtk_ctree_remove_node( ctree, nd );
@@ -868,7 +940,6 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                                item = addrbook_remove_person( abf, item );
                                if( item ) {
                                        addritem_free_item_person( item );
-                                       item = NULL;
                                }
                        }
                        else if( aio->type == ADDR_ITEM_EMAIL ) {
@@ -877,32 +948,32 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                                item = addrbook_person_remove_email( abf, person, item );
                                if( item ) {
                                        addritem_free_item_email( item );
-                                       item = NULL;
                                }
                        }
                }
+               g_list_free( list );
                addressbook_list_select_clear();
                gtk_ctree_select( ctree, addrbook.opened);
                return;
        }
        else if( pobj->type == ADDR_ITEM_GROUP ) {
                /* Items inside groups */
-               GList *node;
-               node = _addressListSelection_;
+               list = addrselect_get_list( _addressSelect_ );
+               node = list;
                while( node ) {
-                       AddrItemObject *aio = node->data;
+                       item = node->data;
                        node = g_list_next( node );
+                       aio = ( AddrItemObject * ) item->addressItem;
                        if( aio->type == ADDR_ITEM_EMAIL ) {
                                ItemEMail *item = ( ItemEMail * ) aio;
                                ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
                                item = addrbook_person_remove_email( abf, person, item );
                                if( item ) {
-                                       addritem_print_item_email( item, stdout );
                                        addritem_free_item_email( item );
-                                       item = NULL;
                                }
                        }
                }
+               g_list_free( list );
                addressbook_list_select_clear();
                gtk_ctree_select( ctree, addrbook.opened);
                return;
@@ -910,7 +981,6 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
 
        gtk_ctree_node_set_row_data( clist, nodeList, NULL );
        gtk_ctree_remove_node( clist, nodeList );
-       addressbook_list_select_remove( obj );
 
 }
 
@@ -919,14 +989,14 @@ static void addressbook_reg_clicked(GtkButton *button, gpointer data)
        addressbook_new_address_cb( NULL, 0, NULL );
 }
 
-gchar *addressbook_format_address( AddressObject * obj ) {
+gchar *addressbook_format_address( AddrItemObject * aio ) {
        gchar *buf = NULL;
        gchar *name = NULL;
        gchar *address = NULL;
 
-       if( obj->type == ADDR_ITEM_EMAIL ) {
+       if( aio->type == ADDR_ITEM_EMAIL ) {
                ItemPerson *person = NULL;
-               ItemEMail *email = ( ItemEMail * ) obj;
+               ItemEMail *email = ( ItemEMail * ) aio;
 
                person = ( ItemPerson * ) ADDRITEM_PARENT(email);
                if( email->address ) {
@@ -945,8 +1015,8 @@ gchar *addressbook_format_address( AddressObject * obj ) {
                        address = email->address;
                }
        }
-       else if( obj->type == ADDR_ITEM_PERSON ) {
-               ItemPerson *person = ( ItemPerson * ) obj;
+       else if( aio->type == ADDR_ITEM_PERSON ) {
+               ItemPerson *person = ( ItemPerson * ) aio;
                GList *node = person->listEMail;
 
                name = ADDRITEM_NAME(person);
@@ -969,43 +1039,54 @@ gchar *addressbook_format_address( AddressObject * obj ) {
 
 static void addressbook_to_clicked(GtkButton *button, gpointer data)
 {
-       GList *node = _addressListSelection_;
-       if (!addrbook.target_compose) return;
+       GList *list, *node;
+       Compose *compose;
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       gchar *addr;
+
+       compose = addrbook.target_compose;
+       if( ! compose ) return;
+
+       list = addrselect_get_list( _addressSelect_ );
+       node = list;
        while( node ) {
-               AddressObject *obj = node->data;
-               Compose *compose = addrbook.target_compose;
+               item = node->data;
                node = g_list_next( node );
-               if( obj->type == ADDR_ITEM_PERSON || obj->type == ADDR_ITEM_EMAIL ) {
-                       gchar *addr = addressbook_format_address( obj );
-                       compose_entry_append( compose, addr, (ComposeEntryType) data );
+               aio = item->addressItem;
+               if( aio->type == ADDR_ITEM_PERSON ||
+                   aio->type == ADDR_ITEM_EMAIL ) {
+                       addr = addressbook_format_address( aio );
+                       compose_entry_append(
+                               compose, addr, (ComposeEntryType) data );
                        g_free( addr );
-                       addr = NULL;
                }
-               else if( obj->type == ADDR_ITEM_GROUP ) {
-                       ItemGroup *group = ( ItemGroup * ) obj;
+               else if( aio->type == ADDR_ITEM_GROUP ) {
+                       ItemGroup *group = ( ItemGroup * ) aio;
                        GList *nodeMail = group->listEMail;
                        while( nodeMail ) {
                                ItemEMail *email = nodeMail->data;
-                               gchar *addr = addressbook_format_address( ( AddressObject * ) email );
-                               compose_entry_append( compose, addr, (ComposeEntryType) data );
+
+                               addr = addressbook_format_address(
+                                               ( AddrItemObject * ) email );
+                               compose_entry_append(
+                                       compose, addr, (ComposeEntryType) data );
                                g_free( addr );
                                nodeMail = g_list_next( nodeMail );
                        }
                }
        }
+       g_list_free( list );
 }
 
 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
-       menu_set_sensitive( addrbook.menu_factory, "/File/New Book",    sensitive );
-       menu_set_sensitive( addrbook.menu_factory, "/File/New vCard",  sensitive );
-#ifdef USE_JPILOT
-       menu_set_sensitive( addrbook.menu_factory, "/File/New JPilot", sensitive );
-#endif
-#ifdef USE_LDAP
-       menu_set_sensitive( addrbook.menu_factory, "/File/New Server",  sensitive );
-#endif
-       menu_set_sensitive( addrbook.menu_factory, "/File/Edit",        sensitive );
-       menu_set_sensitive( addrbook.menu_factory, "/File/Delete",      sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/File/Edit",   sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/File/Delete", sensitive );
+
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Cut",    sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Copy",   sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste",  sensitive );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address",  sensitive );
 
        menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
        menu_set_sensitive( addrbook.menu_factory, "/Address/New Group",   sensitive );
@@ -1051,7 +1132,10 @@ static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode
                ds = addressbook_find_datasource( addrbook.treeSelected );
                if( ds ) {
                        iface = ds->interface;
-                       if( ! iface->readOnly ) {
+                       if( iface->readOnly ) {
+                               canEditTr = FALSE;
+                       }
+                       else {
                                canAdd = editAddress = TRUE;
                        }
                }
@@ -1150,6 +1234,96 @@ static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
 
 }
 
+/*
+* Setup address list popup menu.
+* Enter: pobj  Parent address object in address tree.
+*        obj   Address object in address list.
+*/
+static void addressbook_list_menu_setup( void ) {
+       GtkCTree *clist = NULL;
+       AddressObject *pobj = NULL;
+       AddressObject *obj = NULL;
+       AdapterDSource *ads = NULL;
+       AddressInterface *iface = NULL;
+       AddressDataSource *ds = NULL;
+       gboolean canEdit = FALSE;
+       gboolean canDelete = FALSE;
+       gboolean canCut = FALSE;
+       gboolean canCopy = FALSE;
+       gboolean canPaste = FALSE;
+
+       pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
+       if( pobj == NULL ) return;
+
+       clist = GTK_CTREE(addrbook.clist);
+       obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
+       if( obj == NULL ) canEdit = FALSE;
+
+       menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
+
+       if( pobj->type == ADDR_DATASOURCE ) {
+               ads = ADAPTER_DSOURCE(pobj);
+               ds = ads->dataSource;
+               iface = ds->interface;
+               if( ! iface->readOnly ) {
+                       menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
+                       menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
+                       menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
+                       gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
+                       if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
+                       if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
+                       if( obj ) canEdit = TRUE;
+               }
+       }
+       else if( pobj->type != ADDR_INTERFACE ) {
+               ds = addressbook_find_datasource( addrbook.treeSelected );
+               iface = ds->interface;
+               if( ! iface->readOnly ) {
+                       if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
+                               menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
+                               gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
+                               if( obj ) canEdit = TRUE;
+                       }
+                       if( pobj->type == ADDR_ITEM_FOLDER ) {
+                               menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
+                               menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
+                               if( obj ) canEdit = TRUE;
+                       }
+                       if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
+                       if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
+               }
+       }
+       if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
+
+       canDelete = canEdit;
+       canDelete = canEdit;
+
+       /* Disable edit if more than one row selected */
+       if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE;
+
+       menu_set_sensitive( addrbook.list_factory, "/Edit",   canEdit );
+       menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
+
+       menu_set_sensitive( addrbook.list_factory, "/Cut",           canCut );
+       menu_set_sensitive( addrbook.list_factory, "/Copy",          canCopy );
+       menu_set_sensitive( addrbook.list_factory, "/Paste",         canPaste );
+       menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );
+
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Cut",           canCut );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Copy",          canCopy );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste",         canPaste );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );
+
+       menu_set_sensitive( addrbook.tree_factory, "/Cut",           canCut );
+       menu_set_sensitive( addrbook.tree_factory, "/Copy",          canCopy );
+       menu_set_sensitive( addrbook.tree_factory, "/Paste",         canPaste );
+
+       menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",   canEdit );
+       menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
+
+       gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
+}
+
 static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
                                      GdkEvent *event, gpointer data)
 {
@@ -1163,145 +1337,335 @@ static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
        }
 }
 
-#if 0
-static void addressbook_list_select_show() {
-       GList *node = _addressListSelection_;
-       gchar *addr = NULL;
-       printf( "show selection...>>>\n" );
-       while( node != NULL ) {
-               AddressObject *obj = ( AddressObject * ) node->data;
-               if( obj ) {
-                       printf( "- %d : '%s'\n", obj->type, obj->name );
-                       if( obj->type == ADDR_ITEM_GROUP ) {
-                               ItemGroup *group = ( ItemGroup * ) obj;
-                               GList *node = group->listEMail;
-                               while( node ) {
-                                       ItemEMail *email = node->data;
-                                       addr = addressbook_format_address( ( AddressObject * ) email );
-                                       if( addr ) {
-                                               printf( "\tgrp >%s<\n", addr );
-                                               g_free( addr );
-                                       }
-                                       node = g_list_next( node );
-                               }
-                       }
-                       else {
-                               addr = addressbook_format_address( obj );
-                               if( addr ) {
-                                       printf( "\t>%s<\n", addr );
-                                       g_free( addr );
-                               }
-                       }
+/*
+ * Add list of items into tree node below specified tree node.
+ * Enter: treeNode  Tree node.
+ *        ds        Data source.
+ *        listItems List of items.
+ */
+static void addressbook_treenode_add_list(
+       GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
+{
+       GList *node;
+
+       node = listItems;
+       while( node ) {
+               AddrItemObject *aio;
+               GtkCTreeNode *nn;
+
+               aio = node->data;
+               if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
+                       ItemGroup *group;
+
+                       group = ( ItemGroup * ) aio;
+                       nn = addressbook_node_add_group( treeNode, ds, group );
                }
-               else {
-                       printf( "- NULL" );
+               else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
+                       ItemFolder *folder;
+
+                       folder = ( ItemFolder * ) aio;
+                       nn = addressbook_node_add_folder(
+                               treeNode, ds, folder, ADDR_ITEM_FOLDER );
                }
                node = g_list_next( node );
        }
-       printf( "show selection...<<<\n" );
 }
-#endif
 
-static void addressbook_list_select_clear() {
-       if( _addressListSelection_ ) {
-               g_list_free( _addressListSelection_ );
+/*
+* Cut from address list widget.
+*/
+static void addressbook_clip_cut_cb( void ) {
+       _clipBoard_->cutFlag = TRUE;
+       addrclip_clear( _clipBoard_ );
+       addrclip_add( _clipBoard_, _addressSelect_ );
+       /* addrclip_list_show( _clipBoard_, stdout ); */
+}
+
+/*
+* Copy from address list widget.
+*/
+static void addressbook_clip_copy_cb( void ) {
+       _clipBoard_->cutFlag = FALSE;
+       addrclip_clear( _clipBoard_ );
+       addrclip_add( _clipBoard_, _addressSelect_ );
+       /* addrclip_list_show( _clipBoard_, stdout ); */
+}
+
+/*
+* Paste clipboard into address list widget.
+*/
+static void addressbook_clip_paste_cb( void ) {
+       GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
+       AddressObject *pobj = NULL;
+       AddressDataSource *ds = NULL;
+       AddressBookFile *abf = NULL;
+       ItemFolder *folder = NULL;
+       GList *folderGroup = NULL;
+
+       ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
+       if( ds == NULL ) return;
+       if( addrindex_ds_get_readonly( ds ) ) {
+               addressbook_ds_status_message(
+                       ds, _( "Cannot paste. Target address book is readonly." ) );
+               return;
+       }
+
+       pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
+       if( pobj ) {
+               if( pobj->type == ADDR_ITEM_FOLDER ) {
+                       folder = ADAPTER_FOLDER(pobj)->itemFolder;
+               }
+               else if( pobj->type == ADDR_ITEM_GROUP ) {
+                       addressbook_ds_status_message(
+                               ds, _( "Cannot paste into an address group." ) );
+                       return;
+               }
+       }
+
+       /* Get an address book */
+       abf = addressbook_get_book_file();
+       if( abf == NULL ) return;
+
+       if( _clipBoard_->cutFlag ) {
+               /* Paste/Cut */
+               folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
+
+               /* Remove all groups and folders in clipboard from tree node */
+               addressbook_treenode_remove_item();
+
+               /* Remove all "cut" items */
+               addrclip_delete_item( _clipBoard_ );
+
+               /* Clear clipboard - cut items??? */
+               addrclip_clear( _clipBoard_ );
        }
-       _addressListSelection_ = NULL;
+       else {
+               /* Paste/Copy */
+               folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
+       }
+
+       /* addrclip_list_show( _clipBoard_, stdout ); */
+       if( folderGroup ) {
+               /* Update tree by inserting node for each folder or group */
+               addressbook_treenode_add_list(
+                       addrbook.treeSelected, ds, folderGroup );
+               gtk_ctree_expand( ctree, addrbook.treeSelected );
+               g_list_free( folderGroup );
+               folderGroup = NULL;
+       }
+
+       /* Display items pasted */
+       gtk_ctree_select( ctree, addrbook.opened );
+
 }
 
-static void addressbook_list_select_add( AddressObject *obj ) {
-       if( obj ) {
-               if(     obj->type == ADDR_ITEM_PERSON ||
-                       obj->type == ADDR_ITEM_EMAIL ||
-                       obj->type == ADDR_ITEM_GROUP ) {
-                       if( ! g_list_find( _addressListSelection_, obj ) ) {
-                               _addressListSelection_ = g_list_append( _addressListSelection_, obj );
-                       }
+/*
+* Paste clipboard email addresses only into address list widget.
+*/
+static void addressbook_clip_paste_address_cb( void ) {
+       GtkCTree *clist = GTK_CTREE(addrbook.clist);
+       GtkCTree *ctree;
+       AddressObject *pobj = NULL;
+       AddressDataSource *ds = NULL;
+       AddressBookFile *abf = NULL;
+       ItemFolder *folder = NULL;
+       AddrItemObject *aio;
+       gint cnt;
+
+       if( addrbook.listSelected == NULL ) return;
+
+               ctree = GTK_CTREE( addrbook.ctree );
+       ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
+       if( ds == NULL ) return;
+       if( addrindex_ds_get_readonly( ds ) ) {
+               addressbook_ds_status_message(
+                       ds, _( "Cannot paste. Target address book is readonly." ) );
+               return;
+       }
+
+       pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
+       if( pobj ) {
+               if( pobj->type == ADDR_ITEM_FOLDER ) {
+                       folder = ADAPTER_FOLDER(pobj)->itemFolder;
                }
        }
-       /* addressbook_list_select_show(); */
+
+       abf = addressbook_get_book_file();
+       if( abf == NULL ) return;
+
+       cnt = 0;
+       aio = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
+       if( aio->type == ADDR_ITEM_PERSON ) {
+               ItemPerson *person;
+
+               person = ( ItemPerson * ) aio;
+               if( _clipBoard_->cutFlag ) {
+                       /* Paste/Cut */
+                       cnt = addrclip_paste_person_cut( _clipBoard_, abf, person );
+
+                       /* Remove all "cut" items */
+                       addrclip_delete_address( _clipBoard_ );
+
+                       /* Clear clipboard */
+                       addrclip_clear( _clipBoard_ );
+               }
+               else {
+                       /* Paste/Copy */
+                       cnt = addrclip_paste_person_copy( _clipBoard_, abf, person );
+               }
+               if( cnt > 0 ) {
+                       addritem_person_set_opened( person, TRUE );
+               }
+       }
+
+       /* Display items pasted */
+       if( cnt > 0 ) {
+               gtk_ctree_select( ctree, addrbook.opened );
+       }
 }
 
-static void addressbook_list_select_remove( AddressObject *obj ) {
+/*
+* Add current treenode object to clipboard. Note that widget only allows
+* one entry from the tree list to be selected.
+*/
+static void addressbook_treenode_to_clipboard( void ) {
+       AddressObject *obj = NULL;
+       AddressDataSource *ds = NULL;
+       AddrSelectItem *item;
+       GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
+       GtkCTreeNode *node;
+
+       node = addrbook.treeSelected;
+       if( node == NULL ) return;
+       obj = gtk_ctree_node_get_row_data( ctree, node );
        if( obj == NULL ) return;
-       if( _addressListSelection_ ) {
-               _addressListSelection_ = g_list_remove( _addressListSelection_, obj );
+
+       ds = addressbook_find_datasource( node );
+       if( ds == NULL ) return;
+
+       item = NULL;
+       if( obj->type == ADDR_ITEM_FOLDER ) {
+               AdapterFolder *adapter = ADAPTER_FOLDER(obj);
+               ItemFolder *folder = adapter->itemFolder;
+
+               item = addrselect_create_node( obj );
+               item->uid = g_strdup( ADDRITEM_ID(folder) );
        }
-       /* addressbook_list_select_show(); */
+       else if( obj->type == ADDR_ITEM_GROUP ) {
+               AdapterGroup *adapter = ADAPTER_GROUP(obj);
+               ItemGroup *group = adapter->itemGroup;
+
+               item = addrselect_create_node( obj );
+               item->uid = g_strdup( ADDRITEM_ID(group) );
+       }
+       else if( obj->type == ADDR_DATASOURCE ) {
+               /* Data source */
+               item = addrselect_create_node( obj );
+               item->uid = NULL;
+       }
+
+       if( item ) {
+               /* Clear existing list and add item into list */
+               gchar *cacheID;
+
+               addressbook_list_select_clear();
+               cacheID = addrindex_get_cache_id( _addressIndex_, ds );
+               addrselect_list_add( _addressSelect_, item, cacheID );
+               g_free( cacheID );
+       }
+}
+
+/*
+* Cut from tree widget.
+*/
+static void addressbook_treenode_cut_cb( void ) {
+       _clipBoard_->cutFlag = TRUE;
+       addressbook_treenode_to_clipboard();
+       addrclip_clear( _clipBoard_ );
+       addrclip_add( _clipBoard_, _addressSelect_ );
+       /* addrclip_list_show( _clipBoard_, stdout ); */
 }
 
-static void addressbook_list_row_selected( GtkCTree *clist, GtkCTreeNode *node, gint column, gpointer data ) {
+/*
+* Copy from tree widget.
+*/
+static void addressbook_treenode_copy_cb( void ) {
+       _clipBoard_->cutFlag = FALSE;
+       addressbook_treenode_to_clipboard();
+       addrclip_clear( _clipBoard_ );
+       addrclip_add( _clipBoard_, _addressSelect_ );
+       /* addrclip_list_show( _clipBoard_, stdout ); */
+}
+
+/*
+* Paste clipboard into address tree widget.
+*/
+static void addressbook_treenode_paste_cb( void ) {
+       addressbook_clip_paste_cb();
+}
+
+static void addressbook_list_select_clear( void ) {
+       addrselect_list_clear( _addressSelect_ );
+}
+
+static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
+       gchar *cacheID;
+
+       if( ds == NULL ) return;
+       cacheID = addrindex_get_cache_id( _addressIndex_, ds );
+       addrselect_list_add_obj( _addressSelect_, aio, cacheID );
+       g_free( cacheID );
+}
+
+static void addressbook_list_select_remove( AddrItemObject *aio ) {
+       addrselect_list_remove( _addressSelect_, aio );
+}
+
+static void addressbook_list_row_selected( GtkCTree *clist,
+                                          GtkCTreeNode *node,
+                                          gint column,
+                                          gpointer data )
+{
        GtkEntry *entry = GTK_ENTRY(addrbook.entry);
-       AddressObject *obj = NULL;
+       AddrItemObject *aio = NULL;
        AddressObject *pobj = NULL;
        AdapterDSource *ads = NULL;
-       AddressInterface *iface = NULL;
        AddressDataSource *ds = NULL;
-       gboolean canEdit = FALSE;
-       gboolean canDelete = FALSE;
 
        gtk_entry_set_text( entry, "" );
        addrbook.listSelected = node;
-       obj = gtk_ctree_node_get_row_data( clist, node );
-       if( obj != NULL ) {
-               /* printf( "list select: %d : '%s'\n", obj->type, obj->name ); */
-               addressbook_list_select_add( obj );
-       }
 
        pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
        if( pobj == NULL ) return;
 
-       menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
-
        if( pobj->type == ADDR_DATASOURCE ) {
                ads = ADAPTER_DSOURCE(pobj);
                ds = ads->dataSource;
-               iface = ds->interface;
-               if( ! iface->readOnly ) {
-                       canEdit = TRUE;
-                       menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
-                       menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
-                       menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
-                       gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
-               }
        }
        else if( pobj->type != ADDR_INTERFACE ) {
                ds = addressbook_find_datasource( addrbook.treeSelected );
-               iface = ds->interface;
-               if( ! iface->readOnly ) {
-                       if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
-                               canEdit = TRUE;
-                               menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
-                               gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
-                       }
-                       if( pobj->type == ADDR_ITEM_FOLDER ) {
-                               canEdit = TRUE;
-                               menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
-                               menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
-                       }
-               }
        }
-       if( obj == NULL ) canEdit = FALSE;
-       canDelete = canEdit;
-       if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE;
-
-       menu_set_sensitive( addrbook.list_factory, "/Edit",   canEdit );
-       menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
-
-       menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",   canEdit );
-       menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
 
-       gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
+       aio = gtk_ctree_node_get_row_data( clist, node );
+       if( aio ) {
+               /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
+               addressbook_list_select_add( aio, ds );
+       }
 
+       addressbook_list_menu_setup();
 }
 
-static void addressbook_list_row_unselected( GtkCTree *ctree, GtkCTreeNode *node, gint column, gpointer data ) {
-       AddressObject *obj;
+static void addressbook_list_row_unselected( GtkCTree *ctree,
+                                            GtkCTreeNode *node,
+                                            gint column,
+                                            gpointer data )
+{
+       AddrItemObject *aio;
 
-       obj = gtk_ctree_node_get_row_data( ctree, node );
-       if( obj != NULL ) {
-               /* g_print( "list unselect: %d : '%s'\n", obj->type, obj->name ); */
-               addressbook_list_select_remove( obj );
+       aio = gtk_ctree_node_get_row_data( ctree, node );
+       if( aio != NULL ) {
+               /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
+               addressbook_list_select_remove( aio );
        }
 }
 
@@ -1314,6 +1678,9 @@ static void addressbook_list_button_pressed(GtkWidget *widget,
                                            gpointer data)
 {
        if( ! event ) return;
+
+       addressbook_list_menu_setup();
+
        if( event->button == 3 ) {
                gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
                       event->button, event->time );
@@ -1333,47 +1700,65 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
        GtkCList *clist = GTK_CLIST(ctree);
        gint row, column;
        AddressObject *obj = NULL;
-       /* GtkCTreeNode *node; */
        AdapterDSource *ads = NULL;
        AddressInterface *iface = NULL;
        AddressDataSource *ds = NULL;
-       /* AddressTypeControlItem *atci = NULL; */
        gboolean canEdit = FALSE;
+       gboolean canCut = FALSE;
+       gboolean canCopy = FALSE;
+       gboolean canPaste = FALSE;
+       gboolean canTreeCut = FALSE;
+       gboolean canTreeCopy = FALSE;
+       gboolean canTreePaste = FALSE;
 
        if( ! event ) return;
        addressbook_menubar_set_sensitive( FALSE );
-/* */
+
        if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
                gtk_clist_select_row( clist, row, column );
                gtkut_clist_set_focus_row(clist, row);
                obj = gtk_clist_get_row_data( clist, row );
        }
-/* */
+
        menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
 
        if( obj == NULL ) return;
+
+       if( ! addrclip_is_empty( _clipBoard_ ) ) {
+               canTreePaste = TRUE;
+       }
+
        if (obj->type == ADDR_DATASOURCE) {
                ads = ADAPTER_DSOURCE(obj);
                ds = ads->dataSource;
                iface = ds->interface;
                canEdit = TRUE;
-               if( ! iface->readOnly ) {
+               if( iface->readOnly ) {
+                       canTreePaste = FALSE;
+               }
+               else {
                        menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
                        menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
                        menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
                        gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
                }
+               canTreeCopy = TRUE;
        }
        else if (obj->type == ADDR_ITEM_FOLDER) {
                ds = addressbook_find_datasource( addrbook.treeSelected );
                iface = ds->interface;
-               if( ! iface->readOnly ) {
+               if( iface->readOnly ) {
+                       canTreePaste = FALSE;
+               }
+               else {
                        canEdit = TRUE;
+                       canTreeCut = TRUE;
                        menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
                        menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
                        menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
                        gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
                }
+               canTreeCopy = TRUE;
        }
        else if (obj->type == ADDR_ITEM_GROUP) {
                ds = addressbook_find_datasource( addrbook.treeSelected );
@@ -1384,12 +1769,29 @@ static void addressbook_tree_button_pressed(GtkWidget *ctree,
                        gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
                }
        }
+       else if (obj->type == ADDR_INTERFACE) {
+               canTreePaste = FALSE;
+       }
+
+       if( canEdit ) {
+               if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
+       }
+       if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
+       if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
 
        /* Enable edit */
        menu_set_sensitive( addrbook.tree_factory, "/Edit",   canEdit );
        menu_set_sensitive( addrbook.tree_factory, "/Delete", canEdit );
-       menu_set_sensitive( addrbook.menu_factory, "/File/Edit",   canEdit );
-       menu_set_sensitive( addrbook.menu_factory, "/File/Delete", canEdit );
+       menu_set_sensitive( addrbook.tree_factory, "/Cut",    canTreeCut );
+       menu_set_sensitive( addrbook.tree_factory, "/Copy",   canTreeCopy );
+       menu_set_sensitive( addrbook.tree_factory, "/Paste",  canTreePaste );
+
+       menu_set_sensitive( addrbook.menu_factory, "/File/Edit",          canEdit );
+       menu_set_sensitive( addrbook.menu_factory, "/File/Delete",        canEdit );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Cut",           canCut );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Copy",          canCopy );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste",         canPaste );
+       menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );
 
        if( event->button == 3 ) {
                gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
@@ -1654,10 +2056,11 @@ static void addressbook_treenode_delete_cb(gpointer data, guint action,
        /* Confirm deletion */
        if( obj->type == ADDR_ITEM_FOLDER ) {
                message = g_strdup_printf( _(
-                               "Do you want to delete the folder AND all addresses in `%s' ? \n" \
-                               "If deleting the folder only, addresses will be moved into parent folder." ),
-                               obj->name );
-               aval = alertpanel( _("Delete"), message, _("Folder only"), _("Folder and Addresses"), _("Cancel") );
+                       "Do you want to delete the folder AND all addresses in `%s' ? \n" \
+                       "If deleting the folder only, addresses will be moved into parent folder." ),
+                       obj->name );
+               aval = alertpanel( _("Delete"), message,
+                       _("Folder only"), _("Folder and Addresses"), _("Cancel") );
                g_free(message);
                if( aval == G_ALERTOTHER ) return;
        }
@@ -1672,7 +2075,7 @@ static void addressbook_treenode_delete_cb(gpointer data, guint action,
        if( obj->type == ADDR_DATASOURCE ) {
                /* Remove data source. */
                if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
-                       addressbook_free_child_adapters( node );
+                       addrindex_free_datasource( ds );
                        remFlag = TRUE;
                }
        }
@@ -1698,7 +2101,6 @@ static void addressbook_treenode_delete_cb(gpointer data, guint action,
                        item = addrbook_remove_folder_delete( abf, item );
                        if( item ) {
                                addritem_free_item_folder( item );
-                               addressbook_free_child_adapters( node );
                                remFlag = TRUE;
                        }
                }
@@ -1715,8 +2117,7 @@ static void addressbook_treenode_delete_cb(gpointer data, guint action,
        }
 
        if( remFlag ) {
-               /* Free up adapter and remove node. */
-               addressbook_free_adapter( node );
+               /* Remove node. */
                gtk_ctree_remove_node(ctree, node );
        }
 }
@@ -1768,7 +2169,9 @@ static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *
 }
 
 /*
-* Search for specified group in address index tree.
+* Search for specified child group node in address index tree.
+* Enter: parent Parent node.
+*        group  Group to find.
 */
 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
        GtkCTreeNode *node = NULL;
@@ -1778,7 +2181,9 @@ static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGrou
        if( currRow ) {
                node = currRow->children;
                while( node ) {
-                       AddressObject *obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
+                       AddressObject *obj;
+
+                       obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
                        if( obj->type == ADDR_ITEM_GROUP ) {
                                ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
                                if( g == group ) return node;
@@ -1790,6 +2195,33 @@ static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGrou
        return NULL;
 }
 
+/*
+* Search for specified child folder node in address index tree.
+* Enter: parent Parent node.
+*        folder Folder to find.
+*/
+static GtkCTreeNode *addressbook_find_folder_node( GtkCTreeNode *parent, ItemFolder *folder ) {
+       GtkCTreeNode *node = NULL;
+       GtkCTreeRow *currRow;
+
+       currRow = GTK_CTREE_ROW( parent );
+       if( currRow ) {
+               node = currRow->children;
+               while( node ) {
+                       AddressObject *obj;
+
+                       obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
+                       if( obj->type == ADDR_ITEM_FOLDER ) {
+                               ItemFolder *f = ADAPTER_FOLDER(obj)->itemFolder;
+                               if( f == folder ) return node;
+                       }
+                       currRow = GTK_CTREE_ROW(node);
+                       node = currRow->sibling;
+               }
+       }
+       return NULL;
+}
+
 static AddressBookFile *addressbook_get_book_file() {
        AddressBookFile *abf = NULL;
        AddressDataSource *ds = NULL;
@@ -1850,7 +2282,6 @@ static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget
        if( abf == NULL ) return;
        if( obj->type == ADDR_ITEM_EMAIL ) {
                ItemEMail *email = ( ItemEMail * ) obj;
-               ItemPerson *person;
                if( email == NULL ) return;
                if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
                        /* Edit parent group */
@@ -1863,6 +2294,7 @@ static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget
                }
                else {
                        /* Edit person - email page */
+                       ItemPerson *person;
                        person = ( ItemPerson * ) ADDRITEM_PARENT(email);
                        if( addressbook_edit_person( abf, NULL, person, TRUE ) == NULL ) return;
                        gtk_ctree_select( ctree, addrbook.opened );
@@ -1874,7 +2306,7 @@ static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget
                /* Edit person - basic page */
                ItemPerson *person = ( ItemPerson * ) obj;
                if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return;
-               gtk_ctree_select( ctree, addrbook.opened );
+               gtk_ctree_select( ctree, addrbook.opened);
                invalidate_address_completion();
                return;
        }
@@ -1988,7 +2420,6 @@ static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFol
                GtkCTreeNode *nodeEMail = NULL;
                gchar *text[N_COLS];
                gboolean flgFirst = TRUE, haveAddr = FALSE;
-               /* gint row; */
                ItemPerson *person;
                GList *node;
 
@@ -2094,7 +2525,6 @@ static void addressbook_node_load_datasource( GtkCTree *clist, AddressObject *ob
        AdapterInterface *adapter;
        AddressInterface *iface;
        AddressTypeControlItem *atci = NULL;
-       /* AddressDataSource *ds; */
        GtkCTreeNode *newNode, *node;
        GtkCTreeRow *row;
        GtkCell *cell = NULL;
@@ -2111,7 +2541,9 @@ static void addressbook_node_load_datasource( GtkCTree *clist, AddressObject *ob
        if( row ) {
                node = row->children;
                while( node ) {
-                       gpointer data = gtk_ctree_node_get_row_data( clist, node );
+                       gpointer data;
+
+                       data = gtk_ctree_node_get_row_data( clist, node );
                        row = GTK_CTREE_ROW( node );
                        cell = ( ( GtkCListRow * )row )->cell;
                        text[COL_NAME] = cell->u.text;
@@ -2122,14 +2554,108 @@ static void addressbook_node_load_datasource( GtkCTree *clist, AddressObject *ob
                                      atci->iconXpm, atci->maskXpm,
                                      atci->iconXpmOpen, atci->maskXpmOpen,
                                      FALSE, FALSE);
+                       /*
                        gtk_ctree_node_set_row_data( clist, newNode, data );
+                       gtk_ctree_node_set_row_data_full( clist, newNode, NULL, NULL );
+                       */
                        node = row->sibling;
-
                }
        }
        gtk_ctree_sort_node( clist, NULL );
 }
 
+/*
+* Search ctree widget callback function.
+* Enter: pA Pointer to node.
+*        pB Pointer to data item being sought.
+* Return: Zero (0) if group found.
+*/
+static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
+       AddressObject *aoA;
+
+       aoA = ( AddressObject * ) pA;
+       if( aoA->type == ADDR_ITEM_GROUP ) {
+               ItemGroup *group, *grp;
+
+               grp = ADAPTER_GROUP(aoA)->itemGroup;
+               group = ( ItemGroup * ) pB;
+               if( grp == group ) return 0;    /* Found group */
+       }
+       return 1;
+}
+
+/*
+* Search ctree widget callback function.
+* Enter: pA Pointer to node.
+*        pB Pointer to data item being sought.
+* Return: Zero (0) if folder found.
+*/
+static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
+       AddressObject *aoA;
+
+       aoA = ( AddressObject * ) pA;
+       if( aoA->type == ADDR_ITEM_FOLDER ) {
+               ItemFolder *folder, *fld;
+
+               fld = ADAPTER_FOLDER(aoA)->itemFolder;
+               folder = ( ItemFolder * ) pB;
+               if( fld == folder ) return 0;   /* Found folder */
+       }
+       return 1;
+}
+
+/*
+* Remove folder and group nodes from tree widget for items contained ("cut")
+* in clipboard.
+*/
+static void addressbook_treenode_remove_item( void ) {
+       GList *node;
+       AddrSelectItem *cutItem;
+       AddressCache *cache;
+       AddrItemObject *aio;
+       GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
+       GtkCTreeNode *tn;
+
+       node = _clipBoard_->objectList;
+       while( node ) {
+               cutItem = node->data;
+               node = g_list_next( node );
+               cache = addrindex_get_cache(
+                       _clipBoard_->addressIndex, cutItem->cacheID );
+               if( cache == NULL ) continue;
+               aio = addrcache_get_object( cache, cutItem->uid );
+               if( aio ) {
+                       tn = NULL;
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
+                               ItemFolder *folder;
+
+                               folder = ( ItemFolder * ) aio;
+                               tn = gtk_ctree_find_by_row_data_custom(
+                                       ctree, NULL, folder,
+                                       addressbook_treenode_find_folder_cb );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                               ItemGroup *group;
+
+                               group = ( ItemGroup * ) aio;
+                               tn = gtk_ctree_find_by_row_data_custom(
+                                       ctree, NULL, group,
+                                       addressbook_treenode_find_group_cb );
+                       }
+
+                       if( tn ) {
+                               /* Free up adapter and remove node. */
+                               gtk_ctree_remove_node( ctree, tn );
+                       }
+               }
+       }
+}
+
+/*
+* Find parent datasource for specified tree node.
+* Enter: node Node to test.
+* Return: Data source, or NULL if not found.
+*/
 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
        AddressDataSource *ds = NULL;
        AddressObject *ao;
@@ -2140,10 +2666,10 @@ static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
                if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
                ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
                if( ao ) {
-/*                     printf( "ao->type = %d\n", ao->type ); */
+                       /* printf( "ao->type = %d\n", ao->type ); */
                        if( ao->type == ADDR_DATASOURCE ) {
                                AdapterDSource *ads = ADAPTER_DSOURCE(ao);
-/*                             printf( "found it\n" ); */
+                               /* printf( "found it\n" ); */
                                ds = ads->dataSource;
                                break;
                        }
@@ -2170,7 +2696,7 @@ static void addressbook_set_clist( AddressObject *obj ) {
 
        if( obj->type == ADDR_INTERFACE ) {
                /* printf( "set_clist: loading datasource...\n" ); */
-               /* addressbook_node_load_datasource( clist, obj ); */
+               /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
                return;
        }
 
@@ -2201,64 +2727,43 @@ static void addressbook_set_clist( AddressObject *obj ) {
                        addressbook_folder_load_group( ctreelist, itemFolder );
                }
        }
-
-       gtk_clist_sort(clist);
+       /* gtk_clist_sort(clist); */
        gtk_clist_thaw(clist);
 }
 
 /*
-* Free adaptor for specified node.
+* Call back function to free adaptor. Call back is setup by function
+* gtk_ctree_node_set_row_data_full() when node is populated. This function is
+* called when the address book tree widget node is removed by calling
+* function gtk_ctree_remove_node().
+* Enter: data Tree node's row data.
 */
-static void addressbook_free_adapter( GtkCTreeNode *node ) {
+static void addressbook_free_treenode( gpointer data ) {
        AddressObject *ao;
 
-       g_return_if_fail(addrbook.ctree != NULL);
-
-       if( node ) {
-               if( GTK_CTREE_ROW(node)->level < 2 ) return;
-               ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
-               if( ao == NULL ) return;
-               if( ao->type == ADDR_INTERFACE ) {
-                       AdapterInterface *ai = ADAPTER_INTERFACE(ao);
-                       addrbookctl_free_interface( ai );
-               }
-               else if( ao->type == ADDR_DATASOURCE ) {
-                       AdapterDSource *ads = ADAPTER_DSOURCE(ao);
-                       addrbookctl_free_datasource( ads );
-               }
-               else if( ao->type == ADDR_ITEM_FOLDER ) {
-                       AdapterFolder *af = ADAPTER_FOLDER(ao);
-                       addrbookctl_free_folder( af );
-               }
-               else if( ao->type == ADDR_ITEM_GROUP ) {
-                       AdapterGroup *ag = ADAPTER_GROUP(ao);
-                       addrbookctl_free_group( ag );
-               }
-               gtk_ctree_node_set_row_data( GTK_CTREE(addrbook.ctree), node, NULL );
+       ao = ( AddressObject * ) data;
+       if( ao == NULL ) return;
+       if( ao->type == ADDR_INTERFACE ) {
+               AdapterInterface *ai = ADAPTER_INTERFACE(ao);
+               addrbookctl_free_interface( ai );
+       }
+       else if( ao->type == ADDR_DATASOURCE ) {
+               AdapterDSource *ads = ADAPTER_DSOURCE(ao);
+               addrbookctl_free_datasource( ads );
+       }
+       else if( ao->type == ADDR_ITEM_FOLDER ) {
+               AdapterFolder *af = ADAPTER_FOLDER(ao);
+               addrbookctl_free_folder( af );
+       }
+       else if( ao->type == ADDR_ITEM_GROUP ) {
+               AdapterGroup *ag = ADAPTER_GROUP(ao);
+               addrbookctl_free_group( ag );
        }
 }
 
 /*
-* Free all children adapters.
+* Create new adaptor for specified data source.
 */
-static void addressbook_free_child_adapters( GtkCTreeNode *node ) {
-       GtkCTreeNode *parent, *child;
-       GtkCTreeRow *currRow;
-
-       if( node == NULL ) return;
-       currRow = GTK_CTREE_ROW( node );
-       if( currRow ) {
-               parent = currRow->parent;
-               child = currRow->children;
-               while( child ) {
-                       addressbook_free_child_adapters( child );
-                       addressbook_free_adapter( child );
-                       currRow = GTK_CTREE_ROW( child );
-                       child = currRow->sibling;
-               }
-       }
-}
-
 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
                                AddressObjectType otype, gchar *name )
 {
@@ -2434,121 +2939,6 @@ void addressbook_read_file( void ) {
        debug_print( "done.\n" );
 }
 
-#if 0
-void addressbook_read_file_old( void ) {
-       AddressIndex *addrIndex = NULL;
-       gboolean errFlag = TRUE;
-       gchar *msg = NULL;
-
-       if( _addressIndex_ ) {
-               debug_print( "address book already read!!!\n" );
-               return;
-       }
-
-       addrIndex = addrindex_create_index();
-
-       /* Use use new address book. */
-       /* addrindex_set_file_path( addrIndex, "/home/match/tmp/empty-dir" ); */
-       addrindex_set_file_path( addrIndex, get_rc_dir() );
-       addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
-
-       debug_print( "Reading address index...\n" );
-       addrindex_read_data( addrIndex );
-       if( addrIndex->retVal == MGU_NO_FILE ) {
-               /* Read old address book, performing conversion */
-               debug_print( "Reading and converting old address book...\n" );
-               addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
-               addrindex_read_data( addrIndex );
-               if( addrIndex->retVal == MGU_NO_FILE ) {
-                       /* We do not have a file - new user */
-                       debug_print( "New user... create new books...\n" );
-                       addrindex_create_new_books( addrIndex );
-                       if( addrIndex->retVal == MGU_SUCCESS ) {
-                               /* Save index file */
-                               addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
-                               addrindex_save_data( addrIndex );
-                               if( addrIndex->retVal == MGU_SUCCESS ) {
-                                       errFlag = FALSE;
-                               }
-                               else {
-                                       msg = g_strdup( _( "New user, could not save index file." ) );
-                               }
-                       }
-                       else {
-                               msg = g_strdup( _( "New user, could not save address book files." ) );
-                       }
-               }
-               else {
-                       /* We have an old file */
-                       if( addrIndex->wasConverted ) {
-                               /* Converted successfully - save address index */
-                               addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
-                               addrindex_save_data( addrIndex );
-                               if( addrIndex->retVal == MGU_SUCCESS ) {
-                                       msg = g_strdup( _( "Old address book converted successfully." ) );
-                                       errFlag = FALSE;
-                               }
-                               else {
-                                       msg = g_strdup( _(
-                                               "Old address book converted, " \
-                                               "could not save new address index file" ) );
-                               }
-                       }
-                       else {
-                               /* File conversion failed - just create new books */
-                               debug_print( "File conversion failed... just create new books...\n" );
-                               addrindex_create_new_books( addrIndex );
-                               if( addrIndex->retVal == MGU_SUCCESS ) {
-                                       /* Save index */
-                                       addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
-                                       addrindex_save_data( addrIndex );
-                                       if( addrIndex->retVal == MGU_SUCCESS ) {
-                                               msg = g_strdup( _(
-                                                       "Could not convert address book, " \
-                                                       "but created empty new address book files." ) );
-                                               errFlag = FALSE;
-                                       }
-                                       else {
-                                               msg = g_strdup( _(
-                                                       "Could not convert address book, " \
-                                                       "could not create new address book files." ) );
-                                       }
-                               }
-                               else {
-                                       msg = g_strdup( _(
-                                               "Could not convert address book " \
-                                               "and could not create new address book files." ) );
-                               }
-                       }
-               }
-       }
-       else if( addrIndex->retVal == MGU_SUCCESS ) {
-               errFlag = FALSE;
-       }
-       else {
-               debug_print( "Could not read address index.\n" );
-               addrindex_print_index( addrIndex, stdout );
-               msg = g_strdup( _( "Could not read address index" ) );
-       }
-       _addressIndex_ = addrIndex;
-
-       if( errFlag ) {
-               debug_print( "Error\n%s\n", msg );
-               alertpanel( _( "Addressbook Conversion Error" ), msg,
-                           _( "Close" ), NULL, NULL );
-       }
-       else {
-               if( msg ) {
-                       debug_print( "Warning\n%s\n", msg );
-                       alertpanel( _( "Addressbook Conversion" ), msg,
-                                   _( "Close" ), NULL, NULL );
-               }
-       }
-       if( msg ) g_free( msg );
-       debug_print( "done.\n" );
-}
-#endif
-
 /*
 * Add object into the address index tree widget.
 * Enter: node  Parent node.
@@ -2589,7 +2979,8 @@ static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
                        added = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
                                atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
                                atci->treeLeaf, atci->treeExpand );
-                       gtk_ctree_node_set_row_data(ctree, added, obj);
+                       gtk_ctree_node_set_row_data_full( ctree, added, obj,
+                               addressbook_free_treenode );
                }
        }
 
@@ -2627,7 +3018,8 @@ static GtkCTreeNode *addressbook_node_add_group( GtkCTreeNode *node, AddressData
        newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
                        atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
                        atci->treeLeaf, atci->treeExpand );
-       gtk_ctree_node_set_row_data( ctree, newNode, adapter );
+       gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
+               addressbook_free_treenode );
        gtk_ctree_sort_node( ctree, node );
        return newNode;
 }
@@ -2673,7 +3065,8 @@ static GtkCTreeNode *addressbook_node_add_folder(
                newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
                                atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
                                atci->treeLeaf, atci->treeExpand );
-               gtk_ctree_node_set_row_data( ctree, newNode, adapter );
+               gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
+                       addressbook_free_treenode );
        }
 
        listItems = itemFolder->listFolder;
@@ -2707,10 +3100,10 @@ static void addressbook_delete_object(AddressObject *obj) {
 
        /* Remove data source */
        if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
-               addrindex_free_datasource( _addressIndex_, ds );
+               addrindex_free_datasource( ds );
        }
        /* Free up Adapter object */
-       g_free( ADAPTER_DSOURCE(obj) );
+       g_free( ads );
 }
 
 void addressbook_export_to_file( void ) {
@@ -2737,28 +3130,12 @@ static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
 }
 
 /*
-* Comparsion using names of AddressItem objects.
+* Comparison using cell contents (text in first column). Used for sort
+* address index widget.
 */
-/*
-static gint addressbook_list_compare_func(GtkCList *clist,
-                                         gconstpointer ptr1,
-                                         gconstpointer ptr2)
+static gint addressbook_treenode_compare_func(
+       GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
 {
-       AddressObject *obj1 = ((GtkCListRow *)ptr1)->data;
-       AddressObject *obj2 = ((GtkCListRow *)ptr2)->data;
-       gchar *name1 = NULL, *name2 = NULL;
-       if( obj1 ) name1 = obj1->name;
-       if( obj2 ) name2 = obj2->name;
-       if( ! name1 ) return ( name2 != NULL );
-       if( ! name2 ) return -1;
-       return strcasecmp(name1, name2);
-}
-*/
-
-/*
-* Comparison using cell contents (text in first column).
-*/
-static gint addressbook_list_compare_func( GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 ) {
        GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
        GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
        gchar *name1 = NULL, *name2 = NULL;
@@ -2769,47 +3146,51 @@ static gint addressbook_list_compare_func( GtkCList *clist, gconstpointer ptr1,
        return strcasecmp( name1, name2 );
 }
 
-/* static */ 
-gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b)
+/*
+* Comparison using object names and types.
+*/
+static gint addressbook_list_compare_func(
+       GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
 {
-       const AddressObject *obj = a;
-       const gchar *name = b;
-       AddressTypeControlItem *atci = NULL;
-
-       if (!obj || !name) return -1;
+       AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
+       AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
+       gchar *name1 = NULL, *name2 = NULL;
 
-       atci = addrbookctl_lookup( obj->type );
-       if( ! atci ) return -1;
-       if( ! obj->name ) return -1;
-       return strcasecmp(obj->name, name);
-}
+       /* Order by cell contents */
+       name1 = ADDRITEM_NAME( aio1 );
+       name2 = ADDRITEM_NAME( aio2 );
 
-static void addressbook_book_show_message( AddressBookFile *abf ) {
-       *addressbook_msgbuf = '\0';
-       if( abf ) {
-               if( abf->retVal == MGU_SUCCESS ) {
-                       sprintf( addressbook_msgbuf, "%s", abf->name );
+       if( aio1->type == aio2->type ) {
+               /* Order by name */
+               if( ! name1 ) return ( name2 != NULL );
+               if( ! name2 ) return -1;
+               return strcasecmp( name1, name2 );
+       }
+       else {
+               /* Order groups before person */
+               if( aio1->type == ITEMTYPE_GROUP ) {
+                       return -1;
                }
-               else {
-                       sprintf( addressbook_msgbuf, "%s: %s", abf->name, mgu_error2string( abf->retVal ) );
+               else if( aio2->type == ITEMTYPE_GROUP ) {
+                       return 1;
                }
+               return 0;
        }
-       addressbook_status_show( addressbook_msgbuf );
 }
 
 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
        AdapterDSource *ads;
        AdapterInterface *adapter;
+       GtkCTreeNode *newNode;
 
        adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
        if( adapter == NULL ) return;
-       if( addrbook.treeSelected == NULL ) return;
-       if( addrbook.treeSelected != adapter->treeNode ) return;
        ads = addressbook_edit_book( _addressIndex_, NULL );
        if( ads ) {
-               addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
-               if( addrbook.treeSelected == addrbook.opened ) {
-                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
+               newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
+               if( newNode ) {
+                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
+                       addrbook.treeSelected = newNode;
                }
        }
 }
@@ -2817,30 +3198,18 @@ static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *wid
 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
        AdapterDSource *ads;
        AdapterInterface *adapter;
+       GtkCTreeNode *newNode;
 
        adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
        if( adapter == NULL ) return;
-       if( addrbook.treeSelected != adapter->treeNode ) return;
        ads = addressbook_edit_vcard( _addressIndex_, NULL );
        if( ads ) {
-               addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
-               if( addrbook.treeSelected == addrbook.opened ) {
-                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
-               }
-       }
-}
-
-static void addressbook_vcard_show_message( VCardFile *vcf ) {
-       *addressbook_msgbuf = '\0';
-       if( vcf ) {
-               if( vcf->retVal == MGU_SUCCESS ) {
-                       sprintf( addressbook_msgbuf, "%s", vcf->name );
-               }
-               else {
-                       sprintf( addressbook_msgbuf, "%s: %s", vcf->name, mgu_error2string( vcf->retVal ) );
+               newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
+               if( newNode ) {
+                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
+                       addrbook.treeSelected = newNode;
                }
        }
-       addressbook_status_show( addressbook_msgbuf );
 }
 
 #ifdef USE_JPILOT
@@ -2848,34 +3217,21 @@ static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *w
        AdapterDSource *ads;
        AdapterInterface *adapter;
        AddressInterface *iface;
+       GtkCTreeNode *newNode;
 
        adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
        if( adapter == NULL ) return;
-       if( addrbook.treeSelected != adapter->treeNode ) return;
        iface = adapter->interface;
        if( ! iface->haveLibrary ) return;
        ads = addressbook_edit_jpilot( _addressIndex_, NULL );
        if( ads ) {
-               addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
-               if( addrbook.treeSelected == addrbook.opened ) {
-                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
-               }
-       }
-}
-
-static void addressbook_jpilot_show_message( JPilotFile *jpf ) {
-       *addressbook_msgbuf = '\0';
-       if( jpf ) {
-               if( jpf->retVal == MGU_SUCCESS ) {
-                       sprintf( addressbook_msgbuf, "%s", jpf->name );
-               }
-               else {
-                       sprintf( addressbook_msgbuf, "%s: %s", jpf->name, mgu_error2string( jpf->retVal ) );
+               newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
+               if( newNode ) {
+                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
+                       addrbook.treeSelected = newNode;
                }
        }
-       addressbook_status_show( addressbook_msgbuf );
 }
-
 #endif
 
 #ifdef USE_LDAP
@@ -2883,33 +3239,36 @@ static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *wid
        AdapterDSource *ads;
        AdapterInterface *adapter;
        AddressInterface *iface;
+       GtkCTreeNode *newNode;
 
        adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
        if( adapter == NULL ) return;
-       if( addrbook.treeSelected != adapter->treeNode ) return;
        iface = adapter->interface;
        if( ! iface->haveLibrary ) return;
        ads = addressbook_edit_ldap( _addressIndex_, NULL );
        if( ads ) {
-               addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
-               if( addrbook.treeSelected == addrbook.opened ) {
-                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
+               newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
+               if( newNode ) {
+                       gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
+                       addrbook.treeSelected = newNode;
                }
        }
 }
 
 static void addressbook_ldap_show_message( SyldapServer *svr ) {
+       gchar *name;
        *addressbook_msgbuf = '\0';
        if( svr ) {
+               name = syldap_get_name( svr );
                if( svr->busyFlag ) {
-                       sprintf( addressbook_msgbuf, "%s: %s", svr->name, ADDRESSBOOK_LDAP_BUSYMSG );
+                       sprintf( addressbook_msgbuf, "%s: %s", name, ADDRESSBOOK_LDAP_BUSYMSG );
                }
                else {
                        if( svr->retVal == MGU_SUCCESS ) {
-                               sprintf( addressbook_msgbuf, "%s", svr->name );
+                               sprintf( addressbook_msgbuf, "%s", name );
                        }
                        else {
-                               sprintf( addressbook_msgbuf, "%s: %s", svr->name, mgu_error2string( svr->retVal ) );
+                               sprintf( addressbook_msgbuf, "%s: %s", name, mgu_error2string( svr->retVal ) );
                        }
                }
        }
@@ -3004,6 +3363,25 @@ static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
 * ***********************************************************************
 */
 
+/*
+ * Remap object types.
+ * Enter:  abType AddressObjectType (used in tree node).
+ * Return: ItemObjectType (used in address cache data).
+ */
+ItemObjectType addressbook_type2item( AddressObjectType abType ) {
+       ItemObjectType ioType;
+
+       ioType = ITEMTYPE_NONE;
+       switch( abType ) {
+               case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON;     break;
+               case ADDR_ITEM_EMAIL:  ioType = ITEMTYPE_EMAIL;      break;
+               case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER;     break;
+               case ADDR_ITEM_GROUP:  ioType = ITEMTYPE_GROUP;      break;
+               case ADDR_DATASOURCE:  ioType = ITEMTYPE_DATASOURCE; break;
+       }
+       return ioType;
+}
+
 /*
 * Build table that controls the rendering of object types.
 */
@@ -3136,7 +3514,7 @@ void addrbookctl_build_map( GtkWidget *window ) {
        g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
        _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
 
-       /* JPilot */
+       /* J-Pilot */
        atci = g_new0( AddressTypeControlItem, 1 );
        atci->objectType = ADDR_JPILOT;
        atci->interfaceType = ADDR_IF_JPILOT;
@@ -3253,6 +3631,10 @@ void addrbookctl_build_iflist() {
 
        if( _addressIndex_ == NULL ) {
                _addressIndex_ = addrindex_create_index();
+               if( _clipBoard_ == NULL ) {
+                       _clipBoard_ = addrclip_create();
+               }
+               addrclip_set_index( _clipBoard_, _addressIndex_ );
        }
        _addressInterfaceList_ = NULL;
        list = addrindex_get_interface_list( _addressIndex_ );
@@ -3467,7 +3849,7 @@ static void addressbook_import_ldif_cb() {
                        if( abf ) {
                                ds = addrindex_index_add_datasource( _addressIndex_, ADDR_IF_BOOK, abf );
                                ads = addressbook_create_ds_adapter( ds, ADDR_BOOK, NULL );
-                               addressbook_ads_set_name( ads, abf->name );
+                               addressbook_ads_set_name( ads, addrbook_get_name( abf ) );
                                newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
                                if( newNode ) {
                                        gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
@@ -3485,7 +3867,7 @@ static void addressbook_import_ldif_cb() {
 /*
 * Import MUTT file.
 */
-static void addressbook_import_mutt_cb(void) {
+static void addressbook_import_mutt_cb() {
        AddressDataSource *ds = NULL;
        AdapterDSource *ads = NULL;
        AddressBookFile *abf = NULL;
@@ -3499,7 +3881,7 @@ static void addressbook_import_mutt_cb(void) {
                        if( abf ) {
                                ds = addrindex_index_add_datasource( _addressIndex_, ADDR_IF_BOOK, abf );
                                ads = addressbook_create_ds_adapter( ds, ADDR_BOOK, NULL );
-                               addressbook_ads_set_name( ads, abf->name );
+                               addressbook_ads_set_name( ads, addrbook_get_name( abf ) );
                                newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
                                if( newNode ) {
                                        gtk_ctree_select( GTK_CTREE(addrbook.ctree), newNode );
@@ -3517,3 +3899,4 @@ static void addressbook_import_mutt_cb(void) {
 /*
 * End of Source.
 */
+
index 919bf40e3f9c90f3ebc6df06763b8e33b227cfac..ffa87ffe1bc26d52b5db5b3ed931ef8ce78bbfc9 100644 (file)
@@ -147,8 +147,10 @@ AdapterDSource *addressbook_create_ds_adapter      ( AddressDataSource     *ds,
                                                  AddressObjectType     otype,
                                                  gchar                 *name );
 
-void addressbook_ads_set_name                  ( AdapterDSource        *adapter,
-                                                 gchar *value );
+void addressbook_ads_set_name          ( AdapterDSource *adapter,
+                                         gchar          *value );
+
+ItemObjectType addressbook_type2item   ( AddressObjectType abType );
 
 #endif /* __ADDRESSITEM_H__ */
 
index e6407cb80355a5345b1059e25539005d24e9edf1..e612aafa35a67e58c5b60523ac4edad84e98782f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
 #include "defs.h"
 
 #include <glib.h>
-#include <stdlib.h>
 
 #include "intl.h"
 #include "mgutils.h"
@@ -181,10 +180,9 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
        addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
-       iface = addrindex_create_interface( ADDR_IF_JPILOT, "JPilot", TAG_IF_JPILOT, TAG_DS_JPILOT );
+       iface = addrindex_create_interface( ADDR_IF_JPILOT, "J-Pilot", TAG_IF_JPILOT, TAG_DS_JPILOT );
 #ifdef USE_JPILOT
-       /* iface->haveLibrary = jpilot_test_pilot_lib(); */
-       iface->haveLibrary = TRUE;
+       iface->haveLibrary = jpilot_test_pilot_lib();
        iface->useInterface = iface->haveLibrary;
        iface->getModifyFlag = ( void * ) jpilot_get_modified;
        iface->getAccessFlag = ( void * ) jpilot_get_accessed;
@@ -206,8 +204,7 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
 
        iface = addrindex_create_interface( ADDR_IF_LDAP, "LDAP", TAG_IF_LDAP, TAG_DS_LDAP );
 #ifdef USE_LDAP
-       /* iface->haveLibrary = syldap_test_ldap_lib(); */
-       iface->haveLibrary = TRUE;
+       iface->haveLibrary = syldap_test_ldap_lib();
        iface->useInterface = iface->haveLibrary;
        iface->getAccessFlag = ( void * ) syldap_get_accessed;
        /* iface->getModifyFlag = ( void * ) syldap_get_modified; */
@@ -227,12 +224,16 @@ static void addrindex_build_if_list( AddressIndex *addrIndex ) {
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
        /* Two old legacy data sources */
-       iface = addrindex_create_interface( ADDR_IF_COMMON, "Old Address - common", TAG_IF_OLD_COMMON, NULL );
+       iface = addrindex_create_interface(
+                       ADDR_IF_COMMON, "Old Address - common",
+                       TAG_IF_OLD_COMMON, NULL );
        iface->legacyFlag = TRUE;
        addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
 
-       iface = addrindex_create_interface( ADDR_IF_COMMON, "Old Address - personal", TAG_IF_OLD_PERSONAL, NULL );
+       iface = addrindex_create_interface(
+                       ADDR_IF_COMMON, "Old Address - personal",
+                       TAG_IF_OLD_PERSONAL, NULL );
        iface->legacyFlag = TRUE;
        addrIndex->interfaceList = g_list_append( addrIndex->interfaceList, iface );
        ADDRITEM_PARENT(iface) = ADDRITEM_OBJECT(addrIndex);
@@ -256,102 +257,55 @@ static void addrindex_free_attributes( GList *list ) {
 }
 
 /*
-* Free up data source.
+* Create new data source.
+* Enter: ifType Interface type to create.
+* Return: Initialized data source.
 */
-void addrindex_free_datasource( AddressIndex *addrIndex, AddressDataSource *ds ) {
-       AddressInterface *iface = NULL;
-       g_return_if_fail( addrIndex != NULL );
-       g_return_if_fail( ds != NULL );
-
-       if( ds->interface == NULL ) {
-               iface = addrindex_get_interface( addrIndex, ds->type );
-       }
-       if( iface == NULL ) return;
-
-       if( iface->useInterface ) {
-               if( iface->type == ADDR_IF_BOOK ) {
-                       AddressBookFile *abf = ds->rawDataSource;
-                       if( abf ) {
-                               addrbook_free_book( abf );
-                       }
-               }
-               else if( iface->type == ADDR_IF_VCARD ) {
-                       VCardFile *vcf = ds->rawDataSource;
-                       if( vcf ) {
-                               vcard_free( vcf );
-                       }
-               }
-#ifdef USE_JPILOT
-               else if( iface->type == ADDR_IF_JPILOT ) {
-                       JPilotFile *jpf = ds->rawDataSource;
-                       if( jpf ) {
-                               jpilot_free( jpf );
-                       }
-               }
-#endif
-#ifdef USE_LDAP
-               else if( iface->type == ADDR_IF_LDAP ) {
-                       SyldapServer *server = ds->rawDataSource;
-                       if( server ) {
-                               syldap_free( server );
-                       }
-               }
-#endif
-       }
-       else {
-               GList *list = ds->rawDataSource;
-               addrindex_free_attributes( list );
-       }
-
-       g_free( ADDRITEM_ID(addrIndex) );
-       g_free( ADDRITEM_NAME(addrIndex) );
-
-       ADDRITEM_TYPE(addrIndex) = ITEMTYPE_NONE;
-       ADDRITEM_ID(addrIndex) = NULL;
-       ADDRITEM_NAME(addrIndex) = NULL;
-       ADDRITEM_PARENT(addrIndex) = NULL;
-       ADDRITEM_SUBTYPE(addrIndex) = 0;
-       ds->type = ADDR_IF_NONE;
-       ds->rawDataSource = NULL;
-       ds->interface = NULL;
+AddressDataSource *addrindex_create_datasource( AddressIfType ifType ) {
+       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
 
-       ds->type = ADDR_IF_NONE;
+       ds = g_new0( AddressDataSource, 1 );
+       ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
+       ADDRITEM_ID(ds) = NULL;
+       ADDRITEM_NAME(ds) = NULL;
+       ADDRITEM_PARENT(ds) = NULL;
+       ADDRITEM_SUBTYPE(ds) = 0;
+       ds->type = ifType;
        ds->rawDataSource = NULL;
        ds->interface = NULL;
-       g_free( ds );
+       return ds;
 }
 
-static void addrindex_free_all_datasources( AddressInterface *iface ) {
-       GList *node = iface->listSource;
-       while( node ) {
-               AddressDataSource *ds = node->data;
+/*
+* Free up data source.
+*/
+void addrindex_free_datasource( AddressDataSource *ds ) {
+       AddressInterface *iface;
+
+       g_return_if_fail( ds != NULL );
+
+       iface = ds->interface;
+       if( iface == NULL ) return;
+       if( ds->rawDataSource != NULL ) {
                if( iface->useInterface ) {
                        if( iface->type == ADDR_IF_BOOK ) {
                                AddressBookFile *abf = ds->rawDataSource;
-                               if( abf ) {
-                                       addrbook_free_book( abf );
-                               }
+                               addrbook_free_book( abf );
                        }
                        else if( iface->type == ADDR_IF_VCARD ) {
                                VCardFile *vcf = ds->rawDataSource;
-                               if( vcf ) {
-                                       vcard_free( vcf );
-                               }
+                               vcard_free( vcf );
                        }
 #ifdef USE_JPILOT
                        else if( iface->type == ADDR_IF_JPILOT ) {
                                JPilotFile *jpf = ds->rawDataSource;
-                               if( jpf ) {
-                                       jpilot_free( jpf );
-                               }
+                               jpilot_free( jpf );
                        }
 #endif
 #ifdef USE_LDAP
                        else if( iface->type == ADDR_IF_LDAP ) {
                                SyldapServer *server = ds->rawDataSource;
-                               if( server ) {
-                                       syldap_free( server );
-                               }
+                               syldap_free( server );
                        }
 #endif
                }
@@ -359,11 +313,24 @@ static void addrindex_free_all_datasources( AddressInterface *iface ) {
                        GList *list = ds->rawDataSource;
                        addrindex_free_attributes( list );
                }
+       }
+
+       ADDRITEM_TYPE(ds) = ITEMTYPE_NONE;
+       ADDRITEM_ID(ds) = NULL;
+       ADDRITEM_NAME(ds) = NULL;
+       ADDRITEM_PARENT(ds) = NULL;
+       ADDRITEM_SUBTYPE(ds) = 0;
+       ds->type = ADDR_IF_NONE;
+       ds->interface = NULL;
+       ds->rawDataSource = NULL;
+       g_free( ds );
+}
 
-               ds->type = ADDR_IF_NONE;
-               ds->rawDataSource = NULL;
-               ds->interface = NULL;
-               g_free( ds );
+static void addrindex_free_all_datasources( AddressInterface *iface ) {
+       GList *node = iface->listSource;
+       while( node ) {
+               AddressDataSource *ds = node->data;
+               addrindex_free_datasource( ds );
                node->data = NULL;
                node = g_list_next( node );
        }
@@ -395,10 +362,119 @@ static void addrindex_free_interface( AddressInterface *iface ) {
        iface->listSource = NULL;
 }
 
+/*
+ * Return cache ID for specified data source.
+ * Enter: addrIndex Address index.
+ *        ds        Data source.
+ * Return: ID or NULL if not found. This can be g_free() when done.
+ */
+gchar *addrindex_get_cache_id( AddressIndex *addrIndex, AddressDataSource *ds ) {
+       gchar *cacheID = NULL;
+       AddrBookBase *adbase;
+       AddressCache *cache;
+
+       g_return_val_if_fail( addrIndex != NULL, NULL );
+       g_return_val_if_fail( ds != NULL, NULL );
+
+       adbase = ( AddrBookBase * ) ds->rawDataSource;
+       if( adbase ) {
+               cache = adbase->addressCache;
+               if( cache ) {
+                       cacheID = g_strdup( cache->cacheID );
+               }
+       }
+
+       return cacheID;
+}
+
+/*
+ * Return data source for specified cacheID.
+ * Enter: addrIndex Address index.
+ *        cacheID   ID.
+ * Return: Data source, or NULL if not found.
+ */
+AddressDataSource *addrindex_get_datasource( AddressIndex *addrIndex, const gchar *cacheID ) {
+       g_return_val_if_fail( addrIndex != NULL, NULL );
+       g_return_val_if_fail( cacheID != NULL, NULL );
+       return ( AddressDataSource * ) g_hash_table_lookup( addrIndex->hashCache, cacheID );
+}
+
+/*
+ * Return cache for specified cacheID.
+ * Enter: addrIndex Address index.
+ *        cacheID   ID.
+ * Return: Address cache, or NULL if not found.
+ */
+AddressCache *addrindex_get_cache( AddressIndex *addrIndex, const gchar *cacheID ) {
+       AddressDataSource *ds;
+       AddrBookBase *adbase;
+       AddressCache *cache;
+
+       g_return_val_if_fail( addrIndex != NULL, NULL );
+       g_return_val_if_fail( cacheID != NULL, NULL );
+
+       cache = NULL;
+       ds = addrindex_get_datasource( addrIndex, cacheID );
+       if( ds ) {
+               adbase = ( AddrBookBase * ) ds->rawDataSource;
+               cache = adbase->addressCache;
+       }
+       return cache;
+}
+
+/*
+ * Add data source into hash.
+ * Enter: addrIndex Address index.
+ *        ds        Data source.
+ */
+static addrindex_hash_add_cache( AddressIndex *addrIndex, AddressDataSource *ds ) {
+       gchar *cacheID;
+
+       cacheID = addrindex_get_cache_id( addrIndex, ds );
+       if( cacheID ) {
+               g_hash_table_insert( addrIndex->hashCache, cacheID, ds );
+       }
+}
+
+/*
+* Free hash table callback function.
+*/
+static gboolean addrindex_free_cache_cb( gpointer key, gpointer value, gpointer data ) {
+       printf( "free cache db: %s\n", key );
+       g_free( key );
+       key = NULL;
+       value = NULL;
+       return TRUE;
+}
+
+/*
+* Free hash table of address cache items.
+*/
+static void addrindex_free_cache_hash( GHashTable *table ) {
+       g_hash_table_freeze( table );
+       g_hash_table_foreach_remove( table, addrindex_free_cache_cb, NULL );
+       g_hash_table_thaw( table );
+       g_hash_table_destroy( table );
+}
+
+/*
+* Remove address cache for specified data source from internal hashtable.
+*/
+static void addrindex_hash_remove_cache( AddressIndex *addrIndex, AddressDataSource *ds ) {
+       gchar *cacheID;
+
+       cacheID = addrindex_get_cache_id( addrIndex, ds );
+       if( cacheID ) {
+               g_hash_table_remove( addrIndex->hashCache, cacheID );
+               g_free( cacheID );
+               cacheID = NULL;
+       }
+}
+
 /*
 * Create new object.
 */
-AddressIndex *addrindex_create_index() {
+AddressIndex *addrindex_create_index( void ) {
        AddressIndex *addrIndex = g_new0( AddressIndex, 1 );
 
        ADDRITEM_TYPE(addrIndex) = ITEMTYPE_INDEX;
@@ -415,6 +491,7 @@ AddressIndex *addrindex_create_index() {
        addrIndex->interfaceList = NULL;
        addrIndex->lastType = ADDR_IF_NONE;
        addrIndex->dirtyFlag = FALSE;
+       addrIndex->hashCache = g_hash_table_new( g_str_hash, g_str_equal );
        addrindex_build_if_list( addrIndex );
        return addrIndex;
 }
@@ -476,6 +553,8 @@ void addrindex_free_index( AddressIndex *addrIndex ) {
        }
        g_list_free( addrIndex->interfaceList );
        addrIndex->interfaceList = NULL;
+       addrindex_free_cache_hash( addrIndex->hashCache );
+       addrIndex->hashCache = NULL;
        g_free( addrIndex );
 }
 
@@ -496,7 +575,9 @@ void addrindex_print_index( AddressIndex *addrIndex, FILE *stream ) {
 /*
 * Retrieve specified interface from index.
 */
-AddressInterface *addrindex_get_interface( AddressIndex *addrIndex, AddressIfType ifType ) {
+AddressInterface *addrindex_get_interface(
+       AddressIndex *addrIndex, AddressIfType ifType )
+{
        AddressInterface *retVal = NULL;
        GList *node;
 
@@ -514,20 +595,6 @@ AddressInterface *addrindex_get_interface( AddressIndex *addrIndex, AddressIfTyp
        return retVal;
 }
 
-AddressDataSource *addrindex_create_datasource() {
-       AddressDataSource *ds = NULL;
-       ds = g_new0( AddressDataSource, 1 );
-       ADDRITEM_TYPE(ds) = ITEMTYPE_DATASOURCE;
-       ADDRITEM_ID(ds) = NULL;
-       ADDRITEM_NAME(ds) = NULL;
-       ADDRITEM_PARENT(ds) = NULL;
-       ADDRITEM_SUBTYPE(ds) = 0;
-       ds->type = ADDR_IF_NONE;
-       ds->rawDataSource = NULL;
-       ds->interface = NULL;
-       return ds;
-}
-
 /*
 * Add data source to index.
 * Enter: addrIndex  Address index object.
@@ -537,7 +604,9 @@ AddressDataSource *addrindex_create_datasource() {
 * Note: The raw data object (for example, AddressBookFile or VCardFile object) should be
 * supplied as the dataSource argument.
 */
-AddressDataSource *addrindex_index_add_datasource( AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource ) {
+AddressDataSource *addrindex_index_add_datasource(
+       AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource )
+{
        AddressInterface *iface;
        AddressDataSource *ds = NULL;
 
@@ -546,13 +615,15 @@ AddressDataSource *addrindex_index_add_datasource( AddressIndex *addrIndex, Addr
 
        iface = addrindex_get_interface( addrIndex, ifType );
        if( iface ) {
-               ds = addrindex_create_datasource();
+               ds = addrindex_create_datasource( ifType );
                ADDRITEM_PARENT(ds) = ADDRITEM_OBJECT(iface);
                ds->type = ifType;
                ds->rawDataSource = dataSource;
                ds->interface = iface;
                iface->listSource = g_list_append( iface->listSource, ds );
                addrIndex->dirtyFlag = TRUE;
+
+               addrindex_hash_add_cache( addrIndex, ds );
        }
        return ds;
 }
@@ -564,7 +635,9 @@ AddressDataSource *addrindex_index_add_datasource( AddressIndex *addrIndex, Addr
 * Return: Data source if removed, or NULL if data source was not found in
 * index. Note the this object must still be freed.
 */
-AddressDataSource *addrindex_index_remove_datasource( AddressIndex *addrIndex, AddressDataSource *dataSource ) {
+AddressDataSource *addrindex_index_remove_datasource(
+       AddressIndex *addrIndex, AddressDataSource *dataSource )
+{
        AddressDataSource *retVal = FALSE;
        AddressInterface *iface;
 
@@ -576,12 +649,18 @@ AddressDataSource *addrindex_index_remove_datasource( AddressIndex *addrIndex, A
                iface->listSource = g_list_remove( iface->listSource, dataSource );
                addrIndex->dirtyFlag = TRUE;
                dataSource->interface = NULL;
+
+               /* Remove cache from hash table */
+               addrindex_hash_remove_cache( addrIndex, dataSource );
+
                retVal = dataSource;
        }
        return retVal;
 }
 
-static AddressInterface *addrindex_tag_get_interface( AddressIndex *addrIndex, gchar *tag, AddressIfType ifType ) {
+static AddressInterface *addrindex_tag_get_interface(
+       AddressIndex *addrIndex, gchar *tag, AddressIfType ifType )
+{
        AddressInterface *retVal = NULL;
        GList *node = addrIndex->interfaceList;
 
@@ -604,7 +683,9 @@ static AddressInterface *addrindex_tag_get_interface( AddressIndex *addrIndex, g
        return retVal;
 }
 
-static AddressInterface *addrindex_tag_get_datasource( AddressIndex *addrIndex, AddressIfType ifType, gchar *tag ) {
+static AddressInterface *addrindex_tag_get_datasource(
+       AddressIndex *addrIndex, AddressIfType ifType, gchar *tag )
+{
        AddressInterface *retVal = NULL;
        GList *node = addrIndex->interfaceList;
 
@@ -625,6 +706,7 @@ static AddressInterface *addrindex_tag_get_datasource( AddressIndex *addrIndex,
 * Interface XML parsing functions.
 * ***********************************************************************
 */
+/*
 static void show_attribs( GList *attr ) {
        while( attr ) {
                gchar *name = ((XMLAttr *)attr->data)->name;
@@ -634,6 +716,7 @@ static void show_attribs( GList *attr ) {
        }
        printf( "\t---\n" );
 }
+*/
 
 static void addrindex_write_elem_s( FILE *fp, gint lvl, gchar *name ) {
        gint i;
@@ -699,6 +782,7 @@ static void addrindex_write_attributes( FILE *fp, gchar *tag, GList *list, gint
        }
 }
 
+/*
 static void addrindex_print_attributes( GList *list, FILE *stream ) {
        GList *node = list;
        while( node ) {
@@ -707,12 +791,14 @@ static void addrindex_print_attributes( GList *list, FILE *stream ) {
                node = g_list_next( node );
        }
 }
+*/
 
 static AddressDataSource *addrindex_parse_book( XMLFile *file ) {
-       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
+       AddressDataSource *ds;
        AddressBookFile *abf;
        GList *attr;
 
+       ds = addrindex_create_datasource( ADDR_IF_BOOK );
        abf = addrbook_create_book();
        attr = xml_get_current_tag_attr( file );
        while( attr ) {
@@ -734,17 +820,18 @@ static void addrindex_write_book( FILE *fp, AddressDataSource *ds, gint lvl ) {
        AddressBookFile *abf = ds->rawDataSource;
        if( abf ) {
                addrindex_write_elem_s( fp, lvl, TAG_DS_ADDRESS_BOOK );
-               addrindex_write_attr( fp, ATTAG_BOOK_NAME, abf->name );
+               addrindex_write_attr( fp, ATTAG_BOOK_NAME, addrbook_get_name( abf ) );
                addrindex_write_attr( fp, ATTAG_BOOK_FILE, abf->fileName );
                fputs( " />\n", fp );
        }
 }
 
 static AddressDataSource *addrindex_parse_vcard( XMLFile *file ) {
-       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
+       AddressDataSource *ds;
        VCardFile *vcf;
        GList *attr;
 
+       ds = addrindex_create_datasource( ADDR_IF_VCARD );
        vcf = vcard_create();
        attr = xml_get_current_tag_attr( file );
        while( attr ) {
@@ -766,7 +853,7 @@ static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
        VCardFile *vcf = ds->rawDataSource;
        if( vcf ) {
                addrindex_write_elem_s( fp, lvl, TAG_DS_VCARD );
-               addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcf->name );
+               addrindex_write_attr( fp, ATTAG_VCARD_NAME, vcard_get_name( vcf ) );
                addrindex_write_attr( fp, ATTAG_VCARD_FILE, vcf->path );
                fputs( " />\n", fp );
        }
@@ -774,10 +861,11 @@ static void addrindex_write_vcard( FILE *fp, AddressDataSource *ds, gint lvl ) {
 
 #ifdef USE_JPILOT
 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
-       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
+       AddressDataSource *ds;
        JPilotFile *jpf;
        GList *attr;
 
+       ds = addrindex_create_datasource( ADDR_IF_JPILOT );
        jpf = jpilot_create();
        attr = xml_get_current_tag_attr( file );
        while( attr ) {
@@ -814,7 +902,7 @@ static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
                GList *node;
                GList *customLbl = jpilot_get_custom_labels( jpf );
                addrindex_write_elem_s( fp, lvl, TAG_DS_JPILOT );
-               addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpf->name );
+               addrindex_write_attr( fp, ATTAG_JPILOT_NAME, jpilot_get_name( jpf ) );
                addrindex_write_attr( fp, ATTAG_JPILOT_FILE, jpf->path );
                node = customLbl;
                ind = 1;
@@ -829,11 +917,12 @@ static void addrindex_write_jpilot( FILE *fp,AddressDataSource *ds, gint lvl ) {
        }
 }
 #else
-/* Just read/write name-value pairs */
+/* Just read/write name-value pairs (preserve data found in file)  */
 static AddressDataSource *addrindex_parse_jpilot( XMLFile *file ) {
-       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
-       GList *list = addrindex_read_attributes( file );
-       ds->rawDataSource = list;
+       AddressDataSource *ds;
+
+       ds = addrindex_create_datasource( ADDR_IF_JPILOT );
+       ds->rawDataSource = addrindex_read_attributes( file );
        return ds;
 }
 
@@ -847,10 +936,11 @@ static void addrindex_write_jpilot( FILE *fp, AddressDataSource *ds, gint lvl )
 
 #ifdef USE_LDAP
 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
-       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
+       AddressDataSource *ds;
        SyldapServer *server;
        GList *attr;
 
+       ds = addrindex_create_datasource( ADDR_IF_LDAP );
        server = syldap_create();
        attr = xml_get_current_tag_attr( file );
        while( attr ) {
@@ -897,7 +987,7 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
                gchar value[256];
 
                addrindex_write_elem_s( fp, lvl, TAG_DS_LDAP );
-               addrindex_write_attr( fp, ATTAG_LDAP_NAME, server->name );
+               addrindex_write_attr( fp, ATTAG_LDAP_NAME, syldap_get_name( server ) );
                addrindex_write_attr( fp, ATTAG_LDAP_HOST, server->hostName );
 
                sprintf( value, "%d", server->port );   
@@ -917,11 +1007,12 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
        }
 }
 #else
-/* Just read/write name-value pairs */
+/* Just read/write name-value pairs (preserve data found in file)  */
 static AddressDataSource *addrindex_parse_ldap( XMLFile *file ) {
-       AddressDataSource *ds = g_new0( AddressDataSource, 1 );
-       GList *list = addrindex_read_attributes( file );
-       ds->rawDataSource = list;
+       AddressDataSource *ds;
+
+       ds = addrindex_create_datasource( ADDR_IF_LDAP );
+       ds->rawDataSource = addrindex_read_attributes( file );
        return ds;
 }
 
@@ -939,8 +1030,6 @@ static void addrindex_write_ldap( FILE *fp, AddressDataSource *ds, gint lvl ) {
 */
 static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
        guint prev_level;
-       /* gchar *element; */
-       /* GList *attr; */
        XMLTag *xtag;
        AddressInterface *iface = NULL, *dsIFace = NULL;
        AddressDataSource *ds;
@@ -951,67 +1040,42 @@ static void addrindex_read_index( AddressIndex *addrIndex, XMLFile *file ) {
                if( file->level < prev_level ) return;
 
                xtag = xml_get_current_tag( file );
-               /* printf( "tag : %s\n", xtag->tag ); */
 
                iface = addrindex_tag_get_interface( addrIndex, xtag->tag, ADDR_IF_NONE );
                if( iface ) {
                        addrIndex->lastType = iface->type;
                        if( iface->legacyFlag ) addrIndex->needsConversion = TRUE;
-                       /* printf( "found : %s\n", iface->name ); */
                }
                else {
-                       dsIFace = addrindex_tag_get_datasource( addrIndex, addrIndex->lastType, xtag->tag );
+                       dsIFace = addrindex_tag_get_datasource(
+                                       addrIndex, addrIndex->lastType, xtag->tag );
                        if( dsIFace ) {
                                /* Add data source to list */
-                               /* printf( "\tdata source: %s\n", dsIFace->name ); */
                                ds = NULL;
                                if( addrIndex->lastType == ADDR_IF_BOOK ) {
                                        ds = addrindex_parse_book( file );
                                        if( ds->rawDataSource ) {
-                                               addrbook_set_path( ds->rawDataSource, addrIndex->filePath );
-                                               /* addrbook_print_book( ds->rawDataSource, stdout ); */
+                                               addrbook_set_path( ds->rawDataSource,
+                                                       addrIndex->filePath );
                                        }
                                }
                                else if( addrIndex->lastType == ADDR_IF_VCARD ) {
                                        ds = addrindex_parse_vcard( file );
-                                       /* if( ds->rawDataSource ) { */
-                                       /*      vcard_print_file( ds->rawDataSource, stdout ); */
-                                       /* } */
                                }
                                else if( addrIndex->lastType == ADDR_IF_JPILOT ) {
                                        ds = addrindex_parse_jpilot( file );
-                                       /*
-                                       if( ds->rawDataSource ) {
-                                               jpilot_print_file( ds->rawDataSource, stdout );
-                                               // addrindex_print_attributes( ds->rawDataSource, stdout );
-                                       }
-                                       */
                                }
                                else if( addrIndex->lastType == ADDR_IF_LDAP ) {
                                        ds = addrindex_parse_ldap( file );
-                                       /*
-                                       if( ds->rawDataSource ) {
-                                               syldap_print_data( ds->rawDataSource, stdout );
-                                               // addrindex_print_attributes( ds->rawDataSource, stdout );
-                                       }
-                                       */
                                }
                                if( ds ) {
-                                       ds->type = addrIndex->lastType;
                                        ds->interface = dsIFace;
-                                       dsIFace->listSource = g_list_append( dsIFace->listSource, ds );
+                                       addrindex_hash_add_cache( addrIndex, ds );
+                                       dsIFace->listSource =
+                                               g_list_append( dsIFace->listSource, ds );
                                }
-                               /* printf( "=============================\n\n" ); */
                        }
                }
-               /*
-               element = xml_get_element( file );
-               attr = xml_get_current_tag_attr( file );
-               if( _interfaceLast_ && ! _interfaceLast_->legacyFlag ) {
-                       show_attribs( attr );
-                       printf( "\ttag  value : %s :\n", element );
-               }
-               */
                addrindex_read_index( addrIndex, file );
        }
 }
@@ -1167,7 +1231,7 @@ gint addrindex_save_all_books( AddressIndex *addrIndex ) {
                        while( nodeDS ) {
                                AddressDataSource *ds = nodeDS->data;
                                AddressBookFile *abf = ds->rawDataSource;
-                               if( abf->dirtyFlag ) {
+                               if( addrbook_get_dirty( abf ) ) {
                                        if( abf->readFlag ) {
                                                addrbook_save_data( abf );
                                                if( abf->retVal != MGU_SUCCESS ) {
index a31ed8e45ad48f5239c78fb0589577919748192c..2c602c1bb01629f0fcfef25d639b98298c59e7d8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <glib.h>
 #include "addritem.h"
+#include "addrcache.h"
 
 #define ADDRESSBOOK_MAX_IFACE  4
 #define ADDRESSBOOK_INDEX_FILE "addrbook--index.xml"
@@ -54,6 +55,7 @@ struct _AddressIndex {
        AddressIfType lastType;
        gboolean dirtyFlag;
        GList *interfaceList;
+       GHashTable *hashCache;
 };
 
 typedef struct _AddressInterface AddressInterface;
@@ -90,21 +92,39 @@ struct _AddressDataSource {
        gpointer rawDataSource;
 };
 
-AddressIndex *addrindex_create_index   ();
-void addrindex_set_file_path           ( AddressIndex *addrIndex, const gchar *value );
-void addrindex_set_file_name           ( AddressIndex *addrIndex, const gchar *value );
-void addrindex_set_dirty               ( AddressIndex *addrIndex, const gboolean value );
+AddressIndex *addrindex_create_index   ( void );
+void addrindex_set_file_path           ( AddressIndex *addrIndex,
+                                         const gchar *value );
+void addrindex_set_file_name           ( AddressIndex *addrIndex,
+                                         const gchar *value );
+void addrindex_set_dirty               ( AddressIndex *addrIndex,
+                                         const gboolean value );
 GList *addrindex_get_interface_list    ( AddressIndex *addrIndex );
 void addrindex_free_index              ( AddressIndex *addrIndex );
 void addrindex_print_index             ( AddressIndex *addrIndex, FILE *stream );
 
-AddressInterface *addrindex_get_interface              ( AddressIndex *addrIndex, AddressIfType ifType );
-AddressDataSource *addrindex_index_add_datasource      ( AddressIndex *addrIndex, AddressIfType ifType, gpointer dataSource );
-AddressDataSource *addrindex_index_remove_datasource   ( AddressIndex *addrIndex, AddressDataSource *dataSource );
-void addrindex_free_datasource                         ( AddressIndex *addrIndex, AddressDataSource *ds );
+AddressInterface *addrindex_get_interface      ( AddressIndex *addrIndex,
+                                                 AddressIfType ifType );
+
+AddressDataSource *addrindex_create_datasource ( AddressIfType ifType );
+
+AddressDataSource *addrindex_index_add_datasource      ( AddressIndex *addrIndex,
+                                                         AddressIfType ifType,
+                                                         gpointer dataSource );
+AddressDataSource *addrindex_index_remove_datasource   ( AddressIndex *addrIndex,
+                                                         AddressDataSource *dataSource );
+
+void addrindex_free_datasource         ( AddressDataSource *ds );
+gchar *addrindex_get_cache_id          ( AddressIndex *addrIndex,
+                                         AddressDataSource *ds );
+AddressDataSource *addrindex_get_datasource    ( AddressIndex *addrIndex,
+                                                 const gchar *cacheID );
+AddressCache *addrindex_get_cache      ( AddressIndex *addrIndex,
+                                         const gchar *cacheID );
 
 gint addrindex_read_data               ( AddressIndex *addrIndex );
-gint addrindex_write_to                        ( AddressIndex *addrIndex, const gchar *newFile );
+gint addrindex_write_to                        ( AddressIndex *addrIndex,
+                                         const gchar *newFile );
 gint addrindex_save_data               ( AddressIndex *addrIndex );
 gint addrindex_create_new_books                ( AddressIndex *addrIndex );
 gint addrindex_save_all_books          ( AddressIndex *addrIndex );
@@ -118,7 +138,8 @@ ItemFolder *addrindex_ds_get_root_folder( AddressDataSource *ds );
 GList *addrindex_ds_get_list_folder    ( AddressDataSource *ds );
 GList *addrindex_ds_get_list_person    ( AddressDataSource *ds );
 gchar *addrindex_ds_get_name           ( AddressDataSource *ds );
-void addrindex_ds_set_access_flag      ( AddressDataSource *ds, gboolean *value );
+void addrindex_ds_set_access_flag      ( AddressDataSource *ds,
+                                         gboolean *value );
 gboolean addrindex_ds_get_readonly     ( AddressDataSource *ds );
 GList *addrindex_ds_get_all_persons    ( AddressDataSource *ds );
 GList *addrindex_ds_get_all_groups     ( AddressDataSource *ds );
index 70127ad4d1aa7eb5784fc87b243d33df1bb58ed8..1a83413c0413ffdfbf89d6e2c1864d5c5b9f5e2f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -44,13 +44,28 @@ ItemEMail *addritem_create_item_email( void ) {
 }
 
 /*
-* Create copy of specified email address item.
+* Create a shallow copy of specified email address item.
+* Enter: item E-Mail to copy.
 */
 ItemEMail *addritem_copy_item_email( ItemEMail *item ) {
        ItemEMail *itemNew = NULL;
        if( item ) {
                itemNew = addritem_create_item_email();
-               ADDRITEM_TYPE(itemNew) = ADDRITEM_TYPE(item);
+               ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
+               itemNew->address = g_strdup( item->address );
+               itemNew->remarks = g_strdup( item->remarks );
+       }
+       return itemNew;
+}
+
+/*
+* Create a full copy of specified email address item.
+* Enter: item E-Mail to copy.
+*/
+ItemEMail *addritem_copyfull_item_email( ItemEMail *item ) {
+       ItemEMail *itemNew = NULL;
+       if( item ) {
+               itemNew = addritem_create_item_email();
                ADDRITEM_ID(itemNew) = g_strdup( ADDRITEM_ID(item) );
                ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
                ADDRITEM_PARENT(itemNew) = ADDRITEM_PARENT(item);
@@ -169,6 +184,25 @@ ItemPerson *addritem_create_item_person( void ) {
        return person;
 }
 
+/*
+* Create a shallow copy of address book person.
+* Enter: item Person to copy.
+*/
+ItemPerson *addritem_copy_item_person( ItemPerson *item ) {
+       ItemPerson *itemNew;
+
+       itemNew = NULL;
+       if( item ) {
+               itemNew = addritem_create_item_person();
+               ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
+               itemNew->firstName = g_strdup( item->firstName );
+               itemNew->lastName = g_strdup( item->lastName );
+               itemNew->nickName = g_strdup( item->nickName );
+               itemNew->externalID = g_strdup( item->externalID );
+       }
+       return itemNew;
+}
+
 void addritem_person_set_id( ItemPerson *person, const gchar *value ) {
        ADDRITEM_ID(person) = mgu_replace_string( ADDRITEM_ID(person), value );
 }
@@ -542,6 +576,23 @@ ItemGroup *addritem_create_item_group( void ) {
        return group;
 }
 
+/*
+* Copy address book group.
+* Enter:  item Group to copy.
+* Return: A copy of the group. 
+*/
+ItemGroup *addritem_copy_item_group( ItemGroup *item ) {
+       ItemGroup *itemNew;
+
+       itemNew = g_new0( ItemGroup, 1 );
+       if( item ) {
+               itemNew = addritem_create_item_group();
+               ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
+               itemNew->remarks = g_strdup( item->remarks );
+       }
+       return itemNew;
+}
+
 /*
 * Specify name to be used.
 */
@@ -692,10 +743,25 @@ ItemFolder *addritem_create_item_folder( void ) {
        folder->listFolder = NULL;
        folder->listPerson = NULL;
        folder->listGroup = NULL;
-       folder->userData = NULL;
        return folder;
 }
 
+/*
+* Copy address book folder.
+* Enter:  item Folder to copy.
+* Return: A copy of the folder. 
+*/
+ItemFolder *addritem_copy_item_folder( ItemFolder *item ) {
+       ItemFolder *itemNew;
+
+       itemNew = g_new0( ItemFolder, 1 );
+       if( item ) {
+               itemNew = addritem_create_item_folder();
+               ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
+       }
+       return itemNew;
+}
+
 /*
 * Specify name to be used.
 */
@@ -736,9 +802,6 @@ void addritem_free_item_folder( ItemFolder *folder ) {
        folder->listGroup = NULL;
        folder->listPerson = NULL;
 
-       g_free( folder->userData );
-       folder->userData = NULL;
-
        g_free( folder );
 }
 
@@ -892,6 +955,30 @@ void addritem_print_item_folder( ItemFolder *folder, FILE *stream ) {
        fprintf( stream, "\t###\n" );
 }
 
+/*
+* Print address item.
+*/
+void addritem_print_item( AddrItemObject *aio, FILE *stream ) {
+       g_return_if_fail( aio != NULL );
+
+       if( aio->type == ITEMTYPE_PERSON ) {
+               ItemPerson *item = ( ItemPerson * ) aio;
+               addritem_print_item_person( item, stream );
+       }
+       else if( aio->type == ITEMTYPE_EMAIL ) {
+               ItemEMail *item = ( ItemEMail * ) aio;
+               addritem_print_item_email( item, stream );
+       }
+       else if( aio->type == ITEMTYPE_GROUP ) {
+               ItemGroup *item = ( ItemGroup * ) aio;
+               addritem_print_item_group( item, stream );
+       }
+       else if( aio->type == ITEMTYPE_FOLDER ) {
+               ItemFolder *item = ( ItemFolder * ) aio;
+               addritem_print_item_folder( item, stream );
+       }
+}
+
 /*
 * Return link list of persons for specified folder. Note that the list contains
 * references to items and should be g_free() when done. Do *NOT* attempt to use the
index 80cbdaa5b5594735b579f354281d63a59e67c3dd..a90495f5f6d0669e7e77d70baf9c4c1928a973c8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2001 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2002 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -84,12 +84,11 @@ typedef struct _ItemFolder ItemFolder;
 struct _ItemFolder {
        AddrItemObject obj;
        gchar    *remarks;
-       gboolean isRoot;
-       GList    *listItems;
-       GList    *listFolder;
-       GList    *listPerson;
-       GList    *listGroup;
-       gpointer userData;
+       gboolean isRoot;        /* TRUE if root folder */
+       GList    *listItems;    /* Used for temporary items only */
+       GList    *listFolder;   /* List of contained (child) folders */
+       GList    *listPerson;   /* List of contained persons */
+       GList    *listGroup;    /* List of contained (child) groups */
 };
 
 typedef struct _ItemGroup ItemGroup;
@@ -102,6 +101,7 @@ struct _ItemGroup {
 /* Function prototypes */
 ItemEMail *addritem_create_item_email  ( void );
 ItemEMail *addritem_copy_item_email    ( ItemEMail *item );
+ItemEMail *addritem_copyfull_item_email        ( ItemEMail *item );
 void addritem_email_set_id             ( ItemEMail *email, const gchar *value );
 void addritem_email_set_alias          ( ItemEMail *email, const gchar *value );
 void addritem_email_set_address                ( ItemEMail *email, const gchar *value );
@@ -116,6 +116,7 @@ void addritem_attrib_set_value              ( UserAttribute *item, const gchar *value );
 void addritem_free_attribute           ( UserAttribute *item );
 
 ItemPerson *addritem_create_item_person        ( void );
+ItemPerson *addritem_copy_item_person  ( ItemPerson *item );
 void addritem_person_set_id            ( ItemPerson *person, const gchar *value );
 void addritem_person_set_first_name    ( ItemPerson *person, const gchar *value );
 void addritem_person_set_last_name     ( ItemPerson *person, const gchar *value );
@@ -128,8 +129,8 @@ void addritem_free_list_email               ( GList *list );
 void addritem_free_list_attribute      ( GList *list );
 
 ItemGroup *addritem_create_item_group  ( void );
+ItemGroup *addritem_copy_item_group    ( ItemGroup *item );
 void addritem_free_item_group          ( ItemGroup *group );
-void addritem_print                    ( ItemGroup *group, FILE *stream );
 void addritem_group_set_id             ( ItemGroup *group, const gchar *value );
 void addritem_group_set_name           ( ItemGroup *group, const gchar *value );
 void addritem_group_set_remarks                ( ItemGroup *group, const gchar *value );
@@ -139,6 +140,7 @@ void addritem_print_attribute               ( UserAttribute *item, FILE *stream );
 void addritem_print_item_person                ( ItemPerson *person, FILE *stream );
 void addritem_print_item_group         ( ItemGroup *group, FILE *stream );
 void addritem_print_item_folder                ( ItemFolder *folder, FILE *stream );
+void addritem_print_item               ( AddrItemObject *aio, FILE *stream );
 
 gboolean addritem_person_add_email             ( ItemPerson *person, ItemEMail *email );
 ItemEMail *addritem_person_get_email           ( ItemPerson *person, const gchar *eid );
@@ -151,6 +153,7 @@ UserAttribute *addritem_person_remove_attrib_id     ( ItemPerson *person, const gcha
 UserAttribute *addritem_person_remove_attribute        ( ItemPerson *person, UserAttribute *attrib );
 
 ItemFolder *addritem_create_item_folder        ( void );
+ItemFolder *addritem_copy_item_folder  ( ItemFolder *item );
 void addritem_folder_set_id            ( ItemFolder *folder, const gchar *value );
 void addritem_folder_set_name          ( ItemFolder *folder, const gchar *value );
 void addritem_folder_set_remarks       ( ItemFolder *folder, const gchar *value );
index c282faee65dd8c34030131e97f5d168163f74c3f..76345e2b5efb4c54cbb2708dac8bd961d5ef2ea0 100644 (file)
 
 #include "prefs_common.h"
 
-/*
-static struct _AddressEdit_dlg {
-       GtkWidget *window;
-       GtkWidget *name_entry;
-       GtkWidget *addr_entry;
-       GtkWidget *rem_entry;
-       GtkWidget *ok_btn;
-       GtkWidget *cancel_btn;
-} addredit;
-*/
-
 static struct _PersonEdit_dlg {
        GtkWidget *window;
        GtkWidget *notebook;
@@ -112,170 +101,6 @@ typedef enum {
 #define PAGE_EMAIL             1
 #define PAGE_ATTRIBUTES        2
 
-#if 0
-#define SET_LABEL_AND_ENTRY(str, entry, top) \
-{ \
-       label = gtk_label_new(str); \
-       gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \
-                        GTK_FILL, 0, 0, 0); \
-       gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
- \
-       entry = gtk_entry_new(); \
-       gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \
-                        GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \
-}
-
-static void edit_address_ok(GtkWidget *widget, gboolean *cancelled)
-{
-       *cancelled = FALSE;
-       gtk_main_quit();
-}
-
-static void edit_address_cancel(GtkWidget *widget, gboolean *cancelled)
-{
-       *cancelled = TRUE;
-       gtk_main_quit();
-}
-
-static gint edit_address_delete_event(GtkWidget *widget, GdkEventAny *event,
-                                     gboolean *cancelled)
-{
-       *cancelled = TRUE;
-       gtk_main_quit();
-
-       return TRUE;
-}
-
-static void edit_address_key_pressed(GtkWidget *widget, GdkEventKey *event,
-                                    gboolean *cancelled)
-{
-       if (event && event->keyval == GDK_Escape) {
-               *cancelled = TRUE;
-               gtk_main_quit();
-       }
-}
-
-static void addressbook_edit_address_create(gboolean *cancelled)
-{
-       GtkWidget *window;
-       GtkWidget *vbox;
-       GtkWidget *table;
-       GtkWidget *label;
-       GtkWidget *name_entry;
-       GtkWidget *addr_entry;
-       GtkWidget *rem_entry;
-       GtkWidget *hbbox;
-       GtkWidget *ok_btn;
-       GtkWidget *cancel_btn;
-
-       debug_print("Creating edit_address window...\n");
-
-       window = gtk_window_new(GTK_WINDOW_DIALOG);
-       gtk_widget_set_usize(window, 400, -1);
-       /* gtk_container_set_border_width(GTK_CONTAINER(window), 8); */
-       gtk_window_set_title(GTK_WINDOW(window), _("Edit address"));
-       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
-       gtk_window_set_modal(GTK_WINDOW(window), TRUE); 
-       gtk_signal_connect(GTK_OBJECT(window), "delete_event",
-                          GTK_SIGNAL_FUNC(edit_address_delete_event),
-                          cancelled);
-       gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
-                          GTK_SIGNAL_FUNC(edit_address_key_pressed),
-                          cancelled);
-
-       vbox = gtk_vbox_new(FALSE, 8);
-       gtk_container_add(GTK_CONTAINER(window), vbox);
-
-       table = gtk_table_new(3, 2, FALSE);
-       gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
-       gtk_table_set_row_spacings(GTK_TABLE(table), 8);
-       gtk_table_set_col_spacings(GTK_TABLE(table), 8);
-
-       SET_LABEL_AND_ENTRY(_("Name"),    name_entry, 0);
-       SET_LABEL_AND_ENTRY(_("Address"), addr_entry, 1);
-       SET_LABEL_AND_ENTRY(_("Remarks"), rem_entry,  2);
-
-       gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
-                               &cancel_btn, _("Cancel"), NULL, NULL);
-       gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
-       gtk_widget_grab_default(ok_btn);
-
-       gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
-                          GTK_SIGNAL_FUNC(edit_address_ok), cancelled);
-       gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
-                          GTK_SIGNAL_FUNC(edit_address_cancel), cancelled);
-
-       gtk_widget_show_all(vbox);
-
-       addredit.window     = window;
-       addredit.name_entry = name_entry;
-       addredit.addr_entry = addr_entry;
-       addredit.rem_entry  = rem_entry;
-       addredit.ok_btn     = ok_btn;
-       addredit.cancel_btn = cancel_btn;
-}
-
-AddressItem *addressbook_edit_address(AddressItem *item)
-{
-       static gboolean cancelled;
-       const gchar *str;
-
-       if (!addredit.window)
-               addressbook_edit_address_create(&cancelled);
-       gtk_widget_grab_focus(addredit.ok_btn);
-       gtk_widget_grab_focus(addredit.name_entry);
-       gtk_widget_show(addredit.window);
-       manage_window_set_transient(GTK_WINDOW(addredit.window));
-
-       gtk_entry_set_text(GTK_ENTRY(addredit.name_entry), "");
-       gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry), "");
-       gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry),  "");
-
-       if (item) {
-               if (ADDRESS_OBJECT_NAME(item))
-                       gtk_entry_set_text(GTK_ENTRY(addredit.name_entry),
-                                          ADDRESS_OBJECT_NAME(item));
-               if (item->address)
-                       gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry),
-                                          item->address);
-               if (item->remarks)
-                       gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry),
-                                          item->remarks);
-       }
-
-       gtk_main();
-       gtk_widget_hide(addredit.window);
-       if (cancelled == TRUE) return NULL;
-
-       str = gtk_entry_get_text(GTK_ENTRY(addredit.name_entry));
-       if (*str == '\0') return NULL;
-
-       if (!item) {
-               item = mgu_create_address();
-               ADDRESS_OBJECT_TYPE(item) = ADDR_ITEM;
-       }
-
-       g_free(ADDRESS_OBJECT_NAME(item));
-       ADDRESS_OBJECT_NAME(item) = g_strdup(str);
-
-       str = gtk_entry_get_text(GTK_ENTRY(addredit.addr_entry));
-       g_free(item->address);
-       if (*str == '\0')
-               item->address = NULL;
-       else
-               item->address = g_strdup(str);
-
-       str = gtk_entry_get_text(GTK_ENTRY(addredit.rem_entry));
-       g_free(item->remarks);
-       if (*str == '\0')
-               item->remarks = NULL;
-       else
-               item->remarks = g_strdup(str);
-
-       return item;
-}
-#endif /* 0 */
-
 static void edit_person_status_show( gchar *msg ) {
        if( personeditdlg.statusbar != NULL ) {
                gtk_statusbar_pop( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid );
@@ -361,13 +186,13 @@ static void edit_person_switch_page( GtkNotebook *notebook, GtkNotebookPage *pag
 /*
 * Load clist with a copy of person's email addresses.
 */
-void edit_person_load_email( ItemPerson *person ) {
+static void edit_person_load_email( ItemPerson *person ) {
        GList *node = person->listEMail;
        GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
        gchar *text[ EMAIL_N_COLS ];
        while( node ) {
                ItemEMail *emorig = ( ItemEMail * ) node->data;
-               ItemEMail *email = addritem_copy_item_email( emorig );
+               ItemEMail *email = addritem_copyfull_item_email( emorig );
                gint row;
                text[ EMAIL_COL_EMAIL   ] = email->address;
                text[ EMAIL_COL_ALIAS   ] = email->obj.name;
@@ -494,10 +319,28 @@ static void edit_person_email_add( gpointer data ) {
        }
 }
 
+/*
+* Comparison using cell contents (text in first column). Used for sort
+* address index widget.
+*/
+static gint edit_person_attrib_compare_func(
+       GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
+{
+       GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
+       GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
+       gchar *name1 = NULL, *name2 = NULL;
+
+       if( cell1 ) name1 = cell1->u.text;
+       if( cell2 ) name2 = cell2->u.text;
+       if( ! name1 ) return ( name2 != NULL );
+       if( ! name2 ) return -1;
+       return strcasecmp( name1, name2 );
+}
+
 /*
 * Load clist with a copy of person's email addresses.
 */
-void edit_person_load_attrib( ItemPerson *person ) {
+static void edit_person_load_attrib( ItemPerson *person ) {
        GList *node = person->listAttrib;
        GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
        gchar *text[ ATTRIB_N_COLS ];
@@ -672,7 +515,7 @@ static void addressbook_edit_person_dialog_create( gboolean *cancelled ) {
 
 }
 
-void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
+static void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
        GtkWidget *vbox;
        GtkWidget *table;
        GtkWidget *label;
@@ -737,7 +580,7 @@ void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
        personeditdlg.entry_nick  = entry_nn;
 }
 
-void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
+static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
        GtkWidget *vbox;
        GtkWidget *hbox;
        GtkWidget *vboxl;
@@ -777,12 +620,11 @@ void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
        hbox = gtk_hbox_new( FALSE, 0 );
        gtk_container_add( GTK_CONTAINER( vbox ), hbox );
 
-       /* EMail list */
+       /* Address list */
        vboxl = gtk_vbox_new( FALSE, 4 );
        gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
        gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
 
-       /* Address list */
        clist_swin = gtk_scrolled_window_new( NULL, NULL );
        gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
@@ -885,7 +727,7 @@ void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
        personeditdlg.entry_remarks = entry_remarks;
 }
 
-void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
+static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
        GtkWidget *vbox;
        GtkWidget *hbox;
        GtkWidget *vboxl;
@@ -927,7 +769,6 @@ void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
        gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
        gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
 
-       /* Address list */
        clist_swin = gtk_scrolled_window_new( NULL, NULL );
        gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
@@ -939,6 +780,8 @@ void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
        gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
        gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME );
        gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE );
+       gtk_clist_set_compare_func( GTK_CLIST(clist), edit_person_attrib_compare_func );
+       gtk_clist_set_auto_sort( GTK_CLIST(clist), TRUE );
 
        for( i = 0; i < ATTRIB_N_COLS; i++ )
                GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
index 87f5cd11cf677ad2f8a9b29182ee8238b2aa7606..0fa4f4e65030bbdc5bb00342ae6734072a0e5344 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -62,8 +62,6 @@ static struct _AddrBookEdit_Dlg {
        AddressBookFile *bookFile;
 } addrbookedit_dlg;
 
-/* static struct _AddressFileSelection vcard_file_selector; */
-
 /*
 * Edit functions.
 */
@@ -247,7 +245,8 @@ static void addressbook_edit_book_create( gboolean *cancelled ) {
        addrbookedit_dlg.check_btn  = check_btn;
        /* addrbookedit_dlg.file_btn   = file_btn; */
        addrbookedit_dlg.statusbar  = statusbar;
-       addrbookedit_dlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Addressbook Dialog" );
+       addrbookedit_dlg.status_cid = gtk_statusbar_get_context_id(
+                       GTK_STATUSBAR(statusbar), "Edit Addressbook Dialog" );
 }
 
 AdapterDSource *addressbook_edit_book( AddressIndex *addrIndex, AdapterDSource *ads ) {
@@ -271,8 +270,9 @@ AdapterDSource *addressbook_edit_book( AddressIndex *addrIndex, AdapterDSource *
        if( ads ) {
                ds = ads->dataSource;
                abf = ds->rawDataSource;
-               if (abf->name)
-                       gtk_entry_set_text(GTK_ENTRY(addrbookedit_dlg.name_entry), abf->name);
+               if ( addrbook_get_name( abf ) )
+                       gtk_entry_set_text(GTK_ENTRY(addrbookedit_dlg.name_entry),
+                               addrbook_get_name( abf ) );
                if( abf->fileName )
                        gtk_label_set_text(GTK_LABEL(addrbookedit_dlg.file_label), abf->fileName);
                gtk_window_set_title( GTK_WINDOW(addrbookedit_dlg.window), _("Edit Addressbook"));
@@ -332,7 +332,6 @@ AdapterDSource *addressbook_edit_book( AddressIndex *addrIndex, AdapterDSource *
                }
                addressbook_ads_set_name( ads, sName );
                addrbook_set_name( abf, sName );
-               abf->dirtyFlag = TRUE;
        }
        g_free( sName );
 
index ae629d7e1f2796bd590a2256888df34d13f09a27..172ea1d6b6edd7e2a7eeb9ddf80bf77e08d6b5cb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -393,8 +393,9 @@ AdapterDSource *addressbook_edit_jpilot( AddressIndex *addrIndex, AdapterDSource
        if( ads ) {
                ds = ads->dataSource;
                jpf = ds->rawDataSource;
-               if (jpf->name)
-                       gtk_entry_set_text(GTK_ENTRY(jpilotedit.name_entry), jpf->name);
+               if ( jpilot_get_name( jpf ) )
+                       gtk_entry_set_text(GTK_ENTRY(jpilotedit.name_entry),
+                               jpilot_get_name( jpf ) );
                if (jpf->path)
                        gtk_entry_set_text(GTK_ENTRY(jpilotedit.file_entry), jpf->path);
                gtk_window_set_title( GTK_WINDOW(jpilotedit.window), _("Edit JPilot Entry"));
index ff32635ee477c9bc6d88c05a683f05afbc708313..2e5e552db4e9c1f9f23d134af23fed41000478b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -516,8 +516,9 @@ AdapterDSource *addressbook_edit_ldap( AddressIndex *addrIndex, AdapterDSource *
        if( ads ) {
                ds = ads->dataSource;
                server = ds->rawDataSource;
-               if (server->name)
-                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name), server->name);
+               if ( syldap_get_name( server ) )
+                       gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_name),
+                               syldap_get_name( server ) );
                if (server->hostName)
                        gtk_entry_set_text(GTK_ENTRY(ldapedit.entry_server), server->hostName);
                gtk_spin_button_set_value( GTK_SPIN_BUTTON( ldapedit.spinbtn_port ), server->port );
index 63fe121adfd4a7d6139b90eb85aa987ac935b788..28bbc18a4e49bb8b834f95a11922958fa8425c29 100644 (file)
@@ -284,8 +284,8 @@ AdapterDSource *addressbook_edit_vcard( AddressIndex *addrIndex, AdapterDSource
        if( ads ) {
                ds = ads->dataSource;
                vcf = ds->rawDataSource;
-               if (vcf->name)
-                       gtk_entry_set_text(GTK_ENTRY(vcardedit.name_entry), vcf->name);
+               if ( vcard_get_name( vcf ) )
+                       gtk_entry_set_text(GTK_ENTRY(vcardedit.name_entry), vcard_get_name( vcf ) );
                if (vcf->path)
                        gtk_entry_set_text(GTK_ENTRY(vcardedit.file_entry), vcf->path);
                gtk_window_set_title( GTK_WINDOW(vcardedit.window), _("Edit vCard Entry"));
index 506f3dd885bd67dcd783968ddbbd244d6c13af90..c2983b8bdaae89028d0428a772b16dbcab6b4e4f 100644 (file)
@@ -271,7 +271,6 @@ static gboolean imp_ldif_field_move() {
        /* Import data into file */
        if( ldif_import_data( _ldifFile_, abf->addressCache ) == MGU_SUCCESS ) {
                addrbook_save_data( abf );
-               abf->dirtyFlag = TRUE;
                _importedBook_ = abf;
                retVal = TRUE;
        }
index 9e933380f9e0500b4981d0c1edd580b9243bdb5f..f0017f5c56f25e17f27744074f120e47ab20f905 100644 (file)
@@ -110,7 +110,6 @@ static gboolean imp_mutt_import_file( gchar *sName, gchar *sFile ) {
        mutt_set_file( mdf, sFile );
        if( mutt_import_data( mdf, abf->addressCache ) == MGU_SUCCESS ) {
                addrbook_save_data( abf );
-               abf->dirtyFlag = TRUE;
                _importedBook_ = abf;
                retVal = TRUE;
        }
index c9988d11bd55b0c120722cbc442f6206135f750b..629c3e5390790ebb0c4860c53a5e2f4788c268a6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,7 +35,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
-/* #include <dlfcn.h> */
+#include <dlfcn.h>
 #include <netinet/in.h>
 
 #ifdef HAVE_LIBPISOCK_PI_ARGS_H
@@ -52,6 +52,7 @@
 #include "addritem.h"
 #include "addrcache.h"
 #include "jpilot.h"
+#include "adbookbase.h"
 
 #define JPILOT_DBHOME_DIR   ".jpilot"
 #define JPILOT_DBHOME_FILE  "AddressDB.pdb"
@@ -153,15 +154,16 @@ typedef struct {
 JPilotFile *jpilot_create() {
        JPilotFile *pilotFile;
        pilotFile = g_new0( JPilotFile, 1 );
-       pilotFile->name = NULL;
+       pilotFile->type = ADBOOKTYPE_JPILOT;
+       pilotFile->addressCache = addrcache_create();
+       pilotFile->accessFlag = FALSE;
+       pilotFile->retVal = MGU_SUCCESS;
+
        pilotFile->file = NULL;
        pilotFile->path = NULL;
-       pilotFile->addressCache = addrcache_create();
        pilotFile->readMetadata = FALSE;
        pilotFile->customLabels = NULL;
        pilotFile->labelInd = NULL;
-       pilotFile->retVal = MGU_SUCCESS;
-       pilotFile->accessFlag = FALSE;
        pilotFile->havePC3 = FALSE;
        pilotFile->pc3ModifyTime = 0;
        return pilotFile;
@@ -182,7 +184,7 @@ JPilotFile *jpilot_create_path( const gchar *path ) {
 */
 void jpilot_set_name( JPilotFile* pilotFile, const gchar *value ) {
        g_return_if_fail( pilotFile != NULL );
-       pilotFile->name = mgu_replace_string( pilotFile->name, value );
+       addrcache_set_name( pilotFile->addressCache, value );
 }
 void jpilot_set_file( JPilotFile* pilotFile, const gchar *value ) {
        g_return_if_fail( pilotFile != NULL );
@@ -205,7 +207,7 @@ ItemFolder *jpilot_get_root_folder( JPilotFile *pilotFile ) {
 }
 gchar *jpilot_get_name( JPilotFile *pilotFile ) {
        g_return_val_if_fail( pilotFile != NULL, NULL );
-       return pilotFile->name;
+       return addrcache_get_name( pilotFile->addressCache );
 }
 
 /*
@@ -384,21 +386,27 @@ gboolean jpilot_get_accessed( JPilotFile *pilotFile ) {
 void jpilot_free( JPilotFile *pilotFile ) {
        g_return_if_fail( pilotFile != NULL );
 
-       /* Free internal stuff */
-       g_free( pilotFile->path );
-
        /* Release custom labels */
        jpilot_clear_custom_labels( pilotFile );
 
        /* Clear cache */
        addrcache_clear( pilotFile->addressCache );
        addrcache_free( pilotFile->addressCache );
-       pilotFile->addressCache = NULL;
+
+       /* Free internal stuff */
+       g_free( pilotFile->path );
+
+       pilotFile->file = NULL;
+       pilotFile->path = NULL;
        pilotFile->readMetadata = FALSE;
-       pilotFile->accessFlag = FALSE;
        pilotFile->havePC3 = FALSE;
        pilotFile->pc3ModifyTime = 0;
 
+       pilotFile->type = ADBOOKTYPE_NONE;
+       pilotFile->addressCache = NULL;
+       pilotFile->accessFlag = FALSE;
+       pilotFile->retVal = MGU_SUCCESS;
+
        /* Now release file object */
        g_free( pilotFile );
 }
@@ -828,6 +836,7 @@ static gint jpilot_read_db_files( JPilotFile *pilotFile, GList **records ) {
                        return MGU_ERROR_READ;
                }
                if (feof(in)) {
+                       fclose(in);
                        return MGU_EOF;
                }
        }
@@ -845,6 +854,7 @@ static gint jpilot_read_db_files( JPilotFile *pilotFile, GList **records ) {
                                break;
                        }
                        if (feof(in)) {
+                               fclose(in);
                                return MGU_EOF;
                        }
                }
@@ -1316,6 +1326,7 @@ GList *jpilot_load_phone_label( JPilotFile *pilotFile, GList *labelList ) {
 /*
 * Load list with character strings of label names. Only none blank names
 * are loaded.
+* Return: list of labels. Should by g_free()'d when done.
 */
 GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) {
        gint i;
@@ -1500,8 +1511,9 @@ gint jpilot_check_label( struct AddressAppInfo *ai, gchar *lblCheck ) {
 * Validate that all parameters specified.
 * Return: TRUE if data is good.
 */
-gboolean jpilot_validate( const JPilotFile *pilotFile ) {
+gboolean jpilot_validate( JPilotFile *pilotFile ) {
        gboolean retVal;
+       gchar *name;
 
        g_return_val_if_fail( pilotFile != NULL, FALSE );
 
@@ -1512,8 +1524,9 @@ gboolean jpilot_validate( const JPilotFile *pilotFile ) {
        else {
                retVal = FALSE;
        }
-       if( pilotFile->name ) {
-               if( strlen( pilotFile->name ) < 1 ) retVal = FALSE;
+       name = jpilot_get_name( pilotFile );
+       if( name ) {
+               if( strlen( name ) < 1 ) retVal = FALSE;
        }
        else {
                retVal = FALSE;
@@ -1594,7 +1607,7 @@ gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName
        if( labelName ) {
                node = pilotFile->customLabels;
                while( node ) {
-                       if( g_strcasecmp( labelName, node->data ) == 0 ) {
+                       if( g_strcasecmp( labelName, ( gchar * ) node->data ) == 0 ) {
                                retVal = TRUE;
                                break;
                        }
@@ -1608,7 +1621,6 @@ gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName
 * Test whether pilot link library installed.
 * Return: TRUE if library available.
 */
-#if 0
 gboolean jpilot_test_pilot_lib( void ) {
        void *handle, *fun;
 
@@ -1632,7 +1644,6 @@ gboolean jpilot_test_pilot_lib( void ) {
        dlclose( handle );
        return TRUE;
 }
-#endif /* 0 */
 
 #endif /* USE_JPILOT */
 
index b1ddada3e8da7f03fbfa790f090bb5a8e2807fed..ea432d58fd7216bf86708e4139095a38e6e5354d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "addritem.h"
 #include "addrcache.h"
+#include "adbookbase.h"
 
 typedef struct _JPilotFile JPilotFile;
 
 struct _JPilotFile {
-       gchar                 *name;
-       FILE                  *file;
-       gchar                 *path;
-       AddressCache          *addressCache;
+       AddressBookType type;
+       AddressCache *addressCache;
+       gboolean accessFlag;
+       gint     retVal;
+       FILE     *file;
+       gchar    *path;
        struct AddressAppInfo addrInfo;
-       gboolean              readMetadata;
-       GList                 *customLabels;
-       GList                 *labelInd;
-       gint                  retVal;
-       gboolean              accessFlag;
-       gboolean              havePC3;
-       time_t                pc3ModifyTime;
+       gboolean readMetadata;
+       GList    *customLabels;
+       GList    *labelInd;
+       gboolean havePC3;
+       time_t   pc3ModifyTime;
 };
 
 /* Limits */
@@ -67,8 +68,8 @@ struct _JPilotFile {
 #define JPILOT_NUM_CATEG       16      /* Number of categories */
 #define JPILOT_LEN_LABEL       15      /* Max length of label */
 #define JPILOT_LEN_CATEG       15      /* Max length of category */
-#define JPILOT_NUM_ADDR_PHONE  5       /* Number of phone entries a person
-                                          can have */
+#define JPILOT_NUM_ADDR_PHONE  5       /* Number of phone entries a person */
+                                       /* can have */
 
 /* Function prototypes */
 JPilotFile *jpilot_create              ( void );
@@ -98,7 +99,7 @@ gchar *jpilot_get_category_name               ( JPilotFile *pilotFile, gint catID );
 GList *jpilot_load_phone_label         ( JPilotFile *pilotFile, GList *labelList );
 GList *jpilot_load_custom_label                ( JPilotFile *pilotFile, GList *labelList );
 
-gboolean jpilot_validate               ( const JPilotFile *pilotFile );
+gboolean jpilot_validate               ( JPilotFile *pilotFile );
 gchar *jpilot_find_pilotdb             ( void );
 
 gint jpilot_test_read_file             ( const gchar *fileSpec );
@@ -107,7 +108,7 @@ void jpilot_clear_custom_labels             ( JPilotFile *pilotFile );
 void jpilot_add_custom_label           ( JPilotFile *pilotFile, const gchar *labelName );
 GList *jpilot_get_custom_labels                ( JPilotFile *pilotFile );
 gboolean jpilot_test_custom_label      ( JPilotFile *pilotFile, const gchar *labelName );
-/* gboolean jpilot_test_pilot_lib              ( void ); */
+gboolean jpilot_test_pilot_lib         ( void );
 
 gint jpilot_read_modified              ( JPilotFile *pilotFile );
 
index 58395302ca0db0b1fbc82b337b2f243699241260..1d3bcffc8a465d29eb8029b2dfc95aaf18c55cc5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <ldap.h>
 #include <lber.h>
 #include <pthread.h>
-/* #include <dlfcn.h> */
+#include <dlfcn.h>
 
 #include "mgutils.h"
 #include "addritem.h"
 #include "addrcache.h"
 #include "syldap.h"
 #include "utils.h"
+#include "adbookbase.h"
 
 /*
 * Create new LDAP server interface object.
@@ -52,7 +53,10 @@ SyldapServer *syldap_create() {
        debug_print("Creating LDAP server interface object\n");
 
        ldapServer = g_new0( SyldapServer, 1 );
-       ldapServer->name = NULL;
+       ldapServer->type = ADBOOKTYPE_LDAP;
+       ldapServer->addressCache = addrcache_create();
+       ldapServer->accessFlag = FALSE;
+       ldapServer->retVal = MGU_SUCCESS;
        ldapServer->hostName = NULL;
        ldapServer->port = SYLDAP_DFL_PORT;
        ldapServer->baseDN = NULL;
@@ -64,12 +68,9 @@ SyldapServer *syldap_create() {
        ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
        ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
        ldapServer->newSearch = TRUE;
-       ldapServer->addressCache = addrcache_create();
        ldapServer->thread = NULL;
        ldapServer->busyFlag = FALSE;
-       ldapServer->retVal = MGU_SUCCESS;
        ldapServer->callBack = NULL;
-       ldapServer->accessFlag = FALSE;
        ldapServer->idleId = 0;
        return ldapServer;
 }
@@ -78,8 +79,8 @@ SyldapServer *syldap_create() {
 * Specify name to be used.
 */
 void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) {
-       ldapServer->name = mgu_replace_string( ldapServer->name, value );
-       g_strstrip( ldapServer->name );
+       g_return_if_fail( ldapServer != NULL );
+       addrcache_set_name( ldapServer->addressCache, value );
 }
 
 /*
@@ -210,7 +211,7 @@ ItemFolder *syldap_get_root_folder( SyldapServer *ldapServer ) {
 
 gchar *syldap_get_name( SyldapServer *ldapServer ) {
        g_return_val_if_fail( ldapServer != NULL, NULL );
-       return ldapServer->name;
+       return addrcache_get_name( ldapServer->addressCache );
 }
 
 gboolean syldap_get_accessed( SyldapServer *ldapServer ) {
@@ -228,8 +229,11 @@ void syldap_free( SyldapServer *ldapServer ) {
 
        ldapServer->callBack = NULL;
 
+       /* Clear cache */
+       addrcache_clear( ldapServer->addressCache );
+       addrcache_free( ldapServer->addressCache );
+
        /* Free internal stuff */
-       g_free( ldapServer->name );
        g_free( ldapServer->hostName );
        g_free( ldapServer->baseDN );
        g_free( ldapServer->bindDN );
@@ -238,32 +242,31 @@ void syldap_free( SyldapServer *ldapServer ) {
        g_free( ldapServer->searchValue );
        g_free( ldapServer->thread );
 
-       ldapServer->port = 0;
-       ldapServer->entriesRead = 0;
-       ldapServer->maxEntries = 0;
-       ldapServer->newSearch = FALSE;
-
-       /* Clear cache */
-       addrcache_clear( ldapServer->addressCache );
-       addrcache_free( ldapServer->addressCache );
 
        /* Clear pointers */
-       ldapServer->name = NULL;
        ldapServer->hostName = NULL;
+       ldapServer->port = 0;
        ldapServer->baseDN = NULL;
        ldapServer->bindDN = NULL;
        ldapServer->bindPass = NULL;
        ldapServer->searchCriteria = NULL;
        ldapServer->searchValue = NULL;
-       ldapServer->addressCache = NULL;
+       ldapServer->entriesRead = 0;
+       ldapServer->maxEntries = 0;
+       ldapServer->timeOut = 0;
+       ldapServer->newSearch = FALSE;
        ldapServer->thread = NULL;
        ldapServer->busyFlag = FALSE;
-       ldapServer->retVal = MGU_SUCCESS;
+       ldapServer->callBack = NULL;
+       ldapServer->idleId = 0;
+
+       ldapServer->type = ADBOOKTYPE_NONE;
+       ldapServer->addressCache = NULL;
        ldapServer->accessFlag = FALSE;
+       ldapServer->retVal = MGU_SUCCESS;
 
        /* Now release LDAP object */
        g_free( ldapServer );
-
 }
 
 /*
@@ -273,7 +276,6 @@ void syldap_print_data( SyldapServer *ldapServer, FILE *stream ) {
        g_return_if_fail( ldapServer != NULL );
 
        fprintf( stream, "SyldapServer:\n" );
-       fprintf( stream, "     name: '%s'\n", ldapServer->name );
        fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
        fprintf( stream, "     port: %d\n",   ldapServer->port );
        fprintf( stream, "  base dn: '%s'\n", ldapServer->baseDN );
@@ -295,7 +297,6 @@ void syldap_print_short( SyldapServer *ldapServer, FILE *stream ) {
        g_return_if_fail( ldapServer != NULL );
 
        fprintf( stream, "SyldapServer:\n" );
-       fprintf( stream, "     name: '%s'\n", ldapServer->name );
        fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
        fprintf( stream, "     port: %d\n",   ldapServer->port );
        fprintf( stream, "  base dn: '%s'\n", ldapServer->baseDN );
@@ -675,7 +676,8 @@ gint syldap_read_data( SyldapServer *ldapServer ) {
                /* TODO: really necessary to call gdk_threads_XXX()??? gtk_idle_add()
                 * should do this - could someone check the GTK sources please? */
                gdk_threads_enter();
-               ldapServer->idleId = gtk_idle_add((GtkFunction)syldap_display_search_results, ldapServer);
+               ldapServer->idleId = gtk_idle_add((GtkFunction)syldap_display_search_results,
+                               ldapServer);
                gdk_threads_leave();
        }
 
@@ -1065,7 +1067,6 @@ gboolean syldap_test_connect( SyldapServer *ldapServer ) {
 * Test whether LDAP libraries installed.
 * Return: TRUE if library available.
 */
-#if 0
 gboolean syldap_test_ldap_lib() {
        void *handle, *fun;
        
@@ -1118,7 +1119,6 @@ gboolean syldap_test_ldap_lib() {
 
        return TRUE;
 }
-#endif /* 0 */
 
 #endif /* USE_LDAP */
 
index f760dfadbf091d919939514e974ee1530b411c04..2729c8390fbabe8376d5807aa4a8a1ab2e486aed 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
 
 #include "addritem.h"
 #include "addrcache.h"
+#include "adbookbase.h"
 
 #define SYLDAP_DFL_PORT        389
 #define SYLDAP_MAX_ENTRIES     20
 
 typedef struct _SyldapServer SyldapServer;
 struct _SyldapServer {
-       gchar        *name;
-       gchar        *hostName;
-       gint         port;
-       gchar        *baseDN;
-       gchar        *bindDN;
-       gchar        *bindPass;
-       gchar        *searchCriteria;
-       gchar        *searchValue;
-       gint         entriesRead;
-       gint         maxEntries;
-       gint         timeOut;
-       gboolean     newSearch;
+       AddressBookType type;
        AddressCache *addressCache;
-       /* ItemFolder   *rootFolder; */
-       gboolean     accessFlag;
-       gint         retVal;
-       pthread_t    *thread;
-       gboolean     busyFlag;
-       void         (*callBack)( void * );
-       guint        idleId;
+       gboolean  accessFlag;
+       gint      retVal;
+       gchar     *hostName;
+       gint      port;
+       gchar     *baseDN;
+       gchar     *bindDN;
+       gchar     *bindPass;
+       gchar     *searchCriteria;
+       gchar     *searchValue;
+       gint      entriesRead;
+       gint      maxEntries;
+       gint      timeOut;
+       gboolean  newSearch;
+       pthread_t *thread;
+       gboolean  busyFlag;
+       void      (*callBack)( void * );
+       guint     idleId;
 };
 
 /* Function prototypes */
@@ -104,7 +104,7 @@ GList *syldap_read_basedn_s ( const gchar *host, const gint port, const gchar *b
 GList *syldap_read_basedn      ( SyldapServer *ldapServer );
 gboolean syldap_test_connect_s ( const gchar *host, const gint port );
 gboolean syldap_test_connect   ( SyldapServer *ldapServer );
-/* gboolean syldap_test_ldap_lib       ( void ); */
+gboolean syldap_test_ldap_lib  ( void );
 
 #endif /* USE_LDAP */
 
index 6c2451c441b5cadf3fe9fc41584845623417caf4..6f9f7a59a784cc31524baf468e17e1836901e026 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
 #include "vcard.h"
 #include "addritem.h"
 #include "addrcache.h"
+#include "adbookbase.h"
 
 #define GNOMECARD_DIR     ".gnome"
 #define GNOMECARD_FILE    "GnomeCard"
 VCardFile *vcard_create() {
        VCardFile *cardFile;
        cardFile = g_new0( VCardFile, 1 );
-       cardFile->name = NULL;
-       cardFile->path = NULL;
-       cardFile->file = NULL;
-       cardFile->bufptr = cardFile->buffer;
+       cardFile->type = ADBOOKTYPE_VCARD;
        cardFile->addressCache = addrcache_create();
-       cardFile->retVal = MGU_SUCCESS;
        cardFile->accessFlag = FALSE;
+       cardFile->retVal = MGU_SUCCESS;
+
+       cardFile->file = NULL;
+       cardFile->path = NULL;
+       cardFile->bufptr = cardFile->buffer;
        return cardFile;
 }
 
@@ -60,8 +62,7 @@ VCardFile *vcard_create() {
 */
 void vcard_set_name( VCardFile* cardFile, const gchar *value ) {
        g_return_if_fail( cardFile != NULL );
-       cardFile->name = mgu_replace_string( cardFile->name, value );
-       g_strstrip( cardFile->name );
+       addrcache_set_name( cardFile->addressCache, value );
 }
 void vcard_set_file( VCardFile* cardFile, const gchar *value ) {
        g_return_if_fail( cardFile != NULL );
@@ -111,7 +112,7 @@ ItemFolder *vcard_get_root_folder( VCardFile *cardFile ) {
 }
 gchar *vcard_get_name( VCardFile *cardFile ) {
        g_return_val_if_fail( cardFile != NULL, NULL );
-       return cardFile->name;
+       return addrcache_get_name( cardFile->addressCache );
 }
 
 /*
@@ -140,25 +141,25 @@ void vcard_free( VCardFile *cardFile ) {
        /* Close file */
        if( cardFile->file ) fclose( cardFile->file );
 
-       /* Free internal stuff */
-       g_free( cardFile->name );
-       g_free( cardFile->path );
-
        /* Clear cache */
        addrcache_clear( cardFile->addressCache );
        addrcache_free( cardFile->addressCache );
 
+       /* Free internal stuff */
+       g_free( cardFile->path );
+
        /* Clear pointers */
        cardFile->file = NULL;
-       cardFile->name = NULL;
        cardFile->path = NULL;
+       cardFile->bufptr = NULL;
+
+       cardFile->type = ADBOOKTYPE_NONE;
        cardFile->addressCache = NULL;
-       cardFile->retVal = MGU_SUCCESS;
        cardFile->accessFlag = FALSE;
+       cardFile->retVal = MGU_SUCCESS;
 
        /* Now release file object */
        g_free( cardFile );
-
 }
 
 /*
@@ -168,7 +169,6 @@ void vcard_print_file( VCardFile *cardFile, FILE *stream ) {
        g_return_if_fail( cardFile != NULL );
 
        fprintf( stream, "VCardFile:\n" );
-       fprintf( stream, "     name: '%s'\n", cardFile->name );
        fprintf( stream, "file spec: '%s'\n", cardFile->path );
        fprintf( stream, "  ret val: %d\n",   cardFile->retVal );
        addrcache_print( cardFile->addressCache, stream );
@@ -270,11 +270,10 @@ static void vcard_free_lists( GSList *listName, GSList *listAddr, GSList *listRe
 * Param: cardFile - object.
 * Param: tagvalue - will be placed into the linked list.
 */
-static gchar *vcard_read_qp( VCardFile *cardFile, gchar *tagvalue ) {
+static gchar *vcard_read_qp( VCardFile *cardFile, char *tagvalue ) {
        GSList *listQP = NULL;
        gint len = 0;
        gchar *line = tagvalue;
-
        while( line ) {
                listQP = g_slist_append( listQP, line );
                len = strlen( line ) - 1;
@@ -298,7 +297,7 @@ static gchar *vcard_read_qp( VCardFile *cardFile, gchar *tagvalue ) {
 * Parse tag name from line buffer.
 * Return: Buffer containing the tag name, or NULL if no delimiter char found.
 */
-static gchar *vcard_get_tagname( gchar* line, gchar dlm ) {
+static gchar *vcard_get_tagname( char* line, gchar dlm ) {
        gint len = 0;
        gchar *tag = NULL;
        gchar *lptr = line;
@@ -469,9 +468,7 @@ static void vcard_read_file( VCardFile *cardFile ) {
        /* GSList *listQP = NULL; */
 
        for( ;; ) {
-               gchar *line;
-
-               line = vcard_get_line( cardFile );
+               gchar *line =  vcard_get_line( cardFile );
                if( line == NULL ) break;
 
                /* fprintf( stdout, "%s\n", line ); */
@@ -484,7 +481,6 @@ static void vcard_read_file( VCardFile *cardFile ) {
                }
 
                /* fprintf( stdout, "\ttemp:  %s\n", tagtemp ); */
-
                tagvalue = vcard_get_tagvalue( line, VCARD_SEP_TAG );
                if( tagvalue == NULL ) {
                        g_free( tagtemp );
@@ -544,6 +540,7 @@ static void vcard_read_file( VCardFile *cardFile ) {
                g_free( tagvalue );
                g_free( tagtemp );
                g_free( line );
+               line = NULL;
        }
 
        /* Free lists */
@@ -614,6 +611,7 @@ GList *vcard_get_all_persons( VCardFile *cardFile ) {
 */
 gboolean vcard_validate( const VCardFile *cardFile ) {
        gboolean retVal;
+       gchar *name;
 
        g_return_val_if_fail( cardFile != NULL, FALSE );
 
@@ -624,8 +622,9 @@ gboolean vcard_validate( const VCardFile *cardFile ) {
        else {
                retVal = FALSE;
        }
-       if( cardFile->name ) {
-               if( strlen( cardFile->name ) < 1 ) retVal = FALSE;
+       name = addrcache_get_name( cardFile->addressCache );
+       if( name ) {
+               if( strlen( name ) < 1 ) retVal = FALSE;
        }
        else {
                retVal = FALSE;
@@ -773,3 +772,4 @@ gint vcard_test_read_file( const gchar *fileSpec ) {
 /*
 * End of Source.
 */
+
index dc68e98db449136e79e6cd3bed9f45d495e56ea2..5b93d79bd267bee5dfbb64e103ac53b2e8a3490b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2001 Match Grun
+ * Copyright (C) 2001-2002 Match Grun
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
 
 #include "addritem.h"
 #include "addrcache.h"
+#include "adbookbase.h"
 
 #define VCARDBUFSIZE       1024
 
 #define        VCARD_SEP_TYPE     ';'
 
 /*
-// Typical vCard entry:
-//
-// BEGIN:VCARD
-// FN:Axle Rose
-// N:Rose;Axle;D;Ms;Jnr
-// REV:2001-04-22T03:52:05
-// ADR;HOME:;;777 Lexington Avenue;Denver;CO;80299;USA
-// ADR;POSTAL:P O Box 777;;;Denver;CO;80298;Usa
-// TEL;HOME:303-555-1234
-// EMAIL;AOL:axlerose@aol.com
-// EMAIL;INTERNET:axlerose@netscape.net
-// TITLE:Janitor
-// ORG:The Company
-// URL:http://www.axlerose.com
-// END:VCARD
+* Typical vCard entry:
+*
+* BEGIN:VCARD
+* FN:Axle Rose
+* N:Rose;Axle;D;Ms;Jnr
+* REV:2001-04-22T03:52:05
+* ADR;HOME:;;777 Lexington Avenue;Denver;CO;80299;USA
+* ADR;POSTAL:P O Box 777;;;Denver;CO;80298;Usa
+* TEL;HOME:303-555-1234
+* EMAIL;AOL:axlerose@aol.com
+* EMAIL;INTERNET:axlerose@netscape.net
+* TITLE:Janitor
+* ORG:The Company
+* URL:http://www.axlerose.com
+* END:VCARD
 */
 
 /* vCard object */
 typedef struct _VCardFile VCardFile;
 struct _VCardFile {
-       gchar        *name;
-       FILE         *file;
-       gchar        *path;
-       gchar        buffer[ VCARDBUFSIZE ];
-       gchar        *bufptr;
+       AddressBookType type;
        AddressCache *addressCache;
-       gint         retVal;
-       gboolean     accessFlag;
+       gboolean accessFlag;
+       gint     retVal;
+       FILE     *file;
+       gchar    *path;
+       gchar    buffer[ VCARDBUFSIZE ];
+       gchar    *bufptr;
 };
 
-// Function prototypes
+/* Function prototypes */
 VCardFile *vcard_create                        ( void );
 VCardFile *vcard_create_path           ( const gchar *path );
 void vcard_set_name                    ( VCardFile* cardFile, const gchar *value );