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