Mercurial > pidgin.yaz
changeset 1840:00aef397a1fe
[gaim-migrate @ 1850]
reworked some of the proxy stuff so that it's non-blocking now. next thing to do is to get IRC, MSN, Napster, and Jabber to use the new proxy_connect code. After that, Oscar and Yahoo (maybe Zephyr too? not likely)
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Sat, 12 May 2001 01:38:04 +0000 |
parents | 109cacf1ff97 |
children | 93f0629d4099 |
files | src/dialogs.c src/gaim.h src/html.c src/prefs.c src/proxy.c src/proxy.h src/toc.c |
diffstat | 7 files changed, 612 insertions(+), 213 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dialogs.c Fri May 11 21:54:27 2001 +0000 +++ b/src/dialogs.c Sat May 12 01:38:04 2001 +0000 @@ -1784,16 +1784,6 @@ gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sw)), 0); } -void g_show_info(struct aim_user *user, char *url) { - char *url_text = grab_url(user, url); - if (connections) - g_show_info_text(away_subs(url_text, - ((struct gaim_connection *)connections->data)->username)); - else - g_show_info_text(url_text); - g_free(url_text); -} - /*------------------------------------------------------------------------*/ /* The dialog for adding to permit/deny */ /*------------------------------------------------------------------------*/
--- a/src/gaim.h Fri May 11 21:54:27 2001 +0000 +++ b/src/gaim.h Sat May 12 01:38:04 2001 +0000 @@ -590,7 +590,7 @@ /* Functions in html.c */ extern struct g_url parse_url(char *); -extern char *grab_url(struct aim_user *, char *); +extern void grab_url(struct aim_user *, char *, void (*callback)(gpointer, char *), gpointer); extern gchar *strip_html(gchar *); /* Functions in idle.c */ @@ -838,8 +838,7 @@ extern void show_log_dialog(struct conversation *); extern void show_find_email(struct gaim_connection *gc); extern void show_find_info(); -extern void g_show_info (struct aim_user *, char *); -extern void g_show_info_text (char *); +extern void g_show_info_text(char *); extern void show_set_info(struct gaim_connection *); extern void show_set_dir(); extern void show_fgcolor_dialog(struct conversation *c, GtkWidget *color);
--- a/src/html.c Fri May 11 21:54:27 2001 +0000 +++ b/src/html.c Sat May 12 01:38:04 2001 +0000 @@ -100,11 +100,17 @@ return test; } -char *grab_url(struct aim_user *user, char *url) -{ +struct grab_url_data { + void (*callback)(gpointer, char *); + gpointer data; struct g_url website; + char *url; +}; + +static void grab_url_callback(gpointer dat, gint sock, GdkInputCondition cond) +{ + struct grab_url_data *gunk = dat; char *webdata = NULL; - int sock; int len; int read_rv; int datalen = 0; @@ -113,18 +119,14 @@ int startsaving = 0; GtkWidget *pw = NULL, *pbar = NULL, *label; - website = parse_url(url); - - if (user) { - if ((sock = proxy_connect(website.address, website.port, user->proto_opt[2], - atoi(user->proto_opt[3]), atoi(user->proto_opt[4]))) < 0) - return g_strdup(_("g003: Error opening connection.\n")); - } else { - if ((sock = proxy_connect(website.address, website.port, NULL, 0, -1)) < 0) - return g_strdup(_("g003: Error opening connection.\n")); + if (sock == -1) { + gunk->callback(gunk->data, NULL); + g_free(gunk->url); + g_free(gunk); + return; } - g_snprintf(buf, sizeof(buf), "GET /%s HTTP/1.0\r\n\r\n", website.page); + g_snprintf(buf, sizeof(buf), "GET /%s HTTP/1.0\r\n\r\n", gunk->website.page); debug_printf("Request: %s\n", buf); write(sock, buf, strlen(buf)); fcntl(sock, F_SETFL, O_NONBLOCK); @@ -153,7 +155,8 @@ char tmpbuf[1024]; sscanf(cs, "Content-Length: %d", &datalen); - g_snprintf(tmpbuf, 1024, _("Getting %d bytes from %s"), datalen, url); + g_snprintf(tmpbuf, 1024, _("Getting %d bytes from %s"), + datalen, gunk->url); pw = gtk_dialog_new(); label = gtk_label_new(tmpbuf); @@ -204,5 +207,36 @@ gtk_widget_destroy(pw); close(sock); - return webdata; + gunk->callback(gunk->data, webdata); + g_free(gunk->url); + g_free(gunk); } + +void grab_url(struct aim_user *user, char *url, void (*callback)(gpointer, char *), gpointer data) +{ + int sock; + struct grab_url_data *gunk = g_new0(struct grab_url_data, 1); + + gunk->callback = callback; + gunk->data = data; + gunk->url = g_strdup(url); + gunk->website = parse_url(url); + + if (user) { + if ((sock = proxy_connect(gunk->website.address, gunk->website.port, + user->proto_opt[2], atoi(user->proto_opt[3]), + atoi(user->proto_opt[4]), + grab_url_callback, gunk)) < 0) { + g_free(gunk->url); + g_free(gunk); + callback(data, g_strdup(_("g003: Error opening connection.\n"))); + } + } else { + if ((sock = proxy_connect(gunk->website.address, gunk->website.port, NULL, 0, -1, + grab_url_callback, gunk)) < 0) { + g_free(gunk->url); + g_free(gunk); + callback(data, g_strdup(_("g003: Error opening connection.\n"))); + } + } +}
--- a/src/prefs.c Fri May 11 21:54:27 2001 +0000 +++ b/src/prefs.c Sat May 12 01:38:04 2001 +0000 @@ -841,16 +841,19 @@ static struct chat_page *cp = NULL; -static void refresh_list(GtkWidget *w, gpointer *m) -{ - char *text = grab_url(NULL, "http://www.aol.com/community/chat/allchats.html"); +static void ref_list_callback(gpointer data, char *text) { char *c; - int len = strlen(text); + int len; GtkWidget *item; GList *items = GTK_LIST(cp->list1)->children; struct chat_room *cr; c = text; + if (!text) + return; + + len = strlen(text); + while (items) { g_free(gtk_object_get_user_data(GTK_OBJECT(items->data))); items = items->next; @@ -909,6 +912,11 @@ g_free(text); } +static void refresh_list(GtkWidget *w, gpointer *m) +{ + grab_url(NULL, "http://www.aol.com/community/chat/allchats.html", ref_list_callback, NULL); +} + static void add_chat(GtkWidget *w, gpointer *m) { GList *sel = GTK_LIST(cp->list1)->selection;
--- a/src/proxy.c Fri May 11 21:54:27 2001 +0000 +++ b/src/proxy.c Sat May 12 01:38:04 2001 +0000 @@ -34,11 +34,40 @@ #include <netdb.h> #include <netinet/in.h> #include <unistd.h> +#include <fcntl.h> +#include <errno.h> #include <gtk/gtk.h> #include "gaim.h" #include "proxy.h" -static int proxy_connect_none(char *host, unsigned short port) +struct PHB { + GdkInputFunction func; + gpointer data; + char *host; + int port; + gint inpa; +}; + +static void no_one_calls(gpointer data, gint source, GdkInputCondition cond) +{ + struct PHB *phb = data; + int len, error = ETIMEDOUT; + debug_printf("Connected\n"); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + gdk_input_remove(phb->inpa); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb); + return; + } + fcntl(source, F_SETFL, 0); + gdk_input_remove(phb->inpa); + phb->func(phb->data, source, GDK_INPUT_READ); + g_free(phb); +} + +static int proxy_connect_none(char *host, unsigned short port, struct PHB *phb) { struct sockaddr_in sin; struct hostent *hp; @@ -46,20 +75,43 @@ debug_printf("connecting to %s:%d with no proxy\n", host, port); - if (!(hp = gethostbyname(host))) + if (!(hp = gethostbyname(host))) { + g_free(phb); return -1; + } memset(&sin, 0, sizeof(struct sockaddr_in)); memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons(port); - if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { + g_free(phb); return -1; + } + fcntl(fd, F_SETFL, O_NONBLOCK); if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - close(fd); - return -1; + if ((errno == EINPROGRESS) || (errno == EINTR)) { + debug_printf("Connect would have blocked\n"); + phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, no_one_calls, phb); + } else { + close(fd); + g_free(phb); + return -1; + } + } else { + int len, error = ETIMEDOUT; + debug_printf("Connect didn't block\n"); + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(fd); + g_free(phb); + return -1; + } + fcntl(fd, F_SETFL, 0); + phb->func(phb->data, fd, GDK_INPUT_READ); + g_free(phb); } return fd; @@ -68,133 +120,345 @@ #define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" #define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" -static int proxy_connect_http(char *host, unsigned short port, char *proxyhost, unsigned short proxyport) +static void http_canread(gpointer data, gint source, GdkInputCondition cond) +{ + int nlc = 0; + int pos = 0; + struct PHB *phb = data; + char inputline[8192]; + + gdk_input_remove(phb->inpa); + + while ((nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { + if (inputline[pos-1] == '\n') + nlc++; + else if (inputline[pos-1] != '\r') + nlc = 0; + } + inputline[pos] = '\0'; + + debug_printf("Proxy says: %s\n", inputline); + + if ((memcmp(HTTP_GOODSTRING , inputline, strlen(HTTP_GOODSTRING )) == 0) || + (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { + phb->func(phb->data, source, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; +} + +static void http_canwrite(gpointer data, gint source, GdkInputCondition cond) +{ + char cmd[384]; + struct PHB *phb = data; + int len, error = ETIMEDOUT; + debug_printf("Connected\n"); + if (phb->inpa > 0) + gdk_input_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + fcntl(source, F_SETFL, 0); + + snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\n\r\n", phb->host, phb->port); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + + phb->inpa = gdk_input_add(source, GDK_INPUT_READ, http_canread, phb); +} + +static int proxy_connect_http(char *host, unsigned short port, + char *proxyhost, unsigned short proxyport, + struct PHB *phb) { struct hostent *hp; struct sockaddr_in sin; int fd = -1; - char cmd[384]; - char inputline[8192]; - int nlc = 0; - int pos = 0; debug_printf("connecting to %s:%d via %s:%d using HTTP\n", host, port, proxyhost, proxyport); - if (!(hp = gethostbyname(proxyhost))) + if (!(hp = gethostbyname(proxyhost))) { + g_free(phb); return -1; + } memset(&sin, 0, sizeof(struct sockaddr_in)); memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons(proxyport); - if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) - return -1; - - if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - close(fd); + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { + g_free(phb); return -1; } - snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\n\r\n", host, port); + phb->host = g_strdup(host); + phb->port = port; - if (send(fd, cmd, strlen(cmd), 0) < 0) { - close(fd); - return -1; + fcntl(fd, F_SETFL, O_NONBLOCK); + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if ((errno == EINPROGRESS) || (errno == EINTR)) { + debug_printf("Connect would have blocked\n"); + phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, http_canwrite, phb); + } else { + close(fd); + g_free(phb->host); + g_free(phb); + return -1; + } + } else { + int len, error = ETIMEDOUT; + debug_printf("Connect didn't block\n"); + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(fd); + g_free(phb->host); + g_free(phb); + return -1; + } + fcntl(fd, F_SETFL, 0); + http_canwrite(phb, fd, GDK_INPUT_WRITE); } - while ((nlc != 2) && (read(fd, &inputline[pos++], 1) == 1)) { - if (inputline[pos-1] == '\n') - nlc++; - else if (inputline[pos-1] != '\r') - nlc = 0; + + return fd; +} + +static void s4_canread(gpointer data, gint source, GdkInputCondition cond) +{ + unsigned char packet[12]; + struct PHB *phb = data; + + gdk_input_remove(phb->inpa); + + memset(packet, 0, sizeof(packet)); + if (read(source, packet, 9) >= 4 && packet[1] == 90) { + phb->func(phb->data, source, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; } - debug_printf("Proxy says: %s\n", inputline); + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); +} - if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || - (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { - return fd; +static void s4_canwrite(gpointer data, gint source, GdkInputCondition cond) +{ + unsigned char packet[12]; + struct hostent *hp; + struct PHB *phb = data; + int len, error = ETIMEDOUT; + debug_printf("Connected\n"); + if (phb->inpa > 0) + gdk_input_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + fcntl(source, F_SETFL, 0); + + /* XXX does socks4 not support host name lookups by the proxy? */ + if (!(hp = gethostbyname(phb->host))) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; } - close(fd); - return -1; + packet[0] = 4; + packet[1] = 1; + packet[2] = phb->port >> 8; + packet[3] = phb->port & 0xff; + packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; + packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; + packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; + packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; + packet[8] = 0; + if (write(source, packet, 9) != 9) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + + phb->inpa = gdk_input_add(source, GDK_INPUT_READ, s4_canread, phb); } static int proxy_connect_socks4(char *host, unsigned short port, - char *proxyhost, unsigned short proxyport) + char *proxyhost, unsigned short proxyport, + struct PHB *phb) { struct sockaddr_in sin; - unsigned char packet[12]; struct hostent *hp; int fd = -1; debug_printf("connecting to %s:%d via %s:%d using SOCKS4\n", host, port, proxyhost, proxyport); - if (!(hp = gethostbyname(proxyhost))) + if (!(hp = gethostbyname(proxyhost))) { + g_free(phb); return -1; + } memset(&sin, 0, sizeof(struct sockaddr_in)); memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons(proxyport); - if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) - return -1; - - if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - close(fd); + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { + g_free(phb); return -1; } - /* XXX does socks4 not support host name lookups by the proxy? */ - if (!(hp = gethostbyname(host))) - return -1; + phb->host = g_strdup(host); + phb->port = port; + + fcntl(fd, F_SETFL, O_NONBLOCK); + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if ((errno == EINPROGRESS) || (errno == EINTR)) { + debug_printf("Connect would have blocked\n"); + phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, s4_canwrite, phb); + } else { + close(fd); + g_free(phb->host); + g_free(phb); + return -1; + } + } else { + int len, error = ETIMEDOUT; + debug_printf("Connect didn't block\n"); + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(fd); + g_free(phb->host); + g_free(phb); + return -1; + } + fcntl(fd, F_SETFL, 0); + s4_canwrite(phb, fd, GDK_INPUT_WRITE); + } - packet[0] = 4; - packet[1] = 1; - packet[2] = port >> 8; - packet[3] = port & 0xff; - packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; - packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; - packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; - packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; - packet[8] = 0; - if (write(fd, packet, 9) == 9) { - memset(packet, 0, sizeof(packet)); - if (read(fd, packet, 9) >= 4 && packet[1] == 90) - return fd; + return fd; +} + +static void s5_canread_again(gpointer data, gint source, GdkInputCondition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + gdk_input_remove(phb->inpa); + debug_printf("able to read again\n"); + + if (read(source, buf, 10) < 10) { + debug_printf("or not...\n"); + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; } - close(fd); + if ((buf[0] != 0x05) || (buf[1] != 0x00)) { + debug_printf("bad data\n"); + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } - return -1; + phb->func(phb->data, source, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; } -static int proxy_connect_socks5(char *host, unsigned short port, - char *proxyhost, unsigned short proxyport) +static void s5_canread(gpointer data, gint source, GdkInputCondition cond) { - int i, fd = -1; unsigned char buf[512]; - struct sockaddr_in sin; - struct hostent *hp; - int hlen = strlen(host); + struct PHB *phb = data; + int hlen = strlen(phb->host); + + gdk_input_remove(phb->inpa); + debug_printf("able to read\n"); - debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", host, port, proxyhost, proxyport); + if (read(source, buf, 2) < 2) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + + if ((buf[0] != 0x05) || (buf[1] == 0xff)) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } - if (!(hp = gethostbyname(proxyhost))) - return -1; + buf[0] = 0x05; + buf[1] = 0x01; /* CONNECT */ + buf[2] = 0x00; /* reserved */ + buf[3] = 0x03; /* address type -- host name */ + buf[4] = hlen; + memcpy(buf + 5, phb->host, hlen); + buf[5 + strlen(phb->host)] = phb->port >> 8; + buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - sin.sin_port = htons(proxyport); + if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } - if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) - return -1; + phb->inpa = gdk_input_add(source, GDK_INPUT_READ, s5_canread_again, phb); +} - if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - close(fd); - return -1; +static void s5_canwrite(gpointer data, gint source, GdkInputCondition cond) +{ + unsigned char buf[512]; + int i; + struct PHB *phb = data; + int len, error = ETIMEDOUT; + debug_printf("Connected\n"); + if (phb->inpa > 0) + gdk_input_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; } + fcntl(source, F_SETFL, 0); i = 0; buf[0] = 0x05; /* SOCKS version 5 */ @@ -202,58 +466,98 @@ buf[2] = 0x00; i = 3; - if (write(fd, buf, i) < i) { - close(fd); - return -1; + if (write(source, buf, i) < i) { + debug_printf("unable to write\n"); + close(source); + phb->func(phb->data, -1, GDK_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; } - if (read(fd, buf, 2) < 2) { - close(fd); - return -1; - } + phb->inpa = gdk_input_add(source, GDK_INPUT_READ, s5_canread, phb); +} - if ((buf[0] != 0x05) || (buf[1] == 0xff)) { - close(fd); +static int proxy_connect_socks5(char *host, unsigned short port, + char *proxyhost, unsigned short proxyport, + struct PHB *phb) +{ + int fd = -1; + struct sockaddr_in sin; + struct hostent *hp; + + debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", host, port, proxyhost, proxyport); + + if (!(hp = gethostbyname(proxyhost))) { + g_free(phb); return -1; } - buf[0] = 0x05; - buf[1] = 0x01; /* CONNECT */ - buf[2] = 0x00; /* reserved */ - buf[3] = 0x03; /* address type -- host name */ - buf[4] = hlen; - memcpy(buf + 5, host, hlen); - buf[5 + strlen(host)] = port >> 8; - buf[5 + strlen(host) + 1] = port & 0xff; + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + sin.sin_port = htons(proxyport); - if (write(fd, buf, (5 + strlen(host) + 2)) < (5 + strlen(host) + 2)) { - close(fd); + if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { + g_free(phb); return -1; } - if (read(fd, buf, 10) < 10) { - close(fd); - return -1; - } - if ((buf[0] != 0x05) || (buf[1] != 0x00)) { - close(fd); - return -1; + + phb->host = g_strdup(host); + phb->port = port; + + fcntl(fd, F_SETFL, O_NONBLOCK); + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if ((errno == EINPROGRESS) || (errno == EINTR)) { + debug_printf("Connect would have blocked\n"); + phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, s5_canwrite, phb); + } else { + close(fd); + g_free(phb->host); + g_free(phb); + return -1; + } + } else { + int len, error = ETIMEDOUT; + debug_printf("Connect didn't block\n"); + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(fd); + g_free(phb->host); + g_free(phb); + return -1; + } + fcntl(fd, F_SETFL, 0); + s5_canwrite(phb, fd, GDK_INPUT_WRITE); } return fd; } -int proxy_connect(char *host, int port, char *proxyhost, int proxyport, int proxytype) +int proxy_connect(char *host, int port, + char *proxyhost, int proxyport, int proxytype, + GdkInputFunction func, gpointer data) { - if (!host || !port || (port == -1)) + struct PHB *phb = g_new0(struct PHB, 1); + phb->func = func; + phb->data = data; + + if (!host || !port || (port == -1) || !func) { + g_free(phb); return -1; - else if ((proxytype == PROXY_NONE) || + } + + if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || - !proxyport || (proxyport == -1)) return proxy_connect_none(host, port); + !proxyport || (proxyport == -1)) + return proxy_connect_none(host, port, phb); else if (proxytype == PROXY_HTTP) - return proxy_connect_http(host, port, proxyhost, proxyport); + return proxy_connect_http(host, port, proxyhost, proxyport, phb); else if (proxytype == PROXY_SOCKS4) - return proxy_connect_socks4(host, port, proxyhost, proxyport); + return proxy_connect_socks4(host, port, proxyhost, proxyport, phb); else if (proxytype == PROXY_SOCKS5) - return proxy_connect_socks5(host, port, proxyhost, proxyport); + return proxy_connect_socks5(host, port, proxyhost, proxyport, phb); + + g_free(phb); return -1; }
--- a/src/proxy.h Fri May 11 21:54:27 2001 +0000 +++ b/src/proxy.h Sat May 12 01:38:04 2001 +0000 @@ -30,12 +30,15 @@ #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> +#include <gtk/gtk.h> #define PROXY_NONE 0 #define PROXY_HTTP 1 #define PROXY_SOCKS4 2 #define PROXY_SOCKS5 3 -extern int proxy_connect(char *host, int port, char *proxyhost, int proxyport, int proxytype); +extern int proxy_connect(char *host, int port, + char *proxyhost, int proxyport, int proxytype, + GdkInputFunction func, gpointer data); #endif
--- a/src/toc.c Fri May 11 21:54:27 2001 +0000 +++ b/src/toc.c Sat May 12 01:38:04 2001 +0000 @@ -115,13 +115,14 @@ /* constants to identify proto_opts */ #define USEROPT_AUTH 0 #define USEROPT_AUTHPORT 1 -#define USEROPT_SOCKSHOST 2 -#define USEROPT_SOCKSPORT 3 +#define USEROPT_PROXYHOST 2 +#define USEROPT_PROXYPORT 3 #define USEROPT_PROXYTYPE 4 static GtkWidget *join_chat_spin = NULL; static GtkWidget *join_chat_entry = NULL; +static void toc_login_callback(gpointer, gint, GdkInputCondition); static void toc_callback(gpointer, gint, GdkInputCondition); static unsigned char *roast_password(char *); static void accept_file_dialog(struct ft_request *); @@ -140,28 +141,41 @@ g_snprintf(buf, sizeof buf, "Looking up %s", user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST); - /* this is such a hack */ set_login_progress(gc, 1, buf); - while (gtk_events_pending()) - gtk_main_iteration(); - if (!g_slist_find(connections, gc)) - return; + debug_printf("* Client connects to TOC\n"); tdt->toc_fd = proxy_connect(user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST, - user->proto_opt[USEROPT_AUTHPORT][0] ? atoi(user-> - proto_opt[USEROPT_AUTHPORT]) : - TOC_PORT, user->proto_opt[USEROPT_SOCKSHOST], - atoi(user->proto_opt[USEROPT_SOCKSPORT]), - atoi(user->proto_opt[USEROPT_PROXYTYPE])); + user->proto_opt[USEROPT_AUTHPORT][0] ? + atoi(user->proto_opt[USEROPT_AUTHPORT]) : TOC_PORT, + user->proto_opt[USEROPT_PROXYHOST], + atoi(user->proto_opt[USEROPT_PROXYPORT]), + atoi(user->proto_opt[USEROPT_PROXYTYPE]), + toc_login_callback, gc); - debug_printf("* Client connects to TOC\n"); if (tdt->toc_fd < 0) { g_snprintf(buf, sizeof(buf), "Connect to %s failed", user->proto_opt[USEROPT_AUTH]); hide_login_progress(gc, buf); signoff(gc); return; } +} + +static void toc_login_callback(gpointer data, gint source, GdkInputCondition cond) +{ + struct gaim_connection *gc = data; + struct toc_data *tdt = gc->proto_data; + char buf[80]; + + if (source == -1) { + /* we didn't successfully connect. tdt->toc_fd is valid here */ + hide_login_progress(gc, "Unable to connect."); + signoff(gc); + return; + } + + if (tdt->toc_fd == 0) + tdt->toc_fd = source; debug_printf("* Client sends \"FLAPON\\r\\n\\r\\n\"\n"); if (write(tdt->toc_fd, FLAPON, strlen(FLAPON)) < 0) { @@ -280,6 +294,14 @@ return rp; } +static void toc_got_info(gpointer data, char *url_text) +{ + if (!url_text) + return; + + g_show_info_text(url_text); +} + static void toc_callback(gpointer data, gint source, GdkInputCondition condition) { struct gaim_connection *gc = (struct gaim_connection *)data; @@ -557,8 +579,13 @@ name = strtok(NULL, ":"); url = strtok(NULL, ":"); - g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", TOC_HOST, TOC_PORT, url); - g_show_info(gc->user, tmp); + g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", + gc->user->proto_opt[USEROPT_AUTH][0] ? + gc->user->proto_opt[USEROPT_AUTH] : TOC_HOST, + gc->user->proto_opt[USEROPT_AUTHPORT][0] ? + atoi(gc->user->proto_opt[USEROPT_AUTHPORT]) : TOC_PORT, + url); + grab_url(gc->user, tmp, toc_got_info, NULL); } else if (!strcasecmp(c, "DIR_STATUS")) { } else if (!strcasecmp(c, "ADMIN_NICK_STATUS")) { } else if (!strcasecmp(c, "ADMIN_PASSWD_STATUS")) { @@ -993,12 +1020,12 @@ } else if (entrynum == USEROPT_AUTHPORT) { g_snprintf(user->proto_opt[USEROPT_AUTHPORT], sizeof(user->proto_opt[USEROPT_AUTHPORT]), "%s", gtk_entry_get_text(entry)); - } else if (entrynum == USEROPT_SOCKSHOST) { - g_snprintf(user->proto_opt[USEROPT_SOCKSHOST], - sizeof(user->proto_opt[USEROPT_SOCKSHOST]), "%s", gtk_entry_get_text(entry)); - } else if (entrynum == USEROPT_SOCKSPORT) { - g_snprintf(user->proto_opt[USEROPT_SOCKSPORT], - sizeof(user->proto_opt[USEROPT_SOCKSPORT]), "%s", gtk_entry_get_text(entry)); + } else if (entrynum == USEROPT_PROXYHOST) { + g_snprintf(user->proto_opt[USEROPT_PROXYHOST], + sizeof(user->proto_opt[USEROPT_PROXYHOST]), "%s", gtk_entry_get_text(entry)); + } else if (entrynum == USEROPT_PROXYPORT) { + g_snprintf(user->proto_opt[USEROPT_PROXYPORT], + sizeof(user->proto_opt[USEROPT_PROXYPORT]), "%s", gtk_entry_get_text(entry)); } } @@ -1078,11 +1105,11 @@ entry = gtk_entry_new(); gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0); - gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_SOCKSHOST); + gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_PROXYHOST); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(toc_print_option), user); - if (user->proto_opt[USEROPT_SOCKSHOST][0]) { - debug_printf("setting text %s\n", user->proto_opt[USEROPT_SOCKSHOST]); - gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_SOCKSHOST]); + if (user->proto_opt[USEROPT_PROXYHOST][0]) { + debug_printf("setting text %s\n", user->proto_opt[USEROPT_PROXYHOST]); + gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_PROXYHOST]); } gtk_widget_show(entry); @@ -1097,11 +1124,11 @@ entry = gtk_entry_new(); gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0); - gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_SOCKSPORT); + gtk_object_set_user_data(GTK_OBJECT(entry), (void *)USEROPT_PROXYPORT); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(toc_print_option), user); - if (user->proto_opt[USEROPT_SOCKSPORT][0]) { - debug_printf("setting text %s\n", user->proto_opt[USEROPT_SOCKSPORT]); - gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_SOCKSPORT]); + if (user->proto_opt[USEROPT_PROXYPORT][0]) { + debug_printf("setting text %s\n", user->proto_opt[USEROPT_PROXYPORT]); + gtk_entry_set_text(GTK_ENTRY(entry), user->proto_opt[USEROPT_PROXYPORT]); } gtk_widget_show(entry); @@ -1375,6 +1402,7 @@ char *ip; int port; long size; + struct stat st; GtkWidget *window; int files; @@ -1521,6 +1549,23 @@ } } +static void toc_send_file_connect(gpointer data, gint src, GdkInputCondition cond) +{ + struct file_transfer *ft = data; + + if (src == -1) { + do_error_dialog(_("Could not connect for transfer!"), _("Error")); + g_free(ft->filename); + g_free(ft->cookie); + g_free(ft->user); + g_free(ft->ip); + g_free(ft); + return; + } + + ft->inpa = gdk_input_add(src, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_send_file_callback, ft); +} + static void toc_send_file(gpointer a, struct file_transfer *old_ft) { struct file_transfer *ft; @@ -1550,9 +1595,10 @@ fd = proxy_connect(ft->ip, ft->port, - user->proto_opt[USEROPT_SOCKSHOST], - atoi(user->proto_opt[USEROPT_SOCKSPORT]), - atoi(user->proto_opt[USEROPT_PROXYTYPE])); + user->proto_opt[USEROPT_PROXYHOST], + atoi(user->proto_opt[USEROPT_PROXYPORT]), + atoi(user->proto_opt[USEROPT_PROXYTYPE]), + toc_send_file_connect, ft); if (fd < 0) { do_error_dialog(_("Could not connect for transfer!"), _("Error")); g_free(ft->filename); @@ -1562,8 +1608,6 @@ g_free(ft); return; } - - ft->inpa = gdk_input_add(fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_send_file_callback, ft); } static void toc_get_file_callback(gpointer data, gint source, GdkInputCondition cond) @@ -1683,15 +1727,63 @@ } } +static void toc_get_file_connect(gpointer data, gint src, GdkInputCondition cond) +{ + struct file_transfer *ft = data; + struct file_header *hdr; + char *buf; + + if (src == -1) { + do_error_dialog(_("Could not connect for transfer!"), _("Error")); + fclose(ft->file); + g_free(ft->filename); + g_free(ft->cookie); + g_free(ft->user); + g_free(ft->ip); + g_free(ft); + return; + } + + hdr = (struct file_header *)ft; + hdr->magic[0] = 'O'; hdr->magic[1] = 'F'; hdr->magic[2] = 'T'; hdr->magic[3] = '2'; + hdr->hdrlen = htons(256); + hdr->hdrtype = htons(0x1108); + buf = frombase64(ft->cookie); + g_snprintf(hdr->bcookie, 8, "%s", buf); + g_free(buf); + hdr->totfiles = htons(1); hdr->filesleft = htons(1); + hdr->totparts = htons(1); hdr->partsleft = htons(1); + hdr->totsize = htonl((long)ft->st.st_size); /* combined size of all files */ + /* size = strlen("mm/dd/yyyy hh:mm sizesize 'name'\r\n") */ + hdr->size = htonl(28 + strlen(g_basename(ft->filename))); /* size of listing.txt */ + hdr->modtime = htonl(ft->st.st_mtime); + hdr->checksum = htonl(0x89f70000); /* uh... */ + g_snprintf(hdr->idstring, 32, "OFT_Windows ICBMFT V1.1 32"); + hdr->flags = 0x02; + hdr->lnameoffset = 0x1A; + hdr->lsizeoffset = 0x10; + g_snprintf(hdr->name, 64, "listing.txt"); + if (write(src, hdr, 256) < 0) { + do_error_dialog(_("Could not write file header!"), _("Error")); + fclose(ft->file); + g_free(ft->filename); + g_free(ft->cookie); + g_free(ft->user); + g_free(ft->ip); + g_free(ft); + return; + } + + ft->inpa = gdk_input_add(src, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_get_file_callback, ft); +} + static void toc_get_file(gpointer a, struct file_transfer *old_ft) { struct file_transfer *ft; - struct file_header *hdr; char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window)); int fd; struct aim_user *user; char *buf, buf2[BUF_LEN * 2]; - struct stat st; if (file_is_dir(dirname, old_ft->window)) return; @@ -1706,7 +1798,7 @@ g_free(ft); return; } - if (stat(dirname, &st)) { + if (stat(dirname, &ft->st)) { buf = g_strdup_printf("Unable to examine %s!", dirname); do_error_dialog(buf, "Error"); g_free(buf); @@ -1727,9 +1819,10 @@ fd = proxy_connect(ft->ip, ft->port, - user->proto_opt[USEROPT_SOCKSHOST], - atoi(user->proto_opt[USEROPT_SOCKSPORT]), - atoi(user->proto_opt[USEROPT_PROXYTYPE])); + user->proto_opt[USEROPT_PROXYHOST], + atoi(user->proto_opt[USEROPT_PROXYPORT]), + atoi(user->proto_opt[USEROPT_PROXYTYPE]), + toc_get_file_connect, ft); if (fd < 0) { do_error_dialog(_("Could not connect for transfer!"), _("Error")); fclose(ft->file); @@ -1740,38 +1833,6 @@ g_free(ft); return; } - - hdr = (struct file_header *)ft; - hdr->magic[0] = 'O'; hdr->magic[1] = 'F'; hdr->magic[2] = 'T'; hdr->magic[3] = '2'; - hdr->hdrlen = htons(256); - hdr->hdrtype = htons(0x1108); - buf = frombase64(ft->cookie); - g_snprintf(hdr->bcookie, 8, "%s", buf); - g_free(buf); - hdr->totfiles = htons(1); hdr->filesleft = htons(1); - hdr->totparts = htons(1); hdr->partsleft = htons(1); - hdr->totsize = htonl((long)st.st_size); /* combined size of all files */ - /* size = strlen("mm/dd/yyyy hh:mm sizesize 'name'\r\n") */ - hdr->size = htonl(28 + strlen(g_basename(ft->filename))); /* size of listing.txt */ - hdr->modtime = htonl(st.st_mtime); - hdr->checksum = htonl(0x89f70000); /* uh... */ - g_snprintf(hdr->idstring, 32, "OFT_Windows ICBMFT V1.1 32"); - hdr->flags = 0x02; - hdr->lnameoffset = 0x1A; - hdr->lsizeoffset = 0x10; - g_snprintf(hdr->name, 64, "listing.txt"); - if (write(fd, hdr, 256) < 0) { - do_error_dialog(_("Could not write file header!"), _("Error")); - fclose(ft->file); - g_free(ft->filename); - g_free(ft->cookie); - g_free(ft->user); - g_free(ft->ip); - g_free(ft); - return; - } - - ft->inpa = gdk_input_add(fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_get_file_callback, ft); } static void cancel_callback(gpointer a, struct file_transfer *ft) {