X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=uzbl.c;h=25c3c382f88e1c1fe6b69192a8b3be4b4fe64c30;hb=5941ba2954f4d4694668f61189f940cb40fbfb51;hp=454efc1b671387642f800c0d390a1e06d10661e2;hpb=36c780a3afa026723b93abd4f48d3fcec055c9f3;p=uzbl-mobile diff --git a/uzbl.c b/uzbl.c index 454efc1..25c3c38 100644 --- a/uzbl.c +++ b/uzbl.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -54,54 +55,101 @@ #include #include #include "uzbl.h" - +#include "config.h" static Uzbl uzbl; +typedef void (*Command)(WebKitWebView*, GArray *argv); + -/* define names and pointers to all config specific variables */ + +/* commandline arguments (set initial values for the state variables) */ +static const +GOptionEntry entries[] = +{ + { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, + "Uri to load at startup (equivalent to 'set uri = URI')", "URI" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, + "Whether to print all messages or just errors.", NULL }, + { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, + "Name of the current instance (defaults to Xorg window id)", "NAME" }, + { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, + "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; + +/* associate command names to their properties */ typedef const struct { void **ptr; int type; + int dump; void (*func)(void); } uzbl_cmdprop; -enum {TYPE_INT, TYPE_STRING}; +enum {TYPE_INT, TYPE_STR}; + +/* an abbreviation to help keep the table's width humane */ +#define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun } const struct { char *name; uzbl_cmdprop cp; } var_name_to_ptr[] = { -/* variable name pointer to variable in code variable type callback function */ -/* ------------------------------------------------------------------------------------------------------------------- */ - { "uri", {.ptr = (void *)&uzbl.state.uri, .type = TYPE_STRING, .func = cmd_load_uri}}, - { "status_message", {.ptr = (void *)&uzbl.gui.sbar.msg, .type = TYPE_STRING, .func = update_title}}, - { "show_status", {.ptr = (void *)&uzbl.behave.show_status, .type = TYPE_INT, .func = cmd_set_status}}, - { "status_top", {.ptr = (void *)&uzbl.behave.status_top, .type = TYPE_INT, .func = move_statusbar}}, - { "status_format", {.ptr = (void *)&uzbl.behave.status_format, .type = TYPE_STRING, .func = update_title}}, - { "status_background", {.ptr = (void *)&uzbl.behave.status_background, .type = TYPE_STRING, .func = update_title}}, - { "title_format_long", {.ptr = (void *)&uzbl.behave.title_format_long, .type = TYPE_STRING, .func = update_title}}, - { "title_format_short", {.ptr = (void *)&uzbl.behave.title_format_short, .type = TYPE_STRING, .func = update_title}}, - { "insert_mode", {.ptr = (void *)&uzbl.behave.insert_mode, .type = TYPE_INT, .func = NULL}}, - { "always_insert_mode", {.ptr = (void *)&uzbl.behave.always_insert_mode, .type = TYPE_INT, .func = cmd_always_insert_mode}}, - { "reset_command_mode", {.ptr = (void *)&uzbl.behave.reset_command_mode, .type = TYPE_INT, .func = NULL}}, - { "modkey" , {.ptr = (void *)&uzbl.behave.modkey, .type = TYPE_STRING, .func = cmd_modkey}}, - { "load_finish_handler",{.ptr = (void *)&uzbl.behave.load_finish_handler, .type = TYPE_STRING, .func = NULL}}, - { "load_start_handler", {.ptr = (void *)&uzbl.behave.load_start_handler, .type = TYPE_STRING, .func = NULL}}, - { "load_commit_handler",{.ptr = (void *)&uzbl.behave.load_commit_handler, .type = TYPE_STRING, .func = NULL}}, - { "history_handler", {.ptr = (void *)&uzbl.behave.history_handler, .type = TYPE_STRING, .func = NULL}}, - { "download_handler", {.ptr = (void *)&uzbl.behave.download_handler, .type = TYPE_STRING, .func = NULL}}, - { "cookie_handler", {.ptr = (void *)&uzbl.behave.cookie_handler, .type = TYPE_STRING, .func = NULL}}, - { "fifo_dir", {.ptr = (void *)&uzbl.behave.fifo_dir, .type = TYPE_STRING, .func = cmd_fifo_dir}}, - { "socket_dir", {.ptr = (void *)&uzbl.behave.socket_dir, .type = TYPE_STRING, .func = cmd_socket_dir}}, - { "http_debug", {.ptr = (void *)&uzbl.behave.http_debug, .type = TYPE_INT, .func = cmd_http_debug}}, - { "default_font_size", {.ptr = (void *)&uzbl.behave.default_font_size, .type = TYPE_INT, .func = cmd_default_font_size}}, - { "minimum_font_size", {.ptr = (void *)&uzbl.behave.minimum_font_size, .type = TYPE_INT, .func = cmd_minimum_font_size}}, - { "shell_cmd", {.ptr = (void *)&uzbl.behave.shell_cmd, .type = TYPE_STRING, .func = NULL}}, - { "proxy_url", {.ptr = (void *)&uzbl.net.proxy_url, .type = TYPE_STRING, .func = set_proxy_url}}, - { "max_conns", {.ptr = (void *)&uzbl.net.max_conns, .type = TYPE_INT, .func = cmd_max_conns}}, - { "max_conns_host", {.ptr = (void *)&uzbl.net.max_conns_host, .type = TYPE_INT, .func = cmd_max_conns_host}}, - { "useragent", {.ptr = (void *)&uzbl.net.useragent, .type = TYPE_STRING, .func = cmd_useragent}}, - { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}} +/* variable name pointer to variable in code type dump callback function */ +/* --------------------------------------------------------------------------------------- */ + { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)}, + { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)}, + { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)}, + { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)}, + { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)}, + { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)}, + { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)}, + { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)}, + { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)}, + { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)}, + { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)}, + { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)}, + { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)}, + { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)}, + { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)}, + { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)}, + { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)}, + { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)}, + { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)}, + { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)}, + { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)}, + { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)}, + { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)}, + { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)}, + { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)}, + { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)}, + { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)}, + { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)}, + { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)}, + { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)}, + { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)}, + { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)}, + { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)}, + { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)}, + { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)}, + { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)}, + /* exported WebKitWebSettings properties*/ + { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)}, + { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)}, + { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)}, + { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)}, + { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)}, + { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)}, + { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)}, + { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)}, + { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)}, + { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)}, + { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)}, + { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)}, + { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)}, + { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)}, + { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)}, + + { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}} }, *n2v_p = var_name_to_ptr; const struct { @@ -138,19 +186,55 @@ make_var_to_name_hash() { } } -/* commandline arguments (set initial values for the state variables) */ -static GOptionEntry entries[] = -{ - { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load at startup (equivalent to 'set uri = URI')", "URI" }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, "Whether to print all messages or just errors.", NULL }, - { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" }, - { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" }, - { NULL, 0, 0, 0, NULL, NULL, NULL } -}; - -typedef void (*Command)(WebKitWebView*, GArray *argv); - /* --- UTILITY FUNCTIONS --- */ +static gchar * +expand_vars(char *s) { + char ret[256], /* 256 chars per var name should be safe */ + *vend; + uzbl_cmdprop *c; + char upto = ' '; + GString *buf = g_string_new(""); + + while(*s) { + /* found quotation char */ + if(*s == '\\') { + g_string_append_c(buf, *++s); + s++; + } + /* found variable */ + else if(*s == '@') { + if(*(s+1) == '{') { + upto = '}'; s++; + } + s++; + if( (vend = strchr(s, upto)) || + (vend = strchr(s, '\0')) ) { + strncpy(ret, s, vend-s); + ret[vend-s] = '\0'; + if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) { + if(c->type == TYPE_STR) + g_string_append(buf, (gchar *)*c->ptr); + else if(c->type == TYPE_INT) { + char *b = itos((int)*c->ptr); + g_string_append(buf, b); + g_free(b); + } + } + if(upto == ' ') + s = vend; + else + s = vend+1; + upto = ' '; + } + } + /* every other char */ + else { + g_string_append_c(buf, *s); + s++; + } + } + return g_string_free(buf, FALSE); +} char * itos(int val) { @@ -161,6 +245,9 @@ itos(int val) { } static gchar* +strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go + +static gchar* argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); } static char * @@ -170,7 +257,7 @@ str_replace (const char* search, const char* replace, const char* string) { buf = g_strsplit (string, search, -1); ret = g_strjoinv (replace, buf); - g_strfreev(buf); + g_strfreev(buf); // somebody said this segfaults return ret; } @@ -202,26 +289,29 @@ read_file_by_line (gchar *path) { } static -gchar* parseenv (const char* string) { +gchar* parseenv (char* string) { extern char** environ; - gchar* newstring = g_strdup (string); + gchar* tmpstr = NULL; int i = 0; + while (environ[i] != NULL) { - gchar** env = g_strsplit (environ[i], "=", 0); - gchar* envname = malloc (strlen (env[0]) + 1); - - strcat (envname, "$"); - strcat (envname, env[0]); - - newstring = str_replace(envname, env[1], newstring); + gchar** env = g_strsplit (environ[i], "=", 2); + gchar* envname = g_strconcat ("$", env[0], NULL); + + if (g_strrstr (string, envname) != NULL) { + tmpstr = g_strdup(string); + g_free (string); + string = str_replace(envname, env[1], tmpstr); + g_free (tmpstr); + } g_free (envname); - //g_strfreev (env); - This still breaks uzbl, but shouldn't. The mystery thickens... - i ++; + g_strfreev (env); // somebody said this breaks uzbl + i++; } - return newstring; + return string; } static sigfunc* @@ -251,6 +341,19 @@ clean_up(void) { g_hash_table_destroy(uzbl.behave.commands); } +/* used for html_mode_timeout + * be sure to extend this function to use + * more timers if needed in other places +*/ +static void +set_timeout(int seconds) { + struct itimerval t; + memset(&t, 0, sizeof t); + + t.it_value.tv_sec = seconds; + t.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &t, NULL); +} /* --- SIGNAL HANDLER --- */ @@ -267,6 +370,15 @@ catch_sigint(int s) { exit(EXIT_SUCCESS); } +static void +catch_alrm(int s) { + (void) s; + + set_var_value("mode", "0"); + render_html(); +} + + /* --- CALLBACKS --- */ static gboolean @@ -324,23 +436,27 @@ scroll (GtkAdjustment* bar, GArray *argv) { gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount); } -static void scroll_begin(WebKitWebView* page, GArray *argv) { +static void +scroll_begin(WebKitWebView* page, GArray *argv) { (void) page; (void) argv; gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v)); } -static void scroll_end(WebKitWebView* page, GArray *argv) { +static void +scroll_end(WebKitWebView* page, GArray *argv) { (void) page; (void) argv; gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) - gtk_adjustment_get_page_size(uzbl.gui.bar_v)); } -static void scroll_vert(WebKitWebView* page, GArray *argv) { +static void +scroll_vert(WebKitWebView* page, GArray *argv) { (void) page; scroll(uzbl.gui.bar_v, argv); } -static void scroll_horz(WebKitWebView* page, GArray *argv) { +static void +scroll_horz(WebKitWebView* page, GArray *argv) { (void) page; scroll(uzbl.gui.bar_h, argv); } @@ -416,6 +532,7 @@ load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { (void) page; (void) frame; (void) data; + g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page? if (uzbl.behave.load_start_handler) run_handler(uzbl.behave.load_start_handler, ""); } @@ -424,14 +541,13 @@ static void load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { (void) page; (void) data; - free (uzbl.state.uri); + g_free (uzbl.state.uri); GString* newuri = g_string_new (webkit_web_frame_get_uri (frame)); uzbl.state.uri = g_string_free (newuri, FALSE); if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) { uzbl.behave.insert_mode = uzbl.behave.always_insert_mode; update_title(); } - g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page? if (uzbl.behave.load_commit_handler) run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri); } @@ -451,7 +567,7 @@ log_history_cb () { char date [80]; time ( &rawtime ); timeinfo = localtime ( &rawtime ); - strftime (date, 80, " \"%Y-%m-%d %H:%M:%S\"", timeinfo); + strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo); run_handler(uzbl.behave.history_handler, date); } } @@ -488,12 +604,22 @@ static struct {char *name; Command command[2];} cmdlist[] = { "script", {run_external_js, 0} }, { "toggle_status", {toggle_status_cb, 0} }, { "spawn", {spawn, 0} }, + { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler { "sh", {spawn_sh, 0} }, + { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler { "exit", {close_uzbl, 0} }, { "search", {search_forward_text, NOSPLIT} }, { "search_reverse", {search_reverse_text, NOSPLIT} }, + { "dehilight", {dehilight, 0} }, { "toggle_insert_mode", {toggle_insert_mode, 0} }, - { "runcmd", {runcmd, NOSPLIT} } + { "set", {set_var, NOSPLIT} }, + { "get", {get_var, NOSPLIT} }, + { "bind", {act_bind, NOSPLIT} }, + { "dump_config", {act_dump_config, 0} }, + { "keycmd", {keycmd, NOSPLIT} }, + { "keycmd_nl", {keycmd_nl, NOSPLIT} }, + { "keycmd_bs", {keycmd_bs, 0} }, + { "chain", {chain, 0} } }; static void @@ -536,9 +662,40 @@ file_exists (const char * filename) { } static void +set_var(WebKitWebView *page, GArray *argv) { + (void) page; + gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2); + gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " ")); + set_var_value(g_strstrip(split[0]), value); + g_free(value); + g_strfreev(split); +} + +static void +get_var(WebKitWebView *page, GArray *argv) { + (void) page; + get_var_value(argv_idx(argv, 0)); +} + +static void +act_bind(WebKitWebView *page, GArray *argv) { + (void) page; + gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2); + gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " ")); + add_binding(g_strstrip(split[0]), value); + g_free(value); + g_strfreev(split); +} + + +static void +act_dump_config() { + dump_config(); +} + +static void toggle_insert_mode(WebKitWebView *page, GArray *argv) { (void)page; - (void)argv; if (argv_idx(argv, 0)) { if (strcmp (argv_idx(argv, 0), "0") == 0) { @@ -587,6 +744,7 @@ run_external_js (WebKitWebView * web_view, GArray *argv) { js = newjs; } i ++; + g_free (line); } if (uzbl.state.verbose) @@ -605,27 +763,19 @@ run_external_js (WebKitWebView * web_view, GArray *argv) { static void search_text (WebKitWebView *page, GArray *argv, const gboolean forward) { - if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) - uzbl.state.searchtx = g_strdup(argv_idx(argv, 0)); - - if (uzbl.state.searchtx != NULL) { - if (uzbl.state.verbose) - printf ("Searching: %s\n", uzbl.state.searchtx); - - if (g_strcmp0 (uzbl.state.searchtx, uzbl.state.searchold) != 0) { + if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) { + if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) { webkit_web_view_unmark_text_matches (page); - webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0); - - if (uzbl.state.searchold != NULL) - g_free (uzbl.state.searchold); - - uzbl.state.searchold = g_strdup (uzbl.state.searchtx); + webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0); + uzbl.state.searchtx = g_strdup(argv_idx(argv, 0)); } - + } + + if (uzbl.state.searchtx) { + if (uzbl.state.verbose) + printf ("Searching: %s\n", uzbl.state.searchtx); webkit_web_view_set_highlight_text_matches (page, TRUE); webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE); - g_free(uzbl.state.searchtx); - uzbl.state.searchtx = NULL; } } @@ -640,6 +790,13 @@ search_reverse_text (WebKitWebView *page, GArray *argv) { } static void +dehilight (WebKitWebView *page, GArray *argv) { + (void) argv; + webkit_web_view_set_highlight_text_matches (page, FALSE); +} + + +static void new_window_load_uri (const gchar * uri) { GString* to_execute = g_string_new (""); g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri); @@ -659,6 +816,45 @@ new_window_load_uri (const gchar * uri) { } static void +chain (WebKitWebView *page, GArray *argv) { + (void)page; + gchar *a = NULL; + gchar **parts = NULL; + guint i = 0; + while ((a = argv_idx(argv, i++))) { + parts = g_strsplit (a, " ", 2); + parse_command(parts[0], parts[1]); + g_strfreev (parts); + } +} + +static void +keycmd (WebKitWebView *page, GArray *argv) { + (void)page; + (void)argv; + g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0)); + run_keycmd(FALSE); + update_title(); +} + +static void +keycmd_nl (WebKitWebView *page, GArray *argv) { + (void)page; + (void)argv; + g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0)); + run_keycmd(TRUE); + update_title(); +} + +static void +keycmd_bs (WebKitWebView *page, GArray *argv) { + (void)page; + (void)argv; + g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1); + update_title(); +} + +static void close_uzbl (WebKitWebView *page, GArray *argv) { (void)page; (void)argv; @@ -668,7 +864,7 @@ close_uzbl (WebKitWebView *page, GArray *argv) { /* --Statusbar functions-- */ static char* build_progressbar_ascii(int percent) { - int width=10; + int width=uzbl.gui.sbar.progress_w; int i; double l; GString *bar = g_string_new(""); @@ -677,10 +873,10 @@ build_progressbar_ascii(int percent) { l = (int)(l+.5)>=(int)l ? l+.5 : l; for(i=0; i<(int)l; i++) - g_string_append(bar, "="); + g_string_append(bar, uzbl.gui.sbar.progress_s); for(; istr? - g_markup_printf_escaped("%s", uzbl.state.keycmd->str) : - g_strdup(""); - g_string_append(ret, buf); - free(buf); + if(escape_markup) { + buf = uzbl.state.keycmd->str? + g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup(""); + g_string_append(ret, buf); + g_free(buf); + } + else + g_string_append(ret, uzbl.state.keycmd->str? + uzbl.state.keycmd->str:g_strdup("")); break; case SYM_MODE: g_string_append(ret, - uzbl.behave.insert_mode?"[I]":"[C]"); + uzbl.behave.insert_mode? + uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator); break; case SYM_MSG: g_string_append(ret, - uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:""); + uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:""); break; /* useragent syms */ case SYM_WK_MAJ: buf = itos(WEBKIT_MAJOR_VERSION); g_string_append(ret, buf); - free(buf); + g_free(buf); break; case SYM_WK_MIN: buf = itos(WEBKIT_MINOR_VERSION); g_string_append(ret, buf); - free(buf); + g_free(buf); break; case SYM_WK_MIC: buf = itos(WEBKIT_MICRO_VERSION); g_string_append(ret, buf); - free(buf); + g_free(buf); break; case SYM_SYSNAME: g_string_append(ret, uzbl.state.unameinfo.sysname); @@ -857,7 +1070,7 @@ expand_template(const char *template) { else if(token == G_TOKEN_INT) { buf = itos(g_scanner_cur_value(uzbl.scan).v_int); g_string_append(ret, buf); - free(buf); + g_free(buf); } else if(token == G_TOKEN_IDENTIFIER) { g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier); @@ -901,11 +1114,15 @@ run_command (const gchar *command, const guint npre, const gchar **args, for (i = npre; i < g_strv_length((gchar**)args); i++) sharg_append(a, args[i]); + gboolean result; - if (sync) result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, stdout, NULL, NULL, &err); - else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, &err); + if (sync) { + if (*stdout) *stdout = strfree(*stdout); + + result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, stdout, NULL, NULL, &err); + } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &err); if (uzbl.state.verbose) { GString *s = g_string_new("spawned:"); @@ -917,6 +1134,9 @@ run_command (const gchar *command, const guint npre, const gchar **args, g_string_append_printf(s, " -- result: %s", (result ? "true" : "false")); printf("%s\n", s->str); g_string_free(s, TRUE); + if(stdout) { + printf("Stdout: %s\n", *stdout); + } } if (err) { g_printerr("error on run_command: %s\n", err->message); @@ -970,7 +1190,16 @@ spawn(WebKitWebView *web_view, GArray *argv) { (void)web_view; //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after if (argv_idx(argv, 0)) - run_command(argv_idx(argv, 0), 0, (const gchar **) argv->data + sizeof(gchar*), FALSE, NULL); + run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL); +} + +static void +spawn_sync(WebKitWebView *web_view, GArray *argv) { + (void)web_view; + + if (argv_idx(argv, 0)) + run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), + TRUE, &uzbl.comm.sync_stdout); } static void @@ -995,6 +1224,28 @@ spawn_sh(WebKitWebView *web_view, GArray *argv) { } static void +spawn_sh_sync(WebKitWebView *web_view, GArray *argv) { + (void)web_view; + if (!uzbl.behave.shell_cmd) { + g_printerr ("spawn_sh_sync: shell_cmd is not set!\n"); + return; + } + + guint i; + gchar *spacer = g_strdup(""); + g_array_insert_val(argv, 1, spacer); + gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); + + for (i = 1; i < g_strv_length(cmd); i++) + g_array_prepend_val(argv, cmd[i]); + + if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, + TRUE, &uzbl.comm.sync_stdout); + g_free (spacer); + g_strfreev (cmd); +} + +static void parse_command(const char *cmd, const char *param) { Command *c; @@ -1004,9 +1255,9 @@ parse_command(const char *cmd, const char *param) { gchar **par = split_quoted(param, TRUE); GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - if (c[1]) { /* don't split */ + if (c[1] == NOSPLIT) { /* don't split */ sharg_append(a, param); - } else { + } else if (par) { for (i = 0; i < g_strv_length(par); i++) sharg_append(a, par[i]); } @@ -1018,28 +1269,13 @@ parse_command(const char *cmd, const char *param) { g_printerr ("command \"%s\" not understood. ignoring.\n", cmd); } -/* command parser */ -static void -setup_regex() { - uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$", - G_REGEX_OPTIMIZE, 0, NULL); - uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", - G_REGEX_OPTIMIZE, 0, NULL); - uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$", - G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL); - uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$", - G_REGEX_OPTIMIZE, 0, NULL); - uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$", - G_REGEX_OPTIMIZE, 0, NULL); -} - static gboolean -get_var_value(gchar *name) { +get_var_value(const gchar *name) { uzbl_cmdprop *c; if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { - if(c->type == TYPE_STRING) - printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr); + if(c->type == TYPE_STR) + printf("VAR: %s VALUE: (%s)\n", name, (char *)*c->ptr); else if(c->type == TYPE_INT) printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr); } @@ -1104,38 +1340,135 @@ cmd_http_debug() { SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); } +static WebKitWebSettings* +view_settings() { + return webkit_web_view_get_settings(uzbl.gui.web_view); +} + +static void +cmd_font_size() { + WebKitWebSettings *ws = view_settings(); + if (uzbl.behave.font_size > 0) { + g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL); + } + + if (uzbl.behave.monospace_size > 0) { + g_object_set (G_OBJECT(ws), "default-monospace-font-size", + uzbl.behave.monospace_size, NULL); + } else { + g_object_set (G_OBJECT(ws), "default-monospace-font-size", + uzbl.behave.font_size, NULL); + } +} + static void -cmd_default_font_size() { - WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view); - g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.default_font_size, NULL); +cmd_disable_plugins() { + g_object_set (G_OBJECT(view_settings()), "enable-plugins", + !uzbl.behave.disable_plugins, NULL); +} + +static void +cmd_disable_scripts() { + g_object_set (G_OBJECT(view_settings()), "enable-scripts", + !uzbl.behave.disable_scripts, NULL); } static void cmd_minimum_font_size() { - WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view); - g_object_set (G_OBJECT(ws), "minimum-font-size", uzbl.behave.minimum_font_size, NULL); + g_object_set (G_OBJECT(view_settings()), "minimum-font-size", + uzbl.behave.minimum_font_size, NULL); } +static void +cmd_autoload_img() { + g_object_set (G_OBJECT(view_settings()), "auto-load-images", + uzbl.behave.autoload_img, NULL); +} + static void -cmd_fifo_dir() { - char *buf; +cmd_autoshrink_img() { + g_object_set (G_OBJECT(view_settings()), "auto-shrink-images", + uzbl.behave.autoshrink_img, NULL); +} - buf = init_fifo(uzbl.behave.fifo_dir); - if(uzbl.behave.fifo_dir) - free(uzbl.behave.fifo_dir); - uzbl.behave.fifo_dir = buf?buf:g_strdup(""); +static void +cmd_enable_spellcheck() { + g_object_set (G_OBJECT(view_settings()), "enable-spell-checking", + uzbl.behave.enable_spellcheck, NULL); } static void -cmd_socket_dir() { - char *buf; +cmd_enable_private() { + g_object_set (G_OBJECT(view_settings()), "enable-private-browsing", + uzbl.behave.enable_private, NULL); +} + +static void +cmd_print_bg() { + g_object_set (G_OBJECT(view_settings()), "print-backgrounds", + uzbl.behave.print_bg, NULL); +} - buf = init_socket(uzbl.behave.fifo_dir); - if(uzbl.behave.socket_dir) - free(uzbl.behave.socket_dir); +static void +cmd_style_uri() { + g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri", + uzbl.behave.style_uri, NULL); +} + +static void +cmd_resizable_txt() { + g_object_set (G_OBJECT(view_settings()), "resizable-text-areas", + uzbl.behave.resizable_txt, NULL); +} + +static void +cmd_default_encoding() { + g_object_set (G_OBJECT(view_settings()), "default-encoding", + uzbl.behave.default_encoding, NULL); +} + +static void +cmd_enforce_96dpi() { + g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi", + uzbl.behave.enforce_96dpi, NULL); +} - uzbl.behave.socket_dir = buf?buf:g_strdup(""); +static void +cmd_caret_browsing() { + g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing", + uzbl.behave.caret_browsing, NULL); +} + +static void +cmd_cookie_handler() { + gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2); + /* pitfall: doesn't handle chain actions; must the sync_ action manually */ + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.cookie_handler); + uzbl.behave.cookie_handler = + g_strdup_printf("sync_%s %s", split[0], split[1]); + } + g_strfreev (split); +} + +static void +cmd_fifo_dir() { + uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); +} + +static void +cmd_socket_dir() { + uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir); +} + +static void +cmd_inject_html() { + if(uzbl.behave.inject_html) { + webkit_web_view_load_html_string (uzbl.gui.web_view, + uzbl.behave.inject_html, NULL); + } } static void @@ -1145,9 +1478,10 @@ cmd_modkey() { buf = g_utf8_strup(uzbl.behave.modkey, -1); uzbl.behave.modmask = 0; - + if(uzbl.behave.modkey) - free(uzbl.behave.modkey); + g_free(uzbl.behave.modkey); + uzbl.behave.modkey = buf; for (i = 0; modkeys[i].key != NULL; i++) { if (g_strrstr(buf, modkeys[i].key)) @@ -1157,13 +1491,16 @@ cmd_modkey() { static void cmd_useragent() { - char *buf; - - buf = set_useragent(uzbl.net.useragent); - if(uzbl.net.useragent) - free(uzbl.net.useragent); - - uzbl.net.useragent = buf?buf:g_strdup(""); + if (*uzbl.net.useragent == ' ') { + g_free (uzbl.net.useragent); + uzbl.net.useragent = NULL; + } else { + gchar *ua = expand_template(uzbl.net.useragent, FALSE); + if (ua) + g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL); + g_free(uzbl.net.useragent); + uzbl.net.useragent = ua; + } } static void @@ -1189,109 +1526,79 @@ move_statusbar() { static gboolean set_var_value(gchar *name, gchar *val) { - void *p = NULL; uzbl_cmdprop *c = NULL; char *endp = NULL; - char *buf=NULL; + char *buf = NULL; if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { /* check for the variable type */ - if (c->type == TYPE_STRING) { - free(*c->ptr); - *c->ptr = g_strdup(val); + if (c->type == TYPE_STR) { + buf = expand_vars(val); + g_free(*c->ptr); + *c->ptr = buf; } else if(c->type == TYPE_INT) { - int *ip = c->ptr; - *ip = (int)strtoul(val, &endp, 10); + int *ip = (int *)c->ptr; + buf = expand_vars(val); + *ip = (int)strtoul(buf, &endp, 10); + g_free(buf); } /* invoke a command specific function */ if(c->func) c->func(); - - /* this will be removed as soon as we have converted to - * the callback interface - */ - p = *c->ptr; } return TRUE; } static void -runcmd(WebKitWebView* page, GArray *argv) { - (void) page; - parse_cmd_line(argv_idx(argv, 0)); +render_html() { + Behaviour *b = &uzbl.behave; + + if(b->html_buffer->str) { + webkit_web_view_load_html_string (uzbl.gui.web_view, + b->html_buffer->str, b->base_url); + g_string_free(b->html_buffer, TRUE); + b->html_buffer = g_string_new(""); + } } +enum {M_CMD, M_HTML}; static void parse_cmd_line(const char *ctl_line) { - gchar **tokens; - - /* SET command */ - if(ctl_line[0] == 's' || ctl_line[0] == 'S') { - tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - gchar* value = parseenv (tokens[2]); - set_var_value(tokens[1], value); - g_strfreev(tokens); - g_free(value); - } - else - printf("Error in command: %s\n", tokens[0]); - } - /* GET command */ - else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') { - tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - get_var_value(tokens[1]); - g_strfreev(tokens); - } - else - printf("Error in command: %s\n", tokens[0]); - } - /* BIND command */ - else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') { - tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - gchar* value = parseenv (tokens[2]); - add_binding(tokens[1], value); - g_strfreev(tokens); - g_free(value); - } - else - printf("Error in command: %s\n", tokens[0]); - } - /* ACT command */ - else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') { - tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - parse_command(tokens[1], tokens[2]); - g_strfreev(tokens); + Behaviour *b = &uzbl.behave; + size_t len=0; + + if(b->mode == M_HTML) { + len = strlen(b->html_endmarker); + /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */ + if(len == strlen(ctl_line)-1 && + !strncmp(b->html_endmarker, ctl_line, len)) { + set_timeout(0); + set_var_value("mode", "0"); + render_html(); + return; } - else - printf("Error in command: %s\n", tokens[0]); - } - /* KEYCMD command */ - else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') { - tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - /* should incremental commands want each individual "keystroke" - sent in a loop or the whole string in one go like now? */ - g_string_assign(uzbl.state.keycmd, tokens[1]); - run_keycmd(FALSE); - if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N")) - run_keycmd(TRUE); - update_title(); - g_strfreev(tokens); + else { + set_timeout(b->html_timeout); + g_string_append(b->html_buffer, ctl_line); } } - /* Comments */ - else if( (ctl_line[0] == '#') + else if((ctl_line[0] == '#') /* Comments */ || (ctl_line[0] == ' ') || (ctl_line[0] == '\n')) ; /* ignore these lines */ - else - printf("Command not understood (%s)\n", ctl_line); - - return; + else { /* parse a command */ + gchar *ctlstrip; + gchar **tokens = NULL; + + if (ctl_line[strlen(ctl_line) - 1] == '\n') /* strip trailing newline */ + ctlstrip = g_strndup(ctl_line, strlen(ctl_line) - 1); + else ctlstrip = g_strdup(ctl_line); + + tokens = g_strsplit(ctlstrip, " ", 2); + parse_command(tokens[0], tokens[1]); + g_free(ctlstrip); + g_strfreev(tokens); + } } static gchar* @@ -1350,6 +1657,7 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ } if (*dir == ' ') { /* space unsets the variable */ + g_free (dir); return NULL; } @@ -1374,20 +1682,17 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ /* if we got this far, there was an error; cleanup */ if (error) g_error_free (error); + g_free(dir); g_free(path); return NULL; } static gboolean control_stdin(GIOChannel *gio, GIOCondition condition) { + (void) condition; gchar *ctl_line = NULL; GIOStatus ret; - if (condition & G_IO_HUP) { - ret = g_io_channel_shutdown (gio, FALSE, NULL); - return FALSE; - } - ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL); if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) ) return FALSE; @@ -1527,12 +1832,12 @@ update_title (void) { if (b->show_status) { if (b->title_format_short) { - parsed = expand_template(b->title_format_short); + parsed = expand_template(b->title_format_short, FALSE); gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed); g_free(parsed); } if (b->status_format) { - parsed = expand_template(b->status_format); + parsed = expand_template(b->status_format, TRUE); gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed); g_free(parsed); } @@ -1544,7 +1849,7 @@ update_title (void) { } } else { if (b->title_format_long) { - parsed = expand_template(b->title_format_long); + parsed = expand_template(b->title_format_long, FALSE); gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed); g_free(parsed); } @@ -1575,6 +1880,7 @@ key_press_cb (GtkWidget* window, GdkEventKey* event) if (event->keyval == GDK_Escape) { g_string_truncate(uzbl.state.keycmd, 0); update_title(); + dehilight(uzbl.gui.web_view, NULL); return TRUE; } @@ -1589,15 +1895,13 @@ key_press_cb (GtkWidget* window, GdkEventKey* event) if (str) { g_string_append (uzbl.state.keycmd, str); update_title (); - free (str); + g_free (str); } return TRUE; } - if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) { - g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1); - update_title(); - } + if (event->keyval == GDK_BackSpace) + keycmd_bs(NULL, NULL); gboolean key_ret = FALSE; if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) @@ -1613,57 +1917,58 @@ key_press_cb (GtkWidget* window, GdkEventKey* event) static void run_keycmd(const gboolean key_ret) { /* run the keycmd immediately if it isn't incremental and doesn't take args */ - Action *action; - if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) { + Action *act; + if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) { g_string_truncate(uzbl.state.keycmd, 0); - parse_command(action->name, action->param); + parse_command(act->name, act->param); return; } /* try if it's an incremental keycmd or one that takes args, and run it */ GString* short_keys = g_string_new (""); GString* short_keys_inc = g_string_new (""); - unsigned int i; + guint i; for (i=0; i<(uzbl.state.keycmd->len); i++) { g_string_append_c(short_keys, uzbl.state.keycmd->str[i]); g_string_assign(short_keys_inc, short_keys->str); g_string_append_c(short_keys, '_'); g_string_append_c(short_keys_inc, '*'); - gboolean exec_now = FALSE; - if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) { - if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */ - } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) { - if (key_ret) { /* just quit the incremental command on return */ - g_string_truncate(uzbl.state.keycmd, 0); - break; - } else exec_now = TRUE; /* always exec incr. commands on keys other than return */ - } - - if (exec_now) { - GString* parampart = g_string_new (uzbl.state.keycmd->str); - GString* actionname = g_string_new (""); - GString* actionparam = g_string_new (""); - g_string_erase (parampart, 0, i+1); - if (action->name) - g_string_printf (actionname, action->name, parampart->str); - if (action->param) - g_string_printf (actionparam, action->param, parampart->str); - parse_command(actionname->str, actionparam->str); - g_string_free (actionname, TRUE); - g_string_free (actionparam, TRUE); - g_string_free (parampart, TRUE); - if (key_ret) + if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) { + /* run normal cmds only if return was pressed */ + exec_paramcmd(act, i); + g_string_truncate(uzbl.state.keycmd, 0); + break; + } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) { + if (key_ret) /* just quit the incremental command on return */ g_string_truncate(uzbl.state.keycmd, 0); + else exec_paramcmd(act, i); /* otherwise execute the incremental */ break; } - + g_string_truncate(short_keys, short_keys->len - 1); } g_string_free (short_keys, TRUE); g_string_free (short_keys_inc, TRUE); } +static void +exec_paramcmd(const Action *act, const guint i) { + GString *parampart = g_string_new (uzbl.state.keycmd->str); + GString *actionname = g_string_new (""); + GString *actionparam = g_string_new (""); + g_string_erase (parampart, 0, i+1); + if (act->name) + g_string_printf (actionname, act->name, parampart->str); + if (act->param) + g_string_printf (actionparam, act->param, parampart->str); + parse_command(actionname->str, actionparam->str); + g_string_free(actionname, TRUE); + g_string_free(actionparam, TRUE); + g_string_free(parampart, TRUE); +} + + static GtkWidget* create_browser () { GUI *g = &uzbl.gui; @@ -1718,26 +2023,105 @@ GtkWidget* create_window () { return window; } +static gchar** +inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) { + /* + If actname is one that calls an external command, this function will inject + newargs in front of the user-provided args in that command line. They will + come become after the body of the script (in sh) or after the name of + the command to execute (in spawn). + i.e. sh becomes sh and + span becomes spawn . + + The return value consist of two strings: the action (sh, ...) and its args. + + If act is not one that calls an external command, then the given action merely + gets duplicated. + */ + GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*)); + gchar *actdup = g_strdup(actname); + g_array_append_val(rets, actdup); + + if ((g_strcmp0(actname, "spawn") == 0) || + (g_strcmp0(actname, "sh") == 0) || + (g_strcmp0(actname, "sync_spawn") == 0) || + (g_strcmp0(actname, "sync_sh") == 0)) { + guint i; + GString *a = g_string_new(""); + gchar **spawnparts = split_quoted(origargs, FALSE); + g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */ + if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */ + + for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */ + if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]); + + g_array_append_val(rets, a->str); + g_string_free(a, FALSE); + g_strfreev(spawnparts); + } else { + gchar *origdup = g_strdup(origargs); + g_array_append_val(rets, origdup); + } + return (gchar**)g_array_free(rets, FALSE); +} + static void run_handler (const gchar *act, const gchar *args) { + /* Consider this code a temporary hack to make the handlers usable. + In practice, all this splicing, injection, and reconstruction is + inefficient, annoying and hard to manage. Potential pitfalls arise + when the handler specific args 1) are not quoted (the handler + callbacks should take care of this) 2) are quoted but interfere + with the users' own quotation. A more ideal solution is + to refactor parse_command so that it doesn't just take a string + and execute it; rather than that, we should have a function which + returns the argument vector parsed from the string. This vector + could be modified (e.g. insert additional args into it) before + passing it to the next function that actually executes it. Though + it still isn't perfect for chain actions.. will reconsider & re- + factor when I have the time. -duc */ + char **parts = g_strsplit(act, " ", 2); if (!parts) return; - else if ((g_strcmp0(parts[0], "spawn") == 0) - || (g_strcmp0(parts[0], "sh") == 0)) { - guint i; - GString *a = g_string_new (""); - char **spawnparts; - spawnparts = split_quoted(parts[1], FALSE); - g_string_append_printf(a, "%s", spawnparts[0]); - if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */ - for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */ - g_string_append_printf(a, " %s", spawnparts[i]); - parse_command(parts[0], a->str); - g_string_free (a, TRUE); - g_strfreev (spawnparts); - } else - parse_command(parts[0], parts[1]); - g_strfreev (parts); + if (g_strcmp0(parts[0], "chain") == 0) { + GString *newargs = g_string_new(""); + gchar **chainparts = split_quoted(parts[1], FALSE); + + /* for every argument in the chain, inject the handler args + and make sure the new parts are wrapped in quotes */ + gchar **cp = chainparts; + gchar quot = '\''; + gchar *quotless = NULL; + gchar **spliced_quotless = NULL; // sigh -_-; + gchar **inpart = NULL; + + while (*cp) { + if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */ + quot = **cp; + quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2); + } else quotless = g_strdup(*cp); + + spliced_quotless = g_strsplit(quotless, " ", 2); + inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args); + g_strfreev(spliced_quotless); + + g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot); + g_free(quotless); + g_strfreev(inpart); + cp++; + } + + parse_command(parts[0], &(newargs->str[1])); + g_string_free(newargs, TRUE); + g_strfreev(chainparts); + + } else { + gchar **inparts = inject_handler_args(parts[0], parts[1], args); + parse_command(inparts[0], inparts[1]); + g_free(inparts[0]); + g_free(inparts[1]); + } + g_strfreev(parts); } static void @@ -1753,10 +2137,7 @@ add_binding (const gchar *key, const gchar *act) { printf ("Binding %-10s : %s\n", key, act); action = new_action(parts[0], parts[1]); - if(g_hash_table_lookup(uzbl.bindings, key)) - g_hash_table_remove(uzbl.bindings, key); - g_hash_table_insert(uzbl.bindings, g_strdup(key), action); - + g_hash_table_replace(uzbl.bindings, g_strdup(key), action); g_strfreev(parts); } @@ -1794,16 +2175,15 @@ find_xdg_file (int xdg_type, char* filename) { if (! file_exists (temporary_file) && xdg_type != 2) { buf = get_xdg_var (XDG[3 + xdg_type]); temporary_string = (char *) strtok_r (buf, ":", &saveptr); - free(buf); + g_free(buf); - while (temporary_string && ! file_exists (temporary_file)) { - strcpy (temporary_file, temporary_string); - strcat (temporary_file, filename); - temporary_string = (char * ) strtok_r (NULL, ":", &saveptr); + while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) { + g_free (temporary_file); + temporary_file = g_strconcat (temporary_string, filename, NULL); } } - g_free (temporary_string); + //g_free (temporary_string); - segfaults. if (file_exists (temporary_file)) { return temporary_file; @@ -1811,12 +2191,14 @@ find_xdg_file (int xdg_type, char* filename) { return NULL; } } - static void settings_init () { State *s = &uzbl.state; Network *n = &uzbl.net; - uzbl.behave.reset_command_mode = 1; + int i; + for (i = 0; default_config[i].command != NULL; i++) { + parse_cmd_line(default_config[i].command); + } if (!s->config_file) { s->config_file = find_xdg_file (0, "/uzbl/config"); @@ -1830,55 +2212,34 @@ settings_init () { while ((line = g_array_index(lines, gchar*, i))) { parse_cmd_line (line); i ++; + g_free (line); } g_array_free (lines, TRUE); } else { if (uzbl.state.verbose) printf ("No configuration file loaded.\n"); } - if (!uzbl.behave.status_format) - set_var_value("status_format", STATUS_DEFAULT); - if (!uzbl.behave.title_format_long) - set_var_value("title_format_long", TITLE_LONG_DEFAULT); - if (!uzbl.behave.title_format_short) - set_var_value("title_format_short", TITLE_SHORT_DEFAULT); - g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL); } -static gchar* -set_useragent(gchar *val) { - if (*val == ' ') { - g_free(val); - return NULL; - } - gchar *ua = expand_template(val); - if (ua) - g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL); - return ua; -} - static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ (void) session; (void) user_data; - if (!uzbl.behave.cookie_handler) return; + if (!uzbl.behave.cookie_handler) + return; - gchar * stdout = NULL; soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - gchar *action = g_strdup ("GET"); + GString *s = g_string_new (""); SoupURI * soup_uri = soup_message_get_uri(msg); - sharg_append(a, action); - sharg_append(a, soup_uri->host); - sharg_append(a, soup_uri->path); - run_command(uzbl.behave.cookie_handler, 0, (const gchar **) a->data, TRUE, &stdout); /* TODO: use handler */ - //run_handler(uzbl.behave.cookie_handler); /* TODO: global stdout pointer, spawn_sync */ - if(stdout) { - soup_message_headers_replace (msg->request_headers, "Cookie", stdout); - } - g_free (action); - g_array_free(a, TRUE); + g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path); + run_handler(uzbl.behave.cookie_handler, s->str); + + if(uzbl.comm.sync_stdout) + soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout); + if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + g_string_free(s, TRUE); } static void @@ -1888,21 +2249,138 @@ save_cookies (SoupMessage *msg, gpointer user_data){ char *cookie; for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ cookie = soup_cookie_to_set_cookie_header(ck->data); - GArray *a = g_array_new(TRUE, FALSE, sizeof(gchar*)); SoupURI * soup_uri = soup_message_get_uri(msg); - gchar *action = strdup("PUT"); - sharg_append(a, action); - sharg_append(a, soup_uri->host); - sharg_append(a, soup_uri->path); - sharg_append(a, cookie); - run_command(uzbl.behave.cookie_handler, 0, (const gchar **) a->data, FALSE, NULL); + GString *s = g_string_new (""); + g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie); + run_handler(uzbl.behave.cookie_handler, s->str); g_free (cookie); - g_free (action); - g_array_free(a, TRUE); + g_string_free(s, TRUE); } g_slist_free(ck); } +/* --- WEBINSPECTOR --- */ +static void +hide_window_cb(GtkWidget *widget, gpointer data) { + (void) data; + + gtk_widget_hide(widget); +} + +static WebKitWebView* +create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){ + (void) data; + (void) page; + (void) web_inspector; + GtkWidget* scrolled_window; + GtkWidget* new_web_view; + GUI *g = &uzbl.gui; + + g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(G_OBJECT(g->inspector_window), "delete-event", + G_CALLBACK(hide_window_cb), NULL); + + gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector"); + gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300); + gtk_widget_show(g->inspector_window); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window); + gtk_widget_show(scrolled_window); + + new_web_view = webkit_web_view_new(); + gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view); + + return WEBKIT_WEB_VIEW(new_web_view); +} + +static gboolean +inspector_show_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + gtk_widget_show(uzbl.gui.inspector_window); + return TRUE; +} + +/* TODO: Add variables and code to make use of these functions */ +static gboolean +inspector_close_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + return TRUE; +} + +static gboolean +inspector_attach_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +static gboolean +inspector_dettach_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +static gboolean +inspector_uri_changed_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +static gboolean +inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +static void +set_up_inspector() { + GUI *g = &uzbl.gui; + WebKitWebSettings *settings = view_settings(); + g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL); + + uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view); + g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL); + + g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL); +} + +static void +dump_var_hash(gpointer k, gpointer v, gpointer ud) { + (void) ud; + uzbl_cmdprop *c = v; + + if(!c->dump) + return; + + if(c->type == TYPE_STR) + printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" "); + else if(c->type == TYPE_INT) + printf("set %s = %d\n", (char *)k, (int)*c->ptr); +} + +static void +dump_key_hash(gpointer k, gpointer v, gpointer ud) { + (void) ud; + Action *a = v; + + printf("bind %s = %s %s\n", (char *)k , + (char *)a->name, a->param?(char *)a->param:""); +} + +static void +dump_config() { + g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL); + g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL); +} + +/** -- MAIN -- **/ int main (int argc, char* argv[]) { gtk_init (&argc, &argv); @@ -1916,6 +2394,7 @@ main (int argc, char* argv[]) { g_option_context_add_main_entries (context, entries, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free(context); /* initialize hash table */ uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); @@ -1926,11 +2405,27 @@ main (int argc, char* argv[]) { fprintf(stderr, "uzbl: error hooking SIGTERM\n"); if(setup_signal(SIGINT, catch_sigint) == SIG_ERR) fprintf(stderr, "uzbl: error hooking SIGINT\n"); + if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR) + fprintf(stderr, "uzbl: error hooking SIGALARM\n"); + if(uname(&uzbl.state.unameinfo) == -1) g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n"); - setup_regex(); + uzbl.gui.sbar.progress_s = g_strdup("="); + uzbl.gui.sbar.progress_u = g_strdup("·"); + uzbl.gui.sbar.progress_w = 10; + + /* HTML mode defaults*/ + uzbl.behave.html_buffer = g_string_new(""); + uzbl.behave.html_endmarker = g_strdup("."); + uzbl.behave.html_timeout = 60; + uzbl.behave.base_url = g_strdup("http://invalid"); + + /* default mode indicators */ + uzbl.behave.insert_indicator = g_strdup("I"); + uzbl.behave.cmd_indicator = g_strdup("C"); + setup_scanner(); commands_hash (); make_var_to_name_hash(); @@ -1947,7 +2442,6 @@ main (int argc, char* argv[]) { uzbl.gui.main_window = create_window (); gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox); - //load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed? gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); gtk_widget_show_all (uzbl.gui.main_window); @@ -1973,6 +2467,9 @@ main (int argc, char* argv[]) { else update_title(); + /* WebInspector */ + set_up_inspector(); + create_stdin(); if(uzbl.state.uri) {