/* * Copyright 2003 Phil Mellor * Copyright 2003 John M Bell * Copyright 2004 James Bursa * Copyright 2005 Richard Wilson * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** \file * Option reading and saving (implementation). * * Options are stored in the format key:value, one per line. For bool options, * value is "0" or "1". */ #include #include #include #include #include #include "css/css.h" #include "desktop/options.h" #include "desktop/plot_style.h" #include "utils/log.h" #include "utils/utils.h" #if defined(riscos) #include "riscos/options.h" #elif defined(nsgtk) #include "gtk/options.h" #elif defined(nsbeos) #include "beos/options.h" #elif defined(nsamiga) #include "amiga/options.h" #elif defined(nsframebuffer) #include "framebuffer/options.h" #elif defined(nsatari) #include "atari/options.h" #elif defined(nsmonkey) #include "monkey/options.h" #else #define EXTRA_OPTION_DEFINE #define EXTRA_OPTION_TABLE #endif /** An HTTP proxy should be used. */ bool option_http_proxy = false; /** Hostname of proxy. */ char *option_http_proxy_host = 0; /** Proxy port. */ int option_http_proxy_port = 8080; /** Proxy authentication method. */ int option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; /** Proxy authentication user name */ char *option_http_proxy_auth_user = 0; /** Proxy authentication password */ char *option_http_proxy_auth_pass = 0; /** Default font size / 0.1pt. */ int option_font_size = 128; /** Minimum font size. */ int option_font_min_size = 85; /** Default sans serif font */ char *option_font_sans; /** Default serif font */ char *option_font_serif; /** Default monospace font */ char *option_font_mono; /** Default cursive font */ char *option_font_cursive; /** Default fantasy font */ char *option_font_fantasy; /** Accept-Language header. */ char *option_accept_language = 0; /** Accept-Charset header. */ char *option_accept_charset = 0; /** Preferred maximum size of memory cache / bytes. */ int option_memory_cache_size = 2 * 1024 * 1024; /** Preferred expiry age of disc cache / days. */ int option_disc_cache_age = 28; /** Whether to block advertisements */ bool option_block_ads = false; /** Minimum GIF animation delay */ int option_minimum_gif_delay = 10; /** Whether to send the referer HTTP header */ bool option_send_referer = true; /** Whether to animate images */ bool option_animate_images = true; /** How many days to retain URL data for */ int option_expire_url = 28; /** Default font family */ int option_font_default = PLOT_FONT_FAMILY_SANS_SERIF; /** ca-bundle location */ char *option_ca_bundle = 0; /** ca-path location */ char *option_ca_path = 0; /** Cookie file location */ char *option_cookie_file = 0; /** Cookie jar location */ char *option_cookie_jar = 0; /** Home page location */ char *option_homepage_url = 0; /** search web from url bar */ bool option_search_url_bar = false; /** URL completion in url bar */ bool option_url_suggestion = true; /** default web search provider */ int option_search_provider = 0; /** default x position of new windows */ int option_window_x = 0; /** default y position of new windows */ int option_window_y = 0; /** default width of new windows */ int option_window_width = 0; /** default height of new windows */ int option_window_height = 0; /** width of screen when above options were saved */ int option_window_screen_width = 0; /** height of screen when above options were saved */ int option_window_screen_height = 0; /** default size of status bar vs. h scroll bar */ int option_toolbar_status_width = 6667; /** default window scale */ int option_scale = 100; /* Whether to reflow web pages while objects are fetching */ bool option_incremental_reflow = true; /* Minimum time between HTML reflows while objects are fetching */ #ifdef riscos unsigned int option_min_reflow_period = 100; /* time in cs */ #else unsigned int option_min_reflow_period = 25; /* time in cs */ #endif bool option_core_select_menu = false; /** top margin of exported page*/ int option_margin_top = DEFAULT_MARGIN_TOP_MM; /** bottom margin of exported page*/ int option_margin_bottom = DEFAULT_MARGIN_BOTTOM_MM; /** left margin of exported page*/ int option_margin_left = DEFAULT_MARGIN_LEFT_MM; /** right margin of exported page*/ int option_margin_right = DEFAULT_MARGIN_RIGHT_MM; /** scale of exported content*/ int option_export_scale = DEFAULT_EXPORT_SCALE * 100; /**suppressing images in printed content*/ bool option_suppress_images = false; /**turning off all backgrounds for printed content*/ bool option_remove_backgrounds = false; /**turning on content loosening for printed content*/ bool option_enable_loosening = true; /**compression of PDF documents*/ bool option_enable_PDF_compression = true; /**setting a password and encoding PDF documents*/ bool option_enable_PDF_password = false; /* Fetcher configuration */ /** Maximum simultaneous active fetchers */ int option_max_fetchers = 24; /** Maximum simultaneous active fetchers per host. * (<=option_max_fetchers else it makes no sense) * Note that rfc2616 section 8.1.4 says that there should be no more than * two keepalive connections per host. None of the main browsers follow this * as it slows page fetches down considerably. * See https://bugzilla.mozilla.org/show_bug.cgi?id=423377#c4 */ int option_max_fetchers_per_host = 5; /** Maximum number of inactive fetchers cached. * The total number of handles netsurf will therefore have open * is this plus option_max_fetchers. */ int option_max_cached_fetch_handles = 6; /** Suppress debug output from cURL. */ bool option_suppress_curl_debug = true; /** Whether to allow target="_blank" */ bool option_target_blank = true; /** Whether second mouse button opens in new tab */ bool option_button_2_tab = true; /* Interface colours */ colour option_gui_colour_bg_1 = 0xFFCCBB; /** Background (bbggrr) */ colour option_gui_colour_fg_1 = 0x000000; /** Foreground (bbggrr) */ colour option_gui_colour_fg_2 = 0xFFFBF8; /** Foreground selected (bbggrr) */ /* system colours */ colour option_sys_colour_ActiveBorder = 0x00000000; colour option_sys_colour_ActiveCaption = 0x00000000; colour option_sys_colour_AppWorkspace = 0x00000000; colour option_sys_colour_Background = 0x00000000; colour option_sys_colour_ButtonFace = 0x00000000; colour option_sys_colour_ButtonHighlight = 0x00000000; colour option_sys_colour_ButtonShadow = 0x00000000; colour option_sys_colour_ButtonText = 0x00000000; colour option_sys_colour_CaptionText = 0x0000000; colour option_sys_colour_GrayText = 0x00000000; colour option_sys_colour_Highlight = 0x00000000; colour option_sys_colour_HighlightText = 0x00000000; colour option_sys_colour_InactiveBorder = 0x00000000; colour option_sys_colour_InactiveCaption = 0x00000000; colour option_sys_colour_InactiveCaptionText = 0x00000000; colour option_sys_colour_InfoBackground = 0x00000000; colour option_sys_colour_InfoText = 0x00000000; colour option_sys_colour_Menu = 0x00000000; colour option_sys_colour_MenuText = 0x0000000; colour option_sys_colour_Scrollbar = 0x0000000; colour option_sys_colour_ThreeDDarkShadow = 0x000000; colour option_sys_colour_ThreeDFace = 0x000000; colour option_sys_colour_ThreeDHighlight = 0x000000; colour option_sys_colour_ThreeDLightShadow = 0x000000; colour option_sys_colour_ThreeDShadow = 0x000000; colour option_sys_colour_Window = 0x000000; colour option_sys_colour_WindowFrame = 0x000000; colour option_sys_colour_WindowText = 0x000000; EXTRA_OPTION_DEFINE enum option_type_e { OPTION_BOOL, OPTION_INTEGER, OPTION_STRING, OPTION_COLOUR } ; struct option_entry_s { const char *key; enum option_type_e type; void *p; }; struct option_entry_s option_table[] = { { "http_proxy", OPTION_BOOL, &option_http_proxy }, { "http_proxy_host", OPTION_STRING, &option_http_proxy_host }, { "http_proxy_port", OPTION_INTEGER, &option_http_proxy_port }, { "http_proxy_auth", OPTION_INTEGER, &option_http_proxy_auth }, { "http_proxy_auth_user", OPTION_STRING, &option_http_proxy_auth_user }, { "http_proxy_auth_pass", OPTION_STRING, &option_http_proxy_auth_pass }, { "font_size", OPTION_INTEGER, &option_font_size }, { "font_min_size", OPTION_INTEGER, &option_font_min_size }, { "font_sans", OPTION_STRING, &option_font_sans }, { "font_serif", OPTION_STRING, &option_font_serif }, { "font_mono", OPTION_STRING, &option_font_mono }, { "font_cursive", OPTION_STRING, &option_font_cursive }, { "font_fantasy", OPTION_STRING, &option_font_fantasy }, { "accept_language", OPTION_STRING, &option_accept_language }, { "accept_charset", OPTION_STRING, &option_accept_charset }, { "memory_cache_size", OPTION_INTEGER, &option_memory_cache_size }, { "disc_cache_age", OPTION_INTEGER, &option_disc_cache_age }, { "block_advertisements", OPTION_BOOL, &option_block_ads }, { "minimum_gif_delay", OPTION_INTEGER, &option_minimum_gif_delay }, { "send_referer", OPTION_BOOL, &option_send_referer }, { "animate_images", OPTION_BOOL, &option_animate_images }, { "expire_url", OPTION_INTEGER, &option_expire_url }, { "font_default", OPTION_INTEGER, &option_font_default }, { "ca_bundle", OPTION_STRING, &option_ca_bundle }, { "ca_path", OPTION_STRING, &option_ca_path }, { "cookie_file", OPTION_STRING, &option_cookie_file }, { "cookie_jar", OPTION_STRING, &option_cookie_jar }, { "homepage_url", OPTION_STRING, &option_homepage_url }, { "search_url_bar", OPTION_BOOL, &option_search_url_bar}, { "search_provider", OPTION_INTEGER, &option_search_provider}, { "url_suggestion", OPTION_BOOL, &option_url_suggestion }, { "window_x", OPTION_INTEGER, &option_window_x }, { "window_y", OPTION_INTEGER, &option_window_y }, { "window_width", OPTION_INTEGER, &option_window_width }, { "window_height", OPTION_INTEGER, &option_window_height }, { "window_screen_width", OPTION_INTEGER, &option_window_screen_width }, { "window_screen_height", OPTION_INTEGER, &option_window_screen_height }, { "toolbar_status_size", OPTION_INTEGER, &option_toolbar_status_width }, { "scale", OPTION_INTEGER, &option_scale }, { "incremental_reflow", OPTION_BOOL, &option_incremental_reflow }, { "min_reflow_period", OPTION_INTEGER, &option_min_reflow_period }, { "core_select_menu", OPTION_BOOL, &option_core_select_menu }, /* Fetcher options */ { "max_fetchers", OPTION_INTEGER, &option_max_fetchers }, { "max_fetchers_per_host", OPTION_INTEGER, &option_max_fetchers_per_host }, { "max_cached_fetch_handles", OPTION_INTEGER, &option_max_cached_fetch_handles }, { "suppress_curl_debug",OPTION_BOOL, &option_suppress_curl_debug }, { "target_blank", OPTION_BOOL, &option_target_blank }, { "button_2_tab", OPTION_BOOL, &option_button_2_tab }, /* PDF / Print options*/ { "margin_top", OPTION_INTEGER, &option_margin_top}, { "margin_bottom", OPTION_INTEGER, &option_margin_bottom}, { "margin_left", OPTION_INTEGER, &option_margin_left}, { "margin_right", OPTION_INTEGER, &option_margin_right}, { "export_scale", OPTION_INTEGER, &option_export_scale}, { "suppress_images", OPTION_BOOL, &option_suppress_images}, { "remove_backgrounds", OPTION_BOOL, &option_remove_backgrounds}, { "enable_loosening", OPTION_BOOL, &option_enable_loosening}, { "enable_PDF_compression", OPTION_BOOL, &option_enable_PDF_compression}, { "enable_PDF_password", OPTION_BOOL, &option_enable_PDF_password}, /* Interface colours */ { "gui_colour_bg_1", OPTION_COLOUR, &option_gui_colour_bg_1}, { "gui_colour_fg_1", OPTION_COLOUR, &option_gui_colour_fg_1}, { "gui_colour_fg_2", OPTION_COLOUR, &option_gui_colour_fg_2}, /* System colours */ { "sys_colour_ActiveBorder",OPTION_COLOUR,&option_sys_colour_ActiveBorder }, { "sys_colour_ActiveCaption",OPTION_COLOUR,&option_sys_colour_ActiveCaption }, { "sys_colour_AppWorkspace",OPTION_COLOUR,&option_sys_colour_AppWorkspace }, { "sys_colour_Background",OPTION_COLOUR,&option_sys_colour_Background }, { "sys_colour_ButtonFace",OPTION_COLOUR,&option_sys_colour_ButtonFace }, { "sys_colour_ButtonHighlight",OPTION_COLOUR,&option_sys_colour_ButtonHighlight }, { "sys_colour_ButtonShadow",OPTION_COLOUR,&option_sys_colour_ButtonShadow }, { "sys_colour_ButtonText",OPTION_COLOUR,&option_sys_colour_ButtonText }, { "sys_colour_CaptionText",OPTION_COLOUR,&option_sys_colour_CaptionText }, { "sys_colour_GrayText",OPTION_COLOUR,&option_sys_colour_GrayText }, { "sys_colour_Highlight",OPTION_COLOUR,&option_sys_colour_Highlight }, { "sys_colour_HighlightText",OPTION_COLOUR,&option_sys_colour_HighlightText }, { "sys_colour_InactiveBorder",OPTION_COLOUR,&option_sys_colour_InactiveBorder }, { "sys_colour_InactiveCaption",OPTION_COLOUR,&option_sys_colour_InactiveCaption }, { "sys_colour_InactiveCaptionText",OPTION_COLOUR,&option_sys_colour_InactiveCaptionText }, { "sys_colour_InfoBackground",OPTION_COLOUR,&option_sys_colour_InfoBackground }, { "sys_colour_InfoText",OPTION_COLOUR,&option_sys_colour_InfoText }, { "sys_colour_Menu",OPTION_COLOUR,&option_sys_colour_Menu }, { "sys_colour_MenuText",OPTION_COLOUR,&option_sys_colour_MenuText }, { "sys_colour_Scrollbar",OPTION_COLOUR,&option_sys_colour_Scrollbar }, { "sys_colour_ThreeDDarkShadow",OPTION_COLOUR,&option_sys_colour_ThreeDDarkShadow }, { "sys_colour_ThreeDFace",OPTION_COLOUR,&option_sys_colour_ThreeDFace }, { "sys_colour_ThreeDHighlight",OPTION_COLOUR,&option_sys_colour_ThreeDHighlight }, { "sys_colour_ThreeDLightShadow",OPTION_COLOUR,&option_sys_colour_ThreeDLightShadow }, { "sys_colour_ThreeDShadow",OPTION_COLOUR,&option_sys_colour_ThreeDShadow }, { "sys_colour_Window",OPTION_COLOUR,&option_sys_colour_Window }, { "sys_colour_WindowFrame",OPTION_COLOUR,&option_sys_colour_WindowFrame }, { "sys_colour_WindowText",OPTION_COLOUR,&option_sys_colour_WindowText }, EXTRA_OPTION_TABLE }; #define option_table_entries (sizeof option_table / sizeof option_table[0]) /** * Set an option value based on a string */ static bool strtooption(const char *value, struct option_entry_s *option_entry) { bool ret = false; colour rgbcolour; /* RRGGBB */ switch (option_entry->type) { case OPTION_BOOL: *((bool *)option_entry->p) = value[0] == '1'; ret = true; break; case OPTION_INTEGER: *((int *)option_entry->p) = atoi(value); ret = true; break; case OPTION_COLOUR: sscanf(value, "%x", &rgbcolour); *((colour *)option_entry->p) = ((0x000000FF & rgbcolour) << 16) | ((0x0000FF00 & rgbcolour) << 0) | ((0x00FF0000 & rgbcolour) >> 16); ret = true; break; case OPTION_STRING: free(*((char **)option_entry->p)); *((char **)option_entry->p) = strdup(value); ret = true; break; } return ret; } /* exported interface documented in options.h */ void options_read(const char *path) { char s[100]; FILE *fp; fp = fopen(path, "r"); if (!fp) { LOG(("failed to open file '%s'", path)); return; } while (fgets(s, 100, fp)) { char *colon, *value; unsigned int i; if (s[0] == 0 || s[0] == '#') continue; colon = strchr(s, ':'); if (colon == 0) continue; s[strlen(s) - 1] = 0; /* remove \n at end */ *colon = 0; /* terminate key */ value = colon + 1; for (i = 0; i != option_table_entries; i++) { if (strcasecmp(s, option_table[i].key) != 0) continue; strtooption(value, option_table + i); break; } } fclose(fp); if (option_font_size < 50) option_font_size = 50; if (1000 < option_font_size) option_font_size = 1000; if (option_font_min_size < 10) option_font_min_size = 10; if (500 < option_font_min_size) option_font_min_size = 500; if (option_memory_cache_size < 0) option_memory_cache_size = 0; } /* exported interface documented in options.h */ void options_write(const char *path) { unsigned int entry; FILE *fp; colour rgbcolour; /* RRGGBB */ fp = fopen(path, "w"); if (!fp) { LOG(("failed to open file '%s' for writing", path)); return; } for (entry = 0; entry != option_table_entries; entry++) { switch (option_table[entry].type) { case OPTION_BOOL: fprintf(fp, "%s:%c\n", option_table[entry].key, *((bool *) option_table[entry].p) ? '1' : '0'); break; case OPTION_INTEGER: fprintf(fp, "%s:%i\n", option_table[entry].key, *((int *) option_table[entry].p)); break; case OPTION_COLOUR: rgbcolour = ((0x000000FF & *((colour *) option_table[entry].p)) << 16) | ((0x0000FF00 & *((colour *) option_table[entry].p)) << 0) | ((0x00FF0000 & *((colour *) option_table[entry].p)) >> 16); fprintf(fp, "%s:%06x\n", option_table[entry].key, rgbcolour); break; case OPTION_STRING: if (((*((char **) option_table[entry].p)) != NULL) && (*(*((char **) option_table[entry].p)) != 0)) { fprintf(fp, "%s:%s\n", option_table[entry].key, *((char **) option_table[entry].p)); } break; } } fclose(fp); } /** * Output an option value into a string, in HTML format. * * \param option The option to output the value of. * \param size The size of the string buffer. * \param pos The current position in string * \param string The string in which to output the value. * \return The number of bytes written to string or -1 on error */ static size_t options_output_value_html(struct option_entry_s *option, size_t size, size_t pos, char *string) { size_t slen = 0; /* length added to string */ colour rgbcolour; /* RRGGBB */ switch (option->type) { case OPTION_BOOL: slen = snprintf(string + pos, size - pos, "%s", *((bool *)option->p) ? "true" : "false"); break; case OPTION_INTEGER: slen = snprintf(string + pos, size - pos, "%i", *((int *)option->p)); break; case OPTION_COLOUR: rgbcolour = ((0x000000FF & *((colour *) option->p)) << 16) | ((0x0000FF00 & *((colour *) option->p)) << 0) | ((0x00FF0000 & *((colour *) option->p)) >> 16); slen = snprintf(string + pos, size - pos, "#%06x", rgbcolour, (~rgbcolour) & 0xffffff, rgbcolour); break; case OPTION_STRING: if (*((char **)option->p) != NULL) { slen = snprintf(string + pos, size - pos, "%s", *((char **)option->p)); } else { slen = snprintf(string + pos, size - pos, "NULL" ""); } break; } return slen; } /** * Output an option value into a string, in plain text format. * * \param option The option to output the value of. * \param size The size of the string buffer. * \param pos The current position in string * \param string The string in which to output the value. * \return The number of bytes written to string or -1 on error */ static size_t options_output_value_text(struct option_entry_s *option, size_t size, size_t pos, char *string) { size_t slen = 0; /* length added to string */ colour rgbcolour; /* RRGGBB */ switch (option->type) { case OPTION_BOOL: slen = snprintf(string + pos, size - pos, "%c", *((bool *)option->p) ? '1' : '0'); break; case OPTION_INTEGER: slen = snprintf(string + pos, size - pos, "%i", *((int *)option->p)); break; case OPTION_COLOUR: rgbcolour = ((0x000000FF & *((colour *) option->p)) << 16) | ((0x0000FF00 & *((colour *) option->p)) << 0) | ((0x00FF0000 & *((colour *) option->p)) >> 16); slen = snprintf(string + pos, size - pos, "%06x", rgbcolour); break; case OPTION_STRING: if (*((char **)option->p) != NULL) { slen = snprintf(string + pos, size - pos, "%s", *((char **)option->p)); } break; } return slen; } /* exported interface documented in options.h */ void options_commandline(int *pargc, char **argv) { char *arg; char *val; int arglen; int idx = 1; int mv_loop; unsigned int entry_loop; while (idx < *pargc) { arg = argv[idx]; arglen = strlen(arg); /* check we have an option */ /* option must start -- and be as long as the shortest option*/ if ((arglen < (2+5) ) || (arg[0] != '-') || (arg[1] != '-')) break; arg += 2; /* skip -- */ val = strchr(arg, '='); if (val == NULL) { /* no equals sign - next parameter is val */ idx++; if (idx >= *pargc) break; val = argv[idx]; } else { /* equals sign */ arglen = val - arg ; val++; } /* arg+arglen is the option to set, val is the value */ LOG(("%.*s = %s",arglen,arg,val)); for (entry_loop = 0; entry_loop < option_table_entries; entry_loop++) { if (strncmp(arg, option_table[entry_loop].key, arglen) == 0) { strtooption(val, option_table + entry_loop); break; } } idx++; } /* remove processed options from argv */ for (mv_loop=0;mv_loop < (*pargc - idx); mv_loop++) { argv[mv_loop + 1] = argv[mv_loop + idx]; } *pargc -= (idx - 1); } /* exported interface documented in options.h */ int options_snoptionf(char *string, size_t size, unsigned int option, const char *fmt) { size_t slen = 0; /* current output string length */ int fmtc = 0; /* current index into format string */ struct option_entry_s *option_entry; if (option >= option_table_entries) return -1; option_entry = option_table + option; while((slen < size) && (fmt[fmtc] != 0)) { if (fmt[fmtc] == '%') { fmtc++; switch (fmt[fmtc]) { case 'k': slen += snprintf(string + slen, size - slen, "%s", option_entry->key); break; case 't': switch (option_entry->type) { case OPTION_BOOL: slen += snprintf(string + slen, size - slen, "boolean"); break; case OPTION_INTEGER: slen += snprintf(string + slen, size - slen, "integer"); break; case OPTION_COLOUR: slen += snprintf(string + slen, size - slen, "colour"); break; case OPTION_STRING: slen += snprintf(string + slen, size - slen, "string"); break; } break; case 'V': slen += options_output_value_html(option_entry, size, slen, string); break; case 'v': slen += options_output_value_text(option_entry, size, slen, string); break; } fmtc++; } else { string[slen] = fmt[fmtc]; slen++; fmtc++; } } /* Ensure that we NUL-terminate the output */ string[min(slen, size - 1)] = '\0'; return slen; } /* exported interface documented in options.h */ void options_dump(FILE *outf) { char buffer[256]; int opt_loop = 0; int res; do { res = options_snoptionf(buffer, sizeof buffer, opt_loop, "%k:%v\n"); if (res > 0) { fprintf(outf, "%s", buffer); } opt_loop++; } while (res > 0); }