comparison libpurple/protocols/msn/contact.c @ 20685:02df6998b466

propagate from branch 'im.pidgin.rlaager.merging.2_2_1_conflicts' (head 4ad1081695d083df424898e6e7091f731b401265) to branch 'im.pidgin.pidgin' (head d33243e8f5347776c81f81a0e4ba3a76ae5505a5)
author Richard Laager <rlaager@wiktel.com>
date Fri, 28 Sep 2007 16:34:43 +0000
parents 0e1bc5c51030
children 4dd60add6a7c
comparison
equal deleted inserted replaced
20258:509ca8ebe515 20685:02df6998b466
1 /**
2 * @file contact.c
3 * get MSN contacts via SOAP request
4 * created by MaYuan<mayuan2006@gmail.com>
5 *
6 * purple
7 *
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27 #include "msn.h"
28 #include "contact.h"
29 #include "xmlnode.h"
30 #include "group.h"
31
32 const char *MsnSoapPartnerScenarioText[] =
33 {
34 "Initial",
35 "ContactSave",
36 "MessengerPendingList",
37 "ContactMsgrAPI",
38 "BlockUnblock"
39 };
40
41 const char *MsnMemberRole[] =
42 {
43 "Forward",
44 "Allow",
45 "Block",
46 "Reverse",
47 "Pending"
48 };
49
50 /* new a contact */
51 MsnContact *
52 msn_contact_new(MsnSession *session)
53 {
54 MsnContact *contact;
55
56 contact = g_new0(MsnContact, 1);
57 contact->session = session;
58 contact->soapconn = msn_soap_new(session,contact,1);
59
60 return contact;
61 }
62
63 /* destroy the contact */
64 void
65 msn_contact_destroy(MsnContact *contact)
66 {
67 msn_soap_destroy(contact->soapconn);
68 g_free(contact);
69 }
70
71 MsnCallbackState *
72 msn_callback_state_new(void)
73 {
74 return g_new0(MsnCallbackState, 1);
75 }
76
77 void
78 msn_callback_state_free(MsnCallbackState *state)
79 {
80 if (state == NULL)
81 return;
82
83 g_free(state->who);
84 g_free(state->uid);
85 g_free(state->old_group_name);
86 g_free(state->new_group_name);
87 g_free(state->guid);
88
89 g_free(state);
90 }
91
92 void
93 msn_callback_state_set_who(MsnCallbackState *state, const gchar *who)
94 {
95 gchar *new_str = NULL;
96
97 g_return_if_fail(state != NULL);
98
99 if (who != NULL)
100 new_str = g_strdup(who);
101
102 g_free(state->who);
103 state->who = new_str;
104 }
105
106 void
107 msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid)
108 {
109 gchar *new_str = NULL;
110
111 g_return_if_fail(state != NULL);
112
113 if (uid != NULL)
114 new_str = g_strdup(uid);
115
116 g_free(state->uid);
117 state->uid = new_str;
118 }
119
120 void
121 msn_callback_state_set_old_group_name(MsnCallbackState *state, const gchar *old_group_name)
122 {
123 gchar *new_str = NULL;
124
125 g_return_if_fail(state != NULL);
126
127 if (old_group_name != NULL)
128 new_str = g_strdup(old_group_name);
129
130 g_free(state->old_group_name);
131 state->old_group_name = new_str;
132 }
133
134 void
135 msn_callback_state_set_new_group_name(MsnCallbackState *state, const gchar *new_group_name)
136 {
137 gchar *new_str = NULL;
138
139 g_return_if_fail(state != NULL);
140
141 if (new_group_name != NULL)
142 new_str = g_strdup(new_group_name);
143
144 g_free(state->new_group_name);
145 state->new_group_name = new_str;
146 }
147
148 void
149 msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid)
150 {
151 gchar *new_str = NULL;
152
153 g_return_if_fail(state != NULL);
154
155 if (guid != NULL)
156 new_str = g_strdup(guid);
157
158 g_free(state->guid);
159 state->guid = new_str;
160 }
161
162
163 void
164 msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id)
165 {
166 g_return_if_fail(state != NULL);
167
168 state->list_id = list_id;
169 }
170
171 void
172 msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action)
173 {
174 g_return_if_fail(state != NULL);
175
176 state->action |= action;
177 }
178
179 /*contact SOAP server login error*/
180 static void
181 msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error)
182 {
183 MsnSession *session;
184
185 session = soapconn->session;
186 g_return_if_fail(session != NULL);
187
188 msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server"));
189 }
190
191 /*msn contact SOAP server connect process*/
192 static gboolean
193 msn_contact_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc)
194 {
195 MsnSession * session;
196 MsnContact *contact;
197
198 contact = soapconn->parent;
199 g_return_val_if_fail(contact != NULL, TRUE);
200
201 session = contact->session;
202 g_return_val_if_fail(session != NULL, FALSE);
203
204 /*login ok!We can retrieve the contact list*/
205 // msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
206 return TRUE;
207 }
208
209 /*get MSN member role utility*/
210 static MsnListId
211 msn_get_memberrole(char *role)
212 {
213 g_return_val_if_fail(role != NULL, 0);
214
215 if (!strcmp(role,"Allow")) {
216 return MSN_LIST_AL;
217 } else if (!strcmp(role,"Block")) {
218 return MSN_LIST_BL;
219 } else if (!strcmp(role,"Reverse")) {
220 return MSN_LIST_RL;
221 } else if (!strcmp(role,"Pending")) {
222 return MSN_LIST_PL;
223 }
224 return 0;
225 }
226
227 /*get User Type*/
228 static int
229 msn_get_user_type(char *type)
230 {
231 g_return_val_if_fail(type != NULL, 0);
232
233 if (!strcmp(type,"Regular")) {
234 return MSN_USER_TYPE_PASSPORT;
235 }
236 if (!strcmp(type,"Live")) {
237 return MSN_USER_TYPE_PASSPORT;
238 }
239 if (!strcmp(type,"LivePending")) {
240 return MSN_USER_TYPE_PASSPORT;
241 }
242
243 return MSN_USER_TYPE_UNKNOWN;
244 }
245
246 /* Create the AddressBook in the server, if we don't have one */
247 static gboolean
248 msn_create_address_cb(MsnSoapConn *soapconn)
249 {
250 MsnContact *contact;
251
252 if (soapconn->body == NULL)
253 return TRUE;
254
255 contact = soapconn->parent;
256 g_return_val_if_fail(contact != NULL, TRUE);
257
258 purple_debug_info("MSN AddressBook", "Address Book successfully created!\n");
259 msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
260
261 // msn_soap_free_read_buf(soapconn);
262 return TRUE;
263 }
264
265 static void
266 msn_create_address_written_cb(MsnSoapConn *soapconn)
267 {
268 purple_debug_info("MSN AddressBook","AddressBookAdd written\n");
269 soapconn->read_cb = msn_create_address_cb;
270
271 return;
272 }
273
274 static void
275 msn_create_address_book(MsnContact * contact)
276 {
277 MsnSoapReq *soap_request;
278 gchar *body;
279
280 g_return_if_fail(contact != NULL);
281 g_return_if_fail(contact->session != NULL);
282 g_return_if_fail(contact->session->user != NULL);
283 g_return_if_fail(contact->session->user->passport != NULL);
284
285 purple_debug_info("MSN AddressBook","Creating an Address Book.\n");
286
287 body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport);
288
289 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
290 MSN_ADDRESS_BOOK_POST_URL,MSN_ADD_ADDRESSBOOK_SOAP_ACTION,
291 body,
292 NULL,
293 msn_create_address_cb,
294 msn_create_address_written_cb,
295 msn_contact_connect_init);
296 msn_soap_post(contact->soapconn, soap_request);
297
298 g_free(body);
299
300 return;
301 }
302
303 /*parse contact list*/
304 static void
305 msn_parse_contact_list(MsnContact * contact)
306 {
307 MsnSession * session;
308 MsnListOp list_op = 0;
309 MsnListId list;
310 char * passport, *typedata;
311 xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
312 xmlnode *node, *body, *response, *result, *services;
313 xmlnode *service, *memberships, *info, *handle, *handletype;
314 xmlnode *membershipnode, *members, *member, *passportNode;
315
316 session = contact->session;
317 node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
318
319 if (node == NULL) {
320 purple_debug_error("MSNCL","Unable to parse SOAP data!\n");
321 return;
322 }
323
324 purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len);
325
326 purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node,
327 node->name ? node->name : "(null)",
328 (node->child && node->child->name) ? node->child->name : "(null)",
329 (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)");
330
331 body = xmlnode_get_child(node, "Body");
332
333 if (body == NULL) {
334 purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n");
335 xmlnode_free(node);
336 return;
337 }
338 purple_debug_info("MSNCL","Body @ %p: Name: '%s'\n",body,body->name);
339
340 /* Did we receive a <Fault> ? */
341 if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) {
342 purple_debug_info("MSNCL","Fault received from SOAP server!\n");
343
344 if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) {
345 gchar * faultstring = xmlnode_get_data(faultstringnode);
346 purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)");
347 g_free(faultstring);
348 }
349 if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) {
350 purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name);
351
352 if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) {
353 purple_debug_info("MSNCL","errorcode @ %p, name: %s\n", errorcode, errorcode->name);
354
355 if (errorcode->child != NULL) {
356 gchar *errorcodestring = xmlnode_get_data(errorcode);
357 purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)");
358
359 if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) {
360 xmlnode_free(node);
361 g_free(errorcodestring);
362 msn_create_address_book(contact);
363 return;
364 }
365 g_free(errorcodestring);
366 }
367 }
368 }
369 xmlnode_free(node);
370 msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
371 return;
372 }
373
374 response = xmlnode_get_child(body,"FindMembershipResponse");
375
376 if (response == NULL) {
377 /* we may get a response if our cache data is too old:
378 *
379 * <faultstring>Need to do full sync. Can't sync deltas Client
380 * has too old a copy for us to do a delta sync</faultstring>
381 */
382 xmlnode_free(node);
383 msn_get_contact_list(contact, MSN_PS_INITIAL, NULL);
384 return;
385 }
386 purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name);
387
388 result = xmlnode_get_child(response,"FindMembershipResult");
389 if (result == NULL) {
390 purple_debug_warning("MSNCL","Received No Update!\n");
391 xmlnode_free(node);
392 return;
393 }
394 purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n", result, result->name);
395
396 if ( (services = xmlnode_get_child(result,"Services")) == NULL) {
397 purple_debug_misc("MSNCL","No <Services> received.\n");
398 xmlnode_free(node);
399 return;
400 }
401
402 purple_debug_info("MSNCL","Services @ %p\n",services);
403
404 for (service = xmlnode_get_child(services, "Service"); service;
405 service = xmlnode_get_next_twin(service)) {
406 purple_debug_info("MSNCL","Service @ %p\n",service);
407
408 if ( (info = xmlnode_get_child(service,"Info")) == NULL ) {
409 purple_debug_error("MSNCL","Error getting 'Info' child node\n");
410 continue;
411 }
412 if ( (handle = xmlnode_get_child(info,"Handle")) == NULL ) {
413 purple_debug_error("MSNCL","Error getting 'Handle' child node\n");
414 continue;
415 }
416 if ( (handletype = xmlnode_get_child(handle,"Type")) == NULL ) {
417 purple_debug_error("MSNCL","Error getting 'Type' child node\n");
418 continue;
419 }
420
421 if ( (typedata = xmlnode_get_data(handletype)) == NULL) {
422 purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n");
423 continue;
424 }
425
426 purple_debug_info("MSNCL","processing '%s' Service\n", typedata);
427
428 if ( !g_strcasecmp(typedata, "Profile") ) {
429 /* Process Windows Live 'Messenger Roaming Identity' */
430 g_free(typedata);
431 continue;
432 }
433
434 if ( !g_strcasecmp(typedata, "Messenger") ) {
435 char *LastChangeStr = NULL;
436 xmlnode *LastChangeNode;
437
438 /*Last Change Node*/
439 if ((LastChangeNode = xmlnode_get_child(service, "LastChange")))
440 LastChangeStr = xmlnode_get_data(LastChangeNode);
441 purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)");
442 purple_account_set_string(session->account, "CLLastChange", LastChangeStr);
443 g_free(LastChangeStr);
444
445 memberships = xmlnode_get_child(service,"Memberships");
446 if (memberships == NULL) {
447 purple_debug_warning("MSNCL","Memberships = NULL, cleaning up and returning.\n");
448 g_free(typedata);
449 xmlnode_free(node);
450 return;
451 }
452 purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name);
453 for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode;
454 membershipnode = xmlnode_get_next_twin(membershipnode)){
455 xmlnode *roleNode;
456 char *role = NULL;
457 list = 0;
458
459 if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) {
460 role = xmlnode_get_data(roleNode);
461 list = msn_get_memberrole(role);
462 }
463 list_op = 1 << list;
464
465 purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op);
466
467 g_free(role);
468
469 members = xmlnode_get_child(membershipnode, "Members");
470 for (member = xmlnode_get_child(members, "Member"); member;
471 member = xmlnode_get_next_twin(member)){
472 MsnUser *user = NULL;
473 xmlnode *typeNode, *membershipIdNode = NULL;
474 gchar *type, *membershipId = NULL;
475 const char *member_type = xmlnode_get_attrib(member, "type");
476
477 purple_debug_info("MSNCL","Member type: %s\n", member_type ? member_type : "(null)");
478
479 if (!member_type)
480 continue;
481
482 if(!g_strcasecmp(member_type, "PassportMember") ) {
483 passport = type = NULL;
484 if ((passportNode = xmlnode_get_child(member, "PassportName")))
485 passport = xmlnode_get_data(passportNode);
486 if ((typeNode = xmlnode_get_child(member, "Type")))
487 type = xmlnode_get_data(typeNode);
488 purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)");
489 /* Why do we even bother parsing it just to free it??? */
490 g_free(type);
491
492 user = msn_userlist_find_add_user(session->userlist,passport,NULL);
493 g_free(passport);
494
495 membershipIdNode = xmlnode_get_child(member,"MembershipId");
496 if (membershipIdNode != NULL) {
497 membershipId = xmlnode_get_data(membershipIdNode);
498 if (membershipId != NULL) {
499 user->membership_id[list] = atoi(membershipId);
500 g_free(membershipId);
501 }
502 }
503
504 msn_got_lst_user(session, user, list_op, NULL);
505 }
506 else if (!g_strcasecmp(member_type, "PhoneMember")) {
507 }
508 else if (!g_strcasecmp(member_type, "EmailMember")) {
509 xmlnode *emailNode;
510 passport = NULL;
511
512 if ((emailNode = xmlnode_get_child(member, "Email")))
513 passport = xmlnode_get_data(emailNode);
514 purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op);
515
516 user = msn_userlist_find_add_user(session->userlist, passport, NULL);
517 g_free(passport);
518
519 membershipIdNode = xmlnode_get_child(member,"MembershipId");
520 if (membershipIdNode != NULL) {
521 membershipId = xmlnode_get_data(membershipIdNode);
522 if (membershipId != NULL) {
523 user->membership_id[list] = atoi(membershipId);
524 g_free(membershipId);
525 }
526 }
527
528 msn_got_lst_user(session, user, list_op, NULL);
529 }
530 }
531 }
532 g_free(typedata); /* Free 'Type' node data after processing 'Messenger' Service */
533 }
534 }
535
536 xmlnode_free(node); /* Free the whole XML tree */
537 }
538
539 static gboolean
540 msn_get_contact_list_cb(MsnSoapConn *soapconn)
541 {
542 MsnContact *contact;
543 MsnSession *session;
544 const char *abLastChange;
545 const char *dynamicItemLastChange;
546 gchar *partner_scenario;
547
548 if (soapconn->body == NULL)
549 return TRUE;
550
551 purple_debug_misc("MSNCL","Got the contact list!\n");
552
553 contact = soapconn->parent;
554 g_return_val_if_fail(contact != NULL, TRUE);
555 session = soapconn->session;
556 g_return_val_if_fail(session != NULL, FALSE);
557 g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
558
559 partner_scenario = soapconn->data_cb;
560
561 msn_parse_contact_list(contact);
562 /*free the read buffer*/
563 msn_soap_free_read_buf(soapconn);
564
565 abLastChange = purple_account_get_string(session->account, "ablastChange", NULL);
566 dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL);
567
568 if (!strcmp(partner_scenario, MsnSoapPartnerScenarioText[MSN_PS_INITIAL])) {
569
570 #ifdef MSN_PARTIAL_LISTS
571 /* XXX: this should be enabled when we can correctly do partial
572 syncs with the server. Currently we need to retrieve the whole
573 list to detect sync issues */
574 msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
575 #else
576 msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL);
577 #endif
578 } else {
579 msn_soap_free_read_buf(soapconn);
580 }
581
582 return TRUE;
583 }
584
585 static void
586 msn_get_contact_written_cb(MsnSoapConn *soapconn)
587 {
588 purple_debug_misc("MSNCL","Sent SOAP request for the contact list.\n");
589 soapconn->read_cb = msn_get_contact_list_cb;
590 }
591
592 /* SOAP get contact list*/
593 void
594 msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time)
595 {
596 MsnSoapReq *soap_request;
597 gchar *body = NULL;
598 gchar * update_str;
599 const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario];
600
601 purple_debug_misc("MSNCL","Getting Contact List.\n");
602
603 if ( update_time != NULL ) {
604 purple_debug_info("MSNCL","Last update time: %s\n",update_time);
605 update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time);
606 } else {
607 update_str = g_strdup("");
608 }
609
610 body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str);
611 g_free(update_str);
612
613 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
614 MSN_GET_CONTACT_POST_URL,
615 MSN_GET_CONTACT_SOAP_ACTION,
616 body,
617 (gpointer) partner_scenario_str,
618 msn_get_contact_list_cb,
619 msn_get_contact_written_cb,
620 msn_contact_connect_init);
621 msn_soap_post(contact->soapconn,soap_request);
622 g_free(body);
623 }
624
625 static void
626 msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node)
627 {
628 MsnSession *session = contact->session;
629 xmlnode *group;
630
631 purple_debug_info("MsnAb","msn_parse_addressbook_groups()\n");
632
633 for(group = xmlnode_get_child(node, "Group"); group;
634 group = xmlnode_get_next_twin(group)){
635 xmlnode *groupId, *groupInfo, *groupname;
636 char *group_id, *group_name;
637
638 groupId = xmlnode_get_child(group,"groupId");
639 group_id = xmlnode_get_data(groupId);
640 groupInfo = xmlnode_get_child(group,"groupInfo");
641 groupname = xmlnode_get_child(groupInfo,"name");
642 group_name = xmlnode_get_data(groupname);
643
644 msn_group_new(session->userlist, group_id, group_name);
645
646 if (group_id == NULL){
647 /* Group of ungroupped buddies */
648 g_free(group_name);
649 continue;
650 }
651
652 purple_debug_info("MsnAB","group_id: %s, name: %s\n",group_id,group_name);
653 if ((purple_find_group(group_name)) == NULL){
654 PurpleGroup *g = purple_group_new(group_name);
655 purple_blist_add_group(g, NULL);
656 }
657 g_free(group_id);
658 g_free(group_name);
659 }
660 }
661
662 static void
663 msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node)
664 {
665 MsnSession *session = contact->session;
666 xmlnode *contactNode;
667 char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL;
668
669 for(contactNode = xmlnode_get_child(node, "Contact"); contactNode;
670 contactNode = xmlnode_get_next_twin(contactNode)) {
671 xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds;
672 MsnUser *user;
673 MsnUserType usertype;
674
675 if (!(contactId = xmlnode_get_child(contactNode,"contactId"))
676 || !(contactInfo = xmlnode_get_child(contactNode, "contactInfo"))
677 || !(contactType = xmlnode_get_child(contactInfo, "contactType")))
678 continue;
679
680 g_free(passport);
681 g_free(Name);
682 g_free(uid);
683 g_free(type);
684 passport = Name = uid = type = NULL;
685
686 uid = xmlnode_get_data(contactId);
687 type = xmlnode_get_data(contactType);
688
689 /*setup the Display Name*/
690 if (type && !strcmp(type, "Me")){
691 char *friendly = NULL;
692 if ((displayName = xmlnode_get_child(contactInfo, "displayName")))
693 friendly = xmlnode_get_data(displayName);
694 purple_connection_set_display_name(session->account->gc, friendly ? purple_url_decode(friendly) : NULL);
695 g_free(friendly);
696 continue; /* Not adding own account as buddy to buddylist */
697 }
698
699 usertype = msn_get_user_type(type);
700 passportName = xmlnode_get_child(contactInfo, "passportName");
701 if (passportName == NULL) {
702 xmlnode *emailsNode, *contactEmailNode, *emailNode;
703 xmlnode *messengerEnabledNode;
704 char *msnEnabled;
705
706 /*TODO: add it to the none-instant Messenger group and recognize as email Membership*/
707 /*Yahoo User?*/
708 emailsNode = xmlnode_get_child(contactInfo, "emails");
709 if (emailsNode == NULL) {
710 /*TODO: need to support the Mobile type*/
711 continue;
712 }
713 for(contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode;
714 contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){
715 if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) {
716 /* XXX: Should this be a continue instead of a break? It seems like it'd cause unpredictable results otherwise. */
717 break;
718 }
719
720 msnEnabled = xmlnode_get_data(messengerEnabledNode);
721
722 if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) {
723 g_free(passport);
724 passport = xmlnode_get_data(emailNode);
725 }
726
727 if(msnEnabled && !strcmp(msnEnabled, "true")) {
728 /*Messenger enabled, Get the Passport*/
729 purple_debug_info("MsnAB", "Yahoo User %s\n", passport ? passport : "(null)");
730 usertype = MSN_USER_TYPE_YAHOO;
731 g_free(msnEnabled);
732 break;
733 } else {
734 /*TODO maybe we can just ignore it in Purple?*/
735 purple_debug_info("MSNAB", "Other type user\n");
736 }
737
738 g_free(msnEnabled);
739 }
740 } else {
741 passport = xmlnode_get_data(passportName);
742 }
743
744 if (passport == NULL)
745 continue;
746
747 if ((displayName = xmlnode_get_child(contactInfo, "displayName")))
748 Name = xmlnode_get_data(displayName);
749 else
750 Name = g_strdup(passport);
751
752 purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s}\n",
753 passport, uid ? uid : "(null)", Name ? Name : "(null)");
754
755 user = msn_userlist_find_add_user(session->userlist, passport, Name);
756 msn_user_set_uid(user, uid);
757 msn_user_set_type(user, usertype);
758
759 purple_debug_misc("MsnAB","parse guid...\n");
760 groupIds = xmlnode_get_child(contactInfo, "groupIds");
761 if (groupIds) {
762 for (guid = xmlnode_get_child(groupIds, "guid"); guid;
763 guid = xmlnode_get_next_twin(guid)){
764 char *group_id = xmlnode_get_data(guid);
765 msn_user_add_group_id(user, group_id);
766 purple_debug_misc("MsnAB", "guid:%s\n", group_id ? group_id : "(null)");
767 g_free(group_id);
768 }
769 } else {
770 /*not in any group,Then set default group*/
771 msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID);
772 }
773
774 msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL);
775 }
776
777 g_free(passport);
778 g_free(Name);
779 g_free(uid);
780 g_free(type);
781 }
782
783 static gboolean
784 msn_parse_addressbook(MsnContact * contact)
785 {
786 MsnSession * session;
787 xmlnode * node,*body,*response,*result;
788 xmlnode *groups;
789 xmlnode *contacts;
790 xmlnode *abNode;
791 xmlnode *fault, *faultstringnode, *faultdetail, *errorcode;
792
793 session = contact->session;
794
795
796
797 node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len);
798 if ( node == NULL ) {
799 purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len);
800 return FALSE;
801 }
802
803 purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len);
804
805 purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name);
806
807 body = xmlnode_get_child(node,"Body");
808 purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name);
809
810 /* TODO: This appears to be used in a number of places and should be de-duplicated */
811 if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) {
812 purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n");
813
814 if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) {
815 gchar *faultstring = xmlnode_get_data(faultstringnode);
816 purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)");
817 g_free(faultstring);
818 }
819 if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) {
820 purple_debug_info("MSN AddressBook","detail @ %p, name: %s\n",faultdetail, faultdetail->name);
821
822 if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) {
823 gchar *errorcodestring;
824 purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name);
825
826 errorcodestring = xmlnode_get_data(errorcode);
827 purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)");
828
829 if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) {
830 g_free(errorcodestring);
831 xmlnode_free(node);
832 return TRUE;
833 }
834 g_free(errorcodestring);
835 }
836 }
837 xmlnode_free(node);
838 return FALSE;
839 }
840
841
842 response = xmlnode_get_child(body,"ABFindAllResponse");
843
844 if (response == NULL) {
845 xmlnode_free(node);
846 return FALSE;
847 }
848
849 purple_debug_misc("MSN SOAP","response{%p},name:%s\n",response,response->name);
850 result = xmlnode_get_child(response,"ABFindAllResult");
851 if(result == NULL){
852 purple_debug_misc("MSNAB","receive no address book update\n");
853 xmlnode_free(node);
854 return TRUE;
855 }
856 purple_debug_info("MSN SOAP","result{%p},name:%s\n",result,result->name);
857
858 /*Process Group List*/
859 groups = xmlnode_get_child(result,"groups");
860 if (groups != NULL) {
861 msn_parse_addressbook_groups(contact, groups);
862 }
863
864 /*add a default No group to set up the no group Membership*/
865 msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID,
866 MSN_INDIVIDUALS_GROUP_NAME);
867 purple_debug_misc("MsnAB","group_id:%s name:%s\n",
868 MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME);
869 if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){
870 PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME);
871 purple_blist_add_group(g, NULL);
872 }
873
874 /*add a default No group to set up the no group Membership*/
875 msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
876 purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
877 if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){
878 PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME);
879 purple_blist_add_group(g, NULL);
880 }
881
882 /*Process contact List*/
883 purple_debug_info("MSNAB","process contact list...\n");
884 contacts =xmlnode_get_child(result,"contacts");
885 if (contacts != NULL) {
886 msn_parse_addressbook_contacts(contact, contacts);
887 }
888
889 abNode =xmlnode_get_child(result,"ab");
890 if(abNode != NULL){
891 xmlnode *node2;
892 char *tmp = NULL;
893
894 if ((node2 = xmlnode_get_child(abNode, "lastChange")))
895 tmp = xmlnode_get_data(node2);
896 purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)");
897 purple_account_set_string(session->account, "ablastChange", tmp);
898
899 g_free(tmp); tmp = NULL;
900 if ((node2 = xmlnode_get_child(abNode, "DynamicItemLastChanged")))
901 tmp = xmlnode_get_data(node2);
902 purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)");
903 purple_account_set_string(session->account, "DynamicItemLastChanged", tmp);
904 g_free(tmp);
905 }
906
907 xmlnode_free(node);
908 msn_soap_free_read_buf(contact->soapconn);
909 return TRUE;
910 }
911
912 static gboolean
913 msn_get_address_cb(MsnSoapConn *soapconn)
914 {
915 MsnContact *contact;
916 MsnSession *session;
917
918 if (soapconn->body == NULL)
919 return TRUE;
920
921 contact = soapconn->parent;
922 g_return_val_if_fail(contact != NULL, TRUE);
923 session = soapconn->session;
924 g_return_val_if_fail(session != NULL, FALSE);
925
926 purple_debug_misc("MSN AddressBook", "Got the Address Book!\n");
927
928 if ( msn_parse_addressbook(contact) ) {
929 //msn_soap_free_read_buf(soapconn);
930
931 if (!session->logged_in) {
932 msn_send_privacy(session->account->gc);
933 msn_notification_dump_contact(session);
934 }
935
936 /*free the read buffer*/
937 msn_soap_free_read_buf(soapconn);
938 return TRUE;
939 } else {
940 /* This is making us loop infinitely when we fail to parse the address book,
941 disable for now (we should re-enable when we send timestamps)
942 */
943 /*
944 msn_get_address_book(contact, NULL, NULL);
945 */
946 msn_session_disconnect(session);
947 purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book"));
948 return FALSE;
949 }
950 }
951
952 /**/
953 static void
954 msn_address_written_cb(MsnSoapConn *soapconn)
955 {
956 purple_debug_misc("MSN AddressBook","Sent SOAP request for the Address Book.\n");
957 soapconn->read_cb = msn_get_address_cb;
958 }
959
960 /*get the address book*/
961 void
962 msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange)
963 {
964 MsnSoapReq *soap_request;
965 char *body;
966 char *update_str = NULL;
967
968 purple_debug_misc("MSN AddressBook","Getting Address Book\n");
969
970 /*build SOAP and POST it*/
971 if (dynamicItemLastChange != NULL)
972 update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, dynamicItemLastChange);
973 else if (LastChanged != NULL)
974 update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged);
975
976
977 body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? update_str : "");
978 g_free(update_str);
979
980 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
981 MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION,
982 body,
983 NULL,
984 msn_get_address_cb,
985 msn_address_written_cb,
986 msn_contact_connect_init);
987 msn_soap_post(contact->soapconn,soap_request);
988 g_free(body);
989 }
990
991 static gboolean
992 msn_add_contact_read_cb(MsnSoapConn *soapconn)
993 {
994 MsnCallbackState *state = NULL;
995 MsnUserList *userlist;
996 MsnUser *user;
997
998 g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
999 g_return_val_if_fail(soapconn->session != NULL, FALSE);
1000 g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
1001
1002 state = (MsnCallbackState *) soapconn->data_cb;
1003
1004 if (soapconn->body == NULL) {
1005 msn_callback_state_free(state);
1006 return TRUE;
1007 }
1008
1009 userlist = soapconn->session->userlist;
1010
1011 purple_debug_info("MSNCL","Contact added successfully\n");
1012
1013 // the code this block is replacing didn't send ADL for yahoo contacts,
1014 // but i haven't confirmed this is WLM's behaviour wrt yahoo contacts
1015
1016 if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) {
1017
1018 msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
1019 msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
1020 }
1021 msn_notification_send_fqy(soapconn->session, state->who);
1022
1023 user = msn_userlist_find_add_user(userlist, state->who, state->who);
1024 msn_user_add_group_id(user, state->guid);
1025
1026 if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
1027 msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL);
1028 } else {
1029 msn_soap_free_read_buf(soapconn);
1030 }
1031
1032 msn_callback_state_free(state);
1033
1034 return TRUE;
1035 }
1036
1037 static void
1038 msn_add_contact_written_cb(MsnSoapConn *soapconn)
1039 {
1040 purple_debug_info("MSNCL","Add contact request written\n");
1041 soapconn->read_cb = msn_add_contact_read_cb;
1042 }
1043
1044 /* add a Contact in MSN_INDIVIDUALS_GROUP */
1045 void
1046 msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport)
1047 {
1048 MsnSoapReq *soap_request;
1049 gchar *body = NULL;
1050 gchar *contact_xml = NULL;
1051
1052 g_return_if_fail(passport != NULL);
1053 /* gchar *escaped_displayname;
1054
1055
1056 if (displayname != NULL) {
1057 escaped_displayname = g_markup_decode_text(displayname, -1);
1058 } else {
1059 escaped_displayname = passport;
1060 }
1061 contact_xml = g_strdup_printf(MSN_XML_ADD_CONTACT, escaped_displayname, passport);
1062 */
1063 purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport);
1064
1065 // if ( !strcmp(state->guid, MSN_INDIVIDUALS_GROUP_ID) ) {
1066 contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
1067 // }
1068 body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml);
1069
1070 g_free(contact_xml);
1071
1072 /*build SOAP and POST it*/
1073
1074 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1075 MSN_ADDRESS_BOOK_POST_URL,
1076 MSN_CONTACT_ADD_SOAP_ACTION,
1077 body,
1078 state,
1079 msn_add_contact_read_cb,
1080 msn_add_contact_written_cb,
1081 msn_contact_connect_init);
1082 msn_soap_post(contact->soapconn,soap_request);
1083
1084 g_free(body);
1085 }
1086
1087 static gboolean
1088 msn_add_contact_to_group_read_cb(MsnSoapConn *soapconn)
1089 {
1090 MsnCallbackState *state;
1091 MsnUserList *userlist;
1092
1093 g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
1094 g_return_val_if_fail(soapconn->session != NULL, FALSE);
1095 g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
1096
1097 userlist = soapconn->session->userlist;
1098
1099 state = (MsnCallbackState *) soapconn->data_cb;
1100
1101 if (soapconn->body == NULL) {
1102 msn_callback_state_free(state);
1103 return TRUE;
1104 }
1105
1106 if (msn_userlist_add_buddy_to_group(userlist, state->who, state->new_group_name) == TRUE) {
1107 purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name);
1108 } else {
1109 purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name);
1110 }
1111
1112 if (state->action & MSN_ADD_BUDDY) {
1113 MsnUser *user = msn_userlist_find_user(userlist, state->who);
1114
1115 if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) {
1116
1117 msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL);
1118 msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL);
1119 }
1120 msn_notification_send_fqy(soapconn->session, state->who);
1121
1122 if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) {
1123 msn_del_contact_from_list(soapconn->session->contact, NULL, state->who, MSN_LIST_PL);
1124 msn_callback_state_free(state);
1125 return TRUE;
1126 }
1127 }
1128
1129 if (state->action & MSN_MOVE_BUDDY) {
1130 msn_del_contact_from_group(soapconn->session->contact, state->who, state->old_group_name);
1131 } else {
1132 msn_callback_state_free(state);
1133 msn_soap_free_read_buf(soapconn);
1134 }
1135 return TRUE;
1136 }
1137
1138 static void
1139 msn_add_contact_to_group_written_cb(MsnSoapConn *soapconn)
1140 {
1141 purple_debug_info("MSNCL","Add contact to group request sent!\n");
1142 soapconn->read_cb = msn_add_contact_to_group_read_cb;
1143 }
1144
1145 void
1146 msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state,
1147 const char *passport, const char *groupId)
1148 {
1149 MsnSoapReq *soap_request;
1150 MsnUserList *userlist;
1151 MsnUser *user;
1152 gchar *body = NULL, *contact_xml;
1153
1154 g_return_if_fail(passport != NULL);
1155 g_return_if_fail(groupId != NULL);
1156
1157 g_return_if_fail(contact != NULL);
1158 g_return_if_fail(contact->session != NULL);
1159 g_return_if_fail(contact->session->userlist != NULL);
1160
1161 userlist = contact->session->userlist;
1162
1163 if (!strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) {
1164
1165 user = msn_userlist_find_add_user(userlist, passport, passport);
1166
1167 if (state->action & MSN_ADD_BUDDY) {
1168 msn_add_contact(contact, state, passport);
1169 return;
1170 }
1171
1172 if (state->action & MSN_MOVE_BUDDY) {
1173 msn_user_add_group_id(user, groupId);
1174 msn_del_contact_from_group(contact, passport, state->old_group_name);
1175 } else {
1176 msn_callback_state_free(state);
1177 }
1178
1179 return;
1180 }
1181
1182
1183 purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport,
1184 msn_userlist_find_group_name(userlist, groupId));
1185
1186 user = msn_userlist_find_user(userlist, passport);
1187 if (user == NULL) {
1188 purple_debug_warning("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport);
1189 }
1190
1191 if (user->uid != NULL) {
1192 contact_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
1193 } else {
1194 contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
1195 }
1196
1197 body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml);
1198 g_free(contact_xml);
1199
1200 /*build SOAP and POST it*/
1201
1202 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1203 MSN_ADDRESS_BOOK_POST_URL,
1204 MSN_ADD_CONTACT_GROUP_SOAP_ACTION,
1205 body,
1206 state,
1207 msn_add_contact_to_group_read_cb,
1208 msn_add_contact_to_group_written_cb,
1209 msn_contact_connect_init);
1210 msn_soap_post(contact->soapconn,soap_request);
1211
1212 g_free(body);
1213 }
1214
1215
1216
1217 static gboolean
1218 msn_delete_contact_read_cb(MsnSoapConn *soapconn)
1219 {
1220 MsnUser *user;
1221 MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb;
1222 MsnUserList *userlist;
1223
1224 g_return_val_if_fail(soapconn->session != NULL, FALSE);
1225 g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
1226
1227 userlist = soapconn->session->userlist;
1228
1229 if (soapconn->body == NULL) {
1230 msn_callback_state_free(state);
1231 return TRUE;
1232 }
1233
1234 purple_debug_info("MSNCL","Delete contact successful\n");
1235
1236 user = msn_userlist_find_user_with_id(userlist, state->uid);
1237 if (user != NULL) {
1238 msn_userlist_remove_user(userlist, user);
1239 }
1240
1241 msn_callback_state_free(state);
1242 msn_soap_free_read_buf(soapconn);
1243
1244 return TRUE;
1245 }
1246
1247 static void
1248 msn_delete_contact_written_cb(MsnSoapConn *soapconn)
1249 {
1250 purple_debug_info("MSNCL","Delete contact request written\n");
1251 soapconn->read_cb = msn_delete_contact_read_cb;
1252 }
1253
1254 /*delete a Contact*/
1255 void
1256 msn_delete_contact(MsnContact *contact, const char *contactId)
1257 {
1258 gchar *body = NULL;
1259 gchar *contact_id_xml = NULL ;
1260 MsnSoapReq *soap_request;
1261 MsnCallbackState *state;
1262
1263 g_return_if_fail(contactId != NULL);
1264 contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId);
1265
1266 state = msn_callback_state_new();
1267 msn_callback_state_set_uid(state, contactId);
1268
1269 /* build SOAP request */
1270 purple_debug_info("MSNCL","Deleting contact with contactId: %s\n", contactId);
1271 body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml);
1272 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1273 MSN_ADDRESS_BOOK_POST_URL,
1274 MSN_CONTACT_DEL_SOAP_ACTION,
1275 body,
1276 state,
1277 msn_delete_contact_read_cb,
1278 msn_delete_contact_written_cb,
1279 msn_contact_connect_init);
1280
1281 g_free(contact_id_xml);
1282
1283 /* POST the SOAP request */
1284 msn_soap_post(contact->soapconn, soap_request);
1285
1286 g_free(body);
1287 }
1288
1289 static gboolean
1290 msn_del_contact_from_group_read_cb(MsnSoapConn *soapconn)
1291 {
1292 MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb;
1293
1294 if (soapconn->body == NULL) {
1295 msn_callback_state_free(state);
1296 return TRUE;
1297 }
1298
1299 if (msn_userlist_rem_buddy_from_group(soapconn->session->userlist, state->who, state->old_group_name)) {
1300 purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name);
1301 } else {
1302 purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name);
1303 }
1304
1305 msn_callback_state_free(state);
1306 msn_soap_free_read_buf(soapconn);
1307
1308 return TRUE;
1309 }
1310
1311 static void
1312 msn_del_contact_from_group_written_cb(MsnSoapConn *soapconn)
1313 {
1314 purple_debug_info("MSN CL","Del contact from group request sent!\n");
1315 soapconn->read_cb = msn_del_contact_from_group_read_cb;
1316 }
1317
1318 void
1319 msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name)
1320 {
1321 MsnSoapReq *soap_request;
1322 MsnUserList * userlist;
1323 MsnUser *user;
1324 MsnCallbackState *state;
1325 gchar *body = NULL, *contact_id_xml;
1326 const gchar *groupId;
1327
1328 g_return_if_fail(passport != NULL);
1329 g_return_if_fail(group_name != NULL);
1330 g_return_if_fail(contact != NULL);
1331 g_return_if_fail(contact->session != NULL);
1332 g_return_if_fail(contact->session->userlist != NULL);
1333
1334 userlist = contact->session->userlist;
1335
1336 groupId = msn_userlist_find_group_id(userlist, group_name);
1337 if (groupId != NULL) {
1338 purple_debug_info("MSN CL", "Deleting user %s from group %s\n", passport, group_name);
1339 } else {
1340 purple_debug_warning("MSN CL", "Unable to retrieve group id from group %s !\n", group_name);
1341 return;
1342 }
1343
1344 user = msn_userlist_find_user(userlist, passport);
1345
1346 if (user == NULL) {
1347 purple_debug_warning("MSN CL", "Unable to retrieve user from passport %s!\n", passport);
1348 return;
1349 }
1350
1351 if ( !strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) {
1352 msn_user_remove_group_id(user, groupId);
1353 return;
1354 }
1355
1356 state = msn_callback_state_new();
1357 msn_callback_state_set_who(state, passport);
1358 msn_callback_state_set_guid(state, groupId);
1359 msn_callback_state_set_old_group_name(state, group_name);
1360
1361 contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
1362 body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId);
1363 g_free(contact_id_xml);
1364
1365 /*build SOAP and POST it*/
1366 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1367 MSN_ADDRESS_BOOK_POST_URL,
1368 MSN_CONTACT_DEL_GROUP_SOAP_ACTION,
1369 body,
1370 state,
1371 msn_del_contact_from_group_read_cb,
1372 msn_del_contact_from_group_written_cb,
1373 msn_contact_connect_init);
1374 msn_soap_post(contact->soapconn,soap_request);
1375
1376 g_free(body);
1377 }
1378
1379
1380 static gboolean
1381 msn_update_contact_read_cb(MsnSoapConn *soapconn)
1382 {
1383 if (soapconn->body == NULL)
1384 return TRUE;
1385
1386 purple_debug_info("MSN CL","Contact updated successfully\n");
1387
1388 return TRUE;
1389 }
1390
1391 static void
1392 msn_update_contact_written_cb(MsnSoapConn *soapconn)
1393 {
1394 purple_debug_info("MSN CL","Update contact information request sent\n");
1395 soapconn->read_cb = msn_update_contact_read_cb;
1396 }
1397
1398 /* Update a contact's nickname */
1399
1400 void
1401 msn_update_contact(MsnContact *contact, const char* nickname)
1402 {
1403 MsnSoapReq *soap_request;
1404 gchar *body = NULL, *escaped_nickname;
1405
1406 purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname);
1407
1408 escaped_nickname = g_markup_escape_text(nickname, -1);
1409
1410 body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname);
1411
1412 g_free(escaped_nickname);
1413 /*build SOAP and POST it*/
1414 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1415 MSN_ADDRESS_BOOK_POST_URL,
1416 MSN_CONTACT_UPDATE_SOAP_ACTION,
1417 body,
1418 NULL,
1419 msn_update_contact_read_cb,
1420 msn_update_contact_written_cb,
1421 msn_contact_connect_init);
1422 msn_soap_post(contact->soapconn, soap_request);
1423
1424 g_free(body);
1425 }
1426
1427
1428 static gboolean
1429 msn_del_contact_from_list_read_cb(MsnSoapConn *soapconn)
1430 {
1431 MsnCallbackState *state = NULL;
1432
1433 g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
1434 g_return_val_if_fail(soapconn->session != NULL, FALSE);
1435 g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
1436
1437 state = (MsnCallbackState *) soapconn->data_cb;
1438
1439 if (soapconn->body == NULL) {
1440 msn_callback_state_free(state);
1441 return TRUE;
1442 }
1443
1444 purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
1445
1446 if (state->list_id == MSN_LIST_PL) {
1447 msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL);
1448 return TRUE;
1449 }
1450
1451 if (state->list_id == MSN_LIST_AL) {
1452 purple_privacy_permit_remove(soapconn->session->account, state->who, TRUE);
1453 msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
1454 msn_callback_state_free(state);
1455 return TRUE;
1456 }
1457
1458 if (state->list_id == MSN_LIST_BL) {
1459 purple_privacy_deny_remove(soapconn->session->account, state->who, TRUE);
1460 msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_AL);
1461 msn_callback_state_free(state);
1462 return TRUE;
1463 }
1464
1465 msn_callback_state_free(state);
1466 msn_soap_free_read_buf(soapconn);
1467
1468 return TRUE;
1469 }
1470
1471 static void
1472 msn_del_contact_from_list_written_cb(MsnSoapConn *soapconn)
1473 {
1474 purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n");
1475 soapconn->read_cb = msn_del_contact_from_list_read_cb;
1476 }
1477
1478 void
1479 msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state,
1480 const gchar *passport, const MsnListId list)
1481 {
1482 MsnSoapReq *soap_request;
1483 gchar *body = NULL, *member = NULL;
1484 MsnSoapPartnerScenario partner_scenario;
1485 MsnUser *user;
1486
1487 g_return_if_fail(contact != NULL);
1488 g_return_if_fail(passport != NULL);
1489 g_return_if_fail(list < 5);
1490
1491 purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]);
1492
1493 if (state == NULL) {
1494 state = msn_callback_state_new();
1495 }
1496 msn_callback_state_set_list_id(state, list);
1497 msn_callback_state_set_who(state, passport);
1498
1499 if (list == MSN_LIST_PL) {
1500 g_return_if_fail(contact->session != NULL);
1501 g_return_if_fail(contact->session->userlist != NULL);
1502
1503 user = msn_userlist_find_user(contact->session->userlist, passport);
1504
1505 partner_scenario = MSN_PS_CONTACT_API;
1506 member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]);
1507 } else {
1508 /* list == MSN_LIST_AL || list == MSN_LIST_BL */
1509 partner_scenario = MSN_PS_BLOCK_UNBLOCK;
1510
1511 member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
1512 }
1513
1514 body = g_strdup_printf( MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE,
1515 MsnSoapPartnerScenarioText[partner_scenario],
1516 MsnMemberRole[list],
1517 member);
1518 g_free(member);
1519
1520 soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
1521 MSN_SHARE_POST_URL,
1522 MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION,
1523 body,
1524 state,
1525 msn_del_contact_from_list_read_cb,
1526 msn_del_contact_from_list_written_cb,
1527 msn_contact_connect_init);
1528
1529 msn_soap_post(contact->soapconn,soap_request);
1530
1531 g_free(body);
1532 }
1533
1534 static gboolean
1535 msn_add_contact_to_list_read_cb(MsnSoapConn *soapconn)
1536 {
1537 MsnCallbackState *state = NULL;
1538
1539 g_return_val_if_fail(soapconn->data_cb != NULL, TRUE);
1540
1541 state = (MsnCallbackState *) soapconn->data_cb;
1542
1543 if (soapconn->body == NULL) {
1544 msn_callback_state_free(state);
1545 return TRUE;
1546 }
1547
1548 purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]);
1549
1550 if (state->list_id == MSN_LIST_RL && (state->action & MSN_DENIED_BUDDY) ) {
1551 g_return_val_if_fail(soapconn->session != NULL, FALSE);
1552 g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
1553
1554 msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL);
1555 return TRUE;
1556 }
1557
1558 if (state->list_id == MSN_LIST_AL) {
1559 purple_privacy_permit_add(soapconn->session->account, state->who, TRUE);
1560 } else if (state->list_id == MSN_LIST_BL) {
1561 purple_privacy_deny_add(soapconn->session->account, state->who, TRUE);
1562 }
1563
1564 msn_callback_state_free(state);
1565 msn_soap_free_read_buf(soapconn);
1566 return TRUE;
1567 }
1568
1569
1570 static void
1571 msn_add_contact_to_list_written_cb(MsnSoapConn *soapconn)
1572 {
1573 purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n");
1574 soapconn->read_cb = msn_add_contact_to_list_read_cb;
1575 }
1576
1577 void
1578 msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state,
1579 const gchar *passport, const MsnListId list)
1580 {
1581 MsnSoapReq *soap_request;
1582 gchar *body = NULL, *member = NULL;
1583 MsnSoapPartnerScenario partner_scenario;
1584
1585 g_return_if_fail(contact != NULL);
1586 g_return_if_fail(passport != NULL);
1587 g_return_if_fail(list < 5);
1588
1589 purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]);
1590
1591 if (state == NULL) {
1592 state = msn_callback_state_new();
1593 }
1594 msn_callback_state_set_list_id(state, list);
1595 msn_callback_state_set_who(state, passport);
1596
1597 partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK;
1598
1599 member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport);
1600
1601 body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE,
1602 MsnSoapPartnerScenarioText[partner_scenario],
1603 MsnMemberRole[list],
1604 member);
1605
1606 g_free(member);
1607
1608 soap_request = msn_soap_request_new( MSN_CONTACT_SERVER,
1609 MSN_SHARE_POST_URL,
1610 MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION,
1611 body,
1612 state,
1613 msn_add_contact_to_list_read_cb,
1614 msn_add_contact_to_list_written_cb,
1615 msn_contact_connect_init);
1616
1617 msn_soap_post(contact->soapconn, soap_request);
1618
1619 g_free(body);
1620 }
1621
1622
1623 #if 0
1624 static gboolean
1625 msn_gleams_read_cb(MsnSoapConn * soapconn)
1626 {
1627 purple_debug_info("MSN CL","Gleams read done\n");
1628 return TRUE;
1629 }
1630
1631 static void
1632 msn_gleams_written_cb(MsnSoapConn * soapconn)
1633 {
1634 purple_debug_info("MSNP14","finish Group written\n");
1635 soapconn->read_cb = msn_gleams_read_cb;
1636 // msn_soap_read_cb(data,source,cond);
1637 }
1638
1639 /*get the gleams info*/
1640 void
1641 msn_get_gleams(MsnContact *contact)
1642 {
1643 MsnSoapReq *soap_request;
1644
1645 purple_debug_info("MSNP14","msn get gleams info...\n");
1646 /*build SOAP and POST it*/
1647 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1648 MSN_ADDRESS_BOOK_POST_URL,
1649 MSN_GET_GLEAMS_SOAP_ACTION,
1650 MSN_GLEAMS_TEMPLATE,
1651 NULL,
1652 msn_gleams_read_cb,
1653 msn_gleams_written_cb,
1654 msn_contact_connect_init);
1655 msn_soap_post(contact->soapconn,soap_request);
1656 }
1657 #endif
1658
1659
1660 /***************************************************************
1661 * Group Operations
1662 ***************************************************************/
1663
1664 static gboolean
1665 msn_group_read_cb(MsnSoapConn *soapconn)
1666 {
1667 MsnUserList *userlist;
1668 MsnCallbackState *state = NULL;
1669
1670 purple_debug_info("MSN CL", "Group request successful.\n");
1671
1672 g_return_val_if_fail(soapconn->session != NULL, FALSE);
1673 g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE);
1674 g_return_val_if_fail(soapconn->session->contact != NULL, FALSE);
1675
1676 state = (MsnCallbackState *) soapconn->data_cb;
1677
1678 if (soapconn->body == NULL) {
1679 msn_callback_state_free(state);
1680 return TRUE;
1681 }
1682
1683 if (state) {
1684 userlist = soapconn->session->userlist;
1685
1686 if (state->action & MSN_RENAME_GROUP) {
1687 msn_userlist_rename_group_id(soapconn->session->userlist,
1688 state->guid,
1689 state->new_group_name);
1690 }
1691
1692 if (state->action & MSN_ADD_GROUP) {
1693 gchar *guid, *endguid;
1694
1695 guid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "<guid>");
1696 guid += 6;
1697 endguid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "</guid>");
1698 *endguid = '\0';
1699 /* create and add the new group to the userlist */
1700 purple_debug_info("MSN CL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid);
1701 msn_group_new(soapconn->session->userlist, guid, state->new_group_name);
1702
1703 if (state->action & MSN_ADD_BUDDY) {
1704 msn_userlist_add_buddy(soapconn->session->userlist,
1705 state->who,
1706 state->new_group_name);
1707 msn_callback_state_free(state);
1708 return TRUE;
1709 }
1710
1711 if (state->action & MSN_MOVE_BUDDY) {
1712 msn_add_contact_to_group(soapconn->session->contact, state, state->who, guid);
1713 return TRUE;
1714 }
1715 }
1716
1717 if (state->action & MSN_DEL_GROUP) {
1718 GList *l;
1719
1720 msn_userlist_remove_group_id(soapconn->session->userlist, state->guid);
1721 for (l = userlist->users; l != NULL; l = l->next) {
1722 msn_user_remove_group_id( (MsnUser *)l->data, state->guid);
1723 }
1724
1725 }
1726
1727 msn_callback_state_free(state);
1728 }
1729
1730 msn_soap_free_read_buf(soapconn);
1731 return TRUE;
1732 }
1733
1734 static void
1735 msn_group_written_cb(MsnSoapConn *soapconn)
1736 {
1737 purple_debug_info("MSN CL","Sent group request.\n");
1738 soapconn->read_cb = msn_group_read_cb;
1739 }
1740
1741 /* add group */
1742 void
1743 msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name)
1744 {
1745 MsnSoapReq *soap_request;
1746 MsnContact *contact;
1747 char *body = NULL;
1748 gchar *escaped_group_name;
1749
1750 g_return_if_fail(session != NULL);
1751 g_return_if_fail(group_name != NULL);
1752
1753 contact = session->contact;
1754 purple_debug_info("MSN CL","Adding group %s to contact list.\n", group_name);
1755
1756 if (state == NULL) {
1757 state = msn_callback_state_new();
1758 }
1759
1760 msn_callback_state_set_action(state, MSN_ADD_GROUP);
1761 msn_callback_state_set_new_group_name(state, group_name);
1762
1763 /* escape group name's html special chars so it can safely be sent
1764 * in a XML SOAP request
1765 */
1766 escaped_group_name = g_markup_escape_text(group_name, -1);
1767 body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name);
1768 g_free(escaped_group_name);
1769
1770 /*build SOAP and POST it*/
1771 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1772 MSN_ADDRESS_BOOK_POST_URL,
1773 MSN_GROUP_ADD_SOAP_ACTION,
1774 body,
1775 state,
1776 msn_group_read_cb,
1777 msn_group_written_cb,
1778 msn_contact_connect_init);
1779 msn_soap_post(contact->soapconn,soap_request);
1780
1781 g_free(body);
1782 }
1783
1784 /* delete group */
1785 void
1786 msn_del_group(MsnSession *session, const gchar *group_name)
1787 {
1788 MsnSoapReq *soap_request;
1789 MsnContact *contact;
1790 MsnCallbackState *state;
1791 char *body = NULL;
1792 const gchar *guid;
1793
1794 g_return_if_fail(session != NULL);
1795
1796 g_return_if_fail(group_name != NULL);
1797 contact = session->contact;
1798 purple_debug_info("MSN CL","Deleting group %s from contact list\n", group_name);
1799
1800 guid = msn_userlist_find_group_id(session->userlist, group_name);
1801
1802 /* if group uid we need to del is NULL,
1803 * we need to delete nothing
1804 */
1805 if (guid == NULL) {
1806 purple_debug_info("MSN CL", "Group %s guid not found, returning.\n", group_name);
1807 return;
1808 }
1809
1810 if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) {
1811 // XXX add back PurpleGroup since it isn't really removed in the server?
1812 return;
1813 }
1814
1815 state = msn_callback_state_new();
1816 msn_callback_state_set_action(state, MSN_DEL_GROUP);
1817 msn_callback_state_set_guid(state, guid);
1818
1819 body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid);
1820 /*build SOAP and POST it*/
1821 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1822 MSN_ADDRESS_BOOK_POST_URL,
1823 MSN_GROUP_DEL_SOAP_ACTION,
1824 body,
1825 state,
1826 msn_group_read_cb,
1827 msn_group_written_cb,
1828 msn_contact_connect_init);
1829 msn_soap_post(contact->soapconn, soap_request);
1830
1831 g_free(body);
1832 }
1833
1834 /* rename group */
1835 void
1836 msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name)
1837 {
1838 MsnSoapReq *soap_request;
1839 MsnContact *contact;
1840 gchar * escaped_group_name, *body = NULL;
1841 const gchar * guid;
1842 MsnCallbackState *state = msn_callback_state_new();
1843
1844 g_return_if_fail(session != NULL);
1845 g_return_if_fail(session->userlist != NULL);
1846 g_return_if_fail(old_group_name != NULL);
1847 g_return_if_fail(new_group_name != NULL);
1848
1849 contact = session->contact;
1850 purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name);
1851
1852 guid = msn_userlist_find_group_id(session->userlist, old_group_name);
1853 if (guid == NULL)
1854 return;
1855
1856 msn_callback_state_set_guid(state, guid);
1857 msn_callback_state_set_new_group_name(state, new_group_name);
1858
1859 if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) {
1860 msn_add_group(session, state, new_group_name);
1861 // XXX move every buddy there (we probably need to fix concurrent SOAP reqs first)
1862 }
1863
1864 msn_callback_state_set_action(state, MSN_RENAME_GROUP);
1865
1866 /* escape group name's html special chars so it can safely be sent
1867 * in a XML SOAP request
1868 */
1869 escaped_group_name = g_markup_escape_text(new_group_name, -1);
1870
1871 body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name);
1872
1873 soap_request = msn_soap_request_new(MSN_CONTACT_SERVER,
1874 MSN_ADDRESS_BOOK_POST_URL,
1875 MSN_GROUP_RENAME_SOAP_ACTION,
1876 body,
1877 state,
1878 msn_group_read_cb,
1879 msn_group_written_cb,
1880 msn_contact_connect_init);
1881 msn_soap_post(contact->soapconn, soap_request);
1882
1883 g_free(escaped_group_name);
1884 g_free(body);
1885 }
1886
1887 void
1888 msn_contact_connect_init(MsnSoapConn *soapconn)
1889 {
1890 msn_soap_init(soapconn, MSN_CONTACT_SERVER, 1,
1891 msn_contact_login_connect_cb,
1892 msn_contact_login_error_cb);
1893 }