Prepare for release 1.9.0.
[xxxterm.git] / settings.c
blobd1de255fc9a81c6e861de11538058028ee4d8882
1 /*
2 * Copyright (c) 2010, 2011 Marco Peereboom <marco@peereboom.us>
3 * Copyright (c) 2011 Stevan Andjelkovic <stevan@student.chalmers.se>
4 * Copyright (c) 2010, 2011 Edd Barrett <vext01@gmail.com>
5 * Copyright (c) 2011 Todd T. Fries <todd@fries.net>
6 * Copyright (c) 2011 Raphael Graf <r@undefined.ch>
7 * Copyright (c) 2011 Michal Mazurek <akfaew@jasminek.net>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include "xxxterm.h"
24 /* globals */
25 SoupURI *proxy_uri = NULL;
26 PangoFontDescription *cmd_font;
27 PangoFontDescription *oops_font;
28 PangoFontDescription *statusbar_font;
29 PangoFontDescription *tabbar_font;
31 /* settings that require restart */
32 int tabless = 0; /* allow only 1 tab */
33 int enable_socket = 0;
34 int single_instance = 0; /* only allow one xxxterm to run */
35 int fancy_bar = 1; /* fancy toolbar */
36 int browser_mode = XT_BM_NORMAL;
37 int enable_localstorage = 1;
38 char *statusbar_elems = NULL;
40 /* runtime settings */
41 int show_tabs = 1; /* show tabs on notebook */
42 int tab_style = XT_TABS_NORMAL; /* tab bar style */
43 int show_url = 1; /* show url toolbar on notebook */
44 int show_statusbar = 0; /* vimperator style status bar */
45 int ctrl_click_focus = 0; /* ctrl click gets focus */
46 int cookies_enabled = 1; /* enable cookies */
47 int read_only_cookies = 0; /* enable to not write cookies */
48 int enable_scripts = 1;
49 int enable_plugins = 1;
50 gfloat default_zoom_level = 1.0;
51 char default_script[PATH_MAX];
52 int window_height = 768;
53 int window_width = 1024;
54 int icon_size = 2; /* 1 = smallest, 2+ = bigger */
55 int refresh_interval = 10; /* download refresh interval */
56 int enable_plugin_whitelist = 0;
57 int enable_cookie_whitelist = 0;
58 int enable_js_whitelist = 0;
59 int session_timeout = 3600; /* cookie session timeout */
60 int cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
61 char *ssl_ca_file = NULL;
62 char *resource_dir = NULL;
63 gboolean ssl_strict_certs = FALSE;
64 int append_next = 1; /* append tab after current tab */
65 char *home = NULL;
66 char *search_string = NULL;
67 char *http_proxy = NULL;
68 char download_dir[PATH_MAX];
69 char runtime_settings[PATH_MAX]; /* override of settings */
70 int allow_volatile_cookies = 0;
71 int save_global_history = 0; /* save global history to disk */
72 char *user_agent = NULL;
73 int save_rejected_cookies = 0;
74 int session_autosave = 0;
75 int guess_search = 0;
76 int dns_prefetch = FALSE;
77 gint max_connections = 25;
78 gint max_host_connections = 5;
79 gint enable_spell_checking = 0;
80 char *spell_check_languages = NULL;
81 int xterm_workaround = 0;
82 char *url_regex = NULL;
83 int history_autosave = 0;
84 char search_file[PATH_MAX];
85 char command_file[PATH_MAX];
86 char *encoding = NULL;
87 int autofocus_onload = 0;
88 int js_autorun_enabled = 1;
89 int edit_mode = XT_EM_HYBRID;
91 char *cmd_font_name = NULL;
92 char *oops_font_name = NULL;
93 char *statusbar_font_name = NULL;
94 char *tabbar_font_name = NULL;
96 char *get_download_dir(struct settings *);
97 char *get_default_script(struct settings *);
98 char *get_runtime_dir(struct settings *);
99 char *get_tab_style(struct settings *);
100 char *get_edit_mode(struct settings *);
101 char *get_work_dir(struct settings *);
103 int add_cookie_wl(struct settings *, char *);
104 int add_js_wl(struct settings *, char *);
105 int add_pl_wl(struct settings *, char *);
106 int add_mime_type(struct settings *, char *);
107 int add_alias(struct settings *, char *);
108 int add_kb(struct settings *, char *);
110 int set_download_dir(struct settings *, char *);
111 int set_default_script(struct settings *, char *);
112 int set_runtime_dir(struct settings *, char *);
113 int set_tab_style(struct settings *, char *);
114 int set_edit_mode(struct settings *, char *);
115 int set_work_dir(struct settings *, char *);
117 void walk_mime_type(struct settings *, void (*)(struct settings *,
118 char *, void *), void *);
119 void walk_alias(struct settings *, void (*)(struct settings *,
120 char *, void *), void *);
121 void walk_cookie_wl(struct settings *, void (*)(struct settings *,
122 char *, void *), void *);
123 void walk_js_wl(struct settings *, void (*)(struct settings *,
124 char *, void *), void *);
125 void walk_pl_wl(struct settings *, void (*)(struct settings *,
126 char *, void *), void *);
127 void walk_kb(struct settings *, void (*)(struct settings *, char *,
128 void *), void *);
131 set_http_proxy(char *proxy)
133 SoupURI *uri;
135 if (proxy == NULL)
136 return (1);
138 /* see if we need to clear it instead */
139 if (strlen(proxy) == 0) {
140 setup_proxy(NULL);
141 return (0);
144 uri = soup_uri_new(proxy);
145 if (uri == NULL || !SOUP_URI_VALID_FOR_HTTP(uri))
146 return (1);
148 setup_proxy(proxy);
150 soup_uri_free(uri);
152 return (0);
155 struct special {
156 int (*set)(struct settings *, char *);
157 char *(*get)(struct settings *);
158 void (*walk)(struct settings *,
159 void (*cb)(struct settings *, char *, void *),
160 void *);
163 struct special s_browser_mode = {
164 set_browser_mode,
165 get_browser_mode,
166 NULL
169 struct special s_cookie = {
170 set_cookie_policy,
171 get_cookie_policy,
172 NULL
175 struct special s_alias = {
176 add_alias,
177 NULL,
178 walk_alias
181 struct special s_mime = {
182 add_mime_type,
183 NULL,
184 walk_mime_type
187 struct special s_js = {
188 add_js_wl,
189 NULL,
190 walk_js_wl
193 struct special s_pl = {
194 add_pl_wl,
195 NULL,
196 walk_pl_wl
199 struct special s_kb = {
200 add_kb,
201 NULL,
202 walk_kb
205 struct special s_cookie_wl = {
206 add_cookie_wl,
207 NULL,
208 walk_cookie_wl
211 struct special s_default_script = {
212 set_default_script,
213 get_default_script,
214 NULL
217 struct special s_download_dir = {
218 set_download_dir,
219 get_download_dir,
220 NULL
223 struct special s_work_dir = {
224 set_work_dir,
225 get_work_dir,
226 NULL
229 struct special s_tab_style = {
230 set_tab_style,
231 get_tab_style,
232 NULL
235 struct special s_edit_mode = {
236 set_edit_mode,
237 get_edit_mode,
238 NULL
241 struct settings rs[] = {
242 { "allow_volatile_cookies", XT_S_INT, 0, &allow_volatile_cookies, NULL, NULL },
243 { "append_next", XT_S_INT, 0, &append_next, NULL, NULL },
244 { "autofocus_onload", XT_S_INT, 0, &autofocus_onload, NULL, NULL },
245 { "browser_mode", XT_S_INT, 0, NULL, NULL,&s_browser_mode },
246 { "cookie_policy", XT_S_INT, 0, NULL, NULL,&s_cookie },
247 { "cookies_enabled", XT_S_INT, 0, &cookies_enabled, NULL, NULL },
248 { "ctrl_click_focus", XT_S_INT, 0, &ctrl_click_focus, NULL, NULL },
249 { "default_zoom_level", XT_S_FLOAT, 0, NULL, NULL, NULL, &default_zoom_level },
250 { "default_script", XT_S_STR, 0, NULL, NULL,&s_default_script },
251 { "download_dir", XT_S_STR, 0, NULL, NULL,&s_download_dir },
252 { "edit_mode", XT_S_STR, 0, NULL, NULL,&s_edit_mode },
253 { "enable_cookie_whitelist", XT_S_INT, 0, &enable_cookie_whitelist, NULL, NULL },
254 { "enable_js_whitelist", XT_S_INT, 0, &enable_js_whitelist, NULL, NULL },
255 { "enable_plugin_whitelist", XT_S_INT, 0, &enable_plugin_whitelist, NULL, NULL },
256 { "enable_localstorage", XT_S_INT, 0, &enable_localstorage, NULL, NULL },
257 { "enable_plugins", XT_S_INT, 0, &enable_plugins, NULL, NULL },
258 { "enable_scripts", XT_S_INT, 0, &enable_scripts, NULL, NULL },
259 { "enable_socket", XT_S_INT, XT_SF_RESTART,&enable_socket, NULL, NULL },
260 { "enable_spell_checking", XT_S_INT, 0, &enable_spell_checking, NULL, NULL },
261 { "encoding", XT_S_STR, 0, NULL, &encoding, NULL },
262 { "fancy_bar", XT_S_INT, XT_SF_RESTART,&fancy_bar, NULL, NULL },
263 { "guess_search", XT_S_INT, 0, &guess_search, NULL, NULL },
264 { "history_autosave", XT_S_INT, 0, &history_autosave, NULL, NULL },
265 { "home", XT_S_STR, 0, NULL, &home, NULL },
266 { "http_proxy", XT_S_STR, 0, NULL, &http_proxy, NULL, NULL, set_http_proxy },
267 { "icon_size", XT_S_INT, 0, &icon_size, NULL, NULL },
268 { "js_autorun_enabled", XT_S_INT, 0, &js_autorun_enabled, NULL, NULL },
269 { "max_connections", XT_S_INT, XT_SF_RESTART,&max_connections, NULL, NULL },
270 { "max_host_connections", XT_S_INT, XT_SF_RESTART,&max_host_connections, NULL, NULL },
271 { "read_only_cookies", XT_S_INT, 0, &read_only_cookies, NULL, NULL },
272 { "refresh_interval", XT_S_INT, 0, &refresh_interval, NULL, NULL },
273 { "resource_dir", XT_S_STR, 0, NULL, &resource_dir, NULL },
274 { "search_string", XT_S_STR, 0, NULL, &search_string, NULL },
275 { "save_global_history", XT_S_INT, XT_SF_RESTART,&save_global_history, NULL, NULL },
276 { "save_rejected_cookies", XT_S_INT, XT_SF_RESTART,&save_rejected_cookies, NULL, NULL },
277 { "session_timeout", XT_S_INT, 0, &session_timeout, NULL, NULL },
278 { "session_autosave", XT_S_INT, 0, &session_autosave, NULL, NULL },
279 { "single_instance", XT_S_INT, XT_SF_RESTART,&single_instance, NULL, NULL },
280 { "show_tabs", XT_S_INT, 0, &show_tabs, NULL, NULL },
281 { "show_url", XT_S_INT, 0, &show_url, NULL, NULL },
282 { "show_statusbar", XT_S_INT, 0, &show_statusbar, NULL, NULL },
283 { "spell_check_languages", XT_S_STR, 0, NULL, &spell_check_languages, NULL },
284 { "ssl_ca_file", XT_S_STR, 0, NULL, &ssl_ca_file, NULL },
285 { "ssl_strict_certs", XT_S_INT, 0, &ssl_strict_certs, NULL, NULL },
286 { "statusbar_elems", XT_S_STR, 0, NULL, &statusbar_elems, NULL },
287 { "tab_style", XT_S_STR, 0, NULL, NULL,&s_tab_style },
288 { "url_regex", XT_S_STR, 0, NULL, &url_regex, NULL },
289 { "user_agent", XT_S_STR, 0, NULL, &user_agent, NULL },
290 { "window_height", XT_S_INT, 0, &window_height, NULL, NULL },
291 { "window_width", XT_S_INT, 0, &window_width, NULL, NULL },
292 { "work_dir", XT_S_STR, 0, NULL, NULL,&s_work_dir },
293 { "xterm_workaround", XT_S_INT, 0, &xterm_workaround, NULL, NULL },
295 /* font settings */
296 { "cmd_font", XT_S_STR, 0, NULL, &cmd_font_name, NULL },
297 { "oops_font", XT_S_STR, 0, NULL, &oops_font_name, NULL },
298 { "statusbar_font", XT_S_STR, 0, NULL, &statusbar_font_name, NULL },
299 { "tabbar_font", XT_S_STR, 0, NULL, &tabbar_font_name, NULL },
301 /* runtime settings */
302 { "alias", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_alias },
303 { "cookie_wl", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cookie_wl },
304 { "js_wl", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_js },
305 { "keybinding", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_kb },
306 { "mime_type", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_mime },
307 { "pl_wl", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_pl },
310 size_t
311 get_settings_size(void)
313 return (LENGTH(rs));
316 char *
317 get_setting_name(int i)
319 if (i > LENGTH(rs))
320 return (NULL);
321 return (rs[i].name);
324 char *
325 get_as_string(struct settings *s)
327 char *r = NULL;
329 if (s == NULL)
330 return (NULL);
332 if (s->s) {
333 if (s->s->get)
334 r = s->s->get(s);
335 else
336 warnx("get_as_string skip %s\n", s->name);
337 } else if (s->type == XT_S_INT)
338 r = g_strdup_printf("%d", *s->ival);
339 else if (s->type == XT_S_STR)
340 r = g_strdup(*s->sval);
341 else if (s->type == XT_S_FLOAT)
342 r = g_strdup_printf("%f", *s->fval);
343 else
344 r = g_strdup_printf("INVALID TYPE");
346 return (r);
349 void
350 settings_walk(void (*cb)(struct settings *, char *, void *), void *cb_args)
352 int i;
353 char *s;
355 for (i = 0; i < LENGTH(rs); i++) {
356 if (rs[i].s && rs[i].s->walk)
357 rs[i].s->walk(&rs[i], cb, cb_args);
358 else {
359 s = get_as_string(&rs[i]);
360 cb(&rs[i], s, cb_args);
361 g_free(s);
367 set_browser_mode(struct settings *s, char *val)
369 if (!strcmp(val, "whitelist")) {
370 browser_mode = XT_BM_WHITELIST;
371 allow_volatile_cookies = 0;
372 cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
373 cookies_enabled = 1;
374 enable_cookie_whitelist = 1;
375 enable_plugin_whitelist = 1;
376 enable_plugins = 0;
377 read_only_cookies = 0;
378 save_rejected_cookies = 0;
379 session_timeout = 3600;
380 enable_scripts = 0;
381 enable_js_whitelist = 1;
382 enable_localstorage = 0;
383 } else if (!strcmp(val, "normal")) {
384 browser_mode = XT_BM_NORMAL;
385 allow_volatile_cookies = 0;
386 cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
387 cookies_enabled = 1;
388 enable_cookie_whitelist = 0;
389 enable_plugin_whitelist = 0;
390 enable_plugins = 1;
391 read_only_cookies = 0;
392 save_rejected_cookies = 0;
393 session_timeout = 3600;
394 enable_scripts = 1;
395 enable_js_whitelist = 0;
396 enable_localstorage = 1;
397 } else if (!strcmp(val, "kiosk")) {
398 browser_mode = XT_BM_KIOSK;
399 allow_volatile_cookies = 0;
400 cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
401 cookies_enabled = 1;
402 enable_cookie_whitelist = 0;
403 enable_plugin_whitelist = 0;
404 enable_plugins = 1;
405 read_only_cookies = 0;
406 save_rejected_cookies = 0;
407 session_timeout = 3600;
408 enable_scripts = 1;
409 enable_js_whitelist = 0;
410 enable_localstorage = 1;
411 show_tabs = 0;
412 tabless = 1;
413 } else
414 return (1);
416 return (0);
419 char *
420 get_browser_mode(struct settings *s)
422 char *r = NULL;
424 if (browser_mode == XT_BM_WHITELIST)
425 r = g_strdup("whitelist");
426 else if (browser_mode == XT_BM_NORMAL)
427 r = g_strdup("normal");
428 else if (browser_mode == XT_BM_KIOSK)
429 r = g_strdup("kiosk");
430 else
431 return (NULL);
433 return (r);
437 set_cookie_policy(struct settings *s, char *val)
439 if (!strcmp(val, "no3rdparty"))
440 cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
441 else if (!strcmp(val, "accept"))
442 cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
443 else if (!strcmp(val, "reject"))
444 cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NEVER;
445 else
446 return (1);
448 return (0);
451 char *
452 get_cookie_policy(struct settings *s)
454 char *r = NULL;
456 if (cookie_policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY)
457 r = g_strdup("no3rdparty");
458 else if (cookie_policy == SOUP_COOKIE_JAR_ACCEPT_ALWAYS)
459 r = g_strdup("accept");
460 else if (cookie_policy == SOUP_COOKIE_JAR_ACCEPT_NEVER)
461 r = g_strdup("reject");
462 else
463 return (NULL);
465 return (r);
468 char *
469 get_default_script(struct settings *s)
471 if (default_script[0] == '\0')
472 return (0);
473 return (g_strdup(default_script));
477 set_default_script(struct settings *s, char *val)
479 if (val[0] == '~')
480 snprintf(default_script, sizeof default_script, "%s/%s",
481 pwd->pw_dir, &val[1]);
482 else
483 strlcpy(default_script, val, sizeof default_script);
485 return (0);
488 char *
489 get_download_dir(struct settings *s)
491 if (download_dir[0] == '\0')
492 return (0);
493 return (g_strdup(download_dir));
497 set_download_dir(struct settings *s, char *val)
499 if (val[0] == '~')
500 snprintf(download_dir, sizeof download_dir, "%s/%s",
501 pwd->pw_dir, &val[1]);
502 else
503 strlcpy(download_dir, val, sizeof download_dir);
505 return (0);
509 add_alias(struct settings *s, char *line)
511 char *l, *alias;
512 struct alias *a = NULL;
514 if (s == NULL || line == NULL) {
515 show_oops(NULL, "add_alias invalid parameters");
516 return (1);
519 l = line;
520 a = g_malloc(sizeof(*a));
522 if ((alias = strsep(&l, " \t,")) == NULL || l == NULL) {
523 show_oops(NULL, "add_alias: incomplete alias definition");
524 goto bad;
526 if (strlen(alias) == 0 || strlen(l) == 0) {
527 show_oops(NULL, "add_alias: invalid alias definition");
528 goto bad;
531 a->a_name = g_strdup(alias);
532 a->a_uri = g_strdup(l);
534 DNPRINTF(XT_D_CONFIG, "add_alias: %s for %s\n", a->a_name, a->a_uri);
536 TAILQ_INSERT_TAIL(&aliases, a, entry);
538 return (0);
539 bad:
540 if (a)
541 g_free(a);
542 return (1);
545 void
546 walk_alias(struct settings *s,
547 void (*cb)(struct settings *, char *, void *), void *cb_args)
549 struct alias *a;
550 char *str;
552 if (s == NULL || cb == NULL) {
553 show_oops(NULL, "walk_alias invalid parameters");
554 return;
557 TAILQ_FOREACH(a, &aliases, entry) {
558 str = g_strdup_printf("%s --> %s", a->a_name, a->a_uri);
559 cb(s, str, cb_args);
560 g_free(str);
565 add_mime_type(struct settings *s, char *line)
567 char *mime_type;
568 char *l;
569 struct mime_type *m = NULL;
570 int downloadfirst = 0;
572 /* XXX this could be smarter */
574 if (line == NULL || strlen(line) == 0) {
575 show_oops(NULL, "add_mime_type invalid parameters");
576 return (1);
579 l = line;
580 if (*l == '@') {
581 downloadfirst = 1;
582 l++;
584 m = g_malloc(sizeof(*m));
586 if ((mime_type = strsep(&l, " \t,")) == NULL || l == NULL) {
587 show_oops(NULL, "add_mime_type: invalid mime_type");
588 goto bad;
590 if (mime_type[strlen(mime_type) - 1] == '*') {
591 mime_type[strlen(mime_type) - 1] = '\0';
592 m->mt_default = 1;
593 } else
594 m->mt_default = 0;
596 if (strlen(mime_type) == 0 || strlen(l) == 0) {
597 show_oops(NULL, "add_mime_type: invalid mime_type");
598 goto bad;
601 m->mt_type = g_strdup(mime_type);
602 m->mt_action = g_strdup(l);
603 m->mt_download = downloadfirst;
605 DNPRINTF(XT_D_CONFIG, "add_mime_type: type %s action %s default %d\n",
606 m->mt_type, m->mt_action, m->mt_default);
608 TAILQ_INSERT_TAIL(&mtl, m, entry);
610 return (0);
611 bad:
612 if (m)
613 g_free(m);
614 return (1);
617 void
618 walk_mime_type(struct settings *s,
619 void (*cb)(struct settings *, char *, void *), void *cb_args)
621 struct mime_type *m;
622 char *str;
624 if (s == NULL || cb == NULL) {
625 show_oops(NULL, "walk_mime_type invalid parameters");
626 return;
629 TAILQ_FOREACH(m, &mtl, entry) {
630 str = g_strdup_printf("%s%s --> %s",
631 m->mt_type,
632 m->mt_default ? "*" : "",
633 m->mt_action);
634 cb(s, str, cb_args);
635 g_free(str);
639 /* inherent to GTK not all keys will be caught at all times */
640 /* XXX sort key bindings */
641 struct key_binding keys[] = {
642 { "command_mode", 0, 1, GDK_Escape },
643 { "insert_mode", 0, 0, GDK_i },
644 { "cookiejar", MOD1, 1, GDK_j },
645 { "downloadmgr", MOD1, 1, GDK_d },
646 { "history", MOD1, 1, GDK_h },
647 { "print", CTRL, 1, GDK_p },
648 { "search", 0, 0, GDK_slash },
649 { "searchb", 0, 0, GDK_question },
650 { "statustoggle", CTRL, 1, GDK_n },
651 { "command", 0, 0, GDK_colon },
652 { "qa", CTRL, 1, GDK_q },
653 { "restart", MOD1, 1, GDK_q },
654 { "js toggle", CTRL, 1, GDK_j },
655 { "plugin toggle", MOD1, 1, GDK_p },
656 { "cookie toggle", MOD1, 1, GDK_c },
657 { "togglesrc", CTRL, 1, GDK_s },
658 { "yankuri", 0, 0, GDK_y },
659 { "pasteuricur", 0, 0, GDK_p },
660 { "pasteurinew", 0, 0, GDK_P },
661 { "toplevel toggle", 0, 1, GDK_F4 },
662 { "help", 0, 1, GDK_F1 },
663 { "run_script", MOD1, 1, GDK_r },
664 { "proxy toggle", 0, 1, GDK_F2 },
666 /* search */
667 { "searchnext", 0, 0, GDK_n },
668 { "searchprevious", 0, 0, GDK_N },
670 /* focus */
671 { "focusaddress", 0, 1, GDK_F6 },
672 { "focussearch", 0, 1, GDK_F7 },
674 /* hinting */
675 { "hinting", 0, 0, GDK_f },
676 { "hinting", 0, 0, GDK_period },
677 { "hinting_newtab", SHFT, 0, GDK_F },
678 { "hinting_newtab", 0, 0, GDK_comma },
680 /* custom stylesheet */
681 { "userstyle", 0, 0, GDK_s },
683 /* navigation */
684 { "goback", 0, 0, GDK_BackSpace },
685 { "goback", MOD1, 1, GDK_Left },
686 { "goforward", SHFT, 1, GDK_BackSpace },
687 { "goforward", MOD1, 1, GDK_Right },
688 { "reload", 0, 1, GDK_F5 },
689 { "reload", CTRL, 1, GDK_r },
690 { "reload", CTRL, 1, GDK_l },
691 { "favorites", MOD1, 1, GDK_f },
693 /* vertical movement */
694 { "scrolldown", 0, 0, GDK_j },
695 { "scrolldown", 0, 0, GDK_Down },
696 { "scrollup", 0, 0, GDK_Up },
697 { "scrollup", 0, 0, GDK_k },
698 { "scrollbottom", 0, 0, GDK_G },
699 { "scrollbottom", 0, 0, GDK_End },
700 { "scrolltop", 0, 0, GDK_Home },
701 { "scrollpagedown", 0, 0, GDK_space },
702 { "scrollpagedown", CTRL, 1, GDK_f },
703 { "scrollhalfdown", CTRL, 1, GDK_d },
704 { "scrollpagedown", 0, 0, GDK_Page_Down },
705 { "scrollpageup", 0, 0, GDK_Page_Up },
706 { "scrollpageup", CTRL, 1, GDK_b },
707 { "scrollhalfup", CTRL, 1, GDK_u },
708 /* horizontal movement */
709 { "scrollright", 0, 0, GDK_l },
710 { "scrollright", 0, 0, GDK_Right },
711 { "scrollleft", 0, 0, GDK_Left },
712 { "scrollleft", 0, 0, GDK_h },
713 { "scrollfarright", 0, 0, GDK_dollar },
714 { "scrollfarleft", 0, 0, GDK_0 },
716 /* tabs */
717 { "tabnew", CTRL, 1, GDK_t },
718 { "999tabnew", CTRL, 1, GDK_T },
719 { "tabclose", CTRL, 1, GDK_w },
720 { "tabundoclose", 0, 0, GDK_U },
721 { "tabnext 1", CTRL, 1, GDK_1 },
722 { "tabnext 2", CTRL, 1, GDK_2 },
723 { "tabnext 3", CTRL, 1, GDK_3 },
724 { "tabnext 4", CTRL, 1, GDK_4 },
725 { "tabnext 5", CTRL, 1, GDK_5 },
726 { "tabnext 6", CTRL, 1, GDK_6 },
727 { "tabnext 7", CTRL, 1, GDK_7 },
728 { "tabnext 8", CTRL, 1, GDK_8 },
729 { "tabnext 9", CTRL, 1, GDK_9 },
730 { "tabfirst", CTRL, 1, GDK_less },
731 { "tablast", CTRL, 1, GDK_greater },
732 { "tabprevious", CTRL, 1, GDK_Left },
733 { "tabnext", CTRL, 1, GDK_Right },
734 { "focusout", CTRL, 1, GDK_minus },
735 { "focusin", CTRL, 1, GDK_plus },
736 { "focusin", CTRL, 1, GDK_equal },
737 { "focusreset", CTRL, 1, GDK_0 },
739 /* command aliases (handy when -S flag is used) */
740 { "promptopen", 0, 1, GDK_F9 },
741 { "promptopencurrent", 0, 1, GDK_F10 },
742 { "prompttabnew", 0, 1, GDK_F11 },
743 { "prompttabnewcurrent",0, 1, GDK_F12 },
746 void
747 walk_kb(struct settings *s,
748 void (*cb)(struct settings *, char *, void *), void *cb_args)
750 struct key_binding *k;
751 char str[1024];
753 if (s == NULL || cb == NULL) {
754 show_oops(NULL, "walk_kb invalid parameters");
755 return;
758 TAILQ_FOREACH(k, &kbl, entry) {
759 if (k->cmd == NULL)
760 continue;
761 str[0] = '\0';
763 /* sanity */
764 if (gdk_keyval_name(k->key) == NULL)
765 continue;
767 strlcat(str, k->cmd, sizeof str);
768 strlcat(str, ",", sizeof str);
770 if (k->mask & GDK_SHIFT_MASK)
771 strlcat(str, "S-", sizeof str);
772 if (k->mask & GDK_CONTROL_MASK)
773 strlcat(str, "C-", sizeof str);
774 if (k->mask & GDK_MOD1_MASK)
775 strlcat(str, "M1-", sizeof str);
776 if (k->mask & GDK_MOD2_MASK)
777 strlcat(str, "M2-", sizeof str);
778 if (k->mask & GDK_MOD3_MASK)
779 strlcat(str, "M3-", sizeof str);
780 if (k->mask & GDK_MOD4_MASK)
781 strlcat(str, "M4-", sizeof str);
782 if (k->mask & GDK_MOD5_MASK)
783 strlcat(str, "M5-", sizeof str);
785 strlcat(str, gdk_keyval_name(k->key), sizeof str);
786 cb(s, str, cb_args);
790 void
791 init_keybindings(void)
793 int i;
794 struct key_binding *k;
796 for (i = 0; i < LENGTH(keys); i++) {
797 k = g_malloc0(sizeof *k);
798 k->cmd = keys[i].cmd;
799 k->mask = keys[i].mask;
800 k->use_in_entry = keys[i].use_in_entry;
801 k->key = keys[i].key;
802 TAILQ_INSERT_HEAD(&kbl, k, entry);
804 DNPRINTF(XT_D_KEYBINDING, "init_keybindings: added: %s\n",
805 k->cmd ? k->cmd : "unnamed key");
809 void
810 keybinding_clearall(void)
812 struct key_binding *k, *next;
814 for (k = TAILQ_FIRST(&kbl); k; k = next) {
815 next = TAILQ_NEXT(k, entry);
816 if (k->cmd == NULL)
817 continue;
819 DNPRINTF(XT_D_KEYBINDING, "keybinding_clearall: %s\n",
820 k->cmd ? k->cmd : "unnamed key");
821 TAILQ_REMOVE(&kbl, k, entry);
822 g_free(k);
827 keybinding_add(char *cmd, char *key, int use_in_entry)
829 struct key_binding *k;
830 guint keyval, mask = 0;
831 int i;
833 DNPRINTF(XT_D_KEYBINDING, "keybinding_add: %s %s\n", cmd, key);
835 /* Keys which are to be used in entry have been prefixed with an
836 * exclamation mark. */
837 if (use_in_entry)
838 key++;
840 /* find modifier keys */
841 if (strstr(key, "S-"))
842 mask |= GDK_SHIFT_MASK;
843 if (strstr(key, "C-"))
844 mask |= GDK_CONTROL_MASK;
845 if (strstr(key, "M1-"))
846 mask |= GDK_MOD1_MASK;
847 if (strstr(key, "M2-"))
848 mask |= GDK_MOD2_MASK;
849 if (strstr(key, "M3-"))
850 mask |= GDK_MOD3_MASK;
851 if (strstr(key, "M4-"))
852 mask |= GDK_MOD4_MASK;
853 if (strstr(key, "M5-"))
854 mask |= GDK_MOD5_MASK;
856 /* find keyname */
857 for (i = strlen(key) - 1; i > 0; i--)
858 if (key[i] == '-')
859 key = &key[i + 1];
861 /* validate keyname */
862 keyval = gdk_keyval_from_name(key);
863 if (keyval == GDK_VoidSymbol) {
864 warnx("invalid keybinding name %s", key);
865 return (1);
867 /* must run this test too, gtk+ doesn't handle 10 for example */
868 if (gdk_keyval_name(keyval) == NULL) {
869 warnx("invalid keybinding name %s", key);
870 return (1);
873 /* Remove eventual dupes. */
874 TAILQ_FOREACH(k, &kbl, entry)
875 if (k->key == keyval && k->mask == mask) {
876 TAILQ_REMOVE(&kbl, k, entry);
877 g_free(k);
878 break;
881 /* add keyname */
882 k = g_malloc0(sizeof *k);
883 k->cmd = g_strdup(cmd);
884 k->mask = mask;
885 k->use_in_entry = use_in_entry;
886 k->key = keyval;
888 DNPRINTF(XT_D_KEYBINDING, "keybinding_add: %s 0x%x %d 0x%x\n",
889 k->cmd,
890 k->mask,
891 k->use_in_entry,
892 k->key);
893 DNPRINTF(XT_D_KEYBINDING, "keybinding_add: adding: %s %s\n",
894 k->cmd, gdk_keyval_name(keyval));
896 TAILQ_INSERT_HEAD(&kbl, k, entry);
898 return (0);
902 add_kb(struct settings *s, char *entry)
904 char *kb, *key;
906 DNPRINTF(XT_D_KEYBINDING, "add_kb: %s\n", entry);
908 /* clearall is special */
909 if (!strcmp(entry, "clearall")) {
910 keybinding_clearall();
911 return (0);
914 kb = strstr(entry, ",");
915 if (kb == NULL)
916 return (1);
917 *kb = '\0';
918 key = kb + 1;
920 return (keybinding_add(entry, key, key[0] == '!'));
923 void
924 setup_proxy(char *uri)
926 if (proxy_uri) {
927 g_object_set(session, "proxy_uri", NULL, (char *)NULL);
928 soup_uri_free(proxy_uri);
929 proxy_uri = NULL;
931 if (http_proxy) {
932 if (http_proxy != uri) {
933 g_free(http_proxy);
934 http_proxy = NULL;
938 if (uri) {
939 http_proxy = g_strdup(uri);
940 DNPRINTF(XT_D_CONFIG, "setup_proxy: %s\n", uri);
941 proxy_uri = soup_uri_new(http_proxy);
942 if (!(proxy_uri == NULL || !SOUP_URI_VALID_FOR_HTTP(proxy_uri)))
943 g_object_set(session, "proxy-uri", proxy_uri,
944 (char *)NULL);
948 char *
949 get_tab_style(struct settings *s)
951 if (tab_style == XT_TABS_NORMAL)
952 return (g_strdup("normal"));
953 else
954 return (g_strdup("compact"));
958 set_tab_style(struct settings *s, char *val)
960 if (!strcmp(val, "normal"))
961 tab_style = XT_TABS_NORMAL;
962 else if (!strcmp(val, "compact"))
963 tab_style = XT_TABS_COMPACT;
964 else
965 return (1);
967 return (0);
970 char *
971 get_edit_mode(struct settings *s)
973 if (edit_mode == XT_EM_HYBRID)
974 return (g_strdup("hybrid"));
975 else
976 return (g_strdup("vi"));
980 set_edit_mode(struct settings *s, char *val)
982 if (!strcmp(val, "hybrid"))
983 edit_mode = XT_EM_HYBRID;
984 else if (!strcmp(val, "vi"))
985 edit_mode = XT_EM_VI;
986 else
987 return (1);
989 return (0);
992 char *
993 get_work_dir(struct settings *s)
995 if (work_dir[0] == '\0')
996 return (0);
997 return (g_strdup(work_dir));
1001 set_work_dir(struct settings *s, char *val)
1003 if (val[0] == '~')
1004 snprintf(work_dir, sizeof work_dir, "%s/%s",
1005 pwd->pw_dir, &val[1]);
1006 else
1007 strlcpy(work_dir, val, sizeof work_dir);
1009 return (0);
1012 void
1013 walk_cookie_wl(struct settings *s,
1014 void (*cb)(struct settings *, char *, void *), void *cb_args)
1016 struct domain *d;
1018 if (s == NULL || cb == NULL) {
1019 show_oops(NULL, "walk_cookie_wl invalid parameters");
1020 return;
1023 RB_FOREACH_REVERSE(d, domain_list, &c_wl)
1024 cb(s, d->d, cb_args);
1027 void
1028 walk_js_wl(struct settings *s,
1029 void (*cb)(struct settings *, char *, void *), void *cb_args)
1031 struct domain *d;
1033 if (s == NULL || cb == NULL) {
1034 show_oops(NULL, "walk_js_wl invalid parameters");
1035 return;
1038 RB_FOREACH_REVERSE(d, domain_list, &js_wl)
1039 cb(s, d->d, cb_args);
1042 void
1043 walk_pl_wl(struct settings *s,
1044 void (*cb)(struct settings *, char *, void *), void *cb_args)
1046 struct domain *d;
1048 if (s == NULL || cb == NULL) {
1049 show_oops(NULL, "walk_pl_wl invalid parameters");
1050 return;
1053 RB_FOREACH_REVERSE(d, domain_list, &pl_wl)
1054 cb(s, d->d, cb_args);
1058 settings_add(char *var, char *val)
1060 int i, rv, *p;
1061 gfloat *f;
1062 char **s;
1064 /* get settings */
1065 for (i = 0, rv = 0; i < LENGTH(rs); i++) {
1066 if (strcmp(var, rs[i].name))
1067 continue;
1069 if (rs[i].s) {
1070 if (rs[i].s->set(&rs[i], val))
1071 errx(1, "invalid value for %s: %s", var, val);
1072 rv = 1;
1073 break;
1074 } else
1075 switch (rs[i].type) {
1076 case XT_S_INT:
1077 p = rs[i].ival;
1078 *p = atoi(val);
1079 rv = 1;
1080 break;
1081 case XT_S_STR:
1082 s = rs[i].sval;
1083 if (s == NULL)
1084 errx(1, "invalid sval for %s",
1085 rs[i].name);
1086 if (*s)
1087 g_free(*s);
1088 *s = g_strdup(val);
1089 rv = 1;
1090 break;
1091 case XT_S_FLOAT:
1092 f = rs[i].fval;
1093 *f = atof(val);
1094 rv = 1;
1095 break;
1096 case XT_S_INVALID:
1097 default:
1098 errx(1, "invalid type for %s", var);
1100 break;
1102 return (rv);
1105 #define WS "\n= \t"
1106 void
1107 config_parse(char *filename, int runtime)
1109 FILE *config, *f;
1110 char *line, *cp, *var, *val;
1111 size_t len, lineno = 0;
1112 int handled;
1113 char file[PATH_MAX];
1114 struct stat sb;
1116 DNPRINTF(XT_D_CONFIG, "config_parse: filename %s\n", filename);
1118 if (filename == NULL)
1119 return;
1121 if (runtime && runtime_settings[0] != '\0') {
1122 snprintf(file, sizeof file, "%s/%s",
1123 work_dir, runtime_settings);
1124 if (stat(file, &sb)) {
1125 warnx("runtime file doesn't exist, creating it");
1126 if ((f = fopen(file, "w")) == NULL)
1127 err(1, "runtime");
1128 fprintf(f, "# AUTO GENERATED, DO NOT EDIT\n");
1129 fclose(f);
1131 } else
1132 strlcpy(file, filename, sizeof file);
1134 if ((config = fopen(file, "r")) == NULL) {
1135 warn("config_parse: cannot open %s", filename);
1136 return;
1139 for (;;) {
1140 if ((line = fparseln(config, &len, &lineno, NULL, 0)) == NULL)
1141 if (feof(config) || ferror(config))
1142 break;
1144 cp = line;
1145 cp += (long)strspn(cp, WS);
1146 if (cp[0] == '\0') {
1147 /* empty line */
1148 free(line);
1149 continue;
1152 if ((var = strsep(&cp, WS)) == NULL || cp == NULL)
1153 startpage_add("invalid configuration file entry: %s",
1154 line);
1155 else {
1156 cp += (long)strspn(cp, WS);
1158 if ((val = strsep(&cp, "\0")) == NULL)
1159 break;
1161 DNPRINTF(XT_D_CONFIG, "config_parse: %s=%s\n",
1162 var, val);
1163 handled = settings_add(var, val);
1165 if (handled == 0)
1166 startpage_add("invalid configuration file entry"
1167 ": %s=%s", var, val);
1170 free(line);
1173 fclose(config);
1176 struct settings_args {
1177 char **body;
1178 int i;
1181 void
1182 print_setting(struct settings *s, char *val, void *cb_args)
1184 char *tmp, *color;
1185 struct settings_args *sa = cb_args;
1187 if (sa == NULL)
1188 return;
1190 if (s->flags & XT_SF_RUNTIME)
1191 color = "#22cc22";
1192 else
1193 color = "#cccccc";
1195 tmp = *sa->body;
1196 *sa->body = g_strdup_printf(
1197 "%s\n<tr>"
1198 "<td style='background-color: %s; width: 10%%;word-break:break-all'>%s</td>"
1199 "<td style='background-color: %s; width: 20%%;word-break:break-all'>%s</td>",
1200 *sa->body,
1201 color,
1202 s->name,
1203 color,
1206 g_free(tmp);
1207 sa->i++;
1211 set_show(struct tab *t, struct karg *args)
1213 char *body, *page, *tmp;
1214 int i = 1;
1215 struct settings_args sa;
1217 bzero(&sa, sizeof sa);
1218 sa.body = &body;
1220 /* body */
1221 body = g_strdup_printf("<div align='center'><table><tr>"
1222 "<th align='left'>Setting</th>"
1223 "<th align='left'>Value</th></tr>\n");
1225 settings_walk(print_setting, &sa);
1226 i = sa.i;
1228 /* small message if there are none */
1229 if (i == 1) {
1230 tmp = body;
1231 body = g_strdup_printf("%s\n<tr><td style='text-align:center'"
1232 "colspan='2'>No settings</td></tr>\n", body);
1233 g_free(tmp);
1236 tmp = body;
1237 body = g_strdup_printf("%s</table></div>", body);
1238 g_free(tmp);
1240 page = get_html_page("Settings", body, "", 0);
1242 g_free(body);
1244 load_webkit_string(t, page, XT_URI_ABOUT_SET);
1246 g_free(page);
1248 return (XT_CB_PASSTHROUGH);
1252 set(struct tab *t, struct karg *args)
1254 char *p, *val;
1255 int i;
1257 if (args == NULL || args->s == NULL)
1258 return (set_show(t, args));
1260 /* strip spaces */
1261 p = g_strstrip(args->s);
1263 if (strlen(p) == 0)
1264 return (set_show(t, args));
1266 /* we got some sort of string */
1267 val = g_strrstr(p, "=");
1268 if (val) {
1269 *val++ = '\0';
1270 val = g_strchomp(val);
1271 p = g_strchomp(p);
1273 for (i = 0; i < get_settings_size(); i++) {
1274 if (strcmp(rs[i].name, p))
1275 continue;
1277 if (rs[i].activate) {
1278 if (rs[i].activate(val))
1279 show_oops(t, "%s invalid value %s",
1280 p, val);
1281 else
1282 show_oops(t, ":set %s = %s", p, val);
1283 goto done;
1284 } else {
1285 show_oops(t, "not a runtime option: %s", p);
1286 goto done;
1289 show_oops(t, "unknown option: %s", p);
1290 } else {
1291 p = g_strchomp(p);
1293 for (i = 0; i < get_settings_size(); i++) {
1294 if (strcmp(rs[i].name, p))
1295 continue;
1297 /* XXX this could use some cleanup */
1298 switch (rs[i].type) {
1299 case XT_S_INT:
1300 if (rs[i].ival)
1301 show_oops(t, "%s = %d",
1302 rs[i].name, *rs[i].ival);
1303 else if (rs[i].s && rs[i].s->get)
1304 show_oops(t, "%s = %s",
1305 rs[i].name,
1306 rs[i].s->get(&rs[i]));
1307 else if (rs[i].s && rs[i].s->get == NULL)
1308 show_oops(t, "%s = ...", rs[i].name);
1309 else
1310 show_oops(t, "%s = ", rs[i].name);
1311 break;
1312 case XT_S_FLOAT:
1313 if (rs[i].fval)
1314 show_oops(t, "%s = %f",
1315 rs[i].name, *rs[i].fval);
1316 else if (rs[i].s && rs[i].s->get)
1317 show_oops(t, "%s = %s",
1318 rs[i].name,
1319 rs[i].s->get(&rs[i]));
1320 else if (rs[i].s && rs[i].s->get == NULL)
1321 show_oops(t, "%s = ...", rs[i].name);
1322 else
1323 show_oops(t, "%s = ", rs[i].name);
1324 break;
1325 case XT_S_STR:
1326 if (rs[i].sval && *rs[i].sval)
1327 show_oops(t, "%s = %s",
1328 rs[i].name, *rs[i].sval);
1329 else if (rs[i].s && rs[i].s->get)
1330 show_oops(t, "%s = %s",
1331 rs[i].name,
1332 rs[i].s->get(&rs[i]));
1333 else if (rs[i].s && rs[i].s->get == NULL)
1334 show_oops(t, "%s = ...", rs[i].name);
1335 else
1336 show_oops(t, "%s = ", rs[i].name);
1337 break;
1338 default:
1339 show_oops(t, "unknown type for %s", rs[i].name);
1340 goto done;
1343 goto done;
1345 show_oops(t, "unknown option: %s", p);
1347 done:
1348 return (XT_CB_PASSTHROUGH);