From a6d3ceae0ee7cee85020a70b716586425a042900 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 25 May 2014 00:57:48 +0100 Subject: Completely re-write web search provider handling --- amiga/context_menu.c | 31 +-- amiga/gui.c | 85 +++--- amiga/gui_options.c | 3 +- amiga/search.h | 2 - amiga/theme.c | 4 - content/fetchers/resource.c | 1 + desktop/gui.h | 19 +- desktop/gui_factory.c | 44 ++- desktop/netsurf.c | 4 +- desktop/searchweb.c | 644 ++++++++++++++++++++++++++++---------------- desktop/searchweb.h | 96 ++++--- gtk/dialogs/preferences.c | 26 +- gtk/gui.c | 18 +- gtk/scaffolding.c | 119 ++++---- gtk/scaffolding.h | 6 +- gtk/search.c | 30 ++- gtk/toolbar.c | 3 +- 17 files changed, 684 insertions(+), 451 deletions(-) diff --git a/amiga/context_menu.c b/amiga/context_menu.c index e1ce5516e..f4fd09272 100644 --- a/amiga/context_menu.c +++ b/amiga/context_menu.c @@ -982,26 +982,27 @@ static uint32 ami_context_menu_hook(struct Hook *hook,Object *item,APTR reserved case CMID_SELSEARCH: { char *sel; - char *urltxt; - nsurl *url; if(sel = browser_window_get_selection(gwin->bw)) { - urltxt = search_web_from_term(sel); - - if (nsurl_create(urltxt, &url) != NSERROR_OK) { - warn_user("NoMemory", 0); - } else { - browser_window_navigate(gwin->bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); + nserror ret; + nsurl *url; + + ret = search_web_omni(sel, SEARCH_WEB_OMNI_NONE, &url); + free(sel); + if (ret == NSERROR_OK) { + ret = browser_window_navigate(gwin->bw, + url, + NULL, + BW_NAVIGATE_HISTORY, + NULL, + NULL, + NULL); nsurl_unref(url); } - free(sel); + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), 0); + } } } break; diff --git a/amiga/gui.c b/amiga/gui.c index 11f38d498..079ce0aee 100644 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -687,7 +687,7 @@ static nserror ami_set_options(struct nsoption_s *defaults) (char *)strdup("PROGDIR:Resources/ca-bundle")); - search_engines_file_location = nsoption_charp(search_engines_file); + search_web_init(nsoption_charp(search_engines_file)); sprintf(temp, "%s/FontGlyphCache", current_user_dir); nsoption_setnull_charp(font_unicode_file, @@ -1000,7 +1000,7 @@ static void gui_init2(int argc, char** argv) ami_cookies_initialise(); ami_global_history_initialise(); - search_web_provider_details(nsoption_int(search_provider)); + search_web_select_provider(nsoption_int(search_provider)); if (notalreadyrunning && (nsoption_bool(startup_no_window) == false)) @@ -1878,18 +1878,17 @@ void ami_handle_msg(void) break; case GID_URL: + { + nserror ret; + nsurl *url; GetAttr(STRINGA_TextVal, (Object *)gwin->objects[GID_URL], (ULONG *)&storage); - if(utf8 = ami_to_utf8_easy((const char *)storage)) { - if(search_is_url((char *)utf8) == false) - { - utf8 = search_web_from_term(utf8); - } + utf8 = ami_to_utf8_easy((const char *)storage); - if (nsurl_create((char *)utf8, &url) != NSERROR_OK) { - warn_user("NoMemory", 0); - } else { + ret = search_web_omni(utf8, SEARCH_WEB_OMNI_NONE, &url); + ami_utf8_free(utf8); + if (ret == NSERROR_OK) { browser_window_navigate(gwin->bw, url, NULL, @@ -1898,29 +1897,32 @@ void ami_handle_msg(void) NULL, NULL); nsurl_unref(url); - } - ami_utf8_free(utf8); - } else { - warn_user("NoMemory", 0); } + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), 0); + } + } break; case GID_TOOLBARLAYOUT: /* Need fixing: never gets here */ - search_web_retrieve_ico(false); + search_web_select_provider(-1); break; case GID_SEARCHSTRING: + { + nserror ret; + nsurl *url; + GetAttr(STRINGA_TextVal, (Object *)gwin->objects[GID_SEARCHSTRING], (ULONG *)&storage); - if(utf8 = ami_to_utf8_easy((const char *)storage)) { - storage = (ULONG)search_web_from_term(utf8); - ami_utf8_free(utf8); - if (nsurl_create((char *)storage, &url) != NSERROR_OK) { - warn_user("NoMemory", 0); - } else { + utf8 = ami_to_utf8_easy((const char *)storage); + + ret = search_web_omni(utf8, SEARCH_WEB_OMNI_SEARCHONLY, &url); + ami_utf8_free(utf8); + if (ret == NSERROR_OK) { browser_window_navigate(gwin->bw, url, NULL, @@ -1928,11 +1930,13 @@ void ami_handle_msg(void) NULL, NULL, NULL); - nsurl_unref(url); - } - } else { - warn_user("NoMemory", 0); + nsurl_unref(url); + } + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), 0); } + + } break; case GID_HOME: @@ -3873,7 +3877,9 @@ gui_window_create(struct browser_window *bw, glob = &browserglob; if(locked_screen) UnlockPubScreen(NULL,scrn); - search_web_retrieve_ico(false); + + /* set web search provider */ + search_web_select_provider(nsoption_int(search_provider)); ScreenToFront(scrn); @@ -4772,12 +4778,14 @@ static uint32 ami_set_favicon_render_hook(struct Hook *hook, APTR space, } /** - * set gui display of a retrieved favicon representing the search - * provider - * \param ico may be NULL for local calls; then access current cache from - * search_web_ico() + * Gui callback when search provider details are updated. + * + * \param provider_name The providers name. + * \param ico_bitmap The icon bitmap representing the provider. + * \return NSERROR_OK on success else error code. */ -static void gui_set_search_ico(hlcache_handle *ico) +nserror gui_search_web_provider_update(const char *provider_name, + struct bitmap *ico_bitmap) { struct BitMap *bm = NULL; struct IBox *bbox; @@ -4790,10 +4798,9 @@ static void gui_set_search_ico(hlcache_handle *ico) if(IsMinListEmpty(window_list)) return; if(nsoption_bool(kiosk_mode) == true) return; - if (ico == NULL) ico = search_web_ico(); - ico_bitmap = content_get_bitmap(ico); - if ((ico != NULL) && (ico_bitmap != NULL)) + if (ico_bitmap != NULL) { bm = ami_bitmap_get_native(ico_bitmap, 16, 16, NULL); + } node = (struct nsObject *)GetHead((struct List *)window_list); @@ -4807,7 +4814,7 @@ static void gui_set_search_ico(hlcache_handle *ico) RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_SEARCH_ICON], gwin->win, NULL, - GA_HintInfo, search_web_provider_name(), + GA_HintInfo, provider_name, TAG_DONE); EraseRect(gwin->win->RPort, bbox->Left, bbox->Top, @@ -4843,6 +4850,8 @@ static void gui_set_search_ico(hlcache_handle *ico) } } } while(node = nnode); + + return NSERROR_OK; } static uint32 ami_set_search_ico_render_hook(struct Hook *hook, APTR space, @@ -5214,12 +5223,15 @@ static struct gui_fetch_table amiga_fetch_table = { .get_resource_url = gui_get_resource_url, }; +static struct gui_search_web_table amiga_search_web_table = { + .provider_update = gui_search_web_provider_update, +}; + static struct gui_browser_table amiga_browser_table = { .poll = gui_poll, .schedule = ami_schedule, .quit = gui_quit, - .set_search_ico = gui_set_search_ico, .launch_url = gui_launch_url, .create_form_select_menu = gui_create_form_select_menu, .cert_verify = gui_cert_verify, @@ -5247,6 +5259,7 @@ int main(int argc, char** argv) .file = &amiga_file_table, .utf8 = amiga_utf8_table, .search = amiga_search_table, + .search_web = &amiga_search_web_table, .llcache = filesystem_llcache_table, }; diff --git a/amiga/gui_options.c b/amiga/gui_options.c index f3720425a..0b01a93d4 100755 --- a/amiga/gui_options.c +++ b/amiga/gui_options.c @@ -1811,8 +1811,7 @@ void ami_gui_opts_use(bool save) ami_gui_tabs_toggle_all(); GetAttr(CHOOSER_Selected,gow->objects[GID_OPTS_SEARCH_PROV],(ULONG *)&nsoption_int(search_provider)); - search_web_provider_details(nsoption_int(search_provider)); - search_web_retrieve_ico(false); + search_web_select_provider(nsoption_int(search_provider)); GetAttr(GA_Selected,gow->objects[GID_OPTS_CLIPBOARD],(ULONG *)&data); if (data) { diff --git a/amiga/search.h b/amiga/search.h index ce5ae7c21..c4f30eb01 100755 --- a/amiga/search.h +++ b/amiga/search.h @@ -34,6 +34,4 @@ void ami_search_open(struct gui_window *gwin); BOOL ami_search_event(void); void ami_search_close(void); -char *search_engines_file_location; -char *search_default_ico_location; #endif diff --git a/amiga/theme.c b/amiga/theme.c index 1e9640fee..29c72574b 100644 --- a/amiga/theme.c +++ b/amiga/theme.c @@ -123,7 +123,6 @@ int osmouseptr[AMI_LASTPOINTER+1] = { void ami_theme_init(void) { char themefile[1024]; - char searchico[1024]; BPTR lock = 0; strcpy(themefile,nsoption_charp(theme)); @@ -148,9 +147,6 @@ void ami_theme_init(void) UnLock(lock); messages_load(themefile); } - - ami_get_theme_filename(searchico, "theme_search", false); - search_default_ico_location = (char *)strdup(searchico); } void ami_theme_throbber_setup(void) diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c index 2b21fb730..4ce49a06b 100644 --- a/content/fetchers/resource.c +++ b/content/fetchers/resource.c @@ -81,6 +81,7 @@ static const char *fetch_resource_paths[] = { "licence.html", "welcome.html", "favicon.ico", + "default.ico", "netsurf.png", "icons/arrow-l.png", "icons/content.png", diff --git a/desktop/gui.h b/desktop/gui.h index 24838c9df..5710d5328 100644 --- a/desktop/gui.h +++ b/desktop/gui.h @@ -70,6 +70,7 @@ struct download_context; struct nsurl; struct gui_file_table; struct gui_llcache_table; +struct gui_search_web_table; typedef struct nsnsclipboard_styles { size_t start; /**< Start of run */ @@ -489,15 +490,6 @@ struct gui_browser_table { /** called to allow the gui to cleanup */ void (*quit)(void); - /** - * set gui display of a retrieved favicon representing the - * search provider - * - * \param ico may be NULL for local calls; then access current - * cache from search_web_ico() - */ - void (*set_search_ico)(struct hlcache_handle *ico); - /** * core has no fetcher for url */ @@ -573,6 +565,15 @@ struct netsurf_table { */ struct gui_search_table *search; + /** + * Web search table. + * + * Used by the web search provider system. The table is + * optional and may be NULL which uses the default empty + * implementation. + */ + struct gui_search_web_table *search_web; + /** * Low level cache table. * diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c index 45d9516fa..96c28e29d 100644 --- a/desktop/gui_factory.c +++ b/desktop/gui_factory.c @@ -20,6 +20,7 @@ #include "content/backing_store.h" #include "desktop/download.h" +#include "desktop/searchweb.h" #include "desktop/gui_factory.h" #include "utils/file.h" @@ -401,6 +402,33 @@ static nserror verify_search_register(struct gui_search_table *gst) return NSERROR_OK; } +static nserror +gui_default_provider_update(const char *provider_name, + struct bitmap *provider_bitmap) +{ + return NSERROR_OK; +} + +static struct gui_search_web_table default_search_web_table = { + .provider_update = gui_default_provider_update, +}; + +/** verify search table is valid */ +static nserror verify_search_web_register(struct gui_search_web_table *gswt) +{ + /* check table is present */ + if (gswt == NULL) { + return NSERROR_BAD_PARAMETER; + } + + /* mandantory operations */ + if (gswt->provider_update == NULL) { + return NSERROR_BAD_PARAMETER; + } + + return NSERROR_OK; +} + /** verify low level cache persistant backing store table is valid */ static nserror verify_llcache_register(struct gui_llcache_table *glt) { @@ -493,9 +521,6 @@ static void gui_default_quit(void) { } -static void gui_default_set_search_ico(hlcache_handle *ico) -{ -} static void gui_default_launch_url(const char *url) { @@ -550,9 +575,6 @@ static nserror verify_browser_register(struct gui_browser_table *gbt) if (gbt->quit == NULL) { gbt->quit = gui_default_quit; } - if (gbt->set_search_ico == NULL) { - gbt->set_search_ico = gui_default_set_search_ico; - } if (gbt->launch_url == NULL) { gbt->launch_url = gui_default_launch_url; } @@ -651,6 +673,16 @@ nserror gui_factory_register(struct netsurf_table *gt) return err; } + /* web search table */ + if (gt->search_web == NULL) { + /* set default search table */ + gt->search_web = &default_search_web_table; + } + err = verify_search_web_register(gt->search_web); + if (err != NSERROR_OK) { + return err; + } + /* llcache table */ if (gt->llcache == NULL) { /* set default backing store table */ diff --git a/desktop/netsurf.c b/desktop/netsurf.c index e82233a01..153810705 100644 --- a/desktop/netsurf.c +++ b/desktop/netsurf.c @@ -278,8 +278,8 @@ void netsurf_exit(void) LOG(("Finalising JavaScript")); js_finalise(); - LOG(("Closing search and related resources")); - search_web_cleanup(); + LOG(("Finalising Web Search")); + search_web_finalise(); LOG(("Finalising high-level cache")); hlcache_finalise(); diff --git a/desktop/searchweb.c b/desktop/searchweb.c index 71c872b75..88fd0431e 100644 --- a/desktop/searchweb.c +++ b/desktop/searchweb.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Mark Benjamin + * Copyright 2014 Vincent Sanders * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -15,305 +15,485 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - /** \file - * web search (core) + +/** + * \file desktop/searchweb.c + * \brief core web search facilities implementation. */ -#include "utils/config.h" -#include -#include -#include "content/content.h" +#include "utils/log.h" +#include "utils/url.h" +#include "utils/nsoption.h" #include "content/hlcache.h" -#include "desktop/browser.h" + #include "desktop/gui_factory.h" -#include "utils/nsoption.h" #include "desktop/searchweb.h" -#include "utils/config.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/url.h" -#include "utils/utils.h" -static struct search_provider { +struct search_provider { char *name; /**< readable name such as 'google', 'yahoo', etc */ char *hostname; /**< host address such as www.google.com */ char *searchstring; /** < such as "www.google.com?search=%s" */ char *ico; /** < location of domain's favicon */ -} current_search_provider; - -static hlcache_handle *search_ico = NULL; -char *search_engines_file_location; -char *search_default_ico_location; + hlcache_handle *ico_handle; +}; -#ifdef WITH_BMP -static nserror search_web_ico_callback(hlcache_handle *ico, - const hlcache_event *event, void *pw); -#endif +static struct { + struct search_provider *providers; /* web search providers */ + size_t providers_count; /* number of providers */ -/** - * creates a new browser window according to the search term - * \param searchterm such as "my search term" - */ + size_t current; /* current provider */ -bool search_web_new_window(struct browser_window *bw, const char *searchterm) -{ - char *encsearchterm; - char *urltxt; - nsurl *url; - nserror error; - - if (url_escape(searchterm,0, true, NULL, &encsearchterm) != NSERROR_OK) - return false; - - urltxt = search_web_get_url(encsearchterm); - free(encsearchterm); - - error = nsurl_create(urltxt, &url); - if (error == NSERROR_OK) { - error = browser_window_create(BW_CREATE_HISTORY | - BW_CREATE_TAB, - url, - NULL, - bw, - NULL); - nsurl_unref(url); - } - if (error != NSERROR_OK) { - warn_user(messages_get_errorcode(error), 0); - } + hlcache_handle *default_ico_handle; - free(urltxt); - return true; -} +} search_web_ctx; -/** simplistic way of checking whether an entry from the url bar is an - * url / a search; could be improved to properly test terms - */ -bool search_is_url(const char *url) -{ - /** \todo Implement this properly */ +static const char *default_providers = "Google|www.google.com|http://www.google.com/search?q=%s|http://www.google.com/favicon.ico|\n"; - /* For now, everything is an URL */ - return true; -} +static const char *default_search_icon_url = "resource:default.ico"; /** - * caches the details of the current web search provider - * \param reference the enum value of the provider - * browser init code [as well as changing preferences code] should call - * search_web_provider_details(option_search_provider) + * callback for hlcache icon fetch events. */ - -void search_web_provider_details(int reference) +static nserror search_web_ico_callback(hlcache_handle *ico, + const hlcache_event *event, void *pw) { - char buf[300]; - int ref = 0; - FILE *f; - if (search_engines_file_location == NULL) - return; - f = fopen(search_engines_file_location, "r"); - if (f == NULL) - return; - while (fgets(buf, sizeof(buf), f) != NULL) { - if (buf[0] == '\0') - continue; - buf[strlen(buf)-1] = '\0'; - if (ref++ == (int)reference) - break; + hlcache_handle **pico = pw; + + switch (event->type) { + + case CONTENT_MSG_DONE: + LOG(("icon '%s' retrived", nsurl_access(hlcache_handle_get_url(ico)))); + guit->search_web->provider_update(search_web_ctx.providers[search_web_ctx.current].name, content_get_bitmap(ico)); + break; + + case CONTENT_MSG_ERROR: + LOG(("icon %s error: %s", + nsurl_access(hlcache_handle_get_url(ico)), + event->data.error)); + hlcache_handle_release(ico); + *pico = NULL; /* clear reference to released handle */ + break; + + default: + break; } - fclose(f); - if (current_search_provider.name != NULL) - free(current_search_provider.name); - current_search_provider.name = strdup(strtok(buf, "|")); - if (current_search_provider.hostname != NULL) - free(current_search_provider.hostname); - current_search_provider.hostname = strdup(strtok(NULL, "|")); - if (current_search_provider.searchstring != NULL) - free(current_search_provider.searchstring); - current_search_provider.searchstring = strdup(strtok(NULL, "|")); - if (current_search_provider.ico != NULL) - free(current_search_provider.ico); - current_search_provider.ico = strdup(strtok(NULL, "|")); - return; + + return NSERROR_OK; } /** - * escapes a search term then creates the appropriate url from it + * Read providers file. + * + * Allocates stoage of sufficient size for teh providers fiel and + * reads the entire file in. + * + * \param fname The filename to read. + * \param providers_out A pointer to place the result buffer in. + * \param providers_size_out Size of buffer. + * \return NSERROR_OK and providers_out updated or appropriate error code. */ - -char *search_web_from_term(const char *searchterm) +static nserror +read_providers(const char *fname, + char **providers_out, + size_t *providers_size_out) { - char *encsearchterm, *url; - if (url_escape(searchterm, 0, true, NULL, &encsearchterm) != NSERROR_OK) - return strdup(searchterm); - url = search_web_get_url(encsearchterm); - free(encsearchterm); - return url; -} + FILE *providersf; + long ftellsize; + size_t fsize; + char *providersd; + + if (fname == NULL) { + return NSERROR_BAD_PARAMETER; + } -/** accessor for global search provider name */ + providersf = fopen(fname, "r"); + if (providersf == NULL) { + return NSERROR_NOT_FOUND; + } -char *search_web_provider_name(void) -{ - if (current_search_provider.name) - return strdup(current_search_provider.name); - return strdup("google"); -} + if (fseek(providersf, 0, SEEK_END) != 0) { + fclose(providersf); + return NSERROR_INVALID; + } -/** accessor for global search provider hostname */ + ftellsize = ftell(providersf); + if (ftellsize < 0) { + fclose(providersf); + return NSERROR_INVALID; + } + fsize = ftellsize; -char *search_web_provider_host(void) -{ - if (current_search_provider.hostname) - return strdup(current_search_provider.hostname); - return strdup("www.google.com"); -} + if (fseek(providersf, 0, SEEK_SET) != 0) { + fclose(providersf); + return NSERROR_INVALID; + } -/** accessor for global search provider ico name */ + providersd = malloc(fsize + 1); + if (providersd == NULL) { + fclose(providersf); + return NSERROR_NOMEM; + } -char *search_web_ico_name(void) -{ - if (current_search_provider.ico) - return strdup(current_search_provider.ico); - return strdup("http://www.google.com/favicon.ico"); + if (fread(providersd, 1, fsize, providersf) != fsize) { + fclose(providersf); + free(providersd); + } + providersd[fsize] = 0; /* ensure null terminated */ + + fclose(providersf); + + *providers_out = providersd; + *providers_size_out = fsize; + + return NSERROR_OK; } /** - * creates a full url from an encoded search term + * parse search providers from a memory block. + * + * \parm providersd The provider info data. + * \param providers_size The size of the provider data. + * \param providers_out The resulting provider array. + * \param providers_count The number of providers in the output array. + * \return NSERROR_OK on success or error code on faliure. */ - -char *search_web_get_url(const char *encsearchterm) +static nserror +parse_providers(char *providersd, + size_t providers_size, + struct search_provider **providers_out, + size_t *providers_count) { - char *pref, *ret; - int len; - if (current_search_provider.searchstring) - pref = strdup(current_search_provider.searchstring); - else - pref = strdup("http://www.google.com/search?q=%s"); - if (pref == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; + size_t pcount = 0; /* number of providers */ + size_t pidx; + char *nl = providersd; + struct search_provider *providers; + + /* count newlines */ + while (nl != NULL) { + nl = strchr(nl, '\n'); + if (nl != NULL) { + nl++; + pcount+=1; + } + } + + if (pcount == 0) { + return NSERROR_INVALID; } - len = strlen(encsearchterm) + strlen(pref); - ret = malloc(len -1); /* + '\0' - "%s" */ - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(pref); - return NULL; + + providers = malloc(pcount * sizeof(*providers)); + if (providers == NULL) { + return NSERROR_NOMEM; + } + + nl = providersd; + for (pidx = 0; pidx < pcount; pidx++) { + providers[pidx].name = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + providers[pidx].hostname = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + providers[pidx].searchstring = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + providers[pidx].ico = nl; + nl = strchr(nl, '|'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + *nl = 0; + nl++; + + /* skip newline */ + nl = strchr(nl, '\n'); + if (nl == NULL) { + free(providers); + return NSERROR_INVALID; + } + nl++; + + providers[pidx].ico_handle = NULL; } - snprintf(ret, len-1, pref, encsearchterm); - free(pref); - return ret; + + *providers_out = providers; + *providers_count = pcount; + + return NSERROR_OK; } /** - * function to retrieve the search web ico, from cache / from local - * filesystem / from the web - * \param localdefault true when there is no appropriate favicon - * update the search_ico cache else delay until fetcher callback + * create a url for a search provider and a term + * + * \param The provider to use. + * \param term The term being searched for. + * \param url_out The resulting url. + * \return NSERROR_OK on sucess or appropriate error code. */ - -void search_web_retrieve_ico(bool localdefault) +static nserror +make_search_nsurl(struct search_provider *provider, + const char *term, + nsurl **url_out) { -#if !defined(WITH_BMP) - /* This function is of limited use when no BMP support - * is enabled, given the icons it is fetching are BMPs - * more often than not. This also avoids an issue where - * all this code goes mad if BMP support is not enabled. - */ - return; -#else - content_type accept = CONTENT_IMAGE; - char *url; - nserror error; - nsurl *icon_nsurl; + nserror ret; + nsurl *url; + char *eterm; /* escaped term */ + char *searchstr; /* the providers search string */ + char *urlstr; /* the escaped term substituted into the provider */ + char *urlstro; + size_t urlstr_len; + + /* escape the search term and join it to the search url */ + ret = url_escape(term, 0, true, NULL, &eterm); + if (ret != NSERROR_OK) { + return ret; + } - if (localdefault) { - if (search_default_ico_location == NULL) - return; - url = guit->fetch->path_to_url(search_default_ico_location); - } else { - url = search_web_ico_name(); + searchstr = provider->searchstring; + + urlstr_len = strlen(searchstr) + strlen(eterm) + 1; + urlstro = urlstr = malloc(urlstr_len); + if (urlstr == NULL) { + free(eterm); + return NSERROR_NOMEM; } - if (url == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; + /* composite search url */ + for ( ; *searchstr != 0; searchstr++, urlstro++) { + *urlstro = *searchstr; + if ((*searchstr == '%') && (searchstr[1] == 's')) { + searchstr++; /* skip % */ + memcpy(urlstro, eterm, strlen(eterm)); + urlstro += strlen(eterm) - 1; + } } + free(eterm); - error = nsurl_create(url, &icon_nsurl); - if (error != NSERROR_OK) { - free(url); - search_ico = NULL; - return; + ret = nsurl_create(urlstr, &url); + free(urlstr); + if (ret != NSERROR_OK) { + return ret; } - error = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL, - search_web_ico_callback, NULL, NULL, accept, - &search_ico); + *url_out = url; + return NSERROR_OK; +} - nsurl_unref(icon_nsurl); +/* exported interface documented in desktop/searchweb.h */ +nserror +search_web_omni(const char *term, + enum search_web_omni_flags flags, + struct nsurl **url_out) +{ + nserror ret; + nsurl *url; + char *eterm; /* encoded/altered search term */ + + if ((flags & SEARCH_WEB_OMNI_SEARCHONLY) == 0) { + + /* first check to see if the term is a url */ + ret = nsurl_create(term, &url); + if (ret == NSERROR_OK) { + *url_out = url; + return NSERROR_OK; + } + + /* try with adding default scheme */ + eterm = malloc(strlen(term) + SLEN("http://") + 1); + if (eterm == NULL) { + return NSERROR_NOMEM; + } + sprintf(eterm, "http://%s", term); + ret = nsurl_create(eterm, &url); + free(eterm); + if (ret == NSERROR_OK) { + *url_out = url; + return NSERROR_OK; + } + + /* do not pass to search if user has disabled the option */ + if (nsoption_bool(search_url_bar) == false) { + return NSERROR_BAD_URL; + } + } + + /* must be initialised */ + if (search_web_ctx.providers == NULL) { + return NSERROR_INIT_FAILED; + } - if (error != NSERROR_OK) - search_ico = NULL; + /* turn search into a nsurl */ + ret = make_search_nsurl(&search_web_ctx.providers[search_web_ctx.current], term, &url); + if (ret != NSERROR_OK) { + return ret; + } - free(url); -#endif /* WITH_BMP */ + *url_out = url; + return NSERROR_OK; } -/** - * returns a reference to the static global search_ico [ / NULL] - * caller may adjust ico's settings; clearing / free()ing is the core's - * responsibility - */ - -hlcache_handle *search_web_ico(void) +/* exported interface documented in desktop/searchweb.h */ +nserror search_web_select_provider(int selection) { - return search_ico; + nserror ret; + struct search_provider *provider; + struct bitmap *ico_bitmap = NULL; + + /* must be initialised */ + if (search_web_ctx.providers == NULL) { + return NSERROR_INIT_FAILED; + } + + /* negative value just selects whatevers current */ + if (selection >= 0) { + /* ensure selection lies within acceptable range */ + if ((size_t)selection < search_web_ctx.providers_count) { + search_web_ctx.current = selection; + } else { + /* out of range */ + search_web_ctx.current = 0; + } + } + + provider = &search_web_ctx.providers[search_web_ctx.current]; + + /* set the icon now (if we can) at least to the default */ + if (provider->ico_handle != NULL) { + ico_bitmap = content_get_bitmap(provider->ico_handle); + } + if (ico_bitmap == NULL) { + ico_bitmap = content_get_bitmap(search_web_ctx.default_ico_handle); + } + /* update the callback with teh provider change. Bitmap may + * be NULL at this point. + */ + guit->search_web->provider_update(provider->name, ico_bitmap); + + + /* if the providers icon has not been retrived get it now */ + if (provider->ico_handle == NULL) { + nsurl *icon_nsurl; + + /* create search icon url */ + ret = nsurl_create(provider->ico, &icon_nsurl); + if (ret != NSERROR_OK) { + return ret; + } + + ret = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL, + search_web_ico_callback, + &provider->ico_handle, + NULL, CONTENT_IMAGE, + &provider->ico_handle); + nsurl_unref(icon_nsurl); + if (ret != NSERROR_OK) { + provider->ico_handle = NULL; + return ret; + } + } + + return NSERROR_OK; } -/** - * Cleans up any remaining resources during shutdown. - */ -void search_web_cleanup(void) +/* exported interface documented in desktop/searchweb.h */ +nserror search_web_init(const char *provider_fname) { - if (search_ico != NULL) { - hlcache_handle_release(search_ico); - search_ico = NULL; + nserror ret; + char *providers; + size_t providers_size; + nsurl *icon_nsurl; + + /* create search icon url */ + ret = nsurl_create(default_search_icon_url, &icon_nsurl); + if (ret != NSERROR_OK) { + return ret; } -} -/** - * callback function to cache ico then notify front when successful - * else retry default from local file system - */ + /* get a list of providers */ + ret = read_providers(provider_fname, &providers, &providers_size); + if (ret != NSERROR_OK) { + providers = strdup(default_providers); + if (providers == NULL) { + return NSERROR_NOMEM; + } + providers_size = strlen(providers); + } -#ifdef WITH_BMP -nserror search_web_ico_callback(hlcache_handle *ico, - const hlcache_event *event, void *pw) -{ - switch (event->type) { + /* parse list of providers */ + ret = parse_providers(providers, + providers_size, + &search_web_ctx.providers, + &search_web_ctx.providers_count); + if (ret != NSERROR_OK) { + free(providers); + return ret; + } - case CONTENT_MSG_DONE: - LOG(("got favicon '%s'", nsurl_access(hlcache_handle_get_url(ico)))); - guit->browser->set_search_ico(search_ico); - break; + /* get default search icon */ + ret = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL, + search_web_ico_callback, + &search_web_ctx.default_ico_handle, + NULL, CONTENT_IMAGE, + &search_web_ctx.default_ico_handle); + nsurl_unref(icon_nsurl); + if (ret != NSERROR_OK) { + search_web_ctx.default_ico_handle = NULL; + free(search_web_ctx.providers); + search_web_ctx.providers = NULL; + free(providers); + return ret; + } - case CONTENT_MSG_ERROR: - LOG(("favicon %s error: %s", - nsurl_access(hlcache_handle_get_url(ico)), - event->data.error)); - hlcache_handle_release(search_ico); - search_ico = NULL; - search_web_retrieve_ico(true); - break; - default: - break; + return NSERROR_OK; +} + +/* exported interface documented in desktop/searchweb.h */ +nserror search_web_finalise(void) +{ + size_t pidx; + + /* must be initialised */ + if (search_web_ctx.providers == NULL) { + return NSERROR_INIT_FAILED; + } + + if (search_web_ctx.default_ico_handle != NULL) { + hlcache_handle_release(search_web_ctx.default_ico_handle); } + for (pidx = 0; pidx < search_web_ctx.providers_count; pidx++) { + if (search_web_ctx.providers[pidx].ico_handle != NULL) { + hlcache_handle_release(search_web_ctx.providers[pidx].ico_handle); + } + } + + /* All the search provider data is held in a single block for + * efficiency. + */ + free(search_web_ctx.providers[0].name); + + free(search_web_ctx.providers); + search_web_ctx.providers = NULL; return NSERROR_OK; } -#endif /* WITH_BMP */ diff --git a/desktop/searchweb.h b/desktop/searchweb.h index 3920f3c6e..612e9bdd1 100644 --- a/desktop/searchweb.h +++ b/desktop/searchweb.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Mark Benjamin + * Copyright 2014 Vincent Sanders * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,65 +16,81 @@ * along with this program. If not, see . */ -#ifndef _NETSURF_DESKTOP_SEARCH_WEB_H_ -#define _NETSURF_DESKTOP_SEARCH_WEB_H_ - -#include -#include -#include - -struct browser_window; -struct hlcache_handle; - -extern char *search_engines_file_location; -extern char *search_default_ico_location; - /** - * open new tab/window for web search term + * \file desktop/searchweb.h + * \brief core web search facilities interface. */ -bool search_web_new_window(struct browser_window *bw, const char *searchterm); -/** - * retrieve full search url from unencoded search term - */ -char *search_web_from_term(const char *searchterm); +#ifndef _NETSURF_DESKTOP_SEARCH_WEB_H_ +#define _NETSURF_DESKTOP_SEARCH_WEB_H_ + +struct bitmap; /** - * retrieve full search url from encoded web search term + * Graphical user interface browser web search function table. + * */ -char *search_web_get_url(const char *encsearchterm); +struct gui_search_web_table { + /** + * called when the search provider details are updated. + * + * \param provider_name The name of the provider. + * \param ico_bitmap The bitmap of the search icon may be NULL + * if no icon is yet available. + */ + nserror (*provider_update)(const char *provider_name, struct bitmap *ico_bitmap); +}; /** - * cache details of web search provider from file + * Flags which alter the behaviour of the omin search. */ -void search_web_provider_details(int reference); +enum search_web_omni_flags { + SEARCH_WEB_OMNI_NONE = 0, /**< no changes to default operation */ + SEARCH_WEB_OMNI_SEARCHONLY = 1, /**< The search does not attempt to + * interpret the url as a url before + * using it as a search term. + */ +}; /** - * retrieve name of web search provider + * Generate a nsurl from a search term. + * + * This interface obtains a url appropriate for the given search + * term. The flags allow control over the operation. By default the + * operations are: + * - interpret the \a term as a url + * - if missing a scheme as a http: url + * - combined with the search providers url into a url for that provider. + * + * \param term The search term. + * \param flags Flags to control operation. + * \param url_out The ourput url on success. + * \return NSERROR_OK on success or appropriate error code. */ -char *search_web_provider_name(void); +nserror search_web_omni(const char *term, enum search_web_omni_flags flags, struct nsurl **url_out); /** - * retrieve hostname of web search provider + * Change the currently selected web search provider. + * + * \param selection Index of the search provider to select or -1 to + * reselect the current provider + * \return NSERROR_OK on success or appropriate error code. */ -char *search_web_provider_host(void); +nserror search_web_select_provider(int selection); /** - * retrieve name of .ico for search bar + * Initialise the web search operations. + * + * \param provider_fname Path to web search providers file. + * \return NSERROR_OK on successful initialisation or appropriate error code. */ -char *search_web_ico_name(void); +nserror search_web_init(const char *provider_fname); /** - * check whether an URL is in fact a search term - * \param url the url being checked - * \return true for url, false for search + * Finalise the web search operations freeing all resources. + * + * \return NSERROR_OK on success or appropriate error code. */ -bool search_is_url(const char *url); - -void search_web_retrieve_ico(bool localdefault); - -struct hlcache_handle *search_web_ico(void); - -void search_web_cleanup(void); +nserror search_web_finalise(void); #endif diff --git a/gtk/dialogs/preferences.c b/gtk/dialogs/preferences.c index d36d0c68b..f5d92e361 100644 --- a/gtk/dialogs/preferences.c +++ b/gtk/dialogs/preferences.c @@ -18,6 +18,7 @@ #include #include +#include #include "utils/utils.h" #include "utils/messages.h" @@ -923,8 +924,6 @@ TOGGLEBUTTON_SIGNALS(checkUrlSearch, search_url_bar) G_MODULE_EXPORT void nsgtk_preferences_comboSearch_changed(GtkComboBox *widget, struct ppref *priv) { - nsgtk_scaffolding *current = scaf_list; - char *name; int provider; provider = gtk_combo_box_get_active(widget); @@ -932,27 +931,8 @@ nsgtk_preferences_comboSearch_changed(GtkComboBox *widget, struct ppref *priv) /* set the option */ nsoption_set_int(search_provider, provider); - /* refresh web search prefs from file */ - search_web_provider_details(provider); - - /* retrieve ico */ - search_web_retrieve_ico(false); - - /* callback may handle changing gui */ - gui_set_search_ico(search_web_ico()); - - /* set entry */ - name = search_web_provider_name(); - if (name != NULL) { - char content[strlen(name) + SLEN("Search ") + 1]; - - sprintf(content, "Search %s", name); - free(name); - while (current) { - nsgtk_scaffolding_set_websearch(current, content); - current = nsgtk_scaffolding_iterate(current); - } - } + /* set search provider */ + search_web_select_provider(provider); } G_MODULE_EXPORT void diff --git a/gtk/gui.c b/gtk/gui.c index b14b4fbe2..3f0d6119f 100644 --- a/gtk/gui.c +++ b/gtk/gui.c @@ -364,12 +364,12 @@ static void gui_init(int argc, char** argv, char **respath) } /* Search engine sources */ - search_engines_file_location = filepath_find(respath, "SearchEngines"); - LOG(("Using '%s' as Search Engines file", search_engines_file_location)); - - /* Default Icon */ - search_default_ico_location = filepath_find(respath, "default.ico"); - LOG(("Using '%s' as default search ico", search_default_ico_location)); + resource_filename = filepath_find(respath, "SearchEngines"); + search_web_init(resource_filename); + if (resource_filename != NULL) { + LOG(("Using '%s' as Search Engines file", resource_filename)); + free(resource_filename); + } /* Default favicon */ resource_filename = filepath_find(respath, "favicon.png"); @@ -562,8 +562,6 @@ static void gui_quit(void) nsgtk_history_destroy(); nsgtk_hotlist_destroy(); - free(search_engines_file_location); - free(search_default_ico_location); free(toolbar_indices_file_location); free(nsgtk_config_home); @@ -1250,7 +1248,6 @@ static struct gui_browser_table nsgtk_browser_table = { .schedule = nsgtk_schedule, .quit = gui_quit, - .set_search_ico = gui_set_search_ico, .launch_url = gui_launch_url, .create_form_select_menu = gui_create_form_select_menu, .cert_verify = gui_cert_verify, @@ -1271,8 +1268,9 @@ int main(int argc, char** argv) .clipboard = nsgtk_clipboard_table, .download = nsgtk_download_table, .fetch = nsgtk_fetch_table, - .search = nsgtk_search_table, .llcache = filesystem_llcache_table, + .search = nsgtk_search_table, + .search_web = nsgtk_search_web_table, }; ret = netsurf_register(&nsgtk_table); diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c index 7ae61dac0..7d4c49c92 100644 --- a/gtk/scaffolding.c +++ b/gtk/scaffolding.c @@ -417,29 +417,20 @@ static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget, gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data) { struct gtk_scaffolding *g = data; - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - char *urltxt; + nserror ret; nsurl *url; - nserror error; - if (search_is_url(gtk_entry_get_text(GTK_ENTRY(g->url_bar))) == false) { - urltxt = search_web_from_term(gtk_entry_get_text(GTK_ENTRY( - g->url_bar))); - } else { - urltxt = strdup(gtk_entry_get_text(GTK_ENTRY(g->url_bar))); + ret = search_web_omni(gtk_entry_get_text(GTK_ENTRY(g->url_bar)), + SEARCH_WEB_OMNI_NONE, + &url); + if (ret == NSERROR_OK) { + ret = browser_window_navigate(nsgtk_get_browser_window(g->top_level), + url, NULL, BW_NAVIGATE_HISTORY, + NULL, NULL, NULL); + nsurl_unref(url); } - - if (urltxt != NULL) { - error = nsurl_create(urltxt, &url); - if (error != NSERROR_OK) { - warn_user(messages_get_errorcode(error), 0); - } else { - browser_window_navigate(bw, url, NULL, - BW_NAVIGATE_HISTORY, NULL, - NULL, NULL); - nsurl_unref(url); - } - free(urltxt); + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), 0); } return TRUE; @@ -1814,7 +1805,6 @@ static bool nsgtk_new_scaffolding_popup(struct gtk_scaffolding *g, GtkAccelGroup nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) { struct gtk_scaffolding *g; - char *searchname; int i; GtkAccelGroup *group; GError* error = NULL; @@ -2078,30 +2068,10 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) nsgtk_toolbar_connect_all(g); nsgtk_attach_menu_handlers(g); - /* prepare to set the web search ico */ - - /* init web search prefs from file */ - search_web_provider_details(nsoption_int(search_provider)); - - /* potentially retrieve ico */ - if (search_web_ico() == NULL) { - search_web_retrieve_ico(false); - } - - /* set entry */ - searchname = search_web_provider_name(); - if (searchname != NULL) { - char searchcontent[strlen(searchname) + SLEN("Search ") + 1]; - sprintf(searchcontent, "Search %s", searchname); - nsgtk_scaffolding_set_websearch(g, searchcontent); - free(searchname); - } - nsgtk_scaffolding_initial_sensitivity(g); g->fullscreen = false; - /* attach to the list */ if (scaf_list) scaf_list->prev = g; @@ -2113,8 +2083,8 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) nsgtk_theme_init(); nsgtk_theme_implement(g); - /* set web search ico */ - gui_set_search_ico(search_web_ico()); + /* set web search provider */ + search_web_select_provider(nsoption_int(search_provider)); /* finally, show the window. */ gtk_widget_show(GTK_WIDGET(g->window)); @@ -2227,38 +2197,65 @@ nsgtk_scaffolding_set_icon(struct gui_window *gw) gtk_widget_show_all(GTK_WIDGET(sc->buttons[URL_BAR_ITEM]->button)); } -void gui_set_search_ico(hlcache_handle *ico) +/** + * Gui callback when search provider details are updated. + * + * \param provider_name The providers name. + * \param ico_bitmap The icon bitmap representing the provider. + * \return NSERROR_OK on success else error code. + */ +static nserror +gui_search_web_provider_update(const char *provider_name, + struct bitmap *provider_bitmap) { - struct bitmap *srch_bitmap; nsgtk_scaffolding *current; - GdkPixbuf *srch_pixbuf; + GdkPixbuf *srch_pixbuf = NULL; + char *searchcontent; - if ((ico == NULL) && - (ico = search_web_ico()) == NULL) { - return; - } + if (provider_bitmap != NULL) { + srch_pixbuf = nsgdk_pixbuf_get_from_surface(provider_bitmap->surface, 16, 16); - srch_bitmap = content_get_bitmap(ico); - if (srch_bitmap == NULL) { - return; + if (srch_pixbuf == NULL) { + return NSERROR_NOMEM; + } } - srch_pixbuf = nsgdk_pixbuf_get_from_surface(srch_bitmap->surface, 16, 16); - - if (srch_pixbuf == NULL) { - return; + /* setup the search content name */ + searchcontent = malloc(strlen(provider_name) + SLEN("Search ") + 1); + if (searchcontent != NULL) { + sprintf(searchcontent, "Search %s", provider_name); } - /* add ico to each window's toolbar */ + /* set the search provider parameters up in each scaffold */ for (current = scaf_list; current != NULL; current = current->next) { - nsgtk_entry_set_icon_from_pixbuf(current->webSearchEntry, - GTK_ENTRY_ICON_PRIMARY, - srch_pixbuf); + /* add ico to each window's toolbar */ + if (srch_pixbuf != NULL) { + nsgtk_entry_set_icon_from_pixbuf(current->webSearchEntry, + GTK_ENTRY_ICON_PRIMARY, + srch_pixbuf); + } + + /* set search entry text */ + if (searchcontent != NULL) { + nsgtk_scaffolding_set_websearch(current, searchcontent); + } else { + nsgtk_scaffolding_set_websearch(current, provider_name); + } } + free(searchcontent); + g_object_unref(srch_pixbuf); + + return NSERROR_OK; } +static struct gui_search_web_table search_web_table = { + .provider_update = gui_search_web_provider_update, +}; + +struct gui_search_web_table *nsgtk_search_web_table = &search_web_table; + bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g) { /* We are considered "busy" if the stop button is sensitive */ diff --git a/gtk/scaffolding.h b/gtk/scaffolding.h index 285f9bb53..f03a3402a 100644 --- a/gtk/scaffolding.h +++ b/gtk/scaffolding.h @@ -22,10 +22,14 @@ #include #include "utils/errors.h" +struct bitmap; struct hlcache_handle; struct gui_window; +struct gui_search_web_table; typedef struct gtk_scaffolding nsgtk_scaffolding; +extern struct gui_search_web_table *nsgtk_search_web_table; + typedef enum { BACK_BUTTON = 0, HISTORY_BUTTON, @@ -178,6 +182,6 @@ void gui_window_set_title(struct gui_window *g, const char *title); void gui_window_set_url(struct gui_window *g, const char *url); void gui_window_start_throbber(struct gui_window *g); void gui_window_stop_throbber(struct gui_window *g); -void gui_set_search_ico(struct hlcache_handle *ico); + #endif /* NETSURF_GTK_SCAFFOLDING_H */ diff --git a/gtk/search.c b/gtk/search.c index 44f9ddeb6..2bb8a85bd 100644 --- a/gtk/search.c +++ b/gtk/search.c @@ -192,13 +192,29 @@ gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data) { - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - temp_open_background = 0; - search_web_new_window(nsgtk_get_browser_window( - nsgtk_scaffolding_top_level(g)), - (char *)gtk_entry_get_text(GTK_ENTRY( - nsgtk_scaffolding_websearch(g)))); - temp_open_background = -1; + struct gtk_scaffolding *g = data; + nserror ret; + nsurl *url; + + ret = search_web_omni( + gtk_entry_get_text(GTK_ENTRY(nsgtk_scaffolding_websearch(g))), + SEARCH_WEB_OMNI_SEARCHONLY, + &url); + if (ret == NSERROR_OK) { + temp_open_background = 0; + ret = browser_window_create( + BW_CREATE_HISTORY | BW_CREATE_TAB, + url, + NULL, + nsgtk_get_browser_window(nsgtk_scaffolding_top_level(g)), + NULL); + temp_open_background = -1; + nsurl_unref(url); + } + if (ret != NSERROR_OK) { + warn_user(messages_get_errorcode(ret), 0); + } + return TRUE; } diff --git a/gtk/toolbar.c b/gtk/toolbar.c index d4a197bd4..c60bab6f1 100644 --- a/gtk/toolbar.c +++ b/gtk/toolbar.c @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include #include #include "desktop/browser.h" @@ -438,7 +439,7 @@ void nsgtk_toolbar_close(nsgtk_scaffolding *g) /* update favicon etc */ nsgtk_scaffolding_set_top_level(nsgtk_scaffolding_top_level(g)); - gui_set_search_ico(search_web_ico()); + search_web_select_provider(-1); } /** -- cgit v1.2.3