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