source: protocols/msn/soap.c @ 5fecede

Last change on this file since 5fecede was 5fecede, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-08T17:29:43Z

Enough changes to successfully login up to (but not including) fetching the
contact list.

  • Property mode set to 100644
File size: 6.8 KB
Line 
1/** soap.c
2 *
3 * SOAP-related functions. Some manager at Microsoft apparently thought
4 * MSNP wasn't XMLy enough so someone stepped up and changed that. This
5 * is the result.
6 *
7 * Copyright (C) 2010 Wilmer van der Gaast <wilmer@gaast.net>
8 *
9 * This program is free software; you can redistribute it and/or modify             
10 * it under the terms of the GNU General Public License version 2                   
11 * as published by the Free Software Foundation                                     
12 *                                                                                   
13 * This program is distributed in the hope that is will be useful,                 
14 * bit WITHOU ANY WARRANTY; without even the implied warranty of                   
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                   
16 * GNU General Public License for more details.                                     
17 *                                                                                   
18 * You should have received a copy of the GNU General Public License               
19 * along with this program; if not, write to the Free Software                     
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA         
21 *
22 */
23
24#include "http_client.h"
25#include "soap.h"
26#include "msn.h"
27#include "bitlbee.h"
28#include "url.h"
29#include "misc.h"
30#include "base64.h"
31#include "xmltree.h"
32#include <ctype.h>
33#include <errno.h>
34
35typedef enum
36{
37        MSN_SOAP_OK,
38        MSN_SOAP_RETRY,
39        MSN_SOAP_ABORT,
40} msn_soap_result_t;
41
42struct msn_soap_req_data;
43
44typedef int (*msn_soap_func) ( struct msn_soap_req_data * );
45
46struct msn_soap_req_data
47{
48        void *data;
49        struct im_connection *ic;
50        int ttl;
51       
52        char *url, *action, *payload;
53        struct http_request *http_req;
54       
55        const struct xt_handler_entry *xml_parser;
56        msn_soap_func build_request, handle_response, free_data;
57};
58
59static int msn_soap_send_request( struct msn_soap_req_data *req );
60
61static int msn_soap_start( struct im_connection *ic,
62                    void *data,
63                    msn_soap_func build_request,
64                    const struct xt_handler_entry *xml_parser,
65                    msn_soap_func handle_response,
66                    msn_soap_func free_data )
67{
68        struct msn_soap_req_data *req = g_new0( struct msn_soap_req_data, 1 );
69       
70        req->ic = ic;
71        req->data = data;
72        req->xml_parser = xml_parser;
73        req->build_request = build_request;
74        req->handle_response = handle_response;
75        req->free_data = free_data;
76        req->ttl = 3;
77       
78        return msn_soap_send_request( req );
79}
80
81static void msn_soap_handle_response( struct http_request *http_req );
82
83static int msn_soap_send_request( struct msn_soap_req_data *soap_req )
84{
85        char *http_req;
86        url_t url;
87       
88        soap_req->build_request( soap_req );
89       
90        url_set( &url, soap_req->url );
91        http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host,
92                soap_req->action, strlen( soap_req->payload ), soap_req->payload );
93       
94        soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS,
95                http_req, msn_soap_handle_response, soap_req );
96       
97        g_free( http_req );
98       
99        return soap_req->http_req != NULL;
100}
101
102static void msn_soap_handle_response( struct http_request *http_req )
103{
104        struct msn_soap_req_data *soap_req = http_req->data;
105        int st;
106       
107        if( http_req->body_size > 0 )
108        {
109                struct xt_parser *parser;
110               
111                parser = xt_new( soap_req->xml_parser, soap_req );
112                xt_feed( parser, http_req->reply_body, http_req->body_size );
113                xt_handle( parser, NULL, -1 );
114                xt_free( parser );
115        }
116       
117        st = soap_req->handle_response( soap_req );
118       
119        g_free( soap_req->url );
120        g_free( soap_req->action );
121        g_free( soap_req->payload );
122        soap_req->url = soap_req->action = soap_req->payload = NULL;
123       
124        if( st == MSN_SOAP_RETRY && --soap_req->ttl )
125                msn_soap_send_request( soap_req );
126        else
127        {
128                soap_req->free_data( soap_req );
129                g_free( soap_req );
130        }
131}
132
133
134/* oim_send: Sending offline messages */
135
136struct msn_soap_oim_send_data
137{
138        char *to;
139        char *msg;
140        int number;
141        int need_retry;
142};
143
144static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req )
145{
146        struct msn_soap_oim_send_data *oim = soap_req->data;
147        struct im_connection *ic = soap_req->ic;
148        struct msn_data *md = ic->proto_data;
149        char *display_name_b64;
150       
151        display_name_b64 = tobase64( ic->displayname );
152       
153        soap_req->url = g_strdup( SOAP_OIM_SEND_URL );
154        soap_req->action = g_strdup( SOAP_OIM_ACTION_URL );
155        soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD,
156                ic->acc->user, display_name_b64, oim->to, md->passport_token,
157                MSNP11_PROD_ID, md->lock_key ? md->lock_key : "",
158                oim->number, oim->number, oim->msg );
159       
160        g_free( display_name_b64 );
161       
162        return 1;
163}
164
165static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data )
166{
167        struct msn_soap_req_data *soap_req = data;
168        struct msn_soap_oim_send_data *oim = soap_req->data;
169        struct im_connection *ic = soap_req->ic;
170        struct msn_data *md = ic->proto_data;
171       
172        g_free( md->lock_key );
173        md->lock_key = msn_p11_challenge( node->text );
174       
175        oim->need_retry = 1;
176       
177        return XT_HANDLED;
178}
179
180static const struct xt_handler_entry msn_soap_oim_send_parser[] = {
181        { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge },
182        { NULL,               NULL,     NULL                        }
183};
184
185static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req )
186{
187        struct msn_soap_oim_send_data *oim = soap_req->data;
188       
189        if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 )
190        {
191                oim->need_retry = 0;
192                return MSN_SOAP_RETRY;
193        }
194        else if( soap_req->http_req->status_code == 200 )
195        {
196                imcb_log( soap_req->ic, "Offline message successfully delivered to %s", oim->to );
197                return MSN_SOAP_OK;
198        }
199        else
200        {
201                imcb_log( soap_req->ic, "Failed to deliver offline message to %s:\n%s", oim->to, oim->msg );
202                return MSN_SOAP_ABORT;
203        }
204}
205
206static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req )
207{
208        struct msn_soap_oim_send_data *oim = soap_req->data;
209       
210        g_free( oim->to );
211        g_free( oim->msg );
212        g_free( oim );
213       
214        return 0;
215}
216
217int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg )
218{
219        struct msn_soap_oim_send_data *data;
220       
221        data = g_new0( struct msn_soap_oim_send_data, 1 );
222        data->to = g_strdup( to );
223        data->msg = tobase64( msg );
224        data->number = 1;
225       
226        return msn_soap_start( ic, data, msn_soap_oim_build_request,
227                                         msn_soap_oim_send_parser,
228                                         msn_soap_oim_handle_response,
229                                         msn_soap_oim_free_data );
230}
231
232int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq )
233{
234        GSList *l;
235        char *n = NULL;
236       
237        for( l = *msgq; l; l = l->next )
238        {
239                struct msn_message *m = l->data;
240               
241                if( n == NULL )
242                        n = m->who;
243                if( strcmp( n, m->who ) == 0 )
244                        msn_soap_oim_send( ic, m->who, m->text );
245        }
246       
247        while( *msgq != NULL )
248        {
249                struct msn_message *m = (*msgq)->data;
250               
251                g_free( m->who );
252                g_free( m->text );
253                g_free( m );
254               
255                *msgq = g_slist_remove( *msgq, m );
256        }
257}
Note: See TracBrowser for help on using the repository browser.