1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2002-2012 Match Grun and the Claws Mail team
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 3 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, see <http://www.gnu.org/licenses/>.
17  *
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 #include <glib/gi18n.h>
51 
52 #include "addrcache.h"
53 #include "addrbook.h"
54 #include "addrselect.h"
55 #include "addrindex.h"
56 #include "addrclip.h"
57 #include "alertpanel.h"
58 #include "defs.h"
59 #include "file-utils.h"
60 
61 /*
62 * Create a clipboard.
63 */
addrclip_create(void)64 AddressClipboard *addrclip_create( void ) {
65 	AddressClipboard *clipBoard;
66 
67 	clipBoard = g_new0( AddressClipboard, 1 );
68 	clipBoard->cutFlag = FALSE;
69 	clipBoard->objectList = NULL;
70 	return clipBoard;
71 }
72 
73 /*
74 * Clear clipboard.
75 */
addrclip_clear(AddressClipboard * clipBoard)76 void addrclip_clear( AddressClipboard *clipBoard ) {
77 	GList *node;
78 	AddrSelectItem *item;
79 
80 	cm_return_if_fail( clipBoard != NULL );
81 	node = clipBoard->objectList;
82 	while( node ) {
83 		item = node->data;
84 		addrselect_item_free( item );
85 		node->data = NULL;
86 		node = g_list_next( node );
87 	}
88 	g_list_free( clipBoard->objectList );
89 	clipBoard->objectList = NULL;
90 }
91 
92 /*
93 * Free up a clipboard.
94 */
addrclip_free(AddressClipboard * clipBoard)95 void addrclip_free( AddressClipboard *clipBoard ) {
96 	cm_return_if_fail( clipBoard != NULL );
97 
98 	addrclip_clear( clipBoard );
99 	clipBoard->cutFlag = FALSE;
100 	g_free(clipBoard);
101 }
102 
103 /*
104 * Setup reference to address index.
105 */
addrclip_set_index(AddressClipboard * clipBoard,AddressIndex * addrIndex)106 void addrclip_set_index(
107 	AddressClipboard *clipBoard, AddressIndex *addrIndex )
108 {
109 	cm_return_if_fail( clipBoard != NULL );
110 	cm_return_if_fail( addrIndex != NULL );
111 	clipBoard->addressIndex = addrIndex;
112 }
113 
114 /*
115 * Test whether clipboard is empty.
116 * Enter: clipBoard Clipboard.
117 * Return: TRUE if clipboard is empty.
118 */
addrclip_is_empty(AddressClipboard * clipBoard)119 gboolean addrclip_is_empty( AddressClipboard *clipBoard ) {
120 	gboolean retVal = TRUE;
121 
122 	if( clipBoard ) {
123 		if( clipBoard->objectList ) retVal = FALSE;
124 	}
125 	return retVal;
126 }
127 
128 /*
129 * Add a list of address selection objects to clipbard.
130 * Enter: clipBoard Clipboard.
131 *        addrList  List of address selection objects.
132 */
addrclip_add(AddressClipboard * clipBoard,AddrSelectList * asl)133 void addrclip_add( AddressClipboard *clipBoard, AddrSelectList *asl ) {
134 	GList *node;
135 
136 	cm_return_if_fail( clipBoard != NULL );
137 	cm_return_if_fail( asl != NULL );
138 	node = asl->listSelect;
139 	while( node ) {
140 		AddrSelectItem *item, *itemCopy;
141 
142 		item = node->data;
143 		itemCopy = addrselect_item_copy( item );
144 		clipBoard->objectList =
145 			g_list_append( clipBoard->objectList, itemCopy );
146 		node = g_list_next( node );
147 	}
148 }
149 
150 /*
151 * Show clipboard contents.
152 * Enter: clipBoard Clipboard.
153 *        stream    Output stream.
154 */
addrclip_list_show(AddressClipboard * clipBoard,FILE * stream)155 void addrclip_list_show( AddressClipboard *clipBoard, FILE *stream ) {
156 	GList *node;
157 	AddrItemObject *aio;
158 	AddressCache *cache;
159 
160 	cm_return_if_fail( clipBoard != NULL );
161 	node = clipBoard->objectList;
162 	while( node != NULL ) {
163 		AddrSelectItem *item;
164 
165 		item = node->data;
166 		addrselect_item_print( item, stream );
167 
168 		cache = addrindex_get_cache( clipBoard->addressIndex, item->cacheID );
169 		aio = addrcache_get_object( cache, item->uid );
170 		if( aio ) {
171 			if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
172 				addritem_print_item_person( ( ItemPerson * ) aio, stream );
173 			}
174 			else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
175 				addritem_print_item_email( ( ItemEMail * ) aio, stream );
176 			}
177 			else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
178 				addritem_print_item_group( ( ItemGroup * ) aio, stream );
179 			}
180 			else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
181 				addritem_print_item_folder( ( ItemFolder * ) aio, stream );
182 			}
183 		}
184 		node = g_list_next( node );
185 	}
186 }
187 
188 /* Pasted address pointers */
189 typedef struct _AddrClip_EMail_ AddrClip_EMail;
190 struct _AddrClip_EMail_ {
191 	ItemEMail *original;
192 	ItemEMail *copy;
193 };
194 
195 /*
196  * Free up specified list of addresses.
197  */
addrclip_free_copy_list(GList * copyList)198 static void addrclip_free_copy_list( GList *copyList ) {
199 	GList *node;
200 
201 	node = copyList;
202 	while( node ) {
203 		AddrClip_EMail *em = node->data;
204 		em->original = NULL;
205 		em->copy = NULL;
206 		g_free( em );
207 		em = NULL;
208 		node = g_list_next( node );
209 	}
210 }
211 
212 /*
213  * Paste person into cache.
214  * Enter: cache    Address cache to paste into.
215  *        folder   Folder to store
216  *        person   Person to paste.
217  *        copyLIst List of email addresses pasted.
218  * Return: Update list of email addresses pasted.
219  */
addrclip_cache_add_person(AddressCache * cache,ItemFolder * folder,ItemPerson * person,GList * copyList)220 static GList *addrclip_cache_add_person(
221 	AddressCache *cache, ItemFolder *folder, ItemPerson *person,
222 	GList *copyList )
223 {
224 	ItemPerson *newPerson;
225 	ItemEMail *email;
226 	ItemEMail *newEMail;
227 	UserAttribute *attrib;
228 	UserAttribute *newAttrib;
229 	GList *node;
230 	AddrClip_EMail *em;
231 
232 	/* Copy person */
233 	newPerson = addritem_copy_item_person( person );
234 	addrcache_id_person( cache, newPerson );
235 	addrcache_folder_add_person( cache, folder, newPerson );
236 
237 	/* Copy email addresses */
238 	node = person->listEMail;
239 	while( node ) {
240 		email = node->data;
241 		newEMail = addritem_copy_item_email( email );
242 		addrcache_id_email( cache, newEMail );
243 		addrcache_person_add_email( cache, newPerson, newEMail );
244 		node = g_list_next( node );
245 
246 		/* Take a copy of the original */
247 		em = g_new0( AddrClip_EMail, 1 );
248 		em->original = email;
249 		em->copy = newEMail;
250 		copyList = g_list_append( copyList, em );
251 	}
252 
253 	/* Copy user attributes */
254 	node = person->listAttrib;
255 	while( node ) {
256 		attrib = node->data;
257 		newAttrib = addritem_copy_attribute( attrib );
258 		addrcache_id_attribute( cache, newAttrib );
259 		addritem_person_add_attribute( newPerson, newAttrib );
260 		node = g_list_next( node );
261 	}
262 
263 	/* Set picture name and create picture file (from copy) if missing */
264 	addritem_person_set_picture(newPerson, ADDRITEM_ID(newPerson));
265 	if( strcmp(ADDRITEM_ID(newPerson), ADDRITEM_ID(person)) ) {
266 		gchar *pictureFile;
267 		gchar *newPictureFile;
268 
269 		pictureFile = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S,
270 							person->picture, ".png", NULL );
271 		newPictureFile = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S,
272 							newPerson->picture, ".png", NULL );
273 		if (file_exist(pictureFile, FALSE) && !file_exist(newPictureFile, FALSE)) {
274 			debug_print("copying contact picture file: %s -> %s\n", person->picture, newPerson->picture);
275 			copy_file(pictureFile, newPictureFile, FALSE);
276 		}
277 		g_free( pictureFile );
278 		g_free( newPictureFile );
279 	}
280 
281 	return copyList;
282 }
283 
284 /*
285  * Search for new email record in copied email list.
286  * Enter: copyList  List of copied email address mappings.
287  *        emailOrig Original email item.
288  * Return: New email item corresponding to original item if pasted. Or NULL if
289  *         not found.
290  */
addrclip_find_copied_email(GList * copyList,ItemEMail * emailOrig)291 static ItemEMail *addrclip_find_copied_email(
292 	GList *copyList, ItemEMail *emailOrig )
293 {
294 	ItemEMail *emailCopy;
295 	GList *node;
296 	AddrClip_EMail *em;
297 
298 	emailCopy = NULL;
299 	node = copyList;
300 	while( node ) {
301 		em = node->data;
302 		if( em->original == emailOrig ) {
303 			emailCopy = em->copy;
304 			break;
305 		}
306 		node = g_list_next( node );
307 	}
308 	return emailCopy;
309 }
310 
311 /*
312  * Paste group into cache.
313  * Enter: cache    Address cache to paste into.
314  *        folder   Folder to store
315  *        group    Group to paste.
316  *        copyList List of email addresses pasted.
317  * Return: Group added.
318  */
addrclip_cache_add_group(AddressCache * cache,ItemFolder * folder,ItemGroup * group,GList * copyList)319 static ItemGroup *addrclip_cache_add_group(
320 	AddressCache *cache, ItemFolder *folder, ItemGroup *group,
321 	GList *copyList )
322 {
323 	ItemGroup *newGroup;
324 	ItemEMail *emailOrig, *emailCopy;
325 	GList *node;
326 
327 	/* Copy group */
328 	newGroup = addritem_copy_item_group( group );
329 	addrcache_id_group( cache, newGroup );
330 	addrcache_folder_add_group( cache, folder, newGroup );
331 
332 	/* Add references of copied addresses to group */
333 	node = group->listEMail;
334 	while( node ) {
335 		emailOrig = ( ItemEMail * ) node->data;
336 		emailCopy = addrclip_find_copied_email( copyList, emailOrig );
337 		if( emailCopy ) {
338 			addrcache_group_add_email( cache, newGroup, emailCopy );
339 		}
340 		node = g_list_next( node );
341 	}
342 	return newGroup;
343 }
344 
345 /*
346  * Copy specified folder into cache. Note this functions uses pointers to
347  * folders to copy from. There should not be any deleted items referenced
348  * by these pointers!!!
349  * Enter: cache        Address cache to copy into.
350  *        targetFolder Target folder.
351  *        folder       Folder to copy.
352  * Return: Folder added.
353  */
addrclip_cache_copy_folder(AddressCache * cache,ItemFolder * targetFolder,ItemFolder * folder)354 static ItemFolder *addrclip_cache_copy_folder(
355 	AddressCache *cache, ItemFolder *targetFolder, ItemFolder *folder )
356 {
357 	ItemFolder *newFolder;
358 	ItemGroup *newGroup;
359 	GList *node;
360 	GList *copyList;
361 
362 	/* Copy folder */
363 	newFolder = addritem_copy_item_folder( folder );
364 	addrcache_id_folder( cache, newFolder );
365 	addrcache_folder_add_folder( cache, targetFolder, newFolder );
366 
367 	/* Copy people to new folder */
368 	copyList = NULL;
369 	node = folder->listPerson;
370 	while( node ) {
371 		ItemPerson *item = node->data;
372 		node = g_list_next( node );
373 		copyList = addrclip_cache_add_person(
374 				cache, newFolder, item, copyList );
375 	}
376 
377 	/* Copy groups to new folder */
378 	node = folder->listGroup;
379 	while( node ) {
380 		ItemGroup *item = node->data;
381 		node = g_list_next( node );
382 		newGroup = addrclip_cache_add_group(
383 				cache, newFolder, item, copyList );
384 		if (newGroup == NULL) {
385 			g_message("error allocating memory for new group\n");
386 		}
387 	}
388 	g_list_free( copyList );
389 
390 	/* Copy folders to new folder (recursive) */
391 	node = folder->listFolder;
392 	while( node ) {
393 		ItemFolder *item = node->data;
394 		node = g_list_next( node );
395 		addrclip_cache_copy_folder( cache, newFolder, item );
396 	}
397 
398 	return newFolder;
399 }
400 
addrclip_is_subfolder_of(ItemFolder * is_parent,ItemFolder * is_child)401 static gboolean addrclip_is_subfolder_of(ItemFolder *is_parent, ItemFolder *is_child)
402 {
403 	ItemFolder *folder;
404 	AddrItemObject *obj;
405 
406 	cm_return_val_if_fail(is_parent != NULL, FALSE);
407 	cm_return_val_if_fail(is_child != NULL, FALSE);
408 
409 	if (is_parent == is_child)
410 		return TRUE;
411 
412 	folder = is_child;
413 	obj = folder->obj.parent;
414 	while (obj) {
415 		if ((void*)obj == (void*)is_parent)
416 			return TRUE;
417 		obj = obj->parent;
418 	}
419 	return FALSE;
420 }
421 
422 /*
423 * Paste item list into address book.
424 * Enter: cache     Target address cache.
425 *        folder    Target folder where data is pasted.
426 *        itemList  List of items to paste.
427 *        clipBoard Clipboard.
428 * Return: List of group or folder items added.
429 */
addrclip_cache_add_folder(AddressCache * cache,ItemFolder * folder,GList * itemList,AddressClipboard * clipBoard)430 static GList *addrclip_cache_add_folder(
431 	AddressCache *cache, ItemFolder *folder, GList *itemList,
432 	AddressClipboard *clipBoard )
433 {
434 	GList *folderGroup;
435 	GList *node;
436 	AddrSelectItem *item;
437 	AddrItemObject *aio;
438 	AddressCache *cacheFrom;
439 	gboolean haveGroups;
440 	GList *copyList;
441 
442 	folderGroup = NULL;
443 	copyList = NULL;
444 	haveGroups = FALSE;
445 	node = itemList;
446 	while( node ) {
447 		item = node->data;
448 		node = g_list_next( node );
449 
450 		cacheFrom = addrindex_get_cache(
451 				clipBoard->addressIndex, item->cacheID );
452 		if( cacheFrom == NULL ) continue;
453 		if( item->uid ) {
454 			aio = addrcache_get_object( cacheFrom, item->uid );
455 			if( aio ) {
456 				if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
457 					ItemPerson *person;
458 
459 					person = ( ItemPerson * ) aio;
460 					copyList = addrclip_cache_add_person(
461 						cache, folder, person, copyList );
462 				}
463 				/*
464 				else if( ADDRITEM_TYPE(aio) == ITEMTYPE_EMAIL ) {
465 				}
466 				*/
467 				else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
468 					haveGroups = TRUE;	/* Process later */
469 				}
470 				else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
471 					ItemFolder *itemFolder, *newFolder;
472 
473 					itemFolder = ( ItemFolder * ) aio;
474 					if (!addrclip_is_subfolder_of(itemFolder, folder)) {
475 						newFolder = addrclip_cache_copy_folder(
476 								cache, folder, itemFolder );
477 						folderGroup =
478 							g_list_append( folderGroup, newFolder );
479 					} else {
480 						alertpanel_error(
481 							_("Cannot copy a folder to itself or to its sub-structure.") );
482 					}
483 				}
484 			}
485 		}
486 		else {
487 			if( item->objectType == ITEMTYPE_DATASOURCE ) {
488 				/*
489 				* Must be an address book - allow copy only if
490 				* copying from a different cache.
491 				*/
492 				if( cache != cacheFrom ) {
493 					ItemFolder *itemFolder, *newFolder;
494 
495 					itemFolder = cacheFrom->rootFolder;
496 					newFolder = addrclip_cache_copy_folder(
497 						cache, folder, itemFolder );
498 					addritem_folder_set_name( newFolder,
499 						addrcache_get_name( cacheFrom ) );
500 					folderGroup =
501 						g_list_append( folderGroup, newFolder );
502 				} else {
503 					alertpanel_error(
504 						_("Cannot copy an address book to itself.") );
505 				}
506 			}
507 		}
508 	}
509 
510 	/* Finally add any groups */
511 	if( haveGroups ) {
512 		node = itemList;
513 		while( node ) {
514 			item = node->data;
515 			node = g_list_next( node );
516 			cacheFrom = addrindex_get_cache(
517 					clipBoard->addressIndex, item->cacheID );
518 			if( cacheFrom == NULL ) continue;
519 			aio = addrcache_get_object( cacheFrom, item->uid );
520 			if( aio ) {
521 				if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
522 					ItemGroup *group, *newGroup;
523 
524 					group = ( ItemGroup * ) aio;
525 					newGroup = addrclip_cache_add_group(
526 						cache, folder, group, copyList );
527 					folderGroup =
528 						g_list_append( folderGroup, newGroup );
529 				}
530 			}
531 		}
532 	}
533 
534 	/* Free up stuff */
535 	addrclip_free_copy_list( copyList );
536 	g_list_free( copyList );
537 	copyList = NULL;
538 
539 	return folderGroup;
540 }
541 
542 /*
543 * Move items in list into new folder
544 * Enter: cache        Target address cache.
545 *        targetFolder Target folder where data is pasted.
546 *        itemList     List of items to paste.
547 *        clipBoard    Clipboard.
548 * Return: List of group or folder items added.
549 */
addrclip_cache_move_items(AddressCache * cache,ItemFolder * targetFolder,GList * itemList,AddressClipboard * clipBoard)550 static GList *addrclip_cache_move_items(
551 	AddressCache *cache, ItemFolder *targetFolder, GList *itemList,
552 	AddressClipboard *clipBoard )
553 {
554 	GList *folderGroup;
555 	GList *node;
556 	AddrSelectItem *item;
557 	AddrItemObject *aio;
558 	AddressCache *cacheFrom;
559 
560 	folderGroup = NULL;
561 	node = itemList;
562 	while( node ) {
563 		item = node->data;
564 		node = g_list_next( node );
565 		cacheFrom = addrindex_get_cache(
566 				clipBoard->addressIndex, item->cacheID );
567 		if( cacheFrom == NULL ) continue;
568 		aio = addrcache_get_object( cacheFrom, item->uid );
569 		if( aio ) {
570 			if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
571 				ItemPerson *person;
572 
573 				person = ( ItemPerson * ) aio;
574 				addrcache_folder_move_person(
575 					cache, person, targetFolder );
576 			}
577 			else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
578 				ItemGroup *group;
579 
580 				group = ( ItemGroup * ) aio;
581 				addrcache_folder_move_group(
582 					cache, group, targetFolder );
583 				folderGroup = g_list_append( folderGroup, group );
584 			}
585 			else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
586 				ItemFolder *folder = ( ItemFolder * ) aio;
587 
588 				if (!addrclip_is_subfolder_of(folder, targetFolder)) {
589 					addrcache_folder_move_folder(
590 						cache, folder, targetFolder );
591 					folderGroup =
592 						g_list_append( folderGroup, folder );
593 				} else {
594 					alertpanel_error(
595 						_("Cannot move a folder to itself or to its sub-structure.") );
596 				}
597 			}
598 		}
599 	}
600 	return folderGroup;
601 }
602 
603 /*
604 * Get address cache of first item in list. This assumes that all items in
605 * the clipboard are located in the same cache.
606 * Enter: clipBoard Clipboard.
607 * Return: List of group or folder items added.
608 */
addrclip_list_get_cache(AddressClipboard * clipBoard)609 static AddressCache *addrclip_list_get_cache( AddressClipboard *clipBoard ) {
610 	AddressCache *cache;
611 	GList *itemList;
612 	AddrSelectItem *item;
613 
614 	cache = NULL;
615 	itemList = clipBoard->objectList;
616 	if( itemList ) {
617 		item = itemList->data;
618 		cache = addrindex_get_cache(
619 				clipBoard->addressIndex, item->cacheID );
620 	}
621 	return cache;
622 }
623 
624 /*
625 * Paste (copy) clipboard into address book.
626 * Enter: clipBoard Clipboard.
627 *        book      Target address book.
628 *        folder    Target folder where data is pasted, or null for root folder.
629 * Return: List of group or folder items added.
630 */
addrclip_paste_copy(AddressClipboard * clipBoard,AddressBookFile * book,ItemFolder * folder)631 GList *addrclip_paste_copy(
632 	AddressClipboard *clipBoard, AddressBookFile *book,
633 	ItemFolder *folder )
634 {
635 	AddressCache *cache;
636 	GList *itemList;
637 	GList *folderGroup;
638 
639 	cm_return_val_if_fail( clipBoard != NULL, NULL );
640 
641 	cache = book->addressCache;
642 	if( folder == NULL ) folder = cache->rootFolder;
643 
644 	folderGroup = NULL;
645 	itemList = clipBoard->objectList;
646 	folderGroup = addrclip_cache_add_folder(
647 			cache, folder, itemList, clipBoard );
648 
649 	return folderGroup;
650 }
651 
652 /*
653 * Remove items that were cut from clipboard.
654 * Enter: clipBoard Clipboard.
655 */
addrclip_delete_item(AddressClipboard * clipBoard)656 void addrclip_delete_item( AddressClipboard *clipBoard ) {
657 	AddrSelectItem *item;
658 	AddrItemObject *aio;
659 	AddressCache *cacheFrom;
660 	GList *node;
661 
662 	/* If cutting within current cache, no deletion is necessary */
663 	if( clipBoard->moveFlag ) return;
664 
665 	/* Remove groups */
666 	node = clipBoard->objectList;
667 	while( node ) {
668 		item = node->data;
669 		node = g_list_next( node );
670 		cacheFrom = addrindex_get_cache(
671 				clipBoard->addressIndex, item->cacheID );
672 		if( cacheFrom == NULL ) continue;
673 		aio = addrcache_get_object( cacheFrom, item->uid );
674 		if( aio ) {
675 			if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
676 				ItemGroup *group;
677 
678 				group = ( ItemGroup * ) aio;
679 				group = addrcache_remove_group( cacheFrom, group );
680 				if( group ) {
681 					addritem_free_item_group( group );
682 				}
683 			}
684 		}
685 	}
686 
687 	/* Remove persons and folders */
688 	node = clipBoard->objectList;
689 	while( node ) {
690 		item = node->data;
691 		node = g_list_next( node );
692 
693 		cacheFrom = addrindex_get_cache(
694 				clipBoard->addressIndex, item->cacheID );
695 		if( cacheFrom == NULL ) continue;
696 
697 		aio = addrcache_get_object( cacheFrom, item->uid );
698 		if( aio ) {
699 			if( ADDRITEM_TYPE(aio) == ITEMTYPE_PERSON ) {
700 				ItemPerson *person;
701 
702 				person = ( ItemPerson * ) aio;
703 				person = addrcache_remove_person( cacheFrom, person );
704 				if( person ) {
705 					addritem_free_item_person( person );
706 				}
707 			}
708 			else if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
709 				ItemFolder *itemFolder;
710 
711 				itemFolder = ( ItemFolder * ) aio;
712 				itemFolder = addrcache_remove_folder_delete(
713 						cacheFrom, itemFolder );
714 				addritem_free_item_folder( itemFolder );
715 			}
716 		}
717 	}
718 }
719 
720 /*
721 * Paste (move) clipboard into address book.
722 * Enter: clipBoard Clipboard.
723 *        book      Target address book.
724 *        folder    Target folder where data is pasted, or null for root folder.
725 * Return: List of group or folder items added.
726 */
addrclip_paste_cut(AddressClipboard * clipBoard,AddressBookFile * book,ItemFolder * folder)727 GList *addrclip_paste_cut(
728 	AddressClipboard *clipBoard, AddressBookFile *book,
729 	ItemFolder *folder )
730 {
731 	AddressCache *cache, *cacheFrom;
732 	GList *itemList;
733 	GList *folderGroup;
734 
735 	cm_return_val_if_fail( clipBoard != NULL, NULL );
736 
737 	cache = book->addressCache;
738 	if( folder == NULL ) folder = cache->rootFolder;
739 
740 	folderGroup = NULL;
741 	clipBoard->moveFlag = FALSE;
742 	cacheFrom = addrclip_list_get_cache( clipBoard );
743 	if( cacheFrom && cacheFrom == cache ) {
744 		/* Move items between folders in same book */
745 		itemList = clipBoard->objectList;
746 		folderGroup = addrclip_cache_move_items(
747 				cache, folder, itemList, clipBoard );
748 		clipBoard->moveFlag = TRUE;
749 	}
750 	else {
751 		/* Move items across address books */
752 		itemList = clipBoard->objectList;
753 		folderGroup = addrclip_cache_add_folder(
754 				cache, folder, itemList, clipBoard );
755 	}
756 
757 	return folderGroup;
758 }
759 /*
760 * End of Source.
761 */
762 
763