one more fix to expand_vars
[uzbl-mobile] / uzbl.c
diff --git a/uzbl.c b/uzbl.c
index bcbef83..ee5c6bb 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -41,6 +41,7 @@
 #include <sys/types.h>
 #include <sys/un.h>
 #include <sys/utsname.h>
+#include <sys/time.h>
 #include <webkit/webkit.h>
 #include <stdio.h>
 #include <string.h>
 static Uzbl uzbl;
 typedef void (*Command)(WebKitWebView*, GArray *argv);
 
+
+
 /* commandline arguments (set initial values for the state variables) */
-static GOptionEntry entries[] =
+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" },
+    { "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_STR};
 
 /* an abbreviation to help keep the table's width humane */
-#define PTR(var, t, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .func = fun }
+#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          type  callback function    */
+/*    variable name         pointer to variable in code          type  dump callback function    */
 /*  --------------------------------------------------------------------------------------- */
-    { "uri",                 PTR(uzbl.state.uri,                  STR, cmd_load_uri)},
-    { "status_message",      PTR(uzbl.gui.sbar.msg,               STR, update_title)},
-    { "show_status",         PTR(uzbl.behave.show_status,         INT, cmd_set_status)},
-    { "status_top",          PTR(uzbl.behave.status_top,          INT, move_statusbar)},
-    { "status_format",       PTR(uzbl.behave.status_format,       STR, update_title)},
-    { "status_pbar_done",    PTR(uzbl.gui.sbar.progress_s,        STR, update_title)},
-    { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u,        STR, update_title)},
-    { "status_pbar_width",   PTR(uzbl.gui.sbar.progress_w,        INT, update_title)},
-    { "status_background",   PTR(uzbl.behave.status_background,   STR, update_title)},
-    { "title_format_long",   PTR(uzbl.behave.title_format_long,   STR, update_title)},
-    { "title_format_short",  PTR(uzbl.behave.title_format_short,  STR, update_title)},
-    { "insert_mode",         PTR(uzbl.behave.insert_mode,         INT, NULL)},
-    { "always_insert_mode",  PTR(uzbl.behave.always_insert_mode,  INT, cmd_always_insert_mode)},
-    { "reset_command_mode",  PTR(uzbl.behave.reset_command_mode,  INT, NULL)},
-    { "modkey",              PTR(uzbl.behave.modkey,              STR, cmd_modkey)},
-    { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, NULL)},
-    { "load_start_handler",  PTR(uzbl.behave.load_start_handler,  STR, NULL)},
-    { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, NULL)},
-    { "history_handler",     PTR(uzbl.behave.history_handler,     STR, NULL)},
-    { "download_handler",    PTR(uzbl.behave.download_handler,    STR, NULL)},
-    { "cookie_handler",      PTR(uzbl.behave.cookie_handler,      STR, NULL)},
-    { "fifo_dir",            PTR(uzbl.behave.fifo_dir,            STR, cmd_fifo_dir)},
-    { "socket_dir",          PTR(uzbl.behave.socket_dir,          STR, cmd_socket_dir)},
-    { "http_debug",          PTR(uzbl.behave.http_debug,          INT, cmd_http_debug)},
-    { "font_size",           PTR(uzbl.behave.font_size,           INT, cmd_font_size)},
-    { "monospace_size",      PTR(uzbl.behave.monospace_size,      INT, cmd_font_size)},
-    { "minimum_font_size",   PTR(uzbl.behave.minimum_font_size,   INT, cmd_minimum_font_size)},
-    { "disable_plugins",     PTR(uzbl.behave.disable_plugins,     INT, cmd_disable_plugins)},
-    { "shell_cmd",           PTR(uzbl.behave.shell_cmd,           STR, NULL)},
-    { "proxy_url",           PTR(uzbl.net.proxy_url,              STR, set_proxy_url)},
-    { "max_conns",           PTR(uzbl.net.max_conns,              INT, cmd_max_conns)},
-    { "max_conns_host",      PTR(uzbl.net.max_conns_host,         INT, cmd_max_conns_host)},
-    { "useragent",           PTR(uzbl.net.useragent,              STR, cmd_useragent)},
-    { NULL,                  {.ptr = NULL, .type = TYPE_INT, .func = NULL}}
+    { "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 {
@@ -158,8 +186,48 @@ make_var_to_name_hash() {
     }
 }
 
-
 /* --- UTILITY FUNCTIONS --- */
+static gchar *
+expand_vars(char *s) {
+
+    char ret[256],  /* 256 chars per var name should be safe */
+         *vend;
+    uzbl_cmdprop *c;
+    GString *buf = g_string_new("");
+
+    while(*s) {
+        /* found quotation char */
+        if(*s == '\\') {
+            g_string_append_c(buf, *++s);
+            s++;
+        }
+        /* found variable */
+        else if(*s == '@') {
+            s++;
+            if( (vend = strchr(s, ' ')) ||
+                (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);
+                    }
+                }
+                s = vend;
+            }
+        }
+        /* every other char */
+        else {
+            g_string_append_c(buf, *s);
+            s++;
+        }
+    }
+    return g_string_free(buf, FALSE);
+}
 
 char *
 itos(int val) {
@@ -170,6 +238,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 *
@@ -263,6 +334,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 --- */
 
@@ -279,6 +363,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
@@ -336,23 +429,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);
 }
@@ -428,6 +525,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, "");
 }
@@ -443,7 +541,6 @@ load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
         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);
 }
@@ -500,12 +597,21 @@ 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}              }
+    { "runcmd",             {runcmd, NOSPLIT}              },
+    { "set",                {set_var, 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
@@ -548,6 +654,21 @@ file_exists (const char * filename) {
 }
 
 static void
+set_var(WebKitWebView *page, GArray *argv) {
+    (void) page;
+    gchar *ctl_line;
+
+    ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
+    parse_cmd_line(ctl_line);
+    g_free(ctl_line);
+}
+
+static void
+act_dump_config() {
+    dump_config();
+}
+
+static void
 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
     (void)page;
 
@@ -644,6 +765,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);
@@ -663,6 +791,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;
@@ -822,7 +989,8 @@ expand_template(const char *template, gboolean escape_markup) {
                      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,
@@ -923,10 +1091,13 @@ run_command (const gchar *command, const guint npre, const gchar **args,
         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:");
@@ -995,6 +1166,15 @@ spawn(WebKitWebView *web_view, GArray *argv) {
 }
 
 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
 spawn_sh(WebKitWebView *web_view, GArray *argv) {
     (void)web_view;
     if (!uzbl.behave.shell_cmd) {
@@ -1016,6 +1196,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;
 
@@ -1050,8 +1252,6 @@ setup_regex() {
             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
@@ -1125,9 +1325,14 @@ 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 = webkit_web_view_get_settings(uzbl.gui.web_view);
+    WebKitWebSettings *ws = view_settings();
     if (uzbl.behave.font_size > 0) {
         g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
     }
@@ -1143,14 +1348,93 @@ cmd_font_size() {
 
 static void
 cmd_disable_plugins() {
-    WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
-    g_object_set (G_OBJECT(ws), "enable-plugins", !uzbl.behave.disable_plugins, NULL);
+    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_autoshrink_img() {
+    g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
+            uzbl.behave.autoshrink_img, NULL);
+}
+
+
+static void
+cmd_enable_spellcheck() {
+    g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
+            uzbl.behave.enable_spellcheck, NULL);
+}
+
+static void
+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);
+}
+
+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);
+}
+
+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);
+    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
@@ -1164,6 +1448,14 @@ cmd_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
 cmd_modkey() {
     int i;
     char *buf;
@@ -1220,15 +1512,19 @@ static gboolean
 set_var_value(gchar *name, gchar *val) {
     uzbl_cmdprop *c = NULL;
     char *endp = NULL;
+    char *buf = NULL;
 
     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
         /* check for the variable type */
         if (c->type == TYPE_STR) {
+            buf = expand_vars(val);
             g_free(*c->ptr);
-            *c->ptr = g_strdup(val);
+            *c->ptr = buf;
         } else if(c->type == TYPE_INT) {
-            int *ip = GPOINTER_TO_INT(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 */
@@ -1244,72 +1540,91 @@ runcmd(WebKitWebView* page, GArray *argv) {
 }
 
 static void
+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 = NULL;
-
-    /* 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(g_strdup(tokens[2]));
-            set_var_value(tokens[1], value);
-            g_free(value);
+    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]);
-    }
-    /* 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]);
+        else {
+            set_timeout(b->html_timeout);
+            g_string_append(b->html_buffer, ctl_line);
         }
-        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(g_strdup(tokens[2]));
-            add_binding(tokens[1], value);
-            g_free(value);
+    else {
+        /* 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(g_strdup(tokens[2]));
+                set_var_value(tokens[1], value);
+                g_free(value);
+            }
+            else
+                printf("Error in command: %s\n", tokens[0]);
         }
-        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]);
+        /* 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]);
+            }
+            else
+                printf("Error in command: %s\n", tokens[0]);
         }
-        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();
+        /* 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(g_strdup(tokens[2]));
+                add_binding(tokens[1], value);
+                g_free(value);
+            }
+            else
+                printf("Error in command: %s\n", tokens[0]);
         }
-    }
-    /* Comments */
-    else if(   (ctl_line[0] == '#')
-            || (ctl_line[0] == ' ')
-            || (ctl_line[0] == '\n'))
-        ; /* ignore these lines */
-    else
-        printf("Command not understood (%s)\n", ctl_line);
+        /* 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]);
+            }
+            else
+                printf("Error in command: %s\n", tokens[0]);
+        }
+        /* Comments */
+        else if(   (ctl_line[0] == '#')
+                || (ctl_line[0] == ' ')
+                || (ctl_line[0] == '\n'))
+            ; /* ignore these lines */
+        else
+            printf("Command not understood (%s)\n", ctl_line);
 
-    if(tokens)
-        g_strfreev(tokens);
+        if(tokens)
+            g_strfreev(tokens);
+    }
 
     return;
 }
@@ -1593,6 +1908,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;
     }
 
@@ -1612,10 +1928,8 @@ key_press_cb (GtkWidget* window, GdkEventKey* event)
         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))
@@ -1631,57 +1945,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;
@@ -1741,13 +2056,16 @@ run_handler (const gchar *act, const gchar *args) {
     char **parts = g_strsplit(act, " ", 2);
     if (!parts) return;
     else if ((g_strcmp0(parts[0], "spawn") == 0)
-             || (g_strcmp0(parts[0], "sh") == 0)) {
+             || (g_strcmp0(parts[0], "sh") == 0)
+             || (g_strcmp0(parts[0], "sync_spawn") == 0)
+             || (g_strcmp0(parts[0], "sync_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);
@@ -1862,21 +2180,18 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use
     (void) user_data;
     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);
+    //printf("stdout: %s\n", uzbl.comm.sync_stdout);   // debugging
+    if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+        
+    g_string_free(s, TRUE);
 }
 
 static void
@@ -1886,21 +2201,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);
@@ -1925,6 +2357,9 @@ 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");
@@ -1933,6 +2368,16 @@ main (int argc, char* argv[]) {
     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_regex();
     setup_scanner();
     commands_hash ();
@@ -1975,6 +2420,9 @@ main (int argc, char* argv[]) {
     else
         update_title();
 
+    /* WebInspector */
+    set_up_inspector();
+
     create_stdin();
 
     if(uzbl.state.uri) {