source: protocols/msn/soap.c @ 193dc74

Last change on this file since 193dc74 was 193dc74, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-14T16:16:52Z

Responses to add requests work now.

  • Property mode set to 100644
File size: 20.0 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
[bc090f0]149
[523fb23]150/* passport_sso: Authentication MSNP15+ */
151
152struct msn_soap_passport_sso_data
153{
154        char *policy;
155        char *nonce;
156        char *secret;
157};
158
159static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req )
160{
161        struct msn_soap_passport_sso_data *sd = soap_req->data;
162        struct im_connection *ic = soap_req->ic;
163       
[73efe3a]164        if( g_str_has_suffix( ic->acc->user, "@msn.com" ) )
165                soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN );
166        else
167                soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL );
168       
[523fb23]169        soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD,
170                ic->acc->user, ic->acc->pass, sd->policy );
171       
172        return MSN_SOAP_OK;
173}
174
175static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer data )
176{
177        struct msn_soap_req_data *soap_req = data;
178        struct msn_soap_passport_sso_data *sd = soap_req->data;
179        struct msn_data *md = soap_req->ic->proto_data;
180        struct xt_node *p;
181        char *id;
182       
183        if( ( id = xt_find_attr( node, "Id" ) ) == NULL )
184                return XT_HANDLED;
185        id += strlen( id ) - 1;
186        if( *id == '1' &&
187            ( p = node->parent ) && ( p = p->parent ) &&
188            ( p = xt_find_node( p->children, "wst:RequestedProofToken" ) ) &&
189            ( p = xt_find_node( p->children, "wst:BinarySecret" ) ) &&
190            p->text )
191                sd->secret = g_strdup( p->text );
192       
[91d6e91]193        *id -= '1';
194        if( *id >= 0 && *id <= 2 )
195        {
196                g_free( md->tokens[(int)*id] );
197                md->tokens[(int)*id] = g_strdup( node->text );
198        }
[523fb23]199       
200        return XT_HANDLED;
201}
202
203static const struct xt_handler_entry msn_soap_passport_sso_parser[] = {
204        { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token },
205        { NULL, NULL, NULL }
206};
207
208static char *msn_key_fuckery( char *key, int key_len, char *type )
209{
210        unsigned char hash1[20+strlen(type)+1];
211        unsigned char hash2[20];
212        char *ret;
213       
214        sha1_hmac( key, key_len, type, 0, hash1 );
215        strcpy( (char*) hash1 + 20, type );
216        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2 );
217       
218        /* This is okay as hash1 is read completely before it's overwritten. */
219        sha1_hmac( key, key_len, (char*) hash1, 20, hash1 );
220        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1 );
221       
222        ret = g_malloc( 24 );
223        memcpy( ret, hash2, 20 );
224        memcpy( ret + 20, hash1, 4 );
225        return ret;
226}
227
228static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req )
229{
230        struct msn_soap_passport_sso_data *sd = soap_req->data;
231        struct im_connection *ic = soap_req->ic;
232        char *key1, *key2, *key3, *blurb64;
233        int key1_len;
234        unsigned char *padnonce, *des3res;
235        struct
236        {
237                unsigned int uStructHeaderSize; // 28. Does not count data
238                unsigned int uCryptMode; // CRYPT_MODE_CBC (1)
239                unsigned int uCipherType; // TripleDES (0x6603)
240                unsigned int uHashType; // SHA1 (0x8004)
241                unsigned int uIVLen;    // 8
242                unsigned int uHashLen;  // 20
243                unsigned int uCipherLen; // 72
244                unsigned char iv[8];
245                unsigned char hash[20];
246                unsigned char cipherbytes[72];
247        } blurb = {
248                GUINT32_TO_LE( 28 ),
249                GUINT32_TO_LE( 1 ),
250                GUINT32_TO_LE( 0x6603 ),
251                GUINT32_TO_LE( 0x8004 ),
252                GUINT32_TO_LE( 8 ),
253                GUINT32_TO_LE( 20 ),
254                GUINT32_TO_LE( 72 ),
255        };
256
257        key1_len = base64_decode( sd->secret, (unsigned char**) &key1 );
258       
259        key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH" );
260        key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION" );
261       
262        sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash );
263        padnonce = g_malloc( strlen( sd->nonce ) + 8 );
264        strcpy( (char*) padnonce, sd->nonce );
265        memset( padnonce + strlen( sd->nonce ), 8, 8 );
266       
267        random_bytes( blurb.iv, 8 );
268       
269        ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res );
270        memcpy( blurb.cipherbytes, des3res, 72 );
271       
272        blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) );
273        msn_auth_got_passport_token( ic, blurb64 );
274       
275        g_free( padnonce );
276        g_free( blurb64 );
277        g_free( des3res );
278        g_free( key1 );
279        g_free( key2 );
280        g_free( key3 );
281       
282        return MSN_SOAP_OK;
283}
284
285static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req )
286{
287        struct msn_soap_passport_sso_data *sd = soap_req->data;
288       
289        g_free( sd->policy );
290        g_free( sd->nonce );
291        g_free( sd->secret );
292       
293        return MSN_SOAP_OK;
294}
295
296int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce )
297{
298        struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 );
299       
300        sd->policy = g_strdup( policy );
301        sd->nonce = g_strdup( nonce );
302       
303        return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request,
304                                       msn_soap_passport_sso_parser,
305                                       msn_soap_passport_sso_handle_response,
306                                       msn_soap_passport_sso_free_data );
307}
308
309
[bc090f0]310/* oim_send: Sending offline messages */
311
312struct msn_soap_oim_send_data
313{
314        char *to;
315        char *msg;
316        int number;
317        int need_retry;
318};
319
[e5a8118]320static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req )
321{
322        struct msn_soap_oim_send_data *oim = soap_req->data;
323        struct im_connection *ic = soap_req->ic;
324        struct msn_data *md = ic->proto_data;
325        char *display_name_b64;
326       
[91d6e91]327        display_name_b64 = tobase64( set_getstr( &ic->acc->set, "display_name" ) );
[e5a8118]328       
329        soap_req->url = g_strdup( SOAP_OIM_SEND_URL );
[7db65b7]330        soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION );
[e5a8118]331        soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD,
[91d6e91]332                ic->acc->user, display_name_b64, MSNP_VER, MSNP_BUILD,
333                oim->to, md->tokens[2],
[5fecede]334                MSNP11_PROD_ID, md->lock_key ? md->lock_key : "",
335                oim->number, oim->number, oim->msg );
[e5a8118]336       
337        g_free( display_name_b64 );
338       
[523fb23]339        return MSN_SOAP_OK;
[e5a8118]340}
341
342static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data )
343{
344        struct msn_soap_req_data *soap_req = data;
345        struct msn_soap_oim_send_data *oim = soap_req->data;
346        struct im_connection *ic = soap_req->ic;
347        struct msn_data *md = ic->proto_data;
348       
349        g_free( md->lock_key );
350        md->lock_key = msn_p11_challenge( node->text );
351       
352        oim->need_retry = 1;
353       
354        return XT_HANDLED;
355}
356
357static const struct xt_handler_entry msn_soap_oim_send_parser[] = {
358        { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge },
359        { NULL,               NULL,     NULL                        }
360};
361
362static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req )
363{
364        struct msn_soap_oim_send_data *oim = soap_req->data;
365       
[bc090f0]366        if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 )
[e5a8118]367        {
368                oim->need_retry = 0;
369                return MSN_SOAP_RETRY;
370        }
371        else if( soap_req->http_req->status_code == 200 )
[bc090f0]372        {
373                imcb_log( soap_req->ic, "Offline message successfully delivered to %s", oim->to );
[e5a8118]374                return MSN_SOAP_OK;
[bc090f0]375        }
[e5a8118]376        else
[bc090f0]377        {
378                imcb_log( soap_req->ic, "Failed to deliver offline message to %s:\n%s", oim->to, oim->msg );
[e5a8118]379                return MSN_SOAP_ABORT;
[bc090f0]380        }
[e5a8118]381}
382
383static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req )
384{
385        struct msn_soap_oim_send_data *oim = soap_req->data;
386       
387        g_free( oim->to );
388        g_free( oim->msg );
389        g_free( oim );
390       
[523fb23]391        return MSN_SOAP_OK;
[e5a8118]392}
393
394int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg )
395{
396        struct msn_soap_oim_send_data *data;
397       
398        data = g_new0( struct msn_soap_oim_send_data, 1 );
399        data->to = g_strdup( to );
400        data->msg = tobase64( msg );
401        data->number = 1;
402       
403        return msn_soap_start( ic, data, msn_soap_oim_build_request,
404                                         msn_soap_oim_send_parser,
405                                         msn_soap_oim_handle_response,
406                                         msn_soap_oim_free_data );
407}
[bc090f0]408
409int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq )
410{
411        GSList *l;
412        char *n = NULL;
413       
414        for( l = *msgq; l; l = l->next )
415        {
416                struct msn_message *m = l->data;
417               
418                if( n == NULL )
419                        n = m->who;
420                if( strcmp( n, m->who ) == 0 )
421                        msn_soap_oim_send( ic, m->who, m->text );
422        }
423       
424        while( *msgq != NULL )
425        {
426                struct msn_message *m = (*msgq)->data;
427               
428                g_free( m->who );
429                g_free( m->text );
430                g_free( m );
431               
432                *msgq = g_slist_remove( *msgq, m );
433        }
[523fb23]434       
435        return 1;
[bc090f0]436}
[7db65b7]437
438
439/* memlist: Fetching the membership list (NOT address book) */
440
441static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req )
442{
[7f34ce2]443        struct msn_data *md = soap_req->ic->proto_data;
444       
[7db65b7]445        soap_req->url = g_strdup( SOAP_MEMLIST_URL );
446        soap_req->action = g_strdup( SOAP_MEMLIST_ACTION );
[7f34ce2]447        soap_req->payload = g_markup_printf_escaped( SOAP_MEMLIST_PAYLOAD, md->tokens[1] );
[7db65b7]448       
449        return 1;
450}
451
[7f34ce2]452static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data )
453{
454        bee_user_t *bu;
455        struct msn_buddy_data *bd;
456        struct xt_node *p;
457        char *role = NULL, *handle = NULL;
458        struct msn_soap_req_data *soap_req = data;
459        struct im_connection *ic = soap_req->ic;
460       
461        if( ( p = node->parent ) && ( p = p->parent ) &&
462            ( p = xt_find_node( p->children, "MemberRole" ) ) )
463                role = p->text;
464       
465        if( ( p = xt_find_node( node->children, "PassportName" ) ) )
466                handle = p->text;
467       
468        if( !role || !handle || 
469            !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
470               ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )
471                return XT_HANDLED;
472       
473        bd = bu->data;
474        if( strcmp( role, "Allow" ) == 0 )
475                bd->flags |= MSN_BUDDY_AL;
476        else if( strcmp( role, "Block" ) == 0 )
477                bd->flags |= MSN_BUDDY_BL;
478        else if( strcmp( role, "Reverse" ) == 0 )
[e5854a8]479        {
[7f34ce2]480                bd->flags |= MSN_BUDDY_RL;
[e5854a8]481                msn_buddy_ask( bu );
482        }
[7f34ce2]483        else if( strcmp( role, "Pending" ) == 0 )
[e5854a8]484        {
[7f34ce2]485                bd->flags |= MSN_BUDDY_PL;
[e5854a8]486                msn_buddy_ask( bu );
487        }
488       
489        printf( "%s %d\n", handle, bd->flags );
[7f34ce2]490       
491        return XT_HANDLED;
492}
493
[7db65b7]494static const struct xt_handler_entry msn_soap_memlist_parser[] = {
[7f34ce2]495        { "Member", "Members", msn_soap_memlist_member },
[7db65b7]496        { NULL,               NULL,     NULL                        }
497};
498
499static int msn_soap_memlist_handle_response( struct msn_soap_req_data *soap_req )
500{
[7f34ce2]501        msn_soap_addressbook_request( soap_req->ic );
502       
503        return MSN_SOAP_OK;
[7db65b7]504}
505
506static int msn_soap_memlist_free_data( struct msn_soap_req_data *soap_req )
507{
508        return 0;
509}
510
511int msn_soap_memlist_request( struct im_connection *ic )
512{
513        return msn_soap_start( ic, NULL, msn_soap_memlist_build_request,
514                                         msn_soap_memlist_parser,
515                                         msn_soap_memlist_handle_response,
516                                         msn_soap_memlist_free_data );
517}
[7f34ce2]518
[193dc74]519/* Variant: Adding/Removing people */
520struct msn_soap_memlist_edit_data
521{
522        char *handle;
523        gboolean add;
524        msn_buddy_flags_t list;
525};
526
527static int msn_soap_memlist_edit_build_request( struct msn_soap_req_data *soap_req )
528{
529        struct msn_data *md = soap_req->ic->proto_data;
530        struct msn_soap_memlist_edit_data *med = soap_req->data;
531        char *add, *scenario, *list;
532       
533        soap_req->url = g_strdup( SOAP_MEMLIST_URL );
534        if( med->add )
535        {
536                soap_req->action = g_strdup( SOAP_MEMLIST_ADD_ACTION );
537                add = "Add";
538        }
539        else
540        {
541                soap_req->action = g_strdup( SOAP_MEMLIST_DEL_ACTION );
542                add = "Delete";
543        }
544        switch( med->list )
545        {
546        case MSN_BUDDY_AL:
547                scenario = "BlockUnblock";
548                list = "Allow";
549                break;
550        case MSN_BUDDY_BL:
551                scenario = "BlockUnblock";
552                list = "Block";
553                break;
554        case MSN_BUDDY_RL:
555                scenario = "Timer";
556                list = "Reverse";
557                break;
558        case MSN_BUDDY_PL:
559        default:
560                scenario = "Timer";
561                list = "Pending";
562                break;
563        }
564        soap_req->payload = g_markup_printf_escaped( SOAP_MEMLIST_EDIT_PAYLOAD,
565                scenario, md->tokens[1], add, list, med->handle, add );
566       
567        return 1;
568}
569
570static int msn_soap_memlist_edit_handle_response( struct msn_soap_req_data *soap_req )
571{
572        return MSN_SOAP_OK;
573}
574
575static int msn_soap_memlist_edit_free_data( struct msn_soap_req_data *soap_req )
576{
577        struct msn_soap_memlist_edit_data *med = soap_req->data;
578       
579        g_free( med->handle );
580        g_free( med );
581       
582        return 0;
583}
584
585int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list )
586{
587        struct msn_soap_memlist_edit_data *med;
588       
589        med = g_new0( struct msn_soap_memlist_edit_data, 1 );
590        med->handle = g_strdup( handle );
591        med->add = add;
592        med->list = list;
593       
594        return msn_soap_start( ic, med, msn_soap_memlist_edit_build_request,
595                                        NULL,
596                                        msn_soap_memlist_edit_handle_response,
597                                        msn_soap_memlist_edit_free_data );
598}
599
[7f34ce2]600
601/* addressbook: Fetching the membership list (NOT address book) */
602
603static int msn_soap_addressbook_build_request( struct msn_soap_req_data *soap_req )
604{
605        struct msn_data *md = soap_req->ic->proto_data;
606       
607        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
608        soap_req->action = g_strdup( SOAP_ADDRESSBOOK_ACTION );
609        soap_req->payload = g_markup_printf_escaped( SOAP_ADDRESSBOOK_PAYLOAD, md->tokens[1] );
610       
611        return 1;
612}
613
614static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data )
615{
616        struct xt_node *p;
617        char *id = NULL, *name = NULL;
618        struct msn_soap_req_data *soap_req = data;
619       
620        if( ( p = node->parent ) &&
621            ( p = xt_find_node( p->children, "groupId" ) ) )
622                id = p->text;
623       
624        if( ( p = xt_find_node( node->children, "name" ) ) )
625                name = p->text;
626       
627        printf( "%s %s\n", id, name );
628       
629        return XT_HANDLED;
630}
631
632static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer data )
633{
634        bee_user_t *bu;
635        struct msn_buddy_data *bd;
636        struct xt_node *p;
637        char *id = NULL, *type = NULL, *handle = NULL, *display_name = NULL;
638        struct msn_soap_req_data *soap_req = data;
639        struct im_connection *ic = soap_req->ic;
640       
641        if( ( p = node->parent ) &&
642            ( p = xt_find_node( p->children, "contactId" ) ) )
643                id = p->text;
644        if( ( p = xt_find_node( node->children, "contactType" ) ) )
645                type = p->text;
646        if( ( p = xt_find_node( node->children, "passportName" ) ) )
647                handle = p->text;
648        if( ( p = xt_find_node( node->children, "displayName" ) ) )
649                display_name = p->text;
650       
651        if( type && g_strcasecmp( type, "me" ) == 0 )
652        {
653                set_t *set = set_find( &ic->acc->set, "display_name" );
654                g_free( set->value );
655                set->value = g_strdup( display_name );
656               
657                return XT_HANDLED;
658        }
659       
660        if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) &&
661            !( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) )
662                return XT_HANDLED;
663       
664        bd = bu->data;
665        bd->flags |= MSN_BUDDY_FL;
666        g_free( bd->cid );
667        bd->cid = g_strdup( id );
668       
669        imcb_rename_buddy( ic, handle, display_name );
670       
671        printf( "%s %s %s %s\n", id, type, handle, display_name );
672       
673        return XT_HANDLED;
674}
675
676static const struct xt_handler_entry msn_soap_addressbook_parser[] = {
677        { "contactInfo", "Contact", msn_soap_addressbook_contact },
678        { "groupInfo", "Group", msn_soap_addressbook_group },
679        { NULL,               NULL,     NULL                        }
680};
681
682static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req )
683{
[ca7de3a]684        msn_auth_got_contact_list( soap_req->ic );
[7f34ce2]685        return MSN_SOAP_OK;
686}
687
688static int msn_soap_addressbook_free_data( struct msn_soap_req_data *soap_req )
689{
690        return 0;
691}
692
693int msn_soap_addressbook_request( struct im_connection *ic )
694{
695        return msn_soap_start( ic, NULL, msn_soap_addressbook_build_request,
696                                         msn_soap_addressbook_parser,
697                                         msn_soap_addressbook_handle_response,
698                                         msn_soap_addressbook_free_data );
699}
[4452e69]700
701/* Variant: Change our display name. */
702static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_req )
703{
704        struct msn_data *md = soap_req->ic->proto_data;
705       
706        soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL );
707        soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION );
708        soap_req->payload = g_markup_printf_escaped( SOAP_AB_NAMECHANGE_PAYLOAD,
709                md->tokens[1], (char *) soap_req->data );
710       
711        return 1;
712}
713
714static int msn_soap_ab_namechange_handle_response( struct msn_soap_req_data *soap_req )
715{
716        /* TODO: Ack the change? Not sure what the NAKs look like.. */
717        return MSN_SOAP_OK;
718}
719
720static int msn_soap_ab_namechange_free_data( struct msn_soap_req_data *soap_req )
721{
722        g_free( soap_req->data );
723        return 0;
724}
725
726int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new )
727{
728        return msn_soap_start( ic, g_strdup( new ),
729                               msn_soap_ab_namechange_build_request,
730                               NULL,
731                               msn_soap_ab_namechange_handle_response,
732                               msn_soap_ab_namechange_free_data );
733}
Note: See TracBrowser for help on using the repository browser.