diff options
-rw-r--r-- | AUTHORS | 7 | ||||
-rw-r--r-- | Makefile | 33 | ||||
-rw-r--r-- | Makefile-new-test | 51 | ||||
-rw-r--r-- | README | 16 | ||||
-rw-r--r-- | docs/FAQ | 9 | ||||
-rw-r--r-- | docs/INSTALL | 6 | ||||
-rw-r--r-- | examples/configs/sampleconfig | 5 | ||||
-rw-r--r-- | examples/configs/sampleconfig-dev | 10 | ||||
-rw-r--r-- | examples/data/style.css | 26 | ||||
-rwxr-xr-x | examples/scripts/clipboard.sh | 2 | ||||
-rwxr-xr-x | examples/scripts/cookies.sh | 53 | ||||
-rwxr-xr-x | examples/scripts/formfiller.pl | 60 | ||||
-rwxr-xr-x | examples/scripts/formfiller.sh | 2 | ||||
-rw-r--r-- | examples/scripts/linkfollow.js | 360 | ||||
-rwxr-xr-x | examples/scripts/load_url_from_bookmarks.sh | 4 | ||||
-rwxr-xr-x | examples/scripts/load_url_from_history.sh | 4 | ||||
-rwxr-xr-x | examples/scripts/yank.sh | 9 | ||||
-rw-r--r-- | uzbl.c | 61 | ||||
-rw-r--r-- | uzbl.h | 9 | ||||
-rw-r--r-- | uzblctrl.c | 7 |
20 files changed, 490 insertions, 244 deletions
@@ -3,11 +3,11 @@ Developers: Dieter Plaetinck (Dieter@be) <email is dieter AT plaetinck.be> Dusan Popovic (dusanx) Michael Walker (Barrucadu) <email is mike AT barrucadu.co.uk> - Přemysl Hrubý, (anydot) <email is dfenze AT gmail.com> + Přemysl Hrubý (anydot) <email is dfenze AT gmail.com> Robert Manea (robm) <email is rob DOT manea AT gmail DOT com> + Henri Kemppainen (DuClare) <email is akarinotengoku AT THE DOMAIN OF gmail.com> Contributors: - (DuClare) - Various improvements Zane Ashby (HashBox) - Rewrote FIFO interface. Fixed various bugs. (sentientswitch) - Cleaned up code. Added some commands. Jan Kolkmeier (jouz) - scrolling, link following @@ -17,6 +17,9 @@ Contributors: (salinasv) - move some variables to heap Sylvester Johansson (scj) - form filler script & different take on link follower (mxf) - uzblcat + Mark Nevill - misc patches + Uli Schlachter (psychon) - basic mime_policy_cb & Makefile patch + (uranther) - zoom level Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c Which is copyrighted: @@ -1,7 +1,9 @@ -CPPFLAGS=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" -LDFLAGS=$(shell pkg-config --libs gtk+-2.0 webkit-1.0) +CPPFLAGS:=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" $(CPPFLAGS) +LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0) $(LDFLAGS) all: uzbl uzblctrl +PREFIX?=$(DESTDIR)/usr + test: uzbl ./uzbl --uri http://www.uzbl.org @@ -16,18 +18,19 @@ clean: rm -f uzblctrl install: - install -d $(DESTDIR)/usr/bin - install -d $(DESTDIR)/usr/share/uzbl/docs - install -d $(DESTDIR)/usr/share/uzbl/examples - install -D -m755 uzbl $(DESTDIR)/usr/bin/uzbl - install -D -m755 uzblctrl $(DESTDIR)/usr/bin/uzblctrl - cp -ax docs $(DESTDIR)/usr/share/uzbl/ - cp -ax config.h $(DESTDIR)/usr/share/uzbl/docs/ - cp -ax examples $(DESTDIR)/usr/share/uzbl/ - install -D -m644 AUTHORS $(DESTDIR)/usr/share/uzbl/docs - install -D -m644 README $(DESTDIR)/usr/share/uzbl/docs + install -d $(PREFIX)/bin + install -d $(PREFIX)/share/uzbl/docs + install -d $(PREFIX)/share/uzbl/examples + install -D -m755 uzbl $(PREFIX)/bin/uzbl + install -D -m755 uzblctrl $(PREFIX)/bin/uzblctrl + cp -ax docs $(PREFIX)/share/uzbl/ + cp -ax config.h $(PREFIX)/share/uzbl/docs/ + cp -ax examples $(PREFIX)/share/uzbl/ + install -D -m644 AUTHORS $(PREFIX)/share/uzbl/docs + install -D -m644 README $(PREFIX)/share/uzbl/docs + uninstall: - rm -rf $(DESTDIR)/usr/bin/uzbl - rm -rf $(DESTDIR)/usr/bin/uzblctrl - rm -rf $(DESTDIR)/usr/share/uzbl + rm -rf $(PREFIX)/bin/uzbl + rm -rf $(PREFIX)/bin/uzblctrl + rm -rf $(PREFIX)/share/uzbl diff --git a/Makefile-new-test b/Makefile-new-test new file mode 100644 index 0000000..5985c90 --- /dev/null +++ b/Makefile-new-test @@ -0,0 +1,51 @@ +LIBS := gtk+-2.0 webkit-1.0 +ARCH := $(shell uname -m) +COMMIT := $(shell git log | head -n1 | sed "s/.* //") +DEBUG := -ggdb -Wall -W -DG_ERRORCHECK_MUTEXES + +CFLAGS := $(shell --cflags $(LIBS)) $(DEBUG) -DARCH="$(ARCH)" -DCOMMIT="\"$(COMMIT)\"" +LDFLAGS := $(shell --libs $(LIBS)) $(LDFLAGS) + +PREFIX ?= $(DESTDIR)/usr +BINDIR ?= $(PREFIX)/bin +UZBLDATA ?= $(PREFIX)/share/uzbl +DOCSDIR ?= $(PREFIX)/share/uzbl/docs +EXMPLSDIR ?= $(PREFIX)/share/uzbl/examples + +all: uzbl uzblctrl + +uzbl: uzbl.c uzbl.h config.h + +%: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LIBS) -o $@ $< + +test: uzbl + ./uzbl --uri http://www.uzbl.org + +test-config: uzbl + ./uzbl --uri http://www.uzbl.org < examples/configs/sampleconfig-dev + +test-config-real: uzbl + ./uzbl --uri http://www.uzbl.org < $(EXMPLSDIR)/configs/sampleconfig + +clean: + rm -f uzbl + rm -f uzblctrl + +install: + install -d $(BINDIR) + install -d $(DOCSDIR) + install -d $(EXMPLSDIR) + install -D -m755 uzbl $(BINDIR)/uzbl + install -D -m755 uzblctrl $(BINDIR)/uzblctrl + cp -ax docs/* $(DOCSDIR) + cp -ax config.h $(DOCSDIR) + cp -ax examples/* $(EXMPLSDIR) + install -D -m644 AUTHORS $(DOCSDIR) + install -D -m644 README $(DOCSDIR) + + +uninstall: + rm -rf $(BINDIR)/uzbl + rm -rf $(BINDIR)/uzblctrl + rm -rf $(UZBLDATA) @@ -83,14 +83,6 @@ When uzbl forks a new instance (eg "open in new window") it will use the same co If you made changes to the configuration at runtime, these are not pased on to the child. ### COMMAND SYNTAX -Commands are used for: - -* creating keybindings -* altering variables -* getting the values of variables -* running actions -* setting the input buffer - Uzbl will read commands via standard input, named fifo pipe (if `fifo_dir` is set) and IPC socket (when `socket_dir` is set). For convenience, uzbl can also be instructed to read commands from a file on startup by using the `-c` option. Indeed, the config file is nothing more than a list of commands. @@ -151,7 +143,7 @@ The following commands are recognized: * `sync_spawn <executable> <additional args>` * `sync_sh <command>` - these are synchronous variants of `spawn` and `sh`, which means uzbl will wait for them to return - - you should only need to use these manually if you want to use a chain action in a handler that wants output from the command it runs + - you should only need to use these manually if you want to use a chain command in a handler that wants output from the command it runs * `exit` * `search <string>` * `search_reverse <string>` @@ -163,9 +155,9 @@ The following commands are recognized: - keycmd sets the interactive command buffer to `<string>`. If the given string is a valid binding, it will execute. `Keycmd_nl` is like `keycmd`, but it also emulates a press of return, causing bindings with a parameter to execute. For example, `keycmd_nl o google.com` would load the said url if you have a binding like `bind o _ = uri %s`. * `keycmd_bs` - erase (backspace) one character from the command buffer -* `chain <action> <action> ..` - - use for chaining multiple actions - - remember to quote the actions; one action must come as one parameter +* `chain <command> <command> ..` + - use for chaining multiple commands + - remember to quote the commands; one command must come as one parameter - if you use `chain` with a handler script which must return some output (such as a cookie handler -- uzbl will wait for and use its output), use sync_spawn or sync_sh instead of spawn or sh in the command that should give the output @@ -68,12 +68,19 @@ Note that we do *not* depend on any Gnome libraries such as gconf. _That_ would ### Do you support flash? javascript? Ajax? Recent html/css/.. standards? Yes, Webkit takes care of all of that. Not that we like all of these, but you can use them if you want. +### What's the difference between the socket file and the fifo? +They both have advantages and disadvantages: + + * fifo's are _very_ easy to work with. You can write just plaintext commands into them, but they are unidirectional (you can only communicate in one direction) + * Sockets are bidirectional but more complex. You cannot just write a plaintext string into them. In shellscripts you can use uzblctrl or netcat to work with sockets, when programming you need to use library functions. + +So, when writing scripts, using fifo's is usually the fastest method (because you do not need to fork another process), so fifo is preferred unless you need a response. + ### Does the world really need another browser? We did try a lot of browsers, and we do not suffer [NIH](http://en.wikipedia.org/wiki/Not_Invented_Here). We believe that the approach taken by way too many browsers is wrong. We do not want browsers that try to do everything, instead we prefer a system where different applications work together, which gives plenty of advantages. We also like open source. We take a lot of things from other projects and we also try to contribute to other projects. - ### What? You call all of this user-friendly? Yes. If you don't agree, don't use it :) diff --git a/docs/INSTALL b/docs/INSTALL index 3453e03..1c0d007 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -1,11 +1,13 @@ -Arch Linux ----------- +Packages +-------- [Arch Linux](http://www.archlinux.org) is our distro of choice, and the distro we use for testing. You can find a [PKGBUILD](http://aur.archlinux.org/packages.php?ID=25972) on the AUR, which installs the latest from the master branch. You can edit the PKGBUILD to change to any other branch you want. +For other distros, see [uzbl.org/wiki/howtos](http://www.uzbl.org/wiki/howtos) + From source ----------- You can pull the code from git or get a tagged tarball. diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 42edf75..9bb0025 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -69,6 +69,7 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out +bind 0 = sh "echo set zoom_level = 1.0 > $4" bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. @@ -89,8 +90,8 @@ bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 8 primary -bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 9 clipboard +bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 6 primary +bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 7 clipboard # does the same as yurl but without needing a script bind y2url = sh "echo -n $6 | xclip" # go the page from primary selection diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 002f550..c8eddd0 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -60,7 +60,7 @@ set shell_cmd = sh -c set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 -set status_format = <span font_family="monospace"><span background="khaki" foreground="black">MODE</span> [<span weight="bold" foreground="red">KEYCMD</span>] <span foreground="#606060"> LOAD_PROGRESSBAR </span><span foreground="#99FF66">URI</span> <span foreground="khaki">NAME</span> <span foreground="orange">MSG</span><span foreground="#606060">SELECTED_URI</span></span> +set status_format = <span font_family="monospace"><span background="khaki" foreground="black">[MODE]</span> [<span weight="bold" foreground="red">KEYCMD</span>] <span foreground="#606060"> LOAD_PROGRESSBAR </span><span foreground="#99FF66">URI</span> <span foreground="khaki">NAME</span> <span foreground="orange">MSG</span><span foreground="#606060">SELECTED_URI</span></span> set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = TITLE - Uzbl browser <NAME> @@ -69,7 +69,8 @@ set title_format_long = KEYCMD MODE TITLE - Uzbl browser <NAME> > SELECTED_URI set status_pbar_done = * set status_pbar_pending = - set status_pbar_width = 12 - +set insert_indicator = I +set command_indicator = C set modkey = Mod1 # reset to command mode when new page is loaded set reset_command_mode = 1 @@ -103,6 +104,7 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out +bind 0 = sh "echo set zoom_level = 1.0 > $4" bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. @@ -125,8 +127,8 @@ bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn ./examples/scripts/yank.sh 8 primary -bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard +bind yurl = spawn ./examples/scripts/yank.sh 6 primary +bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard # does the same as yurl but without needing a script bind y2url = sh 'echo -n $6 | xclip' # go the page from primary selection diff --git a/examples/data/style.css b/examples/data/style.css new file mode 100644 index 0000000..de0a38b --- /dev/null +++ b/examples/data/style.css @@ -0,0 +1,26 @@ +.uzbl_highlight { background-color: yellow;} +.uzbl_h_first { background-color: lightgreen;} + +.uzbl_follow { border-style: dotted; + border-width: thin; +} + +#uzbl_hint > div { + display: inline; + border: 2px solid #4a6600; + background-color: #b9ff00; + color: black; + font-size: 9px; + font-weight: bold; + line-height: 9px; + margin: 0px; + padding: 0px; + position: absolute; + z-index: 1000; + -webkit-border-radius: 6px; + text-decoration: none; + -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px); +} + +/* vim:set et ts=4: */ + diff --git a/examples/scripts/clipboard.sh b/examples/scripts/clipboard.sh index e13f053..c64b65c 100755 --- a/examples/scripts/clipboard.sh +++ b/examples/scripts/clipboard.sh @@ -9,7 +9,7 @@ selection=$(xclip -o) case $action in "yank" ) echo -n "$url" | xclip;; - "goto" ) echo "act uri $selection" > "$fifo";; + "goto" ) echo "uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index cd449dc..efac322 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -1,4 +1,7 @@ #!/bin/bash + +# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! + # this is an example script of how you could manage your cookies.. # we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) # This is one textfile with entries like this: @@ -21,16 +24,23 @@ # http://kb.mozillazine.org/Cookies.txt # don't always append cookies, sometimes we need to overwrite -if [ -f /usr/share/uzbl/examples/configs/cookies ] -then - file=/usr/share/uzbl/examples/configs/cookies -else - file=./examples/configs/cookies #useful when developing -fi - -#cookie_file=$XDG_DATA_HOME/uzbl/cookies.txt -cookie_file=./examples/data/cookies.txt - +[ -f /usr/share/uzbl/examples/configs/cookies ] && file=/usr/share/uzbl/examples/configs/cookies +[ -f $XDG_CONFIG_HOME/uzbl/cookies ] && file=$XDG_CONFIG_HOME/uzbl/cookies +[ -f ./examples/configs/cookies ] && file=./examples/configs/cookies #useful when developing +[ -z "$file" ] && exit 1 + +[ -d /usr/share/uzbl/examples/data ] && cookie_file=/usr/share/uzbl/examples/data/cookies.txt +[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_file=$XDG_DATA_HOME/uzbl/cookies.txt +[ -d ./examples/data/ ] && cookie_file=./examples/data/cookies.txt #useful when developing +[ -z "$cookie_file" ] && exit 1 + +# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. +#notifier= +#notifier=notify-send +notify_wrapper () { + echo "$@" >> $HOME/cookielog +} +notifier=notify_wrapper which zenity &>/dev/null || exit 2 # Example cookie: @@ -52,6 +62,10 @@ field_name= field_value= field_exp='end_session' +function notify () { + [ -n "$notifier" ] && $notifier "$@" +} + # FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET function parse_cookie () { @@ -79,19 +93,32 @@ function parse_cookie () { # match cookies in cookies.txt againsh hostname and path function get_cookie () { path_esc=${path//\//\\/} - cookie=`awk "/^[^\t]*$host\t[^\t]*\t$path_esc/" $cookie_file 2>/dev/null | tail -n 1` + search="^[^\t]*$host\t[^\t]*\t$path_esc" + cookie=`awk "/$search/" $cookie_file 2>/dev/null | tail -n 1` if [ -z "$cookie" ] then + notify "Get_cookie: search: $search in $cookie_file -> no result" false else + notify "Get_cookie: search: $search in $cookie_file -> result: $cookie" read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" cookie="$name=$value" - #echo "COOKIE $cookie" >> $HOME/cookielog true fi } -[ $action == PUT ] && parse_cookie && echo -e "$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" >> $cookie_file +function save_cookie () { + if parse_cookie + then + data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" + notify "save_cookie: adding $data to $cookie_file" + echo -e "$data" >> $cookie_file + else + notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" + fi +} + +[ $action == PUT ] && save_cookie [ $action == GET ] && get_cookie && echo "$cookie" exit diff --git a/examples/scripts/formfiller.pl b/examples/scripts/formfiller.pl index a6e07a0..c590836 100755 --- a/examples/scripts/formfiller.pl +++ b/examples/scripts/formfiller.pl @@ -15,11 +15,11 @@ # bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit use strict; -use Switch; +use warnings; my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; -my ($config,$pid,$xid,$fifo,$socket,$url,$title,$cmd) = @ARGV; -if($fifo eq "") { die "No fifo"; }; +my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV; +if (!defined $fifoname || $fifoname eq "") { die "No fifo"; } sub domain { my ($url) = @_; @@ -41,29 +41,29 @@ my %command; $command{load} = sub { my ($domain) = @_; - my $file = "$keydir/$domain"; - if( -e $file){ - open(FH,$file); - my (@lines) = <FH>; - close(FH); + my $filename = "$keydir/$domain"; + if (-e $filename){ + open(my $file, $filename) or die "Failed to open $filename: $!"; + my (@lines) = <$file>; + close($file); $|++; - open(FIFO,">>$fifo"); - print "opened $fifo\n"; + open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!"; foreach my $line (@lines) { - if($line !~ m/^#/){ - my ($type,$name,$value) = ($line =~ /\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); - switch ($type) { - case "" {} - case "checkbox" { printf FIFO 'act js document.getElementsByName("%s")[0].checked = %s;', $name, $value} - case "submit" { printf FIFO 'act js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name } - else { printf FIFO 'act js document.getElementsByName("%s")[0].value = "%s";', $name, $value} - } - - print FIFO "\n"; + next if ($line =~ m/^#/); + my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); + if ($type eq "checkbox") + { + printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;', $name, $value; + } elsif ($type eq "submit") + { + printf $fifo 'js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; + } elsif ($type ne "") + { + printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";', $name, $value; } + print $fifo "\n"; } $|--; - close(FIFO); } else { $command{new}->($domain); $command{edit}->($domain); @@ -76,24 +76,24 @@ $command{edit} = sub { system ($editor, $file); } else { $command{new}->($domain); -} + } }; $command{new} = sub { my ($domain) = @_; - my $file = "$keydir/$domain"; - open(FILE,">>$file"); + my $filename = "$keydir/$domain"; + open (my $file,">>", $filename) or die "Failed to open $filename: $!"; $|++; - print FILE "#make sure that there are no extra submits, since it may trigger the wrong one\n"; - printf FILE "#%-10s | %-10s | %s\n", @fields; - print FILE "#------------------------------\n"; + print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n"; + printf $file "#%-10s | %-10s | %s\n", @fields; + print $file "#------------------------------\n"; my @data = `$downloader $url`; foreach my $line (@data){ if($line =~ m/<input ([^>].*?)>/i){ - $line =~ s/.*(<input ([^>].*?)>).*/\1/; - printf FILE " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; + $line =~ s/.*(<input ([^>].*?)>).*/$1/; + printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; }; }; - close(FILE); $|--; }; + $command{$cmd}->(domain($url)); diff --git a/examples/scripts/formfiller.sh b/examples/scripts/formfiller.sh index 45cde69..5debcce 100755 --- a/examples/scripts/formfiller.sh +++ b/examples/scripts/formfiller.sh @@ -49,7 +49,7 @@ domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') if [ "$action" = 'load' ] then [[ -e $keydir/$domain ]] || exit 2 - gawk -F': ' '{ print "act js document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo + gawk -F': ' '{ print "js document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo else if [ "$action" == 'new' ] then diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 9b7d811..b90b82d 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -2,174 +2,262 @@ // requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 // // first, it needs to be loaded before every time it is used. -// One way would be to use something like load_start_handler to send -// "act script link_follower.js" +// One way would be to use the load_commit_handler: +// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' // // when script is loaded, it can be invoked with -// bind f* = js setHints("%s") -// bind f_ = js followLink("%s") +// bind f* = js hints.set("%s", hints.open) +// bind f_ = js hints.follow("%s",hints.open) +// +// At the moment, it may be useful to have way of forcing uzbl to load the script +// bind :lf = script /usr/share/uzbl/examples/scripts/linkfollow.js +// +// The default style for the hints are pretty ugly, so it is recommended to add the following +// to config file +// set stylesheet_uri = /usr/share/uzbl/examples/data/style.css // // based on follow_Numbers.js // -// TODO: add classes to hinted elements +// TODO: fix styling for the first element +// TODO: emulate mouseover events when visiting some elements +// TODO: rewrite the element->action handling + + +function Hints(){ + + // Settings + //////////////////////////////////////////////////////////////////////////// + // if set to true, you must explicitly call hints.follow(), otherwise it will + // follow the link if there is only one matching result + var requireReturn = true; -var uzblid = 'uzbl_hint'; -var uzblclass = 'uzbl_hint_class' + // Case sensitivity flag + var matchCase = "i"; -var doc = document; + // For case sensitive matching, uncomment: + // var matchCase = ""; -function elementPosition(el) { + + var uzblid = 'uzbl_hint'; + var uzblclass = 'uzbl_highlight'; + var uzblclassfirst = 'uzbl_h_first'; + var doc = document; + var visible = []; + var hintdiv; + + this.set = hint; + this.follow = follow; + this.keyPressHandler = keyPressHandler; + + function elementPosition(el) { var up = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; var height = el.offsetHeight; while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; } - return [up, left, width, height]; -} + return {up: up, left: left, width: width, height: height}; + } -function generateHint(el, label) { - var hint = doc.createElement('div'); - hint.setAttribute('class', uzblclass); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.zIndex = '10000'; - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} + function elementInViewport(p) { + return (p.up < window.pageYOffset + window.innerHeight && + p.left < window.pageXOffset + window.innerWidth && + (p.up + p.height) > window.pageYOffset && + (p.left + p.width) > window.pageXOffset); + } -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return (up < window.pageYOffset + window.innerHeight && - left < window.pageXOffset + window.innerWidth - && (up + height) > window.pageYOffset - && (left + width) > window.pageXOffset); -} + function isVisible(el) { + if (el == doc) { return true; } + if (!el) { return false; } + if (!el.parentNode) { return false; } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); + } -function isVisible(el) { - - if (el == doc) { return true; } - if (!el) { return false; } - if (!el.parentNode) { return false; } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} + // the vimperator defaults minus the xhtml elements, since it gave DOM errors + var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; -var hintable = "//a[@href] | //img | //input"; - -function Matcher(str){ - var numbers = str.replace(/[^\d]/g,""); - var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); - this.test = test; - this.toString = toString; - this.numbers = numbers; - function test(element) { - // test all the regexp - return words.every(function (regex) { return element.textContent.match(regex)}); - } - function toString(){ - return "{"+numbers+"},{"+words+"}"; - } -} + function Matcher(str){ + var numbers = str.replace(/[^\d]/g,""); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)}); + this.test = test; + this.toString = toString; + this.numbers = numbers; + function test(element) { + // test all the regexp + return words.every(function (regex) { return element.node.textContent.match(regex)}); + } + } + function HintElement(node,pos){ -function setHints(r){ - if(doc.body) doc.body.setAttribute("onkeyup","keyPressHandler(event)"); - var re = new Matcher(r); - clearHints(); - var c = 1; - var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0; i < items.snapshotLength;i++){ - var item = items.snapshotItem(i); - if(re.test(item) && isVisible(item) && elementInViewport(item)){ - var h = generateHint(item,c); - item.appendChild(h); - c++; - } - } -} + this.node = node; + this.isHinted = false; + this.position = pos; + this.num = 0; -function clearHints(){ - var items = doc.evaluate("//div[@class='" + uzblclass + "']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0; i < items.snapshotLength;i++){ - var item = items.snapshotItem(i); - item.parentNode.removeChild(item); - } -} + this.addHint = function (labelNum) { + // TODO: fix uzblclassfirst + if(!this.isHinted){ + this.node.className += " " + uzblclass; + } + this.isHinted = true; + + // create hint + var hintNode = doc.createElement('div'); + hintNode.name = uzblid; + hintNode.innerText = labelNum; + hintNode.style.left = this.position.left + 'px'; + hintNode.style.top = this.position.up + 'px'; + hintNode.style.position = "absolute"; + doc.body.firstChild.appendChild(hintNode); + + } + this.removeHint = function(){ + if(this.isHinted){ + var s = (this.num)?uzblclassfirst:uzblclass; + this.node.className = this.node.className.replace(new RegExp(" "+s,"g"),""); + this.isHinted = false; + } + } + } + + function createHintDiv(){ + var hintdiv = doc.getElementById(uzblid); + if(hintdiv){ + hintdiv.parentNode.removeChild(hintdiv); + } + hintdiv = doc.createElement("div"); + hintdiv.setAttribute('id',uzblid); + doc.body.insertBefore(hintdiv,doc.body.firstChild); + return hintdiv; + } + + function init(){ + // WHAT? + doc.body.setAttribute("onkeyup","hints.keyPressHandler(event)"); + hintdiv = createHintDiv(); + visible = []; + + var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + for (var i = 0;i<items.snapshotLength;i++){ + var item = items.snapshotItem(i); + var pos = elementPosition(item); + if(isVisible && elementInViewport(elementPosition(item))){ + visible.push(new HintElement(item,pos)); + } + } + } + + function clear(){ + + visible.forEach(function (n) { n.removeHint(); } ); + hintdiv = doc.getElementById(uzblid); + while(hintdiv){ + hintdiv.parentNode.removeChild(hintdiv); + hintdiv = doc.getElementById(uzblid); + } + } + + function update(str,openFun) { + var match = new Matcher(str); + hintdiv = createHintDiv(); + var i = 1; + visible.forEach(function (n) { + if(match.test(n)) { + n.addHint(i); + i++; + } else { + n.removeHint(); + }}); + if(!requireReturn){ + if(i==2){ //only been incremented once + follow(str,openFun); + } + } + } + + function hint(str,openFun){ + if(str.length == 0) init(); + update(str,openFun); + } -function keyPressHandler(e) { + function keyPressHandler(e) { var kC = window.event ? event.keyCode: e.keyCode; var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; if (kC == Esc) { - clearHints(); - doc.body.removeAttribute("onkeyup"); + clear(); + doc.body.removeAttribute("onkeyup"); + } + } + + this.openNewWindow = function(item){ + // TODO: this doesn't work yet + item.className += " uzbl_follow"; + window.open(item.href,"uzblnew",""); + } + this.open = function(item){ + simulateMouseOver(item); + item.className += " uzbl_follow"; + window.location = item.href; + } + + function simulateMouseOver(item){ + var evt = doc.createEvent("MouseEvents"); + evt.initMouseEvent("MouseOver",true,true, + doc.defaultView,1,0,0,0,0, + false,false,false,false,0,null); + return item.dispatchEvent(evt); + } + + + function follow(str,openFunction){ + var m = new Matcher(str); + var items = visible.filter(function (n) { return n.isHinted }); + clear(); + var num = parseInt(m.numbers,10); + if(num){ + var item = items[num-1].node; + } else { + var item = items[0].node; } -} -function followLink(follow){ - var m = new Matcher(follow); - var elements = doc.evaluate("//*/div[@class='"+uzblclass+"']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - // filter - var matched = []; - for (var i = 0; i < elements.snapshotLength;i++){ - var item = elements.snapshotItem(i); - if(m.test(item.parentNode)){ - matched.push(item.parentNode); - } - } - clearHints(); - if(matched.length == 1) { - var item = matched[0]; - } else { - var item = matched[parseInt(m.numbers,10)-1]; - } if (item) { - item.style.backgroundColor = "blue"; - - var name = item.tagName; - if (name == 'A') { - if(item.click) {item.click()}; - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { + var name = item.tagName; + if (name == 'A') { + if(item.click) {item.click()}; + openFunction(item); + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { item.focus(); item.select(); } else { item.click(); - window.location = item.href; } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + openFunction(item); + } } + } } + +var hints = new Hints(); + +// vim:set et sw=2: + + diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 21ea33d..1ae39ff 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -18,5 +18,5 @@ else goto=`awk '{print $1}' $file | $DMENU $COLORS` fi -#[ -n "$goto" ] && echo "act uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" +#[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 649c6b7..37c2afc 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -17,5 +17,5 @@ else current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` fi -[ -n "$goto" ] && echo "act uri $goto" > $4 -#[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" +[ -n "$goto" ] && echo "uri $goto" > $4 +#[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/yank.sh b/examples/scripts/yank.sh index d4926be..ee140c7 100755 --- a/examples/scripts/yank.sh +++ b/examples/scripts/yank.sh @@ -2,10 +2,11 @@ # in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) # make the 2nd argument one of : primary, secondary, clipboard. # examples: -# bind yurl = spawn ./examples/scripts/yank.sh 8 primary -# bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard +# bind yurl = spawn ./examples/scripts/yank.sh 6 primary +# bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard which xclip &>/dev/null || exit 1 -[ "$2" == primary -o "$2" == secondary -o "$2" == clipboard ] || exit 2 +[ "$9" == primary -o "$9" == secondary -o "$9" == clipboard ] || exit 2 -echo -n "${!1}" | xclip -selection $2
\ No newline at end of file +echo echo -n "${!8}" '|' xclip -selection $9 +echo -n "${!8}" | xclip -selection $9 @@ -43,16 +43,14 @@ #include <sys/utsname.h> #include <sys/time.h> #include <webkit/webkit.h> +#include <libsoup/soup.h> + #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> -#include <string.h> #include <fcntl.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <libsoup/soup.h> #include <signal.h> #include "uzbl.h" #include "config.h" @@ -85,7 +83,7 @@ typedef const struct { void (*func)(void); } uzbl_cmdprop; -enum {TYPE_INT, TYPE_STR}; +enum {TYPE_INT, TYPE_STR, TYPE_FLOAT}; /* an abbreviation to help keep the table's width humane */ #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun } @@ -133,7 +131,8 @@ const struct { { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)}, { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)}, { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)}, - /* exported WebKitWebSettings properties*/ + /* exported WebKitWebSettings properties */ + { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)}, { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)}, { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)}, { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)}, @@ -392,6 +391,23 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequ return (FALSE); } +static gboolean +mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { + (void) frame; + (void) request; + (void) user_data; + + /* If we can display it, let's display it... */ + if (webkit_web_view_can_show_mime_type (web_view, mime_type)) { + webkit_web_policy_decision_use (policy_decision); + return TRUE; + } + + /* ...everything we can't displayed is downloaded */ + webkit_web_policy_decision_download (policy_decision); + return TRUE; +} + WebKitWebView* create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) { (void) web_view; @@ -582,7 +598,6 @@ VIEWFUNC(go_forward) #undef VIEWFUNC /* -- command to callback/function map for things we cannot attach to any signals */ -// TODO: reload static struct {char *name; Command command[2];} cmdlist[] = { /* key function no_split */ { "back", {view_go_back, 0} }, @@ -952,7 +967,7 @@ expand_template(const char *template, gboolean escape_markup) { token = g_scanner_get_next_token(uzbl.scan); if(token == G_TOKEN_SYMBOL) { - sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol; + sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol); switch(sym) { case SYM_URI: if(escape_markup) { @@ -1136,6 +1151,9 @@ run_command (const gchar *command, const guint npre, const gchar **args, g_string_append_printf(s, " -- result: %s", (result ? "true" : "false")); printf("%s\n", s->str); g_string_free(s, TRUE); + if(stdout) { + printf("Stdout: %s\n", *stdout); + } } if (err) { g_printerr("error on run_command: %s\n", err->message); @@ -1348,6 +1366,11 @@ cmd_font_size() { } static void +cmd_zoom_level() { + webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level); +} + +static void cmd_disable_plugins() { g_object_set (G_OBJECT(view_settings()), "enable-plugins", !uzbl.behave.disable_plugins, NULL); @@ -1527,6 +1550,11 @@ set_var_value(gchar *name, gchar *val) { buf = expand_vars(val); *ip = (int)strtoul(buf, &endp, 10); g_free(buf); + } else if (c->type == TYPE_FLOAT) { + float *fp = (float *)c->ptr; + buf = expand_vars(val); + *fp = strtof(buf, &endp); + g_free(buf); } /* invoke a command specific function */ @@ -1977,6 +2005,7 @@ create_browser () { g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view); return scrolled_window; } @@ -2124,6 +2153,8 @@ add_binding (const gchar *key, const gchar *act) { printf ("Binding %-10s : %s\n", key, act); action = new_action(parts[0], parts[1]); + if (g_hash_table_remove (uzbl.bindings, key)) + g_warning ("Overwriting existing binding for \"%s\"", key); g_hash_table_replace(uzbl.bindings, g_strdup(key), action); g_strfreev(parts); } @@ -2213,7 +2244,8 @@ settings_init () { static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ (void) session; (void) user_data; - if (!uzbl.behave.cookie_handler) return; + if (!uzbl.behave.cookie_handler) + return; soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); GString *s = g_string_new (""); @@ -2221,10 +2253,13 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path); run_handler(uzbl.behave.cookie_handler, s->str); - if(uzbl.comm.sync_stdout) - soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout); - //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging - if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { + char *p = strchr(uzbl.comm.sync_stdout, '\n' ); + if ( p != NULL ) *p = '\0'; + soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout); + } + if (uzbl.comm.sync_stdout) + uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); g_string_free(s, TRUE); } @@ -149,6 +149,7 @@ typedef struct { guint font_size; guint monospace_size; guint minimum_font_size; + gfloat zoom_level; guint disable_plugins; guint disable_scripts; guint autoload_img; @@ -248,6 +249,9 @@ print(WebKitWebView *page, GArray *argv); static gboolean new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); +static gboolean +mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data); + WebKitWebView* create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data); @@ -474,10 +478,15 @@ cmd_max_conns(); static void cmd_max_conns_host(); +/* exported WebKitWebSettings properties */ + static void cmd_font_size(); static void +cmd_zoom_level(); + +static void cmd_disable_plugins(); static void @@ -23,7 +23,7 @@ static gchar* command; static GOptionEntry entries[] = { - { "socket", 's', 0, G_OPTION_ARG_STRING, &sockpath, "Socket path of the client uzbl", NULL }, + { "socket", 's', 0, G_OPTION_ARG_STRING, &sockpath, "Path to the uzbl socket", NULL }, { "command", 'c', 0, G_OPTION_ARG_STRING, &command, "The uzbl command to execute", NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; @@ -31,7 +31,7 @@ static GOptionEntry entries[] = int main(int argc, char* argv[]) { GError *error = NULL; - GOptionContext* context = g_option_context_new ("- some stuff here maybe someday"); + GOptionContext* context = g_option_context_new ("- utility for controlling and interacting with uzbl through its socket file"); //TODO: get stuff back from uzbl g_option_context_add_main_entries (context, entries, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); g_option_context_parse (context, &argc, &argv, &error); @@ -64,8 +64,7 @@ main(int argc, char* argv[]) { return 0; } else { - printf ("You need to specify the -s and -c parameters for uzblctrl to do anything of use.\n"); - printf ("Usage: uzblctrl -s /path/to/socket -c \"command\"\n"); + puts ("Usage: uzblctrl -s /path/to/socket -c \"command\""); return 1; } } |