| |
1 /** |
| |
2 * @file httpmethod.c HTTP connection method |
| |
3 * |
| |
4 * gaim |
| |
5 * |
| |
6 * Gaim is the legal property of its developers, whose names are too numerous |
| |
7 * to list here. Please refer to the COPYRIGHT file distributed with this |
| |
8 * source distribution. |
| |
9 * |
| |
10 * This program is free software; you can redistribute it and/or modify |
| |
11 * it under the terms of the GNU General Public License as published by |
| |
12 * the Free Software Foundation; either version 2 of the License, or |
| |
13 * (at your option) any later version. |
| |
14 * |
| |
15 * This program is distributed in the hope that it will be useful, |
| |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
18 * GNU General Public License for more details. |
| |
19 * |
| |
20 * You should have received a copy of the GNU General Public License |
| |
21 * along with this program; if not, write to the Free Software |
| |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
23 */ |
| |
24 #include "msn.h" |
| |
25 #include "debug.h" |
| |
26 #include "httpconn.h" |
| |
27 |
| |
28 typedef struct |
| |
29 { |
| |
30 MsnHttpConn *httpconn; |
| |
31 char *buffer; |
| |
32 size_t size; |
| |
33 |
| |
34 } MsnHttpQueueData; |
| |
35 |
| |
36 static void read_cb(gpointer data, gint source, GaimInputCondition cond); |
| |
37 void msn_httpconn_process_queue(MsnHttpConn *httpconn); |
| |
38 gboolean msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, |
| |
39 size_t size, char **ret_buf, size_t *ret_size, |
| |
40 gboolean *error); |
| |
41 |
| |
42 MsnHttpConn * |
| |
43 msn_httpconn_new(MsnServConn *servconn) |
| |
44 { |
| |
45 MsnHttpConn *httpconn; |
| |
46 |
| |
47 g_return_val_if_fail(servconn != NULL, NULL); |
| |
48 |
| |
49 httpconn = g_new0(MsnHttpConn, 1); |
| |
50 |
| |
51 /* TODO: Remove this */ |
| |
52 httpconn->session = servconn->session; |
| |
53 |
| |
54 httpconn->servconn = servconn; |
| |
55 |
| |
56 return httpconn; |
| |
57 } |
| |
58 |
| |
59 void |
| |
60 msn_httpconn_destroy(MsnHttpConn *httpconn) |
| |
61 { |
| |
62 g_return_if_fail(httpconn != NULL); |
| |
63 |
| |
64 if (httpconn->connected) |
| |
65 msn_httpconn_disconnect(httpconn); |
| |
66 |
| |
67 if (httpconn->host != NULL) |
| |
68 g_free(httpconn->host); |
| |
69 |
| |
70 g_free(httpconn); |
| |
71 } |
| |
72 |
| |
73 static void |
| |
74 show_error(MsnHttpConn *httpconn) |
| |
75 { |
| |
76 GaimConnection *gc; |
| |
77 char *tmp; |
| |
78 char *cmd; |
| |
79 |
| |
80 const char *names[] = { "Notification", "Switchboard" }; |
| |
81 const char *name; |
| |
82 |
| |
83 gc = gaim_account_get_connection(httpconn->servconn->session->account); |
| |
84 name = names[httpconn->servconn->type]; |
| |
85 |
| |
86 switch (httpconn->servconn->cmdproc->error) |
| |
87 { |
| |
88 case MSN_ERROR_CONNECT: |
| |
89 tmp = g_strdup_printf(_("Unable to connect to %s server"), |
| |
90 name); |
| |
91 break; |
| |
92 case MSN_ERROR_WRITE: |
| |
93 tmp = g_strdup_printf(_("Error writing to %s server"), name); |
| |
94 break; |
| |
95 case MSN_ERROR_READ: |
| |
96 cmd = httpconn->servconn->cmdproc->last_trans; |
| |
97 tmp = g_strdup_printf(_("Error reading from %s server"), name); |
| |
98 gaim_debug_info("msn", "Last command was: %s\n", cmd); |
| |
99 break; |
| |
100 default: |
| |
101 tmp = g_strdup_printf(_("Unknown error from %s server"), name); |
| |
102 break; |
| |
103 } |
| |
104 |
| |
105 if (httpconn->servconn->type == MSN_SERVER_NS) |
| |
106 { |
| |
107 gaim_connection_error(gc, tmp); |
| |
108 } |
| |
109 else |
| |
110 { |
| |
111 MsnSwitchBoard *swboard; |
| |
112 swboard = httpconn->servconn->cmdproc->data; |
| |
113 swboard->error = MSN_SB_ERROR_CONNECTION; |
| |
114 } |
| |
115 |
| |
116 g_free(tmp); |
| |
117 } |
| |
118 |
| |
119 static ssize_t |
| |
120 write_raw(MsnHttpConn *httpconn, const void *buffer, size_t len) |
| |
121 { |
| |
122 ssize_t s; |
| |
123 ssize_t res; /* result of the write operation */ |
| |
124 |
| |
125 #ifdef MSN_DEBUG_HTTP |
| |
126 gaim_debug_misc("msn", "Writing HTTP: {%s}\n", buffer); |
| |
127 #endif |
| |
128 |
| |
129 s = 0; |
| |
130 |
| |
131 do |
| |
132 { |
| |
133 res = write(httpconn->fd, buffer, len); |
| |
134 if (res >= 0) |
| |
135 { |
| |
136 s += res; |
| |
137 } |
| |
138 else if (errno != EAGAIN) |
| |
139 { |
| |
140 httpconn->servconn->cmdproc->error = MSN_ERROR_WRITE; |
| |
141 show_error(httpconn); |
| |
142 return -1; |
| |
143 } |
| |
144 } while (s < len); |
| |
145 |
| |
146 return s; |
| |
147 } |
| |
148 |
| |
149 void |
| |
150 msn_httpconn_poll(MsnHttpConn *httpconn) |
| |
151 { |
| |
152 int r; |
| |
153 char *temp; |
| |
154 |
| |
155 g_return_if_fail(httpconn != NULL); |
| |
156 |
| |
157 if (httpconn->waiting_response || |
| |
158 httpconn->queue != NULL) |
| |
159 { |
| |
160 return; |
| |
161 } |
| |
162 |
| |
163 temp = g_strdup_printf( |
| |
164 "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n" |
| |
165 "Accept: */*\r\n" |
| |
166 "Accept-Language: en-us\r\n" |
| |
167 "User-Agent: MSMSGS\r\n" |
| |
168 "Host: %s\r\n" |
| |
169 "Proxy-Connection: Keep-Alive\r\n" |
| |
170 "Connection: Keep-Alive\r\n" |
| |
171 "Pragma: no-cache\r\n" |
| |
172 "Content-Type: application/x-msn-messenger\r\n" |
| |
173 "Content-Length: 0\r\n" |
| |
174 "\r\n", |
| |
175 httpconn->host, |
| |
176 httpconn->full_session_id, |
| |
177 httpconn->host); |
| |
178 |
| |
179 r = write_raw(httpconn, temp, strlen(temp)); |
| |
180 |
| |
181 g_free(temp); |
| |
182 |
| |
183 if (r > 0) |
| |
184 { |
| |
185 httpconn->waiting_response = TRUE; |
| |
186 httpconn->dirty = FALSE; |
| |
187 } |
| |
188 } |
| |
189 |
| |
190 static gboolean |
| |
191 poll(gpointer data) |
| |
192 { |
| |
193 MsnHttpConn *httpconn; |
| |
194 |
| |
195 httpconn = data; |
| |
196 |
| |
197 #if 0 |
| |
198 gaim_debug_info("msn", "polling from %s\n", httpconn->session_id); |
| |
199 #endif |
| |
200 |
| |
201 if (httpconn->dirty) |
| |
202 msn_httpconn_poll(httpconn); |
| |
203 |
| |
204 return TRUE; |
| |
205 } |
| |
206 |
| |
207 static void |
| |
208 connect_cb(gpointer data, gint source, GaimInputCondition cond) |
| |
209 { |
| |
210 MsnHttpConn *httpconn = data; |
| |
211 |
| |
212 httpconn->fd = source; |
| |
213 |
| |
214 if (source > 0) |
| |
215 { |
| |
216 httpconn->inpa = gaim_input_add(httpconn->fd, GAIM_INPUT_READ, |
| |
217 read_cb, data); |
| |
218 |
| |
219 httpconn->timer = gaim_timeout_add(2000, poll, httpconn); |
| |
220 |
| |
221 httpconn->waiting_response = FALSE; |
| |
222 msn_httpconn_process_queue(httpconn); |
| |
223 } |
| |
224 else |
| |
225 { |
| |
226 gaim_debug_error("msn", "HTTP: Connection error\n"); |
| |
227 show_error(httpconn); |
| |
228 } |
| |
229 } |
| |
230 |
| |
231 gboolean |
| |
232 msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port) |
| |
233 { |
| |
234 int r; |
| |
235 |
| |
236 g_return_val_if_fail(httpconn != NULL, FALSE); |
| |
237 g_return_val_if_fail(host != NULL, FALSE); |
| |
238 g_return_val_if_fail(port > 0, FALSE); |
| |
239 |
| |
240 if (httpconn->connected) |
| |
241 msn_httpconn_disconnect(httpconn); |
| |
242 |
| |
243 r = gaim_proxy_connect(httpconn->session->account, |
| |
244 "gateway.messenger.hotmail.com", 80, connect_cb, |
| |
245 httpconn); |
| |
246 |
| |
247 if (r == 0) |
| |
248 { |
| |
249 httpconn->waiting_response = TRUE; |
| |
250 httpconn->connected = TRUE; |
| |
251 } |
| |
252 |
| |
253 return httpconn->connected; |
| |
254 } |
| |
255 |
| |
256 void |
| |
257 msn_httpconn_disconnect(MsnHttpConn *httpconn) |
| |
258 { |
| |
259 g_return_if_fail(httpconn != NULL); |
| |
260 g_return_if_fail(httpconn->connected); |
| |
261 |
| |
262 if (httpconn->timer) |
| |
263 gaim_timeout_remove(httpconn->timer); |
| |
264 |
| |
265 httpconn->timer = 0; |
| |
266 |
| |
267 if (httpconn->inpa > 0) |
| |
268 { |
| |
269 gaim_input_remove(httpconn->inpa); |
| |
270 httpconn->inpa = 0; |
| |
271 } |
| |
272 |
| |
273 close(httpconn->fd); |
| |
274 |
| |
275 httpconn->rx_buf = NULL; |
| |
276 httpconn->rx_len = 0; |
| |
277 |
| |
278 httpconn->connected = FALSE; |
| |
279 |
| |
280 /* msn_servconn_disconnect(httpconn->servconn); */ |
| |
281 } |
| |
282 |
| |
283 static void |
| |
284 read_cb(gpointer data, gint source, GaimInputCondition cond) |
| |
285 { |
| |
286 MsnHttpConn *httpconn; |
| |
287 MsnServConn *servconn; |
| |
288 MsnSession *session; |
| |
289 char buf[MSN_BUF_LEN]; |
| |
290 char *cur, *end, *old_rx_buf; |
| |
291 int len, cur_len; |
| |
292 char *result_msg = NULL; |
| |
293 size_t result_len = 0; |
| |
294 gboolean error; |
| |
295 |
| |
296 httpconn = data; |
| |
297 servconn = NULL; |
| |
298 session = httpconn->session; |
| |
299 |
| |
300 len = read(httpconn->fd, buf, sizeof(buf) - 1); |
| |
301 |
| |
302 if (len <= 0) |
| |
303 { |
| |
304 gaim_debug_error("msn", "HTTP: Read error\n"); |
| |
305 show_error(httpconn); |
| |
306 msn_httpconn_disconnect(httpconn); |
| |
307 |
| |
308 return; |
| |
309 } |
| |
310 |
| |
311 buf[len] = '\0'; |
| |
312 |
| |
313 httpconn->rx_buf = g_realloc(httpconn->rx_buf, len + httpconn->rx_len + 1); |
| |
314 memcpy(httpconn->rx_buf + httpconn->rx_len, buf, len + 1); |
| |
315 httpconn->rx_len += len; |
| |
316 |
| |
317 if (!msn_httpconn_parse_data(httpconn, httpconn->rx_buf, httpconn->rx_len, |
| |
318 &result_msg, &result_len, &error)) |
| |
319 { |
| |
320 /* We must wait for more input */ |
| |
321 |
| |
322 return; |
| |
323 } |
| |
324 |
| |
325 httpconn->servconn->processing = FALSE; |
| |
326 |
| |
327 servconn = httpconn->servconn; |
| |
328 |
| |
329 if (error) |
| |
330 { |
| |
331 gaim_debug_error("msn", "HTTP: Special error\n"); |
| |
332 show_error(httpconn); |
| |
333 msn_httpconn_disconnect(httpconn); |
| |
334 |
| |
335 return; |
| |
336 } |
| |
337 |
| |
338 if (result_len == 0) |
| |
339 { |
| |
340 /* Nothing to do here */ |
| |
341 #if 0 |
| |
342 gaim_debug_info("msn", "HTTP: nothing to do here\n"); |
| |
343 #endif |
| |
344 g_free(httpconn->rx_buf); |
| |
345 httpconn->rx_buf = NULL; |
| |
346 httpconn->rx_len = 0; |
| |
347 return; |
| |
348 } |
| |
349 |
| |
350 g_free(httpconn->rx_buf); |
| |
351 httpconn->rx_buf = NULL; |
| |
352 httpconn->rx_len = 0; |
| |
353 |
| |
354 servconn->rx_buf = result_msg; |
| |
355 servconn->rx_len = result_len; |
| |
356 |
| |
357 end = old_rx_buf = servconn->rx_buf; |
| |
358 |
| |
359 servconn->processing = TRUE; |
| |
360 |
| |
361 do |
| |
362 { |
| |
363 cur = end; |
| |
364 |
| |
365 if (servconn->payload_len) |
| |
366 { |
| |
367 if (servconn->payload_len > servconn->rx_len) |
| |
368 /* The payload is still not complete. */ |
| |
369 break; |
| |
370 |
| |
371 cur_len = servconn->payload_len; |
| |
372 end += cur_len; |
| |
373 } |
| |
374 else |
| |
375 { |
| |
376 end = strstr(cur, "\r\n"); |
| |
377 |
| |
378 if (end == NULL) |
| |
379 /* The command is still not complete. */ |
| |
380 break; |
| |
381 |
| |
382 *end = '\0'; |
| |
383 end += 2; |
| |
384 cur_len = end - cur; |
| |
385 } |
| |
386 |
| |
387 servconn->rx_len -= cur_len; |
| |
388 |
| |
389 if (servconn->payload_len) |
| |
390 { |
| |
391 msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len); |
| |
392 servconn->payload_len = 0; |
| |
393 } |
| |
394 else |
| |
395 { |
| |
396 msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); |
| |
397 } |
| |
398 } while (servconn->connected && servconn->rx_len > 0); |
| |
399 |
| |
400 if (servconn->connected) |
| |
401 { |
| |
402 if (servconn->rx_len > 0) |
| |
403 servconn->rx_buf = g_memdup(cur, servconn->rx_len); |
| |
404 else |
| |
405 servconn->rx_buf = NULL; |
| |
406 } |
| |
407 |
| |
408 servconn->processing = FALSE; |
| |
409 |
| |
410 if (servconn->wasted) |
| |
411 msn_servconn_destroy(servconn); |
| |
412 |
| |
413 g_free(old_rx_buf); |
| |
414 } |
| |
415 |
| |
416 void |
| |
417 msn_httpconn_process_queue(MsnHttpConn *httpconn) |
| |
418 { |
| |
419 if (httpconn->queue != NULL) |
| |
420 { |
| |
421 MsnHttpQueueData *queue_data; |
| |
422 |
| |
423 queue_data = (MsnHttpQueueData *)httpconn->queue->data; |
| |
424 |
| |
425 httpconn->queue = g_list_remove(httpconn->queue, queue_data); |
| |
426 |
| |
427 msn_httpconn_write(queue_data->httpconn, |
| |
428 queue_data->buffer, |
| |
429 queue_data->size); |
| |
430 |
| |
431 g_free(queue_data->buffer); |
| |
432 g_free(queue_data); |
| |
433 } |
| |
434 else |
| |
435 { |
| |
436 httpconn->dirty = TRUE; |
| |
437 } |
| |
438 } |
| |
439 |
| |
440 size_t |
| |
441 msn_httpconn_write(MsnHttpConn *httpconn, const char *buf, size_t size) |
| |
442 { |
| |
443 char *params; |
| |
444 char *temp; |
| |
445 gboolean first; |
| |
446 const char *server_types[] = { "NS", "SB" }; |
| |
447 const char *server_type; |
| |
448 size_t r; /* result of the write operation */ |
| |
449 size_t len; |
| |
450 char *host; |
| |
451 MsnServConn *servconn; |
| |
452 |
| |
453 /* TODO: remove http data from servconn */ |
| |
454 |
| |
455 g_return_val_if_fail(httpconn != NULL, 0); |
| |
456 g_return_val_if_fail(buf != NULL, 0); |
| |
457 g_return_val_if_fail(size > 0, 0); |
| |
458 |
| |
459 servconn = httpconn->servconn; |
| |
460 |
| |
461 if (httpconn->waiting_response) |
| |
462 { |
| |
463 MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1); |
| |
464 |
| |
465 queue_data->httpconn = httpconn; |
| |
466 queue_data->buffer = g_memdup(buf, size); |
| |
467 queue_data->size = size; |
| |
468 |
| |
469 httpconn->queue = g_list_append(httpconn->queue, queue_data); |
| |
470 /* httpconn->dirty = TRUE; */ |
| |
471 |
| |
472 /* servconn->processing = TRUE; */ |
| |
473 |
| |
474 return size; |
| |
475 } |
| |
476 |
| |
477 first = httpconn->virgin; |
| |
478 server_type = server_types[servconn->type]; |
| |
479 |
| |
480 if (first) |
| |
481 { |
| |
482 host = "gateway.messenger.hotmail.com"; |
| |
483 |
| |
484 /* The first time servconn->host is the host we should connect to. */ |
| |
485 params = g_strdup_printf("Action=open&Server=%s&IP=%s", |
| |
486 server_type, |
| |
487 servconn->host); |
| |
488 } |
| |
489 else |
| |
490 { |
| |
491 /* The rest of the times servconn->host is the gateway host. */ |
| |
492 host = httpconn->host; |
| |
493 |
| |
494 params = g_strdup_printf("SessionID=%s", |
| |
495 httpconn->full_session_id); |
| |
496 } |
| |
497 |
| |
498 temp = g_strdup_printf( |
| |
499 "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" |
| |
500 "Accept: */*\r\n" |
| |
501 "Accept-Language: en-us\r\n" |
| |
502 "User-Agent: MSMSGS\r\n" |
| |
503 "Host: %s\r\n" |
| |
504 "Proxy-Connection: Keep-Alive\r\n" |
| |
505 "Connection: Keep-Alive\r\n" |
| |
506 "Pragma: no-cache\r\n" |
| |
507 "Content-Type: application/x-msn-messenger\r\n" |
| |
508 "Content-Length: %d\r\n" |
| |
509 "\r\n", |
| |
510 host, |
| |
511 params, |
| |
512 host, |
| |
513 (int)size); |
| |
514 |
| |
515 g_free(params); |
| |
516 |
| |
517 len = strlen(temp); |
| |
518 temp = g_realloc(temp, len + size + 1); |
| |
519 memcpy(temp + len, buf, size); |
| |
520 len += size; |
| |
521 temp[len] = '\0'; |
| |
522 |
| |
523 r = write_raw(httpconn, temp, len); |
| |
524 |
| |
525 g_free(temp); |
| |
526 |
| |
527 if (r > 0) |
| |
528 { |
| |
529 httpconn->virgin = FALSE; |
| |
530 httpconn->waiting_response = TRUE; |
| |
531 httpconn->dirty = FALSE; |
| |
532 } |
| |
533 |
| |
534 return r; |
| |
535 } |
| |
536 |
| |
537 gboolean |
| |
538 msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, |
| |
539 size_t size, char **ret_buf, size_t *ret_size, |
| |
540 gboolean *error) |
| |
541 { |
| |
542 GaimConnection *gc; |
| |
543 const char *s, *c; |
| |
544 char *headers, *body; |
| |
545 const char *body_start; |
| |
546 char *tmp; |
| |
547 size_t body_len = 0; |
| |
548 gboolean wasted = FALSE; |
| |
549 |
| |
550 g_return_val_if_fail(httpconn != NULL, FALSE); |
| |
551 g_return_val_if_fail(buf != NULL, FALSE); |
| |
552 g_return_val_if_fail(size > 0, FALSE); |
| |
553 g_return_val_if_fail(ret_buf != NULL, FALSE); |
| |
554 g_return_val_if_fail(ret_size != NULL, FALSE); |
| |
555 g_return_val_if_fail(error != NULL, FALSE); |
| |
556 |
| |
557 #if 0 |
| |
558 gaim_debug_info("msn", "HTTP: parsing data {%s}\n", buf); |
| |
559 #endif |
| |
560 |
| |
561 httpconn->waiting_response = FALSE; |
| |
562 |
| |
563 gc = gaim_account_get_connection(httpconn->session->account); |
| |
564 |
| |
565 /* Healthy defaults. */ |
| |
566 body = NULL; |
| |
567 |
| |
568 *ret_buf = NULL; |
| |
569 *ret_size = 0; |
| |
570 *error = FALSE; |
| |
571 |
| |
572 /* First, some tests to see if we have a full block of stuff. */ |
| |
573 if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) && |
| |
574 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) && |
| |
575 ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && |
| |
576 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0))) |
| |
577 { |
| |
578 *error = TRUE; |
| |
579 |
| |
580 return FALSE; |
| |
581 } |
| |
582 |
| |
583 if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0) |
| |
584 { |
| |
585 if ((s = strstr(buf, "\r\n\r\n")) == NULL) |
| |
586 return FALSE; |
| |
587 |
| |
588 s += 4; |
| |
589 |
| |
590 if (*s == '\0') |
| |
591 { |
| |
592 *ret_buf = g_strdup(""); |
| |
593 *ret_size = 0; |
| |
594 |
| |
595 msn_httpconn_process_queue(httpconn); |
| |
596 |
| |
597 return TRUE; |
| |
598 } |
| |
599 |
| |
600 buf = s; |
| |
601 size -= (s - buf); |
| |
602 } |
| |
603 |
| |
604 if ((s = strstr(buf, "\r\n\r\n")) == NULL) |
| |
605 return FALSE; |
| |
606 |
| |
607 headers = g_strndup(buf, s - buf); |
| |
608 s += 4; /* Skip \r\n */ |
| |
609 body_start = s; |
| |
610 body_len = size - (body_start - buf); |
| |
611 |
| |
612 if ((s = strstr(headers, "Content-Length: ")) != NULL) |
| |
613 { |
| |
614 int tmp_len; |
| |
615 |
| |
616 s += strlen("Content-Length: "); |
| |
617 |
| |
618 if ((c = strchr(s, '\r')) == NULL) |
| |
619 { |
| |
620 g_free(headers); |
| |
621 |
| |
622 return FALSE; |
| |
623 } |
| |
624 |
| |
625 tmp = g_strndup(s, c - s); |
| |
626 tmp_len = atoi(tmp); |
| |
627 g_free(tmp); |
| |
628 |
| |
629 if (body_len != tmp_len) |
| |
630 { |
| |
631 g_free(headers); |
| |
632 |
| |
633 #if 0 |
| |
634 gaim_debug_warning("msn", |
| |
635 "body length (%d) != content length (%d)\n", |
| |
636 body_len, tmp_len); |
| |
637 #endif |
| |
638 |
| |
639 return FALSE; |
| |
640 } |
| |
641 } |
| |
642 |
| |
643 body = g_memdup(body_start, body_len); |
| |
644 |
| |
645 #ifdef MSN_DEBUG_HTTP |
| |
646 gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n\r\n%s}\n", headers, body); |
| |
647 #endif |
| |
648 |
| |
649 /* Now we should be able to process the data. */ |
| |
650 if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL) |
| |
651 { |
| |
652 char *full_session_id, *gw_ip, *session_action; |
| |
653 char *t, *session_id; |
| |
654 char **elems, **cur, **tokens; |
| |
655 |
| |
656 full_session_id = gw_ip = session_action = NULL; |
| |
657 |
| |
658 s += strlen("X-MSN-Messenger: "); |
| |
659 |
| |
660 if ((c = strchr(s, '\r')) == NULL) |
| |
661 { |
| |
662 gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); |
| |
663 gaim_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}", |
| |
664 buf); |
| |
665 |
| |
666 return FALSE; |
| |
667 } |
| |
668 |
| |
669 tmp = g_strndup(s, c - s); |
| |
670 |
| |
671 elems = g_strsplit(tmp, "; ", 0); |
| |
672 |
| |
673 for (cur = elems; *cur != NULL; cur++) |
| |
674 { |
| |
675 tokens = g_strsplit(*cur, "=", 2); |
| |
676 |
| |
677 if (strcmp(tokens[0], "SessionID") == 0) |
| |
678 full_session_id = tokens[1]; |
| |
679 else if (strcmp(tokens[0], "GW-IP") == 0) |
| |
680 gw_ip = tokens[1]; |
| |
681 else if (strcmp(tokens[0], "Session") == 0) |
| |
682 session_action = tokens[1]; |
| |
683 |
| |
684 g_free(tokens[0]); |
| |
685 /* Don't free each of the tokens, only the array. */ |
| |
686 g_free(tokens); |
| |
687 } |
| |
688 |
| |
689 g_strfreev(elems); |
| |
690 |
| |
691 g_free(tmp); |
| |
692 |
| |
693 if ((session_action != NULL) && (strcmp(session_action, "close") == 0)) |
| |
694 wasted = TRUE; |
| |
695 |
| |
696 g_free(session_action); |
| |
697 |
| |
698 t = strchr(full_session_id, '.'); |
| |
699 session_id = g_strndup(full_session_id, t - full_session_id); |
| |
700 |
| |
701 if (!wasted) |
| |
702 { |
| |
703 if (httpconn->full_session_id != NULL); |
| |
704 g_free(httpconn->full_session_id); |
| |
705 |
| |
706 httpconn->full_session_id = full_session_id; |
| |
707 |
| |
708 if (httpconn->session_id != NULL); |
| |
709 g_free(httpconn->session_id); |
| |
710 |
| |
711 httpconn->session_id = session_id; |
| |
712 |
| |
713 if (httpconn->host != NULL); |
| |
714 g_free(httpconn->host); |
| |
715 |
| |
716 httpconn->host = gw_ip; |
| |
717 } |
| |
718 else |
| |
719 { |
| |
720 MsnServConn *servconn; |
| |
721 |
| |
722 /* It's going to die. */ |
| |
723 |
| |
724 servconn = httpconn->servconn; |
| |
725 |
| |
726 if (servconn != NULL) |
| |
727 servconn->wasted = TRUE; |
| |
728 |
| |
729 g_free(full_session_id); |
| |
730 g_free(gw_ip); |
| |
731 } |
| |
732 } |
| |
733 |
| |
734 g_free(headers); |
| |
735 |
| |
736 *ret_buf = body; |
| |
737 *ret_size = body_len; |
| |
738 |
| |
739 msn_httpconn_process_queue(httpconn); |
| |
740 |
| |
741 return TRUE; |
| |
742 } |