source: protocols/msn/soap.c @ bc090f0

Last change on this file since bc090f0 was bc090f0, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-20T22:42:59Z

Error reporting and added a msgq_send function. Need to put some more
intelligence into it later.

  • 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 ? : "", oim->number, oim->number, oim->msg );
158       
159        g_free( display_name_b64 );
160       
161        return 1;
162}
163
164static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data )
165{
166        struct msn_soap_req_data *soap_req = data;
167        struct msn_soap_oim_send_data *oim = soap_req->data;
168        struct im_connection *ic = soap_req->ic;
169        struct msn_data *md = ic->proto_data;
170       
171        g_free( md->lock_key );
172        md->lock_key = msn_p11_challenge( node->text );
173       
174        oim->need_retry = 1;
175       
176        return XT_HANDLED;
177}
178
179static const struct xt_handler_entry msn_soap_oim_send_parser[] = {
180        { "LockKeyChallenge", "detail", msn_soap_oim_send_challenge },
181        { NULL,               NULL,     NULL                        }
182};
183
184static int msn_soap_oim_handle_response( struct msn_soap_req_data *soap_req )
185{
186        struct msn_soap_oim_send_data *oim = soap_req->data;
187       
188        if( soap_req->http_req->status_code == 500 && oim->need_retry && soap_req->ttl > 0 )
189        {
190                oim->need_retry = 0;
191                return MSN_SOAP_RETRY;
192        }
193        else if( soap_req->http_req->status_code == 200 )
194        {
195                imcb_log( soap_req->ic, "Offline message successfully delivered to %s", oim->to );
196                return MSN_SOAP_OK;
197        }
198        else
199        {
200                imcb_log( soap_req->ic, "Failed to deliver offline message to %s:\n%s", oim->to, oim->msg );
201                return MSN_SOAP_ABORT;
202        }
203}
204
205static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req )
206{
207        struct msn_soap_oim_send_data *oim = soap_req->data;
208       
209        g_free( oim->to );
210        g_free( oim->msg );
211        g_free( oim );
212       
213        return 0;
214}
215
216int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg )
217{
218        struct msn_soap_oim_send_data *data;
219       
220        data = g_new0( struct msn_soap_oim_send_data, 1 );
221        data->to = g_strdup( to );
222        data->msg = tobase64( msg );
223        data->number = 1;
224       
225        return msn_soap_start( ic, data, msn_soap_oim_build_request,
226                                         msn_soap_oim_send_parser,
227                                         msn_soap_oim_handle_response,
228                                         msn_soap_oim_free_data );
229}
230
231int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq )
232{
233        GSList *l;
234        char *n = NULL;
235       
236        for( l = *msgq; l; l = l->next )
237        {
238                struct msn_message *m = l->data;
239               
240                if( n == NULL )
241                        n = m->who;
242                if( strcmp( n, m->who ) == 0 )
243                        msn_soap_oim_send( ic, m->who, m->text );
244        }
245       
246        while( *msgq != NULL )
247        {
248                struct msn_message *m = (*msgq)->data;
249               
250                g_free( m->who );
251                g_free( m->text );
252                g_free( m );
253               
254                *msgq = g_slist_remove( *msgq, m );
255        }
256}
Note: See TracBrowser for help on using the repository browser.