source: protocols/msn/soap.c @ 6ddb223

Last change on this file since 6ddb223 was 6ddb223, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-14T19:57:13Z

Separate boilerplate and body of abservice SOAP requests since the former's
the same all the time (and I have to add some more request types).

  • Property mode set to 100644
File size: 20.5 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - All the SOAPy XML stuff.
8   Some manager at Microsoft apparently thought MSNP wasn't XMLy enough so
9   someone stepped up and changed that. This is the result. Kilobytes and
10   more kilobytes of XML vomit to transfer tiny bits of informaiton. */
11
12/*
13  This program is free software; you can redistribute it and/or modify
14  it under the terms of the GNU General Public License as published by
15  the Free Software Foundation; either version 2 of the License, or
16  (at your option) any later version.
17
18  This program is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  GNU General Public License for more details.
22
23  You should have received a copy of the GNU General Public License with
24  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
25  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
26  Suite 330, Boston, MA  02111-1307  USA
27*/
28
29#include "http_client.h"
30#include "soap.h"
31#include "msn.h"
32#include "bitlbee.h"
33#include "url.h"
34#include "misc.h"
35#include "sha1.h"
36#include "base64.h"
37#include "xmltree.h"
38#include <ctype.h>
39#include <errno.h>
40
41/* This file tries to make SOAP stuff pretty simple to do by letting you just
42   provide a function to build a request, a few functions to parse various
43   parts of the response, and a function to run when the full response was
44   received and parsed. See the various examples below. */
45
46typedef enum
47{
48        MSN_SOAP_OK,
49        MSN_SOAP_RETRY,
50        MSN_SOAP_ABORT,
51} msn_soap_result_t;
52
53struct msn_soap_req_data;
54typedef int (*msn_soap_func) ( struct msn_soap_req_data * );
55
56struct msn_soap_req_data
57{
58        void *data;
59        struct im_connection *ic;
60        int ttl;
61       
62        char *url, *action, *payload;
63        struct http_request *http_req;
64       
65        const struct xt_handler_entry *xml_parser;
66        msn_soap_func build_request, handle_response, free_data;
67};
68
69static int msn_soap_send_request( struct msn_soap_req_data *req );
70
71static int msn_soap_start( struct im_connection *ic,
72                    void *data,
73                    msn_soap_func build_request,
74                    const struct xt_handler_entry *xml_parser,
75                    msn_soap_func handle_response,
76                    msn_soap_func free_data )
77{
78        struct msn_soap_req_data *req = g_new0( struct msn_soap_req_data, 1 );
79       
80        req->ic = ic;
81        req->data = data;
82        req->xml_parser = xml_parser;
83        req->build_request = build_request;
84        req->handle_response = handle_response;
85        req->free_data = free_data;
86        req->ttl = 3;
87       
88        return msn_soap_send_request( req );
89}
90
91static void msn_soap_handle_response( struct http_request *http_req );
92
93static int msn_soap_send_request( struct msn_soap_req_data *soap_req )
94{
95        char *http_req;
96        char *soap_action = NULL;
97        url_t url;
98       
99        soap_req->build_request( soap_req );
100       
101        if( soap_req->action )
102                soap_action = g_strdup_printf( "SOAPAction: \"%s\"\r\n", soap_req->action );
103       
104        url_set( &url, soap_req->url );
105        http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host,
106                soap_action ? soap_action : "",
107                strlen( soap_req->payload ), soap_req->payload );
108       
109        soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS,
110                http_req, msn_soap_handle_response, soap_req );
111       
112        g_free( http_req );
113        g_free( soap_action );
114       
115        return soap_req->http_req != NULL;
116}
117
118static void msn_soap_handle_response( struct http_request *http_req )
119{
120        struct msn_soap_req_data *soap_req = http_req->data;
121        int st;
122       
123        if( http_req->body_size > 0 )
124        {
125                struct xt_parser *parser;
126               
127                parser = xt_new( soap_req->xml_parser, soap_req );
128                xt_feed( parser, http_req->reply_body, http_req->body_size );
129                xt_handle( parser, NULL, -1 );
130                xt_free( parser );
131        }
132       
133        st = soap_req->handle_response( soap_req );
134       
135        g_free( soap_req->url );
136        g_free( soap_req->action );
137        g_free( soap_req->payload );
138        soap_req->url = soap_req->action = soap_req->payload = NULL;
139       
140        if( st == MSN_SOAP_RETRY && --soap_req->ttl )
141                msn_soap_send_request( soap_req );
142        else
143        {
144                soap_req->free_data( soap_req );
145                g_free( soap_req );
146        }
147}
148
149static char *msn_soap_abservice_build( const char *body_fmt, const char *scenario, const char *ticket, ... )
150{
151        va_list params;
152        char *ret, *format, *body;
153       
154        format = g_markup_printf_escaped( SOAP_ABSERVICE_PAYLOAD, scenario, ticket );
155       
156        va_start( params, ticket );
157        body = g_strdup_vprintf( body_fmt, params );
158        va_end( params );
159       
160        ret = g_strdup_printf( format, body );
161        g_free( body );
162        g_free( format );
163       
164        return ret;
165}
166
167
168/* passport_sso: Authentication MSNP15+ */
169
170struct msn_soap_passport_sso_data
171{
172        char *policy;
173        char *nonce;
174        char *secret;
175};
176
177static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req )
178{
179        struct msn_soap_passport_sso_data *sd = soap_req->data;
180        struct im_connection *ic = soap_req->ic;
181       
182        if( g_str_has_suffix( ic->acc->user, "@msn.com" ) )
183                soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN );
184        else
185                soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL );
186       
187        soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD,
188                ic->acc->user, ic->acc->pass, sd->policy );
189       
190        return MSN_SOAP_OK;
191}
192
193static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer data )
194{
195        struct msn_soap_req_data *soap_req = data;
196        struct msn_soap_passport_sso_data *sd = soap_req->data;
197        struct msn_data *md = soap_req->ic->proto_data;
198        struct xt_node *p;
199        char *id;
200       
201        if( ( id = xt_find_attr( node, "Id" ) ) == NULL )
202                return XT_HANDLED;
203        id += strlen( id ) - 1;
204        if( *id == '1' &&
205            ( p = node->parent ) && ( p = p->parent ) &&
206            ( p = xt_find_node( p->children, "wst:RequestedProofToken" ) ) &&
207            ( p = xt_find_node( p->children, "wst:BinarySecret" ) ) &&
208            p->text )
209                sd->secret = g_strdup( p->text );
210       
211        *id -= '1';
212        if( *id >= 0 && *id <= 2 )
213        {
214                g_free( md->tokens[(int)*id] );
215                md->tokens[(int)*id] = g_strdup( node->text );
216        }
217       
218        return XT_HANDLED;
219}
220
221static const struct xt_handler_entry msn_soap_passport_sso_parser[] = {
222        { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token },
223        { NULL, NULL, NULL }
224};
225
226static char *msn_key_fuckery( char *key, int key_len, char *type )
227{
228        unsigned char hash1[20+strlen(type)+1];
229        unsigned char hash2[20];
230        char *ret;
231       
232        sha1_hmac( key, key_len, type, 0, hash1 );
233        strcpy( (char*) hash1 + 20, type );
234        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2 );
235       
236        /* This is okay as hash1 is read completely before it's overwritten. */
237        sha1_hmac( key, key_len, (char*) hash1, 20, hash1 );
238        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1 );
239       
240        ret = g_malloc( 24 );
241        memcpy( ret, hash2, 20 );
242        memcpy( ret + 20, hash1, 4 );
243        return ret;
244}
245
246static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req )
247{
248        struct msn_soap_passport_sso_data *sd = soap_req->data;
249        struct im_connection *ic = soap_req->ic;
250        char *key1, *key2, *key3, *blurb64;
251        int key1_len;
252        unsigned char *padnonce, *des3res;
253        struct
254        {
255                unsigned int uStructHeaderSize; // 28. Does not count data
256                unsigned int uCryptMode; // CRYPT_MODE_CBC (1)
257                unsigned int uCipherType; // TripleDES (0x6603)
258                unsigned int uHashType; // SHA1 (0x8004)
259                unsigned int uIVLen;    // 8
260                unsigned int uHashLen;  // 20
261                unsigned int uCipherLen; // 72
262                unsigned char iv[8];
263                unsigned char hash[20];
264                unsigned char cipherbytes[72];
265        } blurb = {
266                GUINT32_TO_LE( 28 ),
267                GUINT32_TO_LE( 1 ),
268                GUINT32_TO_LE( 0x6603 ),
269                GUINT32_TO_LE( 0x8004 ),
270                GUINT32_TO_LE( 8 ),
271                GUINT32_TO_LE( 20 ),
272                GUINT32_TO_LE( 72 ),
273        };
274
275        key1_len = base64_decode( sd->secret, (unsigned char**) &key1 );
276       
277        key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH" );
278        key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION" );
279       
280        sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash );
281        padnonce = g_malloc( strlen( sd->nonce ) + 8 );
282        strcpy( (char*) padnonce, sd->nonce );
283        memset( padnonce + strlen( sd->nonce ), 8, 8 );
284       
285        random_bytes( blurb.iv, 8 );
286       
287        ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res );
288        memcpy( blurb.cipherbytes, des3res, 72 );
289       
290        blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) );
291        msn_auth_got_passport_token( ic, blurb64 );
292       
293        g_free( padnonce );
294        g_free( blurb64 );
295        g_free( des3res );
296        g_free( key1 );
297        g_free( key2 );
298        g_free( key3 );
299       
300        return MSN_SOAP_OK;
301}
302
303static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req )
304{
305        struct msn_soap_passport_sso_data *sd = soap_req->data;
306       
307        g_free( sd->policy );
308        g_free( sd->nonce );
309        g_free( sd->secret );
310       
311        return MSN_SOAP_OK;
312}
313
314int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce )
315{
316        struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 );
317       
318        sd->policy = g_strdup( policy );
319        sd->nonce = g_strdup( nonce );
320       
321        return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request,
322                                       msn_soap_passport_sso_parser,
323                                       msn_soap_passport_sso_handle_response,
324                                       msn_soap_passport_sso_free_data );
325}
326
327
328/* oim_send: Sending offline messages */
329
330struct msn_soap_oim_send_data
331{
332        char *to;
333        char *msg;
334        int number;
335        int need_retry;
336};
337
338static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req )
339{
340        struct msn_soap_oim_send_data *oim = soap_req->data;
341        struct im_connection *ic = soap_req->ic;
342        struct msn_data *md = ic->proto_data;
343        char *display_name_b64;
344       
345        display_name_b64 = tobase64( set_getstr( &ic->acc->set, "display_name" ) );
346       
347        soap_req->url = g_strdup( SOAP_OIM_SEND_URL );
348        soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION );
349        soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD,
350                ic->acc->user, display_name_b64, MSNP_VER, MSNP_BUILD,
351                oim->to, md->tokens[2],
352                MSNP11_PROD_ID, md->lock_key ? md->lock_key : "",
353                oim->number, oim->number, oim->msg );
354       
355        g_free( display_name_b64 );
356       
357        return MSN_SOAP_OK;
358}
359
360static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data )
361{
362        struct msn_soap_req_data *soap_req = data;
363        struct msn_soap_oim_send_data *oim = soap_req->data;
364        struct im_connection *ic = soap_req->ic;
365        struct msn_data *md = ic->proto_data;
366       
367        g_free( md->lock_key );
368        md->lock_key = msn_p11_challenge( node->text );
369       
370        oim->need_retry = 1;
371       
372        return XT_HANDLED;
373}
374
375static const struct xt_handler_entry msn_soap_oim_send_parser[] = {
376        { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge },
377        { NULL,               NULL,     NULL                        }
378};
379
380static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req )
381{
382        struct msn_soap_oim_send_data *oim = soap_req->data;
383       
384        if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 )
385        {
386                oim->need_retry = 0;
387                return MSN_SOAP_RETRY;
388        }
389        else if( soap_req->http_req->status_code == 200 )
390        {
391                imcb_log( soap_req->ic, "Offline message successfully delivered to %s", oim->to );
392                return MSN_SOAP_OK;
393        }
394        else
395        {
396                imcb_log( soap_req->ic, "Failed to deliver offline message to %s:\n%s", oim->to, oim->msg );
397                return MSN_SOAP_ABORT;
398        }
399}
400
401static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req )
402{
403        struct msn_soap_oim_send_data *oim = soap_req->data;
404       
405        g_free( oim->to );
406        g_free( oim->msg );
407        g_free( oim );
408       
409        return MSN_SOAP_OK;
410}
411
412int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg )
413{
414        struct msn_soap_oim_send_data *data;
415       
416        data = g_new0( struct msn_soap_oim_send_data, 1 );
417        data->to = g_strdup( to );
418        data->msg = tobase64( msg );
419        data->number = 1;
420       
421        return msn_soap_start( ic, data, msn_soap_oim_build_request,
422                                         msn_soap_oim_send_parser,
423                                         msn_soap_oim_handle_response,
424                                         msn_soap_oim_free_data );
425}
426
427int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq )
428{
429        GSList *l;
430        char *n = NULL;
431       
432        for( l = *msgq; l; l = l->next )
433        {
434                struct msn_message *m = l->data;
435               
436                if( n == NULL )
437                        n = m->who;
438                if( strcmp( n, m->who ) == 0 )
439                        msn_soap_oim_send( ic, m->who, m->text );
440        }
441       
442        while( *msgq != NULL )
443        {
444                struct msn_message *m = (*msgq)->data;
445               
446                g_free( m->who );
447                g_free( m->text );
448                g_free( m );
449               
450                *msgq = g_slist_remove( *msgq, m );
451        }
452       
453        return 1;
454}
455
456
457/* memlist: Fetching the membership list (NOT address book) */
458
459static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req )
460{
461        struct msn_data *md = soap_req->ic->proto_data;
462       
463        soap_req->url = g_strdup( SOAP_MEMLIST_URL );
464        soap_req->action = g_strdup( SOAP_MEMLIST_ACTION );
465        soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_PAYLOAD, "Initial", md->tokens[1] );
466       
467        return 1;
468}
469
470static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data )
471{
472        bee_user_t *bu;
473        struct msn_buddy_data *bd;
474        struct xt_node *p;
475        char *role = NULL, *handle = NULL;
476        struct msn_soap_req_data *soap_req = data;
477        struct im_connection *ic = soap_req->ic;
478       
479        if( ( p = node->parent ) && ( p = p->parent ) &&
480            ( p = xt_find_node( p->children, "MemberRole" ) ) )
481                role = p->text;
482       
483        if( ( p = xt_find_node( node->children, "PassportName" ) ) )
484                handle = p->text;
485       
486        if( !role || !handle || 
487            !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
488               ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )
489                return XT_HANDLED;
490       
491        bd = bu->data;
492        if( strcmp( role, "Allow" ) == 0 )
493                bd->flags |= MSN_BUDDY_AL;
494        else if( strcmp( role, "Block" ) == 0 )
495                bd->flags |= MSN_BUDDY_BL;
496        else if( strcmp( role, "Reverse" ) == 0 )
497        {
498                bd->flags |= MSN_BUDDY_RL;
499                msn_buddy_ask( bu );
500        }
501        else if( strcmp( role, "Pending" ) == 0 )
502        {
503                bd->flags |= MSN_BUDDY_PL;
504                msn_buddy_ask( bu );
505        }
506       
507        printf( "%s %d\n", handle, bd->flags );
508       
509        return XT_HANDLED;
510}
511
512static const struct xt_handler_entry msn_soap_memlist_parser[] = {
513        { "Member", "Members", msn_soap_memlist_member },
514        { NULL,               NULL,     NULL                        }
515};
516
517static int msn_soap_memlist_handle_response( struct msn_soap_req_data *soap_req )
518{
519        msn_soap_addressbook_request( soap_req->ic );
520       
521        return MSN_SOAP_OK;
522}
523
524static int msn_soap_memlist_free_data( struct msn_soap_req_data *soap_req )
525{
526        return 0;
527}
528
529int msn_soap_memlist_request( struct im_connection *ic )
530{
531        return msn_soap_start( ic, NULL, msn_soap_memlist_build_request,
532                                         msn_soap_memlist_parser,
533                                         msn_soap_memlist_handle_response,
534                                         msn_soap_memlist_free_data );
535}
536
537/* Variant: Adding/Removing people */
538struct msn_soap_memlist_edit_data
539{
540        char *handle;
541        gboolean add;
542        msn_buddy_flags_t list;
543};
544
545static int msn_soap_memlist_edit_build_request( struct msn_soap_req_data *soap_req )
546{
547        struct msn_data *md = soap_req->ic->proto_data;
548        struct msn_soap_memlist_edit_data *med = soap_req->data;
549        char *add, *scenario, *list;
550       
551        soap_req->url = g_strdup( SOAP_MEMLIST_URL );
552        if( med->add )
553        {
554                soap_req->action = g_strdup( SOAP_MEMLIST_ADD_ACTION );
555                add = "Add";
556        }
557        else
558        {
559                soap_req->action = g_strdup( SOAP_MEMLIST_DEL_ACTION );
560                add = "Delete";
561        }
562        switch( med->list )
563        {
564        case MSN_BUDDY_AL:
565                scenario = "BlockUnblock";
566                list = "Allow";
567                break;
568        case MSN_BUDDY_BL:
569                scenario = "BlockUnblock";
570                list = "Block";
571                break;
572        case MSN_BUDDY_RL:
573                scenario = "Timer";
574                list = "Reverse";
575                break;
576        case MSN_BUDDY_PL:
577        default:
578                scenario = "Timer";
579                list = "Pending";
580                break;
581        }
582        soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_EDIT_PAYLOAD,
583                scenario, md->tokens[1], add, list, med->handle, add );
584       
585        return 1;
586}
587
588static int msn_soap_memlist_edit_handle_response( struct msn_soap_req_data *soap_req )
589{
590        return MSN_SOAP_OK;
591}
592
593static int msn_soap_memlist_edit_free_data( struct msn_soap_req_data *soap_req )
594{
595        struct msn_soap_memlist_edit_data *med = soap_req->data;
596       
597        g_free( med->handle );
598        g_free( med );
599       
600        return 0;
601}
602
603int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list )
604{
605        struct msn_soap_memlist_edit_data *med;
606       
607        med = g_new0( struct msn_soap_memlist_edit_data, 1 );
608        med->handle = g_strdup( handle );
609        med->add = add;
610        med->list = list;
611       
612        return msn_soap_start( ic, med, msn_soap_memlist_edit_build_request,
613                                        NULL,
614                                        msn_soap_memlist_edit_handle_response,
615                                        msn_soap_memlist_edit_free_data );
616}
617
618
619/* addressbook: Fetching the membership list (NOT address book) */
620
621static int msn_soap_addressbook_build_request( struct msn_soap_req_data *soap_req )
622{
623        struct msn_data *md = soap_req->ic->proto_data;
624       
625        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
626        soap_req->action = g_strdup( SOAP_ADDRESSBOOK_ACTION );
627        soap_req->payload = msn_soap_abservice_build( SOAP_ADDRESSBOOK_PAYLOAD, "Initial", md->tokens[1] );
628       
629        return 1;
630}
631
632static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data )
633{
634        struct xt_node *p;
635        char *id = NULL, *name = NULL;
636        struct msn_soap_req_data *soap_req = data;
637       
638        if( ( p = node->parent ) &&
639            ( p = xt_find_node( p->children, "groupId" ) ) )
640                id = p->text;
641       
642        if( ( p = xt_find_node( node->children, "name" ) ) )
643                name = p->text;
644       
645        printf( "%s %s\n", id, name );
646       
647        return XT_HANDLED;
648}
649
650static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer data )
651{
652        bee_user_t *bu;
653        struct msn_buddy_data *bd;
654        struct xt_node *p;
655        char *id = NULL, *type = NULL, *handle = NULL, *display_name = NULL;
656        struct msn_soap_req_data *soap_req = data;
657        struct im_connection *ic = soap_req->ic;
658       
659        if( ( p = node->parent ) &&
660            ( p = xt_find_node( p->children, "contactId" ) ) )
661                id = p->text;
662        if( ( p = xt_find_node( node->children, "contactType" ) ) )
663                type = p->text;
664        if( ( p = xt_find_node( node->children, "passportName" ) ) )
665                handle = p->text;
666        if( ( p = xt_find_node( node->children, "displayName" ) ) )
667                display_name = p->text;
668       
669        if( type && g_strcasecmp( type, "me" ) == 0 )
670        {
671                set_t *set = set_find( &ic->acc->set, "display_name" );
672                g_free( set->value );
673                set->value = g_strdup( display_name );
674               
675                return XT_HANDLED;
676        }
677       
678        if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) &&
679            !( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) )
680                return XT_HANDLED;
681       
682        bd = bu->data;
683        bd->flags |= MSN_BUDDY_FL;
684        g_free( bd->cid );
685        bd->cid = g_strdup( id );
686       
687        imcb_rename_buddy( ic, handle, display_name );
688       
689        printf( "%s %s %s %s\n", id, type, handle, display_name );
690       
691        return XT_HANDLED;
692}
693
694static const struct xt_handler_entry msn_soap_addressbook_parser[] = {
695        { "contactInfo", "Contact", msn_soap_addressbook_contact },
696        { "groupInfo", "Group", msn_soap_addressbook_group },
697        { NULL,               NULL,     NULL                        }
698};
699
700static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req )
701{
702        msn_auth_got_contact_list( soap_req->ic );
703        return MSN_SOAP_OK;
704}
705
706static int msn_soap_addressbook_free_data( struct msn_soap_req_data *soap_req )
707{
708        return 0;
709}
710
711int msn_soap_addressbook_request( struct im_connection *ic )
712{
713        return msn_soap_start( ic, NULL, msn_soap_addressbook_build_request,
714                                         msn_soap_addressbook_parser,
715                                         msn_soap_addressbook_handle_response,
716                                         msn_soap_addressbook_free_data );
717}
718
719/* Variant: Change our display name. */
720static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_req )
721{
722        struct msn_data *md = soap_req->ic->proto_data;
723       
724        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
725        soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION );
726        soap_req->payload = msn_soap_abservice_build( SOAP_AB_NAMECHANGE_PAYLOAD,
727                "Initial", md->tokens[1], (char *) soap_req->data );
728       
729        return 1;
730}
731
732static int msn_soap_ab_namechange_handle_response( struct msn_soap_req_data *soap_req )
733{
734        /* TODO: Ack the change? Not sure what the NAKs look like.. */
735        return MSN_SOAP_OK;
736}
737
738static int msn_soap_ab_namechange_free_data( struct msn_soap_req_data *soap_req )
739{
740        g_free( soap_req->data );
741        return 0;
742}
743
744int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new )
745{
746        return msn_soap_start( ic, g_strdup( new ),
747                               msn_soap_ab_namechange_build_request,
748                               NULL,
749                               msn_soap_ab_namechange_handle_response,
750                               msn_soap_ab_namechange_free_data );
751}
Note: See TracBrowser for help on using the repository browser.