Mercurial > pidgin.yaz
diff src/util.c @ 7094:2343c3aa1dec
[gaim-migrate @ 7659]
grab_url() and parse_url() are gone, replaced with gaim_url_fetch() and
gaim_url_parse(). They were also moved to util.[ch].
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Wed, 01 Oct 2003 03:01:25 +0000 |
parents | acd2a66e59ed |
children | c8bf2da398e3 |
line wrap: on
line diff
--- a/src/util.c Wed Oct 01 02:06:12 2003 +0000 +++ b/src/util.c Wed Oct 01 03:01:25 2003 +0000 @@ -1,7 +1,9 @@ /* - * gaim + * @file util.h Utility Functions + * @ingroup core * * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> + * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,15 +18,44 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ - #include "internal.h" #include "conversation.h" #include "debug.h" #include "prpl.h" #include "prefs.h" +#include "util.h" + +typedef struct +{ + void (*callback)(void *, const char *, size_t); + void *user_data; + + struct + { + char *address; + int port; + char *page; + + } website; + + char *url; + gboolean full; + char *user_agent; + gboolean http11; + + int inpa; + + gboolean sentreq; + gboolean newline; + gboolean startsaving; + char *webdata; + unsigned long len; + unsigned long data_len; + +} GaimFetchUrlData; + static char home_dir[MAXPATHLEN]; @@ -996,14 +1027,17 @@ } } -gboolean gaim_markup_find_tag(const char *needle, const char *haystack, const char **start, const char **end, GData **attributes) { +gboolean +gaim_markup_find_tag(const char *needle, const char *haystack, + const char **start, const char **end, GData **attributes) +{ GData *attribs; const char *cur = haystack; char *name = NULL; gboolean found = FALSE; gboolean in_tag = FALSE; gboolean in_attr = FALSE; - char *in_quotes = NULL; + const char *in_quotes = NULL; size_t needlelen = strlen(needle); g_datalist_init(&attribs); @@ -1133,3 +1167,332 @@ return found; } + +gboolean +gaim_url_parse(const char *url, char **ret_host, int *ret_port, + char **ret_path) +{ + char scan_info[255]; + char port_str[5]; + int f; + const char *turl; + char host[256], path[256]; + int port = 0; + /* hyphen at end includes it in control set */ + static char addr_ctrl[] = "A-Za-z0-9.-"; + static char port_ctrl[] = "0-9"; + static char page_ctrl[] = "A-Za-z0-9.~_/:*!@&%%?=+^-"; + + g_return_val_if_fail(url != NULL, FALSE); + + if ((turl = strstr(url, "http://")) != NULL || + (turl = strstr(url, "HTTP://")) != NULL) + { + turl += 7; + url = turl; + } + + g_snprintf(scan_info, sizeof(scan_info), + "%%[%s]:%%[%s]/%%[%s]", addr_ctrl, port_ctrl, page_ctrl); + + f = sscanf(url, scan_info, host, port_str, path); + + if (f == 1) + { + g_snprintf(scan_info, sizeof(scan_info), + "%%[%s]/%%[%s]", + addr_ctrl, page_ctrl); + f = sscanf(url, scan_info, host, path); + g_snprintf(port_str, sizeof(port_str), "80"); + } + + if (f == 1) + *path = '\0'; + + sscanf(port_str, "%d", &port); + + if (ret_host != NULL) *ret_host = g_strdup(host); + if (ret_port != NULL) *ret_port = port; + if (ret_path != NULL) *ret_path = g_strdup(path); + + return TRUE; +} + +static void +destroy_fetch_url_data(GaimFetchUrlData *gfud) +{ + if (gfud->webdata != NULL) g_free(gfud->webdata); + if (gfud->url != NULL) g_free(gfud->url); + if (gfud->user_agent != NULL) g_free(gfud->user_agent); + if (gfud->website.address != NULL) g_free(gfud->website.address); + if (gfud->website.page != NULL) g_free(gfud->website.page); + + g_free(gfud); +} + +static gboolean +parse_redirect(const char *data, size_t data_len, gint sock, + GaimFetchUrlData *gfud) +{ + gchar *s; + + if ((s = g_strstr_len(data, data_len, "Location: ")) != NULL) + { + gchar *new_url, *temp_url, *end; + gboolean full; + int len; + + s += strlen("Location: "); + end = strchr(s, '\r'); + + /* Just in case :) */ + if (end == NULL) + end = strchr(s, '\n'); + + len = end - s; + + new_url = g_malloc(len + 1); + strncpy(new_url, s, len); + new_url[len] = '\0'; + + full = gfud->full; + + if (*new_url == '/' || g_strstr_len(new_url, len, "://") == NULL) + { + temp_url = new_url; + + new_url = g_strdup_printf("%s:%d%s", gfud->website.address, + gfud->website.port, temp_url); + + g_free(temp_url); + + full = FALSE; + } + + /* Close the existing stuff. */ + gaim_input_remove(gfud->inpa); + close(sock); + + gaim_debug_info("gaim_url_fetch", "Redirecting to %s\n", new_url); + + /* Try again, with this new location. */ + gaim_url_fetch(new_url, full, gfud->user_agent, gfud->http11, + gfud->callback, gfud->user_data); + + /* Free up. */ + g_free(new_url); + destroy_fetch_url_data(gfud); + + return TRUE; + } + + return FALSE; +} + +static size_t +parse_content_len(const char *data, size_t data_len) +{ + size_t content_len = 0; + + sscanf(data, "Content-Length: %d", &content_len); + + return content_len; +} + +static void +url_fetched_cb(gpointer url_data, gint sock, GaimInputCondition cond) +{ + GaimFetchUrlData *gfud = url_data; + char data; + + if (sock == -1) + { + gfud->callback(gfud->user_data, NULL, 0); + + destroy_fetch_url_data(gfud); + + return; + } + + if (!gfud->sentreq) + { + char buf[1024]; + + if (gfud->user_agent) + { + if (gfud->http11) + { + g_snprintf(buf, sizeof(buf), + "GET %s%s HTTP/1.1\r\n" + "User-Agent: \"%s\"\r\n" + "Host: %s\r\n\r\n", + (gfud->full ? "" : "/"), + (gfud->full ? gfud->url : gfud->website.page), + gfud->user_agent, gfud->website.address); + } + else + { + g_snprintf(buf, sizeof(buf), + "GET %s%s HTTP/1.0\r\n" + "User-Agent: \"%s\"\r\n\r\n", + (gfud->full ? "" : "/"), + (gfud->full ? gfud->url : gfud->website.page), + gfud->user_agent); + } + } + else + { + if (gfud->http11) + { + g_snprintf(buf, sizeof(buf), + "GET %s%s HTTP/1.1\r\n" + "Host: %s\r\n\r\n", + (gfud->full ? "" : "/"), + (gfud->full ? gfud->url : gfud->website.page), + gfud->website.address); + } + else + { + g_snprintf(buf, sizeof(buf), + "GET %s%s HTTP/1.0\r\n\r\n", + (gfud->full ? "" : "/"), + (gfud->full ? gfud->url : gfud->website.page)); + } + } + + gaim_debug_misc("gaim_url_fetch", "Request: %s\n", buf); + + write(sock, buf, strlen(buf)); + fcntl(sock, F_SETFL, O_NONBLOCK); + gfud->sentreq = TRUE; + gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ, + url_fetched_cb, url_data); + gfud->data_len = 4096; + gfud->webdata = g_malloc(gfud->data_len); + + return; + } + + if (read(sock, &data, 1) > 0 || errno == EWOULDBLOCK) + { + if (errno == EWOULDBLOCK) + { + errno = 0; + + return; + } + + gfud->len++; + + if (gfud->len == gfud->data_len + 1) + { + gfud->data_len += (gfud->data_len) / 2; + + gfud->webdata = g_realloc(gfud->webdata, gfud->data_len); + } + + gfud->webdata[gfud->len - 1] = data; + + if (!gfud->startsaving) + { + if (data == '\r') + return; + + if (data == '\n') + { + if (gfud->newline) + { + size_t content_len; + gfud->startsaving = TRUE; + + /* See if we can find a redirect. */ + if (parse_redirect(gfud->webdata, gfud->len, sock, gfud)) + return; + + /* No redirect. See if we can find a content length. */ + content_len = parse_content_len(gfud->webdata, gfud->len); + + if (content_len == 0) + { + /* We'll stick with an initial 8192 */ + content_len = 8192; + } + + /* Out with the old... */ + gfud->len = 0; + g_free(gfud->webdata); + gfud->webdata = NULL; + + /* In with the new. */ + gfud->data_len = content_len; + gfud->webdata = g_malloc(gfud->data_len); + } + else + gfud->newline = TRUE; + + return; + } + + gfud->newline = FALSE; + } + } + else if (errno != ETIMEDOUT) + { + gfud->webdata = g_realloc(gfud->webdata, gfud->len + 1); + gfud->webdata[gfud->len] = 0; + + gaim_debug_misc("gaim_url_fetch", "Received: '%s'\n", gfud->webdata); + + gaim_input_remove(gfud->inpa); + close(sock); + gfud->callback(gfud->user_data, gfud->webdata, gfud->len); + + if (gfud->webdata) + g_free(gfud->webdata); + + destroy_fetch_url_data(gfud); + } + else + { + gaim_input_remove(gfud->inpa); + close(sock); + + gfud->callback(gfud->user_data, NULL, 0); + + destroy_fetch_url_data(gfud); + } +} + +void +gaim_url_fetch(const char *url, gboolean full, + const char *user_agent, gboolean http11, + void (*cb)(gpointer, const char *, size_t), + void *user_data) +{ + int sock; + GaimFetchUrlData *gfud; + + g_return_if_fail(url != NULL); + g_return_if_fail(cb != NULL); + + gfud = g_new0(GaimFetchUrlData, 1); + + gfud->callback = cb; + gfud->user_data = user_data; + gfud->url = g_strdup(url); + gfud->user_agent = (user_agent != NULL ? g_strdup(user_agent) : NULL); + gfud->http11 = http11; + gfud->full = full; + + gaim_url_parse(url, &gfud->website.address, &gfud->website.port, + &gfud->website.page); + + if ((sock = gaim_proxy_connect(NULL, gfud->website.address, + gfud->website.port, url_fetched_cb, + gfud)) < 0) + { + destroy_fetch_url_data(gfud); + + cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); + } +}