source: protocols/msn/soap.c @ d97f51b

Last change on this file since d97f51b was d97f51b, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-14T23:23:23Z

Fix issues with logging in with huge SSO tickets (hilariously, the 1024-
byte buffer was just one byte too short, resulting in a \r-terminated
login line and the server waiting for the \n). Also using xt_find_path().

  • Property mode set to 100644
File size: 22.9 KB
RevLine 
[4e4af1b]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*/
[e5a8118]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"
[523fb23]35#include "sha1.h"
[e5a8118]36#include "base64.h"
37#include "xmltree.h"
38#include <ctype.h>
39#include <errno.h>
40
[4e4af1b]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
[e5a8118]46typedef enum
47{
48        MSN_SOAP_OK,
49        MSN_SOAP_RETRY,
50        MSN_SOAP_ABORT,
51} msn_soap_result_t;
52
[12767e3]53struct msn_soap_req_data;
54typedef int (*msn_soap_func) ( struct msn_soap_req_data * );
55
[e5a8118]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;
[523fb23]96        char *soap_action = NULL;
[e5a8118]97        url_t url;
98       
99        soap_req->build_request( soap_req );
100       
[523fb23]101        if( soap_req->action )
102                soap_action = g_strdup_printf( "SOAPAction: \"%s\"\r\n", soap_req->action );
[7db65b7]103       
[e5a8118]104        url_set( &url, soap_req->url );
105        http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host,
[523fb23]106                soap_action ? soap_action : "",
[7db65b7]107                strlen( soap_req->payload ), soap_req->payload );
[e5a8118]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       
[ffb6dea]112        g_free( http_req );
[523fb23]113        g_free( soap_action );
[ffb6dea]114       
[e5a8118]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       
[ffb6dea]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       
[e5a8118]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
[6ddb223]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
[bc090f0]167
[523fb23]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       
[73efe3a]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       
[523fb23]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' &&
[d97f51b]205            ( p = xt_find_path( node, "../../wst:RequestedProofToken/wst:BinarySecret" ) ) &&
[523fb23]206            p->text )
207                sd->secret = g_strdup( p->text );
208       
[91d6e91]209        *id -= '1';
210        if( *id >= 0 && *id <= 2 )
211        {
212                g_free( md->tokens[(int)*id] );
213                md->tokens[(int)*id] = g_strdup( node->text );
214        }
[523fb23]215       
216        return XT_HANDLED;
217}
218
219static const struct xt_handler_entry msn_soap_passport_sso_parser[] = {
220        { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token },
221        { NULL, NULL, NULL }
222};
223
224static char *msn_key_fuckery( char *key, int key_len, char *type )
225{
226        unsigned char hash1[20+strlen(type)+1];
227        unsigned char hash2[20];
228        char *ret;
229       
230        sha1_hmac( key, key_len, type, 0, hash1 );
231        strcpy( (char*) hash1 + 20, type );
232        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2 );
233       
234        /* This is okay as hash1 is read completely before it's overwritten. */
235        sha1_hmac( key, key_len, (char*) hash1, 20, hash1 );
236        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1 );
237       
238        ret = g_malloc( 24 );
239        memcpy( ret, hash2, 20 );
240        memcpy( ret + 20, hash1, 4 );
241        return ret;
242}
243
244static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req )
245{
246        struct msn_soap_passport_sso_data *sd = soap_req->data;
247        struct im_connection *ic = soap_req->ic;
248        char *key1, *key2, *key3, *blurb64;
249        int key1_len;
250        unsigned char *padnonce, *des3res;
251        struct
252        {
253                unsigned int uStructHeaderSize; // 28. Does not count data
254                unsigned int uCryptMode; // CRYPT_MODE_CBC (1)
255                unsigned int uCipherType; // TripleDES (0x6603)
256                unsigned int uHashType; // SHA1 (0x8004)
257                unsigned int uIVLen;    // 8
258                unsigned int uHashLen;  // 20
259                unsigned int uCipherLen; // 72
260                unsigned char iv[8];
261                unsigned char hash[20];
262                unsigned char cipherbytes[72];
263        } blurb = {
264                GUINT32_TO_LE( 28 ),
265                GUINT32_TO_LE( 1 ),
266                GUINT32_TO_LE( 0x6603 ),
267                GUINT32_TO_LE( 0x8004 ),
268                GUINT32_TO_LE( 8 ),
269                GUINT32_TO_LE( 20 ),
270                GUINT32_TO_LE( 72 ),
271        };
272
273        key1_len = base64_decode( sd->secret, (unsigned char**) &key1 );
274       
275        key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH" );
276        key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION" );
277       
278        sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash );
279        padnonce = g_malloc( strlen( sd->nonce ) + 8 );
280        strcpy( (char*) padnonce, sd->nonce );
281        memset( padnonce + strlen( sd->nonce ), 8, 8 );
282       
283        random_bytes( blurb.iv, 8 );
284       
285        ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res );
286        memcpy( blurb.cipherbytes, des3res, 72 );
287       
288        blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) );
289        msn_auth_got_passport_token( ic, blurb64 );
290       
291        g_free( padnonce );
292        g_free( blurb64 );
293        g_free( des3res );
294        g_free( key1 );
295        g_free( key2 );
296        g_free( key3 );
297       
298        return MSN_SOAP_OK;
299}
300
301static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req )
302{
303        struct msn_soap_passport_sso_data *sd = soap_req->data;
304       
305        g_free( sd->policy );
306        g_free( sd->nonce );
307        g_free( sd->secret );
308       
309        return MSN_SOAP_OK;
310}
311
312int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce )
313{
314        struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 );
315       
316        sd->policy = g_strdup( policy );
317        sd->nonce = g_strdup( nonce );
318       
319        return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request,
320                                       msn_soap_passport_sso_parser,
321                                       msn_soap_passport_sso_handle_response,
322                                       msn_soap_passport_sso_free_data );
323}
324
325
[bc090f0]326/* oim_send: Sending offline messages */
327
328struct msn_soap_oim_send_data
329{
330        char *to;
331        char *msg;
332        int number;
333        int need_retry;
334};
335
[e5a8118]336static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req )
337{
338        struct msn_soap_oim_send_data *oim = soap_req->data;
339        struct im_connection *ic = soap_req->ic;
340        struct msn_data *md = ic->proto_data;
341        char *display_name_b64;
342       
[91d6e91]343        display_name_b64 = tobase64( set_getstr( &ic->acc->set, "display_name" ) );
[e5a8118]344       
345        soap_req->url = g_strdup( SOAP_OIM_SEND_URL );
[7db65b7]346        soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION );
[e5a8118]347        soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD,
[91d6e91]348                ic->acc->user, display_name_b64, MSNP_VER, MSNP_BUILD,
349                oim->to, md->tokens[2],
[5fecede]350                MSNP11_PROD_ID, md->lock_key ? md->lock_key : "",
351                oim->number, oim->number, oim->msg );
[e5a8118]352       
353        g_free( display_name_b64 );
354       
[523fb23]355        return MSN_SOAP_OK;
[e5a8118]356}
357
358static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data )
359{
360        struct msn_soap_req_data *soap_req = data;
361        struct msn_soap_oim_send_data *oim = soap_req->data;
362        struct im_connection *ic = soap_req->ic;
363        struct msn_data *md = ic->proto_data;
364       
365        g_free( md->lock_key );
366        md->lock_key = msn_p11_challenge( node->text );
367       
368        oim->need_retry = 1;
369       
370        return XT_HANDLED;
371}
372
373static const struct xt_handler_entry msn_soap_oim_send_parser[] = {
374        { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge },
375        { NULL,               NULL,     NULL                        }
376};
377
378static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req )
379{
380        struct msn_soap_oim_send_data *oim = soap_req->data;
381       
[bc090f0]382        if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 )
[e5a8118]383        {
384                oim->need_retry = 0;
385                return MSN_SOAP_RETRY;
386        }
387        else if( soap_req->http_req->status_code == 200 )
[bc090f0]388        {
389                imcb_log( soap_req->ic, "Offline message successfully delivered to %s", oim->to );
[e5a8118]390                return MSN_SOAP_OK;
[bc090f0]391        }
[e5a8118]392        else
[bc090f0]393        {
394                imcb_log( soap_req->ic, "Failed to deliver offline message to %s:\n%s", oim->to, oim->msg );
[e5a8118]395                return MSN_SOAP_ABORT;
[bc090f0]396        }
[e5a8118]397}
398
399static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req )
400{
401        struct msn_soap_oim_send_data *oim = soap_req->data;
402       
403        g_free( oim->to );
404        g_free( oim->msg );
405        g_free( oim );
406       
[523fb23]407        return MSN_SOAP_OK;
[e5a8118]408}
409
410int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg )
411{
412        struct msn_soap_oim_send_data *data;
413       
414        data = g_new0( struct msn_soap_oim_send_data, 1 );
415        data->to = g_strdup( to );
416        data->msg = tobase64( msg );
417        data->number = 1;
418       
419        return msn_soap_start( ic, data, msn_soap_oim_build_request,
420                                         msn_soap_oim_send_parser,
421                                         msn_soap_oim_handle_response,
422                                         msn_soap_oim_free_data );
423}
[bc090f0]424
425int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq )
426{
427        GSList *l;
428        char *n = NULL;
429       
430        for( l = *msgq; l; l = l->next )
431        {
432                struct msn_message *m = l->data;
433               
434                if( n == NULL )
435                        n = m->who;
436                if( strcmp( n, m->who ) == 0 )
437                        msn_soap_oim_send( ic, m->who, m->text );
438        }
439       
440        while( *msgq != NULL )
441        {
442                struct msn_message *m = (*msgq)->data;
443               
444                g_free( m->who );
445                g_free( m->text );
446                g_free( m );
447               
448                *msgq = g_slist_remove( *msgq, m );
449        }
[523fb23]450       
451        return 1;
[bc090f0]452}
[7db65b7]453
454
455/* memlist: Fetching the membership list (NOT address book) */
456
457static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req )
458{
[7f34ce2]459        struct msn_data *md = soap_req->ic->proto_data;
460       
[7db65b7]461        soap_req->url = g_strdup( SOAP_MEMLIST_URL );
462        soap_req->action = g_strdup( SOAP_MEMLIST_ACTION );
[6ddb223]463        soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_PAYLOAD, "Initial", md->tokens[1] );
[7db65b7]464       
465        return 1;
466}
467
[7f34ce2]468static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data )
469{
470        bee_user_t *bu;
471        struct msn_buddy_data *bd;
472        struct xt_node *p;
473        char *role = NULL, *handle = NULL;
474        struct msn_soap_req_data *soap_req = data;
475        struct im_connection *ic = soap_req->ic;
476       
[d97f51b]477        if( ( p = xt_find_path( node, "../../MemberRole" ) ) )
[7f34ce2]478                role = p->text;
479       
480        if( ( p = xt_find_node( node->children, "PassportName" ) ) )
481                handle = p->text;
482       
483        if( !role || !handle || 
484            !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
485               ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )
486                return XT_HANDLED;
487       
488        bd = bu->data;
489        if( strcmp( role, "Allow" ) == 0 )
490                bd->flags |= MSN_BUDDY_AL;
491        else if( strcmp( role, "Block" ) == 0 )
492                bd->flags |= MSN_BUDDY_BL;
493        else if( strcmp( role, "Reverse" ) == 0 )
[e5854a8]494        {
[7f34ce2]495                bd->flags |= MSN_BUDDY_RL;
[e5854a8]496                msn_buddy_ask( bu );
497        }
[7f34ce2]498        else if( strcmp( role, "Pending" ) == 0 )
[e5854a8]499        {
[7f34ce2]500                bd->flags |= MSN_BUDDY_PL;
[e5854a8]501                msn_buddy_ask( bu );
502        }
503       
504        printf( "%s %d\n", handle, bd->flags );
[7f34ce2]505       
506        return XT_HANDLED;
507}
508
[7db65b7]509static const struct xt_handler_entry msn_soap_memlist_parser[] = {
[7f34ce2]510        { "Member", "Members", msn_soap_memlist_member },
[7db65b7]511        { NULL,               NULL,     NULL                        }
512};
513
514static int msn_soap_memlist_handle_response( struct msn_soap_req_data *soap_req )
515{
[7f34ce2]516        msn_soap_addressbook_request( soap_req->ic );
517       
518        return MSN_SOAP_OK;
[7db65b7]519}
520
521static int msn_soap_memlist_free_data( struct msn_soap_req_data *soap_req )
522{
523        return 0;
524}
525
526int msn_soap_memlist_request( struct im_connection *ic )
527{
528        return msn_soap_start( ic, NULL, msn_soap_memlist_build_request,
529                                         msn_soap_memlist_parser,
530                                         msn_soap_memlist_handle_response,
531                                         msn_soap_memlist_free_data );
532}
[7f34ce2]533
[193dc74]534/* Variant: Adding/Removing people */
535struct msn_soap_memlist_edit_data
536{
537        char *handle;
538        gboolean add;
539        msn_buddy_flags_t list;
540};
541
542static int msn_soap_memlist_edit_build_request( struct msn_soap_req_data *soap_req )
543{
544        struct msn_data *md = soap_req->ic->proto_data;
545        struct msn_soap_memlist_edit_data *med = soap_req->data;
546        char *add, *scenario, *list;
547       
548        soap_req->url = g_strdup( SOAP_MEMLIST_URL );
549        if( med->add )
550        {
551                soap_req->action = g_strdup( SOAP_MEMLIST_ADD_ACTION );
552                add = "Add";
553        }
554        else
555        {
556                soap_req->action = g_strdup( SOAP_MEMLIST_DEL_ACTION );
557                add = "Delete";
558        }
559        switch( med->list )
560        {
561        case MSN_BUDDY_AL:
562                scenario = "BlockUnblock";
563                list = "Allow";
564                break;
565        case MSN_BUDDY_BL:
566                scenario = "BlockUnblock";
567                list = "Block";
568                break;
569        case MSN_BUDDY_RL:
570                scenario = "Timer";
571                list = "Reverse";
572                break;
573        case MSN_BUDDY_PL:
574        default:
575                scenario = "Timer";
576                list = "Pending";
577                break;
578        }
[6ddb223]579        soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_EDIT_PAYLOAD,
[193dc74]580                scenario, md->tokens[1], add, list, med->handle, add );
581       
582        return 1;
583}
584
585static int msn_soap_memlist_edit_handle_response( struct msn_soap_req_data *soap_req )
586{
587        return MSN_SOAP_OK;
588}
589
590static int msn_soap_memlist_edit_free_data( struct msn_soap_req_data *soap_req )
591{
592        struct msn_soap_memlist_edit_data *med = soap_req->data;
593       
594        g_free( med->handle );
595        g_free( med );
596       
597        return 0;
598}
599
600int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list )
601{
602        struct msn_soap_memlist_edit_data *med;
603       
604        med = g_new0( struct msn_soap_memlist_edit_data, 1 );
605        med->handle = g_strdup( handle );
606        med->add = add;
607        med->list = list;
608       
609        return msn_soap_start( ic, med, msn_soap_memlist_edit_build_request,
610                                        NULL,
611                                        msn_soap_memlist_edit_handle_response,
612                                        msn_soap_memlist_edit_free_data );
613}
614
[7f34ce2]615
616/* addressbook: Fetching the membership list (NOT address book) */
617
618static int msn_soap_addressbook_build_request( struct msn_soap_req_data *soap_req )
619{
620        struct msn_data *md = soap_req->ic->proto_data;
621       
622        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
623        soap_req->action = g_strdup( SOAP_ADDRESSBOOK_ACTION );
[6ddb223]624        soap_req->payload = msn_soap_abservice_build( SOAP_ADDRESSBOOK_PAYLOAD, "Initial", md->tokens[1] );
[7f34ce2]625       
626        return 1;
627}
628
629static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data )
630{
631        struct xt_node *p;
632        char *id = NULL, *name = NULL;
633        struct msn_soap_req_data *soap_req = data;
634       
[d97f51b]635        if( ( p = xt_find_path( node, "../groupId" ) ) )
[7f34ce2]636                id = p->text;
637       
638        if( ( p = xt_find_node( node->children, "name" ) ) )
639                name = p->text;
640       
641        printf( "%s %s\n", id, name );
642       
643        return XT_HANDLED;
644}
645
646static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer data )
647{
648        bee_user_t *bu;
649        struct msn_buddy_data *bd;
650        struct xt_node *p;
651        char *id = NULL, *type = NULL, *handle = NULL, *display_name = NULL;
652        struct msn_soap_req_data *soap_req = data;
653        struct im_connection *ic = soap_req->ic;
654       
[d97f51b]655        if( ( p = xt_find_path( node, "../contactId" ) ) )
[7f34ce2]656                id = p->text;
657        if( ( p = xt_find_node( node->children, "contactType" ) ) )
658                type = p->text;
659        if( ( p = xt_find_node( node->children, "passportName" ) ) )
660                handle = p->text;
661        if( ( p = xt_find_node( node->children, "displayName" ) ) )
662                display_name = p->text;
663       
664        if( type && g_strcasecmp( type, "me" ) == 0 )
665        {
666                set_t *set = set_find( &ic->acc->set, "display_name" );
667                g_free( set->value );
668                set->value = g_strdup( display_name );
669               
670                return XT_HANDLED;
671        }
672       
[d97f51b]673        if( handle == NULL )
674                return XT_HANDLED;
675       
[7f34ce2]676        if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) &&
677            !( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) )
678                return XT_HANDLED;
679       
680        bd = bu->data;
681        bd->flags |= MSN_BUDDY_FL;
682        g_free( bd->cid );
683        bd->cid = g_strdup( id );
684       
685        imcb_rename_buddy( ic, handle, display_name );
686       
687        printf( "%s %s %s %s\n", id, type, handle, display_name );
688       
689        return XT_HANDLED;
690}
691
692static const struct xt_handler_entry msn_soap_addressbook_parser[] = {
693        { "contactInfo", "Contact", msn_soap_addressbook_contact },
694        { "groupInfo", "Group", msn_soap_addressbook_group },
695        { NULL,               NULL,     NULL                        }
696};
697
698static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req )
699{
[ca7de3a]700        msn_auth_got_contact_list( soap_req->ic );
[7f34ce2]701        return MSN_SOAP_OK;
702}
703
704static int msn_soap_addressbook_free_data( struct msn_soap_req_data *soap_req )
705{
706        return 0;
707}
708
709int msn_soap_addressbook_request( struct im_connection *ic )
710{
711        return msn_soap_start( ic, NULL, msn_soap_addressbook_build_request,
712                                         msn_soap_addressbook_parser,
713                                         msn_soap_addressbook_handle_response,
714                                         msn_soap_addressbook_free_data );
715}
[4452e69]716
717/* Variant: Change our display name. */
718static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_req )
719{
720        struct msn_data *md = soap_req->ic->proto_data;
721       
722        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
723        soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION );
[6ddb223]724        soap_req->payload = msn_soap_abservice_build( SOAP_AB_NAMECHANGE_PAYLOAD,
725                "Initial", md->tokens[1], (char *) soap_req->data );
[4452e69]726       
727        return 1;
728}
729
730static int msn_soap_ab_namechange_handle_response( struct msn_soap_req_data *soap_req )
731{
732        /* TODO: Ack the change? Not sure what the NAKs look like.. */
733        return MSN_SOAP_OK;
734}
735
736static int msn_soap_ab_namechange_free_data( struct msn_soap_req_data *soap_req )
737{
738        g_free( soap_req->data );
739        return 0;
740}
741
742int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new )
743{
744        return msn_soap_start( ic, g_strdup( new ),
745                               msn_soap_ab_namechange_build_request,
746                               NULL,
747                               msn_soap_ab_namechange_handle_response,
748                               msn_soap_ab_namechange_free_data );
749}
[4fc95c5]750
751/* Add a contact. */
752static int msn_soap_ab_contact_add_build_request( struct msn_soap_req_data *soap_req )
753{
754        struct msn_data *md = soap_req->ic->proto_data;
755        bee_user_t *bu = soap_req->data;
756       
757        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
758        soap_req->action = g_strdup( SOAP_AB_CONTACT_ADD_ACTION );
759        soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_ADD_PAYLOAD,
760                "ContactSave", md->tokens[1], bu->handle, bu->fullname ? bu->fullname : bu->handle );
761       
762        return 1;
763}
764
765static xt_status msn_soap_ab_contact_add_cid( struct xt_node *node, gpointer data )
766{
767        struct msn_soap_req_data *soap_req = data;
768        bee_user_t *bu = soap_req->data;
769        struct msn_buddy_data *bd = bu->data;
770       
771        g_free( bd->cid );
772        bd->cid = g_strdup( node->text );
773       
774        return XT_HANDLED;
775}
776
777static const struct xt_handler_entry msn_soap_ab_contact_add_parser[] = {
778        { "guid", "ABContactAddResult", msn_soap_ab_contact_add_cid },
779        { NULL,               NULL,     NULL                        }
780};
781
782static int msn_soap_ab_contact_add_handle_response( struct msn_soap_req_data *soap_req )
783{
784        /* TODO: Ack the change? Not sure what the NAKs look like.. */
785        return MSN_SOAP_OK;
786}
787
788static int msn_soap_ab_contact_add_free_data( struct msn_soap_req_data *soap_req )
789{
790        return 0;
791}
792
793int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu )
794{
795        return msn_soap_start( ic, bu,
796                               msn_soap_ab_contact_add_build_request,
797                               msn_soap_ab_contact_add_parser,
798                               msn_soap_ab_contact_add_handle_response,
799                               msn_soap_ab_contact_add_free_data );
800}
801
802/* Remove a contact. */
803static int msn_soap_ab_contact_del_build_request( struct msn_soap_req_data *soap_req )
804{
805        struct msn_data *md = soap_req->ic->proto_data;
806        bee_user_t *bu = soap_req->data;
807        struct msn_buddy_data *bd = bu->data;
808       
809        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
810        soap_req->action = g_strdup( SOAP_AB_CONTACT_DEL_ACTION );
811        soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_DEL_PAYLOAD,
812                "Timer", md->tokens[1], bd->cid );
813       
814        return 1;
815}
816
817static int msn_soap_ab_contact_del_handle_response( struct msn_soap_req_data *soap_req )
818{
819        /* TODO: Ack the change? Not sure what the NAKs look like.. */
820        return MSN_SOAP_OK;
821}
822
823static int msn_soap_ab_contact_del_free_data( struct msn_soap_req_data *soap_req )
824{
825        return 0;
826}
827
828int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu )
829{
830        return msn_soap_start( ic, bu,
831                               msn_soap_ab_contact_del_build_request,
832                               NULL,
833                               msn_soap_ab_contact_del_handle_response,
834                               msn_soap_ab_contact_del_free_data );
835}
Note: See TracBrowser for help on using the repository browser.