summaryrefslogtreecommitdiff
path: root/desktop/searchweb.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2014-05-25 00:57:48 +0100
committerVincent Sanders <vince@kyllikki.org>2014-05-25 01:01:59 +0100
commita6d3ceae0ee7cee85020a70b716586425a042900 (patch)
tree1177195f3f3ab1b38d7beb2ec5e412bc2170e4c2 /desktop/searchweb.c
parentfb5af8a1b612e210384a1a6a4f8d5ee5fafef054 (diff)
downloadnetsurf-a6d3ceae0ee7cee85020a70b716586425a042900.tar.gz
netsurf-a6d3ceae0ee7cee85020a70b716586425a042900.tar.bz2
Completely re-write web search provider handling
Diffstat (limited to 'desktop/searchweb.c')
-rw-r--r--desktop/searchweb.c644
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 */