Mercurial > pidgin
comparison src/proxy.c @ 5681:46d7ad0dfa26
[gaim-migrate @ 6100]
Rewrote the proxy code. It should now work with the new prefs, and it has a
namespace and API too!
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Tue, 03 Jun 2003 02:00:33 +0000 |
| parents | 86456ec3ca25 |
| children | 059d95c67cda |
comparison
equal
deleted
inserted
replaced
| 5680:71cc0d5376c2 | 5681:46d7ad0dfa26 |
|---|---|
| 1 /* | 1 /** |
| 2 * @file proxy.c Proxy API | |
| 3 * @ingroup core | |
| 4 * | |
| 2 * gaim | 5 * gaim |
| 3 * | 6 * |
| 4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | 7 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> |
| 8 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> | |
| 5 * | 9 * |
| 6 * This program is free software; you can redistribute it and/or modify | 10 * This program is free software; you can redistribute it and/or modify |
| 7 * it under the terms of the GNU General Public License as published by | 11 * it under the terms of the GNU General Public License as published by |
| 8 * the Free Software Foundation; either version 2 of the License, or | 12 * the Free Software Foundation; either version 2 of the License, or |
| 9 * (at your option) any later version. | 13 * (at your option) any later version. |
| 45 | 49 |
| 46 #include <fcntl.h> | 50 #include <fcntl.h> |
| 47 #include <errno.h> | 51 #include <errno.h> |
| 48 #include "gaim.h" | 52 #include "gaim.h" |
| 49 #include "proxy.h" | 53 #include "proxy.h" |
| 54 #include "prefs.h" | |
| 50 | 55 |
| 51 #ifdef _WIN32 | 56 #ifdef _WIN32 |
| 52 #include "win32dep.h" | 57 #include "win32dep.h" |
| 53 #endif | 58 #endif |
| 54 | 59 |
| 55 #define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) | 60 #define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) |
| 56 #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) | 61 #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) |
| 57 | 62 |
| 58 struct gaim_proxy_info global_proxy_info; | 63 static GaimProxyInfo *global_proxy_info = NULL; |
| 64 static gboolean global_proxy_info_from_prefs = FALSE; | |
| 59 | 65 |
| 60 struct PHB { | 66 struct PHB { |
| 61 GaimInputFunction func; | 67 GaimInputFunction func; |
| 62 gpointer data; | 68 gpointer data; |
| 63 char *host; | 69 char *host; |
| 64 int port; | 70 int port; |
| 65 gint inpa; | 71 gint inpa; |
| 66 struct gaim_proxy_info *gpi; | 72 GaimProxyInfo *gpi; |
| 67 GaimAccount *account; | 73 GaimAccount *account; |
| 68 }; | 74 }; |
| 69 | 75 |
| 70 typedef struct _GaimIOClosure { | 76 typedef struct _GaimIOClosure { |
| 71 GaimInputFunction function; | 77 GaimInputFunction function; |
| 72 guint result; | 78 guint result; |
| 73 gpointer data; | 79 gpointer data; |
| 80 | |
| 74 } GaimIOClosure; | 81 } GaimIOClosure; |
| 75 | 82 |
| 83 /************************************************************************** | |
| 84 * Proxy structure API | |
| 85 **************************************************************************/ | |
| 86 GaimProxyInfo * | |
| 87 gaim_proxy_info_new(void) | |
| 88 { | |
| 89 return g_new0(GaimProxyInfo, 1); | |
| 90 } | |
| 91 | |
| 92 void | |
| 93 gaim_proxy_info_destroy(GaimProxyInfo *info) | |
| 94 { | |
| 95 g_return_if_fail(info != NULL); | |
| 96 | |
| 97 if (info->host != NULL) g_free(info->host); | |
| 98 if (info->username != NULL) g_free(info->username); | |
| 99 if (info->password != NULL) g_free(info->password); | |
| 100 | |
| 101 g_free(info); | |
| 102 } | |
| 103 | |
| 104 void | |
| 105 gaim_proxy_info_set_type(GaimProxyInfo *info, GaimProxyType type) | |
| 106 { | |
| 107 g_return_if_fail(info != NULL); | |
| 108 | |
| 109 info->type = type; | |
| 110 } | |
| 111 | |
| 112 void | |
| 113 gaim_proxy_info_set_host(GaimProxyInfo *info, const char *host) | |
| 114 { | |
| 115 g_return_if_fail(info != NULL); | |
| 116 | |
| 117 if (info->host != NULL) | |
| 118 g_free(info->host); | |
| 119 | |
| 120 info->host = (host == NULL ? NULL : g_strdup(host)); | |
| 121 } | |
| 122 | |
| 123 void | |
| 124 gaim_proxy_info_set_port(GaimProxyInfo *info, int port) | |
| 125 { | |
| 126 g_return_if_fail(info != NULL); | |
| 127 | |
| 128 info->port = port; | |
| 129 } | |
| 130 | |
| 131 void | |
| 132 gaim_proxy_info_set_username(GaimProxyInfo *info, const char *username) | |
| 133 { | |
| 134 g_return_if_fail(info != NULL); | |
| 135 | |
| 136 if (info->username != NULL) | |
| 137 g_free(info->username); | |
| 138 | |
| 139 info->username = (username == NULL ? NULL : g_strdup(username)); | |
| 140 } | |
| 141 | |
| 142 void | |
| 143 gaim_proxy_info_set_password(GaimProxyInfo *info, const char *password) | |
| 144 { | |
| 145 g_return_if_fail(info != NULL); | |
| 146 | |
| 147 if (info->password != NULL) | |
| 148 g_free(info->password); | |
| 149 | |
| 150 info->password = (password == NULL ? NULL : g_strdup(password)); | |
| 151 } | |
| 152 | |
| 153 GaimProxyType | |
| 154 gaim_proxy_info_get_type(const GaimProxyInfo *info) | |
| 155 { | |
| 156 g_return_val_if_fail(info != NULL, GAIM_PROXY_NONE); | |
| 157 | |
| 158 return info->type; | |
| 159 } | |
| 160 | |
| 161 const char * | |
| 162 gaim_proxy_info_get_host(const GaimProxyInfo *info) | |
| 163 { | |
| 164 g_return_val_if_fail(info != NULL, NULL); | |
| 165 | |
| 166 return info->host; | |
| 167 } | |
| 168 | |
| 169 int | |
| 170 gaim_proxy_info_get_port(const GaimProxyInfo *info) | |
| 171 { | |
| 172 g_return_val_if_fail(info != NULL, 0); | |
| 173 | |
| 174 return info->port; | |
| 175 } | |
| 176 | |
| 177 const char * | |
| 178 gaim_proxy_info_get_username(const GaimProxyInfo *info) | |
| 179 { | |
| 180 g_return_val_if_fail(info != NULL, NULL); | |
| 181 | |
| 182 return info->username; | |
| 183 } | |
| 184 | |
| 185 const char * | |
| 186 gaim_proxy_info_get_password(const GaimProxyInfo *info) | |
| 187 { | |
| 188 g_return_val_if_fail(info != NULL, NULL); | |
| 189 | |
| 190 return info->password; | |
| 191 } | |
| 192 | |
| 193 /************************************************************************** | |
| 194 * Global Proxy API | |
| 195 **************************************************************************/ | |
| 196 void | |
| 197 gaim_global_proxy_set_from_prefs(gboolean from_prefs) | |
| 198 { | |
| 199 global_proxy_info_from_prefs = from_prefs; | |
| 200 } | |
| 201 | |
| 202 GaimProxyInfo * | |
| 203 gaim_global_proxy_get_info(void) | |
| 204 { | |
| 205 return global_proxy_info; | |
| 206 } | |
| 207 | |
| 208 gboolean | |
| 209 gaim_global_proxy_is_from_prefs(void) | |
| 210 { | |
| 211 return global_proxy_info_from_prefs; | |
| 212 } | |
| 213 | |
| 214 /************************************************************************** | |
| 215 * Proxy API | |
| 216 **************************************************************************/ | |
| 76 static void gaim_io_destroy(gpointer data) | 217 static void gaim_io_destroy(gpointer data) |
| 77 { | 218 { |
| 78 g_free(data); | 219 g_free(data); |
| 79 } | 220 } |
| 80 | 221 |
| 577 g_free(req->addr); | 718 g_free(req->addr); |
| 578 g_free(req); | 719 g_free(req); |
| 579 return FALSE; | 720 return FALSE; |
| 580 } | 721 } |
| 581 | 722 |
| 582 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) | 723 int |
| 724 gaim_gethostbyname_async(const char *hostname, int port, | |
| 725 dns_callback_t callback, gpointer data) | |
| 583 { | 726 { |
| 584 struct sockaddr_in sin; | 727 struct sockaddr_in sin; |
| 585 pending_dns_request_t *req; | 728 pending_dns_request_t *req; |
| 586 | 729 |
| 587 if (!inet_aton(hostname, &sin.sin_addr)) { | 730 if (!inet_aton(hostname, &sin.sin_addr)) { |
| 608 return 0; | 751 return 0; |
| 609 } | 752 } |
| 610 | 753 |
| 611 #endif | 754 #endif |
| 612 | 755 |
| 613 static void no_one_calls(gpointer data, gint source, GaimInputCondition cond) | 756 static void |
| 757 no_one_calls(gpointer data, gint source, GaimInputCondition cond) | |
| 614 { | 758 { |
| 615 struct PHB *phb = data; | 759 struct PHB *phb = data; |
| 616 unsigned int len; | 760 unsigned int len; |
| 617 int error=0; | 761 int error=0; |
| 618 int ret=0; | 762 int ret=0; |
| 624 ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); | 768 ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); |
| 625 if (ret < 0 || error != 0) { | 769 if (ret < 0 || error != 0) { |
| 626 if(ret==0) errno = error; | 770 if(ret==0) errno = error; |
| 627 close(source); | 771 close(source); |
| 628 gaim_input_remove(phb->inpa); | 772 gaim_input_remove(phb->inpa); |
| 629 if(!phb->account || phb->account->gc) | 773 |
| 774 if (phb->account == NULL || | |
| 775 gaim_account_get_connection(phb->account) != NULL) { | |
| 776 | |
| 630 phb->func(phb->data, -1, GAIM_INPUT_READ); | 777 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 778 } | |
| 779 | |
| 631 g_free(phb->host); | 780 g_free(phb->host); |
| 632 g_free(phb); | 781 g_free(phb); |
| 633 | 782 |
| 634 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 783 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 635 "getsockopt SO_ERROR check: %s\n", strerror(errno)); | 784 "getsockopt SO_ERROR check: %s\n", strerror(errno)); |
| 636 return; | 785 return; |
| 637 } | 786 } |
| 787 | |
| 638 fcntl(source, F_SETFL, 0); | 788 fcntl(source, F_SETFL, 0); |
| 639 gaim_input_remove(phb->inpa); | 789 gaim_input_remove(phb->inpa); |
| 640 if(!phb->account || phb->account->gc) | 790 |
| 791 if (phb->account == NULL || | |
| 792 gaim_account_get_connection(phb->account) != NULL) { | |
| 793 | |
| 641 phb->func(phb->data, source, GAIM_INPUT_READ); | 794 phb->func(phb->data, source, GAIM_INPUT_READ); |
| 795 } | |
| 796 | |
| 642 g_free(phb->host); | 797 g_free(phb->host); |
| 643 g_free(phb); | 798 g_free(phb); |
| 644 } | 799 } |
| 645 | 800 |
| 646 static gboolean clean_connect(gpointer data) | 801 static gboolean clean_connect(gpointer data) |
| 647 { | 802 { |
| 648 struct PHB *phb = data; | 803 struct PHB *phb = data; |
| 649 | 804 |
| 650 if(!phb->account || phb->account->gc) | 805 if (phb->account == NULL || |
| 806 gaim_account_get_connection(phb->account) != NULL) { | |
| 807 | |
| 651 phb->func(phb->data, phb->port, GAIM_INPUT_READ); | 808 phb->func(phb->data, phb->port, GAIM_INPUT_READ); |
| 809 } | |
| 810 | |
| 652 g_free(phb->host); | 811 g_free(phb->host); |
| 653 g_free(phb); | 812 g_free(phb); |
| 654 | 813 |
| 655 return FALSE; | 814 return FALSE; |
| 656 } | 815 } |
| 657 | 816 |
| 658 | 817 |
| 659 static int proxy_connect_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | 818 static int |
| 819 proxy_connect_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | |
| 660 { | 820 { |
| 661 int fd = -1; | 821 int fd = -1; |
| 662 | 822 |
| 663 gaim_debug(GAIM_DEBUG_INFO, "proxy", | 823 gaim_debug(GAIM_DEBUG_INFO, "proxy", |
| 664 "Connecting to %s:%d with no proxy\n", phb->host, phb->port); | 824 "Connecting to %s:%d with no proxy\n", phb->host, phb->port); |
| 673 if (connect(fd, (struct sockaddr *)addr, addrlen) < 0) { | 833 if (connect(fd, (struct sockaddr *)addr, addrlen) < 0) { |
| 674 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 834 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 675 gaim_debug(GAIM_DEBUG_WARNING, "proxy", | 835 gaim_debug(GAIM_DEBUG_WARNING, "proxy", |
| 676 "Connect would have blocked.\n"); | 836 "Connect would have blocked.\n"); |
| 677 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb); | 837 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb); |
| 678 } else { | 838 } |
| 839 else { | |
| 679 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 840 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 680 "Connect failed (errno %d)\n", errno); | 841 "Connect failed (errno %d)\n", errno); |
| 681 close(fd); | 842 close(fd); |
| 682 return -1; | 843 return -1; |
| 683 } | 844 } |
| 684 } else { | 845 } |
| 846 else { | |
| 685 unsigned int len; | 847 unsigned int len; |
| 686 int error = ETIMEDOUT; | 848 int error = ETIMEDOUT; |
| 687 gaim_debug(GAIM_DEBUG_MISC, "proxy", "Connect didn't block.\n"); | 849 gaim_debug(GAIM_DEBUG_MISC, "proxy", "Connect didn't block.\n"); |
| 688 len = sizeof(error); | 850 len = sizeof(error); |
| 689 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 851 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 702 } | 864 } |
| 703 | 865 |
| 704 #define HTTP_GOODSTRING "HTTP/1.0 200" | 866 #define HTTP_GOODSTRING "HTTP/1.0 200" |
| 705 #define HTTP_GOODSTRING2 "HTTP/1.1 200" | 867 #define HTTP_GOODSTRING2 "HTTP/1.1 200" |
| 706 | 868 |
| 707 static void http_canread(gpointer data, gint source, GaimInputCondition cond) | 869 static void |
| 870 http_canread(gpointer data, gint source, GaimInputCondition cond) | |
| 708 { | 871 { |
| 709 int nlc = 0; | 872 int nlc = 0; |
| 710 int pos = 0; | 873 int pos = 0; |
| 711 int minor, major, status, error=0; | 874 int minor, major, status, error=0; |
| 712 struct PHB *phb = data; | 875 struct PHB *phb = data; |
| 719 nlc++; | 882 nlc++; |
| 720 else if (inputline[pos - 1] != '\r') | 883 else if (inputline[pos - 1] != '\r') |
| 721 nlc = 0; | 884 nlc = 0; |
| 722 } | 885 } |
| 723 inputline[pos] = '\0'; | 886 inputline[pos] = '\0'; |
| 724 | 887 |
| 725 error = strncmp(inputline, "HTTP/", 5) != 0; | 888 error = strncmp(inputline, "HTTP/", 5) != 0; |
| 726 if(!error) { | 889 if(!error) { |
| 727 p = inputline + 5; | 890 p = inputline + 5; |
| 728 major = strtol(p, &p, 10); | 891 major = strtol(p, &p, 10); |
| 729 error = (major==0) || (*p != '.'); | 892 error = (major==0) || (*p != '.'); |
| 742 if(error) { | 905 if(error) { |
| 743 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 906 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 744 "Unable to parse proxy's response: %s\n", inputline); | 907 "Unable to parse proxy's response: %s\n", inputline); |
| 745 close(source); | 908 close(source); |
| 746 source=-1; | 909 source=-1; |
| 747 } else if(status!=200) { | 910 } |
| 911 else if(status!=200) { | |
| 748 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 912 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 749 "Proxy server replied: (%s)\n", p); | 913 "Proxy server replied: (%s)\n", p); |
| 750 close(source); | 914 close(source); |
| 751 source=-1; | 915 source=-1; |
| 752 } | 916 } |
| 756 g_free(phb->host); | 920 g_free(phb->host); |
| 757 g_free(phb); | 921 g_free(phb); |
| 758 return; | 922 return; |
| 759 } | 923 } |
| 760 | 924 |
| 761 static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) | 925 static void |
| 926 http_canwrite(gpointer data, gint source, GaimInputCondition cond) | |
| 762 { | 927 { |
| 763 char request[8192]; | 928 char request[8192]; |
| 764 int request_len = 0; | 929 int request_len = 0; |
| 765 struct PHB *phb = data; | 930 struct PHB *phb = data; |
| 766 unsigned int len; | 931 unsigned int len; |
| 768 | 933 |
| 769 gaim_debug(GAIM_DEBUG_INFO, "http proxy", "Connected.\n"); | 934 gaim_debug(GAIM_DEBUG_INFO, "http proxy", "Connected.\n"); |
| 770 | 935 |
| 771 if (phb->inpa > 0) | 936 if (phb->inpa > 0) |
| 772 gaim_input_remove(phb->inpa); | 937 gaim_input_remove(phb->inpa); |
| 938 | |
| 773 len = sizeof(error); | 939 len = sizeof(error); |
| 940 | |
| 774 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 941 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 775 close(source); | 942 close(source); |
| 776 if(!phb->account || phb->account->gc) | 943 |
| 944 if (phb->account == NULL || | |
| 945 gaim_account_get_connection(phb->account) != NULL) { | |
| 946 | |
| 777 phb->func(phb->data, -1, GAIM_INPUT_READ); | 947 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 948 } | |
| 949 | |
| 778 g_free(phb->host); | 950 g_free(phb->host); |
| 779 g_free(phb); | 951 g_free(phb); |
| 780 return; | 952 return; |
| 781 } | 953 } |
| 782 request_len = g_snprintf(request, sizeof(request), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, | 954 request_len = g_snprintf(request, sizeof(request), |
| 783 phb->host, phb->port); | 955 "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", |
| 784 | 956 phb->host, phb->port, phb->host, phb->port); |
| 785 if (phb->gpi->proxyuser) { | 957 |
| 958 if (gaim_proxy_info_get_username(phb->gpi) != NULL) { | |
| 786 char *t1, *t2; | 959 char *t1, *t2; |
| 787 t1 = g_strdup_printf("%s:%s", phb->gpi->proxyuser, phb->gpi->proxypass); | 960 t1 = g_strdup_printf("%s:%s", |
| 961 gaim_proxy_info_get_username(phb->gpi), | |
| 962 gaim_proxy_info_get_password(phb->gpi)); | |
| 963 | |
| 788 t2 = tobase64(t1, strlen(t1)); | 964 t2 = tobase64(t1, strlen(t1)); |
| 789 g_free(t1); | 965 g_free(t1); |
| 790 g_return_if_fail(request_len < sizeof(request)); | 966 g_return_if_fail(request_len < sizeof(request)); |
| 791 request_len += g_snprintf(request + request_len, sizeof(request) - request_len, "Proxy-Authorization: Basic %s\r\n", t2); | 967 request_len += g_snprintf(request + request_len, |
| 968 sizeof(request) - request_len, | |
| 969 "Proxy-Authorization: Basic %s\r\n", t2); | |
| 792 g_free(t2); | 970 g_free(t2); |
| 793 } | 971 } |
| 794 | 972 |
| 795 g_return_if_fail(request_len < sizeof(request)); | 973 g_return_if_fail(request_len < sizeof(request)); |
| 796 strcpy(request + request_len, "\r\n"); | 974 strcpy(request + request_len, "\r\n"); |
| 797 request_len += 2; | 975 request_len += 2; |
| 798 | 976 |
| 799 if (write(source, request, request_len) < 0) { | 977 if (write(source, request, request_len) < 0) { |
| 800 close(source); | 978 close(source); |
| 801 if(!phb->account || phb->account->gc) | 979 |
| 980 if (phb->account == NULL || | |
| 981 gaim_account_get_connection(phb->account) != NULL) { | |
| 982 | |
| 802 phb->func(phb->data, -1, GAIM_INPUT_READ); | 983 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 984 } | |
| 985 | |
| 803 g_free(phb->host); | 986 g_free(phb->host); |
| 804 g_free(phb); | 987 g_free(phb); |
| 805 return; | 988 return; |
| 806 } | 989 } |
| 807 | 990 |
| 808 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); | 991 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); |
| 809 } | 992 } |
| 810 | 993 |
| 811 static int proxy_connect_http(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | 994 static int |
| 995 proxy_connect_http(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | |
| 812 { | 996 { |
| 813 int fd = -1; | 997 int fd = -1; |
| 814 | 998 |
| 815 gaim_debug(GAIM_DEBUG_INFO, "http proxy", | 999 gaim_debug(GAIM_DEBUG_INFO, "http proxy", |
| 816 "Connecting to %s:%d via %s:%d using HTTP\n", | 1000 "Connecting to %s:%d via %s:%d using HTTP\n", |
| 817 phb->host, phb->port, phb->gpi->proxyhost, | 1001 phb->host, phb->port, |
| 818 phb->gpi->proxyport); | 1002 gaim_proxy_info_get_host(phb->gpi), |
| 1003 gaim_proxy_info_get_port(phb->gpi)); | |
| 819 | 1004 |
| 820 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 1005 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| 821 return -1; | 1006 return -1; |
| 822 } | 1007 } |
| 823 | 1008 |
| 825 | 1010 |
| 826 if (connect(fd, addr, addrlen) < 0) { | 1011 if (connect(fd, addr, addrlen) < 0) { |
| 827 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 1012 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 828 gaim_debug(GAIM_DEBUG_WARNING, "http proxy", | 1013 gaim_debug(GAIM_DEBUG_WARNING, "http proxy", |
| 829 "Connect would have blocked.\n"); | 1014 "Connect would have blocked.\n"); |
| 830 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb); | 1015 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, |
| 1016 http_canwrite, phb); | |
| 831 } else { | 1017 } else { |
| 832 close(fd); | 1018 close(fd); |
| 833 return -1; | 1019 return -1; |
| 834 } | 1020 } |
| 835 } else { | 1021 } |
| 1022 else { | |
| 836 unsigned int len; | 1023 unsigned int len; |
| 837 int error = ETIMEDOUT; | 1024 int error = ETIMEDOUT; |
| 838 | 1025 |
| 839 gaim_debug(GAIM_DEBUG_MISC, "http proxy", | 1026 gaim_debug(GAIM_DEBUG_MISC, "http proxy", |
| 840 "Connect didn't block.\n"); | 1027 "Connect didn't block.\n"); |
| 849 } | 1036 } |
| 850 | 1037 |
| 851 return fd; | 1038 return fd; |
| 852 } | 1039 } |
| 853 | 1040 |
| 854 static void s4_canread(gpointer data, gint source, GaimInputCondition cond) | 1041 static void |
| 1042 s4_canread(gpointer data, gint source, GaimInputCondition cond) | |
| 855 { | 1043 { |
| 856 unsigned char packet[12]; | 1044 unsigned char packet[12]; |
| 857 struct PHB *phb = data; | 1045 struct PHB *phb = data; |
| 858 | 1046 |
| 859 gaim_input_remove(phb->inpa); | 1047 gaim_input_remove(phb->inpa); |
| 860 | 1048 |
| 861 memset(packet, 0, sizeof(packet)); | 1049 memset(packet, 0, sizeof(packet)); |
| 862 | 1050 |
| 863 if (read(source, packet, 9) >= 4 && packet[1] == 90) { | 1051 if (read(source, packet, 9) >= 4 && packet[1] == 90) { |
| 864 if(!phb->account || phb->account->gc) | 1052 if (phb->account == NULL || |
| 865 phb->func(phb->data, source, GAIM_INPUT_READ); | 1053 gaim_account_get_connection(phb->account) != NULL) { |
| 1054 | |
| 1055 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1056 } | |
| 1057 | |
| 866 g_free(phb->host); | 1058 g_free(phb->host); |
| 867 g_free(phb); | 1059 g_free(phb); |
| 868 return; | 1060 return; |
| 869 } | 1061 } |
| 870 | 1062 |
| 871 close(source); | 1063 close(source); |
| 872 if(!phb->account || phb->account->gc) | 1064 |
| 1065 if (phb->account == NULL || | |
| 1066 gaim_account_get_connection(phb->account) != NULL) { | |
| 1067 | |
| 873 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1068 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1069 } | |
| 1070 | |
| 874 g_free(phb->host); | 1071 g_free(phb->host); |
| 875 g_free(phb); | 1072 g_free(phb); |
| 876 } | 1073 } |
| 877 | 1074 |
| 878 static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) | 1075 static void |
| 1076 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) | |
| 879 { | 1077 { |
| 880 unsigned char packet[12]; | 1078 unsigned char packet[12]; |
| 881 struct hostent *hp; | 1079 struct hostent *hp; |
| 882 struct PHB *phb = data; | 1080 struct PHB *phb = data; |
| 883 unsigned int len; | 1081 unsigned int len; |
| 885 | 1083 |
| 886 gaim_debug(GAIM_DEBUG_INFO, "s4 proxy", "Connected.\n"); | 1084 gaim_debug(GAIM_DEBUG_INFO, "s4 proxy", "Connected.\n"); |
| 887 | 1085 |
| 888 if (phb->inpa > 0) | 1086 if (phb->inpa > 0) |
| 889 gaim_input_remove(phb->inpa); | 1087 gaim_input_remove(phb->inpa); |
| 1088 | |
| 890 len = sizeof(error); | 1089 len = sizeof(error); |
| 1090 | |
| 891 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1091 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 892 close(source); | 1092 close(source); |
| 893 if(!phb->account || phb->account->gc) | 1093 |
| 1094 if (phb->account == NULL || | |
| 1095 gaim_account_get_connection(phb->account) != NULL) { | |
| 1096 | |
| 894 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1097 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1098 } | |
| 1099 | |
| 895 g_free(phb->host); | 1100 g_free(phb->host); |
| 896 g_free(phb); | 1101 g_free(phb); |
| 897 return; | 1102 return; |
| 898 } | 1103 } |
| 899 fcntl(source, F_SETFL, 0); | 1104 fcntl(source, F_SETFL, 0); |
| 900 | 1105 |
| 901 /* XXX does socks4 not support host name lookups by the proxy? */ | 1106 /* XXX does socks4 not support host name lookups by the proxy? */ |
| 902 if (!(hp = gethostbyname(phb->host))) { | 1107 if (!(hp = gethostbyname(phb->host))) { |
| 903 close(source); | 1108 close(source); |
| 904 if(!phb->account || phb->account->gc) | 1109 |
| 1110 if (phb->account == NULL || | |
| 1111 gaim_account_get_connection(phb->account) != NULL) { | |
| 1112 | |
| 905 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1113 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1114 } | |
| 1115 | |
| 906 g_free(phb->host); | 1116 g_free(phb->host); |
| 907 g_free(phb); | 1117 g_free(phb); |
| 908 return; | 1118 return; |
| 909 } | 1119 } |
| 910 | 1120 |
| 918 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; | 1128 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; |
| 919 packet[8] = 0; | 1129 packet[8] = 0; |
| 920 | 1130 |
| 921 if (write(source, packet, 9) != 9) { | 1131 if (write(source, packet, 9) != 9) { |
| 922 close(source); | 1132 close(source); |
| 923 if(!phb->account || phb->account->gc) | 1133 |
| 1134 if (phb->account == NULL || | |
| 1135 gaim_account_get_connection(phb->account) != NULL) { | |
| 1136 | |
| 924 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1137 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1138 } | |
| 1139 | |
| 925 g_free(phb->host); | 1140 g_free(phb->host); |
| 926 g_free(phb); | 1141 g_free(phb); |
| 927 return; | 1142 return; |
| 928 } | 1143 } |
| 929 | 1144 |
| 930 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb); | 1145 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb); |
| 931 } | 1146 } |
| 932 | 1147 |
| 933 static int proxy_connect_socks4(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | 1148 static int |
| 1149 proxy_connect_socks4(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | |
| 934 { | 1150 { |
| 935 int fd = -1; | 1151 int fd = -1; |
| 936 | 1152 |
| 937 gaim_debug(GAIM_DEBUG_INFO, "socks4 proxy", | 1153 gaim_debug(GAIM_DEBUG_INFO, "socks4 proxy", |
| 938 "Connecting to %s:%d via %s:%d using SOCKS4\n", | 1154 "Connecting to %s:%d via %s:%d using SOCKS4\n", |
| 939 phb->host, phb->port, phb->gpi->proxyhost, | 1155 phb->host, phb->port, |
| 940 phb->gpi->proxyport); | 1156 gaim_proxy_info_get_host(phb->gpi), |
| 941 | 1157 gaim_proxy_info_get_port(phb->gpi)); |
| 942 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 1158 |
| 1159 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) | |
| 943 return -1; | 1160 return -1; |
| 944 } | |
| 945 | 1161 |
| 946 fcntl(fd, F_SETFL, O_NONBLOCK); | 1162 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 1163 | |
| 947 if (connect(fd, addr, addrlen) < 0) { | 1164 if (connect(fd, addr, addrlen) < 0) { |
| 948 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 1165 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 949 gaim_debug(GAIM_DEBUG_WARNING, "socks4 proxy", | 1166 gaim_debug(GAIM_DEBUG_WARNING, "socks4 proxy", |
| 950 "Connect would have blocked.\n"); | 1167 "Connect would have blocked.\n"); |
| 951 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s4_canwrite, phb); | 1168 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s4_canwrite, phb); |
| 952 } else { | 1169 } |
| 1170 else { | |
| 953 close(fd); | 1171 close(fd); |
| 954 return -1; | 1172 return -1; |
| 955 } | 1173 } |
| 956 } else { | 1174 } else { |
| 957 unsigned int len; | 1175 unsigned int len; |
| 959 | 1177 |
| 960 gaim_debug(GAIM_DEBUG_MISC, "socks4 proxy", | 1178 gaim_debug(GAIM_DEBUG_MISC, "socks4 proxy", |
| 961 "Connect didn't block.\n"); | 1179 "Connect didn't block.\n"); |
| 962 | 1180 |
| 963 len = sizeof(error); | 1181 len = sizeof(error); |
| 1182 | |
| 964 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1183 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 965 close(fd); | 1184 close(fd); |
| 966 return -1; | 1185 return -1; |
| 967 } | 1186 } |
| 1187 | |
| 968 fcntl(fd, F_SETFL, 0); | 1188 fcntl(fd, F_SETFL, 0); |
| 969 s4_canwrite(phb, fd, GAIM_INPUT_WRITE); | 1189 s4_canwrite(phb, fd, GAIM_INPUT_WRITE); |
| 970 } | 1190 } |
| 971 | 1191 |
| 972 return fd; | 1192 return fd; |
| 973 } | 1193 } |
| 974 | 1194 |
| 975 static void s5_canread_again(gpointer data, gint source, GaimInputCondition cond) | 1195 static void |
| 1196 s5_canread_again(gpointer data, gint source, GaimInputCondition cond) | |
| 976 { | 1197 { |
| 977 unsigned char buf[512]; | 1198 unsigned char buf[512]; |
| 978 struct PHB *phb = data; | 1199 struct PHB *phb = data; |
| 979 | 1200 |
| 980 gaim_input_remove(phb->inpa); | 1201 gaim_input_remove(phb->inpa); |
| 981 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read again.\n"); | 1202 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read again.\n"); |
| 982 | 1203 |
| 983 if (read(source, buf, 10) < 10) { | 1204 if (read(source, buf, 10) < 10) { |
| 984 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", "or not...\n"); | 1205 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", "or not...\n"); |
| 985 close(source); | 1206 close(source); |
| 986 if(!phb->account || phb->account->gc) | 1207 |
| 1208 if (phb->account == NULL || | |
| 1209 gaim_account_get_connection(phb->account) != NULL) { | |
| 1210 | |
| 987 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1211 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1212 } | |
| 1213 | |
| 988 g_free(phb->host); | 1214 g_free(phb->host); |
| 989 g_free(phb); | 1215 g_free(phb); |
| 990 return; | 1216 return; |
| 991 } | 1217 } |
| 992 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { | 1218 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { |
| 993 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Bad data.\n"); | 1219 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Bad data.\n"); |
| 994 close(source); | 1220 close(source); |
| 995 if(!phb->account || phb->account->gc) | 1221 |
| 1222 if (phb->account == NULL || | |
| 1223 gaim_account_get_connection(phb->account) != NULL) { | |
| 1224 | |
| 996 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1225 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1226 } | |
| 1227 | |
| 997 g_free(phb->host); | 1228 g_free(phb->host); |
| 998 g_free(phb); | 1229 g_free(phb); |
| 999 return; | 1230 return; |
| 1000 } | 1231 } |
| 1001 | 1232 |
| 1002 if(!phb->account || phb->account->gc) | 1233 if (phb->account == NULL || |
| 1234 gaim_account_get_connection(phb->account) != NULL) { | |
| 1235 | |
| 1003 phb->func(phb->data, source, GAIM_INPUT_READ); | 1236 phb->func(phb->data, source, GAIM_INPUT_READ); |
| 1237 } | |
| 1238 | |
| 1004 g_free(phb->host); | 1239 g_free(phb->host); |
| 1005 g_free(phb); | 1240 g_free(phb); |
| 1006 return; | 1241 } |
| 1007 } | 1242 |
| 1008 | 1243 static void |
| 1009 static void s5_sendconnect(gpointer data, gint source) | 1244 s5_sendconnect(gpointer data, gint source) |
| 1010 { | 1245 { |
| 1011 unsigned char buf[512]; | 1246 unsigned char buf[512]; |
| 1012 struct PHB *phb = data; | 1247 struct PHB *phb = data; |
| 1013 int hlen = strlen(phb->host); | 1248 int hlen = strlen(phb->host); |
| 1014 | 1249 |
| 1021 buf[5 + strlen(phb->host)] = phb->port >> 8; | 1256 buf[5 + strlen(phb->host)] = phb->port >> 8; |
| 1022 buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; | 1257 buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; |
| 1023 | 1258 |
| 1024 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { | 1259 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { |
| 1025 close(source); | 1260 close(source); |
| 1026 if(!phb->account || phb->account->gc) | 1261 |
| 1262 if (phb->account == NULL || | |
| 1263 gaim_account_get_connection(phb->account) != NULL) { | |
| 1264 | |
| 1027 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1265 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1266 } | |
| 1267 | |
| 1028 g_free(phb->host); | 1268 g_free(phb->host); |
| 1029 g_free(phb); | 1269 g_free(phb); |
| 1030 return; | 1270 return; |
| 1031 } | 1271 } |
| 1032 | 1272 |
| 1033 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); | 1273 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); |
| 1034 } | 1274 } |
| 1035 | 1275 |
| 1036 static void s5_readauth(gpointer data, gint source, GaimInputCondition cond) | 1276 static void |
| 1277 s5_readauth(gpointer data, gint source, GaimInputCondition cond) | |
| 1037 { | 1278 { |
| 1038 unsigned char buf[512]; | 1279 unsigned char buf[512]; |
| 1039 struct PHB *phb = data; | 1280 struct PHB *phb = data; |
| 1040 | 1281 |
| 1041 gaim_input_remove(phb->inpa); | 1282 gaim_input_remove(phb->inpa); |
| 1042 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got auth response.\n"); | 1283 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got auth response.\n"); |
| 1043 | 1284 |
| 1044 if (read(source, buf, 2) < 2) { | 1285 if (read(source, buf, 2) < 2) { |
| 1045 close(source); | 1286 close(source); |
| 1046 if(!phb->account || phb->account->gc) | 1287 |
| 1288 if (phb->account == NULL || | |
| 1289 gaim_account_get_connection(phb->account) != NULL) { | |
| 1290 | |
| 1047 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1291 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1292 } | |
| 1293 | |
| 1048 g_free(phb->host); | 1294 g_free(phb->host); |
| 1049 g_free(phb); | 1295 g_free(phb); |
| 1050 return; | 1296 return; |
| 1051 } | 1297 } |
| 1052 | 1298 |
| 1053 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { | 1299 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { |
| 1054 close(source); | 1300 close(source); |
| 1055 if(!phb->account || phb->account->gc) | 1301 |
| 1302 if (phb->account == NULL || | |
| 1303 gaim_account_get_connection(phb->account) != NULL) { | |
| 1304 | |
| 1056 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1305 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1306 } | |
| 1307 | |
| 1057 g_free(phb->host); | 1308 g_free(phb->host); |
| 1058 g_free(phb); | 1309 g_free(phb); |
| 1059 return; | 1310 return; |
| 1060 } | 1311 } |
| 1061 | 1312 |
| 1062 s5_sendconnect(phb, source); | 1313 s5_sendconnect(phb, source); |
| 1063 } | 1314 } |
| 1064 | 1315 |
| 1065 static void s5_canread(gpointer data, gint source, GaimInputCondition cond) | 1316 static void |
| 1317 s5_canread(gpointer data, gint source, GaimInputCondition cond) | |
| 1066 { | 1318 { |
| 1067 unsigned char buf[512]; | 1319 unsigned char buf[512]; |
| 1068 struct PHB *phb = data; | 1320 struct PHB *phb = data; |
| 1069 | 1321 |
| 1070 gaim_input_remove(phb->inpa); | 1322 gaim_input_remove(phb->inpa); |
| 1071 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read.\n"); | 1323 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read.\n"); |
| 1072 | 1324 |
| 1073 if (read(source, buf, 2) < 2) { | 1325 if (read(source, buf, 2) < 2) { |
| 1074 close(source); | 1326 close(source); |
| 1075 if(!phb->account || phb->account->gc) | 1327 |
| 1328 if (phb->account == NULL || | |
| 1329 gaim_account_get_connection(phb->account) != NULL) { | |
| 1330 | |
| 1076 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1331 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1332 } | |
| 1333 | |
| 1077 g_free(phb->host); | 1334 g_free(phb->host); |
| 1078 g_free(phb); | 1335 g_free(phb); |
| 1079 return; | 1336 return; |
| 1080 } | 1337 } |
| 1081 | 1338 |
| 1082 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { | 1339 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { |
| 1083 close(source); | 1340 close(source); |
| 1084 if(!phb->account || phb->account->gc) | 1341 |
| 1342 if (phb->account == NULL || | |
| 1343 gaim_account_get_connection(phb->account) != NULL) { | |
| 1344 | |
| 1085 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1345 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1346 } | |
| 1347 | |
| 1086 g_free(phb->host); | 1348 g_free(phb->host); |
| 1087 g_free(phb); | 1349 g_free(phb); |
| 1088 return; | 1350 return; |
| 1089 } | 1351 } |
| 1090 | 1352 |
| 1091 if (buf[1] == 0x02) { | 1353 if (buf[1] == 0x02) { |
| 1092 unsigned int i = strlen(phb->gpi->proxyuser), j = strlen(phb->gpi->proxypass); | 1354 unsigned int i, j; |
| 1355 | |
| 1356 i = strlen(gaim_proxy_info_get_username(phb->gpi)); | |
| 1357 j = strlen(gaim_proxy_info_get_password(phb->gpi)); | |
| 1358 | |
| 1093 buf[0] = 0x01; /* version 1 */ | 1359 buf[0] = 0x01; /* version 1 */ |
| 1094 buf[1] = i; | 1360 buf[1] = i; |
| 1095 memcpy(buf + 2, phb->gpi->proxyuser, i); | 1361 memcpy(buf + 2, gaim_proxy_info_get_username(phb->gpi), i); |
| 1096 buf[2 + i] = j; | 1362 buf[2 + i] = j; |
| 1097 memcpy(buf + 2 + i + 1, phb->gpi->proxypass, j); | 1363 memcpy(buf + 2 + i + 1, gaim_proxy_info_get_password(phb->gpi), j); |
| 1098 | 1364 |
| 1099 if (write(source, buf, 3 + i + j) < 3 + i + j) { | 1365 if (write(source, buf, 3 + i + j) < 3 + i + j) { |
| 1100 close(source); | 1366 close(source); |
| 1101 if(!phb->account || phb->account->gc) | 1367 |
| 1368 if (phb->account == NULL || | |
| 1369 gaim_account_get_connection(phb->account) != NULL) { | |
| 1370 | |
| 1102 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1371 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1372 } | |
| 1373 | |
| 1103 g_free(phb->host); | 1374 g_free(phb->host); |
| 1104 g_free(phb); | 1375 g_free(phb); |
| 1105 return; | 1376 return; |
| 1106 } | 1377 } |
| 1107 | 1378 |
| 1108 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); | 1379 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); |
| 1109 } else { | 1380 } |
| 1381 else { | |
| 1110 s5_sendconnect(phb, source); | 1382 s5_sendconnect(phb, source); |
| 1111 } | 1383 } |
| 1112 } | 1384 } |
| 1113 | 1385 |
| 1114 static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond) | 1386 static void |
| 1387 s5_canwrite(gpointer data, gint source, GaimInputCondition cond) | |
| 1115 { | 1388 { |
| 1116 unsigned char buf[512]; | 1389 unsigned char buf[512]; |
| 1117 int i; | 1390 int i; |
| 1118 struct PHB *phb = data; | 1391 struct PHB *phb = data; |
| 1119 unsigned int len; | 1392 unsigned int len; |
| 1121 | 1394 |
| 1122 gaim_debug(GAIM_INFO, "socks5 proxy", "Connected.\n"); | 1395 gaim_debug(GAIM_INFO, "socks5 proxy", "Connected.\n"); |
| 1123 | 1396 |
| 1124 if (phb->inpa > 0) | 1397 if (phb->inpa > 0) |
| 1125 gaim_input_remove(phb->inpa); | 1398 gaim_input_remove(phb->inpa); |
| 1399 | |
| 1126 len = sizeof(error); | 1400 len = sizeof(error); |
| 1127 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1401 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 1128 close(source); | 1402 close(source); |
| 1129 if(!phb->account || phb->account->gc) | 1403 if (phb->account == NULL || |
| 1404 gaim_account_get_connection(phb->account) != NULL) { | |
| 1405 | |
| 1130 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1406 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1407 } | |
| 1408 | |
| 1131 g_free(phb->host); | 1409 g_free(phb->host); |
| 1132 g_free(phb); | 1410 g_free(phb); |
| 1133 return; | 1411 return; |
| 1134 } | 1412 } |
| 1135 fcntl(source, F_SETFL, 0); | 1413 fcntl(source, F_SETFL, 0); |
| 1136 | 1414 |
| 1137 i = 0; | 1415 i = 0; |
| 1138 buf[0] = 0x05; /* SOCKS version 5 */ | 1416 buf[0] = 0x05; /* SOCKS version 5 */ |
| 1139 if (phb->gpi->proxyuser[0]) { | 1417 |
| 1418 if (gaim_proxy_info_get_username(phb->gpi) != NULL) { | |
| 1140 buf[1] = 0x02; /* two methods */ | 1419 buf[1] = 0x02; /* two methods */ |
| 1141 buf[2] = 0x00; /* no authentication */ | 1420 buf[2] = 0x00; /* no authentication */ |
| 1142 buf[3] = 0x02; /* username/password authentication */ | 1421 buf[3] = 0x02; /* username/password authentication */ |
| 1143 i = 4; | 1422 i = 4; |
| 1144 } else { | 1423 } |
| 1424 else { | |
| 1145 buf[1] = 0x01; | 1425 buf[1] = 0x01; |
| 1146 buf[2] = 0x00; | 1426 buf[2] = 0x00; |
| 1147 i = 3; | 1427 i = 3; |
| 1148 } | 1428 } |
| 1149 | 1429 |
| 1150 if (write(source, buf, i) < i) { | 1430 if (write(source, buf, i) < i) { |
| 1151 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Unable to write\n"); | 1431 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Unable to write\n"); |
| 1152 close(source); | 1432 close(source); |
| 1153 if(!phb->account || phb->account->gc) | 1433 |
| 1434 if (phb->account == NULL || | |
| 1435 gaim_account_get_connection(phb->account) != NULL) { | |
| 1436 | |
| 1154 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1437 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1438 } | |
| 1439 | |
| 1155 g_free(phb->host); | 1440 g_free(phb->host); |
| 1156 g_free(phb); | 1441 g_free(phb); |
| 1157 return; | 1442 return; |
| 1158 } | 1443 } |
| 1159 | 1444 |
| 1160 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb); | 1445 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb); |
| 1161 } | 1446 } |
| 1162 | 1447 |
| 1163 static int proxy_connect_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | 1448 static int |
| 1449 proxy_connect_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) | |
| 1164 { | 1450 { |
| 1165 int fd = -1; | 1451 int fd = -1; |
| 1166 | 1452 |
| 1167 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", | 1453 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", |
| 1168 "Connecting to %s:%d via %s:%d using SOCKS5\n", | 1454 "Connecting to %s:%d via %s:%d using SOCKS5\n", |
| 1169 phb->host, phb->port, phb->gpi->proxyhost, | 1455 phb->host, phb->port, |
| 1170 phb->gpi->proxyport); | 1456 gaim_proxy_info_get_host(phb->gpi), |
| 1171 | 1457 gaim_proxy_info_get_port(phb->gpi)); |
| 1172 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 1458 |
| 1459 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) | |
| 1173 return -1; | 1460 return -1; |
| 1174 } | |
| 1175 | 1461 |
| 1176 fcntl(fd, F_SETFL, O_NONBLOCK); | 1462 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 1463 | |
| 1177 if (connect(fd, addr, addrlen) < 0) { | 1464 if (connect(fd, addr, addrlen) < 0) { |
| 1178 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 1465 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 1179 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", | 1466 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", |
| 1180 "Connect would have blocked.\n"); | 1467 "Connect would have blocked.\n"); |
| 1468 | |
| 1181 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s5_canwrite, phb); | 1469 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s5_canwrite, phb); |
| 1182 } else { | 1470 } |
| 1471 else { | |
| 1183 close(fd); | 1472 close(fd); |
| 1184 return -1; | 1473 return -1; |
| 1185 } | 1474 } |
| 1186 } else { | 1475 } |
| 1476 else { | |
| 1187 unsigned int len; | 1477 unsigned int len; |
| 1188 int error = ETIMEDOUT; | 1478 int error = ETIMEDOUT; |
| 1189 | 1479 |
| 1190 gaim_debug(GAIM_DEBUG_MISC, "socks5 proxy", | 1480 gaim_debug(GAIM_DEBUG_MISC, "socks5 proxy", |
| 1191 "Connect didn't block.\n"); | 1481 "Connect didn't block.\n"); |
| 1482 | |
| 1192 len = sizeof(error); | 1483 len = sizeof(error); |
| 1484 | |
| 1193 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1485 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 1194 close(fd); | 1486 close(fd); |
| 1195 return -1; | 1487 return -1; |
| 1196 } | 1488 } |
| 1489 | |
| 1197 fcntl(fd, F_SETFL, 0); | 1490 fcntl(fd, F_SETFL, 0); |
| 1198 s5_canwrite(phb, fd, GAIM_INPUT_WRITE); | 1491 s5_canwrite(phb, fd, GAIM_INPUT_WRITE); |
| 1199 } | 1492 } |
| 1200 | 1493 |
| 1201 return fd; | 1494 return fd; |
| 1202 } | 1495 } |
| 1203 | 1496 |
| 1204 static void connection_host_resolved(GSList *hosts, gpointer data, const char *error_message) | 1497 static void |
| 1498 connection_host_resolved(GSList *hosts, gpointer data, | |
| 1499 const char *error_message) | |
| 1205 { | 1500 { |
| 1206 struct PHB *phb = (struct PHB*)data; | 1501 struct PHB *phb = (struct PHB*)data; |
| 1207 size_t addrlen; | 1502 size_t addrlen; |
| 1208 struct sockaddr *addr; | 1503 struct sockaddr *addr; |
| 1209 int ret = -1; | 1504 int ret = -1; |
| 1210 | 1505 |
| 1211 while(hosts) { | 1506 while (hosts) { |
| 1212 addrlen = GPOINTER_TO_INT(hosts->data); | 1507 addrlen = GPOINTER_TO_INT(hosts->data); |
| 1213 hosts = hosts->next; | 1508 hosts = hosts->next; |
| 1214 addr = hosts->data; | 1509 addr = hosts->data; |
| 1215 hosts = hosts->next; | 1510 hosts = hosts->next; |
| 1216 | 1511 |
| 1217 switch(phb->gpi->proxytype) | 1512 switch (gaim_proxy_info_get_type(phb->gpi)) |
| 1218 { | 1513 { |
| 1219 case PROXY_NONE: | 1514 case GAIM_PROXY_NONE: |
| 1220 ret = proxy_connect_none(phb, addr, addrlen); | 1515 ret = proxy_connect_none(phb, addr, addrlen); |
| 1221 break; | 1516 break; |
| 1222 case PROXY_HTTP: | 1517 |
| 1518 case GAIM_PROXY_HTTP: | |
| 1223 ret = proxy_connect_http(phb, addr, addrlen); | 1519 ret = proxy_connect_http(phb, addr, addrlen); |
| 1224 break; | 1520 break; |
| 1225 case PROXY_SOCKS4: | 1521 |
| 1522 case GAIM_PROXY_SOCKS4: | |
| 1226 ret = proxy_connect_socks4(phb, addr, addrlen); | 1523 ret = proxy_connect_socks4(phb, addr, addrlen); |
| 1227 break; | 1524 break; |
| 1228 case PROXY_SOCKS5: | 1525 |
| 1526 case GAIM_PROXY_SOCKS5: | |
| 1229 ret = proxy_connect_socks5(phb, addr, addrlen); | 1527 ret = proxy_connect_socks5(phb, addr, addrlen); |
| 1230 break; | 1528 break; |
| 1231 } | 1529 |
| 1530 default: | |
| 1531 break; | |
| 1532 } | |
| 1533 | |
| 1232 if (ret > 0) | 1534 if (ret > 0) |
| 1233 break; | 1535 break; |
| 1234 } | 1536 } |
| 1235 if(ret < 0) { | 1537 |
| 1236 if(!phb->account || phb->account->gc) | 1538 if (ret < 0) { |
| 1539 if (phb->account == NULL || | |
| 1540 gaim_account_get_connection(phb->account) != NULL) { | |
| 1541 | |
| 1237 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1542 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1543 } | |
| 1544 | |
| 1238 g_free(phb->host); | 1545 g_free(phb->host); |
| 1239 g_free(phb); | 1546 g_free(phb); |
| 1240 } | 1547 } |
| 1241 } | 1548 } |
| 1242 | 1549 |
| 1243 int | 1550 int |
| 1244 proxy_connect(GaimAccount *account, const char *host, int port, GaimInputFunction func, gpointer data) | 1551 gaim_proxy_connect(GaimAccount *account, const char *host, int port, |
| 1552 GaimInputFunction func, gpointer data) | |
| 1245 { | 1553 { |
| 1246 const char *connecthost = host; | 1554 const char *connecthost = host; |
| 1247 int connectport = port; | 1555 int connectport = port; |
| 1248 struct PHB *phb = g_new0(struct PHB, 1); | 1556 struct PHB *phb = g_new0(struct PHB, 1); |
| 1249 if(!account || !account->gpi) | 1557 |
| 1250 phb->gpi = &global_proxy_info; | 1558 g_return_val_if_fail(host != NULL, -1); |
| 1559 g_return_val_if_fail(port != 0 && port != -1, -1); | |
| 1560 g_return_val_if_fail(func != NULL, -1); | |
| 1561 | |
| 1562 if (account == NULL || gaim_account_get_proxy_info(account) == NULL) | |
| 1563 phb->gpi = gaim_global_proxy_get_info(); | |
| 1251 else | 1564 else |
| 1252 phb->gpi = account->gpi; | 1565 phb->gpi = gaim_account_get_proxy_info(account); |
| 1566 | |
| 1253 phb->func = func; | 1567 phb->func = func; |
| 1254 phb->data = data; | 1568 phb->data = data; |
| 1255 phb->host = g_strdup(host); | 1569 phb->host = g_strdup(host); |
| 1256 phb->port = port; | 1570 phb->port = port; |
| 1257 phb->account = account; | 1571 phb->account = account; |
| 1258 | 1572 |
| 1259 if (!host || !port || (port == -1) || !func) { | 1573 if ((gaim_proxy_info_get_type(phb->gpi) != GAIM_PROXY_NONE) && |
| 1260 if(host) | 1574 (gaim_proxy_info_get_host(phb->gpi) == NULL || |
| 1261 g_free(phb->host); | 1575 gaim_proxy_info_get_port(phb->gpi) == 0 || |
| 1262 g_free(phb); | 1576 gaim_proxy_info_get_port(phb->gpi) == -1)) { |
| 1263 return -1; | 1577 |
| 1264 } | 1578 gaim_proxy_info_set_type(phb->gpi, GAIM_PROXY_NONE); |
| 1265 | 1579 } |
| 1266 if ((phb->gpi->proxytype!=PROXY_NONE) && (!phb->gpi->proxyhost || !phb->gpi->proxyhost[0] || !phb->gpi->proxyport || (phb->gpi->proxyport == -1))) | 1580 |
| 1267 phb->gpi->proxytype=PROXY_NONE; | 1581 switch (gaim_proxy_info_get_type(phb->gpi)) |
| 1268 | |
| 1269 switch(phb->gpi->proxytype) | |
| 1270 { | 1582 { |
| 1271 case PROXY_NONE: | 1583 case GAIM_PROXY_NONE: |
| 1272 break; | 1584 break; |
| 1273 case PROXY_HTTP: | 1585 |
| 1274 case PROXY_SOCKS4: | 1586 case GAIM_PROXY_HTTP: |
| 1275 case PROXY_SOCKS5: | 1587 case GAIM_PROXY_SOCKS4: |
| 1276 connecthost=phb->gpi->proxyhost; | 1588 case GAIM_PROXY_SOCKS5: |
| 1277 connectport=phb->gpi->proxyport; | 1589 connecthost = gaim_proxy_info_get_host(phb->gpi); |
| 1590 connectport = gaim_proxy_info_get_port(phb->gpi); | |
| 1278 break; | 1591 break; |
| 1592 | |
| 1279 default: | 1593 default: |
| 1280 g_free(phb->host); | 1594 g_free(phb->host); |
| 1281 g_free(phb); | 1595 g_free(phb); |
| 1282 return -1; | 1596 return -1; |
| 1283 } | 1597 } |
| 1284 | 1598 |
| 1285 return gaim_gethostbyname_async(connecthost, connectport, connection_host_resolved, phb); | 1599 return gaim_gethostbyname_async(connecthost, connectport, |
| 1286 } | 1600 connection_host_resolved, phb); |
| 1601 } | |
| 1602 | |
| 1603 | |
| 1604 static void | |
| 1605 proxy_pref_cb(const char *name, GaimPrefType type, gpointer value, | |
| 1606 gpointer data) | |
| 1607 { | |
| 1608 GaimProxyInfo *info = gaim_global_proxy_get_info(); | |
| 1609 | |
| 1610 if (!strcmp(name, "/core/proxy/type")) | |
| 1611 gaim_proxy_info_set_type(info, GPOINTER_TO_INT(value)); | |
| 1612 else if (!strcmp(name, "/core/proxy/host")) | |
| 1613 gaim_proxy_info_set_host(info, value); | |
| 1614 else if (!strcmp(name, "/core/proxy/port")) | |
| 1615 gaim_proxy_info_set_port(info, GPOINTER_TO_INT(value)); | |
| 1616 else if (!strcmp(name, "/core/proxy/username")) | |
| 1617 gaim_proxy_info_set_username(info, value); | |
| 1618 else if (!strcmp(name, "/core/proxy/password")) | |
| 1619 gaim_proxy_info_set_password(info, value); | |
| 1620 } | |
| 1621 | |
| 1622 void | |
| 1623 gaim_proxy_init(void) | |
| 1624 { | |
| 1625 /* Initialize a default proxy info struct. */ | |
| 1626 global_proxy_info = gaim_proxy_info_new(); | |
| 1627 | |
| 1628 /* Proxy */ | |
| 1629 gaim_prefs_add_none("/core/proxy"); | |
| 1630 gaim_prefs_add_string("/core/proxy/type", "none"); | |
| 1631 gaim_prefs_add_string("/core/proxy/host", ""); | |
| 1632 gaim_prefs_add_int("/core/proxy/port", 0); | |
| 1633 gaim_prefs_add_string("/core/proxy/username", ""); | |
| 1634 gaim_prefs_add_string("/core/proxy/password", ""); | |
| 1635 | |
| 1636 /* Setup callbacks for the preferences. */ | |
| 1637 gaim_prefs_connect_callback("/core/proxy/type", | |
| 1638 proxy_pref_cb, NULL); | |
| 1639 gaim_prefs_connect_callback("/core/proxy/host", | |
| 1640 proxy_pref_cb, NULL); | |
| 1641 gaim_prefs_connect_callback("/core/proxy/port", | |
| 1642 proxy_pref_cb, NULL); | |
| 1643 gaim_prefs_connect_callback("/core/proxy/username", | |
| 1644 proxy_pref_cb, NULL); | |
| 1645 gaim_prefs_connect_callback("/core/proxy/password", | |
| 1646 proxy_pref_cb, NULL); | |
| 1647 } |
