Mercurial > pidgin
annotate src/protocols/msn/httpconn.c @ 11957:7584cc821c19
[gaim-migrate @ 14248]
we'll give this a try
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Thu, 03 Nov 2005 13:12:37 +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 } |
