Merge commit 'dieterbe/experimental'
[uzbl-mobile] / uzbl.c
1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3.  See LICENSE file.
4
5
6 /*
7  * Copyright (C) 2006, 2007 Apple Inc.
8  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
35
36 #include <gtk/gtk.h>
37 #include <gdk/gdkx.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/un.h>
43 #include <sys/utsname.h>
44 #include <sys/time.h>
45 #include <webkit/webkit.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <fcntl.h>
53 #include <sys/socket.h>
54 #include <sys/un.h>
55 #include <libsoup/soup.h>
56 #include <signal.h>
57 #include "uzbl.h"
58 #include "config.h"
59
60 static Uzbl uzbl;
61 typedef void (*Command)(WebKitWebView*, GArray *argv);
62
63
64
65 /* commandline arguments (set initial values for the state variables) */
66 static const 
67 GOptionEntry entries[] =
68 {
69     { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
70         "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
71     { "verbose", 'v', 0, G_OPTION_ARG_NONE,   &uzbl.state.verbose,
72         "Whether to print all messages or just errors.", NULL },
73     { "name",    'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, 
74         "Name of the current instance (defaults to Xorg window id)", "NAME" },
75     { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   
76         "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
77     { NULL,      0, 0, 0, NULL, NULL, NULL }
78 };
79
80 /* associate command names to their properties */
81 typedef const struct {
82     void **ptr;
83     int type;
84     int dump;
85     void (*func)(void);
86 } uzbl_cmdprop;
87
88 enum {TYPE_INT, TYPE_STR};
89
90 /* an abbreviation to help keep the table's width humane */
91 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
92
93 const struct {
94     char *name;
95     uzbl_cmdprop cp;
96 } var_name_to_ptr[] = {
97 /*    variable name         pointer to variable in code          type  dump callback function    */
98 /*  --------------------------------------------------------------------------------------- */
99     { "uri",                 PTR(uzbl.state.uri,                  STR,  1,   cmd_load_uri)},
100 <<<<<<< HEAD:uzbl.c
101 =======
102     { "verbose",             PTR(uzbl.state.verbose,              INT,  1,   NULL)},
103 >>>>>>> dieterbe/experimental:uzbl.c
104     { "mode",                PTR(uzbl.behave.mode,                INT,  0,   NULL)},
105     { "inject_html",         PTR(uzbl.behave.inject_html,         STR,  0,   cmd_inject_html)},
106     { "base_url",            PTR(uzbl.behave.base_url,            STR,  1,   NULL)},
107     { "html_endmarker",      PTR(uzbl.behave.html_endmarker,      STR,  1,   NULL)},
108     { "html_mode_timeout",   PTR(uzbl.behave.html_timeout,        INT,  1,   NULL)},
109     { "status_message",      PTR(uzbl.gui.sbar.msg,               STR,  1,   update_title)},
110     { "show_status",         PTR(uzbl.behave.show_status,         INT,  1,   cmd_set_status)},
111     { "status_top",          PTR(uzbl.behave.status_top,          INT,  1,   move_statusbar)},
112     { "status_format",       PTR(uzbl.behave.status_format,       STR,  1,   update_title)},
113     { "status_pbar_done",    PTR(uzbl.gui.sbar.progress_s,        STR,  1,   update_title)},
114     { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u,        STR,  1,   update_title)},
115     { "status_pbar_width",   PTR(uzbl.gui.sbar.progress_w,        INT,  1,   update_title)},
116     { "status_background",   PTR(uzbl.behave.status_background,   STR,  1,   update_title)},
117     { "insert_indicator",    PTR(uzbl.behave.insert_indicator,    STR,  1,   update_title)},
118     { "command_indicator",   PTR(uzbl.behave.cmd_indicator,       STR,  1,   update_title)},
119     { "title_format_long",   PTR(uzbl.behave.title_format_long,   STR,  1,   update_title)},
120     { "title_format_short",  PTR(uzbl.behave.title_format_short,  STR,  1,   update_title)},
121     { "insert_mode",         PTR(uzbl.behave.insert_mode,         INT,  1,   NULL)},
122     { "always_insert_mode",  PTR(uzbl.behave.always_insert_mode,  INT,  1,   cmd_always_insert_mode)},
123     { "reset_command_mode",  PTR(uzbl.behave.reset_command_mode,  INT,  1,   NULL)},
124     { "modkey",              PTR(uzbl.behave.modkey,              STR,  1,   cmd_modkey)},
125     { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR,  1,   NULL)},
126     { "load_start_handler",  PTR(uzbl.behave.load_start_handler,  STR,  1,   NULL)},
127     { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR,  1,   NULL)},
128     { "history_handler",     PTR(uzbl.behave.history_handler,     STR,  1,   NULL)},
129     { "download_handler",    PTR(uzbl.behave.download_handler,    STR,  1,   NULL)},
130     { "cookie_handler",      PTR(uzbl.behave.cookie_handler,      STR,  1,   cmd_cookie_handler)},
131     { "fifo_dir",            PTR(uzbl.behave.fifo_dir,            STR,  1,   cmd_fifo_dir)},
132     { "socket_dir",          PTR(uzbl.behave.socket_dir,          STR,  1,   cmd_socket_dir)},
133     { "http_debug",          PTR(uzbl.behave.http_debug,          INT,  1,   cmd_http_debug)},
134     { "shell_cmd",           PTR(uzbl.behave.shell_cmd,           STR,  1,   NULL)},
135     { "proxy_url",           PTR(uzbl.net.proxy_url,              STR,  1,   set_proxy_url)},
136     { "max_conns",           PTR(uzbl.net.max_conns,              INT,  1,   cmd_max_conns)},
137     { "max_conns_host",      PTR(uzbl.net.max_conns_host,         INT,  1,   cmd_max_conns_host)},
138     { "useragent",           PTR(uzbl.net.useragent,              STR,  1,   cmd_useragent)},
139     /* exported WebKitWebSettings properties*/
140     { "font_size",           PTR(uzbl.behave.font_size,           INT,  1,   cmd_font_size)},
141     { "monospace_size",      PTR(uzbl.behave.monospace_size,      INT,  1,   cmd_font_size)},
142     { "minimum_font_size",   PTR(uzbl.behave.minimum_font_size,   INT,  1,   cmd_minimum_font_size)},
143     { "disable_plugins",     PTR(uzbl.behave.disable_plugins,     INT,  1,   cmd_disable_plugins)},
144     { "disable_scripts",     PTR(uzbl.behave.disable_scripts,     INT,  1,   cmd_disable_scripts)},
145     { "autoload_images",     PTR(uzbl.behave.autoload_img,        INT,  1,   cmd_autoload_img)},
146     { "autoshrink_images",   PTR(uzbl.behave.autoshrink_img,      INT,  1,   cmd_autoshrink_img)},
147     { "enable_spellcheck",   PTR(uzbl.behave.enable_spellcheck,   INT,  1,   cmd_enable_spellcheck)},
148     { "enable_private",      PTR(uzbl.behave.enable_private,      INT,  1,   cmd_enable_private)},
149     { "print_backgrounds",   PTR(uzbl.behave.print_bg,            INT,  1,   cmd_print_bg)},
150     { "stylesheet_uri",      PTR(uzbl.behave.style_uri,           STR,  1,   cmd_style_uri)},
151     { "resizable_text_areas",PTR(uzbl.behave.resizable_txt,       INT,  1,   cmd_resizable_txt)},
152     { "default_encoding",    PTR(uzbl.behave.default_encoding,    STR,  1,   cmd_default_encoding)},
153     { "enforce_96_dpi",      PTR(uzbl.behave.enforce_96dpi,       INT,  1,   cmd_enforce_96dpi)},
154     { "caret_browsing",      PTR(uzbl.behave.caret_browsing,      INT,  1,   cmd_caret_browsing)},
155
156     { NULL,                  {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
157 }, *n2v_p = var_name_to_ptr;
158
159 const struct {
160     char *key;
161     guint mask;
162 } modkeys[] = {
163     { "SHIFT",   GDK_SHIFT_MASK   }, // shift
164     { "LOCK",    GDK_LOCK_MASK    }, // capslock or shiftlock, depending on xserver's modmappings
165     { "CONTROL", GDK_CONTROL_MASK }, // control
166     { "MOD1",    GDK_MOD1_MASK    }, // 4th mod - normally alt but depends on modmappings
167     { "MOD2",    GDK_MOD2_MASK    }, // 5th mod
168     { "MOD3",    GDK_MOD3_MASK    }, // 6th mod
169     { "MOD4",    GDK_MOD4_MASK    }, // 7th mod
170     { "MOD5",    GDK_MOD5_MASK    }, // 8th mod
171     { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
172     { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
173     { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
174     { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
175     { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
176     { "SUPER",   GDK_SUPER_MASK   }, // super (since 2.10)
177     { "HYPER",   GDK_HYPER_MASK   }, // hyper (since 2.10)
178     { "META",    GDK_META_MASK    }, // meta (since 2.10)
179     { NULL,      0                }
180 };
181
182
183 /* construct a hash from the var_name_to_ptr array for quick access */
184 static void
185 make_var_to_name_hash() {
186     uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
187     while(n2v_p->name) {
188         g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
189         n2v_p++;
190     }
191 }
192
193 /* --- UTILITY FUNCTIONS --- */
194 static gchar *
195 expand_vars(char *s) {
196     uzbl_cmdprop *c;
197     char upto = ' ';
198     char ret[256],  *vend;
199     GString *buf = g_string_new("");
200
201     while(*s) {
202         switch(*s) {
203             case '\\':
204                 g_string_append_c(buf, *++s);
205                 s++;
206                 break;
207             case '@':
208                 if(*(s+1) == '{') {
209                     upto = '}'; s++;
210                 }
211                 s++;
212                 if( (vend = strchr(s, upto)) ||
213                         (vend = strchr(s, '\0')) ) {
214                     strncpy(ret, s, vend-s);
215                     ret[vend-s] = '\0';
216                     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
217                         if(c->type == TYPE_STR)
218                             g_string_append(buf, (gchar *)*c->ptr);
219                         else if(c->type == TYPE_INT) {
220                             char *b = itos((int)*c->ptr);
221                             g_string_append(buf, b);
222                             g_free(b);
223                         }
224                     }
225                     if(upto == ' ') s = vend;
226                     else s = vend+1;
227                     upto = ' ';
228                 }
229                 break;
230             default:
231                 g_string_append_c(buf, *s);
232                 s++;
233                 break;
234         }
235     }
236     return g_string_free(buf, FALSE);
237 }
238
239 char *
240 itos(int val) {
241     char tmp[20];
242
243     snprintf(tmp, sizeof(tmp), "%i", val);
244     return g_strdup(tmp);
245 }
246
247 static gchar*
248 strfree(gchar *str) { g_free(str); return NULL; }  // for freeing & setting to null in one go
249
250 static gchar*
251 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
252
253 static char *
254 str_replace (const char* search, const char* replace, const char* string) {
255     gchar **buf;
256     char *ret;
257
258     buf = g_strsplit (string, search, -1);
259     ret = g_strjoinv (replace, buf);
260     g_strfreev(buf); // somebody said this segfaults
261
262     return ret;
263 }
264
265 static GArray*
266 read_file_by_line (gchar *path) {
267     GIOChannel *chan = NULL;
268     gchar *readbuf = NULL;
269     gsize len;
270     GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
271     int i = 0;
272     
273     chan = g_io_channel_new_file(path, "r", NULL);
274     
275     if (chan) {
276         while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
277             const gchar* val = g_strdup (readbuf);
278             g_array_append_val (lines, val);
279             g_free (readbuf);
280             i ++;
281         }
282         
283         g_io_channel_unref (chan);
284     } else {
285         fprintf(stderr, "File '%s' not be read.\n", path);
286     }
287     
288     return lines;
289 }
290
291 static
292 gchar* parseenv (char* string) {
293     extern char** environ;
294     gchar* tmpstr = NULL;
295     int i = 0;
296     
297
298     while (environ[i] != NULL) {
299         gchar** env = g_strsplit (environ[i], "=", 2);
300         gchar* envname = g_strconcat ("$", env[0], NULL);
301
302         if (g_strrstr (string, envname) != NULL) {
303             tmpstr = g_strdup(string);
304             g_free (string);
305             string = str_replace(envname, env[1], tmpstr);
306             g_free (tmpstr);
307         }
308
309         g_free (envname);
310         g_strfreev (env); // somebody said this breaks uzbl
311         i++;
312     }
313
314     return string;
315 }
316
317 static sigfunc*
318 setup_signal(int signr, sigfunc *shandler) {
319     struct sigaction nh, oh;
320
321     nh.sa_handler = shandler;
322     sigemptyset(&nh.sa_mask);
323     nh.sa_flags = 0;
324
325     if(sigaction(signr, &nh, &oh) < 0)
326         return SIG_ERR;
327
328     return NULL;
329 }
330
331 static void
332 clean_up(void) {
333     if (uzbl.behave.fifo_dir)
334         unlink (uzbl.comm.fifo_path);
335     if (uzbl.behave.socket_dir)
336         unlink (uzbl.comm.socket_path);
337
338     g_free(uzbl.state.executable_path);
339     g_string_free(uzbl.state.keycmd, TRUE);
340     g_hash_table_destroy(uzbl.bindings);
341     g_hash_table_destroy(uzbl.behave.commands);
342 }
343
344 /* used for html_mode_timeout 
345  * be sure to extend this function to use
346  * more timers if needed in other places
347 */
348 static void
349 set_timeout(int seconds) {
350     struct itimerval t;
351     memset(&t, 0, sizeof t);
352
353     t.it_value.tv_sec =  seconds;
354     t.it_value.tv_usec = 0;
355     setitimer(ITIMER_REAL, &t, NULL);
356 }
357
358 /* --- SIGNAL HANDLER --- */
359
360 static void
361 catch_sigterm(int s) {
362     (void) s;
363     clean_up();
364 }
365
366 static void
367 catch_sigint(int s) {
368     (void) s;
369     clean_up();
370     exit(EXIT_SUCCESS);
371 }
372
373 static void
374 catch_alrm(int s) {
375     (void) s;
376
377     set_var_value("mode", "0");
378     render_html();
379 }
380
381
382 /* --- CALLBACKS --- */
383
384 static gboolean
385 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
386     (void) web_view;
387     (void) frame;
388     (void) navigation_action;
389     (void) policy_decision;
390     (void) user_data;
391     const gchar* uri = webkit_network_request_get_uri (request);
392     if (uzbl.state.verbose)
393         printf("New window requested -> %s \n", uri);
394     new_window_load_uri(uri);
395     return (FALSE);
396 }
397
398 WebKitWebView*
399 create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer user_data) {
400     (void) web_view;
401     (void) frame;
402     (void) user_data;
403     if (uzbl.state.selected_url != NULL) {
404         if (uzbl.state.verbose)
405             printf("\nNew web view -> %s\n",uzbl.state.selected_url);
406         new_window_load_uri(uzbl.state.selected_url);
407     } else {
408         if (uzbl.state.verbose)
409             printf("New web view -> %s\n","Nothing to open, exiting");
410     }
411     return (NULL);
412 }
413
414 static gboolean
415 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
416     (void) web_view;
417     (void) user_data;
418     if (uzbl.behave.download_handler) {
419         const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
420         if (uzbl.state.verbose)
421             printf("Download -> %s\n",uri);
422         /* if urls not escaped, we may have to escape and quote uri before this call */
423         run_handler(uzbl.behave.download_handler, uri);
424     }
425     return (FALSE);
426 }
427
428 /* scroll a bar in a given direction */
429 static void
430 scroll (GtkAdjustment* bar, GArray *argv) {
431     gdouble amount;
432     gchar *end;
433
434     amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
435     if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
436     gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
437 }
438
439 static void
440 scroll_begin(WebKitWebView* page, GArray *argv) {
441     (void) page; (void) argv;
442     gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
443 }
444
445 static void
446 scroll_end(WebKitWebView* page, GArray *argv) {
447     (void) page; (void) argv;
448     gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
449                               gtk_adjustment_get_page_size(uzbl.gui.bar_v));
450 }
451
452 static void
453 scroll_vert(WebKitWebView* page, GArray *argv) {
454     (void) page;
455     scroll(uzbl.gui.bar_v, argv);
456 }
457
458 static void
459 scroll_horz(WebKitWebView* page, GArray *argv) {
460     (void) page;
461     scroll(uzbl.gui.bar_h, argv);
462 }
463
464 static void
465 cmd_set_status() {
466     if (!uzbl.behave.show_status) {
467         gtk_widget_hide(uzbl.gui.mainbar);
468     } else {
469         gtk_widget_show(uzbl.gui.mainbar);
470     }
471     update_title();
472 }
473
474 static void
475 toggle_status_cb (WebKitWebView* page, GArray *argv) {
476     (void)page;
477     (void)argv;
478
479     if (uzbl.behave.show_status) {
480         gtk_widget_hide(uzbl.gui.mainbar);
481     } else {
482         gtk_widget_show(uzbl.gui.mainbar);
483     }
484     uzbl.behave.show_status = !uzbl.behave.show_status;
485     update_title();
486 }
487
488 static void
489 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
490     (void) page;
491     (void) title;
492     (void) data;
493     //Set selected_url state variable
494     g_free(uzbl.state.selected_url);
495     uzbl.state.selected_url = NULL;
496     if (link) {
497         uzbl.state.selected_url = g_strdup(link);
498     }
499     update_title();
500 }
501
502 static void
503 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
504     (void) web_view;
505     (void) web_frame;
506     (void) data;
507     if (uzbl.gui.main_title)
508         g_free (uzbl.gui.main_title);
509     uzbl.gui.main_title = g_strdup (title);
510     update_title();
511 }
512
513 static void
514 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
515     (void) page;
516     (void) data;
517     uzbl.gui.sbar.load_progress = progress;
518     update_title();
519 }
520
521 static void
522 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
523     (void) page;
524     (void) frame;
525     (void) data;
526     if (uzbl.behave.load_finish_handler)
527         run_handler(uzbl.behave.load_finish_handler, "");
528 }
529
530 static void
531 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
532     (void) page;
533     (void) frame;
534     (void) data;
535     g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
536     if (uzbl.behave.load_start_handler)
537         run_handler(uzbl.behave.load_start_handler, "");
538 }
539
540 static void
541 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
542     (void) page;
543     (void) data;
544     g_free (uzbl.state.uri);
545     GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
546     uzbl.state.uri = g_string_free (newuri, FALSE);
547     if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
548         uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
549         update_title();
550     }
551     if (uzbl.behave.load_commit_handler)
552         run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
553 }
554
555 static void
556 destroy_cb (GtkWidget* widget, gpointer data) {
557     (void) widget;
558     (void) data;
559     gtk_main_quit ();
560 }
561
562 static void
563 log_history_cb () {
564    if (uzbl.behave.history_handler) {
565        time_t rawtime;
566        struct tm * timeinfo;
567        char date [80];
568        time ( &rawtime );
569        timeinfo = localtime ( &rawtime );
570        strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
571        run_handler(uzbl.behave.history_handler, date);
572    }
573 }
574
575
576 /* VIEW funcs (little webkit wrappers) */
577 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
578 VIEWFUNC(reload)
579 VIEWFUNC(reload_bypass_cache)
580 VIEWFUNC(stop_loading)
581 VIEWFUNC(zoom_in)
582 VIEWFUNC(zoom_out)
583 VIEWFUNC(go_back)
584 VIEWFUNC(go_forward)
585 #undef VIEWFUNC
586
587 /* -- command to callback/function map for things we cannot attach to any signals */
588 // TODO: reload
589 static struct {char *name; Command command[2];} cmdlist[] =
590 {   /* key                   function      no_split      */
591     { "back",               {view_go_back, 0}              },
592     { "forward",            {view_go_forward, 0}           },
593     { "scroll_vert",        {scroll_vert, 0}               },
594     { "scroll_horz",        {scroll_horz, 0}               },
595     { "scroll_begin",       {scroll_begin, 0}              },
596     { "scroll_end",         {scroll_end, 0}                },
597     { "reload",             {view_reload, 0},              },
598     { "reload_ign_cache",   {view_reload_bypass_cache, 0}  },
599     { "stop",               {view_stop_loading, 0},        },
600     { "zoom_in",            {view_zoom_in, 0},             }, //Can crash (when max zoom reached?).
601     { "zoom_out",           {view_zoom_out, 0},            },
602     { "uri",                {load_uri, NOSPLIT}            },
603     { "js",                 {run_js, NOSPLIT}              },
604     { "script",             {run_external_js, 0}           },
605     { "toggle_status",      {toggle_status_cb, 0}          },
606     { "spawn",              {spawn, 0}                     },
607     { "sync_spawn",         {spawn_sync, 0}                }, // needed for cookie handler
608     { "sh",                 {spawn_sh, 0}                  },
609     { "sync_sh",            {spawn_sh_sync, 0}             }, // needed for cookie handler
610     { "exit",               {close_uzbl, 0}                },
611     { "search",             {search_forward_text, NOSPLIT} },
612     { "search_reverse",     {search_reverse_text, NOSPLIT} },
613     { "dehilight",          {dehilight, 0}                 },
614     { "toggle_insert_mode", {toggle_insert_mode, 0}        },
615 <<<<<<< HEAD:uzbl.c
616     { "runcmd",             {runcmd, NOSPLIT}              },
617     { "set",                {set_var, NOSPLIT}             },
618     { "dump_config",        {act_dump_config, 0}           }
619 =======
620     { "set",                {set_var, NOSPLIT}             },
621     //{ "get",                {get_var, NOSPLIT}             },
622     { "bind",               {act_bind, NOSPLIT}            },
623     { "dump_config",        {act_dump_config, 0}           },
624     { "keycmd",             {keycmd, NOSPLIT}              },
625     { "keycmd_nl",          {keycmd_nl, NOSPLIT}           },
626     { "keycmd_bs",          {keycmd_bs, 0}                 },
627     { "chain",              {chain, 0}                     },
628     { "print",              {print, NOSPLIT}               }
629 >>>>>>> dieterbe/experimental:uzbl.c
630 };
631
632 static void
633 commands_hash(void)
634 {
635     unsigned int i;
636     uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
637
638     for (i = 0; i < LENGTH(cmdlist); i++)
639         g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
640 }
641
642 /* -- CORE FUNCTIONS -- */
643
644 void
645 free_action(gpointer act) {
646     Action *action = (Action*)act;
647     g_free(action->name);
648     if (action->param)
649         g_free(action->param);
650     g_free(action);
651 }
652
653 Action*
654 new_action(const gchar *name, const gchar *param) {
655     Action *action = g_new(Action, 1);
656
657     action->name = g_strdup(name);
658     if (param)
659         action->param = g_strdup(param);
660     else
661         action->param = NULL;
662
663     return action;
664 }
665
666 static bool
667 file_exists (const char * filename) {
668     return (access(filename, F_OK) == 0);
669 }
670
671 static void
672 set_var(WebKitWebView *page, GArray *argv) {
673     (void) page;
674     gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
675     gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
676     set_var_value(g_strstrip(split[0]), value);
677     g_free(value);
678     g_strfreev(split);
679 }
680
681 static void
682 print(WebKitWebView *page, GArray *argv) {
683     (void) page;
684     gchar* buf;
685
686     buf = expand_vars(argv_idx(argv, 0));
687     puts(buf);
688     g_free(buf);
689 }
690
691 static void
692 act_bind(WebKitWebView *page, GArray *argv) {
693     (void) page;
694     gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
695     gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
696     add_binding(g_strstrip(split[0]), value);
697     g_free(value);
698     g_strfreev(split);
699 }
700
701
702 static void
703 act_dump_config() {
704     dump_config();
705 }
706
707 static void
708 act_dump_config() {
709     dump_config();
710 }
711
712 static void
713 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
714     (void)page;
715
716     if (argv_idx(argv, 0)) {
717         if (strcmp (argv_idx(argv, 0), "0") == 0) {
718             uzbl.behave.insert_mode = FALSE;
719         } else {
720             uzbl.behave.insert_mode = TRUE;
721         }
722     } else {
723         uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
724     }
725
726     update_title();
727 }
728
729 static void
730 load_uri (WebKitWebView *web_view, GArray *argv) {
731     if (argv_idx(argv, 0)) {
732         GString* newuri = g_string_new (argv_idx(argv, 0));
733         if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
734             g_string_prepend (newuri, "http://");
735         /* if we do handle cookies, ask our handler for them */
736         webkit_web_view_load_uri (web_view, newuri->str);
737         g_string_free (newuri, TRUE);
738     }
739 }
740
741 static void
742 run_js (WebKitWebView * web_view, GArray *argv) {
743     if (argv_idx(argv, 0))
744         webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
745 }
746
747 static void
748 run_external_js (WebKitWebView * web_view, GArray *argv) {
749     if (argv_idx(argv, 0)) {
750         GArray* lines = read_file_by_line (argv_idx (argv, 0));
751         gchar*  js = NULL;
752         int i = 0;
753         gchar* line;
754
755         while ((line = g_array_index(lines, gchar*, i))) {
756             if (js == NULL) {
757                 js = g_strdup (line);
758             } else {
759                 gchar* newjs = g_strconcat (js, line, NULL);
760                 js = newjs;
761             }
762             i ++;
763             g_free (line);
764         }
765         
766         if (uzbl.state.verbose)
767             printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
768
769         if (argv_idx (argv, 1)) {
770             gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
771             g_free (js);
772             js = newjs;
773         }
774         webkit_web_view_execute_script (web_view, js);
775         g_free (js);
776         g_array_free (lines, TRUE);
777     }
778 }
779
780 static void
781 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
782     if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
783         if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
784             webkit_web_view_unmark_text_matches (page);
785             webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
786             uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
787         }
788     }
789     
790     if (uzbl.state.searchtx) {
791         if (uzbl.state.verbose)
792             printf ("Searching: %s\n", uzbl.state.searchtx);
793         webkit_web_view_set_highlight_text_matches (page, TRUE);
794         webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
795     }
796 }
797
798 static void
799 search_forward_text (WebKitWebView *page, GArray *argv) {
800     search_text(page, argv, TRUE);
801 }
802
803 static void
804 search_reverse_text (WebKitWebView *page, GArray *argv) {
805     search_text(page, argv, FALSE);
806 }
807
808 static void
809 dehilight (WebKitWebView *page, GArray *argv) {
810     (void) argv;
811     webkit_web_view_set_highlight_text_matches (page, FALSE);
812 }
813
814
815 static void
816 new_window_load_uri (const gchar * uri) {
817     GString* to_execute = g_string_new ("");
818     g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
819     int i;
820     for (i = 0; entries[i].long_name != NULL; i++) {
821         if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
822             gchar** str = (gchar**)entries[i].arg_data;
823             if (*str!=NULL) {
824                 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
825             }
826         }
827     }
828     if (uzbl.state.verbose)
829         printf("\n%s\n", to_execute->str);
830     g_spawn_command_line_async (to_execute->str, NULL);
831     g_string_free (to_execute, TRUE);
832 }
833
834 static void
835 chain (WebKitWebView *page, GArray *argv) {
836     (void)page;
837     gchar *a = NULL;
838     gchar **parts = NULL;
839     guint i = 0;    
840     while ((a = argv_idx(argv, i++))) {
841         parts = g_strsplit (a, " ", 2);
842         parse_command(parts[0], parts[1]);
843         g_strfreev (parts);
844     }
845 }
846
847 static void
848 keycmd (WebKitWebView *page, GArray *argv) {
849     (void)page;
850     (void)argv;
851     g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
852     run_keycmd(FALSE);
853     update_title();
854 }
855
856 static void
857 keycmd_nl (WebKitWebView *page, GArray *argv) {
858     (void)page;
859     (void)argv;
860     g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
861     run_keycmd(TRUE);
862     update_title();
863 }
864
865 static void
866 keycmd_bs (WebKitWebView *page, GArray *argv) {
867     (void)page;
868     (void)argv;
869     g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
870     update_title();
871 }
872
873 static void
874 close_uzbl (WebKitWebView *page, GArray *argv) {
875     (void)page;
876     (void)argv;
877     gtk_main_quit ();
878 }
879
880 /* --Statusbar functions-- */
881 static char*
882 build_progressbar_ascii(int percent) {
883    int width=uzbl.gui.sbar.progress_w;
884    int i;
885    double l;
886    GString *bar = g_string_new("");
887
888    l = (double)percent*((double)width/100.);
889    l = (int)(l+.5)>=(int)l ? l+.5 : l;
890
891    for(i=0; i<(int)l; i++)
892        g_string_append(bar, uzbl.gui.sbar.progress_s);
893
894    for(; i<width; i++)
895        g_string_append(bar, uzbl.gui.sbar.progress_u);
896
897    return g_string_free(bar, FALSE);
898 }
899
900 static void
901 setup_scanner() {
902      const GScannerConfig scan_config = {
903              (
904               "\t\r\n"
905              )            /* cset_skip_characters */,
906              (
907               G_CSET_a_2_z
908               "_#"
909               G_CSET_A_2_Z
910              )            /* cset_identifier_first */,
911              (
912               G_CSET_a_2_z
913               "_0123456789"
914               G_CSET_A_2_Z
915               G_CSET_LATINS
916               G_CSET_LATINC
917              )            /* cset_identifier_nth */,
918              ( "" )    /* cpair_comment_single */,
919
920              TRUE         /* case_sensitive */,
921
922              FALSE        /* skip_comment_multi */,
923              FALSE        /* skip_comment_single */,
924              FALSE        /* scan_comment_multi */,
925              TRUE         /* scan_identifier */,
926              TRUE         /* scan_identifier_1char */,
927              FALSE        /* scan_identifier_NULL */,
928              TRUE         /* scan_symbols */,
929              FALSE        /* scan_binary */,
930              FALSE        /* scan_octal */,
931              FALSE        /* scan_float */,
932              FALSE        /* scan_hex */,
933              FALSE        /* scan_hex_dollar */,
934              FALSE        /* scan_string_sq */,
935              FALSE        /* scan_string_dq */,
936              TRUE         /* numbers_2_int */,
937              FALSE        /* int_2_float */,
938              FALSE        /* identifier_2_string */,
939              FALSE        /* char_2_token */,
940              FALSE        /* symbol_2_token */,
941              TRUE         /* scope_0_fallback */,
942              FALSE,
943              TRUE
944      };
945
946      uzbl.scan = g_scanner_new(&scan_config);
947      while(symp->symbol_name) {
948          g_scanner_scope_add_symbol(uzbl.scan, 0,
949                          symp->symbol_name,
950                          GINT_TO_POINTER(symp->symbol_token));
951          symp++;
952      }
953 }
954
955 static gchar *
956 expand_template(const char *template, gboolean escape_markup) {
957      if(!template) return NULL;
958
959      GTokenType token = G_TOKEN_NONE;
960      GString *ret = g_string_new("");
961      char *buf=NULL;
962      int sym;
963
964      g_scanner_input_text(uzbl.scan, template, strlen(template));
965      while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
966          token = g_scanner_get_next_token(uzbl.scan);
967
968          if(token == G_TOKEN_SYMBOL) {
969              sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
970              switch(sym) {
971                  case SYM_URI:
972                      if(escape_markup) {
973                          buf = uzbl.state.uri?
974                              g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
975                          g_string_append(ret, buf);
976                          g_free(buf);
977                      }
978                      else
979                          g_string_append(ret, uzbl.state.uri?
980                                  uzbl.state.uri:g_strdup(""));
981                      break;
982                  case SYM_LOADPRGS:
983                      buf = itos(uzbl.gui.sbar.load_progress);
984                      g_string_append(ret, buf);
985                      g_free(buf);
986                      break;
987                  case SYM_LOADPRGSBAR:
988                      buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
989                      g_string_append(ret, buf);
990                      g_free(buf);
991                      break;
992                  case SYM_TITLE:
993                      if(escape_markup) {
994                          buf = uzbl.gui.main_title?
995                              g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
996                          g_string_append(ret, buf);
997                          g_free(buf);
998                      }
999                      else
1000                          g_string_append(ret, uzbl.gui.main_title?
1001                                  uzbl.gui.main_title:g_strdup(""));
1002                      break;
1003                  case SYM_SELECTED_URI:
1004                      if(escape_markup) {
1005                          buf = uzbl.state.selected_url?
1006                              g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1007                          g_string_append(ret, buf);
1008                          g_free(buf);
1009                      }
1010                      else
1011                          g_string_append(ret, uzbl.state.selected_url?
1012                                  uzbl.state.selected_url:g_strdup(""));
1013                      break;
1014                  case SYM_NAME:
1015                      buf = itos(uzbl.xwin);
1016                      g_string_append(ret,
1017                              uzbl.state.instance_name?uzbl.state.instance_name:buf);
1018                      g_free(buf);
1019                      break;
1020                  case SYM_KEYCMD:
1021                      if(escape_markup) {
1022                          buf = uzbl.state.keycmd->str?
1023                              g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1024                          g_string_append(ret, buf);
1025                          g_free(buf);
1026                      }
1027                      else
1028                          g_string_append(ret, uzbl.state.keycmd->str?
1029                                  uzbl.state.keycmd->str:g_strdup(""));
1030                      break;
1031                  case SYM_MODE:
1032                      g_string_append(ret,
1033                              uzbl.behave.insert_mode?
1034                              uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1035                      break;
1036                  case SYM_MSG:
1037                      g_string_append(ret,
1038                              uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1039                      break;
1040                      /* useragent syms */
1041                  case SYM_WK_MAJ:
1042                      buf = itos(WEBKIT_MAJOR_VERSION);
1043                      g_string_append(ret, buf);
1044                      g_free(buf);
1045                      break;
1046                  case SYM_WK_MIN:
1047                      buf = itos(WEBKIT_MINOR_VERSION);
1048                      g_string_append(ret, buf);
1049                      g_free(buf);
1050                      break;
1051                  case SYM_WK_MIC:
1052                      buf = itos(WEBKIT_MICRO_VERSION);
1053                      g_string_append(ret, buf);
1054                      g_free(buf);
1055                      break;
1056                  case SYM_SYSNAME:
1057                      g_string_append(ret, uzbl.state.unameinfo.sysname);
1058                      break;
1059                  case SYM_NODENAME:
1060                      g_string_append(ret, uzbl.state.unameinfo.nodename);
1061                      break;
1062                  case SYM_KERNREL:
1063                      g_string_append(ret, uzbl.state.unameinfo.release);
1064                      break;
1065                  case SYM_KERNVER:
1066                      g_string_append(ret, uzbl.state.unameinfo.version);
1067                      break;
1068                  case SYM_ARCHSYS:
1069                      g_string_append(ret, uzbl.state.unameinfo.machine);
1070                      break;
1071                  case SYM_ARCHUZBL:
1072                      g_string_append(ret, ARCH);
1073                      break;
1074 #ifdef _GNU_SOURCE
1075                  case SYM_DOMAINNAME:
1076                      g_string_append(ret, uzbl.state.unameinfo.domainname);
1077                      break;
1078 #endif
1079                  case SYM_COMMIT:
1080                      g_string_append(ret, COMMIT);
1081                      break;
1082                  default:
1083                      break;
1084              }
1085          }
1086          else if(token == G_TOKEN_INT) {
1087              buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1088              g_string_append(ret, buf);
1089              g_free(buf);
1090          }
1091          else if(token == G_TOKEN_IDENTIFIER) {
1092              g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1093          }
1094          else if(token == G_TOKEN_CHAR) {
1095              g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1096          }
1097      }
1098
1099      return g_string_free(ret, FALSE);
1100 }
1101 /* --End Statusbar functions-- */
1102
1103 static void
1104 sharg_append(GArray *a, const gchar *str) {
1105     const gchar *s = (str ? str : "");
1106     g_array_append_val(a, s);
1107 }
1108
1109 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1110 static gboolean
1111 run_command (const gchar *command, const guint npre, const gchar **args,
1112              const gboolean sync, char **stdout) {
1113    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1114     GError *err = NULL;
1115     
1116     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1117     gchar *pid = itos(getpid());
1118     gchar *xwin = itos(uzbl.xwin);
1119     guint i;
1120     sharg_append(a, command);
1121     for (i = 0; i < npre; i++) /* add n args before the default vars */
1122         sharg_append(a, args[i]);
1123     sharg_append(a, uzbl.state.config_file);
1124     sharg_append(a, pid);
1125     sharg_append(a, xwin);
1126     sharg_append(a, uzbl.comm.fifo_path);
1127     sharg_append(a, uzbl.comm.socket_path);
1128     sharg_append(a, uzbl.state.uri);
1129     sharg_append(a, uzbl.gui.main_title);
1130
1131     for (i = npre; i < g_strv_length((gchar**)args); i++)
1132         sharg_append(a, args[i]);
1133     
1134     gboolean result;
1135     if (sync) {
1136         if (*stdout) *stdout = strfree(*stdout);
1137         
1138         result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1139                               NULL, NULL, stdout, NULL, NULL, &err);
1140     } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1141                                   NULL, NULL, NULL, &err);
1142
1143     if (uzbl.state.verbose) {
1144         GString *s = g_string_new("spawned:");
1145         for (i = 0; i < (a->len); i++) {
1146             gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1147             g_string_append_printf(s, " %s", qarg);
1148             g_free (qarg);
1149         }
1150         g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1151         printf("%s\n", s->str);
1152         g_string_free(s, TRUE);
1153         if(stdout) {
1154             printf("Stdout: %s\n", *stdout);
1155         }
1156     }
1157     if (err) {
1158         g_printerr("error on run_command: %s\n", err->message);
1159         g_error_free (err);
1160     }
1161     g_free (pid);
1162     g_free (xwin);
1163     g_array_free (a, TRUE);
1164     return result;
1165 }
1166
1167 static gchar**
1168 split_quoted(const gchar* src, const gboolean unquote) {
1169     /* split on unquoted space, return array of strings;
1170        remove a layer of quotes and backslashes if unquote */
1171     if (!src) return NULL;
1172     
1173     gboolean dq = FALSE;
1174     gboolean sq = FALSE;
1175     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1176     GString *s = g_string_new ("");
1177     const gchar *p;
1178     gchar **ret;
1179     gchar *dup;
1180     for (p = src; *p != '\0'; p++) {
1181         if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1182         else if (*p == '\\') { g_string_append_c(s, *p++);
1183                                g_string_append_c(s, *p); }
1184         else if ((*p == '"') && unquote && !sq) dq = !dq;
1185         else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1186                                      dq = !dq; }
1187         else if ((*p == '\'') && unquote && !dq) sq = !sq;
1188         else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1189                                       sq = ! sq; }
1190         else if ((*p == ' ') && !dq && !sq) {
1191             dup = g_strdup(s->str);
1192             g_array_append_val(a, dup);
1193             g_string_truncate(s, 0);
1194         } else g_string_append_c(s, *p);
1195     }
1196     dup = g_strdup(s->str);
1197     g_array_append_val(a, dup);
1198     ret = (gchar**)a->data;
1199     g_array_free (a, FALSE);
1200     g_string_free (s, TRUE);
1201     return ret;
1202 }
1203
1204 static void
1205 spawn(WebKitWebView *web_view, GArray *argv) {
1206     (void)web_view;
1207     //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1208     if (argv_idx(argv, 0))
1209         run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1210 }
1211
1212 static void
1213 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1214     (void)web_view;
1215     
1216     if (argv_idx(argv, 0))
1217         run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1218                     TRUE, &uzbl.comm.sync_stdout);
1219 }
1220
1221 static void
1222 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1223     (void)web_view;
1224     if (!uzbl.behave.shell_cmd) {
1225         g_printerr ("spawn_sh: shell_cmd is not set!\n");
1226         return;
1227     }
1228     
1229     guint i;
1230     gchar *spacer = g_strdup("");
1231     g_array_insert_val(argv, 1, spacer);
1232     gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1233
1234     for (i = 1; i < g_strv_length(cmd); i++)
1235         g_array_prepend_val(argv, cmd[i]);
1236
1237     if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1238     g_free (spacer);
1239     g_strfreev (cmd);
1240 }
1241
1242 static void
1243 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1244     (void)web_view;
1245     if (!uzbl.behave.shell_cmd) {
1246         g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1247         return;
1248     }
1249     
1250     guint i;
1251     gchar *spacer = g_strdup("");
1252     g_array_insert_val(argv, 1, spacer);
1253     gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1254
1255     for (i = 1; i < g_strv_length(cmd); i++)
1256         g_array_prepend_val(argv, cmd[i]);
1257          
1258     if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1259                          TRUE, &uzbl.comm.sync_stdout);
1260     g_free (spacer);
1261     g_strfreev (cmd);
1262 }
1263
1264 static void
1265 parse_command(const char *cmd, const char *param) {
1266     Command *c;
1267
1268     if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1269
1270             guint i;
1271             gchar **par = split_quoted(param, TRUE);
1272             GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1273
1274             if (c[1] == NOSPLIT) { /* don't split */
1275                 sharg_append(a, param);
1276             } else if (par) {
1277                 for (i = 0; i < g_strv_length(par); i++)
1278                     sharg_append(a, par[i]);
1279             }
1280             c[0](uzbl.gui.web_view, a);
1281             g_strfreev (par);
1282             g_array_free (a, TRUE);
1283
1284     } else
1285         g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1286 }
1287
1288 static void
1289 set_proxy_url() {
1290     SoupURI *suri;
1291
1292     if(*uzbl.net.proxy_url == ' '
1293        || uzbl.net.proxy_url == NULL) {
1294         soup_session_remove_feature_by_type(uzbl.net.soup_session,
1295                 (GType) SOUP_SESSION_PROXY_URI);
1296     }
1297     else {
1298         suri = soup_uri_new(uzbl.net.proxy_url);
1299         g_object_set(G_OBJECT(uzbl.net.soup_session),
1300                 SOUP_SESSION_PROXY_URI,
1301                 suri, NULL);
1302         soup_uri_free(suri);
1303     }
1304     return;
1305 }
1306
1307 static void
1308 cmd_load_uri() {
1309     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1310     g_array_append_val (a, uzbl.state.uri);
1311     load_uri(uzbl.gui.web_view, a);
1312     g_array_free (a, TRUE);
1313 }
1314
1315 static void 
1316 cmd_always_insert_mode() {
1317     uzbl.behave.insert_mode =
1318         uzbl.behave.always_insert_mode ?  TRUE : FALSE;
1319     update_title();
1320 }
1321
1322 static void
1323 cmd_max_conns() {
1324     g_object_set(G_OBJECT(uzbl.net.soup_session),
1325             SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1326 }
1327
1328 static void
1329 cmd_max_conns_host() {
1330     g_object_set(G_OBJECT(uzbl.net.soup_session),
1331             SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1332 }
1333
1334 static void
1335 cmd_http_debug() {
1336     soup_session_remove_feature
1337         (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1338     /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1339     /*g_free(uzbl.net.soup_logger);*/
1340
1341     uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1342     soup_session_add_feature(uzbl.net.soup_session,
1343             SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1344 }
1345
1346 static WebKitWebSettings*
1347 view_settings() {
1348     return webkit_web_view_get_settings(uzbl.gui.web_view);
1349 }
1350
1351 static void
1352 cmd_font_size() {
1353     WebKitWebSettings *ws = view_settings();
1354     if (uzbl.behave.font_size > 0) {
1355         g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1356     }
1357     
1358     if (uzbl.behave.monospace_size > 0) {
1359         g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1360                       uzbl.behave.monospace_size, NULL);
1361     } else {
1362         g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1363                       uzbl.behave.font_size, NULL);
1364     }
1365 }
1366
1367 static void
1368 cmd_disable_plugins() {
1369     g_object_set (G_OBJECT(view_settings()), "enable-plugins", 
1370             !uzbl.behave.disable_plugins, NULL);
1371 }
1372
1373 static void
1374 cmd_disable_scripts() {
1375     g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1376             !uzbl.behave.disable_scripts, NULL);
1377 }
1378
1379 static void
1380 cmd_minimum_font_size() {
1381     g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1382             uzbl.behave.minimum_font_size, NULL);
1383 }
1384 static void
1385 cmd_autoload_img() {
1386     g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1387             uzbl.behave.autoload_img, NULL);
1388 }
1389
1390
1391 static void
1392 cmd_autoshrink_img() {
1393     g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1394             uzbl.behave.autoshrink_img, NULL);
1395 }
1396
1397
1398 static void
1399 cmd_enable_spellcheck() {
1400     g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1401             uzbl.behave.enable_spellcheck, NULL);
1402 }
1403
1404 static void
1405 cmd_enable_private() {
1406     g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1407             uzbl.behave.enable_private, NULL);
1408 }
1409
1410 static void
1411 cmd_print_bg() {
1412     g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1413             uzbl.behave.print_bg, NULL);
1414 }
1415
1416 static void 
1417 cmd_style_uri() {
1418     g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1419             uzbl.behave.style_uri, NULL);
1420 }
1421
1422 static void 
1423 cmd_resizable_txt() {
1424     g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1425             uzbl.behave.resizable_txt, NULL);
1426 }
1427
1428 static void 
1429 cmd_default_encoding() {
1430     g_object_set (G_OBJECT(view_settings()), "default-encoding",
1431             uzbl.behave.default_encoding, NULL);
1432 }
1433
1434 static void 
1435 cmd_enforce_96dpi() {
1436     g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1437             uzbl.behave.enforce_96dpi, NULL);
1438 }
1439
1440 static void 
1441 cmd_caret_browsing() {
1442     g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1443             uzbl.behave.caret_browsing, NULL);
1444 }
1445
1446 static void
1447 cmd_cookie_handler() {
1448     gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1449     /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1450     if ((g_strcmp0(split[0], "sh") == 0) ||
1451         (g_strcmp0(split[0], "spawn") == 0)) {
1452         g_free (uzbl.behave.cookie_handler);
1453         uzbl.behave.cookie_handler =
1454             g_strdup_printf("sync_%s %s", split[0], split[1]);
1455     }
1456     g_strfreev (split);
1457 }
1458
1459 static void
1460 cmd_fifo_dir() {
1461     uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1462 }
1463
1464 static void
1465 cmd_socket_dir() {
1466     uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1467 }
1468
1469 static void
1470 cmd_inject_html() {
1471     if(uzbl.behave.inject_html) {
1472         webkit_web_view_load_html_string (uzbl.gui.web_view,
1473                 uzbl.behave.inject_html, NULL);
1474     }
1475 }
1476
1477 static void
1478 cmd_modkey() {
1479     int i;
1480     char *buf;
1481
1482     buf = g_utf8_strup(uzbl.behave.modkey, -1);
1483     uzbl.behave.modmask = 0;
1484
1485     if(uzbl.behave.modkey) 
1486         g_free(uzbl.behave.modkey);
1487     uzbl.behave.modkey = buf;
1488
1489     for (i = 0; modkeys[i].key != NULL; i++) {
1490         if (g_strrstr(buf, modkeys[i].key))
1491             uzbl.behave.modmask |= modkeys[i].mask;
1492     }
1493 }
1494
1495 static void
1496 cmd_useragent() {
1497     if (*uzbl.net.useragent == ' ') {
1498         g_free (uzbl.net.useragent);
1499         uzbl.net.useragent = NULL;
1500     } else {
1501         gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1502         if (ua)
1503             g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1504         g_free(uzbl.net.useragent);
1505         uzbl.net.useragent = ua;
1506     }
1507 }
1508
1509 static void
1510 move_statusbar() {
1511     gtk_widget_ref(uzbl.gui.scrolled_win);
1512     gtk_widget_ref(uzbl.gui.mainbar);
1513     gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1514     gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1515
1516     if(uzbl.behave.status_top) {
1517         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1518         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1519     }
1520     else {
1521         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1522         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1523     }
1524     gtk_widget_unref(uzbl.gui.scrolled_win);
1525     gtk_widget_unref(uzbl.gui.mainbar);
1526     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1527     return;
1528 }
1529
1530 static gboolean
1531 set_var_value(gchar *name, gchar *val) {
1532     uzbl_cmdprop *c = NULL;
1533     char *endp = NULL;
1534     char *buf = NULL;
1535
1536     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1537         /* check for the variable type */
1538         if (c->type == TYPE_STR) {
1539             buf = expand_vars(val);
1540             g_free(*c->ptr);
1541             *c->ptr = buf;
1542         } else if(c->type == TYPE_INT) {
1543             int *ip = (int *)c->ptr;
1544             buf = expand_vars(val);
1545             *ip = (int)strtoul(buf, &endp, 10);
1546             g_free(buf);
1547         }
1548
1549         /* invoke a command specific function */
1550         if(c->func) c->func();
1551     }
1552     return TRUE;
1553 }
1554
1555 static void
1556 render_html() {
1557     Behaviour *b = &uzbl.behave;
1558
1559     if(b->html_buffer->str) {
1560         webkit_web_view_load_html_string (uzbl.gui.web_view,
1561                 b->html_buffer->str, b->base_url);
1562         g_string_free(b->html_buffer, TRUE);
1563         b->html_buffer = g_string_new("");
1564     }
1565 }
1566
1567 enum {M_CMD, M_HTML};
1568 static void
1569 parse_cmd_line(const char *ctl_line) {
1570     Behaviour *b = &uzbl.behave;
1571     size_t len=0;
1572
1573     if(b->mode == M_HTML) {
1574         len = strlen(b->html_endmarker);
1575         /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1576         if(len == strlen(ctl_line)-1 &&
1577            !strncmp(b->html_endmarker, ctl_line, len)) {
1578             set_timeout(0);
1579             set_var_value("mode", "0");
1580             render_html();
1581             return;
1582         }
1583         else {
1584             set_timeout(b->html_timeout);
1585             g_string_append(b->html_buffer, ctl_line);
1586         }
1587     }
1588     else if((ctl_line[0] == '#') /* Comments */
1589             || (ctl_line[0] == ' ')
1590             || (ctl_line[0] == '\n'))
1591         ; /* ignore these lines */
1592     else { /* parse a command */
1593         gchar *ctlstrip;
1594         gchar **tokens = NULL;
1595         len = strlen(ctl_line);
1596
1597         if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1598             ctlstrip = g_strndup(ctl_line, len - 1);
1599         else ctlstrip = g_strdup(ctl_line);
1600
1601         tokens = g_strsplit(ctlstrip, " ", 2);
1602         parse_command(tokens[0], tokens[1]);
1603         g_free(ctlstrip);
1604         g_strfreev(tokens);
1605     }
1606 }
1607
1608 static gchar*
1609 build_stream_name(int type, const gchar* dir) {
1610     char *xwin_str;
1611     State *s = &uzbl.state;
1612     gchar *str;
1613
1614     xwin_str = itos((int)uzbl.xwin);
1615     if (type == FIFO) {
1616         str = g_strdup_printf
1617             ("%s/uzbl_fifo_%s", dir,
1618              s->instance_name ? s->instance_name : xwin_str);
1619     } else if (type == SOCKET) {
1620         str = g_strdup_printf
1621             ("%s/uzbl_socket_%s", dir,
1622              s->instance_name ? s->instance_name : xwin_str );
1623     }
1624     g_free(xwin_str);
1625     return str;
1626 }
1627
1628 static gboolean
1629 control_fifo(GIOChannel *gio, GIOCondition condition) {
1630     if (uzbl.state.verbose)
1631         printf("triggered\n");
1632     gchar *ctl_line;
1633     GIOStatus ret;
1634     GError *err = NULL;
1635
1636     if (condition & G_IO_HUP)
1637         g_error ("Fifo: Read end of pipe died!\n");
1638
1639     if(!gio)
1640        g_error ("Fifo: GIOChannel broke\n");
1641
1642     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1643     if (ret == G_IO_STATUS_ERROR) {
1644         g_error ("Fifo: Error reading: %s\n", err->message);
1645         g_error_free (err);
1646     }
1647
1648     parse_cmd_line(ctl_line);
1649     g_free(ctl_line);
1650
1651     return TRUE;
1652 }
1653
1654 static gchar*
1655 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1656     if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1657         if (unlink(uzbl.comm.fifo_path) == -1)
1658             g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1659         g_free(uzbl.comm.fifo_path);
1660         uzbl.comm.fifo_path = NULL;
1661     }
1662
1663     if (*dir == ' ') { /* space unsets the variable */
1664         g_free (dir);
1665         return NULL;
1666     }
1667
1668     GIOChannel *chan = NULL;
1669     GError *error = NULL;
1670     gchar *path = build_stream_name(FIFO, dir);
1671
1672     if (!file_exists(path)) {
1673         if (mkfifo (path, 0666) == 0) {
1674             // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file.
1675             chan = g_io_channel_new_file(path, "r+", &error);
1676             if (chan) {
1677                 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1678                     if (uzbl.state.verbose)
1679                         printf ("init_fifo: created successfully as %s\n", path);
1680                     uzbl.comm.fifo_path = path;
1681                     return dir;
1682                 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1683             } else g_warning ("init_fifo: can't open: %s\n", error->message);
1684         } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1685     } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1686
1687     /* if we got this far, there was an error; cleanup */
1688     if (error) g_error_free (error);
1689     g_free(dir);
1690     g_free(path);
1691     return NULL;
1692 }
1693
1694 static gboolean
1695 control_stdin(GIOChannel *gio, GIOCondition condition) {
1696     (void) condition;
1697     gchar *ctl_line = NULL;
1698     GIOStatus ret;
1699
1700     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1701     if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1702         return FALSE;
1703
1704     parse_cmd_line(ctl_line);
1705     g_free(ctl_line);
1706
1707     return TRUE;
1708 }
1709
1710 static void
1711 create_stdin () {
1712     GIOChannel *chan = NULL;
1713     GError *error = NULL;
1714
1715     chan = g_io_channel_unix_new(fileno(stdin));
1716     if (chan) {
1717         if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1718             g_error ("Stdin: could not add watch\n");
1719         } else {
1720             if (uzbl.state.verbose)
1721                 printf ("Stdin: watch added successfully\n");
1722         }
1723     } else {
1724         g_error ("Stdin: Error while opening: %s\n", error->message);
1725     }
1726     if (error) g_error_free (error);
1727 }
1728
1729 static gboolean
1730 control_socket(GIOChannel *chan) {
1731     struct sockaddr_un remote;
1732     char buffer[512], *ctl_line;
1733     char temp[128];
1734     int sock, clientsock, n, done;
1735     unsigned int t;
1736
1737     sock = g_io_channel_unix_get_fd(chan);
1738
1739     memset (buffer, 0, sizeof (buffer));
1740
1741     t          = sizeof (remote);
1742     clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1743
1744     done = 0;
1745     do {
1746         memset (temp, 0, sizeof (temp));
1747         n = recv (clientsock, temp, 128, 0);
1748         if (n == 0) {
1749             buffer[strlen (buffer)] = '\0';
1750             done = 1;
1751         }
1752         if (!done)
1753             strcat (buffer, temp);
1754     } while (!done);
1755
1756     if (strcmp (buffer, "\n") < 0) {
1757         buffer[strlen (buffer) - 1] = '\0';
1758     } else {
1759         buffer[strlen (buffer)] = '\0';
1760     }
1761     close (clientsock);
1762     ctl_line = g_strdup(buffer);
1763     parse_cmd_line (ctl_line);
1764
1765 /*
1766    TODO: we should be able to do it with this.  but glib errors out with "Invalid argument"
1767     GError *error = NULL;
1768     gsize len;
1769     GIOStatus ret;
1770     ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1771     if (ret == G_IO_STATUS_ERROR)
1772         g_error ("Error reading: %s\n", error->message);
1773
1774     printf("Got line %s (%u bytes) \n",ctl_line, len);
1775     if(ctl_line) {
1776        parse_line(ctl_line);
1777 */
1778
1779     g_free(ctl_line);
1780     return TRUE;
1781 }
1782
1783 static gchar*
1784 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1785     if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1786         if (unlink(uzbl.comm.socket_path) == -1)
1787             g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1788         g_free(uzbl.comm.socket_path);
1789         uzbl.comm.socket_path = NULL;
1790     }
1791
1792     if (*dir == ' ') {
1793         g_free(dir);
1794         return NULL;
1795     }
1796
1797     GIOChannel *chan = NULL;
1798     int sock, len;
1799     struct sockaddr_un local;
1800     gchar *path = build_stream_name(SOCKET, dir);
1801
1802     sock = socket (AF_UNIX, SOCK_STREAM, 0);
1803
1804     local.sun_family = AF_UNIX;
1805     strcpy (local.sun_path, path);
1806     unlink (local.sun_path);
1807
1808     len = strlen (local.sun_path) + sizeof (local.sun_family);
1809     if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1810         if (uzbl.state.verbose)
1811             printf ("init_socket: opened in %s\n", path);
1812         listen (sock, 5);
1813
1814         if( (chan = g_io_channel_unix_new(sock)) ) {
1815             g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1816             uzbl.comm.socket_path = path;
1817             return dir;
1818         }
1819     } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1820
1821     /* if we got this far, there was an error; cleanup */
1822     g_free(path);
1823     g_free(dir);
1824     return NULL;
1825 }
1826
1827 /*
1828  NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1829  it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1830 */
1831 // this function may be called very early when the templates are not set (yet), hence the checks
1832 static void
1833 update_title (void) {
1834     Behaviour *b = &uzbl.behave;
1835     gchar *parsed;
1836
1837     if (b->show_status) {
1838         if (b->title_format_short) {
1839             parsed = expand_template(b->title_format_short, FALSE);
1840             gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1841             g_free(parsed);
1842         }
1843         if (b->status_format) {
1844             parsed = expand_template(b->status_format, TRUE);
1845             gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1846             g_free(parsed);
1847         }
1848         if (b->status_background) {
1849             GdkColor color;
1850             gdk_color_parse (b->status_background, &color);
1851             //labels and hboxes do not draw their own background.  applying this on the window is ok as we the statusbar is the only affected widget.  (if not, we could also use GtkEventBox)
1852             gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1853         }
1854     } else {
1855         if (b->title_format_long) {
1856             parsed = expand_template(b->title_format_long, FALSE);
1857             gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1858             g_free(parsed);
1859         }
1860     }
1861 }
1862
1863 static gboolean
1864 key_press_cb (GtkWidget* window, GdkEventKey* event)
1865 {
1866     //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1867
1868     (void) window;
1869
1870     if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1871         || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right || event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R)
1872         return FALSE;
1873
1874     /* turn off insert mode (if always_insert_mode is not used) */
1875     if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1876         uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1877         update_title();
1878         return TRUE;
1879     }
1880
1881     if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1882         return FALSE;
1883
1884     if (event->keyval == GDK_Escape) {
1885         g_string_truncate(uzbl.state.keycmd, 0);
1886         update_title();
1887         dehilight(uzbl.gui.web_view, NULL);
1888         return TRUE;
1889     }
1890
1891     //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1892     if (event->keyval == GDK_Insert) {
1893         gchar * str;
1894         if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1895             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1896         } else {
1897             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1898         }
1899         if (str) {
1900             g_string_append (uzbl.state.keycmd, str);
1901             update_title ();
1902             g_free (str);
1903         }
1904         return TRUE;
1905     }
1906
1907     if (event->keyval == GDK_BackSpace)
1908         keycmd_bs(NULL, NULL);
1909
1910     gboolean key_ret = FALSE;
1911     if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1912         key_ret = TRUE;
1913     if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1914
1915     run_keycmd(key_ret);
1916     update_title();
1917     if (key_ret) return (!uzbl.behave.insert_mode);
1918     return TRUE;
1919 }
1920
1921 static void
1922 run_keycmd(const gboolean key_ret) {
1923     /* run the keycmd immediately if it isn't incremental and doesn't take args */
1924     Action *act;
1925     if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1926         g_string_truncate(uzbl.state.keycmd, 0);
1927         parse_command(act->name, act->param);
1928         return;
1929     }
1930
1931     /* try if it's an incremental keycmd or one that takes args, and run it */
1932     GString* short_keys = g_string_new ("");
1933     GString* short_keys_inc = g_string_new ("");
1934     guint i;
1935     for (i=0; i<(uzbl.state.keycmd->len); i++) {
1936         g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1937         g_string_assign(short_keys_inc, short_keys->str);
1938         g_string_append_c(short_keys, '_');
1939         g_string_append_c(short_keys_inc, '*');
1940
1941         if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1942             /* run normal cmds only if return was pressed */
1943             exec_paramcmd(act, i);
1944             g_string_truncate(uzbl.state.keycmd, 0);
1945             break;
1946         } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1947             if (key_ret)  /* just quit the incremental command on return */
1948                 g_string_truncate(uzbl.state.keycmd, 0);
1949             else exec_paramcmd(act, i); /* otherwise execute the incremental */
1950             break;
1951         }
1952         
1953         g_string_truncate(short_keys, short_keys->len - 1);
1954     }
1955     g_string_free (short_keys, TRUE);
1956     g_string_free (short_keys_inc, TRUE);
1957 }
1958
1959 static void
1960 exec_paramcmd(const Action *act, const guint i) {
1961     GString *parampart = g_string_new (uzbl.state.keycmd->str);
1962     GString *actionname = g_string_new ("");
1963     GString *actionparam = g_string_new ("");
1964     g_string_erase (parampart, 0, i+1);
1965     if (act->name)
1966         g_string_printf (actionname, act->name, parampart->str);
1967     if (act->param)
1968         g_string_printf (actionparam, act->param, parampart->str);
1969     parse_command(actionname->str, actionparam->str);
1970     g_string_free(actionname, TRUE);
1971     g_string_free(actionparam, TRUE);
1972     g_string_free(parampart, TRUE);
1973 }
1974
1975
1976 static GtkWidget*
1977 create_browser () {
1978     GUI *g = &uzbl.gui;
1979
1980     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1981     //main_window_ref = g_object_ref(scrolled_window);
1982     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
1983
1984     g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1985     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1986
1987     g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1988     g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1989     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1990     g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1991     g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1992     g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1993     g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1994     g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1995     g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1996     g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1997
1998     return scrolled_window;
1999 }
2000
2001 static GtkWidget*
2002 create_mainbar () {
2003     GUI *g = &uzbl.gui;
2004
2005     g->mainbar = gtk_hbox_new (FALSE, 0);
2006
2007     /* keep a reference to the bar so we can re-pack it at runtime*/
2008     //sbar_ref = g_object_ref(g->mainbar);
2009
2010     g->mainbar_label = gtk_label_new ("");
2011     gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2012     gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2013     gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2014     gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2015     gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2016     return g->mainbar;
2017 }
2018
2019 static
2020 GtkWidget* create_window () {
2021     GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2022     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2023     gtk_widget_set_name (window, "Uzbl browser");
2024     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2025     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2026
2027     return window;
2028 }
2029
2030 static gchar**
2031 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2032     /*
2033       If actname is one that calls an external command, this function will inject
2034       newargs in front of the user-provided args in that command line.  They will
2035       come become after the body of the script (in sh) or after the name of
2036       the command to execute (in spawn).
2037       i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2038       span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2039
2040       The return value consist of two strings: the action (sh, ...) and its args.
2041
2042       If act is not one that calls an external command, then the given action merely
2043       gets duplicated.
2044     */
2045     GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2046     gchar *actdup = g_strdup(actname);
2047     g_array_append_val(rets, actdup);
2048
2049     if ((g_strcmp0(actname, "spawn") == 0) ||
2050         (g_strcmp0(actname, "sh") == 0) ||
2051         (g_strcmp0(actname, "sync_spawn") == 0) ||
2052         (g_strcmp0(actname, "sync_sh") == 0)) {
2053         guint i;
2054         GString *a = g_string_new("");
2055         gchar **spawnparts = split_quoted(origargs, FALSE);
2056         g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2057         if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2058
2059         for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2060             if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2061
2062         g_array_append_val(rets, a->str);
2063         g_string_free(a, FALSE);
2064         g_strfreev(spawnparts);
2065     } else {
2066         gchar *origdup = g_strdup(origargs);
2067         g_array_append_val(rets, origdup);
2068     }
2069     return (gchar**)g_array_free(rets, FALSE);
2070 }
2071
2072 static void
2073 run_handler (const gchar *act, const gchar *args) {
2074     /* Consider this code a temporary hack to make the handlers usable.
2075        In practice, all this splicing, injection, and reconstruction is
2076        inefficient, annoying and hard to manage.  Potential pitfalls arise
2077        when the handler specific args 1) are not quoted  (the handler
2078        callbacks should take care of this)  2) are quoted but interfere
2079        with the users' own quotation.  A more ideal solution is
2080        to refactor parse_command so that it doesn't just take a string
2081        and execute it; rather than that, we should have a function which
2082        returns the argument vector parsed from the string.  This vector
2083        could be modified (e.g. insert additional args into it) before
2084        passing it to the next function that actually executes it.  Though
2085        it still isn't perfect for chain actions..  will reconsider & re-
2086        factor when I have the time. -duc */
2087
2088     char **parts = g_strsplit(act, " ", 2);
2089     if (!parts) return;
2090     if (g_strcmp0(parts[0], "chain") == 0) {
2091         GString *newargs = g_string_new("");
2092         gchar **chainparts = split_quoted(parts[1], FALSE);
2093         
2094         /* for every argument in the chain, inject the handler args
2095            and make sure the new parts are wrapped in quotes */
2096         gchar **cp = chainparts;
2097         gchar quot = '\'';
2098         gchar *quotless = NULL;
2099         gchar **spliced_quotless = NULL; // sigh -_-;
2100         gchar **inpart = NULL;
2101         
2102         while (*cp) {
2103             if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2104                 quot = **cp;
2105                 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2106             } else quotless = g_strdup(*cp);
2107
2108             spliced_quotless = g_strsplit(quotless, " ", 2);
2109             inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2110             g_strfreev(spliced_quotless);
2111             
2112             g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2113             g_free(quotless);
2114             g_strfreev(inpart);
2115             cp++;
2116         }
2117
2118         parse_command(parts[0], &(newargs->str[1]));
2119         g_string_free(newargs, TRUE);
2120         g_strfreev(chainparts);
2121         
2122     } else {
2123         gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2124         parse_command(inparts[0], inparts[1]);
2125         g_free(inparts[0]);
2126         g_free(inparts[1]);
2127     }
2128     g_strfreev(parts);
2129 }
2130
2131 static void
2132 add_binding (const gchar *key, const gchar *act) {
2133     char **parts = g_strsplit(act, " ", 2);
2134     Action *action;
2135
2136     if (!parts)
2137         return;
2138
2139     //Debug:
2140     if (uzbl.state.verbose)
2141         printf ("Binding %-10s : %s\n", key, act);
2142     action = new_action(parts[0], parts[1]);
2143
2144     g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2145     g_strfreev(parts);
2146 }
2147
2148 static gchar*
2149 get_xdg_var (XDG_Var xdg) {
2150     const gchar* actual_value = getenv (xdg.environmental);
2151     const gchar* home         = getenv ("HOME");
2152
2153     gchar* return_value = str_replace ("~", home, actual_value);
2154
2155     if (! actual_value || strcmp (actual_value, "") == 0) {
2156         if (xdg.default_value) {
2157             return_value = str_replace ("~", home, xdg.default_value);
2158         } else {
2159             return_value = NULL;
2160         }
2161     }
2162     return return_value;
2163 }
2164
2165 static gchar*
2166 find_xdg_file (int xdg_type, char* filename) {
2167     /* xdg_type = 0 => config
2168        xdg_type = 1 => data
2169        xdg_type = 2 => cache*/
2170
2171     gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2172     gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2173     g_free (xdgv);
2174
2175     gchar* temporary_string;
2176     char*  saveptr;
2177     char*  buf;
2178
2179     if (! file_exists (temporary_file) && xdg_type != 2) {
2180         buf = get_xdg_var (XDG[3 + xdg_type]);
2181         temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2182         g_free(buf);
2183
2184         while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2185             g_free (temporary_file);
2186             temporary_file = g_strconcat (temporary_string, filename, NULL);
2187         }
2188     }
2189     
2190     //g_free (temporary_string); - segfaults.
2191
2192     if (file_exists (temporary_file)) {
2193         return temporary_file;
2194     } else {
2195         return NULL;
2196     }
2197 }
2198 static void
2199 settings_init () {
2200     State *s = &uzbl.state;
2201     Network *n = &uzbl.net;
2202     int i;
2203     for (i = 0; default_config[i].command != NULL; i++) {
2204         parse_cmd_line(default_config[i].command);
2205     }
2206
2207     if (!s->config_file) {
2208         s->config_file = find_xdg_file (0, "/uzbl/config");
2209     }
2210
2211     if (s->config_file) {
2212         GArray* lines = read_file_by_line (s->config_file);
2213         int i = 0;
2214         gchar* line;
2215
2216         while ((line = g_array_index(lines, gchar*, i))) {
2217             parse_cmd_line (line);
2218             i ++;
2219             g_free (line);
2220         }
2221         g_array_free (lines, TRUE);
2222     } else {
2223         if (uzbl.state.verbose)
2224             printf ("No configuration file loaded.\n");
2225     }
2226
2227     g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2228 }
2229
2230 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2231     (void) session;
2232     (void) user_data;
2233     if (!uzbl.behave.cookie_handler)
2234          return;
2235
2236     soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2237     GString *s = g_string_new ("");
2238     SoupURI * soup_uri = soup_message_get_uri(msg);
2239     g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2240     run_handler(uzbl.behave.cookie_handler, s->str);
2241
2242     if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2243         char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2244         if ( p != NULL ) *p = '\0';
2245         soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2246     }
2247     if (uzbl.comm.sync_stdout)
2248         uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2249         
2250     g_string_free(s, TRUE);
2251 }
2252
2253 static void
2254 save_cookies (SoupMessage *msg, gpointer user_data){
2255     (void) user_data;
2256     GSList *ck;
2257     char *cookie;
2258     for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2259         cookie = soup_cookie_to_set_cookie_header(ck->data);
2260         SoupURI * soup_uri = soup_message_get_uri(msg);
2261         GString *s = g_string_new ("");
2262         g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2263         run_handler(uzbl.behave.cookie_handler, s->str);
2264         g_free (cookie);
2265         g_string_free(s, TRUE);
2266     }
2267     g_slist_free(ck);
2268 }
2269
2270 /* --- WEBINSPECTOR --- */
2271 static void
2272 hide_window_cb(GtkWidget *widget, gpointer data) {
2273     (void) data;
2274
2275     gtk_widget_hide(widget);
2276 }
2277
2278 static WebKitWebView*
2279 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2280     (void) data;
2281     (void) page;
2282     (void) web_inspector;
2283     GtkWidget* scrolled_window;
2284     GtkWidget* new_web_view;
2285     GUI *g = &uzbl.gui;
2286
2287     g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2288     g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2289             G_CALLBACK(hide_window_cb), NULL);
2290
2291     gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2292     gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2293     gtk_widget_show(g->inspector_window);
2294
2295     scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2296     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2297             GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2298     gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2299     gtk_widget_show(scrolled_window);
2300
2301     new_web_view = webkit_web_view_new();
2302     gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2303
2304     return WEBKIT_WEB_VIEW(new_web_view);
2305 }
2306
2307 static gboolean
2308 inspector_show_window_cb (WebKitWebInspector* inspector){
2309     (void) inspector;
2310     gtk_widget_show(uzbl.gui.inspector_window);
2311     return TRUE;
2312 }
2313
2314 /* TODO: Add variables and code to make use of these functions */
2315 static gboolean
2316 inspector_close_window_cb (WebKitWebInspector* inspector){
2317     (void) inspector;
2318     return TRUE;
2319 }
2320
2321 static gboolean
2322 inspector_attach_window_cb (WebKitWebInspector* inspector){
2323     (void) inspector;
2324     return FALSE;
2325 }
2326
2327 static gboolean
2328 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2329     (void) inspector;
2330     return FALSE;
2331 }
2332
2333 static gboolean
2334 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2335     (void) inspector;
2336     return FALSE;
2337 }
2338
2339 static gboolean
2340 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2341     (void) inspector;
2342     return FALSE;
2343 }
2344
2345 static void
2346 set_up_inspector() {
2347     GUI *g = &uzbl.gui;
2348     WebKitWebSettings *settings = view_settings();
2349     g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2350
2351     uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2352     g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2353     g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2354     g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2355     g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2356     g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2357     g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2358
2359     g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2360 }
2361
2362 static void
2363 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2364     (void) ud;
2365     uzbl_cmdprop *c = v;
2366
2367     if(!c->dump)
2368         return;
2369
2370     if(c->type == TYPE_STR)
2371         printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2372     else if(c->type == TYPE_INT)
2373         printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2374 }
2375
2376 static void
2377 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2378     (void) ud;
2379     Action *a = v;
2380 <<<<<<< HEAD:uzbl.c
2381
2382     printf("bind %s = %s %s\n", (char *)k ,
2383             (char *)a->name, a->param?(char *)a->param:"");
2384 }
2385
2386 =======
2387
2388     printf("bind %s = %s %s\n", (char *)k ,
2389             (char *)a->name, a->param?(char *)a->param:"");
2390 }
2391
2392 >>>>>>> dieterbe/experimental:uzbl.c
2393 static void
2394 dump_config() {
2395     g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2396     g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2397 }
2398
2399 /** -- MAIN -- **/
2400 int
2401 main (int argc, char* argv[]) {
2402     gtk_init (&argc, &argv);
2403     if (!g_thread_supported ())
2404         g_thread_init (NULL);
2405     uzbl.state.executable_path = g_strdup(argv[0]);
2406     uzbl.state.selected_url = NULL;
2407     uzbl.state.searchtx = NULL;
2408
2409     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2410     g_option_context_add_main_entries (context, entries, NULL);
2411     g_option_context_add_group (context, gtk_get_option_group (TRUE));
2412     g_option_context_parse (context, &argc, &argv, NULL);
2413     g_option_context_free(context);
2414     
2415     gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2416     gboolean verbose_override = uzbl.state.verbose;
2417
2418     /* initialize hash table */
2419     uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2420
2421     uzbl.net.soup_session = webkit_get_default_session();
2422     uzbl.state.keycmd = g_string_new("");
2423
2424     if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2425         fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2426     if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2427         fprintf(stderr, "uzbl: error hooking SIGINT\n");
2428     if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2429         fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2430
2431
2432     if(uname(&uzbl.state.unameinfo) == -1)
2433         g_printerr("Can't retrieve unameinfo.  Your useragent might appear wrong.\n");
2434
2435     uzbl.gui.sbar.progress_s = g_strdup("=");
2436     uzbl.gui.sbar.progress_u = g_strdup("ยท");
2437     uzbl.gui.sbar.progress_w = 10;
2438
2439     /* HTML mode defaults*/
2440     uzbl.behave.html_buffer = g_string_new("");
2441     uzbl.behave.html_endmarker = g_strdup(".");
2442     uzbl.behave.html_timeout = 60;
2443     uzbl.behave.base_url = g_strdup("http://invalid");
2444
2445     /* default mode indicators */
2446     uzbl.behave.insert_indicator = g_strdup("I");
2447     uzbl.behave.cmd_indicator    = g_strdup("C");
2448
2449 <<<<<<< HEAD:uzbl.c
2450     setup_regex();
2451 =======
2452 >>>>>>> dieterbe/experimental:uzbl.c
2453     setup_scanner();
2454     commands_hash ();
2455     make_var_to_name_hash();
2456
2457     uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2458
2459     uzbl.gui.scrolled_win = create_browser();
2460     create_mainbar();
2461
2462     /* initial packing */
2463     gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2464     gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2465
2466     uzbl.gui.main_window = create_window ();
2467     gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2468
2469
2470     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2471     gtk_widget_show_all (uzbl.gui.main_window);
2472     uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2473
2474     if (uzbl.state.verbose) {
2475         printf("Uzbl start location: %s\n", argv[0]);
2476         printf("window_id %i\n",(int) uzbl.xwin);
2477         printf("pid %i\n", getpid ());
2478         printf("name: %s\n", uzbl.state.instance_name);
2479     }
2480
2481     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2482     uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2483     uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2484     uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2485     gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2486
2487     settings_init ();
2488
2489     if (!uzbl.behave.show_status)
2490         gtk_widget_hide(uzbl.gui.mainbar);
2491     else
2492         update_title();
2493
2494     /* WebInspector */
2495     set_up_inspector();
2496
2497     create_stdin();
2498
2499     if (verbose_override > uzbl.state.verbose)
2500         uzbl.state.verbose = verbose_override;
2501     
2502     if (uri_override) {
2503         set_var_value("uri", uri_override);
2504         g_free(uri_override);
2505     } else if (uzbl.state.uri)
2506         cmd_load_uri(uzbl.gui.web_view, NULL);
2507
2508     gtk_main ();
2509     clean_up();
2510
2511     return EXIT_SUCCESS;
2512 }
2513
2514 /* vi: set et ts=4: */