about summary refs log blame commit diff stats
path: root/settings.c
blob: 340c510aaa17b3c378f9120ca162d6c747a1a53b (plain) (tree)
1
2
3
4
5
6
7
8






                                                                     
                                                   













                                                                           
                     







                                          
                  
                                                      




                                                                      
                                  
                                                                         
                                                   
                                            
                                         
                                        



                                                              
                                     
                                       
                                           
                                                                          
                                           
                                            
                                          

                                         
                                     
                                         
                                       



                                                                           
                                                                               







                                                                                              
                                                                                         






                                                                                          
                                                                                         


                                                                                   


                                                                              
                                              
                                            



                                                                    
                                                                              
                                                          

                                                                              

                                                            
                                                                              




                                                                  
                                        
                                                  
                                       
                                                                      
                                      

                                                                      
 
                                                                          


                                            




                                                       
                                                        
                                                  
                                                      
                                                 
                                                
                                                    
                                                  






                                                         
                                                  
                                                           
                                                         
                                                          
 
                                        
                                             




                                               
                                      
                                 
                                                            
                                                   
                                                              


                                                    
                                              







                                                    
                                                           
                                             
                                                         
                                         

                                                               
                                                         
                                                        




                                                 

                                                             

                                              

                                                       




                                             
                                      
                                     




                                                  

                                                         
                                             
                                            
                                             
                                              

                                                   












                                                                              

                                                                              

                                                                               

                                                                             

                                                                              





                                     

                                                  
                                  



























                                                                          





                                      











                                    





                                       





























                                       





                                 





                                            





                                         

















                                          





                                             





                                       





                                           





                                





                                         





                                     





                                       
                                

                                                                                                                                        
                                                                                                                 

                                                                                                                            
                                                                                                                            
                                                                                              
                                                                                                      



                                                                                                                                 
                                                                                                                 
                                                                                                                                
                                                                                              
                                                                                                               
                                                                                                                                        
                                                                                          
                                                                                                                              
                                                                                                                                          

                                                                                                                                    
                                                                                                                              
                                                                                                                                  
                                                                                                                                  
                                                                                                                                          

                                                                                                                        
                                                                                                         
                                                                                                                                      
                                                                                                                                          
                                                                                              
                                                                                                                    
                                                                                                              
                                                                                                                    
                                                                                          
                                                                                                            
                                                                                              
                                                                                                          
                                                                                                                     
                                                                                                     
                                                                                                    

                                                                                                                
                                                                                                        
                                                                                                                              
                                                                                                   
                                                                                                                            
                                                                                                  

                                                                                                                 
                                                                                                                
                                                                                                                            

                                                                                                                          
                                                                                                              
                                                                                                            
                                                                                                           
                                                                                                                                
                                                                                                           
                                                                                                                            
                                                                                                     

                                                                                                                   
                                                                                                       

                                                                                                            
                                                                                                       
                                                                                                                            
                                                                                                                              
                                                                                                         
                                                                                                           
                                                                                                        
                                                                                          
                                                                                                                            
 
                              
                                                                                                    
                                                                                                        
                                                                                                        

                                                                                                          



                                                                                                   
                                                                                                 

  
   





                                                


                                                              











                                                                               







                                                        



                   

                            


                                        







                                                     



                   



                                   



                                                      



                                                              










                                                                     



                                                       



                                                               










                                                                       



                                                            



                                                                          
                                                            
                                 








                                                                    

                                                                








                                   



                                                         



                                                                    












                                                                           







                                                              



                   


                     
                             



                                                
                   

 


                              

                                      



                                                              

                   
 








































































                                                                           
                                                      

                                           













                                                              
                                                 

                                           













                                                              
                                                 

                                           

























                                              



































                                               













                                                                      


                                 


                                                    





                                                                          



























                                                                   
                                                                 


                   



                                                
                                                    


                                                 










                                               
                                                             








































































































































                                                                              
                                                                  
                                                                  



                                                                  

                                                                  
                                                                  
                                                                  

                                                                  



                                                                  


                                                                  
                                                                  

                                                                  
                                                                  
                                                                  
                                                                  
                                                                  





                                                                  

                                                                  








                                                                  
                                                                  


                                                                  





                                                                  










                                                                  

                                                                  

                                                                  

                                                                  








                                                                  

                                                                  
                                                                  
                                                                  
















                                                                  

                                                          



                                                                  





























































































































































                                                                          





















                                                                              











                                                                     
                                                 








                                                                             




















                                                           
   

































                                                                      

                                       

                                             
 

                                  

                                    
                                                 








                                                                 
                                    





                                                              
                                                 
                                          


   





























                                                                    

































                                                                         



















































                                                                         

                                 



                                        







                                                          







                                                                        
   
















                                                          




                                        







                                                          



                   




                                        







                                                                      



                   

                                  


                                        







                                                            
                   


   




                                        







                                                                        



                   




                                        







                                                            



                   




                                        







                                                                



                   

                                     


                                        







                                                                  





                                    


                                        







                                                                


                   






                                        








                                                                


                                                                      









                                        







                                                      








                                                                     


                                        







                                                                        









                                        







                                                      












                                                                     




                                                                    
                            

                                            











                                                                            







                                                                        


                   







                                                                       













                                                
      






                                        







                                                     








                                        







                                                            




                                                                      








                                                   

                                                 







                                                  
                             
                                       

                                      






                                                      

                                                    















                                                             






                                                                


                                          







                                       





                                        







                                                           








                                        




                                                          
                            

                                       








                                        







                                                           








                                        






                                                     


                                   

 
   





                                           






                                                     





                                                 





                                           






                                                     





                                                 



                                      

                                              



                                                                              


















                                                                               
                                                  
                                                                            


                                                                          
                                                      







                                        








                                                                               



                   



                                        



                                                   


                   














                                                     













                                                         


                   


                      

                                   



                                                                       

                                                                        











                                                                
                                                                              

                                                                     



                                                                           
























                                             





                                              



                                                  
                                          







                                                  
         
                                            


                   

















































                                                                 


                          










                                                                      



                   


                                                  
                              


                                  




                                                                          
                                                           
                                                                  









                                         
                                                            








                                            





                                               



                                                               
                                         
                                                        






                                                     
                                                                
                 



                   












                                             
      

                                 
                                      








                                            
                                         
                                    
                                     






                           

































                                                


                                              


      









                                           
                                                     


                   





                                        







                                                          


                   















































                                                                     


                                                 





                                                  
                                                     
                                                       




                                           




















































                                                                              
                                                         




























































                                                                                
                                                       









                                              
                                   








                                                                                         
                                          

                    

                                



























































                                                                              
                                              

                              
                                      















































































                                                                                
/*
 * Copyright (c) 2010, 2011 Marco Peereboom <marco@peereboom.us>
 * Copyright (c) 2011 Stevan Andjelkovic <stevan@student.chalmers.se>
 * Copyright (c) 2010, 2011 Edd Barrett <vext01@gmail.com>
 * Copyright (c) 2011 Todd T. Fries <todd@fries.net>
 * Copyright (c) 2011 Raphael Graf <r@undefined.ch>
 * Copyright (c) 2011 Michal Mazurek <akfaew@jasminek.net>
 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <xombrero.h>

/* globals */
SoupURI			*proxy_uri = NULL;
PangoFontDescription	*cmd_font;
PangoFontDescription	*oops_font;
PangoFontDescription	*statusbar_font;
PangoFontDescription	*tabbar_font;

/* non-settings */
int		tabless = 0;	/* allow only 1 tab */
char		search_file[PATH_MAX];
char		command_file[PATH_MAX];
char		runtime_settings[PATH_MAX]; /* override of settings */

/* settings that require restart */
int		enable_socket = 0;
int		single_instance = 0; /* only allow one xombrero to run */
int		fancy_bar = 1;	/* fancy toolbar */
int		browser_mode = XT_BM_NORMAL;
int		gui_mode = XT_GM_CLASSIC;
char		*statusbar_elems = NULL;
int		window_height = 768;
int		window_width = 1024;
int		window_maximize = 0;
int		icon_size = 2; /* 1 = smallest, 2+ = bigger */
char		*resource_dir = NULL;
char		download_dir[PATH_MAX];
int		allow_volatile_cookies = 0;
int		save_global_history = 0; /* save global history to disk */
struct user_agent	*user_agent = NULL;
struct http_accept	*http_accept = NULL;
int		save_rejected_cookies = 0;
gint		max_connections = 25;
gint		max_host_connections = 5;
int		history_autosave = 0;
int		edit_mode = XT_EM_HYBRID;
char		*include_config = NULL;

/* runtime settings */
int		show_tabs = XT_DS_SHOW_TABS;	/* show tabs on notebook */
int		tab_style = XT_DS_TAB_STYLE; /* tab bar style */
int		statusbar_style = XT_DS_STATUSBAR_STYLE; /* status bar style */
int		show_url = XT_DS_SHOW_URL;	/* show url toolbar on notebook */
int		show_statusbar = XT_DS_SHOW_STATUSBAR; /* vimperator style status bar */
int		ctrl_click_focus = XT_DS_CTRL_CLICK_FOCUS; /* ctrl click gets focus */
int		cookies_enabled = XT_DS_COOKIES_ENABLED; /* enable cookies */
int		read_only_cookies = XT_DS_READ_ONLY_COOKIES; /* enable to not write cookies */
int		enable_scripts = XT_DS_ENABLE_SCRIPTS;
int		enable_plugins = XT_DS_ENABLE_PLUGINS;
gfloat		default_zoom_level = XT_DS_DEFAULT_ZOOM_LEVEL;
char		default_script[PATH_MAX];	/* special setting - is never g_free'd */
int		refresh_interval = XT_DS_REFRESH_INTERVAL; /* download refresh interval */
int		enable_plugin_whitelist = XT_DS_ENABLE_PLUGIN_WHITELIST;
int		enable_cookie_whitelist = XT_DS_ENABLE_COOKIE_WHITELIST;
int		enable_js_whitelist = XT_DS_ENABLE_JS_WHITELIST;
int		enable_localstorage = XT_DS_ENABLE_LOCALSTORAGE;
int		session_timeout = XT_DS_SESSION_TIMEOUT; /* cookie session timeout */
int		cookie_policy = XT_DS_COOKIE_POLICY;
char		ssl_ca_file[PATH_MAX];		/* special setting - is never g_free'd */
gboolean	ssl_strict_certs = XT_DS_SSL_STRICT_CERTS;
gboolean	enable_strict_transport = XT_DS_ENABLE_STRICT_TRANSPORT;
int		append_next = XT_DS_APPEND_NEXT; /* append tab after current tab */
char		*home = NULL;			/* allocated/set at startup */
char		*search_string = NULL;		/* allocated/set at startup */
char		*http_proxy = NULL;
int		http_proxy_starts_enabled = 1;
int		download_mode = XT_DM_START;
int		color_visited_uris = XT_DS_COLOR_VISITED_URIS;
int		session_autosave = XT_DS_SESSION_AUTOSAVE;
int		guess_search = XT_DS_GUESS_SEARCH;
gint		enable_spell_checking = XT_DS_ENABLE_SPELL_CHECKING;
char		*spell_check_languages = NULL;	/* allocated/set at startup */
int		xterm_workaround = XT_DS_XTERM_WORKAROUND;
char		*url_regex = NULL;		/* allocated/set at startup */
char		*encoding = NULL;		/* allocated/set at startup */
int		autofocus_onload = XT_DS_AUTOFOCUS_ONLOAD;
int		enable_js_autorun = XT_DS_ENABLE_JS_AUTORUN;
char		*userstyle = NULL;		/* allocated/set at startup */
int		userstyle_global = XT_DS_USERSTYLE_GLOBAL;
int		auto_load_images = XT_DS_AUTO_LOAD_IMAGES;
int		enable_autoscroll = XT_DS_ENABLE_AUTOSCROLL;
int		enable_favicon_entry = XT_DS_ENABLE_FAVICON_ENTRY;
int		enable_favicon_tabs = XT_DS_ENABLE_FAVICON_TABS;
char		*external_editor = NULL;
int		referer_mode = XT_DS_REFERER_MODE;
char		*referer_custom = NULL;
int		download_notifications = XT_DS_DOWNLOAD_NOTIFICATIONS;
int		warn_cert_changes = 0;
int		allow_insecure_content = XT_DS_ALLOW_INSECURE_CONTENT;
int		allow_insecure_scripts = XT_DS_ALLOW_INSECURE_SCRIPTS;

char		*cmd_font_name = NULL;	/* these are all set at startup */
char		*oops_font_name = NULL;
char		*statusbar_font_name = NULL;
char		*tabbar_font_name = NULL;

char		*get_download_dir(struct settings *);
char		*get_default_script(struct settings *);
char		*get_runtime_dir(struct settings *);
char		*get_tab_style(struct settings *);
char		*get_statusbar_style(struct settings *);
char		*get_edit_mode(struct settings *);
char		*get_download_mode(struct settings *);
char		*get_work_dir(struct settings *);
char		*get_referer(struct settings *);
char		*get_ssl_ca_file(struct settings *);
char		*get_userstyle(struct settings *);

int		add_cookie_wl(struct settings *, char *);
int		add_js_wl(struct settings *, char *);
int		add_pl_wl(struct settings *, char *);
int		add_mime_type(struct settings *, char *);
int		add_alias(struct settings *, char *);
int		add_kb(struct settings *, char *);
int		add_ua(struct settings *, char *);
int		add_http_accept(struct settings *, char *);
int		add_cmd_alias(struct settings *, char *);
int		add_custom_uri(struct settings *, char *);

int		set_append_next(char *);
int		set_autofocus_onload(char *);
int		set_cmd_font(char *);
int		set_color_visited_uris(char *);
int		set_cookie_policy_rt(char *);
int		set_cookies_enabled(char *);
int		set_ctrl_click_focus(char *);
int		set_fancy_bar(char *);
int		set_home(char *);
int		set_download_dir(struct settings *, char *);
int		set_download_notifications(char *);
int		set_default_script(struct settings *, char *);
int		set_default_script_rt(char *);
int		set_default_zoom_level(char *);
int		set_enable_cookie_whitelist(char *);
int		set_enable_js_autorun(char *);
int		set_enable_js_whitelist(char *);
int		set_enable_localstorage(char *);
int		set_enable_plugins(char *);
int		set_enable_plugin_whitelist(char *);
int		set_enable_scripts(char *);
int		set_enable_spell_checking(char *);
int		set_enable_strict_transport(char *);
int		set_encoding_rt(char *);
int		set_runtime_dir(struct settings *, char *);
int		set_tabbar_font(char *value);
int		set_tab_style(struct settings *, char *);
int		set_tab_style_rt(char *);
int		set_statusbar_style(struct settings *, char *);
int		set_statusbar_style_rt(char *);
int		set_edit_mode(struct settings *, char *);
int		set_work_dir(struct settings *, char *);
int		set_auto_load_images(char *);
int		set_enable_autoscroll(char *);
int		set_enable_favicon_entry(char *);
int		set_enable_favicon_tabs(char *);
int		set_guess_search(char *);
int		set_download_mode(struct settings *, char *);
int		set_download_mode_rt(char *);
int		set_oops_font(char *);
int		set_read_only_cookies(char *);
int		set_referer(struct settings *, char *);
int		set_referer_rt(char *);
int		set_refresh_interval(char *);
int		set_search_string(char *s);
int		set_session_autosave(char *);
int		set_session_timeout(char *);
int		set_show_statusbar(char *);
int		set_show_tabs(char *);
int		set_show_url(char *);
int		set_spell_check_languages(char *);
int		set_ssl_ca_file_rt(char *);
int		set_ssl_strict_certs(char *);
int		set_statusbar_font(char *);
int		set_url_regex(char *);
int		set_userstyle(struct settings *, char *);
int		set_userstyle_rt(char *);
int		set_userstyle_global(char *);
int		set_external_editor(char *);
int		set_xterm_workaround(char *);
int		set_warn_cert_changes(char *);
int		set_allow_insecure_content(char *);
int		set_allow_insecure_scripts(char *);

void		walk_mime_type(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_alias(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_cookie_wl(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_js_wl(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_pl_wl(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_kb(struct settings *, void (*)(struct settings *, char *,
		    void *), void *);
void		walk_ua(struct settings *, void (*)(struct settings *, char *,
		    void *), void *);
void		walk_http_accept(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_cmd_alias(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);
void		walk_custom_uri(struct settings *, void (*)(struct settings *,
		    char *, void *), void *);

int
set_http_proxy(char *proxy)
{
	SoupURI			*uri;

	/* see if we need to clear it */
	if (proxy == NULL || strlen(proxy) == 0) {
		setup_proxy(NULL);
		return (0);
	}

	uri = soup_uri_new(proxy);
	if (uri == NULL || !SOUP_URI_VALID_FOR_HTTP(uri))
		return (1);

	setup_proxy(proxy);

	soup_uri_free(uri);

	return (0);
}

struct special {
	int		(*set)(struct settings *, char *);
	char		*(*get)(struct settings *);
	void		(*walk)(struct settings *,
			    void (*cb)(struct settings *, char *, void *),
			    void *);
};

struct special		s_browser_mode = {
	set_browser_mode,
	get_browser_mode,
	NULL
};

struct special		s_gui_mode = {
	set_gui_mode,
	get_gui_mode,
	NULL
};

struct special		s_cookie = {
	set_cookie_policy,
	get_cookie_policy,
	NULL
};

struct special		s_alias = {
	add_alias,
	NULL,
	walk_alias
};

struct special		s_cmd_alias = {
	add_cmd_alias,
	NULL,
	walk_cmd_alias
};

struct special		s_mime = {
	add_mime_type,
	NULL,
	walk_mime_type
};

struct special		s_js = {
	add_js_wl,
	NULL,
	walk_js_wl
};

struct special		s_pl = {
	add_pl_wl,
	NULL,
	walk_pl_wl
};

struct special		s_kb = {
	add_kb,
	NULL,
	walk_kb
};

struct special		s_cookie_wl = {
	add_cookie_wl,
	NULL,
	walk_cookie_wl
};

struct special		s_uri = {
	add_custom_uri,
	NULL,
	walk_custom_uri,
};

struct special		s_default_script = {
	set_default_script,
	get_default_script,
	NULL
};

struct special		s_ssl_ca_file = {
	set_ssl_ca_file,
	get_ssl_ca_file,
	NULL
};

struct special		s_download_dir = {
	set_download_dir,
	get_download_dir,
	NULL
};

struct special		s_work_dir = {
	set_work_dir,
	get_work_dir,
	NULL
};

struct special		s_tab_style = {
	set_tab_style,
	get_tab_style,
	NULL
};

struct special		s_statusbar_style = {
	set_statusbar_style,
	get_statusbar_style,
	NULL
};

struct special		s_edit_mode = {
	set_edit_mode,
	get_edit_mode,
	NULL
};

struct special		s_download_mode = {
	set_download_mode,
	get_download_mode,
	NULL
};

struct special		s_ua = {
	add_ua,
	NULL,
	walk_ua
};

struct special		s_http_accept = {
	add_http_accept,
	NULL,
	walk_http_accept
};

struct special		s_referer = {
	set_referer,
	get_referer,
	NULL
};

struct special		s_userstyle = {
	set_userstyle,
	get_userstyle,
	NULL
};

struct settings		rs[] = {
	{ "allow_insecure_content",	XT_S_INT, 0,		&allow_insecure_content, NULL, NULL, NULL, set_allow_insecure_content },
	{ "allow_insecure_scripts",	XT_S_INT, 0,		&allow_insecure_scripts, NULL, NULL, NULL, set_allow_insecure_scripts },
	{ "allow_volatile_cookies",	XT_S_INT, 0,		&allow_volatile_cookies, NULL, NULL, NULL, NULL},
	{ "append_next",		XT_S_INT, 0,		&append_next, NULL, NULL, NULL, set_append_next },
	{ "auto_load_images",		XT_S_INT, 0,		&auto_load_images, NULL, NULL, NULL, set_auto_load_images },
	{ "autofocus_onload",		XT_S_INT, 0,		&autofocus_onload, NULL, NULL, NULL, set_autofocus_onload },
	{ "browser_mode",		XT_S_INT, 0, NULL, NULL,&s_browser_mode, NULL, NULL },
	{ "cmd_font",			XT_S_STR, 0, NULL, &cmd_font_name, NULL, NULL, set_cmd_font },
	{ "color_visited_uris",		XT_S_INT, 0,		&color_visited_uris , NULL, NULL, NULL, set_color_visited_uris },
	{ "cookie_policy",		XT_S_INT, 0, NULL, NULL,&s_cookie, NULL, set_cookie_policy_rt },
	{ "cookies_enabled",		XT_S_INT, 0,		&cookies_enabled, NULL, NULL, NULL, set_cookies_enabled },
	{ "ctrl_click_focus",		XT_S_INT, 0,		&ctrl_click_focus, NULL, NULL, NULL, set_ctrl_click_focus },
	{ "default_script",		XT_S_STR, 1, NULL, NULL,&s_default_script, NULL, set_default_script_rt },
	{ "default_zoom_level",		XT_S_FLOAT, 0,		NULL, NULL, NULL, &default_zoom_level, set_default_zoom_level },
	{ "download_dir",		XT_S_STR, 0, NULL, NULL,&s_download_dir, NULL, NULL },
	{ "download_mode",		XT_S_STR, 0, NULL, NULL,&s_download_mode, NULL, set_download_mode_rt },
	{ "download_notifications",	XT_S_INT, 0,		&download_notifications, NULL, NULL, NULL, set_download_notifications },
	{ "edit_mode",			XT_S_STR, 0, NULL, NULL,&s_edit_mode, NULL, NULL},
	{ "enable_autoscroll",		XT_S_INT, 0,		&enable_autoscroll, NULL, NULL, NULL, set_enable_autoscroll },
	{ "enable_cookie_whitelist",	XT_S_INT, 0,		&enable_cookie_whitelist, NULL, NULL, NULL, set_enable_cookie_whitelist },
	{ "enable_favicon_entry",	XT_S_INT, 0,		&enable_favicon_entry, NULL, NULL, NULL, set_enable_favicon_entry },
	{ "enable_favicon_tabs",	XT_S_INT, 0,		&enable_favicon_tabs, NULL, NULL, NULL, set_enable_favicon_tabs },
	{ "enable_js_autorun",		XT_S_INT, 0,		&enable_js_autorun, NULL, NULL, NULL, set_enable_js_autorun },
	{ "enable_js_whitelist",	XT_S_INT, 0,		&enable_js_whitelist, NULL, NULL, NULL, set_enable_js_whitelist },
	{ "enable_localstorage",	XT_S_INT, 0,		&enable_localstorage, NULL, NULL, NULL, set_enable_localstorage },
	{ "enable_plugin_whitelist",	XT_S_INT, 0,		&enable_plugin_whitelist, NULL, NULL, NULL, set_enable_plugin_whitelist },
	{ "enable_plugins",		XT_S_INT, 0,		&enable_plugins, NULL, NULL, NULL, set_enable_plugins },
	{ "enable_scripts",		XT_S_INT, 0,		&enable_scripts, NULL, NULL, NULL, set_enable_scripts },
	{ "enable_socket",		XT_S_INT, XT_SF_RESTART,&enable_socket, NULL, NULL, NULL, NULL },
	{ "enable_spell_checking",	XT_S_INT, 0,		&enable_spell_checking, NULL, NULL, NULL, set_enable_spell_checking },
	{ "enable_strict_transport",	XT_S_INT, 0,		&enable_strict_transport, NULL, NULL, NULL, set_enable_strict_transport },
	{ "encoding",			XT_S_STR, 0, NULL,	&encoding, NULL, NULL, NULL },
	{ "external_editor",		XT_S_STR,0, NULL,	&external_editor, NULL, NULL, set_external_editor },
	{ "fancy_bar",			XT_S_INT, XT_SF_RESTART,&fancy_bar, NULL, NULL, NULL, set_fancy_bar },
	{ "guess_search",		XT_S_INT, 0,		&guess_search, NULL, NULL, NULL, set_guess_search },
	{ "gui_mode",			XT_S_INT, 0, NULL, NULL,&s_gui_mode, NULL, NULL },
	{ "history_autosave",		XT_S_INT, 0,		&history_autosave, NULL, NULL, NULL, NULL },
	{ "home",			XT_S_STR, 0, NULL,	&home, NULL, NULL, set_home },
	{ "http_proxy",			XT_S_STR, 0, NULL,	&http_proxy, NULL, NULL, set_http_proxy },
	{ "http_proxy_starts_enabled",	XT_S_INT, 0,		&http_proxy_starts_enabled, NULL, NULL, NULL, NULL },
	{ "icon_size",			XT_S_INT, 0,		&icon_size, NULL, NULL, NULL, NULL },
	{ "include_config",		XT_S_STR, 0, NULL,	&include_config, NULL, NULL, NULL },
	{ "max_connections",		XT_S_INT, XT_SF_RESTART,&max_connections, NULL, NULL, NULL, NULL },
	{ "max_host_connections",	XT_S_INT, XT_SF_RESTART,&max_host_connections, NULL, NULL, NULL, NULL },
	{ "oops_font",			XT_S_STR, 0, NULL, &oops_font_name, NULL, NULL, set_oops_font },
	{ "read_only_cookies",		XT_S_INT, 0,		&read_only_cookies, NULL, NULL, NULL, set_read_only_cookies },
	{ "referer",			XT_S_STR, 0, NULL, NULL,&s_referer, NULL, set_referer_rt },
	{ "refresh_interval",		XT_S_INT, 0,		&refresh_interval, NULL, NULL, NULL, set_refresh_interval },
	{ "resource_dir",		XT_S_STR, 0, NULL,	&resource_dir, NULL, NULL, NULL },
	{ "save_global_history",	XT_S_INT, XT_SF_RESTART,&save_global_history, NULL, NULL, NULL, NULL },
	{ "save_rejected_cookies",	XT_S_INT, XT_SF_RESTART,&save_rejected_cookies, NULL, NULL, NULL, NULL },
	{ "search_string",		XT_S_STR, 0, NULL,	&search_string, NULL, NULL, set_search_string },
	{ "session_autosave",		XT_S_INT, 0,		&session_autosave, NULL, NULL, NULL, set_session_autosave },
	{ "session_timeout",		XT_S_INT, 0,		&session_timeout, NULL, NULL, NULL, set_session_timeout },
	{ "show_statusbar",		XT_S_INT, 0,		&show_statusbar, NULL, NULL, NULL, set_show_statusbar },
	{ "show_tabs",			XT_S_INT, 0,		&show_tabs, NULL, NULL, NULL, set_show_tabs },
	{ "show_url",			XT_S_INT, 0,		&show_url, NULL, NULL, NULL, set_show_url },
	{ "single_instance",		XT_S_INT, XT_SF_RESTART,&single_instance, NULL, NULL, NULL, NULL },
	{ "spell_check_languages",	XT_S_STR, 0, NULL,	&spell_check_languages, NULL, NULL, set_spell_check_languages },
	{ "ssl_ca_file",		XT_S_STR, 0, NULL, NULL,&s_ssl_ca_file, NULL, set_ssl_ca_file_rt },
	{ "ssl_strict_certs",		XT_S_INT, 0,		&ssl_strict_certs, NULL, NULL, NULL, set_ssl_strict_certs },
	{ "statusbar_elems",		XT_S_STR, 0, NULL,	&statusbar_elems, NULL, NULL, NULL },
	{ "statusbar_font",		XT_S_STR, 0, NULL, &statusbar_font_name, NULL, NULL, set_statusbar_font },
	{ "statusbar_style",		XT_S_STR, 0, NULL, NULL,&s_statusbar_style, NULL, set_statusbar_style_rt },
	{ "tab_style",			XT_S_STR, 0, NULL, NULL,&s_tab_style, NULL, set_tab_style_rt },
	{ "tabbar_font",		XT_S_STR, 0, NULL, &tabbar_font_name, NULL, NULL, set_tabbar_font },
	{ "url_regex",			XT_S_STR, 0, NULL,	&url_regex, NULL, NULL, set_url_regex },
	{ "userstyle",			XT_S_STR, 0, NULL, NULL,&s_userstyle, NULL, set_userstyle_rt },
	{ "userstyle_global",		XT_S_INT, 0,		&userstyle_global, NULL, NULL, NULL, set_userstyle_global },
	{ "warn_cert_changes",		XT_S_INT, 0,		&warn_cert_changes, NULL, NULL, NULL, set_warn_cert_changes },
	{ "window_height",		XT_S_INT, 0,		&window_height, NULL, NULL, NULL, NULL },
	{ "window_maximize",		XT_S_INT, 0,		&window_maximize, NULL, NULL, NULL, NULL },
	{ "window_width",		XT_S_INT, 0,		&window_width, NULL, NULL, NULL, NULL },
	{ "work_dir",			XT_S_STR, 0, NULL, NULL,&s_work_dir, NULL, NULL },
	{ "xterm_workaround",		XT_S_INT, 0,		&xterm_workaround, NULL, NULL, NULL, set_xterm_workaround },

	/* special settings */
	{ "alias",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_alias, NULL, NULL },
	{ "cmd_alias",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cmd_alias, NULL, NULL },
	{ "cookie_wl",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cookie_wl, NULL, NULL },
	{ "custom_uri",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_uri, NULL, NULL },
	{ "http_accept",		XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_http_accept, NULL, NULL },
	{ "js_wl",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_js, NULL, NULL },
	{ "keybinding",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_kb, NULL, NULL },
	{ "mime_type",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_mime, NULL, NULL },
	{ "pl_wl",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_pl, NULL, NULL },
	{ "user_agent",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_ua, NULL, NULL },
};

int
set_default_zoom_level(char *value)
{
	struct karg		args = {0};
	struct tab		*t;

	if (value == NULL || strlen(value) == 0)
		default_zoom_level = XT_DS_DEFAULT_ZOOM_LEVEL;
	else
		default_zoom_level = g_strtod(value, NULL);
	args.i = 100;	/* adjust = 100 percent for no additional adjustment */
	TAILQ_FOREACH(t, &tabs, entry)
		resizetab(t, &args);
	return (0);
}

int
set_cookies_enabled(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		cookies_enabled = XT_DS_COOKIES_ENABLED;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		cookies_enabled = tmp;
	}
	return (0);
}

int
set_append_next(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		append_next = XT_DS_APPEND_NEXT;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		append_next = tmp;
	}
	return (0);
}

int
set_cmd_font(char *value)
{
	struct tab		*t;

	if (cmd_font_name)
		g_free(cmd_font_name);
	if (cmd_font)
		pango_font_description_free(cmd_font);
	if (value == NULL || strlen(value) == 0)
		cmd_font_name = g_strdup(XT_DS_CMD_FONT_NAME);
	else
		cmd_font_name = g_strdup(value);
	cmd_font = pango_font_description_from_string(cmd_font_name);
	TAILQ_FOREACH(t, &tabs, entry)
		gtk_widget_modify_font(GTK_WIDGET(t->cmd), cmd_font);
	return (0);
}

int
set_oops_font(char *value)
{
	struct tab		*t;

	if (oops_font_name)
		g_free(oops_font_name);
	if (oops_font)
		pango_font_description_free(oops_font);
	if (value == NULL || strlen(value) == 0)
		cmd_font_name = g_strdup(XT_DS_OOPS_FONT_NAME);
	else
		oops_font_name = g_strdup(value);
	oops_font = pango_font_description_from_string(oops_font_name);
	TAILQ_FOREACH(t, &tabs, entry)
		gtk_widget_modify_font(GTK_WIDGET(t->oops), oops_font);
	return (0);
}

int
set_statusbar_font(char *value)
{
	struct tab		*t;

	if (statusbar_font_name)
		g_free(statusbar_font_name);
	if (statusbar_font)
		pango_font_description_free(statusbar_font);
	if (value == NULL || strlen(value) == 0)
		statusbar_font_name = g_strdup(XT_DS_STATUSBAR_FONT_NAME);
	else
		statusbar_font_name = g_strdup(value);
	statusbar_font = pango_font_description_from_string(
	    statusbar_font_name);
	TAILQ_FOREACH(t, &tabs, entry) {
		gtk_widget_modify_font(GTK_WIDGET(t->sbe.statusbar),
		    statusbar_font);
		gtk_widget_modify_font(GTK_WIDGET(t->sbe.buffercmd),
		    statusbar_font);
		gtk_widget_modify_font(GTK_WIDGET(t->sbe.zoom),
		    statusbar_font);
		gtk_widget_modify_font(GTK_WIDGET(t->sbe.position),
		    statusbar_font);
		gtk_widget_modify_font(GTK_WIDGET(t->sbe.proxy),
		    statusbar_font);
	}
	return (0);
}

int
set_tabbar_font(char *value)
{
	struct tab		*t;

	if (tabbar_font_name)
		g_free(tabbar_font_name);
	if (tabbar_font)
		pango_font_description_free(tabbar_font);
	if (value == NULL || strlen(value) == 0)
		tabbar_font_name = g_strdup(XT_DS_TABBAR_FONT_NAME);
	else
		tabbar_font_name = g_strdup(value);
	tabbar_font = pango_font_description_from_string(tabbar_font_name);
	TAILQ_FOREACH(t, &tabs, entry)
		gtk_widget_modify_font(GTK_WIDGET(t->tab_elems.label),
		    tabbar_font);
	return (0);
}

int
set_color_visited_uris(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		color_visited_uris = XT_DS_COLOR_VISITED_URIS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		color_visited_uris = tmp;
	}
	return (0);
}

int
set_home(char *value)
{
	if (home)
		g_free(home);
	if (value == NULL || strlen(value) == 0)
		home = g_strdup(XT_DS_HOME);
	else
		home = g_strdup(value);
	return (0);
}

int
set_search_string(char *value)
{
	if (search_string)
		g_free(search_string);
	if (value == NULL || strlen(value) == 0)
		search_string = g_strdup(XT_DS_SEARCH_STRING);
	else
		search_string = g_strdup(value);
	return (0);
}

size_t
get_settings_size(void)
{
	return (LENGTH(rs));
}

char *
get_setting_name(int i)
{
	if (i > LENGTH(rs))
		return (NULL);
	return (rs[i].name);
}

char *
get_as_string(struct settings *s)
{
	char			*r = NULL;

	if (s == NULL)
		return (NULL);

	if (s->s) {
		if (s->s->get)
			r = s->s->get(s);
		else
			warnx("get_as_string skip %s\n", s->name);
	} else if (s->type == XT_S_INT)
		r = g_strdup_printf("%d", *s->ival);
	else if (s->type == XT_S_STR)
		r = g_strdup(*s->sval);
	else if (s->type == XT_S_FLOAT)
		r = g_strdup_printf("%f", *s->fval);
	else
		r = g_strdup_printf("INVALID TYPE");

	return (r);
}

void
settings_walk(void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	int			i;
	char			*s;

	for (i = 0; i < LENGTH(rs); i++) {
		if (rs[i].s && rs[i].s->walk)
			rs[i].s->walk(&rs[i], cb, cb_args);
		else {
			s = get_as_string(&rs[i]);
			cb(&rs[i], s, cb_args);
			g_free(s);
		}
	}
}

int
set_browser_mode(struct settings *s, char *val)
{
	if (!strcmp(val, "whitelist")) {
		browser_mode = XT_BM_WHITELIST;
		allow_volatile_cookies	= 0;
		cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
		cookies_enabled = 1;
		enable_cookie_whitelist = 1;
		enable_plugin_whitelist = 1;
		enable_plugins = 0;
		read_only_cookies = 0;
		save_rejected_cookies = 0;
		session_timeout = 3600;
		enable_scripts = 0;
		enable_js_whitelist = 1;
		enable_localstorage = 0;
		referer_mode = XT_REFERER_SAME_DOMAIN;
		allow_insecure_content = 0;
		allow_insecure_scripts = 0;
	} else if (!strcmp(val, "normal")) {
		browser_mode = XT_BM_NORMAL;
		allow_volatile_cookies = 0;
		cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
		cookies_enabled = 1;
		enable_cookie_whitelist = 0;
		enable_plugin_whitelist = 0;
		enable_plugins = 1;
		read_only_cookies = 0;
		save_rejected_cookies = 0;
		session_timeout = 3600;
		enable_scripts = 1;
		enable_js_whitelist = 0;
		enable_localstorage = 1;
		referer_mode = XT_REFERER_ALWAYS;
		allow_insecure_content = 1;
		allow_insecure_scripts = 1;
	} else if (!strcmp(val, "kiosk")) {
		browser_mode = XT_BM_KIOSK;
		allow_volatile_cookies = 0;
		cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
		cookies_enabled = 1;
		enable_cookie_whitelist = 0;
		enable_plugin_whitelist = 0;
		enable_plugins = 1;
		read_only_cookies = 0;
		save_rejected_cookies = 0;
		session_timeout = 3600;
		enable_scripts = 1;
		enable_js_whitelist = 0;
		enable_localstorage = 1;
		referer_mode = XT_REFERER_ALWAYS;
		allow_insecure_content = 1;
		allow_insecure_scripts = 1;
		show_tabs = 0;
		tabless = 1;
	} else
		return (1);

	return (0);
}

char *
get_browser_mode(struct settings *s)
{
	char			*r = NULL;

	if (browser_mode == XT_BM_WHITELIST)
		r = g_strdup("whitelist");
	else if (browser_mode == XT_BM_NORMAL)
		r = g_strdup("normal");
	else if (browser_mode == XT_BM_KIOSK)
		r = g_strdup("kiosk");
	else
		return (NULL);

	return (r);
}

int
set_gui_mode(struct settings *s, char *val)
{
	if (!strcmp(val, "classic")) {
		fancy_bar = 1;
		show_tabs = 1;
		tab_style = XT_TABS_NORMAL;
		show_url = 1;
		show_statusbar = 0;
	} else if (!strcmp(val, "minimal")) {
		fancy_bar = 0;
		show_tabs = 1;
		tab_style = XT_TABS_COMPACT;
		show_url = 0;
		show_statusbar = 1;
	} else
		return (1);

	return (0);
}

char *
get_gui_mode(struct settings *s)
{
	char			*r = NULL;

	if (gui_mode == XT_GM_CLASSIC)
		r = g_strdup("classic");
	else if (browser_mode == XT_GM_MINIMAL)
		r = g_strdup("minimal");
	else
		return (NULL);

	return (r);
}

int
set_cookie_policy(struct settings *s, char *val)
{
	if (!strcmp(val, "no3rdparty"))
		cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
	else if (!strcmp(val, "accept"))
		cookie_policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
	else if (!strcmp(val, "reject"))
		cookie_policy = SOUP_COOKIE_JAR_ACCEPT_NEVER;
	else
		return (1);

	return (0);
}

int
set_cookie_policy_rt(char *value)
{
	if (value == NULL || strlen(value) == 0)
		cookie_policy = XT_DS_COOKIE_POLICY;
	else if (set_cookie_policy(NULL, value))
		return (-1);
	g_object_set(G_OBJECT(s_cookiejar), SOUP_COOKIE_JAR_ACCEPT_POLICY,
	    cookie_policy, (void *)NULL);
	return (0);
}

char *
get_cookie_policy(struct settings *s)
{
	char			*r = NULL;

	if (cookie_policy == SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY)
		r = g_strdup("no3rdparty");
	else if (cookie_policy == SOUP_COOKIE_JAR_ACCEPT_ALWAYS)
		r = g_strdup("accept");
	else if (cookie_policy == SOUP_COOKIE_JAR_ACCEPT_NEVER)
		r = g_strdup("reject");
	else
		return (NULL);

	return (r);
}

char *
get_default_script(struct settings *s)
{
	if (default_script[0] == '\0')
		return (0);
	return (g_strdup(default_script));
}

int
set_default_script(struct settings *s, char *val)
{
	expand_tilde(default_script, sizeof default_script, val);
	return (0);
}

int
set_default_script_rt(char *value)
{
	if (value == NULL || strlen(value) == 0)
		return set_default_script(NULL, "");
	return (set_default_script(NULL, value));
}

char *
get_download_dir(struct settings *s)
{
	if (download_dir[0] == '\0')
		return (0);
	return (g_strdup(download_dir));
}

int
set_download_dir(struct settings *s, char *val)
{
	expand_tilde(download_dir, sizeof download_dir, val);
	return (0);
}

int
add_alias(struct settings *s, char *line)
{
	char			*l, *alias;
	struct alias		*a = NULL;

	if (s == NULL || line == NULL) {
		show_oops(NULL, "add_alias invalid parameters");
		return (1);
	}

	l = line;
	a = g_malloc(sizeof(*a));

	if ((alias = strsep(&l, " \t,")) == NULL || l == NULL) {
		show_oops(NULL, "add_alias: incomplete alias definition");
		goto bad;
	}
	if (strlen(alias) == 0 || strlen(l) == 0) {
		show_oops(NULL, "add_alias: invalid alias definition");
		goto bad;
	}

	a->a_name = g_strdup(alias);
	a->a_uri = g_strdup(l);

	DNPRINTF(XT_D_CONFIG, "add_alias: %s for %s\n", a->a_name, a->a_uri);

	TAILQ_INSERT_TAIL(&aliases, a, entry);

	return (0);
bad:
	if (a)
		g_free(a);
	return (1);
}

void
walk_alias(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct alias		*a;
	char			*str;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_alias invalid parameters");
		return;
	}

	TAILQ_FOREACH(a, &aliases, entry) {
		str = g_strdup_printf("%s --> %s", a->a_name, a->a_uri);
		cb(s, str, cb_args);
		g_free(str);
	}
}

int
add_mime_type(struct settings *s, char *line)
{
	char			*mime_type;
	char			*l;
	struct mime_type	*m = NULL;
	int			downloadfirst = 0;

	/* XXX this could be smarter */

	if (line == NULL || strlen(line) == 0) {
		show_oops(NULL, "add_mime_type invalid parameters");
		return (1);
	}

	l = line;
	if (*l == '@') {
		downloadfirst = 1;
		l++;
	}
	m = g_malloc(sizeof(*m));

	if ((mime_type = strsep(&l, " \t,")) == NULL || l == NULL) {
		show_oops(NULL, "add_mime_type: invalid mime_type");
		goto bad;
	}
	if (mime_type[strlen(mime_type) - 1] == '*') {
		mime_type[strlen(mime_type) - 1] = '\0';
		m->mt_default = 1;
	} else
		m->mt_default = 0;

	if (strlen(mime_type) == 0 || strlen(l) == 0) {
		show_oops(NULL, "add_mime_type: invalid mime_type");
		goto bad;
	}

	m->mt_type = g_strdup(mime_type);
	m->mt_action = g_strdup(l);
	m->mt_download = downloadfirst;

	DNPRINTF(XT_D_CONFIG, "add_mime_type: type %s action %s default %d\n",
	    m->mt_type, m->mt_action, m->mt_default);

	TAILQ_INSERT_TAIL(&mtl, m, entry);

	return (0);
bad:
	if (m)
		g_free(m);
	return (1);
}

void
walk_mime_type(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct mime_type	*m;
	char			*str;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_mime_type invalid parameters");
		return;
	}

	TAILQ_FOREACH(m, &mtl, entry) {
		str = g_strdup_printf("%s%s --> %s",
		    m->mt_type,
		    m->mt_default ? "*" : "",
		    m->mt_action);
		cb(s, str, cb_args);
		g_free(str);
	}
}

/* inherent to GTK not all keys will be caught at all times */
/* XXX sort key bindings */
struct key_binding	keys[] = {
	{ "command_mode",	0,	1,	GDK_Escape	},
	{ "insert_mode",	0,	0,	GDK_i		},
	{ "cookiejar",		MOD1,	1,	GDK_j		},
	{ "downloadmgr",	MOD1,	1,	GDK_d		},
	{ "history",		MOD1,	1,	GDK_h		},
	{ "print",		CTRL,	1,	GDK_p		},
	{ "search",		0,	0,	GDK_slash	},
	{ "searchb",		0,	0,	GDK_question	},
	{ "statustoggle",	CTRL,	1,	GDK_n		},
	{ "command",		0,	0,	GDK_colon	},
	{ "qa",			CTRL,	1,	GDK_q		},
	{ "restart",		MOD1,	1,	GDK_q		},
	{ "js toggle",		CTRL,	1,	GDK_j		},
	{ "plugin toggle",	MOD1,	1,	GDK_p		},
	{ "cookie toggle",	MOD1,	1,	GDK_c		},
	{ "togglesrc",		CTRL,	1,	GDK_s		},
	{ "yankuri",		0,	0,	GDK_y		},
	{ "pasteuricur",	0,	0,	GDK_p		},
	{ "pasteurinew",	0,	0,	GDK_P		},
	{ "toplevel toggle",	0,	1,	GDK_F4		},
	{ "help",		0,	1,	GDK_F1		},
	{ "run_script",		MOD1,	1,	GDK_r		},
	{ "proxy toggle",	0,	1,	GDK_F2		},
	{ "editelement",	CTRL,	1,	GDK_i		},
	{ "passthrough",	CTRL,	1,	GDK_z		},
	{ "modurl",		CTRL,	1,	GDK_Return	},

	/* search */
	{ "searchnext",		0,	0,	GDK_n		},
	{ "searchprevious",	0,	0,	GDK_N		},

	/* focus */
	{ "focusaddress",	0,	1,	GDK_F6		},
	{ "focussearch",	0,	1,	GDK_F7		},

	/* hinting */
	{ "hinting",		0,	0,	GDK_f		},
	{ "hinting",		0,	0,	GDK_period	},
	{ "hinting_newtab",	SHFT,	0,	GDK_F		},
	{ "hinting_newtab",	0,	0,	GDK_comma	},

	/* custom stylesheet */
	{ "userstyle",		0,	0,	GDK_s		},
	{ "userstyle_global",	SHFT,	0,	GDK_S		},

	/* navigation */
	{ "goback",		0,	0,	GDK_BackSpace	},
	{ "goback",		MOD1,	1,	GDK_Left	},
	{ "goforward",		SHFT,	1,	GDK_BackSpace	},
	{ "goforward",		MOD1,	1,	GDK_Right	},
	{ "reload",		0,	1,	GDK_F5		},
	{ "reload",		CTRL,	1,	GDK_r		},
	{ "reload",		CTRL,	1,	GDK_l		},
	{ "favorites",		MOD1,	1,	GDK_f		},

	/* vertical movement */
	{ "scrolldown",		0,	0,	GDK_j		},
	{ "scrolldown",		0,	0,	GDK_Down	},
	{ "scrollup",		0,	0,	GDK_Up		},
	{ "scrollup",		0,	0,	GDK_k		},
	{ "scrollbottom",	0,	0,	GDK_G		},
	{ "scrollbottom",	0,	0,	GDK_End		},
	{ "scrolltop",		0,	0,	GDK_Home	},
	{ "scrollpagedown",	0,	0,	GDK_space	},
	{ "scrollpagedown",	CTRL,	1,	GDK_f		},
	{ "scrollhalfdown",	CTRL,	1,	GDK_d		},
	{ "scrollpagedown",	0,	0,	GDK_Page_Down	},
	{ "scrollpageup",	0,	0,	GDK_Page_Up	},
	{ "scrollpageup",	CTRL,	1,	GDK_b		},
	{ "scrollhalfup",	CTRL,	1,	GDK_u		},
	/* horizontal movement */
	{ "scrollright",	0,	0,	GDK_l		},
	{ "scrollright",	0,	0,	GDK_Right	},
	{ "scrollleft",		0,	0,	GDK_Left	},
	{ "scrollleft",		0,	0,	GDK_h		},
	{ "scrollfarright",	0,	0,	GDK_dollar	},
	{ "scrollfarleft",	0,	0,	GDK_0		},

	/* tabs */
	{ "tabnew",		CTRL,	1,	GDK_t		},
	{ "999tabnew",		CTRL,	1,	GDK_T		},
	{ "tabclose",		CTRL,	1,	GDK_w		},
	{ "tabundoclose",	0,	0,	GDK_U		},
	{ "tabnext 1",		CTRL,	1,	GDK_1		},
	{ "tabnext 2",		CTRL,	1,	GDK_2		},
	{ "tabnext 3",		CTRL,	1,	GDK_3		},
	{ "tabnext 4",		CTRL,	1,	GDK_4		},
	{ "tabnext 5",		CTRL,	1,	GDK_5		},
	{ "tabnext 6",		CTRL,	1,	GDK_6		},
	{ "tabnext 7",		CTRL,	1,	GDK_7		},
	{ "tabnext 8",		CTRL,	1,	GDK_8		},
	{ "tabnext 9",		CTRL,	1,	GDK_9		},
	{ "tabfirst",		CTRL,	1,	GDK_less	},
	{ "tablast",		CTRL,	1,	GDK_greater	},
	{ "tabprevious",	CTRL,	1,	GDK_Left	},
	{ "tabnext",		CTRL,	1,	GDK_Right	},
	{ "focusout",		CTRL,	1,	GDK_minus	},
	{ "focusin",		CTRL,	1,	GDK_plus	},
	{ "focusin",		CTRL,	1,	GDK_equal	},
	{ "focusreset",		CTRL,	1,	GDK_0		},

	/* command aliases (handy when -S flag is used) */
	{ ":open ",		0,	1,	GDK_F9		},
	{ ":open <uri>",	0,	1,	GDK_F10		},
	{ ":tabnew ",		0,	1,	GDK_F11		},
	{ ":tabnew <uri>",	0,	1,	GDK_F12		},
};

void
walk_kb(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct key_binding	*k;
	char			str[1024];

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_kb invalid parameters");
		return;
	}

	TAILQ_FOREACH(k, &kbl, entry) {
		if (k->cmd == NULL)
			continue;
		str[0] = '\0';

		/* sanity */
		if (gdk_keyval_name(k->key) == NULL)
			continue;

		strlcat(str, k->cmd, sizeof str);
		strlcat(str, ",", sizeof str);

		if (k->mask & GDK_SHIFT_MASK)
			strlcat(str, "S-", sizeof str);
		if (k->mask & GDK_CONTROL_MASK)
			strlcat(str, "C-", sizeof str);
		if (k->mask & GDK_MOD1_MASK)
			strlcat(str, "M1-", sizeof str);
		if (k->mask & GDK_MOD2_MASK)
			strlcat(str, "M2-", sizeof str);
		if (k->mask & GDK_MOD3_MASK)
			strlcat(str, "M3-", sizeof str);
		if (k->mask & GDK_MOD4_MASK)
			strlcat(str, "M4-", sizeof str);
		if (k->mask & GDK_MOD5_MASK)
			strlcat(str, "M5-", sizeof str);

		strlcat(str, gdk_keyval_name(k->key), sizeof str);
		cb(s, str, cb_args);
	}
}

void
init_keybindings(void)
{
	int			i;
	struct key_binding	*k;

	for (i = 0; i < LENGTH(keys); i++) {
		k = g_malloc0(sizeof *k);
		k->cmd = keys[i].cmd;
		k->mask = keys[i].mask;
		k->use_in_entry = keys[i].use_in_entry;
		k->key = keys[i].key;
		TAILQ_INSERT_HEAD(&kbl, k, entry);

		DNPRINTF(XT_D_KEYBINDING, "init_keybindings: added: %s\n",
		    k->cmd ? k->cmd : "unnamed key");
	}
}

void
keybinding_clearall(void)
{
	struct key_binding	*k, *next;

	for (k = TAILQ_FIRST(&kbl); k; k = next) {
		next = TAILQ_NEXT(k, entry);
		if (k->cmd == NULL)
			continue;

		DNPRINTF(XT_D_KEYBINDING, "keybinding_clearall: %s\n",
		    k->cmd ? k->cmd : "unnamed key");
		TAILQ_REMOVE(&kbl, k, entry);
		g_free(k);
	}
}

int
keybinding_add(char *cmd, char *key, int use_in_entry)
{
	struct key_binding	*k;
	guint			keyval, mask = 0;
	int			i;

	DNPRINTF(XT_D_KEYBINDING, "keybinding_add: %s %s\n", cmd, key);

	/* Keys which are to be used in entry have been prefixed with an
	 * exclamation mark. */
	if (use_in_entry)
		key++;

	/* find modifier keys */
	if (strstr(key, "S-"))
		mask |= GDK_SHIFT_MASK;
	if (strstr(key, "C-"))
		mask |= GDK_CONTROL_MASK;
	if (strstr(key, "M1-"))
		mask |= GDK_MOD1_MASK;
	if (strstr(key, "M2-"))
		mask |= GDK_MOD2_MASK;
	if (strstr(key, "M3-"))
		mask |= GDK_MOD3_MASK;
	if (strstr(key, "M4-"))
		mask |= GDK_MOD4_MASK;
	if (strstr(key, "M5-"))
		mask |= GDK_MOD5_MASK;

	/* find keyname */
	for (i = strlen(key) - 1; i > 0; i--)
		if (key[i] == '-')
			key = &key[i + 1];

	/* validate keyname */
	keyval = gdk_keyval_from_name(key);
	if (keyval == GDK_VoidSymbol) {
		warnx("invalid keybinding name %s", key);
		return (1);
	}
	/* must run this test too, gtk+ doesn't handle 10 for example */
	if (gdk_keyval_name(keyval) == NULL) {
		warnx("invalid keybinding name %s", key);
		return (1);
	}

	/* Remove eventual dupes. */
	TAILQ_FOREACH(k, &kbl, entry)
		if (k->key == keyval && k->mask == mask) {
			TAILQ_REMOVE(&kbl, k, entry);
			g_free(k);
			break;
		}

	/* add keyname */
	k = g_malloc0(sizeof *k);
	k->cmd = g_strdup(cmd);
	k->mask = mask;
	k->use_in_entry = use_in_entry;
	k->key = keyval;

	DNPRINTF(XT_D_KEYBINDING, "keybinding_add: %s 0x%x %d 0x%x\n",
	    k->cmd,
	    k->mask,
	    k->use_in_entry,
	    k->key);
	DNPRINTF(XT_D_KEYBINDING, "keybinding_add: adding: %s %s\n",
	    k->cmd, gdk_keyval_name(keyval));

	TAILQ_INSERT_HEAD(&kbl, k, entry);

	return (0);
}

int
cmd_alias_add(char *alias, char *cmd)
{
	struct cmd_alias	*c;

	/* XXX */
	TAILQ_FOREACH(c, &cal, entry)
		if (!strcmp((alias), c->alias)) {
			TAILQ_REMOVE(&cal, c, entry);
			g_free(c);
		}

	c = g_malloc(sizeof (struct cmd_alias));
	c->alias = g_strchug(g_strdup(alias));
	c->cmd = g_strchug(g_strdup(cmd));

	DNPRINTF(XT_D_CUSTOM_URI, "cmd_alias_add: %s %s\n", c->alias, c->cmd);

	TAILQ_INSERT_HEAD(&cal, c, entry);
	return (0);
}

int
custom_uri_add(char *uri, char *cmd)
{
	struct custom_uri	*u;

	TAILQ_FOREACH(u, &cul, entry)
		if (!strcmp((uri), u->uri) && !strcmp(cmd, u->cmd)) {
			TAILQ_REMOVE(&cul, u, entry);
			g_free(u);
		}

	u = g_malloc(sizeof (struct custom_uri));
	u->uri = g_strdup(uri);
	expand_tilde(u->cmd, sizeof u->cmd, cmd);

	DNPRINTF(XT_D_CUSTOM_URI, "custom_uri_add: %s %s\n", u->uri, u->cmd);

	/* don't check here if the script is valid, wait until running it */
	TAILQ_INSERT_HEAD(&cul, u, entry);
	return (0);
}

int
add_kb(struct settings *s, char *entry)
{
	char			*kb, *key;

	DNPRINTF(XT_D_KEYBINDING, "add_kb: %s\n", entry);

	/* clearall is special */
	if (!strcmp(entry, "clearall")) {
		keybinding_clearall();
		return (0);
	}

	kb = strstr(entry, ",");
	if (kb == NULL)
		return (1);
	*kb = '\0';
	key = kb + 1;

	return (keybinding_add(entry, key, key[0] == '!'));
}

int
add_custom_uri(struct settings *s, char *entry)
{
	char			*uri, *cmd;

	DNPRINTF(XT_D_CUSTOM_URI, "add_custom_uri: %s\n", entry);

	uri = strstr(entry, ",");
	if (uri == NULL)
		return (1);
	*uri = '\0';
	cmd = uri + 1;

	return (custom_uri_add(entry, cmd));
}

void
walk_custom_uri(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct custom_uri	*u;
	char			buf[1024];

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_custom_uri invalid parameters");
		return;
	}

	TAILQ_FOREACH(u, &cul, entry) {
		snprintf(buf, sizeof buf, "%s,%s", u->uri, u->cmd);
		cb(s, buf, cb_args);
	}
}

int
add_ua(struct settings *s, char *value)
{
	struct user_agent	*ua;
	static int		ua_count = 0;

	ua = g_malloc(sizeof *ua);
	ua->id = ua_count++;
	ua->value = g_strdup(value);

	RB_INSERT(user_agent_list, &ua_list, ua);

	return (0);
}


void
walk_ua(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct user_agent	*ua;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_ua invalid parameters");
		return;
	}

	RB_FOREACH(ua, user_agent_list, &ua_list)
		cb(s, ua->value, cb_args);
}

int
add_http_accept(struct settings *s, char *value)
{
	struct http_accept		*ha;
	static int			ha_count = 0;

	ha = g_malloc(sizeof *ha);
	ha->id = ha_count++;
	ha->value = g_strdup(value);

	RB_INSERT(http_accept_list, &ha_list, ha);

	return (0);
}

void
walk_http_accept(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct http_accept		*ha;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "%s: invalid parameters", __func__);
		return;
	}

	RB_FOREACH(ha, http_accept_list, &ha_list)
		cb(s, ha->value, cb_args);
}

int
add_cmd_alias(struct settings *s, char *entry)
{
	char			*alias, *cmd;

	DNPRINTF(XT_D_CMD_ALIAS, "add_cmd_alias: %s\n", entry);

	alias = strstr(entry, ",");
	if (alias == NULL)
		return (1);
	*alias = '\0';
	cmd = alias + 1;

	return (cmd_alias_add(entry, cmd));
}

void
walk_cmd_alias(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct cmd_alias	*c;
	char			buf[1024];

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_cmd_alias invalid parameters");
		return;
	}

	TAILQ_FOREACH(c, &cal, entry) {
		snprintf(buf, sizeof buf, "%s --> %s", c->alias, c->cmd);
		cb(s, buf, cb_args);
	}
}

int
set_allow_insecure_content(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		allow_insecure_content = XT_DS_ALLOW_INSECURE_CONTENT;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		allow_insecure_content = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		if (is_g_object_setting(G_OBJECT(t->settings),
		    "enable-display-of-insecure-content")) {
			g_object_set(G_OBJECT(t->settings),
			    "enable-display-of-insecure-content",
			    allow_insecure_content, (char *)NULL);
			webkit_web_view_set_settings(t->wv, t->settings);
		}
	return (0);
}

int
set_allow_insecure_scripts(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		allow_insecure_scripts = XT_DS_ALLOW_INSECURE_SCRIPTS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		allow_insecure_scripts = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		if (is_g_object_setting(G_OBJECT(t->settings),
		    "enable-running-of-insecure-content")) {
			g_object_set(G_OBJECT(t->settings),
			    "enable-running-of-insecure-content",
			    allow_insecure_scripts, (char *)NULL);
			webkit_web_view_set_settings(t->wv, t->settings);
		}
	return (0);
}

int
set_auto_load_images(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		auto_load_images = XT_DS_AUTO_LOAD_IMAGES;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		auto_load_images = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry) {
		g_object_set(G_OBJECT(t->settings),
		    "auto-load-images", auto_load_images, (char *)NULL);
		webkit_web_view_set_settings(t->wv, t->settings);
	}
	return (0);
}

int
set_autofocus_onload(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		autofocus_onload = XT_DS_AUTOFOCUS_ONLOAD;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		autofocus_onload = tmp;
	}
	return (0);
}

int
set_ctrl_click_focus(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		ctrl_click_focus = XT_DS_CTRL_CLICK_FOCUS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		ctrl_click_focus = tmp;
	}
	return (0);
}

int
set_download_notifications(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		download_notifications = XT_DS_DOWNLOAD_NOTIFICATIONS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		download_notifications = tmp;
	}
	return (0);
}

int
set_enable_autoscroll(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_autoscroll = XT_DS_ENABLE_AUTOSCROLL;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_autoscroll = tmp;
	}
	return (0);
}

int
set_enable_cookie_whitelist(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_cookie_whitelist = XT_DS_ENABLE_COOKIE_WHITELIST;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_cookie_whitelist = tmp;
	}
	return (0);
}

int
set_enable_js_autorun(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_js_autorun = XT_DS_ENABLE_JS_AUTORUN;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_js_autorun = tmp;
	}
	return (0);
}

int
set_enable_js_whitelist(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_js_whitelist = XT_DS_ENABLE_JS_WHITELIST;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_js_whitelist = tmp;
	}
	return (0);
}

int
set_enable_favicon_entry(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_favicon_entry = XT_DS_ENABLE_FAVICON_ENTRY;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_favicon_entry = tmp;
	}
	return (0);
}

int
set_enable_favicon_tabs(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_favicon_tabs = XT_DS_ENABLE_FAVICON_TABS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_favicon_tabs = tmp;
	}
	return (0);
}

int
set_enable_localstorage(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_localstorage = XT_DS_ENABLE_LOCALSTORAGE;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_localstorage = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		g_object_set(G_OBJECT(t->settings),
		    "enable-html5-local-storage", enable_localstorage,
		    (char *)NULL);
	return (0);
}

int
set_enable_plugins(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_plugins = XT_DS_ENABLE_PLUGINS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_plugins = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		g_object_set(G_OBJECT(t->settings), "enable-plugins",
		    enable_plugins, (char *)NULL);
	return (0);
}

int
set_enable_plugin_whitelist(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_plugin_whitelist = XT_DS_ENABLE_PLUGIN_WHITELIST;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_plugin_whitelist = tmp;
	}
	return (0);
}

int
set_enable_scripts(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_scripts = XT_DS_ENABLE_SCRIPTS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_scripts = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		g_object_set(G_OBJECT(t->settings), "enable-scripts",
		    enable_scripts, (char *)NULL);
	return (0);
}

int
set_enable_spell_checking(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_spell_checking = XT_DS_ENABLE_SPELL_CHECKING;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
		return (-1);
		enable_spell_checking = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		g_object_set(G_OBJECT(t->settings), "enable_spell_checking",
		    enable_spell_checking, (char *)NULL);
	return (0);
}

int
set_enable_strict_transport(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		enable_strict_transport = XT_DS_ENABLE_STRICT_TRANSPORT;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		enable_strict_transport = tmp;
	}
	return (0);
}

#if 0
/*
 * XXX: this is currently broken.  Need to figure out what to do with
 * this.  Problemm is set_encoding will refresh the tab it's run on, so
 * we can either put a big fat warning in the manpage and refresh every
 * single open tab with the new encoding or scrap it as a runtime
 * setting.
 */
int
set_encoding_rt(char *value)
{
	struct karg		args = {0};

	if (value == NULL || strlen(value) == 0)
		return (-1);
	if (encoding)
		g_free(encoding);
	encoding = g_strdup(value);
	args.s = encoding;
	set_encoding(get_current_tab(), &args);
	return (0);
}
#endif

int
set_guess_search(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		guess_search = XT_DS_GUESS_SEARCH;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		guess_search = tmp;
	}
	return (0);
}

int
set_read_only_cookies(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		read_only_cookies = XT_DS_READ_ONLY_COOKIES;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		read_only_cookies = tmp;
	}
	g_object_set(G_OBJECT(p_cookiejar), SOUP_COOKIE_JAR_READ_ONLY,
	    read_only_cookies, (void *)NULL);
	return (0);
}

char *
get_referer(struct settings *s)
{
	if (referer_mode == XT_REFERER_ALWAYS)
		return (g_strdup("always"));
	if (referer_mode == XT_REFERER_NEVER)
		return (g_strdup("never"));
	if (referer_mode == XT_REFERER_SAME_DOMAIN)
		return (g_strdup("same-domain"));
	if (referer_mode == XT_REFERER_SAME_FQDN)
		return (g_strdup("same-fqdn"));
	if (referer_mode == XT_REFERER_CUSTOM)
		return (g_strdup(referer_custom));
	return (NULL);
}

int
set_referer(struct settings *s, char *value)
{
	if (referer_custom) {
		g_free(referer_custom);
		referer_custom = NULL;
	}

	if (!strcmp(value, "always"))
		referer_mode = XT_REFERER_ALWAYS;
	else if (!strcmp(value, "never"))
		referer_mode = XT_REFERER_NEVER;
	else if (!strcmp(value, "same-domain"))
		referer_mode = XT_REFERER_SAME_DOMAIN;
	else if (!strcmp(value, "same-fqdn"))
		referer_mode = XT_REFERER_SAME_FQDN;
	else if (!valid_url_type(value)) {
		referer_mode = XT_REFERER_CUSTOM;
		referer_custom = g_strdup(value);
	} else {
		/* we've already free'd the custom referer */
		if (referer_mode == XT_REFERER_CUSTOM)
			referer_mode = XT_REFERER_NEVER;
		return (1);
	}

	return (0);
}

int
set_referer_rt(char *value)
{
	if (value == NULL || strlen(value) == 0) {
		if (referer_custom)
			g_free(referer_custom);
		referer_custom = g_strdup(XT_DS_REFERER_CUSTOM);
		referer_mode = XT_DS_REFERER_MODE;
		return (0);
	}
	return (set_referer(NULL, value));
}

char *
get_ssl_ca_file(struct settings *s)
{
	if (strlen(ssl_ca_file) == 0)
		return (NULL);
	return (g_strdup(ssl_ca_file));
}

int
set_refresh_interval(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		refresh_interval = XT_DS_REFRESH_INTERVAL;
	else {
		tmp = strtonum(value, 0, INT_MAX, &errstr);
		if (errstr)
			return (-1);
		refresh_interval = tmp;
	}
	return (0);
}

int
set_session_autosave(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		session_autosave = XT_DS_SESSION_AUTOSAVE;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
		return (-1);
		session_autosave = tmp;
	}
	return (0);
}

int
set_session_timeout(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		session_timeout = XT_DS_SESSION_TIMEOUT;
	else {
		tmp = strtonum(value, 0, INT_MAX, &errstr);
		if (errstr)
			return (-1);
		session_timeout = tmp;
	}
	return (0);
}

int
set_show_statusbar(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		tmp = XT_DS_SHOW_STATUSBAR;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
	}
	show_statusbar = tmp;
	statusbar_set_visibility();
	return (0);
}

int
set_show_tabs(char *value)
{
	struct karg		args = {0};
	int			val;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		val = XT_DS_SHOW_TABS;
	else {
		val = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
	}
	args.i = val ? XT_TAB_SHOW : XT_TAB_HIDE;
	tabaction(get_current_tab(), &args);
	return (0);
}

int
set_show_url(char *value)
{
	struct karg		args = {0};
	int			val;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		val = XT_DS_SHOW_URL;
	else {
		val = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
	}
	args.i = val ? XT_URL_SHOW : XT_URL_HIDE;
	urlaction(get_current_tab(), &args);
	return (0);
}

int
set_spell_check_languages(char *value)
{
	struct tab		*t;

	if (spell_check_languages)
		g_free(spell_check_languages);
	if (value == NULL || strlen(value) == 0)
		spell_check_languages = g_strdup(XT_DS_SPELL_CHECK_LANGUAGES);
	else
		spell_check_languages = g_strdup(value);
	TAILQ_FOREACH(t, &tabs, entry)
		g_object_set(G_OBJECT(t->settings), "spell_checking_languages",
		    spell_check_languages, (char *)NULL);
	return (0);
}

int
check_valid_file(char *name)
{
	struct stat		sb;

	if (name == NULL || stat(name, &sb))
		return (-1);
	return (0);
}

int
set_ssl_ca_file_rt(char *value)
{
	if (value == NULL || strlen(value) == 0) {
		strlcpy(ssl_ca_file, XT_DS_SSL_CA_FILE, sizeof ssl_ca_file);
		g_object_set(session, SOUP_SESSION_SSL_CA_FILE, "", NULL);
		return (0);
	} else
		return (set_ssl_ca_file(NULL, value));
}

int
set_ssl_strict_certs(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		ssl_strict_certs = XT_DS_SSL_STRICT_CERTS;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		ssl_strict_certs = tmp;
	}
	g_object_set(session, SOUP_SESSION_SSL_STRICT, ssl_strict_certs, NULL);
	return (0);
}

int
set_external_editor(char *editor)
{
	if (external_editor)
		g_free(external_editor);
	if (editor == NULL || strlen(editor) == 0)
		external_editor = NULL;
	else
		external_editor = g_strdup(editor);
	return (0);
}

int
set_fancy_bar(char *value)
{
	struct tab		*t;
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		fancy_bar = 1;	/* XXX */
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		fancy_bar = tmp;
	}
	TAILQ_FOREACH(t, &tabs, entry)
		if (fancy_bar) {
			gtk_widget_show(t->backward);
			gtk_widget_show(t->forward);
			gtk_widget_show(t->stop);
			gtk_widget_show(t->js_toggle);
			gtk_widget_show(t->search_entry);
		} else {
			gtk_widget_hide(t->backward);
			gtk_widget_hide(t->forward);
			gtk_widget_hide(t->stop);
			gtk_widget_hide(t->js_toggle);
			gtk_widget_hide(t->search_entry);
		}
	return (0);
}

void
setup_proxy(char *uri)
{
	struct tab		*t;

	if (proxy_uri) {
		g_object_set(session, "proxy_uri", NULL, (char *)NULL);
		soup_uri_free(proxy_uri);
		proxy_uri = NULL;
		TAILQ_FOREACH(t, &tabs, entry)
			gtk_entry_set_text(GTK_ENTRY(t->sbe.proxy), "");
	}
	if (http_proxy) {
		if (http_proxy != uri) {
			g_free(http_proxy);
			http_proxy = NULL;
		}
	}

	if (uri) {
		http_proxy = g_strdup(uri);
		DNPRINTF(XT_D_CONFIG, "setup_proxy: %s\n", uri);
		proxy_uri = soup_uri_new(http_proxy);
		if (proxy_uri != NULL && SOUP_URI_VALID_FOR_HTTP(proxy_uri)) {
			g_object_set(session, "proxy-uri", proxy_uri,
			    (char *)NULL);
			TAILQ_FOREACH(t, &tabs, entry)
				gtk_entry_set_text(GTK_ENTRY(t->sbe.proxy),
				    "proxy");
		}
	}
}

char *
get_tab_style(struct settings *s)
{
	if (tab_style == XT_TABS_NORMAL)
		return (g_strdup("normal"));
	else
		return (g_strdup("compact"));
}

int
set_tab_style(struct settings *s, char *val)
{
	if (!strcmp(val, "normal"))
		tab_style = XT_TABS_NORMAL;
	else if (!strcmp(val, "compact"))
		tab_style = XT_TABS_COMPACT;
	else
		return (1);

	return (0);
}

int
set_tab_style_rt(char *value)
{
	struct karg		args = {0};
	int			old_tab_style;

	if (value == NULL || strlen(value) == 0) {
		if (tab_style == XT_DS_TAB_STYLE)
			return (0);
		tab_style = XT_TABS_COMPACT;
		args.i = XT_TAB_NEXTSTYLE;
	} else {
		old_tab_style = tab_style;
		if (set_tab_style(NULL, value))
			return (-1);
		if (old_tab_style != tab_style) {
			tab_style = old_tab_style;
			args.i = XT_TAB_NEXTSTYLE;
		}
	}
	tabaction(get_current_tab(), &args);
	return (0);
}

char *
get_statusbar_style(struct settings *s)
{
	if (statusbar_style == XT_STATUSBAR_URL)
		return (g_strdup("url"));
	else
		return (g_strdup("title"));
}

int
set_statusbar_style(struct settings *s, char *val)
{
	if (!strcmp(val, "url"))
		statusbar_style = XT_STATUSBAR_URL;
	else if (!strcmp(val, "title"))
		statusbar_style = XT_STATUSBAR_TITLE;
	else
		return (1);

	return (0);
}

int
set_statusbar_style_rt(char *value)
{
	struct tab		*t;
	const gchar		*page_uri;

	if (value == NULL || strlen(value) == 0) {
		if (statusbar_style == XT_DS_STATUSBAR_STYLE)
			return (0);
		statusbar_style = XT_DS_STATUSBAR_STYLE;
	} else {
		if (!strcmp(value, "url"))
			statusbar_style = XT_STATUSBAR_URL;
		else if (!strcmp(value, "title"))
			statusbar_style = XT_STATUSBAR_TITLE;
	}

	/* apply changes */
	TAILQ_FOREACH(t, &tabs, entry) {
		if (statusbar_style == XT_STATUSBAR_TITLE)
			set_status(t, "%s", get_title(t, FALSE));
		else if ((page_uri = get_uri(t)) != NULL)
			set_status(t, "%s", page_uri);
	}
	
	return (0);
}

int
set_url_regex(char *value)
{
	if (value == NULL || strlen(value) == 0) {
		if (url_regex)
			g_free(url_regex);
		url_regex = g_strdup(XT_DS_URL_REGEX);
	} else {
		if (regcomp(&url_re, value, REG_EXTENDED | REG_NOSUB))
			return (-1);
		if (url_regex)
			g_free(url_regex);
		url_regex = g_strdup(value);
	}
	return (0);
}

int
set_userstyle(struct settings *s, char *value)
{
	char		script[PATH_MAX] = {'\0'};
	char		*path;

	if (userstyle)
		g_free(userstyle);
	if (value == NULL || strlen(value) == 0) {
		path = g_strdup_printf("%s" PS "style.css", resource_dir);
		userstyle = g_filename_to_uri(path, NULL, NULL);
		g_free(path);
	} else {
		expand_tilde(script, sizeof script, value);
		userstyle = g_filename_to_uri(script, NULL, NULL);
	}
	if (stylesheet)
		g_free(stylesheet);
	stylesheet = g_strdup(userstyle);
	return (0);
}

char *
get_userstyle(struct settings *s)
{
	return (g_filename_from_uri(userstyle, NULL, NULL));
}

int
set_userstyle_rt(char *value)
{
	return (set_userstyle(NULL, value));
}

int
set_userstyle_global(char *value)
{
	struct karg		args = {0};
	int			tmp, old_style;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0) {
		if (userstyle_global == XT_DS_USERSTYLE_GLOBAL)
			return (0);
		userstyle_global = 1;
		args.i = XT_STYLE_GLOBAL;
		userstyle_cmd(get_current_tab(), &args);
	} else {
		old_style = userstyle_global;
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		if (tmp != old_style) {
			args.i = XT_STYLE_GLOBAL;
			userstyle_cmd(get_current_tab(), &args);
		}
	}
	return (0);
}

int
set_warn_cert_changes(char *value)
{
	int			tmp;
	const char		*errstr;

	tmp = strtonum(value, 0, 1, &errstr);
	if (errstr)
		return (-1);
	warn_cert_changes = tmp;
	return (0);
}

char *
get_edit_mode(struct settings *s)
{
	if (edit_mode == XT_EM_HYBRID)
		return (g_strdup("hybrid"));
	else
		return (g_strdup("vi"));
}

int
set_edit_mode(struct settings *s, char *val)
{
	if (!strcmp(val, "hybrid"))
		edit_mode = XT_EM_HYBRID;
	else if (!strcmp(val, "vi"))
		edit_mode = XT_EM_VI;
	else
		return (1);

	return (0);
}

char *
get_download_mode(struct settings *s)
{
	switch (download_mode) {
	case XT_DM_START:
		return (g_strdup("start"));
		break;
	case XT_DM_ASK:
		return (g_strdup("ask"));
		break;
	case XT_DM_ADD:
		return (g_strdup("add"));
		break;
	}
	return (g_strdup("unknown"));
}

int
set_download_mode(struct settings *s, char *val)
{
	if (!strcmp(val, "start"))
		download_mode = XT_DM_START;
	else if (!strcmp(val, "ask"))
		download_mode = XT_DM_ASK;
	else if (!strcmp(val, "add"))
		download_mode = XT_DM_ADD;
	else
		return (1);

	return (0);
}

int
set_download_mode_rt(char *val)
{
	if (val == NULL || strlen(val) == 0)
		return (-1);
	return (set_download_mode(NULL, val));
}

char *
get_work_dir(struct settings *s)
{
	if (work_dir[0] == '\0')
		return (0);
	return (g_strdup(work_dir));
}

int
set_work_dir(struct settings *s, char *val)
{
	expand_tilde(work_dir, sizeof work_dir, val);
	return (0);
}

int
set_xterm_workaround(char *value)
{
	int			tmp;
	const char		*errstr;

	if (value == NULL || strlen(value) == 0)
		xterm_workaround = XT_DS_XTERM_WORKAROUND;
	else {
		tmp = strtonum(value, 0, 1, &errstr);
		if (errstr)
			return (-1);
		xterm_workaround = tmp;
	}
	return (0);
}

void
walk_cookie_wl(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct domain		*d;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_cookie_wl invalid parameters");
		return;
	}

	RB_FOREACH_REVERSE(d, domain_list, &c_wl)
		cb(s, d->d, cb_args);
}

void
walk_js_wl(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct domain		*d;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_js_wl invalid parameters");
		return;
	}

	RB_FOREACH_REVERSE(d, domain_list, &js_wl)
		cb(s, d->d, cb_args);
}

void
walk_pl_wl(struct settings *s,
    void (*cb)(struct settings *, char *, void *), void *cb_args)
{
	struct domain		*d;

	if (s == NULL || cb == NULL) {
		show_oops(NULL, "walk_pl_wl invalid parameters");
		return;
	}

	RB_FOREACH_REVERSE(d, domain_list, &pl_wl)
		cb(s, d->d, cb_args);
}

int
settings_add(char *var, char *val)
{
	int			i, rv, *p;
	gfloat			*f;
	char			c[PATH_MAX], **s;

	/* get settings */
	for (i = 0, rv = 0; i < LENGTH(rs); i++) {
		if (strcmp(var, rs[i].name))
			continue;

		if (!strcmp(var, "include_config")) {
			expand_tilde(c, sizeof c, val);
			config_parse(c, 0);
			rv = 1;
			break;
		}

		if (rs[i].s) {
			if (rs[i].s->set(&rs[i], val))
				errx(1, "invalid value for %s: %s", var, val);
			rv = 1;
			break;
		} else
			switch (rs[i].type) {
			case XT_S_INT:
				p = rs[i].ival;
				*p = atoi(val);
				rv = 1;
				break;
			case XT_S_STR:
				s = rs[i].sval;
				if (s == NULL)
					errx(1, "invalid sval for %s",
					    rs[i].name);
				if (*s)
					g_free(*s);
				*s = g_strdup(val);
				rv = 1;
				break;
			case XT_S_FLOAT:
				f = rs[i].fval;
				*f = atof(val);
				rv = 1;
				break;
			case XT_S_INVALID:
			default:
				errx(1, "invalid type for %s", var);
			}
		break;
	}
	return (rv);
}

#define WS	"\n= \t"
void
config_parse(char *filename, int runtime)
{
	FILE			*config, *f;
	char			*line, *cp, *var, *val;
	size_t			len, lineno = 0;
	int			handled;
	char			file[PATH_MAX];
	struct stat		sb;

	DNPRINTF(XT_D_CONFIG, "config_parse: filename %s\n", filename);

	if (filename == NULL)
		return;

	if (runtime && runtime_settings[0] != '\0') {
		snprintf(file, sizeof file, "%s" PS "%s",
		    work_dir, runtime_settings);
		if (stat(file, &sb)) {
			warnx("runtime file doesn't exist, creating it");
			if ((f = fopen(file, "w")) == NULL)
				err(1, "runtime");
			fprintf(f, "# AUTO GENERATED, DO NOT EDIT\n");
			fclose(f);
		}
	} else
		strlcpy(file, filename, sizeof file);

	if ((config = fopen(file, "r")) == NULL) {
		warn("config_parse: cannot open %s", filename);
		return;
	}

	for (;;) {
		if ((line = fparseln(config, &len, &lineno, NULL, 0)) == NULL)
			if (feof(config) || ferror(config))
				break;

		cp = line;
		cp += (long)strspn(cp, WS);
		if (cp[0] == '\0') {
			/* empty line */
			free(line);
			continue;
		}

		if ((var = strsep(&cp, WS)) == NULL || cp == NULL)
			startpage_add("invalid configuration file entry: %s",
			    line);
		else {
			cp += (long)strspn(cp, WS);

			if ((val = strsep(&cp, "\0")) == NULL)
				break;

			DNPRINTF(XT_D_CONFIG, "config_parse: %s=%s\n",
			    var, val);
			handled = settings_add(var, val);

			if (handled == 0)
				startpage_add("invalid configuration file entry"
				    ": %s=%s", var, val);
		}

		free(line);
	}

	fclose(config);
}

struct settings_args {
	char		**body;
	int		i;
};

void
print_setting(struct settings *s, char *val, void *cb_args)
{
	char			*enc_val, *tmp, *color;
	struct settings_args	*sa = cb_args;

	if (sa == NULL)
		return;

	if (s->flags & XT_SF_RUNTIME)
		color = "#22cc22";
	else
		color = "#cccccc";

	enc_val = html_escape(val);
	tmp = *sa->body;
	*sa->body = g_strdup_printf(
	    "%s\n<tr>"
	    "<td style='background-color: %s; width: 10%%;word-break:break-all'>%s</td>"
	    "<td style='background-color: %s; width: 20%%;word-break:break-all'>%s</td>",
	    *sa->body,
	    color,
	    s->name,
	    color,
	    enc_val == NULL ? "" : enc_val
	    );
	g_free(tmp);
	if (enc_val)
		g_free(enc_val);
	sa->i++;
}

int
set_show(struct tab *t, struct karg *args)
{
	char			*body, *page, *tmp;
	int			i = 1;
	struct settings_args	sa;

	bzero(&sa, sizeof sa);
	sa.body = &body;

	/* body */
	body = g_strdup_printf("<div align='center'><table><tr>"
	    "<th align='left'>Setting</th>"
	    "<th align='left'>Value</th></tr>\n");

	settings_walk(print_setting, &sa);
	i = sa.i;

	/* small message if there are none */
	if (i == 1) {
		tmp = body;
		body = g_strdup_printf("%s\n<tr><td style='text-align:center'"
		    "colspan='2'>No settings</td></tr>\n", body);
		g_free(tmp);
	}

	tmp = body;
	body = g_strdup_printf("%s</table></div>", body);
	g_free(tmp);

	page = get_html_page("Settings", body, "", 0);

	g_free(body);

	load_webkit_string(t, page, XT_URI_ABOUT_SET);

	g_free(page);

	return (XT_CB_PASSTHROUGH);
}

int
set(struct tab *t, struct karg *args)
{
	char			*p, *val;
	int			i;

	if (args == NULL || args->s == NULL)
		return (set_show(t, args));

	/* strip spaces */
	p = g_strstrip(args->s);

	if (strlen(p) == 0)
		return (set_show(t, args));

	/* we got some sort of string */
	val = g_strstr_len(p, strlen(p), "=");
	if (val) {
		*val++ = '\0';
		val = g_strstrip(val);
		p = g_strchomp(p);

		for (i = 0; i < get_settings_size(); i++) {
			if (strcmp(rs[i].name, p))
				continue;

			if (rs[i].activate) {
				if (rs[i].activate(val))
					show_oops(t, "%s invalid value %s",
					    p, val);
				else
					show_oops(t, ":set %s = %s", p, val);
				goto done;
			} else {
				show_oops(t, "not a runtime option: %s", p);
				goto done;
			}
		}
		show_oops(t, "unknown option: %s", p);
	} else {
		p = g_strchomp(p);

		for (i = 0; i < get_settings_size(); i++) {
			if (strcmp(rs[i].name, p))
				continue;

			/* XXX this could use some cleanup */
			switch (rs[i].type) {
			case XT_S_INT:
				if (rs[i].ival)
					show_oops(t, "%s = %d",
					    rs[i].name, *rs[i].ival);
				else if (rs[i].s && rs[i].s->get)
					show_oops(t, "%s = %s",
					    rs[i].name,
					    rs[i].s->get(&rs[i]));
				else if (rs[i].s && rs[i].s->get == NULL)
					show_oops(t, "%s = ...", rs[i].name);
				else
					show_oops(t, "%s = ", rs[i].name);
				break;
			case XT_S_FLOAT:
				if (rs[i].fval)
					show_oops(t, "%s = %f",
					    rs[i].name, *rs[i].fval);
				else if (rs[i].s && rs[i].s->get)
					show_oops(t, "%s = %s",
					    rs[i].name,
					    rs[i].s->get(&rs[i]));
				else if (rs[i].s && rs[i].s->get == NULL)
					show_oops(t, "%s = ...", rs[i].name);
				else
					show_oops(t, "%s = ", rs[i].name);
				break;
			case XT_S_STR:
				if (rs[i].sval && *rs[i].sval)
					show_oops(t, "%s = %s",
					    rs[i].name, *rs[i].sval);
				else if (rs[i].s && rs[i].s->get)
					show_oops(t, "%s = %s",
					    rs[i].name,
					    rs[i].s->get(&rs[i]));
				else if (rs[i].s && rs[i].s->get == NULL)
					show_oops(t, "%s = ...", rs[i].name);
				else
					show_oops(t, "%s = ", rs[i].name);
				break;
			default:
				show_oops(t, "unknown type for %s", rs[i].name);
				goto done;
			}

			goto done;
		}
		show_oops(t, "unknown option: %s", p);
	}
done:
	return (XT_CB_PASSTHROUGH);
}