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