| |
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 *body; |
| |
32 size_t body_len; |
| |
33 } MsnHttpQueueData; |
| |
34 |
| |
35 static void |
| |
36 msn_httpconn_process_queue(MsnHttpConn *httpconn) |
| |
37 { |
| |
38 httpconn->waiting_response = FALSE; |
| |
39 |
| |
40 if (httpconn->queue != NULL) |
| |
41 { |
| |
42 MsnHttpQueueData *queue_data; |
| |
43 |
| |
44 queue_data = (MsnHttpQueueData *)httpconn->queue->data; |
| |
45 |
| |
46 httpconn->queue = g_list_remove(httpconn->queue, queue_data); |
| |
47 |
| |
48 msn_httpconn_write(queue_data->httpconn, |
| |
49 queue_data->body, |
| |
50 queue_data->body_len); |
| |
51 |
| |
52 g_free(queue_data->body); |
| |
53 g_free(queue_data); |
| |
54 } |
| |
55 } |
| |
56 |
| |
57 static gboolean |
| |
58 msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, |
| |
59 size_t size, char **ret_buf, size_t *ret_size, |
| |
60 gboolean *error) |
| |
61 { |
| |
62 const char *s, *c; |
| |
63 char *header, *body; |
| |
64 const char *body_start; |
| |
65 char *tmp; |
| |
66 size_t body_len = 0; |
| |
67 gboolean wasted = FALSE; |
| |
68 |
| |
69 g_return_val_if_fail(httpconn != NULL, FALSE); |
| |
70 g_return_val_if_fail(buf != NULL, FALSE); |
| |
71 g_return_val_if_fail(size > 0, FALSE); |
| |
72 g_return_val_if_fail(ret_buf != NULL, FALSE); |
| |
73 g_return_val_if_fail(ret_size != NULL, FALSE); |
| |
74 g_return_val_if_fail(error != NULL, FALSE); |
| |
75 |
| |
76 #if 0 |
| |
77 gaim_debug_info("msn", "HTTP: parsing data {%s}\n", buf); |
| |
78 #endif |
| |
79 |
| |
80 /* Healthy defaults. */ |
| |
81 body = NULL; |
| |
82 |
| |
83 *ret_buf = NULL; |
| |
84 *ret_size = 0; |
| |
85 *error = FALSE; |
| |
86 |
| |
87 /* First, some tests to see if we have a full block of stuff. */ |
| |
88 if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) && |
| |
89 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) && |
| |
90 ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && |
| |
91 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0))) |
| |
92 { |
| |
93 *error = TRUE; |
| |
94 |
| |
95 return FALSE; |
| |
96 } |
| |
97 |
| |
98 if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0) |
| |
99 { |
| |
100 if ((s = strstr(buf, "\r\n\r\n")) == NULL) |
| |
101 return FALSE; |
| |
102 |
| |
103 s += 4; |
| |
104 |
| |
105 if (*s == '\0') |
| |
106 { |
| |
107 *ret_buf = g_strdup(""); |
| |
108 *ret_size = 0; |
| |
109 |
| |
110 msn_httpconn_process_queue(httpconn); |
| |
111 |
| |
112 return TRUE; |
| |
113 } |
| |
114 |
| |
115 buf = s; |
| |
116 size -= (s - buf); |
| |
117 } |
| |
118 |
| |
119 if ((s = strstr(buf, "\r\n\r\n")) == NULL) |
| |
120 /* Need to wait for the full HTTP header to arrive */ |
| |
121 return FALSE; |
| |
122 |
| |
123 s += 4; /* Skip \r\n */ |
| |
124 header = g_strndup(buf, s - buf); |
| |
125 body_start = s; |
| |
126 body_len = size - (body_start - buf); |
| |
127 |
| |
128 if ((s = gaim_strcasestr(header, "Content-Length: ")) != NULL) |
| |
129 { |
| |
130 int tmp_len; |
| |
131 |
| |
132 s += strlen("Content-Length: "); |
| |
133 |
| |
134 if ((c = strchr(s, '\r')) == NULL) |
| |
135 { |
| |
136 g_free(header); |
| |
137 |
| |
138 return FALSE; |
| |
139 } |
| |
140 |
| |
141 tmp = g_strndup(s, c - s); |
| |
142 tmp_len = atoi(tmp); |
| |
143 g_free(tmp); |
| |
144 |
| |
145 if (body_len != tmp_len) |
| |
146 { |
| |
147 /* Need to wait for the full packet to arrive */ |
| |
148 |
| |
149 g_free(header); |
| |
150 |
| |
151 #if 0 |
| |
152 gaim_debug_warning("msn", |
| |
153 "body length (%d) != content length (%d)\n", |
| |
154 body_len, tmp_len); |
| |
155 #endif |
| |
156 |
| |
157 return FALSE; |
| |
158 } |
| |
159 } |
| |
160 |
| |
161 body = g_malloc0(body_len + 1); |
| |
162 memcpy(body, body_start, body_len); |
| |
163 |
| |
164 #ifdef MSN_DEBUG_HTTP |
| |
165 gaim_debug_misc("msn", "Incoming HTTP buffer (header): {%s\r\n}\n", |
| |
166 header); |
| |
167 #endif |
| |
168 |
| |
169 /* Now we should be able to process the data. */ |
| |
170 if ((s = gaim_strcasestr(header, "X-MSN-Messenger: ")) != NULL) |
| |
171 { |
| |
172 char *full_session_id, *gw_ip, *session_action; |
| |
173 char *t, *session_id; |
| |
174 char **elems, **cur, **tokens; |
| |
175 |
| |
176 full_session_id = gw_ip = session_action = NULL; |
| |
177 |
| |
178 s += strlen("X-MSN-Messenger: "); |
| |
179 |
| |
180 if ((c = strchr(s, '\r')) == NULL) |
| |
181 { |
| |
182 msn_session_set_error(httpconn->session, |
| |
183 MSN_ERROR_HTTP_MALFORMED, NULL); |
| |
184 gaim_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}", |
| |
185 buf); |
| |
186 |
| |
187 g_free(body); |
| |
188 return FALSE; |
| |
189 } |
| |
190 |
| |
191 tmp = g_strndup(s, c - s); |
| |
192 |
| |
193 elems = g_strsplit(tmp, "; ", 0); |
| |
194 |
| |
195 for (cur = elems; *cur != NULL; cur++) |
| |
196 { |
| |
197 tokens = g_strsplit(*cur, "=", 2); |
| |
198 |
| |
199 if (strcmp(tokens[0], "SessionID") == 0) |
| |
200 full_session_id = tokens[1]; |
| |
201 else if (strcmp(tokens[0], "GW-IP") == 0) |
| |
202 gw_ip = tokens[1]; |
| |
203 else if (strcmp(tokens[0], "Session") == 0) |
| |
204 session_action = tokens[1]; |
| |
205 else |
| |
206 g_free(tokens[1]); |
| |
207 |
| |
208 g_free(tokens[0]); |
| |
209 /* Don't free each of the tokens, only the array. */ |
| |
210 g_free(tokens); |
| |
211 } |
| |
212 |
| |
213 g_strfreev(elems); |
| |
214 |
| |
215 g_free(tmp); |
| |
216 |
| |
217 if ((session_action != NULL) && (strcmp(session_action, "close") == 0)) |
| |
218 wasted = TRUE; |
| |
219 |
| |
220 g_free(session_action); |
| |
221 |
| |
222 t = strchr(full_session_id, '.'); |
| |
223 session_id = g_strndup(full_session_id, t - full_session_id); |
| |
224 |
| |
225 if (!wasted) |
| |
226 { |
| |
227 g_free(httpconn->full_session_id); |
| |
228 httpconn->full_session_id = full_session_id; |
| |
229 |
| |
230 g_free(httpconn->session_id); |
| |
231 httpconn->session_id = session_id; |
| |
232 |
| |
233 g_free(httpconn->host); |
| |
234 httpconn->host = gw_ip; |
| |
235 } |
| |
236 else |
| |
237 { |
| |
238 MsnServConn *servconn; |
| |
239 |
| |
240 /* It's going to die. */ |
| |
241 /* poor thing */ |
| |
242 |
| |
243 servconn = httpconn->servconn; |
| |
244 |
| |
245 /* I'll be honest, I don't fully understand all this, but this |
| |
246 * causes crashes, Stu. */ |
| |
247 /* if (servconn != NULL) |
| |
248 servconn->wasted = TRUE; */ |
| |
249 |
| |
250 g_free(full_session_id); |
| |
251 g_free(session_id); |
| |
252 g_free(gw_ip); |
| |
253 } |
| |
254 } |
| |
255 |
| |
256 g_free(header); |
| |
257 |
| |
258 *ret_buf = body; |
| |
259 *ret_size = body_len; |
| |
260 |
| |
261 msn_httpconn_process_queue(httpconn); |
| |
262 |
| |
263 return TRUE; |
| |
264 } |
| |
265 |
| |
266 static void |
| |
267 read_cb(gpointer data, gint source, GaimInputCondition cond) |
| |
268 { |
| |
269 MsnHttpConn *httpconn; |
| |
270 MsnServConn *servconn; |
| |
271 MsnSession *session; |
| |
272 char buf[MSN_BUF_LEN]; |
| |
273 char *cur, *end, *old_rx_buf; |
| |
274 int len, cur_len; |
| |
275 char *result_msg = NULL; |
| |
276 size_t result_len = 0; |
| |
277 gboolean error = FALSE; |
| |
278 |
| |
279 httpconn = data; |
| |
280 servconn = NULL; |
| |
281 session = httpconn->session; |
| |
282 |
| |
283 len = read(httpconn->fd, buf, sizeof(buf) - 1); |
| |
284 |
| |
285 if (len < 0 && errno == EAGAIN) |
| |
286 return; |
| |
287 else if (len <= 0) |
| |
288 { |
| |
289 gaim_debug_error("msn", "HTTP: Read error\n"); |
| |
290 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ); |
| |
291 |
| |
292 return; |
| |
293 } |
| |
294 |
| |
295 buf[len] = '\0'; |
| |
296 |
| |
297 httpconn->rx_buf = g_realloc(httpconn->rx_buf, len + httpconn->rx_len + 1); |
| |
298 memcpy(httpconn->rx_buf + httpconn->rx_len, buf, len + 1); |
| |
299 httpconn->rx_len += len; |
| |
300 |
| |
301 if (!msn_httpconn_parse_data(httpconn, httpconn->rx_buf, httpconn->rx_len, |
| |
302 &result_msg, &result_len, &error)) |
| |
303 { |
| |
304 /* Either we must wait for more input, or something went wrong */ |
| |
305 if (error) |
| |
306 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ); |
| |
307 |
| |
308 return; |
| |
309 } |
| |
310 |
| |
311 httpconn->servconn->processing = FALSE; |
| |
312 |
| |
313 servconn = httpconn->servconn; |
| |
314 |
| |
315 if (error) |
| |
316 { |
| |
317 gaim_debug_error("msn", "HTTP: Special error\n"); |
| |
318 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ); |
| |
319 |
| |
320 return; |
| |
321 } |
| |
322 |
| |
323 g_free(httpconn->rx_buf); |
| |
324 httpconn->rx_buf = NULL; |
| |
325 httpconn->rx_len = 0; |
| |
326 |
| |
327 if (result_len == 0) |
| |
328 { |
| |
329 /* Nothing to do here */ |
| |
330 #if 0 |
| |
331 gaim_debug_info("msn", "HTTP: nothing to do here\n"); |
| |
332 #endif |
| |
333 g_free(result_msg); |
| |
334 return; |
| |
335 } |
| |
336 |
| |
337 g_free(servconn->rx_buf); |
| |
338 servconn->rx_buf = result_msg; |
| |
339 servconn->rx_len = result_len; |
| |
340 |
| |
341 end = old_rx_buf = servconn->rx_buf; |
| |
342 |
| |
343 servconn->processing = TRUE; |
| |
344 |
| |
345 do |
| |
346 { |
| |
347 cur = end; |
| |
348 |
| |
349 if (servconn->payload_len) |
| |
350 { |
| |
351 if (servconn->payload_len > servconn->rx_len) |
| |
352 /* The payload is still not complete. */ |
| |
353 break; |
| |
354 |
| |
355 cur_len = servconn->payload_len; |
| |
356 end += cur_len; |
| |
357 } |
| |
358 else |
| |
359 { |
| |
360 end = strstr(cur, "\r\n"); |
| |
361 |
| |
362 if (end == NULL) |
| |
363 /* The command is still not complete. */ |
| |
364 break; |
| |
365 |
| |
366 *end = '\0'; |
| |
367 end += 2; |
| |
368 cur_len = end - cur; |
| |
369 } |
| |
370 |
| |
371 servconn->rx_len -= cur_len; |
| |
372 |
| |
373 if (servconn->payload_len) |
| |
374 { |
| |
375 msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len); |
| |
376 servconn->payload_len = 0; |
| |
377 } |
| |
378 else |
| |
379 { |
| |
380 msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); |
| |
381 } |
| |
382 } while (servconn->connected && servconn->rx_len > 0); |
| |
383 |
| |
384 if (servconn->connected) |
| |
385 { |
| |
386 if (servconn->rx_len > 0) |
| |
387 servconn->rx_buf = g_memdup(cur, servconn->rx_len); |
| |
388 else |
| |
389 servconn->rx_buf = NULL; |
| |
390 } |
| |
391 |
| |
392 servconn->processing = FALSE; |
| |
393 |
| |
394 if (servconn->wasted) |
| |
395 msn_servconn_destroy(servconn); |
| |
396 |
| |
397 g_free(old_rx_buf); |
| |
398 } |
| |
399 |
| |
400 static void |
| |
401 httpconn_write_cb(gpointer data, gint source, GaimInputCondition cond) |
| |
402 { |
| |
403 MsnHttpConn *httpconn; |
| |
404 int ret, writelen; |
| |
405 |
| |
406 httpconn = data; |
| |
407 writelen = gaim_circ_buffer_get_max_read(httpconn->tx_buf); |
| |
408 |
| |
409 if (writelen == 0) |
| |
410 { |
| |
411 gaim_input_remove(httpconn->tx_handler); |
| |
412 httpconn->tx_handler = 0; |
| |
413 return; |
| |
414 } |
| |
415 |
| |
416 ret = write(httpconn->fd, httpconn->tx_buf->outptr, writelen); |
| |
417 if (ret <= 0) |
| |
418 { |
| |
419 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) |
| |
420 /* No worries */ |
| |
421 return; |
| |
422 |
| |
423 /* Error! */ |
| |
424 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_WRITE); |
| |
425 return; |
| |
426 } |
| |
427 |
| |
428 gaim_circ_buffer_mark_read(httpconn->tx_buf, ret); |
| |
429 |
| |
430 /* TODO: I don't think these 2 lines are needed. Remove them? */ |
| |
431 if (ret == writelen) |
| |
432 httpconn_write_cb(data, source, cond); |
| |
433 } |
| |
434 |
| |
435 static gboolean |
| |
436 write_raw(MsnHttpConn *httpconn, const char *data, size_t data_len) |
| |
437 { |
| |
438 ssize_t res; /* result of the write operation */ |
| |
439 |
| |
440 if (httpconn->tx_handler == 0) |
| |
441 res = write(httpconn->fd, data, data_len); |
| |
442 else |
| |
443 { |
| |
444 res = -1; |
| |
445 errno = EAGAIN; |
| |
446 } |
| |
447 |
| |
448 if ((res <= 0) && ((errno != EAGAIN) && (errno != EWOULDBLOCK))) |
| |
449 { |
| |
450 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_WRITE); |
| |
451 return FALSE; |
| |
452 } |
| |
453 |
| |
454 if (res < 0 || res < data_len) |
| |
455 { |
| |
456 if (res < 0) |
| |
457 res = 0; |
| |
458 if (httpconn->tx_handler == 0 && httpconn->fd) |
| |
459 httpconn->tx_handler = gaim_input_add(httpconn->fd, |
| |
460 GAIM_INPUT_WRITE, httpconn_write_cb, httpconn); |
| |
461 gaim_circ_buffer_append(httpconn->tx_buf, data + res, |
| |
462 data_len - res); |
| |
463 } |
| |
464 |
| |
465 return TRUE; |
| |
466 } |
| |
467 |
| |
468 static char * |
| |
469 msn_httpconn_proxy_auth(MsnHttpConn *httpconn) |
| |
470 { |
| |
471 GaimAccount *account; |
| |
472 GaimProxyInfo *gpi; |
| |
473 const char *username, *password; |
| |
474 char *auth = NULL; |
| |
475 |
| |
476 account = httpconn->session->account; |
| |
477 |
| |
478 if (gaim_account_get_proxy_info(account) == NULL) |
| |
479 gpi = gaim_global_proxy_get_info(); |
| |
480 else |
| |
481 gpi = gaim_account_get_proxy_info(account); |
| |
482 |
| |
483 if (gpi == NULL || !(gaim_proxy_info_get_type(gpi) == GAIM_PROXY_HTTP || |
| |
484 gaim_proxy_info_get_type(gpi) == GAIM_PROXY_USE_ENVVAR)) |
| |
485 return NULL; |
| |
486 |
| |
487 username = gaim_proxy_info_get_username(gpi); |
| |
488 password = gaim_proxy_info_get_password(gpi); |
| |
489 |
| |
490 if (username != NULL) { |
| |
491 char *tmp; |
| |
492 auth = g_strdup_printf("%s:%s", username, password ? password : ""); |
| |
493 tmp = gaim_base64_encode((const guchar *)auth, strlen(auth)); |
| |
494 g_free(auth); |
| |
495 auth = g_strdup_printf("Proxy-Authorization: Basic %s\r\n", tmp); |
| |
496 g_free(tmp); |
| |
497 } |
| |
498 |
| |
499 return auth; |
| |
500 } |
| |
501 |
| |
502 static gboolean |
| |
503 msn_httpconn_poll(gpointer data) |
| |
504 { |
| |
505 MsnHttpConn *httpconn; |
| |
506 char *header; |
| |
507 char *auth; |
| |
508 |
| |
509 httpconn = data; |
| |
510 |
| |
511 g_return_val_if_fail(httpconn != NULL, FALSE); |
| |
512 |
| |
513 if ((httpconn->host == NULL) || (httpconn->full_session_id == NULL)) |
| |
514 { |
| |
515 /* There's no need to poll if the session is not fully established */ |
| |
516 return TRUE; |
| |
517 } |
| |
518 |
| |
519 if (httpconn->waiting_response) |
| |
520 { |
| |
521 /* There's no need to poll if we're already waiting for a response */ |
| |
522 return TRUE; |
| |
523 } |
| |
524 |
| |
525 auth = msn_httpconn_proxy_auth(httpconn); |
| |
526 |
| |
527 header = g_strdup_printf( |
| |
528 "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n" |
| |
529 "Accept: */*\r\n" |
| |
530 "Accept-Language: en-us\r\n" |
| |
531 "User-Agent: MSMSGS\r\n" |
| |
532 "Host: %s\r\n" |
| |
533 "Proxy-Connection: Keep-Alive\r\n" |
| |
534 "%s" /* Proxy auth */ |
| |
535 "Connection: Keep-Alive\r\n" |
| |
536 "Pragma: no-cache\r\n" |
| |
537 "Content-Type: application/x-msn-messenger\r\n" |
| |
538 "Content-Length: 0\r\n\r\n", |
| |
539 httpconn->host, |
| |
540 httpconn->full_session_id, |
| |
541 httpconn->host, |
| |
542 auth ? auth : ""); |
| |
543 |
| |
544 g_free(auth); |
| |
545 |
| |
546 if (write_raw(httpconn, header, strlen(header))) |
| |
547 httpconn->waiting_response = TRUE; |
| |
548 |
| |
549 g_free(header); |
| |
550 |
| |
551 return TRUE; |
| |
552 } |
| |
553 |
| |
554 ssize_t |
| |
555 msn_httpconn_write(MsnHttpConn *httpconn, const char *body, size_t body_len) |
| |
556 { |
| |
557 char *params; |
| |
558 char *data; |
| |
559 int header_len; |
| |
560 char *auth; |
| |
561 const char *server_types[] = { "NS", "SB" }; |
| |
562 const char *server_type; |
| |
563 char *host; |
| |
564 MsnServConn *servconn; |
| |
565 |
| |
566 /* TODO: remove http data from servconn */ |
| |
567 |
| |
568 g_return_val_if_fail(httpconn != NULL, 0); |
| |
569 g_return_val_if_fail(body != NULL, 0); |
| |
570 g_return_val_if_fail(body_len > 0, 0); |
| |
571 |
| |
572 servconn = httpconn->servconn; |
| |
573 |
| |
574 if (httpconn->waiting_response) |
| |
575 { |
| |
576 MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1); |
| |
577 |
| |
578 queue_data->httpconn = httpconn; |
| |
579 queue_data->body = g_memdup(body, body_len); |
| |
580 queue_data->body_len = body_len; |
| |
581 |
| |
582 httpconn->queue = g_list_append(httpconn->queue, queue_data); |
| |
583 |
| |
584 return body_len; |
| |
585 } |
| |
586 |
| |
587 server_type = server_types[servconn->type]; |
| |
588 |
| |
589 if (httpconn->virgin) |
| |
590 { |
| |
591 host = "gateway.messenger.hotmail.com"; |
| |
592 |
| |
593 /* The first time servconn->host is the host we should connect to. */ |
| |
594 params = g_strdup_printf("Action=open&Server=%s&IP=%s", |
| |
595 server_type, |
| |
596 servconn->host); |
| |
597 httpconn->virgin = FALSE; |
| |
598 } |
| |
599 else |
| |
600 { |
| |
601 /* The rest of the times servconn->host is the gateway host. */ |
| |
602 host = httpconn->host; |
| |
603 |
| |
604 if (host == NULL || httpconn->full_session_id == NULL) |
| |
605 { |
| |
606 gaim_debug_warning("msn", "Attempted HTTP write before session is established\n"); |
| |
607 return -1; |
| |
608 } |
| |
609 |
| |
610 params = g_strdup_printf("SessionID=%s", |
| |
611 httpconn->full_session_id); |
| |
612 } |
| |
613 |
| |
614 auth = msn_httpconn_proxy_auth(httpconn); |
| |
615 |
| |
616 data = g_strdup_printf( |
| |
617 "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" |
| |
618 "Accept: */*\r\n" |
| |
619 "Accept-Language: en-us\r\n" |
| |
620 "User-Agent: MSMSGS\r\n" |
| |
621 "Host: %s\r\n" |
| |
622 "Proxy-Connection: Keep-Alive\r\n" |
| |
623 "%s" /* Proxy auth */ |
| |
624 "Connection: Keep-Alive\r\n" |
| |
625 "Pragma: no-cache\r\n" |
| |
626 "Content-Type: application/x-msn-messenger\r\n" |
| |
627 "Content-Length: %d\r\n\r\n", |
| |
628 host, |
| |
629 params, |
| |
630 host, |
| |
631 auth ? auth : "", |
| |
632 (int) body_len); |
| |
633 |
| |
634 g_free(params); |
| |
635 |
| |
636 g_free(auth); |
| |
637 |
| |
638 header_len = strlen(data); |
| |
639 data = g_realloc(data, header_len + body_len); |
| |
640 memcpy(data + header_len, body, body_len); |
| |
641 |
| |
642 if (write_raw(httpconn, data, header_len + body_len)) |
| |
643 httpconn->waiting_response = TRUE; |
| |
644 |
| |
645 g_free(data); |
| |
646 |
| |
647 return body_len; |
| |
648 } |
| |
649 |
| |
650 MsnHttpConn * |
| |
651 msn_httpconn_new(MsnServConn *servconn) |
| |
652 { |
| |
653 MsnHttpConn *httpconn; |
| |
654 |
| |
655 g_return_val_if_fail(servconn != NULL, NULL); |
| |
656 |
| |
657 httpconn = g_new0(MsnHttpConn, 1); |
| |
658 |
| |
659 gaim_debug_info("msn", "new httpconn (%p)\n", httpconn); |
| |
660 |
| |
661 /* TODO: Remove this */ |
| |
662 httpconn->session = servconn->session; |
| |
663 |
| |
664 httpconn->servconn = servconn; |
| |
665 |
| |
666 httpconn->tx_buf = gaim_circ_buffer_new(MSN_BUF_LEN); |
| |
667 httpconn->tx_handler = 0; |
| |
668 |
| |
669 return httpconn; |
| |
670 } |
| |
671 |
| |
672 void |
| |
673 msn_httpconn_destroy(MsnHttpConn *httpconn) |
| |
674 { |
| |
675 g_return_if_fail(httpconn != NULL); |
| |
676 |
| |
677 gaim_debug_info("msn", "destroy httpconn (%p)\n", httpconn); |
| |
678 |
| |
679 if (httpconn->connected) |
| |
680 msn_httpconn_disconnect(httpconn); |
| |
681 |
| |
682 g_free(httpconn->full_session_id); |
| |
683 |
| |
684 g_free(httpconn->session_id); |
| |
685 |
| |
686 g_free(httpconn->host); |
| |
687 |
| |
688 gaim_circ_buffer_destroy(httpconn->tx_buf); |
| |
689 if (httpconn->tx_handler > 0) |
| |
690 gaim_input_remove(httpconn->tx_handler); |
| |
691 |
| |
692 g_free(httpconn); |
| |
693 } |
| |
694 |
| |
695 static void |
| |
696 connect_cb(gpointer data, gint source, const gchar *error_message) |
| |
697 { |
| |
698 MsnHttpConn *httpconn; |
| |
699 |
| |
700 httpconn = data; |
| |
701 httpconn->connect_info = NULL; |
| |
702 httpconn->fd = source; |
| |
703 |
| |
704 if (source >= 0) |
| |
705 { |
| |
706 httpconn->inpa = gaim_input_add(httpconn->fd, GAIM_INPUT_READ, |
| |
707 read_cb, data); |
| |
708 |
| |
709 httpconn->timer = gaim_timeout_add(2000, msn_httpconn_poll, httpconn); |
| |
710 |
| |
711 msn_httpconn_process_queue(httpconn); |
| |
712 } |
| |
713 else |
| |
714 { |
| |
715 gaim_debug_error("msn", "HTTP: Connection error\n"); |
| |
716 msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_CONNECT); |
| |
717 } |
| |
718 } |
| |
719 |
| |
720 gboolean |
| |
721 msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port) |
| |
722 { |
| |
723 g_return_val_if_fail(httpconn != NULL, FALSE); |
| |
724 g_return_val_if_fail(host != NULL, FALSE); |
| |
725 g_return_val_if_fail(port > 0, FALSE); |
| |
726 |
| |
727 if (httpconn->connected) |
| |
728 msn_httpconn_disconnect(httpconn); |
| |
729 |
| |
730 httpconn->connect_info = gaim_proxy_connect(httpconn->session->account, |
| |
731 "gateway.messenger.hotmail.com", 80, connect_cb, httpconn); |
| |
732 |
| |
733 if (httpconn->connect_info != NULL) |
| |
734 { |
| |
735 httpconn->waiting_response = TRUE; |
| |
736 httpconn->connected = TRUE; |
| |
737 } |
| |
738 |
| |
739 return httpconn->connected; |
| |
740 } |
| |
741 |
| |
742 void |
| |
743 msn_httpconn_disconnect(MsnHttpConn *httpconn) |
| |
744 { |
| |
745 g_return_if_fail(httpconn != NULL); |
| |
746 |
| |
747 if (!httpconn->connected) |
| |
748 return; |
| |
749 |
| |
750 if (httpconn->connect_info != NULL) |
| |
751 { |
| |
752 gaim_proxy_connect_cancel(httpconn->connect_info); |
| |
753 httpconn->connect_info = NULL; |
| |
754 } |
| |
755 |
| |
756 if (httpconn->timer) |
| |
757 { |
| |
758 gaim_timeout_remove(httpconn->timer); |
| |
759 httpconn->timer = 0; |
| |
760 } |
| |
761 |
| |
762 if (httpconn->inpa > 0) |
| |
763 { |
| |
764 gaim_input_remove(httpconn->inpa); |
| |
765 httpconn->inpa = 0; |
| |
766 } |
| |
767 |
| |
768 close(httpconn->fd); |
| |
769 httpconn->fd = -1; |
| |
770 |
| |
771 g_free(httpconn->rx_buf); |
| |
772 httpconn->rx_buf = NULL; |
| |
773 httpconn->rx_len = 0; |
| |
774 |
| |
775 httpconn->connected = FALSE; |
| |
776 |
| |
777 /* msn_servconn_disconnect(httpconn->servconn); */ |
| |
778 } |