NetSurf
main.c
Go to the documentation of this file.
1/*
2 * Copyright 2011 Daniel Silverstone <dsilvers@digital-scurf.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#include <stdio.h>
20#include <stdlib.h>
21#include <limits.h>
22#include <sys/select.h>
23#include <sys/types.h>
24#include <unistd.h>
25#include <string.h>
26#include <errno.h>
27#include <signal.h>
28
29#include "utils/config.h"
30#include "utils/sys_time.h"
31#include "utils/log.h"
32#include "utils/messages.h"
33#include "utils/filepath.h"
34#include "utils/nsoption.h"
35#include "utils/nsurl.h"
36#include "netsurf/misc.h"
37#include "netsurf/netsurf.h"
38#include "netsurf/url_db.h"
39#include "netsurf/cookie_db.h"
40#include "content/fetch.h"
42
43#include "monkey/output.h"
44#include "monkey/dispatch.h"
45#include "monkey/browser.h"
46#include "monkey/401login.h"
47#include "monkey/filetype.h"
48#include "monkey/fetch.h"
49#include "monkey/schedule.h"
50#include "monkey/bitmap.h"
51#include "monkey/layout.h"
52
53/** maximum number of languages in language vector */
54#define LANGV_SIZE 32
55/** maximum length of all strings in language vector */
56#define LANGS_SIZE 4096
57
58/** resource search path vector */
59char **respaths;
60
61static bool monkey_done = false;
62
63/**
64 * Cause an abnormal program termination.
65 *
66 * \note This never returns and is intended to terminate without any cleanup.
67 *
68 * \param error The message to display to the user.
69 */
70static void die(const char * const error)
71{
72 moutf(MOUT_DIE, "%s", error);
73 exit(EXIT_FAILURE);
74}
75
76/**
77 * obtain language from environment
78 *
79 * start with GNU extension LANGUAGE environment variable and then try
80 * POSIX variables LC_ALL, LC_MESSAGES and LANG
81 *
82 */
83static const char *get_language(void)
84{
85 const char *lang;
86
87 lang = getenv("LANGUAGE");
88 if ((lang != NULL) && (lang[0] != '\0')) {
89 return lang;
90 }
91
92 lang = getenv("LC_ALL");
93 if ((lang != NULL) && (lang[0] != '\0')) {
94 return lang;
95 }
96
97 lang = getenv("LC_MESSAGES");
98 if ((lang != NULL) && (lang[0] != '\0')) {
99 return lang;
100 }
101
102 lang = getenv("LANG");
103 if ((lang != NULL) && (lang[0] != '\0')) {
104 return lang;
105 }
106
107 return NULL;
108}
109
110
111/**
112 * provide a string vector of languages in preference order
113 *
114 * environment variables are processed to aquire a colon separated
115 * list of languages which are converted into a string vector. The
116 * vector will always have the C language as its last entry.
117 *
118 * This implementation creates an internal static representation of
119 * the vector when first called and returns that for all subsequent
120 * calls. i.e. changing the environment does not change the returned
121 * vector on repeated calls.
122 *
123 * If the environment variables have more than LANGV_SIZE languages or
124 * LANGS_SIZE bytes of data the results list will be curtailed.
125 */
126static const char * const *get_languagev(void)
127{
128 static const char *langv[LANGV_SIZE];
129 int langidx = 0; /* index of next entry in vector */
130 static char langs[LANGS_SIZE];
131 char *curp; /* next language parameter in langs string */
132 const char *lange; /* language from environment variable */
133 int lang_len;
134 char *cln; /* colon in lange */
135
136 /* return cached vector */
137 if (langv[0] != NULL) {
138 return &langv[0];
139 }
140
141 curp = &langs[0];
142
143 lange = get_language();
144
145 if (lange != NULL) {
146 lang_len = strlen(lange) + 1;
147 if (lang_len < (LANGS_SIZE - 2)) {
148 memcpy(curp, lange, lang_len);
149 while ((curp[0] != 0) &&
150 (langidx < (LANGV_SIZE - 2))) {
151 /* avoid using strchrnul as it is not portable */
152 cln = strchr(curp, ':');
153 if (cln == NULL) {
154 langv[langidx++] = curp;
155 curp += lang_len;
156 break;
157 } else {
158 if ((cln - curp) > 1) {
159 /* only place non empty entries in vector */
160 langv[langidx++] = curp;
161 }
162 *cln++ = 0; /* null terminate */
163 lang_len -= (cln - curp);
164 curp = cln;
165 }
166 }
167 }
168 }
169
170 /* ensure C language is present */
171 langv[langidx++] = curp;
172 *curp++ = 'C';
173 *curp++ = 0;
174 langv[langidx] = NULL;
175
176 return &langv[0];
177}
178
179/**
180 * Create an array of valid paths to search for resources.
181 *
182 * The idea is that all the complex path computation to find resources
183 * is performed here, once, rather than every time a resource is
184 * searched for.
185 *
186 * \param resource_path A shell style colon separated path list
187 * \return A string vector of valid paths where resources can be found
188 */
189static char **
190nsmonkey_init_resource(const char *resource_path)
191{
192 const char * const *langv;
193 char **pathv; /* resource path string vector */
194 char **respath; /* resource paths vector */
195
196 pathv = filepath_path_to_strvec(resource_path);
197
198 langv = get_languagev();
199
200 respath = filepath_generate(pathv, langv);
201
203
204 return respath;
205}
206
207static void monkey_quit(void)
208{
210 urldb_save(nsoption_charp(url_file));
212}
213
214static nserror gui_launch_url(struct nsurl *url)
215{
216 moutf(MOUT_GENERIC, "LAUNCH URL %s", nsurl_access(url));
217 return NSERROR_OK;
218}
219
220static nserror gui_present_cookies(const char *search_term)
221{
222 if (search_term != NULL) {
223 moutf(MOUT_GENERIC, "PRESENT_COOKIES %s", search_term);
224 } else {
225 moutf(MOUT_GENERIC, "PRESENT_COOKIES");
226 }
227 return NSERROR_OK;
228}
229
230static void quit_handler(int argc, char **argv)
231{
232 monkey_done = true;
233}
234
235static void monkey_options_handle_command(int argc, char **argv)
236{
237 nsoption_commandline(&argc, argv, nsoptions);
238}
239
240/**
241 * Set option defaults for monkey frontend
242 *
243 * @param defaults The option table to update.
244 * @return error status.
245 */
247{
248 /* Set defaults for absent option strings */
249 nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"));
250 nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"));
251 nsoption_setnull_charp(url_file, strdup("~/.netsurf/URLs"));
252
253 return NSERROR_OK;
254}
255
256
257/**
258 * Ensures output logging stream is correctly configured
259 */
260static bool nslog_stream_configure(FILE *fptr)
261{
262 /* set log stream to be non-buffering */
263 setbuf(fptr, NULL);
264
265 return true;
266}
267
270
271 .quit = monkey_quit,
272 .launch_url = gui_launch_url,
273 .login = gui_401login_open,
274 .present_cookies = gui_present_cookies,
275};
276
277static void monkey_run(void)
278{
279 fd_set read_fd_set, write_fd_set, exc_fd_set;
280 int max_fd;
281 int rdy_fd;
282 int schedtm;
283 struct timeval tv;
284 struct timeval* timeout;
285
286 while (!monkey_done) {
287
288 /* discover the next scheduled event time */
289 schedtm = monkey_schedule_run();
290
291 /* clears fdset */
292 fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
293
294 /* add stdin to the set */
295 if (max_fd < 0) {
296 max_fd = 0;
297 }
298 FD_SET(0, &read_fd_set);
299 FD_SET(0, &exc_fd_set);
300
301 /* setup timeout */
302 switch (schedtm) {
303 case -1:
304 NSLOG(netsurf, INFO, "Iterate blocking");
305 moutf(MOUT_GENERIC, "POLL BLOCKING");
306 timeout = NULL;
307 break;
308
309 case 0:
310 NSLOG(netsurf, INFO, "Iterate immediate");
311 tv.tv_sec = 0;
312 tv.tv_usec = 0;
313 timeout = &tv;
314 break;
315
316 default:
317 NSLOG(netsurf, INFO, "Iterate non-blocking");
318 moutf(MOUT_GENERIC, "POLL TIMED %d", schedtm);
319 tv.tv_sec = schedtm / 1000; /* miliseconds to seconds */
320 tv.tv_usec = (schedtm % 1000) * 1000; /* remainder to microseconds */
321 timeout = &tv;
322 break;
323 }
324
325 rdy_fd = select(max_fd + 1,
326 &read_fd_set,
327 &write_fd_set,
328 &exc_fd_set,
329 timeout);
330 if (rdy_fd < 0) {
331 NSLOG(netsurf, CRITICAL, "Unable to select: %s", strerror(errno));
332 monkey_done = true;
333 } else if (rdy_fd > 0) {
334 if (FD_ISSET(0, &read_fd_set)) {
336 }
337 }
338 }
339}
340
341#if (!defined(NDEBUG) && defined(HAVE_EXECINFO))
342#include <execinfo.h>
343static void *backtrace_buffer[4096];
344
345void
346__assert_fail(const char *__assertion, const char *__file,
347 unsigned int __line, const char *__function)
348{
349 int frames;
350 fprintf(stderr,
351 "MONKEY: Assertion failure!\n"
352 "%s:%d: %s: Assertion `%s` failed.\n",
353 __file, __line, __function, __assertion);
354
355 frames = backtrace(&backtrace_buffer[0], 4096);
356 if (frames > 0 && frames < 4096) {
357 fprintf(stderr, "Backtrace:\n");
358 fflush(stderr);
359 backtrace_symbols_fd(&backtrace_buffer[0], frames, 2);
360 }
361
362 abort();
363}
364
365static void
366signal_handler(int sig)
367{
368 int frames;
369 fprintf(stderr, "Caught signal %s (%d)\n",
370 ((sig == SIGSEGV) ? "SIGSEGV" :
371 ((sig == SIGILL) ? "SIGILL" :
372 ((sig == SIGFPE) ? "SIGFPE" :
373 ((sig == SIGBUS) ? "SIGBUS" :
374 "unknown signal")))),
375 sig);
376 frames = backtrace(&backtrace_buffer[0], 4096);
377 if (frames > 0 && frames < 4096) {
378 fprintf(stderr, "Backtrace:\n");
379 fflush(stderr);
380 backtrace_symbols_fd(&backtrace_buffer[0], frames, 2);
381 }
382
383 abort();
384}
385
386#endif
387
388int
389main(int argc, char **argv)
390{
391 char *messages;
392 char *options;
393 char buf[PATH_MAX];
394 nserror ret;
395 struct netsurf_table monkey_table = {
397 .window = monkey_window_table,
398 .download = monkey_download_table,
399 .fetch = monkey_fetch_table,
400 .bitmap = monkey_bitmap_table,
401 .layout = monkey_layout_table,
402 .llcache = filesystem_llcache_table,
403 };
404
405#if (!defined(NDEBUG) && defined(HAVE_EXECINFO))
406 /* Catch segfault, illegal instructions and fp exceptions */
407 signal(SIGSEGV, signal_handler);
408 signal(SIGILL, signal_handler);
409 signal(SIGFPE, signal_handler);
410 /* It's unlikely, but SIGBUS could happen on some platforms */
411 signal(SIGBUS, signal_handler);
412#endif
413
414 ret = netsurf_register(&monkey_table);
415 if (ret != NSERROR_OK) {
416 die("NetSurf operation table failed registration");
417 }
418
419 /* Unbuffer stdin/out/err */
420 setbuf(stdin, NULL);
421 setbuf(stdout, NULL);
422 setbuf(stderr, NULL);
423
424 /* Prep the search paths */
425 respaths = nsmonkey_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"MONKEY_RESPATH":./frontends/monkey/res");
426
427 /* initialise logging. Not fatal if it fails but not much we can do
428 * about it either.
429 */
431
432 /* user options setup */
434 if (ret != NSERROR_OK) {
435 die("Options failed to initialise");
436 }
437 options = filepath_find(respaths, "Choices");
439 free(options);
440 nsoption_commandline(&argc, argv, nsoptions);
441
442 messages = filepath_find(respaths, "Messages");
443 ret = messages_add_from_file(messages);
444 if (ret != NSERROR_OK) {
445 NSLOG(netsurf, INFO, "Messages failed to load");
446 }
447
448 /* common initialisation */
449 ret = netsurf_init(NULL);
450 free(messages);
451 if (ret != NSERROR_OK) {
452 die("NetSurf failed to initialise");
453 }
454
455 filepath_sfinddef(respaths, buf, "mime.types", "/etc/");
457
458 urldb_load(nsoption_charp(url_file));
460
461 /* Free resource paths now we're done finding resources */
462 for (char **s = respaths; *s != NULL; s++) {
463 free(*s);
464 }
465 free(respaths);
466
468 if (ret != NSERROR_OK) {
469 die("quit handler failed to register");
470 }
471
473 if (ret != NSERROR_OK) {
474 die("window handler failed to register");
475 }
476
478 if (ret != NSERROR_OK) {
479 die("options handler failed to register");
480 }
481
483 if (ret != NSERROR_OK) {
484 die("login handler failed to register");
485 }
486
487
488 moutf(MOUT_GENERIC, "STARTED");
489 monkey_run();
490
491 moutf(MOUT_GENERIC, "CLOSING_DOWN");
493
494 netsurf_exit();
495 moutf(MOUT_GENERIC, "FINISHED");
496
497 /* finalise options */
499
500 /* finalise logging */
502
503 /* And free any monkey-specific bits */
505
506 return 0;
507}
void monkey_login_handle_command(int argc, char **argv)
Definition: 401login.c:207
#define PATH_MAX
Definition: gui.h:31
Low-level source data cache backing store interface.
struct gui_llcache_table * filesystem_llcache_table
nserror gui_401login_open(struct nsurl *url, const char *realm, const char *username, const char *password, nserror(*cb)(const char *username, const char *password, void *pw), void *cbpw)
Definition: login.cpp:175
nserror fetch_fdset(fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, int *maxfd_out)
Get the set of file descriptors the fetchers are currently using.
Definition: fetch.c:385
Fetching of data from a URL (interface).
Unified cookie database public interface.
void urldb_save_cookies(const char *filename)
Save persistent cookies to file.
Definition: urldb.c:4448
void urldb_load_cookies(const char *filename)
Load a cookie file into the database.
Definition: urldb.c:4281
char options[PATH_MAX]
Definition: gui.c:91
void monkey_process_command(void)
Definition: dispatch.c:64
nserror monkey_register_handler(const char *cmd, handle_command_fn fn)
Definition: dispatch.c:39
void monkey_free_handlers(void)
Definition: dispatch.c:53
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
char ** filepath_path_to_strvec(const char *path)
Convert a colon separated list of path elements into a string vector.
Definition: filepath.c:313
char * filepath_find(char **respathv, const char *filename)
Searches an array of resource paths for a file.
Definition: filepath.c:129
char * filepath_sfinddef(char **respathv, char *filepath, const char *filename, const char *def)
Searches an array of resource paths for a file optionally forcing a default.
Definition: filepath.c:152
void filepath_free_strvec(char **pathv)
Free a string vector.
Definition: filepath.c:356
char ** filepath_generate(char *const *pathv, const char *const *langv)
Merge two string vectors into a resource search path vector.
Definition: filepath.c:184
Utility routines to obtain paths to file resources.
struct gui_bitmap_table * monkey_bitmap_table
Definition: bitmap.c:128
void monkey_kill_browser_windows(void)
Definition: browser.c:66
struct gui_window_table * monkey_window_table
Definition: browser.c:794
void monkey_window_handle_command(int argc, char **argv)
Definition: browser.c:701
struct gui_download_table * monkey_download_table
Definition: download.c:95
struct gui_fetch_table * monkey_fetch_table
Definition: fetch.c:53
struct gui_layout_table * monkey_layout_table
Definition: layout.c:117
Interface to platform-specific miscellaneous browser operation table.
nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
Initialise the logging system.
Definition: log.c:190
void nslog_finalise(void)
Shut down the logging system.
Definition: log.c:299
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
nserror messages_add_from_file(const char *path)
Read keys and values from messages file into the standard Messages hash.
Definition: messages.c:177
Localised message support (interface).
void monkey_fetch_filetype_fin(void)
Definition: filetype.c:168
void monkey_fetch_filetype_init(const char *mimefile)
Definition: filetype.c:54
char ** respaths
resource search path vector
Definition: main.c:59
static void monkey_run(void)
Definition: main.c:277
#define LANGV_SIZE
maximum number of languages in language vector
Definition: main.c:54
static nserror gui_launch_url(struct nsurl *url)
Definition: main.c:214
int main(int argc, char **argv)
Normal entry point from OS.
Definition: main.c:389
static nserror set_defaults(struct nsoption_s *defaults)
Set option defaults for monkey frontend.
Definition: main.c:246
static bool nslog_stream_configure(FILE *fptr)
Ensures output logging stream is correctly configured.
Definition: main.c:260
static void monkey_options_handle_command(int argc, char **argv)
Definition: main.c:235
static const char * get_language(void)
obtain language from environment
Definition: main.c:83
#define LANGS_SIZE
maximum length of all strings in language vector
Definition: main.c:56
static void die(const char *const error)
Cause an abnormal program termination.
Definition: main.c:70
static const char *const * get_languagev(void)
provide a string vector of languages in preference order
Definition: main.c:126
static void monkey_quit(void)
Definition: main.c:207
static struct gui_misc_table monkey_misc_table
Definition: main.c:268
static char ** nsmonkey_init_resource(const char *resource_path)
Create an array of valid paths to search for resources.
Definition: main.c:190
static bool monkey_done
Definition: main.c:61
static void quit_handler(int argc, char **argv)
Definition: main.c:230
static nserror gui_present_cookies(const char *search_term)
Definition: main.c:220
nserror monkey_schedule(int tival, void(*callback)(void *p), void *p)
Schedule a callback.
Definition: schedule.c:100
int monkey_schedule_run(void)
Process scheduled callbacks up to current time.
Definition: schedule.c:133
NetSurf core interface registration, construction and destruction.
void netsurf_exit(void)
Finalise NetSurf core.
Definition: netsurf.c:232
nserror netsurf_init(const char *store_path)
Initialise netsurf core.
Definition: netsurf.c:107
nserror netsurf_register(struct netsurf_table *table)
Register operation table.
Definition: gui_factory.c:777
NetSurf URL handling (interface).
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
int moutf(enum monkey_output_type mout_type, const char *fmt,...)
Definition: output.c:39
@ MOUT_DIE
Definition: output.h:23
@ MOUT_GENERIC
Definition: output.h:26
Interface to utility string handling.
Graphical user interface browser misc function table.
Definition: misc.h:39
nserror(* schedule)(int t, void(*callback)(void *p), void *p)
Schedule a callback.
Definition: misc.h:58
NetSurf operation function table.
Definition: gui_table.h:48
struct gui_misc_table * misc
Browser table.
Definition: gui_table.h:57
BSD style timeval macros.
Unified URL information database public interface.
nserror urldb_save(const char *filename)
Export the current database to file.
Definition: urldb.c:3094
nserror urldb_load(const char *filename)
Import an URL database from file, replacing any existing database.
Definition: urldb.c:2876
struct nsoption_s * nsoptions_default
global default option table.
Definition: nsoption.c:46
static struct nsoption_s defaults[]
The table of compiled in default options.
Definition: nsoption.c:64
nserror nsoption_read(const char *path, struct nsoption_s *opts)
Read choices file and set them in the passed table.
Definition: nsoption.c:696
struct nsoption_s * nsoptions
global active option table.
Definition: nsoption.c:45
nserror nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
Process commandline and set options approriately.
Definition: nsoption.c:856
nserror nsoption_init(nsoption_set_default_t *set_defaults, struct nsoption_s **popts, struct nsoption_s **pdefs)
Initialise option system.
Definition: nsoption.c:608
nserror nsoption_finalise(struct nsoption_s *opts, struct nsoption_s *defs)
Finalise option system.
Definition: nsoption.c:663
Option reading and saving interface.
#define nsoption_charp(OPTION)
Get the value of a string option.
Definition: nsoption.h:331
#define nsoption_setnull_charp(OPTION, VALUE)
set string option in default table if currently unset
Definition: nsoption.h:376