comparison libpurple/protocols/msn/soap2.c @ 20527:0034d7e89032

mostly done with soap level parsing, compiles
author Ka-Hing Cheung <khc@hxbc.us>
date Fri, 21 Sep 2007 06:50:40 +0000
parents 915e11fbaeb0
children 06527cc0f79b
comparison
equal deleted inserted replaced
20526:915e11fbaeb0 20527:0034d7e89032
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */ 24 */
25 25
26 #include "soap2.h" 26 #include "soap2.h"
27 27
28 #include "debug.h"
28 #include "xmlnode.h" 29 #include "xmlnode.h"
29 30
30 #include <glib.h> 31 #include <glib.h>
31 #include <error.h> 32 #include <error.h>
32 33
63 MsnSoapConnection2 *conn = data; 64 MsnSoapConnection2 *conn = data;
64 65
65 msn_soap_connection2_cleanup(conn); 66 msn_soap_connection2_cleanup(conn);
66 } 67 }
67 68
69 static gboolean
70 msn_soap_handle_redirect(MsnSoapConnection2 *conn, const char *url)
71 {
72 char *c;
73
74 /* Skip the http:// */
75 if ((c = strchr(url, '/')) != NULL)
76 url += 2;
77
78 if ((c = strchr(url, '/')) != NULL) {
79 g_free(conn->request->host);
80 g_free(conn->request->path);
81
82 conn->request->host = g_strndup(url, c - url);
83 conn->request->path = g_strdup(c);
84
85 purple_input_remove(conn->io_handle);
86 conn->io_handle = 0;
87
88 msn_soap_connection2_post(conn, conn->request,
89 conn->request->cb, conn->request->data);
90
91 return TRUE;
92 }
93
94 return FALSE;
95 }
96
97 static gboolean
98 msn_soap_handle_body(MsnSoapConnection2 *conn, MsnSoapResponse *response)
99 {
100 xmlnode *node = response->message->xml;
101
102 if (strcmp(node->name, "Envelop") == 0 &&
103 node->child && strcmp(node->child->name, "Header") == 0 &&
104 node->child->next) {
105 xmlnode *body = node->child->next;
106
107 if (strcmp(body->name, "Fault")) {
108 xmlnode *fault = xmlnode_get_child(body, "faultcode");
109
110 if (fault != NULL) {
111 if (strcmp(fault->data, "psf:Redirect") == 0) {
112 xmlnode *url = xmlnode_get_child(fault, "redirectUrl");
113
114 if (url && !msn_soap_handle_redirect(conn, url->data)) {
115 return TRUE;
116 }
117 } else if (strcmp(fault->data, "wsse:FailedAuthentication")) {
118 xmlnode *reason = xmlnode_get_child(fault, "faultstring");
119
120 msn_session_set_error(conn->session, MSN_ERROR_AUTH,
121 reason ? reason->data : NULL);
122
123 return TRUE;
124 }
125 }
126
127 conn->request->cb(conn, conn->request, conn->response,
128 conn->request->data);
129
130 return TRUE;
131 }
132 }
133
134 return FALSE;
135 }
136
68 static void 137 static void
69 msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) 138 msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond)
70 { 139 {
71 MsnSoapConnection2 *conn = data; 140 MsnSoapConnection2 *conn = data;
141 MsnSoapMessage *message;
72 int count; 142 int count;
73 char buf[8192]; 143 char buf[8192];
74 int linebreak; 144 char *linebreak;
75 145
76 g_return_if_fail(cond == PURPLE_INPUT_READ); 146 g_return_if_fail(cond == PURPLE_INPUT_READ);
77 147
78 count = purple_ssl_read(conn->ssl, buf, sizeof(buf)); 148 count = purple_ssl_read(conn->ssl, buf, sizeof(buf));
79 if (count < 0 && errno == EAGAIN) 149 if (count < 0 && errno == EAGAIN)
81 else if (count <= 0) { 151 else if (count <= 0) {
82 msn_soap_connection2_cleanup(conn); 152 msn_soap_connection2_cleanup(conn);
83 return; 153 return;
84 } 154 }
85 155
86 if (conn->buf == NULL) { 156 if (conn->response == NULL) {
87 conn->buf = g_memdup(buf, count); 157 conn->response = msn_soap_response_new();
88 conn->buf_len = len; 158 conn->response->message = msn_soap_message_new();
159 }
160
161 message = conn->response->message;
162
163 if (message->buf == NULL) {
164 message->buf = g_memdup(buf, count);
165 message->buf_len = count;
89 } else { 166 } else {
90 conn->buf = g_realloc(conn->buf, conn->buf_len + count); 167 message->buf = g_realloc(message->buf, message->buf_len + count);
91 memcpy(conn->buf + conn->buf_len, buf, count); 168 memcpy(message->buf + message->buf_len, buf, count);
92 conn->buf_len += count; 169 message->buf_len += count;
93 } 170 }
94 171
95 if (conn->response == NULL) { 172 if (conn->response->seen_newline) {
96 conn->response = msn_soap_message_new(conn->current->action, NULL); 173 if (message->buf_len - message->buf_count >=
97 } 174 conn->response->body_len) {
98 175 xmlnode *node = xmlnode_from_str(
99 while ((linebreak = strstr(conn->buf + conn->buf_count, "\r\n")) != NULL) { 176 message->buf + message->buf_count, conn->response->body_len);
100 177
178 if (node == NULL) {
179 purple_debug_info("soap", "Malformed SOAP response: %s\n",
180 message->buf + message->buf_count);
181 } else {
182 conn->response->message->xml = node;
183 msn_soap_handle_body(conn, conn->response);
184 }
185 }
186
187 return;
188 }
189
190 while ((linebreak = strstr(message->buf + message->buf_count, "\r\n"))
191 != NULL) {
192 message->buf_count = linebreak - message->buf + 2;
193
194 if (conn->response->code == -1) {
195 if (sscanf(message->buf + message->buf_count, "HTTP/1.1 %d",
196 &conn->response->code) != 1) {
197 /* something horribly wrong */
198 msn_soap_connection2_destroy_foreach_cb(conn->request, conn);
199 conn->request = NULL;
200 } else if (conn->response->code == 503) {
201 msn_session_set_error(conn->session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
202 }
203 } else if (message->buf + message->buf_count == linebreak) {
204 /* blank line */
205 conn->response->seen_newline = TRUE;
206 } else {
207 char *sep = strstr(message->buf + message->buf_count, ": ");
208 char *key = message->buf + message->buf_count;
209 char *value = sep + 2;
210
211 *sep = '\0';
212 *linebreak = '\0';
213 msn_soap_message_add_header(message, key, value);
214
215 if ((conn->response->code == 301 || conn->response->code == 300)
216 && strcmp(key, "Location") == 0) {
217
218 if (msn_soap_handle_redirect(conn, value)) {
219
220 } else if (conn->request->cb) {
221 conn->request->cb(conn, conn->request, NULL,
222 conn->request->data);
223 }
224 } else if (conn->response->code == 401 &&
225 strcmp(key, "WWW-Authenticate") == 0) {
226 char *error = strstr(value, "cbtxt=");
227
228 if (error) {
229 error += strlen("cbtxt=");
230 }
231
232 msn_session_set_error(conn->session, MSN_ERROR_AUTH,
233 error ? purple_url_decode(error) : NULL);
234 } else if (strcmp(key, "Content-Length") == 0) {
235 conn->response->body_len = atoi(value);
236 }
237 }
101 } 238 }
102 } 239 }
103 240
104 static void 241 static void
105 msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond) 242 msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond)
106 { 243 {
107 MsnSoapConnection2 *conn = data; 244 MsnSoapConnection2 *conn = data;
245 MsnSoapMessage *message = conn->request->message;
108 int written; 246 int written;
109 247
110 g_return_if_fail(cond == PURPLE_INPUT_WRITE); 248 g_return_if_fail(cond == PURPLE_INPUT_WRITE);
111 249
112 written = purple_ssl_write(conn->ssl, conn->buf + conn->buf_count, 250 written = purple_ssl_write(conn->ssl, message->buf + message->buf_count,
113 conn->buf_len - conn->buf_count); 251 message->buf_len - message->buf_count);
114 252
115 if (written < 0 && errno == EAGAIN) 253 if (written < 0 && errno == EAGAIN)
116 return; 254 return;
117 else if (written <= 0) { 255 else if (written <= 0) {
118 msn_soap_connection2_cleanup(conn); 256 msn_soap_connection2_cleanup(conn);
119 return; 257 return;
120 } 258 }
121 259
122 conn->buf_count += written; 260 message->buf_count += written;
123 261
124 if (conn->buf_count < conn->buf_len) 262 if (message->buf_count < message->buf_len)
125 return; 263 return;
126 264
127 /* we are done! */ 265 /* we are done! */
128 g_free(conn->buf);
129 conn->buf_len = 0;
130 conn->buf_count = 0;
131
132 purple_input_remove(conn->io_handle); 266 purple_input_remove(conn->io_handle);
133 conn->io_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ, 267 conn->io_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ,
134 msn_soap_read_cb, conn); 268 msn_soap_read_cb, conn);
135 } 269 }
136 270
137 static gboolean 271 static gboolean
138 msn_soap_connection2_run(gpointer data) 272 msn_soap_connection2_run(gpointer data)
139 { 273 {
140 MsnSoapConnection2 *conn = data; 274 MsnSoapConnection2 *conn = data;
141 MsnSoapMessage *req = g_queue_peek_head(conn->queue); 275 MsnSoapRequest *req = g_queue_peek_head(conn->queue);
142 276
143 if (req) { 277 if (req) {
144 if (conn->ssl) { 278 if (conn->ssl) {
145 if (strcmp(conn->ssl->host, req->host) != 0 || 279 if (strcmp(conn->ssl->host, req->host) != 0 ||
146 strcmp(conn->path, req->path) != 0) { 280 strcmp(conn->path, req->path) != 0) {
281 purple_input_remove(conn->io_handle);
282 conn->io_handle = 0;
147 purple_ssl_close(conn->ssl); 283 purple_ssl_close(conn->ssl);
148 conn->ssl = NULL; 284 conn->ssl = NULL;
149 g_free(conn->path); 285 g_free(conn->path);
150 conn->path = NULL; 286 conn->path = NULL;
151 } 287 }
155 conn->ssl = purple_ssl_connect(conn->session->account, req->host, 291 conn->ssl = purple_ssl_connect(conn->session->account, req->host,
156 443, msn_soap_connected_cb, msn_soap_error_cb, conn); 292 443, msn_soap_connected_cb, msn_soap_error_cb, conn);
157 conn->path = g_strdup(req->path); 293 conn->path = g_strdup(req->path);
158 } else { 294 } else {
159 int len = -1; 295 int len = -1;
160 char *body = xmlnode_to_str(req->message, &len); 296 MsnSoapMessage *message = req->message;
297 char *body = xmlnode_to_str(message->xml, &len);
161 GString *str = g_string_new(""); 298 GString *str = g_string_new("");
162 GSList *iter; 299 GSList *iter;
163 300
164 g_queue_pop_head(conn->queue); 301 g_queue_pop_head(conn->queue);
165 302
176 "Cache-Control: no-cache\r\n", 313 "Cache-Control: no-cache\r\n",
177 req->path, req->action, 314 req->path, req->action,
178 conn->session->passport_info.mspauth, 315 conn->session->passport_info.mspauth,
179 req->host, len); 316 req->host, len);
180 317
181 for (iter = req->headers; iter; iter = iter->next) { 318 for (iter = req->message->headers; iter; iter = iter->next) {
182 g_string_append(str, (char *)iter->data); 319 g_string_append(str, (char *)iter->data);
183 g_string_append(str, "\r\n"); 320 g_string_append(str, "\r\n");
184 } 321 }
185 322
186 g_string_append(str, "\r\n"); 323 g_string_append(str, "\r\n");
187 g_string_append(str, body); 324 g_string_append(str, body);
188 325
189 conn->buf_len = str->len; 326 message->buf_len = str->len;
190 conn->buf = g_string_free(str, FALSE); 327 message->buf = g_string_free(str, FALSE);
191 conn->buf_count = 0; 328 message->buf_count = 0;
192 conn->current = req; 329 conn->request = req;
193 330
194 conn->io_handle = purple_input_add(conn->ssl->fd, 331 conn->io_handle = purple_input_add(conn->ssl->fd,
195 PURPLE_INPUT_WRITE, msn_soap_write_cb, conn); 332 PURPLE_INPUT_WRITE, msn_soap_write_cb, conn);
196 msn_soap_write_cb(conn, conn->ssl->fd, PURPLE_INPUT_WRITE); 333 msn_soap_write_cb(conn, conn->ssl->fd, PURPLE_INPUT_WRITE);
197 } 334 }
200 conn->idle_handle = 0; 337 conn->idle_handle = 0;
201 return FALSE; 338 return FALSE;
202 } 339 }
203 340
204 void 341 void
205 msn_soap_connection2_post(MsnSoapConnection2 *conn, MsnSoapMessage *req, 342 msn_soap_connection2_post(MsnSoapConnection2 *conn, MsnSoapRequest *req,
206 const char *host, const char *path, MsnSoapCallback cb, gpointer data) 343 MsnSoapCallback cb, gpointer data)
207 { 344 {
208 req->cb = cb; 345 req->cb = cb;
209 req->data = data; 346 req->data = data;
210 req->host = g_strdup(host);
211 req->path = g_strdup(path);
212 347
213 g_queue_push_tail(conn->queue, req); 348 g_queue_push_tail(conn->queue, req);
214 349
215 if (conn->idle_handle == 0) 350 if (conn->idle_handle == 0)
216 conn->idle_handle = g_idle_add(msn_soap_connection2_run, conn); 351 conn->idle_handle = g_idle_add(msn_soap_connection2_run, conn);
217 } 352 }
218 353
219 static void 354 static void
220 msn_soap_connection2_destroy_foreach_cb(gpointer item, gpointer data) 355 msn_soap_connection2_destroy_foreach_cb(gpointer item, gpointer data)
221 { 356 {
222 MsnSoapMessage *req = item; 357 MsnSoapRequest *req = item;
223 MsnSoapConnection2 *conn = data; 358 MsnSoapConnection2 *conn = data;
224 359
225 if (req->cb) 360 if (req->cb)
226 req->cb(conn, req, NULL, req->data); 361 req->cb(conn, req, NULL, req->data);
227 362
228 msn_soap_message_destroy(req); 363 msn_soap_request2_destroy(req);
229 } 364 }
230 365
231 static void 366 static void
232 msn_soap_connection2_cleanup(MsnSoapConnection2 *conn) 367 msn_soap_connection2_cleanup(MsnSoapConnection2 *conn)
233 { 368 {
234 g_queue_foreach(conn->queue, msn_soap_connection2_destroy_foreach_cb, conn); 369 g_queue_foreach(conn->queue, msn_soap_connection2_destroy_foreach_cb, conn);
235 if (conn->current) { 370 if (conn->request) {
236 msn_soap_connection2_destroy_foreach_cb(conn->current, conn); 371 msn_soap_connection2_destroy_foreach_cb(conn->request, conn);
237 conn->current = NULL; 372 conn->request = NULL;
238 } 373 }
239 374
240 purple_input_remove(conn->io_handle); 375 purple_input_remove(conn->io_handle);
241 conn->io_handle = 0; 376 conn->io_handle = 0;
242 g_source_remove(conn->idle_handle); 377 g_source_remove(conn->idle_handle);
243 conn->idle_handle = 0; 378 conn->idle_handle = 0;
244 379
245 g_free(conn->buf);
246 conn->buf_len = 0;
247 conn->buf_count = 0;
248
249 if (conn->ssl) { 380 if (conn->ssl) {
250 purple_ssl_close(conn->ssl); 381 purple_ssl_close(conn->ssl);
251 conn->ssl = NULL; 382 conn->ssl = NULL;
252 } 383 }
253 384
263 g_queue_free(conn->queue); 394 g_queue_free(conn->queue);
264 g_free(conn); 395 g_free(conn);
265 } 396 }
266 397
267 MsnSoapMessage * 398 MsnSoapMessage *
268 msn_soap_message_new(const char *action, xmlnode *message) 399 msn_soap_message_new()
269 { 400 {
270 MsnSoapMessage *req = g_new0(MsnSoapMessage, 1); 401 MsnSoapMessage *req = g_new0(MsnSoapMessage, 1);
271 402
403 return req;
404 }
405
406 void
407 msn_soap_message_destroy(MsnSoapMessage *message)
408 {
409 g_slist_foreach(message->headers, (GFunc)g_free, NULL);
410 g_free(message->buf);
411 g_free(message);
412 }
413
414 void
415 msn_soap_message_add_header(MsnSoapMessage *req,
416 const char *name, const char *value)
417 {
418 char *header = g_strdup_printf("%s: %s\r\n", name, value);
419
420 req->headers = g_slist_prepend(req->headers, header);
421 }
422
423 MsnSoapRequest *
424 msn_soap_request2_new(const char *host, const char *path, const char *action)
425 {
426 MsnSoapRequest *req = g_new0(MsnSoapRequest, 1);
427
428 req->host = g_strdup(host);
429 req->path = g_strdup(path);
272 req->action = g_strdup(action); 430 req->action = g_strdup(action);
273 req->message = message;
274 431
275 return req; 432 return req;
276 } 433 }
277 434
278 void 435 void
279 msn_soap_message_destroy(MsnSoapMessage *req) 436 msn_soap_request2_destroy(MsnSoapRequest *req)
280 { 437 {
281 g_free(req->action); 438 g_free(req->action);
282 g_slist_foreach(req->headers, (GFunc)g_free, NULL);
283 g_free(req->host); 439 g_free(req->host);
284 g_free(req->path); 440 g_free(req->path);
441 msn_soap_message_destroy(req->message);
285 g_free(req); 442 g_free(req);
286 } 443 }
287 444
288 void 445 MsnSoapResponse *
289 msn_soap_message_add_header(MsnSoapMessage *req, 446 msn_soap_response_new(void)
290 const char *name, const char *value) 447 {
291 { 448 MsnSoapResponse *resp = g_new0(MsnSoapResponse, 1);
292 char *header = g_strdup_printf("%s: %s\r\n", name, value); 449
293 450 return resp;
294 req->headers = g_slist_prepend(req->headers, header); 451 }
295 } 452
453 void
454 msn_soap_response_destroy(MsnSoapResponse *resp)
455 {
456 msn_soap_message_destroy(resp->message);
457 resp->code = -1;
458 resp->body_len = -1;
459 g_free(resp);
460 }