From 5f5ca2c20587e035278163c9b444b36cfff6dced Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 17 Jul 2015 19:18:20 +0100 Subject: [PATCH 01/10] Add a function to retrieve the decoded version of IDNA URLs --- utils/nsurl.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ utils/nsurl.h | 14 ++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/utils/nsurl.c b/utils/nsurl.c index 8d53be84f..bb3054df1 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1698,6 +1698,51 @@ const char *nsurl_access(const nsurl *url) return url->string; } +const 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 (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, + &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 b84f55eed..4fbc17b49 100644 --- a/utils/nsurl.h +++ b/utils/nsurl.h @@ -180,6 +180,20 @@ bool nsurl_has_component(const nsurl *url, nsurl_component part); 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'. + */ +const char *nsurl_access_utf8(const nsurl *url); + + /** * Access a URL's path leaf as a string * From 6afda499c290bea17fe2bcf5fcd257a1770528cf Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 17 Jul 2015 19:44:26 +0100 Subject: [PATCH 02/10] Show the IDN decoded form in the URL bar on GTK if the option is set. --- desktop/options.h | 3 +++ gtk/scaffolding.c | 8 +++++++- utils/nsurl.c | 2 +- utils/nsurl.h | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/desktop/options.h b/desktop/options.h index 33ecb7554..f01261ee1 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 4506ac27f..dc03d9453 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/utils/nsurl.c b/utils/nsurl.c index bb3054df1..6a9296022 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1698,7 +1698,7 @@ const char *nsurl_access(const nsurl *url) return url->string; } -const char *nsurl_access_utf8(const nsurl *url) +char *nsurl_access_utf8(const nsurl *url) { lwc_string *host; char *idna_host; diff --git a/utils/nsurl.h b/utils/nsurl.h index 4fbc17b49..07d73f17f 100644 --- a/utils/nsurl.h +++ b/utils/nsurl.h @@ -191,7 +191,7 @@ const char *nsurl_access(const nsurl *url); * * The returned string has a trailing '\0'. */ -const char *nsurl_access_utf8(const nsurl *url); +char *nsurl_access_utf8(const nsurl *url); /** From 920cb0571d93f956385e193389dd1f564efc5304 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 17 Jul 2015 20:44:52 +0100 Subject: [PATCH 03/10] Check we've obtained the host string --- utils/nsurl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/nsurl.c b/utils/nsurl.c index 6a9296022..6675ee1a7 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1713,6 +1713,11 @@ char *nsurl_access_utf8(const nsurl *url) 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); From dd38897a26cf888d2c546b7db9da8ec125a37b53 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 17 Jul 2015 20:59:49 +0100 Subject: [PATCH 04/10] Enable Amiga frontend to show decoded IDNs subject to local charset restrictions. TODO: Statusbar link text --- amiga/gui.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/amiga/gui.c b/amiga/gui.c index b4f3b136d..8c2fde542 100644 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -4895,9 +4895,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); From 53141c70899962fbcf88e56d08a7ecd8d5e15f9c Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 18 Jul 2015 19:29:46 +0100 Subject: [PATCH 05/10] Modify the status bar link text so it shows either the ASCII encoded or IDN host, depending on the set option. Default is to display the encoded version as this provides some security making phishing domains more obvious, and a lot of our frontends are unable to display the full range of UTF-8 characters on the status bar. Displaying the decoded address in the URL bar requires frontends to be updated (GTK and Amiga done already), and the same caveats apply. --- render/html_interaction.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/render/html_interaction.c b/render/html_interaction.c index 6e2a2df4c..af8417448 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); From ac8eccd035a4676938fb08d70b23bc4dfb9fa4d6 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 18 Jul 2015 19:48:13 +0100 Subject: [PATCH 06/10] Enable RISC OS to display decoded IDNs in the URL bar (subject to local charset restrictions) --- riscos/window.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/riscos/window.c b/riscos/window.c index 097ab9ee6..dbed46d2a 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); } From 5206518a75d34cdf03a5118276e7ba4c106b6bfc Mon Sep 17 00:00:00 2001 From: Chris Young Date: Mon, 20 Jul 2015 19:23:54 +0100 Subject: [PATCH 07/10] Add URL fragment --- utils/nsurl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/nsurl.c b/utils/nsurl.c index 6675ee1a7..78647b4ae 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1731,7 +1731,7 @@ char *nsurl_access_utf8(const nsurl *url) return strdup(url->string); } - if (nsurl_get(url, NSURL_PORT | NSURL_PATH | NSURL_QUERY, + if (nsurl_get(url, NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT, &path, &path_len) != NSERROR_OK) { return strdup(url->string); } From 65b510fbc3ad822ab8c75e6d94eaee5b6ceb07a4 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 23 Jul 2015 00:05:22 +0100 Subject: [PATCH 08/10] Rework IDN URL retrieval to return an nserror --- amiga/gui.c | 32 ++++++++++++----------- render/html_interaction.c | 17 ++++++++----- utils/nsurl.c | 53 ++++++++++++++++++++------------------- utils/nsurl.h | 16 +++++++----- 4 files changed, 66 insertions(+), 52 deletions(-) diff --git a/amiga/gui.c b/amiga/gui.c index 8c2fde542..afc05bf67 100644 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -4892,23 +4892,27 @@ static void gui_window_set_status(struct gui_window *g, const char *text) static nserror gui_window_set_url(struct gui_window *g, nsurl *url) { + size_t idn_url_l; + char *idn_url_s = NULL; + char *url_lc = NULL; + if(!g) return NSERROR_OK; if (g == g->shared->gw) { - 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); + if(nsoption_bool(display_decoded_idn) == true) { + if (nsurl_access_utf8(url, &idn_url_s, &idn_url_l) == NSERROR_OK) { + url_lc = ami_utf8_easy(idn_url_s); + } + } + + RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_URL], + g->shared->win, NULL, + STRINGA_TextVal, url_lc ? url_lc : nsurl_access(url), + TAG_DONE); + + if(url_lc) { + ami_utf8_free(url_lc); + if(idn_url_s) free(idn_url_s); } } diff --git a/render/html_interaction.c b/render/html_interaction.c index af8417448..1b2e5b9c9 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -300,7 +300,8 @@ 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; + char *url_s = NULL; + size_t url_l = 0; const char *target = 0; char status_buffer[200]; const char *status = 0; @@ -816,21 +817,25 @@ void html_mouse_action(struct content *c, struct browser_window *bw, } } else if (url) { if (nsoption_bool(display_decoded_idn) == true) { - idn_url = nsurl_access_utf8(url); + if (nsurl_access_utf8(url, &url_s, &url_l) != NSERROR_OK) { + /* Unable to obtain a decoded IDN. This is not a fatal error. + * Ensure the string pointer is NULL so we use the encoded version. */ + url_s = NULL; + } } if (title) { snprintf(status_buffer, sizeof status_buffer, "%s: %s", - idn_url ? idn_url : nsurl_access(url), title); + url_s ? url_s : nsurl_access(url), title); } else { snprintf(status_buffer, sizeof status_buffer, "%s", - idn_url ? idn_url : nsurl_access(url)); + url_s ? url_s : nsurl_access(url)); } status = status_buffer; - if (idn_url != NULL) - free(idn_url); + if (url_s != NULL) + free(url_s); pointer = get_pointer_shape(url_box, imagemap); diff --git a/utils/nsurl.c b/utils/nsurl.c index 78647b4ae..ed6d896b6 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1698,8 +1698,11 @@ const char *nsurl_access(const nsurl *url) return url->string; } -char *nsurl_access_utf8(const nsurl *url) + +/* exported interface, documented in nsurl.h */ +nserror nsurl_access_utf8(const nsurl *url, char **url_s, size_t *url_l) { + nserror err; lwc_string *host; char *idna_host; size_t idna_host_len; @@ -1707,45 +1710,43 @@ char *nsurl_access_utf8(const nsurl *url) 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(host == NULL) + return NSERROR_BAD_URL; - 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); - } + err = idna_decode(lwc_string_data(host), lwc_string_length(host), + &idna_host, &idna_host_len); lwc_string_unref(host); - if (nsurl_get(url, NSURL_SCHEME | NSURL_CREDENTIALS, - &scheme, &scheme_len) != NSERROR_OK) { - return strdup(url->string); - } + if (err != NSERROR_OK) + return err; - if (nsurl_get(url, NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT, - &path, &path_len) != NSERROR_OK) { - return strdup(url->string); - } + err = nsurl_get(url, NSURL_SCHEME | NSURL_CREDENTIALS, + &scheme, &scheme_len); - idna_url_len = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */ - idna_url = malloc(idna_url_len); + if (err != NSERROR_OK) + return err; - if (idna_url == NULL) { - return strdup(url->string); - } + err = nsurl_get(url, NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT, + &path, &path_len); - snprintf(idna_url, idna_url_len, "%s%s%s", scheme, idna_host, path); + if (err != NSERROR_OK) + return err; - return(idna_url); + *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */ + *url_s = malloc(*url_l); + + if (*url_s == NULL) + return NSERROR_NOMEM; + + snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path); + + return NSERROR_OK; } diff --git a/utils/nsurl.h b/utils/nsurl.h index 07d73f17f..383b35711 100644 --- a/utils/nsurl.h +++ b/utils/nsurl.h @@ -181,17 +181,21 @@ const char *nsurl_access(const nsurl *url); /** - * Access a NetSurf URL object as a UTF-8 string (for human readable IDNA) + * Access a NetSurf URL object as a UTF-8 string (for human readable IDNs) * * \param url NetSurf URL to retrieve a string pointer for. - * \return the required string + * \param url_s Returns a url string + * \param url_l Returns length of url_s + * \return NSERROR_OK on success, appropriate error otherwise * - * It is up to the client to free the returned string when they have - * finished with it. + * If return value != NSERROR_OK, nothing will be returned in url_s or url_l. * - * The returned string has a trailing '\0'. + * The string returned in url_s is owned by the client and it is up to them + * to free it. It includes a trailing '\0'. + * + * The length returned in url_l excludes the trailing '\0'. */ -char *nsurl_access_utf8(const nsurl *url); +nserror nsurl_access_utf8(const nsurl *url, char **url_s, size_t *url_l); /** From 27adf07fb7752ede0d3a5f874d7c85f2e71c47c2 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sun, 26 Jul 2015 18:09:25 +0100 Subject: [PATCH 09/10] Update gtk frontend to new API --- amiga/gui.c | 2 +- gtk/scaffolding.c | 18 ++++++++++++------ utils/nsurl.h | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/amiga/gui.c b/amiga/gui.c index afc05bf67..cfd6b44b2 100644 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -4898,7 +4898,7 @@ static nserror gui_window_set_url(struct gui_window *g, nsurl *url) if(!g) return NSERROR_OK; - if (g == g->shared->gw) { + if(g == g->shared->gw) { if(nsoption_bool(display_decoded_idn) == true) { if (nsurl_access_utf8(url, &idn_url_s, &idn_url_l) == NSERROR_OK) { url_lc = ami_utf8_easy(idn_url_s); diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c index dc03d9453..ef1b4ade7 100644 --- a/gtk/scaffolding.c +++ b/gtk/scaffolding.c @@ -2343,16 +2343,22 @@ void nsgtk_window_set_title(struct gui_window *gw, const char *title) nserror gui_window_set_url(struct gui_window *gw, nsurl *url) { struct nsgtk_scaffolding *g; + size_t idn_url_l; + char *idn_url_s = NULL; + nserror err; g = nsgtk_get_scaffold(gw); if (g->top_level == gw) { - 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); + if (nsoption_bool(display_decoded_idn) == true) { + if (nsurl_access_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) + idn_url_s = NULL; } + + gtk_entry_set_text(GTK_ENTRY(g->url_bar), idn_url_s ? idn_url_s : nsurl_access(url)); + + if(idn_url_s) + free(idn_url_s); + gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1); } return NSERROR_OK; diff --git a/utils/nsurl.h b/utils/nsurl.h index 383b35711..85e46dfd6 100644 --- a/utils/nsurl.h +++ b/utils/nsurl.h @@ -183,7 +183,7 @@ const char *nsurl_access(const nsurl *url); /** * Access a NetSurf URL object as a UTF-8 string (for human readable IDNs) * - * \param url NetSurf URL to retrieve a string pointer for. + * \param url NetSurf URL object * \param url_s Returns a url string * \param url_l Returns length of url_s * \return NSERROR_OK on success, appropriate error otherwise From aabea8eceb8d77cef934e7b4d0cd2015f1103411 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sun, 26 Jul 2015 18:11:58 +0100 Subject: [PATCH 10/10] Update RISC OS frontend to new API --- gtk/scaffolding.c | 1 - riscos/window.c | 18 +++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c index ef1b4ade7..a9904debf 100644 --- a/gtk/scaffolding.c +++ b/gtk/scaffolding.c @@ -2345,7 +2345,6 @@ nserror gui_window_set_url(struct gui_window *gw, nsurl *url) struct nsgtk_scaffolding *g; size_t idn_url_l; char *idn_url_s = NULL; - nserror err; g = nsgtk_get_scaffold(gw); if (g->top_level == gw) { diff --git a/riscos/window.c b/riscos/window.c index dbed46d2a..59c24ac8a 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -1038,16 +1038,20 @@ 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; + size_t idn_url_l; + char *idn_url_s = NULL; if (g->toolbar) { - 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); + if (nsoption_bool(display_decoded_idn) == true) { + if (nsurl_access_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) + idn_url_s = NULL; } + + ro_toolbar_set_url(g->toolbar, idn_url_s ? idn_url_s : nsurl_access(url), true, false); + + if (idn_url_s) + free(idn_url_s); + ro_gui_url_complete_start(g->toolbar); }