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