addressbook cut, copy and paste
authorMatch Grun <match@dimensional.com>
Sat, 19 Jan 2002 06:05:08 +0000 (06:05 +0000)
committerMatch Grun <match@dimensional.com>
Sat, 19 Jan 2002 06:05:08 +0000 (06:05 +0000)
src/adbookbase.h [new file with mode: 0644]
src/addrclip.c [new file with mode: 0644]
src/addrclip.h [new file with mode: 0644]
src/addrselect.c [new file with mode: 0644]
src/addrselect.h [new file with mode: 0644]

diff --git a/src/adbookbase.h b/src/adbookbase.h
new file mode 100644 (file)
index 0000000..87a602f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Address book base data.
+ */
+
+#ifndef __ADBOOKBASE_H__
+#define __ADBOOKBASE_H__
+
+#include <glib.h>
+
+#include "addrcache.h"
+
+typedef enum {
+       ADBOOKTYPE_NONE,
+       ADBOOKTYPE_BOOK,
+       ADBOOKTYPE_VCARD,
+       ADBOOKTYPE_JPILOT,
+       ADBOOKTYPE_LDAP
+} AddressBookType;
+
+/*
+ * All address book interfaces should implement the following data
+ * structure at the start of their data structure.
+ */
+typedef struct _AddrBook_Base AddrBookBase;
+struct _AddrBook_Base {
+       AddressBookType type;
+       AddressCache    *addressCache;
+};
+
+#endif /* __ADBOOKBASE_H__ */
+
+
diff --git a/src/addrclip.c b/src/addrclip.c
new file mode 100644 (file)
index 0000000..bbf4fb0
--- /dev/null
@@ -0,0 +1,1124 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Contains address clipboard objects and related functions. The address 
+ * clipboard is implemented as a linked list of AddrSelectItem objects. 
+ * The address clipboard offers two groups of functions:
+ *
+ * a) Cut, copy and paste of address item objects (ItemFolder, ItemGroup,
+ *    ItemPerson) into a folder. With this method, we can paste ItemPerson
+ *    objects but not unattached ItemEMail objects into a folder. ItemEMail 
+ *    objects are owned by an ItemPerson object. Any ItemEMail objects that 
+ *    appear in the clipboard are ignored. If an ItemPerson object is found, 
+ *    the ItemPerson *and* ItemEMail objects that it owns are pasted.
+ *
+ * b) Copy and paste of ItemEMail address objects only into (below) 
+ *    ItemPerson objects. All ItemEMail objects which are owned by
+ *    ItemPerson and referenced by ItemGroup objects are pasted. Any
+ *    ItemFolder objects in the clipboard, and any objects owned by
+ *    ItemFolder objects are ignored.
+ *
+ * Objects are inserted to the clipboard by copying (cloning) 
+ * AddrSelectItem objects from the address books selection list to the
+ * clipboard's internal selection list. The clipboard makes use of the
+ * object id's and address cache id's to access objects contained in
+ * the address cache. If the referenced object is not found, it is
+ * ignored. This eliminates the need to delete pointers in multiple
+ * linked lists when an address object is deleted.
+ * 
+ */
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "addritem.h"
+#include "addrcache.h"
+#include "addrbook.h"
+#include "addrselect.h"
+#include "addrindex.h"
+#include "addrclip.h"
+
+/*
+* Create a clipboard.
+*/
+AddressClipboard *addrclip_create( void ) {
+       AddressClipboard *clipBoard;
+
+       clipBoard = g_new0( AddressClipboard, 1 );
+       clipBoard->cutFlag = FALSE;
+       clipBoard->objectList = NULL;
+       return clipBoard;
+}
+
+/*
+* Clear clipboard.
+*/
+void addrclip_clear( AddressClipboard *clipBoard ) {
+       GList *node;
+       AddrSelectItem *item;
+
+       g_return_if_fail( clipBoard != NULL );
+       node = clipBoard->objectList;
+       while( node ) {
+               item = node->data;
+               addrselect_item_free( item );
+               node->data = NULL;
+               node = g_list_next( node );
+       }
+       g_list_free( clipBoard->objectList );
+       clipBoard->objectList = NULL;
+}
+
+/*
+* Free up a clipboard.
+*/
+void addrclip_free( AddressClipboard *clipBoard ) {
+       g_return_if_fail( clipBoard != NULL );
+
+       addrclip_clear( clipBoard );
+       clipBoard->cutFlag = FALSE;
+}
+
+/*
+* Setup reference to address index.
+*/
+void addrclip_set_index(
+       AddressClipboard *clipBoard, AddressIndex *addrIndex )
+{
+       g_return_if_fail( clipBoard != NULL );
+       g_return_if_fail( addrIndex != NULL );
+       clipBoard->addressIndex = addrIndex;
+}
+
+/*
+* Test whether clipboard is empty.
+* Enter: clipBoard Clipboard.
+* Return: TRUE if clipboard is empty.
+*/
+gboolean addrclip_is_empty( AddressClipboard *clipBoard ) {
+       gboolean retVal = TRUE;
+
+       if( clipBoard ) {
+               if( clipBoard->objectList ) retVal = FALSE;
+       }
+       return retVal;
+}
+
+/*
+* Add a list of address selection objects to clipbard.
+* Enter: clipBoard Clipboard.
+*        addrList  List of address selection objects.
+*/
+void addrclip_add( AddressClipboard *clipBoard, AddrSelectList *asl ) {
+       GList *node;
+
+       g_return_if_fail( clipBoard != NULL );
+       g_return_if_fail( asl != NULL );
+       node = asl->listSelect;
+       while( node ) {
+               AddrSelectItem *item, *itemCopy;
+
+               item = node->data;
+               itemCopy = addrselect_item_copy( item );
+               clipBoard->objectList =
+                       g_list_append( clipBoard->objectList, itemCopy );
+               node = g_list_next( node );
+       }
+}
+
+/*
+* Add a single address selection objects to clipbard.
+* Enter: clipBoard Clipboard.
+*        item      Address selection object.
+*/
+void addrclip_add_item(
+       AddressClipboard *clipBoard, AddrSelectItem *item )
+{
+       g_return_if_fail( clipBoard != NULL );
+       if( item ) {
+               AddrSelectItem *itemCopy;
+
+               itemCopy = addrselect_item_copy( item );
+               clipBoard->objectList =
+                       g_list_append( clipBoard->objectList, itemCopy );
+       }
+}
+
+static void addrclip_print( AddrSelectItem *item, FILE *stream ) {
+       fprintf( stream, "Select Record\n" );
+       fprintf( stream, "obj type: %d\n", item->objectType );
+       fprintf( stream, "     uid: %s\n", item->uid );
+       fprintf( stream, "---\n" );
+}
+
+/*
+* Show clipboard contents.
+* Enter: clipBoard Clipboard.
+*        stream    Output stream.
+*/
+void addrclip_list_show( AddressClipboard *clipBoard, FILE *stream ) {
+       GList *node;
+       AddrItemObject *aio;
+       AddressCache *cache;
+
+       g_return_if_fail( clipBoard != NULL );
+       fprintf( stream, "clipboard show selection...>>>\n" );
+       node = clipBoard->objectList;
+       while( node != NULL ) {
+               AddrSelectItem *item;
+
+               item = node->data;
+               addrselect_item_print( item, stream );
+
+               cache = addrindex_get_cache( clipBoard->addressIndex, item->cacheID );
+               aio = addrcache_get_object( cache, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+                               addritem_print_item_person( ( ItemPerson * ) aio, stream );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
+                               addritem_print_item_email( ( ItemEMail * ) aio, stream );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                               addritem_print_item_group( ( ItemGroup * ) aio, stream );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
+                               addritem_print_item_folder( ( ItemFolder * ) aio, stream );
+                       }
+               }
+               node = g_list_next( node );
+       }
+       fprintf( stream, "clipboard show selection...<<<\n" );
+}
+
+/* Pasted address pointers */
+typedef struct _AddrClip_EMail_ AddrClip_EMail;
+struct _AddrClip_EMail_ {
+       ItemEMail *original;
+       ItemEMail *copy;
+};
+
+/*
+ * Free up specified list of addresses.
+ */
+static void addrclip_free_copy_list( GList *copyList ) {
+       GList *node;
+
+       node = copyList;
+       while( node ) {
+               AddrClip_EMail *em = node->data;
+               em->original = NULL;
+               em->copy = NULL;
+               g_free( em );
+               em = NULL;
+               node = g_list_next( node );
+       }
+}
+
+/*
+ * Paste person into cache.
+ * Enter: cache    Address cache to paste into.
+ *        folder   Folder to store
+ *        person   Person to paste.
+ *        copyLIst List of email addresses pasted.
+ * Return: Update list of email addresses pasted.
+ */
+static GList *addrclip_cache_add_person(
+       AddressCache *cache, ItemFolder *folder, ItemPerson *person,
+       GList *copyList )
+{
+       ItemPerson *newPerson;
+       ItemEMail *email;
+       ItemEMail *newEMail;
+       UserAttribute *attrib;
+       UserAttribute *newAttrib;
+       GList *node;
+       AddrClip_EMail *em;
+
+       /* Copy person */
+       newPerson = addritem_copy_item_person( person );
+       addrcache_id_person( cache, newPerson );
+       addrcache_folder_add_person( cache, folder, newPerson );
+
+       /* Copy email addresses */
+       node = person->listEMail;
+       while( node ) {
+               email = node->data;
+               newEMail = addritem_copy_item_email( email );
+               addrcache_id_email( cache, newEMail );
+               addrcache_person_add_email( cache, newPerson, newEMail );
+               node = g_list_next( node );
+
+               /* Take a copy of the original */
+               em = g_new0( AddrClip_EMail, 1 );
+               em->original = email;
+               em->copy = newEMail;
+               copyList = g_list_append( copyList, em );
+       }
+
+       /* Copy user attributes */
+       node = person->listAttrib;
+       while( node ) {
+               attrib = node->data;
+               newAttrib = addritem_copy_attribute( attrib );
+               addrcache_id_attribute( cache, newAttrib );
+               addritem_person_add_attribute( newPerson, newAttrib );
+               node = g_list_next( node );
+       }
+
+       return copyList;
+}
+
+/*
+ * Paste unattached email into cache.
+ * Enter: cache    Address cache to paste into.
+ *        folder   Folder to store
+ *        email    EMail to add.
+ *        copyList List of email addresses pasted.
+ * Return: Update list of email addresses pasted.
+ */
+static GList *addrclip_cache_add_email(
+       AddressCache *cache, ItemFolder *folder, ItemEMail *email,
+       GList *copyList )
+{
+       ItemPerson *newPerson;
+       ItemEMail *newEMail;
+       AddrClip_EMail *em;
+
+       /* Create a person */
+       newPerson = addritem_create_item_person();
+       addritem_person_set_common_name( newPerson, "" );
+       addrcache_id_person( cache, newPerson );
+       addrcache_folder_add_person( cache, folder, newPerson );
+
+       /* Copy email addresses */
+       newEMail = addritem_copy_item_email( email );
+       addrcache_id_email( cache, newEMail );
+       addrcache_person_add_email( cache, newPerson, newEMail );
+
+       /* Take a copy of the original */
+       em = g_new0( AddrClip_EMail, 1 );
+       em->original = email;
+       em->copy = newEMail;
+       copyList = g_list_append( copyList, em );
+
+       return copyList;
+}
+
+/*
+ * Test whether specified E-Mail address object is already in clipboard and
+ * owned by an ItemPerson objects.
+ * Enter: email  E-Mail to test.
+ * Return: TRUE if duplicate found.
+ */
+static gboolean addrclip_test_email(
+       AddressClipboard *clipBoard, ItemEMail *testEMail )
+{
+       ItemPerson *person;
+       ItemEMail *email;
+       GList *node, *nodeMail;
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       AddressCache *cache;
+
+       node = clipBoard->objectList;
+       while( node ) {
+               item = node->data;
+               cache = addrindex_get_cache( clipBoard->addressIndex, item->cacheID );
+               aio = addrcache_get_object( cache, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+                               person = ( ItemPerson * ) aio;
+                               nodeMail = person->listEMail;
+                               while( nodeMail ) {
+                                       email = nodeMail->data;
+                                       if( email == testEMail ) return TRUE;
+                                       nodeMail = g_list_next( nodeMail );
+                               }
+                       }
+               }
+               node = g_list_next( node );
+       }
+       return FALSE;
+}
+
+/*
+ * Search for new email record in copied email list.
+ * Enter: copyList  List of copied email address mappings.
+ *        emailOrig Original email item.
+ * Return: New email item corresponding to original item if pasted. Or NULL if
+ *         not found.
+ */
+static ItemEMail *addrclip_find_copied_email(
+       GList *copyList, ItemEMail *emailOrig )
+{
+       ItemEMail *emailCopy;
+       GList *node;
+       AddrClip_EMail *em;
+
+       emailCopy = NULL;
+       node = copyList;
+       while( node ) {
+               em = node->data;
+               if( em->original == emailOrig ) {
+                       emailCopy = em->copy;
+                       break;
+               }
+               node = g_list_next( node );
+       }
+       return emailCopy;
+}
+
+/*
+ * Paste group into cache.
+ * Enter: cache    Address cache to paste into.
+ *        folder   Folder to store
+ *        group    Group to paste.
+ *        copyList List of email addresses pasted.
+ * Return: Group added.
+ */
+static ItemGroup *addrclip_cache_add_group(
+       AddressCache *cache, ItemFolder *folder, ItemGroup *group,
+       GList *copyList )
+{
+       ItemGroup *newGroup;
+       ItemEMail *emailOrig, *emailCopy;
+       GList *node;
+
+       /* Copy group */
+       newGroup = addritem_copy_item_group( group );
+       addrcache_id_group( cache, newGroup );
+       addrcache_folder_add_group( cache, folder, newGroup );
+
+       /* Add references of copied addresses to group */
+       node = group->listEMail;
+       while( node ) {
+               emailOrig = ( ItemEMail * ) node->data;
+               emailCopy = addrclip_find_copied_email( copyList, emailOrig );
+               if( emailCopy ) {
+                       addrcache_group_add_email( cache, newGroup, emailCopy );
+               }
+               node = g_list_next( node );
+       }
+       return newGroup;
+}
+
+/*
+ * Copy specified folder into cache. Note this functions uses pointers to
+ * folders to copy from. There should not be any deleted items referenced
+ * by these pointers!!!
+ * Enter: cache        Address cache to copy into.
+ *        targetFolder Target folder.
+ *        folder       Folder to copy.
+ * Return: Folder added.
+ */
+static ItemFolder *addrclip_cache_copy_folder(
+       AddressCache *cache, ItemFolder *targetFolder, ItemFolder *folder )
+{
+       ItemFolder *newFolder;
+       ItemGroup *newGroup;
+       GList *node;
+       GList *copyList;
+
+       /* Copy folder */
+       newFolder = addritem_copy_item_folder( folder );
+       addrcache_id_folder( cache, newFolder );
+       addrcache_folder_add_folder( cache, targetFolder, newFolder );
+
+       /* Copy people to new folder */
+       copyList = NULL;
+       node = folder->listPerson;
+       while( node ) {
+               ItemPerson *item = node->data;
+               node = g_list_next( node );
+               copyList = addrclip_cache_add_person(
+                               cache, newFolder, item, copyList );
+       }
+
+       /* Copy groups to new folder */
+       node = folder->listGroup;
+       while( node ) {
+               ItemGroup *item = node->data;
+               node = g_list_next( node );
+               newGroup = addrclip_cache_add_group(
+                               cache, newFolder, item, copyList );
+       }
+       g_list_free( copyList );
+
+       /* Copy folders to new folder (recursive) */
+       node = folder->listFolder;
+       while( node ) {
+               ItemFolder *item = node->data;
+               node = g_list_next( node );
+               addrclip_cache_copy_folder( cache, newFolder, item );
+       }
+
+       return newFolder;
+}
+
+/*
+* Paste item list into address book.
+* Enter: cache     Target address cache.
+*        folder    Target folder where data is pasted.
+*        itemList  List of items to paste.
+*        clipBoard Clipboard.
+* Return: List of group or folder items added.
+*/
+static GList *addrclip_cache_add_folder(
+       AddressCache *cache, ItemFolder *folder, GList *itemList,
+       AddressClipboard *clipBoard )
+{
+       GList *folderGroup;
+       GList *node;
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       AddressCache *cacheFrom;
+       gboolean haveGroups;
+       GList *copyList;
+
+       folderGroup = NULL;
+       copyList = NULL;
+       haveGroups = FALSE;
+       node = itemList;
+       while( node ) {
+               item = node->data;
+               node = g_list_next( node );
+
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+               if( item->uid ) {
+                       aio = addrcache_get_object( cacheFrom, item->uid );
+                       if( aio ) {
+                               if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+                                       ItemPerson *person;
+
+                                       person = ( ItemPerson * ) aio;
+                                       copyList = addrclip_cache_add_person(
+                                               cache, folder, person, copyList );
+                               }
+                               /*
+                               else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
+                               } 
+                               */
+                               else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                                       haveGroups = TRUE;      /* Process later */
+                               }
+                               else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
+                                       ItemFolder *itemFolder, *newFolder;
+
+                                       itemFolder = ( ItemFolder * ) aio;
+                                       newFolder = addrclip_cache_copy_folder(
+                                                       cache, folder, itemFolder );
+                                       folderGroup =
+                                               g_list_append( folderGroup, newFolder );
+                               }
+                       }
+               }
+               else {
+                       if( item->objectType == ITEMTYPE_DATASOURCE ) {
+                               /*
+                               * Must be an address book - allow copy only if
+                               * copying from a different cache.
+                               */
+                               if( cache != cacheFrom ) {
+                                       ItemFolder *itemFolder, *newFolder;
+
+                                       itemFolder = cacheFrom->rootFolder;
+                                       newFolder = addrclip_cache_copy_folder(
+                                               cache, folder, itemFolder );
+                                       addritem_folder_set_name( newFolder,
+                                               addrcache_get_name( cacheFrom ) );
+                                       folderGroup =
+                                               g_list_append( folderGroup, newFolder );
+                               }
+                       }
+               }
+       }
+
+       /* Finally add any groups */
+       if( haveGroups ) {
+               node = itemList;
+               while( node ) {
+                       item = node->data;
+                       node = g_list_next( node );
+                       cacheFrom = addrindex_get_cache(
+                                       clipBoard->addressIndex, item->cacheID );
+                       if( cacheFrom == NULL ) continue;
+                       aio = addrcache_get_object( cacheFrom, item->uid );
+                       if( aio ) {
+                               if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                                       ItemGroup *group, *newGroup;
+
+                                       group = ( ItemGroup * ) aio;
+                                       newGroup = addrclip_cache_add_group(
+                                               cache, folder, group, copyList );
+                                       folderGroup =
+                                               g_list_append( folderGroup, newGroup );
+                               }
+                       }
+               }
+       }
+
+       /* Free up stuff */
+       addrclip_free_copy_list( copyList );
+       g_list_free( copyList );
+       copyList = NULL;
+
+       return folderGroup;
+}
+
+/*
+* Move items in list into new folder
+* Enter: cache        Target address cache.
+*        targetFolder Target folder where data is pasted.
+*        itemList     List of items to paste.
+*        clipBoard    Clipboard.
+* Return: List of group or folder items added.
+*/
+static GList *addrclip_cache_move_items(
+       AddressCache *cache, ItemFolder *targetFolder, GList *itemList,
+       AddressClipboard *clipBoard )
+{
+       GList *folderGroup;
+       GList *node;
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       AddressCache *cacheFrom;
+
+       folderGroup = NULL;
+       node = itemList;
+       while( node ) {
+               item = node->data;
+               node = g_list_next( node );
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+               aio = addrcache_get_object( cacheFrom, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+                               ItemPerson *person;
+
+                               person = ( ItemPerson * ) aio;
+                               addrcache_folder_move_person(
+                                       cache, person, targetFolder );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                               ItemGroup *group;
+
+                               group = ( ItemGroup * ) aio;
+                               addrcache_folder_move_group(
+                                       cache, group, targetFolder );
+                               folderGroup = g_list_append( folderGroup, group );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
+                               ItemFolder *folder;
+
+                               folder = ( ItemFolder * ) aio;
+                               addrcache_folder_move_folder(
+                                       cache, folder, targetFolder );
+                               folderGroup =
+                                       g_list_append( folderGroup, folder );
+                       }
+               }
+       }
+       return folderGroup;
+}
+
+/*
+* Get address cache of first item in list. This assumes that all items in
+* the clipboard are located in the same cache.
+* Enter: clipBoard Clipboard.
+* Return: List of group or folder items added.
+*/
+static AddressCache *addrclip_list_get_cache( AddressClipboard *clipBoard ) {
+       AddressCache *cache;
+       GList *itemList;
+       AddrSelectItem *item;
+
+       cache = NULL;
+       itemList = clipBoard->objectList;
+       if( itemList ) {
+               item = itemList->data;
+               cache = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+       }
+       return cache;
+}
+
+/*
+* Paste (copy) clipboard into address book.
+* Enter: clipBoard Clipboard.
+*        book      Target address book.
+*        folder    Target folder where data is pasted, or null for root folder.
+* Return: List of group or folder items added.
+*/
+GList *addrclip_paste_copy(
+       AddressClipboard *clipBoard, AddressBookFile *book,
+       ItemFolder *folder )
+{
+       AddressCache *cache;
+       GList *itemList;
+       GList *folderGroup;
+
+       g_return_val_if_fail( clipBoard != NULL, NULL );
+
+       cache = book->addressCache;
+       if( folder == NULL ) folder = cache->rootFolder;
+
+       folderGroup = NULL;
+       itemList = clipBoard->objectList;
+       folderGroup = addrclip_cache_add_folder(
+                       cache, folder, itemList, clipBoard );
+
+       return folderGroup;
+}
+
+/*
+* Remove items that were cut from clipboard.
+* Enter: clipBoard Clipboard.
+*/
+void addrclip_delete_item( AddressClipboard *clipBoard ) {
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       AddressCache *cacheFrom;
+       GList *node;
+
+       /* If cutting within current cache, no deletion is necessary */
+       if( clipBoard->moveFlag ) return;
+
+       /* Remove groups */
+       node = clipBoard->objectList;
+       while( node ) {
+               item = node->data;
+               node = g_list_next( node );
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+               aio = addrcache_get_object( cacheFrom, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                               ItemGroup *group;
+
+                               group = ( ItemGroup * ) aio;
+                               group = addrcache_remove_group( cacheFrom, group );
+                               if( group ) {
+                                       addritem_free_item_group( group );
+                               }
+                       }
+               }
+       }
+
+       /* Remove persons and folders */
+       node = clipBoard->objectList;
+       while( node ) {
+               item = node->data;
+               node = g_list_next( node );
+
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+
+               aio = addrcache_get_object( cacheFrom, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+                               ItemPerson *person;
+
+                               person = ( ItemPerson * ) aio;
+                               person = addrcache_remove_person( cacheFrom, person );
+                               if( person ) {
+                                       addritem_free_item_person( person );
+                               }
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
+                               ItemFolder *itemFolder;
+
+                               itemFolder = ( ItemFolder * ) aio;
+                               itemFolder = addrcache_remove_folder_delete(
+                                               cacheFrom, itemFolder );
+                               addritem_free_item_folder( itemFolder );
+                       }
+               }
+       }
+}
+
+/*
+* Paste (move) clipboard into address book.
+* Enter: clipBoard Clipboard.
+*        book      Target address book.
+*        folder    Target folder where data is pasted, or null for root folder.
+* Return: List of group or folder items added.
+*/
+GList *addrclip_paste_cut(
+       AddressClipboard *clipBoard, AddressBookFile *book,
+       ItemFolder *folder )
+{
+       AddressCache *cache, *cacheFrom;
+       GList *itemList;
+       GList *folderGroup;
+
+       g_return_val_if_fail( clipBoard != NULL, NULL );
+
+       cache = book->addressCache;
+       if( folder == NULL ) folder = cache->rootFolder;
+
+       folderGroup = NULL;
+       clipBoard->moveFlag = FALSE;
+       cacheFrom = addrclip_list_get_cache( clipBoard );
+       if( cacheFrom && cacheFrom == cache ) {
+               /* Move items between folders in same book */
+               itemList = clipBoard->objectList;
+               folderGroup = addrclip_cache_move_items(
+                               cache, folder, itemList, clipBoard );
+               clipBoard->moveFlag = TRUE;
+       }
+       else {
+               /* Move items across address books */
+               itemList = clipBoard->objectList;
+               folderGroup = addrclip_cache_add_folder(
+                               cache, folder, itemList, clipBoard );
+       }
+
+       return folderGroup;
+}
+
+/*
+ * ============================================================================
+ * Paste address only.
+ * ============================================================================
+ */
+
+/*
+ * Copy email addresses from specified list.
+ * Enter: cache      Address cache to paste into.
+ *        target     Person to receive email addresses.
+ *        listEMail  List of email addresses.
+ * Return: Number of addresses added.
+ */
+static gint addrclip_person_add_email(
+       AddressCache *cache, ItemPerson *target, GList *listEMail )
+{
+       gint cnt;
+       GList *node;
+
+       /* Copy email addresses */
+       cnt = 0;
+       node = listEMail;
+       while( node ) {
+               ItemEMail *email, *newEMail;
+
+               email = node->data;
+               newEMail = addritem_copy_item_email( email );
+               addrcache_id_email( cache, newEMail );
+               addrcache_person_add_email( cache, target, newEMail );
+               node = g_list_next( node );
+               cnt++;
+       }
+       return cnt;
+}
+
+/*
+* Paste (copy) E-Mail addresses from clipboard into specified person.
+* Enter: aio     Address item to copy from.
+*        cache   Target address cache.
+*        person  Target person where data is pasted.
+* Return: Number of EMail records added.
+*/
+static gint addrclip_copy_email_to_person(
+       AddrItemObject *aio, AddressCache *cache, ItemPerson *person )
+{
+       gint cnt;
+       GList *listEMail;
+
+       cnt = 0;
+
+       if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+               ItemPerson *fromPerson;
+
+               fromPerson = ( ItemPerson * ) aio;
+               listEMail = fromPerson->listEMail;
+               cnt += addrclip_person_add_email(
+                       cache, person, listEMail );
+       }
+       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
+               ItemEMail *email, *newEMail;
+
+               email = ( ItemEMail * ) aio;
+               newEMail = addritem_copy_item_email( email );
+               addrcache_id_email( cache, newEMail );
+               addrcache_person_add_email( cache, person, newEMail );
+               cnt++;
+       }
+       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+               ItemGroup *group;
+
+               group = ( ItemGroup * ) aio;
+               listEMail = group->listEMail;
+               cnt += addrclip_person_add_email(
+                       cache, person, listEMail );
+       }
+       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
+               ItemFolder *folder;
+               AddrItemObject *item;
+               GList *node;
+
+               folder = ( ItemFolder * ) aio;
+               node = folder->listPerson;
+               while( node ) {
+                       item = node->data;
+                       node = g_list_next( node );
+                       cnt += addrclip_copy_email_to_person( item, cache, person );
+               }
+
+               node = folder->listGroup;
+               while( node ) {
+                       item = node->data;
+                       node = g_list_next( node );
+                       cnt += addrclip_copy_email_to_person( item, cache, person );
+               }
+
+               node = folder->listFolder;
+               while( node ) {
+                       item = node->data;
+                       node = g_list_next( node );
+                       cnt += addrclip_copy_email_to_person( item, cache, person );
+               }
+       }
+       return cnt;
+}
+
+/*
+* Paste (copy) E-Mail addresses from clipboard into specified person.
+* Enter: clipBoard Clipboard.
+*        cache     Target address cache.
+*        person    Target person where data is pasted.
+* Return: Number of EMail records added.
+*/
+static gint addrclip_copyto_person(
+       AddressClipboard *clipBoard, AddressCache *cache, ItemPerson *person )
+{
+       gint cnt;
+       GList *node;
+
+       cnt = 0;
+       node = clipBoard->objectList;
+       while( node ) {
+               AddressCache *cacheFrom;
+               AddrSelectItem *item;
+               AddrItemObject *aio;
+
+               item = node->data;
+               node = g_list_next( node );
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+               aio = addrcache_get_object( cacheFrom, item->uid );
+               if( aio ) {
+                       cnt += addrclip_copy_email_to_person( aio, cache, person );
+               }
+       }
+       return cnt;
+}
+
+/*
+* Paste (copy) E-Mail addresses from clipboard into specified person.
+* Enter: clipBoard Clipboard.
+*        book      Target address book.
+*        person    Target person where data is pasted.
+* Return: Number of EMail records added.
+*/
+gint addrclip_paste_person_copy(
+       AddressClipboard *clipBoard, AddressBookFile *book,
+       ItemPerson *person )
+{
+       gint cnt;
+       AddressCache *cache;
+
+       cnt = 0;
+       g_return_val_if_fail( clipBoard != NULL, cnt );
+
+       cache = book->addressCache;
+       if( person ) {
+               cnt = addrclip_copyto_person( clipBoard, cache, person );
+       }
+       return cnt;
+}
+
+/*
+ * Move email addresses for specified person to target person.
+ * Enter: cache      Address cache to paste into.
+ *        fromPerson Person supplying email addresses.
+ *        target     Person to receive email addresses.
+ * Return: Number of addresses moved.
+ */
+static gint addrclip_person_move_email(
+       AddressCache *cache, ItemPerson *fromPerson, ItemPerson *target )
+{
+       gint cnt;
+       GList *node;
+
+       cnt = 0;
+       while( node = fromPerson->listEMail ) {
+               ItemEMail *email;
+
+               email = node->data;
+               addrcache_person_move_email( cache, email, target );
+               cnt++;
+       }
+       return cnt;
+}
+
+/*
+* Paste (cut) E-Mail addresses from clipboard into specified person.
+* Enter: clipBoard Clipboard.
+*        cache     Target address cache.
+*        person    Target person where data is pasted.
+* Return: Number of EMail records added.
+*/
+static gint addrclip_paste_person_move(
+       AddressClipboard *clipBoard, AddressCache *cache, ItemPerson *person )
+{
+       gint cnt;
+       AddressCache *cacheFrom;
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       GList *node;
+       GList *listEMail;
+
+       cnt = 0;
+       node = clipBoard->objectList;
+       while( node ) {
+               item = node->data;
+               node = g_list_next( node );
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+               aio = addrcache_get_object( cacheFrom, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
+                               ItemPerson *fromPerson;
+
+                               fromPerson = ( ItemPerson * ) aio;
+                               cnt += addrclip_person_move_email(
+                                       cache, fromPerson, person );
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
+                               ItemEMail *email;
+
+                               email = ( ItemEMail * ) aio;
+                               addrcache_person_move_email(
+                                       cache, email, person );
+                               cnt++;
+                       }
+                       else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
+                               ItemGroup *group;
+
+                               group = ( ItemGroup * ) aio;
+                               listEMail = group->listEMail;
+                               cnt += addrclip_person_add_email(
+                                       cache, person, listEMail );
+                       }
+               }
+       }
+       return cnt;
+}
+
+/*
+* Paste (cut) E-Mail addresses from clipboard into specified person.
+* Enter: clipBoard Clipboard.
+*        book      Target address book.
+*        person    Target person where data is pasted.
+* Return: Number of EMail records added.
+*/
+gint addrclip_paste_person_cut(
+       AddressClipboard *clipBoard, AddressBookFile *book,
+       ItemPerson *person )
+{
+       gint cnt;
+       AddressCache *cache, *cacheFrom;
+
+       cnt = 0;
+       g_return_val_if_fail( clipBoard != NULL, cnt );
+
+       cache = book->addressCache;
+       if( person ) {
+               clipBoard->moveFlag = FALSE;
+               cacheFrom = addrclip_list_get_cache( clipBoard );
+               if( cacheFrom && cacheFrom == cache ) {
+                       /* Move items between folders in same book */
+                       cnt = addrclip_paste_person_move(
+                               clipBoard, cache, person );
+                       clipBoard->moveFlag = TRUE;
+               }
+               else {
+                       /* Move items across address books */
+                       cnt = addrclip_copyto_person(
+                               clipBoard, cache, person );
+               }
+       }
+       return cnt;
+}
+
+/*
+* Remove address items that were cut from clipboard. Note that that only
+* E-Mail items are actually deleted. Any Person items will not be deleted
+* (not even E-Mail items that owned by a person). Any Group or Folder
+* items will *NOT* be deleted.
+* Enter: clipBoard Clipboard.
+*/
+void addrclip_delete_address( AddressClipboard *clipBoard ) {
+       AddrSelectItem *item;
+       AddrItemObject *aio;
+       AddressCache *cacheFrom;
+       GList *node;
+
+       /* If cutting within current cache, no deletion is necessary */
+       if( clipBoard->moveFlag ) return;
+
+       /* Remove groups */
+       node = clipBoard->objectList;
+       while( node ) {
+               item = node->data;
+               node = g_list_next( node );
+               cacheFrom = addrindex_get_cache(
+                               clipBoard->addressIndex, item->cacheID );
+               if( cacheFrom == NULL ) continue;
+               aio = addrcache_get_object( cacheFrom, item->uid );
+               if( aio ) {
+                       if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
+                               ItemEMail *email;
+                               ItemPerson *person;
+
+                               email = ( ItemEMail * ) aio;
+                               person = ( ItemPerson * ) ADDRITEM_PARENT(email);
+                               email = addrcache_person_remove_email(
+                                               cacheFrom, person, email );
+                               if( email ) {
+                                       addritem_free_item_email( email );
+                               }
+                       }
+               }
+       }
+}
+
+/*
+* End of Source.
+*/
+
diff --git a/src/addrclip.h b/src/addrclip.h
new file mode 100644 (file)
index 0000000..05afec4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Address clip board selection.
+ */
+
+#ifndef __ADDRESS_CLIP_H__
+#define __ADDRESS_CLIP_H__
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "addrindex.h"
+#include "addrselect.h"
+
+/*
+* Selection data.
+*/
+typedef struct _AddressClipboard_ AddressClipboard;
+struct _AddressClipboard_ {
+       gboolean     cutFlag;           /* Indicates cut/copy operation    */
+       gboolean     moveFlag;          /* Internal move indicator for cut */
+       AddressIndex *addressIndex;     /* Reference to address index      */
+       GList        *objectList;       /* List of objects in clipboard    */
+};
+
+/*
+* Function prototypes.
+*/
+AddressClipboard *addrclip_create      ( void );
+void addrclip_clear            ( AddressClipboard *clipBoard );
+void addrclip_free             ( AddressClipboard *clipBoard );
+void addrclip_set_index                ( AddressClipboard *clipBoard,
+                                 AddressIndex *addrIndex );
+void addrclip_add              ( AddressClipboard *clipBoard,
+                                 AddrSelectList *asl );
+/*
+void addrclip_add              ( AddressClipboard *clipBoard,
+                                 GList *addrList );
+*/
+void addrclip_add_item         ( AddressClipboard *clipBoard,
+                                 AddrSelectItem *item );
+gboolean addrclip_is_empty     ( AddressClipboard *clipBoard );
+void addrclip_list_show                ( AddressClipboard *clipBoard,
+                                 FILE *stream );
+void addrclip_delete_item      ( AddressClipboard *clipBoard );
+GList *addrclip_paste_copy     ( AddressClipboard *clipBoard,
+                                 AddressBookFile *book,
+                                 ItemFolder *folder );
+GList *addrclip_paste_cut      ( AddressClipboard *clipBoard,
+                                 AddressBookFile *book,
+                                 ItemFolder *folder );
+void addrclip_delete_address   ( AddressClipboard *clipBoard );
+gint addrclip_paste_person_copy        ( AddressClipboard *clipBoard,
+                                 AddressBookFile *book,
+                                 ItemPerson *person );
+gint addrclip_paste_person_cut ( AddressClipboard *clipBoard,
+                                 AddressBookFile *book,
+                                 ItemPerson *person );
+
+#endif /* __ADDRRESS_CLIP_H__ */
+
diff --git a/src/addrselect.c b/src/addrselect.c
new file mode 100644 (file)
index 0000000..d867d78
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Address list item selection objects.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "addritem.h"
+#include "addrselect.h"
+#include "addressitem.h"
+#include "mgutils.h"
+
+/*
+* Create a selection record from an address cache item.
+* Enter: aio Item object.
+*/
+AddrSelectItem *addrselect_create_item( AddrItemObject *aio ) {
+       AddrSelectItem *item = NULL;
+
+       if( aio ) {
+               item = g_new0( AddrSelectItem, 1 );
+               item->objectType = aio->type;
+               item->addressItem = aio;
+               item->uid = g_strdup( aio->uid );
+               item->cacheID = NULL;
+       }
+       return item;
+}
+
+/*
+* Create a selection record from an address object (in tree node).
+* Enter: obj Address object.
+*/
+AddrSelectItem *addrselect_create_node( AddressObject *obj ) {
+       AddrSelectItem *item = NULL;
+
+       if( obj ) {
+               item = g_new0( AddrSelectItem, 1 );
+               item->objectType = addressbook_type2item( obj->type );
+               item->addressItem = NULL;
+               item->uid = NULL;
+               item->cacheID = NULL;
+       }
+       return item;
+}
+
+/*
+* Create a copy of a selection record.
+* Enter: item Address entry to copy.
+*/
+AddrSelectItem *addrselect_item_copy( AddrSelectItem *item ) {
+       AddrSelectItem *copy = NULL;
+
+       if( item ) {
+               copy = g_new0( AddrSelectItem, 1 );
+               copy->objectType = item->objectType;
+               copy->addressItem = item->addressItem;
+               copy->uid = g_strdup( item->uid );
+               copy->cacheID = g_strdup( item->cacheID );
+       }
+       return copy;
+}
+
+/*
+* Free selection record.
+*/
+void addrselect_item_free( AddrSelectItem *item ) {
+       if( item ) {
+               g_free( item->uid );
+               g_free( item->cacheID );
+               item->objectType = ITEMTYPE_NONE;
+               item->addressItem = NULL;
+               item->uid = NULL;
+               item->cacheID = NULL;
+       }
+       g_free( item );
+}
+
+/*
+* Properties.
+*/
+void addrselect_set_cache_id( AddrSelectItem *item, const gchar *value ) {
+       g_return_if_fail( item != NULL );
+       item->cacheID = mgu_replace_string( item->cacheID, value );
+}
+
+void addrselect_item_print( AddrSelectItem *item, FILE *stream ) {
+       fprintf( stream, "Select Record\n" );
+       fprintf( stream, "obj type: %d\n", item->objectType );
+       fprintf( stream, "     uid: %s\n", item->uid );
+       fprintf( stream, "cache id: %s\n", item->cacheID );
+       fprintf( stream, "---\n" );
+}
+
+/*
+* Create a new selection.
+* Return: Initialized object.
+*/
+AddrSelectList *addrselect_list_create() {
+       AddrSelectList *asl;
+
+       asl = g_new0( AddrSelectList, 1 );
+       asl->listSelect = NULL;
+       return asl;
+}
+
+/*
+* Clear list of selection records.
+* Enter: asl List to process.
+*/
+void addrselect_list_clear( AddrSelectList *asl ) {
+       GList *node;
+
+       g_return_if_fail( asl != NULL );
+       node = asl->listSelect;
+       while( node ) {
+               AddrSelectItem *item;
+
+               item = node->data;
+               addrselect_item_free( item );
+               node->data = NULL;
+               node = g_list_next( node );
+       }
+       g_list_free( asl->listSelect );
+       asl->listSelect = NULL;
+}
+
+/*
+* Free selection list.
+* Enter: asl List to free.
+*/
+void addrselect_list_free( AddrSelectList *asl ) {
+       g_return_if_fail( asl != NULL );
+
+       addrselect_list_clear( asl );
+       g_list_free( asl->listSelect );
+       asl->listSelect = NULL;
+       g_free( asl );
+}
+
+/*
+* Test whether selection is empty.
+* Enter: asl List to test.
+* Return: TRUE if list is empty.
+*/
+gboolean addrselect_test_empty( AddrSelectList *asl ) {
+       g_return_val_if_fail( asl != NULL, TRUE );
+       return ( asl->listSelect == NULL );
+}
+
+/*
+* Return list of AddrSelectItem objects.
+* Enter: asl List to process.
+* Return: List of selection items. The list should should be g_list_free()
+* when done. Items contained in the list should not be freed!!!
+*/
+GList *addrselect_get_list( AddrSelectList *asl ) {
+       GList *node, *list;
+
+       g_return_if_fail( asl != NULL );
+       list = NULL;
+       node = asl->listSelect;
+       while( node ) {
+               list = g_list_append( list, node->data );
+               node = g_list_next( node );
+       }
+       return list;
+}
+
+static gchar *addrselect_format_address( AddrItemObject * aio ) {
+       gchar *buf = NULL;
+       gchar *name = NULL;
+       gchar *address = NULL;
+
+       if( aio->type == ADDR_ITEM_EMAIL ) {
+               ItemPerson *person = NULL;
+               ItemEMail *email = ( ItemEMail * ) aio;
+
+               person = ( ItemPerson * ) ADDRITEM_PARENT(email);
+               if( email->address ) {
+                       if( ADDRITEM_NAME(email) ) {
+                               name = ADDRITEM_NAME(email);
+                               if( *name == '\0' ) {
+                                       name = ADDRITEM_NAME(person);
+                               }
+                       }
+                       else if( ADDRITEM_NAME(person) ) {
+                               name = ADDRITEM_NAME(person);
+                       }
+                       else {
+                               buf = g_strdup( email->address );
+                       }
+                       address = email->address;
+               }
+       }
+       else if( aio->type == ADDR_ITEM_PERSON ) {
+               ItemPerson *person = ( ItemPerson * ) aio;
+               GList *node = person->listEMail;
+
+               name = ADDRITEM_NAME(person);
+               if( node ) {
+                       ItemEMail *email = ( ItemEMail * ) node->data;
+                       address = email->address;
+               }
+       }
+       if( address ) {
+               if( name ) {
+                       buf = g_strdup_printf( "%s <%s>", name, address );
+               }
+               else {
+                       buf = g_strdup( address );
+               }
+       }
+       return buf;
+}
+
+/*
+* Print formatted addresses list to specified stream.
+* Enter: asl    List to process.
+*        stream Stream.
+*/
+void addrselect_list_print( AddrSelectList *asl, FILE *stream ) {
+       GList *node;
+
+       g_return_if_fail( asl != NULL );
+       fprintf( stream, "show selection...>>>\n" );
+       node = asl->listSelect;
+       while( node != NULL ) {
+               AddrSelectItem *item;
+               AddrItemObject *aio;
+               gchar *addr;
+
+               item = node->data;
+               aio = ( AddrItemObject * ) item->addressItem;
+               if( aio ) {
+                       fprintf( stream, "- %d : '%s'\n", aio->type, aio->name );
+                       if( aio->type == ADDR_ITEM_GROUP ) {
+                               ItemGroup *group = ( ItemGroup * ) aio;
+                               GList *node = group->listEMail;
+                               while( node ) {
+                                       ItemEMail *email = node->data;
+                                       addr = addrselect_format_address(
+                                               ( AddrItemObject * ) email );
+                                       if( addr ) {
+                                               fprintf( stream, "\tgrp >%s<\n", addr );
+                                               g_free( addr );
+                                       }
+                                       node = g_list_next( node );
+                               }
+                       }
+                       else {
+                               addr = addrselect_format_address( aio );
+                               if( addr ) {
+                                       fprintf( stream, "\t>%s<\n", addr );
+                                       g_free( addr );
+                               }
+                       }
+               }
+               else {
+                       fprintf( stream, "- NULL" );
+               }
+               node = g_list_next( node );
+       }
+       fprintf( stream, "show selection...<<<\n" );
+}
+
+/*
+* Print address items to specified stream.
+* Enter: asl    List to process.
+*        stream Stream.
+*/
+void addrselect_list_show( AddrSelectList *asl, FILE *stream ) {
+       GList *node;
+
+       g_return_if_fail( asl != NULL );
+       fprintf( stream, "show selection...>>>\n" );
+       node = asl->listSelect;
+       while( node != NULL ) {
+               AddrSelectItem *item;
+
+               item = node->data;
+               addrselect_item_print( item, stream );
+               node = g_list_next( node );
+       }
+       fprintf( stream, "show selection...<<<\n" );
+}
+
+/*
+* Test whether specified object is in list.
+* Enter: list List to check.
+*        aio  Object to test.
+* Return item found, or NULL if not in list.
+*/
+static AddrSelectItem *addrselect_list_find( GList *list, AddrItemObject *aio ) {
+       GList *node;
+
+       node = list;
+       while( node ) {
+               AddrSelectItem *item;
+
+               item = node->data;
+               if( item->addressItem == aio ) return item;
+               node = g_list_next( node );
+       }
+       return NULL;
+}
+
+/*
+* Add a single object into the list.
+* Enter: asl     Address selection object.
+*        obj     Address object.
+*        cacheID Cache ID. Should be g_free() after calling function.
+* Return: Adjusted list.
+*/
+void addrselect_list_add_obj( AddrSelectList *asl, AddrItemObject *aio, gchar *cacheID ) {
+       AddrSelectItem *item;
+
+       g_return_if_fail( asl != NULL );
+       if( aio == NULL ) return;
+
+       /* Check whether object is in list */
+       if( addrselect_list_find( asl->listSelect, aio ) ) return;
+
+       if( aio->type == ADDR_ITEM_PERSON ||
+           aio->type == ADDR_ITEM_EMAIL ||
+           aio->type == ADDR_ITEM_GROUP ) {
+               item = addrselect_create_item( aio );
+               item->cacheID = g_strdup( cacheID );
+               asl->listSelect = g_list_append( asl->listSelect, item );
+       }
+       /* addrselect_list_show( asl, stdout ); */
+}
+
+/*
+* Add a single item into the list.
+* Enter: asl     Address selection object.
+*        item    Address select item.
+*        cacheID Cache ID. Should be g_free() after calling function.
+* Return: Adjusted list.
+*/
+void addrselect_list_add( AddrSelectList *asl, AddrSelectItem *item, gchar *cacheID ) {
+       g_return_if_fail( asl != NULL );
+       if( item == NULL ) return;
+
+       /* Check whether object is in list */
+       if( g_list_find( asl->listSelect, item ) ) return;
+
+       item->cacheID = g_strdup( cacheID );
+       asl->listSelect = g_list_append( asl->listSelect, item );
+}
+
+/*
+* Remove specified object from list.
+* Enter: asl  Address selection object.
+*        aio  Object to remove.
+*/
+void addrselect_list_remove( AddrSelectList *asl, AddrItemObject *aio ) {
+       GList *node;
+       AddrSelectItem *item;
+
+       g_return_if_fail( asl != NULL );
+       if( aio == NULL ) return;
+       node = asl->listSelect;
+       while( node ) {
+               item = node->data;
+               if( item->addressItem == aio ) {
+                       addrselect_item_free( item );
+                       node->data = NULL;
+                       asl->listSelect = g_list_remove_link( asl->listSelect, node );
+                       break;
+               }
+               node = g_list_next( node );
+       }
+       /* addrselect_list_show( list, stdout ); */
+}
+
+/*
+* End of Source.
+*/
+
+
diff --git a/src/addrselect.h b/src/addrselect.h
new file mode 100644 (file)
index 0000000..78d7e2b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Address list item selection.
+ */
+
+#ifndef __ADDR_SELECT_H__
+#define __ADDR_SELECT_H__
+
+#include "addritem.h"
+#include "addressitem.h"
+#include "addrcache.h"
+
+/*
+* Selection item data.
+*/
+typedef struct _AddrSelectItem_ AddrSelectItem;
+struct _AddrSelectItem_ {
+       ItemObjectType    objectType;
+       AddrItemObject    *addressItem;
+       gchar             *uid;
+       gchar             *cacheID;
+};
+
+/*
+ * Selection list object.
+ */
+typedef struct _AddrSelectList_ AddrSelectList;
+struct _AddrSelectList_ {
+       GList *listSelect;
+};
+
+AddrSelectItem *addrselect_create_item ( AddrItemObject *aio );
+AddrSelectItem *addrselect_create_node ( AddressObject *obj );
+AddrSelectItem *addrselect_item_copy   ( AddrSelectItem *item );
+void addrselect_item_free              ( AddrSelectItem *item );
+void addrselect_item_print             ( AddrSelectItem *item,
+                                         FILE *stream );
+AddrSelectList *addrselect_list_create ( void );
+void addrselect_list_free              ( AddrSelectList *asl );
+GList *addrselect_get_list             ( AddrSelectList *asl );
+void addrselect_list_clear             ( AddrSelectList *asl );
+gboolean addrselect_test_empty         ( AddrSelectList *asl );
+void addrselect_list_add_obj           ( AddrSelectList *asl,
+                                         AddrItemObject *aio,
+                                         gchar *cacheID );
+void addrselect_list_add               ( AddrSelectList *asl,
+                                         AddrSelectItem *item,
+                                         gchar *cacheID );
+void addrselect_list_remove            ( AddrSelectList *asl,
+                                         AddrItemObject *aio );
+void addrselect_list_show              ( AddrSelectList *asl,
+                                         FILE *stream );
+void addrselect_list_print             ( AddrSelectList *asl,
+                                         FILE *stream );
+
+#endif /* __ADDR_SELECT_H__ */
+