2005-02-17 [paul] 1.0.1cvs11.4
[claws.git] / src / addrclip.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2002 Match Grun
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Contains address clipboard objects and related functions. The address 
22  * clipboard is implemented as a linked list of AddrSelectItem objects. 
23  * The address clipboard offers two groups of functions:
24  *
25  * a) Cut, copy and paste of address item objects (ItemFolder, ItemGroup,
26  *    ItemPerson) into a folder. With this method, we can paste ItemPerson
27  *    objects but not unattached ItemEMail objects into a folder. ItemEMail 
28  *    objects are owned by an ItemPerson object. Any ItemEMail objects that 
29  *    appear in the clipboard are ignored. If an ItemPerson object is found, 
30  *    the ItemPerson *and* ItemEMail objects that it owns are pasted.
31  *
32  * b) Copy and paste of ItemEMail address objects only into (below) 
33  *    ItemPerson objects. All ItemEMail objects which are owned by
34  *    ItemPerson and referenced by ItemGroup objects are pasted. Any
35  *    ItemFolder objects in the clipboard, and any objects owned by
36  *    ItemFolder objects are ignored.
37  *
38  * Objects are inserted to the clipboard by copying (cloning) 
39  * AddrSelectItem objects from the address books selection list to the
40  * clipboard's internal selection list. The clipboard makes use of the
41  * object id's and address cache id's to access objects contained in
42  * the address cache. If the referenced object is not found, it is
43  * ignored. This eliminates the need to delete pointers in multiple
44  * linked lists when an address object is deleted.
45  * 
46  */
47
48 #include <stdio.h>
49 #include <glib.h>
50
51 #include "addrcache.h"
52 #include "addrbook.h"
53 #include "addrselect.h"
54 #include "addrindex.h"
55 #include "addrclip.h"
56
57 /*
58 * Create a clipboard.
59 */
60 AddressClipboard *addrclip_create( void ) {
61         AddressClipboard *clipBoard;
62
63         clipBoard = g_new0( AddressClipboard, 1 );
64         clipBoard->cutFlag = FALSE;
65         clipBoard->objectList = NULL;
66         return clipBoard;
67 }
68
69 /*
70 * Clear clipboard.
71 */
72 void addrclip_clear( AddressClipboard *clipBoard ) {
73         GList *node;
74         AddrSelectItem *item;
75
76         g_return_if_fail( clipBoard != NULL );
77         node = clipBoard->objectList;
78         while( node ) {
79                 item = node->data;
80                 addrselect_item_free( item );
81                 node->data = NULL;
82                 node = g_list_next( node );
83         }
84         g_list_free( clipBoard->objectList );
85         clipBoard->objectList = NULL;
86 }
87
88 /*
89 * Free up a clipboard.
90 */
91 void addrclip_free( AddressClipboard *clipBoard ) {
92         g_return_if_fail( clipBoard != NULL );
93
94         addrclip_clear( clipBoard );
95         clipBoard->cutFlag = FALSE;
96 }
97
98 /*
99 * Setup reference to address index.
100 */
101 void addrclip_set_index(
102         AddressClipboard *clipBoard, AddressIndex *addrIndex )
103 {
104         g_return_if_fail( clipBoard != NULL );
105         g_return_if_fail( addrIndex != NULL );
106         clipBoard->addressIndex = addrIndex;
107 }
108
109 /*
110 * Test whether clipboard is empty.
111 * Enter: clipBoard Clipboard.
112 * Return: TRUE if clipboard is empty.
113 */
114 gboolean addrclip_is_empty( AddressClipboard *clipBoard ) {
115         gboolean retVal = TRUE;
116
117         if( clipBoard ) {
118                 if( clipBoard->objectList ) retVal = FALSE;
119         }
120         return retVal;
121 }
122
123 /*
124 * Add a list of address selection objects to clipbard.
125 * Enter: clipBoard Clipboard.
126 *        addrList  List of address selection objects.
127 */
128 void addrclip_add( AddressClipboard *clipBoard, AddrSelectList *asl ) {
129         GList *node;
130
131         g_return_if_fail( clipBoard != NULL );
132         g_return_if_fail( asl != NULL );
133         node = asl->listSelect;
134         while( node ) {
135                 AddrSelectItem *item, *itemCopy;
136
137                 item = node->data;
138                 itemCopy = addrselect_item_copy( item );
139                 clipBoard->objectList =
140                         g_list_append( clipBoard->objectList, itemCopy );
141                 node = g_list_next( node );
142         }
143 }
144
145 /*
146 * Add a single address selection objects to clipbard.
147 * Enter: clipBoard Clipboard.
148 *        item      Address selection object.
149 */
150 void addrclip_add_item(
151         AddressClipboard *clipBoard, AddrSelectItem *item )
152 {
153         g_return_if_fail( clipBoard != NULL );
154         if( item ) {
155                 AddrSelectItem *itemCopy;
156
157                 itemCopy = addrselect_item_copy( item );
158                 clipBoard->objectList =
159                         g_list_append( clipBoard->objectList, itemCopy );
160         }
161 }
162
163 /*
164 * Show clipboard contents.
165 * Enter: clipBoard Clipboard.
166 *        stream    Output stream.
167 */
168 void addrclip_list_show( AddressClipboard *clipBoard, FILE *stream ) {
169         GList *node;
170         AddrItemObject *aio;
171         AddressCache *cache;
172
173         g_return_if_fail( clipBoard != NULL );
174         node = clipBoard->objectList;
175         while( node != NULL ) {
176                 AddrSelectItem *item;
177
178                 item = node->data;
179                 addrselect_item_print( item, stream );
180
181                 cache = addrindex_get_cache( clipBoard->addressIndex, item->cacheID );
182                 aio = addrcache_get_object( cache, item->uid );
183                 if( aio ) {
184                         if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
185                                 addritem_print_item_person( ( ItemPerson * ) aio, stream );
186                         }
187                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
188                                 addritem_print_item_email( ( ItemEMail * ) aio, stream );
189                         }
190                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
191                                 addritem_print_item_group( ( ItemGroup * ) aio, stream );
192                         }
193                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
194                                 addritem_print_item_folder( ( ItemFolder * ) aio, stream );
195                         }
196                 }
197                 node = g_list_next( node );
198         }
199 }
200
201 /* Pasted address pointers */
202 typedef struct _AddrClip_EMail_ AddrClip_EMail;
203 struct _AddrClip_EMail_ {
204         ItemEMail *original;
205         ItemEMail *copy;
206 };
207
208 /*
209  * Free up specified list of addresses.
210  */
211 static void addrclip_free_copy_list( GList *copyList ) {
212         GList *node;
213
214         node = copyList;
215         while( node ) {
216                 AddrClip_EMail *em = node->data;
217                 em->original = NULL;
218                 em->copy = NULL;
219                 g_free( em );
220                 em = NULL;
221                 node = g_list_next( node );
222         }
223 }
224
225 /*
226  * Paste person into cache.
227  * Enter: cache    Address cache to paste into.
228  *        folder   Folder to store
229  *        person   Person to paste.
230  *        copyLIst List of email addresses pasted.
231  * Return: Update list of email addresses pasted.
232  */
233 static GList *addrclip_cache_add_person(
234         AddressCache *cache, ItemFolder *folder, ItemPerson *person,
235         GList *copyList )
236 {
237         ItemPerson *newPerson;
238         ItemEMail *email;
239         ItemEMail *newEMail;
240         UserAttribute *attrib;
241         UserAttribute *newAttrib;
242         GList *node;
243         AddrClip_EMail *em;
244
245         /* Copy person */
246         newPerson = addritem_copy_item_person( person );
247         addrcache_id_person( cache, newPerson );
248         addrcache_folder_add_person( cache, folder, newPerson );
249
250         /* Copy email addresses */
251         node = person->listEMail;
252         while( node ) {
253                 email = node->data;
254                 newEMail = addritem_copy_item_email( email );
255                 addrcache_id_email( cache, newEMail );
256                 addrcache_person_add_email( cache, newPerson, newEMail );
257                 node = g_list_next( node );
258
259                 /* Take a copy of the original */
260                 em = g_new0( AddrClip_EMail, 1 );
261                 em->original = email;
262                 em->copy = newEMail;
263                 copyList = g_list_append( copyList, em );
264         }
265
266         /* Copy user attributes */
267         node = person->listAttrib;
268         while( node ) {
269                 attrib = node->data;
270                 newAttrib = addritem_copy_attribute( attrib );
271                 addrcache_id_attribute( cache, newAttrib );
272                 addritem_person_add_attribute( newPerson, newAttrib );
273                 node = g_list_next( node );
274         }
275
276         return copyList;
277 }
278
279 /*
280  * Search for new email record in copied email list.
281  * Enter: copyList  List of copied email address mappings.
282  *        emailOrig Original email item.
283  * Return: New email item corresponding to original item if pasted. Or NULL if
284  *         not found.
285  */
286 static ItemEMail *addrclip_find_copied_email(
287         GList *copyList, ItemEMail *emailOrig )
288 {
289         ItemEMail *emailCopy;
290         GList *node;
291         AddrClip_EMail *em;
292
293         emailCopy = NULL;
294         node = copyList;
295         while( node ) {
296                 em = node->data;
297                 if( em->original == emailOrig ) {
298                         emailCopy = em->copy;
299                         break;
300                 }
301                 node = g_list_next( node );
302         }
303         return emailCopy;
304 }
305
306 /*
307  * Paste group into cache.
308  * Enter: cache    Address cache to paste into.
309  *        folder   Folder to store
310  *        group    Group to paste.
311  *        copyList List of email addresses pasted.
312  * Return: Group added.
313  */
314 static ItemGroup *addrclip_cache_add_group(
315         AddressCache *cache, ItemFolder *folder, ItemGroup *group,
316         GList *copyList )
317 {
318         ItemGroup *newGroup;
319         ItemEMail *emailOrig, *emailCopy;
320         GList *node;
321
322         /* Copy group */
323         newGroup = addritem_copy_item_group( group );
324         addrcache_id_group( cache, newGroup );
325         addrcache_folder_add_group( cache, folder, newGroup );
326
327         /* Add references of copied addresses to group */
328         node = group->listEMail;
329         while( node ) {
330                 emailOrig = ( ItemEMail * ) node->data;
331                 emailCopy = addrclip_find_copied_email( copyList, emailOrig );
332                 if( emailCopy ) {
333                         addrcache_group_add_email( cache, newGroup, emailCopy );
334                 }
335                 node = g_list_next( node );
336         }
337         return newGroup;
338 }
339
340 /*
341  * Copy specified folder into cache. Note this functions uses pointers to
342  * folders to copy from. There should not be any deleted items referenced
343  * by these pointers!!!
344  * Enter: cache        Address cache to copy into.
345  *        targetFolder Target folder.
346  *        folder       Folder to copy.
347  * Return: Folder added.
348  */
349 static ItemFolder *addrclip_cache_copy_folder(
350         AddressCache *cache, ItemFolder *targetFolder, ItemFolder *folder )
351 {
352         ItemFolder *newFolder;
353         ItemGroup *newGroup;
354         GList *node;
355         GList *copyList;
356
357         /* Copy folder */
358         newFolder = addritem_copy_item_folder( folder );
359         addrcache_id_folder( cache, newFolder );
360         addrcache_folder_add_folder( cache, targetFolder, newFolder );
361
362         /* Copy people to new folder */
363         copyList = NULL;
364         node = folder->listPerson;
365         while( node ) {
366                 ItemPerson *item = node->data;
367                 node = g_list_next( node );
368                 copyList = addrclip_cache_add_person(
369                                 cache, newFolder, item, copyList );
370         }
371
372         /* Copy groups to new folder */
373         node = folder->listGroup;
374         while( node ) {
375                 ItemGroup *item = node->data;
376                 node = g_list_next( node );
377                 newGroup = addrclip_cache_add_group(
378                                 cache, newFolder, item, copyList );
379         }
380         g_list_free( copyList );
381
382         /* Copy folders to new folder (recursive) */
383         node = folder->listFolder;
384         while( node ) {
385                 ItemFolder *item = node->data;
386                 node = g_list_next( node );
387                 addrclip_cache_copy_folder( cache, newFolder, item );
388         }
389
390         return newFolder;
391 }
392
393 /*
394 * Paste item list into address book.
395 * Enter: cache     Target address cache.
396 *        folder    Target folder where data is pasted.
397 *        itemList  List of items to paste.
398 *        clipBoard Clipboard.
399 * Return: List of group or folder items added.
400 */
401 static GList *addrclip_cache_add_folder(
402         AddressCache *cache, ItemFolder *folder, GList *itemList,
403         AddressClipboard *clipBoard )
404 {
405         GList *folderGroup;
406         GList *node;
407         AddrSelectItem *item;
408         AddrItemObject *aio;
409         AddressCache *cacheFrom;
410         gboolean haveGroups;
411         GList *copyList;
412
413         folderGroup = NULL;
414         copyList = NULL;
415         haveGroups = FALSE;
416         node = itemList;
417         while( node ) {
418                 item = node->data;
419                 node = g_list_next( node );
420
421                 cacheFrom = addrindex_get_cache(
422                                 clipBoard->addressIndex, item->cacheID );
423                 if( cacheFrom == NULL ) continue;
424                 if( item->uid ) {
425                         aio = addrcache_get_object( cacheFrom, item->uid );
426                         if( aio ) {
427                                 if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
428                                         ItemPerson *person;
429
430                                         person = ( ItemPerson * ) aio;
431                                         copyList = addrclip_cache_add_person(
432                                                 cache, folder, person, copyList );
433                                 }
434                                 /*
435                                 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
436                                 } 
437                                 */
438                                 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
439                                         haveGroups = TRUE;      /* Process later */
440                                 }
441                                 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
442                                         ItemFolder *itemFolder, *newFolder;
443
444                                         itemFolder = ( ItemFolder * ) aio;
445                                         newFolder = addrclip_cache_copy_folder(
446                                                         cache, folder, itemFolder );
447                                         folderGroup =
448                                                 g_list_append( folderGroup, newFolder );
449                                 }
450                         }
451                 }
452                 else {
453                         if( item->objectType == ITEMTYPE_DATASOURCE ) {
454                                 /*
455                                 * Must be an address book - allow copy only if
456                                 * copying from a different cache.
457                                 */
458                                 if( cache != cacheFrom ) {
459                                         ItemFolder *itemFolder, *newFolder;
460
461                                         itemFolder = cacheFrom->rootFolder;
462                                         newFolder = addrclip_cache_copy_folder(
463                                                 cache, folder, itemFolder );
464                                         addritem_folder_set_name( newFolder,
465                                                 addrcache_get_name( cacheFrom ) );
466                                         folderGroup =
467                                                 g_list_append( folderGroup, newFolder );
468                                 }
469                         }
470                 }
471         }
472
473         /* Finally add any groups */
474         if( haveGroups ) {
475                 node = itemList;
476                 while( node ) {
477                         item = node->data;
478                         node = g_list_next( node );
479                         cacheFrom = addrindex_get_cache(
480                                         clipBoard->addressIndex, item->cacheID );
481                         if( cacheFrom == NULL ) continue;
482                         aio = addrcache_get_object( cacheFrom, item->uid );
483                         if( aio ) {
484                                 if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
485                                         ItemGroup *group, *newGroup;
486
487                                         group = ( ItemGroup * ) aio;
488                                         newGroup = addrclip_cache_add_group(
489                                                 cache, folder, group, copyList );
490                                         folderGroup =
491                                                 g_list_append( folderGroup, newGroup );
492                                 }
493                         }
494                 }
495         }
496
497         /* Free up stuff */
498         addrclip_free_copy_list( copyList );
499         g_list_free( copyList );
500         copyList = NULL;
501
502         return folderGroup;
503 }
504
505 /*
506 * Move items in list into new folder
507 * Enter: cache        Target address cache.
508 *        targetFolder Target folder where data is pasted.
509 *        itemList     List of items to paste.
510 *        clipBoard    Clipboard.
511 * Return: List of group or folder items added.
512 */
513 static GList *addrclip_cache_move_items(
514         AddressCache *cache, ItemFolder *targetFolder, GList *itemList,
515         AddressClipboard *clipBoard )
516 {
517         GList *folderGroup;
518         GList *node;
519         AddrSelectItem *item;
520         AddrItemObject *aio;
521         AddressCache *cacheFrom;
522
523         folderGroup = NULL;
524         node = itemList;
525         while( node ) {
526                 item = node->data;
527                 node = g_list_next( node );
528                 cacheFrom = addrindex_get_cache(
529                                 clipBoard->addressIndex, item->cacheID );
530                 if( cacheFrom == NULL ) continue;
531                 aio = addrcache_get_object( cacheFrom, item->uid );
532                 if( aio ) {
533                         if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
534                                 ItemPerson *person;
535
536                                 person = ( ItemPerson * ) aio;
537                                 addrcache_folder_move_person(
538                                         cache, person, targetFolder );
539                         }
540                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
541                                 ItemGroup *group;
542
543                                 group = ( ItemGroup * ) aio;
544                                 addrcache_folder_move_group(
545                                         cache, group, targetFolder );
546                                 folderGroup = g_list_append( folderGroup, group );
547                         }
548                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
549                                 ItemFolder *folder;
550
551                                 folder = ( ItemFolder * ) aio;
552                                 addrcache_folder_move_folder(
553                                         cache, folder, targetFolder );
554                                 folderGroup =
555                                         g_list_append( folderGroup, folder );
556                         }
557                 }
558         }
559         return folderGroup;
560 }
561
562 /*
563 * Get address cache of first item in list. This assumes that all items in
564 * the clipboard are located in the same cache.
565 * Enter: clipBoard Clipboard.
566 * Return: List of group or folder items added.
567 */
568 static AddressCache *addrclip_list_get_cache( AddressClipboard *clipBoard ) {
569         AddressCache *cache;
570         GList *itemList;
571         AddrSelectItem *item;
572
573         cache = NULL;
574         itemList = clipBoard->objectList;
575         if( itemList ) {
576                 item = itemList->data;
577                 cache = addrindex_get_cache(
578                                 clipBoard->addressIndex, item->cacheID );
579         }
580         return cache;
581 }
582
583 /*
584 * Paste (copy) clipboard into address book.
585 * Enter: clipBoard Clipboard.
586 *        book      Target address book.
587 *        folder    Target folder where data is pasted, or null for root folder.
588 * Return: List of group or folder items added.
589 */
590 GList *addrclip_paste_copy(
591         AddressClipboard *clipBoard, AddressBookFile *book,
592         ItemFolder *folder )
593 {
594         AddressCache *cache;
595         GList *itemList;
596         GList *folderGroup;
597
598         g_return_val_if_fail( clipBoard != NULL, NULL );
599
600         cache = book->addressCache;
601         if( folder == NULL ) folder = cache->rootFolder;
602
603         folderGroup = NULL;
604         itemList = clipBoard->objectList;
605         folderGroup = addrclip_cache_add_folder(
606                         cache, folder, itemList, clipBoard );
607
608         return folderGroup;
609 }
610
611 /*
612 * Remove items that were cut from clipboard.
613 * Enter: clipBoard Clipboard.
614 */
615 void addrclip_delete_item( AddressClipboard *clipBoard ) {
616         AddrSelectItem *item;
617         AddrItemObject *aio;
618         AddressCache *cacheFrom;
619         GList *node;
620
621         /* If cutting within current cache, no deletion is necessary */
622         if( clipBoard->moveFlag ) return;
623
624         /* Remove groups */
625         node = clipBoard->objectList;
626         while( node ) {
627                 item = node->data;
628                 node = g_list_next( node );
629                 cacheFrom = addrindex_get_cache(
630                                 clipBoard->addressIndex, item->cacheID );
631                 if( cacheFrom == NULL ) continue;
632                 aio = addrcache_get_object( cacheFrom, item->uid );
633                 if( aio ) {
634                         if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
635                                 ItemGroup *group;
636
637                                 group = ( ItemGroup * ) aio;
638                                 group = addrcache_remove_group( cacheFrom, group );
639                                 if( group ) {
640                                         addritem_free_item_group( group );
641                                 }
642                         }
643                 }
644         }
645
646         /* Remove persons and folders */
647         node = clipBoard->objectList;
648         while( node ) {
649                 item = node->data;
650                 node = g_list_next( node );
651
652                 cacheFrom = addrindex_get_cache(
653                                 clipBoard->addressIndex, item->cacheID );
654                 if( cacheFrom == NULL ) continue;
655
656                 aio = addrcache_get_object( cacheFrom, item->uid );
657                 if( aio ) {
658                         if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
659                                 ItemPerson *person;
660
661                                 person = ( ItemPerson * ) aio;
662                                 person = addrcache_remove_person( cacheFrom, person );
663                                 if( person ) {
664                                         addritem_free_item_person( person );
665                                 }
666                         }
667                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
668                                 ItemFolder *itemFolder;
669
670                                 itemFolder = ( ItemFolder * ) aio;
671                                 itemFolder = addrcache_remove_folder_delete(
672                                                 cacheFrom, itemFolder );
673                                 addritem_free_item_folder( itemFolder );
674                         }
675                 }
676         }
677 }
678
679 /*
680 * Paste (move) clipboard into address book.
681 * Enter: clipBoard Clipboard.
682 *        book      Target address book.
683 *        folder    Target folder where data is pasted, or null for root folder.
684 * Return: List of group or folder items added.
685 */
686 GList *addrclip_paste_cut(
687         AddressClipboard *clipBoard, AddressBookFile *book,
688         ItemFolder *folder )
689 {
690         AddressCache *cache, *cacheFrom;
691         GList *itemList;
692         GList *folderGroup;
693
694         g_return_val_if_fail( clipBoard != NULL, NULL );
695
696         cache = book->addressCache;
697         if( folder == NULL ) folder = cache->rootFolder;
698
699         folderGroup = NULL;
700         clipBoard->moveFlag = FALSE;
701         cacheFrom = addrclip_list_get_cache( clipBoard );
702         if( cacheFrom && cacheFrom == cache ) {
703                 /* Move items between folders in same book */
704                 itemList = clipBoard->objectList;
705                 folderGroup = addrclip_cache_move_items(
706                                 cache, folder, itemList, clipBoard );
707                 clipBoard->moveFlag = TRUE;
708         }
709         else {
710                 /* Move items across address books */
711                 itemList = clipBoard->objectList;
712                 folderGroup = addrclip_cache_add_folder(
713                                 cache, folder, itemList, clipBoard );
714         }
715
716         return folderGroup;
717 }
718
719 /*
720  * ============================================================================
721  * Paste address only.
722  * ============================================================================
723  */
724
725 /*
726  * Copy email addresses from specified list.
727  * Enter: cache      Address cache to paste into.
728  *        target     Person to receive email addresses.
729  *        listEMail  List of email addresses.
730  * Return: Number of addresses added.
731  */
732 static gint addrclip_person_add_email(
733         AddressCache *cache, ItemPerson *target, GList *listEMail )
734 {
735         gint cnt;
736         GList *node;
737
738         /* Copy email addresses */
739         cnt = 0;
740         node = listEMail;
741         while( node ) {
742                 ItemEMail *email, *newEMail;
743
744                 email = node->data;
745                 newEMail = addritem_copy_item_email( email );
746                 addrcache_id_email( cache, newEMail );
747                 addrcache_person_add_email( cache, target, newEMail );
748                 node = g_list_next( node );
749                 cnt++;
750         }
751         return cnt;
752 }
753
754 /*
755 * Paste (copy) E-Mail addresses from clipboard into specified person.
756 * Enter: aio     Address item to copy from.
757 *        cache   Target address cache.
758 *        person  Target person where data is pasted.
759 * Return: Number of EMail records added.
760 */
761 static gint addrclip_copy_email_to_person(
762         AddrItemObject *aio, AddressCache *cache, ItemPerson *person )
763 {
764         gint cnt;
765         GList *listEMail;
766
767         cnt = 0;
768
769         if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
770                 ItemPerson *fromPerson;
771
772                 fromPerson = ( ItemPerson * ) aio;
773                 listEMail = fromPerson->listEMail;
774                 cnt += addrclip_person_add_email(
775                         cache, person, listEMail );
776         }
777         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
778                 ItemEMail *email, *newEMail;
779
780                 email = ( ItemEMail * ) aio;
781                 newEMail = addritem_copy_item_email( email );
782                 addrcache_id_email( cache, newEMail );
783                 addrcache_person_add_email( cache, person, newEMail );
784                 cnt++;
785         }
786         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
787                 ItemGroup *group;
788
789                 group = ( ItemGroup * ) aio;
790                 listEMail = group->listEMail;
791                 cnt += addrclip_person_add_email(
792                         cache, person, listEMail );
793         }
794         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
795                 ItemFolder *folder;
796                 AddrItemObject *item;
797                 GList *node;
798
799                 folder = ( ItemFolder * ) aio;
800                 node = folder->listPerson;
801                 while( node ) {
802                         item = node->data;
803                         node = g_list_next( node );
804                         cnt += addrclip_copy_email_to_person( item, cache, person );
805                 }
806
807                 node = folder->listGroup;
808                 while( node ) {
809                         item = node->data;
810                         node = g_list_next( node );
811                         cnt += addrclip_copy_email_to_person( item, cache, person );
812                 }
813
814                 node = folder->listFolder;
815                 while( node ) {
816                         item = node->data;
817                         node = g_list_next( node );
818                         cnt += addrclip_copy_email_to_person( item, cache, person );
819                 }
820         }
821         return cnt;
822 }
823
824 /*
825 * Paste (copy) E-Mail addresses from clipboard into specified person.
826 * Enter: clipBoard Clipboard.
827 *        cache     Target address cache.
828 *        person    Target person where data is pasted.
829 * Return: Number of EMail records added.
830 */
831 static gint addrclip_copyto_person(
832         AddressClipboard *clipBoard, AddressCache *cache, ItemPerson *person )
833 {
834         gint cnt;
835         GList *node;
836
837         cnt = 0;
838         node = clipBoard->objectList;
839         while( node ) {
840                 AddressCache *cacheFrom;
841                 AddrSelectItem *item;
842                 AddrItemObject *aio;
843
844                 item = node->data;
845                 node = g_list_next( node );
846                 cacheFrom = addrindex_get_cache(
847                                 clipBoard->addressIndex, item->cacheID );
848                 if( cacheFrom == NULL ) continue;
849                 aio = addrcache_get_object( cacheFrom, item->uid );
850                 if( aio ) {
851                         cnt += addrclip_copy_email_to_person( aio, cache, person );
852                 }
853         }
854         return cnt;
855 }
856
857 /*
858 * Paste (copy) E-Mail addresses from clipboard into specified person.
859 * Enter: clipBoard Clipboard.
860 *        book      Target address book.
861 *        person    Target person where data is pasted.
862 * Return: Number of EMail records added.
863 */
864 gint addrclip_paste_person_copy(
865         AddressClipboard *clipBoard, AddressBookFile *book,
866         ItemPerson *person )
867 {
868         gint cnt;
869         AddressCache *cache;
870
871         cnt = 0;
872         g_return_val_if_fail( clipBoard != NULL, cnt );
873
874         cache = book->addressCache;
875         if( person ) {
876                 cnt = addrclip_copyto_person( clipBoard, cache, person );
877         }
878         return cnt;
879 }
880
881 /*
882  * Move email addresses for specified person to target person.
883  * Enter: cache      Address cache to paste into.
884  *        fromPerson Person supplying email addresses.
885  *        target     Person to receive email addresses.
886  * Return: Number of addresses moved.
887  */
888 static gint addrclip_person_move_email(
889         AddressCache *cache, ItemPerson *fromPerson, ItemPerson *target )
890 {
891         gint cnt;
892         GList *node;
893
894         cnt = 0;
895         while( (node = fromPerson->listEMail) != NULL ) {
896                 ItemEMail *email;
897
898                 email = node->data;
899                 addrcache_person_move_email( cache, email, target );
900                 cnt++;
901         }
902         return cnt;
903 }
904
905 /*
906 * Paste (cut) E-Mail addresses from clipboard into specified person.
907 * Enter: clipBoard Clipboard.
908 *        cache     Target address cache.
909 *        person    Target person where data is pasted.
910 * Return: Number of EMail records added.
911 */
912 static gint addrclip_paste_person_move(
913         AddressClipboard *clipBoard, AddressCache *cache, ItemPerson *person )
914 {
915         gint cnt;
916         AddressCache *cacheFrom;
917         AddrSelectItem *item;
918         AddrItemObject *aio;
919         GList *node;
920         GList *listEMail;
921
922         cnt = 0;
923         node = clipBoard->objectList;
924         while( node ) {
925                 item = node->data;
926                 node = g_list_next( node );
927                 cacheFrom = addrindex_get_cache(
928                                 clipBoard->addressIndex, item->cacheID );
929                 if( cacheFrom == NULL ) continue;
930                 aio = addrcache_get_object( cacheFrom, item->uid );
931                 if( aio ) {
932                         if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
933                                 ItemPerson *fromPerson;
934
935                                 fromPerson = ( ItemPerson * ) aio;
936                                 cnt += addrclip_person_move_email(
937                                         cache, fromPerson, person );
938
939                                 if( addritem_person_empty( fromPerson ) ) {
940                                         fromPerson =
941                                                 addrcache_remove_person(
942                                                         cacheFrom, fromPerson );
943                                         if( fromPerson != NULL ) {
944                                                 addritem_free_item_person( fromPerson );
945                                         }
946                                 }
947                                 fromPerson = NULL;
948                         }
949                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
950                                 ItemEMail *email;
951
952                                 email = ( ItemEMail * ) aio;
953                                 addrcache_person_move_email(
954                                         cache, email, person );
955                                 cnt++;
956                         }
957                         else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
958                                 ItemGroup *group;
959
960                                 group = ( ItemGroup * ) aio;
961                                 listEMail = group->listEMail;
962                                 cnt += addrclip_person_add_email(
963                                         cache, person, listEMail );
964                         }
965                 }
966         }
967         return cnt;
968 }
969
970 /*
971 * Paste (cut) E-Mail addresses from clipboard into specified person.
972 * Enter: clipBoard Clipboard.
973 *        book      Target address book.
974 *        person    Target person where data is pasted.
975 * Return: Number of EMail records added.
976 */
977 gint addrclip_paste_person_cut(
978         AddressClipboard *clipBoard, AddressBookFile *book,
979         ItemPerson *person )
980 {
981         gint cnt;
982         AddressCache *cache, *cacheFrom;
983
984         cnt = 0;
985         g_return_val_if_fail( clipBoard != NULL, cnt );
986
987         cache = book->addressCache;
988         if( person ) {
989                 clipBoard->moveFlag = FALSE;
990                 cacheFrom = addrclip_list_get_cache( clipBoard );
991                 if( cacheFrom && cacheFrom == cache ) {
992                         cnt = addrclip_paste_person_move(
993                                 clipBoard, cache, person );
994                         clipBoard->moveFlag = TRUE;
995                 }
996                 else {
997                         /* Move items across address books */
998                         cnt = addrclip_copyto_person(
999                                 clipBoard, cache, person );
1000                 }
1001         }
1002         return cnt;
1003 }
1004
1005 /*
1006 * Remove address items that were cut from clipboard. Note that that only
1007 * E-Mail items are actually deleted. Any Person items will not be deleted
1008 * (not even E-Mail items that owned by a person). Any Group or Folder
1009 * items will *NOT* be deleted.
1010 * Enter: clipBoard Clipboard.
1011 */
1012 void addrclip_delete_address( AddressClipboard *clipBoard ) {
1013         AddrSelectItem *item;
1014         AddrItemObject *aio;
1015         AddressCache *cacheFrom;
1016         GList *node;
1017
1018         /* If cutting within current cache, no deletion is necessary */
1019         if( clipBoard->moveFlag ) return;
1020
1021         /* Remove groups */
1022         node = clipBoard->objectList;
1023         while( node ) {
1024                 item = node->data;
1025                 node = g_list_next( node );
1026                 cacheFrom = addrindex_get_cache(
1027                                 clipBoard->addressIndex, item->cacheID );
1028                 if( cacheFrom == NULL ) continue;
1029                 aio = addrcache_get_object( cacheFrom, item->uid );
1030                 if( aio ) {
1031                         if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
1032                                 ItemEMail *email;
1033                                 ItemPerson *person;
1034
1035                                 email = ( ItemEMail * ) aio;
1036                                 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1037                                 email = addrcache_person_remove_email(
1038                                                 cacheFrom, person, email );
1039                                 if( email ) {
1040                                         addritem_free_item_email( email );
1041                                 }
1042                         }
1043                 }
1044         }
1045 }
1046
1047 /*
1048 * End of Source.
1049 */
1050