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 = "DuckDuckGo|www.duckduckgo.com|https://www.duckduckgo.com/html/?q=%s|https://www.duckduckgo.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 /* ensure providers are initialised */
355 if (search_web_ctx.providers == NULL) {
356 ret = search_web_init(NULL);
357 if (ret != NSERROR_OK) {
358 return ret;
359 }
360 }
361 if (search_web_ctx.providers == NULL) {
362 return NSERROR_INIT_FAILED;
363 }
364
365 /* turn search into a nsurl */
367 if (ret != NSERROR_OK) {
368 return ret;
369 }
370
371 *url_out = url;
372 return NSERROR_OK;
373}
374
375/* exported interface documented in desktop/searchweb.h */
377{
378 struct search_provider *provider;
379 struct bitmap *ico_bitmap = NULL;
380
381 /* must be initialised */
382 if (search_web_ctx.providers == NULL) {
383 return NSERROR_INIT_FAILED;
384 }
385
387
388 /* set the icon now (if we can) at least to the default */
389 if (provider->ico_handle != NULL) {
390 ico_bitmap = content_get_bitmap(provider->ico_handle);
391 }
392 if ((ico_bitmap == NULL) &&
395 }
396
397 *bitmap_out = ico_bitmap;
398 return NSERROR_OK;
399}
400
401
402/* exported interface documented in desktop/searchweb.h */
404{
405 struct search_provider *provider;
406 struct bitmap *ico_bitmap = NULL;
407 size_t pidx;
408
409 /* must be initialised */
410 if (search_web_ctx.providers == NULL) {
411 return NSERROR_INIT_FAILED;
412 }
413
414 /* negative value just selects whatevers current */
415 if (selection != NULL) {
416 for (pidx=0; pidx < search_web_ctx.providers_count;pidx++) {
417 if (strcmp(search_web_ctx.providers[pidx].name, selection)==0) {
418 search_web_ctx.current = pidx;
419 break;
420 }
421 }
422 if (pidx == search_web_ctx.providers_count) {
423 /* selected provider not found */
425 }
426 }
427
429
430 /* set the icon now (if we can) at least to the default */
431 if (provider->ico_handle != NULL) {
432 ico_bitmap = content_get_bitmap(provider->ico_handle);
433 }
434 if ((ico_bitmap == NULL) &&
437 }
438
439 /* signal the frontend with the provider change. Bitmap may
440 * be NULL at this point.
441 */
442 guit->search_web->provider_update(provider->name, ico_bitmap);
443
444 /* if the providers icon has not been retrieved get it now */
445 if (provider->ico_handle == NULL) {
446 nsurl *icon_nsurl;
447 nserror ret;
448
449 /* create search icon url */
450 ret = nsurl_create(provider->ico, &icon_nsurl);
451 if (ret != NSERROR_OK) {
452 return ret;
453 }
454
455 ret = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL,
457 provider,
458 NULL, CONTENT_IMAGE,
459 &provider->ico_handle);
460 nsurl_unref(icon_nsurl);
461 if (ret != NSERROR_OK) {
462 provider->ico_handle = NULL;
463 return ret;
464 }
465 }
466
467 return NSERROR_OK;
468}
469
470/**
471 * callback for hlcache icon fetch events.
472 */
473static nserror
475 const hlcache_event *event,
476 void *pw)
477{
478 struct search_web_ctx_s *ctx = pw;
479
480 switch (event->type) {
481
482 case CONTENT_MSG_DONE:
483 NSLOG(netsurf, INFO, "default icon '%s' retrieved",
485
486 /* only set to default icon if providers icon has no handle */
487 if (ctx->providers[search_web_ctx.current].ico_handle == NULL) {
490 content_get_bitmap(ico));
491 }
492 break;
493
495 NSLOG(netsurf, INFO, "icon %s error: %s",
497 event->data.errordata.errormsg);
498
500 /* clear reference to released handle */
501 ctx->default_ico_handle = NULL;
502 break;
503
504 default:
505 break;
506 }
507
508 return NSERROR_OK;
509}
510
511/* exported interface documented in desktop/searchweb.h */
512ssize_t search_web_iterate_providers(ssize_t iter, const char **name)
513{
514 if (iter < 0) {
515 iter=0;
516 } else {
517 iter++;
518 }
519
520 if ((size_t)iter >= search_web_ctx.providers_count) {
521 iter = -1;
522 } else {
523 *name = search_web_ctx.providers[iter].name;
524 }
525
526 return iter;
527}
528
529
530/* exported interface documented in desktop/searchweb.h */
531nserror search_web_init(const char *provider_fname)
532{
533 nserror ret;
534 char *providers;
535 size_t providers_size;
536 nsurl *icon_nsurl;
537
538 /* create search icon url */
539 ret = nsurl_create(default_search_icon_url, &icon_nsurl);
540 if (ret != NSERROR_OK) {
541 return ret;
542 }
543
544 /* get a list of providers */
545 ret = read_providers(provider_fname, &providers, &providers_size);
546 if (ret != NSERROR_OK) {
548 if (providers == NULL) {
549 return NSERROR_NOMEM;
550 }
551 providers_size = strlen(providers);
552 }
553
554 /* parse list of providers */
556 providers_size,
559 if (ret != NSERROR_OK) {
560 free(providers);
561 return ret;
562 }
563
564 /* get default search icon */
565 ret = hlcache_handle_retrieve(icon_nsurl,
566 0,
567 NULL,
568 NULL,
571 NULL,
574 nsurl_unref(icon_nsurl);
575 if (ret != NSERROR_OK) {
579 free(providers);
580 return ret;
581 }
582
583
584 return NSERROR_OK;
585}
586
587/* exported interface documented in desktop/searchweb.h */
589{
590 size_t pidx;
591
592 /* must be initialised */
593 if (search_web_ctx.providers == NULL) {
594 return NSERROR_INIT_FAILED;
595 }
596
599 }
600 for (pidx = 0; pidx < search_web_ctx.providers_count; pidx++) {
601 if (search_web_ctx.providers[pidx].ico_handle != NULL) {
603 }
604 }
605
606 /* All the search provider data is held in a single block for
607 * efficiency.
608 */
610
613
614 return NSERROR_OK;
615}
@ 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:531
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:403
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:588
static nserror default_ico_callback(hlcache_handle *ico, const hlcache_event *event, void *pw)
callback for hlcache icon fetch events.
Definition: searchweb.c:474
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:512
nserror search_web_get_provider_bitmap(struct bitmap **bitmap_out)
obtain the current providers bitmap
Definition: searchweb.c:376
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