76649175b85cb8d5532df2bbdc96ec1350877f42
[claws.git] / src / addritem.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2007 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 /*
21  * General primitive address item objects.
22  */
23
24 #include <glib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "utils.h"
29 #include "addritem.h"
30 #include "mgutils.h"
31 #include "codeconv.h"
32
33 /**
34  * Create new email address item.
35  * \return Initialized email item.
36  */
37 ItemEMail *addritem_create_item_email( void ) {
38         ItemEMail *item;
39         item = g_new0( ItemEMail, 1 );
40         ADDRITEM_TYPE(item) = ITEMTYPE_EMAIL;
41         ADDRITEM_ID(item) = NULL;
42         ADDRITEM_NAME(item) = NULL;
43         ADDRITEM_PARENT(item) = NULL;
44         ADDRITEM_SUBTYPE(item) = 0;
45         item->address = NULL;
46         item->remarks = NULL;
47         return item;
48 }
49
50 /**
51  * Create a shallow copy of specified email address item.
52  * \param  item E-Mail to copy.
53  * \return Copy of email, or <i>NULL</i> if null argument supplied.
54  */
55 ItemEMail *addritem_copy_item_email( ItemEMail *item ) {
56         ItemEMail *itemNew = NULL;
57         if( item ) {
58                 itemNew = addritem_create_item_email();
59                 ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
60                 itemNew->address = g_strdup( item->address );
61                 itemNew->remarks = g_strdup( item->remarks );
62         }
63         return itemNew;
64 }
65
66 /**
67  * Create a full copy (deep copy) of specified email address item.
68  * \param  item E-Mail to copy.
69  * \return Copy of email.
70  */
71 ItemEMail *addritem_copyfull_item_email( ItemEMail *item ) {
72         ItemEMail *itemNew = NULL;
73         if( item ) {
74                 itemNew = addritem_create_item_email();
75                 ADDRITEM_ID(itemNew) = g_strdup( ADDRITEM_ID(item) );
76                 ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
77                 ADDRITEM_PARENT(itemNew) = ADDRITEM_PARENT(item);
78                 itemNew->address = g_strdup( item->address );
79                 itemNew->remarks = g_strdup( item->remarks );
80         }
81         return itemNew;
82 }
83
84 /**
85  * Specify ID for email.
86  * \param email E-Mail item.
87  * \param value ID.
88  */
89 void addritem_email_set_id( ItemEMail *email, const gchar *value ) {
90         ADDRITEM_ID(email) = mgu_replace_string( ADDRITEM_ID(email), value );
91 }
92
93 /**
94  * Specify alias for email.
95  * \param email E-Mail item.
96  * \param value Alias.
97  */
98 void addritem_email_set_alias( ItemEMail *email, const gchar *value ) {
99         ADDRITEM_NAME(email) = mgu_replace_string( ADDRITEM_NAME(email), value );
100 }
101
102 /**
103  * Specify address for email.
104  * \param email E-Mail item.
105  * \param value Address.
106  */
107 void addritem_email_set_address( ItemEMail *email, const gchar *value ) {
108         email->address = mgu_replace_string( email->address, value );
109 }
110
111 /**
112  * Specify remarks for email.
113  * \param email E-Mail item.
114  * \param value Remarks.
115  */
116 void addritem_email_set_remarks( ItemEMail *email, const gchar *value ) {
117         email->remarks = mgu_replace_string( email->remarks, value );
118 }
119
120 /**
121  * Free address item email object.
122  * \param item E-Mail item to free.
123  */
124 void addritem_free_item_email( ItemEMail *item ) {
125         g_return_if_fail( item != NULL );
126
127         /* Free internal stuff */
128         g_free( ADDRITEM_ID(item) );
129         g_free( ADDRITEM_NAME(item) );
130         g_free( item->address );
131         g_free( item->remarks );
132
133         ADDRITEM_OBJECT(item)->type = ITEMTYPE_NONE;
134         ADDRITEM_ID(item) = NULL;
135         ADDRITEM_NAME(item) = NULL;
136         ADDRITEM_PARENT(item) = NULL;
137         ADDRITEM_SUBTYPE(item) = 0;
138         item->address = NULL;
139         item->remarks = NULL;
140         g_free( item );
141 }
142
143 /**
144  * Create new attribute object.
145  * \return Initialized attribute object.
146  */
147 UserAttribute *addritem_create_attribute( void ) {
148         UserAttribute *item;
149         item = g_new0( UserAttribute, 1 );
150         item->uid = NULL;
151         item->name = NULL;
152         item->value = NULL;
153         return item;
154 }
155
156 /**
157  * Create copy (deep copy) of specified attribute.
158  * \param  item Attribute to copy.
159  * \return Copy of attribute, or <i>NULL</i> if null argument supplied.
160  */
161 UserAttribute *addritem_copy_attribute( UserAttribute *item ) {
162         UserAttribute *itemNew = NULL;
163         if( item ) {
164                 itemNew = addritem_create_attribute();
165                 itemNew->uid = g_strdup( item->uid );
166                 itemNew->name = g_strdup( item->name );
167                 itemNew->value = g_strdup( item->value );
168         }
169         return itemNew;
170 }
171
172 /**
173  * Specify ID for attribute.
174  * \param item Attribute object.
175  * \param value ID.
176  */
177 void addritem_attrib_set_id( UserAttribute *item, const gchar *value ) {
178         g_return_if_fail( item != NULL );
179         item->uid = mgu_replace_string( item->uid, value );
180 }
181
182 /**
183  * Specify name for attribute.
184  * \param item Attribute object.
185  * \param value Name.
186  */
187 void addritem_attrib_set_name( UserAttribute *item, const gchar *value ) {
188         g_return_if_fail( item != NULL );
189         item->name = mgu_replace_string( item->name, value );
190 }
191
192 /**
193  * Specify value for attribute.
194  * \param item Attribute object.
195  * \param value Value.
196  */
197 void addritem_attrib_set_value( UserAttribute *item, const gchar *value ) {
198         g_return_if_fail( item != NULL );
199         item->value = mgu_replace_string( item->value, value );
200 }
201
202 /**
203  * Free user attribute.
204  * \param item Attribute object to free.
205  */
206 void addritem_free_attribute( UserAttribute *item ) {
207         g_return_if_fail( item != NULL );
208         g_free( item->uid );
209         g_free( item->name );
210         g_free( item->value );
211         item->uid = NULL;
212         item->name = NULL;
213         item->value = NULL;
214         g_free( item );
215 }
216
217 /**
218  * Create new address book person.
219  * \return Initialized person object.
220  */
221 ItemPerson *addritem_create_item_person( void ) {
222         ItemPerson *person;
223         person = g_new0( ItemPerson, 1 );
224         ADDRITEM_TYPE(person) = ITEMTYPE_PERSON;
225         ADDRITEM_ID(person) = NULL;
226         ADDRITEM_NAME(person) = NULL;
227         ADDRITEM_PARENT(person) = NULL;
228         ADDRITEM_SUBTYPE(person) = 0;
229         person->firstName = NULL;
230         person->lastName = NULL;
231         person->nickName = NULL;
232         person->listEMail = NULL;
233         person->listAttrib = NULL;
234         person->externalID = NULL;
235         person->isOpened = FALSE;
236         return person;
237 }
238
239 /**
240  * Create a shallow copy of address book person object.
241  * \param  item Person to copy.
242  * \return Copy of person, or <i>NULL</i> if null argument supplied.
243  */
244 ItemPerson *addritem_copy_item_person( ItemPerson *item ) {
245         ItemPerson *itemNew;
246
247         itemNew = NULL;
248         if( item ) {
249                 itemNew = addritem_create_item_person();
250                 ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
251                 itemNew->firstName = g_strdup( item->firstName );
252                 itemNew->lastName = g_strdup( item->lastName );
253                 itemNew->nickName = g_strdup( item->nickName );
254                 itemNew->externalID = g_strdup( item->externalID );
255         }
256         return itemNew;
257 }
258
259 /**
260  * Specify ID for person object.
261  * \param person Person object.
262  * \param value ID.
263  */
264 void addritem_person_set_id( ItemPerson *person, const gchar *value ) {
265         ADDRITEM_ID(person) = mgu_replace_string( ADDRITEM_ID(person), value );
266 }
267
268 /**
269  * Specify first name for person object.
270  * \param person Person object.
271  * \param value Name.
272  */
273 void addritem_person_set_first_name( ItemPerson *person, const gchar *value ) {
274         if (!value || g_utf8_validate(value, -1, NULL))
275                 person->firstName = mgu_replace_string( person->firstName, value );
276         else {
277                 gchar *out = conv_codeset_strdup(value, 
278                                 conv_get_locale_charset_str_no_utf8(),
279                                 CS_INTERNAL);
280                 if (out)
281                         person->firstName = mgu_replace_string( person->firstName, out );
282                 g_free(out);
283         }
284 }
285
286 /**
287  * Specify last name for person object.
288  * \param person Person object.
289  * \param value name.
290  */
291 void addritem_person_set_last_name( ItemPerson *person, const gchar *value ) {
292         if (!value || g_utf8_validate(value, -1, NULL))
293                 person->lastName = mgu_replace_string( person->lastName, value );
294         else {
295                 gchar *out = conv_codeset_strdup(value, 
296                                 conv_get_locale_charset_str_no_utf8(),
297                                 CS_INTERNAL);
298                 if (out)
299                         person->lastName = mgu_replace_string( person->lastName, out );
300                 g_free(out);
301         }
302 }
303
304 /**
305  * Specify nick name for person object.
306  * \param person Person object.
307  * \param value name.
308  */
309 void addritem_person_set_nick_name( ItemPerson *person, const gchar *value ) {
310         if (!value || g_utf8_validate(value, -1, NULL))
311                 person->nickName = mgu_replace_string( person->nickName, value );
312         else {
313                 gchar *out = conv_codeset_strdup(value, 
314                                 conv_get_locale_charset_str_no_utf8(),
315                                 CS_INTERNAL);
316                 if (out)
317                         person->nickName = mgu_replace_string( person->nickName, out );
318                 g_free(out);
319         }
320 }
321
322 /**
323  * Specify common name for person object.
324  * \param person Person object.
325  * \param value name.
326  */
327 void addritem_person_set_common_name( ItemPerson *person, const gchar *value ) {
328         if (!value || g_utf8_validate(value, -1, NULL))
329                 ADDRITEM_NAME(person) = mgu_replace_string( ADDRITEM_NAME(person), value );
330         else {
331                 gchar *out = conv_codeset_strdup(value, 
332                                 conv_get_locale_charset_str_no_utf8(),
333                                 CS_INTERNAL);
334                 if (out)
335                         ADDRITEM_NAME(person) = mgu_replace_string( ADDRITEM_NAME(person), out );
336                 g_free(out);
337         }
338 }
339
340 /**
341  * Specify external ID for person object.
342  * \param person Person object.
343  * \param value ID.
344  */
345 void addritem_person_set_external_id( ItemPerson *person, const gchar *value ) {
346         person->externalID = mgu_replace_string( person->externalID, value );
347 }
348
349 /**
350  * Specify value of open indicator for person object. This is typically used to
351  * simplify open/close folders in the address book GUI.
352  * \param person Person object.
353  * \param value  Value for indicator. Set to <i>TRUE</i> if opened.
354  */
355 void addritem_person_set_opened( ItemPerson *person, const gboolean value ) {
356         person->isOpened = value;
357 }
358
359 /**
360  * Test whether person's data is empty.
361  * \param  person Person to test.
362  * \return <i>TRUE</i> if empty.
363  */
364 gboolean addritem_person_empty( ItemPerson *person ) {
365         gchar *t;
366
367         if( person == NULL ) return FALSE;
368
369         t = ADDRITEM_NAME(person);
370         if( t != NULL && strlen( t ) > 0 ) return FALSE;
371
372         t = person->firstName;
373         if( t != NULL && strlen( t ) > 0 ) return FALSE;
374
375         t = person->lastName;
376         if( t != NULL && strlen( t ) > 0 ) return FALSE;
377
378         t = person->nickName;
379         if( t != NULL && strlen( t ) > 0 ) return FALSE;
380
381         if( person->listEMail  != NULL ) return FALSE;
382         if( person->listAttrib != NULL ) return FALSE;
383
384         return TRUE;
385 }
386
387 /**
388  * Free linked list of item addresses; both addresses and the list are freed.
389  * It is assumed that addresses are *NOT* contained within some other
390  * container.
391  * \param list List of addresses to be freed.
392  */
393 void addritem_free_list_email( GList *list ) {
394         GList *node = list;
395         while( node ) {
396                 ItemEMail *email = node->data;
397
398                 addritem_free_item_email( email );
399                 node->data = NULL;
400                 node = g_list_next( node );
401         }
402         g_list_free( list );
403         list = NULL;
404 }
405
406 /**
407  * Free linked list of attributes; both attributes and the list are freed.
408  * It is assumed that attributes are *NOT* contained within some other
409  * container.
410  * \param list List of attributes to be freed.
411  */
412 void addritem_free_list_attribute( GList *list ) {
413         GList *node = list;
414         while( node ) {
415                 addritem_free_attribute( node->data );
416                 node->data = NULL;
417                 node = g_list_next( node );
418         }
419         g_list_free( list );
420 }
421
422 /**
423  * Free address person object.
424  * \param person Person object to free.
425  */
426 void addritem_free_item_person( ItemPerson *person ) {
427         g_return_if_fail( person != NULL );
428
429         /* Free internal stuff */
430         g_free( ADDRITEM_ID(person) );
431         g_free( ADDRITEM_NAME(person) );
432         g_free( person->firstName );
433         g_free( person->lastName );
434         g_free( person->nickName );
435         g_free( person->externalID );
436         g_list_free( person->listEMail );
437         addritem_free_list_attribute( person->listAttrib );
438
439         ADDRITEM_OBJECT(person)->type = ITEMTYPE_NONE;
440         ADDRITEM_ID(person) = NULL;
441         ADDRITEM_NAME(person) = NULL;
442         ADDRITEM_PARENT(person) = NULL;
443         ADDRITEM_SUBTYPE(person) = 0;
444         person->firstName = NULL;
445         person->lastName = NULL;
446         person->nickName = NULL;
447         person->externalID = NULL;
448         person->listEMail = NULL;
449         person->listAttrib = NULL;
450
451         g_free( person );
452 }
453
454 /**
455  * Print E-Mail address object for debug.
456  * \param item   Item to print.
457  * \param stream Output stream.
458  */
459 void addritem_print_item_email( ItemEMail *item, FILE *stream ) {
460         g_return_if_fail( item != NULL );
461         fprintf( stream, "\t\tt/id: %d : '%s'\n", ADDRITEM_TYPE(item), ADDRITEM_ID(item) );
462         fprintf( stream, "\t\tsubty: %d\n", ADDRITEM_SUBTYPE(item) );
463         fprintf( stream, "\t\talis: '%s'\n", ADDRITEM_NAME(item) );
464         fprintf( stream, "\t\taddr: '%s'\n", item->address );
465         fprintf( stream, "\t\trems: '%s'\n", item->remarks );
466         fprintf( stream, "\t\t---\n" );
467 }
468
469 /**
470  * Print user attribute object for debug.
471  * \param item   Attribute to print.
472  * \param stream Output stream.
473  */
474 void addritem_print_attribute( UserAttribute *item, FILE *stream ) {
475         g_return_if_fail( item != NULL );
476         fprintf( stream, "\t\tuid  : '%s'\n", item->uid );
477         fprintf( stream, "\t\tname : '%s'\n", item->name );
478         fprintf( stream, "\t\tvalue: '%s'\n", item->value );
479         fprintf( stream, "\t\t---\n" );
480 }
481
482 /**
483  * Print person item for debug.
484  * \param person Person to print.
485  * \param stream Output stream.
486  */
487 void addritem_print_item_person( ItemPerson *person, FILE *stream ) {
488         GList *node;
489         g_return_if_fail( person != NULL );
490         fprintf( stream, "Person:\n" );
491         fprintf( stream, "\tt/uid: %d : '%s'\n", ADDRITEM_TYPE(person), ADDRITEM_ID(person) );
492         fprintf( stream, "\tsubty: %d\n", ADDRITEM_SUBTYPE(person) );
493         fprintf( stream, "\tcommn: '%s'\n", ADDRITEM_NAME(person) );
494         fprintf( stream, "\tfirst: '%s'\n", person->firstName );
495         fprintf( stream, "\tlast : '%s'\n", person->lastName );
496         fprintf( stream, "\tnick : '%s'\n", person->nickName );
497         fprintf( stream, "\textID: '%s'\n", person->externalID );
498         fprintf( stream, "\teMail:\n" );
499         fprintf( stream, "\t---\n" );
500         node = person->listEMail;
501         while( node ) {
502                 addritem_print_item_email( node->data, stream );
503                 node = g_list_next( node );
504         }
505         fprintf( stream, "\tuAttr:\n" );
506         fprintf( stream, "\t---\n" );
507         node = person->listAttrib;
508         while( node ) {
509                 addritem_print_attribute( node->data, stream );
510                 node = g_list_next( node );
511         }
512         fprintf( stream, "\t===\n" );
513 }
514
515 /**
516  * Add E-Mail address object to person.
517  * \param  person Person.
518  * \param  email  E-Mail object to add.
519  * \return <i>TRUE</i> if E-Mail added.
520  */
521 gboolean addritem_person_add_email( ItemPerson *person, ItemEMail *email ) {
522         GList *node;
523
524         g_return_val_if_fail( person != NULL, FALSE );
525         g_return_val_if_fail( email != NULL, FALSE );
526
527         node = person->listEMail;
528         while( node ) {
529                 if( node->data == email ) return FALSE;
530                 node = g_list_next( node );
531         }
532         person->listEMail = g_list_append( person->listEMail, email );
533         ADDRITEM_PARENT(email) = ADDRITEM_OBJECT(person);
534         return TRUE;
535 }
536
537 /**
538  * Return email object with specified ID for specified person.
539  * \param  person Person object.
540  * \param  eid    EMail ID.
541  * \return EMail object, or <i>NULL</i> if not found.
542  */
543 ItemEMail *addritem_person_get_email( ItemPerson *person, const gchar *eid ) {
544         ItemEMail *email = NULL;
545         GList *node;
546
547         g_return_val_if_fail( person != NULL, NULL );
548         if( eid == NULL || *eid == '\0' ) return NULL;
549
550         /* Look for email */
551         node = person->listEMail;
552         while( node ) {
553                 AddrItemObject *objE = node->data;
554                 gchar *ide = ADDRITEM_ID(objE);
555                 if( ide ) {
556                         if( strcmp( ide, eid ) == 0 ) {
557                                 email = ( ItemEMail * ) objE;
558                         }
559                 }
560                 node = g_list_next( node );
561         }
562         return email;
563 }
564
565 /**
566  * Remove email address with specified ID for specified person.
567  * \param  person Person object.
568  * \param  eid    EMail ID.
569  * \return EMail object, or <i>NULL</i> if not found. Note that object should
570  *         still be freed after calling this function.
571  */
572 ItemEMail *addritem_person_remove_email_id( ItemPerson *person, const gchar *eid ) {
573         ItemEMail *email = NULL;
574         GList *node;
575
576         g_return_val_if_fail( person != NULL, NULL );
577         if( eid == NULL || *eid == '\0' ) return NULL;
578
579         /* Look for email */
580         node = person->listEMail;
581         while( node ) {
582                 AddrItemObject *objE = node->data;
583                 gchar *ide = ADDRITEM_ID(objE);
584                 if( ide ) {
585                         if( strcmp( ide, eid ) == 0 ) {
586                                 email = ( ItemEMail * ) objE;
587                         }
588                 }
589                 node = g_list_next( node );
590         }
591
592         if( email ) {
593                 /* Remove email from person's address list */
594                 if( person->listEMail ) {
595                         person->listEMail = g_list_remove( person->listEMail, email );
596                 }
597                 /* Unlink reference to person. */
598                 ADDRITEM_PARENT(email) = NULL;
599         }
600         return email;
601 }
602
603 /**
604  * Remove email address for specified person.
605  * \param  person Person.
606  * \param  email  EMail to remove.
607  * \return EMail object, or <i>NULL</i> if not found. Note that object should
608  *         still be freed after calling this method.
609  */
610 ItemEMail *addritem_person_remove_email( ItemPerson *person, ItemEMail *email ) {
611         gboolean found = FALSE;
612         GList *node;
613
614         g_return_val_if_fail( person != NULL, NULL );
615         if( email == NULL ) return NULL;
616
617         /* Look for email */
618         node = person->listEMail;
619         while( node ) {
620                 if( node-> data == email ) {
621                         found = TRUE;
622                         break;
623                 }
624                 node = g_list_next( node );
625         }
626
627         if( found ) {
628                 /* Remove email from person's address list */
629                 if( person->listEMail ) {
630                         person->listEMail = g_list_remove( person->listEMail, email );
631                 }
632                 /* Unlink reference to person. */
633                 ADDRITEM_PARENT(email) = NULL;
634                 return email;
635         }
636         return NULL;
637 }
638
639 /**
640  * Add user attribute to specified person.
641  * \param  person Person.
642  * \param  attrib Attribute to add.
643  * \return <i>TRUE</i> if item added.
644  */
645 void addritem_person_add_attribute(
646                         ItemPerson *person, UserAttribute *attrib )
647 {
648         g_return_if_fail( person != NULL );
649         person->listAttrib = g_list_append( person->listAttrib, attrib );
650 }
651
652 /**
653  * Return attribute with specified ID for person.
654  * \param  person Person object.
655  * \param  aid    Attribute ID.
656  * \return Reference to UserAttribute object, or <i>NULL</i> if not found.
657  */
658 UserAttribute *addritem_person_get_attribute(
659                         ItemPerson *person, const gchar *aid )
660 {
661         UserAttribute *attrib = NULL;
662         GList *node;
663
664         g_return_val_if_fail( person != NULL, NULL );
665         if( aid == NULL || *aid == '\0' ) return NULL;
666
667         /* Look for attribute */
668         node = person->listAttrib;
669         while( node ) {
670                 UserAttribute *attr = node->data;
671                 gchar *ida = attr->uid;
672                 if( ida ) {
673                         if( strcmp( ida, aid ) == 0 ) {
674                                 attrib = attr;
675                         }
676                 }
677                 node = g_list_next( node );
678         }
679         return attrib;
680 }
681
682 /**
683  * Remove attribute with specified ID from person.
684  * \param  person Person object.
685  * \param  aid    Attribute ID to remove.
686  * \return UserAttribute object, or <i>NULL</i> if not found. Note that
687  *         attribute object should still be freed after calling this method.
688  */
689 UserAttribute *addritem_person_remove_attrib_id(
690                         ItemPerson *person, const gchar *aid )
691 {
692         UserAttribute *attrib = NULL;
693         GList *node;
694
695         g_return_val_if_fail( person != NULL, NULL );
696         if( aid == NULL || *aid == '\0' ) return NULL;
697
698         /* Look for attribute */
699         node = person->listAttrib;
700         while( node ) {
701                 UserAttribute *attr = node->data;
702                 gchar *ida = attr->uid;
703                 if( ida ) {
704                         if( strcmp( ida, aid ) == 0 ) {
705                                 attrib = attr;
706                         }
707                 }
708                 node = g_list_next( node );
709         }
710
711         /* Remove email from person's address list */
712         if( person->listAttrib ) {
713                 person->listAttrib = g_list_remove( person->listAttrib, attrib );
714         }
715         return attrib;
716 }
717
718 /**
719  * Remove attribute from person.
720  * \param  person Person.
721  * \param  attrib Attribute to remove.
722  * \return UserAttribute object to remove. Note that attribute object should
723  *         still be freed.
724  */
725 UserAttribute *addritem_person_remove_attribute(
726                         ItemPerson *person, UserAttribute *attrib )
727 {
728         gboolean found = FALSE;
729         GList *node;
730
731         g_return_val_if_fail( person != NULL, NULL );
732         if( attrib == NULL ) return NULL;
733
734         /* Look for attribute */
735         node = person->listAttrib;
736         while( node ) {
737                 if( node-> data == attrib ) {
738                         found = TRUE;
739                         break;
740                 }
741                 node = g_list_next( node );
742         }
743
744         if( found ) {
745                 /* Remove attribute */
746                 if( person->listAttrib ) {
747                         person->listAttrib = g_list_remove( person->listAttrib, attrib );
748                 }
749         }
750         return attrib;
751 }
752
753 /**
754  * Create new address book group object.
755  * \return Initialized group object.
756  */
757 ItemGroup *addritem_create_item_group( void ) {
758         ItemGroup *group;
759
760         group = g_new0( ItemGroup, 1 );
761         ADDRITEM_TYPE(group) = ITEMTYPE_GROUP;
762         ADDRITEM_ID(group) = NULL;
763         ADDRITEM_NAME(group) = NULL;
764         ADDRITEM_PARENT(group) = NULL;
765         ADDRITEM_SUBTYPE(group) = 0;
766         group->remarks = NULL;
767         group->listEMail = NULL;
768         return group;
769 }
770
771 /**
772  * Copy (deep copy) address book group.
773  * \param  item Group to copy.
774  * \return Copy of the group object, or <i>NULL</i> if null argument supplied.
775  */
776 ItemGroup *addritem_copy_item_group( ItemGroup *item ) {
777         ItemGroup *itemNew;
778
779         itemNew = g_new0( ItemGroup, 1 );
780         if( item ) {
781                 itemNew = addritem_create_item_group();
782                 ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
783                 itemNew->remarks = g_strdup( item->remarks );
784         }
785         return itemNew;
786 }
787
788 /**
789  * Specify ID to be used for group.
790  * \param group Group object.
791  * \param value ID of group.
792  */
793 void addritem_group_set_id( ItemGroup *group, const gchar *value ) {
794         ADDRITEM_ID(group) = mgu_replace_string( ADDRITEM_ID(group), value );
795 }
796
797 /**
798  * Specify name to be used for group.
799  * \param group Group object.
800  * \param value Name of group.
801  */
802 void addritem_group_set_name( ItemGroup *group, const gchar *value ) {
803         ADDRITEM_NAME(group) = mgu_replace_string( ADDRITEM_NAME(group), value );
804 }
805
806 /**
807  * Specify remarks to be used for group.
808  * \param group Group object.
809  * \param value Remarks for group.
810  */
811 void addritem_group_set_remarks( ItemGroup *group, const gchar *value ) {
812         group->remarks = mgu_replace_string( group->remarks, value );
813 }
814
815 /**
816  * Free address group object.
817  * \param group Group to free.
818  */
819 void addritem_free_item_group( ItemGroup *group ) {
820         g_return_if_fail( group != NULL );
821
822         /* Free internal stuff */
823         g_free( ADDRITEM_ID(group) );
824         g_free( ADDRITEM_NAME(group) );
825         g_free( group->remarks );
826         mgu_clear_list( group->listEMail );
827         g_list_free( group->listEMail );
828
829         ADDRITEM_TYPE(group) = ITEMTYPE_NONE;
830         ADDRITEM_ID(group) = NULL;
831         ADDRITEM_NAME(group) = NULL;
832         ADDRITEM_PARENT(group) = NULL;
833         ADDRITEM_SUBTYPE(group) = 0;
834         group->remarks = NULL;
835         group->listEMail = NULL;
836
837         g_free( group );
838 }
839
840 /**
841  * Add EMail address to group. Note that a reference to an E-Mail item is
842  * added to a group. A person object is the only container that for an
843  * address.
844  * \param  group Group.
845  * \param  email E-Mail object.
846  * \return <i>TRUE</i> if email item added.
847  */
848 gboolean addritem_group_add_email( ItemGroup *group, ItemEMail *email ) {
849         GList *node;
850
851         g_return_val_if_fail( group != NULL, FALSE );
852         g_return_val_if_fail( email != NULL, FALSE );
853
854         node = group->listEMail;
855         while( node ) {
856                 if( node->data == email ) return FALSE;
857                 node = g_list_next( node );
858         }
859         group->listEMail = g_list_append( group->listEMail, email );
860         return TRUE;
861 }
862
863 /**
864  * Remove email address object for specified group.
865  * \param  group Group from which to remove address.
866  * \param  email EMail to remove
867  * \return EMail object, or <i>NULL if email not found in group. Note that
868  *         this object is referenced (linked) to a group and should *NOT*
869  *         be freed. An E-Mail object object should only be freed after
870  *         removing from a person.
871  */
872 ItemEMail *addritem_group_remove_email( ItemGroup *group, ItemEMail *email ) {
873         if( group && email ) {
874                 GList *node = group->listEMail;
875                 while( node ) {
876                         if( node->data == email ) {
877                                 group->listEMail = g_list_remove( group->listEMail, email );
878                                 return email;
879                         }
880                         node = g_list_next( node );
881                 }
882         }
883         return NULL;
884 }
885
886 /**
887  * Remove person object for specified group.
888  * \param  group Group from which to remove address.
889  * \param  email EMail to remove
890  * \return EMail object, or <i>NULL if email not found in group. Note that
891  *         this object is referenced (linked) to a group and should *NOT*
892  *         be freed. An E-Mail object object should only be freed after
893  *         removing from a person.
894  */
895 ItemPerson *addritem_folder_remove_person( ItemFolder *group, ItemPerson *person ) {
896         if( group && person ) {
897                 GList *node = group->listPerson;
898                 while( node ) {
899                         if( node->data == person ) {
900                                 group->listPerson = g_list_remove( group->listPerson, person );
901                                 return person;
902                         }
903                         node = g_list_next( node );
904                 }
905         }
906         return NULL;
907 }
908
909 /**
910  * Remove email address of specified ID for specified group.
911  * \param  group Group from which to remove address.
912  * \param  eid  EMail ID.
913  * \return EMail object, or <i>NULL</i> if email not found in group. Note that
914  *         this object is referenced (linked) to a group and should *NOT* be
915  *         freed. An E-Mail object should only be freed after removing from a
916  *         person.
917  */
918 ItemEMail *addritem_group_remove_email_id( ItemGroup *group, const gchar *eid ) {
919         if( group ) {
920                 GList *node = group->listEMail;
921                 while( node ) {
922                         ItemEMail *email = ( ItemEMail * ) node->data;
923                         if( strcmp( ADDRITEM_ID( email ), eid ) == 0 ) {
924                                 group->listEMail = g_list_remove( group->listEMail, email );
925                                 return email;
926                         }
927                         node = g_list_next( node );
928                 }
929         }
930         return NULL;
931 }
932
933 /**
934  * Print address group item for debug.
935  * \param group  Group to print.
936  * \param stream Output stream.
937  */
938 void addritem_print_item_group( ItemGroup *group, FILE *stream ) {
939         GList *node;
940         ItemPerson *person;
941         ItemEMail *item;
942         g_return_if_fail( group != NULL );
943         fprintf( stream, "Group:\n" );
944         fprintf( stream, "\tt/u: %d : '%s'\n", ADDRITEM_TYPE(group), ADDRITEM_ID(group) );
945         fprintf( stream, "\tsub: %d\n", ADDRITEM_SUBTYPE(group) );
946         fprintf( stream, "\tgrp: '%s'\n", ADDRITEM_NAME(group) );
947         fprintf( stream, "\trem: '%s'\n", group->remarks );
948         fprintf( stream, "\t---\n" );
949         node = group->listEMail;
950         while( node ) {
951                 item = node->data;
952                 person = ( ItemPerson * ) ADDRITEM_PARENT(item);
953                 if( person ) {
954                         fprintf( stream, "\t\tpid : '%s'\n", ADDRITEM_ID(person) );
955                         fprintf( stream, "\t\tcomn: '%s'\n", ADDRITEM_NAME(person) );
956                 }
957                 else {
958                         fprintf( stream, "\t\tpid : ???\n" );
959                         fprintf( stream, "\t\tcomn: ???\n" );
960                 }
961                 addritem_print_item_email( item, stream );
962                 node = g_list_next( node );
963         }
964         fprintf( stream, "\t***\n" );
965 }
966
967 /**
968  * Create new address folder.
969  * \return Initialized address folder object.
970  */
971 ItemFolder *addritem_create_item_folder( void ) {
972         ItemFolder *folder;
973         folder = g_new0( ItemFolder, 1 );
974         ADDRITEM_TYPE(folder) = ITEMTYPE_FOLDER;
975         ADDRITEM_ID(folder) = NULL;
976         ADDRITEM_NAME(folder) = NULL;
977         ADDRITEM_PARENT(folder) = NULL;
978         ADDRITEM_SUBTYPE(folder) = 0;
979         folder->remarks = NULL;
980         folder->isRoot = FALSE;
981         folder->listItems = NULL;
982         folder->listFolder = NULL;
983         folder->listPerson = NULL;
984         folder->listGroup = NULL;
985         folder->folderType = ADDRFOLDER_NONE;
986         folder->folderData = NULL;
987         folder->isHidden = FALSE;
988         return folder;
989 }
990
991 /**
992  * Copy address book folder. Note that only the folder and not its contents are
993  * copied.
994  * \param  item Folder to copy.
995  * \return A copy of the folder, or <i>NULL</i> if null argument supplied.
996  */
997 ItemFolder *addritem_copy_item_folder( ItemFolder *item ) {
998         ItemFolder *itemNew;
999
1000         itemNew = g_new0( ItemFolder, 1 );
1001         if( item ) {
1002                 itemNew = addritem_create_item_folder();
1003                 ADDRITEM_NAME(itemNew) = g_strdup( ADDRITEM_NAME(item) );
1004                 itemNew->folderType = item->folderType;
1005         }
1006         return itemNew;
1007 }
1008
1009 /**
1010  * Specify ID to be used for folder.
1011  * \param folder Folder.
1012  * \param value  ID.
1013  */
1014 void addritem_folder_set_id( ItemFolder *folder, const gchar *value ) {
1015         ADDRITEM_ID(folder) = mgu_replace_string( ADDRITEM_ID(folder), value );
1016 }
1017
1018 /**
1019  * Specify name to be used for folder.
1020  * \param folder Folder.
1021  * \param value  Name.
1022  */
1023 void addritem_folder_set_name( ItemFolder *folder, const gchar *value ) {
1024         ADDRITEM_NAME(folder) = mgu_replace_string( ADDRITEM_NAME(folder), value );
1025 }
1026
1027 /**
1028  * Specify remarks to be used for folder.
1029  * \param folder Folder.
1030  * \param value  Remarks.
1031  */
1032 void addritem_folder_set_remarks( ItemFolder *folder, const gchar *value ) {
1033         folder->remarks = mgu_replace_string( folder->remarks, value );
1034 }
1035
1036 /**
1037  * Specify visibility of folder.
1038  * \param folder Folder.
1039  * \param value  Set to <code>TRUE</code> to hide folder.
1040  */
1041 void addritem_folder_set_hidden( ItemFolder *folder, const gboolean value ) {
1042         folder->isHidden = value;
1043 }
1044
1045 /**
1046  * Free address folder. Note: this does not free up the lists of children
1047  * (folders, groups and person). This should be done prior to calling this
1048  * function.
1049  * \param folder Folder to free.
1050  */
1051 void addritem_free_item_folder( ItemFolder *folder ) {
1052         g_return_if_fail( folder != NULL );
1053
1054         /* Free internal stuff */
1055         g_free( ADDRITEM_ID(folder) );
1056         g_free( ADDRITEM_NAME(folder) );
1057         g_free( folder->remarks );
1058         mgu_clear_list( folder->listItems );
1059         g_list_free( folder->listItems );
1060
1061         ADDRITEM_TYPE(folder) = ITEMTYPE_NONE;
1062         ADDRITEM_ID(folder) = NULL;
1063         ADDRITEM_NAME(folder) = NULL;
1064         ADDRITEM_PARENT(folder) = NULL;
1065         ADDRITEM_SUBTYPE(folder) = 0;
1066         folder->isRoot = FALSE;
1067         folder->remarks = NULL;
1068         folder->listItems = NULL;
1069         folder->listFolder = NULL;
1070         folder->listGroup = NULL;
1071         folder->listPerson = NULL;
1072         folder->folderType = ADDRFOLDER_NONE;
1073         folder->folderData = NULL;
1074         folder->isHidden = FALSE;
1075
1076         g_free( folder );
1077 }
1078
1079 /**
1080  * Free up folders recursively. Note: this only frees up the lists of
1081  * children and *NOT* the children objects (folders, groups and person).
1082  * This should be done prior to calling this function.
1083  * \param parent Parent folder object to be processed.
1084  */
1085 void addritem_free_item_folder_recurse( ItemFolder *parent ) {
1086         GList *node = parent->listFolder;
1087
1088         while( node ) {
1089                 ItemFolder *folder = node->data;
1090                 addritem_free_item_folder_recurse( folder );
1091                 node = g_list_next( node );
1092         }
1093         g_list_free( parent->listPerson );
1094         g_list_free( parent->listGroup );
1095         g_list_free( parent->listFolder );
1096         parent->listPerson = NULL;
1097         parent->listGroup = NULL;
1098         parent->listFolder = NULL;
1099 }
1100
1101 /**
1102  * Free up list of person objects contained in specified folder.
1103  * \param folder Folder to process.
1104  */
1105 void addritem_folder_free_person( ItemFolder *folder ) {
1106         GList *node;
1107
1108         g_return_if_fail( folder != NULL );
1109         
1110         /* Free up folder of persons. */
1111         node = folder->listPerson;
1112         while( node ) {
1113                 ItemPerson *person = node->data;
1114                 addritem_free_item_person( person );
1115                 person = NULL;
1116                 node = g_list_next( node );
1117         }
1118 }
1119
1120 /**
1121  * Add person into folder.
1122  * \param  folder Folder.
1123  * \param  item   Person to add.
1124  * \return <i>TRUE</i> if person added.
1125  */
1126 gboolean addritem_folder_add_person( ItemFolder *folder, ItemPerson *item ) {
1127         g_return_val_if_fail( folder != NULL, FALSE );
1128         g_return_val_if_fail( item != NULL, FALSE );
1129
1130         folder->listPerson = g_list_append( folder->listPerson, item );
1131         ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
1132         return TRUE;
1133 }
1134
1135 /**
1136  * Add folder into folder.
1137  * \param  folder Folder.
1138  * \param  item   Folder to add.
1139  * \return <i>TRUE</i> if folder added.
1140  */
1141 gboolean addritem_folder_add_folder( ItemFolder *folder, ItemFolder *item ) {
1142         g_return_val_if_fail( folder != NULL, FALSE );
1143         g_return_val_if_fail( item != NULL, FALSE );
1144
1145         folder->listFolder = g_list_append( folder->listFolder, item );
1146         ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
1147         return TRUE;
1148 }
1149
1150 /**
1151  * Add group into folder.
1152  * \param  folder Folder.
1153  * \param  item   Group to add.
1154  * \return <i>TRUE</i> if group added.
1155  */
1156 gboolean addritem_folder_add_group( ItemFolder *folder, ItemGroup *item ) {
1157         g_return_val_if_fail( folder != NULL, FALSE );
1158         g_return_val_if_fail( item != NULL, FALSE );
1159
1160         folder->listGroup = g_list_append( folder->listGroup, item );
1161         ADDRITEM_PARENT(item) = ADDRITEM_OBJECT(folder);
1162         return TRUE;
1163 }
1164
1165 /**
1166  * Print address folder item contents for debug.
1167  * \param folder Folder to process.
1168  * \param stream Output stream.
1169  */
1170 void addritem_print_item_folder( ItemFolder *folder, FILE *stream ) {
1171         GList *node;
1172         /* ItemPerson *person; */
1173         ItemFolder *parent;
1174
1175         g_return_if_fail( folder != NULL );
1176
1177         fprintf( stream, "Folder:\n" );
1178         fprintf( stream, "\tt/u: %d : '%s'\n", ADDRITEM_TYPE(folder), ADDRITEM_ID(folder) );
1179         fprintf( stream, "\tsub: %d\n", ADDRITEM_SUBTYPE(folder) );
1180         fprintf( stream, "\tnam: '%s'\n", ADDRITEM_NAME(folder) );
1181         fprintf( stream, "\trem: '%s'\n", folder->remarks );
1182         fprintf( stream, "\ttyp: %d\n", folder->folderType );
1183         fprintf( stream, "\thid: %s\n", folder->isHidden ? "hidden" : "visible" );
1184         fprintf( stream, "\t---\n" );
1185         parent = ( ItemFolder * ) ADDRITEM_PARENT(folder);
1186         if( parent ) {
1187                 fprintf( stream, "\tpar: %s : %s\n", ADDRITEM_ID(parent), ADDRITEM_NAME(parent) );
1188         }
1189         else {
1190                 fprintf( stream, "\tpar: NULL\n" );
1191         }
1192         node = folder->listFolder;
1193         while( node ) {
1194                 AddrItemObject *aio = node->data;
1195                 if( aio ) {
1196                         if( aio->type == ITEMTYPE_FOLDER ) {
1197                                 ItemFolder *item = ( ItemFolder * ) aio;
1198                                 addritem_print_item_folder( item, stream );
1199                         }
1200                 }
1201                 else {
1202                         fprintf( stream, "\t\tpid : ???\n" );
1203                 }
1204
1205                 node = g_list_next( node );
1206         }
1207
1208         node = folder->listPerson;
1209         while( node ) {
1210                 AddrItemObject *aio = node->data;
1211                 if( aio ) {
1212                         if( aio->type == ITEMTYPE_PERSON ) {
1213                                 ItemPerson *item = ( ItemPerson * ) aio;
1214                                 addritem_print_item_person( item, stream );
1215                         }
1216                 }
1217                 else {
1218                         fprintf( stream, "\t\tpid : ???\n" );
1219                 }
1220
1221                 node = g_list_next( node );
1222         }
1223
1224         node = folder->listGroup;
1225         while( node ) {
1226                 AddrItemObject *aio = node->data;
1227                 if( aio ) {
1228                         if( aio->type == ITEMTYPE_GROUP ) {
1229                                 ItemGroup *item = ( ItemGroup * ) aio;
1230                                 addritem_print_item_group( item, stream );
1231                         }
1232                 }
1233                 else {
1234                         fprintf( stream, "\t\tpid : ???\n" );
1235                 }
1236                 node = g_list_next( node );
1237         }
1238         fprintf( stream, "\t###\n" );
1239 }
1240
1241 /**
1242  * Print address item for debug.
1243  * \param aio    Address item to format.
1244  * \param stream Output stream.
1245  */
1246 void addritem_print_item( AddrItemObject *aio, FILE *stream ) {
1247         g_return_if_fail( aio != NULL );
1248
1249         if( aio->type == ITEMTYPE_PERSON ) {
1250                 ItemPerson *item = ( ItemPerson * ) aio;
1251                 addritem_print_item_person( item, stream );
1252         }
1253         else if( aio->type == ITEMTYPE_EMAIL ) {
1254                 ItemEMail *item = ( ItemEMail * ) aio;
1255                 addritem_print_item_email( item, stream );
1256         }
1257         else if( aio->type == ITEMTYPE_GROUP ) {
1258                 ItemGroup *item = ( ItemGroup * ) aio;
1259                 addritem_print_item_group( item, stream );
1260         }
1261         else if( aio->type == ITEMTYPE_FOLDER ) {
1262                 ItemFolder *item = ( ItemFolder * ) aio;
1263                 addritem_print_item_folder( item, stream );
1264         }
1265 }
1266
1267 /**
1268  * Return link list of persons for specified folder. Note that the list contains
1269  * references to items and should be g_free() when done. Do *NOT* attempt to use the
1270  * addritem_free_xxx() functions... this will destroy the addressbook data!
1271  *
1272  * \param  folder Folder to process.
1273  * \return List of items, or <i>NULL</i> if none.
1274  */
1275 GList *addritem_folder_get_person_list( ItemFolder *folder ) {
1276         GList *list = NULL;
1277         GList *node = NULL;
1278
1279         g_return_val_if_fail( folder != NULL, NULL );
1280
1281         node = folder->listPerson;
1282         while( node ) {
1283                 ItemPerson *person = node->data;
1284                 list = g_list_append( list, person );
1285                 node = g_list_next( node );
1286         }
1287         return list;
1288 }
1289
1290 /**
1291  * Return link list of groups for specified folder. Note that the list contains
1292  * references to items and should be g_free() when done. Do *NOT* attempt to use the
1293  * addritem_free_xxx() functions... this will destroy the addressbook data!
1294  *
1295  * \param  folder Folder to process.
1296  * \return List of items, or <i>NULL</i> if none.
1297  */
1298 GList *addritem_folder_get_group_list( ItemFolder *folder ) {
1299         GList *list = NULL;
1300         GList *node = NULL;
1301
1302         g_return_val_if_fail( folder != NULL, NULL );
1303
1304         node = folder->listGroup;
1305         while( node ) {
1306                 ItemGroup *group = node->data;
1307                 list = g_list_append( list, group );
1308                 node = g_list_next( node );
1309         }
1310         return list;
1311 }
1312
1313 /**
1314  * Move person's email item.
1315  * \param  person     Person.
1316  * \param  itemMove   Item to move.
1317  * \param  itemTarget Target item before which to move item.
1318  * \return Reference to item that was moved, or <i>NULL</i> if null arguments
1319  *         supplied.
1320  */
1321
1322 ItemEMail *addritem_move_email_before(
1323                 ItemPerson *person, ItemEMail *itemMove, ItemEMail *itemTarget )
1324 {
1325         gint posT, posM;
1326
1327         g_return_val_if_fail( person != NULL, NULL );
1328
1329         if( itemTarget == NULL ) return NULL;
1330         if( itemMove == NULL ) return NULL;
1331         if( itemMove == itemTarget ) return itemMove;
1332
1333         posT = g_list_index( person->listEMail, itemTarget );
1334         if( posT < 0 ) return NULL;
1335         posM = g_list_index( person->listEMail, itemMove );
1336         if( posM < 0 ) return NULL;
1337         person->listEMail = g_list_remove( person->listEMail, itemMove );
1338         person->listEMail = g_list_insert( person->listEMail, itemMove, posT );
1339         return itemMove;
1340 }
1341
1342 /**
1343  * Move person's email item.
1344  * \param  person    Person.
1345  * \param  itemMove  Item to move.
1346  * \param  itemTarget Target item after which to move item.
1347  * \return Reference to item that was moved, or <i>NULL</i> if null arguments
1348  *         supplied.
1349  */
1350 ItemEMail *addritem_move_email_after(
1351                 ItemPerson *person, ItemEMail *itemMove, ItemEMail *itemTarget )
1352 {
1353         gint posT, posM;
1354
1355         g_return_val_if_fail( person != NULL, NULL );
1356
1357         if( itemTarget == NULL ) return NULL;
1358         if( itemMove == NULL ) return NULL;
1359         if( itemMove == itemTarget ) return itemMove;
1360
1361         posT = g_list_index( person->listEMail, itemTarget );
1362         if( posT < 0 ) return NULL;
1363         posM = g_list_index( person->listEMail, itemMove );
1364         if( posM < 0 ) return NULL;
1365         person->listEMail = g_list_remove( person->listEMail, itemMove );
1366         person->listEMail = g_list_insert( person->listEMail, itemMove, 1+posT );
1367         return itemMove;
1368 }
1369
1370 /**
1371  * Parse first and last names for person from common name.
1372  * \param person Person to process.
1373  */
1374 void addritem_parse_first_last( ItemPerson *person ) {
1375         gchar *name;
1376         gchar *fName, *lName;
1377         gchar *p;
1378         gint len, i;
1379
1380         g_return_if_fail( person != NULL );
1381
1382         name = ADDRITEM_NAME(person);
1383         if( name == NULL ) return;
1384
1385         fName = NULL;
1386         lName = NULL;
1387         p = strchr( name, ',' );
1388         if( p ) {
1389                 len = ( size_t ) ( p - name );
1390                 lName = g_strndup( name, len );
1391                 fName = g_strdup( p + 1 );
1392         }
1393         else {
1394                 /* Other way around */
1395                 i = strlen( name );
1396                 while( i >= 0 ) {
1397                         if( name[i] == ' ' ) {
1398                                 fName = g_strndup( name, i );
1399                                 lName = g_strdup( &name[i] );
1400                                 break;
1401                         }
1402                         i--;
1403                 }
1404                 if( fName == NULL ) {
1405                         fName = g_strdup( name );
1406                 }
1407         }
1408
1409         g_free( person->firstName );
1410         person->firstName = fName;
1411         if( person->firstName )
1412                 g_strstrip( person->firstName );
1413
1414         g_free( person->lastName );
1415         person->lastName = lName;
1416         if( person->lastName )
1417                 g_strstrip( person->lastName );
1418 }
1419
1420 /**
1421  * Build a path of all ancestor folders for specified folder.
1422  * \param  folder Folder.
1423  * \param  seq    Path sequence, FALSE top down, TRUE bottom up.
1424  * \return List of folders from the top down.
1425  */
1426 GList *addritem_folder_path( const ItemFolder *folder, const gboolean seq ) {
1427         GList *list;
1428         AddrItemObject *item;
1429
1430         list = NULL;
1431         item = ( AddrItemObject * ) folder;
1432         if( seq ) {
1433                 while( item ) {
1434                         list = g_list_prepend( list, item );
1435                         item = ADDRITEM_PARENT( item );
1436                 }
1437         }
1438         else {
1439                 while( item ) {
1440                         list = g_list_append( list, item );
1441                         item = ADDRITEM_PARENT( item );
1442                 }
1443         }
1444         return list;
1445 }
1446
1447 /**
1448  * Format E-Mail address.
1449  * \param email EMail item to format.
1450  * \return Formatted string. Should be freed after use.
1451  */
1452 gchar *addritem_format_email( ItemEMail *email ) {
1453         gchar *address;
1454         gchar *name;
1455         ItemPerson *person;
1456
1457         address = NULL;
1458         name = NULL;
1459         if( ADDRITEM_NAME( email ) ) {
1460                 if( strlen( ADDRITEM_NAME( email ) ) ) {
1461                         name = ADDRITEM_NAME( email );
1462                 }
1463         }
1464         if( ! name ) {
1465                 person = ( ItemPerson * ) ADDRITEM_PARENT( email );
1466                 name = ADDRITEM_NAME( person );
1467         }
1468
1469         if( name ) {
1470                 if( strchr_with_skip_quote( name, '"', ',' ) ) {
1471                         address = g_strdup_printf( "\"%s\" <%s>", name, email->address );
1472                 }
1473                 else {
1474                         address = g_strdup_printf( "%s <%s>", name, email->address );
1475                 }
1476         }
1477         else {
1478                 address = g_strdup_printf( "%s", email->address );
1479         }
1480         return address;
1481 }
1482
1483 /*
1484 * End of Source.
1485 */