Hi I finally got round to the second part of my IDNA work, which is allowing the decoded versions of the domain names to be displayed in the status and URL bars.
This adds an option display_decoded_idn (default is false) which, when enabled, will pass decoded UTF-8 URLs to the status bar and - with an appropriate frontend tweak (I've done GTK, RISC OS and Amiga) - also to the URL bar. When switched off operation is as at present and the code change is minimal. This is in branch chris/display-idna and attached for convenience. Chris
diff --git a/amiga/gui.c b/amiga/gui.c index b7f3285..dc49a69 100644 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -4996,9 +4996,21 @@ static nserror gui_window_set_url(struct gui_window *g, nsurl *url) if(!g) return NSERROR_OK; if (g == g->shared->gw) { - RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_URL], - g->shared->win, NULL, STRINGA_TextVal, - nsurl_access(url), TAG_DONE); + if(nsoption_bool(display_decoded_idn) == false) { + RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_URL], + g->shared->win, NULL, + STRINGA_TextVal, nsurl_access(url), + TAG_DONE); + } else { + char *idn_url = nsurl_access_utf8(url); + char *idn_url_lc = ami_utf8_easy(idn_url); + RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_URL], + g->shared->win, NULL, + STRINGA_TextVal, idn_url_lc, + TAG_DONE); + free(idn_url); + ami_utf8_free(idn_url_lc); + } } ami_update_buttons(g->shared); diff --git a/desktop/options.h b/desktop/options.h index 33ecb75..f01261e 100644 --- a/desktop/options.h +++ b/desktop/options.h @@ -185,6 +185,9 @@ NSOPTION_UINT(min_reflow_period, DEFAULT_REFLOW_PERIOD) /* use core selection menu */ NSOPTION_BOOL(core_select_menu, false) +/* display decoded international domain names */ +NSOPTION_BOOL(display_decoded_idn, false) + /******** Fetcher options ********/ /** Maximum simultaneous active fetchers */ diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c index 4506ac2..dc03d94 100644 --- a/gtk/scaffolding.c +++ b/gtk/scaffolding.c @@ -2346,7 +2346,13 @@ nserror gui_window_set_url(struct gui_window *gw, nsurl *url) g = nsgtk_get_scaffold(gw); if (g->top_level == gw) { - gtk_entry_set_text(GTK_ENTRY(g->url_bar), nsurl_access(url)); + if (nsoption_bool(display_decoded_idn) == false) { + gtk_entry_set_text(GTK_ENTRY(g->url_bar), nsurl_access(url)); + } else { + char *idn_url = nsurl_access_utf8(url); + gtk_entry_set_text(GTK_ENTRY(g->url_bar), idn_url); + free(idn_url); + } gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1); } return NSERROR_OK; diff --git a/render/html_interaction.c b/render/html_interaction.c index 6e2a2df..af84174 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -300,6 +300,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE; const char *title = 0; nsurl *url = 0; + char *idn_url = NULL; const char *target = 0; char status_buffer[200]; const char *status = 0; @@ -814,12 +815,22 @@ void html_mouse_action(struct content *c, struct browser_window *bw, y - html_object_pos_y); } } else if (url) { + if (nsoption_bool(display_decoded_idn) == true) { + idn_url = nsurl_access_utf8(url); + } + if (title) { snprintf(status_buffer, sizeof status_buffer, "%s: %s", - nsurl_access(url), title); - status = status_buffer; - } else - status = nsurl_access(url); + idn_url ? idn_url : nsurl_access(url), title); + } else { + snprintf(status_buffer, sizeof status_buffer, "%s", + idn_url ? idn_url : nsurl_access(url)); + } + + status = status_buffer; + + if (idn_url != NULL) + free(idn_url); pointer = get_pointer_shape(url_box, imagemap); diff --git a/riscos/window.c b/riscos/window.c index 097ab9e..dbed46d 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -1038,8 +1038,16 @@ void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) /* exported function documented in riscos/window.h */ nserror ro_gui_window_set_url(struct gui_window *g, nsurl *url) { + char *idn_url = NULL; + if (g->toolbar) { - ro_toolbar_set_url(g->toolbar, nsurl_access(url), true, false); + if (nsoption_bool(display_decoded_idn) == false) { + ro_toolbar_set_url(g->toolbar, nsurl_access(url), true, false); + } else { + idn_url = nsurl_access_utf8(url); + ro_toolbar_set_url(g->toolbar, idn_url, true, false); + free(idn_url); + } ro_gui_url_complete_start(g->toolbar); } diff --git a/utils/nsurl.c b/utils/nsurl.c index 8d53be8..78647b4 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1698,6 +1698,56 @@ const char *nsurl_access(const nsurl *url) return url->string; } +char *nsurl_access_utf8(const nsurl *url) +{ + lwc_string *host; + char *idna_host; + size_t idna_host_len; + char *scheme; + size_t scheme_len; + char *path; + size_t path_len; + char *idna_url; + size_t idna_url_len; + + assert(url != NULL); + + host = nsurl_get_component(url, NSURL_HOST); + + if(host == NULL) { + return strdup(url->string); + } + + if (idna_decode(lwc_string_data(host), lwc_string_length(host), + &idna_host, &idna_host_len) != NSERROR_OK) { + lwc_string_unref(host); + return strdup(url->string); + } + + lwc_string_unref(host); + + if (nsurl_get(url, NSURL_SCHEME | NSURL_CREDENTIALS, + &scheme, &scheme_len) != NSERROR_OK) { + return strdup(url->string); + } + + if (nsurl_get(url, NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT, + &path, &path_len) != NSERROR_OK) { + return strdup(url->string); + } + + idna_url_len = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */ + idna_url = malloc(idna_url_len); + + if (idna_url == NULL) { + return strdup(url->string); + } + + snprintf(idna_url, idna_url_len, "%s%s%s", scheme, idna_host, path); + + return(idna_url); +} + /* exported interface, documented in nsurl.h */ const char *nsurl_access_leaf(const nsurl *url) diff --git a/utils/nsurl.h b/utils/nsurl.h index b84f55e..07d73f1 100644 --- a/utils/nsurl.h +++ b/utils/nsurl.h @@ -181,6 +181,20 @@ const char *nsurl_access(const nsurl *url); /** + * Access a NetSurf URL object as a UTF-8 string (for human readable IDNA) + * + * \param url NetSurf URL to retrieve a string pointer for. + * \return the required string + * + * It is up to the client to free the returned string when they have + * finished with it. + * + * The returned string has a trailing '\0'. + */ +char *nsurl_access_utf8(const nsurl *url); + + +/** * Access a URL's path leaf as a string * * \param url NetSurf URL to retrieve a string pointer for.