# HG changeset patch # User Mark Doliner # Date 1156713210 0 # Node ID 01daacf7b771baa885ca7f4931bb18e4114a4001 # Parent 33dc9f22b528f5047d609675843359e1b63975a9 [gaim-migrate @ 17060] Make gaim_url_fetch() cancelable and change Yahoo! to take advantage of the changes. Other stuff can be changed later, the important thing is that the API is there. committer: Tailor Script diff -r 33dc9f22b528 -r 01daacf7b771 doc/ChangeLog.API --- a/doc/ChangeLog.API Sun Aug 27 19:47:41 2006 +0000 +++ b/doc/ChangeLog.API Sun Aug 27 21:13:30 2006 +0000 @@ -122,6 +122,9 @@ * gaim_gethostbyname_async(): Renamed to gaim_dnsquery_a() and changed to return a pointer to a data structure that can be used to cancel the pending DNS query using gaim_dnsquery_destroy() + * gaim_url_fetch(): Renamed to gaim_util_fetch_url() and changed + to return a pointer to a data structer that can be used to cancel + the pending HTTP request using gaim_util_fetch_url_cancel(). * gaim_gtk_create_imhtml(): Added sw_ret() parameter * gaim_account_get_log(): Added create parameter * GAIM_CMD_P_VERYHIGH is now GAIM_CMD_P_VERY_HIGH @@ -283,7 +286,7 @@ * gaim_gtk_log_init() * gaim_gtk_log_get_handle() * gaim_gtk_log_uninit() - * gaim_url_fetch_request() + * gaim_util_fetch_url_request() * GaimMenuAction * gaim_menu_action_new() * gaim_menu_action_free() @@ -310,6 +313,8 @@ gaim_proxy_connect() request * gaim_dnsquery_destroy(): Can be used to cancel a pending DNS query. + * gaim_util_fetch_url_cancel(): Can be used to cancel a pending + call to gaim_util_fetch_url() or gaim_util_fetch_url_request(). Signals - Changed: (See the Doxygen docs for details on all signals.) * Signal propagation now stops after a handler returns a non-NULL value. diff -r 33dc9f22b528 -r 01daacf7b771 gtk/gtkprefs.c --- a/gtk/gtkprefs.c Sun Aug 27 19:47:41 2006 +0000 +++ b/gtk/gtkprefs.c Sun Aug 27 21:13:30 2006 +0000 @@ -526,26 +526,29 @@ } static void -theme_got_url(void *data, const char *themedata, size_t len) +theme_got_url(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *themedata, size_t len, const gchar *error_message) { FILE *f; gchar *path; - if (len == 0) + if ((error_message != NULL) || (len == 0)) return; f = gaim_mkstemp(&path, TRUE); fwrite(themedata, len, 1, f); fclose(f); - theme_install_theme(path, data); + theme_install_theme(path, user_data); g_unlink(path); g_free(path); } -static void theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, - guint info, guint t, gpointer data) { +static void +theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, + GtkSelectionData *sd, guint info, guint t, gpointer data) +{ gchar *name = (gchar *)sd->data; if ((sd->length >= 0) && (sd->format == 8)) { @@ -568,9 +571,9 @@ } else if (!g_ascii_strncasecmp(name, "http://", 7)) { /* Oo, a web drag and drop. This is where things * will start to get interesting */ - gaim_url_fetch(name, TRUE, NULL, FALSE, theme_got_url, ".tgz"); + gaim_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, ".tgz"); } else if (!g_ascii_strncasecmp(name, "https://", 8)) { - /* gaim_url_fetch() doesn't support HTTPS, but we want users + /* gaim_util_fetch_url() doesn't support HTTPS, but we want users * to be able to drag and drop links from the SF trackers, so * we'll try it as an HTTP URL. */ char *tmp = g_strdup(name + 1); @@ -578,7 +581,7 @@ tmp[1] = 't'; tmp[2] = 't'; tmp[3] = 'p'; - gaim_url_fetch(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz"); + gaim_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz"); g_free(tmp); } diff -r 33dc9f22b528 -r 01daacf7b771 gtk/plugins/relnot.c --- a/gtk/plugins/relnot.c Sun Aug 27 19:47:41 2006 +0000 +++ b/gtk/plugins/relnot.c Sun Aug 27 21:13:30 2006 +0000 @@ -42,14 +42,14 @@ #define MIN_CHECK_INTERVAL 60 * 60 * 24 static void -version_fetch_cb(void *ud, const char *data, size_t len) +version_fetch_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *changelog, size_t len, const gchar *error_message) { - const char *changelog = data; char *cur_ver, *formatted; GString *message; int i=0; - if(!changelog || !len) + if(error_message || !changelog || !len) return; while(changelog[i] && changelog[i] != '\n') i++; @@ -101,7 +101,7 @@ "gaim" #endif ); - gaim_url_fetch(url, TRUE, NULL, FALSE, version_fetch_cb, NULL); + gaim_util_fetch_url(url, TRUE, NULL, FALSE, version_fetch_cb, NULL); gaim_prefs_set_int("/plugins/gtk/relnot/last_check", time(NULL)); g_free(url); } diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/protocols/msn/msn.c --- a/libgaim/protocols/msn/msn.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/protocols/msn/msn.c Sun Aug 27 21:13:30 2006 +0000 @@ -1402,7 +1402,8 @@ return NULL; } -static void msn_got_photo(void *data, const char *url_text, size_t len); +static void msn_got_photo(GaimUtilFetchUrlData *url_data, gpointer data, + const gchar *url_text, size_t len, const gchar *error_message); #endif @@ -1424,7 +1425,8 @@ sect_info = TRUE; static void -msn_got_info(void *data, const char *url_text, size_t len) +msn_got_info(GaimUtilFetchUrlData *url_data, gpointer data, + const gchar *url_text, size_t len, const gchar *error_message) { MsnGetInfoData *info_data = (MsnGetInfoData *)data; char *stripped, *p, *q; @@ -1459,7 +1461,7 @@ tooltip_text = msn_tooltip_info_text(info_data); title = _("MSN Profile"); - if (url_text == NULL || strcmp(url_text, "") == 0) + if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) { g_snprintf(buf, 1024, "%s%s", tooltip_text, _("Error retrieving profile")); @@ -1824,20 +1826,22 @@ /* Try to put the photo in there too, if there's one */ if (photo_url_text) { - gaim_url_fetch(photo_url_text, FALSE, NULL, FALSE, msn_got_photo, + gaim_util_fetch_url(photo_url_text, FALSE, NULL, FALSE, msn_got_photo, info2_data); } else { /* Emulate a callback */ - msn_got_photo(info2_data, NULL, 0); + /* TODO: Huh? */ + msn_got_photo(NULL, info2_data, NULL, 0, NULL); } } static void -msn_got_photo(void *data, const char *url_text, size_t len) +msn_got_photo(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *url_text, size_t len, const gchar *error_message) { - MsnGetInfoStepTwoData *info2_data = (MsnGetInfoStepTwoData *)data; + MsnGetInfoStepTwoData *info2_data = (MsnGetInfoStepTwoData *)user_data; int id = -1; /* Unmarshall the saved state */ @@ -1849,7 +1853,7 @@ char *tooltip_text = info2_data->tooltip_text; /* Make sure the connection is still valid if we got here by fetching a photo url */ - if (url_text && + if (error_message == NULL || url_text != NULL || g_list_find(gaim_connections_get_all(), info_data->gc) == NULL) { gaim_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n"); @@ -1866,7 +1870,7 @@ } /* Try to put the photo in there too, if there's one and is readable */ - if (data && url_text && len != 0) + if (user_data && url_text && len != 0) { if (strstr(url_text, "400 Bad Request") || strstr(url_text, "403 Forbidden") @@ -1918,7 +1922,7 @@ url = g_strdup_printf("%s%s", PROFILE_URL, name); - gaim_url_fetch(url, FALSE, + gaim_util_fetch_url(url, FALSE, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)", TRUE, msn_got_info, data); diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/protocols/oscar/oscar.c --- a/libgaim/protocols/oscar/oscar.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/protocols/oscar/oscar.c Sun Aug 27 21:13:30 2006 +0000 @@ -1372,7 +1372,7 @@ return 1; } -/* XXX - Should use gaim_url_fetch for the below stuff */ +/* XXX - Should use gaim_util_fetch_url for the below stuff */ struct pieceofcrap { GaimConnection *gc; unsigned long offset; diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/protocols/yahoo/yahoo.c --- a/libgaim/protocols/yahoo/yahoo.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/protocols/yahoo/yahoo.c Sun Aug 27 21:13:30 2006 +0000 @@ -52,7 +52,7 @@ /* #define YAHOO_DEBUG */ static void yahoo_add_buddy(GaimConnection *gc, GaimBuddy *, GaimGroup *); -static void yahoo_login_page_cb(void *user_data, const char *buf, size_t len); +static void yahoo_login_page_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message); static void yahoo_set_status(GaimAccount *account, GaimStatus *status); static void @@ -1885,13 +1885,16 @@ break; case 13: if (!yd->wm) { + GaimUtilFetchUrlData *url_data; yd->wm = TRUE; if (yd->fd >= 0) close(yd->fd); if (gc->inpa) gaim_input_remove(gc->inpa); - gaim_url_fetch(WEBMESSENGER_URL, TRUE, "Gaim/" VERSION, FALSE, - yahoo_login_page_cb, gc); + url_data = gaim_util_fetch_url(WEBMESSENGER_URL, TRUE, + "Gaim/" VERSION, FALSE, yahoo_login_page_cb, gc); + if (url_data != NULL) + yd->url_datas = g_slist_prepend(yd->url_datas, url_data); gaim_notify_warning(gc, NULL, _("Normal authentication failed!"), _("The normal authentication method has failed. " "This means either your password is incorrect, " @@ -2523,14 +2526,16 @@ return hash; } -static void yahoo_login_page_cb(void *user_data, const char *buf, size_t len) +static void +yahoo_login_page_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *url_text, size_t len, const gchar *error_message) { GaimConnection *gc = (GaimConnection *)user_data; GaimAccount *account = gaim_connection_get_account(gc); struct yahoo_data *yd = gc->proto_data; const char *sn = gaim_account_get_username(account); const char *pass = gaim_connection_get_password(gc); - GHashTable *hash = yahoo_login_page_hash(buf, len); + GHashTable *hash = yahoo_login_page_hash(url_text, len); GString *url = g_string_new("GET http://login.yahoo.com/config/login?login="); char md5[33], *hashp = md5, *chal; int i; @@ -2538,6 +2543,8 @@ GaimCipherContext *context; guchar digest[16]; + yd->url_datas = g_slist_remove(yd->url_datas, url_data); + url = g_string_append(url, sn); url = g_string_append(url, "&passwd="); @@ -2709,6 +2716,11 @@ if (gc->inpa) gaim_input_remove(gc->inpa); + while (yd->url_datas) { + gaim_util_fetch_url_cancel(yd->url_datas->data); + yd->url_datas = g_slist_delete_link(yd->url_datas, yd->url_datas); + } + for (l = yd->confs; l; l = l->next) { GaimConversation *conv = l->data; diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/protocols/yahoo/yahoo.h --- a/libgaim/protocols/yahoo/yahoo.h Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/protocols/yahoo/yahoo.h Sun Aug 27 21:13:30 2006 +0000 @@ -139,6 +139,12 @@ struct yahoo_buddy_icon_upload_data *picture_upload_todo; struct _YchtConn *ycht; + + /** + * This linked list contains GaimUtilFetchUrlData structs + * for when we lookup people profile or photo information. + */ + GSList *url_datas; }; #define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255) diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/protocols/yahoo/yahoo_picture.c --- a/libgaim/protocols/yahoo/yahoo_picture.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/protocols/yahoo/yahoo_picture.c Sun Aug 27 21:13:30 2006 +0000 @@ -43,18 +43,27 @@ int checksum; }; -static void yahoo_fetch_picture_cb(void *user_data, const char *pic_data, size_t len) +static void +yahoo_fetch_picture_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *pic_data, size_t len, const gchar *error_message) { - struct yahoo_fetch_picture_data *d = user_data; + struct yahoo_fetch_picture_data *d; + struct yahoo_data *yd; GaimBuddy *b; - if (GAIM_CONNECTION_IS_VALID(d->gc) && len) { + d = user_data; + yd = d->gc->proto_data; + yd->url_datas = g_slist_remove(yd->url_datas, url_data); + + if (error_message != NULL) { + gaim_debug_error("yahoo", "Fetching buddy icon failed: %s\n", error_message); + } else if (len == 0) { + gaim_debug_error("yahoo", "Fetched an icon with length 0. Strange.\n"); + } else { gaim_buddy_icons_set_for_user(gaim_connection_get_account(d->gc), d->who, (void *)pic_data, len); b = gaim_find_buddy(gaim_connection_get_account(d->gc), d->who); if (b) gaim_blist_node_set_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY, d->checksum); - } else { - gaim_debug_error("yahoo", "Fetching buddy icon failed.\n"); } g_free(d->who); @@ -63,6 +72,7 @@ void yahoo_process_picture(GaimConnection *gc, struct yahoo_packet *pkt) { + struct yahoo_data *yd; GSList *l = pkt->hash; char *who = NULL, *us = NULL; gboolean got_icon_info = FALSE, send_icon_info = FALSE; @@ -104,6 +114,7 @@ /* Yahoo IM 6 spits out 0.png as the URL if the buddy icon is not set */ if (who && got_icon_info && url && !strncasecmp(url, "http://", 7)) { /* TODO: make this work p2p, try p2p before the url */ + GaimUtilFetchUrlData *url_data; struct yahoo_fetch_picture_data *data; GaimBuddy *b = gaim_find_buddy(gc->account, who); if (b && (checksum == gaim_blist_node_get_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY))) @@ -113,8 +124,16 @@ data->gc = gc; data->who = g_strdup(who); data->checksum = checksum; - gaim_url_fetch(url, FALSE, "Mozilla/4.0 (compatible; MSIE 5.0)", FALSE, - yahoo_fetch_picture_cb, data); + url_data = gaim_util_fetch_url(url, FALSE, + "Mozilla/4.0 (compatible; MSIE 5.0)", FALSE, + yahoo_fetch_picture_cb, data); + if (url_data != NULL) { + yd = gc->proto_data; + yd->url_datas = g_slist_prepend(yd->url_datas, url_data); + } else { + g_free(data->who); + g_free(data); + } } else if (who && send_icon_info) { yahoo_send_picture_info(gc, who); } diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/protocols/yahoo/yahoo_profile.c --- a/libgaim/protocols/yahoo/yahoo_profile.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/protocols/yahoo/yahoo_profile.c Sun Aug 27 21:13:30 2006 +0000 @@ -742,13 +742,16 @@ return it; } -static void yahoo_got_photo(void *data, const char *url_text, size_t len); +static void +yahoo_got_photo(GaimUtilFetchUrlData *url_data, gpointer data, + const gchar *url_text, size_t len, const gchar *error_message); #endif /* PHOTO_SUPPORT */ -static void yahoo_got_info(void *data, const char *url_text, size_t len) +static void yahoo_got_info(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *url_text, size_t len, const gchar *error_message) { - YahooGetInfoData *info_data = (YahooGetInfoData *)data; + YahooGetInfoData *info_data = (YahooGetInfoData *)user_data; char *p; char buf[1024]; #if PHOTO_SUPPORT @@ -771,26 +774,22 @@ const char *title; profile_state_t profile_state = PROFILE_STATE_DEFAULT; - if (!GAIM_CONNECTION_IS_VALID(info_data->gc)) { - g_free(info_data->name); - g_free(info_data); - return; - } - gaim_debug_info("yahoo", "In yahoo_got_info\n"); yd = info_data->gc->proto_data; - title = (yd->jp? _("Yahoo! Japan Profile") : - _("Yahoo! Profile")); + yd->url_datas = g_slist_remove(yd->url_datas, url_data); + + title = yd->jp ? _("Yahoo! Japan Profile") : + _("Yahoo! Profile"); /* Get the tooltip info string */ tooltip_text = yahoo_tooltip_info_text(info_data); - + /* We failed to grab the profile URL. This is not expected to actually * happen except under unusual error conditions, as Yahoo is observed * to send back HTML, with a 200 status code. */ - if (url_text == NULL || strcmp(url_text, "") == 0) { + if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) { g_snprintf(buf, 1024, "%s%s", tooltip_text, _("Error retrieving profile")); @@ -920,21 +919,32 @@ /* Try to put the photo in there too, if there's one */ if (photo_url_text) { + GaimUtilFetchUrlData *url_data; /* User-uploaded photos use a different server that requires the Host * header, but Yahoo Japan will use the "chunked" content encoding if - * we specify HTTP 1.1. So we have to specify 1.0 & fix gaim_url_fetch + * we specify HTTP 1.1. So we have to specify 1.0 & fix gaim_util_fetch_url */ - gaim_url_fetch(photo_url_text, FALSE, NULL, FALSE, yahoo_got_photo, - info2_data); + url_data = gaim_util_fetch_url(photo_url_text, FALSE, NULL, + FALSE, yahoo_got_photo, info2_data); + if (url_data != NULL) + yd->url_datas = g_slist_prepend(yd->url_datas, url_data); + else { + g_free(info2_data->info_data->name); + g_free(info2_data->info_data); + g_free(info2_data); + } } else { /* Emulate a callback */ - yahoo_got_photo(info2_data, NULL, 0); + yahoo_got_photo(NULL, info2_data, NULL, 0, NULL); } } -static void yahoo_got_photo(void *data, const char *url_text, size_t len) +static void +yahoo_got_photo(GaimUtilFetchUrlData *url_data, gpointer data, + const gchar *url_text, size_t len, const gchar *error_message) { YahooGetInfoStepTwoData *info2_data = (YahooGetInfoStepTwoData *)data; + struct yahoo_data *yd; gboolean found = FALSE; int id = -1; @@ -962,6 +972,10 @@ /* and not \n. The prpl's need to be audited before it can be moved */ /* in to gaim_markup_strip_html*/ char *fudged_buffer; + + yd = info_data->gc->proto_data; + yd->url_datas = g_slist_remove(yd->url_datas, url_data); + fudged_buffer = gaim_strcasereplace(url_buffer, "", "
"); /* nuke the html, it's easier than trying to parse the horrid stuff */ stripped = gaim_markup_strip_html(fudged_buffer); @@ -1197,7 +1211,6 @@ "however, Yahoo! sometimes does fail to find a user's " "profile. If you know that the user exists, " "please try again later.")); - } else { g_string_append_printf(s, "%s

", _("The user's profile is empty.")); @@ -1245,15 +1258,22 @@ struct yahoo_data *yd = gc->proto_data; YahooGetInfoData *data; char *url; + GaimUtilFetchUrlData *url_data; data = g_new0(YahooGetInfoData, 1); data->gc = gc; data->name = g_strdup(name); url = g_strdup_printf("%s%s", - (yd->jp? YAHOOJP_PROFILE_URL: YAHOO_PROFILE_URL), name); + (yd->jp ? YAHOOJP_PROFILE_URL : YAHOO_PROFILE_URL), name); - gaim_url_fetch(url, TRUE, NULL, FALSE, yahoo_got_info, data); + url_data = gaim_util_fetch_url(url, TRUE, NULL, FALSE, yahoo_got_info, data); + if (url_data != NULL) + yd->url_datas = g_slist_prepend(yd->url_datas, url_data); + else { + g_free(data->name); + g_free(data); + } g_free(url); } diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/upnp.c --- a/libgaim/upnp.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/upnp.c Sun Aug 27 21:13:30 2006 +0000 @@ -150,7 +150,6 @@ static void lookup_public_ip(void); static void lookup_internal_ip(void); - static void fire_discovery_callbacks(gboolean success) { @@ -164,7 +163,6 @@ } } - static gboolean gaim_upnp_compare_device(const xmlnode* device, const gchar* deviceType) { @@ -183,7 +181,6 @@ return ret; } - static gboolean gaim_upnp_compare_service(const xmlnode* service, const gchar* serviceType) { @@ -208,7 +205,6 @@ return ret; } - static gchar* gaim_upnp_parse_description_response(const gchar* httpResponse, gsize len, const gchar* httpURL, const gchar* serviceType) @@ -358,9 +354,10 @@ } static void -upnp_parse_description_cb(void *data, const char *httpResponse, gsize len) +upnp_parse_description_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *httpResponse, gsize len, const gchar *error_message) { - UPnPDiscoveryData *dd = data; + UPnPDiscoveryData *dd = user_data; gchar *control_url = NULL; if (len > 0) @@ -431,7 +428,7 @@ gaim_timeout_remove(dd->tima); dd->tima = 0; - gaim_url_fetch_request(descriptionURL, TRUE, NULL, TRUE, httpRequest, + gaim_util_fetch_url_request(descriptionURL, TRUE, NULL, TRUE, httpRequest, TRUE, upnp_parse_description_cb, dd); g_free(httpRequest); @@ -548,7 +545,7 @@ /* We'll either time out or continue successfully */ } -void +static void gaim_upnp_discover_send_broadcast(UPnPDiscoveryData *dd) { gchar *sendMessage = NULL; @@ -598,7 +595,6 @@ gaim_timeout_add(10, gaim_upnp_discover_timeout, dd); } - void gaim_upnp_discover(GaimUPnPCallback cb, gpointer cb_data) { @@ -661,7 +657,7 @@ static void gaim_upnp_generate_action_message_and_send(const gchar* actionName, - const gchar* actionParams, GaimURLFetchCallback cb, + const gchar* actionParams, GaimUtilFetchUrlCallback cb, gpointer cb_data) { @@ -678,7 +674,7 @@ "generate_action_message_and_send(): Failed In Parse URL\n\n"); /* XXX: This should probably be async */ if(cb) - cb(cb_data, NULL, 0); + cb(NULL, cb_data, NULL, 0, NULL); } if(port == 0 || port == -1) { port = DEFAULT_HTTP_PORT; @@ -696,14 +692,13 @@ g_free(pathOfControl); g_free(soapMessage); - gaim_url_fetch_request(control_info.control_url, FALSE, NULL, TRUE, + gaim_util_fetch_url_request(control_info.control_url, FALSE, NULL, TRUE, totalSendMessage, TRUE, cb, cb_data); g_free(totalSendMessage); g_free(addressOfControl); } - const gchar * gaim_upnp_get_public_ip() { @@ -722,11 +717,12 @@ } static void -looked_up_public_ip_cb(gpointer data, const char *httpResponse, gsize len) +looked_up_public_ip_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *httpResponse, gsize len, const gchar *error_message) { gchar* temp, *temp2; - if(!httpResponse) + if ((error_message != NULL) || (httpResponse == NULL)) return; /* extract the ip, or see if there is an error */ @@ -754,7 +750,7 @@ gaim_debug_info("upnp", "NAT Returned IP: %s\n", control_info.publicip); } -void +static void lookup_public_ip() { gaim_upnp_generate_action_message_and_send("GetExternalIPAddress", "", @@ -794,7 +790,7 @@ } -void +static void lookup_internal_ip() { gchar* addressOfControl; @@ -821,14 +817,17 @@ } static void -done_port_mapping_cb(gpointer data, const gchar *httpResponse, gsize len) +done_port_mapping_cb(GaimUtilFetchUrlData *url_data, gpointer user_data, + const gchar *httpResponse, gsize len, const gchar *error_message) { - UPnPMappingAddRemove *ar = data; + UPnPMappingAddRemove *ar = user_data; gboolean success = TRUE; /* determine if port mapping was a success */ - if(!httpResponse || g_strstr_len(httpResponse, len, HTTP_OK) == NULL) { + if ((error_message != NULL) || (httpResponse == NULL) || + (g_strstr_len(httpResponse, len, HTTP_OK) == NULL)) + { gaim_debug_error("upnp", "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse ? httpResponse : "(null)"); diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/util.c --- a/libgaim/util.c Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/util.c Sun Aug 27 21:13:30 2006 +0000 @@ -29,9 +29,9 @@ #include "prefs.h" #include "util.h" -typedef struct +struct _GaimUtilFetchUrlData { - void (*callback)(void *, const char *, size_t); + GaimUtilFetchUrlCallback callback; void *user_data; struct @@ -52,15 +52,16 @@ gsize request_written; gboolean include_headers; - int inpa; + GaimProxyConnectData *connect_data; + int fd; + guint inpa; gboolean got_headers; gboolean has_explicit_data_len; char *webdata; unsigned long len; unsigned long data_len; - -} GaimFetchUrlData; +}; static char custom_home_dir[MAXPATHLEN]; static char home_dir[MAXPATHLEN]; @@ -3059,24 +3060,28 @@ return TRUE; } +/** + * The arguments to this function are similar to printf. + */ static void -destroy_fetch_url_data(GaimFetchUrlData *gfud) +gaim_util_fetch_url_error(GaimUtilFetchUrlData *gfud, const char *format, ...) { - g_free(gfud->webdata); - g_free(gfud->url); - g_free(gfud->user_agent); - g_free(gfud->website.address); - g_free(gfud->website.page); - g_free(gfud->website.user); - g_free(gfud->website.passwd); - g_free(gfud->request); - - g_free(gfud); + gchar *error_message; + va_list args; + + va_start(args, format); + error_message = g_strdup_vprintf(format, args); + va_end(args); + + gfud->callback(gfud, gfud->user_data, NULL, 0, error_message); + g_free(error_message); + gaim_util_fetch_url_cancel(gfud); } +/* TODO: This totally destroys cancelability. */ static gboolean parse_redirect(const char *data, size_t data_len, gint sock, - GaimFetchUrlData *gfud) + GaimUtilFetchUrlData *gfud) { gchar *s; @@ -3116,20 +3121,16 @@ 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); + gaim_debug_info("util", "Redirecting to %s\n", new_url); /* Try again, with this new location. */ - gaim_url_fetch_request(new_url, full, gfud->user_agent, + gaim_util_fetch_url_request(new_url, full, gfud->user_agent, gfud->http11, NULL, gfud->include_headers, gfud->callback, gfud->user_data); - /* Free up. */ + /* Free the old connection */ g_free(new_url); - destroy_fetch_url_data(gfud); + gaim_util_fetch_url_cancel(gfud); return TRUE; } @@ -3173,7 +3174,7 @@ */ if (p && g_strstr_len(p, data_len - (p - data), "\n")) { sscanf(p, "%" G_GSIZE_FORMAT, &content_len); - gaim_debug_misc("parse_content_len", "parsed %u\n", content_len); + gaim_debug_misc("util", "parsed %u\n", content_len); } return content_len; @@ -3183,14 +3184,14 @@ static void url_fetch_recv_cb(gpointer url_data, gint source, GaimInputCondition cond) { - GaimFetchUrlData *gfud = url_data; + GaimUtilFetchUrlData *gfud = url_data; int len; char buf[4096]; char *data_cursor; gboolean got_eof = FALSE; while((len = read(source, buf, sizeof(buf))) > 0) { - /* If we've filled up our butfer, make it bigger */ + /* If we've filled up our buffer, make it bigger */ if((gfud->len + len) >= gfud->data_len) { while((gfud->len + len) >= gfud->data_len) gfud->data_len += sizeof(buf); @@ -3209,13 +3210,13 @@ if(!gfud->got_headers) { char *tmp; - /** See if we've reached the end of the headers yet */ + /* See if we've reached the end of the headers yet */ if((tmp = strstr(gfud->webdata, "\r\n\r\n"))) { char * new_data; guint header_len = (tmp + 4 - gfud->webdata); size_t content_len; - gaim_debug_misc("gaim_url_fetch", "Response headers: '%.*s'\n", + gaim_debug_misc("util", "Response headers: '%.*s'\n", header_len, gfud->webdata); /* See if we can find a redirect. */ @@ -3249,12 +3250,14 @@ new_data = g_try_malloc(content_len); if(new_data == NULL) { - gaim_debug_error("gaim_url_fetch", "Failed to allocate %u bytes: %s\n", - content_len, strerror(errno)); - gaim_input_remove(gfud->inpa); - close(source); - gfud->callback(gfud->user_data, NULL, 0); - destroy_fetch_url_data(gfud); + gaim_debug_error("util", + "Failed to allocate %u bytes: %s\n", + content_len, strerror(errno)); + gaim_util_fetch_url_error(gfud, + _("Unable to allocate enough memory to hold " + "the contents from %s. The web server may " + "be trying something malicious."), + gfud->website.address); return; } @@ -3288,12 +3291,8 @@ } else if(errno != ETIMEDOUT) { got_eof = TRUE; } else { - gaim_input_remove(gfud->inpa); - close(source); - - gfud->callback(gfud->user_data, NULL, 0); - - destroy_fetch_url_data(gfud); + gaim_util_fetch_url_error(gfud, _("Error reading from %s: %s"), + gfud->website.address, strerror(errno)); return; } } @@ -3302,63 +3301,59 @@ 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(source); - gfud->callback(gfud->user_data, gfud->webdata, gfud->len); - - destroy_fetch_url_data(gfud); + gfud->callback(gfud, gfud->user_data, gfud->webdata, gfud->len, NULL); + gaim_util_fetch_url_cancel(gfud); } } static void url_fetch_send_cb(gpointer data, gint source, GaimInputCondition cond) { - GaimFetchUrlData *gfud; + GaimUtilFetchUrlData *gfud; int len, total_len; gfud = data; total_len = strlen(gfud->request); - len = write(source, gfud->request + gfud->request_written, + len = write(gfud->fd, gfud->request + gfud->request_written, total_len - gfud->request_written); - if(len < 0 && errno == EAGAIN) + if (len < 0 && errno == EAGAIN) return; - else if(len < 0) { - gaim_input_remove(gfud->inpa); - close(source); - gfud->callback(gfud->user_data, NULL, 0); - destroy_fetch_url_data(gfud); + else if (len < 0) { + gaim_util_fetch_url_error(gfud, _("Error writing to %s: %s"), + gfud->website.address, strerror(errno)); return; } gfud->request_written += len; - if(gfud->request_written != total_len) + if (gfud->request_written != total_len) return; - /* We're done writing, now start reading */ + /* We're done writing our request, now start reading the response */ gaim_input_remove(gfud->inpa); - gfud->inpa = gaim_input_add(source, GAIM_INPUT_READ, url_fetch_recv_cb, + gfud->inpa = gaim_input_add(gfud->fd, GAIM_INPUT_READ, url_fetch_recv_cb, gfud); } static void url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message) { - GaimFetchUrlData *gfud; + GaimUtilFetchUrlData *gfud; gfud = url_data; + gfud->connect_data = NULL; if (source == -1) { - gfud->callback(gfud->user_data, NULL, 0); - destroy_fetch_url_data(gfud); + gaim_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"), + gfud->website.address, error_message); return; } + gfud->fd = source; + if (!gfud->request) { if (gfud->user_agent) { @@ -3390,31 +3385,31 @@ } } - gaim_debug_misc("gaim_url_fetch", "Request: '%s'\n", gfud->request); + gaim_debug_misc("util", "Request: '%s'\n", gfud->request); gfud->inpa = gaim_input_add(source, GAIM_INPUT_WRITE, url_fetch_send_cb, gfud); url_fetch_send_cb(gfud, source, GAIM_INPUT_WRITE); } -void -gaim_url_fetch_request(const char *url, gboolean full, +GaimUtilFetchUrlData * +gaim_util_fetch_url_request(const char *url, gboolean full, const char *user_agent, gboolean http11, const char *request, gboolean include_headers, - GaimURLFetchCallback cb, void *user_data) + GaimUtilFetchUrlCallback callback, void *user_data) { - GaimFetchUrlData *gfud; - - g_return_if_fail(url != NULL); - g_return_if_fail(cb != NULL); - - gaim_debug_info("gaim_url_fetch", + GaimUtilFetchUrlData *gfud; + + g_return_val_if_fail(url != NULL, NULL); + g_return_val_if_fail(callback != NULL, NULL); + + gaim_debug_info("util", "requested to fetch (%s), full=%d, user_agent=(%s), http11=%d\n", url, full, user_agent?user_agent:"(null)", http11); - gfud = g_new0(GaimFetchUrlData, 1); - - gfud->callback = cb; + gfud = g_new0(GaimUtilFetchUrlData, 1); + + gfud->callback = callback; gfud->user_data = user_data; gfud->url = g_strdup(url); gfud->user_agent = g_strdup(user_agent); @@ -3426,13 +3421,42 @@ gaim_url_parse(url, &gfud->website.address, &gfud->website.port, &gfud->website.page, &gfud->website.user, &gfud->website.passwd); - if (gaim_proxy_connect(NULL, gfud->website.address, - gfud->website.port, url_fetch_connect_cb, gfud) == NULL) + gfud->connect_data = gaim_proxy_connect(NULL, + gfud->website.address, gfud->website.port, + url_fetch_connect_cb, gfud); + + if (gfud->connect_data == NULL) { - destroy_fetch_url_data(gfud); - - cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); + gaim_util_fetch_url_error(gfud, _("Unable to connect to %s"), + gfud->website.address); + return NULL; } + + return gfud; +} + +void +gaim_util_fetch_url_cancel(GaimUtilFetchUrlData *gfud) +{ + if (gfud->connect_data != NULL) + gaim_proxy_connect_cancel(gfud->connect_data); + + if (gfud->inpa > 0) + gaim_input_remove(gfud->inpa); + + if (gfud->fd >= 0) + close(gfud->fd); + + g_free(gfud->website.user); + g_free(gfud->website.passwd); + g_free(gfud->website.address); + g_free(gfud->website.page); + g_free(gfud->url); + g_free(gfud->user_agent); + g_free(gfud->request); + g_free(gfud->webdata); + + g_free(gfud); } const char * diff -r 33dc9f22b528 -r 01daacf7b771 libgaim/util.h --- a/libgaim/util.h Sun Aug 27 19:47:41 2006 +0000 +++ b/libgaim/util.h Sun Aug 27 21:13:30 2006 +0000 @@ -37,6 +37,8 @@ extern "C" { #endif +typedef struct _GaimUtilFetchUrlData GaimUtilFetchUrlData; + typedef struct _GaimMenuAction { char *label; @@ -823,7 +825,22 @@ gboolean gaim_url_parse(const char *url, char **ret_host, int *ret_port, char **ret_path, char **ret_user, char **ret_passwd); -typedef void (*GaimURLFetchCallback) (gpointer data, const char *buf, gsize len); +/** + * This is the signature used for functions that act as the callback + * to gaim_util_fetch_url() or gaim_util_fetch_url_request(). + * + * @param url_data The same value that was returned when you called + * gaim_fetch_url() or gaim_fetch_url_request(). + * @param user_data The user data that your code passed into either + * gaim_util_fetch_url() or gaim_util_fetch_url_request(). + * @param url_text This will be NULL on error. Otherwise this + * will contain the contents of the URL. + * @param len 0 on error, otherwise this is the length of buf. + * @param error_message If something went wrong then this will contain + * a descriptive error message, and buf will be + * NULL and len will be 0. + */ +typedef void (*GaimUtilFetchUrlCallback)(GaimUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message); /** * Fetches the data from a URL, and passes it to a callback function. @@ -836,8 +853,8 @@ * @param cb The callback function. * @param data The user data to pass to the callback function. */ -#define gaim_url_fetch(url, full, user_agent, http11, cb, data) \ - gaim_url_fetch_request(url, full, user_agent, http11, NULL, \ +#define gaim_util_fetch_url(url, full, user_agent, http11, cb, data) \ + gaim_util_fetch_url_request(url, full, user_agent, http11, NULL, \ FALSE, cb, data); /** @@ -850,15 +867,23 @@ * @param http11 TRUE if HTTP/1.1 should be used to download the file. * @param request A HTTP request to send to the server instead of the * standard GET - * @param include_headers if TRUE, include the HTTP headers in the - * response - * @param cb The callback function. + * @param include_headers + * If TRUE, include the HTTP headers in the response. + * @param callback The callback function. * @param data The user data to pass to the callback function. */ -void gaim_url_fetch_request(const char *url, gboolean full, - const char *user_agent, gboolean http11, - const char *request, gboolean include_headers, - GaimURLFetchCallback cb, void *data); +GaimUtilFetchUrlData *gaim_util_fetch_url_request(const gchar *url, + gboolean full, const gchar *user_agent, gboolean http11, + const gchar *request, gboolean include_headers, + GaimUtilFetchUrlCallback callback, gpointer data); + +/** + * Cancel a pending URL request started with either + * gaim_util_fetch_url_request() or gaim_util_fetch_url(). + * + * @param url_data The data returned when you initiated the URL fetch. + */ +void gaim_util_fetch_url_cancel(GaimUtilFetchUrlData *url_data); /** * Decodes a URL into a plain string.