diff options
author | Brendan Taylor <whateley@gmail.com> | 2010-12-30 15:46:39 -0700 |
---|---|---|
committer | Brendan Taylor <whateley@gmail.com> | 2010-12-30 15:46:39 -0700 |
commit | 71dfda767ab2e9bfa2be2f77f1619edf52cc09a4 (patch) | |
tree | 97f44b63a53bc1cb3238f478c8e49a9d5edcf97a /src/uzbl-core.c | |
parent | 4fbba2d523ba65b2dad15cf264eb168157cf0f15 (diff) | |
parent | 99252a853e9dd9e0e706d6793e836fb85f65ab5a (diff) |
Merge branch 'experimental' into dev/script-args-in-env
Conflicts:
src/uzbl-core.c
Diffstat (limited to 'src/uzbl-core.c')
-rw-r--r-- | src/uzbl-core.c | 354 |
1 files changed, 221 insertions, 133 deletions
diff --git a/src/uzbl-core.c b/src/uzbl-core.c index dcdd4c7..592a8dd 100644 --- a/src/uzbl-core.c +++ b/src/uzbl-core.c @@ -93,6 +93,7 @@ const struct var_name_to_ptr_t { { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_set_cookie_handler)}, { "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)}, { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)}, + { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)}, { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)}, { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)}, @@ -414,36 +415,6 @@ find_existing_file(gchar* path_list) { return NULL; } - -/* Returns a new string with environment $variables expanded */ -gchar* -parseenv (gchar* string) { - extern char** environ; - gchar* tmpstr = NULL, * out; - int i = 0; - - if(!string) - return NULL; - - out = g_strdup(string); - while (environ[i] != NULL) { - gchar** env = g_strsplit (environ[i], "=", 2); - gchar* envname = g_strconcat ("$", env[0], NULL); - - if (g_strrstr (string, envname) != NULL) { - tmpstr = out; - out = str_replace(envname, env[1], out); - g_free (tmpstr); - } - - g_free (envname); - g_strfreev (env); // somebody said this breaks uzbl - i++; - } - - return out; -} - void clean_up(void) { if(uzbl.info.pid_str) { @@ -489,15 +460,14 @@ get_click_context() { if(!uzbl.state.last_button) return -1; - ht = webkit_web_view_get_hit_test_result(g->web_view, uzbl.state.last_button); - g_object_get(ht, "context", &context, NULL); + ht = webkit_web_view_get_hit_test_result (g->web_view, uzbl.state.last_button); + g_object_get (ht, "context", &context, NULL); + g_object_unref (ht); return (gint)context; } /* --- SIGNALS --- */ -int sigs[] = {SIGTERM, SIGINT, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGALRM, 0}; - sigfunc* setup_signal(int signr, sigfunc *shandler) { struct sigaction nh, oh; @@ -513,21 +483,9 @@ setup_signal(int signr, sigfunc *shandler) { } void -catch_signal(int s) { - if(s == SIGTERM || - s == SIGINT || - s == SIGILL || - s == SIGFPE || - s == SIGQUIT) { - clean_up(); - exit(EXIT_SUCCESS); - } - else if(s == SIGSEGV) { - clean_up(); - fprintf(stderr, "Program aborted, segmentation fault!\nAttempting to clean up...\n"); - exit(EXIT_FAILURE); - } - else if(s == SIGALRM && uzbl.state.event_buffer) { +empty_event_buffer(int s) { + (void) s; + if(uzbl.state.event_buffer) { g_ptr_array_free(uzbl.state.event_buffer, TRUE); uzbl.state.event_buffer = NULL; } @@ -626,9 +584,10 @@ struct {const char *key; CommandInfo value;} cmdlist[] = { "js", {run_js, TRUE} }, { "script", {run_external_js, 0} }, { "toggle_status", {toggle_status_cb, 0} }, - { "spawn", {spawn, 0} }, + { "spawn", {spawn_async, 0} }, { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler - { "sh", {spawn_sh, 0} }, + { "sync_spawn_exec", {spawn_sync_exec, 0} }, // needed for load_cookies.sh :( + { "sh", {spawn_sh_async, 0} }, { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler { "exit", {close_uzbl, 0} }, { "search", {search_forward_text, TRUE} }, @@ -656,7 +615,9 @@ struct {const char *key; CommandInfo value;} cmdlist[] = { "menu_editable_remove", {menu_remove_edit, TRUE} }, { "hardcopy", {hardcopy, TRUE} }, { "include", {include, TRUE} }, - { "show_inspector", {show_inspector, 0} } + { "show_inspector", {show_inspector, 0} }, + { "add_cookie", {add_cookie, 0} }, + { "delete_cookie", {delete_cookie, 0} } }; void @@ -695,9 +656,8 @@ set_var(WebKitWebView *page, GArray *argv, GString *result) { gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2); if (split[0] != NULL) { - gchar *value = parseenv(split[1] ? g_strchug(split[1]) : " "); + gchar *value = split[1] ? g_strchug(split[1]) : " "; set_var_value(g_strstrip(split[0]), value); - g_free(value); } g_strfreev(split); } @@ -716,7 +676,7 @@ add_to_menu(GArray *argv, guint context) { g->menu_items = g_ptr_array_new(); if(split[1]) - item_cmd = g_strdup(split[1]); + item_cmd = split[1]; if(split[0]) { m = malloc(sizeof(MenuItem)); @@ -726,8 +686,6 @@ add_to_menu(GArray *argv, guint context) { m->issep = FALSE; g_ptr_array_add(g->menu_items, m); } - else - g_free(item_cmd); g_strfreev(split); } @@ -927,14 +885,12 @@ void include(WebKitWebView *page, GArray *argv, GString *result) { (void) page; (void) result; - gchar *pe = NULL, - *path = NULL; + gchar *path = argv_idx(argv, 0); - if(!argv_idx(argv, 0)) + if(!path) return; - pe = parseenv(argv_idx(argv, 0)); - if((path = find_existing_file(pe))) { + if((path = find_existing_file(path))) { if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) { gchar *tmp = g_strdup_printf("File %s can not be read.", path); send_event(COMMAND_ERROR, tmp, NULL); @@ -944,7 +900,6 @@ include(WebKitWebView *page, GArray *argv, GString *result) { send_event(FILE_INCLUDED, path, NULL); g_free(path); } - g_free(pe); } void @@ -955,6 +910,57 @@ show_inspector(WebKitWebView *page, GArray *argv, GString *result) { } void +add_cookie(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + gchar *host, *path, *name, *value; + gboolean secure = 0; + SoupDate *expires = NULL; + + if(argv->len != 6) + return; + + // Parse with same syntax as ADD_COOKIE event + host = argv_idx (argv, 0); + path = argv_idx (argv, 1); + name = argv_idx (argv, 2); + value = argv_idx (argv, 3); + secure = strcmp (argv_idx (argv, 4), "https") == 0; + if (strlen (argv_idx (argv, 5)) != 0) + expires = soup_date_new_from_time_t ( + strtoul (argv_idx (argv, 5), NULL, 10)); + + // Create new cookie + SoupCookie * cookie = soup_cookie_new (name, value, host, path, -1); + soup_cookie_set_secure (cookie, secure); + if (expires) + soup_cookie_set_expires (cookie, expires); + + // Add cookie to jar + uzbl.net.soup_cookie_jar->in_manual_add = 1; + soup_cookie_jar_add_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie); + uzbl.net.soup_cookie_jar->in_manual_add = 0; +} + +void +delete_cookie(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + + if(argv->len < 4) + return; + + SoupCookie * cookie = soup_cookie_new ( + argv_idx (argv, 2), + argv_idx (argv, 3), + argv_idx (argv, 0), + argv_idx (argv, 1), + 0); + + uzbl.net.soup_cookie_jar->in_manual_add = 1; + soup_cookie_jar_delete_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie); + uzbl.net.soup_cookie_jar->in_manual_add = 0; +} + +void act_dump_config() { dump_config(); } @@ -1258,7 +1264,7 @@ run_command (const gchar *command, const gchar **args, const gboolean sync, /*@null@*/ gchar** split_quoted(const gchar* src, const gboolean unquote) { - /* split on unquoted space, return array of strings; + /* split on unquoted space or tab, return array of strings; remove a layer of quotes and backslashes if unquote */ if (!src) return NULL; @@ -1279,7 +1285,7 @@ split_quoted(const gchar* src, const gboolean unquote) { else if ((*p == '\'') && unquote && !dq) sq = !sq; else if (*p == '\'' && !dq) { g_string_append_c(s, *p); sq = ! sq; } - else if ((*p == ' ') && !dq && !sq) { + else if ((*p == ' ' || *p == '\t') && !dq && !sq) { dup = g_strdup(s->str); g_array_append_val(a, dup); g_string_truncate(s, 0); @@ -1294,33 +1300,49 @@ split_quoted(const gchar* src, const gboolean unquote) { } void -_spawn(GArray *argv, char **output_stdout) { +spawn(GArray *argv, gboolean sync, gboolean exec) { gchar *path = NULL; gchar *arg_car = argv_idx(argv, 0); const gchar **arg_cdr = &g_array_index(argv, const gchar *, 1); if (arg_car && (path = find_existing_file(arg_car))) { - run_command(path, arg_cdr, (output_stdout != NULL), output_stdout); + if (uzbl.comm.sync_stdout) + uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + run_command(path, arg_cdr, sync, sync?&uzbl.comm.sync_stdout:NULL); + // run each line of output from the program as a command + if (sync && exec && uzbl.comm.sync_stdout) { + gchar *head = uzbl.comm.sync_stdout; + gchar *tail; + while ((tail = strchr (head, '\n'))) { + *tail = '\0'; + parse_cmd_line(head, NULL); + head = tail + 1; + } + } g_free(path); } } void -spawn(WebKitWebView *web_view, GArray *argv, GString *result) { +spawn_async(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; - - _spawn(argv, NULL); + spawn(argv, FALSE, FALSE); } void spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; + spawn(argv, TRUE, FALSE); +} - _spawn(argv, &uzbl.comm.sync_stdout); +void +spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result) { + (void)web_view; (void)result; + spawn(argv, TRUE, TRUE); } void -_spawn_sh(GArray *argv, char **output_stdout) { +spawn_sh(GArray *argv, gboolean sync) { if (!uzbl.behave.shell_cmd) { g_printerr ("spawn_sh: shell_cmd is not set!\n"); return; @@ -1334,24 +1356,27 @@ _spawn_sh(GArray *argv, char **output_stdout) { for (i = 1; i < g_strv_length(cmd); i++) g_array_prepend_val(argv, cmd[i]); - if (cmd) run_command(cmd[0], (const gchar **) argv->data, - (output_stdout != NULL), output_stdout); + if (cmd) { + if (uzbl.comm.sync_stdout) + uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + run_command(cmd[0], (const gchar **) argv->data, + sync, sync?&uzbl.comm.sync_stdout:NULL); + } g_free (cmdname); g_strfreev (cmd); } void -spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) { +spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; - - _spawn_sh(argv, NULL); + spawn_sh(argv, FALSE); } void spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; - - _spawn_sh(argv, &uzbl.comm.sync_stdout); + spawn_sh(argv, TRUE); } void @@ -1390,14 +1415,13 @@ parse_command(const char *cmd, const char *param, GString *result) { strcmp("request", cmd)) { g_string_printf(tmp, "%s %s", cmd, param?param:""); send_event(COMMAND_EXECUTED, tmp->str, NULL); - g_string_free(tmp, TRUE); } } else { - gchar *tmp = g_strdup_printf("%s %s", cmd, param?param:""); - send_event(COMMAND_ERROR, tmp, NULL); - g_free(tmp); + g_string_printf (tmp, "%s %s", cmd, param?param:""); + send_event(COMMAND_ERROR, tmp->str, NULL); } + g_string_free(tmp, TRUE); } @@ -1568,6 +1592,28 @@ control_fifo(GIOChannel *gio, GIOCondition condition) { return TRUE; } +gboolean +attach_fifo(gchar *path) { + GError *error = NULL; + /* 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. */ + GIOChannel *chan = g_io_channel_new_file(path, "r+", &error); + if (chan) { + if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { + if (uzbl.state.verbose) + printf ("attach_fifo: created successfully as %s\n", path); + send_event(FIFO_SET, path, NULL); + uzbl.comm.fifo_path = path; + g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE); + return TRUE; + } else g_warning ("attach_fifo: could not add watch on %s\n", path); + } else g_warning ("attach_fifo: can't open: %s\n", error->message); + + if (error) g_error_free (error); + return FALSE; +} + /*@null@*/ gchar* init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */ @@ -1577,29 +1623,31 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ uzbl.comm.fifo_path = NULL; } - GIOChannel *chan = NULL; - GError *error = NULL; gchar *path = build_stream_name(FIFO, dir); if (!file_exists(path)) { - if (mkfifo (path, 0666) == 0) { - // 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. - chan = g_io_channel_new_file(path, "r+", &error); - if (chan) { - if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { - if (uzbl.state.verbose) - printf ("init_fifo: created successfully as %s\n", path); - send_event(FIFO_SET, path, NULL); - uzbl.comm.fifo_path = path; - g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE); - return dir; - } else g_warning ("init_fifo: could not add watch on %s\n", path); - } else g_warning ("init_fifo: can't open: %s\n", error->message); + if (mkfifo (path, 0666) == 0 && attach_fifo(path)) { + return dir; } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno)); - } else g_warning ("init_fifo: can't create %s: file exists\n", path); + } else { + /* the fifo exists. but is anybody home? */ + int fd = open(path, O_WRONLY|O_NONBLOCK); + if(fd < 0) { + /* some error occurred, presumably nobody's on the read end. + * we can attach ourselves to it. */ + if(attach_fifo(path)) + return dir; + else + g_warning("init_fifo: can't attach to %s: %s\n", path, strerror(errno)); + } else { + /* somebody's there, we can't use that fifo. */ + close(fd); + /* whatever, this instance can live without a fifo. */ + g_warning ("init_fifo: can't create %s: file exists and is occupied\n", path); + } + } /* if we got this far, there was an error; cleanup */ - if (error) g_error_free (error); g_free(dir); g_free(path); return NULL; @@ -1750,6 +1798,32 @@ control_client_socket(GIOChannel *clientchan) { return TRUE; } + +gboolean +attach_socket(gchar *path, struct sockaddr_un *local) { + GIOChannel *chan = NULL; + int sock = socket (AF_UNIX, SOCK_STREAM, 0); + + if (bind (sock, (struct sockaddr *) local, sizeof(*local)) != -1) { + if (uzbl.state.verbose) + printf ("init_socket: opened in %s\n", path); + + if(listen (sock, 5) < 0) + g_warning ("attach_socket: could not listen on %s: %s\n", path, strerror(errno)); + + if( (chan = g_io_channel_unix_new(sock)) ) { + g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan); + uzbl.comm.socket_path = path; + send_event(SOCKET_SET, path, NULL); + g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE); + return TRUE; + } + } else g_warning ("attach_socket: could not bind to %s: %s\n", path, strerror(errno)); + + return FALSE; +} + + /*@null@*/ gchar* init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */ if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */ @@ -1764,31 +1838,33 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL * return NULL; } - GIOChannel *chan = NULL; - int sock, len; struct sockaddr_un local; gchar *path = build_stream_name(SOCKET, dir); - sock = socket (AF_UNIX, SOCK_STREAM, 0); - local.sun_family = AF_UNIX; strcpy (local.sun_path, path); - unlink (local.sun_path); - len = strlen (local.sun_path) + sizeof (local.sun_family); - if (bind (sock, (struct sockaddr *) &local, len) != -1) { - if (uzbl.state.verbose) - printf ("init_socket: opened in %s\n", path); - listen (sock, 5); - - if( (chan = g_io_channel_unix_new(sock)) ) { - g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan); - uzbl.comm.socket_path = path; - send_event(SOCKET_SET, path, NULL); - g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE); - return dir; + if(!file_exists(path) && attach_socket(path, &local)) { + /* it's free for the taking. */ + return dir; + } else { + /* see if anybody's listening on the socket path we want. */ + int sock = socket (AF_UNIX, SOCK_STREAM, 0); + if(connect(sock, (struct sockaddr *) &local, sizeof(local)) < 0) { + /* some error occurred, presumably nobody's listening. + * we can attach ourselves to it. */ + unlink(path); + if(attach_socket(path, &local)) + return dir; + else + g_warning("init_socket: can't attach to existing socket %s: %s\n", path, strerror(errno)); + } else { + /* somebody's there, we can't use that socket path. */ + close(sock); + /* whatever, this instance can live without a socket. */ + g_warning ("init_socket: can't create %s: socket exists and is occupied\n", path); } - } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno)); + } /* if we got this far, there was an error; cleanup */ g_free(path); @@ -2183,6 +2259,27 @@ retrieve_geometry() { uzbl.gui.geometry = g_string_free(buf, FALSE); } +void +set_webview_scroll_adjustments() { +#ifdef GTK3 + gtk_scrollable_set_hadjustment (GTK_SCROLLABLE(uzbl.gui.web_view), uzbl.gui.bar_h); + gtk_scrollable_set_vadjustment (GTK_SCROLLABLE(uzbl.gui.web_view), uzbl.gui.bar_v); +#else + gtk_widget_set_scroll_adjustments (GTK_WIDGET (uzbl.gui.web_view), + uzbl.gui.bar_h, uzbl.gui.bar_v); +#endif + + g_object_connect((GObject*)uzbl.gui.bar_v, + "signal::value-changed", (GCallback)scroll_vert_cb, NULL, + "signal::changed", (GCallback)scroll_vert_cb, NULL, + NULL); + + g_object_connect((GObject*)uzbl.gui.bar_h, + "signal::value-changed", (GCallback)scroll_horiz_cb, NULL, + "signal::changed", (GCallback)scroll_horiz_cb, NULL, + NULL); +} + /* set up gtk, gobject, variable defaults and other things that tests and other * external applications need to do anyhow */ void @@ -2220,10 +2317,10 @@ initialize(int argc, char *argv[]) { uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new(); soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar)); - for(i=0; sigs[i]; i++) { - if(setup_signal(sigs[i], catch_signal) == SIG_ERR) - fprintf(stderr, "uzbl: error hooking %d: %s\n", sigs[i], strerror(errno)); - } + /* TODO: move the handler setup to event_buffer_timeout and disarm the + * handler in empty_event_buffer? */ + if(setup_signal(SIGALRM, empty_event_buffer) == SIG_ERR) + fprintf(stderr, "uzbl: error hooking %d: %s\n", SIGALRM, strerror(errno)); event_buffer_timeout(10); uzbl.info.webkit_major = webkit_major_version(); @@ -2317,24 +2414,15 @@ main (int argc, char* argv[]) { uzbl.gui.main_window = create_window (); gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox); gtk_widget_show_all (uzbl.gui.main_window); - uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window); + uzbl.xwin = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (uzbl.gui.main_window))); } uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL); uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v); uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL); uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h); - gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v); - g_object_connect((GObject*)uzbl.gui.bar_v, - "signal::value-changed", (GCallback)scroll_vert_cb, NULL, - "signal::changed", (GCallback)scroll_vert_cb, NULL, - NULL); - - g_object_connect((GObject*)uzbl.gui.bar_h, - "signal::value-changed", (GCallback)scroll_horiz_cb, NULL, - "signal::changed", (GCallback)scroll_horiz_cb, NULL, - NULL); + set_webview_scroll_adjustments(); gchar *xwin = g_strdup_printf("%d", (int)uzbl.xwin); g_setenv("UZBL_XID", xwin, TRUE); |