NetSurf
searchweb.c
Go to the documentation of this file.
1/*
2 * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * \brief core web search facilities implementation.
22 */
23
24#include <stdlib.h>
25#include <string.h>
26
27#include "utils/utils.h"
28#include "utils/log.h"
29#include "utils/url.h"
30#include "utils/nsoption.h"
31#include "netsurf/content.h"
32#include "content/hlcache.h"
33
34#include "desktop/searchweb.h"
36
38 char *name; /**< readable name such as 'google', 'yahoo', etc */
39 char *hostname; /**< host address such as www.google.com */
40 char *searchstring; /** < such as "www.google.com?search=%s" */
41 char *ico; /** < location of domain's favicon */
43};
44
45static struct search_web_ctx_s {
46 struct search_provider *providers; /* web search providers */
47 size_t providers_count; /* number of providers */
48
49 size_t current; /* current provider */
50
52
54
55
56static const char *default_providers = "Google|www.google.com|https://www.google.com/search?q=%s|https://www.google.com/favicon.ico|\n";
57
58static const char *default_search_icon_url = "resource:icons/search.png";
59
60
61/**
62 * Read providers file.
63 *
64 * Allocates storage of sufficient size for the providers file and
65 * reads the entire file in.
66 *
67 * \param fname The filename to read.
68 * \param providers_out A pointer to place the result buffer in.
69 * \param providers_size_out Size of buffer.
70 * \return NSERROR_OK and providers_out updated or appropriate error code.
71 */
72static nserror
73read_providers(const char *fname,
74 char **providers_out,
75 size_t *providers_size_out)
76{
77 FILE *providersf;
78 long ftellsize;
79 size_t fsize;
80 char *providersd;
81
82 if (fname == NULL) {
84 }
85
86 providersf = fopen(fname, "r");
87 if (providersf == NULL) {
88 return NSERROR_NOT_FOUND;
89 }
90
91 if (fseek(providersf, 0, SEEK_END) != 0) {
92 fclose(providersf);
93 return NSERROR_INVALID;
94 }
95
96 ftellsize = ftell(providersf);
97 if (ftellsize < 0) {
98 fclose(providersf);
99 return NSERROR_INVALID;
100 }
101 fsize = ftellsize;
102
103 if (fseek(providersf, 0, SEEK_SET) != 0) {
104 fclose(providersf);
105 return NSERROR_INVALID;
106 }
107
108 providersd = malloc(fsize + 1);
109 if (providersd == NULL) {
110 fclose(providersf);
111 return NSERROR_NOMEM;
112 }
113
114 if (fread(providersd, 1, fsize, providersf) != fsize) {
115 fclose(providersf);
116 free(providersd);
117 return NSERROR_BAD_SIZE;
118 }
119 providersd[fsize] = 0; /* ensure null terminated */
120
121 fclose(providersf);
122
123 *providers_out = providersd;
124 *providers_size_out = fsize;
125
126 return NSERROR_OK;
127}
128
129/**
130 * parse search providers from a memory block.
131 *
132 * \param providersd The provider info data.
133 * \param providers_size The size of the provider data.
134 * \param providers_out The resulting provider array.
135 * \param providers_count The number of providers in the output array.
136 * \return NSERROR_OK on success or error code on failure.
137 */
138static nserror
139parse_providers(char *providersd,
140 size_t providers_size,
141 struct search_provider **providers_out,
142 size_t *providers_count)
143{
144 size_t pcount = 0; /* number of providers */
145 size_t pidx;
146 char *nl = providersd;
147 struct search_provider *providers;
148
149 /* count newlines */
150 while (nl != NULL) {
151 nl = strchr(nl, '\n');
152 if (nl != NULL) {
153 nl++;
154 pcount+=1;
155 }
156 }
157
158 if (pcount == 0) {
159 return NSERROR_INVALID;
160 }
161
162 providers = malloc(pcount * sizeof(*providers));
163 if (providers == NULL) {
164 return NSERROR_NOMEM;
165 }
166
167 nl = providersd;
168 for (pidx = 0; pidx < pcount; pidx++) {
169 providers[pidx].name = nl;
170 nl = strchr(nl, '|');
171 if (nl == NULL) {
172 free(providers);
173 return NSERROR_INVALID;
174 }
175 *nl = 0;
176 nl++;
177
178 providers[pidx].hostname = nl;
179 nl = strchr(nl, '|');
180 if (nl == NULL) {
181 free(providers);
182 return NSERROR_INVALID;
183 }
184 *nl = 0;
185 nl++;
186
187 providers[pidx].searchstring = nl;
188 nl = strchr(nl, '|');
189 if (nl == NULL) {
190 free(providers);
191 return NSERROR_INVALID;
192 }
193 *nl = 0;
194 nl++;
195
196 providers[pidx].ico = nl;
197 nl = strchr(nl, '|');
198 if (nl == NULL) {
199 free(providers);
200 return NSERROR_INVALID;
201 }
202 *nl = 0;
203 nl++;
204
205 /* skip newline */
206 nl = strchr(nl, '\n');
207 if (nl == NULL) {
208 free(providers);
209 return NSERROR_INVALID;
210 }
211 nl++;
212
213 providers[pidx].ico_handle = NULL;
214 }
215
216 *providers_out = providers;
217 *providers_count = pcount;
218
219 return NSERROR_OK;
220}
221
222/**
223 * create a url for a search provider and a term
224 *
225 * \param provider The provider to use.
226 * \param term The term being searched for.
227 * \param url_out The resulting url.
228 * \return NSERROR_OK on success or appropriate error code.
229 */
230static nserror
232 const char *term,
233 nsurl **url_out)
234{
235 nserror ret;
236 nsurl *url;
237 char *eterm; /* escaped term */
238 char *searchstr; /* the providers search string */
239 char *urlstr; /* the escaped term substituted into the provider */
240 char *urlstro;
241 size_t urlstr_len;
242
243 /* escape the search term and join it to the search url */
244 ret = url_escape(term, true, NULL, &eterm);
245 if (ret != NSERROR_OK) {
246 return ret;
247 }
248
249 searchstr = provider->searchstring;
250
251 urlstr_len = strlen(searchstr) + strlen(eterm) + 1;
252 urlstro = urlstr = malloc(urlstr_len);
253 if (urlstr == NULL) {
254 free(eterm);
255 return NSERROR_NOMEM;
256 }
257
258 /* composite search url */
259 for ( ; *searchstr != 0; searchstr++, urlstro++) {
260 *urlstro = *searchstr;
261 if ((*searchstr == '%') && (searchstr[1] == 's')) {
262 searchstr++; /* skip % */
263 memcpy(urlstro, eterm, strlen(eterm));
264 urlstro += strlen(eterm) - 1;
265 }
266 }
267 free(eterm);
268 *urlstro = '\0'; /* ensure string is NULL-terminated */
269
270 ret = nsurl_create(urlstr, &url);
271 free(urlstr);
272 if (ret != NSERROR_OK) {
273 return ret;
274 }
275
276 *url_out = url;
277 return NSERROR_OK;
278}
279
280/**
281 * callback for hlcache icon fetch events.
282 */
283static nserror
285 const hlcache_event *event,
286 void *pw)
287{
288 struct search_provider *provider = pw;
289
290 switch (event->type) {
291
292 case CONTENT_MSG_DONE:
293 NSLOG(netsurf, INFO, "icon '%s' retrieved",
297 break;
298
300 NSLOG(netsurf, INFO, "icon %s error: %s",
302 event->data.errordata.errormsg);
303
305 /* clear reference to released handle */
306 provider->ico_handle = NULL;
307 break;
308
309 default:
310 break;
311 }
312
313 return NSERROR_OK;
314}
315
316/* exported interface documented in desktop/searchweb.h */
318search_web_omni(const char *term,
319 enum search_web_omni_flags flags,
320 struct nsurl **url_out)
321{
322 nserror ret;
323 nsurl *url;
324 char *eterm; /* encoded/altered search term */
325
326 if ((flags & SEARCH_WEB_OMNI_SEARCHONLY) == 0) {
327
328 /* first check to see if the term is a url */
329 ret = nsurl_create(term, &url);
330 if (ret == NSERROR_OK) {
331 *url_out = url;
332 return NSERROR_OK;
333 }
334
335 /* try with adding default scheme */
336 eterm = malloc(strlen(term) + SLEN("https://") + 1);
337 if (eterm == NULL) {
338 return NSERROR_NOMEM;
339 }
340 sprintf(eterm, "https://%s", term);
341 ret = nsurl_create(eterm, &url);
342 free(eterm);
343 if (ret == NSERROR_OK) {
344 *url_out = url;
345 return NSERROR_OK;
346 }
347
348 /* do not pass to search if user has disabled the option */
349 if (nsoption_bool(search_url_bar) == false) {
350 return NSERROR_BAD_URL;
351 }
352 }
353
354 /* must be initialised */
355 if (search_web_ctx.providers == NULL) {
356 return NSERROR_INIT_FAILED;
357 }
358
359 /* turn search into a nsurl */
361 if (ret != NSERROR_OK) {
362 return ret;
363 }
364
365 *url_out = url;
366 return NSERROR_OK;
367}
368
369/* exported interface documented in desktop/searchweb.h */
371{
372 struct search_provider *provider;
373 struct bitmap *ico_bitmap = NULL;
374
375 /* must be initialised */
376 if (search_web_ctx.providers == NULL) {
377 return NSERROR_INIT_FAILED;
378 }
379
381
382 /* set the icon now (if we can) at least to the default */
383 if (provider->ico_handle != NULL) {
384 ico_bitmap = content_get_bitmap(provider->ico_handle);
385 }
386 if ((ico_bitmap == NULL) &&
389 }
390
391 *bitmap_out = ico_bitmap;
392 return NSERROR_OK;
393}
394
395
396/* exported interface documented in desktop/searchweb.h */
398{
399 struct search_provider *provider;
400 struct bitmap *ico_bitmap = NULL;
401 size_t pidx;
402
403 /* must be initialised */
404 if (search_web_ctx.providers == NULL) {
405 return NSERROR_INIT_FAILED;
406 }
407
408 /* negative value just selects whatevers current */
409 if (selection != NULL) {
410 for (pidx=0; pidx < search_web_ctx.providers_count;pidx++) {
411 if (strcmp(search_web_ctx.providers[pidx].name, selection)==0) {
412 search_web_ctx.current = pidx;
413 break;
414 }
415 }
416 if (pidx == search_web_ctx.providers_count) {
417 /* selected provider not found */
419 }
420 }
421
423
424 /* set the icon now (if we can) at least to the default */
425 if (provider->ico_handle != NULL) {
426 ico_bitmap = content_get_bitmap(provider->ico_handle);
427 }
428 if ((ico_bitmap == NULL) &&
431 }
432
433 /* signal the frontend with the provider change. Bitmap may
434 * be NULL at this point.
435 */
436 guit->search_web->provider_update(provider->name, ico_bitmap);
437
438 /* if the providers icon has not been retrieved get it now */
439 if (provider->ico_handle == NULL) {
440 nsurl *icon_nsurl;
441 nserror ret;
442
443 /* create search icon url */
444 ret = nsurl_create(provider->ico, &icon_nsurl);
445 if (ret != NSERROR_OK) {
446 return ret;
447 }
448
449 ret = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL,
451 provider,
452 NULL, CONTENT_IMAGE,
453 &provider->ico_handle);
454 nsurl_unref(icon_nsurl);
455 if (ret != NSERROR_OK) {
456 provider->ico_handle = NULL;
457 return ret;
458 }
459 }
460
461 return NSERROR_OK;
462}
463
464/**
465 * callback for hlcache icon fetch events.
466 */
467static nserror
469 const hlcache_event *event,
470 void *pw)
471{
472 struct search_web_ctx_s *ctx = pw;
473
474 switch (event->type) {
475
476 case CONTENT_MSG_DONE:
477 NSLOG(netsurf, INFO, "default icon '%s' retrieved",
479
480 /* only set to default icon if providers icon has no handle */
481 if (ctx->providers[search_web_ctx.current].ico_handle == NULL) {
484 content_get_bitmap(ico));
485 }
486 break;
487
489 NSLOG(netsurf, INFO, "icon %s error: %s",
491 event->data.errordata.errormsg);
492
494 /* clear reference to released handle */
495 ctx->default_ico_handle = NULL;
496 break;
497
498 default:
499 break;
500 }
501
502 return NSERROR_OK;
503}
504
505/* exported interface documented in desktop/searchweb.h */
506ssize_t search_web_iterate_providers(ssize_t iter, const char **name)
507{
508 if (iter < 0) {
509 iter=0;
510 } else {
511 iter++;
512 }
513
514 if ((size_t)iter >= search_web_ctx.providers_count) {
515 iter = -1;
516 } else {
517 *name = search_web_ctx.providers[iter].name;
518 }
519
520 return iter;
521}
522
523
524/* exported interface documented in desktop/searchweb.h */
525nserror search_web_init(const char *provider_fname)
526{
527 nserror ret;
528 char *providers;
529 size_t providers_size;
530 nsurl *icon_nsurl;
531
532 /* create search icon url */
533 ret = nsurl_create(default_search_icon_url, &icon_nsurl);
534 if (ret != NSERROR_OK) {
535 return ret;
536 }
537
538 /* get a list of providers */
539 ret = read_providers(provider_fname, &providers, &providers_size);
540 if (ret != NSERROR_OK) {
542 if (providers == NULL) {
543 return NSERROR_NOMEM;
544 }
545 providers_size = strlen(providers);
546 }
547
548 /* parse list of providers */
550 providers_size,
553 if (ret != NSERROR_OK) {
554 free(providers);
555 return ret;
556 }
557
558 /* get default search icon */
559 ret = hlcache_handle_retrieve(icon_nsurl,
560 0,
561 NULL,
562 NULL,
565 NULL,
568 nsurl_unref(icon_nsurl);
569 if (ret != NSERROR_OK) {
573 free(providers);
574 return ret;
575 }
576
577
578 return NSERROR_OK;
579}
580
581/* exported interface documented in desktop/searchweb.h */
583{
584 size_t pidx;
585
586 /* must be initialised */
587 if (search_web_ctx.providers == NULL) {
588 return NSERROR_INIT_FAILED;
589 }
590
593 }
594 for (pidx = 0; pidx < search_web_ctx.providers_count; pidx++) {
595 if (search_web_ctx.providers[pidx].ico_handle != NULL) {
597 }
598 }
599
600 /* All the search provider data is held in a single block for
601 * efficiency.
602 */
604
607
608 return NSERROR_OK;
609}
@ CONTENT_IMAGE
All images.
Definition: content_type.h:67
@ CONTENT_MSG_DONE
content has finished processing
Definition: content_type.h:119
@ CONTENT_MSG_ERROR
error occurred
Definition: content_type.h:122
nserror search_web_omni(const char *term, enum search_web_omni_flags flags, struct nsurl **url_out)
Generate a nsurl from a search term.
Definition: searchweb.c:318
nserror search_web_init(const char *provider_fname)
Initialise the web search operations.
Definition: searchweb.c:525
static nserror search_web_ico_callback(hlcache_handle *ico, const hlcache_event *event, void *pw)
callback for hlcache icon fetch events.
Definition: searchweb.c:284
static const char * default_providers
Definition: searchweb.c:56
nserror search_web_select_provider(const char *selection)
Change the currently selected web search provider.
Definition: searchweb.c:397
static struct search_web_ctx_s search_web_ctx
static const char * default_search_icon_url
Definition: searchweb.c:58
static nserror parse_providers(char *providersd, size_t providers_size, struct search_provider **providers_out, size_t *providers_count)
parse search providers from a memory block.
Definition: searchweb.c:139
nserror search_web_finalise(void)
Finalise the web search operations freeing all resources.
Definition: searchweb.c:582
static nserror default_ico_callback(hlcache_handle *ico, const hlcache_event *event, void *pw)
callback for hlcache icon fetch events.
Definition: searchweb.c:468
static nserror make_search_nsurl(struct search_provider *provider, const char *term, nsurl **url_out)
create a url for a search provider and a term
Definition: searchweb.c:231
ssize_t search_web_iterate_providers(ssize_t iter, const char **name)
Iterate the search providers, returning their names.
Definition: searchweb.c:506
nserror search_web_get_provider_bitmap(struct bitmap **bitmap_out)
obtain the current providers bitmap
Definition: searchweb.c:370
static nserror read_providers(const char *fname, char **providers_out, size_t *providers_size_out)
Read providers file.
Definition: searchweb.c:73
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_INIT_FAILED
Initialisation failed.
Definition: errors.h:38
@ NSERROR_BAD_URL
Bad URL.
Definition: errors.h:55
@ NSERROR_BAD_PARAMETER
Bad Parameter.
Definition: errors.h:48
@ NSERROR_BAD_SIZE
Bad size.
Definition: errors.h:60
@ NSERROR_INVALID
Invalid data.
Definition: errors.h:49
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:50
Interface to core interface table.
nserror hlcache_handle_release(hlcache_handle *handle)
Release a high-level cache handle.
Definition: hlcache.c:740
nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags, nsurl *referer, llcache_post_data *post, hlcache_handle_callback cb, void *pw, hlcache_child_context *child, content_type accepted_types, hlcache_handle **result)
Retrieve a high-level cache handle for an object.
Definition: hlcache.c:679
High-level resource cache interface.
Public content interface.
struct nsurl * hlcache_handle_get_url(const struct hlcache_handle *handle)
Retrieve the URL associated with a high level cache handle.
struct bitmap * content_get_bitmap(struct hlcache_handle *h)
Retrieve the bitmap contained in an image content.
Definition: content.c:1264
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
nserror nsurl_create(const char *const url_s, nsurl **url)
Create a NetSurf URL object from a URL string.
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
core web search facilities interface.
search_web_omni_flags
Flags which alter the behaviour of the omin search.
Definition: searchweb.h:48
@ SEARCH_WEB_OMNI_SEARCHONLY
The search does not attempt to interpret the url as a url before using it as a search term.
Definition: searchweb.h:55
Interface to utility string handling.
RISC OS wimp toolkit bitmap.
Definition: bitmap.c:68
nserror(* provider_update)(const char *provider_name, struct bitmap *ico_bitmap)
called when the search provider details are updated.
Definition: searchweb.h:42
High-level cache event.
Definition: hlcache.h:43
content_msg type
Event type.
Definition: hlcache.h:44
union content_msg_data data
Event data.
Definition: hlcache.h:45
High-level cache handle.
Definition: hlcache.c:66
struct gui_search_web_table * search_web
Web search table.
Definition: gui_table.h:132
hlcache_handle * ico_handle
< location of domain's favicon
Definition: searchweb.c:42
char * ico
< such as "www.google.com?search=%s"
Definition: searchweb.c:41
char * hostname
host address such as www.google.com
Definition: searchweb.c:39
char * name
readable name such as 'google', 'yahoo', etc
Definition: searchweb.c:38
char * searchstring
Definition: searchweb.c:40
size_t providers_count
Definition: searchweb.c:47
struct search_provider * providers
Definition: searchweb.c:46
size_t current
Definition: searchweb.c:49
hlcache_handle * default_ico_handle
Definition: searchweb.c:51
struct content_msg_data::@99 errordata
CONTENT_MSG_ERROR - Error from content or underlying fetch.
const char * errormsg
The message.
Definition: content.h:95
nserror url_escape(const char *unescaped, bool sptoplus, const char *escexceptions, char **result)
Escape a string suitable for inclusion in an URL.
Definition: url.c:131
Interface to URL parsing and joining operations.
Option reading and saving interface.
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:304
Interface to a number of general purpose functionality.
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:88