Applied commit http://github.com/robm/uzbl/commit/17160f7aaeac7bb822d260a00d33109d014...
[uzbl-mobile] / uzbl.c-temp
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 <webkit/webkit.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include <string.h>
51 #include <fcntl.h>
52 #include <sys/socket.h>
53 #include <sys/un.h>
54 #include <libsoup/soup.h>
55 #include <signal.h>
56 #include "uzbl.h"
57
58
59 static Uzbl uzbl;
60
61 /* define names and pointers to all config specific variables */
62 typedef const struct {
63     void **ptr;
64     int type;
65     void (*func)(void);
66 } uzbl_cmdprop;
67
68 enum {TYPE_INT, TYPE_STRING};
69
70 const struct {
71     char *name;
72     uzbl_cmdprop cp;
73 } var_name_to_ptr[] = {
74 /*    variable name           pointer to variable in code                         variable type      callback function  */
75 /*  ------------------------------------------------------------------------------------------------------------------- */
76     { "uri",                {.ptr = (void *)&uzbl.state.uri,                   .type = TYPE_STRING, .func = cmd_load_uri}},
77     { "status_message",     {.ptr = (void *)&uzbl.gui.sbar.msg,                .type = TYPE_STRING, .func = update_title}},
78     { "show_status",        {.ptr = (void *)&uzbl.behave.show_status,          .type = TYPE_INT,    .func = cmd_set_status}},
79     { "status_top",         {.ptr = (void *)&uzbl.behave.status_top,           .type = TYPE_INT,    .func = move_statusbar}},
80     { "status_format",      {.ptr = (void *)&uzbl.behave.status_format,        .type = TYPE_STRING, .func = update_title}},
81     { "status_background",  {.ptr = (void *)&uzbl.behave.status_background,    .type = TYPE_STRING, .func = update_title}},
82     { "title_format_long",  {.ptr = (void *)&uzbl.behave.title_format_long,    .type = TYPE_STRING, .func = update_title}},
83     { "title_format_short", {.ptr = (void *)&uzbl.behave.title_format_short,   .type = TYPE_STRING, .func = update_title}},
84     { "insert_mode",        {.ptr = (void *)&uzbl.behave.insert_mode,          .type = TYPE_INT,    .func = NULL}},
85     { "always_insert_mode", {.ptr = (void *)&uzbl.behave.always_insert_mode,   .type = TYPE_INT,    .func = cmd_always_insert_mode}},
86     { "reset_command_mode", {.ptr = (void *)&uzbl.behave.reset_command_mode,   .type = TYPE_INT,    .func = NULL}},
87     { "modkey"     ,        {.ptr = (void *)&uzbl.behave.modkey,               .type = TYPE_STRING, .func = cmd_modkey}},
88     { "load_finish_handler",{.ptr = (void *)&uzbl.behave.load_finish_handler,  .type = TYPE_STRING, .func = NULL}},
89     { "load_start_handler", {.ptr = (void *)&uzbl.behave.load_start_handler,   .type = TYPE_STRING, .func = NULL}},
90     { "load_commit_handler",{.ptr = (void *)&uzbl.behave.load_commit_handler,  .type = TYPE_STRING, .func = NULL}},
91     { "history_handler",    {.ptr = (void *)&uzbl.behave.history_handler,      .type = TYPE_STRING, .func = NULL}},
92     { "download_handler",   {.ptr = (void *)&uzbl.behave.download_handler,     .type = TYPE_STRING, .func = NULL}},
93     { "cookie_handler",     {.ptr = (void *)&uzbl.behave.cookie_handler,       .type = TYPE_STRING, .func = NULL}},
94     { "fifo_dir",           {.ptr = (void *)&uzbl.behave.fifo_dir,             .type = TYPE_STRING, .func = cmd_fifo_dir}},
95     { "socket_dir",         {.ptr = (void *)&uzbl.behave.socket_dir,           .type = TYPE_STRING, .func = cmd_socket_dir}},
96     { "http_debug",         {.ptr = (void *)&uzbl.behave.http_debug,           .type = TYPE_INT,    .func = cmd_http_debug}},
97     { "default_font_size",  {.ptr = (void *)&uzbl.behave.default_font_size,    .type = TYPE_INT,    .func = cmd_default_font_size}},
98     { "minimum_font_size",  {.ptr = (void *)&uzbl.behave.minimum_font_size,    .type = TYPE_INT,    .func = cmd_minimum_font_size}},
99     { "shell_cmd",          {.ptr = (void *)&uzbl.behave.shell_cmd,            .type = TYPE_STRING, .func = NULL}},
100     { "proxy_url",          {.ptr = (void *)&uzbl.net.proxy_url,               .type = TYPE_STRING, .func = set_proxy_url}},
101     { "max_conns",          {.ptr = (void *)&uzbl.net.max_conns,               .type = TYPE_INT,    .func = cmd_max_conns}},
102     { "max_conns_host",     {.ptr = (void *)&uzbl.net.max_conns_host,          .type = TYPE_INT,    .func = cmd_max_conns_host}},
103     { "useragent",          {.ptr = (void *)&uzbl.net.useragent,               .type = TYPE_STRING, .func = cmd_useragent}},
104     { NULL,                 {.ptr = NULL,                                      .type = TYPE_INT,    .func = NULL}}
105 }, *n2v_p = var_name_to_ptr;
106
107 const struct {
108     char *key;
109     guint mask;
110 } modkeys[] = {
111     { "SHIFT",   GDK_SHIFT_MASK   }, // shift
112     { "LOCK",    GDK_LOCK_MASK    }, // capslock or shiftlock, depending on xserver's modmappings
113     { "CONTROL", GDK_CONTROL_MASK }, // control
114     { "MOD1",    GDK_MOD1_MASK    }, // 4th mod - normally alt but depends on modmappings
115     { "MOD2",    GDK_MOD2_MASK    }, // 5th mod
116     { "MOD3",    GDK_MOD3_MASK    }, // 6th mod
117     { "MOD4",    GDK_MOD4_MASK    }, // 7th mod
118     { "MOD5",    GDK_MOD5_MASK    }, // 8th mod
119     { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
120     { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
121     { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
122     { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
123     { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
124     { "SUPER",   GDK_SUPER_MASK   }, // super (since 2.10)
125     { "HYPER",   GDK_HYPER_MASK   }, // hyper (since 2.10)
126     { "META",    GDK_META_MASK    }, // meta (since 2.10)
127     { NULL,      0                }
128 };
129
130
131 /* construct a hash from the var_name_to_ptr array for quick access */
132 static void
133 make_var_to_name_hash() {
134     uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
135     while(n2v_p->name) {
136         g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
137         n2v_p++;
138     }
139 }
140
141 /* commandline arguments (set initial values for the state variables) */
142 static GOptionEntry entries[] =
143 {
144     { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
145     { "verbose", 'v', 0, G_OPTION_ARG_NONE,   &uzbl.state.verbose,       "Whether to print all messages or just errors.", NULL },
146     { "name",    'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" },
147     { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
148     { NULL,      0, 0, 0, NULL, NULL, NULL }
149 };
150
151 typedef void (*Command)(WebKitWebView*, GArray *argv);
152
153 /* --- UTILITY FUNCTIONS --- */
154
155 char *
156 itos(int val) {
157     char tmp[20];
158
159     snprintf(tmp, sizeof(tmp), "%i", val);
160     return g_strdup(tmp);
161 }
162
163 static gchar*
164 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
165
166 static char *
167 str_replace (const char* search, const char* replace, const char* string) {
168     gchar **buf;
169     char *ret;
170
171     buf = g_strsplit (string, search, -1);
172     ret = g_strjoinv (replace, buf);
173     g_strfreev(buf);
174
175     return ret;
176 }
177
178 static GArray*
179 read_file_by_line (gchar *path) {
180     GIOChannel *chan = NULL;
181     gchar *readbuf = NULL;
182     gsize len;
183     GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
184     int i = 0;
185     
186     chan = g_io_channel_new_file(path, "r", NULL);
187     
188     if (chan) {
189         while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
190             const gchar* val = g_strdup (readbuf);
191             g_array_append_val (lines, val);
192             g_free (readbuf);
193             i ++;
194         }
195         
196         g_io_channel_unref (chan);
197     } else {
198         fprintf(stderr, "File '%s' not be read.\n", path);
199     }
200     
201     return lines;
202 }
203
204 static
205 gchar* parseenv (const char* string) {
206     extern char** environ;
207     gchar* newstring = g_strdup (string);
208     int i = 0;
209
210     while (environ[i] != NULL) {
211         gchar** env = g_strsplit (environ[i], "=", 0);
212         gchar* envname = malloc (strlen (env[0]) + 1);
213
214         strcat (envname, "$");
215         strcat (envname, env[0]);
216
217         newstring = str_replace(envname, env[1], newstring);
218
219         g_free (envname);
220         //g_strfreev (env); - This still breaks uzbl, but shouldn't. The mystery thickens...
221         i ++;
222     }
223
224     return newstring;
225 }
226
227 static sigfunc*
228 setup_signal(int signr, sigfunc *shandler) {
229     struct sigaction nh, oh;
230
231     nh.sa_handler = shandler;
232     sigemptyset(&nh.sa_mask);
233     nh.sa_flags = 0;
234
235     if(sigaction(signr, &nh, &oh) < 0)
236         return SIG_ERR;
237
238     return NULL;
239 }
240
241 static void
242 clean_up(void) {
243     if (uzbl.behave.fifo_dir)
244         unlink (uzbl.comm.fifo_path);
245     if (uzbl.behave.socket_dir)
246         unlink (uzbl.comm.socket_path);
247
248     g_free(uzbl.state.executable_path);
249     g_string_free(uzbl.state.keycmd, TRUE);
250     g_hash_table_destroy(uzbl.bindings);
251     g_hash_table_destroy(uzbl.behave.commands);
252 }
253
254
255 /* --- SIGNAL HANDLER --- */
256
257 static void
258 catch_sigterm(int s) {
259     (void) s;
260     clean_up();
261 }
262
263 static void
264 catch_sigint(int s) {
265     (void) s;
266     clean_up();
267     exit(EXIT_SUCCESS);
268 }
269
270 /* --- CALLBACKS --- */
271
272 static gboolean
273 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
274     (void) web_view;
275     (void) frame;
276     (void) navigation_action;
277     (void) policy_decision;
278     (void) user_data;
279     const gchar* uri = webkit_network_request_get_uri (request);
280     if (uzbl.state.verbose)
281         printf("New window requested -> %s \n", uri);
282     new_window_load_uri(uri);
283     return (FALSE);
284 }
285
286 WebKitWebView*
287 create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer user_data) {
288     (void) web_view;
289     (void) frame;
290     (void) user_data;
291     if (uzbl.state.selected_url != NULL) {
292         if (uzbl.state.verbose)
293             printf("\nNew web view -> %s\n",uzbl.state.selected_url);
294         new_window_load_uri(uzbl.state.selected_url);
295     } else {
296         if (uzbl.state.verbose)
297             printf("New web view -> %s\n","Nothing to open, exiting");
298     }
299     return (NULL);
300 }
301
302 static gboolean
303 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
304     (void) web_view;
305     (void) user_data;
306     if (uzbl.behave.download_handler) {
307         const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
308         if (uzbl.state.verbose)
309             printf("Download -> %s\n",uri);
310         /* if urls not escaped, we may have to escape and quote uri before this call */
311         run_handler(uzbl.behave.download_handler, uri);
312     }
313     return (FALSE);
314 }
315
316 /* scroll a bar in a given direction */
317 static void
318 scroll (GtkAdjustment* bar, GArray *argv) {
319     gdouble amount;
320     gchar *end;
321
322     amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
323     if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
324     gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
325 }
326
327 static void scroll_begin(WebKitWebView* page, GArray *argv) {
328     (void) page; (void) argv;
329     gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
330 }
331
332 static void scroll_end(WebKitWebView* page, GArray *argv) {
333     (void) page; (void) argv;
334     gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
335                               gtk_adjustment_get_page_size(uzbl.gui.bar_v));
336 }
337
338 static void scroll_vert(WebKitWebView* page, GArray *argv) {
339     (void) page;
340     scroll(uzbl.gui.bar_v, argv);
341 }
342
343 static void scroll_horz(WebKitWebView* page, GArray *argv) {
344     (void) page;
345     scroll(uzbl.gui.bar_h, argv);
346 }
347
348 static void
349 cmd_set_status() {
350     if (!uzbl.behave.show_status) {
351         gtk_widget_hide(uzbl.gui.mainbar);
352     } else {
353         gtk_widget_show(uzbl.gui.mainbar);
354     }
355     update_title();
356 }
357
358 static void
359 toggle_status_cb (WebKitWebView* page, GArray *argv) {
360     (void)page;
361     (void)argv;
362
363     if (uzbl.behave.show_status) {
364         gtk_widget_hide(uzbl.gui.mainbar);
365     } else {
366         gtk_widget_show(uzbl.gui.mainbar);
367     }
368     uzbl.behave.show_status = !uzbl.behave.show_status;
369     update_title();
370 }
371
372 static void
373 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
374     (void) page;
375     (void) title;
376     (void) data;
377     //Set selected_url state variable
378     g_free(uzbl.state.selected_url);
379     uzbl.state.selected_url = NULL;
380     if (link) {
381         uzbl.state.selected_url = g_strdup(link);
382     }
383     update_title();
384 }
385
386 static void
387 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
388     (void) web_view;
389     (void) web_frame;
390     (void) data;
391     if (uzbl.gui.main_title)
392         g_free (uzbl.gui.main_title);
393     uzbl.gui.main_title = g_strdup (title);
394     update_title();
395 }
396
397 static void
398 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
399     (void) page;
400     (void) data;
401     uzbl.gui.sbar.load_progress = progress;
402     update_title();
403 }
404
405 static void
406 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
407     (void) page;
408     (void) frame;
409     (void) data;
410     if (uzbl.behave.load_finish_handler)
411         run_handler(uzbl.behave.load_finish_handler, "");
412 }
413
414 static void
415 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
416     (void) page;
417     (void) frame;
418     (void) data;
419     if (uzbl.behave.load_start_handler)
420         run_handler(uzbl.behave.load_start_handler, "");
421 }
422
423 static void
424 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
425     (void) page;
426     (void) data;
427     free (uzbl.state.uri);
428     GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
429     uzbl.state.uri = g_string_free (newuri, FALSE);
430     if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
431         uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
432         update_title();
433     }
434     g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
435     if (uzbl.behave.load_commit_handler)
436         run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
437 }
438
439 static void
440 destroy_cb (GtkWidget* widget, gpointer data) {
441     (void) widget;
442     (void) data;
443     gtk_main_quit ();
444 }
445
446 static void
447 log_history_cb () {
448    if (uzbl.behave.history_handler) {
449        time_t rawtime;
450        struct tm * timeinfo;
451        char date [80];
452        time ( &rawtime );
453        timeinfo = localtime ( &rawtime );
454 <<<<<<< HEAD:uzbl.c
455        strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
456 =======
457        strftime (date, 80, " \"%Y-%m-%d %H:%M:%S\"", timeinfo);
458 >>>>>>> 17160f7... Remove bunches of old code, fix run_handler, free some stuff:uzbl.c
459        run_handler(uzbl.behave.history_handler, date);
460    }
461 }
462
463
464 /* VIEW funcs (little webkit wrappers) */
465 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
466 VIEWFUNC(reload)
467 VIEWFUNC(reload_bypass_cache)
468 VIEWFUNC(stop_loading)
469 VIEWFUNC(zoom_in)
470 VIEWFUNC(zoom_out)
471 VIEWFUNC(go_back)
472 VIEWFUNC(go_forward)
473 #undef VIEWFUNC
474
475 /* -- command to callback/function map for things we cannot attach to any signals */
476 // TODO: reload
477 static struct {char *name; Command command[2];} cmdlist[] =
478 {   /* key                   function      no_split      */
479     { "back",               {view_go_back, 0}              },
480     { "forward",            {view_go_forward, 0}           },
481     { "scroll_vert",        {scroll_vert, 0}               },
482     { "scroll_horz",        {scroll_horz, 0}               },
483     { "scroll_begin",       {scroll_begin, 0}              },
484     { "scroll_end",         {scroll_end, 0}                },
485     { "reload",             {view_reload, 0},              },
486     { "reload_ign_cache",   {view_reload_bypass_cache, 0}  },
487     { "stop",               {view_stop_loading, 0},        },
488     { "zoom_in",            {view_zoom_in, 0},             }, //Can crash (when max zoom reached?).
489     { "zoom_out",           {view_zoom_out, 0},            },
490     { "uri",                {load_uri, NOSPLIT}            },
491     { "js",                 {run_js, NOSPLIT}              },
492     { "script",             {run_external_js, 0}           },
493     { "toggle_status",      {toggle_status_cb, 0}          },
494     { "spawn",              {spawn, 0}                     },
495     { "sh",                 {spawn_sh, 0}                  },
496     { "exit",               {close_uzbl, 0}                },
497     { "search",             {search_forward_text, NOSPLIT} },
498     { "search_reverse",     {search_reverse_text, NOSPLIT} },
499     { "toggle_insert_mode", {toggle_insert_mode, 0}        },
500     { "runcmd",             {runcmd, NOSPLIT}              }
501 };
502
503 static void
504 commands_hash(void)
505 {
506     unsigned int i;
507     uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
508
509     for (i = 0; i < LENGTH(cmdlist); i++)
510         g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
511 }
512
513 /* -- CORE FUNCTIONS -- */
514
515 void
516 free_action(gpointer act) {
517     Action *action = (Action*)act;
518     g_free(action->name);
519     if (action->param)
520         g_free(action->param);
521     g_free(action);
522 }
523
524 Action*
525 new_action(const gchar *name, const gchar *param) {
526     Action *action = g_new(Action, 1);
527
528     action->name = g_strdup(name);
529     if (param)
530         action->param = g_strdup(param);
531     else
532         action->param = NULL;
533
534     return action;
535 }
536
537 static bool
538 file_exists (const char * filename) {
539     return (access(filename, F_OK) == 0);
540 }
541
542 static void
543 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
544     (void)page;
545     (void)argv;
546
547     if (argv_idx(argv, 0)) {
548         if (strcmp (argv_idx(argv, 0), "0") == 0) {
549             uzbl.behave.insert_mode = FALSE;
550         } else {
551             uzbl.behave.insert_mode = TRUE;
552         }
553     } else {
554         uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
555     }
556
557     update_title();
558 }
559
560 static void
561 load_uri (WebKitWebView *web_view, GArray *argv) {
562     if (argv_idx(argv, 0)) {
563         GString* newuri = g_string_new (argv_idx(argv, 0));
564         if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
565             g_string_prepend (newuri, "http://");
566         /* if we do handle cookies, ask our handler for them */
567         webkit_web_view_load_uri (web_view, newuri->str);
568         g_string_free (newuri, TRUE);
569     }
570 }
571
572 static void
573 run_js (WebKitWebView * web_view, GArray *argv) {
574     if (argv_idx(argv, 0))
575         webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
576 }
577
578 static void
579 run_external_js (WebKitWebView * web_view, GArray *argv) {
580     if (argv_idx(argv, 0)) {
581         GArray* lines = read_file_by_line (argv_idx (argv, 0));
582         gchar*  js = NULL;
583         int i = 0;
584         gchar* line;
585
586         while ((line = g_array_index(lines, gchar*, i))) {
587             if (js == NULL) {
588                 js = g_strdup (line);
589             } else {
590                 gchar* newjs = g_strconcat (js, line, NULL);
591                 js = newjs;
592             }
593             i ++;
594         }
595         
596         if (uzbl.state.verbose)
597             printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
598
599         if (argv_idx (argv, 1)) {
600             gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
601             g_free (js);
602             js = newjs;
603         }
604         webkit_web_view_execute_script (web_view, js);
605         g_free (js);
606         g_array_free (lines, TRUE);
607     }
608 }
609
610 static void
611 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
612     if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0'))
613         uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
614
615     if (uzbl.state.searchtx != NULL) {
616         if (uzbl.state.verbose)
617             printf ("Searching: %s\n", uzbl.state.searchtx);
618
619         if (g_strcmp0 (uzbl.state.searchtx, uzbl.state.searchold) != 0) {
620             webkit_web_view_unmark_text_matches (page);
621             webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
622
623             if (uzbl.state.searchold != NULL)
624                 g_free (uzbl.state.searchold);
625
626             uzbl.state.searchold = g_strdup (uzbl.state.searchtx);
627         }
628
629         webkit_web_view_set_highlight_text_matches (page, TRUE);
630         webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
631         g_free(uzbl.state.searchtx);
632         uzbl.state.searchtx = NULL;
633     }
634 }
635
636 static void
637 search_forward_text (WebKitWebView *page, GArray *argv) {
638     search_text(page, argv, TRUE);
639 }
640
641 static void
642 search_reverse_text (WebKitWebView *page, GArray *argv) {
643     search_text(page, argv, FALSE);
644 }
645
646 static void
647 new_window_load_uri (const gchar * uri) {
648     GString* to_execute = g_string_new ("");
649     g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
650     int i;
651     for (i = 0; entries[i].long_name != NULL; i++) {
652         if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
653             gchar** str = (gchar**)entries[i].arg_data;
654             if (*str!=NULL) {
655                 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
656             }
657         }
658     }
659     if (uzbl.state.verbose)
660         printf("\n%s\n", to_execute->str);
661     g_spawn_command_line_async (to_execute->str, NULL);
662     g_string_free (to_execute, TRUE);
663 }
664
665 static void
666 close_uzbl (WebKitWebView *page, GArray *argv) {
667     (void)page;
668     (void)argv;
669     gtk_main_quit ();
670 }
671
672 /* --Statusbar functions-- */
673 static char*
674 build_progressbar_ascii(int percent) {
675    int width=10;
676    int i;
677    double l;
678    GString *bar = g_string_new("");
679
680    l = (double)percent*((double)width/100.);
681    l = (int)(l+.5)>=(int)l ? l+.5 : l;
682
683    for(i=0; i<(int)l; i++)
684        g_string_append(bar, "=");
685
686    for(; i<width; i++)
687        g_string_append(bar, "·");
688
689    return g_string_free(bar, FALSE);
690 }
691
692 static void
693 setup_scanner() {
694      const GScannerConfig scan_config = {
695              (
696               "\t\r\n"
697              )            /* cset_skip_characters */,
698              (
699               G_CSET_a_2_z
700               "_#"
701               G_CSET_A_2_Z
702              )            /* cset_identifier_first */,
703              (
704               G_CSET_a_2_z
705               "_0123456789"
706               G_CSET_A_2_Z
707               G_CSET_LATINS
708               G_CSET_LATINC
709              )            /* cset_identifier_nth */,
710              ( "" )    /* cpair_comment_single */,
711
712              TRUE         /* case_sensitive */,
713
714              FALSE        /* skip_comment_multi */,
715              FALSE        /* skip_comment_single */,
716              FALSE        /* scan_comment_multi */,
717              TRUE         /* scan_identifier */,
718              TRUE         /* scan_identifier_1char */,
719              FALSE        /* scan_identifier_NULL */,
720              TRUE         /* scan_symbols */,
721              FALSE        /* scan_binary */,
722              FALSE        /* scan_octal */,
723              FALSE        /* scan_float */,
724              FALSE        /* scan_hex */,
725              FALSE        /* scan_hex_dollar */,
726              FALSE        /* scan_string_sq */,
727              FALSE        /* scan_string_dq */,
728              TRUE         /* numbers_2_int */,
729              FALSE        /* int_2_float */,
730              FALSE        /* identifier_2_string */,
731              FALSE        /* char_2_token */,
732              FALSE        /* symbol_2_token */,
733              TRUE         /* scope_0_fallback */,
734              FALSE,
735              TRUE
736      };
737
738      uzbl.scan = g_scanner_new(&scan_config);
739      while(symp->symbol_name) {
740          g_scanner_scope_add_symbol(uzbl.scan, 0,
741                          symp->symbol_name,
742                          GINT_TO_POINTER(symp->symbol_token));
743          symp++;
744      }
745 }
746
747 static gchar *
748 expand_template(const char *template) {
749      if(!template) return NULL;
750
751      GTokenType token = G_TOKEN_NONE;
752      GString *ret = g_string_new("");
753      char *buf=NULL;
754      int sym;
755
756      g_scanner_input_text(uzbl.scan, template, strlen(template));
757      while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
758          token = g_scanner_get_next_token(uzbl.scan);
759
760          if(token == G_TOKEN_SYMBOL) {
761              sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
762              switch(sym) {
763                  case SYM_URI:
764                      buf = uzbl.state.uri?
765                          g_markup_printf_escaped("%s", uzbl.state.uri) :
766                          g_strdup("");
767                      g_string_append(ret, buf);
768                      free(buf);
769                      break;
770                  case SYM_LOADPRGS:
771                      buf = itos(uzbl.gui.sbar.load_progress);
772                      g_string_append(ret, buf);
773                      free(buf);
774                      break;
775                  case SYM_LOADPRGSBAR:
776                      buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
777                      g_string_append(ret, buf);
778                      g_free(buf);
779                      break;
780                  case SYM_TITLE:
781                      buf = uzbl.gui.main_title?
782                          g_markup_printf_escaped("%s", uzbl.gui.main_title) :
783                          g_strdup("");
784                      g_string_append(ret, buf);
785                      free(buf);
786                      break;
787                  case SYM_SELECTED_URI:
788                      buf = uzbl.state.selected_url?
789                          g_markup_printf_escaped("%s", uzbl.state.selected_url) :
790                          g_strdup("");
791                      g_string_append(ret, buf);
792                      free(buf);
793                     break;
794                  case SYM_NAME:
795                      buf = itos(uzbl.xwin);
796                      g_string_append(ret,
797                          uzbl.state.instance_name?uzbl.state.instance_name:buf);
798                      free(buf);
799                      break;
800                  case SYM_KEYCMD:
801                      buf = uzbl.state.keycmd->str?
802                          g_markup_printf_escaped("%s", uzbl.state.keycmd->str) :
803                          g_strdup("");
804                      g_string_append(ret, buf);
805                      free(buf);
806                      break;
807                  case SYM_MODE:
808                      g_string_append(ret,
809                          uzbl.behave.insert_mode?"[I]":"[C]");
810                      break;
811                  case SYM_MSG:
812                      g_string_append(ret,
813                          uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
814                      break;
815                      /* useragent syms */
816                  case SYM_WK_MAJ:
817                      buf = itos(WEBKIT_MAJOR_VERSION);
818                      g_string_append(ret, buf);
819                      free(buf);
820                      break;
821                  case SYM_WK_MIN:
822                      buf = itos(WEBKIT_MINOR_VERSION);
823                      g_string_append(ret, buf);
824                      free(buf);
825                      break;
826                  case SYM_WK_MIC:
827                      buf = itos(WEBKIT_MICRO_VERSION);
828                      g_string_append(ret, buf);
829                      free(buf);
830                      break;
831                  case SYM_SYSNAME:
832                      g_string_append(ret, uzbl.state.unameinfo.sysname);
833                      break;
834                  case SYM_NODENAME:
835                      g_string_append(ret, uzbl.state.unameinfo.nodename);
836                      break;
837                  case SYM_KERNREL:
838                      g_string_append(ret, uzbl.state.unameinfo.release);
839                      break;
840                  case SYM_KERNVER:
841                      g_string_append(ret, uzbl.state.unameinfo.version);
842                      break;
843                  case SYM_ARCHSYS:
844                      g_string_append(ret, uzbl.state.unameinfo.machine);
845                      break;
846                  case SYM_ARCHUZBL:
847                      g_string_append(ret, ARCH);
848                      break;
849 #ifdef _GNU_SOURCE
850                  case SYM_DOMAINNAME:
851                      g_string_append(ret, uzbl.state.unameinfo.domainname);
852                      break;
853 #endif
854                  case SYM_COMMIT:
855                      g_string_append(ret, COMMIT);
856                      break;
857                  default:
858                      break;
859              }
860          }
861          else if(token == G_TOKEN_INT) {
862              buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
863              g_string_append(ret, buf);
864              free(buf);
865          }
866          else if(token == G_TOKEN_IDENTIFIER) {
867              g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
868          }
869          else if(token == G_TOKEN_CHAR) {
870              g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
871          }
872      }
873
874      return g_string_free(ret, FALSE);
875 }
876 /* --End Statusbar functions-- */
877
878 static void
879 sharg_append(GArray *a, const gchar *str) {
880     const gchar *s = (str ? str : "");
881     g_array_append_val(a, s);
882 }
883
884 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
885 static gboolean
886 run_command (const gchar *command, const guint npre, const gchar **args,
887              const gboolean sync, char **stdout) {
888    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
889     GError *err = NULL;
890     
891     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
892     gchar *pid = itos(getpid());
893     gchar *xwin = itos(uzbl.xwin);
894     guint i;
895     sharg_append(a, command);
896     for (i = 0; i < npre; i++) /* add n args before the default vars */
897         sharg_append(a, args[i]);
898     sharg_append(a, uzbl.state.config_file);
899     sharg_append(a, pid);
900     sharg_append(a, xwin);
901     sharg_append(a, uzbl.comm.fifo_path);
902     sharg_append(a, uzbl.comm.socket_path);
903     sharg_append(a, uzbl.state.uri);
904     sharg_append(a, uzbl.gui.main_title);
905
906 <<<<<<< HEAD:uzbl.c
907     for (i = npre; i < g_strv_length((gchar**)args); i++)
908 =======
909     guint i;
910     for (i = 0; i < g_strv_length(args); i++)
911 >>>>>>> 17160f7... Remove bunches of old code, fix run_handler, free some stuff:uzbl.c
912         sharg_append(a, args[i]);
913     gboolean result;
914     if (sync) result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
915                                     NULL, NULL, stdout, NULL, NULL, &err);
916     else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
917                                 NULL, NULL, NULL, &err);
918
919     if (uzbl.state.verbose) {
920 <<<<<<< HEAD:uzbl.c
921         GString *s = g_string_new("spawned:");
922         for (i = 0; i < (a->len); i++) {
923             gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
924             g_string_append_printf(s, " %s", qarg);
925             g_free (qarg);
926         }
927         g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
928         printf("%s\n", s->str);
929         g_string_free(s, TRUE);
930 =======
931         gchar *cli = g_strjoinv(" ", (gchar **)a->data);
932         printf("Called %s.  Result: %s\n", cli, (result ? "TRUE" : "FALSE" ));
933         g_free (cli);
934 >>>>>>> 17160f7... Remove bunches of old code, fix run_handler, free some stuff:uzbl.c
935     }
936     if (err) {
937         g_printerr("error on run_command: %s\n", err->message);
938         g_error_free (err);
939     }
940     g_free (pid);
941     g_free (xwin);
942 <<<<<<< HEAD:uzbl.c
943     g_array_free (a, TRUE);
944 =======
945     g_array_free (a, FALSE);
946 >>>>>>> 17160f7... Remove bunches of old code, fix run_handler, free some stuff:uzbl.c
947     return result;
948 }
949
950 static gchar**
951 split_quoted(const gchar* src, const gboolean unquote) {
952     /* split on unquoted space, return array of strings;
953        remove a layer of quotes and backslashes if unquote */
954     if (!src) return NULL;
955     
956     gboolean dq = FALSE;
957     gboolean sq = FALSE;
958     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
959     GString *s = g_string_new ("");
960     const gchar *p;
961     gchar **ret;
962     gchar *dup;
963     for (p = src; *p != '\0'; p++) {
964         if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
965         else if (*p == '\\') { g_string_append_c(s, *p++);
966                                g_string_append_c(s, *p); }
967         else if ((*p == '"') && unquote && !sq) dq = !dq;
968         else if (*p == '"' && !sq) { g_string_append_c(s, *p);
969                                      dq = !dq; }
970         else if ((*p == '\'') && unquote && !dq) sq = !sq;
971         else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
972                                       sq = ! sq; }
973         else if ((*p == ' ') && !dq && !sq) {
974             dup = g_strdup(s->str);
975             g_array_append_val(a, dup);
976             g_string_truncate(s, 0);
977         } else g_string_append_c(s, *p);
978     }
979     dup = g_strdup(s->str);
980     g_array_append_val(a, dup);
981     ret = (gchar**)a->data;
982     g_array_free (a, FALSE);
983     g_string_free (s, TRUE);
984     return ret;
985 }
986
987 static void
988 spawn(WebKitWebView *web_view, GArray *argv) {
989     (void)web_view;
990     //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
991 <<<<<<< HEAD:uzbl.c
992     if (argv_idx(argv, 0)) run_command(argv_idx(argv, 0), 0, (const gchar **) argv->data + sizeof(gchar*), FALSE, NULL);
993 =======
994     gchar **cmd = split_quoted(param);
995     if (cmd) run_command(cmd[0], &cmd[1], FALSE, NULL);
996     g_strfreev (cmd);
997 >>>>>>> 17160f7... Remove bunches of old code, fix run_handler, free some stuff:uzbl.c
998 }
999
1000 static void
1001 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1002     (void)web_view;
1003     if (!uzbl.behave.shell_cmd) {
1004         g_printerr ("spawn_sh: shell_cmd is not set!\n");
1005         return;
1006     }
1007     
1008     guint i;
1009     gchar *spacer = g_strdup("");
1010     g_array_insert_val(argv, 1, spacer);
1011     gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1012
1013     for (i = 1; i < g_strv_length(cmd); i++)
1014         g_array_prepend_val(argv, cmd[i]);
1015
1016     if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1017     g_free (spacer);
1018     g_strfreev (cmd);
1019 }
1020
1021 static void
1022 parse_command(const char *cmd, const char *param) {
1023     Command *c;
1024
1025     if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1026
1027             guint i;
1028             gchar **par = split_quoted(param, TRUE);
1029             GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1030
1031             if (c[1]) { /* don't split */
1032                 sharg_append(a, param);
1033             } else {
1034                 for (i = 0; i < g_strv_length(par); i++)
1035                     sharg_append(a, par[i]);
1036             }
1037             c[0](uzbl.gui.web_view, a);
1038             g_strfreev (par);
1039             g_array_free (a, TRUE);
1040
1041     } else
1042         g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1043 }
1044
1045 /* command parser */
1046 static void
1047 setup_regex() {
1048     uzbl.comm.get_regex  = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1049             G_REGEX_OPTIMIZE, 0, NULL);
1050     uzbl.comm.set_regex  = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1051             G_REGEX_OPTIMIZE, 0, NULL);
1052     uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1053             G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1054     uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1055             G_REGEX_OPTIMIZE, 0, NULL);
1056     uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1057             G_REGEX_OPTIMIZE, 0, NULL);
1058 }
1059
1060 static gboolean
1061 get_var_value(gchar *name) {
1062     uzbl_cmdprop *c;
1063
1064     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1065         if(c->type == TYPE_STRING)
1066             printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1067         else if(c->type == TYPE_INT)
1068             printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1069     }
1070     return TRUE;
1071 }
1072
1073 static void
1074 set_proxy_url() {
1075     SoupURI *suri;
1076
1077     if(*uzbl.net.proxy_url == ' '
1078        || uzbl.net.proxy_url == NULL) {
1079         soup_session_remove_feature_by_type(uzbl.net.soup_session,
1080                 (GType) SOUP_SESSION_PROXY_URI);
1081     }
1082     else {
1083         suri = soup_uri_new(uzbl.net.proxy_url);
1084         g_object_set(G_OBJECT(uzbl.net.soup_session),
1085                 SOUP_SESSION_PROXY_URI,
1086                 suri, NULL);
1087         soup_uri_free(suri);
1088     }
1089     return;
1090 }
1091
1092 static void
1093 cmd_load_uri() {
1094     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1095     g_array_append_val (a, uzbl.state.uri);
1096     load_uri(uzbl.gui.web_view, a);
1097     g_array_free (a, TRUE);
1098 }
1099
1100 static void 
1101 cmd_always_insert_mode() {
1102     uzbl.behave.insert_mode =
1103         uzbl.behave.always_insert_mode ?  TRUE : FALSE;
1104     update_title();
1105 }
1106
1107 static void
1108 cmd_max_conns() {
1109     g_object_set(G_OBJECT(uzbl.net.soup_session),
1110             SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1111 }
1112
1113 static void
1114 cmd_max_conns_host() {
1115     g_object_set(G_OBJECT(uzbl.net.soup_session),
1116             SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1117 }
1118
1119 static void
1120 cmd_http_debug() {
1121     soup_session_remove_feature
1122         (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1123     /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1124     /*g_free(uzbl.net.soup_logger);*/
1125
1126     uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1127     soup_session_add_feature(uzbl.net.soup_session,
1128             SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1129 }
1130
1131 static void
1132 cmd_default_font_size() {
1133     WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
1134     g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.default_font_size, NULL);
1135 }
1136
1137 static void
1138 cmd_minimum_font_size() {
1139     WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
1140     g_object_set (G_OBJECT(ws), "minimum-font-size", uzbl.behave.minimum_font_size, NULL);
1141 }
1142
1143 static void
1144 cmd_fifo_dir() {
1145     char *buf;
1146
1147     buf = init_fifo(uzbl.behave.fifo_dir);
1148     if(uzbl.behave.fifo_dir) 
1149         free(uzbl.behave.fifo_dir);
1150
1151     uzbl.behave.fifo_dir = buf?buf:g_strdup("");
1152 }
1153
1154 static void
1155 cmd_socket_dir() {
1156     char *buf;
1157
1158     buf = init_socket(uzbl.behave.fifo_dir);
1159     if(uzbl.behave.socket_dir) 
1160         free(uzbl.behave.socket_dir);
1161
1162     uzbl.behave.socket_dir = buf?buf:g_strdup("");
1163 }
1164
1165 static void
1166 cmd_modkey() {
1167     int i;
1168     char *buf;
1169
1170     buf = g_utf8_strup(uzbl.behave.modkey, -1);
1171     uzbl.behave.modmask = 0;
1172     
1173     if(uzbl.behave.modkey) 
1174         free(uzbl.behave.modkey);
1175
1176     for (i = 0; modkeys[i].key != NULL; i++) {
1177         if (g_strrstr(buf, modkeys[i].key))
1178             uzbl.behave.modmask |= modkeys[i].mask;
1179     }
1180 }
1181
1182 static void
1183 cmd_useragent() {
1184     char *buf;
1185
1186     buf = set_useragent(uzbl.net.useragent);
1187     if(uzbl.net.useragent) 
1188         free(uzbl.net.useragent);
1189             
1190     uzbl.net.useragent = buf?buf:g_strdup("");
1191 }
1192
1193 static void
1194 move_statusbar() {
1195     gtk_widget_ref(uzbl.gui.scrolled_win);
1196     gtk_widget_ref(uzbl.gui.mainbar);
1197     gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1198     gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1199
1200     if(uzbl.behave.status_top) {
1201         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1202         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1203     }
1204     else {
1205         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1206         gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1207     }
1208     gtk_widget_unref(uzbl.gui.scrolled_win);
1209     gtk_widget_unref(uzbl.gui.mainbar);
1210     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1211     return;
1212 }
1213
1214 static gboolean
1215 set_var_value(gchar *name, gchar *val) {
1216     void *p = NULL;
1217     uzbl_cmdprop *c = NULL;
1218     char *endp = NULL;
1219     char *buf=NULL;
1220
1221     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1222         /* check for the variable type */
1223         if (c->type == TYPE_STRING) {
1224             free(*c->ptr);
1225             *c->ptr = g_strdup(val);
1226         } else if(c->type == TYPE_INT) {
1227             int *ip = c->ptr;
1228             *ip = (int)strtoul(val, &endp, 10);
1229         }
1230
1231         /* invoke a command specific function */
1232         if(c->func) c->func();
1233
1234         /* this will be removed as soon as we have converted to
1235         * the callback interface
1236         */
1237         p = *c->ptr;
1238     }
1239     return TRUE;
1240 }
1241
1242 static void
1243 runcmd(WebKitWebView* page, GArray *argv) {
1244     (void) page;
1245     parse_cmd_line(argv_idx(argv, 0));
1246 }
1247
1248 static void
1249 parse_cmd_line(const char *ctl_line) {
1250     gchar **tokens;
1251
1252     /* SET command */
1253     if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1254         tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1255         if(tokens[0][0] == 0) {
1256             gchar* value = parseenv (tokens[2]);
1257             set_var_value(tokens[1], value);
1258             g_strfreev(tokens);
1259             g_free(value);
1260         }
1261         else
1262             printf("Error in command: %s\n", tokens[0]);
1263     }
1264     /* GET command */
1265     else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1266         tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1267         if(tokens[0][0] == 0) {
1268             get_var_value(tokens[1]);
1269             g_strfreev(tokens);
1270         }
1271         else
1272             printf("Error in command: %s\n", tokens[0]);
1273     }
1274     /* BIND command */
1275     else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1276         tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1277         if(tokens[0][0] == 0) {
1278             gchar* value = parseenv (tokens[2]);
1279             add_binding(tokens[1], value);
1280             g_strfreev(tokens);
1281             g_free(value);
1282         }
1283         else
1284             printf("Error in command: %s\n", tokens[0]);
1285     }
1286     /* ACT command */
1287     else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1288         tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1289         if(tokens[0][0] == 0) {
1290             parse_command(tokens[1], tokens[2]);
1291             g_strfreev(tokens);
1292         }
1293         else
1294             printf("Error in command: %s\n", tokens[0]);
1295     }
1296     /* KEYCMD command */
1297     else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1298         tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1299         if(tokens[0][0] == 0) {
1300             /* should incremental commands want each individual "keystroke"
1301                sent in a loop or the whole string in one go like now? */
1302             g_string_assign(uzbl.state.keycmd, tokens[1]);
1303             run_keycmd(FALSE);
1304             if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1305                 run_keycmd(TRUE);
1306             update_title();
1307             g_strfreev(tokens);
1308         }
1309     }
1310     /* Comments */
1311     else if(   (ctl_line[0] == '#')
1312             || (ctl_line[0] == ' ')
1313             || (ctl_line[0] == '\n'))
1314         ; /* ignore these lines */
1315     else
1316         printf("Command not understood (%s)\n", ctl_line);
1317
1318     return;
1319 }
1320
1321 static gchar*
1322 build_stream_name(int type, const gchar* dir) {
1323     char *xwin_str;
1324     State *s = &uzbl.state;
1325     gchar *str;
1326
1327     xwin_str = itos((int)uzbl.xwin);
1328     if (type == FIFO) {
1329         str = g_strdup_printf
1330             ("%s/uzbl_fifo_%s", dir,
1331              s->instance_name ? s->instance_name : xwin_str);
1332     } else if (type == SOCKET) {
1333         str = g_strdup_printf
1334             ("%s/uzbl_socket_%s", dir,
1335              s->instance_name ? s->instance_name : xwin_str );
1336     }
1337     g_free(xwin_str);
1338     return str;
1339 }
1340
1341 static gboolean
1342 control_fifo(GIOChannel *gio, GIOCondition condition) {
1343     if (uzbl.state.verbose)
1344         printf("triggered\n");
1345     gchar *ctl_line;
1346     GIOStatus ret;
1347     GError *err = NULL;
1348
1349     if (condition & G_IO_HUP)
1350         g_error ("Fifo: Read end of pipe died!\n");
1351
1352     if(!gio)
1353        g_error ("Fifo: GIOChannel broke\n");
1354
1355     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1356     if (ret == G_IO_STATUS_ERROR) {
1357         g_error ("Fifo: Error reading: %s\n", err->message);
1358         g_error_free (err);
1359     }
1360
1361     parse_cmd_line(ctl_line);
1362     g_free(ctl_line);
1363
1364     return TRUE;
1365 }
1366
1367 static gchar*
1368 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1369     if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1370         if (unlink(uzbl.comm.fifo_path) == -1)
1371             g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1372         g_free(uzbl.comm.fifo_path);
1373         uzbl.comm.fifo_path = NULL;
1374     }
1375
1376     if (*dir == ' ') { /* space unsets the variable */
1377         return NULL;
1378     }
1379
1380     GIOChannel *chan = NULL;
1381     GError *error = NULL;
1382     gchar *path = build_stream_name(FIFO, dir);
1383
1384     if (!file_exists(path)) {
1385         if (mkfifo (path, 0666) == 0) {
1386             // 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.
1387             chan = g_io_channel_new_file(path, "r+", &error);
1388             if (chan) {
1389                 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1390                     if (uzbl.state.verbose)
1391                         printf ("init_fifo: created successfully as %s\n", path);
1392                     uzbl.comm.fifo_path = path;
1393                     return dir;
1394                 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1395             } else g_warning ("init_fifo: can't open: %s\n", error->message);
1396         } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1397     } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1398
1399     /* if we got this far, there was an error; cleanup */
1400     if (error) g_error_free (error);
1401     g_free(path);
1402     return NULL;
1403 }
1404
1405 static gboolean
1406 control_stdin(GIOChannel *gio, GIOCondition condition) {
1407     gchar *ctl_line = NULL;
1408     GIOStatus ret;
1409
1410     if (condition & G_IO_HUP) {
1411         ret = g_io_channel_shutdown (gio, FALSE, NULL);
1412         return FALSE;
1413     }
1414
1415     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1416     if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1417         return FALSE;
1418
1419     parse_cmd_line(ctl_line);
1420     g_free(ctl_line);
1421
1422     return TRUE;
1423 }
1424
1425 static void
1426 create_stdin () {
1427     GIOChannel *chan = NULL;
1428     GError *error = NULL;
1429
1430     chan = g_io_channel_unix_new(fileno(stdin));
1431     if (chan) {
1432         if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1433             g_error ("Stdin: could not add watch\n");
1434         } else {
1435             if (uzbl.state.verbose)
1436                 printf ("Stdin: watch added successfully\n");
1437         }
1438     } else {
1439         g_error ("Stdin: Error while opening: %s\n", error->message);
1440     }
1441     if (error) g_error_free (error);
1442 }
1443
1444 static gboolean
1445 control_socket(GIOChannel *chan) {
1446     struct sockaddr_un remote;
1447     char buffer[512], *ctl_line;
1448     char temp[128];
1449     int sock, clientsock, n, done;
1450     unsigned int t;
1451
1452     sock = g_io_channel_unix_get_fd(chan);
1453
1454     memset (buffer, 0, sizeof (buffer));
1455
1456     t          = sizeof (remote);
1457     clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1458
1459     done = 0;
1460     do {
1461         memset (temp, 0, sizeof (temp));
1462         n = recv (clientsock, temp, 128, 0);
1463         if (n == 0) {
1464             buffer[strlen (buffer)] = '\0';
1465             done = 1;
1466         }
1467         if (!done)
1468             strcat (buffer, temp);
1469     } while (!done);
1470
1471     if (strcmp (buffer, "\n") < 0) {
1472         buffer[strlen (buffer) - 1] = '\0';
1473     } else {
1474         buffer[strlen (buffer)] = '\0';
1475     }
1476     close (clientsock);
1477     ctl_line = g_strdup(buffer);
1478     parse_cmd_line (ctl_line);
1479
1480 /*
1481    TODO: we should be able to do it with this.  but glib errors out with "Invalid argument"
1482     GError *error = NULL;
1483     gsize len;
1484     GIOStatus ret;
1485     ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1486     if (ret == G_IO_STATUS_ERROR)
1487         g_error ("Error reading: %s\n", error->message);
1488
1489     printf("Got line %s (%u bytes) \n",ctl_line, len);
1490     if(ctl_line) {
1491        parse_line(ctl_line);
1492 */
1493
1494     g_free(ctl_line);
1495     return TRUE;
1496 }
1497
1498 static gchar*
1499 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1500     if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1501         if (unlink(uzbl.comm.socket_path) == -1)
1502             g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1503         g_free(uzbl.comm.socket_path);
1504         uzbl.comm.socket_path = NULL;
1505     }
1506
1507     if (*dir == ' ') {
1508         g_free(dir);
1509         return NULL;
1510     }
1511
1512     GIOChannel *chan = NULL;
1513     int sock, len;
1514     struct sockaddr_un local;
1515     gchar *path = build_stream_name(SOCKET, dir);
1516
1517     sock = socket (AF_UNIX, SOCK_STREAM, 0);
1518
1519     local.sun_family = AF_UNIX;
1520     strcpy (local.sun_path, path);
1521     unlink (local.sun_path);
1522
1523     len = strlen (local.sun_path) + sizeof (local.sun_family);
1524     if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1525         if (uzbl.state.verbose)
1526             printf ("init_socket: opened in %s\n", path);
1527         listen (sock, 5);
1528
1529         if( (chan = g_io_channel_unix_new(sock)) ) {
1530             g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1531             uzbl.comm.socket_path = path;
1532             return dir;
1533         }
1534     } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1535
1536     /* if we got this far, there was an error; cleanup */
1537     g_free(path);
1538     g_free(dir);
1539     return NULL;
1540 }
1541
1542 /*
1543  NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1544  it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1545 */
1546 // this function may be called very early when the templates are not set (yet), hence the checks
1547 static void
1548 update_title (void) {
1549     Behaviour *b = &uzbl.behave;
1550     gchar *parsed;
1551
1552     if (b->show_status) {
1553         if (b->title_format_short) {
1554             parsed = expand_template(b->title_format_short);
1555             gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1556             g_free(parsed);
1557         }
1558         if (b->status_format) {
1559             parsed = expand_template(b->status_format);
1560             gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1561             g_free(parsed);
1562         }
1563         if (b->status_background) {
1564             GdkColor color;
1565             gdk_color_parse (b->status_background, &color);
1566             //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)
1567             gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1568         }
1569     } else {
1570         if (b->title_format_long) {
1571             parsed = expand_template(b->title_format_long);
1572             gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1573             g_free(parsed);
1574         }
1575     }
1576 }
1577
1578 static gboolean
1579 key_press_cb (GtkWidget* window, GdkEventKey* event)
1580 {
1581     //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1582
1583     (void) window;
1584
1585     if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1586         || 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)
1587         return FALSE;
1588
1589     /* turn off insert mode (if always_insert_mode is not used) */
1590     if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1591         uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1592         update_title();
1593         return TRUE;
1594     }
1595
1596     if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1597         return FALSE;
1598
1599     if (event->keyval == GDK_Escape) {
1600         g_string_truncate(uzbl.state.keycmd, 0);
1601         update_title();
1602         return TRUE;
1603     }
1604
1605     //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1606     if (event->keyval == GDK_Insert) {
1607         gchar * str;
1608         if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1609             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1610         } else {
1611             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1612         }
1613         if (str) {
1614             g_string_append (uzbl.state.keycmd, str);
1615             update_title ();
1616             free (str);
1617         }
1618         return TRUE;
1619     }
1620
1621     if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1622         g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1623         update_title();
1624     }
1625
1626     gboolean key_ret = FALSE;
1627     if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1628         key_ret = TRUE;
1629     if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1630
1631     run_keycmd(key_ret);
1632     update_title();
1633     if (key_ret) return (!uzbl.behave.insert_mode);
1634     return TRUE;
1635 }
1636
1637 static void
1638 run_keycmd(const gboolean key_ret) {
1639     /* run the keycmd immediately if it isn't incremental and doesn't take args */
1640     Action *action;
1641     if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1642         g_string_truncate(uzbl.state.keycmd, 0);
1643         parse_command(action->name, action->param);
1644         return;
1645     }
1646
1647     /* try if it's an incremental keycmd or one that takes args, and run it */
1648     GString* short_keys = g_string_new ("");
1649     GString* short_keys_inc = g_string_new ("");
1650     unsigned int i;
1651     for (i=0; i<(uzbl.state.keycmd->len); i++) {
1652         g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1653         g_string_assign(short_keys_inc, short_keys->str);
1654         g_string_append_c(short_keys, '_');
1655         g_string_append_c(short_keys_inc, '*');
1656
1657         gboolean exec_now = FALSE;
1658         if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1659             if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */
1660         } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1661             if (key_ret) { /* just quit the incremental command on return */
1662                 g_string_truncate(uzbl.state.keycmd, 0);
1663                 break;
1664             } else exec_now = TRUE; /* always exec incr. commands on keys other than return */
1665         }
1666
1667         if (exec_now) {
1668             GString* parampart = g_string_new (uzbl.state.keycmd->str);
1669             GString* actionname = g_string_new ("");
1670             GString* actionparam = g_string_new ("");
1671             g_string_erase (parampart, 0, i+1);
1672             if (action->name)
1673                 g_string_printf (actionname, action->name, parampart->str);
1674             if (action->param)
1675                 g_string_printf (actionparam, action->param, parampart->str);
1676             parse_command(actionname->str, actionparam->str);
1677             g_string_free (actionname, TRUE);
1678             g_string_free (actionparam, TRUE);
1679             g_string_free (parampart, TRUE);
1680             if (key_ret)
1681                 g_string_truncate(uzbl.state.keycmd, 0);
1682             break;
1683         }
1684
1685         g_string_truncate(short_keys, short_keys->len - 1);
1686     }
1687     g_string_free (short_keys, TRUE);
1688     g_string_free (short_keys_inc, TRUE);
1689 }
1690
1691 static GtkWidget*
1692 create_browser () {
1693     GUI *g = &uzbl.gui;
1694
1695     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1696     //main_window_ref = g_object_ref(scrolled_window);
1697     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
1698
1699     g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1700     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1701
1702     g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1703     g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1704     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1705     g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1706     g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1707     g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1708     g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1709     g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1710     g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1711     g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1712
1713     return scrolled_window;
1714 }
1715
1716 static GtkWidget*
1717 create_mainbar () {
1718     GUI *g = &uzbl.gui;
1719
1720     g->mainbar = gtk_hbox_new (FALSE, 0);
1721
1722     /* keep a reference to the bar so we can re-pack it at runtime*/
1723     //sbar_ref = g_object_ref(g->mainbar);
1724
1725     g->mainbar_label = gtk_label_new ("");
1726     gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1727     gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1728     gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1729     gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1730     gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1731     return g->mainbar;
1732 }
1733
1734 static
1735 GtkWidget* create_window () {
1736     GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1737     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1738     gtk_widget_set_name (window, "Uzbl browser");
1739     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1740     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1741
1742     return window;
1743 }
1744
1745 static void
1746 run_handler (const gchar *act, const gchar *args) {
1747     char **parts = g_strsplit(act, " ", 2);
1748     if (!parts) return;
1749 <<<<<<< HEAD:uzbl.c
1750     else if ((g_strcmp0(parts[0], "spawn") == 0)
1751              || (g_strcmp0(parts[0], "sh") == 0)) {
1752         guint i;
1753         GString *a = g_string_new ("");
1754         char **spawnparts;
1755         spawnparts = split_quoted(parts[1], FALSE);
1756         g_string_append_printf(a, "%s", spawnparts[0]);
1757         if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1758         for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1759             g_string_append_printf(a, " %s", spawnparts[i]);
1760 =======
1761     else if (g_strcmp0(parts[0], "spawn") == 0) {
1762         GString *a = g_string_new ("");
1763         char **spawnparts;
1764         spawnparts = split_quoted(parts[1]);
1765         g_string_append_printf(a, "\"%s\"", spawnparts[0]);
1766         g_string_append(a, args); /* append handler args before user args */
1767         int i;
1768         for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1769             g_string_append_printf(a, " \"%s\"", spawnparts[i]);
1770 >>>>>>> 17160f7... Remove bunches of old code, fix run_handler, free some stuff:uzbl.c
1771         parse_command(parts[0], a->str);
1772         g_string_free (a, TRUE);
1773         g_strfreev (spawnparts);
1774     } else
1775         parse_command(parts[0], parts[1]);
1776     g_strfreev (parts);
1777 }
1778
1779 static void
1780 add_binding (const gchar *key, const gchar *act) {
1781     char **parts = g_strsplit(act, " ", 2);
1782     Action *action;
1783
1784     if (!parts)
1785         return;
1786
1787     //Debug:
1788     if (uzbl.state.verbose)
1789         printf ("Binding %-10s : %s\n", key, act);
1790     action = new_action(parts[0], parts[1]);
1791
1792     if(g_hash_table_lookup(uzbl.bindings, key))
1793         g_hash_table_remove(uzbl.bindings, key);
1794     g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1795
1796     g_strfreev(parts);
1797 }
1798
1799 static gchar*
1800 get_xdg_var (XDG_Var xdg) {
1801     const gchar* actual_value = getenv (xdg.environmental);
1802     const gchar* home         = getenv ("HOME");
1803
1804     gchar* return_value = str_replace ("~", home, actual_value);
1805
1806     if (! actual_value || strcmp (actual_value, "") == 0) {
1807         if (xdg.default_value) {
1808             return_value = str_replace ("~", home, xdg.default_value);
1809         } else {
1810             return_value = NULL;
1811         }
1812     }
1813     return return_value;
1814 }
1815
1816 static gchar*
1817 find_xdg_file (int xdg_type, char* filename) {
1818     /* xdg_type = 0 => config
1819        xdg_type = 1 => data
1820        xdg_type = 2 => cache*/
1821
1822     gchar* xdgv = get_xdg_var (XDG[xdg_type]);
1823     gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
1824     g_free (xdgv);
1825
1826     gchar* temporary_string;
1827     char*  saveptr;
1828     char*  buf;
1829
1830     if (! file_exists (temporary_file) && xdg_type != 2) {
1831         buf = get_xdg_var (XDG[3 + xdg_type]);
1832         temporary_string = (char *) strtok_r (buf, ":", &saveptr);
1833         free(buf);
1834
1835         while (temporary_string && ! file_exists (temporary_file)) {
1836             strcpy (temporary_file, temporary_string);
1837             strcat (temporary_file, filename);
1838             temporary_string = (char * ) strtok_r (NULL, ":", &saveptr);
1839         }
1840     }
1841     
1842     g_free (temporary_string);
1843
1844     if (file_exists (temporary_file)) {
1845         return temporary_file;
1846     } else {
1847         return NULL;
1848     }
1849 }
1850
1851 static void
1852 settings_init () {
1853     State *s = &uzbl.state;
1854     Network *n = &uzbl.net;
1855
1856     uzbl.behave.reset_command_mode = 1;
1857
1858     if (!s->config_file) {
1859         s->config_file = find_xdg_file (0, "/uzbl/config");
1860     }
1861
1862     if (s->config_file) {
1863         GIOChannel *chan = NULL;
1864         gchar *readbuf = NULL;
1865         gsize len;
1866
1867         chan = g_io_channel_new_file(s->config_file, "r", NULL);
1868
1869         if (chan) {
1870             while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
1871                     == G_IO_STATUS_NORMAL) {
1872                 parse_cmd_line(readbuf);
1873                 g_free (readbuf);
1874             }
1875
1876             g_io_channel_unref (chan);
1877             if (uzbl.state.verbose)
1878                 printf ("Config %s loaded\n", s->config_file);
1879         } else {
1880             fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
1881         }
1882     } else {
1883         if (uzbl.state.verbose)
1884             printf ("No configuration file loaded.\n");
1885     }
1886     if (!uzbl.behave.status_format)
1887         set_var_value("status_format", STATUS_DEFAULT);
1888     if (!uzbl.behave.title_format_long)
1889         set_var_value("title_format_long", TITLE_LONG_DEFAULT);
1890     if (!uzbl.behave.title_format_short)
1891         set_var_value("title_format_short", TITLE_SHORT_DEFAULT);
1892
1893
1894     g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1895 }
1896
1897 static gchar*
1898 set_useragent(gchar *val) {
1899     if (*val == ' ') {
1900         g_free(val);
1901         return NULL;
1902     }
1903     gchar *ua = expand_template(val);
1904     if (ua)
1905         g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1906     return ua;
1907 }
1908
1909 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1910     (void) session;
1911     (void) user_data;
1912     if (!uzbl.behave.cookie_handler) return;
1913
1914     gchar * stdout = NULL;
1915     soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1916     GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1917     gchar *action = g_strdup ("GET");
1918     SoupURI * soup_uri = soup_message_get_uri(msg);
1919     sharg_append(a, action);
1920     sharg_append(a, soup_uri->host);
1921     sharg_append(a, soup_uri->path);
1922     run_command(uzbl.behave.cookie_handler, 0, (const gchar **) a->data, TRUE, &stdout); /* TODO: use handler */
1923     //run_handler(uzbl.behave.cookie_handler); /* TODO: global stdout pointer, spawn_sync */
1924     if(stdout) {
1925         soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1926     }
1927     g_free (action);
1928     g_array_free(a, TRUE);
1929 }
1930
1931 static void
1932 save_cookies (SoupMessage *msg, gpointer user_data){
1933     (void) user_data;
1934     GSList *ck;
1935     char *cookie;
1936     for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1937         cookie = soup_cookie_to_set_cookie_header(ck->data);
1938         GArray *a = g_array_new(TRUE, FALSE, sizeof(gchar*));
1939         SoupURI * soup_uri = soup_message_get_uri(msg);
1940         gchar *action = strdup("PUT");
1941         sharg_append(a, action);
1942         sharg_append(a, soup_uri->host);
1943         sharg_append(a, soup_uri->path);
1944         sharg_append(a, cookie);
1945         run_command(uzbl.behave.cookie_handler, 0, (const gchar **) a->data, FALSE, NULL);
1946         g_free (cookie);
1947         g_free (action);
1948         g_array_free(a, TRUE);
1949     }
1950     g_slist_free(ck);
1951 }
1952
1953 int
1954 main (int argc, char* argv[]) {
1955     gtk_init (&argc, &argv);
1956     if (!g_thread_supported ())
1957         g_thread_init (NULL);
1958
1959     uzbl.state.executable_path = g_strdup(argv[0]);
1960     uzbl.state.selected_url = NULL;
1961     uzbl.state.searchtx = NULL;
1962
1963     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1964     g_option_context_add_main_entries (context, entries, NULL);
1965     g_option_context_add_group (context, gtk_get_option_group (TRUE));
1966     g_option_context_parse (context, &argc, &argv, NULL);
1967     /* initialize hash table */
1968     uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1969
1970     uzbl.net.soup_session = webkit_get_default_session();
1971     uzbl.state.keycmd = g_string_new("");
1972
1973     if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1974         fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1975     if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
1976         fprintf(stderr, "uzbl: error hooking SIGINT\n");
1977
1978     if(uname(&uzbl.state.unameinfo) == -1)
1979         g_printerr("Can't retrieve unameinfo.  Your useragent might appear wrong.\n");
1980
1981     setup_regex();
1982     setup_scanner();
1983     commands_hash ();
1984     make_var_to_name_hash();
1985
1986     uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
1987
1988     uzbl.gui.scrolled_win = create_browser();
1989     create_mainbar();
1990
1991     /* initial packing */
1992     gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1993     gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1994
1995     uzbl.gui.main_window = create_window ();
1996     gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
1997
1998     //load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
1999
2000     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2001     gtk_widget_show_all (uzbl.gui.main_window);
2002     uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2003
2004     if (uzbl.state.verbose) {
2005         printf("Uzbl start location: %s\n", argv[0]);
2006         printf("window_id %i\n",(int) uzbl.xwin);
2007         printf("pid %i\n", getpid ());
2008         printf("name: %s\n", uzbl.state.instance_name);
2009     }
2010
2011     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2012     uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2013     uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2014     uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2015     gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2016
2017     settings_init ();
2018
2019     if (!uzbl.behave.show_status)
2020         gtk_widget_hide(uzbl.gui.mainbar);
2021     else
2022         update_title();
2023
2024     create_stdin();
2025
2026     //if(uzbl.state.uri)
2027     //    load_uri (uzbl.gui.web_view, uzbl.state.uri);
2028
2029     gtk_main ();
2030     clean_up();
2031
2032     return EXIT_SUCCESS;
2033 }
2034
2035 /* vi: set et ts=4: */