| 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 } |
| 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 } |