Mercurial > pidgin.yaz
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 } |