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