aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--AUTHORS3
-rw-r--r--Makefile79
-rw-r--r--README104
-rw-r--r--docs/COMMUNITY10
-rw-r--r--docs/INSTALL1
-rw-r--r--docs/README.uzbl-event-manager99
-rw-r--r--examples/config/config67
-rw-r--r--examples/data/per-site-settings3
-rw-r--r--examples/data/plugins/cookies.py176
-rw-r--r--examples/data/plugins/downloads.py69
-rwxr-xr-xexamples/data/scripts/auth.py2
-rwxr-xr-xexamples/data/scripts/download.sh35
-rwxr-xr-xexamples/data/scripts/follow.sh2
-rwxr-xr-xexamples/data/scripts/formfiller.sh3
-rwxr-xr-xexamples/data/scripts/go_input.sh19
-rwxr-xr-xexamples/data/scripts/history.sh2
-rwxr-xr-xexamples/data/scripts/insert_bookmark.sh5
-rwxr-xr-xexamples/data/scripts/load_cookies.sh20
-rwxr-xr-xexamples/data/scripts/load_url_from_bookmarks.sh1
-rwxr-xr-xexamples/data/scripts/load_url_from_history.sh3
-rwxr-xr-xexamples/data/scripts/per-site-settings.py117
-rw-r--r--examples/data/scripts/pipermail.js71
-rwxr-xr-xexamples/data/scripts/scheme.py2
-rwxr-xr-xexamples/data/scripts/session.sh35
-rwxr-xr-xexamples/data/scripts/userscript.sh40
-rwxr-xr-xexamples/data/scripts/userscripts.sh8
-rw-r--r--examples/data/scripts/util/dmenu.sh14
-rw-r--r--examples/data/scripts/util/uzbl-args.sh17
-rw-r--r--examples/data/scripts/util/uzbl-window.sh6
-rwxr-xr-xexamples/data/scripts/uzbl-tabbed5
-rwxr-xr-xmisc/env.sh4
-rw-r--r--src/callbacks.c159
-rw-r--r--src/callbacks.h5
-rw-r--r--src/cookie-jar.c26
-rw-r--r--src/cookie-jar.h1
-rw-r--r--src/events.c22
-rw-r--r--src/events.h4
-rwxr-xr-xsrc/uzbl-browser4
-rw-r--r--src/uzbl-core.c429
-rw-r--r--src/uzbl-core.h24
-rw-r--r--tests/Makefile38
-rw-r--r--tests/test-command.c38
43 files changed, 1238 insertions, 535 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 830df44..f7e4a16 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -35,7 +35,7 @@ In alphabetical order:
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.
+ David Keijser (keis) - the add_cookie/delete_cookie + distributor system, various C and python patches.
Devon Jones <devon.jones@gmail.com> - uzbl_tabbed: bring_to_front
Dieter Plaetinck (Dieter@be) <dieter AT plaetinck.be> - several contributions
Dmytro Milinevskyy - uzbl-tabbed useability patches
@@ -51,6 +51,7 @@ 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
diff --git a/Makefile b/Makefile
index 04f35d0..7724303 100644
--- a/Makefile
+++ b/Makefile
@@ -1,50 +1,71 @@
# 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 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
+# 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
+# RUN_PREFIX : what the prefix is when the software is run. usually the same as PREFIX
+PREFIX?=/usr/local
+INSTALLDIR?=$(DESTDIR)$(PREFIX)
+DOCDIR?=$(INSTALLDIR)/share/uzbl/docs
+RUN_PREFIX?=$(PREFIX)
+
+# gtk2
+REQ_PKGS = gtk+-2.0 webkit-1.0
+CPPFLAGS =
+
+# gtk3
+#REQ_PKGS = gtk+-3.0 webkitgtk-3.0
+#CPPFLAGS = -DGTK3
+
+# --- configuration ends here ---
+
+REQ_PKGS += libsoup-2.4 gthread-2.0 glib-2.0
+
+ARCH:=$(shell uname -m)
+ARCH!=echo `uname -m`
+
+COMMIT_HASH:=$(shell ./misc/hash.sh)
+COMMIT_HASH!=echo `./misc/hash.sh`
-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)
+CPPFLAGS += -DARCH=\"$(ARCH)\" -DCOMMIT=\"$(COMMIT_HASH)\"
+
+PKG_CFLAGS:=$(shell pkg-config --cflags $(REQ_PKGS))
+PKG_CFLAGS!=echo pkg-config --cflags $(REQ_PKGS)
+
+LDLIBS:=$(shell pkg-config --libs $(REQ_PKGS) x11)
+LDLIBS!=echo pkg-config --libs $(REQ_PKGS) x11
+
+CFLAGS += -std=c99 $(PKG_CFLAGS) -ggdb -W -Wall -Wextra -pedantic -pthread
SRC = $(wildcard src/*.c)
HEAD = $(wildcard src/*.h)
-OBJ = $(foreach obj, $(SRC:.c=.o), $(notdir $(obj)))
+OBJ = $(foreach obj, $(SRC:.c=.o), $(notdir $(obj)))
+LOBJ = $(foreach obj, $(SRC:.c=.lo), $(notdir $(obj)))
all: uzbl-browser uzbl-cookie-manager
VPATH:=src
-.c.o:
- @echo -e "${CC} -c ${CFLAGS} $<"
- @${CC} -c ${CFLAGS} $<
-
${OBJ}: ${HEAD}
uzbl-core: ${OBJ}
- @echo -e "\n${CC} -o $@ ${OBJ} ${UZBL_LDFLAGS}"
- @${CC} -o $@ ${OBJ} ${UZBL_LDFLAGS}
-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-cookie-manager: examples/uzbl-cookie-manager.o util.o
+ @echo -e "\n${CC} -o $@ examples/uzbl-cookie-manager.o util.o ${shell pkg-config --libs glib-2.0 libsoup-2.4}"
+ @${CC} -o $@ examples/uzbl-cookie-manager.o util.o $(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
-# RUN_PREFIX : what the prefix is when the software is run. usually the same as PREFIX
-PREFIX?=/usr/local
-INSTALLDIR?=$(DESTDIR)$(PREFIX)
-DOCDIR?=$(INSTALLDIR)/share/uzbl/docs
-RUN_PREFIX?=$(PREFIX)
-
# the 'tests' target can never be up to date
.PHONY: tests
force:
+# this is here because the .so needs to be compiled with -fPIC on x86_64
+${LOBJ}: ${SRC} ${HEAD}
+ $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -c src/$(@:.lo=.c) -o $@
+
# When compiling unit tests, compile uzbl as a library first
-tests: ${OBJ} force
- $(CC) -shared -Wl ${OBJ} -o ./tests/libuzbl-core.so
+tests: ${LOBJ} force
+ $(CC) -shared -Wl ${LOBJ} -o ./tests/libuzbl-core.so
cd ./tests/; $(MAKE)
test-uzbl-core: uzbl-core
@@ -90,12 +111,7 @@ test-uzbl-tabbed-sandbox: uzbl-browser
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
+ rm -f *.o *.lo
find ./examples/ -name "*.pyc" -delete
cd ./tests/; $(MAKE) clean
rm -rf ./sandbox/
@@ -119,9 +135,6 @@ 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 $(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: uzbl-cookie-manager install-dirs
diff --git a/README b/README
index 34556f2..e4e3cab 100644
--- a/README
+++ b/README
@@ -260,6 +260,11 @@ The following commands are recognized:
- Read contents of `<file>` and interpret as a set of `uzbl` commands.
* `show_inspector`
- Show the WebInspector
+* `add_cookie <domain> <path> <name> <value> <scheme> <expires>`
+ - Adds a new cookie to the cookie jar
+* 'delete_cookie <domain> <path> <name> <value> [<scheme> <expires>]`
+ - Deletes a matching cookie from the cookie jar. scheme and expire time
+ is currently not considered when matching.
### VARIABLES AND CONSTANTS
@@ -305,6 +310,9 @@ file).
- `data`: The cookie data. Only included for "PUT" requests.
* `scheme_handler`: handler to execute for each URI navigated to - the
navigation request will be ignored if handler prints "USED\n"
+* `download_handler`: executed when a download is started. the handler script
+ should print a path that the download should be saved to, or print nothing
+ to cancel the download.
* `fifo_dir`: location to store FIFOs.
* `socket_dir`: location to store sockets.
* `http_debug`: HTTP debug mode (value 0-3).
@@ -480,47 +488,47 @@ 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:
+Handler scripts (`download_handler`, `cookie_handler`, `scheme_handler` and
+`authentication_handler`) are called with special arguments:
-* download
+* download handler
- - `$8 url`: The URL of the item to be downloaded.
- - `$9 proxy`: (optional) The URL of an HTTP proxy.
+ - `$1 url`: The URL of the item to be downloaded.
+ - `$2 suggested_filename`: A filename suggested by the server or based on the URL.
+ - `$3 content_type`: The mimetype of the file to be downloaded.
+ - `$4 total_size`: The size of the file to be downloaded in bytes. This may be inaccurate.
* cookie handler
- - `$8 GET/PUT`: Whether a cookie should be sent to the server (`GET`) or
+ - `$1 GET/PUT`: Whether a cookie should be sent to the server (`GET`) or
stored by the browser (`PUT`).
- - `$9 scheme`: Either `http` or `https`.
- - `$10 host`: If current page URL is `www.example.com/somepage`, this could be
+ - `$2 scheme`: Either `http` or `https`.
+ - `$3 host`: If current page URL is `www.example.com/somepage`, this could be
something else than `example.com`, eg advertising from another host.
- - `$11 path`: The request address path.
- - `$12 data`: The cookie data. Only included for `PUT` requests.
+ - `$4 path`: The request address path.
+ - `$5 data`: The cookie data. Only included for `PUT` requests.
* scheme handler
- - `$8 URI` of the page to be navigated to
+ - `$1 URI` of the page to be navigated to
* 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.
+ - `$1`: authentication zone unique identifier
+ - `$2`: domain part of URL that requests authentication
+ - `$3`: authentication realm
+ - `$4`: FALSE if this is the first attempt to authenticate, TRUE otherwise
### Formfiller.sh
@@ -566,15 +574,15 @@ Example:
Script will be executed on each authentication request.
It will receive four auth-related parameters:
- $8 authentication zone unique identifier (may be used as 'key')
- $9 domain part of URL that requests authentication
- $10 authentication realm
- $11 FALSE if this is the first attempt to authenticate, TRUE otherwise
+ $1 authentication zone unique identifier (may be used as 'key')
+ $2 domain part of URL that requests authentication
+ $3 authentication realm
+ $4 FALSE if this is the first attempt to authenticate, TRUE otherwise
Script is expected to print exactly two lines of text on stdout (that means
its output must contain exactly two '\n' bytes).
The first line contains username, the second one - password.
-If authentication fails, script will be executed again (with $11 = TRUE).
+If authentication fails, script will be executed again (with $4 = TRUE).
Non-interactive scripts should handle this case and do not try to
authenticate again to avoid loops. If number of '\n' characters in scripts
output does not equal 2, authentication will fail.
@@ -583,7 +591,7 @@ That means 401 error will be displayed and uzbl won't try to authenticate anymor
The simplest example of authentication handler script is:
#!/bin/sh
-[ "$11" == "TRUE ] && exit
+[ "$4" == "TRUE ] && exit
echo alice
echo wonderland
@@ -626,11 +634,10 @@ The EM allows:
* Many fine-grained events (`hover_over_link`, `key_press`, `key_release`,..)
* See example `uzbl-event-manager`.
-**Note**: Cookie events are not sent to an event handler but handled internally
- through the cookie handler because of their synchronous nature. Cookie events
- are really something completely different from all other events. Maybe someday
- we'll use HTTP proxies or synchronous events (which also have other nice use
- cases), but for now we still use the handler code.
+**Note**: Cookie events are sent in addition to (optionally) being handled by
+ the cookie handler (set by the cookie_handler var). If using a handler it will
+ take precedence before the internal state configured by (add|delete)_cookie
+ commands.
Events have this format:
@@ -668,8 +675,13 @@ Events have this format:
* `EVENT [uzbl_instance_name] TITLE_CHANGED title_name`: When the title of the
page (and hence maybe, the window title) changed. `title_name` is the new
title.
-* `EVENT [uzbl_instance_name] DOWNLOAD_REQUEST download_uri`: When content needs
- to be downloaded, `download_uri` is the URI to get.
+* `EVENT [uzbl_instance_name] DOWNLOAD_STARTED destination_path`: A download
+ has been started, the file will be saved to `destination_path`.
+* `EVENT [uzbl_instance_name] DOWNLOAD_PROGRESS destination_path progress`:
+ While a download is active this event notifies you of the progress.
+ `progress` is a decimal between 0 and 1.
+* `EVENT [uzbl_instance_name] DOWNLOAD_COMPLETE destination_path`: The
+ download being saved to `destination_path` is now complete.
* `EVENT [uzbl_instance_name] LINK_HOVER uri`: The mouse hovers over the link
`uri`.
* `EVENT [uzbl_instance_name] LINK_UNHOVER uri`: The mouse leaves the link
@@ -699,6 +711,11 @@ Events have this format:
Xembed mode, `plug_id` is the Xembed ID used.
* `EVENT [uzbl_instance_name] BUILTINS command_list`: Shows a list of all `uzbl`
commands, whitespace separated, on startup.
+* `EVENT [uzbl_instance_name] ADD_COOKIE domain path name value scheme expire`:
+ When a cookie was added or replaced. scheme is 'http' or 'https', expire will
+ be a unix-timestamp or empty
+* `EVENT [uzbl_instance_name] DELETE_COOKIE domain path name value scheme expire`:
+ When a cookie was deleted. arguments as ADD_COOKIE
Events/requests which the EM and its plugins listens for
@@ -773,6 +790,15 @@ Events/requests which the EM and its plugins listens for
`<index>` is `+`, advance the cursor by one character, and if it is `-`,
move the cursor back by one character.
* `START_COMPLETION`: TODO explain completion
+* `BLACKLIST_COOKIE`: add a rule for blacklisting cookies
+ - `request BLACKLIST_COOKIE <component> <regexp>`: Blacklist cookies where
+ `<component>` matches `<regexp>`. `<component>` is one of `domain`,
+ `path`, `name`, `value`, `scheme` or `expires`.
+* `WHITELIST_COOKIE`: add a rule for whitelisting cookies (if any whitelist is
+ set then only cookies that are whitelisted cookies will be used)
+ - `request WHITELIST_COOKIE <component> <regexp>`: Whitelist cookies where
+ `<component>` matches `<regexp>`. `<component>` is one of `domain`,
+ `path`, `name`, `value`, `scheme` or `expires`.
### COMMAND LINE ARGUMENTS
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 accd383..0f6a662 100644
--- a/docs/INSTALL
+++ b/docs/INSTALL
@@ -13,6 +13,7 @@ You can pull the code from git or get a tagged tarball.
[ $ git checkout origin/experimental ] # optional. see below
$ make
$ sudo make install
+
If you want to remove uzbl again, you can issue:
$ make uninstall
diff --git a/docs/README.uzbl-event-manager b/docs/README.uzbl-event-manager
new file mode 100644
index 0000000..074811e
--- /dev/null
+++ b/docs/README.uzbl-event-manager
@@ -0,0 +1,99 @@
+# The uzbl event manager #
+
+## Core ##
+
+## Plugins ##
+
+### mode.py ###
+- Named modes with different settings
+- Connects To: (MODE_CONFIG, MODE_CONFIRM)
+- Watches: mode, default_mode
+- Emits: MODE_CHANGED, MODE_CONFIRM
+
+Changes between modes configured with MODE_CONFIG when the mode variable changes.
+
+MODE_CONFIG <mode> <var> = <value>
+ configures `mode` to have `var` set to `value`
+
+MODE_CONFIRM <mode>
+ Emitted when the mode has changed with a round trip to uzbl-core to allow
+ the settings to take effect.
+ emits MODE_CHANGE if `mode` matches the current mode
+
+MODE_CHANGE <mode>
+ Emitted when the mode has changed
+
+
+### keycmd.py ###
+- Tracks the currently entered command
+- Connects To: FOCUS_GAINED, FOCUS_LOST, KEY_PRESS, KEY_RELEASE, (APPEND_KEYCMD,
+ IGNORE_KEY, INJECT_KEYCMD, KEYCMD_BACKSPACE, KEYCMD_DELETE,
+ KEYCMD_EXEC_CURRENT, KEYCMD_STRIP_WORD, MODKEY_ADDITION, MODMAP,
+ SET_CURSOR_POS, SET_KEYCMD)
+- Emits: KEYCMD_UPDATE, KEYCMD_EXEC, MODCMD_UPDATE, MODCMD_EXEC
+
+Maintains a command line that is manipulated by simple keypresses and a number
+of events.
+
+
+### bind.py ###
+- Provides support for key bindings
+- Connects To: (BIND, MODE_BIND, MODE_CHANGED, KEYCMD_UPDATE, KEYCMD_EXEC,
+ MODCMD_UPDATE, MODCMD_EXEC)
+- Emits: EXEC_BIND
+
+Listens for changes in keycmd and modcmd and executes bindings configured by
+BIND and MODE_BIND.
+
+BIND <bind> = <command>
+ short hand for MODE_BIND global <bind> = <command>
+
+MODE_BIND <mode> <bind> = <command>
+ Makes <bind> execute <command> while the current mode is matched by `mode`.
+ `mode` is a comma separated list of modes in which this binding should
+ apply. The special mode 'global' will match all modes except any modes
+ excluded by prefixing them with '-'.
+
+ e.g
+ MODE_BIND global,-insert <Up> = scroll vertical -20
+ will make the Up-key scroll up in all modes except insert
+
+EXEC_BIND <bind> <args> <kwargs>
+ Emitted before executing `bind` with `args` as arguments and `kwargs` as
+ keyword arguments. `bind` is a Bind instance, <args> a sequence and <kwargs>
+ a dictionary.
+
+
+### cookies.py ###
+- Cookie synchronization and persistence
+- Connects To: ADD_COOKIE, DELETE_COOKIE, (BLACKLIST_COOKIE, WHITELIST_COOKIE)
+
+This plugin acts on the (ADD|DELETE)_COOKIE events by issuing add_cookie or
+delete_cookie commands as appropriate to other connected uzbl instances.
+However if the cookie is blacklisted (see below) the cookie will not be
+forwarded and instead delete_cookie will be sent to the source so that the
+cookie will not be included in future HTTP requests.
+
+This plugin also maintains a mozilla cookies.txt compatible file with all your
+persistent cookies in $XDG_DATA_HOME/uzbl/cookies.txt and all your session
+cookies in $XDG_DATA_HOME/uzbl/session-cookies.txt.
+
+The blacklist is configured using the BLACKLIST_COOKIE and WHITELIST_COOKIE
+events. If any whitelist is set, then any cookie that is not whitelisted will
+be rejected. Otherwise, only cookies that have been blacklisted will be
+rejected.
+
+BLACKLIST_COOKIE <part> <re>
+ Adds a new blacklist filter. cookies where the component specified by
+ `part` matches the regular expression `re` will be filtered. part can be
+ either 0-5 or any of the symbolic names domain, path, name, value, scheme,
+ expires
+
+ for example to block all cookies which name is "__utm" followed by a single
+ character (google analytics cookies) do.
+ request BLACKLIST_COOKIE name '^__utm.$'
+
+WHITELIST_COOKIE <part> <re>
+ Adds a new whitelist filter. cookies where the component specified by
+ `part` matches the regular expression `re` will be allowed. part can be any
+ of the parts allowed for the BLACKLIST_COOKIE event
diff --git a/examples/config/config b/examples/config/config
index fe08a41..7b9fba2 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,28 +36,25 @@ 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 scheme_handler = sync_spawn @scripts_dir/scheme.py
set authentication_handler = sync_spawn @scripts_dir/auth.py
+set download_handler = sync_spawn @scripts_dir/download.sh
# === Dynamic event handlers =================================================
# Open link in new window
-@on_event NEW_WINDOW sh 'uzbl-browser ${8:+-u "$8"}' %r
+@on_event NEW_WINDOW sh 'uzbl-browser ${1:+-u "$1"}' %r
# Open in current window
#@on_event NEW_WINDOW uri %s
# Open in new tab
#@on_event NEW_WINDOW event NEW_TAB %s
-# Download handler
-@on_event DOWNLOAD_REQUEST spawn @scripts_dir/download.sh %s \@proxy_url
-
# Load start handler
@on_event LOAD_START @set_status <span foreground="khaki">wait</span>
# Reset the keycmd on navigation
@@ -64,8 +63,8 @@ set authentication_handler = sync_spawn @scripts_dir/auth.py
# Load commit handlers
@on_event LOAD_COMMIT @set_status <span foreground="green">recv</span>
-# Userscript support. Add all scripts to $XDG_DATA_HOME/uzbl/userscripts
-#@on_event LOAD_COMMIT spawn @scripts_dir/userscripts.sh
+# Userscripts/per-site-settings. See the script and the example configuration for details
+#@on_event LOAD_COMMIT spawn @scripts_dir/per-site-settings.py @data_home/uzbl/per-site-settings
# Load finish handlers
@on_event LOAD_FINISH @set_status <span foreground="gold">done</span>
@@ -104,7 +103,9 @@ set name_section = <span foreground="khaki">\@[\@NAME]\@</span>
set status_section = <span foreground="orange">\@status_message</span>
set selected_section = <span foreground="#606060">\@[\@SELECTED_URI]\@</span>
-set status_format = <span font_family="monospace">@mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section</span>
+set download_section = <span foreground="white">\@downloads</span>
+
+set status_format = <span font_family="monospace">@mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section @download_section</span>
set title_format_long = \@keycmd_prompt \@raw_modcmd \@raw_keycmd \@TITLE - Uzbl browser <\@NAME> \@SELECTED_URI
@@ -120,6 +121,10 @@ set progress.pending =
set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}.@{WEBKIT_MICRO}) (@(+uname -sm)@ [@ARCH_UZBL]) (Commit @COMMIT)
+# === Configure cookie blacklist ========================================================
+# Drop google analytics tracking cookies
+#request BLACKLIST_COOKIE name '^__utm.$'
+
# === Key binding configuration ==============================================
# --- Internal modmapping and ignoring ---------------------------------------
@@ -190,7 +195,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 [ "$1" ]; then uzbl-browser -u "$1"; else echo "uri $(xclip -o | sed s/\\\@/%40/g)" > "$UZBL_FIFO"; fi' '\@SELECTED_URI'
# --- Keyboard bindings ------------------------------------------------------
@@ -254,14 +259,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
@@ -276,24 +281,24 @@ set ebind = @mode_bind global,-insert
@cbind gh = uri http://www.uzbl.org
# Yanking & pasting binds
-@cbind yu = sh 'echo -n $6 | xclip'
-@cbind yU = sh 'echo -n $8 | xclip' \@SELECTED_URI
-@cbind yy = sh 'echo -n $7 | xclip'
-@cbind yY = sh 'echo -n $8 | xclip' \@SELECTED_URI
+@cbind yu = sh 'echo -n "$UZBL_URI" | xclip'
+@cbind yU = sh 'echo -n "$1" | xclip' \@SELECTED_URI
+@cbind yy = sh 'echo -n "$UZBL_TITLE" | xclip'
+@cbind yY = sh 'echo -n "$1" | xclip' \@SELECTED_URI
# Clone current window
-@cbind c = sh 'uzbl-browser -u $6'
+@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
@@ -328,12 +333,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_NEXT `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 $6" > $4'
-@cbind gD = sh 'echo "event NEW_TAB_NEXT $6" > $4'
+@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
@@ -398,6 +403,8 @@ set stack = @mode_config stack
set default_mode = command
# === Post-load misc commands ================================================
+sync_spawn_exec @scripts_dir/load_cookies.sh
+sync_spawn_exec @scripts_dir/load_cookies.sh @data_home/uzbl/session-cookies.txt
# Set the "home" page.
set uri = uzbl.org/doesitwork/@COMMIT
diff --git a/examples/data/per-site-settings b/examples/data/per-site-settings
new file mode 100644
index 0000000..78bade4
--- /dev/null
+++ b/examples/data/per-site-settings
@@ -0,0 +1,3 @@
+.*
+ .*/\d+-\w+/(thread|subject|author|date).html
+ script @data_home/uzbl/scripts/pipermail.js
diff --git a/examples/data/plugins/cookies.py b/examples/data/plugins/cookies.py
new file mode 100644
index 0000000..c9fe2c3
--- /dev/null
+++ b/examples/data/plugins/cookies.py
@@ -0,0 +1,176 @@
+""" Basic cookie manager
+ forwards cookies to all other instances connected to the event manager"""
+
+from collections import defaultdict
+import os, re
+
+# these are symbolic names for the components of the cookie tuple
+symbolic = {'domain': 0, 'path':1, 'name':2, 'value':3, 'scheme':4, 'expires':5}
+
+_splitquoted = re.compile("( |\\\".*?\\\"|'.*?')")
+def splitquoted(text):
+ return [str(p.strip('\'"')) for p in _splitquoted.split(text) if p.strip()]
+
+# allows for partial cookies
+# ? allow wildcard in key
+def match(key, cookie):
+ for k,c in zip(key,cookie):
+ if k != c:
+ return False
+ return True
+
+class NullStore(object):
+ def add_cookie(self, rawcookie, cookie):
+ pass
+
+ def delete_cookie(self, rkey, key):
+ pass
+
+class ListStore(list):
+ def add_cookie(self, rawcookie, cookie):
+ self.append(rawcookie)
+
+ def delete_cookie(self, rkey, key):
+ self[:] = [x for x in self if not match(key, splitquoted(x))]
+
+class TextStore(object):
+ def __init__(self, filename):
+ self.filename = filename
+
+ def as_event(self, cookie):
+ if cookie[0].startswith("#HttpOnly_"):
+ domain = cookie[0][len("#HttpOnly_"):]
+ elif cookie[0].startswith('#'):
+ return None
+ else:
+ domain = cookie[0]
+ return (domain,
+ cookie[2],
+ cookie[5],
+ cookie[6],
+ 'https' if cookie[3] == 'TRUE' else 'http',
+ cookie[4])
+
+ def as_file(self, cookie):
+ return (cookie[0],
+ 'TRUE' if cookie[0].startswith('.') else 'FALSE',
+ cookie[1],
+ 'TRUE' if cookie[4] == 'https' else 'FALSE',
+ cookie[5],
+ cookie[2],
+ cookie[3])
+
+ def add_cookie(self, rawcookie, cookie):
+ assert len(cookie) == 6
+
+ # delete equal cookies (ignoring expire time, value and secure flag)
+ self.delete_cookie(None, cookie[:-3])
+
+ first = not os.path.exists(self.filename)
+ with open(self.filename, 'a') as f:
+ if first:
+ print >> f, "# HTTP Cookie File"
+ print >> f, '\t'.join(self.as_file(cookie))
+
+ def delete_cookie(self, rkey, key):
+ if not os.path.exists(self.filename):
+ return
+
+ # read all cookies
+ with open(self.filename, 'r') as f:
+ cookies = f.readlines()
+
+ # write those that don't match the cookie to delete
+ with open(self.filename, 'w') as f:
+ for l in cookies:
+ c = self.as_event(l.split('\t'))
+ if c is None or not match(key, c):
+ print >> f, l,
+
+xdg_data_home = os.environ.get('XDG_DATA_HOME', os.path.join(os.environ['HOME'], '.local/share'))
+DefaultStore = TextStore(os.path.join(xdg_data_home, 'uzbl/cookies.txt'))
+SessionStore = TextStore(os.path.join(xdg_data_home, 'uzbl/session-cookies.txt'))
+
+def match_list(_list, cookie):
+ for component, match in _list:
+ if match(cookie[component]) is not None:
+ return True
+ return False
+
+# accept a cookie only when:
+# a. there is no whitelist and the cookie is in the blacklist
+# b. the cookie is in the whitelist and not in the blacklist
+def accept_cookie(uzbl, cookie):
+ if uzbl.cookie_whitelist:
+ if match_list(uzbl.cookie_whitelist, cookie):
+ return not match_list(uzbl.cookie_blacklist, cookie)
+ return False
+
+ return not match_list(uzbl.cookie_blacklist, cookie)
+
+def expires_with_session(uzbl, cookie):
+ return cookie[5] == ''
+
+def get_recipents(uzbl):
+ """ get a list of Uzbl instances to send the cookie too. """
+ # This could be a lot more interesting
+ return [u for u in uzbl.parent.uzbls.values() if u is not uzbl]
+
+def get_store(uzbl, session=False):
+ if session:
+ return SessionStore
+ return DefaultStore
+
+def add_cookie(uzbl, cookie):
+ splitted = splitquoted(cookie)
+ if accept_cookie(uzbl, splitted):
+ for u in get_recipents(uzbl):
+ u.send('add_cookie %s' % cookie)
+
+ get_store(uzbl, expires_with_session(uzbl, splitted)).add_cookie(cookie, splitted)
+ else:
+ logger.debug('cookie %r is blacklisted' % splitted)
+ uzbl.send('delete_cookie %s' % cookie)
+
+def delete_cookie(uzbl, cookie):
+ for u in get_recipents(uzbl):
+ u.send('delete_cookie %s' % cookie)
+
+ splitted = splitquoted(cookie)
+ if len(splitted) == 6:
+ get_store(uzbl, expires_with_session(uzbl, splitted)).delete_cookie(cookie, splitted)
+ else:
+ for store in set([get_store(uzbl, session) for session in (True, False)]):
+ store.delete_cookie(cookie, splitted)
+
+# add a cookie matcher to a whitelist or a blacklist.
+# a matcher is a (component, re) tuple that matches a cookie when the
+# "component" part of the cookie matches the regular expression "re".
+# "component" is one of the keys defined in the variable "symbolic" above,
+# or the index of a component of a cookie tuple.
+def add_cookie_matcher(_list, arg):
+ component, regexp = splitquoted(arg)
+ try:
+ component = symbolic[component]
+ except KeyError:
+ component = int(component)
+ assert component <= 5
+ _list.append((component, re.compile(regexp).search))
+
+def blacklist(uzbl, arg):
+ add_cookie_matcher(uzbl.cookie_blacklist, arg)
+
+def whitelist(uzbl, arg):
+ add_cookie_matcher(uzbl.cookie_whitelist, arg)
+
+def init(uzbl):
+ connect_dict(uzbl, {
+ 'ADD_COOKIE': add_cookie,
+ 'DELETE_COOKIE': delete_cookie,
+ 'BLACKLIST_COOKIE': blacklist,
+ 'WHITELIST_COOKIE': whitelist
+ })
+ export_dict(uzbl, {
+ 'cookie_blacklist' : [],
+ 'cookie_whitelist' : []
+ })
diff --git a/examples/data/plugins/downloads.py b/examples/data/plugins/downloads.py
new file mode 100644
index 0000000..7bf32d7
--- /dev/null
+++ b/examples/data/plugins/downloads.py
@@ -0,0 +1,69 @@
+# this plugin does a very simple display of download progress. to use it, add
+# @downloads to your status_format.
+
+import os
+ACTIVE_DOWNLOADS = {}
+
+# after a download's status has changed this is called to update the status bar
+def update_download_section(uzbl):
+ global ACTIVE_DOWNLOADS
+
+ if len(ACTIVE_DOWNLOADS):
+ # add a newline before we list downloads
+ result = '&#10;downloads:'
+ for path in ACTIVE_DOWNLOADS:
+ # add each download
+ fn = os.path.basename(path)
+ progress, = ACTIVE_DOWNLOADS[path]
+
+ dl = " %s (%d%%)" % (fn, progress * 100)
+
+ # replace entities to make sure we don't break our markup
+ # (this could be done with an @[]@ expansion in uzbl, but then we
+ # can't use the &#10; above to make a new line)
+ dl = dl.replace("&", "&amp;").replace("<", "&lt;")
+ result += dl
+ else:
+ result = ''
+
+ # and the result gets saved to an uzbl variable that can be used in
+ # status_format
+ if uzbl.config.get('downloads', '') != result:
+ uzbl.config['downloads'] = result
+
+def download_started(uzbl, destination_path):
+ # add to the list of active downloads
+ global ACTIVE_DOWNLOADS
+ ACTIVE_DOWNLOADS[destination_path] = (0.0,)
+
+ # update the progress
+ update_download_section(uzbl)
+
+def download_progress(uzbl, args):
+ # parse the arguments
+ s = args.rindex(' ')
+ destination_path = args[:s]
+ progress = float(args[s+1:])
+
+ # update the progress
+ global ACTIVE_DOWNLOADS
+ ACTIVE_DOWNLOADS[destination_path] = (progress,)
+
+ # update the status bar variable
+ update_download_section(uzbl)
+
+def download_complete(uzbl, destination_path):
+ # remove from the list of active downloads
+ global ACTIVE_DOWNLOADS
+ del ACTIVE_DOWNLOADS[destination_path]
+
+ # update the status bar variable
+ update_download_section(uzbl)
+
+# plugin init hook
+def init(uzbl):
+ connect_dict(uzbl, {
+ 'DOWNLOAD_STARTED': download_started,
+ 'DOWNLOAD_PROGRESS': download_progress,
+ 'DOWNLOAD_COMPLETE': download_complete,
+ })
diff --git a/examples/data/scripts/auth.py b/examples/data/scripts/auth.py
index 9c1b4fc..592a2c6 100755
--- a/examples/data/scripts/auth.py
+++ b/examples/data/scripts/auth.py
@@ -46,7 +46,7 @@ def getText(authInfo, authHost, authRealm):
return rv, output
if __name__ == '__main__':
- rv, output = getText(sys.argv[8], sys.argv[9], sys.argv[10])
+ rv, output = getText(sys.argv[1], sys.argv[2], sys.argv[3])
if (rv == gtk.RESPONSE_OK):
print output;
else:
diff --git a/examples/data/scripts/download.sh b/examples/data/scripts/download.sh
index 606aa62..c410ad2 100755
--- a/examples/data/scripts/download.sh
+++ b/examples/data/scripts/download.sh
@@ -1,26 +1,25 @@
#!/bin/sh
-# just an example of how you could handle your downloads
-# try some pattern matching on the uri to determine what we should do
+#
+# uzbl's example configuration sets this script up as its download_handler.
+# when uzbl starts a download it runs this script.
+# if the script prints a file path to stdout, uzbl will save the download to
+# that path.
+# if nothing is printed to stdout, the download will be cancelled.
-. $UZBL_UTIL_DIR/uzbl-args.sh
. $UZBL_UTIL_DIR/uzbl-dir.sh
-# Some sites block the default wget --user-agent..
-GET="wget --user-agent=Firefox --content-disposition --load-cookies=$UZBL_COOKIE_JAR"
+# the URL that is being downloaded
+uri=$1
-url="$1"
+# a filename suggested by the server or based on the URL
+suggested_filename=${2:-$(echo "$uri" | sed 's/\W/-/g')}
-http_proxy="$2"
-export http_proxy
+# the mimetype of the file being downloaded
+content_type=$3
-if [ -z "$url" ]; then
- echo "you must supply a url! ($url)"
- exit 1
-fi
+# the size of the downloaded file in bytes. this is not always accurate, since
+# the server might not have sent a size with its response headers.
+total_size=$4
-# only changes the dir for the $get sub process
-if echo "$url" | grep -E '.*\.torrent' >/dev/null; then
- ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url")
-else
- ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url")
-fi
+# just save the file to the default directory with the suggested name
+echo $UZBL_DOWNLOAD_DIR/$suggested_filename
diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh
index c8ded84..d1560bf 100755
--- a/examples/data/scripts/follow.sh
+++ b/examples/data/scripts/follow.sh
@@ -3,8 +3,6 @@
# This script is just a wrapper around follow.js that lets us change uzbl's mode
# after a link is selected.
-. "$UZBL_UTIL_DIR"/uzbl-args.sh
-
# 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
diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh
index b2e61ec..c6822e6 100755
--- a/examples/data/scripts/formfiller.sh
+++ b/examples/data/scripts/formfiller.sh
@@ -45,7 +45,6 @@ DMENU_OPTIONS="vertical resize"
. $UZBL_UTIL_DIR/dmenu.sh
. $UZBL_UTIL_DIR/editor.sh
-. $UZBL_UTIL_DIR/uzbl-args.sh
. $UZBL_UTIL_DIR/uzbl-dir.sh
RAND=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -c 1-5)
@@ -56,7 +55,7 @@ MODELINE="> vim:ft=formfiller"
action=$1
-domain=$(echo $UZBL_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
action="new"
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 0561fe9..266d65d 100755
--- a/examples/data/scripts/history.sh
+++ b/examples/data/scripts/history.sh
@@ -4,4 +4,4 @@
[ -w "$UZBL_HISTORY_FILE" ] || [ ! -a "$UZBL_HISTORY_FILE" ] || exit 1
-echo $(date +'%Y-%m-%d %H:%M:%S')" $6 $7" >> $UZBL_HISTORY_FILE
+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 24f7241..f67e67a 100755
--- a/examples/data/scripts/insert_bookmark.sh
+++ b/examples/data/scripts/insert_bookmark.sh
@@ -1,6 +1,5 @@
#!/bin/sh
-. "$UZBL_UTIL_DIR"/uzbl-args.sh
. "$UZBL_UTIL_DIR"/uzbl-dir.sh
[ -d "$UZBL_DATA_DIR" ] || exit 1
@@ -8,9 +7,9 @@
which zenity >/dev/null 2>&1 || exit 2
-tags=$(zenity --entry --text="Enter space-separated tags for bookmark $UZBL_URL:")
+tags=$(zenity --entry --text="Enter space-separated tags for bookmark $UZBL_URI:")
exitstatus=$?
[ $exitstatus -eq 0 ] || exit $exitstatus
# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags
-echo "$UZBL_URL $tags" >> "$UZBL_BOOKMARKS_FILE"
+echo "$UZBL_URI $tags" >> "$UZBL_BOOKMARKS_FILE"
diff --git a/examples/data/scripts/load_cookies.sh b/examples/data/scripts/load_cookies.sh
new file mode 100755
index 0000000..17ec2ad
--- /dev/null
+++ b/examples/data/scripts/load_cookies.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+if [ "$1" != "" ]; then
+ cookie_file=$1
+else
+ cookie_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/cookies.txt
+fi
+
+awk -F \\t '
+BEGIN {
+ scheme["TRUE"] = "https";
+ scheme["FALSE"] = "http";
+}
+$0 ~ /^#HttpOnly_/ {
+printf("add_cookie \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", substr($1,length("#HttpOnly_"),length($1)), $3, $6, $7, scheme[$4], $5)
+}
+$0 !~ /^#/ {
+printf("add_cookie \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", $1, $3, $6, $7, scheme[$4], $5)
+}
+' $cookie_file
diff --git a/examples/data/scripts/load_url_from_bookmarks.sh b/examples/data/scripts/load_url_from_bookmarks.sh
index 9346526..a5d9586 100755
--- a/examples/data/scripts/load_url_from_bookmarks.sh
+++ b/examples/data/scripts/load_url_from_bookmarks.sh
@@ -6,7 +6,6 @@ DMENU_SCHEME="bookmarks"
DMENU_OPTIONS="xmms vertical resize"
. "$UZBL_UTIL_DIR"/dmenu.sh
-. "$UZBL_UTIL_DIR"/uzbl-args.sh
. "$UZBL_UTIL_DIR"/uzbl-dir.sh
[ -r "$UZBL_BOOKMARKS_FILE" ] || exit 1
diff --git a/examples/data/scripts/load_url_from_history.sh b/examples/data/scripts/load_url_from_history.sh
index 4499e7f..59ad492 100755
--- a/examples/data/scripts/load_url_from_history.sh
+++ b/examples/data/scripts/load_url_from_history.sh
@@ -4,7 +4,6 @@ DMENU_SCHEME="history"
DMENU_OPTIONS="xmms vertical resize"
. "$UZBL_UTIL_DIR"/dmenu.sh
-. "$UZBL_UTIL_DIR"/uzbl-args.sh
. "$UZBL_UTIL_DIR"/uzbl-dir.sh
[ -r "$UZBL_HISTORY_FILE" ] || exit 1
@@ -13,7 +12,7 @@ DMENU_OPTIONS="xmms vertical resize"
# 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)
+ goto=$( (echo $current; awk '{print $3}' "$UZBL_HISTORY_FILE" | grep -v "^$current\$" | sort -u) | $DMENU)
else
# 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.
diff --git a/examples/data/scripts/per-site-settings.py b/examples/data/scripts/per-site-settings.py
new file mode 100755
index 0000000..89df4e6
--- /dev/null
+++ b/examples/data/scripts/per-site-settings.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# Per-site settings plugin
+
+# Example configuration usage:
+#
+# @on_event LOAD_COMMIT spawn @scripts_dir/per-site-settings.py @data_home/uzbl/per-site-settings
+
+# Format of the settings file:
+#
+# <url>
+# <path>
+# <command>
+#
+# - url
+# May either be a regex, or literal. If literal, it will block any
+# subdomains as well.
+# - path
+# May either be a regex, or literal. If literal, it will block any
+# decendent paths as well.
+# - command
+# Given to uzbl verbatim.
+#
+# Matches are attempted on a literal match first.
+#
+# Any of the specifications can be repeated and acts as a fall-through to the
+# next level. Make sure indentation lines up locally. Any indentation addition
+# is considered as a fall through to the next level and any decrease is
+# considered a pop back (zero is always urls). This works because it's only 3
+# deep. Four and we'd have to keep track of things.
+
+import os
+import re
+import socket
+import stat
+import subprocess
+import tempfile
+import urlparse
+import sys
+
+
+def match_url(url, patt):
+ return url.endswith(patt) or re.match(patt, url)
+
+
+def match_path(path, patt):
+ return path.startswith(patt) or re.match(patt, path)
+
+
+def grep_url(url, path, fin):
+ entries = []
+ cur_indent = 0
+ passing = [False, False]
+ # 0 == url
+ # 1 == path
+ # 2 == command
+ state = 0
+ for line in fin:
+ raw = line.strip()
+
+ indent = len(line) - len(raw) - 1
+ if not indent:
+ # Reset state
+ passing = [False, False]
+ state = 0
+ else:
+ # previous level
+ if indent < cur_indent:
+ if state == 1:
+ passing[0] = False
+ elif state == 2:
+ passing[1] = False
+ state -= 1
+ # next level
+ elif cur_indent < indent:
+ state += 1
+
+ # parse the line
+ if state == 0:
+ if not passing[0] and match_url(url, raw):
+ passing[0] = True
+ elif state == 1 and passing[0]:
+ if not passing[1] and match_path(path, raw):
+ passing[1] = True
+ elif state == 2 and passing[1]:
+ entries.append(raw)
+
+ cur_indent = indent
+
+ return entries
+
+
+def write_to_socket(commands, sockpath):
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(sockpath)
+ for command in commands:
+ sock.send(command)
+ sock.close()
+
+
+if __name__ == '__main__':
+ sockpath = os.environ['UZBL_SOCKET']
+ url = urlparse.urlparse(os.environ['UZBL_URI'])
+ filepath = sys.argv[1]
+
+ mode = os.stat(filepath)[stat.ST_MODE]
+
+ if mode & stat.S_IEXEC:
+ fin = tempfile.TemporaryFile()
+ subprocess.Popen([filepath], stdout=fin).wait()
+ else:
+ fin = open(filepath, 'r')
+
+ commands = grep_url(url.hostname, url.path, fin)
+
+ fin.close()
+
+ write_to_socket(commands, sockpath)
diff --git a/examples/data/scripts/pipermail.js b/examples/data/scripts/pipermail.js
new file mode 100644
index 0000000..5ec4aa4
--- /dev/null
+++ b/examples/data/scripts/pipermail.js
@@ -0,0 +1,71 @@
+// this is a userscript inspired by "Pipermail Navigation Links" by Michael
+// Stone <http://userscripts.org/scripts/show/3174>.
+
+// it adds previous month/next month navigation links in pipermail mailing
+// list archives.
+
+// we wrap the whole thing in a function (that gets called immediately) so
+// that this script doesn't interfere with any javascript in the page.
+(function() {
+
+// figure out what page we're looking at right now
+var urlparts = document.location.toString().split("/");
+var currView = urlparts[urlparts.length-1].split("#")[0];
+var currDate = urlparts[urlparts.length-2].split("-");
+
+// figure out the URLs to the next month and previous month
+var months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July',
+ 'August', 'September', 'October', 'November', 'December' ];
+
+var thisMonth = currDate[1];
+var prevMonth;
+var nextMonth;
+
+var thisYear = currDate[0];
+var prevYear = thisYear;
+var nextYear = thisYear;
+
+if(thisMonth == 'January') {
+ prevMonth = "December";
+ nextMonth = "February";
+ prevYear = parseInt(thisYear) - 1;
+} else if(thisMonth == 'December') {
+ prevMonth = "November";
+ nextMonth = "January";
+ nextYear = parseInt(thisYear) + 1;
+} else {
+ var monthNum = months.indexOf(thisMonth);
+ prevMonth = months[monthNum - 1];
+ nextMonth = months[monthNum + 1];
+}
+
+var prevHref = "../" + prevYear + "-" + prevMonth + "/" + currView;
+var nextHref = "../" + nextYear + "-" + nextMonth + "/" + currView;
+
+// find the navigation header and footer
+var selector = "a[href='date.html#start']";
+
+// if we're on a "date" page then the date link isn't displayed
+if(currView == "date.html")
+ selector = "a[href='author.html#start']";
+
+var navLinks = document.querySelectorAll(selector);
+
+// append the prev/next links to the navigation header and footer
+for(var i = 0; i < navLinks.length; i++) {
+ var victim = navLinks[i].parentNode;
+
+ var prevEl = document.createElement("a");
+ prevEl.textContent = "[ prev month ]";
+ prevEl.href = prevHref;
+
+ var nextEl = document.createElement("a");
+ nextEl.textContent = "[ next month ]";
+ nextEl.href = nextHref;
+
+ victim.appendChild(prevEl);
+ victim.appendChild(document.createTextNode(" "));
+ victim.appendChild(nextEl);
+}
+
+})();
diff --git a/examples/data/scripts/scheme.py b/examples/data/scripts/scheme.py
index 0916466..4b0b7ca 100755
--- a/examples/data/scripts/scheme.py
+++ b/examples/data/scripts/scheme.py
@@ -13,7 +13,7 @@ def detach_open(cmd):
print 'USED'
if __name__ == '__main__':
- uri = sys.argv[8]
+ uri = sys.argv[1]
u = urlparse.urlparse(uri)
if u.scheme == 'mailto':
detach_open(['xterm', '-e', 'mail', u.path])
diff --git a/examples/data/scripts/session.sh b/examples/data/scripts/session.sh
index 203cd52..ee09cf2 100755
--- a/examples/data/scripts/session.sh
+++ b/examples/data/scripts/session.sh
@@ -1,14 +1,17 @@
#!/bin/sh
#
# Very simple session manager for uzbl-browser.
-# To use, add a line like 'bind quit = spawn @scripts_dir/session.sh endsession'
-# to your config.
-# To restore the session, run this script with the argument "launch". An
-# instance of uzbl-browser will be launched for each stored url.
+# 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 called with "endsession" as the argument, it will backup
-# $UZBL_SESSION_FILE, look for fifos in $UZBL_FIFO_DIR and instruct each of them
-# to store its current url in $UZBL_SESSION_FILE and terminate.
+# 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.
@@ -27,14 +30,13 @@ fi
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
- . "$UZBL_UTIL_DIR"/uzbl-args.sh
-fi
-
-scriptfile=$0 # this script
+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 "$UZBL_SESSION_FILE")
@@ -43,8 +45,8 @@ case $act in
else
for url in $urls; do
$UZBL --uri "$url" &
- disown
done
+ mv "$UZBL_SESSION_FILE" "$UZBL_SESSION_FILE~"
fi
;;
@@ -53,18 +55,17 @@ case $act in
echo "session manager: endinstance must be called from uzbl"
exit 1
fi
- [ "$UZBL_URL" != "(null)" ] && echo "$UZBL_URL" >> "$UZBL_SESSION_FILE"
+ [ "$UZBL_URI" != "(null)" ] && echo "$UZBL_URI" >> "$UZBL_SESSION_FILE"
echo exit > "$UZBL_FIFO"
;;
"endsession" )
- mv "$UZBL_SESSION_FILE" "$UZBL_SESSION_FILE~"
for fifo in "$UZBL_FIFO_DIR"/uzbl_fifo_*; do
if [ "$fifo" != "$UZBL_FIFO" ]; then
echo "spawn $scriptfile endinstance" > "$fifo"
fi
done
- echo "spawn $scriptfile endinstance" > "$UZBL_FIFO"
+ [ -z "$UZBL_FIFO" ] || echo "spawn $scriptfile endinstance" > "$UZBL_FIFO"
;;
* )
diff --git a/examples/data/scripts/userscript.sh b/examples/data/scripts/userscript.sh
deleted file mode 100755
index 33a24ae..0000000
--- a/examples/data/scripts/userscript.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-
-if [ $# = "3" ]
-then
- fifo="$1"
- url="$2"
- SCRIPT="$3"
-else
- fifo="$4"
- url="$6"
- SCRIPT="$8"
-fi
-
-# Extract metadata chunk
-META="`sed -ne '/^\s*\/\/\s*==UserScript==\s*$/,/^\s*\/\/\s*==\/UserScript==\s*$/p' "$SCRIPT"`"
-SHOULD_RUN=false # Assume this script will not be included
-# Loop over all include rules
-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
- SHOULD_RUN=true
- break
- fi
-done
-
-# Loop over all exclude rules
-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
- SHOULD_RUN=false
- break
- fi
-done
-
-# Run the script
-if [ $SHOULD_RUN = true ]; then
- echo "script '$SCRIPT'" > "$fifo"
-fi
diff --git a/examples/data/scripts/userscripts.sh b/examples/data/scripts/userscripts.sh
deleted file mode 100755
index 8896224..0000000
--- a/examples/data/scripts/userscripts.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-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"
-done
diff --git a/examples/data/scripts/util/dmenu.sh b/examples/data/scripts/util/dmenu.sh
index f789178..354d7d1 100644
--- a/examples/data/scripts/util/dmenu.sh
+++ b/examples/data/scripts/util/dmenu.sh
@@ -60,14 +60,20 @@ fi
if dmenu --help 2>&1 | grep -q '\[-xs\]'; then
DMENU_XMMS_ARGS="-xs"
DMENU_HAS_XMMS=1
+fi
- if echo $DMENU_OPTIONS | grep -q -w 'xmms'; then
- DMENU_ARGS="$DMENU_ARGS $DMENU_XMMS_ARGS"
- fi
+# Detect the tok patch
+if dmenu --help 2>&1 | grep -q '\[-t\]'; then
+ DMENU_XMMS_ARGS="-t"
+ DMENU_HAS_XMMS=1
+fi
+
+if echo $DMENU_OPTIONS | grep -q -w 'xmms'; then
+ DMENU_ARGS="$DMENU_ARGS $DMENU_XMMS_ARGS"
fi
# Detect the vertical patch
-if dmenu --help 2>&1 | grep -q '\[-l <lines>\]'; then
+if dmenu --help 2>&1 | grep -q '\[-l <\?lines>\?\]'; then
# Default to 10 lines
if [ -z "$DMENU_LINES" ]; then
DMENU_LINES=10
diff --git a/examples/data/scripts/util/uzbl-args.sh b/examples/data/scripts/util/uzbl-args.sh
deleted file mode 100644
index 7a3dbe5..0000000
--- a/examples/data/scripts/util/uzbl-args.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-# Arguments from uzbl
-
-UZBL_CONFIG=$1
-shift
-UZBL_PID=$1
-shift
-UZBL_XID=$1
-shift
-UZBL_FIFO=$1
-shift
-UZBL_SOCKET=$1
-shift
-UZBL_URL=$1
-shift
-UZBL_TITLE=$1
-shift
diff --git a/examples/data/scripts/util/uzbl-window.sh b/examples/data/scripts/util/uzbl-window.sh
index b2771e4..a7e92eb 100644
--- a/examples/data/scripts/util/uzbl-window.sh
+++ b/examples/data/scripts/util/uzbl-window.sh
@@ -1,12 +1,6 @@
#!/bin/sh
# uzbl window detection
-if [ -z "$UZBL_XID" ]; then
- echo "Error: UZBL_XID not set"
- echo "Please source uzbl-args.sh first"
- exit 1
-fi
-
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 | \
diff --git a/examples/data/scripts/uzbl-tabbed b/examples/data/scripts/uzbl-tabbed
index 9e5d715..0086c04 100755
--- a/examples/data/scripts/uzbl-tabbed
+++ b/examples/data/scripts/uzbl-tabbed
@@ -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)
diff --git a/misc/env.sh b/misc/env.sh
index 0dfedfa..68377f2 100755
--- a/misc/env.sh
+++ b/misc/env.sh
@@ -10,7 +10,7 @@
# Maybe we should spawn processes from here with an 'exec' at the end?
# Re-define our home location inside the sandbox dir.
-export HOME=./sandbox/home
+export HOME=$(pwd)/sandbox/home
# Export default XDG_{DATA,CACHE,..}_HOME locations inside the sandbox
# directory according to defaults in the xdg specification.
@@ -20,4 +20,4 @@ export XDG_CACHE_HOME=$HOME/.cache
export XDG_CONFIG_HOME=$HOME/.config
# Needed to run uzbl-browser etc from here.
-export PATH="./sandbox/usr/local/bin:$PATH"
+export PATH="$(pwd)/sandbox/usr/local/bin:$PATH"
diff --git a/src/callbacks.c b/src/callbacks.c
index f596472..673979e 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -324,7 +324,8 @@ cmd_scrollbars_visibility() {
uzbl.gui.bar_v = gtk_range_get_adjustment (GTK_RANGE (uzbl.gui.scbar_v));
uzbl.gui.bar_h = gtk_range_get_adjustment (GTK_RANGE (uzbl.gui.scbar_h));
}
- gtk_widget_set_scroll_adjustments (GTK_WIDGET (uzbl.gui.web_view), uzbl.gui.bar_h, uzbl.gui.bar_v);
+
+ set_webview_scroll_adjustments();
}
/* requires webkit >=1.1.14 */
@@ -411,6 +412,7 @@ 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
@@ -436,6 +438,7 @@ load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
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;
@@ -743,41 +746,139 @@ create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer us
(void) web_view;
(void) frame;
(void) user_data;
- if (uzbl.state.selected_url != NULL) {
- if (uzbl.state.verbose)
- printf("\nNew web view -> %s\n", uzbl.state.selected_url);
- if (strncmp(uzbl.state.selected_url, "javascript:", strlen("javascript:")) == 0) {
- WebKitWebView* new_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ if (uzbl.state.verbose)
+ printf("New web view -> javascript link...\n");
- g_signal_connect (new_view, "web-view-ready",
- G_CALLBACK(create_web_view_js_cb), NULL);
+ WebKitWebView* new_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- return new_view;
- }
- else
- send_event(NEW_WINDOW, uzbl.state.selected_url, NULL);
+ g_signal_connect (new_view, "web-view-ready",
+ G_CALLBACK(create_web_view_js_cb), NULL);
+ return new_view;
+}
- } else {
- if (uzbl.state.verbose)
- printf("New web view -> javascript link...\n");
+void
+download_progress_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_data) {
+ (void) pspec; (void) user_data;
+
+ gdouble progress;
+ g_object_get(download, "progress", &progress, NULL);
- WebKitWebView* new_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ const gchar *dest_uri = webkit_download_get_destination_uri(download);
+ const gchar *dest_path = dest_uri + strlen("file://");
- g_signal_connect (new_view, "web-view-ready",
- G_CALLBACK(create_web_view_js_cb), NULL);
- return new_view;
+ gchar *details = g_strdup_printf("%s %.2lf", dest_path, progress);
+ send_event(DOWNLOAD_PROGRESS, details, NULL);
+ g_free(details);
+}
+
+void
+download_status_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_data) {
+ (void) pspec; (void) user_data;
+
+ WebKitDownloadStatus status;
+ g_object_get(download, "status", &status, NULL);
+
+ switch(status) {
+ case WEBKIT_DOWNLOAD_STATUS_CREATED:
+ case WEBKIT_DOWNLOAD_STATUS_STARTED:
+ case WEBKIT_DOWNLOAD_STATUS_ERROR:
+ case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
+ return; /* these are irrelevant */
+ case WEBKIT_DOWNLOAD_STATUS_FINISHED:
+ {
+ const gchar *dest_uri = webkit_download_get_destination_uri(download);
+ const gchar *dest_path = dest_uri + strlen("file://");
+ send_event(DOWNLOAD_COMPLETE, dest_path, NULL);
+ }
}
- return NULL;
}
gboolean
-download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
- (void) web_view;
- (void) user_data;
+download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_data) {
+ (void) web_view; (void) user_data;
- send_event(DOWNLOAD_REQ, webkit_download_get_uri ((WebKitDownload*)download), NULL);
- return (FALSE);
+ /* get the URI being downloaded */
+ const gchar *uri = webkit_download_get_uri(download);
+
+ if (uzbl.state.verbose)
+ printf("Download requested -> %s\n", uri);
+
+ if (!uzbl.behave.download_handler) {
+ webkit_download_cancel(download);
+ return FALSE; /* reject downloads when there's no download handler */
+ }
+
+ /* get a reasonable suggestion for a filename */
+ const gchar *suggested_filename;
+ g_object_get(download, "suggested-filename", &suggested_filename, NULL);
+
+ /* get the mimetype of the download */
+ const gchar *content_type;
+ WebKitNetworkResponse *r = webkit_download_get_network_response(download);
+ /* downloads can be initiated from the context menu, in that case there is
+ no network response yet and trying to get one would crash. */
+ if(WEBKIT_IS_NETWORK_RESPONSE(r)) {
+ SoupMessage *m = webkit_network_response_get_message(r);
+ SoupMessageHeaders *h;
+ g_object_get(m, "response-headers", &h, NULL);
+ content_type = soup_message_headers_get_one(h, "Content-Type");
+ } else
+ content_type = "application/octet-stream";
+
+ /* get the filesize of the download, as given by the server.
+ (this may be inaccurate, there's nothing we can do about that.) */
+ unsigned int total_size = webkit_download_get_total_size(download);
+
+ gchar *ev = g_strdup_printf("'%s' '%s' '%s' %d", uri, suggested_filename,
+ content_type, total_size);
+ run_handler(uzbl.behave.download_handler, ev);
+ g_free(ev);
+
+ /* no response, cancel the download */
+ if(!uzbl.comm.sync_stdout) {
+ webkit_download_cancel(download);
+ return FALSE;
+ }
+
+ /* no response, cancel the download */
+ if(uzbl.comm.sync_stdout[0] == 0) {
+ webkit_download_cancel(download);
+ uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+ return FALSE;
+ }
+
+ /* we got a response, it's the path we should download the file to */
+ gchar *destination_path = uzbl.comm.sync_stdout;
+ uzbl.comm.sync_stdout = NULL;
+
+ /* presumably people don't need newlines in their filenames. */
+ char *p = strchr(destination_path, '\n');
+ if ( p != NULL ) *p = '\0';
+
+ /* set up progress callbacks */
+ g_signal_connect(download, "notify::status", G_CALLBACK(download_status_cb), NULL);
+ g_signal_connect(download, "notify::progress", G_CALLBACK(download_progress_cb), NULL);
+
+ /* convert relative path to absolute path */
+ if(destination_path[0] != '/') {
+ gchar *rel_path = destination_path;
+ gchar *cwd = g_get_current_dir();
+ destination_path = g_strconcat(cwd, "/", destination_path, NULL);
+ g_free(cwd);
+ g_free(rel_path);
+ }
+
+ send_event(DOWNLOAD_STARTED, destination_path, NULL);
+
+ /* convert absolute path to file:// URI */
+ gchar *destination_uri = g_strconcat("file://", destination_path, NULL);
+ g_free(destination_path);
+
+ webkit_download_set_destination_uri(download, destination_uri);
+ g_free(destination_uri);
+
+ return TRUE;
}
gboolean
@@ -852,14 +953,14 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
(context & mi->context)) {
if(mi->issep) {
item = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(m), item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), item);
gtk_widget_show(item);
}
else {
item = gtk_menu_item_new_with_label(mi->name);
g_signal_connect(item, "activate",
G_CALLBACK(run_menu_command), mi->cmd);
- gtk_menu_append(GTK_MENU(m), item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), item);
gtk_widget_show(item);
}
hit++;
@@ -870,14 +971,14 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
!hit) {
if(mi->issep) {
item = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(m), item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), item);
gtk_widget_show(item);
}
else {
item = gtk_menu_item_new_with_label(mi->name);
g_signal_connect(item, "activate",
G_CALLBACK(run_menu_command), mi->cmd);
- gtk_menu_append(GTK_MENU(m), item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), item);
gtk_widget_show(item);
}
}
diff --git a/src/callbacks.h b/src/callbacks.h
index a4258f2..40fa80d 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -133,9 +133,6 @@ cmd_load_start();
WebKitWebSettings*
view_settings();
-gboolean
-download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data);
-
void
toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result);
@@ -197,7 +194,7 @@ request_starting_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebRes
create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data);
gboolean
-download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data);
+download_cb (WebKitWebView *web_view, WebKitDownload *download, gpointer user_data);
void
populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c);
diff --git a/src/cookie-jar.c b/src/cookie-jar.c
index f2e340b..626e454 100644
--- a/src/cookie-jar.c
+++ b/src/cookie-jar.c
@@ -12,6 +12,7 @@
#include "cookie-jar.h"
#include "uzbl-core.h"
+#include "events.h"
static void
uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data);
@@ -38,6 +39,8 @@ soup_cookie_jar_socket_init(UzblCookieJar *jar) {
jar->handler = NULL;
jar->socket_path = NULL;
jar->connection_fd = -1;
+ jar->in_get_callback = 0;
+ jar->in_manual_add = 0;
}
static void
@@ -141,7 +144,7 @@ request_started(SoupSessionFeature *feature, SoupSession *session,
static void
changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
- (void) old_cookie;
+ SoupCookie * cookie = new_cookie ? new_cookie : old_cookie;
UzblCookieJar *uzbl_jar = UZBL_COOKIE_JAR(jar);
@@ -155,6 +158,25 @@ changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
if(uzbl_jar->in_get_callback)
return;
+ gchar *scheme = cookie->secure ? "https" : "http";
+
+ /* send a ADD or DELETE -_COOKIE event depending on what have changed */
+ if(!uzbl_jar->in_manual_add) {
+ gchar *expires = NULL;
+ if(cookie->expires)
+ expires = g_strdup_printf ("%d", soup_date_to_time_t (cookie->expires));
+
+ gchar * eventstr = g_strdup_printf ("'%s' '%s' '%s' '%s' '%s' '%s'",
+ cookie->domain, cookie->path, cookie->name, cookie->value, scheme, expires?expires:"");
+ if(new_cookie)
+ send_event(ADD_COOKIE, eventstr, NULL);
+ else
+ send_event(DELETE_COOKIE, eventstr, NULL);
+ g_free(eventstr);
+ if(expires)
+ g_free(expires);
+ }
+
/* 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)
@@ -162,8 +184,6 @@ changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
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);
diff --git a/src/cookie-jar.h b/src/cookie-jar.h
index 80af00e..f3e3733 100644
--- a/src/cookie-jar.h
+++ b/src/cookie-jar.h
@@ -16,6 +16,7 @@ typedef struct {
int connection_fd;
gboolean in_get_callback;
+ gboolean in_manual_add;
} UzblCookieJar;
typedef struct {
diff --git a/src/events.c b/src/events.c
index 20e3675..baaf8f3 100644
--- a/src/events.c
+++ b/src/events.c
@@ -22,7 +22,6 @@ const char *event_table[LAST_EVENT] = {
"REQUEST_STARTING" ,
"KEY_PRESS" ,
"KEY_RELEASE" ,
- "DOWNLOAD_REQUEST" ,
"COMMAND_EXECUTED" ,
"LINK_HOVER" ,
"TITLE_CHANGED" ,
@@ -45,10 +44,14 @@ const char *event_table[LAST_EVENT] = {
"PLUG_CREATED" ,
"COMMAND_ERROR" ,
"BUILTINS" ,
- "PTR_MOVE"
"PTR_MOVE" ,
"SCROLL_VERT" ,
- "SCROLL_HORIZ"
+ "SCROLL_HORIZ" ,
+ "DOWNLOAD_STARTED" ,
+ "DOWNLOAD_PROGRESS",
+ "DOWNLOAD_COMPLETE",
+ "ADD_COOKIE" ,
+ "DELETE_COOKIE"
};
void
@@ -136,24 +139,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) {
@@ -163,7 +158,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/events.h b/src/events.h
index bc7960d..3c7b933 100644
--- a/src/events.h
+++ b/src/events.h
@@ -7,7 +7,7 @@
enum event_type {
LOAD_START, LOAD_COMMIT, LOAD_FINISH, LOAD_ERROR,
REQUEST_STARTING,
- KEY_PRESS, KEY_RELEASE, DOWNLOAD_REQ, COMMAND_EXECUTED,
+ KEY_PRESS, KEY_RELEASE, COMMAND_EXECUTED,
LINK_HOVER, TITLE_CHANGED, GEOMETRY_CHANGED,
WEBINSPECTOR, NEW_WINDOW, SELECTION_CHANGED,
VARIABLE_SET, FIFO_SET, SOCKET_SET,
@@ -16,6 +16,8 @@ enum event_type {
FOCUS_LOST, FOCUS_GAINED, FILE_INCLUDED,
PLUG_CREATED, COMMAND_ERROR, BUILTINS,
PTR_MOVE, SCROLL_VERT, SCROLL_HORIZ,
+ DOWNLOAD_STARTED, DOWNLOAD_PROGRESS, DOWNLOAD_COMPLETE,
+ ADD_COOKIE, DELETE_COOKIE,
/* must be last entry */
LAST_EVENT
diff --git a/src/uzbl-browser b/src/uzbl-browser
index 88d3742..faa2829 100755
--- a/src/uzbl-browser
+++ b/src/uzbl-browser
@@ -8,6 +8,8 @@
# to your $XDG_DATA_HOME/uzbl/scripts/ and edit them
PREFIX=/usr/local
+export PREFIX
+
EXAMPLES=$PREFIX/share/uzbl/examples
XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share}
@@ -66,7 +68,7 @@ fi
# 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
- ${UZBL_COOKIE_DAEMON:-uzbl-cookie-manager}
+# ${UZBL_COOKIE_DAEMON:-uzbl-cookie-manager}
#fi
# uzbl-event-manager will exit if one is already running.
diff --git a/src/uzbl-core.c b/src/uzbl-core.c
index cb20fd7..592a8dd 100644
--- a/src/uzbl-core.c
+++ b/src/uzbl-core.c
@@ -93,6 +93,7 @@ const struct var_name_to_ptr_t {
{ "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_set_cookie_handler)},
{ "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)},
{ "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)},
+ { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
{ "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
{ "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
{ "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
@@ -414,36 +415,6 @@ find_existing_file(gchar* path_list) {
return NULL;
}
-
-/* Returns a new string with environment $variables expanded */
-gchar*
-parseenv (gchar* string) {
- extern char** environ;
- gchar* tmpstr = NULL, * out;
- int i = 0;
-
- if(!string)
- return NULL;
-
- out = g_strdup(string);
- while (environ[i] != NULL) {
- gchar** env = g_strsplit (environ[i], "=", 2);
- gchar* envname = g_strconcat ("$", env[0], NULL);
-
- if (g_strrstr (string, envname) != NULL) {
- tmpstr = out;
- out = str_replace(envname, env[1], out);
- g_free (tmpstr);
- }
-
- g_free (envname);
- g_strfreev (env); // somebody said this breaks uzbl
- i++;
- }
-
- return out;
-}
-
void
clean_up(void) {
if(uzbl.info.pid_str) {
@@ -489,15 +460,14 @@ get_click_context() {
if(!uzbl.state.last_button)
return -1;
- ht = webkit_web_view_get_hit_test_result(g->web_view, uzbl.state.last_button);
- g_object_get(ht, "context", &context, NULL);
+ ht = webkit_web_view_get_hit_test_result (g->web_view, uzbl.state.last_button);
+ g_object_get (ht, "context", &context, NULL);
+ g_object_unref (ht);
return (gint)context;
}
/* --- SIGNALS --- */
-int sigs[] = {SIGTERM, SIGINT, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGALRM, 0};
-
sigfunc*
setup_signal(int signr, sigfunc *shandler) {
struct sigaction nh, oh;
@@ -513,21 +483,9 @@ setup_signal(int signr, sigfunc *shandler) {
}
void
-catch_signal(int s) {
- if(s == SIGTERM ||
- s == SIGINT ||
- s == SIGILL ||
- s == SIGFPE ||
- s == SIGQUIT) {
- clean_up();
- exit(EXIT_SUCCESS);
- }
- else if(s == SIGSEGV) {
- clean_up();
- fprintf(stderr, "Program aborted, segmentation fault!\nAttempting to clean up...\n");
- exit(EXIT_FAILURE);
- }
- else if(s == SIGALRM && uzbl.state.event_buffer) {
+empty_event_buffer(int s) {
+ (void) s;
+ if(uzbl.state.event_buffer) {
g_ptr_array_free(uzbl.state.event_buffer, TRUE);
uzbl.state.event_buffer = NULL;
}
@@ -626,9 +584,10 @@ struct {const char *key; CommandInfo value;} cmdlist[] =
{ "js", {run_js, TRUE} },
{ "script", {run_external_js, 0} },
{ "toggle_status", {toggle_status_cb, 0} },
- { "spawn", {spawn, 0} },
+ { "spawn", {spawn_async, 0} },
{ "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
- { "sh", {spawn_sh, 0} },
+ { "sync_spawn_exec", {spawn_sync_exec, 0} }, // needed for load_cookies.sh :(
+ { "sh", {spawn_sh_async, 0} },
{ "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
{ "exit", {close_uzbl, 0} },
{ "search", {search_forward_text, TRUE} },
@@ -656,7 +615,9 @@ struct {const char *key; CommandInfo value;} cmdlist[] =
{ "menu_editable_remove", {menu_remove_edit, TRUE} },
{ "hardcopy", {hardcopy, TRUE} },
{ "include", {include, TRUE} },
- { "show_inspector", {show_inspector, 0} }
+ { "show_inspector", {show_inspector, 0} },
+ { "add_cookie", {add_cookie, 0} },
+ { "delete_cookie", {delete_cookie, 0} }
};
void
@@ -695,9 +656,8 @@ set_var(WebKitWebView *page, GArray *argv, GString *result) {
gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
if (split[0] != NULL) {
- gchar *value = parseenv(split[1] ? g_strchug(split[1]) : " ");
+ gchar *value = split[1] ? g_strchug(split[1]) : " ";
set_var_value(g_strstrip(split[0]), value);
- g_free(value);
}
g_strfreev(split);
}
@@ -716,7 +676,7 @@ add_to_menu(GArray *argv, guint context) {
g->menu_items = g_ptr_array_new();
if(split[1])
- item_cmd = g_strdup(split[1]);
+ item_cmd = split[1];
if(split[0]) {
m = malloc(sizeof(MenuItem));
@@ -726,8 +686,6 @@ add_to_menu(GArray *argv, guint context) {
m->issep = FALSE;
g_ptr_array_add(g->menu_items, m);
}
- else
- g_free(item_cmd);
g_strfreev(split);
}
@@ -927,14 +885,12 @@ void
include(WebKitWebView *page, GArray *argv, GString *result) {
(void) page;
(void) result;
- gchar *pe = NULL,
- *path = NULL;
+ gchar *path = argv_idx(argv, 0);
- if(!argv_idx(argv, 0))
+ if(!path)
return;
- pe = parseenv(argv_idx(argv, 0));
- if((path = find_existing_file(pe))) {
+ if((path = find_existing_file(path))) {
if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) {
gchar *tmp = g_strdup_printf("File %s can not be read.", path);
send_event(COMMAND_ERROR, tmp, NULL);
@@ -944,7 +900,6 @@ include(WebKitWebView *page, GArray *argv, GString *result) {
send_event(FILE_INCLUDED, path, NULL);
g_free(path);
}
- g_free(pe);
}
void
@@ -955,6 +910,57 @@ show_inspector(WebKitWebView *page, GArray *argv, GString *result) {
}
void
+add_cookie(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+ gchar *host, *path, *name, *value;
+ gboolean secure = 0;
+ SoupDate *expires = NULL;
+
+ if(argv->len != 6)
+ return;
+
+ // Parse with same syntax as ADD_COOKIE event
+ host = argv_idx (argv, 0);
+ path = argv_idx (argv, 1);
+ name = argv_idx (argv, 2);
+ value = argv_idx (argv, 3);
+ secure = strcmp (argv_idx (argv, 4), "https") == 0;
+ if (strlen (argv_idx (argv, 5)) != 0)
+ expires = soup_date_new_from_time_t (
+ strtoul (argv_idx (argv, 5), NULL, 10));
+
+ // Create new cookie
+ SoupCookie * cookie = soup_cookie_new (name, value, host, path, -1);
+ soup_cookie_set_secure (cookie, secure);
+ if (expires)
+ soup_cookie_set_expires (cookie, expires);
+
+ // Add cookie to jar
+ uzbl.net.soup_cookie_jar->in_manual_add = 1;
+ soup_cookie_jar_add_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie);
+ uzbl.net.soup_cookie_jar->in_manual_add = 0;
+}
+
+void
+delete_cookie(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+
+ if(argv->len < 4)
+ return;
+
+ SoupCookie * cookie = soup_cookie_new (
+ argv_idx (argv, 2),
+ argv_idx (argv, 3),
+ argv_idx (argv, 0),
+ argv_idx (argv, 1),
+ 0);
+
+ uzbl.net.soup_cookie_jar->in_manual_add = 1;
+ soup_cookie_jar_delete_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie);
+ uzbl.net.soup_cookie_jar->in_manual_add = 0;
+}
+
+void
act_dump_config() {
dump_config();
}
@@ -1209,30 +1215,19 @@ sharg_append(GArray *a, const gchar *str) {
g_array_append_val(a, s);
}
-// make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
+/* make sure that the args string you pass can properly be interpreted (eg
+ * properly escaped against whitespace, quotes etc) */
gboolean
-run_command (const gchar *command, const guint npre, const gchar **args,
- const gboolean sync, char **output_stdout) {
- //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
+run_command (const gchar *command, const gchar **args, const gboolean sync,
+ char **output_stdout) {
GError *err = NULL;
GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
- 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]);
- sharg_append(a, uzbl.state.config_file);
- sharg_append(a, pid);
- sharg_append(a, xwin);
- sharg_append(a, uzbl.comm.fifo_path);
- sharg_append(a, uzbl.comm.socket_path);
- sharg_append(a, uzbl.state.uri);
- sharg_append(a, uzbl.gui.main_title);
-
- for (i = npre; i < g_strv_length((gchar**)args); i++)
+
+ for (i = 0; i < g_strv_length((gchar**)args); i++)
sharg_append(a, args[i]);
gboolean result;
@@ -1263,15 +1258,13 @@ run_command (const gchar *command, const guint npre, const gchar **args,
g_printerr("error on run_command: %s\n", err->message);
g_error_free (err);
}
- g_free (pid);
- g_free (xwin);
g_array_free (a, TRUE);
return result;
}
/*@null@*/ gchar**
split_quoted(const gchar* src, const gboolean unquote) {
- /* split on unquoted space, return array of strings;
+ /* split on unquoted space or tab, return array of strings;
remove a layer of quotes and backslashes if unquote */
if (!src) return NULL;
@@ -1292,7 +1285,7 @@ split_quoted(const gchar* src, const gboolean unquote) {
else if ((*p == '\'') && unquote && !dq) sq = !sq;
else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
sq = ! sq; }
- else if ((*p == ' ') && !dq && !sq) {
+ else if ((*p == ' ' || *p == '\t') && !dq && !sq) {
dup = g_strdup(s->str);
g_array_append_val(a, dup);
g_string_truncate(s, 0);
@@ -1307,75 +1300,83 @@ split_quoted(const gchar* src, const gboolean unquote) {
}
void
-spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
+spawn(GArray *argv, gboolean sync, gboolean exec) {
gchar *path = NULL;
+ gchar *arg_car = argv_idx(argv, 0);
+ const gchar **arg_cdr = &g_array_index(argv, const gchar *, 1);
- //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
- if (argv_idx(argv, 0) &&
- ((path = find_existing_file(argv_idx(argv, 0)))) ) {
- run_command(path, 0,
- ((const gchar **) (argv->data + sizeof(gchar*))),
- FALSE, NULL);
+ if (arg_car && (path = find_existing_file(arg_car))) {
+ if (uzbl.comm.sync_stdout)
+ uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+ run_command(path, arg_cdr, sync, sync?&uzbl.comm.sync_stdout:NULL);
+ // run each line of output from the program as a command
+ if (sync && exec && uzbl.comm.sync_stdout) {
+ gchar *head = uzbl.comm.sync_stdout;
+ gchar *tail;
+ while ((tail = strchr (head, '\n'))) {
+ *tail = '\0';
+ parse_cmd_line(head, NULL);
+ head = tail + 1;
+ }
+ }
g_free(path);
}
}
void
-spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+spawn_async(WebKitWebView *web_view, GArray *argv, GString *result) {
(void)web_view; (void)result;
- gchar *path = NULL;
+ spawn(argv, FALSE, FALSE);
+}
- if (argv_idx(argv, 0) &&
- ((path = find_existing_file(argv_idx(argv, 0)))) ) {
- run_command(path, 0,
- ((const gchar **) (argv->data + sizeof(gchar*))),
- TRUE, &uzbl.comm.sync_stdout);
- g_free(path);
- }
+void
+spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
+ spawn(argv, TRUE, FALSE);
}
void
-spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
+spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result) {
(void)web_view; (void)result;
+ spawn(argv, TRUE, TRUE);
+}
+
+void
+spawn_sh(GArray *argv, gboolean sync) {
if (!uzbl.behave.shell_cmd) {
g_printerr ("spawn_sh: shell_cmd is not set!\n");
return;
}
-
guint i;
- gchar *spacer = g_strdup("");
- g_array_insert_val(argv, 1, spacer);
+
gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
+ gchar *cmdname = g_strdup(cmd[0]);
+ g_array_insert_val(argv, 1, cmdname);
for (i = 1; i < g_strv_length(cmd); i++)
g_array_prepend_val(argv, cmd[i]);
- if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
- g_free (spacer);
+ if (cmd) {
+ if (uzbl.comm.sync_stdout)
+ uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+
+ run_command(cmd[0], (const gchar **) argv->data,
+ sync, sync?&uzbl.comm.sync_stdout:NULL);
+ }
+ g_free (cmdname);
g_strfreev (cmd);
}
void
-spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result) {
(void)web_view; (void)result;
- if (!uzbl.behave.shell_cmd) {
- g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
- return;
- }
-
- guint i;
- gchar *spacer = g_strdup("");
- g_array_insert_val(argv, 1, spacer);
- gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
-
- for (i = 1; i < g_strv_length(cmd); i++)
- g_array_prepend_val(argv, cmd[i]);
+ spawn_sh(argv, FALSE);
+}
- if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
- TRUE, &uzbl.comm.sync_stdout);
- g_free (spacer);
- g_strfreev (cmd);
+void
+spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
+ spawn_sh(argv, TRUE);
}
void
@@ -1414,14 +1415,13 @@ parse_command(const char *cmd, const char *param, GString *result) {
strcmp("request", cmd)) {
g_string_printf(tmp, "%s %s", cmd, param?param:"");
send_event(COMMAND_EXECUTED, tmp->str, NULL);
- g_string_free(tmp, TRUE);
}
}
else {
- gchar *tmp = g_strdup_printf("%s %s", cmd, param?param:"");
- send_event(COMMAND_ERROR, tmp, NULL);
- g_free(tmp);
+ g_string_printf (tmp, "%s %s", cmd, param?param:"");
+ send_event(COMMAND_ERROR, tmp->str, NULL);
}
+ g_string_free(tmp, TRUE);
}
@@ -1592,6 +1592,28 @@ control_fifo(GIOChannel *gio, GIOCondition condition) {
return TRUE;
}
+gboolean
+attach_fifo(gchar *path) {
+ GError *error = NULL;
+ /* we don't really need to write to the file, but if we open the
+ * file as 'r' we will block here, waiting for a writer to open
+ * the file. */
+ GIOChannel *chan = g_io_channel_new_file(path, "r+", &error);
+ if (chan) {
+ if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
+ if (uzbl.state.verbose)
+ printf ("attach_fifo: created successfully as %s\n", path);
+ send_event(FIFO_SET, path, NULL);
+ uzbl.comm.fifo_path = path;
+ g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE);
+ return TRUE;
+ } else g_warning ("attach_fifo: could not add watch on %s\n", path);
+ } else g_warning ("attach_fifo: can't open: %s\n", error->message);
+
+ if (error) g_error_free (error);
+ return FALSE;
+}
+
/*@null@*/ gchar*
init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
@@ -1601,28 +1623,31 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
uzbl.comm.fifo_path = NULL;
}
- GIOChannel *chan = NULL;
- GError *error = NULL;
gchar *path = build_stream_name(FIFO, dir);
if (!file_exists(path)) {
- if (mkfifo (path, 0666) == 0) {
- // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file.
- chan = g_io_channel_new_file(path, "r+", &error);
- if (chan) {
- if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
- if (uzbl.state.verbose)
- printf ("init_fifo: created successfully as %s\n", path);
- send_event(FIFO_SET, path, NULL);
- uzbl.comm.fifo_path = path;
- return dir;
- } else g_warning ("init_fifo: could not add watch on %s\n", path);
- } else g_warning ("init_fifo: can't open: %s\n", error->message);
+ if (mkfifo (path, 0666) == 0 && attach_fifo(path)) {
+ return dir;
} else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
- } else g_warning ("init_fifo: can't create %s: file exists\n", path);
+ } else {
+ /* the fifo exists. but is anybody home? */
+ int fd = open(path, O_WRONLY|O_NONBLOCK);
+ if(fd < 0) {
+ /* some error occurred, presumably nobody's on the read end.
+ * we can attach ourselves to it. */
+ if(attach_fifo(path))
+ return dir;
+ else
+ g_warning("init_fifo: can't attach to %s: %s\n", path, strerror(errno));
+ } else {
+ /* somebody's there, we can't use that fifo. */
+ close(fd);
+ /* whatever, this instance can live without a fifo. */
+ g_warning ("init_fifo: can't create %s: file exists and is occupied\n", path);
+ }
+ }
/* if we got this far, there was an error; cleanup */
- if (error) g_error_free (error);
g_free(dir);
g_free(path);
return NULL;
@@ -1773,6 +1798,32 @@ control_client_socket(GIOChannel *clientchan) {
return TRUE;
}
+
+gboolean
+attach_socket(gchar *path, struct sockaddr_un *local) {
+ GIOChannel *chan = NULL;
+ int sock = socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (bind (sock, (struct sockaddr *) local, sizeof(*local)) != -1) {
+ if (uzbl.state.verbose)
+ printf ("init_socket: opened in %s\n", path);
+
+ if(listen (sock, 5) < 0)
+ g_warning ("attach_socket: could not listen on %s: %s\n", path, strerror(errno));
+
+ if( (chan = g_io_channel_unix_new(sock)) ) {
+ g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
+ uzbl.comm.socket_path = path;
+ send_event(SOCKET_SET, path, NULL);
+ g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE);
+ return TRUE;
+ }
+ } else g_warning ("attach_socket: could not bind to %s: %s\n", path, strerror(errno));
+
+ return FALSE;
+}
+
+
/*@null@*/ gchar*
init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
@@ -1787,30 +1838,33 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
return NULL;
}
- GIOChannel *chan = NULL;
- int sock, len;
struct sockaddr_un local;
gchar *path = build_stream_name(SOCKET, dir);
- sock = socket (AF_UNIX, SOCK_STREAM, 0);
-
local.sun_family = AF_UNIX;
strcpy (local.sun_path, path);
- unlink (local.sun_path);
-
- len = strlen (local.sun_path) + sizeof (local.sun_family);
- if (bind (sock, (struct sockaddr *) &local, len) != -1) {
- if (uzbl.state.verbose)
- printf ("init_socket: opened in %s\n", path);
- listen (sock, 5);
- if( (chan = g_io_channel_unix_new(sock)) ) {
- g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
- uzbl.comm.socket_path = path;
- send_event(SOCKET_SET, path, NULL);
- return dir;
+ if(!file_exists(path) && attach_socket(path, &local)) {
+ /* it's free for the taking. */
+ return dir;
+ } else {
+ /* see if anybody's listening on the socket path we want. */
+ int sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if(connect(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ /* some error occurred, presumably nobody's listening.
+ * we can attach ourselves to it. */
+ unlink(path);
+ if(attach_socket(path, &local))
+ return dir;
+ else
+ g_warning("init_socket: can't attach to existing socket %s: %s\n", path, strerror(errno));
+ } else {
+ /* somebody's there, we can't use that socket path. */
+ close(sock);
+ /* whatever, this instance can live without a socket. */
+ g_warning ("init_socket: can't create %s: socket exists and is occupied\n", path);
}
- } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
+ }
/* if we got this far, there was an error; cleanup */
g_free(path);
@@ -2075,6 +2129,7 @@ settings_init () {
send_event(COMMAND_ERROR, tmp, NULL);
g_free(tmp);
}
+ g_setenv("UZBL_CONFIG", s->config_file, TRUE);
} else if (uzbl.state.verbose)
printf ("No configuration file loaded.\n");
@@ -2204,6 +2259,27 @@ retrieve_geometry() {
uzbl.gui.geometry = g_string_free(buf, FALSE);
}
+void
+set_webview_scroll_adjustments() {
+#ifdef GTK3
+ gtk_scrollable_set_hadjustment (GTK_SCROLLABLE(uzbl.gui.web_view), uzbl.gui.bar_h);
+ gtk_scrollable_set_vadjustment (GTK_SCROLLABLE(uzbl.gui.web_view), uzbl.gui.bar_v);
+#else
+ gtk_widget_set_scroll_adjustments (GTK_WIDGET (uzbl.gui.web_view),
+ uzbl.gui.bar_h, uzbl.gui.bar_v);
+#endif
+
+ g_object_connect((GObject*)uzbl.gui.bar_v,
+ "signal::value-changed", (GCallback)scroll_vert_cb, NULL,
+ "signal::changed", (GCallback)scroll_vert_cb, NULL,
+ NULL);
+
+ g_object_connect((GObject*)uzbl.gui.bar_h,
+ "signal::value-changed", (GCallback)scroll_horiz_cb, NULL,
+ "signal::changed", (GCallback)scroll_horiz_cb, NULL,
+ NULL);
+}
+
/* set up gtk, gobject, variable defaults and other things that tests and other
* external applications need to do anyhow */
void
@@ -2241,10 +2317,10 @@ initialize(int argc, char *argv[]) {
uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new();
soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar));
- for(i=0; sigs[i]; i++) {
- if(setup_signal(sigs[i], catch_signal) == SIG_ERR)
- fprintf(stderr, "uzbl: error hooking %d: %s\n", sigs[i], strerror(errno));
- }
+ /* TODO: move the handler setup to event_buffer_timeout and disarm the
+ * handler in empty_event_buffer? */
+ if(setup_signal(SIGALRM, empty_event_buffer) == SIG_ERR)
+ fprintf(stderr, "uzbl: error hooking %d: %s\n", SIGALRM, strerror(errno));
event_buffer_timeout(10);
uzbl.info.webkit_major = webkit_major_version();
@@ -2338,31 +2414,26 @@ main (int argc, char* argv[]) {
uzbl.gui.main_window = create_window ();
gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
gtk_widget_show_all (uzbl.gui.main_window);
- uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
+ uzbl.xwin = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (uzbl.gui.main_window)));
}
uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
- gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
- g_object_connect((GObject*)uzbl.gui.bar_v,
- "signal::value-changed", (GCallback)scroll_vert_cb, NULL,
- "signal::changed", (GCallback)scroll_vert_cb, NULL,
- NULL);
+ set_webview_scroll_adjustments();
- g_object_connect((GObject*)uzbl.gui.bar_h,
- "signal::value-changed", (GCallback)scroll_horiz_cb, NULL,
- "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 b5a502e..129c6a5 100644
--- a/src/uzbl-core.h
+++ b/src/uzbl-core.h
@@ -133,6 +133,7 @@ typedef struct {
gchar* fantasy_font_family;
gchar* cursive_font_family;
gchar* scheme_handler;
+ gchar* download_handler;
gboolean show_status;
gboolean forward_keys;
gboolean status_top;
@@ -228,9 +229,6 @@ itos(int val);
gchar*
strfree(gchar *str);
-gchar*
-parseenv (gchar* string);
-
void
clean_up(void);
@@ -262,14 +260,14 @@ void
close_uzbl (WebKitWebView *page, GArray *argv, GString *result);
gboolean
-run_command(const gchar *command, const guint npre,
- const gchar **args, const gboolean sync, char **output_stdout);
+run_command(const gchar *command, const gchar **args, const gboolean sync,
+ char **output_stdout);
void
-spawn(WebKitWebView *web_view, GArray *argv, GString *result);
+spawn_async(WebKitWebView *web_view, GArray *argv, GString *result);
void
-spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result);
+spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result);
void
spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result);
@@ -278,6 +276,9 @@ void
spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result);
void
+spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result);
+
+void
parse_command(const char *cmd, const char *param, GString *result);
void
@@ -397,6 +398,9 @@ void
retrieve_geometry();
void
+set_webview_scroll_adjustments();
+
+void
event(WebKitWebView *page, GArray *argv, GString *result);
void
@@ -454,6 +458,12 @@ void
show_inspector(WebKitWebView *page, GArray *argv, GString *result);
void
+add_cookie(WebKitWebView *page, GArray *argv, GString *result);
+
+void
+delete_cookie(WebKitWebView *page, GArray *argv, GString *result);
+
+void
builtins();
typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);
diff --git a/tests/Makefile b/tests/Makefile
index 3f63adf..bfe74c5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,17 +1,41 @@
-CFLAGS:=-std=c99 -I$(shell pwd)/../ -L$(shell pwd) -luzbl-core $(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 -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" $(CPPFLAGS)
-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 -DG_ERRORCHECK_MUTEXES -DCOMMIT='"\""'`git log | head -n1 | sed "s/.* //"`'"\""' $(CPPFLAGS)
+# gtk2
+REQ_PKGS = gtk+-2.0 webkit-1.0
+CPPFLAGS = -DERRORCHECK_MUTEXES -I ../
-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)
+# gtk3
+#REQ_PKGS = gtk+-3.0 webkitgtk-3.0
+#CPPFLAGS = -DERRORCHECK_MUTEXES -DGTK3 -I ../
-GTESTER:=gtester
-GTESTER_REPORT:=gtester-report
+# --- configuration ends here ---
-TEST_PROGS:=test-expand test-command
+REQ_PKGS += libsoup-2.4 gthread-2.0 glib-2.0
+
+ARCH:=$(shell uname -m)
+ARCH!=echo `uname -m`
+
+COMMIT_HASH:=$(shell cd .. && ./misc/hash.sh)
+COMMIT_HASH!=echo `cd .. && ./misc/hash.sh`
+
+CPPFLAGS += -DARCH=\"$(ARCH)\" -DCOMMIT=\"$(COMMIT_HASH)\"
+
+PKG_CFLAGS:=$(shell pkg-config --cflags $(REQ_PKGS))
+PKG_CFLAGS!=echo pkg-config --cflags $(REQ_PKGS)
+
+LDLIBS:=$(shell pkg-config --libs $(REQ_PKGS) x11)
+LDLIBS!=echo pkg-config --libs $(REQ_PKGS) x11
+
+CFLAGS += -std=c99 $(PKG_CFLAGS) -ggdb -fPIC -W -Wall -Wextra -pedantic -pthread
+
+GTESTER = gtester
+GTESTER_REPORT = gtester-report
+
+TEST_PROGS = test-expand test-command
all: $(TEST_PROGS)
LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." $(GTESTER) --verbose $(TEST_PROGS)
+${TEST_PROGS}: libuzbl-core.so
+
clean:
rm -f $(TEST_PROGS)
rm -f libuzbl-core.so
diff --git a/tests/test-command.c b/tests/test-command.c
index 6194081..7b33405 100644
--- a/tests/test-command.c
+++ b/tests/test-command.c
@@ -29,33 +29,6 @@ extern UzblCore uzbl;
#define INSTANCE_NAME "testing"
-gchar*
-assert_str_beginswith(GString *expected, gchar *actual) {
- gchar *actual_beginning = g_strndup(actual, expected->len);
- g_assert_cmpstr(expected->str, ==, actual_beginning);
- g_free(actual_beginning);
-
- /* return the part of the actual string that hasn't been compared yet */
- return &actual[expected->len];
-}
-
-/* compare the contents of uzbl.comm.sync_stdout to the standard arguments that
- * should have been passed. This is meant to be called after something like "sync echo". */
-gchar*
-assert_sync_beginswith_stdarg() {
- GString *stdargs = g_string_new("");
-
- g_string_append_printf(stdargs, "%s %d %d ", uzbl.state.config_file, getpid(), (int)uzbl.xwin);
- g_string_append_printf(stdargs, "%s %s ", uzbl.comm.fifo_path, uzbl.comm.socket_path);
- g_string_append_printf(stdargs, "%s %s ", uzbl.state.uri, uzbl.gui.main_title);
-
- gchar *rest = assert_str_beginswith(stdargs, uzbl.comm.sync_stdout);
-
- g_string_free(stdargs, TRUE);
-
- return rest;
-}
-
#define ASSERT_EVENT(EF, STR) { read_event(ef); \
g_assert_cmpstr("EVENT [" INSTANCE_NAME "] " STR "\n", ==, ef->event_buffer); }
@@ -314,13 +287,10 @@ test_run_handler_arg_order (void) {
assert(uzbl.comm.sync_stdout);
- /* the result should begin with the standard handler arguments */
- gchar *rest = assert_sync_beginswith_stdarg();
-
/* the rest of the result should be the arguments passed to run_handler. */
/* the arguments in the second argument to run_handler should be placed before any
* included in the first argument to run handler. */
- g_assert_cmpstr("abc def uvw xyz\n", ==, rest);
+ g_assert_cmpstr("abc def uvw xyz\n", ==, uzbl.comm.sync_stdout);
}
void
@@ -330,12 +300,8 @@ test_run_handler_expand (void) {
assert(uzbl.comm.sync_stdout);
- /* the result should begin with the standard handler arguments */
- gchar *rest = assert_sync_beginswith_stdarg();
-
- /* the rest of the result should be the arguments passed to run_handler. */
/* the user-specified arguments to the handler should have been expanded */
- g_assert_cmpstr("result: Test uzbl uzr agent\n", ==, rest);
+ g_assert_cmpstr("result: Test uzbl uzr agent\n", ==, uzbl.comm.sync_stdout);
}
int