aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--AUTHORS5
-rw-r--r--Makefile55
-rw-r--r--README41
-rw-r--r--docs/COMMUNITY10
-rw-r--r--docs/INSTALL1
-rw-r--r--docs/README.cookies63
-rw-r--r--examples/config/config64
-rw-r--r--examples/config/cookies22
-rwxr-xr-xexamples/data/scripts/auth.py68
-rwxr-xr-xexamples/data/scripts/download.sh22
-rw-r--r--examples/data/scripts/follow.js73
-rwxr-xr-xexamples/data/scripts/follow.sh36
-rwxr-xr-xexamples/data/scripts/formfiller.sh123
-rwxr-xr-xexamples/data/scripts/go_input.sh19
-rwxr-xr-xexamples/data/scripts/history.sh8
-rwxr-xr-xexamples/data/scripts/insert_bookmark.sh21
-rwxr-xr-xexamples/data/scripts/instance-select-wmii.sh72
-rwxr-xr-xexamples/data/scripts/load_url_from_bookmarks.sh28
-rwxr-xr-xexamples/data/scripts/load_url_from_history.sh33
-rwxr-xr-xexamples/data/scripts/session.sh130
-rwxr-xr-xexamples/data/scripts/userscript.sh16
-rwxr-xr-xexamples/data/scripts/userscripts.sh2
-rw-r--r--examples/data/scripts/util/dmenu.sh103
-rw-r--r--examples/data/scripts/util/editor.sh15
-rw-r--r--examples/data/scripts/util/uzbl-dir.sh19
-rw-r--r--examples/data/scripts/util/uzbl-window.sh11
-rwxr-xr-xexamples/data/scripts/uzbl-cookie-daemon44
-rwxr-xr-xexamples/data/scripts/uzbl-event-manager2
-rwxr-xr-xexamples/data/scripts/uzbl-tabbed22
-rw-r--r--examples/uzbl-cookie-manager.c381
-rw-r--r--src/callbacks.c137
-rw-r--r--src/callbacks.h21
-rw-r--r--src/cookie-jar.c306
-rw-r--r--src/cookie-jar.h33
-rw-r--r--src/events.c114
-rw-r--r--src/util.c110
-rw-r--r--src/util.h18
-rwxr-xr-xsrc/uzbl-browser92
-rw-r--r--src/uzbl-core.c483
-rw-r--r--src/uzbl-core.h37
41 files changed, 1777 insertions, 1084 deletions
diff --git a/.gitignore b/.gitignore
index 078164f..2ddbb60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ uzbl-core
*.pyc
*~
tags
+uzbl-cookie-manager
diff --git a/AUTHORS b/AUTHORS
index 3b3e241..848f467 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -26,11 +26,13 @@ In alphabetical order:
Andrea Marchesini <baku@ippolita.net> - resource-request-starting
Andy Spencer - security fixes
Barak A. Pearlmutter - typo fix
+ Ben Boeckel (mathstuf) - added scroll events, refactored the default shell scripts
Brendan Taylor (bct) - various bugfixes, making misc variables much better using expand(), refactoring some internal var stuff
Cedric Staub - Javascript cookies
Chris Mason - code snippets such as basic cookie handler
Chris van Dijk (quigybo) - work on uzbl-tabbed
Ciprian Dorin, Craciun - patches
+ Daiki Ueno (ueno) - fix for crash when opening image in new window
Damien Leon - misc
Daniel M. Hackney - documentation cleanups
David Keijser - various C and python patches.
@@ -49,6 +51,8 @@ In alphabetical order:
James S Wheaton (uranther) - zoom level, test framework
Jan Kolkmeier (jouz) - scrolling, link following
Jason Woofenden (JasonWoof) - geometry=maximized, link following
+ Jochen Sprickerhof - session.sh enhancements
+ Lars-Dominik Braun (PromyLOPh) - added ability to enable/disable the webkit page cache
Laurence Withers (lwithers) - talk_to_socket
Luca Bruno <lucab@debian.org> - bashims fixes
Mark Nevill - misc patches
@@ -56,6 +60,7 @@ In alphabetical order:
Matthew Bauer <mjbauer95@gmail.com> - userscripts
Maximilian Gaß (mxey) - several small patches
Michael Fiano (axionix) - added cookie_daemon.py whitelist
+ Michael Raskin - added show_inspector command
Michael Walker (Barrucadu) <mike AT barrucadu.co.uk> - contributions to early uzbl
Moritz Lenz - small doc fix
Nicolas Pouillard - refactored scroll command
diff --git a/Makefile b/Makefile
index 5287d5c..e4d1b42 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,16 @@
# first entries are for gnu make, 2nd for BSD make. see http://lists.uzbl.org/pipermail/uzbl-dev-uzbl.org/2009-July/000177.html
-CFLAGS:=-std=c99 $(shell pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -lgthread-2.0 -DCOMMIT="\"$(shell ./misc/hash.sh)\"" $(CPPFLAGS) -fPIC -W -Wall -Wextra -pedantic
-CFLAGS!=echo -std=c99 `pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0` -ggdb -Wall -W -DARCH='"\""'`uname -m`'"\""' -lgthread-2.0 -DCOMMIT='"\""'`./misc/hash.sh`'"\""' $(CPPFLAGS) -fPIC -W -Wall -Wextra -pedantic
+CFLAGS:=-std=c99 $(shell pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0 glib-2.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -lgthread-2.0 -DCOMMIT="\"$(shell ./misc/hash.sh)\"" $(CPPFLAGS) -fPIC -W -Wall -Wextra -pedantic
+CFLAGS!=echo -std=c99 `pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0 glib-2.0` -ggdb -Wall -W -DARCH='"\""'`uname -m`'"\""' -lgthread-2.0 -DCOMMIT='"\""'`./misc/hash.sh`'"\""' $(CPPFLAGS) -fPIC -W -Wall -Wextra -pedantic
-LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -pthread $(LDFLAGS)
-LDFLAGS!=echo `pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0` -pthread $(LDFLAGS)
+UZBL_LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0 x11) -pthread $(LDFLAGS)
+UZBL_LDFLAGS!=echo `pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0 x11` -pthread $(LDFLAGS)
SRC = $(wildcard src/*.c)
HEAD = $(wildcard src/*.h)
OBJ = $(foreach obj, $(SRC:.c=.o), $(notdir $(obj)))
-all: uzbl-browser
+all: uzbl-browser uzbl-cookie-manager
VPATH:=src
@@ -21,10 +21,14 @@ VPATH:=src
${OBJ}: ${HEAD}
uzbl-core: ${OBJ}
- @echo -e "\n${CC} -o $@ ${OBJ} ${LDFLAGS}"
- @${CC} -o $@ ${OBJ} ${LDFLAGS}
+ @echo -e "\n${CC} -o $@ ${OBJ} ${UZBL_LDFLAGS}"
+ @${CC} -o $@ ${OBJ} ${UZBL_LDFLAGS}
-uzbl-browser: uzbl-core
+uzbl-cookie-manager: examples/uzbl-cookie-manager.o src/util.o
+ @echo -e "\n${CC} -o $@ uzbl-cookie-manager.o util.o ${LDFLAGS} ${shell pkg-config --libs glib-2.0 libsoup-2.4}"
+ @${CC} -o $@ uzbl-cookie-manager.o util.o ${LDFLAGS} $(shell pkg-config --libs glib-2.0 libsoup-2.4)
+
+uzbl-browser: uzbl-core uzbl-cookie-manager
# packagers, set DESTDIR to your "package directory" and PREFIX to the prefix you want to have on the end-user system
# end-users who build from source: don't care about DESTDIR, update PREFIX if you want to
@@ -62,20 +66,36 @@ test-uzbl-browser-sandbox: uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data
cp -np ./misc/env.sh ./sandbox/env.sh
- source ./sandbox/env.sh && uzbl-cookie-daemon restart -nv &
- source ./sandbox/env.sh && uzbl-event-manager restart -navv &
+ -source ./sandbox/env.sh && uzbl-cookie-manager -v
+ -source ./sandbox/env.sh && uzbl-event-manager restart -avv
source ./sandbox/env.sh && uzbl-browser --uri http://www.uzbl.org --verbose
- source ./sandbox/env.sh && uzbl-cookie-daemon stop -v
+ kill `cat ./sandbox/home/.cache/uzbl/cookie_daemon_socket.pid`
+ source ./sandbox/env.sh && uzbl-event-manager stop -ivv
+ make DESTDIR=./sandbox uninstall
+ rm -rf ./sandbox/usr
+
+test-uzbl-tabbed-sandbox: uzbl-browser
+ make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-core
+ make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser
+ make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data
+ cp -np ./misc/env.sh ./sandbox/env.sh
+ -source ./sandbox/env.sh && uzbl-cookie-manager -v
+ -source ./sandbox/env.sh && uzbl-event-manager restart -avv
+ source ./sandbox/env.sh && ./sandbox/home/.local/share/uzbl/scripts/uzbl-tabbed
+ kill `cat ./sandbox/home/.cache/uzbl/cookie_daemon_socket.pid`
source ./sandbox/env.sh && uzbl-event-manager stop -ivv
make DESTDIR=./sandbox uninstall
rm -rf ./sandbox/usr
clean:
rm -f uzbl-core
+ rm -f uzbl-cookie-manager
rm -f uzbl-core.o
rm -f events.o
rm -f callbacks.o
rm -f inspector.o
+ rm -f cookie-jar.o
+ rm -f util.o
find ./examples/ -name "*.pyc" -delete
cd ./tests/; $(MAKE) clean
rm -rf ./sandbox/
@@ -99,20 +119,19 @@ install-uzbl-core: all install-dirs
install -m644 AUTHORS $(DOCDIR)/
cp -r examples $(INSTALLDIR)/share/uzbl/
chmod 755 $(INSTALLDIR)/share/uzbl/examples/data/scripts/*
- mv $(INSTALLDIR)/share/uzbl/examples/config/config{,.bak}
- sed 's#^set prefix.*=.*#set prefix = $(RUN_PREFIX)#' < $(INSTALLDIR)/share/uzbl/examples/config/config.bak > $(INSTALLDIR)/share/uzbl/examples/config/config
- rm $(INSTALLDIR)/share/uzbl/examples/config/config.bak
install -m755 uzbl-core $(INSTALLDIR)/bin/uzbl-core
-install-uzbl-browser: install-dirs
+install-uzbl-browser: uzbl-cookie-manager install-dirs
install -m755 src/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser
- install -m755 examples/data/scripts/uzbl-cookie-daemon $(INSTALLDIR)/bin/uzbl-cookie-daemon
+ install -m755 uzbl-cookie-manager $(INSTALLDIR)/bin/uzbl-cookie-manager
install -m755 examples/data/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager
- mv $(INSTALLDIR)/bin/uzbl-browser{,.bak}
+ mv $(INSTALLDIR)/bin/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser.bak
sed 's#^PREFIX=.*#PREFIX=$(RUN_PREFIX)#' < $(INSTALLDIR)/bin/uzbl-browser.bak > $(INSTALLDIR)/bin/uzbl-browser
+ chmod 755 $(INSTALLDIR)/bin/uzbl-browser
rm $(INSTALLDIR)/bin/uzbl-browser.bak
- mv $(INSTALLDIR)/bin/uzbl-event-manager{,.bak}
+ mv $(INSTALLDIR)/bin/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager.bak
sed "s#^PREFIX = .*#PREFIX = '$(RUN_PREFIX)'#" < $(INSTALLDIR)/bin/uzbl-event-manager.bak > $(INSTALLDIR)/bin/uzbl-event-manager
+ chmod 755 $(INSTALLDIR)/bin/uzbl-event-manager
rm $(INSTALLDIR)/bin/uzbl-event-manager.bak
install-uzbl-tabbed: install-dirs
diff --git a/README b/README
index 176e67f..22c1a99 100644
--- a/README
+++ b/README
@@ -258,6 +258,8 @@ The following commands are recognized:
- Open the print dialog.
* `include <file>`
- Read contents of `<file>` and interpret as a set of `uzbl` commands.
+* `show_inspector`
+ - Show the WebInspector
### VARIABLES AND CONSTANTS
@@ -335,6 +337,7 @@ file).
* `fantasy_font_family`: The default Fantasy font family used to display text.
* `monospace_size`: The default size of monospaced font (default 1).
* `minimum_font_size`: The minimum font size used to display text (default 1).
+* `enable_pagecache`: Enable the webkit pagecache (it caches rendered pages for a speedup when you go back or forward in history) (default 0).
* `disable_plugins`: Disable embedded plugin objects (default 0).
* `disable_scripts`: Disable embedded scripting languages (default 0).
* `autoload_images`: Automatically load images (default 1).
@@ -477,23 +480,22 @@ You can use external scripts with Uzbl the following ways:
Have a look at the sample configs and scripts!
-Handler scripts that are called by `uzbl` are passed the following arguments:
+Scripts called by `uzbl` (with `spawn`, `sync_spawn`, `sh` or `sync_sh`) have
+access to the following environment variables:
-* `$1 config`: The configuration file loaded by this `uzbl` instance.
-* `$2 pid`: The process ID of this `uzbl` instance.
-* `$3 x_id`: The X Windows ID of the process.
-* `$4 fifo`: The filename of the FIFO being used, if any.
-* `$5 socket`: The filename of the Unix socket being used, if any.
-* `$6 uri`: The URI of the current page.
-* `$7 title`: The current page title.
-* `.. [ script specific ] (optional)`
+* `$UZBL_CONFIG`: The configuration file loaded by this `uzbl` instance.
+* `$UZBL_PID`: The process ID of this `uzbl` instance.
+* `$UZBL_XID`: The X Windows ID of the process.
+* `$UZBL_FIFO`: The filename of the FIFO being used, if any.
+* `$UZBL_SOCKET`: The filename of the Unix socket being used, if any.
+* `$UZBL_URI`: The URI of the current page.
+* `$UZBL_TITLE`: The current page title.
-The script specific arguments are:
+These variables are also available as positional arguments `$1` through `$7`,
+but this is deprecated and will be removed.
-* download
-
- - `$8 url`: The URL of the item to be downloaded.
- - `$9 proxy`: (optional) The URL of an HTTP proxy.
+Handler scripts (`cookie_handler`, `scheme_handler` and
+`authentication_handler`) are called with special arguments:
* cookie handler
@@ -511,13 +513,10 @@ The script specific arguments are:
* authentication handler:
- $8 authentication zone unique identifier
- $9 domain part of URL that requests authentication
- $10 authentication realm
- $11 FALSE if this is the first attempt to authenticate, TRUE otherwise
-
-Custom, userdefined scripts (`spawn foo bar`) get first the arguments as
-specified in the config and then the above 7 are added at the end.
+ - `$8`: authentication zone unique identifier
+ - `$9`: domain part of URL that requests authentication
+ - `$10`: authentication realm
+ - `$11`: FALSE if this is the first attempt to authenticate, TRUE otherwise
### Formfiller.sh
diff --git a/docs/COMMUNITY b/docs/COMMUNITY
index 2817ee9..cbf3b48 100644
--- a/docs/COMMUNITY
+++ b/docs/COMMUNITY
@@ -4,12 +4,12 @@ COMMUNITY
### Mailing list
* Address: [uzbl-dev@lists.uzbl.org](mailto:uzbl-dev@lists.uzbl.org)
-* [Page](http://lists.uzbl.org/listinfo.cgi/uzbl-dev-uzbl.org)
-* [Archives](http://lists.uzbl.org/pipermail/uzbl-dev-uzbl.org/)
+* [Page](http://lists.uzbl.org/listinfo/uzbl-dev)
+* [Archives](http://lists.uzbl.org/pipermail/uzbl-dev/)
### IRC
-* `#uzbl` on irc.freenode.net
+* `#uzbl` on irc.freenode.net ([webchat](http://webchat.freenode.net/?channels=uzbl))
* [Archive](http://www.uzbl.org/irc-log)
### Website
@@ -23,10 +23,6 @@ COMMUNITY
### Code repositories
* [github.com/Dieterbe/uzbl](http://github.com/Dieterbe/uzbl/)
-* [github.com/anydot/uzbl](http://github.com/anydot/uzbl/)
-* [github.com/Barrucadu/uzbl](http://github.com/Barrucadu/uzbl/)
-* [github.com/dusanx/uzbl](http://github.com/dusanx/uzbl/)
-* [github.com/robm/uzbl](http://github.com/robm/uzbl/)
There are more contributors who have forks. See:
diff --git a/docs/INSTALL b/docs/INSTALL
index 76ddccc..accd383 100644
--- a/docs/INSTALL
+++ b/docs/INSTALL
@@ -30,6 +30,7 @@ If you want the specific subprojects, you can issue:
Dependencies
------------
Dependencies which are optional for uzbl-core are marked with an asterisk. (i.e. these are needed for extra scripts)
+
* libwebkit 1.1.15 or higher
* libsoup 2.24 or higher (dep for webkit/gtk+)
* gtk 2.14 or higher
diff --git a/docs/README.cookies b/docs/README.cookies
new file mode 100644
index 0000000..148603f
--- /dev/null
+++ b/docs/README.cookies
@@ -0,0 +1,63 @@
+# Cookies and Uzbl #
+
+The speed of cookie lookups is important, since a single page load can involve
+dozens of HTTP requests, each of which needs a separate cookie lookup (since
+another instance of uzbl may have obtained new cookies for a site).
+
+It is possible handle cookie lookup (and storage) using a `spawn_async` cookie
+handler, but spawning new processes is inherently slow so a `talk_to_socket`
+cookie daemon (like the default uzbl-cookie-manager) is recommended.
+
+## uzbl-cookie-manager ##
+
+uzbl-cookie-manager is a cookie daemon based on libsoup's SoupCookieJar. Cookies
+are stored in a file in the Mozilla cookies.txt format (default location
+$XDG_DATA_HOME/.local/share/cookies.txt).
+
+### uzbl-cookie-manager Whitelist ###
+
+If a whitelist file is present (default location
+$XDG_CONFIG_HOME/uzbl/cookie_whitelist), then website attempts to set cookies
+will be ignored unless the site's domain is present in the whitelist.
+
+The whitelist can contain comment lines beginning with `#`, and domain lines. A
+domain line beginning with . will whitelist the given domain name and any
+subdomain of it. Otherwise only exact matches of the domain are whitelisted.
+
+For instance, given this whitelist file:
+
+ example.com
+ .uzbl.org
+
+uzbl-cookie-manager would accept cookies for example.com, uzbl.org and
+www.uzbl.org, but ignore cookies set for www.example.com (and any other
+domain that is not a subdomain of uzbl.org).
+
+## uzbl-cookie-daemon ##
+
+uzbl-cookie-daemon is a Python cookie daemon based on Python's cookielib.
+Cookielib's lookup algorithm isn't very efficient for our needs, so
+uzbl-cookie-daemon is noticeably slow.
+
+## Cookie Daemon Protocol ##
+
+When uzbl's `cookie_handler` variable is set to `talk_to_socket path`, uzbl
+connects to the Unix domain socket located at `path`. uzbl will send a cookie
+lookup request on this socket every time it makes an HTTP request. The format of
+this lookup request is:
+
+ GET\0scheme\0host\0path\0
+
+where `\0` is the null character, `scheme` is the URL scheme (http or https),
+`host` is the hostname from the URL and `path` is the requested path. The cookie
+daemon should respond with the names and values of cookies that match the
+request, in the format used by the `Cookie` header, terminated with a `\0`.
+
+When a website adds, deletes or changes a cookie, uzbl notifies the cookie
+daemon with a request in the format:
+
+ PUT\0scheme\0host\0path\0name=value\0
+
+where `scheme`, `host` and `path` are (approximately) as above, and `name=value`
+is the cookie name-value pair to store. The cookie daemon should respond by
+writing `\0` to the socket.
diff --git a/examples/config/config b/examples/config/config
index 5656664..e282bb9 100644
--- a/examples/config/config
+++ b/examples/config/config
@@ -3,8 +3,10 @@
# === Core settings ==========================================================
-# Install location prefix.
-set prefix = /usr/local
+# common directory locations
+set prefix = @(echo $PREFIX)@
+set data_home = @(echo $XDG_DATA_HOME)@
+set cache_home = @(echo $XDG_CACHE_HOME)@
# Interface paths.
set fifo_dir = /tmp
@@ -34,20 +36,20 @@ set set_mode = set mode =
set set_status = set status_message =
# Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable"
-set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data:scripts
+set scripts_dir = @data_home/uzbl:@prefix/share/uzbl/examples/data:scripts
# === Hardcoded handlers =====================================================
# These handlers can't be moved to the new event system yet as we don't
# support events that can wait for a response from a script.
-set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket
+set cookie_handler = talk_to_socket @cache_home/uzbl/cookie_daemon_socket
set scheme_handler = sync_spawn @scripts_dir/scheme.py
set authentication_handler = sync_spawn @scripts_dir/auth.py
# === Dynamic event handlers =================================================
# Open link in new window
-@on_event NEW_WINDOW sh 'uzbl-browser -u "$8"' %r
+@on_event NEW_WINDOW sh 'uzbl-browser ${8:+-u "$8"}' %r
# Open in current window
#@on_event NEW_WINDOW uri %s
# Open in new tab
@@ -127,6 +129,7 @@ set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}.@{WEBKIT_MI
@modmap <Control> <Ctrl>
@modmap <ISO_Left_Tab> <Shift-Tab>
@modmap <space> <Space>
+@modmap <KP_Enter> <Enter>
#modkey_addition <Key1> <Key2> <Result>
@modkey_addition <Shift> <Ctrl> <Meta>
@@ -136,6 +139,7 @@ set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}.@{WEBKIT_MI
#ignore_key <glob>
@ignore_key <ISO_*>
@ignore_key <Shift>
+@ignore_key <Multi_key>
# --- Bind aliases -----------------------------------------------------------
@@ -179,7 +183,7 @@ set ebind = @mode_bind global,-insert
# --- Mouse bindings ---------------------------------------------------------
# Middle click open in new window
-@bind <Button2> = sh 'if [ "$8" ]; then uzbl-browser -u "$8"; else echo "uri $(xclip -o | sed s/\\\@/%40/g)" > $4; fi' \@SELECTED_URI
+@bind <Button2> = sh 'if [ "$8" ]; then uzbl-browser -u "$8"; else echo "uri $(xclip -o | sed s/\\\@/%40/g)" > "$UZBL_FIFO"; fi' \@SELECTED_URI
# --- Keyboard bindings ------------------------------------------------------
@@ -187,6 +191,9 @@ set ebind = @mode_bind global,-insert
# a colon.
@cbind :_ = %s
+# open a new window or a new tab (see the on_event NEW_WINDOW settings above)
+@cbind w = event NEW_WINDOW
+
# Page movement binds
@cbind j = scroll vertical 20
@cbind k = scroll vertical -20
@@ -194,8 +201,12 @@ set ebind = @mode_bind global,-insert
@cbind l = scroll horizontal 20
@cbind <Page_Up> = scroll vertical -100%
@cbind <Page_Down> = scroll vertical 100%
+@cbind <Ctrl>f = scroll vertical 100%
+@cbind <Ctrl>b = scroll vertical -100%
@cbind << = scroll vertical begin
@cbind >> = scroll vertical end
+@cbind <Home> = scroll vertical begin
+@cbind <End> = scroll vertical end
@cbind ^ = scroll horizontal begin
@cbind $ = scroll horizontal end
@cbind <Space> = scroll vertical end
@@ -236,14 +247,14 @@ set ebind = @mode_bind global,-insert
# Exit binding
@cbind ZZ = exit
# Dump config to stdout
-@cbind !dump = sh "echo dump_config > $4"
+@cbind !dump = sh 'echo dump_config > "$UZBL_FIFO"'
# Reload all variables in the config
-@cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 | grep '^set ' > $4"
+@cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' \"$UZBL_CONFIG\" | grep '^set ' > \"$UZBL_FIFO\""
# Use socat to directly inject commands into uzbl-core and view events
# raised by uzbl-core:
-@cbind <Ctrl><Alt>t = sh 'xterm -e "socat unix-connect:$5 -"'
-#@cbind <Ctrl><Alt>t = sh 'urxvt -e socat unix-connect:$5 -'
+@cbind <Ctrl><Alt>t = sh "xterm -e 'socat unix-connect:\"$UZBL_SOCKET\" -'"
+#@cbind <Ctrl><Alt>t = sh "urxvt -e 'socat unix-connect:\"$UZBL_SOCKET\" -'"
# Uri opening prompts
@cbind o<uri:>_ = uri %s
@@ -258,20 +269,24 @@ set ebind = @mode_bind global,-insert
@cbind gh = uri http://www.uzbl.org
# Yanking & pasting binds
-@cbind yu = sh 'printf $6 | xclip'
-@cbind yy = sh 'printf $7 | xclip'
+@cbind yu = sh 'echo -n "$UZBL_URI" | xclip'
+@cbind yU = sh 'echo -n $8 | xclip' \@SELECTED_URI
+@cbind yy = sh 'echo -n "$UZBL_TITLE" | xclip'
+@cbind yY = sh 'echo -n $8 | xclip' \@SELECTED_URI
+# Clone current window
+@cbind c = sh 'uzbl-browser -u "$UZBL_URI"'
# Go the page from primary selection
-@cbind p = sh 'echo "uri `xclip -selection primary -o | sed s/\\\@/%40/g`" > $4'
+@cbind p = sh 'echo "uri `xclip -selection primary -o | sed s/\\\@/%40/g`" > "$UZBL_FIFO"'
# Go to the page in clipboard
-@cbind P = sh 'echo "uri `xclip -selection clipboard -o | sed s/\\\@/%40/g`" > $4'
+@cbind P = sh 'echo "uri `xclip -selection clipboard -o | sed s/\\\@/%40/g`" > "$UZBL_FIFO"'
# Start a new uzbl instance from the page in primary selection
-@cbind 'p = sh 'exec uzbl-browser --uri $(xclip -o)'
+@cbind 'p = sh 'exec uzbl-browser --uri "$(xclip -o)"'
# paste primary selection into keycmd at the cursor position
-@bind <Shift-Insert> = sh 'echo "event INJECT_KEYCMD `xclip -o | sed s/\\\@/%40/g`" > $4'
+@bind <Shift-Insert> = sh 'echo "event INJECT_KEYCMD `xclip -o | sed s/\\\@/%40/g`" > "$UZBL_FIFO"'
# Bookmark inserting binds
-@cbind <Ctrl>b<tags:>_ = sh 'echo `printf "$6 %s"` >> $XDG_DATA_HOME/uzbl/bookmarks'
+@cbind <Ctrl>b<tags:>_ = sh 'echo `printf "$UZBL_URI %s"` >> "$XDG_DATA_HOME"/uzbl/bookmarks'
# Or use a script to insert a bookmark.
@cbind B = spawn @scripts_dir/insert_bookmark.sh
@@ -306,7 +321,12 @@ set formfiller = spawn @scripts_dir/formfiller.sh
@cbind gN = event NEW_TAB_NEXT
@cbind go<uri:>_ = event NEW_TAB %s
@cbind gO<uri:>_ = event NEW_TAB_NEXT %s
-@cbind gY = sh 'echo "event NEW_TAB `xclip -selection primary -o | sed s/\\\@/%40/g`" > $4'
+@cbind gy = sh 'echo "event NEW_TAB `xclip -selection primary -o | sed s/\\\@/%40/g`" > "$UZBL_FIFO"'
+@cbind gY = sh 'echo "event NEW_TAB_NEXT `xclip -selection primary -o | sed s/\\\@/%40/g`" > "$UZBL_FIFO"'
+
+# Clone current tab
+@cbind gd = sh 'echo "event NEW_TAB $UZBL_URI" > "$UZBL_FIFO"'
+@cbind gD = sh 'echo "event NEW_TAB_NEXT $UZBL_URI" > "$UZBL_FIFO"'
# Closing / resting
@cbind gC = exit
@@ -360,13 +380,13 @@ set stack = @mode_config stack
@insert modcmd_updates = 0
# Multi-stage-binding mode config.
-@stack keycmd_events = 1
-@stack modcmd_updates = 1
-@stack forward_keys = 0
@stack keycmd_style = foreground="red"
-@stack prompt_style = foreground="#888" weight="light"
@stack status_background = #202020
@stack mode_indicator = Bnd
+@stack prompt_style = foreground="#888" weight="light"
+@stack keycmd_events = 1
+@stack modcmd_updates = 1
+@stack forward_keys = 0
set default_mode = command
diff --git a/examples/config/cookies b/examples/config/cookies
deleted file mode 100644
index 9b7374a..0000000
--- a/examples/config/cookies
+++ /dev/null
@@ -1,22 +0,0 @@
-# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script.
-# stick to this format.
-# trusted -> always store what we get, send what we have (TODO: by default, or when requested?)
-# deny -> deny storing + sending
-
-# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind...
-
-
-TRUSTED
-bbs.archlinux.org
-archlinux.org
-linux.com
-
-
-
-
-DENY
-www.icanhascheezburger.com
-
-
-
-# rest -> ask \ No newline at end of file
diff --git a/examples/data/scripts/auth.py b/examples/data/scripts/auth.py
index 4feb90b..9c1b4fc 100755
--- a/examples/data/scripts/auth.py
+++ b/examples/data/scripts/auth.py
@@ -4,50 +4,50 @@ import gtk
import sys
def responseToDialog(entry, dialog, response):
- dialog.response(response)
+ dialog.response(response)
def getText(authInfo, authHost, authRealm):
- dialog = gtk.MessageDialog(
- None,
- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
- gtk.MESSAGE_QUESTION,
- gtk.BUTTONS_OK_CANCEL,
- None)
- dialog.set_markup('%s at %s' % (authRealm, authHost))
+ dialog = gtk.MessageDialog(
+ None,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ gtk.MESSAGE_QUESTION,
+ gtk.BUTTONS_OK_CANCEL,
+ None)
+ dialog.set_markup('%s at %s' % (authRealm, authHost))
- login = gtk.Entry()
- password = gtk.Entry()
- password.set_visibility(False)
+ login = gtk.Entry()
+ password = gtk.Entry()
+ password.set_visibility(False)
- login.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK)
- password.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK)
+ login.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK)
+ password.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK)
- hbox = gtk.HBox();
+ hbox = gtk.HBox();
- vbox_entries = gtk.VBox();
- vbox_labels = gtk.VBox();
+ vbox_entries = gtk.VBox();
+ vbox_labels = gtk.VBox();
- vbox_labels.pack_start(gtk.Label("Login:"), False, 5, 5)
- vbox_labels.pack_end(gtk.Label("Password:"), False, 5, 5)
+ vbox_labels.pack_start(gtk.Label("Login:"), False, 5, 5)
+ vbox_labels.pack_end(gtk.Label("Password:"), False, 5, 5)
- vbox_entries.pack_start(login)
- vbox_entries.pack_end(password)
+ vbox_entries.pack_start(login)
+ vbox_entries.pack_end(password)
- dialog.format_secondary_markup("Please enter username and password:")
- hbox.pack_start(vbox_labels, True, True, 0)
- hbox.pack_end(vbox_entries, True, True, 0)
+ dialog.format_secondary_markup("Please enter username and password:")
+ hbox.pack_start(vbox_labels, True, True, 0)
+ hbox.pack_end(vbox_entries, True, True, 0)
- dialog.vbox.pack_start(hbox)
- dialog.show_all()
- rv = dialog.run()
+ dialog.vbox.pack_start(hbox)
+ dialog.show_all()
+ rv = dialog.run()
- output = login.get_text() + "\n" + password.get_text()
- dialog.destroy()
- return rv, output
+ output = login.get_text() + "\n" + password.get_text()
+ dialog.destroy()
+ return rv, output
if __name__ == '__main__':
- rv, output = getText(sys.argv[8], sys.argv[9], sys.argv[10])
- if (rv == gtk.RESPONSE_OK):
- print output;
- else:
- exit(1)
+ rv, output = getText(sys.argv[8], sys.argv[9], sys.argv[10])
+ if (rv == gtk.RESPONSE_OK):
+ print output;
+ else:
+ exit(1)
diff --git a/examples/data/scripts/download.sh b/examples/data/scripts/download.sh
index f6d34e9..b378a85 100755
--- a/examples/data/scripts/download.sh
+++ b/examples/data/scripts/download.sh
@@ -2,21 +2,25 @@
# just an example of how you could handle your downloads
# try some pattern matching on the uri to determine what we should do
+shift 7
+. $UZBL_UTIL_DIR/uzbl-dir.sh
+
# Some sites block the default wget --user-agent..
-GET="wget --user-agent=Firefox --content-disposition --load-cookies=$XDG_DATA_HOME/uzbl/cookies.txt"
+GET="wget --user-agent=Firefox --content-disposition --load-cookies=$UZBL_COOKIE_FILE"
-dest="$HOME"
-url="$8"
+url="$1"
-http_proxy="$9"
+http_proxy="$2"
export http_proxy
-test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; }
+if [ -z "$url" ]; then
+ echo "you must supply a url! ($url)"
+ exit 1
+fi
# only changes the dir for the $get sub process
-if echo "$url" | grep -E '.*\.torrent' >/dev/null;
-then
- ( cd "$dest"; $GET "$url")
+if echo "$url" | grep -E '.*\.torrent' >/dev/null; then
+ ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url")
else
- ( cd "$dest"; $GET "$url")
+ ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url")
fi
diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js
index 77c40cd..d995696 100644
--- a/examples/data/scripts/follow.js
+++ b/examples/data/scripts/follow.js
@@ -119,25 +119,21 @@ function generateHint(el, label) {
// hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)';
return hint;
}
-//Here we choose what to do with an element if we
-//want to "follow" it. On form elements we "select"
-//or pass the focus, on links we try to perform a click,
-//but at least set the href of the link. (needs some improvements)
+
+// Here we choose what to do with an element that the user has selected.
+// Form elements get selected and/or focussed, and links and buttons are
+// clicked. This function returns "XXXRESET_MODEXXX" to indicate that uzbl
+// should be reset to command mode with an empty keycmd, or
+// "XXX_EMIT_FORM_ACTIVEXXX" to indicate that uzbl should be set to insert mode.
function clickElem(item) {
removeAllHints();
if (item) {
var name = item.tagName;
- if (name == 'A') {
+ if (name == 'BUTTON') {
item.click();
- window.location = item.href;
- return "XXXRESET_MODEXXX";
+ return "XXXRESET_MODEXXX";
} else if (name == 'INPUT') {
- var type;
- try {
- type = item.getAttribute('type').toUpperCase();
- } catch(err) {
- type = 'TEXT';
- }
+ var type = item.type.toUpperCase();
if (type == 'TEXT' || type == 'SEARCH' || type == 'PASSWORD') {
item.focus();
item.select();
@@ -153,6 +149,7 @@ function clickElem(item) {
} else {
item.click();
window.location = item.href;
+ return "XXXRESET_MODEXXX";
}
}
}
@@ -175,7 +172,7 @@ function addFormElems() {
for (var f = 0; f < forms.length; f++) {
for (var e = 0; e < forms[f].elements.length; e++) {
var el = forms[f].elements[e];
- if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) {
+ if (el && ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) {
res[0].push(el);
}
}
@@ -202,38 +199,38 @@ function reDrawHints(elems, chars) {
// pass: number of keys
// returns: key length
function labelLength(n) {
- var oldn = n;
- var keylen = 0;
- if(n < 2) {
- return 1;
- }
- n -= 1; // our highest key will be n-1
- while(n) {
- keylen += 1;
- n = Math.floor(n / charset.length);
- }
- return keylen;
+ var oldn = n;
+ var keylen = 0;
+ if(n < 2) {
+ return 1;
+ }
+ n -= 1; // our highest key will be n-1
+ while(n) {
+ keylen += 1;
+ n = Math.floor(n / charset.length);
+ }
+ return keylen;
}
// pass: number
// returns: label
function intToLabel(n) {
- var label = '';
- do {
- label = charset.charAt(n % charset.length) + label;
- n = Math.floor(n / charset.length);
- } while(n);
- return label;
+ var label = '';
+ do {
+ label = charset.charAt(n % charset.length) + label;
+ n = Math.floor(n / charset.length);
+ } while(n);
+ return label;
}
// pass: label
// returns: number
function labelToInt(label) {
- var n = 0;
- var i;
- for(i = 0; i < label.length; ++i) {
- n *= charset.length;
- n += charset.indexOf(label[i]);
- }
- return n;
+ var n = 0;
+ var i;
+ for(i = 0; i < label.length; ++i) {
+ n *= charset.length;
+ n += charset.indexOf(label[i]);
+ }
+ return n;
}
//Put it all together
function followLinks(follow) {
diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh
index ba59575..2d666a2 100755
--- a/examples/data/scripts/follow.sh
+++ b/examples/data/scripts/follow.sh
@@ -1,21 +1,23 @@
#!/bin/sh
-config=$1;
-shift
-pid=$1;
-shift
-xid=$1;
-shift
-fifo=$1;
-shift
-socket=$1;
-shift
-url=$1;
-shift
-title=$1;
-shift
+# This script is just a wrapper around follow.js that lets us change uzbl's mode
+# after a link is selected.
-case $(echo 'script @scripts_dir/follow.js "@{follow_hint_keys} '$1'"' | socat - unix-connect:$socket) in
- *XXXEMIT_FORM_ACTIVEXXX*) echo 'event FORM_ACTIVE' | socat - unix-connect:$socket ;;
- *XXXRESET_MODEXXX*) echo 'set mode=' | socat - unix-connect:$socket ;;
+shift 7
+
+# if socat is installed then we can change Uzbl's input mode once a link is
+# selected; otherwise we just select a link.
+if ! which socat >/dev/null 2>&1; then
+ echo 'script @scripts_dir/follow.js "@{follow_hint_keys} '$1'"' > "$UZBL_FIFO"
+ exit
+fi
+
+result=$(echo 'script @scripts_dir/follow.js "@{follow_hint_keys} '$1'"' | socat - unix-connect:"$UZBL_SOCKET")
+case $result in
+ *XXXEMIT_FORM_ACTIVEXXX*)
+ # a form element was selected
+ echo 'event FORM_ACTIVE' > "$UZBL_FIFO" ;;
+ *XXXRESET_MODEXXX*)
+ # a link was selected, reset uzbl's input mode
+ echo 'set mode=' > "$UZBL_FIFO" ;;
esac
diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh
index deccea2..6e04573 100755
--- a/examples/data/scripts/formfiller.sh
+++ b/examples/data/scripts/formfiller.sh
@@ -2,12 +2,12 @@
#
# Enhanced html form (eg for logins) filler (and manager) for uzbl.
#
-# uses settings files like: $keydir/<domain>
+# uses settings files like: $UZBL_FORMS_DIR/<domain>
# files contain lines like: !profile=<profile_name>
# <fieldname>(fieldtype): <value>
-# profile_name should be replaced with a name that will tell sth about that
+# profile_name should be replaced with a name that will tell sth about that
# profile
-# fieldtype can be checkbox, text or password, textarea - only for information
+# fieldtype can be checkbox, text or password, textarea - only for information
# pupropse (auto-generated) - don't change that
#
# Texteares: for textareas edited text can be now splitted into more lines.
@@ -37,63 +37,32 @@
# something else (or empty): if file not available: new, otherwise load.
#
-# config dmenu colors and prompt
-NB="#0f0f0f"
-NF="#4e7093"
-SB="#003d7c"
-SF="#3a9bff"
+DMENU_ARGS="-i"
+DMENU_SCHEMA="formfiller"
+DMENU_LINES="3"
+DMENU_PROMPT="Choose profile"
+DMENU_OPTIONS="vertical resize"
-if [ "`dmenu --help 2>&1| grep lines`x" != "x" ]
-then
- LINES=" -l 3 "
-else
- LINES=""
-fi
+. $UZBL_UTIL_DIR/dmenu.sh
+. $UZBL_UTIL_DIR/editor.sh
+. $UZBL_UTIL_DIR/uzbl-dir.sh
-PROMPT="Choose profile"
RAND=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -c 1-5)
MODELINE="> vim:ft=formfiller"
-keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/dforms
-
-[ -d "`dirname $keydir`" ] || exit 1
-[ -d "$keydir" ] || mkdir "$keydir"
+[ -d "$(dirname $UZBL_FORMS_DIR)" ] || exit 1
+[ -d $UZBL_FORMS_DIR ] || mkdir $UZBL_FORMS_DIR || exit 1
-editor="${VISUAL}"
-if [ -z "${editor}" ]; then
- if [ -z "${EDITOR}" ]; then
- editor='xterm -e vim'
- else
- editor="xterm -e ${EDITOR}"
- fi
-fi
+shift 7
-config=$1;
-shift
-pid=$1;
-shift
-xid=$1;
-shift
-fifo=$1;
-shift
-socket=$1;
-shift
-url=$1;
-shift
-title=$1;
-shift
action=$1
-[ -d $keydir ] || mkdir $keydir || exit 1
-
-domain=$(echo $url | sed 's/\(http\|https\):\/\/\([^\/]\+\)\/.*/\2/')
+domain=$(echo $UZBL_URI | sed 's/\(http\|https\):\/\/\([^\/]\+\)\/.*/\2/')
-if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' -a "$action" != 'add' -a "$action" != 'once' ]
-then
+if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' -a "$action" != 'add' -a "$action" != 'once' ]; then
action="new"
- [ -e "$keydir/$domain" ] && action="load"
-elif [ "$action" = 'edit' ] && [ ! -e "$keydir/$domain" ]
-then
+ [ -e "$UZBL_FORMS_DIR/$domain" ] && action="load"
+elif [ "$action" = 'edit' ] && [ ! -e "$UZBL_FORMS_DIR/$domain" ]; then
action="new"
fi
@@ -153,41 +122,38 @@ insertFunction="function insert(fname, ftype, fvalue, fchecked) { \
} \
}; "
-if [ "$action" = 'load' ]
-then
- [ -e $keydir/$domain ] || exit 2
- if [ `cat $keydir/$domain|grep "!profile"|wc -l` -gt 1 ]
- then
- menu=`cat $keydir/$domain| \
- sed -n 's/^!profile=\([^[:blank:]]\+\)/\1/p'`
- option=`printf "$menu"| dmenu ${LINES} -nb "${NB}" -nf "${NF}" -sb "${SB}" -sf "${SF}" -p "${PROMPT}"`
+if [ "$action" = 'load' ]; then
+ [ -e $UZBL_FORMS_DIR/$domain ] || exit 2
+ if [ $(cat $UZBL_FORMS_DIR/$domain | grep "!profile" | wc -l) -gt 1 ]; then
+ menu=$(cat $UZBL_FORMS_DIR/$domain | \
+ sed -n 's/^!profile=\([^[:blank:]]\+\)/\1/p')
+ option=$(printf "$menu" | $DMENU)
fi
# Remove comments
sed '/^>/d' -i $tmpfile
- sed 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' -i $keydir/$domain
- fields=`cat $keydir/$domain | \
+ sed 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' -i $UZBL_FORMS_DIR/$domain
+ fields=$(cat $UZBL_FORMS_DIR/$domain | \
sed -n "/^!profile=${option}/,/^!profile=/p" | \
sed '/^!profile=/d' | \
sed 's/^\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):/%{>\1\2):<}%/' | \
sed 's/^\(.\+\)$/<{br}>\1/' | \
tr -d '\n' | \
- sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g'`
+ sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g')
printf '%s\n' "${fields}" | \
sed -n -e "s/\([^(]\+\)(\(password\|text\|search\|textarea\)\+):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\2', '\3', 0);/p" | \
- sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' > $fifo
+ sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' | socat - unix-connect:$UZBL_SOCKET
printf '%s\n' "${fields}" | \
sed -n -e "s/\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\3', '\2', \4);/p" | \
- sed -e 's/@/\\@/g' > $fifo
-elif [ "$action" = "once" ]
-then
- tmpfile=`mktemp`
+ sed -e 's/@/\\@/g' | socat - unix-connect:$UZBL_SOCKET
+elif [ "$action" = "once" ]; then
+ tmpfile=$(mktemp)
printf 'js %s dump(); \n' "$dumpFunction" | \
- socat - unix-connect:$socket | \
+ socat - unix-connect:$UZBL_SOCKET | \
sed -n '/^[^(]\+([^)]\+):/p' > $tmpfile
echo "$MODELINE" >> $tmpfile
- ${editor} $tmpfile
+ $UZBL_EDITOR $tmpfile
[ -e $tmpfile ] || exit 2
@@ -195,23 +161,22 @@ then
sed '/^>/d' -i $tmpfile
sed 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' -i $tmpfile
- fields=`cat $tmpfile | \
+ fields=$(cat $tmpfile | \
sed 's/^\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):/%{>\1\2):<}%/' | \
sed 's/^\(.\+\)$/<{br}>\1/' | \
tr -d '\n' | \
- sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g'`
+ sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g')
printf '%s\n' "${fields}" | \
sed -n -e "s/\([^(]\+\)(\(password\|text\|search\|textarea\)\+):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\2', '\3', 0);/p" | \
- sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' > $fifo
+ sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' | socat - unix-connect:$UZBL_SOCKET
printf '%s\n' "${fields}" | \
sed -n -e "s/\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\3', '\2', \4);/p" | \
- sed -e 's/@/\\@/g' > $fifo
+ sed -e 's/@/\\@/g' | socat - unix-connect:$UZBL_SOCKET
rm -f $tmpfile
else
- if [ "$action" = 'new' -o "$action" = 'add' ]
- then
- [ "$action" = 'new' ] && echo "$MODELINE" > $keydir/$domain
- echo "!profile=NAME_THIS_PROFILE$RAND" >> $keydir/$domain
+ if [ "$action" = 'new' -o "$action" = 'add' ]; then
+ [ "$action" = 'new' ] && echo "$MODELINE" > $UZBL_FORMS_DIR/$domain
+ echo "!profile=NAME_THIS_PROFILE$RAND" >> $UZBL_FORMS_DIR/$domain
#
# 2. and 3. line (tr -d and sed) are because, on gmail login for example,
# <input > tag is splited into lines
@@ -229,11 +194,11 @@ else
# passwd(password):
#
printf 'js %s dump(); \n' "$dumpFunction" | \
- socat - unix-connect:$socket | \
- sed -n '/^[^(]\+([^)]\+):/p' >> $keydir/$domain
+ socat - unix-connect:$UZBL_SOCKET | \
+ sed -n '/^[^(]\+([^)]\+):/p' >> $UZBL_FORMS_DIR/$domain
fi
- [ -e "$keydir/$domain" ] || exit 3 #this should never happen, but you never know.
- $editor "$keydir/$domain" #TODO: if user aborts save in editor, the file is already overwritten
+ [ -e "$UZBL_FORMS_DIR/$domain" ] || exit 3 #this should never happen, but you never know.
+ $UZBL_EDITOR "$UZBL_FORMS_DIR/$domain" #TODO: if user aborts save in editor, the file is already overwritten
fi
# vim:fileencoding=utf-8:sw=4
diff --git a/examples/data/scripts/go_input.sh b/examples/data/scripts/go_input.sh
index c873dd8..ace0e79 100755
--- a/examples/data/scripts/go_input.sh
+++ b/examples/data/scripts/go_input.sh
@@ -1,20 +1,5 @@
#!/bin/sh
-config=$1;
-shift
-pid=$1;
-shift
-xid=$1;
-shift
-fifo=$1;
-shift
-socket=$1;
-shift
-url=$1;
-shift
-title=$1;
-shift
-
-case $(echo 'script @scripts_dir/go_input.js' | socat - unix-connect:$socket) in
- *XXXEMIT_FORM_ACTIVEXXX*) echo 'event FORM_ACTIVE' | socat - unix-connect:$socket ;;
+case $(echo 'script @scripts_dir/go_input.js' | socat - unix-connect:"$UZBL_SOCKET") in
+ *XXXEMIT_FORM_ACTIVEXXX*) echo 'event FORM_ACTIVE' > "$UZBL_FIFO" ;;
esac
diff --git a/examples/data/scripts/history.sh b/examples/data/scripts/history.sh
index 7c83aa6..266d65d 100755
--- a/examples/data/scripts/history.sh
+++ b/examples/data/scripts/history.sh
@@ -1,5 +1,7 @@
#!/bin/sh
-file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history
-[ -d `dirname $file` ] || exit 1
-echo `date +'%Y-%m-%d %H:%M:%S'`" $6 $7" >> $file
+. $UZBL_UTIL_DIR/uzbl-dir.sh
+
+[ -w "$UZBL_HISTORY_FILE" ] || [ ! -a "$UZBL_HISTORY_FILE" ] || exit 1
+
+echo $(date +'%Y-%m-%d %H:%M:%S')" $UZBL_URI $UZBL_TITLE" >> $UZBL_HISTORY_FILE
diff --git a/examples/data/scripts/insert_bookmark.sh b/examples/data/scripts/insert_bookmark.sh
index 2ec5975..f67e67a 100755
--- a/examples/data/scripts/insert_bookmark.sh
+++ b/examples/data/scripts/insert_bookmark.sh
@@ -1,18 +1,15 @@
#!/bin/sh
-[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1
-file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks
+. "$UZBL_UTIL_DIR"/uzbl-dir.sh
-which zenity 2>&1 >/dev/null || exit 2
-url=$6
-# replace tabs, they are pointless in titles and we want to use tabs as delimiter.
-title=$(echo "$7" | sed 's/\t/ /')
-entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$url $title\t"`
+[ -d "$UZBL_DATA_DIR" ] || exit 1
+[ -w "$UZBL_BOOKMARKS_FILE" ] || [ ! -a "$UZBL_BOOKMARKS_FILE" ] || exit 1
+
+which zenity >/dev/null 2>&1 || exit 2
+
+tags=$(zenity --entry --text="Enter space-separated tags for bookmark $UZBL_URI:")
exitstatus=$?
-if [ $exitstatus -ne 0 ]; then exit $exitstatus; fi
-url=`echo $entry | awk '{print $1}'`
+[ $exitstatus -eq 0 ] || exit $exitstatus
# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags
-echo "$entry" >/dev/null #for some reason we need this.. don't ask me why
-printf "$entry\n" >> $file
-true
+echo "$UZBL_URI $tags" >> "$UZBL_BOOKMARKS_FILE"
diff --git a/examples/data/scripts/instance-select-wmii.sh b/examples/data/scripts/instance-select-wmii.sh
index 64b859e..19d04e8 100755
--- a/examples/data/scripts/instance-select-wmii.sh
+++ b/examples/data/scripts/instance-select-wmii.sh
@@ -11,44 +11,38 @@
# See http://www.uzbl.org/wiki/wmii for more info
# $1 must be one of 'list', 'next', 'prev'
-COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030"
+DMENU_SCHEME="wmii"
-if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'
-then
- DMENU="dmenu -i -xs -rs -l 10" # vertical patch
-else
- DMENU="dmenu -i"
-fi
+. $UZBL_UTIL_DIR/dmenu.sh
-if [ "$1" = 'list' ]
-then
- list=
- # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky
- for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2)
- do
- label=$(wmiir read /client/$i/label)
- list="$list$i : $label\n"
- done
- window=$(printf "$list\n" | $DMENU $COLORS | cut -d ' ' -f1)
- wmiir xwrite /tag/sel/ctl "select client $window"
-elif [ "$1" = 'next' ]
-then
- current=$(wmiir read /client/sel/ctl | head -n 1)
- # find the next uzbl window and focus it
- next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2)
- if [ x"$next" != "x" ]
- then
- wmiir xwrite /tag/sel/ctl "select client $next"
- fi
-elif [ "$1" = 'prev' ]
-then
- current=$(wmiir read /client/sel/ctl | head -n 1)
- prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2)
- if [ x"$prev" != "x" ]
- then
- wmiir xwrite /tag/sel/ctl "select client $prev"
- fi
-else
- echo "\$1 not valid" >&2
- exit 2
-fi
+case "$1" in
+ "list" )
+ list=
+ # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky
+ for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2); do
+ label=$(wmiir read /client/$i/label)
+ list="$list$i : $label\n"
+ done
+ window=$(printf "$list\n" | $DMENU | cut -d ' ' -f1)
+ wmiir xwrite /tag/sel/ctl "select client $window"
+ ;;
+ "next" )
+ current=$(wmiir read /client/sel/ctl | head -n 1)
+ # find the next uzbl window and focus it
+ next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2)
+ if [ -n "$next" ]; then
+ wmiir xwrite /tag/sel/ctl "select client $next"
+ fi
+ ;;
+ "prev" )
+ current=$(wmiir read /client/sel/ctl | head -n 1)
+ prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2)
+ if [ -n "$prev" ]; then
+ wmiir xwrite /tag/sel/ctl "select client $prev"
+ fi
+ ;;
+ * )
+ echo "$1 not valid" >&2
+ exit 2
+ ;;
+esac
diff --git a/examples/data/scripts/load_url_from_bookmarks.sh b/examples/data/scripts/load_url_from_bookmarks.sh
index cb13420..a5d9586 100755
--- a/examples/data/scripts/load_url_from_bookmarks.sh
+++ b/examples/data/scripts/load_url_from_bookmarks.sh
@@ -2,19 +2,21 @@
#NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes.
-file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks
-[ -r "$file" ] || exit
-COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030"
-if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'
-then
- DMENU="dmenu -i -xs -rs -l 10" # vertical patch
- # show tags as well
- goto=`$DMENU $COLORS < $file | awk '{print $1}'`
+DMENU_SCHEME="bookmarks"
+DMENU_OPTIONS="xmms vertical resize"
+
+. "$UZBL_UTIL_DIR"/dmenu.sh
+. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+
+[ -r "$UZBL_BOOKMARKS_FILE" ] || exit 1
+
+if [ -z "$DMENU_HAS_VERTICAL" ]; then
+ # because they are all after each other, just show the url, not their tags.
+ goto=$(awk '{print $1}' "$UZBL_BOOKMARKS_FILE" | $DMENU)
else
- DMENU="dmenu -i"
- # because they are all after each other, just show the url, not their tags.
- goto=`awk '{print $1}' $file | $DMENU $COLORS`
+ # show tags as well
+ goto=$($DMENU < "$UZBL_BOOKMARKS_FILE" | awk '{print $1}')
fi
-#[ -n "$goto" ] && echo "uri $goto" > $4
-[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5
+[ -n "$goto" ] && echo "uri $goto" > "$UZBL_FIFO"
+#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:"$UZBL_SOCKET"
diff --git a/examples/data/scripts/load_url_from_history.sh b/examples/data/scripts/load_url_from_history.sh
index 62e02ac..59ad492 100755
--- a/examples/data/scripts/load_url_from_history.sh
+++ b/examples/data/scripts/load_url_from_history.sh
@@ -1,24 +1,23 @@
#!/bin/sh
-history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history
-[ -r "$history_file" ] || exit 1
+DMENU_SCHEME="history"
+DMENU_OPTIONS="xmms vertical resize"
+
+. "$UZBL_UTIL_DIR"/dmenu.sh
+. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+
+[ -r "$UZBL_HISTORY_FILE" ] || exit 1
# choose from all entries, sorted and uniqued
-# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i`
-COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030"
-if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]';
-then
- DMENU="dmenu -i -xs -rs -l 10" # vertical patch
- # choose an item in reverse order, showing also the date and page titles
- # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url.
- goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'`
+# goto=$(awk '{print $3}' $history_file | sort -u | dmenu -i)
+if [ -z "$DMENU_HAS_VERTICAL" ]; then
+ current=$(tail -n 1 "$UZBL_HISTORY_FILE" | awk '{print $3}');
+ goto=$( (echo $current; awk '{print $3}' "$UZBL_HISTORY_FILE" | grep -v "^$current\$" | sort -u) | $DMENU)
else
- DMENU="dmenu -i"
- # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order
- current=`tail -n 1 $history_file | awk '{print $3}'`;
- goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" \
- | sort -u) | $DMENU $COLORS`
+ # choose an item in reverse order, showing also the date and page titles
+ # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url.
+ goto=$(tac "$UZBL_HISTORY_FILE" | $DMENU | cut -d ' ' -f -3 | awk '{print $NF}')
fi
-[ -n "$goto" ] && echo "uri $goto" > $4
-#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5
+[ -n "$goto" ] && echo "uri $goto" > "$UZBL_FIFO"
+#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:"$UZBL_SOCKET"
diff --git a/examples/data/scripts/session.sh b/examples/data/scripts/session.sh
index 1059b5e..36e0c19 100755
--- a/examples/data/scripts/session.sh
+++ b/examples/data/scripts/session.sh
@@ -1,62 +1,84 @@
#!/bin/sh
+#
+# Very simple session manager for uzbl-browser.
+# To use, add a line like 'bind quit = spawn @scripts_dir/session.sh' to your
+# config. This binding will exit every instance of uzbl and store the URLs they
+# had open in $UZBL_SESSION_FILE.
+#
+# When a session file exists this script can be run with no arguments (or the
+# argument "launch") to start an instance of uzbl-browser for every stored url.
+#
+# If no session file exists (or if called with "endsession" as the first
+# argument), this script looks for instances of uzbl that have fifos in
+# $UZBL_FIFO_DIR and instructs each of them to store its current url in
+# $UZBL_SESSION_FILE and terminate.
+#
+# "endinstance" is used internally and doesn't need to be called manually.
-# Very simple session manager for uzbl-browser. When called with "endsession" as the
-# argument, it'll backup $sessionfile, look for fifos in $fifodir and
-# instruct each of them to store their current url in $sessionfile and
-# terminate themselves. Run with "launch" as the argument and an instance of
-# uzbl-browser will be launched for each stored url. "endinstance" is used internally
-# and doesn't need to be called manually at any point.
-# Add a line like 'bind quit = /path/to/session.sh endsession' to your config
-
-[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1
-scriptfile=$0 # this script
-sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/browser-session # the file in which the "session" (i.e. urls) are stored
-configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file
-UZBL="uzbl-browser -c $configfile" # add custom flags and whatever here.
-
-fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere
-thisfifo="$4"
-act="$8"
-url="$6"
-
-if [ "$act." = "." ]; then
- act="$1"
+if [ -z "$UZBL_UTIL_DIR" ]; then
+ # we're being run standalone, we have to figure out where $UZBL_UTIL_DIR is
+ # using the same logic as uzbl-browser does.
+ UZBL_UTIL_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/scripts/util
+ if ! [ -d "$UZBL_UTIL_DIR" ]; then
+ PREFIX=$(grep '^PREFIX' "$(which uzbl-browser)" | sed 's/.*=//')
+ UZBL_UTIL_DIR=$PREFIX/share/uzbl/examples/data/scripts/util
+ fi
+fi
+
+. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+[ -d "$UZBL_DATA_DIR" ] || exit 1
+
+UZBL="uzbl-browser -c $UZBL_CONFIG_FILE" # add custom flags and whatever here.
+
+if [ $# -gt 1 ]; then
+ # this script is being run from uzbl, rather than standalone
+ # discard the uzbl arguments
+ shift 7
fi
+scriptfile=$(readlink -f $0) # this script
+act="$1"
+
+if [ -z "$act" ]; then
+ [ -f "$UZBL_SESSION_FILE" ] && act="launch" || act="endsession"
+fi
case $act in
- "launch" )
- urls=`cat $sessionfile`
- if [ "$urls." = "." ]; then
- $UZBL
- else
- for url in $urls; do
- $UZBL --uri "$url" &
- done
- fi
- exit 0
- ;;
+ "launch" )
+ urls=$(cat "$UZBL_SESSION_FILE")
+ if [ -z "$urls" ]; then
+ $UZBL
+ else
+ for url in $urls; do
+ $UZBL --uri "$url" &
+ done
+ mv "$UZBL_SESSION_FILE" "$UZBL_SESSION_FILE~"
+ fi
+ ;;
- "endinstance" )
- if [ "$url" != "(null)" ]; then
- echo "$url" >> $sessionfile;
- fi
- echo "exit" > "$thisfifo"
- ;;
-
- "endsession" )
- mv "$sessionfile" "$sessionfile~"
- for fifo in $fifodir/uzbl_fifo_*; do
- if [ "$fifo" != "$thisfifo" ]; then
- echo "spawn $scriptfile endinstance" > "$fifo"
- fi
- done
- echo "spawn $scriptfile endinstance" > "$thisfifo"
- ;;
-
- * ) echo "session manager: bad action"
- echo "Usage: $scriptfile [COMMAND] where commands are:"
- echo " launch - Restore a saved session or start a new one"
- echo " endsession - Quit the running session. Must be called from uzbl"
- ;;
+ "endinstance" )
+ if [ -z "$UZBL_FIFO" ]; then
+ echo "session manager: endinstance must be called from uzbl"
+ exit 1
+ fi
+ [ "$UZBL_URI" != "(null)" ] && echo "$UZBL_URI" >> "$UZBL_SESSION_FILE"
+ echo exit > "$UZBL_FIFO"
+ ;;
+
+ "endsession" )
+ for fifo in "$UZBL_FIFO_DIR"/uzbl_fifo_*; do
+ if [ "$fifo" != "$UZBL_FIFO" ]; then
+ echo "spawn $scriptfile endinstance" > "$fifo"
+ fi
+ done
+ [ -z "$UZBL_FIFO" ] || echo "spawn $scriptfile endinstance" > "$UZBL_FIFO"
+ ;;
+
+ * )
+ echo "session manager: bad action"
+ echo "Usage: $scriptfile [COMMAND] where commands are:"
+ echo " launch - Restore a saved session or start a new one"
+ echo " endinstance - Quit the current instance. Must be called from uzbl"
+ echo " endsession - Quit the running session."
+ ;;
esac
diff --git a/examples/data/scripts/userscript.sh b/examples/data/scripts/userscript.sh
index 33a24ae..fd95fdc 100755
--- a/examples/data/scripts/userscript.sh
+++ b/examples/data/scripts/userscript.sh
@@ -2,13 +2,11 @@
if [ $# = "3" ]
then
- fifo="$1"
- url="$2"
- SCRIPT="$3"
+ UZBL_FIFO=$1
+ UZBL_URI=$2
+ SCRIPT=$3
else
- fifo="$4"
- url="$6"
- SCRIPT="$8"
+ SCRIPT=$8
fi
# Extract metadata chunk
@@ -18,7 +16,7 @@ SHOULD_RUN=false # Assume this script will not be included
for INCLUDE in `echo "$META" | grep "^\s*\/\/\s*@include"`; do
# Munge into grep pattern
INCLUDE="`echo "$INCLUDE" | sed -e 's/^\s*\/\/\s*@include\s*//' -e 's/\./\\\\./g' -e 's/\*/.*/g' -e 's/[\r\n]//g'`"
- if echo "$url" | grep -x "$INCLUDE"; then
+ if echo "$UZBL_URI" | grep -x "$INCLUDE"; then
SHOULD_RUN=true
break
fi
@@ -28,7 +26,7 @@ done
for EXCLUDE in `echo "$META" | grep "^\s*\/\/\s*@exclude"`; do
# Munge into grep pattern
EXCLUDE="`echo "$EXCLUDE" | sed -e 's/^\s*\/\/\s*@exclude\s*//' -e 's/\./\\\\./g' -e 's/\*/.*/g' -e 's/[\r\n]//g'`"
- if echo "$url" | grep -x "$EXCLUDE"; then
+ if echo "$UZBL_URI" | grep -x "$EXCLUDE"; then
SHOULD_RUN=false
break
fi
@@ -36,5 +34,5 @@ done
# Run the script
if [ $SHOULD_RUN = true ]; then
- echo "script '$SCRIPT'" > "$fifo"
+ echo "script '$SCRIPT'" > "$UZBL_FIFO"
fi
diff --git a/examples/data/scripts/userscripts.sh b/examples/data/scripts/userscripts.sh
index 8896224..4f76c90 100755
--- a/examples/data/scripts/userscripts.sh
+++ b/examples/data/scripts/userscripts.sh
@@ -4,5 +4,5 @@ scripts_dir="$XDG_DATA_HOME/uzbl/userscripts"
for SCRIPT in $(grep -rlx "\s*//\s*==UserScript==\s*" "$scripts_dir")
do
- $XDG_DATA_HOME/uzbl/scripts/userscript.sh "$4" "$6" "$SCRIPT"
+ $XDG_DATA_HOME/uzbl/scripts/userscript.sh "$UZBL_FIFO" "$UZBL_URI" "$SCRIPT"
done
diff --git a/examples/data/scripts/util/dmenu.sh b/examples/data/scripts/util/dmenu.sh
new file mode 100644
index 0000000..da61cae
--- /dev/null
+++ b/examples/data/scripts/util/dmenu.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+# dmenu setup
+
+case "$DMENU_SCHEME" in
+ # wmii
+ "wmii" )
+ NB="#303030"
+ NF="khaki"
+ SB="#ccffaa"
+ SF="#303030"
+ ;;
+ # Formfiller
+ "formfiller" )
+ NB="#0f0f0f"
+ NF="#4e7093"
+ SB="#003d7c"
+ SF="#3a9bff"
+ ;;
+ # Bookmarks
+ "bookmarks" )
+ NB="#303030"
+ NF="khaki"
+ SB="#ccffaa"
+ SF="#303030"
+ ;;
+ # History
+ "history" )
+ NB="#303030"
+ NF="khaki"
+ SB="#ccffaa"
+ SF="#303030"
+ ;;
+ # Default
+ * )
+ NB="#303030"
+ NF="khaki"
+ SB="#ccffaa"
+ SF="#303030"
+ ;;
+esac
+
+DMENU_COLORS="-nb $NB -nf $NF -sb $SB -sf $SF"
+
+# Default arguments
+if [ -z "$DMENU_ARGS" ]; then
+ DMENU_ARGS="-i"
+fi
+
+# Set the font if wanted
+if [ -n "$DMENU_FONT" ]; then
+ DMENU_ARGS="$DMENU_ARGS -fn $DMENU_FONT"
+fi
+
+# Set the prompt if wanted
+if [ -n "$DMENU_PROMPT" ]; then
+ DMENU_ARGS="$DMENU_ARGS -p $DMENU_PROMPT"
+fi
+
+# Detect the xmms patch
+if dmenu --help 2>&1 | grep -q '\[-xs\]'; then
+ DMENU_XMMS_ARGS="-xs"
+ DMENU_HAS_XMMS=1
+
+ if echo $DMENU_OPTIONS | grep -q -w 'xmms'; then
+ DMENU_ARGS="$DMENU_ARGS $DMENU_XMMS_ARGS"
+ fi
+fi
+
+# Detect the vertical patch
+if dmenu --help 2>&1 | grep -q '\[-l <\?lines>\?\]'; then
+ # Default to 10 lines
+ if [ -z "$DMENU_LINES" ]; then
+ DMENU_LINES=10
+ fi
+
+ DMENU_VERTICAL_ARGS="-l $DMENU_LINES"
+ DMENU_HAS_VERTICAL=1
+
+ # Detect the resize patch
+ if dmenu --help 2>&1 | grep -q '\[-rs\]'; then
+ DMENU_RESIZE_ARGS="-rs"
+ DMENU_HAS_RESIZE=1
+ fi
+
+ if echo $DMENU_OPTIONS | grep -q -w 'vertical'; then
+ DMENU_ARGS="$DMENU_ARGS $DMENU_VERTICAL_ARGS"
+
+ if echo $DMENU_OPTIONS | grep -q -w 'resize'; then
+ DMENU_ARGS="$DMENU_ARGS $DMENU_RESIZE_ARGS"
+ fi
+ fi
+fi
+
+# Detect placement patch
+if dmenu --help 2>&1 | grep -q '\[-x <xoffset>\]'; then
+ DMENU_PLACE_X="-x"
+ DMENU_PLACE_Y="-y"
+ DMENU_PLACE_WIDTH="-w"
+ DMENU_PLACE_HEIGHT="-h"
+ DMENU_HAS_PLACEMENT=1
+fi
+
+DMENU="dmenu $DMENU_ARGS $DMENU_COLORS"
diff --git a/examples/data/scripts/util/editor.sh b/examples/data/scripts/util/editor.sh
new file mode 100644
index 0000000..1969769
--- /dev/null
+++ b/examples/data/scripts/util/editor.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# Editor selection
+
+if [ -z "$VTERM" ]; then
+ VTERM="xterm"
+fi
+
+UZBL_EDITOR="$VISUAL"
+if [ -z "$UZBL_EDITOR" ]; then
+ if [ -z "$EDITOR" ]; then
+ UZBL_EDITOR="$VTERM -e vim"
+ else
+ UZBL_EDITOR="$VTERM -e $EDITOR"
+ fi
+fi
diff --git a/examples/data/scripts/util/uzbl-dir.sh b/examples/data/scripts/util/uzbl-dir.sh
new file mode 100644
index 0000000..bb56954
--- /dev/null
+++ b/examples/data/scripts/util/uzbl-dir.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Common directories and files used in scripts
+
+# Common things first
+UZBL_DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl
+UZBL_CONFIG_DIR=${XDG_CONFIG_DIR:-$HOME/.config}/uzbl
+UZBL_FIFO_DIR=/tmp
+UZBL_SOCKET_DIR=/tmp
+
+# Directories
+UZBL_DOWNLOAD_DIR=${XDG_DOWNLOAD_DIR:-$HOME}
+UZBL_FORMS_DIR=$UZBL_DATA_DIR/dforms
+
+# Data files
+UZBL_CONFIG_FILE=$UZBL_CONFIG_DIR/config
+UZBL_COOKIE_FILE=$UZBL_DATA_DIR/cookies.txt
+UZBL_BOOKMARKS_FILE=$UZBL_DATA_DIR/bookmarks
+UZBL_HISTORY_FILE=$UZBL_DATA_DIR/history
+UZBL_SESSION_FILE=$UZBL_DATA_DIR/browser-session
diff --git a/examples/data/scripts/util/uzbl-window.sh b/examples/data/scripts/util/uzbl-window.sh
new file mode 100644
index 0000000..a7e92eb
--- /dev/null
+++ b/examples/data/scripts/util/uzbl-window.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# uzbl window detection
+
+UZBL_WIN_POS=$(xwininfo -id $UZBL_XID | \
+ sed -ne 's/Corners:[ ]*[+-]\([0-9]*\)[+-]\([0-9]*\).*$/\1 \2/p')
+UZBL_WIN_SIZE=$(xwininfo -id $UZBL_XID | \
+ sed -ne 's/-geometry[ ]*\([0-9]*\)x\([0-9]*\).*$/\1 \2/p')
+UZBL_WIN_POS_X=$(echo $UZBL_WIN_POS | cut -d\ -f1)
+UZBL_WIN_POS_Y=$(echo $UZBL_WIN_POS | cut -d\ -f2)
+UZBL_WIN_WIDTH=$(echo $UZBL_WIN_SIZE | cut -d\ -f1)
+UZBL_WIN_HEIGHT=$(echo $UZBL_WIN_SIZE | cut -d\ -f2)
diff --git a/examples/data/scripts/uzbl-cookie-daemon b/examples/data/scripts/uzbl-cookie-daemon
index ed88de4..0b9bef9 100755
--- a/examples/data/scripts/uzbl-cookie-daemon
+++ b/examples/data/scripts/uzbl-cookie-daemon
@@ -436,18 +436,26 @@ class CookieMonster:
daemon_timeout = config['daemon_timeout']
echo("listening on %r" % config['cookie_socket'])
+ connections = []
+
while self._running:
# This line tells the socket how many pending incoming connections
# to enqueue at once. Raising this number may or may not increase
# performance.
self.server_socket.listen(1)
- if bool(select.select([self.server_socket], [], [], 1)[0]):
- client_socket, _ = self.server_socket.accept()
- self.handle_request(client_socket)
+ r, w, x = select.select([self.server_socket]+connections, [], [], 1)
+
+ for socket in r:
+ if self.server_socket == socket:
+ client_socket, _ = socket.accept()
+ connections.append(client_socket)
+ else:
+ if not self.handle_request(socket):
+ # connection was closed, forget about the client socket
+ connections.remove(socket)
+
self.last_request = time.time()
- client_socket.close()
- continue
if daemon_timeout:
# Checks if the daemon has been idling for too long.
@@ -462,7 +470,7 @@ class CookieMonster:
# Receive cookie request from client.
data = client_socket.recv(8192)
if not data:
- return
+ return False
# Cookie argument list in packet is null separated.
argv = data.split("\0")
@@ -471,17 +479,17 @@ class CookieMonster:
# Catch the EXIT command sent to kill running daemons.
if action == "EXIT":
self._running = False
- return
+ return False
# Catch whitelist RELOAD command.
elif action == "RELOAD":
self.reload_whitelist()
- return
+ return True
# Return if command unknown.
elif action not in ['GET', 'PUT']:
error("unknown command %r." % argv)
- return
+ return True
# Determine whether or not to print cookie data to terminal.
print_cookie = (config['verbose'] and not config['daemon_mode'])
@@ -499,13 +507,14 @@ class CookieMonster:
req = urllib2.Request(uri)
if action == "GET":
- self.jar.add_cookie_header(req)
- if req.has_header('Cookie'):
- cookie = req.get_header('Cookie')
- client_socket.send(cookie)
- if print_cookie:
- print cookie
-
+ self.jar._policy._now = self._now = int(time.time())
+ cookies = self.jar._cookies_for_request(req)
+ attrs = self.jar._cookie_attrs(cookies)
+ if attrs:
+ cookie = "; ".join(attrs)
+ client_socket.send(cookie)
+ if print_cookie:
+ print cookie
else:
client_socket.send("\0")
@@ -515,10 +524,13 @@ class CookieMonster:
print cookie
self.put_cookie(req, cookie)
+ client_socket.send("\0")
if print_cookie:
print
+ return True
+
def put_cookie(self, req, cookie=None):
'''Put a cookie in the cookie jar.'''
diff --git a/examples/data/scripts/uzbl-event-manager b/examples/data/scripts/uzbl-event-manager
index ab13fbb..8ad3af7 100755
--- a/examples/data/scripts/uzbl-event-manager
+++ b/examples/data/scripts/uzbl-event-manager
@@ -825,7 +825,7 @@ if __name__ == "__main__":
add('-n', '--no-daemon',
dest='daemon_mode', action='store_false', default=True,
- help='daemonize the process')
+ help='do not daemonize the process')
add('-a', '--auto-close',
dest='auto_close', action='store_true', default=False,
diff --git a/examples/data/scripts/uzbl-tabbed b/examples/data/scripts/uzbl-tabbed
index 42837d3..0086c04 100755
--- a/examples/data/scripts/uzbl-tabbed
+++ b/examples/data/scripts/uzbl-tabbed
@@ -158,7 +158,7 @@ import atexit
import types
from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP
-from signal import signal, SIGTERM, SIGINT, SIGCHLD
+from signal import signal, SIGTERM, SIGINT
from optparse import OptionParser, OptionGroup
from traceback import print_exc
@@ -471,8 +471,9 @@ class UzblInstance:
elif var == "gtk_tab_pos":
self.parent.update_gtk_tab_pos()
elif var == "status_background":
- col = gtk.gdk.color_parse(config['status_background'])
- self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col)
+ if config['status_background'].strip():
+ col = gtk.gdk.color_parse(config['status_background'])
+ self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col)
elif var == "tab_titles" or var == "tab_indexes":
for tab in self.parent.notebook:
self.parent.tabs[tab].title_changed(True)
@@ -536,7 +537,6 @@ class UzblTabbed:
self._timers = {}
self._buffer = ""
self._killed = False
- self._processes = []
# A list of the recently closed tabs
self._closed = []
@@ -656,9 +656,6 @@ class UzblTabbed:
# Catch keyboard interrupts
signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT))
- # Catch SIGCHLD
- signal(SIGCHLD, lambda signum, stack_frame: self.join_children())
-
try:
gtk.main()
@@ -678,15 +675,6 @@ class UzblTabbed:
raise
-
- def join_children(self):
- '''Find and remove zombie children processes.'''
-
- for p in self._processes:
- if p.poll() is not None:
- self._processes.remove(p)
-
-
def terminate(self, termsig=None):
'''Handle termination signals and exit safely and cleanly.'''
@@ -1017,7 +1005,7 @@ class UzblTabbed:
cmd = ['uzbl-browser', '-n', name, '-s', str(sid),
'--connect-socket', self.socket_path, '--uri', uri]
- self._processes += [subprocess.Popen(cmd)] # TODO: do i need close_fds=True ?
+ gobject.spawn_async(cmd, flags=gobject.SPAWN_SEARCH_PATH)
uzbl = UzblInstance(self, tab, name, uri, title, switch)
SocketClient.instances_queue[name] = uzbl
diff --git a/examples/uzbl-cookie-manager.c b/examples/uzbl-cookie-manager.c
new file mode 100644
index 0000000..70addf3
--- /dev/null
+++ b/examples/uzbl-cookie-manager.c
@@ -0,0 +1,381 @@
+#define _POSIX_SOURCE
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/unistd.h>
+
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <libsoup/soup-cookie.h>
+#include <libsoup/soup-cookie-jar-text.h>
+#include <libsoup/soup-uri.h>
+
+#include "../src/util.h"
+
+extern const XDG_Var XDG[];
+
+int verbose = 0;
+
+#define SOCK_BACKLOG 10
+#define MAX_COOKIE_LENGTH 4096
+
+char cookie_buffer[MAX_COOKIE_LENGTH];
+
+int setup_socket(const char *cookied_socket_path) {
+ /* delete the cookie socket if it was left behind on a previous run */
+ unlink(cookied_socket_path);
+
+ int socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+
+ if(socket_fd < 0) {
+ fprintf(stderr, "socket failed (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr_un sa;
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, cookied_socket_path);
+
+ if(bind(socket_fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
+ fprintf(stderr, "bind failed (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ if(listen(socket_fd, SOCK_BACKLOG) < 0) {
+ fprintf(stderr, "listen failed (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ return socket_fd;
+}
+
+const char *whitelist_path = NULL;
+GPtrArray *whitelisted_hosts = NULL;
+time_t whitelist_update_time = 0;
+
+void whitelist_line_cb(const gchar* line, void *user_data) {
+ (void) user_data;
+
+ gchar *norm_host;
+
+ const gchar *p = line;
+ while(isspace(*p))
+ p++;
+
+ if(p[0] == '#' || !p[0]) /* ignore comments and blank lines */
+ return;
+
+ if(p[0] == '.')
+ norm_host = g_strdup(p);
+ else
+ norm_host = g_strconcat(".", p, NULL);
+
+ g_ptr_array_add(whitelisted_hosts, g_strchomp(norm_host));
+}
+
+gboolean load_whitelist(const char *whitelist_path) {
+ if(!file_exists(whitelist_path))
+ return FALSE;
+
+ /* check if the whitelist file was updated */
+ struct stat f;
+ if(stat(whitelist_path, &f) < 0)
+ return FALSE;
+
+ if(whitelisted_hosts == NULL)
+ whitelisted_hosts = g_ptr_array_new();
+
+ if(f.st_mtime > whitelist_update_time) {
+ /* the file was updated, reload the whitelist */
+ if(verbose) puts("reloading whitelist");
+ while(whitelisted_hosts->len > 0) {
+ g_free(g_ptr_array_index(whitelisted_hosts, 0));
+ g_ptr_array_remove_index_fast(whitelisted_hosts, 0);
+ }
+ for_each_line_in_file(whitelist_path, whitelist_line_cb, NULL);
+ whitelist_update_time = f.st_mtime;
+ }
+
+ return TRUE;
+}
+
+gboolean should_save_cookie(const char *host) {
+ if(!load_whitelist(whitelist_path))
+ return TRUE; /* some error with the file, assume no whitelist */
+
+ /* we normalize the hostname so it has a . in front like the whitelist entries */
+ gchar *test_host = (host[0] == '.') ? g_strdup(host) : g_strconcat(".", host, NULL);
+ int hl = strlen(test_host);
+
+ /* test against each entry in the whitelist */
+ gboolean result = FALSE;
+ guint i;
+ for(i = 0; i < whitelisted_hosts->len; i++) {
+ /* a match means the host ends with (or is equal to) the whitelist entry */
+ const gchar *entry = g_ptr_array_index(whitelisted_hosts, i);
+ int el = strlen(entry);
+ result = (el <= hl) && !strcmp(test_host + (hl - el), entry);
+
+ if(result)
+ break;
+ }
+
+ g_free(test_host);
+
+ return result;
+}
+
+void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) {
+ const char *command = buff;
+
+ const char *scheme = command + strlen(command) + 1;
+ if((scheme - buff) > len) {
+ fprintf(stderr, "got malformed or partial request\n");
+ return;
+ }
+
+ const char *host = scheme + strlen(scheme) + 1;
+ if((host - buff) > len) {
+ fprintf(stderr, "got malformed or partial request\n");
+ return;
+ }
+
+ const char *path = host + strlen(host) + 1;
+ if((path - buff) > len) {
+ fprintf(stderr, "got malformed or partial request\n");
+ return;
+ }
+
+ /* glue the parts back together into a SoupURI */
+ char *u = g_strconcat(scheme, "://", host, path, NULL);
+ if(verbose) printf("%s %s\n", command, u);
+ SoupURI *uri = soup_uri_new(u);
+ g_free(u);
+
+ if(!strcmp(command, "GET")) {
+ char *result = soup_cookie_jar_get_cookies(j, uri, TRUE);
+ if(result) {
+ if(verbose) puts(result);
+ if(write(fd, result, strlen(result)+1) < 0)
+ fprintf(stderr, "write failed (%s)", strerror(errno));
+
+ g_free(result);
+ } else {
+ if(verbose) puts("-");
+ if(write(fd, "", 1) < 0)
+ fprintf(stderr, "write failed (%s)", strerror(errno));
+ }
+ } else if(!strcmp(command, "PUT")) {
+ const char *name_and_val = path + strlen(path) + 1;
+ if((name_and_val - buff) > len) {
+ fprintf(stderr, "got malformed or partial request\n");
+ return;
+ }
+
+ if(verbose) puts(name_and_val);
+
+ if(should_save_cookie(host)) {
+ char *eql = strchr(name_and_val, '=');
+ eql[0] = 0;
+
+ const char *name = name_and_val;
+ const char *value = eql + 1;
+
+ SoupCookie *cookie = soup_cookie_new(name, value, host, path, SOUP_COOKIE_MAX_AGE_ONE_YEAR);
+
+ soup_cookie_jar_add_cookie(j, cookie);
+ } else if(verbose)
+ puts("no, blacklisted.");
+
+ if(write(fd, "", 1) < 0)
+ fprintf(stderr, "write failed (%s)", strerror(errno));
+ }
+
+ soup_uri_free(uri);
+}
+
+void
+wait_for_things_to_happen_and_then_do_things(SoupCookieJar* j, int cookie_socket) {
+ GArray *connections = g_array_new (FALSE, FALSE, sizeof (int));
+
+ while(1) {
+ unsigned int i;
+ int r;
+ fd_set fs;
+
+ int maxfd = cookie_socket;
+ FD_ZERO(&fs);
+ FD_SET(maxfd, &fs);
+
+ for(i = 0; i < connections->len; i++) {
+ int fd = g_array_index(connections, int, i);
+ if(fd > maxfd) maxfd = fd;
+ FD_SET(fd, &fs);
+ }
+
+ r = select(maxfd+1, &fs, NULL, NULL, NULL);
+ if(r < 0) {
+ fprintf(stderr, "select failed (%s)\n", strerror(errno));
+ continue;
+ }
+
+ if(FD_ISSET(cookie_socket, &fs)) {
+ /* handle new connection */
+ int fd = accept(cookie_socket, NULL, NULL);
+ g_array_append_val(connections, fd);
+ if(verbose) puts("got connection.");
+ }
+
+ for(i = 0; i < connections->len; i++) {
+ /* handle activity on a connection */
+ int fd = g_array_index(connections, int, i);
+ if(FD_ISSET(fd, &fs)) {
+ r = read(fd, cookie_buffer, MAX_COOKIE_LENGTH);
+ if(r < 0) {
+ fprintf(stderr, "read failed (%s)\n", strerror(errno));
+ continue;
+ } else if(r == 0) {
+ if(verbose) puts("client hung up.");
+ g_array_remove_index(connections, i);
+ i--; /* other elements in the array are moved down to fill the gap */
+ continue;
+ }
+ cookie_buffer[r] = 0;
+
+ handle_request(j, cookie_buffer, r, fd);
+ }
+ }
+ }
+}
+
+void usage(const char *progname) {
+ printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-n] [-v]\n", progname);
+ puts("\t-n\tdon't daemonise the process");
+ puts("\t-v\tbe verbose");
+}
+
+void daemonise() {
+ int r = fork();
+
+ if(r < 0) {
+ fprintf(stderr, "fork failed (%s)", strerror(errno));
+ exit(1);
+ } else if (r > 0) {
+ /* this is the parent, which has done its job */
+ exit(0);
+ }
+
+ if(setsid() < 0) {
+ fprintf(stderr, "setsid failed (%s)", strerror(errno));
+ exit(1);
+ }
+}
+
+const char *pid_file_path = NULL;
+const char *cookied_socket_path = NULL;
+
+void cleanup_after_signal(int signal) {
+ (void) signal;
+ unlink(pid_file_path);
+ unlink(cookied_socket_path);
+ exit(0);
+}
+
+int main(int argc, char *argv[]) {
+ int i;
+
+ const char *cookies_txt_path = NULL;
+ gboolean foreground = FALSE;
+
+ for(i = 1; i < argc && argv[i][0] == '-'; i++) {
+ switch(argv[i][1]) {
+ case 's':
+ cookied_socket_path = argv[++i];
+ break;
+ case 'f':
+ cookies_txt_path = argv[++i];
+ break;
+ case 'w':
+ whitelist_path = argv[++i];
+ break;
+ case 'n':
+ foreground = TRUE;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if(!foreground)
+ daemonise();
+
+ if(!cookies_txt_path)
+ cookies_txt_path = g_strconcat(get_xdg_var(XDG[1]), "/uzbl/cookies.txt", NULL);
+
+ if(!cookied_socket_path)
+ cookied_socket_path = g_strconcat(get_xdg_var(XDG[2]), "/uzbl/cookie_daemon_socket", NULL);
+
+ if(!whitelist_path)
+ whitelist_path = g_strconcat(get_xdg_var(XDG[0]), "/uzbl/cookie_whitelist", NULL);
+
+ /* write out and lock the pid file.
+ * this ensures that only one uzbl-cookie-manager is running per-socket.
+ * (we should probably also lock the cookies.txt to prevent accidents...) */
+ pid_file_path = g_strconcat(cookied_socket_path, ".pid", NULL);
+ int lockfd = open(pid_file_path, O_RDWR|O_CREAT, 0600);
+ if(lockfd < 0) {
+ fprintf(stderr, "couldn't open pid file %s (%s)\n", pid_file_path, strerror(errno));
+ return 1;
+ }
+
+ if(flock(lockfd, LOCK_EX|LOCK_NB) < 0) {
+ fprintf(stderr, "couldn't lock pid file %s (%s)\n", pid_file_path, strerror(errno));
+ fprintf(stderr, "uzbl-cookie-manager is probably already running\n");
+ return 1;
+ }
+
+ gchar* pids = g_strdup_printf("%d\n", getpid());
+ write(lockfd, pids, strlen(pids));
+ g_free(pids);
+
+ struct sigaction sa;
+ sa.sa_handler = cleanup_after_signal;
+ if(sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)) {
+ fprintf(stderr, "sigaction failed (%s)\n", strerror(errno));
+ return 1;
+ }
+
+ if(!foreground) {
+ /* close STDIO */
+ close(0);
+ close(1);
+ close(2);
+ }
+
+ g_type_init();
+
+ SoupCookieJar *j = soup_cookie_jar_text_new(cookies_txt_path, FALSE);
+
+ int cookie_socket = setup_socket(cookied_socket_path);
+ if(cookie_socket < 0)
+ return 1;
+
+ wait_for_things_to_happen_and_then_do_things(j, cookie_socket);
+
+ return 0;
+}
diff --git a/src/callbacks.c b/src/callbacks.c
index 07c395c..4f0e4ac 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -6,7 +6,7 @@
#include "uzbl-core.h"
#include "callbacks.h"
#include "events.h"
-
+#include "util.h"
void
set_proxy_url() {
@@ -46,6 +46,19 @@ set_authentication_handler() {
}
void
+set_status_background() {
+ GdkColor color;
+ gdk_color_parse (uzbl.behave.status_background, &color);
+ /* labels and hboxes do not draw their own background. applying this
+ * on the vbox/main_window is ok as the statusbar is the only affected
+ * widget. (if not, we could also use GtkEventBox) */
+ if (uzbl.gui.main_window)
+ gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
+ else if (uzbl.gui.plug)
+ gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
+}
+
+void
set_icon() {
if(file_exists(uzbl.gui.icon)) {
if (uzbl.gui.main_window)
@@ -182,6 +195,12 @@ cmd_zoom_level() {
}
void
+cmd_enable_pagecache() {
+ g_object_set (G_OBJECT(view_settings()), "enable-page-cache",
+ uzbl.behave.enable_pagecache, NULL);
+}
+
+void
cmd_disable_plugins() {
g_object_set (G_OBJECT(view_settings()), "enable-plugins",
!uzbl.behave.disable_plugins, NULL);
@@ -392,20 +411,48 @@ title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
update_title();
send_event(TITLE_CHANGED, uzbl.gui.main_title, NULL);
+ g_setenv("UZBL_TITLE", uzbl.gui.main_title, TRUE);
}
void
-progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
- (void) page;
- (void) data;
- gchar *prg_str;
-
- prg_str = itos(progress);
+progress_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
+ (void) param_spec;
+ int progress = webkit_web_view_get_progress(web_view) * 100;
+ gchar *prg_str = itos(progress);
send_event(LOAD_PROGRESS, prg_str, NULL);
g_free(prg_str);
}
void
+load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
+ (void) param_spec;
+
+ WebKitWebFrame *frame = webkit_web_view_get_main_frame(web_view);
+ WebKitLoadStatus status = webkit_web_view_get_load_status(web_view);
+ switch(status) {
+ case WEBKIT_LOAD_PROVISIONAL:
+ send_event(LOAD_START, uzbl.state.uri, NULL);
+ break;
+ case WEBKIT_LOAD_COMMITTED:
+ g_free (uzbl.state.uri);
+ GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
+ uzbl.state.uri = g_string_free (newuri, FALSE);
+ g_setenv("UZBL_URI", uzbl.state.uri, TRUE);
+
+ send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame), NULL);
+ break;
+ case WEBKIT_LOAD_FINISHED:
+ send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame), NULL);
+ break;
+ case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
+ break; /* we don't do anything with this (yet) */
+ case WEBKIT_LOAD_FAILED:
+ break; /* load_error_cb will handle this case */
+ }
+
+}
+
+void
selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) {
(void)ud;
gchar *tmp;
@@ -417,23 +464,6 @@ selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) {
}
void
-load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
- (void) page;
- (void) data;
-
- send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame), NULL);
-}
-
-void
-load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
- (void) page;
- (void) frame;
- (void) data;
-
- send_event(LOAD_START, uzbl.state.uri, NULL);
-}
-
-void
load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud) {
(void) page;
(void) frame;
@@ -447,17 +477,6 @@ load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer
}
void
-load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
- (void) page;
- (void) data;
- g_free (uzbl.state.uri);
- GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
- uzbl.state.uri = g_string_free (newuri, FALSE);
-
- send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame), NULL);
-}
-
-void
destroy_cb (GtkWidget* widget, gpointer data) {
(void) widget;
(void) data;
@@ -589,9 +608,9 @@ motion_notify_cb(GtkWidget* window, GdkEventMotion* event, gpointer user_data) {
(void) event;
(void) user_data;
- gchar *details;
- details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state);
+ gchar *details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state);
send_event(PTR_MOVE, details, NULL);
+ g_free(details);
return FALSE;
}
@@ -703,11 +722,10 @@ create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) {
if (strncmp(uri, "javascript:", strlen("javascript:")) == 0) {
eval_js(uzbl.gui.web_view, (gchar*) uri + strlen("javascript:"), NULL, "javascript:");
+ gtk_widget_destroy(GTK_WIDGET(web_view));
}
else
send_event(NEW_WINDOW, uri, NULL);
-
- gtk_widget_destroy(GTK_WIDGET(web_view));
}
@@ -717,7 +735,7 @@ create_web_view_js_cb (WebKitWebView* web_view, gpointer user_data) {
(void) user_data;
g_object_connect (web_view, "signal::notify::uri",
- G_CALLBACK(create_web_view_js2_cb), NULL);
+ G_CALLBACK(create_web_view_js2_cb), NULL, NULL);
return TRUE;
}
@@ -869,38 +887,11 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
}
void
-save_cookies_js(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie, gpointer user_data) {
- (void) jar;
- (void) user_data;
- (void) old_cookie;
- char *scheme;
- GString *s;
-
- if(new_cookie != NULL) {
- scheme = (new_cookie->secure == TRUE) ? "https" : "http";
-
- s = g_string_new("");
- g_string_printf(s, "PUT '%s' '%s' '%s' '%s=%s'", scheme, new_cookie->domain, new_cookie->path, new_cookie->name, new_cookie->value);
- run_handler(uzbl.behave.cookie_handler, s->str);
- g_string_free(s, TRUE);
- }
-}
-
-void
-save_cookies_http(SoupMessage *msg, gpointer user_data) {
- (void) user_data;
- GSList *ck;
- char *cookie;
-
- for(ck = soup_cookies_from_response(msg); ck; ck = ck->next){
- cookie = soup_cookie_to_set_cookie_header(ck->data);
- SoupURI *soup_uri = soup_message_get_uri(msg);
- GString *s = g_string_new("");
- g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
- run_handler(uzbl.behave.cookie_handler, s->str);
- g_free (cookie);
- g_string_free(s, TRUE);
- }
+cmd_set_cookie_handler() {
+ if(uzbl.behave.cookie_handler[0] == 0) {
+ g_free(uzbl.behave.cookie_handler);
+ uzbl.behave.cookie_handler = NULL;
+ }
- g_slist_free(ck);
+ uzbl_cookie_jar_set_handler(uzbl.net.soup_cookie_jar, uzbl.behave.cookie_handler);
}
diff --git a/src/callbacks.h b/src/callbacks.h
index 553e388..a4258f2 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -16,6 +16,9 @@ void
set_authentication_handler();
void
+set_status_background();
+
+void
set_icon();
void
@@ -59,6 +62,9 @@ void
cmd_set_zoom_type();
void
+cmd_enable_pagecache();
+
+void
cmd_disable_plugins();
void
@@ -143,16 +149,10 @@ void
title_change_cb (WebKitWebView* web_view, GParamSpec param_spec);
void
-progress_change_cb (WebKitWebView* page, gint progress, gpointer data);
-
-void
-load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data);
-
-void
-load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data);
+progress_change_cb (WebKitWebView* web_view, GParamSpec param_spec);
void
-load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data);
+load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec);
void
load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud);
@@ -218,7 +218,4 @@ gboolean
scroll_horiz_cb(GtkAdjustment *adjust, void *w);
void
-save_cookies_js(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie, gpointer user_data);
-
-void
-save_cookies_http(SoupMessage *msg, gpointer user_data);
+cmd_set_cookie_handler();
diff --git a/src/cookie-jar.c b/src/cookie-jar.c
new file mode 100644
index 0000000..f2e340b
--- /dev/null
+++ b/src/cookie-jar.c
@@ -0,0 +1,306 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <errno.h>
+
+#include <libsoup/soup-uri.h>
+#include <libsoup/soup-cookie.h>
+
+#include "cookie-jar.h"
+#include "uzbl-core.h"
+
+static void
+uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data);
+
+G_DEFINE_TYPE_WITH_CODE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR,
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, uzbl_cookie_jar_session_feature_init))
+
+static void request_started (SoupSessionFeature *feature, SoupSession *session, SoupMessage *msg, SoupSocket *socket);
+static void changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie);
+
+static void setup_handler(UzblCookieJar *jar);
+
+static void connect_cookie_socket(UzblCookieJar *jar);
+static void disconnect_cookie_socket(UzblCookieJar *jar);
+
+static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_len);
+
+static bool has_socket_handler(UzblCookieJar *jar) {
+ return jar->socket_path != NULL;
+}
+
+static void
+soup_cookie_jar_socket_init(UzblCookieJar *jar) {
+ jar->handler = NULL;
+ jar->socket_path = NULL;
+ jar->connection_fd = -1;
+}
+
+static void
+finalize(GObject *object) {
+ disconnect_cookie_socket(UZBL_COOKIE_JAR(object));
+ G_OBJECT_CLASS(soup_cookie_jar_socket_parent_class)->finalize(object);
+}
+
+static void
+soup_cookie_jar_socket_class_init(UzblCookieJarClass *socket_class) {
+ G_OBJECT_CLASS(socket_class)->finalize = finalize;
+ SOUP_COOKIE_JAR_CLASS(socket_class)->changed = changed;
+}
+
+/* override SoupCookieJar's request_started handler */
+static void
+uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data) {
+ (void) user_data;
+ iface->request_started = request_started;
+}
+
+UzblCookieJar *uzbl_cookie_jar_new() {
+ return g_object_new(UZBL_TYPE_COOKIE_JAR, NULL);
+}
+
+void
+uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar* handler) {
+ jar->handler = handler;
+ setup_handler(jar);
+}
+
+char *get_cookies(UzblCookieJar *jar, SoupURI *uri) {
+ gchar *result, *path;
+ GString *s = g_string_new ("GET");
+
+ path = uri->path[0] ? uri->path : "/";
+
+ if(has_socket_handler(jar)) {
+ g_string_append_c(s, 0); /* null-terminate the GET */
+ g_string_append_len(s, uri->scheme, strlen(uri->scheme)+1);
+ g_string_append_len(s, uri->host, strlen(uri->host)+1 );
+ g_string_append_len(s, path, strlen(path)+1 );
+
+ result = do_socket_request(jar, s->str, s->len);
+ /* try it again; older cookie daemons closed the connection after each request */
+ if(result == NULL)
+ result = do_socket_request(jar, s->str, s->len);
+ } else {
+ g_string_append_printf(s, " '%s' '%s' '%s'", uri->scheme, uri->host, uri->path);
+
+ run_handler(jar->handler, s->str);
+ result = g_strdup(uzbl.comm.sync_stdout);
+ }
+ g_string_free(s, TRUE);
+ return result;
+}
+
+/* this is a duplicate of SoupCookieJar's request_started that uses our get_cookies instead */
+static void
+request_started(SoupSessionFeature *feature, SoupSession *session,
+ SoupMessage *msg, SoupSocket *socket) {
+ (void) session; (void) socket;
+ gchar *cookies;
+
+ UzblCookieJar *jar = UZBL_COOKIE_JAR (feature);
+ SoupURI *uri = soup_message_get_uri(msg);
+ gboolean add_to_internal_jar = false;
+
+ if(jar->handler) {
+ cookies = get_cookies(jar, uri);
+ } else {
+ /* no handler is set, fall back to the internal soup cookie jar */
+ cookies = soup_cookie_jar_get_cookies(SOUP_COOKIE_JAR(jar), soup_message_get_uri (msg), TRUE);
+ }
+
+ if (cookies && cookies[0] != 0) {
+ const gchar *next_cookie_start = cookies;
+
+ if (add_to_internal_jar) {
+ /* add the cookie data that we just obtained from the cookie handler
+ to the cookie jar so that javascript has access to them.
+ we set this flag so that we don't trigger the PUT handler. */
+ jar->in_get_callback = true;
+ do {
+ SoupCookie *soup_cookie = soup_cookie_parse(next_cookie_start, uri);
+ if(soup_cookie)
+ soup_cookie_jar_add_cookie(SOUP_COOKIE_JAR(uzbl.net.soup_cookie_jar), soup_cookie);
+ next_cookie_start = strchr(next_cookie_start, ';');
+ } while(next_cookie_start++ != NULL);
+ jar->in_get_callback = false;
+ }
+
+ soup_message_headers_replace (msg->request_headers, "Cookie", cookies);
+ } else {
+ soup_message_headers_remove (msg->request_headers, "Cookie");
+ }
+
+ if(cookies)
+ g_free (cookies);
+}
+
+static void
+changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
+ (void) old_cookie;
+
+ UzblCookieJar *uzbl_jar = UZBL_COOKIE_JAR(jar);
+
+ /* when Uzbl begins an HTTP request, it GETs cookies from the handler
+ and then adds them to the cookie jar so that javascript can access
+ these cookies. this causes a 'changed' callback, which we don't want
+ to do anything, so we just return.
+
+ (if SoupCookieJar let us override soup_cookie_jar_get_cookies we
+ wouldn't have to do this.) */
+ if(uzbl_jar->in_get_callback)
+ return;
+
+ /* the cookie daemon is only interested in new cookies and changed
+ ones, it can take care of deleting expired cookies on its own. */
+ if(!new_cookie)
+ return;
+
+ GString *s = g_string_new ("PUT");
+
+ gchar *scheme = new_cookie->secure ? "https" : "http";
+
+ if(has_socket_handler(uzbl_jar)) {
+ g_string_append_c(s, 0); /* null-terminate the PUT */
+ g_string_append_len(s, scheme, strlen(scheme)+1);
+ g_string_append_len(s, new_cookie->domain, strlen(new_cookie->domain)+1 );
+ g_string_append_len(s, new_cookie->path, strlen(new_cookie->path)+1 );
+ g_string_append_printf(s, "%s=%s", new_cookie->name, new_cookie->value);
+
+ gchar *result = do_socket_request(uzbl_jar, s->str, s->len+1);
+ /* try it again; older cookie daemons closed the connection after each request */
+ if(!result)
+ result = do_socket_request(uzbl_jar, s->str, s->len+1);
+
+ g_free(result);
+ } else {
+ g_string_append_printf(s, " '%s' '%s' '%s' '%s=%s'", scheme, new_cookie->domain, new_cookie->path, new_cookie->name, new_cookie->value);
+
+ run_handler(uzbl_jar->handler, s->str);
+ }
+
+ g_string_free(s, TRUE);
+}
+
+static void
+setup_handler(UzblCookieJar *jar) {
+ if(jar->handler && strncmp(jar->handler, "talk_to_socket", strlen("talk_to_socket")) == 0) {
+ /* extract the socket path from the handler. */
+ jar->socket_path = jar->handler + strlen("talk_to_socket");
+ while(isspace(*jar->socket_path))
+ jar->socket_path++;
+ if(*jar->socket_path == 0)
+ return; /* there was no path specified. */
+ disconnect_cookie_socket(jar);
+ connect_cookie_socket(jar);
+ } else {
+ jar->socket_path = NULL;
+ }
+}
+
+static void
+connect_cookie_socket(UzblCookieJar *jar) {
+ struct sockaddr_un sa;
+ int fd;
+
+ g_strlcpy(sa.sun_path, jar->socket_path, sizeof(sa.sun_path));
+ sa.sun_family = AF_UNIX;
+
+ /* create socket file descriptor and connect it to path */
+ fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if(fd == -1) {
+ g_printerr("connect_cookie_socket: creating socket failed (%s)\n", strerror(errno));
+ return;
+ }
+
+ if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
+ g_printerr("connect_cookie_socket: connect failed (%s)\n", strerror(errno));
+ close(fd);
+ return;
+ }
+
+ /* successful connection! */
+ jar->connection_fd = fd;
+}
+
+static void
+disconnect_cookie_socket(UzblCookieJar *jar) {
+ if(jar->connection_fd > 0) {
+ close(jar->connection_fd);
+ jar->connection_fd = -1;
+ }
+}
+
+static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_length) {
+ int len;
+ ssize_t ret;
+ struct pollfd pfd;
+ gchar *result = NULL;
+
+ if(jar->connection_fd < 0)
+ connect_cookie_socket(jar); /* connection was lost, reconnect */
+
+ /* write request */
+ ret = write(jar->connection_fd, request, request_length);
+ if(ret == -1) {
+ g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
+ disconnect_cookie_socket(jar);
+ return NULL;
+ }
+
+ /* wait for a response, with a 500ms timeout */
+ pfd.fd = jar->connection_fd;
+ pfd.events = POLLIN;
+ while(1) {
+ ret = poll(&pfd, 1, 500);
+ if(ret == 1) break;
+ if(ret == 0) errno = ETIMEDOUT;
+ if(errno == EINTR) continue;
+ g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
+ strerror(errno));
+ if(errno != ETIMEDOUT)
+ disconnect_cookie_socket(jar);
+ return NULL;
+ }
+
+ /* get length of response */
+ if(ioctl(jar->connection_fd, FIONREAD, &len) == -1) {
+ g_printerr("talk_to_socket: cannot find daemon response length, "
+ "ioctl failed (%s)\n", strerror(errno));
+ disconnect_cookie_socket(jar);
+ return NULL;
+ }
+
+ /* there was an empty response. */
+ if(len == 0)
+ return g_strdup("");
+
+ /* there is a response, read it */
+ result = g_malloc(len + 1);
+ if(!result) {
+ g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
+ return NULL;
+ }
+ result[len] = 0; /* ensure result is null terminated */
+
+ gchar *p = result;
+ while(len > 0) {
+ ret = read(jar->connection_fd, p, len);
+ if(ret == -1) {
+ g_printerr("talk_to_socket: failed to read from socket (%s)\n",
+ strerror(errno));
+ disconnect_cookie_socket(jar);
+ g_free(result);
+ return NULL;
+ } else {
+ len -= ret;
+ p += ret;
+ }
+ }
+
+ return result;
+}
diff --git a/src/cookie-jar.h b/src/cookie-jar.h
new file mode 100644
index 0000000..80af00e
--- /dev/null
+++ b/src/cookie-jar.h
@@ -0,0 +1,33 @@
+#ifndef UZBL_COOKIE_JAR_H
+#define UZBL_COOKIE_JAR_H
+
+#include <libsoup/soup-cookie-jar.h>
+
+#define UZBL_TYPE_COOKIE_JAR (soup_cookie_jar_socket_get_type ())
+#define UZBL_COOKIE_JAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UZBL_TYPE_COOKIE_JAR, UzblCookieJar))
+#define UZBL_COOKIE_JAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UZBL_TYPE_COOKIE_JAR, UzblCookieJarClass))
+
+typedef struct {
+ SoupCookieJar parent;
+
+ const gchar *handler;
+
+ const gchar *socket_path;
+ int connection_fd;
+
+ gboolean in_get_callback;
+} UzblCookieJar;
+
+typedef struct {
+ SoupCookieJarClass parent_class;
+} UzblCookieJarClass;
+
+UzblCookieJar *uzbl_cookie_jar_new();
+
+void
+uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar *handler);
+
+char
+*get_cookies(UzblCookieJar *jar, SoupURI *uri);
+
+#endif
diff --git a/src/events.c b/src/events.c
index 55e7f75..fde731a 100644
--- a/src/events.c
+++ b/src/events.c
@@ -59,56 +59,53 @@ event_buffer_timeout(guint sec) {
setitimer(ITIMER_REAL, &t, NULL);
}
-
-void
-send_event_socket(GString *msg) {
+static void
+send_event_sockets(GPtrArray *sockets, GString *msg) {
GError *error = NULL;
- GString *tmp;
- GIOChannel *gio = NULL;
GIOStatus ret;
gsize len;
- guint i=0, j=0;
+ guint i=0;
+
+ while(i < sockets->len) {
+ GIOChannel *gio = g_ptr_array_index(sockets, i++);
+
+ if(gio && gio->is_writeable && msg) {
+ ret = g_io_channel_write_chars (gio,
+ msg->str, msg->len,
+ &len, &error);
+
+ if (ret == G_IO_STATUS_ERROR)
+ g_warning ("Error sending event to socket: %s", error->message);
+ else
+ g_io_channel_flush(gio, &error);
+ }
+ }
+}
+
+static void
+replay_buffered_events() {
+ guint i = 0;
+
+ event_buffer_timeout(0);
+ /* replay buffered events */
+ while(i < uzbl.state.event_buffer->len) {
+ GString *tmp = g_ptr_array_index(uzbl.state.event_buffer, i++);
+ send_event_sockets(uzbl.comm.connect_chan, tmp);
+ g_string_free(tmp, TRUE);
+ }
+
+ g_ptr_array_free(uzbl.state.event_buffer, TRUE);
+ uzbl.state.event_buffer = NULL;
+}
+
+void
+send_event_socket(GString *msg) {
/* write to all --connect-socket sockets */
if(uzbl.comm.connect_chan) {
- while(i < uzbl.comm.connect_chan->len) {
- gio = g_ptr_array_index(uzbl.comm.connect_chan, i++);
- j=0;
-
- if(gio && gio->is_writeable) {
- if(uzbl.state.event_buffer) {
- event_buffer_timeout(0);
-
- /* replay buffered events */
- while(j < uzbl.state.event_buffer->len) {
- tmp = g_ptr_array_index(uzbl.state.event_buffer, j++);
- ret = g_io_channel_write_chars (gio,
- tmp->str, tmp->len,
- &len, &error);
-
- if (ret == G_IO_STATUS_ERROR)
- g_warning ("Error sending event to socket: %s", error->message);
- else
- g_io_channel_flush(gio, &error);
- }
- }
-
- if(msg) {
- ret = g_io_channel_write_chars (gio,
- msg->str, msg->len,
- &len, &error);
-
- if (ret == G_IO_STATUS_ERROR)
- g_warning ("Error sending event to socket: %s", error->message);
- else
- g_io_channel_flush(gio, &error);
- }
- }
- }
- if(uzbl.state.event_buffer) {
- g_ptr_array_free(uzbl.state.event_buffer, TRUE);
- uzbl.state.event_buffer = NULL;
- }
+ send_event_sockets(uzbl.comm.connect_chan, msg);
+ if(uzbl.state.event_buffer)
+ replay_buffered_events();
}
/* buffer events until a socket is set and connected
* or a timeout is encountered
@@ -120,22 +117,8 @@ send_event_socket(GString *msg) {
}
/* write to all client sockets */
- i=0;
if(msg && uzbl.comm.client_chan) {
- while(i < uzbl.comm.client_chan->len) {
- gio = g_ptr_array_index(uzbl.comm.client_chan, i++);
-
- if(gio && gio->is_writeable && msg) {
- ret = g_io_channel_write_chars (gio,
- msg->str, msg->len,
- &len, &error);
-
- if (ret == G_IO_STATUS_ERROR)
- g_warning ("Error sending event to socket: %s", error->message);
- else
- g_io_channel_flush(gio, &error);
- }
- }
+ send_event_sockets(uzbl.comm.client_chan, msg);
}
}
@@ -152,24 +135,16 @@ send_event_stdout(GString *msg) {
void
send_event(int type, const gchar *details, const gchar *custom_event) {
GString *event_message = g_string_new("");
- gchar *buf, *p_val = NULL;
-
- /* expand shell vars */
- if(details) {
- buf = g_strdup(details);
- p_val = parseenv(buf ? g_strchug(buf) : " ");
- g_free(buf);
- }
/* check for custom events */
if(custom_event) {
g_string_printf(event_message, "EVENT [%s] %s %s\n",
- uzbl.state.instance_name, custom_event, p_val);
+ uzbl.state.instance_name, custom_event, details);
}
/* check wether we support the internal event */
else if(type < LAST_EVENT) {
g_string_printf(event_message, "EVENT [%s] %s %s\n",
- uzbl.state.instance_name, event_table[type], p_val);
+ uzbl.state.instance_name, event_table[type], details);
}
if(event_message->str) {
@@ -179,7 +154,6 @@ send_event(int type, const gchar *details, const gchar *custom_event) {
g_string_free(event_message, TRUE);
}
- g_free(p_val);
}
/* Transform gdk key events to our own events */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..c9c728e
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,110 @@
+#define _POSIX_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "util.h"
+
+const XDG_Var XDG[] =
+{
+ { "XDG_CONFIG_HOME", "~/.config" },
+ { "XDG_DATA_HOME", "~/.local/share" },
+ { "XDG_CACHE_HOME", "~/.cache" },
+ { "XDG_CONFIG_DIRS", "/etc/xdg" },
+ { "XDG_DATA_DIRS", "/usr/local/share/:/usr/share/" },
+};
+
+/*@null@*/ gchar*
+get_xdg_var (XDG_Var xdg) {
+ const gchar* actual_value = getenv (xdg.environmental);
+ const gchar* home = getenv ("HOME");
+ gchar* return_value;
+
+ if (! actual_value || strcmp (actual_value, "") == 0) {
+ if (xdg.default_value) {
+ return_value = str_replace ("~", home, xdg.default_value);
+ } else {
+ return_value = NULL;
+ }
+ } else {
+ return_value = str_replace("~", home, actual_value);
+ }
+
+ return return_value;
+}
+
+/*@null@*/ gchar*
+find_xdg_file (int xdg_type, const char* filename) {
+ /* xdg_type = 0 => config
+ xdg_type = 1 => data
+ xdg_type = 2 => cache*/
+
+ gchar* xdgv = get_xdg_var (XDG[xdg_type]);
+ gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
+ g_free (xdgv);
+
+ gchar* temporary_string;
+ char* saveptr;
+ char* buf;
+
+ if (! file_exists (temporary_file) && xdg_type != 2) {
+ buf = get_xdg_var (XDG[3 + xdg_type]);
+ temporary_string = (char *) strtok_r (buf, ":", &saveptr);
+ g_free(buf);
+
+ while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
+ g_free (temporary_file);
+ temporary_file = g_strconcat (temporary_string, filename, NULL);
+ }
+ }
+
+ //g_free (temporary_string); - segfaults.
+
+ if (file_exists (temporary_file)) {
+ return temporary_file;
+ } else {
+ g_free(temporary_file);
+ return NULL;
+ }
+}
+
+gboolean
+file_exists (const char * filename) {
+ return (access(filename, F_OK) == 0);
+}
+
+char *
+str_replace (const char* search, const char* replace, const char* string) {
+ gchar **buf;
+ char *ret;
+
+ if(!string)
+ return NULL;
+
+ buf = g_strsplit (string, search, -1);
+ ret = g_strjoinv (replace, buf);
+ g_strfreev(buf);
+
+ return ret;
+}
+
+gboolean
+for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data) {
+ gchar *line = NULL;
+ gsize len;
+
+ GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
+
+ if (chan) {
+ while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
+ callback(line, user_data);
+ g_free(line);
+ }
+ g_io_channel_unref (chan);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..f03f13e
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,18 @@
+#include <glib.h>
+
+typedef struct {
+ gchar* environmental;
+ gchar* default_value;
+} XDG_Var;
+
+gchar* get_xdg_var (XDG_Var xdg);
+
+gchar* find_xdg_file (int xdg_type, const char* filename);
+
+gboolean file_exists(const char* filename);
+
+char *
+str_replace (const char* search, const char* replace, const char* string);
+
+gboolean
+for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data);
diff --git a/src/uzbl-browser b/src/uzbl-browser
index de4f7af..3c9562d 100755
--- a/src/uzbl-browser
+++ b/src/uzbl-browser
@@ -1,66 +1,82 @@
#!/bin/sh
-# this script implements a more useful out-of-the-box "browsing experience".
-# it does so by combining uzbl-core with a set of "recommended" tools and practices.
-# see docs for more info
-# If you want to customize the behavior of the cookie-daemon or similar helper tools,
-# copy them to your $XDG_DATA_HOME/uzbl/scripts/, edit them and update $PATH
-
-# Also, we assume existence of fifo/socket == correctly functioning cookie_daemon/event_manager.
-# Checking correct functioning of the daemons here would be too complex here, and it's not implemented in uzbl-core either.
-# But this shouldn't cause much problems..
+#
+# This script implements a more useful out-of-the-box "browsing experience".
+# It does so by combining uzbl-core with a set of "recommended" tools and
+# practices. See docs for more info.
+#
+# If you want to customize the behavior any of the helper tools, copy them
+# to your $XDG_DATA_HOME/uzbl/scripts/ and edit them
PREFIX=/usr/local
-if [ -z "$XDG_DATA_HOME" ]
-then
- export XDG_DATA_HOME=$HOME/.local/share
-fi
+export PREFIX
-if [ -z "$XDG_CACHE_HOME" ]
-then
- export XDG_CACHE_HOME=$HOME/.cache
-fi
+EXAMPLES=$PREFIX/share/uzbl/examples
-if [ -z "$XDG_CONFIG_HOME" ]
-then
- export XDG_CONFIG_HOME=$HOME/.config
-fi
+XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share}
+export XDG_DATA_HOME
+
+XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}
+export XDG_CACHE_HOME
+
+XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+export XDG_CONFIG_HOME
# assure the relevant directories exist.
-for dir in $XDG_CACHE_HOME/uzbl $XDG_DATA_HOME/uzbl $XDG_CONFIG_HOME/uzbl
+for dir in "$XDG_CACHE_HOME"/uzbl "$XDG_DATA_HOME"/uzbl "$XDG_CONFIG_HOME"/uzbl
do
- if [ ! -d $dir ]
+ if [ ! -d "$dir" ]
then
- if ! mkdir -p $dir
+ if ! mkdir -p "$dir"
then
echo "could not create $dir" >&2
exit 2
fi
fi
done
+
# if no config exists yet in the recommended location, put the default (recommended) config there
-if [ ! -f $XDG_CONFIG_HOME/uzbl/config ]
+if [ ! -f "$XDG_CONFIG_HOME"/uzbl/config ]
then
- if ! cp $PREFIX/share/uzbl/examples/config/config $XDG_CONFIG_HOME/uzbl/config
+ if [ ! -r "$EXAMPLES"/config/config ]
then
- echo "Could not copy default config to $XDG_CONFIG_HOME/uzbl/config" >&2
+ echo "Error: Global config not found; please check if your distribution ships them separately"
exit 3
fi
+ if ! cp "$EXAMPLES"/config/config "$XDG_CONFIG_HOME"/uzbl/config
+ then
+ echo "Could not copy default config to $XDG_CONFIG_HOME/uzbl/config" >&2
+ # Run with the global config as a last resort
+ config_file=$EXAMPLES/config/config
+ fi
+fi
+
+# this variable is used by the default helper scripts as a location to
+# load shared code from
+if [ -z "$UZBL_UTIL_DIR" ]
+then
+ if [ -d "$XDG_DATA_HOME"/uzbl/scripts/util ]
+ then
+ UZBL_UTIL_DIR=$XDG_DATA_HOME/uzbl/scripts/util
+ elif [ -d $EXAMPLES/data/scripts/util ]
+ then
+ UZBL_UTIL_DIR=$EXAMPLES/data/scripts/util
+ fi
+ export UZBL_UTIL_DIR
fi
-# Uncomment this for a slight speedup at the expense of not having
-# stale cookie daemon sockets cleaned up.
-#if [ ! -S $XDG_CACHE_HOME/uzbl/cookie_daemon_socket ]
+# uzbl-cookie-manager will exit if another instance is already running.
+# we could also check if its pid file exists to avoid having to spawn it.
+#if [ ! -f "$XDG_CACHE_HOME"/uzbl/cookie_daemon_socket.pid ]
#then
- # if you want to customize it, copy to your $XDG_DATA_HOME/uzbl/scripts/ and update $PATH
- uzbl-cookie-daemon -v start
+ ${UZBL_COOKIE_DAEMON:-uzbl-cookie-manager}
#fi
-DAEMON_SOCKET=$XDG_CACHE_HOME/uzbl/event_daemon
-DAEMON_PID=${DAEMON_SOCKET}.pid
-
-#if [ -f "$DAEMON_PID" ]
+# uzbl-event-manager will exit if one is already running.
+# we could also check if its pid file exists to avoid having to spawn it.
+DAEMON_SOCKET="$XDG_CACHE_HOME"/uzbl/event_daemon
+#if [ ! -f "$DAEMON_SOCKET".pid ]
#then
- uzbl-event-manager -va start
+ ${UZBL_EVENT_MANAGER:-uzbl-event-manager -va start}
#fi
-exec uzbl-core "$@" --connect-socket $DAEMON_SOCKET
+exec uzbl-core "$@" ${config_file:+--config "$config_file"} --connect-socket $DAEMON_SOCKET
diff --git a/src/uzbl-core.c b/src/uzbl-core.c
index fdfb811..5adc4e1 100644
--- a/src/uzbl-core.c
+++ b/src/uzbl-core.c
@@ -34,6 +34,7 @@
#include "events.h"
#include "inspector.h"
#include "config.h"
+#include "util.h"
UzblCore uzbl;
@@ -62,15 +63,6 @@ GOptionEntry entries[] =
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
-XDG_Var XDG[] =
-{
- { "XDG_CONFIG_HOME", "~/.config" },
- { "XDG_DATA_HOME", "~/.local/share" },
- { "XDG_CACHE_HOME", "~/.cache" },
- { "XDG_CONFIG_DIRS", "/etc/xdg" },
- { "XDG_DATA_DIRS", "/usr/local/share/:/usr/share/" },
-};
-
/* abbreviations to help keep the table's width humane */
#define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun }
#define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun }
@@ -93,12 +85,12 @@ const struct var_name_to_ptr_t {
{ "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)},
{ "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)},
{ "status_format", PTR_V_STR(uzbl.behave.status_format, 1, NULL)},
- { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, NULL)},
+ { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, set_status_background)},
{ "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, NULL)},
{ "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, NULL)},
{ "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
{ "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)},
- { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, NULL)},
+ { "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)},
{ "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
@@ -125,6 +117,7 @@ const struct var_name_to_ptr_t {
{ "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
{ "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
{ "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
+ { "enable_pagecache", PTR_V_INT(uzbl.behave.enable_pagecache, 1, cmd_enable_pagecache)},
{ "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
{ "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
{ "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
@@ -372,48 +365,6 @@ strfree(gchar *str) {
gchar*
argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
-char *
-str_replace (const char* search, const char* replace, const char* string) {
- gchar **buf;
- char *ret;
-
- if(!string)
- return NULL;
-
- buf = g_strsplit (string, search, -1);
- ret = g_strjoinv (replace, buf);
- g_strfreev(buf);
-
- return ret;
-}
-
-GArray*
-read_file_by_line (const gchar *path) {
- GIOChannel *chan = NULL;
- gchar *readbuf = NULL;
- gsize len;
- GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
- int i = 0;
-
- chan = g_io_channel_new_file(path, "r", NULL);
- if (chan) {
- while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
- const gchar* val = g_strdup (readbuf);
- g_array_append_val (lines, val);
- g_free (readbuf);
- i ++;
- }
-
- g_io_channel_unref (chan);
- } else {
- gchar *tmp = g_strdup_printf("File %s can not be read.", path);
- send_event(COMMAND_ERROR, tmp, NULL);
- g_free(tmp);
- }
-
- return lines;
-}
-
/* search a PATH style string for an existing file+path combination */
gchar*
find_existing_file(gchar* path_list) {
@@ -463,36 +414,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) {
@@ -679,7 +600,6 @@ struct {const char *key; CommandInfo value;} cmdlist[] =
{ "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
{ "sh", {spawn_sh, 0} },
{ "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
- { "talk_to_socket", {talk_to_socket, 0} },
{ "exit", {close_uzbl, 0} },
{ "search", {search_forward_text, TRUE} },
{ "search_reverse", {search_reverse_text, TRUE} },
@@ -705,7 +625,8 @@ struct {const char *key; CommandInfo value;} cmdlist[] =
{ "menu_image_remove", {menu_remove_image, TRUE} },
{ "menu_editable_remove", {menu_remove_edit, TRUE} },
{ "hardcopy", {hardcopy, TRUE} },
- { "include", {include, TRUE} }
+ { "include", {include, TRUE} },
+ { "show_inspector", {show_inspector, 0} }
};
void
@@ -735,11 +656,6 @@ builtins() {
/* -- CORE FUNCTIONS -- */
-bool
-file_exists (const char * filename) {
- return (access(filename, F_OK) == 0);
-}
-
void
set_var(WebKitWebView *page, GArray *argv, GString *result) {
(void) page; (void) result;
@@ -749,9 +665,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);
}
@@ -970,33 +885,39 @@ hardcopy(WebKitWebView *page, GArray *argv, GString *result) {
webkit_web_frame_print(webkit_web_view_get_main_frame(page));
}
+/* just a wrapper so parse_cmd_line can be used with for_each_line_in_file */
+static void
+parse_cmd_line_cb(const char *line, void *user_data) {
+ (void) user_data;
+ parse_cmd_line(line, NULL);
+}
+
void
include(WebKitWebView *page, GArray *argv, GString *result) {
(void) page;
(void) result;
- gchar *pe = NULL,
- *path = NULL,
- *line;
- int i=0;
+ 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))) {
- GArray* lines = read_file_by_line(path);
-
- while ((line = g_array_index(lines, gchar*, i))) {
- parse_cmd_line (line, NULL);
- i++;
- g_free (line);
+ 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);
+ g_free(tmp);
}
- g_array_free (lines, TRUE);
send_event(FILE_INCLUDED, path, NULL);
g_free(path);
}
- g_free(pe);
+}
+
+void
+show_inspector(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) argv; (void) result;
+
+ webkit_web_inspector_show(uzbl.gui.inspector);
}
void
@@ -1156,32 +1077,23 @@ run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
if (argv_idx(argv, 0) &&
((path = find_existing_file(argv_idx(argv, 0)))) ) {
- GArray* lines = read_file_by_line (path);
- gchar* js = NULL;
- int i = 0;
- gchar* line;
-
- while ((line = g_array_index(lines, gchar*, i))) {
- if (js == NULL) {
- js = g_strdup (line);
- } else {
- gchar* newjs = g_strconcat (js, line, NULL);
- js = newjs;
- }
- i ++;
- g_free (line);
+ gchar *file_contents = NULL;
+
+ GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
+ if (chan) {
+ gsize len;
+ g_io_channel_read_to_end(chan, &file_contents, &len, NULL);
+ g_io_channel_unref (chan);
}
if (uzbl.state.verbose)
printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
- gchar* newjs = str_replace("%s", argv_idx (argv, 1)?argv_idx (argv, 1):"", js);
- g_free (js);
- js = newjs;
+ gchar *js = str_replace("%s", argv_idx (argv, 1) ? argv_idx (argv, 1) : "", file_contents);
+ g_free (file_contents);
eval_js (web_view, js, result, path);
g_free (js);
- g_array_free (lines, TRUE);
g_free(path);
}
}
@@ -1274,6 +1186,7 @@ run_command (const gchar *command, const guint npre, const gchar **args,
gchar *pid = itos(getpid());
gchar *xwin = itos(uzbl.xwin);
guint i;
+
sharg_append(a, command);
for (i = 0; i < npre; i++) /* add n args before the default vars */
sharg_append(a, args[i]);
@@ -1432,118 +1345,6 @@ spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
}
void
-talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
-
- int fd, len;
- struct sockaddr_un sa;
- char* sockpath;
- ssize_t ret;
- struct pollfd pfd;
- struct iovec* iov;
- guint i;
-
- if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
-
- /* This function could be optimised by storing a hash table of socket paths
- and associated connected file descriptors rather than closing and
- re-opening for every call. Also we could launch a script if socket connect
- fails. */
-
- /* First element argv[0] is path to socket. Following elements are tokens to
- write to the socket. We write them as a single packet with each token
- separated by an ASCII nul (\0). */
- if(argv->len < 2) {
- g_printerr("talk_to_socket called with only %d args (need at least two).\n",
- (int)argv->len);
- return;
- }
-
- /* copy socket path, null terminate result */
- sockpath = g_array_index(argv, char*, 0);
- g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
- sa.sun_family = AF_UNIX;
-
- /* create socket file descriptor and connect it to path */
- fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
- if(fd == -1) {
- g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
- return;
- }
- if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
- g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
- close(fd);
- return;
- }
-
- /* build request vector */
- iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
- if(!iov) {
- g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
- close(fd);
- return;
- }
- for(i = 1; i < argv->len; ++i) {
- iov[i - 1].iov_base = g_array_index(argv, char*, i);
- iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
- }
-
- /* write request */
- ret = writev(fd, iov, argv->len - 1);
- g_free(iov);
- if(ret == -1) {
- g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
- close(fd);
- return;
- }
-
- /* wait for a response, with a 500ms timeout */
- pfd.fd = fd;
- pfd.events = POLLIN;
- while(1) {
- ret = poll(&pfd, 1, 500);
- if(ret == 1) break;
- if(ret == 0) errno = ETIMEDOUT;
- if(errno == EINTR) continue;
- g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
- strerror(errno));
- close(fd);
- return;
- }
-
- /* get length of response */
- if(ioctl(fd, FIONREAD, &len) == -1) {
- g_printerr("talk_to_socket: cannot find daemon response length, "
- "ioctl failed (%s)\n", strerror(errno));
- close(fd);
- return;
- }
-
- /* if there is a response, read it */
- if(len) {
- uzbl.comm.sync_stdout = g_malloc(len + 1);
- if(!uzbl.comm.sync_stdout) {
- g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
- close(fd);
- return;
- }
- uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
-
- ret = read(fd, uzbl.comm.sync_stdout, len);
- if(ret == -1) {
- g_printerr("talk_to_socket: failed to read from socket (%s)\n",
- strerror(errno));
- close(fd);
- return;
- }
- }
-
- /* clean up */
- close(fd);
- return;
-}
-
-void
parse_command(const char *cmd, const char *param, GString *result) {
CommandInfo *c;
GString *tmp = g_string_new("");
@@ -1716,7 +1517,6 @@ parse_cmd_line(const char *ctl_line, GString *result) {
g_free(ctlstrip);
}
-
/*@null@*/ gchar*
build_stream_name(int type, const gchar* dir) {
State *s = &uzbl.state;
@@ -1779,8 +1579,9 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
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);
+ 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);
@@ -1974,6 +1775,7 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
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;
}
} else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
@@ -1993,32 +1795,29 @@ void
update_title (void) {
Behaviour *b = &uzbl.behave;
gchar *parsed;
+ const gchar *current_title;
+ /* this check is here because if we're starting up or shutting down it might not be a window */
+ gboolean have_main_window = !uzbl.state.plug_mode && GTK_IS_WINDOW(uzbl.gui.main_window);
+
+ if(have_main_window)
+ current_title = gtk_window_get_title (GTK_WINDOW(uzbl.gui.main_window));
if (b->show_status) {
- if (b->title_format_short) {
+ if (b->title_format_short && have_main_window) {
parsed = expand(b->title_format_short, 0);
- if (uzbl.gui.main_window)
+ if(!current_title || strcmp(current_title, parsed))
gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
g_free(parsed);
}
- if (b->status_format) {
+ if (b->status_format && GTK_IS_LABEL(uzbl.gui.mainbar_label)) {
parsed = expand(b->status_format, 0);
gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
g_free(parsed);
}
- if (b->status_background) {
- GdkColor color;
- gdk_color_parse (b->status_background, &color);
- //labels and hboxes do not draw their own background. applying this on the vbox/main_window is ok as the statusbar is the only affected widget. (if not, we could also use GtkEventBox)
- if (uzbl.gui.main_window)
- gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
- else if (uzbl.gui.plug)
- gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
- }
} else {
- if (b->title_format_long) {
+ if (b->title_format_long && have_main_window) {
parsed = expand(b->title_format_long, 0);
- if (uzbl.gui.main_window)
+ if(!current_title || strcmp(current_title, parsed))
gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
g_free(parsed);
}
@@ -2037,12 +1836,10 @@ create_browser () {
"signal::button-press-event", (GCallback)button_press_cb, NULL,
"signal::button-release-event", (GCallback)button_release_cb, NULL,
"signal::motion-notify-event", (GCallback)motion_notify_cb, NULL,
- "signal::title-changed", (GCallback)title_change_cb, NULL,
+ "signal::notify::title", (GCallback)title_change_cb, NULL,
"signal::selection-changed", (GCallback)selection_changed_cb, NULL,
- "signal::load-progress-changed", (GCallback)progress_change_cb, NULL,
- "signal::load-committed", (GCallback)load_commit_cb, NULL,
- "signal::load-started", (GCallback)load_start_cb, NULL,
- "signal::load-finished", (GCallback)load_finish_cb, NULL,
+ "signal::notify::progress", (GCallback)progress_change_cb, NULL,
+ "signal::notify::load-status", (GCallback)load_status_change_cb, NULL,
"signal::load-error", (GCallback)load_error_cb, NULL,
"signal::hovering-over-link", (GCallback)link_hover_cb, NULL,
"signal::navigation-policy-decision-requested", (GCallback)navigation_decision_cb, NULL,
@@ -2125,8 +1922,7 @@ inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *ne
if ((g_strcmp0(actname, "spawn") == 0) ||
(g_strcmp0(actname, "sh") == 0) ||
(g_strcmp0(actname, "sync_spawn") == 0) ||
- (g_strcmp0(actname, "sync_sh") == 0) ||
- (g_strcmp0(actname, "talk_to_socket") == 0)) {
+ (g_strcmp0(actname, "sync_sh") == 0)) {
guint i;
GString *a = g_string_new("");
gchar **spawnparts = split_quoted(origargs, FALSE);
@@ -2222,59 +2018,6 @@ run_handler (const gchar *act, const gchar *args) {
g_strfreev(parts);
}
-/*@null@*/ gchar*
-get_xdg_var (XDG_Var xdg) {
- const gchar* actual_value = getenv (xdg.environmental);
- const gchar* home = getenv ("HOME");
- gchar* return_value;
-
- if (! actual_value || strcmp (actual_value, "") == 0) {
- if (xdg.default_value) {
- return_value = str_replace ("~", home, xdg.default_value);
- } else {
- return_value = NULL;
- }
- } else {
- return_value = str_replace("~", home, actual_value);
- }
-
- return return_value;
-}
-
-/*@null@*/ gchar*
-find_xdg_file (int xdg_type, const char* filename) {
- /* xdg_type = 0 => config
- xdg_type = 1 => data
- xdg_type = 2 => cache*/
-
- gchar* xdgv = get_xdg_var (XDG[xdg_type]);
- gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
- g_free (xdgv);
-
- gchar* temporary_string;
- char* saveptr;
- char* buf;
-
- if (! file_exists (temporary_file) && xdg_type != 2) {
- buf = get_xdg_var (XDG[3 + xdg_type]);
- temporary_string = (char *) strtok_r (buf, ":", &saveptr);
- g_free(buf);
-
- while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
- g_free (temporary_file);
- temporary_file = g_strconcat (temporary_string, filename, NULL);
- }
- }
-
- //g_free (temporary_string); - segfaults.
-
- if (file_exists (temporary_file)) {
- return temporary_file;
- } else {
- g_free(temporary_file);
- return NULL;
- }
-}
void
settings_init () {
State *s = &uzbl.state;
@@ -2295,25 +2038,18 @@ settings_init () {
}
if (s->config_file) {
- GArray* lines = read_file_by_line (s->config_file);
- int i = 0;
- gchar* line;
-
- while ((line = g_array_index(lines, gchar*, i))) {
- parse_cmd_line (line, NULL);
- i ++;
- g_free (line);
+ if(!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) {
+ gchar *tmp = g_strdup_printf("File %s can not be read.", s->config_file);
+ send_event(COMMAND_ERROR, tmp, NULL);
+ g_free(tmp);
}
- g_array_free (lines, TRUE);
- } else {
- if (uzbl.state.verbose)
- printf ("No configuration file loaded.\n");
- }
+ g_setenv("UZBL_CONFIG", s->config_file, TRUE);
+ } else if (uzbl.state.verbose)
+ printf ("No configuration file loaded.\n");
if(s->connect_socket_names)
init_connect_socket();
- g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
g_signal_connect(n->soup_session, "authenticate", G_CALLBACK(handle_authentication), NULL);
}
@@ -2373,57 +2109,6 @@ void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *au
}
}
-void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data) {
- (void) session;
- (void) user_data;
-
- soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies_http), NULL);
- GString *s = g_string_new ("");
- SoupURI * soup_uri = soup_message_get_uri(msg);
- g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
-
- if(uzbl.behave.cookie_handler)
- run_handler(uzbl.behave.cookie_handler, s->str);
-
- if(uzbl.behave.cookie_handler &&
- uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
- char *p = strchr(uzbl.comm.sync_stdout, '\n' );
- if ( p != NULL ) *p = '\0';
- soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
-
- int len = strlen(uzbl.comm.sync_stdout);
-
- if(len > 0) {
- SoupCookie *soup_cookie;
- char *cookies = (char *) g_malloc(len+1);
- strncpy(cookies, uzbl.comm.sync_stdout, len+1);
-
- /* Disconnect to avoid recursion */
- g_object_disconnect(G_OBJECT(uzbl.net.soup_cookie_jar), "any_signal", G_CALLBACK(save_cookies_js), NULL, NULL);
-
- p = cookies - 1;
- while(p != NULL) {
- p = p + 1;
- soup_cookie = soup_cookie_parse((const char *) p, soup_uri);
- if (soup_cookie) {
- if(soup_cookie->domain == NULL)
- soup_cookie->domain = soup_uri->host;
- soup_cookie_jar_add_cookie(uzbl.net.soup_cookie_jar, soup_cookie);
- }
- p = strchr(p, ';');
- }
-
- g_object_connect(G_OBJECT(uzbl.net.soup_cookie_jar), "signal::changed", G_CALLBACK(save_cookies_js), NULL, NULL);
- g_free(cookies);
- }
- }
-
- if (uzbl.comm.sync_stdout)
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
-
- g_string_free(s, TRUE);
-}
-
void
dump_var_hash(gpointer k, gpointer v, gpointer ud) {
(void) ud;
@@ -2522,9 +2207,8 @@ initialize(int argc, char *argv[]) {
uzbl.net.soup_session = webkit_get_default_session();
- uzbl.net.soup_cookie_jar = soup_cookie_jar_new();
+ 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));
- g_object_connect(G_OBJECT(uzbl.net.soup_cookie_jar), "signal::changed", G_CALLBACK(save_cookies_js), NULL, NULL);
for(i=0; sigs[i]; i++) {
if(setup_signal(sigs[i], catch_signal) == SIG_ERR)
@@ -2548,6 +2232,7 @@ initialize(int argc, char *argv[]) {
void
load_uri_imp(gchar *uri) {
GString* newuri;
+ SoupURI* soup_uri;
/* Strip leading whitespaces */
while (*uri) {
@@ -2559,26 +2244,28 @@ load_uri_imp(gchar *uri) {
eval_js(uzbl.gui.web_view, uri, NULL, "javascript:");
return;
}
+
newuri = g_string_new (uri);
- if (!soup_uri_new(uri)) {
- GString* fullpath = g_string_new ("");
+ soup_uri = soup_uri_new(uri);
+
+ if (!soup_uri) {
+ gchar* fullpath;
if (g_path_is_absolute (newuri->str))
- g_string_assign (fullpath, newuri->str);
+ fullpath = newuri->str;
else {
- gchar* wd;
- wd = g_get_current_dir ();
- g_string_assign (fullpath, g_build_filename (wd, newuri->str, NULL));
- free(wd);
+ gchar* wd = g_get_current_dir ();
+ fullpath = g_build_filename (wd, newuri->str, NULL);
+ g_free(wd);
}
struct stat stat_result;
- if (! g_stat(fullpath->str, &stat_result)) {
- g_string_prepend (fullpath, "file://");
- g_string_assign (newuri, fullpath->str);
- }
+ if (! g_stat(fullpath, &stat_result))
+ g_string_printf (newuri, "file://%s", fullpath);
else
g_string_prepend (newuri, "http://");
- g_string_free (fullpath, TRUE);
+ } else {
+ soup_uri_free(soup_uri);
}
+
/* if we do handle cookies, ask our handler for them */
webkit_web_view_load_uri (uzbl.gui.web_view, newuri->str);
g_string_free (newuri, TRUE);
@@ -2639,12 +2326,16 @@ main (int argc, char* argv[]) {
"signal::changed", (GCallback)scroll_horiz_cb, NULL,
NULL);
+ gchar *xwin = g_strdup_printf("%d", (int)uzbl.xwin);
+ g_setenv("UZBL_XID", xwin, TRUE);
+
if(!uzbl.state.instance_name)
- uzbl.state.instance_name = itos((int)uzbl.xwin);
+ uzbl.state.instance_name = g_strdup(xwin);
- GString *tmp = g_string_new("");
- g_string_printf(tmp, "%d", getpid());
- uzbl.info.pid_str = g_string_free(tmp, FALSE);
+ g_free(xwin);
+
+ uzbl.info.pid_str = g_strdup_printf("%d", getpid());
+ g_setenv("UZBL_PID", uzbl.info.pid_str, TRUE);
send_event(INSTANCE_START, uzbl.info.pid_str, NULL);
if(uzbl.state.plug_mode) {
diff --git a/src/uzbl-core.h b/src/uzbl-core.h
index 5760423..6c926c6 100644
--- a/src/uzbl-core.h
+++ b/src/uzbl-core.h
@@ -40,6 +40,8 @@
#include <sys/ioctl.h>
#include <assert.h>
+#include "cookie-jar.h"
+
#define LENGTH(x) (sizeof x / sizeof x[0])
/* gui elements */
@@ -104,8 +106,8 @@ typedef struct {
/* networking */
typedef struct {
- SoupSession *soup_session;
- SoupCookieJar *soup_cookie_jar;
+ SoupSession *soup_session;
+ UzblCookieJar *soup_cookie_jar;
SoupLogger *soup_logger;
char *proxy_url;
char *useragent;
@@ -144,6 +146,7 @@ typedef struct {
guint minimum_font_size;
gfloat zoom_level;
gboolean zoom_type;
+ guint enable_pagecache;
guint disable_plugins;
guint disable_scripts;
guint autoload_img;
@@ -204,12 +207,6 @@ extern UzblCore uzbl;
typedef void sigfunc(int);
-/* XDG Stuff */
-typedef struct {
- gchar* environmental;
- gchar* default_value;
-} XDG_Var;
-
/* uzbl variables */
enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT};
typedef struct {
@@ -228,18 +225,9 @@ typedef struct {
char *
itos(int val);
-char *
-str_replace (const char* search, const char* replace, const char* string);
-
gchar*
strfree(gchar *str);
-GArray*
-read_file_by_line (const gchar *path);
-
-gchar*
-parseenv (gchar* string);
-
void
clean_up(void);
@@ -261,9 +249,6 @@ print(WebKitWebView *page, GArray *argv, GString *result);
void
commands_hash(void);
-bool
-file_exists (const char * filename);
-
void
load_uri (WebKitWebView * web_view, GArray *argv, GString *result);
@@ -278,9 +263,6 @@ run_command(const gchar *command, const guint npre,
const gchar **args, const gboolean sync, char **output_stdout);
void
-talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result);
-
-void
spawn(WebKitWebView *web_view, GArray *argv, GString *result);
void
@@ -349,12 +331,6 @@ create_plug ();
void
run_handler (const gchar *act, const gchar *args);
-/*@null@*/ gchar*
-get_xdg_var (XDG_Var xdg);
-
-/*@null@*/ gchar*
-find_xdg_file (int xdg_type, const char* filename);
-
void
settings_init ();
@@ -472,6 +448,9 @@ void
include(WebKitWebView *page, GArray *argv, GString *result);
void
+show_inspector(WebKitWebView *page, GArray *argv, GString *result);
+
+void
builtins();
typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);