| 279 * address fails. We close the socket, remove the watcher and get |
279 * address fails. We close the socket, remove the watcher and get |
| 280 * rid of input and output buffers. Normally try_connect() will |
280 * rid of input and output buffers. Normally try_connect() will |
| 281 * be called immediately after this. |
281 * be called immediately after this. |
| 282 */ |
282 */ |
| 283 static void |
283 static void |
| 284 gaim_proxy_connect_info_disconnect(GaimProxyConnectInfo *connect_info) |
284 gaim_proxy_connect_data_disconnect(GaimProxyConnectData *connect_data) |
| 285 { |
285 { |
| 286 if (connect_info->inpa > 0) |
286 if (connect_data->inpa > 0) |
| 287 { |
287 { |
| 288 gaim_input_remove(connect_info->inpa); |
288 gaim_input_remove(connect_data->inpa); |
| 289 connect_info->inpa = 0; |
289 connect_data->inpa = 0; |
| 290 } |
290 } |
| 291 |
291 |
| 292 if (connect_info->fd >= 0) |
292 if (connect_data->fd >= 0) |
| 293 { |
293 { |
| 294 close(connect_info->fd); |
294 close(connect_data->fd); |
| 295 connect_info->fd = -1; |
295 connect_data->fd = -1; |
| 296 } |
296 } |
| 297 |
297 |
| 298 g_free(connect_info->write_buffer); |
298 g_free(connect_data->write_buffer); |
| 299 connect_info->write_buffer = NULL; |
299 connect_data->write_buffer = NULL; |
| 300 |
300 |
| 301 g_free(connect_info->read_buffer); |
301 g_free(connect_data->read_buffer); |
| 302 connect_info->read_buffer = NULL; |
302 connect_data->read_buffer = NULL; |
| 303 } |
303 } |
| 304 |
304 |
| 305 static void |
305 static void |
| 306 gaim_proxy_connect_info_destroy(GaimProxyConnectInfo *connect_info) |
306 gaim_proxy_connect_data_destroy(GaimProxyConnectData *connect_data) |
| 307 { |
307 { |
| 308 gaim_proxy_connect_info_disconnect(connect_info); |
308 gaim_proxy_connect_data_disconnect(connect_data); |
| 309 |
309 |
| 310 connect_infos = g_slist_remove(connect_infos, connect_info); |
310 connect_datas = g_slist_remove(connect_datas, connect_data); |
| 311 |
311 |
| 312 if (connect_info->query_data != NULL) |
312 if (connect_data->query_data != NULL) |
| 313 gaim_dnsquery_destroy(connect_info->query_data); |
313 gaim_dnsquery_destroy(connect_data->query_data); |
| 314 |
314 |
| 315 while (connect_info->hosts != NULL) |
315 while (connect_data->hosts != NULL) |
| 316 { |
316 { |
| 317 /* Discard the length... */ |
317 /* Discard the length... */ |
| 318 connect_info->hosts = g_slist_remove(connect_info->hosts, connect_info->hosts->data); |
318 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 319 /* Free the address... */ |
319 /* Free the address... */ |
| 320 g_free(connect_info->hosts->data); |
320 g_free(connect_data->hosts->data); |
| 321 connect_info->hosts = g_slist_remove(connect_info->hosts, connect_info->hosts->data); |
321 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 322 } |
322 } |
| 323 |
323 |
| 324 g_free(connect_info->host); |
324 g_free(connect_data->host); |
| 325 g_free(connect_info); |
325 g_free(connect_data); |
| 326 } |
326 } |
| 327 |
327 |
| 328 static void |
328 static void |
| 329 gaim_proxy_connect_info_connected(GaimProxyConnectInfo *connect_info) |
329 gaim_proxy_connect_data_connected(GaimProxyConnectData *connect_data) |
| 330 { |
330 { |
| 331 connect_info->connect_cb(connect_info->data, connect_info->fd, NULL); |
331 connect_data->connect_cb(connect_data->data, connect_data->fd, NULL); |
| 332 |
332 |
| 333 /* |
333 /* |
| 334 * We've passed the file descriptor to the protocol, so it's no longer |
334 * We've passed the file descriptor to the protocol, so it's no longer |
| 335 * our responsibility, and we should be careful not to free it when |
335 * our responsibility, and we should be careful not to free it when |
| 336 * we destroy the connect_info. |
336 * we destroy the connect_data. |
| 337 */ |
337 */ |
| 338 connect_info->fd = -1; |
338 connect_data->fd = -1; |
| 339 |
339 |
| 340 gaim_proxy_connect_info_destroy(connect_info); |
340 gaim_proxy_connect_data_destroy(connect_data); |
| 341 } |
341 } |
| 342 |
342 |
| 343 /** |
343 /** |
| 344 * @param error An error message explaining why the connection |
344 * @param error An error message explaining why the connection |
| 345 * failed. This will be passed to the callback function |
345 * failed. This will be passed to the callback function |
| 376 * |
376 * |
| 377 * (error == EINPROGRESS can happen after a select because the kernel can |
377 * (error == EINPROGRESS can happen after a select because the kernel can |
| 378 * be overly optimistic sometimes. select is just a hint that you might be |
378 * be overly optimistic sometimes. select is just a hint that you might be |
| 379 * able to do something.) |
379 * able to do something.) |
| 380 */ |
380 */ |
| 381 ret = getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
381 ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); |
| 382 if (ret == 0 && error == EINPROGRESS) |
382 if (ret == 0 && error == EINPROGRESS) |
| 383 return; /* we'll be called again later */ |
383 return; /* we'll be called again later */ |
| 384 if (ret < 0 || error != 0) { |
384 if (ret < 0 || error != 0) { |
| 385 if (ret!=0) |
385 if (ret!=0) |
| 386 error = errno; |
386 error = errno; |
| 387 |
387 |
| 388 gaim_debug_error("proxy", |
388 gaim_debug_error("proxy", |
| 389 "getsockopt SO_ERROR check: %s\n", strerror(error)); |
389 "getsockopt SO_ERROR check: %s\n", strerror(error)); |
| 390 |
390 |
| 391 gaim_proxy_connect_info_disconnect(connect_info); |
391 gaim_proxy_connect_data_disconnect(connect_data); |
| 392 try_connect(connect_info); |
392 try_connect(connect_data); |
| 393 return; |
393 return; |
| 394 } |
394 } |
| 395 |
395 |
| 396 gaim_input_remove(connect_info->inpa); |
396 gaim_input_remove(connect_data->inpa); |
| 397 connect_info->inpa = 0; |
397 connect_data->inpa = 0; |
| 398 |
398 |
| 399 gaim_proxy_connect_info_connected(connect_info); |
399 gaim_proxy_connect_data_connected(connect_data); |
| 400 } |
400 } |
| 401 |
401 |
| 402 static gboolean |
402 static gboolean |
| 403 clean_connect(gpointer data) |
403 clean_connect(gpointer data) |
| 404 { |
404 { |
| 405 GaimProxyConnectInfo *connect_info; |
405 GaimProxyConnectData *connect_data; |
| 406 |
406 |
| 407 connect_info = data; |
407 connect_data = data; |
| 408 gaim_proxy_connect_info_connected(connect_info); |
408 gaim_proxy_connect_data_connected(connect_data); |
| 409 |
409 |
| 410 return FALSE; |
410 return FALSE; |
| 411 } |
411 } |
| 412 |
412 |
| 413 static int |
413 static int |
| 414 proxy_connect_none(GaimProxyConnectInfo *connect_info, struct sockaddr *addr, socklen_t addrlen) |
414 proxy_connect_none(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 415 { |
415 { |
| 416 gaim_debug_info("proxy", "Connecting to %s:%d with no proxy\n", |
416 gaim_debug_info("proxy", "Connecting to %s:%d with no proxy\n", |
| 417 connect_info->host, connect_info->port); |
417 connect_data->host, connect_data->port); |
| 418 |
418 |
| 419 connect_info->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
419 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 420 if (connect_info->fd < 0) |
420 if (connect_data->fd < 0) |
| 421 { |
421 { |
| 422 gaim_debug_error("proxy", |
422 gaim_debug_error("proxy", |
| 423 "Unable to create socket: %s\n", strerror(errno)); |
423 "Unable to create socket: %s\n", strerror(errno)); |
| 424 return -1; |
424 return -1; |
| 425 } |
425 } |
| 426 fcntl(connect_info->fd, F_SETFL, O_NONBLOCK); |
426 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 427 #ifndef _WIN32 |
427 #ifndef _WIN32 |
| 428 fcntl(connect_info->fd, F_SETFD, FD_CLOEXEC); |
428 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 429 #endif |
429 #endif |
| 430 |
430 |
| 431 if (connect(connect_info->fd, (struct sockaddr *)addr, addrlen) != 0) |
431 if (connect(connect_data->fd, (struct sockaddr *)addr, addrlen) != 0) |
| 432 { |
432 { |
| 433 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
433 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 434 gaim_debug_info("proxy", "Connection in progress\n"); |
434 gaim_debug_info("proxy", "Connection in progress\n"); |
| 435 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, no_one_calls, connect_info); |
435 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, no_one_calls, connect_data); |
| 436 } |
436 } |
| 437 else { |
437 else { |
| 438 gaim_debug_error("proxy", |
438 gaim_debug_error("proxy", |
| 439 "Connect failed: %s\n", strerror(errno)); |
439 "Connect failed: %s\n", strerror(errno)); |
| 440 close(connect_info->fd); |
440 close(connect_data->fd); |
| 441 connect_info->fd = -1; |
441 connect_data->fd = -1; |
| 442 return -1; |
442 return -1; |
| 443 } |
443 } |
| 444 } |
444 } |
| 445 else |
445 else |
| 446 { |
446 { |
| 449 */ |
449 */ |
| 450 socklen_t len; |
450 socklen_t len; |
| 451 int error = ETIMEDOUT; |
451 int error = ETIMEDOUT; |
| 452 gaim_debug_info("proxy", "Connected immediately.\n"); |
452 gaim_debug_info("proxy", "Connected immediately.\n"); |
| 453 len = sizeof(error); |
453 len = sizeof(error); |
| 454 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
454 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
| 455 { |
455 { |
| 456 gaim_debug_error("proxy", "getsockopt failed.\n"); |
456 gaim_debug_error("proxy", "getsockopt failed.\n"); |
| 457 close(connect_info->fd); |
457 close(connect_data->fd); |
| 458 connect_info->fd = -1; |
458 connect_data->fd = -1; |
| 459 return -1; |
459 return -1; |
| 460 } |
460 } |
| 461 |
461 |
| 462 /* |
462 /* |
| 463 * We want to call the "connected" callback eventually, but we |
463 * We want to call the "connected" callback eventually, but we |
| 464 * don't want to call it before we return, just in case. |
464 * don't want to call it before we return, just in case. |
| 465 */ |
465 */ |
| 466 gaim_timeout_add(10, clean_connect, connect_info); |
466 gaim_timeout_add(10, clean_connect, connect_data); |
| 467 } |
467 } |
| 468 |
468 |
| 469 return connect_info->fd; |
469 return connect_data->fd; |
| 470 } |
470 } |
| 471 |
471 |
| 472 static void |
472 static void |
| 473 proxy_do_write(gpointer data, gint source, GaimInputCondition cond) |
473 proxy_do_write(gpointer data, gint source, GaimInputCondition cond) |
| 474 { |
474 { |
| 475 GaimProxyConnectInfo *connect_info = data; |
475 GaimProxyConnectData *connect_data = data; |
| 476 const guchar *request = connect_info->write_buffer + connect_info->written_len; |
476 const guchar *request = connect_data->write_buffer + connect_data->written_len; |
| 477 gsize request_len = connect_info->write_buf_len - connect_info->written_len; |
477 gsize request_len = connect_data->write_buf_len - connect_data->written_len; |
| 478 |
478 |
| 479 int ret = write(connect_info->fd, request, request_len); |
479 int ret = write(connect_data->fd, request, request_len); |
| 480 |
480 |
| 481 if(ret < 0 && errno == EAGAIN) |
481 if(ret < 0 && errno == EAGAIN) |
| 482 return; |
482 return; |
| 483 else if(ret < 0) { |
483 else if(ret < 0) { |
| 484 gaim_proxy_connect_info_disconnect(connect_info); |
484 gaim_proxy_connect_data_disconnect(connect_data); |
| 485 try_connect(connect_info); |
485 try_connect(connect_data); |
| 486 return; |
486 return; |
| 487 } else if (ret < request_len) { |
487 } else if (ret < request_len) { |
| 488 connect_info->written_len += ret; |
488 connect_data->written_len += ret; |
| 489 return; |
489 return; |
| 490 } |
490 } |
| 491 |
491 |
| 492 gaim_input_remove(connect_info->inpa); |
492 gaim_input_remove(connect_data->inpa); |
| 493 g_free(connect_info->write_buffer); |
493 g_free(connect_data->write_buffer); |
| 494 connect_info->write_buffer = NULL; |
494 connect_data->write_buffer = NULL; |
| 495 |
495 |
| 496 /* register the response handler for the response */ |
496 /* register the response handler for the response */ |
| 497 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_READ, connect_info->read_cb, connect_info); |
497 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_READ, connect_data->read_cb, connect_data); |
| 498 } |
498 } |
| 499 |
499 |
| 500 #define HTTP_GOODSTRING "HTTP/1.0 200" |
500 #define HTTP_GOODSTRING "HTTP/1.0 200" |
| 501 #define HTTP_GOODSTRING2 "HTTP/1.1 200" |
501 #define HTTP_GOODSTRING2 "HTTP/1.1 200" |
| 502 |
502 |
| 573 len = atoi((const char *)p); |
573 len = atoi((const char *)p); |
| 574 if(tmp) |
574 if(tmp) |
| 575 *tmp = '\r'; |
575 *tmp = '\r'; |
| 576 |
576 |
| 577 /* Compensate for what has already been read */ |
577 /* Compensate for what has already been read */ |
| 578 len -= connect_info->read_len - headers_len; |
578 len -= connect_data->read_len - headers_len; |
| 579 /* I'm assuming that we're doing this to prevent the server from |
579 /* I'm assuming that we're doing this to prevent the server from |
| 580 complaining / breaking since we don't read the whole page */ |
580 complaining / breaking since we don't read the whole page */ |
| 581 while(len--) { |
581 while(len--) { |
| 582 /* TODO: deal with EAGAIN (and other errors) better */ |
582 /* TODO: deal with EAGAIN (and other errors) better */ |
| 583 if (read(connect_info->fd, &tmpc, 1) < 0 && errno != EAGAIN) |
583 if (read(connect_data->fd, &tmpc, 1) < 0 && errno != EAGAIN) |
| 584 break; |
584 break; |
| 585 } |
585 } |
| 586 } |
586 } |
| 587 |
587 |
| 588 if (error) |
588 if (error) |
| 589 { |
589 { |
| 590 msg = g_strdup_printf("Unable to parse response from HTTP proxy: %s\n", |
590 msg = g_strdup_printf("Unable to parse response from HTTP proxy: %s\n", |
| 591 connect_info->read_buffer); |
591 connect_data->read_buffer); |
| 592 gaim_proxy_connect_info_error(connect_info, msg); |
592 gaim_proxy_connect_data_error(connect_data, msg); |
| 593 g_free(msg); |
593 g_free(msg); |
| 594 return; |
594 return; |
| 595 } |
595 } |
| 596 else if (status != 200) |
596 else if (status != 200) |
| 597 { |
597 { |
| 598 gaim_debug_error("proxy", |
598 gaim_debug_error("proxy", |
| 599 "Proxy server replied with:\n%s\n", |
599 "Proxy server replied with:\n%s\n", |
| 600 connect_info->read_buffer); |
600 connect_data->read_buffer); |
| 601 |
601 |
| 602 |
602 |
| 603 if(status == 407 /* Proxy Auth */) { |
603 if(status == 407 /* Proxy Auth */) { |
| 604 gchar *ntlm; |
604 gchar *ntlm; |
| 605 if((ntlm = g_strrstr((const gchar *)connect_info->read_buffer, "Proxy-Authenticate: NTLM "))) { /* Check for Type-2 */ |
605 if((ntlm = g_strrstr((const gchar *)connect_data->read_buffer, "Proxy-Authenticate: NTLM "))) { /* Check for Type-2 */ |
| 606 gchar *tmp = ntlm; |
606 gchar *tmp = ntlm; |
| 607 guint8 *nonce; |
607 guint8 *nonce; |
| 608 gchar *domain = (gchar*)gaim_proxy_info_get_username(connect_info->gpi); |
608 gchar *domain = (gchar*)gaim_proxy_info_get_username(connect_data->gpi); |
| 609 gchar *username; |
609 gchar *username; |
| 610 gchar *request; |
610 gchar *request; |
| 611 gchar *response; |
611 gchar *response; |
| 612 username = strchr(domain, '\\'); |
612 username = strchr(domain, '\\'); |
| 613 if (username == NULL) |
613 if (username == NULL) |
| 614 { |
614 { |
| 615 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
615 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
| 616 gaim_proxy_connect_info_error(connect_info, msg); |
616 gaim_proxy_connect_data_error(connect_data, msg); |
| 617 g_free(msg); |
617 g_free(msg); |
| 618 return; |
618 return; |
| 619 } |
619 } |
| 620 *username = '\0'; |
620 *username = '\0'; |
| 621 username++; |
621 username++; |
| 622 ntlm += strlen("Proxy-Authenticate: NTLM "); |
622 ntlm += strlen("Proxy-Authenticate: NTLM "); |
| 623 while(*tmp != '\r' && *tmp != '\0') tmp++; |
623 while(*tmp != '\r' && *tmp != '\0') tmp++; |
| 624 *tmp = '\0'; |
624 *tmp = '\0'; |
| 625 nonce = gaim_ntlm_parse_type2(ntlm, NULL); |
625 nonce = gaim_ntlm_parse_type2(ntlm, NULL); |
| 626 response = gaim_ntlm_gen_type3(username, |
626 response = gaim_ntlm_gen_type3(username, |
| 627 (gchar*) gaim_proxy_info_get_password(connect_info->gpi), |
627 (gchar*) gaim_proxy_info_get_password(connect_data->gpi), |
| 628 (gchar*) gaim_proxy_info_get_host(connect_info->gpi), |
628 (gchar*) gaim_proxy_info_get_host(connect_data->gpi), |
| 629 domain, nonce, NULL); |
629 domain, nonce, NULL); |
| 630 username--; |
630 username--; |
| 631 *username = '\\'; |
631 *username = '\\'; |
| 632 request = g_strdup_printf( |
632 request = g_strdup_printf( |
| 633 "CONNECT %s:%d HTTP/1.1\r\n" |
633 "CONNECT %s:%d HTTP/1.1\r\n" |
| 634 "Host: %s:%d\r\n" |
634 "Host: %s:%d\r\n" |
| 635 "Proxy-Authorization: NTLM %s\r\n" |
635 "Proxy-Authorization: NTLM %s\r\n" |
| 636 "Proxy-Connection: Keep-Alive\r\n\r\n", |
636 "Proxy-Connection: Keep-Alive\r\n\r\n", |
| 637 connect_info->host, connect_info->port, connect_info->host, |
637 connect_data->host, connect_data->port, connect_data->host, |
| 638 connect_info->port, response); |
638 connect_data->port, response); |
| 639 g_free(response); |
639 g_free(response); |
| 640 |
640 |
| 641 gaim_input_remove(connect_info->inpa); |
641 gaim_input_remove(connect_data->inpa); |
| 642 g_free(connect_info->read_buffer); |
642 g_free(connect_data->read_buffer); |
| 643 connect_info->read_buffer = NULL; |
643 connect_data->read_buffer = NULL; |
| 644 |
644 |
| 645 connect_info->write_buffer = (guchar *)request; |
645 connect_data->write_buffer = (guchar *)request; |
| 646 connect_info->write_buf_len = strlen(request); |
646 connect_data->write_buf_len = strlen(request); |
| 647 connect_info->written_len = 0; |
647 connect_data->written_len = 0; |
| 648 |
648 |
| 649 connect_info->read_cb = http_canread; |
649 connect_data->read_cb = http_canread; |
| 650 |
650 |
| 651 connect_info->inpa = gaim_input_add(connect_info->fd, |
651 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 652 GAIM_INPUT_WRITE, proxy_do_write, connect_info); |
652 GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 653 |
653 |
| 654 proxy_do_write(connect_info, connect_info->fd, cond); |
654 proxy_do_write(connect_data, connect_data->fd, cond); |
| 655 return; |
655 return; |
| 656 } else if((ntlm = g_strrstr((const char *)connect_info->read_buffer, "Proxy-Authenticate: NTLM"))) { /* Empty message */ |
656 } else if((ntlm = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: NTLM"))) { /* Empty message */ |
| 657 gchar request[2048]; |
657 gchar request[2048]; |
| 658 gchar *domain = (gchar*) gaim_proxy_info_get_username(connect_info->gpi); |
658 gchar *domain = (gchar*) gaim_proxy_info_get_username(connect_data->gpi); |
| 659 gchar *username; |
659 gchar *username; |
| 660 int request_len; |
660 int request_len; |
| 661 username = strchr(domain, '\\'); |
661 username = strchr(domain, '\\'); |
| 662 if (username == NULL) |
662 if (username == NULL) |
| 663 { |
663 { |
| 664 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
664 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
| 665 gaim_proxy_connect_info_error(connect_info, msg); |
665 gaim_proxy_connect_data_error(connect_data, msg); |
| 666 g_free(msg); |
666 g_free(msg); |
| 667 return; |
667 return; |
| 668 } |
668 } |
| 669 *username = '\0'; |
669 *username = '\0'; |
| 670 |
670 |
| 671 request_len = g_snprintf(request, sizeof(request), |
671 request_len = g_snprintf(request, sizeof(request), |
| 672 "CONNECT %s:%d HTTP/1.1\r\n" |
672 "CONNECT %s:%d HTTP/1.1\r\n" |
| 673 "Host: %s:%d\r\n", |
673 "Host: %s:%d\r\n", |
| 674 connect_info->host, connect_info->port, |
674 connect_data->host, connect_data->port, |
| 675 connect_info->host, connect_info->port); |
675 connect_data->host, connect_data->port); |
| 676 |
676 |
| 677 g_return_if_fail(request_len < sizeof(request)); |
677 g_return_if_fail(request_len < sizeof(request)); |
| 678 request_len += g_snprintf(request + request_len, |
678 request_len += g_snprintf(request + request_len, |
| 679 sizeof(request) - request_len, |
679 sizeof(request) - request_len, |
| 680 "Proxy-Authorization: NTLM %s\r\n" |
680 "Proxy-Authorization: NTLM %s\r\n" |
| 681 "Proxy-Connection: Keep-Alive\r\n\r\n", |
681 "Proxy-Connection: Keep-Alive\r\n\r\n", |
| 682 gaim_ntlm_gen_type1( |
682 gaim_ntlm_gen_type1( |
| 683 (gchar*) gaim_proxy_info_get_host(connect_info->gpi), |
683 (gchar*) gaim_proxy_info_get_host(connect_data->gpi), |
| 684 domain)); |
684 domain)); |
| 685 *username = '\\'; |
685 *username = '\\'; |
| 686 |
686 |
| 687 gaim_input_remove(connect_info->inpa); |
687 gaim_input_remove(connect_data->inpa); |
| 688 g_free(connect_info->read_buffer); |
688 g_free(connect_data->read_buffer); |
| 689 connect_info->read_buffer = NULL; |
689 connect_data->read_buffer = NULL; |
| 690 |
690 |
| 691 connect_info->write_buffer = g_memdup(request, request_len); |
691 connect_data->write_buffer = g_memdup(request, request_len); |
| 692 connect_info->write_buf_len = request_len; |
692 connect_data->write_buf_len = request_len; |
| 693 connect_info->written_len = 0; |
693 connect_data->written_len = 0; |
| 694 |
694 |
| 695 connect_info->read_cb = http_canread; |
695 connect_data->read_cb = http_canread; |
| 696 |
696 |
| 697 connect_info->inpa = gaim_input_add(connect_info->fd, |
697 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 698 GAIM_INPUT_WRITE, proxy_do_write, connect_info); |
698 GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 699 |
699 |
| 700 proxy_do_write(connect_info, connect_info->fd, cond); |
700 proxy_do_write(connect_data, connect_data->fd, cond); |
| 701 return; |
701 return; |
| 702 } else { |
702 } else { |
| 703 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
703 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
| 704 gaim_proxy_connect_info_error(connect_info, msg); |
704 gaim_proxy_connect_data_error(connect_data, msg); |
| 705 g_free(msg); |
705 g_free(msg); |
| 706 return; |
706 return; |
| 707 } |
707 } |
| 708 } |
708 } |
| 709 if(status == 403 /* Forbidden */ ) { |
709 if(status == 403 /* Forbidden */ ) { |
| 710 msg = g_strdup_printf(_("Access denied: HTTP proxy server forbids port %d tunnelling."), connect_info->port); |
710 msg = g_strdup_printf(_("Access denied: HTTP proxy server forbids port %d tunnelling."), connect_data->port); |
| 711 gaim_proxy_connect_info_error(connect_info, msg); |
711 gaim_proxy_connect_data_error(connect_data, msg); |
| 712 g_free(msg); |
712 g_free(msg); |
| 713 } else { |
713 } else { |
| 714 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
714 msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); |
| 715 gaim_proxy_connect_info_error(connect_info, msg); |
715 gaim_proxy_connect_data_error(connect_data, msg); |
| 716 g_free(msg); |
716 g_free(msg); |
| 717 } |
717 } |
| 718 } else { |
718 } else { |
| 719 gaim_input_remove(connect_info->inpa); |
719 gaim_input_remove(connect_data->inpa); |
| 720 connect_info->inpa = 0; |
720 connect_data->inpa = 0; |
| 721 g_free(connect_info->read_buffer); |
721 g_free(connect_data->read_buffer); |
| 722 connect_info->read_buffer = NULL; |
722 connect_data->read_buffer = NULL; |
| 723 gaim_debug_info("proxy", "HTTP proxy connection established\n"); |
723 gaim_debug_info("proxy", "HTTP proxy connection established\n"); |
| 724 gaim_proxy_connect_info_connected(connect_info); |
724 gaim_proxy_connect_data_connected(connect_data); |
| 725 return; |
725 return; |
| 726 } |
726 } |
| 727 } |
727 } |
| 728 |
728 |
| 729 |
729 |
| 731 static void |
731 static void |
| 732 http_canwrite(gpointer data, gint source, GaimInputCondition cond) |
732 http_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 733 { |
733 { |
| 734 char request[8192]; |
734 char request[8192]; |
| 735 int request_len = 0; |
735 int request_len = 0; |
| 736 GaimProxyConnectInfo *connect_info = data; |
736 GaimProxyConnectData *connect_data = data; |
| 737 socklen_t len; |
737 socklen_t len; |
| 738 int error = ETIMEDOUT; |
738 int error = ETIMEDOUT; |
| 739 |
739 |
| 740 gaim_debug_info("http proxy", "Connected.\n"); |
740 gaim_debug_info("http proxy", "Connected.\n"); |
| 741 |
741 |
| 742 if (connect_info->inpa > 0) |
742 if (connect_data->inpa > 0) |
| 743 { |
743 { |
| 744 gaim_input_remove(connect_info->inpa); |
744 gaim_input_remove(connect_data->inpa); |
| 745 connect_info->inpa = 0; |
745 connect_data->inpa = 0; |
| 746 } |
746 } |
| 747 |
747 |
| 748 len = sizeof(error); |
748 len = sizeof(error); |
| 749 |
749 |
| 750 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
750 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 751 gaim_proxy_connect_info_disconnect(connect_info); |
751 gaim_proxy_connect_data_disconnect(connect_data); |
| 752 try_connect(connect_info); |
752 try_connect(connect_data); |
| 753 return; |
753 return; |
| 754 } |
754 } |
| 755 |
755 |
| 756 gaim_debug_info("proxy", "using CONNECT tunnelling for %s:%d\n", |
756 gaim_debug_info("proxy", "using CONNECT tunnelling for %s:%d\n", |
| 757 connect_info->host, connect_info->port); |
757 connect_data->host, connect_data->port); |
| 758 request_len = g_snprintf(request, sizeof(request), |
758 request_len = g_snprintf(request, sizeof(request), |
| 759 "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", |
759 "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", |
| 760 connect_info->host, connect_info->port, connect_info->host, connect_info->port); |
760 connect_data->host, connect_data->port, connect_data->host, connect_data->port); |
| 761 |
761 |
| 762 if (gaim_proxy_info_get_username(connect_info->gpi) != NULL) { |
762 if (gaim_proxy_info_get_username(connect_data->gpi) != NULL) { |
| 763 char *t1, *t2; |
763 char *t1, *t2; |
| 764 t1 = g_strdup_printf("%s:%s", |
764 t1 = g_strdup_printf("%s:%s", |
| 765 gaim_proxy_info_get_username(connect_info->gpi), |
765 gaim_proxy_info_get_username(connect_data->gpi), |
| 766 gaim_proxy_info_get_password(connect_info->gpi) ? |
766 gaim_proxy_info_get_password(connect_data->gpi) ? |
| 767 gaim_proxy_info_get_password(connect_info->gpi) : ""); |
767 gaim_proxy_info_get_password(connect_data->gpi) : ""); |
| 768 t2 = gaim_base64_encode((const guchar *)t1, strlen(t1)); |
768 t2 = gaim_base64_encode((const guchar *)t1, strlen(t1)); |
| 769 g_free(t1); |
769 g_free(t1); |
| 770 g_return_if_fail(request_len < sizeof(request)); |
770 g_return_if_fail(request_len < sizeof(request)); |
| 771 |
771 |
| 772 request_len += g_snprintf(request + request_len, |
772 request_len += g_snprintf(request + request_len, |
| 773 sizeof(request) - request_len, |
773 sizeof(request) - request_len, |
| 774 "Proxy-Authorization: Basic %s\r\n" |
774 "Proxy-Authorization: Basic %s\r\n" |
| 775 "Proxy-Authorization: NTLM %s\r\n" |
775 "Proxy-Authorization: NTLM %s\r\n" |
| 776 "Proxy-Connection: Keep-Alive\r\n", t2, |
776 "Proxy-Connection: Keep-Alive\r\n", t2, |
| 777 gaim_ntlm_gen_type1( |
777 gaim_ntlm_gen_type1( |
| 778 (gchar*)gaim_proxy_info_get_host(connect_info->gpi),"")); |
778 (gchar*)gaim_proxy_info_get_host(connect_data->gpi),"")); |
| 779 g_free(t2); |
779 g_free(t2); |
| 780 } |
780 } |
| 781 |
781 |
| 782 g_return_if_fail(request_len < sizeof(request)); |
782 g_return_if_fail(request_len < sizeof(request)); |
| 783 strcpy(request + request_len, "\r\n"); |
783 strcpy(request + request_len, "\r\n"); |
| 784 request_len += 2; |
784 request_len += 2; |
| 785 connect_info->write_buffer = g_memdup(request, request_len); |
785 connect_data->write_buffer = g_memdup(request, request_len); |
| 786 connect_info->write_buf_len = request_len; |
786 connect_data->write_buf_len = request_len; |
| 787 connect_info->written_len = 0; |
787 connect_data->written_len = 0; |
| 788 |
788 |
| 789 connect_info->read_cb = http_canread; |
789 connect_data->read_cb = http_canread; |
| 790 |
790 |
| 791 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, proxy_do_write, |
791 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, |
| 792 connect_info); |
792 connect_data); |
| 793 |
793 |
| 794 proxy_do_write(connect_info, connect_info->fd, cond); |
794 proxy_do_write(connect_data, connect_data->fd, cond); |
| 795 } |
795 } |
| 796 |
796 |
| 797 static int |
797 static int |
| 798 proxy_connect_http(GaimProxyConnectInfo *connect_info, struct sockaddr *addr, socklen_t addrlen) |
798 proxy_connect_http(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 799 { |
799 { |
| 800 gaim_debug_info("http proxy", |
800 gaim_debug_info("http proxy", |
| 801 "Connecting to %s:%d via %s:%d using HTTP\n", |
801 "Connecting to %s:%d via %s:%d using HTTP\n", |
| 802 (connect_info->host ? connect_info->host : "(null)"), connect_info->port, |
802 (connect_data->host ? connect_data->host : "(null)"), connect_data->port, |
| 803 (gaim_proxy_info_get_host(connect_info->gpi) ? gaim_proxy_info_get_host(connect_info->gpi) : "(null)"), |
803 (gaim_proxy_info_get_host(connect_data->gpi) ? gaim_proxy_info_get_host(connect_data->gpi) : "(null)"), |
| 804 gaim_proxy_info_get_port(connect_info->gpi)); |
804 gaim_proxy_info_get_port(connect_data->gpi)); |
| 805 |
805 |
| 806 connect_info->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
806 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 807 if (connect_info->fd < 0) |
807 if (connect_data->fd < 0) |
| 808 return -1; |
808 return -1; |
| 809 |
809 |
| 810 fcntl(connect_info->fd, F_SETFL, O_NONBLOCK); |
810 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 811 #ifndef _WIN32 |
811 #ifndef _WIN32 |
| 812 fcntl(connect_info->fd, F_SETFD, FD_CLOEXEC); |
812 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 813 #endif |
813 #endif |
| 814 |
814 |
| 815 if (connect(connect_info->fd, addr, addrlen) != 0) |
815 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 816 { |
816 { |
| 817 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
817 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 818 gaim_debug_info("http proxy", "Connection in progress\n"); |
818 gaim_debug_info("http proxy", "Connection in progress\n"); |
| 819 |
819 |
| 820 if (connect_info->port != 80) { |
820 if (connect_data->port != 80) { |
| 821 /* we need to do CONNECT first */ |
821 /* we need to do CONNECT first */ |
| 822 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, |
822 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, |
| 823 http_canwrite, connect_info); |
823 http_canwrite, connect_data); |
| 824 } else { |
824 } else { |
| 825 gaim_debug_info("proxy", "HTTP proxy connection established\n"); |
825 gaim_debug_info("proxy", "HTTP proxy connection established\n"); |
| 826 gaim_proxy_connect_info_connected(connect_info); |
826 gaim_proxy_connect_data_connected(connect_data); |
| 827 } |
827 } |
| 828 } else { |
828 } else { |
| 829 close(connect_info->fd); |
829 close(connect_data->fd); |
| 830 connect_info->fd = -1; |
830 connect_data->fd = -1; |
| 831 return -1; |
831 return -1; |
| 832 } |
832 } |
| 833 } |
833 } |
| 834 else { |
834 else { |
| 835 socklen_t len; |
835 socklen_t len; |
| 836 int error = ETIMEDOUT; |
836 int error = ETIMEDOUT; |
| 837 |
837 |
| 838 gaim_debug_info("http proxy", "Connected immediately.\n"); |
838 gaim_debug_info("http proxy", "Connected immediately.\n"); |
| 839 |
839 |
| 840 len = sizeof(error); |
840 len = sizeof(error); |
| 841 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
841 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
| 842 { |
842 { |
| 843 close(connect_info->fd); |
843 close(connect_data->fd); |
| 844 connect_info->fd = -1; |
844 connect_data->fd = -1; |
| 845 return -1; |
845 return -1; |
| 846 } |
846 } |
| 847 http_canwrite(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
847 http_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 848 } |
848 } |
| 849 |
849 |
| 850 return connect_info->fd; |
850 return connect_data->fd; |
| 851 } |
851 } |
| 852 |
852 |
| 853 |
853 |
| 854 static void |
854 static void |
| 855 s4_canread(gpointer data, gint source, GaimInputCondition cond) |
855 s4_canread(gpointer data, gint source, GaimInputCondition cond) |
| 856 { |
856 { |
| 857 GaimProxyConnectInfo *connect_info = data; |
857 GaimProxyConnectData *connect_data = data; |
| 858 guchar *buf; |
858 guchar *buf; |
| 859 int len, max_read; |
859 int len, max_read; |
| 860 |
860 |
| 861 /* This is really not going to block under normal circumstances, but to |
861 /* This is really not going to block under normal circumstances, but to |
| 862 * be correct, we deal with the unlikely scenario */ |
862 * be correct, we deal with the unlikely scenario */ |
| 863 |
863 |
| 864 if (connect_info->read_buffer == NULL) { |
864 if (connect_data->read_buffer == NULL) { |
| 865 connect_info->read_buf_len = 12; |
865 connect_data->read_buf_len = 12; |
| 866 connect_info->read_buffer = g_malloc(connect_info->read_buf_len); |
866 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
| 867 connect_info->read_len = 0; |
867 connect_data->read_len = 0; |
| 868 } |
868 } |
| 869 |
869 |
| 870 buf = connect_info->read_buffer + connect_info->read_len; |
870 buf = connect_data->read_buffer + connect_data->read_len; |
| 871 max_read = connect_info->read_buf_len - connect_info->read_len; |
871 max_read = connect_data->read_buf_len - connect_data->read_len; |
| 872 |
872 |
| 873 len = read(connect_info->fd, buf, max_read); |
873 len = read(connect_data->fd, buf, max_read); |
| 874 |
874 |
| 875 if ((len < 0 && errno == EAGAIN) || (len > 0 && len + connect_info->read_len < 4)) |
875 if ((len < 0 && errno == EAGAIN) || (len > 0 && len + connect_data->read_len < 4)) |
| 876 return; |
876 return; |
| 877 else if (len + connect_info->read_len >= 4) { |
877 else if (len + connect_data->read_len >= 4) { |
| 878 if (connect_info->read_buffer[1] == 90) { |
878 if (connect_data->read_buffer[1] == 90) { |
| 879 gaim_proxy_connect_info_connected(connect_info); |
879 gaim_proxy_connect_data_connected(connect_data); |
| 880 return; |
880 return; |
| 881 } |
881 } |
| 882 } |
882 } |
| 883 |
883 |
| 884 gaim_proxy_connect_info_disconnect(connect_info); |
884 gaim_proxy_connect_data_disconnect(connect_data); |
| 885 try_connect(connect_info); |
885 try_connect(connect_data); |
| 886 } |
886 } |
| 887 |
887 |
| 888 static void |
888 static void |
| 889 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) |
889 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 890 { |
890 { |
| 891 unsigned char packet[9]; |
891 unsigned char packet[9]; |
| 892 struct hostent *hp; |
892 struct hostent *hp; |
| 893 GaimProxyConnectInfo *connect_info = data; |
893 GaimProxyConnectData *connect_data = data; |
| 894 socklen_t len; |
894 socklen_t len; |
| 895 int error = ETIMEDOUT; |
895 int error = ETIMEDOUT; |
| 896 |
896 |
| 897 gaim_debug_info("socks4 proxy", "Connected.\n"); |
897 gaim_debug_info("socks4 proxy", "Connected.\n"); |
| 898 |
898 |
| 899 if (connect_info->inpa > 0) |
899 if (connect_data->inpa > 0) |
| 900 { |
900 { |
| 901 gaim_input_remove(connect_info->inpa); |
901 gaim_input_remove(connect_data->inpa); |
| 902 connect_info->inpa = 0; |
902 connect_data->inpa = 0; |
| 903 } |
903 } |
| 904 |
904 |
| 905 len = sizeof(error); |
905 len = sizeof(error); |
| 906 |
906 |
| 907 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
907 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 908 gaim_proxy_connect_info_disconnect(connect_info); |
908 gaim_proxy_connect_data_disconnect(connect_data); |
| 909 try_connect(connect_info); |
909 try_connect(connect_data); |
| 910 return; |
910 return; |
| 911 } |
911 } |
| 912 |
912 |
| 913 /* |
913 /* |
| 914 * The socks4 spec doesn't include support for doing host name |
914 * The socks4 spec doesn't include support for doing host name |
| 917 * server supports this, it would need to be implemented |
917 * server supports this, it would need to be implemented |
| 918 * with an option, or some detection mechanism - in the |
918 * with an option, or some detection mechanism - in the |
| 919 * meantime, stick with plain old SOCKS4. |
919 * meantime, stick with plain old SOCKS4. |
| 920 */ |
920 */ |
| 921 /* TODO: This needs to be non-blocking! */ |
921 /* TODO: This needs to be non-blocking! */ |
| 922 hp = gethostbyname(connect_info->host); |
922 hp = gethostbyname(connect_data->host); |
| 923 if (hp == NULL) { |
923 if (hp == NULL) { |
| 924 gaim_proxy_connect_info_disconnect(connect_info); |
924 gaim_proxy_connect_data_disconnect(connect_data); |
| 925 try_connect(connect_info); |
925 try_connect(connect_data); |
| 926 return; |
926 return; |
| 927 } |
927 } |
| 928 |
928 |
| 929 packet[0] = 4; |
929 packet[0] = 4; |
| 930 packet[1] = 1; |
930 packet[1] = 1; |
| 931 packet[2] = connect_info->port >> 8; |
931 packet[2] = connect_data->port >> 8; |
| 932 packet[3] = connect_info->port & 0xff; |
932 packet[3] = connect_data->port & 0xff; |
| 933 packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; |
933 packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; |
| 934 packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; |
934 packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; |
| 935 packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; |
935 packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; |
| 936 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; |
936 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; |
| 937 packet[8] = 0; |
937 packet[8] = 0; |
| 938 |
938 |
| 939 connect_info->write_buffer = g_memdup(packet, sizeof(packet)); |
939 connect_data->write_buffer = g_memdup(packet, sizeof(packet)); |
| 940 connect_info->write_buf_len = sizeof(packet); |
940 connect_data->write_buf_len = sizeof(packet); |
| 941 connect_info->written_len = 0; |
941 connect_data->written_len = 0; |
| 942 connect_info->read_cb = s4_canread; |
942 connect_data->read_cb = s4_canread; |
| 943 |
943 |
| 944 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_info); |
944 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 945 |
945 |
| 946 proxy_do_write(connect_info, connect_info->fd, cond); |
946 proxy_do_write(connect_data, connect_data->fd, cond); |
| 947 } |
947 } |
| 948 |
948 |
| 949 static int |
949 static int |
| 950 proxy_connect_socks4(GaimProxyConnectInfo *connect_info, struct sockaddr *addr, socklen_t addrlen) |
950 proxy_connect_socks4(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 951 { |
951 { |
| 952 gaim_debug_info("socks4 proxy", |
952 gaim_debug_info("socks4 proxy", |
| 953 "Connecting to %s:%d via %s:%d using SOCKS4\n", |
953 "Connecting to %s:%d via %s:%d using SOCKS4\n", |
| 954 connect_info->host, connect_info->port, |
954 connect_data->host, connect_data->port, |
| 955 gaim_proxy_info_get_host(connect_info->gpi), |
955 gaim_proxy_info_get_host(connect_data->gpi), |
| 956 gaim_proxy_info_get_port(connect_info->gpi)); |
956 gaim_proxy_info_get_port(connect_data->gpi)); |
| 957 |
957 |
| 958 connect_info->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
958 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 959 if (connect_info->fd < 0) |
959 if (connect_data->fd < 0) |
| 960 return -1; |
960 return -1; |
| 961 |
961 |
| 962 fcntl(connect_info->fd, F_SETFL, O_NONBLOCK); |
962 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 963 #ifndef _WIN32 |
963 #ifndef _WIN32 |
| 964 fcntl(connect_info->fd, F_SETFD, FD_CLOEXEC); |
964 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 965 #endif |
965 #endif |
| 966 |
966 |
| 967 if (connect(connect_info->fd, addr, addrlen) != 0) |
967 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 968 { |
968 { |
| 969 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
969 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 970 gaim_debug_info("socks4 proxy", "Connection in progress.\n"); |
970 gaim_debug_info("socks4 proxy", "Connection in progress.\n"); |
| 971 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, s4_canwrite, connect_info); |
971 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, s4_canwrite, connect_data); |
| 972 } |
972 } |
| 973 else { |
973 else { |
| 974 close(connect_info->fd); |
974 close(connect_data->fd); |
| 975 connect_info->fd = -1; |
975 connect_data->fd = -1; |
| 976 return -1; |
976 return -1; |
| 977 } |
977 } |
| 978 } else { |
978 } else { |
| 979 socklen_t len; |
979 socklen_t len; |
| 980 int error = ETIMEDOUT; |
980 int error = ETIMEDOUT; |
| 981 |
981 |
| 982 gaim_debug_info("socks4 proxy", "Connected immediately.\n"); |
982 gaim_debug_info("socks4 proxy", "Connected immediately.\n"); |
| 983 |
983 |
| 984 len = sizeof(error); |
984 len = sizeof(error); |
| 985 |
985 |
| 986 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
986 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
| 987 { |
987 { |
| 988 close(connect_info->fd); |
988 close(connect_data->fd); |
| 989 connect_info->fd = -1; |
989 connect_data->fd = -1; |
| 990 return -1; |
990 return -1; |
| 991 } |
991 } |
| 992 |
992 |
| 993 s4_canwrite(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
993 s4_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 994 } |
994 } |
| 995 |
995 |
| 996 return connect_info->fd; |
996 return connect_data->fd; |
| 997 } |
997 } |
| 998 |
998 |
| 999 static void |
999 static void |
| 1000 s5_canread_again(gpointer data, gint source, GaimInputCondition cond) |
1000 s5_canread_again(gpointer data, gint source, GaimInputCondition cond) |
| 1001 { |
1001 { |
| 1002 guchar *dest, *buf; |
1002 guchar *dest, *buf; |
| 1003 GaimProxyConnectInfo *connect_info = data; |
1003 GaimProxyConnectData *connect_data = data; |
| 1004 int len; |
1004 int len; |
| 1005 |
1005 |
| 1006 if (connect_info->read_buffer == NULL) { |
1006 if (connect_data->read_buffer == NULL) { |
| 1007 connect_info->read_buf_len = 512; |
1007 connect_data->read_buf_len = 512; |
| 1008 connect_info->read_buffer = g_malloc(connect_info->read_buf_len); |
1008 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
| 1009 connect_info->read_len = 0; |
1009 connect_data->read_len = 0; |
| 1010 } |
1010 } |
| 1011 |
1011 |
| 1012 dest = connect_info->read_buffer + connect_info->read_len; |
1012 dest = connect_data->read_buffer + connect_data->read_len; |
| 1013 buf = connect_info->read_buffer; |
1013 buf = connect_data->read_buffer; |
| 1014 |
1014 |
| 1015 gaim_debug_info("socks5 proxy", "Able to read again.\n"); |
1015 gaim_debug_info("socks5 proxy", "Able to read again.\n"); |
| 1016 |
1016 |
| 1017 len = read(connect_info->fd, dest, (connect_info->read_buf_len - connect_info->read_len)); |
1017 len = read(connect_data->fd, dest, (connect_data->read_buf_len - connect_data->read_len)); |
| 1018 if(len < 0 && errno == EAGAIN) |
1018 if(len < 0 && errno == EAGAIN) |
| 1019 return; |
1019 return; |
| 1020 else if(len <= 0) { |
1020 else if(len <= 0) { |
| 1021 gaim_debug_warning("socks5 proxy", "or not...\n"); |
1021 gaim_debug_warning("socks5 proxy", "or not...\n"); |
| 1022 gaim_proxy_connect_info_disconnect(connect_info); |
1022 gaim_proxy_connect_data_disconnect(connect_data); |
| 1023 try_connect(connect_info); |
1023 try_connect(connect_data); |
| 1024 return; |
1024 return; |
| 1025 } |
1025 } |
| 1026 connect_info->read_len += len; |
1026 connect_data->read_len += len; |
| 1027 |
1027 |
| 1028 if(connect_info->read_len < 4) |
1028 if(connect_data->read_len < 4) |
| 1029 return; |
1029 return; |
| 1030 |
1030 |
| 1031 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { |
1031 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { |
| 1032 if ((buf[0] == 0x05) && (buf[1] < 0x09)) |
1032 if ((buf[0] == 0x05) && (buf[1] < 0x09)) |
| 1033 gaim_debug_error("socks5 proxy", socks5errors[buf[1]]); |
1033 gaim_debug_error("socks5 proxy", socks5errors[buf[1]]); |
| 1034 else |
1034 else |
| 1035 gaim_debug_error("socks5 proxy", "Bad data.\n"); |
1035 gaim_debug_error("socks5 proxy", "Bad data.\n"); |
| 1036 gaim_proxy_connect_info_disconnect(connect_info); |
1036 gaim_proxy_connect_data_disconnect(connect_data); |
| 1037 try_connect(connect_info); |
1037 try_connect(connect_data); |
| 1038 return; |
1038 return; |
| 1039 } |
1039 } |
| 1040 |
1040 |
| 1041 /* Skip past BND.ADDR */ |
1041 /* Skip past BND.ADDR */ |
| 1042 switch(buf[3]) { |
1042 switch(buf[3]) { |
| 1043 case 0x01: /* the address is a version-4 IP address, with a length of 4 octets */ |
1043 case 0x01: /* the address is a version-4 IP address, with a length of 4 octets */ |
| 1044 if(connect_info->read_len < 4 + 4) |
1044 if(connect_data->read_len < 4 + 4) |
| 1045 return; |
1045 return; |
| 1046 buf += 4 + 4; |
1046 buf += 4 + 4; |
| 1047 break; |
1047 break; |
| 1048 case 0x03: /* the address field contains a fully-qualified domain name. The first |
1048 case 0x03: /* the address field contains a fully-qualified domain name. The first |
| 1049 octet of the address field contains the number of octets of name that |
1049 octet of the address field contains the number of octets of name that |
| 1050 follow, there is no terminating NUL octet. */ |
1050 follow, there is no terminating NUL octet. */ |
| 1051 if(connect_info->read_len < 4 + 1) |
1051 if(connect_data->read_len < 4 + 1) |
| 1052 return; |
1052 return; |
| 1053 buf += 4 + 1; |
1053 buf += 4 + 1; |
| 1054 if(connect_info->read_len < 4 + 1 + buf[0]) |
1054 if(connect_data->read_len < 4 + 1 + buf[0]) |
| 1055 return; |
1055 return; |
| 1056 buf += buf[0]; |
1056 buf += buf[0]; |
| 1057 break; |
1057 break; |
| 1058 case 0x04: /* the address is a version-6 IP address, with a length of 16 octets */ |
1058 case 0x04: /* the address is a version-6 IP address, with a length of 16 octets */ |
| 1059 if(connect_info->read_len < 4 + 16) |
1059 if(connect_data->read_len < 4 + 16) |
| 1060 return; |
1060 return; |
| 1061 buf += 4 + 16; |
1061 buf += 4 + 16; |
| 1062 break; |
1062 break; |
| 1063 } |
1063 } |
| 1064 |
1064 |
| 1065 if(connect_info->read_len < (buf - connect_info->read_buffer) + 2) |
1065 if(connect_data->read_len < (buf - connect_data->read_buffer) + 2) |
| 1066 return; |
1066 return; |
| 1067 |
1067 |
| 1068 /* Skip past BND.PORT */ |
1068 /* Skip past BND.PORT */ |
| 1069 buf += 2; |
1069 buf += 2; |
| 1070 |
1070 |
| 1071 gaim_proxy_connect_info_connected(connect_info); |
1071 gaim_proxy_connect_data_connected(connect_data); |
| 1072 } |
1072 } |
| 1073 |
1073 |
| 1074 static void |
1074 static void |
| 1075 s5_sendconnect(gpointer data, int source) |
1075 s5_sendconnect(gpointer data, int source) |
| 1076 { |
1076 { |
| 1077 GaimProxyConnectInfo *connect_info = data; |
1077 GaimProxyConnectData *connect_data = data; |
| 1078 int hlen = strlen(connect_info->host); |
1078 int hlen = strlen(connect_data->host); |
| 1079 connect_info->write_buf_len = 5 + hlen + 2; |
1079 connect_data->write_buf_len = 5 + hlen + 2; |
| 1080 connect_info->write_buffer = g_malloc(connect_info->write_buf_len); |
1080 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); |
| 1081 connect_info->written_len = 0; |
1081 connect_data->written_len = 0; |
| 1082 |
1082 |
| 1083 connect_info->write_buffer[0] = 0x05; |
1083 connect_data->write_buffer[0] = 0x05; |
| 1084 connect_info->write_buffer[1] = 0x01; /* CONNECT */ |
1084 connect_data->write_buffer[1] = 0x01; /* CONNECT */ |
| 1085 connect_info->write_buffer[2] = 0x00; /* reserved */ |
1085 connect_data->write_buffer[2] = 0x00; /* reserved */ |
| 1086 connect_info->write_buffer[3] = 0x03; /* address type -- host name */ |
1086 connect_data->write_buffer[3] = 0x03; /* address type -- host name */ |
| 1087 connect_info->write_buffer[4] = hlen; |
1087 connect_data->write_buffer[4] = hlen; |
| 1088 memcpy(connect_info->write_buffer + 5, connect_info->host, hlen); |
1088 memcpy(connect_data->write_buffer + 5, connect_data->host, hlen); |
| 1089 connect_info->write_buffer[5 + hlen] = connect_info->port >> 8; |
1089 connect_data->write_buffer[5 + hlen] = connect_data->port >> 8; |
| 1090 connect_info->write_buffer[5 + hlen + 1] = connect_info->port & 0xff; |
1090 connect_data->write_buffer[5 + hlen + 1] = connect_data->port & 0xff; |
| 1091 |
1091 |
| 1092 connect_info->read_cb = s5_canread_again; |
1092 connect_data->read_cb = s5_canread_again; |
| 1093 |
1093 |
| 1094 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_info); |
1094 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 1095 proxy_do_write(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
1095 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1096 } |
1096 } |
| 1097 |
1097 |
| 1098 static void |
1098 static void |
| 1099 s5_readauth(gpointer data, gint source, GaimInputCondition cond) |
1099 s5_readauth(gpointer data, gint source, GaimInputCondition cond) |
| 1100 { |
1100 { |
| 1101 GaimProxyConnectInfo *connect_info = data; |
1101 GaimProxyConnectData *connect_data = data; |
| 1102 int len; |
1102 int len; |
| 1103 |
1103 |
| 1104 if (connect_info->read_buffer == NULL) { |
1104 if (connect_data->read_buffer == NULL) { |
| 1105 connect_info->read_buf_len = 2; |
1105 connect_data->read_buf_len = 2; |
| 1106 connect_info->read_buffer = g_malloc(connect_info->read_buf_len); |
1106 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
| 1107 connect_info->read_len = 0; |
1107 connect_data->read_len = 0; |
| 1108 } |
1108 } |
| 1109 |
1109 |
| 1110 gaim_debug_info("socks5 proxy", "Got auth response.\n"); |
1110 gaim_debug_info("socks5 proxy", "Got auth response.\n"); |
| 1111 |
1111 |
| 1112 len = read(connect_info->fd, connect_info->read_buffer + connect_info->read_len, |
1112 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, |
| 1113 connect_info->read_buf_len - connect_info->read_len); |
1113 connect_data->read_buf_len - connect_data->read_len); |
| 1114 if(len < 0 && errno == EAGAIN) |
1114 if(len < 0 && errno == EAGAIN) |
| 1115 return; |
1115 return; |
| 1116 else if(len <= 0) { |
1116 else if(len <= 0) { |
| 1117 gaim_proxy_connect_info_disconnect(connect_info); |
1117 gaim_proxy_connect_data_disconnect(connect_data); |
| 1118 try_connect(connect_info); |
1118 try_connect(connect_data); |
| 1119 return; |
1119 return; |
| 1120 } |
1120 } |
| 1121 connect_info->read_len += len; |
1121 connect_data->read_len += len; |
| 1122 |
1122 |
| 1123 if (connect_info->read_len < 2) |
1123 if (connect_data->read_len < 2) |
| 1124 return; |
1124 return; |
| 1125 |
1125 |
| 1126 gaim_input_remove(connect_info->inpa); |
1126 gaim_input_remove(connect_data->inpa); |
| 1127 connect_info->inpa = 0; |
1127 connect_data->inpa = 0; |
| 1128 |
1128 |
| 1129 if ((connect_info->read_buffer[0] != 0x01) || (connect_info->read_buffer[1] != 0x00)) { |
1129 if ((connect_data->read_buffer[0] != 0x01) || (connect_data->read_buffer[1] != 0x00)) { |
| 1130 gaim_proxy_connect_info_disconnect(connect_info); |
1130 gaim_proxy_connect_data_disconnect(connect_data); |
| 1131 try_connect(connect_info); |
1131 try_connect(connect_data); |
| 1132 return; |
1132 return; |
| 1133 } |
1133 } |
| 1134 |
1134 |
| 1135 g_free(connect_info->read_buffer); |
1135 g_free(connect_data->read_buffer); |
| 1136 connect_info->read_buffer = NULL; |
1136 connect_data->read_buffer = NULL; |
| 1137 |
1137 |
| 1138 s5_sendconnect(connect_info, connect_info->fd); |
1138 s5_sendconnect(connect_data, connect_data->fd); |
| 1139 } |
1139 } |
| 1140 |
1140 |
| 1141 static void |
1141 static void |
| 1142 hmacmd5_chap(const unsigned char * challenge, int challen, const char * passwd, unsigned char * response) |
1142 hmacmd5_chap(const unsigned char * challenge, int challen, const char * passwd, unsigned char * response) |
| 1143 { |
1143 { |
| 1184 |
1184 |
| 1185 static void |
1185 static void |
| 1186 s5_readchap(gpointer data, gint source, GaimInputCondition cond) |
1186 s5_readchap(gpointer data, gint source, GaimInputCondition cond) |
| 1187 { |
1187 { |
| 1188 guchar *cmdbuf, *buf; |
1188 guchar *cmdbuf, *buf; |
| 1189 GaimProxyConnectInfo *connect_info = data; |
1189 GaimProxyConnectData *connect_data = data; |
| 1190 int len, navas, currentav; |
1190 int len, navas, currentav; |
| 1191 |
1191 |
| 1192 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got CHAP response.\n"); |
1192 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got CHAP response.\n"); |
| 1193 |
1193 |
| 1194 if (connect_info->read_buffer == NULL) { |
1194 if (connect_data->read_buffer == NULL) { |
| 1195 connect_info->read_buf_len = 20; |
1195 connect_data->read_buf_len = 20; |
| 1196 connect_info->read_buffer = g_malloc(connect_info->read_buf_len); |
1196 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
| 1197 connect_info->read_len = 0; |
1197 connect_data->read_len = 0; |
| 1198 } |
1198 } |
| 1199 |
1199 |
| 1200 len = read(connect_info->fd, connect_info->read_buffer + connect_info->read_len, |
1200 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, |
| 1201 connect_info->read_buf_len - connect_info->read_len); |
1201 connect_data->read_buf_len - connect_data->read_len); |
| 1202 |
1202 |
| 1203 if(len < 0 && errno == EAGAIN) |
1203 if(len < 0 && errno == EAGAIN) |
| 1204 return; |
1204 return; |
| 1205 else if(len <= 0) { |
1205 else if(len <= 0) { |
| 1206 gaim_proxy_connect_info_disconnect(connect_info); |
1206 gaim_proxy_connect_data_disconnect(connect_data); |
| 1207 try_connect(connect_info); |
1207 try_connect(connect_data); |
| 1208 return; |
1208 return; |
| 1209 } |
1209 } |
| 1210 connect_info->read_len += len; |
1210 connect_data->read_len += len; |
| 1211 |
1211 |
| 1212 if (connect_info->read_len < 2) |
1212 if (connect_data->read_len < 2) |
| 1213 return; |
1213 return; |
| 1214 |
1214 |
| 1215 cmdbuf = connect_info->read_buffer; |
1215 cmdbuf = connect_data->read_buffer; |
| 1216 |
1216 |
| 1217 if (*cmdbuf != 0x01) { |
1217 if (*cmdbuf != 0x01) { |
| 1218 gaim_proxy_connect_info_disconnect(connect_info); |
1218 gaim_proxy_connect_data_disconnect(connect_data); |
| 1219 try_connect(connect_info); |
1219 try_connect(connect_data); |
| 1220 return; |
1220 return; |
| 1221 } |
1221 } |
| 1222 cmdbuf++; |
1222 cmdbuf++; |
| 1223 |
1223 |
| 1224 navas = *cmdbuf; |
1224 navas = *cmdbuf; |
| 1225 cmdbuf++; |
1225 cmdbuf++; |
| 1226 |
1226 |
| 1227 for (currentav = 0; currentav < navas; currentav++) { |
1227 for (currentav = 0; currentav < navas; currentav++) { |
| 1228 if (connect_info->read_len - (cmdbuf - connect_info->read_buffer) < 2) |
1228 if (connect_data->read_len - (cmdbuf - connect_data->read_buffer) < 2) |
| 1229 return; |
1229 return; |
| 1230 if (connect_info->read_len - (cmdbuf - connect_info->read_buffer) < cmdbuf[1]) |
1230 if (connect_data->read_len - (cmdbuf - connect_data->read_buffer) < cmdbuf[1]) |
| 1231 return; |
1231 return; |
| 1232 buf = cmdbuf + 2; |
1232 buf = cmdbuf + 2; |
| 1233 switch (cmdbuf[0]) { |
1233 switch (cmdbuf[0]) { |
| 1234 case 0x00: |
1234 case 0x00: |
| 1235 /* Did auth work? */ |
1235 /* Did auth work? */ |
| 1236 if (buf[0] == 0x00) { |
1236 if (buf[0] == 0x00) { |
| 1237 gaim_input_remove(connect_info->inpa); |
1237 gaim_input_remove(connect_data->inpa); |
| 1238 connect_info->inpa = 0; |
1238 connect_data->inpa = 0; |
| 1239 g_free(connect_info->read_buffer); |
1239 g_free(connect_data->read_buffer); |
| 1240 connect_info->read_buffer = NULL; |
1240 connect_data->read_buffer = NULL; |
| 1241 /* Success */ |
1241 /* Success */ |
| 1242 s5_sendconnect(connect_info, connect_info->fd); |
1242 s5_sendconnect(connect_data, connect_data->fd); |
| 1243 return; |
1243 return; |
| 1244 } else { |
1244 } else { |
| 1245 /* Failure */ |
1245 /* Failure */ |
| 1246 gaim_debug_warning("proxy", |
1246 gaim_debug_warning("proxy", |
| 1247 "socks5 CHAP authentication " |
1247 "socks5 CHAP authentication " |
| 1248 "failed. Disconnecting..."); |
1248 "failed. Disconnecting..."); |
| 1249 gaim_proxy_connect_info_disconnect(connect_info); |
1249 gaim_proxy_connect_data_disconnect(connect_data); |
| 1250 try_connect(connect_info); |
1250 try_connect(connect_data); |
| 1251 return; |
1251 return; |
| 1252 } |
1252 } |
| 1253 break; |
1253 break; |
| 1254 case 0x03: |
1254 case 0x03: |
| 1255 /* Server wants our credentials */ |
1255 /* Server wants our credentials */ |
| 1256 |
1256 |
| 1257 connect_info->write_buf_len = 16 + 4; |
1257 connect_data->write_buf_len = 16 + 4; |
| 1258 connect_info->write_buffer = g_malloc(connect_info->write_buf_len); |
1258 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); |
| 1259 connect_info->written_len = 0; |
1259 connect_data->written_len = 0; |
| 1260 |
1260 |
| 1261 hmacmd5_chap(buf, cmdbuf[1], |
1261 hmacmd5_chap(buf, cmdbuf[1], |
| 1262 gaim_proxy_info_get_password(connect_info->gpi), |
1262 gaim_proxy_info_get_password(connect_data->gpi), |
| 1263 connect_info->write_buffer + 4); |
1263 connect_data->write_buffer + 4); |
| 1264 connect_info->write_buffer[0] = 0x01; |
1264 connect_data->write_buffer[0] = 0x01; |
| 1265 connect_info->write_buffer[1] = 0x01; |
1265 connect_data->write_buffer[1] = 0x01; |
| 1266 connect_info->write_buffer[2] = 0x04; |
1266 connect_data->write_buffer[2] = 0x04; |
| 1267 connect_info->write_buffer[3] = 0x10; |
1267 connect_data->write_buffer[3] = 0x10; |
| 1268 |
1268 |
| 1269 gaim_input_remove(connect_info->inpa); |
1269 gaim_input_remove(connect_data->inpa); |
| 1270 g_free(connect_info->read_buffer); |
1270 g_free(connect_data->read_buffer); |
| 1271 connect_info->read_buffer = NULL; |
1271 connect_data->read_buffer = NULL; |
| 1272 |
1272 |
| 1273 connect_info->read_cb = s5_readchap; |
1273 connect_data->read_cb = s5_readchap; |
| 1274 |
1274 |
| 1275 connect_info->inpa = gaim_input_add(connect_info->fd, |
1275 connect_data->inpa = gaim_input_add(connect_data->fd, |
| 1276 GAIM_INPUT_WRITE, proxy_do_write, connect_info); |
1276 GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 1277 |
1277 |
| 1278 proxy_do_write(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
1278 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1279 break; |
1279 break; |
| 1280 case 0x11: |
1280 case 0x11: |
| 1281 /* Server wants to select an algorithm */ |
1281 /* Server wants to select an algorithm */ |
| 1282 if (buf[0] != 0x85) { |
1282 if (buf[0] != 0x85) { |
| 1283 /* Only currently support HMAC-MD5 */ |
1283 /* Only currently support HMAC-MD5 */ |
| 1301 } |
1301 } |
| 1302 |
1302 |
| 1303 static void |
1303 static void |
| 1304 s5_canread(gpointer data, gint source, GaimInputCondition cond) |
1304 s5_canread(gpointer data, gint source, GaimInputCondition cond) |
| 1305 { |
1305 { |
| 1306 GaimProxyConnectInfo *connect_info = data; |
1306 GaimProxyConnectData *connect_data = data; |
| 1307 int len; |
1307 int len; |
| 1308 |
1308 |
| 1309 if (connect_info->read_buffer == NULL) { |
1309 if (connect_data->read_buffer == NULL) { |
| 1310 connect_info->read_buf_len = 2; |
1310 connect_data->read_buf_len = 2; |
| 1311 connect_info->read_buffer = g_malloc(connect_info->read_buf_len); |
1311 connect_data->read_buffer = g_malloc(connect_data->read_buf_len); |
| 1312 connect_info->read_len = 0; |
1312 connect_data->read_len = 0; |
| 1313 } |
1313 } |
| 1314 |
1314 |
| 1315 gaim_debug_info("socks5 proxy", "Able to read.\n"); |
1315 gaim_debug_info("socks5 proxy", "Able to read.\n"); |
| 1316 |
1316 |
| 1317 len = read(connect_info->fd, connect_info->read_buffer + connect_info->read_len, |
1317 len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len, |
| 1318 connect_info->read_buf_len - connect_info->read_len); |
1318 connect_data->read_buf_len - connect_data->read_len); |
| 1319 if(len < 0 && errno == EAGAIN) |
1319 if(len < 0 && errno == EAGAIN) |
| 1320 return; |
1320 return; |
| 1321 else if(len <= 0) { |
1321 else if(len <= 0) { |
| 1322 gaim_proxy_connect_info_disconnect(connect_info); |
1322 gaim_proxy_connect_data_disconnect(connect_data); |
| 1323 try_connect(connect_info); |
1323 try_connect(connect_data); |
| 1324 return; |
1324 return; |
| 1325 } |
1325 } |
| 1326 connect_info->read_len += len; |
1326 connect_data->read_len += len; |
| 1327 |
1327 |
| 1328 if (connect_info->read_len < 2) |
1328 if (connect_data->read_len < 2) |
| 1329 return; |
1329 return; |
| 1330 |
1330 |
| 1331 gaim_input_remove(connect_info->inpa); |
1331 gaim_input_remove(connect_data->inpa); |
| 1332 connect_info->inpa = 0; |
1332 connect_data->inpa = 0; |
| 1333 |
1333 |
| 1334 if ((connect_info->read_buffer[0] != 0x05) || (connect_info->read_buffer[1] == 0xff)) { |
1334 if ((connect_data->read_buffer[0] != 0x05) || (connect_data->read_buffer[1] == 0xff)) { |
| 1335 gaim_proxy_connect_info_disconnect(connect_info); |
1335 gaim_proxy_connect_data_disconnect(connect_data); |
| 1336 try_connect(connect_info); |
1336 try_connect(connect_data); |
| 1337 return; |
1337 return; |
| 1338 } |
1338 } |
| 1339 |
1339 |
| 1340 if (connect_info->read_buffer[1] == 0x02) { |
1340 if (connect_data->read_buffer[1] == 0x02) { |
| 1341 gsize i, j; |
1341 gsize i, j; |
| 1342 const char *u, *p; |
1342 const char *u, *p; |
| 1343 |
1343 |
| 1344 u = gaim_proxy_info_get_username(connect_info->gpi); |
1344 u = gaim_proxy_info_get_username(connect_data->gpi); |
| 1345 p = gaim_proxy_info_get_password(connect_info->gpi); |
1345 p = gaim_proxy_info_get_password(connect_data->gpi); |
| 1346 |
1346 |
| 1347 i = (u == NULL) ? 0 : strlen(u); |
1347 i = (u == NULL) ? 0 : strlen(u); |
| 1348 j = (p == NULL) ? 0 : strlen(p); |
1348 j = (p == NULL) ? 0 : strlen(p); |
| 1349 |
1349 |
| 1350 connect_info->write_buf_len = 1 + 1 + i + 1 + j; |
1350 connect_data->write_buf_len = 1 + 1 + i + 1 + j; |
| 1351 connect_info->write_buffer = g_malloc(connect_info->write_buf_len); |
1351 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); |
| 1352 connect_info->written_len = 0; |
1352 connect_data->written_len = 0; |
| 1353 |
1353 |
| 1354 connect_info->write_buffer[0] = 0x01; /* version 1 */ |
1354 connect_data->write_buffer[0] = 0x01; /* version 1 */ |
| 1355 connect_info->write_buffer[1] = i; |
1355 connect_data->write_buffer[1] = i; |
| 1356 if (u != NULL) |
1356 if (u != NULL) |
| 1357 memcpy(connect_info->write_buffer + 2, u, i); |
1357 memcpy(connect_data->write_buffer + 2, u, i); |
| 1358 connect_info->write_buffer[2 + i] = j; |
1358 connect_data->write_buffer[2 + i] = j; |
| 1359 if (p != NULL) |
1359 if (p != NULL) |
| 1360 memcpy(connect_info->write_buffer + 2 + i + 1, p, j); |
1360 memcpy(connect_data->write_buffer + 2 + i + 1, p, j); |
| 1361 |
1361 |
| 1362 g_free(connect_info->read_buffer); |
1362 g_free(connect_data->read_buffer); |
| 1363 connect_info->read_buffer = NULL; |
1363 connect_data->read_buffer = NULL; |
| 1364 |
1364 |
| 1365 connect_info->read_cb = s5_readauth; |
1365 connect_data->read_cb = s5_readauth; |
| 1366 |
1366 |
| 1367 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, |
1367 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, |
| 1368 proxy_do_write, connect_info); |
1368 proxy_do_write, connect_data); |
| 1369 |
1369 |
| 1370 proxy_do_write(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
1370 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1371 |
1371 |
| 1372 return; |
1372 return; |
| 1373 } else if (connect_info->read_buffer[1] == 0x03) { |
1373 } else if (connect_data->read_buffer[1] == 0x03) { |
| 1374 gsize userlen; |
1374 gsize userlen; |
| 1375 userlen = strlen(gaim_proxy_info_get_username(connect_info->gpi)); |
1375 userlen = strlen(gaim_proxy_info_get_username(connect_data->gpi)); |
| 1376 |
1376 |
| 1377 connect_info->write_buf_len = 7 + userlen; |
1377 connect_data->write_buf_len = 7 + userlen; |
| 1378 connect_info->write_buffer = g_malloc(connect_info->write_buf_len); |
1378 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); |
| 1379 connect_info->written_len = 0; |
1379 connect_data->written_len = 0; |
| 1380 |
1380 |
| 1381 connect_info->write_buffer[0] = 0x01; |
1381 connect_data->write_buffer[0] = 0x01; |
| 1382 connect_info->write_buffer[1] = 0x02; |
1382 connect_data->write_buffer[1] = 0x02; |
| 1383 connect_info->write_buffer[2] = 0x11; |
1383 connect_data->write_buffer[2] = 0x11; |
| 1384 connect_info->write_buffer[3] = 0x01; |
1384 connect_data->write_buffer[3] = 0x01; |
| 1385 connect_info->write_buffer[4] = 0x85; |
1385 connect_data->write_buffer[4] = 0x85; |
| 1386 connect_info->write_buffer[5] = 0x02; |
1386 connect_data->write_buffer[5] = 0x02; |
| 1387 connect_info->write_buffer[6] = userlen; |
1387 connect_data->write_buffer[6] = userlen; |
| 1388 memcpy(connect_info->write_buffer + 7, |
1388 memcpy(connect_data->write_buffer + 7, |
| 1389 gaim_proxy_info_get_username(connect_info->gpi), userlen); |
1389 gaim_proxy_info_get_username(connect_data->gpi), userlen); |
| 1390 |
1390 |
| 1391 g_free(connect_info->read_buffer); |
1391 g_free(connect_data->read_buffer); |
| 1392 connect_info->read_buffer = NULL; |
1392 connect_data->read_buffer = NULL; |
| 1393 |
1393 |
| 1394 connect_info->read_cb = s5_readchap; |
1394 connect_data->read_cb = s5_readchap; |
| 1395 |
1395 |
| 1396 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, |
1396 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, |
| 1397 proxy_do_write, connect_info); |
1397 proxy_do_write, connect_data); |
| 1398 |
1398 |
| 1399 proxy_do_write(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
1399 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1400 |
1400 |
| 1401 return; |
1401 return; |
| 1402 } else { |
1402 } else { |
| 1403 g_free(connect_info->read_buffer); |
1403 g_free(connect_data->read_buffer); |
| 1404 connect_info->read_buffer = NULL; |
1404 connect_data->read_buffer = NULL; |
| 1405 |
1405 |
| 1406 s5_sendconnect(connect_info, connect_info->fd); |
1406 s5_sendconnect(connect_data, connect_data->fd); |
| 1407 } |
1407 } |
| 1408 } |
1408 } |
| 1409 |
1409 |
| 1410 static void |
1410 static void |
| 1411 s5_canwrite(gpointer data, gint source, GaimInputCondition cond) |
1411 s5_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 1412 { |
1412 { |
| 1413 unsigned char buf[5]; |
1413 unsigned char buf[5]; |
| 1414 int i; |
1414 int i; |
| 1415 GaimProxyConnectInfo *connect_info = data; |
1415 GaimProxyConnectData *connect_data = data; |
| 1416 socklen_t len; |
1416 socklen_t len; |
| 1417 int error = ETIMEDOUT; |
1417 int error = ETIMEDOUT; |
| 1418 |
1418 |
| 1419 gaim_debug_info("socks5 proxy", "Connected.\n"); |
1419 gaim_debug_info("socks5 proxy", "Connected.\n"); |
| 1420 |
1420 |
| 1421 if (connect_info->inpa > 0) |
1421 if (connect_data->inpa > 0) |
| 1422 { |
1422 { |
| 1423 gaim_input_remove(connect_info->inpa); |
1423 gaim_input_remove(connect_data->inpa); |
| 1424 connect_info->inpa = 0; |
1424 connect_data->inpa = 0; |
| 1425 } |
1425 } |
| 1426 |
1426 |
| 1427 len = sizeof(error); |
1427 len = sizeof(error); |
| 1428 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
1428 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 1429 gaim_proxy_connect_info_disconnect(connect_info); |
1429 gaim_proxy_connect_data_disconnect(connect_data); |
| 1430 try_connect(connect_info); |
1430 try_connect(connect_data); |
| 1431 return; |
1431 return; |
| 1432 } |
1432 } |
| 1433 |
1433 |
| 1434 i = 0; |
1434 i = 0; |
| 1435 buf[0] = 0x05; /* SOCKS version 5 */ |
1435 buf[0] = 0x05; /* SOCKS version 5 */ |
| 1436 |
1436 |
| 1437 if (gaim_proxy_info_get_username(connect_info->gpi) != NULL) { |
1437 if (gaim_proxy_info_get_username(connect_data->gpi) != NULL) { |
| 1438 buf[1] = 0x03; /* three methods */ |
1438 buf[1] = 0x03; /* three methods */ |
| 1439 buf[2] = 0x00; /* no authentication */ |
1439 buf[2] = 0x00; /* no authentication */ |
| 1440 buf[3] = 0x03; /* CHAP authentication */ |
1440 buf[3] = 0x03; /* CHAP authentication */ |
| 1441 buf[4] = 0x02; /* username/password authentication */ |
1441 buf[4] = 0x02; /* username/password authentication */ |
| 1442 i = 5; |
1442 i = 5; |
| 1445 buf[1] = 0x01; |
1445 buf[1] = 0x01; |
| 1446 buf[2] = 0x00; |
1446 buf[2] = 0x00; |
| 1447 i = 3; |
1447 i = 3; |
| 1448 } |
1448 } |
| 1449 |
1449 |
| 1450 connect_info->write_buf_len = i; |
1450 connect_data->write_buf_len = i; |
| 1451 connect_info->write_buffer = g_malloc(connect_info->write_buf_len); |
1451 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); |
| 1452 memcpy(connect_info->write_buffer, buf, i); |
1452 memcpy(connect_data->write_buffer, buf, i); |
| 1453 |
1453 |
| 1454 connect_info->read_cb = s5_canread; |
1454 connect_data->read_cb = s5_canread; |
| 1455 |
1455 |
| 1456 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_info); |
1456 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, proxy_do_write, connect_data); |
| 1457 proxy_do_write(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
1457 proxy_do_write(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1458 } |
1458 } |
| 1459 |
1459 |
| 1460 static int |
1460 static int |
| 1461 proxy_connect_socks5(GaimProxyConnectInfo *connect_info, struct sockaddr *addr, socklen_t addrlen) |
1461 proxy_connect_socks5(GaimProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) |
| 1462 { |
1462 { |
| 1463 gaim_debug_info("socks5 proxy", |
1463 gaim_debug_info("socks5 proxy", |
| 1464 "Connecting to %s:%d via %s:%d using SOCKS5\n", |
1464 "Connecting to %s:%d via %s:%d using SOCKS5\n", |
| 1465 connect_info->host, connect_info->port, |
1465 connect_data->host, connect_data->port, |
| 1466 gaim_proxy_info_get_host(connect_info->gpi), |
1466 gaim_proxy_info_get_host(connect_data->gpi), |
| 1467 gaim_proxy_info_get_port(connect_info->gpi)); |
1467 gaim_proxy_info_get_port(connect_data->gpi)); |
| 1468 |
1468 |
| 1469 connect_info->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
1469 connect_data->fd = socket(addr->sa_family, SOCK_STREAM, 0); |
| 1470 if (connect_info->fd < 0) |
1470 if (connect_data->fd < 0) |
| 1471 return -1; |
1471 return -1; |
| 1472 |
1472 |
| 1473 fcntl(connect_info->fd, F_SETFL, O_NONBLOCK); |
1473 fcntl(connect_data->fd, F_SETFL, O_NONBLOCK); |
| 1474 #ifndef _WIN32 |
1474 #ifndef _WIN32 |
| 1475 fcntl(connect_info->fd, F_SETFD, FD_CLOEXEC); |
1475 fcntl(connect_data->fd, F_SETFD, FD_CLOEXEC); |
| 1476 #endif |
1476 #endif |
| 1477 |
1477 |
| 1478 if (connect(connect_info->fd, addr, addrlen) != 0) |
1478 if (connect(connect_data->fd, addr, addrlen) != 0) |
| 1479 { |
1479 { |
| 1480 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
1480 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 1481 gaim_debug_info("socks5 proxy", "Connection in progress\n"); |
1481 gaim_debug_info("socks5 proxy", "Connection in progress\n"); |
| 1482 connect_info->inpa = gaim_input_add(connect_info->fd, GAIM_INPUT_WRITE, s5_canwrite, connect_info); |
1482 connect_data->inpa = gaim_input_add(connect_data->fd, GAIM_INPUT_WRITE, s5_canwrite, connect_data); |
| 1483 } |
1483 } |
| 1484 else { |
1484 else { |
| 1485 close(connect_info->fd); |
1485 close(connect_data->fd); |
| 1486 connect_info->fd = -1; |
1486 connect_data->fd = -1; |
| 1487 return -1; |
1487 return -1; |
| 1488 } |
1488 } |
| 1489 } |
1489 } |
| 1490 else { |
1490 else { |
| 1491 socklen_t len; |
1491 socklen_t len; |
| 1493 |
1493 |
| 1494 gaim_debug_info("socks5 proxy", "Connected immediately.\n"); |
1494 gaim_debug_info("socks5 proxy", "Connected immediately.\n"); |
| 1495 |
1495 |
| 1496 len = sizeof(error); |
1496 len = sizeof(error); |
| 1497 |
1497 |
| 1498 if (getsockopt(connect_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
1498 if (getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) |
| 1499 { |
1499 { |
| 1500 close(connect_info->fd); |
1500 close(connect_data->fd); |
| 1501 connect_info->fd = -1; |
1501 connect_data->fd = -1; |
| 1502 return -1; |
1502 return -1; |
| 1503 } |
1503 } |
| 1504 |
1504 |
| 1505 s5_canwrite(connect_info, connect_info->fd, GAIM_INPUT_WRITE); |
1505 s5_canwrite(connect_data, connect_data->fd, GAIM_INPUT_WRITE); |
| 1506 } |
1506 } |
| 1507 |
1507 |
| 1508 return connect_info->fd; |
1508 return connect_data->fd; |
| 1509 } |
1509 } |
| 1510 |
1510 |
| 1511 /** |
1511 /** |
| 1512 * This function iterates through a list of IP addresses and attempts |
1512 * This function iterates through a list of IP addresses and attempts |
| 1513 * to connect to each one. This is called after the hostname is |
1513 * to connect to each one. This is called after the hostname is |
| 1514 * resolved, and if a connection attempt fails. |
1514 * resolved, and if a connection attempt fails. |
| 1515 */ |
1515 */ |
| 1516 static void try_connect(GaimProxyConnectInfo *connect_info) |
1516 static void try_connect(GaimProxyConnectData *connect_data) |
| 1517 { |
1517 { |
| 1518 size_t addrlen; |
1518 size_t addrlen; |
| 1519 struct sockaddr *addr; |
1519 struct sockaddr *addr; |
| 1520 int ret = -1; |
1520 int ret = -1; |
| 1521 |
1521 |
| 1522 if (connect_info->hosts == NULL) |
1522 if (connect_data->hosts == NULL) |
| 1523 { |
1523 { |
| 1524 gaim_proxy_connect_info_error(connect_info, _("Could not resolve host name")); |
1524 gaim_proxy_connect_data_error(connect_data, _("Could not resolve host name")); |
| 1525 return; |
1525 return; |
| 1526 } |
1526 } |
| 1527 |
1527 |
| 1528 while (connect_info->hosts) |
1528 while (connect_data->hosts) |
| 1529 { |
1529 { |
| 1530 addrlen = GPOINTER_TO_INT(connect_info->hosts->data); |
1530 addrlen = GPOINTER_TO_INT(connect_data->hosts->data); |
| 1531 connect_info->hosts = g_slist_remove(connect_info->hosts, connect_info->hosts->data); |
1531 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 1532 addr = connect_info->hosts->data; |
1532 addr = connect_data->hosts->data; |
| 1533 connect_info->hosts = g_slist_remove(connect_info->hosts, connect_info->hosts->data); |
1533 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); |
| 1534 |
1534 |
| 1535 switch (gaim_proxy_info_get_type(connect_info->gpi)) { |
1535 switch (gaim_proxy_info_get_type(connect_data->gpi)) { |
| 1536 case GAIM_PROXY_NONE: |
1536 case GAIM_PROXY_NONE: |
| 1537 ret = proxy_connect_none(connect_info, addr, addrlen); |
1537 ret = proxy_connect_none(connect_data, addr, addrlen); |
| 1538 break; |
1538 break; |
| 1539 |
1539 |
| 1540 case GAIM_PROXY_HTTP: |
1540 case GAIM_PROXY_HTTP: |
| 1541 ret = proxy_connect_http(connect_info, addr, addrlen); |
1541 ret = proxy_connect_http(connect_data, addr, addrlen); |
| 1542 break; |
1542 break; |
| 1543 |
1543 |
| 1544 case GAIM_PROXY_SOCKS4: |
1544 case GAIM_PROXY_SOCKS4: |
| 1545 ret = proxy_connect_socks4(connect_info, addr, addrlen); |
1545 ret = proxy_connect_socks4(connect_data, addr, addrlen); |
| 1546 break; |
1546 break; |
| 1547 |
1547 |
| 1548 case GAIM_PROXY_SOCKS5: |
1548 case GAIM_PROXY_SOCKS5: |
| 1549 ret = proxy_connect_socks5(connect_info, addr, addrlen); |
1549 ret = proxy_connect_socks5(connect_data, addr, addrlen); |
| 1550 break; |
1550 break; |
| 1551 |
1551 |
| 1552 case GAIM_PROXY_USE_ENVVAR: |
1552 case GAIM_PROXY_USE_ENVVAR: |
| 1553 ret = proxy_connect_http(connect_info, addr, addrlen); |
1553 ret = proxy_connect_http(connect_data, addr, addrlen); |
| 1554 break; |
1554 break; |
| 1555 |
1555 |
| 1556 default: |
1556 default: |
| 1557 break; |
1557 break; |
| 1558 } |
1558 } |
| 1655 } |
1655 } |
| 1656 |
1656 |
| 1657 return gpi; |
1657 return gpi; |
| 1658 } |
1658 } |
| 1659 |
1659 |
| 1660 GaimProxyConnectInfo * |
1660 GaimProxyConnectData * |
| 1661 gaim_proxy_connect(GaimAccount *account, const char *host, int port, |
1661 gaim_proxy_connect(GaimAccount *account, const char *host, int port, |
| 1662 GaimProxyConnectFunction connect_cb, gpointer data) |
1662 GaimProxyConnectFunction connect_cb, gpointer data) |
| 1663 { |
1663 { |
| 1664 const char *connecthost = host; |
1664 const char *connecthost = host; |
| 1665 int connectport = port; |
1665 int connectport = port; |
| 1666 GaimProxyConnectInfo *connect_info; |
1666 GaimProxyConnectData *connect_data; |
| 1667 |
1667 |
| 1668 g_return_val_if_fail(host != NULL, NULL); |
1668 g_return_val_if_fail(host != NULL, NULL); |
| 1669 g_return_val_if_fail(port > 0, NULL); |
1669 g_return_val_if_fail(port > 0, NULL); |
| 1670 g_return_val_if_fail(connect_cb != NULL, NULL); |
1670 g_return_val_if_fail(connect_cb != NULL, NULL); |
| 1671 |
1671 |
| 1672 connect_info = g_new0(GaimProxyConnectInfo, 1); |
1672 connect_data = g_new0(GaimProxyConnectData, 1); |
| 1673 connect_info->fd = -1; |
1673 connect_data->fd = -1; |
| 1674 connect_info->connect_cb = connect_cb; |
1674 connect_data->connect_cb = connect_cb; |
| 1675 connect_info->data = data; |
1675 connect_data->data = data; |
| 1676 connect_info->host = g_strdup(host); |
1676 connect_data->host = g_strdup(host); |
| 1677 connect_info->port = port; |
1677 connect_data->port = port; |
| 1678 connect_info->gpi = gaim_proxy_get_setup(account); |
1678 connect_data->gpi = gaim_proxy_get_setup(account); |
| 1679 |
1679 |
| 1680 if ((gaim_proxy_info_get_type(connect_info->gpi) != GAIM_PROXY_NONE) && |
1680 if ((gaim_proxy_info_get_type(connect_data->gpi) != GAIM_PROXY_NONE) && |
| 1681 (gaim_proxy_info_get_host(connect_info->gpi) == NULL || |
1681 (gaim_proxy_info_get_host(connect_data->gpi) == NULL || |
| 1682 gaim_proxy_info_get_port(connect_info->gpi) <= 0)) { |
1682 gaim_proxy_info_get_port(connect_data->gpi) <= 0)) { |
| 1683 |
1683 |
| 1684 gaim_notify_error(NULL, NULL, _("Invalid proxy settings"), _("Either the host name or port number specified for your given proxy type is invalid.")); |
1684 gaim_notify_error(NULL, NULL, _("Invalid proxy settings"), _("Either the host name or port number specified for your given proxy type is invalid.")); |
| 1685 gaim_proxy_connect_info_destroy(connect_info); |
1685 gaim_proxy_connect_data_destroy(connect_data); |
| 1686 return NULL; |
1686 return NULL; |
| 1687 } |
1687 } |
| 1688 |
1688 |
| 1689 switch (gaim_proxy_info_get_type(connect_info->gpi)) |
1689 switch (gaim_proxy_info_get_type(connect_data->gpi)) |
| 1690 { |
1690 { |
| 1691 case GAIM_PROXY_NONE: |
1691 case GAIM_PROXY_NONE: |
| 1692 break; |
1692 break; |
| 1693 |
1693 |
| 1694 case GAIM_PROXY_HTTP: |
1694 case GAIM_PROXY_HTTP: |
| 1695 case GAIM_PROXY_SOCKS4: |
1695 case GAIM_PROXY_SOCKS4: |
| 1696 case GAIM_PROXY_SOCKS5: |
1696 case GAIM_PROXY_SOCKS5: |
| 1697 case GAIM_PROXY_USE_ENVVAR: |
1697 case GAIM_PROXY_USE_ENVVAR: |
| 1698 connecthost = gaim_proxy_info_get_host(connect_info->gpi); |
1698 connecthost = gaim_proxy_info_get_host(connect_data->gpi); |
| 1699 connectport = gaim_proxy_info_get_port(connect_info->gpi); |
1699 connectport = gaim_proxy_info_get_port(connect_data->gpi); |
| 1700 break; |
1700 break; |
| 1701 |
1701 |
| 1702 default: |
1702 default: |
| 1703 gaim_proxy_connect_info_destroy(connect_info); |
1703 gaim_proxy_connect_data_destroy(connect_data); |
| 1704 return NULL; |
1704 return NULL; |
| 1705 } |
1705 } |
| 1706 |
1706 |
| 1707 connect_info->query_data = gaim_dnsquery_a(connecthost, |
1707 connect_data->query_data = gaim_dnsquery_a(connecthost, |
| 1708 connectport, connection_host_resolved, connect_info); |
1708 connectport, connection_host_resolved, connect_data); |
| 1709 if (connect_info->query_data == NULL) |
1709 if (connect_data->query_data == NULL) |
| 1710 { |
1710 { |
| 1711 gaim_proxy_connect_info_destroy(connect_info); |
1711 gaim_proxy_connect_data_destroy(connect_data); |
| 1712 return NULL; |
1712 return NULL; |
| 1713 } |
1713 } |
| 1714 |
1714 |
| 1715 connect_infos = g_slist_prepend(connect_infos, connect_info); |
1715 connect_datas = g_slist_prepend(connect_datas, connect_data); |
| 1716 |
1716 |
| 1717 return connect_info; |
1717 return connect_data; |
| 1718 } |
1718 } |
| 1719 |
1719 |
| 1720 /* |
1720 /* |
| 1721 * Combine some of this code with gaim_proxy_connect() |
1721 * Combine some of this code with gaim_proxy_connect() |
| 1722 */ |
1722 */ |
| 1723 GaimProxyConnectInfo * |
1723 GaimProxyConnectData * |
| 1724 gaim_proxy_connect_socks5(GaimProxyInfo *gpi, const char *host, int port, |
1724 gaim_proxy_connect_socks5(GaimProxyInfo *gpi, const char *host, int port, |
| 1725 GaimProxyConnectFunction connect_cb, gpointer data) |
1725 GaimProxyConnectFunction connect_cb, gpointer data) |
| 1726 { |
1726 { |
| 1727 GaimProxyConnectInfo *connect_info; |
1727 GaimProxyConnectData *connect_data; |
| 1728 |
1728 |
| 1729 g_return_val_if_fail(host != NULL, NULL); |
1729 g_return_val_if_fail(host != NULL, NULL); |
| 1730 g_return_val_if_fail(port > 0, NULL); |
1730 g_return_val_if_fail(port > 0, NULL); |
| 1731 g_return_val_if_fail(connect_cb != NULL, NULL); |
1731 g_return_val_if_fail(connect_cb != NULL, NULL); |
| 1732 |
1732 |
| 1733 connect_info = g_new0(GaimProxyConnectInfo, 1); |
1733 connect_data = g_new0(GaimProxyConnectData, 1); |
| 1734 connect_info->fd = -1; |
1734 connect_data->fd = -1; |
| 1735 connect_info->connect_cb = connect_cb; |
1735 connect_data->connect_cb = connect_cb; |
| 1736 connect_info->data = data; |
1736 connect_data->data = data; |
| 1737 connect_info->host = g_strdup(host); |
1737 connect_data->host = g_strdup(host); |
| 1738 connect_info->port = port; |
1738 connect_data->port = port; |
| 1739 connect_info->gpi = gpi; |
1739 connect_data->gpi = gpi; |
| 1740 |
1740 |
| 1741 connect_info->query_data = |
1741 connect_data->query_data = |
| 1742 gaim_dnsquery_a(gaim_proxy_info_get_host(gpi), |
1742 gaim_dnsquery_a(gaim_proxy_info_get_host(gpi), |
| 1743 gaim_proxy_info_get_port(gpi), |
1743 gaim_proxy_info_get_port(gpi), |
| 1744 connection_host_resolved, connect_info); |
1744 connection_host_resolved, connect_data); |
| 1745 if (connect_info->query_data == NULL) |
1745 if (connect_data->query_data == NULL) |
| 1746 { |
1746 { |
| 1747 gaim_proxy_connect_info_destroy(connect_info); |
1747 gaim_proxy_connect_data_destroy(connect_data); |
| 1748 return NULL; |
1748 return NULL; |
| 1749 } |
1749 } |
| 1750 |
1750 |
| 1751 connect_infos = g_slist_prepend(connect_infos, connect_info); |
1751 connect_datas = g_slist_prepend(connect_datas, connect_data); |
| 1752 |
1752 |
| 1753 return connect_info; |
1753 return connect_data; |
| 1754 } |
1754 } |
| 1755 |
1755 |
| 1756 void |
1756 void |
| 1757 gaim_proxy_connect_cancel(GaimProxyConnectInfo *connect_info) |
1757 gaim_proxy_connect_cancel(GaimProxyConnectData *connect_data) |
| 1758 { |
1758 { |
| 1759 gaim_proxy_connect_info_destroy(connect_info); |
1759 gaim_proxy_connect_data_destroy(connect_data); |
| 1760 } |
1760 } |
| 1761 |
1761 |
| 1762 static void |
1762 static void |
| 1763 proxy_pref_cb(const char *name, GaimPrefType type, |
1763 proxy_pref_cb(const char *name, GaimPrefType type, |
| 1764 gconstpointer value, gpointer data) |
1764 gconstpointer value, gpointer data) |