diff options
Diffstat (limited to 'desktop/searchweb.c')
-rw-r--r-- | desktop/searchweb.c | 644 |
1 files changed, 412 insertions, 232 deletions
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 <netsurf-browser.org.MarkBenjamin@dfgh.net> + * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org> * * 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 <http://www.gnu.org/licenses/>. */ - - /** \file - * web search (core) + +/** + * \file desktop/searchweb.c + * \brief core web search facilities implementation. */ -#include "utils/config.h" -#include <ctype.h> -#include <string.h> -#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 */ |