mark PurpleImageClass as private
[pidgin-git.git] / libpurple / protocols / novell / nmcontact.c
blob6c74e9e59392f13addd2120bec32f0b82edf9c87
1 /*
2 * nmcontact.c
4 * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
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.
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 02111-1301 USA
21 #include <glib.h>
22 #include <string.h>
23 #include "nmcontact.h"
24 #include "nmfield.h"
25 #include "nmuser.h"
26 #include "util.h"
28 struct _NMContact
30 int id;
31 int parent_id;
32 int seq;
33 char *dn;
34 char *display_name;
35 NMUserRecord *user_record;
36 gpointer data;
37 int ref_count;
40 struct _NMFolder
42 int id;
43 int seq;
44 char *name;
45 GSList *folders;
46 GSList *contacts;
47 int ref_count;
50 static int count = 0;
52 static void _release_folder_contacts(NMFolder * folder);
53 static void _release_folder_folders(NMFolder * folder);
54 static void _add_contacts(NMUser * user, NMFolder * folder, NMField * fields);
55 static void _add_folders(NMFolder * root, NMField * fields);
57 /*********************************************************************
58 * Contact API
59 *********************************************************************/
61 NMContact *
62 nm_create_contact()
64 NMContact *contact = g_new0(NMContact, 1);
66 contact->ref_count = 1;
68 purple_debug(PURPLE_DEBUG_INFO, "novell", "Creating contact, total=%d\n",
69 count++);
71 return contact;
75 * This creates a contact for the contact list. The
76 * field array that is passed in should be a
77 * NM_A_FA_CONTACT array.
80 NMContact *
81 nm_create_contact_from_fields(NMField * fields)
83 NMContact *contact;
84 NMField *field;
86 if ( fields == NULL || fields->tag == NULL || fields->ptr_value == 0 ||
87 !purple_strequal(fields->tag, NM_A_FA_CONTACT) )
89 return NULL;
92 contact = nm_create_contact();
94 if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
96 if (field->ptr_value)
97 contact->id = atoi((char *) field->ptr_value);
101 if ((field = nm_locate_field(NM_A_SZ_PARENT_ID, (NMField *) fields->ptr_value))) {
103 if (field->ptr_value)
104 contact->parent_id = atoi((char *) field->ptr_value);
108 if ((field =
109 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
111 if (field->ptr_value)
112 contact->seq = atoi((char *) field->ptr_value);
116 if ((field =
117 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
119 if (field->ptr_value)
120 contact->display_name = g_strdup((char *) field->ptr_value);
124 if ((field = nm_locate_field(NM_A_SZ_DN, (NMField *) fields->ptr_value))) {
126 if (field->ptr_value)
127 contact->dn = g_strdup((char *) field->ptr_value);
131 return contact;
134 void
135 nm_contact_update_list_properties(NMContact * contact, NMField * fields)
137 NMField *field;
139 if (contact == NULL || fields == NULL || fields->ptr_value == 0)
140 return;
142 if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
144 if (field->ptr_value)
145 contact->id = atoi((char *)field->ptr_value);
149 if ((field = nm_locate_field(NM_A_SZ_PARENT_ID, (NMField *) fields->ptr_value))) {
151 if (field->ptr_value)
152 contact->parent_id = atoi((char *) field->ptr_value);
156 if ((field =
157 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
159 if (field->ptr_value)
160 contact->seq = atoi((char *) field->ptr_value);
164 if ((field =
165 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
167 if (field->ptr_value) {
168 g_free(contact->display_name);
170 contact->display_name = g_strdup((char *) field->ptr_value);
175 if ((field = nm_locate_field(NM_A_SZ_DN, (NMField *) fields->ptr_value))) {
177 if (field->ptr_value) {
178 g_free(contact->dn);
180 contact->dn = g_strdup((char *) field->ptr_value);
186 NMField *
187 nm_contact_to_fields(NMContact * contact)
189 NMField *fields = NULL;
191 if (contact == NULL)
192 return NULL;
194 fields = nm_field_add_pointer(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
195 g_strdup_printf("%d", contact->id), NMFIELD_TYPE_UTF8);
197 fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
198 g_strdup_printf("%d", contact->parent_id), NMFIELD_TYPE_UTF8);
200 fields = nm_field_add_pointer(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
201 g_strdup_printf("%d", contact->seq), NMFIELD_TYPE_UTF8);
203 if (contact->display_name != NULL) {
204 fields = nm_field_add_pointer(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
205 g_strdup(contact->display_name), NMFIELD_TYPE_UTF8);
208 if (contact->dn != NULL) {
209 fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
210 g_strdup(contact->dn), NMFIELD_TYPE_UTF8);
213 return fields;
216 void
217 nm_contact_add_ref(NMContact * contact)
219 if (contact)
220 contact->ref_count++;
223 void
224 nm_release_contact(NMContact * contact)
226 if (contact == NULL)
227 return;
229 if (--(contact->ref_count) == 0) {
231 purple_debug(PURPLE_DEBUG_INFO, "novell",
232 "Releasing contact, total=%d\n", --count);
234 g_free(contact->display_name);
235 g_free(contact->dn);
237 if (contact->user_record) {
238 nm_release_user_record(contact->user_record);
241 g_free(contact);
246 const char *
247 nm_contact_get_display_name(NMContact * contact)
249 if (contact == NULL)
250 return NULL;
252 if (contact->user_record != NULL && contact->display_name == NULL) {
253 const char *full_name, *lname, *fname, *cn, *display_id;
255 full_name = nm_user_record_get_full_name(contact->user_record);
256 fname = nm_user_record_get_first_name(contact->user_record);
257 lname = nm_user_record_get_last_name(contact->user_record);
258 cn = nm_user_record_get_userid(contact->user_record);
259 display_id = nm_user_record_get_display_id(contact->user_record);
261 /* Try to build a display name. */
262 if (full_name) {
264 contact->display_name = g_strdup(full_name);
266 } else if (fname && lname) {
268 contact->display_name = g_strdup_printf("%s %s", fname, lname);
270 } else {
272 /* If auth attribute is set use it */
273 if (nm_user_record_get_auth_attr(contact->user_record) &&
274 display_id != NULL) {
276 contact->display_name = g_strdup(display_id);
278 } else {
280 /* Use CN or display id */
281 if (cn) {
283 contact->display_name = g_strdup(cn);
285 } else if (display_id) {
287 contact->display_name = g_strdup(display_id);
296 return contact->display_name;
299 void
300 nm_contact_set_display_name(NMContact * contact, const char *display_name)
302 if (contact == NULL)
303 return;
305 g_free(contact->display_name);
306 contact->display_name = NULL;
308 if (display_name)
309 contact->display_name = g_strdup(display_name);
312 void
313 nm_contact_set_dn(NMContact * contact, const char *dn)
315 if (contact == NULL)
316 return;
318 g_free(contact->dn);
319 contact->dn = NULL;
321 if (dn)
322 contact->dn = g_strdup(dn);
325 const char *
326 nm_contact_get_dn(NMContact * contact)
328 if (contact == NULL)
329 return NULL;
331 return contact->dn;
334 gpointer
335 nm_contact_get_data(NMContact * contact)
337 if (contact == NULL)
338 return NULL;
340 return contact->data;
344 nm_contact_get_id(NMContact * contact)
346 if (contact == NULL)
347 return -1;
349 return contact->id;
353 nm_contact_get_parent_id(NMContact * contact)
355 if (contact == NULL)
356 return -1;
358 return contact->parent_id;
361 void
362 nm_contact_set_data(NMContact * contact, gpointer data)
364 if (contact == NULL)
365 return;
367 contact->data = data;
370 void
371 nm_contact_set_user_record(NMContact * contact, NMUserRecord * user_record)
373 if (contact == NULL)
374 return;
376 if (contact->user_record) {
377 nm_release_user_record(contact->user_record);
380 nm_user_record_add_ref(user_record);
381 contact->user_record = user_record;
384 NMUserRecord *
385 nm_contact_get_user_record(NMContact * contact)
387 if (contact == NULL)
388 return NULL;
390 return contact->user_record;
393 const char *
394 nm_contact_get_userid(NMContact * contact)
396 NMUserRecord *user_record;
397 const char *userid = NULL;
399 if (contact == NULL)
400 return NULL;
402 user_record = nm_contact_get_user_record(contact);
403 if (user_record) {
404 userid = nm_user_record_get_userid(user_record);
407 return userid;
410 const char *
411 nm_contact_get_display_id(NMContact * contact)
413 NMUserRecord *user_record;
414 const char *id = NULL;
416 if (contact == NULL)
417 return NULL;
419 user_record = nm_contact_get_user_record(contact);
420 if (user_record) {
421 id = nm_user_record_get_display_id(user_record);
424 return id;
428 /*********************************************************************
429 * Folder API
430 *********************************************************************/
432 NMFolder *
433 nm_create_folder(const char *name)
435 NMFolder *folder = g_new0(NMFolder, 1);
437 if (name)
438 folder->name = g_strdup(name);
440 folder->ref_count = 1;
442 return folder;
445 NMFolder *
446 nm_create_folder_from_fields(NMField * fields)
448 NMField *field;
449 NMFolder *folder;
451 if (fields == NULL || fields->ptr_value == 0)
452 return NULL;
454 folder = g_new0(NMFolder, 1);
456 if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
458 if (field->ptr_value)
459 folder->id = atoi((char *) field->ptr_value);
462 if ((field =
463 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
465 if (field->ptr_value)
466 folder->seq = atoi((char *) field->ptr_value);
469 if ((field =
470 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
472 if (field->ptr_value)
473 folder->name = g_strdup((char *) field->ptr_value);
476 folder->ref_count = 1;
477 return folder;
480 NMField *
481 nm_folder_to_fields(NMFolder * folder)
483 NMField *fields = NULL;
485 if (folder == NULL)
486 return NULL;
488 fields = nm_field_add_pointer(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
489 g_strdup_printf("%d", folder->id), NMFIELD_TYPE_UTF8);
491 fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
492 g_strdup("0"), NMFIELD_TYPE_UTF8);
494 fields = nm_field_add_pointer(fields, NM_A_SZ_TYPE, 0, NMFIELD_METHOD_VALID, 0,
495 g_strdup("1"), NMFIELD_TYPE_UTF8);
497 fields = nm_field_add_pointer(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
498 g_strdup_printf("%d", folder->seq), NMFIELD_TYPE_UTF8);
500 if (folder->name != NULL) {
501 fields = nm_field_add_pointer(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
502 g_strdup(folder->name), NMFIELD_TYPE_UTF8);
506 return fields;
509 void
510 nm_folder_update_list_properties(NMFolder * folder, NMField * fields)
512 NMField *field;
514 if (folder == NULL || fields == NULL || fields->ptr_value == 0)
515 return;
517 if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
519 if (field->ptr_value)
520 folder->id = atoi((char *) field->ptr_value);
524 if ((field =
525 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
527 if (field->ptr_value)
528 folder->seq = atoi((char *) field->ptr_value);
532 if ((field =
533 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
535 if (field->ptr_value) {
536 g_free(folder->name);
538 folder->name = g_strdup((char *) field->ptr_value);
545 void
546 nm_release_folder(NMFolder * folder)
548 if (folder == NULL)
549 return;
551 if (--(folder->ref_count) == 0) {
552 g_free(folder->name);
554 if (folder->folders) {
555 _release_folder_folders(folder);
558 if (folder->contacts) {
559 _release_folder_contacts(folder);
562 g_free(folder);
567 void
568 nm_folder_add_ref(NMFolder * folder)
570 if (folder)
571 folder->ref_count++;
575 nm_folder_get_subfolder_count(NMFolder * folder)
577 if (folder == NULL)
578 return 0;
580 if (folder->folders)
581 return g_slist_length(folder->folders);
582 else
583 return 0;
586 NMFolder *
587 nm_folder_get_subfolder(NMFolder * folder, int index)
589 if (folder == NULL)
590 return NULL;
592 if (folder->folders)
593 return (NMFolder *) g_slist_nth_data(folder->folders, index);
594 else
595 return NULL;
599 nm_folder_get_contact_count(NMFolder * folder)
601 if (folder == NULL)
602 return 0;
604 if (folder->contacts != NULL)
605 return g_slist_length(folder->contacts);
606 else
607 return 0;
610 NMContact *
611 nm_folder_get_contact(NMFolder * folder, int index)
613 if (folder == NULL)
614 return NULL;
616 if (folder->contacts)
617 return (NMContact *) g_slist_nth_data(folder->contacts, index);
618 else
619 return NULL;
622 const char *
623 nm_folder_get_name(NMFolder * folder)
625 if (folder == NULL)
626 return NULL;
628 return folder->name;
631 void
632 nm_folder_set_name(NMFolder * folder, const char *name)
634 if (folder == NULL || name == NULL)
635 return;
637 g_free(folder->name);
639 folder->name = g_strdup(name);
643 nm_folder_get_id(NMFolder * folder)
645 if (folder == NULL) {
646 return -1;
649 return folder->id;
652 void
653 nm_folder_add_folder_to_list(NMFolder * root, NMFolder * folder)
655 GSList *node;
657 if (root == NULL || folder == NULL)
658 return;
660 node = root->folders;
661 while (node) {
662 if (folder->seq <= ((NMFolder *) node->data)->seq) {
663 nm_folder_add_ref(folder);
664 root->folders = g_slist_insert_before(root->folders, node, folder);
665 break;
667 node = g_slist_next(node);
669 if (node == NULL) {
670 nm_folder_add_ref(folder);
671 root->folders = g_slist_append(root->folders, folder);
675 void
676 nm_folder_remove_contact(NMFolder * folder, NMContact * contact)
678 GSList *node;
680 if (folder == NULL || contact == NULL)
681 return;
683 node = folder->contacts;
684 while (node) {
685 if (contact->id == ((NMContact *) (node->data))->id) {
686 folder->contacts = g_slist_remove(folder->contacts, node->data);
687 nm_release_contact(contact);
688 break;
690 node = g_slist_next(node);
694 void
695 nm_folder_add_contact_to_list(NMFolder * root_folder, NMContact * contact)
697 GSList *node = NULL;
698 NMFolder *folder = root_folder;
700 if (folder == NULL || contact == NULL)
701 return;
703 /* Find folder to add contact to */
704 if (contact->parent_id != 0) {
705 node = folder->folders;
706 while (node) {
707 folder = (NMFolder *) node->data;
708 if (contact->parent_id == folder->id) {
709 break;
711 folder = NULL;
712 node = g_slist_next(node);
716 /* Add contact to list */
717 if (folder) {
718 node = folder->contacts;
719 while (node) {
720 if (contact->seq <= ((NMContact *) (node->data))->seq) {
721 nm_contact_add_ref(contact);
722 folder->contacts =
723 g_slist_insert_before(folder->contacts, node, contact);
724 break;
726 node = g_slist_next(node);
729 if (node == NULL) {
730 nm_contact_add_ref(contact);
731 folder->contacts = g_slist_append(folder->contacts, contact);
736 void
737 nm_folder_add_contacts_and_folders(NMUser * user, NMFolder * root,
738 NMField * fields)
740 /* Add the contacts and folders from the field array */
741 if (user && root && fields) {
742 _add_folders(root, fields);
743 _add_contacts(user, root, fields);
747 gpointer
748 nm_folder_find_item_by_object_id(NMFolder * root_folder, int object_id)
750 int cnt, cnt2, i, j;
751 gpointer item = NULL;
752 NMFolder *folder;
753 NMContact *contact;
755 if (root_folder == NULL)
756 return NULL;
758 /* Check all contacts for the top level folder */
759 cnt = nm_folder_get_contact_count(root_folder);
760 for (i = 0; i < cnt; i++) {
761 contact = nm_folder_get_contact(root_folder, i);
762 if (contact && (contact->id == object_id)) {
763 item = contact;
764 break;
768 /* If we haven't found the item yet, check the subfolders */
769 if (item == NULL) {
770 cnt = nm_folder_get_subfolder_count(root_folder);
771 for (i = 0; (i < cnt) && (item == NULL); i++) {
772 folder = nm_folder_get_subfolder(root_folder, i);
774 /* Check the id of this folder */
775 if (folder && (folder->id == object_id)) {
776 item = folder;
777 break;
780 /* Check all contacts for this folder */
781 cnt2 = nm_folder_get_contact_count(folder);
782 for (j = 0; j < cnt2; j++) {
783 contact = nm_folder_get_contact(folder, j);
784 if (contact && (contact->id == object_id)) {
785 item = contact;
786 break;
792 return item;
795 NMContact *
796 nm_folder_find_contact_by_userid(NMFolder * folder, const char *userid)
798 int cnt, i;
799 NMContact *tmp, *contact = NULL;
801 if (folder == NULL || userid == NULL)
802 return NULL;
804 cnt = nm_folder_get_contact_count(folder);
805 for (i = 0; i < cnt; i++) {
806 tmp = nm_folder_get_contact(folder, i);
807 if (tmp && nm_utf8_str_equal(nm_contact_get_userid(tmp), userid)) {
808 contact = tmp;
809 break;
813 return contact;
816 NMContact *
817 nm_folder_find_contact_by_display_id(NMFolder * folder, const char *display_id)
819 int cnt, i;
820 NMContact *tmp, *contact = NULL;
822 if (folder == NULL || display_id == NULL)
823 return NULL;
825 cnt = nm_folder_get_contact_count(folder);
826 for (i = 0; i < cnt; i++) {
827 tmp = nm_folder_get_contact(folder, i);
828 if (tmp && nm_utf8_str_equal(nm_contact_get_display_id(tmp), display_id)) {
829 contact = tmp;
830 break;
834 return contact;
837 NMContact *
838 nm_folder_find_contact(NMFolder * folder, const char *dn)
840 int cnt, i;
841 NMContact *tmp, *contact = NULL;
843 if (folder == NULL || dn == NULL)
844 return NULL;
846 cnt = nm_folder_get_contact_count(folder);
847 for (i = 0; i < cnt; i++) {
848 tmp = nm_folder_get_contact(folder, i);
849 if (tmp && nm_utf8_str_equal(nm_contact_get_dn(tmp), dn)) {
850 contact = tmp;
851 break;
855 return contact;
859 /*********************************************************************
860 * Utility functions
861 *********************************************************************/
863 static void
864 _release_folder_contacts(NMFolder * folder)
866 GSList *cnode;
867 NMContact *contact;
869 for (cnode = folder->contacts; cnode; cnode = cnode->next) {
870 contact = cnode->data;
871 cnode->data = NULL;
872 nm_release_contact(contact);
875 g_slist_free(folder->contacts);
876 folder->contacts = NULL;
879 static void
880 _release_folder_folders(NMFolder * folder)
882 GSList *fnode;
883 NMFolder *subfolder;
885 if (folder == NULL)
886 return;
888 for (fnode = folder->folders; fnode; fnode = fnode->next) {
889 subfolder = fnode->data;
890 fnode->data = NULL;
891 nm_release_folder(subfolder);
894 g_slist_free(folder->folders);
895 folder->folders = NULL;
898 static void
899 _add_folders(NMFolder * root, NMField * fields)
901 NMFolder *folder = NULL;
902 NMField *locate = NULL;
904 locate = nm_locate_field(NM_A_FA_FOLDER, fields);
905 while (locate != NULL) {
907 /* Create a new folder */
908 folder = nm_create_folder_from_fields(locate);
910 /* Add subfolder to roots folder list */
911 nm_folder_add_folder_to_list(root, folder);
913 /* Decrement the ref count */
914 nm_release_folder(folder);
916 /* Find the next folder */
917 locate = nm_locate_field(NM_A_FA_FOLDER, locate+1);
922 static void
923 _add_contacts(NMUser * user, NMFolder * folder, NMField * fields)
925 NMContact *contact = NULL;
926 NMField *locate = NULL, *details;
927 NMUserRecord *user_record = NULL;
929 locate = nm_locate_field(NM_A_FA_CONTACT, fields);
930 while (locate != NULL) {
932 /* Create a new contact from the fields */
933 contact = nm_create_contact_from_fields(locate);
935 /* Add it to our contact list */
936 nm_folder_add_contact_to_list(folder, contact);
938 /* Update the contact cache */
939 nm_user_add_contact(user, contact);
941 /* Update the user record cache */
942 if ((details = nm_locate_field(NM_A_FA_USER_DETAILS,
943 (NMField *) locate->ptr_value))) {
944 user_record = nm_find_user_record(user, nm_contact_get_dn(contact));
945 if (user_record == NULL) {
946 user_record = nm_create_user_record_from_fields(details);
947 nm_user_record_set_dn(user_record, nm_contact_get_dn(contact));
948 nm_user_add_user_record(user, user_record);
949 nm_release_user_record(user_record);
951 nm_contact_set_user_record(contact, user_record);
954 nm_release_contact(contact);
956 locate = nm_locate_field(NM_A_FA_CONTACT, locate+1);