made statusbar selectable, fix bug in parse status to not ignore # chars
[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 <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
62 /* commandline arguments (set initial values for the state variables) */
63 static GOptionEntry entries[] =
64 {
65     { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load", "URI" },
66     { "name",    'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
67     { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   "Config file", "FILE" },
68     { NULL,      0, 0, 0, NULL, NULL, NULL }
69 };
70
71 typedef void (*Command)(WebKitWebView*, const char *);
72
73 /* XDG stuff */
74 static char *XDG_CONFIG_HOME_default[256];
75 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
76
77
78 /* --- UTILITY FUNCTIONS --- */
79
80 char *
81 itos(int val) {
82     char tmp[20];
83
84     snprintf(tmp, sizeof(tmp), "%i", val);
85     return g_strdup(tmp);
86 }
87
88 static char *
89 str_replace (const char* search, const char* replace, const char* string) {
90     return g_strjoinv (replace, g_strsplit(string, search, -1));
91 }
92
93 static sigfunc*
94 setup_signal(int signr, sigfunc *shandler) {
95     struct sigaction nh, oh;
96
97     nh.sa_handler = shandler;
98     sigemptyset(&nh.sa_mask);
99     nh.sa_flags = 0;
100
101     if(sigaction(signr, &nh, &oh) < 0)
102         return SIG_ERR;
103
104     return NULL;
105 }
106
107 static void
108 clean_up(void) {
109     if (uzbl.behave.fifo_dir)
110         unlink (uzbl.comm.fifo_path);
111     if (uzbl.behave.socket_dir)
112         unlink (uzbl.comm.socket_path);
113
114     g_string_free(uzbl.state.keycmd, TRUE);
115     g_hash_table_destroy(uzbl.bindings);
116     g_hash_table_destroy(uzbl.behave.commands);
117 }
118
119
120 /* --- SIGNAL HANDLER --- */
121
122 static void
123 catch_sigterm(int s) {
124     (void) s;
125     clean_up();
126 }
127
128 /* --- CALLBACKS --- */
129
130 static gboolean
131 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
132     (void) web_view;
133     (void) frame;
134     (void) navigation_action;
135     (void) policy_decision;
136     (void) user_data;
137     const gchar* uri = webkit_network_request_get_uri (request);
138     printf("New window requested -> %s \n", uri);
139     new_window_load_uri(uri);
140     return (FALSE);
141 }
142
143 WebKitWebView*
144 create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer user_data) {
145     (void) web_view;
146     (void) frame;
147     (void) user_data;
148     if (uzbl.state.selected_url[0]!=0) {
149         printf("\nNew web view -> %s\n",uzbl.state.selected_url);
150         new_window_load_uri(uzbl.state.selected_url);
151     } else {
152         printf("New web view -> %s\n","Nothing to open, exiting");
153     }
154     return (NULL);
155 }
156
157 static gboolean
158 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
159     (void) web_view;
160     (void) user_data;
161     if (uzbl.behave.download_handler) {
162         const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
163         printf("Download -> %s\n",uri);
164         run_command_async(uzbl.behave.download_handler, uri);
165     }
166     return (FALSE);
167 }
168
169 /* scroll a bar in a given direction */
170 static void
171 scroll (GtkAdjustment* bar, const char *param) {
172     gdouble amount;
173     gchar *end;
174
175     amount = g_ascii_strtod(param, &end);
176
177     if (*end)
178         fprintf(stderr, "found something after double: %s\n", end);
179
180     gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
181 }
182
183 static void scroll_vert(WebKitWebView* page, const char *param) {
184     (void) page;
185
186     scroll(uzbl.gui.bar_v, param);
187 }
188
189 static void scroll_horz(WebKitWebView* page, const char *param) {
190     (void) page;
191
192     scroll(uzbl.gui.bar_h, param);
193 }
194
195 static void
196 toggle_status_cb (WebKitWebView* page, const char *param) {
197     (void)page;
198     (void)param;
199
200     if (uzbl.behave.show_status) {
201         gtk_widget_hide(uzbl.gui.mainbar);
202     } else {
203         gtk_widget_show(uzbl.gui.mainbar);
204     }
205     uzbl.behave.show_status = !uzbl.behave.show_status;
206     update_title();
207 }
208
209 static void
210 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
211     (void) page;
212     (void) title;
213     (void) data;    
214     //ADD HOVER URL TO WINDOW TITLE
215     uzbl.state.selected_url[0] = '\0';
216     if (link) {
217         strcpy (uzbl.state.selected_url, link);
218     }
219     update_title();
220 }
221
222 static void
223 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
224     (void) web_view;
225     (void) web_frame;
226     (void) data;
227     if (uzbl.gui.main_title)
228         g_free (uzbl.gui.main_title);
229     uzbl.gui.main_title = g_strdup (title);
230     update_title();
231 }
232
233 static void
234 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
235     (void) page;
236     (void) data;
237     uzbl.gui.sbar.load_progress = progress;
238     update_title();
239 }
240
241 static void
242 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
243     (void) page;
244     (void) data;
245     free (uzbl.state.uri);
246     GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
247     uzbl.state.uri = g_string_free (newuri, FALSE);
248 }
249
250 static void
251 destroy_cb (GtkWidget* widget, gpointer data) {
252     (void) widget;
253     (void) data;
254     gtk_main_quit ();
255 }
256
257 static void
258 log_history_cb () {
259    if (uzbl.behave.history_handler) {
260        time_t rawtime;
261        struct tm * timeinfo;
262        char date [80];
263        time ( &rawtime );
264        timeinfo = localtime ( &rawtime );
265        strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
266        GString* args = g_string_new ("");
267        g_string_printf (args, "'%s'", date);
268        run_command_async(uzbl.behave.history_handler, args->str);
269        g_string_free (args, TRUE);
270    }
271 }
272
273
274 /* VIEW funcs (little webkit wrappers) */
275 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
276 VIEWFUNC(reload)
277 VIEWFUNC(reload_bypass_cache)
278 VIEWFUNC(stop_loading)
279 VIEWFUNC(zoom_in)
280 VIEWFUNC(zoom_out)
281 VIEWFUNC(go_back)
282 VIEWFUNC(go_forward)
283 #undef VIEWFUNC
284
285 /* -- command to callback/function map for things we cannot attach to any signals */
286 // TODO: reload
287
288 static struct {char *name; Command command;} cmdlist[] =
289 {
290     { "back",             view_go_back            },
291     { "forward",          view_go_forward         },
292     { "scroll_vert",      scroll_vert             },
293     { "scroll_horz",      scroll_horz             },
294     { "reload",           view_reload,            }, 
295     { "reload_ign_cache", view_reload_bypass_cache},
296     { "stop",             view_stop_loading,      },
297     { "zoom_in",          view_zoom_in,           }, //Can crash (when max zoom reached?).
298     { "zoom_out",         view_zoom_out,          },
299     { "uri",              load_uri                },
300     { "script",           run_js                  },
301     { "toggle_status",    toggle_status_cb        },
302     { "spawn",            spawn                   },
303     { "exit",             close_uzbl              },
304     { "search",           search_text             },
305     { "insert_mode",      set_insert_mode         }
306 };
307
308 static void
309 commands_hash(void)
310 {
311     unsigned int i;
312     uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
313
314     for (i = 0; i < LENGTH(cmdlist); i++)
315         g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
316 }
317
318 /* -- CORE FUNCTIONS -- */
319
320 void
321 free_action(gpointer act) {
322     Action *action = (Action*)act;
323     g_free(action->name);
324     if (action->param)
325         g_free(action->param);
326     g_free(action);
327 }
328
329 Action*
330 new_action(const gchar *name, const gchar *param) {
331     Action *action = g_new(Action, 1);
332
333     action->name = g_strdup(name);
334     if (param)
335         action->param = g_strdup(param);
336     else
337         action->param = NULL;
338
339     return action;
340 }
341
342 static bool
343 file_exists (const char * filename) {
344     FILE *file = fopen (filename, "r");
345     if (file) {
346         fclose (file);
347         return true;
348     }
349     return false;
350 }
351
352 void
353 set_insert_mode(WebKitWebView *page, const gchar *param) {
354     (void)page;
355     (void)param;
356
357     uzbl.behave.insert_mode = TRUE;
358     update_title();
359 }
360
361 static void
362 load_uri (WebKitWebView * web_view, const gchar *param) {
363     if (param) {
364         GString* newuri = g_string_new (param);
365         if (g_strrstr (param, "://") == NULL)
366             g_string_prepend (newuri, "http://");
367                 /* if we do handle cookies, ask our handler for them */
368         webkit_web_view_load_uri (web_view, newuri->str);
369         g_string_free (newuri, TRUE);
370     }
371 }
372
373 static void
374 run_js (WebKitWebView * web_view, const gchar *param) {
375     if (param)
376         webkit_web_view_execute_script (web_view, param);
377 }
378
379 static void
380 search_text (WebKitWebView *page, const char *param) {
381     if ((param) && (param[0] != '\0')) {
382         strcpy(uzbl.state.searchtx, param);
383     }
384     if (uzbl.state.searchtx[0] != '\0') {
385         printf ("Searching: %s\n", uzbl.state.searchtx);
386         webkit_web_view_unmark_text_matches (page);
387         webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
388         webkit_web_view_set_highlight_text_matches (page, TRUE);
389         webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
390     }
391 }
392
393 static void
394 new_window_load_uri (const gchar * uri) {
395     GString* to_execute = g_string_new ("");
396     g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
397     int i;
398     for (i = 0; entries[i].long_name != NULL; i++) {
399         if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
400             gchar** str = (gchar**)entries[i].arg_data;
401             if (*str!=NULL) {
402                 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
403             }
404         }
405     }
406     printf("\n%s\n", to_execute->str);
407     g_spawn_command_line_async (to_execute->str, NULL);
408     g_string_free (to_execute, TRUE);
409 }
410
411 static void
412 close_uzbl (WebKitWebView *page, const char *param) {
413     (void)page;
414     (void)param;
415     gtk_main_quit ();
416 }
417
418 /* --Statusbar functions-- */
419 static char*
420 build_progressbar_ascii(int percent) {
421    int width=10;
422    int i;
423    double l;
424    GString *bar = g_string_new("");
425
426    l = (double)percent*((double)width/100.);
427    l = (int)(l+.5)>=(int)l ? l+.5 : l;
428
429    g_string_append(bar, "[");
430    for(i=0; i<(int)l; i++)
431        g_string_append(bar, "=");
432           
433    for(; i<width; i++)
434        g_string_append(bar, "·");
435    g_string_append(bar, "]");
436
437    return g_string_free(bar, FALSE);
438 }
439
440 static void
441 setup_scanner() {
442      const GScannerConfig scan_config = {
443              (
444               "\t\r\n"
445              )            /* cset_skip_characters */,
446              (
447               G_CSET_a_2_z
448               "_#"
449               G_CSET_A_2_Z
450              )            /* cset_identifier_first */,
451              (
452               G_CSET_a_2_z
453               "_0123456789"
454               G_CSET_A_2_Z
455               G_CSET_LATINS
456               G_CSET_LATINC
457              )            /* cset_identifier_nth */,
458              ( "" )    /* cpair_comment_single */,
459
460              TRUE         /* case_sensitive */,
461
462              FALSE        /* skip_comment_multi */,
463              FALSE        /* skip_comment_single */,
464              FALSE        /* scan_comment_multi */,
465              TRUE         /* scan_identifier */,
466              TRUE         /* scan_identifier_1char */,
467              FALSE        /* scan_identifier_NULL */,
468              TRUE         /* scan_symbols */,
469              FALSE        /* scan_binary */,
470              FALSE        /* scan_octal */,
471              FALSE        /* scan_float */,
472              FALSE        /* scan_hex */,
473              FALSE        /* scan_hex_dollar */,
474              FALSE        /* scan_string_sq */,
475              FALSE        /* scan_string_dq */,
476              TRUE         /* numbers_2_int */,
477              FALSE        /* int_2_float */,
478              FALSE        /* identifier_2_string */,
479              FALSE        /* char_2_token */,
480              FALSE        /* symbol_2_token */,
481              TRUE         /* scope_0_fallback */,
482              FALSE,
483              TRUE
484      };
485
486      uzbl.scan = g_scanner_new(&scan_config);
487      while(symp->symbol_name) {
488          g_scanner_scope_add_symbol(uzbl.scan, 0,
489                          symp->symbol_name,
490                          GINT_TO_POINTER(symp->symbol_token));
491          symp++;
492      }
493 }
494
495 static gchar *
496 parse_status_template(const char *template) {
497      GTokenType token = G_TOKEN_NONE;
498      GString *ret = g_string_new("");
499      gchar *buf=NULL;
500      int sym;
501
502      if(!template)
503          return NULL;
504
505      g_scanner_input_text(uzbl.scan, template, strlen(template));
506      while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
507          token = g_scanner_get_next_token(uzbl.scan);
508
509          if(token == G_TOKEN_SYMBOL) {
510              sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
511              switch(sym) {
512                  case SYM_URI:
513                      g_string_append(ret, 
514                          uzbl.state.uri?
515                          g_markup_printf_escaped("%s", uzbl.state.uri):"");
516                      break;
517                  case SYM_LOADPRGS:
518                      g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
519                      break;
520                  case SYM_LOADPRGSBAR:
521                      buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
522                      g_string_append(ret, buf);
523                      g_free(buf);
524                      break;
525                  case SYM_TITLE:
526                      g_string_append(ret,
527                          uzbl.gui.main_title?
528                          g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
529                      break;
530                  case SYM_NAME:
531                      g_string_append(ret, 
532                          uzbl.state.instance_name?uzbl.state.instance_name:itos(uzbl.xwin));
533                      break;
534                  case SYM_KEYCMD:
535                      g_string_append(ret, 
536                          uzbl.state.keycmd->str ?
537                          g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
538                      break;
539                  case SYM_MODE:
540                      g_string_append(ret, 
541                          uzbl.behave.insert_mode?"[I]":"[C]");
542                      break;
543                  default:
544                      break;
545              }
546          }
547          else if(token == G_TOKEN_INT) {
548              g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
549          }
550          else if(token == G_TOKEN_IDENTIFIER) {
551              g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
552          }
553          else if(token == G_TOKEN_CHAR) {
554              g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
555          }
556      }
557
558      return g_string_free(ret, FALSE);
559 }
560 /* --End Statusbar functions-- */
561
562
563 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
564 static gboolean
565 run_command_async(const char *command, const char *args) {
566    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
567     GString* to_execute = g_string_new ("");
568     gboolean result;
569     g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", 
570                     command, uzbl.state.config_file, (int) getpid() ,
571                     (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
572     g_string_append_printf (to_execute, " '%s' '%s'", 
573                     uzbl.state.uri, "TODO title here");
574     if(args) {
575         g_string_append_printf (to_execute, " %s", args);
576     }
577     result = g_spawn_command_line_async (to_execute->str, NULL);
578     printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
579     g_string_free (to_execute, TRUE);
580     return result;
581 }
582
583 static gboolean
584 run_command_sync(const char *command, const char *args, char **stdout) {
585         //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
586     GString* to_execute = g_string_new ("");
587     gboolean result;
588     g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, uzbl.state.config_file, (int) getpid() , (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
589     g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
590     if(args) {
591         g_string_append_printf (to_execute, " %s", args);
592     }
593     result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, NULL);
594     printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
595     g_string_free (to_execute, TRUE);
596     return result;
597 }
598
599 static void
600 spawn(WebKitWebView *web_view, const char *param) {
601     (void)web_view;
602     run_command_async(param, NULL);
603 }
604
605 static void
606 parse_command(const char *cmd, const char *param) {
607     Command c;
608
609     if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
610         c(uzbl.gui.web_view, param);
611     else
612         fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
613 }
614
615 static void
616 parse_line(char *line) {
617     gchar **parts;
618
619     g_strstrip(line);
620
621     parts = g_strsplit(line, " ", 2);
622
623     if (!parts)
624         return;
625
626     parse_command(parts[0], parts[1]);
627
628     g_strfreev(parts);
629 }
630
631 void
632 build_stream_name(int type) {
633     char *xwin_str;
634     State *s = &uzbl.state;
635     Behaviour *b = &uzbl.behave;
636
637     xwin_str = itos((int)uzbl.xwin);
638     switch(type) {
639         case FIFO:
640             if (b->fifo_dir) {
641                 sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s", 
642                             b->fifo_dir,
643                             s->instance_name ? s->instance_name : xwin_str);
644             } else {
645                 sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s",
646                             s->instance_name ? s->instance_name : xwin_str);
647             }
648             break;
649
650         case SOCKET:
651             if (b->socket_dir) {
652                 sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s",
653                             b->socket_dir,
654                             s->instance_name ? s->instance_name : xwin_str);
655             } else {
656                 sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s",
657                                 s->instance_name ? s->instance_name : xwin_str);
658             }
659             break;
660         default:
661             break;
662     }
663     g_free(xwin_str);
664 }
665
666 static void
667 control_fifo(GIOChannel *gio, GIOCondition condition) {
668     printf("triggered\n");
669     gchar *ctl_line;
670     GIOStatus ret;
671     GError *err = NULL;
672
673     if (condition & G_IO_HUP)
674         g_error ("Fifo: Read end of pipe died!\n");
675
676     if(!gio)
677        g_error ("Fifo: GIOChannel broke\n");
678
679     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
680     if (ret == G_IO_STATUS_ERROR)
681         g_error ("Fifo: Error reading: %s\n", err->message);
682
683     parse_line(ctl_line);
684     g_free(ctl_line);
685     printf("...done\n");
686     return;
687 }
688
689 static void
690 create_fifo() {
691     GIOChannel *chan = NULL;
692     GError *error = NULL;
693
694     build_stream_name(FIFO);
695     if (file_exists(uzbl.comm.fifo_path)) {
696         g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path);
697         return;
698     }
699     if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) {
700         g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno));
701     } else {
702         // 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.
703         chan = g_io_channel_new_file((gchar *) uzbl.comm.fifo_path, "r+", &error);
704         if (chan) {
705             if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
706                 g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path);
707             } else { 
708                 printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path);
709             }
710         } else {
711             g_error ("Fifo: Error while opening: %s\n", error->message);
712         }
713     }
714     return;
715 }
716
717 static void
718 control_socket(GIOChannel *chan) {
719     struct sockaddr_un remote;
720     char buffer[512], *ctl_line;
721     char temp[128];
722     int sock, clientsock, n, done;
723     unsigned int t;
724
725     sock = g_io_channel_unix_get_fd(chan);
726
727     memset (buffer, 0, sizeof (buffer));
728
729     t          = sizeof (remote);
730     clientsock = accept (sock, (struct sockaddr *) &remote, &t);
731
732     done = 0;
733     do {
734         memset (temp, 0, sizeof (temp));
735         n = recv (clientsock, temp, 128, 0);
736         if (n == 0) {
737             buffer[strlen (buffer)] = '\0';
738             done = 1;
739         }
740         if (!done)
741             strcat (buffer, temp);
742     } while (!done);
743
744     if (strcmp (buffer, "\n") < 0) {
745         buffer[strlen (buffer) - 1] = '\0';
746     } else {
747         buffer[strlen (buffer)] = '\0';
748     }
749     close (clientsock);
750     ctl_line = g_strdup(buffer);
751     parse_line (ctl_line);
752
753 /*
754    TODO: we should be able to do it with this.  but glib errors out with "Invalid argument"
755     GError *error = NULL;
756     gsize len;
757     GIOStatus ret;
758     ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
759     if (ret == G_IO_STATUS_ERROR)
760         g_error ("Error reading: %s\n", error->message);
761
762     printf("Got line %s (%u bytes) \n",ctl_line, len);
763     if(ctl_line) {
764        parse_line(ctl_line);
765 */
766
767     g_free(ctl_line);
768     return;
769
770
771 static void
772 create_socket() {
773     GIOChannel *chan = NULL;
774     int sock, len;
775     struct sockaddr_un local;
776
777     build_stream_name(SOCKET);
778     sock = socket (AF_UNIX, SOCK_STREAM, 0);
779
780     local.sun_family = AF_UNIX;
781     strcpy (local.sun_path, uzbl.comm.socket_path);
782     unlink (local.sun_path);
783
784     len = strlen (local.sun_path) + sizeof (local.sun_family);
785     bind (sock, (struct sockaddr *) &local, len);
786
787     if (errno == -1) {
788         printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno));
789     } else {
790         printf ("Socket: Opened in %s\n", uzbl.comm.socket_path);
791         listen (sock, 5);
792
793         if( (chan = g_io_channel_unix_new(sock)) )
794             g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
795     }
796 }
797
798 static void
799 update_title (void) {
800     GString* string_long = g_string_new ("");
801     GString* string_short = g_string_new ("");
802     char* iname = NULL;
803     gchar *statln;
804     int iname_len;
805     State *s = &uzbl.state;
806     Behaviour *b = &uzbl.behave;
807
808     if(s->instance_name) {
809             iname_len = strlen(s->instance_name)+4;
810             iname = malloc(iname_len);
811             snprintf(iname, iname_len, "<%s> ", s->instance_name);
812             
813             g_string_prepend(string_long, iname);
814             g_string_prepend(string_short, iname);
815             free(iname);
816     }
817
818     g_string_append_printf(string_long, "%s ", s->keycmd->str);
819     if (!b->always_insert_mode)
820         g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
821     if (uzbl.gui.main_title) {
822         g_string_append (string_long, uzbl.gui.main_title);
823         g_string_append (string_short, uzbl.gui.main_title);
824     }
825     g_string_append (string_long, " - Uzbl browser");
826     g_string_append (string_short, " - Uzbl browser");
827     if (s->selected_url[0]!=0) {
828         g_string_append_printf (string_long, " -> (%s)", s->selected_url);
829     }
830
831     gchar* title_long = g_string_free (string_long, FALSE);
832     gchar* title_short = g_string_free (string_short, FALSE);
833
834     if (b->show_status) {
835         gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
836         statln = parse_status_template(uzbl.behave.status_format);
837         gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
838         g_free(statln);
839     } else {
840         gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
841     }
842
843     g_free (title_long);
844     g_free (title_short);
845 }
846
847 static gboolean
848 key_press_cb (WebKitWebView* page, GdkEventKey* event)
849 {
850     //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
851
852     (void) page;
853     Action *action;
854
855     if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
856         || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right)
857         return FALSE;
858
859     /* turn off insert mode (if always_insert_mode is not used) */
860     if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
861         uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
862         update_title();
863         return TRUE;
864     }
865
866     if (uzbl.behave.insert_mode && ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask))
867         return FALSE;
868
869     if (event->keyval == GDK_Escape) {
870         g_string_truncate(uzbl.state.keycmd, 0);
871         update_title();
872         return TRUE;
873     }
874
875     //Insert without shift - insert from clipboard; Insert with shift - insert from primary
876     if (event->keyval == GDK_Insert) {
877         gchar * str;
878         if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
879             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
880         } else {
881             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); 
882         }
883         if (str) {
884             g_string_append_printf (uzbl.state.keycmd, "%s",  str);
885             update_title ();
886             free (str);
887         }
888         return TRUE;
889     }
890
891     if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
892         g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
893         update_title();
894         return TRUE;
895     }
896
897     if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
898         GString* short_keys = g_string_new ("");
899         unsigned int i;
900         for (i=0; i<(uzbl.state.keycmd->len); i++) {
901             g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
902             g_string_append_c(short_keys, '_');
903             
904             //printf("\nTesting string: @%s@\n", short_keys->str);
905             if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
906                 GString* parampart = g_string_new (uzbl.state.keycmd->str);
907                 g_string_erase (parampart, 0, i+1);
908                 //printf("\nParameter: @%s@\n", parampart->str);
909                 GString* actionname = g_string_new ("");
910                 if (action->name)
911                     g_string_printf (actionname, action->name, parampart->str);
912                 GString* actionparam = g_string_new ("");
913                 if (action->param)
914                     g_string_printf (actionparam, action->param, parampart->str);
915                 parse_command(actionname->str, actionparam->str);
916                 g_string_free (actionname, TRUE);
917                 g_string_free (actionparam, TRUE);
918                 g_string_free (parampart, TRUE);
919                 g_string_truncate(uzbl.state.keycmd, 0);
920                 update_title();
921             }          
922
923             g_string_truncate(short_keys, short_keys->len - 1);
924         }
925         g_string_free (short_keys, TRUE);
926         return (!uzbl.behave.insert_mode);
927     }
928
929     g_string_append(uzbl.state.keycmd, event->string);
930     if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
931         g_string_truncate(uzbl.state.keycmd, 0);
932         parse_command(action->name, action->param);
933     }
934
935     update_title();
936
937     return TRUE;
938 }
939
940 static GtkWidget*
941 create_browser () {
942     GUI *g = &uzbl.gui;
943
944     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
945     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
946
947     g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
948     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
949
950     g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
951     g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
952     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
953     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
954     g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
955     g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
956     g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); 
957     g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); 
958     g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);  
959
960     return scrolled_window;
961 }
962
963 static GtkWidget*
964 create_mainbar () {
965     GUI *g = &uzbl.gui;
966
967     g->mainbar = gtk_hbox_new (FALSE, 0);
968     g->mainbar_label = gtk_label_new ("");  
969     gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
970     gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
971     gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
972     gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
973     gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
974     return g->mainbar;
975 }
976
977 static
978 GtkWidget* create_window () {
979     GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
980     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
981     gtk_widget_set_name (window, "Uzbl browser");
982     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
983
984     return window;
985 }
986
987 static void
988 add_binding (const gchar *key, const gchar *act) {
989     char **parts = g_strsplit(act, " ", 2);
990     Action *action;
991
992     if (!parts)
993         return;
994
995     //Debug:
996     printf ("Binding %-10s : %s\n", key, act);
997     action = new_action(parts[0], parts[1]);
998     g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
999
1000     g_strfreev(parts);
1001 }
1002
1003 static void
1004 settings_init () {
1005     GKeyFile* config = NULL;
1006     gboolean res  = FALSE;
1007     char *saveptr;
1008     gchar** keys = NULL;
1009     State *s = &uzbl.state;
1010     Network *n = &uzbl.net;
1011     Behaviour *b = &uzbl.behave;
1012
1013     if (!s->config_file) {
1014         const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
1015         if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
1016           XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
1017         }
1018         printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
1019     
1020         strcpy (s->config_file_path, XDG_CONFIG_HOME);
1021         strcat (s->config_file_path, "/uzbl/config");
1022         if (file_exists (s->config_file_path)) {
1023           printf ("Config file %s found.\n", s->config_file_path);
1024           s->config_file = &s->config_file_path[0];
1025         } else {
1026             // Now we check $XDG_CONFIG_DIRS
1027             char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
1028             if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
1029                 XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
1030
1031             printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
1032
1033             char buffer[512];
1034             strcpy (buffer, XDG_CONFIG_DIRS);
1035             const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
1036             while (dir && ! file_exists (s->config_file_path)) {
1037                 strcpy (s->config_file_path, dir);
1038                 strcat (s->config_file_path, "/uzbl/config_file_pathig");
1039                 if (file_exists (s->config_file_path)) {
1040                     printf ("Config file %s found.\n", s->config_file_path);
1041                     s->config_file = &s->config_file_path[0];
1042                 }
1043                 dir = (char * ) strtok_r (NULL, ":", &saveptr);
1044             }
1045         }
1046     }
1047
1048     if (s->config_file) {
1049         config = g_key_file_new ();
1050         res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
1051           if (res) {
1052             printf ("Config %s loaded\n", s->config_file);
1053           } else {
1054             fprintf (stderr, "Config %s loading failed\n", s->config_file);
1055         }
1056     } else {
1057         printf ("No configuration.\n");
1058     }
1059
1060     if (res) {
1061         b->history_handler    = g_key_file_get_value   (config, "behavior", "history_handler",    NULL);
1062         b->download_handler   = g_key_file_get_value   (config, "behavior", "download_handler",   NULL);
1063             b->cookie_handler     = g_key_file_get_string  (config, "behavior", "cookie_handler",     NULL);
1064         b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
1065         b->show_status        = g_key_file_get_boolean (config, "behavior", "show_status",        NULL);
1066         b->modkey             = g_key_file_get_value   (config, "behavior", "modkey",             NULL);
1067         b->status_top         = g_key_file_get_boolean (config, "behavior", "status_top",         NULL);
1068         b->status_format       = g_key_file_get_string (config, "behavior", "status_format",         NULL);
1069         if (! b->fifo_dir)
1070             b->fifo_dir       = g_key_file_get_value  (config, "behavior", "fifo_dir",           NULL);
1071         if (! b->socket_dir)
1072             b->socket_dir     = g_key_file_get_value   (config, "behavior", "socket_dir",         NULL);
1073         keys               = g_key_file_get_keys    (config, "bindings", NULL,                 NULL);
1074     }
1075
1076     printf ("History handler: %s\n",    (b->history_handler    ? b->history_handler  : "disabled"));
1077     printf ("Download manager: %s\n",   (b->download_handler   ? b->download_handler : "disabled"));
1078     printf ("Cookie handler: %s\n",     (b->cookie_handler     ? b->cookie_handler   : "disabled"));
1079     printf ("Fifo directory: %s\n",     (b->fifo_dir           ? b->fifo_dir         : "disabled"));
1080     printf ("Socket directory: %s\n",   (b->socket_dir         ? b->socket_dir       : "disabled"));
1081     printf ("Always insert mode: %s\n", (b->always_insert_mode ? "TRUE"              : "FALSE"));
1082     printf ("Show status: %s\n",        (b->show_status        ? "TRUE"              : "FALSE"));
1083     printf ("Status top: %s\n",         (b->status_top         ? "TRUE"              : "FALSE"));
1084     printf ("Modkey: %s\n",             (b->modkey             ? b->modkey           : "disabled"));
1085     printf ("Status format: %s\n",             (b->status_format            ? b->status_format           : "none"));
1086
1087     if (!b->modkey)
1088         b->modkey = "";
1089
1090     //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
1091     gchar* modkeyup = g_utf8_strup (b->modkey, -1);
1092     if (g_strrstr (modkeyup,"SHIFT") != NULL)    b->modmask |= GDK_SHIFT_MASK;    //the Shift key.
1093     if (g_strrstr (modkeyup,"LOCK") != NULL)     b->modmask |= GDK_LOCK_MASK;     //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock).
1094     if (g_strrstr (modkeyup,"CONTROL") != NULL)  b->modmask |= GDK_CONTROL_MASK;  //the Control key.
1095     if (g_strrstr (modkeyup,"MOD1") != NULL)     b->modmask |= GDK_MOD1_MASK;     //the fourth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier, but normally it is the Alt key).
1096     if (g_strrstr (modkeyup,"MOD2") != NULL)     b->modmask |= GDK_MOD2_MASK;     //the fifth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1097     if (g_strrstr (modkeyup,"MOD3") != NULL)     b->modmask |= GDK_MOD3_MASK;     //the sixth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1098     if (g_strrstr (modkeyup,"MOD4") != NULL)     b->modmask |= GDK_MOD4_MASK;     //the seventh modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1099     if (g_strrstr (modkeyup,"MOD5") != NULL)     b->modmask |= GDK_MOD5_MASK;     //the eighth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1100     if (g_strrstr (modkeyup,"BUTTON1") != NULL)  b->modmask |= GDK_BUTTON1_MASK;  //the first mouse button.
1101     if (g_strrstr (modkeyup,"BUTTON2") != NULL)  b->modmask |= GDK_BUTTON2_MASK;  //the second mouse button.
1102     if (g_strrstr (modkeyup,"BUTTON3") != NULL)  b->modmask |= GDK_BUTTON3_MASK;  //the third mouse button.
1103     if (g_strrstr (modkeyup,"BUTTON4") != NULL)  b->modmask |= GDK_BUTTON4_MASK;  //the fourth mouse button.
1104     if (g_strrstr (modkeyup,"BUTTON5") != NULL)  b->modmask |= GDK_BUTTON5_MASK;  //the fifth mouse button.
1105     if (g_strrstr (modkeyup,"SUPER") != NULL)    b->modmask |= GDK_SUPER_MASK;    //the Super modifier. Since 2.10
1106     if (g_strrstr (modkeyup,"HYPER") != NULL)    b->modmask |= GDK_HYPER_MASK;    //the Hyper modifier. Since 2.10
1107     if (g_strrstr (modkeyup,"META") != NULL)     b->modmask |= GDK_META_MASK;     //the Meta modifier. Since 2.10  */
1108     free (modkeyup);
1109
1110     if (keys) {
1111         int i;
1112         for (i = 0; keys[i]; i++) {
1113             gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL);
1114             
1115             add_binding(g_strstrip(keys[i]), value);
1116             g_free(value);
1117         }
1118
1119         g_strfreev(keys);
1120     }
1121
1122     /* networking options */
1123     if (res) {
1124         n->proxy_url      = g_key_file_get_value   (config, "network", "proxy_server",       NULL);
1125         b->http_debug     = g_key_file_get_integer (config, "network", "http_debug",         NULL);
1126         n->useragent      = g_key_file_get_value   (config, "network", "user-agent",         NULL);
1127         n->max_conns      = g_key_file_get_integer (config, "network", "max_conns",          NULL);
1128         n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
1129     }
1130
1131     if(n->proxy_url){
1132         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(n->proxy_url), NULL);
1133     }
1134         
1135     if(!(b->http_debug <= 3)){
1136         b->http_debug = 0;
1137         fprintf(stderr, "Wrong http_debug level, ignoring.\n");
1138     } else if (b->http_debug > 0) {
1139         n->soup_logger = soup_logger_new(b->http_debug, -1);
1140         soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
1141     }
1142         
1143     if(n->useragent){
1144         char* newagent  = malloc(1024);
1145
1146         strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
1147         strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
1148         strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
1149
1150         if (uname (&s->unameinfo) == -1) {
1151             printf("Error getting uname info. Not replacing system-related user agent variables.\n");
1152         } else {
1153             strcpy(newagent, str_replace("%sysname%",     s->unameinfo.sysname, newagent));
1154             strcpy(newagent, str_replace("%nodename%",    s->unameinfo.nodename, newagent));
1155             strcpy(newagent, str_replace("%kernrel%",     s->unameinfo.release, newagent));
1156             strcpy(newagent, str_replace("%kernver%",     s->unameinfo.version, newagent));
1157             strcpy(newagent, str_replace("%arch-system%", s->unameinfo.machine, newagent));
1158
1159             #ifdef _GNU_SOURCE
1160                 strcpy(newagent, str_replace("%domainname%", s->unameinfo.domainname, newagent));
1161             #endif
1162         }
1163
1164         strcpy(newagent, str_replace("%arch-uzbl%",    ARCH,                       newagent));
1165         strcpy(newagent, str_replace("%commit%",       COMMIT,                     newagent));
1166
1167         n->useragent = malloc(1024);
1168         strcpy(n->useragent, newagent);
1169         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
1170     }
1171
1172     if(n->max_conns >= 1){
1173         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
1174     }
1175
1176     if(n->max_conns_host >= 1){
1177         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
1178     }
1179
1180     printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
1181     printf("HTTP logging level: %d\n", b->http_debug);
1182     printf("User-agent: %s\n", n->useragent? n->useragent : "default");
1183     printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
1184     printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
1185                 
1186
1187
1188         if(b->cookie_handler){
1189                 /* ck = soup_cookie_jar_new(); */
1190                 /* soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(ck)); */
1191                 /* g_signal_connect(ck, "changed", G_CALLBACK(cookie_recieved_action), NULL); */
1192                 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1193         }
1194         
1195 }
1196
1197 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1198     (void) session;
1199     (void) user_data;
1200     soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1201         
1202         /* ask handler for cookies, if there are any, use
1203            soup_message_headers_replace (msg->request_headers,
1204            "Cookie", cookies);
1205            to add them
1206         */
1207 }
1208
1209 static void
1210 save_cookies (SoupMessage *msg, gpointer user_data){
1211     (void) user_data;
1212     GSList *ck;
1213     char *req, *cookie;
1214     for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1215         cookie = soup_cookie_to_set_cookie_header(ck->data);
1216         req = malloc(strlen(cookie) + 10);
1217         sprintf(req, "PUT \"%s\"", cookie);
1218         run_command_async(uzbl.behave.cookie_handler, req);
1219         free(req);
1220         free(cookie);
1221     }
1222     g_slist_free(ck);
1223 }
1224
1225 int
1226 main (int argc, char* argv[]) {
1227     gtk_init (&argc, &argv);
1228     if (!g_thread_supported ())
1229         g_thread_init (NULL);
1230
1231     printf("Uzbl start location: %s\n", argv[0]);
1232     strcpy(uzbl.state.executable_path,argv[0]);
1233
1234     strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
1235     strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
1236
1237     GError *error = NULL;
1238     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1239     g_option_context_add_main_entries (context, entries, NULL);
1240     g_option_context_add_group (context, gtk_get_option_group (TRUE));
1241     g_option_context_parse (context, &argc, &argv, &error);
1242     /* initialize hash table */
1243     uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1244         
1245         uzbl.net.soup_session = webkit_get_default_session();
1246     uzbl.state.keycmd = g_string_new("");
1247
1248     settings_init ();
1249     commands_hash ();
1250         
1251     if (uzbl.behave.always_insert_mode)
1252         uzbl.behave.insert_mode = TRUE;
1253
1254     GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
1255     if (uzbl.behave.status_top)
1256         gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1257     gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
1258     if (!uzbl.behave.status_top)
1259         gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1260
1261     uzbl.gui.main_window = create_window ();
1262     gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox);
1263
1264     load_uri (uzbl.gui.web_view, uzbl.state.uri);
1265
1266     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1267     gtk_widget_show_all (uzbl.gui.main_window);
1268     uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1269     printf("window_id %i\n",(int) uzbl.xwin);
1270     printf("pid %i\n", getpid ());
1271     printf("name: %s\n", uzbl.state.instance_name);
1272
1273     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1274     uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1275     uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1276     uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1277     gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1278
1279
1280     if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1281         fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1282
1283     setup_scanner();
1284     if (!uzbl.behave.status_format)
1285         uzbl.behave.status_format = STATUS_DEFAULT;
1286     if (!uzbl.behave.show_status)
1287         gtk_widget_hide(uzbl.gui.mainbar);
1288     else
1289         update_title();
1290
1291
1292     if (uzbl.behave.fifo_dir)
1293         create_fifo ();
1294     if (uzbl.behave.socket_dir)
1295         create_socket();
1296
1297     gtk_main ();
1298     clean_up();
1299
1300     return EXIT_SUCCESS;
1301 }
1302
1303 /* vi: set et ts=4: */