diff options
33 files changed, 1058 insertions, 594 deletions
@@ -39,6 +39,7 @@ In alphabetical order: Dmytro Milinevskyy - uzbl-tabbed useability patches Dusan Popovic (dusanx) - many contributions to early uzbl Evgeny Grablyk - libsoup settings + Gustavo Chaín <g@0xff.cl> - newbg command Gregor Uhlenheuer (kongo2002) <kongo2002@googlemail.com> - uzbl vim syntax & related files Helmut Grohne (helmut) - move void **ptr to union, various fixes Henri Kemppainen (DuClare) <email is akarinotengoku AT THE DOMAIN OF gmail.com> - many contributions, mostly old handler code @@ -49,8 +50,10 @@ In alphabetical order: Jan Kolkmeier (jouz) - scrolling, link following Jason Woofenden (JasonWoof) - geometry=maximized, link following Laurence Withers (lwithers) - talk_to_socket + Luca Bruno <lucab@debian.org> - bashims fixes Mark Nevill - misc patches Mason Larobina (mason-l) <mason.larobina@gmail.com> - uzbl-tabbed, uzbl-cookie-daemon, uzbl-event-manager & plugins, uzbl vim syntax ... + Matthew Bauer <mjbauer95@gmail.com> - userscripts Maximilian Gaß (mxey) - several small patches Michael Fiano (axionix) - added cookie_daemon.py whitelist Michael Walker (Barrucadu) <mike AT barrucadu.co.uk> - contributions to early uzbl @@ -76,6 +76,7 @@ clean: rm -f events.o rm -f callbacks.o rm -f inspector.o + rm -f cookie-jar.o find ./examples/ -name "*.pyc" -delete cd ./tests/; $(MAKE) clean rm -rf ./sandbox/ diff --git a/examples/config/config b/examples/config/config index b6d9fe3..ef5c122 100644 --- a/examples/config/config +++ b/examples/config/config @@ -34,7 +34,8 @@ 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 = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data:scripts +set scripts_util_dir = @scripts_dir/util # === Hardcoded handlers ===================================================== @@ -64,6 +65,9 @@ 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 + # Load finish handlers @on_event LOAD_FINISH @set_status <span foreground="gold">done</span> @on_event LOAD_FINISH spawn @scripts_dir/history.sh @@ -121,6 +125,7 @@ set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}.@{WEBKIT_MI @modmap <Control> <Ctrl> @modmap <ISO_Left_Tab> <Shift-Tab> @modmap <space> <Space> +@modmap <KP_Enter> <Enter> #modkey_addition <Key1> <Key2> <Result> @modkey_addition <Shift> <Ctrl> <Meta> @@ -130,6 +135,7 @@ set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}.@{WEBKIT_MI #ignore_key <glob> @ignore_key <ISO_*> @ignore_key <Shift> +@ignore_key <Multi_key> # --- Bind aliases ----------------------------------------------------------- @@ -188,8 +194,12 @@ set ebind = @mode_bind global,-insert @cbind l = scroll horizontal 20 @cbind <Page_Up> = scroll vertical -100% @cbind <Page_Down> = scroll vertical 100% +@cbind <Ctrl>f = scroll vertical 100% +@cbind <Ctrl>b = scroll vertical -100% @cbind << = scroll vertical begin @cbind >> = scroll vertical end +@cbind <Home> = scroll vertical begin +@cbind <End> = scroll vertical end @cbind ^ = scroll horizontal begin @cbind $ = scroll horizontal end @cbind <Space> = scroll vertical end @@ -253,8 +263,12 @@ set ebind = @mode_bind global,-insert # 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 +# Clone current window +@cbind c = sh 'uzbl-browser -u $6' # Go the page from primary selection @cbind p = sh 'echo "uri `xclip -selection primary -o | sed s/\\\@/%40/g`" > $4' # Go to the page in clipboard @@ -265,7 +279,7 @@ set ebind = @mode_bind global,-insert @bind <Shift-Insert> = sh 'echo "event INJECT_KEYCMD `xclip -o | sed s/\\\@/%40/g`" > $4' # Bookmark inserting binds -@cbind <Ctrl>b<tags:>_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +@cbind <Ctrl>b<tags:>_ = sh 'echo `printf "$6 %s"` >> $XDG_DATA_HOME/uzbl/bookmarks' # Or use a script to insert a bookmark. @cbind B = spawn @scripts_dir/insert_bookmark.sh @@ -279,7 +293,8 @@ set follow_hint_keys = 0123456789 #set follow_hint_keys = qwerty #set follow_hint_keys = asdfghjkl; #set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234 -@cbind fl* = script @scripts_dir/follow.js '@follow_hint_keys %s' +@cbind fl* = spawn @scripts_dir/follow.sh "%s" +@cbind gi = spawn @scripts_dir/go_input.sh # Form filler binds # This script allows you to configure (per domain) values to fill in form @@ -299,7 +314,12 @@ set formfiller = spawn @scripts_dir/formfiller.sh @cbind gN = event NEW_TAB_NEXT @cbind go<uri:>_ = event NEW_TAB %s @cbind gO<uri:>_ = event NEW_TAB_NEXT %s -@cbind gY = sh 'echo "event NEW_TAB `xclip -selection primary -o | sed s/\\\@/%40/g`" > $4' +@cbind gy = sh 'echo "event NEW_TAB `xclip -selection primary -o | sed s/\\\@/%40/g`" > $4' +@cbind gY = sh 'echo "event NEW_TAB_NEXT `xclip -selection primary -o | sed s/\\\@/%40/g`" > $4' + +# Clone current tab +@cbind gd = sh 'echo "event NEW_TAB $6" > $4' +@cbind gD = sh 'echo "event NEW_TAB_NEXT $6" > $4' # Closing / resting @cbind gC = exit @@ -353,13 +373,13 @@ set stack = @mode_config stack @insert modcmd_updates = 0 # Multi-stage-binding mode config. -@stack keycmd_events = 1 -@stack modcmd_updates = 1 -@stack forward_keys = 0 @stack keycmd_style = foreground="red" -@stack prompt_style = foreground="#888" weight="light" @stack status_background = #202020 @stack mode_indicator = Bnd +@stack prompt_style = foreground="#888" weight="light" +@stack keycmd_events = 1 +@stack modcmd_updates = 1 +@stack forward_keys = 0 set default_mode = command diff --git a/examples/data/scripts/auth.py b/examples/data/scripts/auth.py index 4feb90b..9c1b4fc 100755 --- a/examples/data/scripts/auth.py +++ b/examples/data/scripts/auth.py @@ -4,50 +4,50 @@ import gtk import sys def responseToDialog(entry, dialog, response): - dialog.response(response) + dialog.response(response) def getText(authInfo, authHost, authRealm): - dialog = gtk.MessageDialog( - None, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_QUESTION, - gtk.BUTTONS_OK_CANCEL, - None) - dialog.set_markup('%s at %s' % (authRealm, authHost)) + dialog = gtk.MessageDialog( + None, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_QUESTION, + gtk.BUTTONS_OK_CANCEL, + None) + dialog.set_markup('%s at %s' % (authRealm, authHost)) - login = gtk.Entry() - password = gtk.Entry() - password.set_visibility(False) + login = gtk.Entry() + password = gtk.Entry() + password.set_visibility(False) - login.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK) - password.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK) + login.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK) + password.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK) - hbox = gtk.HBox(); + hbox = gtk.HBox(); - vbox_entries = gtk.VBox(); - vbox_labels = gtk.VBox(); + vbox_entries = gtk.VBox(); + vbox_labels = gtk.VBox(); - vbox_labels.pack_start(gtk.Label("Login:"), False, 5, 5) - vbox_labels.pack_end(gtk.Label("Password:"), False, 5, 5) + vbox_labels.pack_start(gtk.Label("Login:"), False, 5, 5) + vbox_labels.pack_end(gtk.Label("Password:"), False, 5, 5) - vbox_entries.pack_start(login) - vbox_entries.pack_end(password) + vbox_entries.pack_start(login) + vbox_entries.pack_end(password) - dialog.format_secondary_markup("Please enter username and password:") - hbox.pack_start(vbox_labels, True, True, 0) - hbox.pack_end(vbox_entries, True, True, 0) + dialog.format_secondary_markup("Please enter username and password:") + hbox.pack_start(vbox_labels, True, True, 0) + hbox.pack_end(vbox_entries, True, True, 0) - dialog.vbox.pack_start(hbox) - dialog.show_all() - rv = dialog.run() + dialog.vbox.pack_start(hbox) + dialog.show_all() + rv = dialog.run() - output = login.get_text() + "\n" + password.get_text() - dialog.destroy() - return rv, output + output = login.get_text() + "\n" + password.get_text() + dialog.destroy() + return rv, output if __name__ == '__main__': - rv, output = getText(sys.argv[8], sys.argv[9], sys.argv[10]) - if (rv == gtk.RESPONSE_OK): - print output; - else: - exit(1) + rv, output = getText(sys.argv[8], sys.argv[9], sys.argv[10]) + if (rv == gtk.RESPONSE_OK): + print output; + else: + exit(1) diff --git a/examples/data/scripts/download.sh b/examples/data/scripts/download.sh index f6d34e9..7375535 100755 --- a/examples/data/scripts/download.sh +++ b/examples/data/scripts/download.sh @@ -2,21 +2,25 @@ # just an example of how you could handle your downloads # try some pattern matching on the uri to determine what we should do +source $UZBL_UTIL_DIR/uzbl-args.sh +source $UZBL_UTIL_DIR/uzbl-dir.sh + # Some sites block the default wget --user-agent.. -GET="wget --user-agent=Firefox --content-disposition --load-cookies=$XDG_DATA_HOME/uzbl/cookies.txt" +GET="wget --user-agent=Firefox --content-disposition --load-cookies=$UZBL_COOKIE_JAR" -dest="$HOME" -url="$8" +url="$1" -http_proxy="$9" +http_proxy="$2" export http_proxy -test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } +if [ -z "$url" ]; then + echo "you must supply a url! ($url)" + exit 1 +fi # only changes the dir for the $get sub process -if echo "$url" | grep -E '.*\.torrent' >/dev/null; -then - ( cd "$dest"; $GET "$url") +if echo "$url" | grep -E '.*\.torrent' >/dev/null; then + ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url") else - ( cd "$dest"; $GET "$url") + ( cd "$UZBL_DOWNLOAD_DIR"; $GET "$url") fi diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js index a42447c..eacd52f 100644 --- a/examples/data/scripts/follow.js +++ b/examples/data/scripts/follow.js @@ -130,17 +130,26 @@ function clickElem(item) { if (name == 'A') { item.click(); window.location = item.href; + return "XXXRESET_MODEXXX"; } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + var type; + try { + type = item.getAttribute('type').toUpperCase(); + } catch(err) { + type = 'TEXT'; + } + if (type == 'TEXT' || type == 'SEARCH' || type == 'PASSWORD') { item.focus(); item.select(); + return "XXXEMIT_FORM_ACTIVEXXX"; } else { item.click(); + return "XXXRESET_MODEXXX"; } } else if (name == 'TEXTAREA' || name == 'SELECT') { item.focus(); item.select(); + return "XXXEMIT_FORM_ACTIVEXXX"; } else { item.click(); window.location = item.href; @@ -193,38 +202,38 @@ function reDrawHints(elems, chars) { // pass: number of keys // returns: key length function labelLength(n) { - var oldn = n; - var keylen = 0; - if(n < 2) { - return 1; - } - n -= 1; // our highest key will be n-1 - while(n) { - keylen += 1; - n = Math.floor(n / charset.length); - } - return keylen; + var oldn = n; + var keylen = 0; + if(n < 2) { + return 1; + } + n -= 1; // our highest key will be n-1 + while(n) { + keylen += 1; + n = Math.floor(n / charset.length); + } + return keylen; } // pass: number // returns: label function intToLabel(n) { - var label = ''; - do { - label = charset.charAt(n % charset.length) + label; - n = Math.floor(n / charset.length); - } while(n); - return label; + var label = ''; + do { + label = charset.charAt(n % charset.length) + label; + n = Math.floor(n / charset.length); + } while(n); + return label; } // pass: label // returns: number function labelToInt(label) { - var n = 0; - var i; - for(i = 0; i < label.length; ++i) { - n *= charset.length; - n += charset.indexOf(label[i]); - } - return n; + var n = 0; + var i; + for(i = 0; i < label.length; ++i) { + n *= charset.length; + n += charset.indexOf(label[i]); + } + return n; } //Put it all together function followLinks(follow) { @@ -242,7 +251,7 @@ function followLinks(follow) { var oldDiv = doc.getElementById(uzbldivid); var leftover = [[], []]; if (s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); + return clickElem(elems[0][linknr]); } else { for (var j = 0; j < elems[0].length; j++) { var b = true; diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh new file mode 100755 index 0000000..ba59575 --- /dev/null +++ b/examples/data/scripts/follow.sh @@ -0,0 +1,21 @@ +#!/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/follow.js "@{follow_hint_keys} '$1'"' | socat - unix-connect:$socket) in + *XXXEMIT_FORM_ACTIVEXXX*) echo 'event FORM_ACTIVE' | socat - unix-connect:$socket ;; + *XXXRESET_MODEXXX*) echo 'set mode=' | socat - unix-connect:$socket ;; +esac diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh index 69eca17..6982f9a 100755 --- a/examples/data/scripts/formfiller.sh +++ b/examples/data/scripts/formfiller.sh @@ -2,12 +2,12 @@ # # Enhanced html form (eg for logins) filler (and manager) for uzbl. # -# uses settings files like: $keydir/<domain> +# uses settings files like: $UZBL_FORMS_DIR/<domain> # files contain lines like: !profile=<profile_name> # <fieldname>(fieldtype): <value> -# profile_name should be replaced with a name that will tell sth about that +# profile_name should be replaced with a name that will tell sth about that # profile -# fieldtype can be checkbox, text or password, textarea - only for information +# fieldtype can be checkbox, text or password, textarea - only for information # pupropse (auto-generated) - don't change that # # Texteares: for textareas edited text can be now splitted into more lines. @@ -37,62 +37,31 @@ # something else (or empty): if file not available: new, otherwise load. # -# config dmenu colors and prompt -NB="#0f0f0f" -NF="#4e7093" -SB="#003d7c" -SF="#3a9bff" +DMENU_ARGS="-i" +DMENU_SCHEMA="formfiller" +DMENU_LINES="3" +DMENU_PROMPT="Choose profile" +DMENU_OPTIONS="vertical resize" -if [ "`dmenu --help 2>&1| grep lines`x" != "x" ] -then - LINES=" -l 3 " -else - LINES="" -fi +source $UZBL_UTIL_DIR/dmenu.sh +source $UZBL_UTIL_DIR/editor.sh +source $UZBL_UTIL_DIR/uzbl-args.sh +source $UZBL_UTIL_DIR/uzbl-dir.sh -PROMPT="Choose profile" +RAND=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -c 1-5) MODELINE="> vim:ft=formfiller" -keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/dforms +[ -d "$(dirname $UZBL_FORMS_DIR)" ] || exit 1 +[ -d $UZBL_FORMS_DIR ] || mkdir $UZBL_FORMS_DIR || exit 1 -[ -d "`dirname $keydir`" ] || exit 1 -[ -d "$keydir" ] || mkdir "$keydir" - -editor="${VISUAL}" -if [ -z "${editor}" ]; then - if [ -z "${EDITOR}" ]; then - editor='xterm -e vim' - else - editor="xterm -e ${EDITOR}" - fi -fi - -config=$1; -shift -pid=$1; -shift -xid=$1; -shift -fifo=$1; -shift -socket=$1; -shift -url=$1; -shift -title=$1; -shift action=$1 -[ -d $keydir ] || mkdir $keydir || exit 1 - -domain=$(echo $url | sed 's/\(http\|https\):\/\/\([^\/]\+\)\/.*/\2/') +domain=$(echo $UZBL_URL | sed 's/\(http\|https\):\/\/\([^\/]\+\)\/.*/\2/') -if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' -a "$action" != 'add' -a "$action" != 'once' ] -then +if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' -a "$action" != 'add' -a "$action" != 'once' ]; then action="new" - [ -e "$keydir/$domain" ] && action="load" -elif [ "$action" = 'edit' ] && [ ! -e "$keydir/$domain" ] -then + [ -e "$UZBL_FORMS_DIR/$domain" ] && action="load" +elif [ "$action" = 'edit' ] && [ ! -e "$UZBL_FORMS_DIR/$domain" ]; then action="new" fi @@ -152,41 +121,38 @@ insertFunction="function insert(fname, ftype, fvalue, fchecked) { \ } \ }; " -if [ "$action" = 'load' ] -then - [ -e $keydir/$domain ] || exit 2 - if [ `cat $keydir/$domain|grep "!profile"|wc -l` -gt 1 ] - then - menu=`cat $keydir/$domain| \ - sed -n 's/^!profile=\([^[:blank:]]\+\)/\1/p'` - option=`echo -e -n "$menu"| dmenu ${LINES} -nb "${NB}" -nf "${NF}" -sb "${SB}" -sf "${SF}" -p "${PROMPT}"` +if [ "$action" = 'load' ]; then + [ -e $UZBL_FORMS_DIR/$domain ] || exit 2 + if [ $(cat $UZBL_FORMS_DIR/$domain | grep "!profile" | wc -l) -gt 1 ]; then + menu=$(cat $UZBL_FORMS_DIR/$domain | \ + sed -n 's/^!profile=\([^[:blank:]]\+\)/\1/p') + option=$(printf "$menu" | $DMENU) fi # Remove comments sed '/^>/d' -i $tmpfile - sed 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' -i $keydir/$domain - fields=`cat $keydir/$domain | \ + sed 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' -i $UZBL_FORMS_DIR/$domain + fields=$(cat $UZBL_FORMS_DIR/$domain | \ sed -n "/^!profile=${option}/,/^!profile=/p" | \ sed '/^!profile=/d' | \ sed 's/^\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):/%{>\1\2):<}%/' | \ sed 's/^\(.\+\)$/<{br}>\1/' | \ tr -d '\n' | \ - sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g'` + sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g') printf '%s\n' "${fields}" | \ sed -n -e "s/\([^(]\+\)(\(password\|text\|search\|textarea\)\+):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\2', '\3', 0);/p" | \ - sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' > $fifo + sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' | socat - unix-connect:$UZBL_SOCKET printf '%s\n' "${fields}" | \ sed -n -e "s/\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\3', '\2', \4);/p" | \ - sed -e 's/@/\\@/g' > $fifo -elif [ "$action" = "once" ] -then - tmpfile=`mktemp` + sed -e 's/@/\\@/g' | socat - unix-connect:$UZBL_SOCKET +elif [ "$action" = "once" ]; then + tmpfile=$(mktemp) printf 'js %s dump(); \n' "$dumpFunction" | \ - socat - unix-connect:$socket | \ + socat - unix-connect:$UZBL_SOCKET | \ sed -n '/^[^(]\+([^)]\+):/p' > $tmpfile echo "$MODELINE" >> $tmpfile - ${editor} $tmpfile + $UZBL_EDITOR $tmpfile [ -e $tmpfile ] || exit 2 @@ -194,23 +160,22 @@ then sed '/^>/d' -i $tmpfile sed 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' -i $tmpfile - fields=`cat $tmpfile | \ + fields=$(cat $tmpfile | \ sed 's/^\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):/%{>\1\2):<}%/' | \ sed 's/^\(.\+\)$/<{br}>\1/' | \ tr -d '\n' | \ - sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g'` + sed 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g') printf '%s\n' "${fields}" | \ sed -n -e "s/\([^(]\+\)(\(password\|text\|search\|textarea\)\+):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\2', '\3', 0);/p" | \ - sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' > $fifo + sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' | socat - unix-connect:$UZBL_SOCKET printf '%s\n' "${fields}" | \ sed -n -e "s/\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\3', '\2', \4);/p" | \ - sed -e 's/@/\\@/g' > $fifo + sed -e 's/@/\\@/g' | socat - unix-connect:$UZBL_SOCKET rm -f $tmpfile else - if [ "$action" = 'new' -o "$action" = 'add' ] - then - [ "$action" = 'new' ] && echo "$MODELINE" > $keydir/$domain - echo "!profile=NAME_THIS_PROFILE$RANDOM" >> $keydir/$domain + if [ "$action" = 'new' -o "$action" = 'add' ]; then + [ "$action" = 'new' ] && echo "$MODELINE" > $UZBL_FORMS_DIR/$domain + echo "!profile=NAME_THIS_PROFILE$RAND" >> $UZBL_FORMS_DIR/$domain # # 2. and 3. line (tr -d and sed) are because, on gmail login for example, # <input > tag is splited into lines @@ -228,11 +193,11 @@ else # passwd(password): # printf 'js %s dump(); \n' "$dumpFunction" | \ - socat - unix-connect:$socket | \ - sed -n '/^[^(]\+([^)]\+):/p' >> $keydir/$domain + socat - unix-connect:$UZBL_SOCKET | \ + sed -n '/^[^(]\+([^)]\+):/p' >> $UZBL_FORMS_DIR/$domain fi - [ -e "$keydir/$domain" ] || exit 3 #this should never happen, but you never know. - $editor "$keydir/$domain" #TODO: if user aborts save in editor, the file is already overwritten + [ -e "$UZBL_FORMS_DIR/$domain" ] || exit 3 #this should never happen, but you never know. + $UZBL_EDITOR "$UZBL_FORMS_DIR/$domain" #TODO: if user aborts save in editor, the file is already overwritten fi # vim:fileencoding=utf-8:sw=4 diff --git a/examples/data/scripts/go_input.js b/examples/data/scripts/go_input.js new file mode 100644 index 0000000..557671f --- /dev/null +++ b/examples/data/scripts/go_input.js @@ -0,0 +1,27 @@ +var elements = document.querySelectorAll("textarea, input" + [ + ":not([type='button'])", + ":not([type='checkbox'])", + ":not([type='hidden'])", + ":not([type='image'])", + ":not([type='radio'])", + ":not([type='reset'])", + ":not([type='submit'])"].join("")); +function gi() { + if (elements) { + var el, i = 0; + while((el = elements[i++])) { + var style=getComputedStyle(el, null); + if (style.display !== 'none' && style.visibility === 'visible') { + if (el.type === "file") { + el.click(); + } + else { + el.focus(); + } + return "XXXEMIT_FORM_ACTIVEXXX"; + } + } + } +} + +gi(); diff --git a/examples/data/scripts/go_input.sh b/examples/data/scripts/go_input.sh new file mode 100755 index 0000000..c873dd8 --- /dev/null +++ b/examples/data/scripts/go_input.sh @@ -0,0 +1,20 @@ +#!/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 ;; +esac diff --git a/examples/data/scripts/history.sh b/examples/data/scripts/history.sh index 7c83aa6..b91d415 100755 --- a/examples/data/scripts/history.sh +++ b/examples/data/scripts/history.sh @@ -1,5 +1,7 @@ #!/bin/sh -file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history -[ -d `dirname $file` ] || exit 1 -echo `date +'%Y-%m-%d %H:%M:%S'`" $6 $7" >> $file +source $UZBL_UTIL_DIR/uzbl-dir.sh + +[ -w "$UZBL_HISTORY_FILE" ] || exit 1 + +echo $(date +'%Y-%m-%d %H:%M:%S')" $6 $7" >> $UZBL_HISTORY_FILE diff --git a/examples/data/scripts/insert_bookmark.sh b/examples/data/scripts/insert_bookmark.sh index d0ec84e..acef37e 100755 --- a/examples/data/scripts/insert_bookmark.sh +++ b/examples/data/scripts/insert_bookmark.sh @@ -1,18 +1,19 @@ #!/bin/sh -[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1 -file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks +source $UZBL_UTIL_DIR/uzbl-dir.sh -which zenity &>/dev/null || exit 2 -url=$6 +[ -d "$UZBL_DATA_DIR" ] || exit 1 +[ -w "$UZBL_BOOKMARKS_FILE" ] || exit 1 + +which zenity 2>&1 >/dev/null || exit 2 # replace tabs, they are pointless in titles and we want to use tabs as delimiter. -title=$(echo "$7" | sed 's/\t/ /') -entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$url $title\t"` +title=$(echo "$UZBL_TITLE" | sed 's/\t/ /') +entry=$(zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$UZBL_URL $title\t") exitstatus=$? if [ $exitstatus -ne 0 ]; then exit $exitstatus; fi -url=`echo $entry | awk '{print $1}'` +url=$(echo $entry | awk '{print $1}') # TODO: check if already exists, if so, and tags are different: ask if you want to replace tags echo "$entry" >/dev/null #for some reason we need this.. don't ask me why -echo -e "$entry" >> $file +printf "$entry\n" >> $UZBL_BOOKMARKS_FILE true diff --git a/examples/data/scripts/instance-select-wmii.sh b/examples/data/scripts/instance-select-wmii.sh index fdd27e6..e70a143 100755 --- a/examples/data/scripts/instance-select-wmii.sh +++ b/examples/data/scripts/instance-select-wmii.sh @@ -11,44 +11,38 @@ # See http://www.uzbl.org/wiki/wmii for more info # $1 must be one of 'list', 'next', 'prev' -COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" +DMENU_SCHEME="wmii" -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch -else - DMENU="dmenu -i" -fi +source $UZBL_UTIL_DIR/dmenu.sh -if [ "$1" == 'list' ] -then - list= - # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky - for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2) - do - label=$(wmiir read /client/$i/label) - list="$list$i : $label\n" - done - window=$(echo -e "$list" | $DMENU $COLORS | cut -d ' ' -f1) - wmiir xwrite /tag/sel/ctl "select client $window" -elif [ "$1" == 'next' ] -then - current=$(wmiir read /client/sel/ctl | head -n 1) - # find the next uzbl window and focus it - next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2) - if [ x"$next" != "x" ] - then - wmiir xwrite /tag/sel/ctl "select client $next" - fi -elif [ "$1" == 'prev' ] -then - current=$(wmiir read /client/sel/ctl | head -n 1) - prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2) - if [ x"$prev" != "x" ] - then - wmiir xwrite /tag/sel/ctl "select client $prev" - fi -else - echo "\$1 not valid" >&2 - exit 2 -fi +case "$1" in + "list" ) + list= + # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky + for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2); do + label=$(wmiir read /client/$i/label) + list="$list$i : $label\n" + done + window=$(printf "$list\n" | $DMENU | cut -d ' ' -f1) + wmiir xwrite /tag/sel/ctl "select client $window" + ;; + "next" ) + current=$(wmiir read /client/sel/ctl | head -n 1) + # find the next uzbl window and focus it + next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2) + if [ -n "$next" ]; then + wmiir xwrite /tag/sel/ctl "select client $next" + fi + ;; + "prev" ) + current=$(wmiir read /client/sel/ctl | head -n 1) + prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2) + if [ -n "$prev" ]; then + wmiir xwrite /tag/sel/ctl "select client $prev" + fi + ;; + * ) + echo "$1 not valid" >&2 + exit 2 + ;; +esac diff --git a/examples/data/scripts/load_url_from_bookmarks.sh b/examples/data/scripts/load_url_from_bookmarks.sh index 1e9f9e7..564c3f8 100755 --- a/examples/data/scripts/load_url_from_bookmarks.sh +++ b/examples/data/scripts/load_url_from_bookmarks.sh @@ -1,20 +1,23 @@ -#!/bin/bash +#!/bin/sh #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. -file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks -[ -r "$file" ] || exit -COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch - # show tags as well - goto=`$DMENU $COLORS < $file | awk '{print $1}'` +DMENU_SCHEME="bookmarks" +DMENU_OPTIONS="xmms vertical resize" + +source $UZBL_UTIL_DIR/dmenu.sh +source $UZBL_UTIL_DIR/uzbl-args.sh +source $UZBL_UTIL_DIR/uzbl-dir.sh + +[ -r "$UZBL_BOOKMARKS_FILE" ] || exit 1 + +if [ -z "$DMENU_HAS_VERTICAL" ]; then + # because they are all after each other, just show the url, not their tags. + goto=$(awk '{print $1}' $UZBL_BOOKMARKS_FILE | $DMENU) else - DMENU="dmenu -i" - # because they are all after each other, just show the url, not their tags. - goto=`awk '{print $1}' $file | $DMENU $COLORS` + # show tags as well + goto=$($DMENU < $UZBL_BOOKMARKS_FILE | awk '{print $1}') fi -#[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 +#[ -n "$goto" ] && echo "uri $goto" > $UZBL_FIFO +[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$UZBL_SOCKET diff --git a/examples/data/scripts/load_url_from_history.sh b/examples/data/scripts/load_url_from_history.sh index 62e02ac..d094625 100755 --- a/examples/data/scripts/load_url_from_history.sh +++ b/examples/data/scripts/load_url_from_history.sh @@ -1,24 +1,25 @@ #!/bin/sh -history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history -[ -r "$history_file" ] || exit 1 +DMENU_SCHEME="history" +DMENU_OPTIONS="xmms vertical resize" + +source $UZBL_UTIL_DIR/dmenu.sh +source $UZBL_UTIL_DIR/uzbl-args.sh +source $UZBL_UTIL_DIR/uzbl-dir.sh + +[ -r "$UZBL_HISTORY_FILE" ] || exit 1 # choose from all entries, sorted and uniqued -# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` -COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'; -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch - # choose an item in reverse order, showing also the date and page titles - # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. - goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` +# goto=$(awk '{print $3}' $history_file | sort -u | dmenu -i) +if [ -z "$DMENU_HAS_VERTICAL" ]; then + current=$(tail -n 1 $UZBL_HISTORY_FILE | awk '{print $3}'); + goto=$((echo $current; awk '{print $3}' $UZBL_HISTORY_FILE | grep -v "^$current\$" \ + | sort -u) | $DMENU) else - DMENU="dmenu -i" - # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order - current=`tail -n 1 $history_file | awk '{print $3}'`; - goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" \ - | sort -u) | $DMENU $COLORS` + # choose an item in reverse order, showing also the date and page titles + # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. + goto=$(tac $UZBL_HISTORY_FILE | $DMENU | cut -d ' ' -f -3 | awk '{print $NF}') fi -[ -n "$goto" ] && echo "uri $goto" > $4 -#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 +#[ -n "$goto" ] && echo "uri $goto" > $UZBL_FIFO +[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$UZBL_SOCKET diff --git a/examples/data/scripts/session.sh b/examples/data/scripts/session.sh index 1059b5e..89eeb7a 100755 --- a/examples/data/scripts/session.sh +++ b/examples/data/scripts/session.sh @@ -8,55 +8,62 @@ # and doesn't need to be called manually at any point. # Add a line like 'bind quit = /path/to/session.sh endsession' to your config -[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1 -scriptfile=$0 # this script -sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/browser-session # the file in which the "session" (i.e. urls) are stored -configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file -UZBL="uzbl-browser -c $configfile" # add custom flags and whatever here. - -fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere -thisfifo="$4" -act="$8" -url="$6" - -if [ "$act." = "." ]; then - act="$1" -fi +source $UZBL_UTIL_DIR/uzbl-args.sh +source $UZBL_UTIL_DIR/uzbl-dir.sh + +[ -d $UZBL_DATA_DIR ] || exit 1 + +scriptfile=$0 # this script +UZBL="uzbl-browser -c $UZBL_CONFIG_FILE" # add custom flags and whatever here. + +act="$1" +# Test if we were run alone or from uzbl +if [ -z "$UZBL_SOCKET" ]; then + # Take the old config + act="$UZBL_CONFIG" +fi case $act in - "launch" ) - urls=`cat $sessionfile` - if [ "$urls." = "." ]; then - $UZBL - else - for url in $urls; do - $UZBL --uri "$url" & - done - fi - exit 0 - ;; - - "endinstance" ) - if [ "$url" != "(null)" ]; then - echo "$url" >> $sessionfile; - fi - echo "exit" > "$thisfifo" - ;; - - "endsession" ) - mv "$sessionfile" "$sessionfile~" - for fifo in $fifodir/uzbl_fifo_*; do - if [ "$fifo" != "$thisfifo" ]; then - echo "spawn $scriptfile endinstance" > "$fifo" - fi - done - echo "spawn $scriptfile endinstance" > "$thisfifo" - ;; - - * ) echo "session manager: bad action" - echo "Usage: $scriptfile [COMMAND] where commands are:" - echo " launch - Restore a saved session or start a new one" - echo " endsession - Quit the running session. Must be called from uzbl" - ;; + "launch" ) + urls=$(cat $UZBL_SESSION_FILE) + if [ -z "$urls" ]; then + $UZBL + else + for url in $urls; do + $UZBL --uri "$url" & + disown + done + fi + exit 0 + ;; + + "endinstance" ) + if [ -z "$UZBL_SOCKET" ]; then + echo "session manager: endinstance must be called from uzbl" + exit 1 + fi + if [ ! "$UZBL_URL" = "(null)" ]; then + echo "$UZBL_URL" >> $UZBL_SESSION_FILE + fi + echo "exit" | socat - unix-connect:$UZBL_SOCKET + ;; + + "endsession" ) + mv "$UZBL_SESSION_FILE" "$UZBL_SESSION_FILE~" + for sock in $UZBL_SOCKET_DIR/uzbl_fifo_*; do + if [ "$sock" != "$UZBL_SOCKET" ]; then + echo "spawn $scriptfile endinstance" | socat - unix-connect:$socket + fi + done + echo "spawn $scriptfile endinstance" | socat - unix-connect:$UZBL_SOCKET + ;; + + * ) + echo "session manager: bad action" + echo "Usage: $scriptfile [COMMAND] where commands are:" + echo " launch - Restore a saved session or start a new one" + echo " endinstance - Quit the current instance. Must be called from uzbl" + echo " endsession - Quit the running session." + ;; esac diff --git a/examples/data/scripts/userscript.sh b/examples/data/scripts/userscript.sh new file mode 100755 index 0000000..33a24ae --- /dev/null +++ b/examples/data/scripts/userscript.sh @@ -0,0 +1,40 @@ +#!/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 new file mode 100755 index 0000000..8896224 --- /dev/null +++ b/examples/data/scripts/userscripts.sh @@ -0,0 +1,8 @@ +#!/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 new file mode 100644 index 0000000..f789178 --- /dev/null +++ b/examples/data/scripts/util/dmenu.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# dmenu setup + +case "$DMENU_SCHEME" in + # wmii + "wmii" ) + NB="#303030" + NF="khaki" + SB="#ccffaa" + SF="#303030" + ;; + # Formfiller + "formfiller" ) + NB="#0f0f0f" + NF="#4e7093" + SB="#003d7c" + SF="#3a9bff" + ;; + # Bookmarks + "bookmarks" ) + NB="#303030" + NF="khaki" + SB="#ccffaa" + SF="#303030" + ;; + # History + "history" ) + NB="#303030" + NF="khaki" + SB="#ccffaa" + SF="#303030" + ;; + # Default + * ) + NB="#303030" + NF="khaki" + SB="#ccffaa" + SF="#303030" + ;; +esac + +DMENU_COLORS="-nb $NB -nf $NF -sb $SB -sf $SF" + +# Default arguments +if [ -z "$DMENU_ARGS" ]; then + DMENU_ARGS="-i" +fi + +# Set the font if wanted +if [ -n "$DMENU_FONT" ]; then + DMENU_ARGS="$DMENU_ARGS -fn $DMENU_FONT" +fi + +# Set the prompt if wanted +if [ -n "$DMENU_PROMPT" ]; then + DMENU_ARGS="$DMENU_ARGS -p $DMENU_PROMPT" +fi + +# Detect the xmms patch +if dmenu --help 2>&1 | grep -q '\[-xs\]'; then + DMENU_XMMS_ARGS="-xs" + DMENU_HAS_XMMS=1 + + if echo $DMENU_OPTIONS | grep -q -w 'xmms'; then + DMENU_ARGS="$DMENU_ARGS $DMENU_XMMS_ARGS" + fi +fi + +# Detect the vertical patch +if dmenu --help 2>&1 | grep -q '\[-l <lines>\]'; then + # Default to 10 lines + if [ -z "$DMENU_LINES" ]; then + DMENU_LINES=10 + fi + + DMENU_VERTICAL_ARGS="-l $DMENU_LINES" + DMENU_HAS_VERTICAL=1 + + # Detect the resize patch + if dmenu --help 2>&1 | grep -q '\[-rs\]'; then + DMENU_RESIZE_ARGS="-rs" + DMENU_HAS_RESIZE=1 + fi + + if echo $DMENU_OPTIONS | grep -q -w 'vertical'; then + DMENU_ARGS="$DMENU_ARGS $DMENU_VERTICAL_ARGS" + + if echo $DMENU_OPTIONS | grep -q -w 'resize'; then + DMENU_ARGS="$DMENU_ARGS $DMENU_RESIZE_ARGS" + fi + fi +fi + +# Detect placement patch +if dmenu --help 2>&1 | grep -q '\[-x <xoffset>\]'; then + DMENU_PLACE_X="-x" + DMENU_PLACE_Y="-y" + DMENU_PLACE_WIDTH="-w" + DMENU_PLACE_HEIGHT="-h" + DMENU_HAS_PLACEMENT=1 +fi + +DMENU="dmenu $DMENU_ARGS $DMENU_COLORS" diff --git a/examples/data/scripts/util/editor.sh b/examples/data/scripts/util/editor.sh new file mode 100644 index 0000000..1969769 --- /dev/null +++ b/examples/data/scripts/util/editor.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Editor selection + +if [ -z "$VTERM" ]; then + VTERM="xterm" +fi + +UZBL_EDITOR="$VISUAL" +if [ -z "$UZBL_EDITOR" ]; then + if [ -z "$EDITOR" ]; then + UZBL_EDITOR="$VTERM -e vim" + else + UZBL_EDITOR="$VTERM -e $EDITOR" + fi +fi diff --git a/examples/data/scripts/util/uzbl-args.sh b/examples/data/scripts/util/uzbl-args.sh new file mode 100644 index 0000000..7a3dbe5 --- /dev/null +++ b/examples/data/scripts/util/uzbl-args.sh @@ -0,0 +1,17 @@ +#!/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-dir.sh b/examples/data/scripts/util/uzbl-dir.sh new file mode 100644 index 0000000..bb56954 --- /dev/null +++ b/examples/data/scripts/util/uzbl-dir.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Common directories and files used in scripts + +# Common things first +UZBL_DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl +UZBL_CONFIG_DIR=${XDG_CONFIG_DIR:-$HOME/.config}/uzbl +UZBL_FIFO_DIR=/tmp +UZBL_SOCKET_DIR=/tmp + +# Directories +UZBL_DOWNLOAD_DIR=${XDG_DOWNLOAD_DIR:-$HOME} +UZBL_FORMS_DIR=$UZBL_DATA_DIR/dforms + +# Data files +UZBL_CONFIG_FILE=$UZBL_CONFIG_DIR/config +UZBL_COOKIE_FILE=$UZBL_DATA_DIR/cookies.txt +UZBL_BOOKMARKS_FILE=$UZBL_DATA_DIR/bookmarks +UZBL_HISTORY_FILE=$UZBL_DATA_DIR/history +UZBL_SESSION_FILE=$UZBL_DATA_DIR/browser-session diff --git a/examples/data/scripts/util/uzbl-window.sh b/examples/data/scripts/util/uzbl-window.sh new file mode 100644 index 0000000..b2771e4 --- /dev/null +++ b/examples/data/scripts/util/uzbl-window.sh @@ -0,0 +1,17 @@ +#!/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 | \ + sed -ne 's/-geometry[ ]*\([0-9]*\)x\([0-9]*\).*$/\1 \2/p') +UZBL_WIN_POS_X=$(echo $UZBL_WIN_POS | cut -d\ -f1) +UZBL_WIN_POS_Y=$(echo $UZBL_WIN_POS | cut -d\ -f2) +UZBL_WIN_WIDTH=$(echo $UZBL_WIN_SIZE | cut -d\ -f1) +UZBL_WIN_HEIGHT=$(echo $UZBL_WIN_SIZE | cut -d\ -f2) diff --git a/examples/data/scripts/uzbl-cookie-daemon b/examples/data/scripts/uzbl-cookie-daemon index ed88de4..0b9bef9 100755 --- a/examples/data/scripts/uzbl-cookie-daemon +++ b/examples/data/scripts/uzbl-cookie-daemon @@ -436,18 +436,26 @@ class CookieMonster: daemon_timeout = config['daemon_timeout'] echo("listening on %r" % config['cookie_socket']) + connections = [] + while self._running: # This line tells the socket how many pending incoming connections # to enqueue at once. Raising this number may or may not increase # performance. self.server_socket.listen(1) - if bool(select.select([self.server_socket], [], [], 1)[0]): - client_socket, _ = self.server_socket.accept() - self.handle_request(client_socket) + r, w, x = select.select([self.server_socket]+connections, [], [], 1) + + for socket in r: + if self.server_socket == socket: + client_socket, _ = socket.accept() + connections.append(client_socket) + else: + if not self.handle_request(socket): + # connection was closed, forget about the client socket + connections.remove(socket) + self.last_request = time.time() - client_socket.close() - continue if daemon_timeout: # Checks if the daemon has been idling for too long. @@ -462,7 +470,7 @@ class CookieMonster: # Receive cookie request from client. data = client_socket.recv(8192) if not data: - return + return False # Cookie argument list in packet is null separated. argv = data.split("\0") @@ -471,17 +479,17 @@ class CookieMonster: # Catch the EXIT command sent to kill running daemons. if action == "EXIT": self._running = False - return + return False # Catch whitelist RELOAD command. elif action == "RELOAD": self.reload_whitelist() - return + return True # Return if command unknown. elif action not in ['GET', 'PUT']: error("unknown command %r." % argv) - return + return True # Determine whether or not to print cookie data to terminal. print_cookie = (config['verbose'] and not config['daemon_mode']) @@ -499,13 +507,14 @@ class CookieMonster: req = urllib2.Request(uri) if action == "GET": - self.jar.add_cookie_header(req) - if req.has_header('Cookie'): - cookie = req.get_header('Cookie') - client_socket.send(cookie) - if print_cookie: - print cookie - + self.jar._policy._now = self._now = int(time.time()) + cookies = self.jar._cookies_for_request(req) + attrs = self.jar._cookie_attrs(cookies) + if attrs: + cookie = "; ".join(attrs) + client_socket.send(cookie) + if print_cookie: + print cookie else: client_socket.send("\0") @@ -515,10 +524,13 @@ class CookieMonster: print cookie self.put_cookie(req, cookie) + client_socket.send("\0") if print_cookie: print + return True + def put_cookie(self, req, cookie=None): '''Put a cookie in the cookie jar.''' diff --git a/examples/data/scripts/uzbl-tabbed b/examples/data/scripts/uzbl-tabbed index 5bf802a..42837d3 100755 --- a/examples/data/scripts/uzbl-tabbed +++ b/examples/data/scripts/uzbl-tabbed @@ -847,6 +847,8 @@ class UzblTabbed: # Commands ( [] = optional, {} = required ) # new [uri] # open new tab and head to optional uri. + # newbg [uri] + # open a new tab in the background # close [tab-num] # close current tab or close via tab id. # next [n-tabs] @@ -875,6 +877,12 @@ class UzblTabbed: else: self.new_tab() + elif cmd[0] == "newbg": + if len(cmd) == 2: + self.new_tab(cmd[1], switch=False) + else: + self.new_tab(switch=False) + elif cmd[0] == "newfromclip": uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ stdout=subprocess.PIPE).communicate()[0] diff --git a/src/callbacks.c b/src/callbacks.c index d2352b2..eb39a9d 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -589,9 +589,9 @@ motion_notify_cb(GtkWidget* window, GdkEventMotion* event, gpointer user_data) { (void) event; (void) user_data; - gchar *details; - details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state); + gchar *details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state); send_event(PTR_MOVE, details, NULL); + g_free(details); return FALSE; } @@ -703,11 +703,10 @@ create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) { if (strncmp(uri, "javascript:", strlen("javascript:")) == 0) { eval_js(uzbl.gui.web_view, (gchar*) uri + strlen("javascript:"), NULL, "javascript:"); + gtk_widget_destroy(GTK_WIDGET(web_view)); } else send_event(NEW_WINDOW, uri, NULL); - - gtk_widget_destroy(GTK_WIDGET(web_view)); } @@ -717,7 +716,7 @@ create_web_view_js_cb (WebKitWebView* web_view, gpointer user_data) { (void) user_data; g_object_connect (web_view, "signal::notify::uri", - G_CALLBACK(create_web_view_js2_cb), NULL); + G_CALLBACK(create_web_view_js2_cb), NULL, NULL); return TRUE; } @@ -831,38 +830,6 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) { } void -save_cookies_js(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie, gpointer user_data) { - (void) jar; - (void) user_data; - (void) old_cookie; - char *scheme; - GString *s; - - if(new_cookie != NULL) { - scheme = (new_cookie->secure == TRUE) ? "https" : "http"; - - s = g_string_new(""); - g_string_printf(s, "PUT '%s' '%s' '%s' '%s=%s'", scheme, new_cookie->domain, new_cookie->path, new_cookie->name, new_cookie->value); - run_handler(uzbl.behave.cookie_handler, s->str); - g_string_free(s, TRUE); - } -} - -void -save_cookies_http(SoupMessage *msg, gpointer user_data) { - (void) user_data; - GSList *ck; - char *cookie; - - for(ck = soup_cookies_from_response(msg); ck; ck = ck->next){ - cookie = soup_cookie_to_set_cookie_header(ck->data); - SoupURI *soup_uri = soup_message_get_uri(msg); - GString *s = g_string_new(""); - g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie); - run_handler(uzbl.behave.cookie_handler, s->str); - g_free (cookie); - g_string_free(s, TRUE); - } - - g_slist_free(ck); +cmd_set_cookie_handler() { + uzbl_cookie_jar_set_handler(uzbl.net.soup_cookie_jar, uzbl.behave.cookie_handler); } diff --git a/src/callbacks.h b/src/callbacks.h index fdd08e4..0b89f96 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -212,7 +212,4 @@ gboolean focus_cb(GtkWidget* window, GdkEventFocus* event, void *ud); void -save_cookies_js(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie, gpointer user_data); - -void -save_cookies_http(SoupMessage *msg, gpointer user_data); +cmd_set_cookie_handler(); diff --git a/src/cookie-jar.c b/src/cookie-jar.c new file mode 100644 index 0000000..f88acee --- /dev/null +++ b/src/cookie-jar.c @@ -0,0 +1,295 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <poll.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <string.h> +#include <errno.h> + +#include <libsoup/soup-uri.h> +#include <libsoup/soup-cookie.h> + +#include "cookie-jar.h" +#include "uzbl-core.h" + +static void +uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data); + +G_DEFINE_TYPE_WITH_CODE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR, + G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, uzbl_cookie_jar_session_feature_init)) + +static void request_started (SoupSessionFeature *feature, SoupSession *session, SoupMessage *msg, SoupSocket *socket); +static void changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie); + +static void setup_handler(UzblCookieJar *jar); + +static void connect_cookie_socket(UzblCookieJar *jar); +static void disconnect_cookie_socket(UzblCookieJar *jar); + +static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_len); + +static bool has_socket_handler(UzblCookieJar *jar) { + return jar->socket_path != NULL; +} + +static void +soup_cookie_jar_socket_init(UzblCookieJar *jar) { + jar->socket_path = NULL; + jar->connection_fd = -1; +} + +static void +finalize(GObject *object) { + disconnect_cookie_socket(UZBL_COOKIE_JAR(object)); + G_OBJECT_CLASS(soup_cookie_jar_socket_parent_class)->finalize(object); +} + +static void +soup_cookie_jar_socket_class_init(UzblCookieJarClass *socket_class) { + G_OBJECT_CLASS(socket_class)->finalize = finalize; + SOUP_COOKIE_JAR_CLASS(socket_class)->changed = changed; +} + +/* override SoupCookieJar's request_started handler */ +static void +uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data) { + (void) user_data; + iface->request_started = request_started; +} + +UzblCookieJar *uzbl_cookie_jar_new() { + return g_object_new(UZBL_TYPE_COOKIE_JAR, NULL); +} + +void +uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar* handler) { + jar->handler = handler; + setup_handler(jar); +} + +char *get_cookies(UzblCookieJar *jar, SoupURI *uri) { + gchar *result, *path; + GString *s = g_string_new ("GET"); + + path = uri->path[0] ? uri->path : "/"; + + if(has_socket_handler(jar)) { + g_string_append_c(s, 0); /* null-terminate the GET */ + g_string_append_len(s, uri->scheme, strlen(uri->scheme)+1); + g_string_append_len(s, uri->host, strlen(uri->host)+1 ); + g_string_append_len(s, path, strlen(path)+1 ); + + result = do_socket_request(jar, s->str, s->len); + /* try it again; older cookie daemons closed the connection after each request */ + if(result == NULL) + result = do_socket_request(jar, s->str, s->len); + } else { + g_string_append_printf(s, " '%s' '%s' '%s'", uri->scheme, uri->host, uri->path); + + run_handler(jar->handler, s->str); + result = g_strdup(uzbl.comm.sync_stdout); + } + g_string_free(s, TRUE); + return result; +} + +/* this is a duplicate of SoupCookieJar's request_started that uses our get_cookies instead */ +static void +request_started(SoupSessionFeature *feature, SoupSession *session, + SoupMessage *msg, SoupSocket *socket) { + (void) session; (void) socket; + + UzblCookieJar *jar = UZBL_COOKIE_JAR (feature); + SoupURI *uri = soup_message_get_uri(msg); + + gchar *cookies = get_cookies(jar, uri); + + if (cookies && *cookies != 0) { + const gchar *next_cookie_start = cookies; + + /* add the cookie data that we just obtained from the cookie handler + to the cookie jar so that javascript has access to them. + we set this flag so that we don't trigger the PUT handler. */ + jar->in_get_callback = true; + do { + SoupCookie *soup_cookie = soup_cookie_parse(next_cookie_start, uri); + if(soup_cookie) + soup_cookie_jar_add_cookie(SOUP_COOKIE_JAR(uzbl.net.soup_cookie_jar), soup_cookie); + next_cookie_start = strchr(next_cookie_start, ';'); + } while(next_cookie_start++ != NULL); + jar->in_get_callback = false; + + soup_message_headers_replace (msg->request_headers, "Cookie", cookies); + + g_free (cookies); + } else { + soup_message_headers_remove (msg->request_headers, "Cookie"); + } +} + +static void +changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) { + (void) old_cookie; + + UzblCookieJar *uzbl_jar = UZBL_COOKIE_JAR(jar); + + /* when Uzbl begins an HTTP request, it GETs cookies from the handler + and then adds them to the cookie jar so that javascript can access + these cookies. this causes a 'changed' callback, which we don't want + to do anything, so we just return. + + (if SoupCookieJar let us override soup_cookie_jar_get_cookies we + wouldn't have to do this.) */ + if(uzbl_jar->in_get_callback) + return; + + /* the cookie daemon is only interested in new cookies and changed + ones, it can take care of deleting expired cookies on its own. */ + if(!new_cookie) + return; + + GString *s = g_string_new ("PUT"); + + gchar *scheme = new_cookie->secure ? "https" : "http"; + + if(has_socket_handler(uzbl_jar)) { + g_string_append_c(s, 0); /* null-terminate the PUT */ + g_string_append_len(s, scheme, strlen(scheme)+1); + g_string_append_len(s, new_cookie->domain, strlen(new_cookie->domain)+1 ); + g_string_append_len(s, new_cookie->path, strlen(new_cookie->path)+1 ); + g_string_append_printf(s, "%s=%s", new_cookie->name, new_cookie->value); + + gchar *result = do_socket_request(uzbl_jar, s->str, s->len+1); + /* try it again; older cookie daemons closed the connection after each request */ + if(!result) + result = do_socket_request(uzbl_jar, s->str, s->len+1); + + g_free(result); + } else { + g_string_append_printf(s, " '%s' '%s' '%s' '%s=%s'", scheme, new_cookie->domain, new_cookie->path, new_cookie->name, new_cookie->value); + + run_handler(uzbl_jar->handler, s->str); + } + + g_string_free(s, TRUE); +} + +static void +setup_handler(UzblCookieJar *jar) { + if(strncmp(jar->handler, "talk_to_socket", strlen("talk_to_socket")) == 0) { + /* extract the socket path from the handler. */ + jar->socket_path = jar->handler + strlen("talk_to_socket"); + while(isspace(*jar->socket_path)) + jar->socket_path++; + if(*jar->socket_path == 0) + return; /* there was no path specified. */ + disconnect_cookie_socket(jar); + connect_cookie_socket(jar); + } else { + jar->socket_path = NULL; + } +} + +static void +connect_cookie_socket(UzblCookieJar *jar) { + struct sockaddr_un sa; + int fd; + + g_strlcpy(sa.sun_path, jar->socket_path, sizeof(sa.sun_path)); + sa.sun_family = AF_UNIX; + + /* create socket file descriptor and connect it to path */ + fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if(fd == -1) { + g_printerr("connect_cookie_socket: creating socket failed (%s)\n", strerror(errno)); + return; + } + + if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) { + g_printerr("connect_cookie_socket: connect failed (%s)\n", strerror(errno)); + close(fd); + return; + } + + /* successful connection! */ + jar->connection_fd = fd; +} + +static void +disconnect_cookie_socket(UzblCookieJar *jar) { + if(jar->connection_fd > 0) { + close(jar->connection_fd); + jar->connection_fd = -1; + } +} + +static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_length) { + int len; + ssize_t ret; + struct pollfd pfd; + gchar *result = NULL; + + if(jar->connection_fd < 0) + connect_cookie_socket(jar); /* connection was lost, reconnect */ + + /* write request */ + ret = write(jar->connection_fd, request, request_length); + if(ret == -1) { + g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno)); + disconnect_cookie_socket(jar); + return NULL; + } + + /* wait for a response, with a 500ms timeout */ + pfd.fd = jar->connection_fd; + pfd.events = POLLIN; + while(1) { + ret = poll(&pfd, 1, 500); + if(ret == 1) break; + if(ret == 0) errno = ETIMEDOUT; + if(errno == EINTR) continue; + g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n", + strerror(errno)); + if(errno != ETIMEDOUT) + disconnect_cookie_socket(jar); + return NULL; + } + + /* get length of response */ + if(ioctl(jar->connection_fd, FIONREAD, &len) == -1) { + g_printerr("talk_to_socket: cannot find daemon response length, " + "ioctl failed (%s)\n", strerror(errno)); + disconnect_cookie_socket(jar); + return NULL; + } + + /* there was an empty response. */ + if(len == 0) + return g_strdup(""); + + /* there is a response, read it */ + result = g_malloc(len + 1); + if(!result) { + g_printerr("talk_to_socket: failed to allocate %d bytes\n", len); + return NULL; + } + result[len] = 0; /* ensure result is null terminated */ + + gchar *p = result; + while(len > 0) { + ret = read(jar->connection_fd, p, len); + if(ret == -1) { + g_printerr("talk_to_socket: failed to read from socket (%s)\n", + strerror(errno)); + disconnect_cookie_socket(jar); + g_free(result); + return NULL; + } else { + len -= ret; + p += ret; + } + } + + return result; +} diff --git a/src/cookie-jar.h b/src/cookie-jar.h new file mode 100644 index 0000000..80af00e --- /dev/null +++ b/src/cookie-jar.h @@ -0,0 +1,33 @@ +#ifndef UZBL_COOKIE_JAR_H +#define UZBL_COOKIE_JAR_H + +#include <libsoup/soup-cookie-jar.h> + +#define UZBL_TYPE_COOKIE_JAR (soup_cookie_jar_socket_get_type ()) +#define UZBL_COOKIE_JAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UZBL_TYPE_COOKIE_JAR, UzblCookieJar)) +#define UZBL_COOKIE_JAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UZBL_TYPE_COOKIE_JAR, UzblCookieJarClass)) + +typedef struct { + SoupCookieJar parent; + + const gchar *handler; + + const gchar *socket_path; + int connection_fd; + + gboolean in_get_callback; +} UzblCookieJar; + +typedef struct { + SoupCookieJarClass parent_class; +} UzblCookieJarClass; + +UzblCookieJar *uzbl_cookie_jar_new(); + +void +uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar *handler); + +char +*get_cookies(UzblCookieJar *jar, SoupURI *uri); + +#endif diff --git a/src/events.c b/src/events.c index c209550..ee2f96c 100644 --- a/src/events.c +++ b/src/events.c @@ -57,56 +57,53 @@ event_buffer_timeout(guint sec) { setitimer(ITIMER_REAL, &t, NULL); } - -void -send_event_socket(GString *msg) { +static void +send_event_sockets(GPtrArray *sockets, GString *msg) { GError *error = NULL; - GString *tmp; - GIOChannel *gio = NULL; GIOStatus ret; gsize len; - guint i=0, j=0; + guint i=0; + + while(i < sockets->len) { + GIOChannel *gio = g_ptr_array_index(sockets, i++); + + if(gio && gio->is_writeable && msg) { + ret = g_io_channel_write_chars (gio, + msg->str, msg->len, + &len, &error); + + if (ret == G_IO_STATUS_ERROR) + g_warning ("Error sending event to socket: %s", error->message); + else + g_io_channel_flush(gio, &error); + } + } +} + +static void +replay_buffered_events() { + guint i = 0; + event_buffer_timeout(0); + + /* replay buffered events */ + while(i < uzbl.state.event_buffer->len) { + GString *tmp = g_ptr_array_index(uzbl.state.event_buffer, i++); + send_event_sockets(uzbl.comm.connect_chan, tmp); + g_string_free(tmp, TRUE); + } + + g_ptr_array_free(uzbl.state.event_buffer, TRUE); + uzbl.state.event_buffer = NULL; +} + +void +send_event_socket(GString *msg) { /* write to all --connect-socket sockets */ if(uzbl.comm.connect_chan) { - while(i < uzbl.comm.connect_chan->len) { - gio = g_ptr_array_index(uzbl.comm.connect_chan, i++); - j=0; - - if(gio && gio->is_writeable) { - if(uzbl.state.event_buffer) { - event_buffer_timeout(0); - - /* replay buffered events */ - while(j < uzbl.state.event_buffer->len) { - tmp = g_ptr_array_index(uzbl.state.event_buffer, j++); - ret = g_io_channel_write_chars (gio, - tmp->str, tmp->len, - &len, &error); - - if (ret == G_IO_STATUS_ERROR) - g_warning ("Error sending event to socket: %s", error->message); - else - g_io_channel_flush(gio, &error); - } - } - - if(msg) { - ret = g_io_channel_write_chars (gio, - msg->str, msg->len, - &len, &error); - - if (ret == G_IO_STATUS_ERROR) - g_warning ("Error sending event to socket: %s", error->message); - else - g_io_channel_flush(gio, &error); - } - } - } - if(uzbl.state.event_buffer) { - g_ptr_array_free(uzbl.state.event_buffer, TRUE); - uzbl.state.event_buffer = NULL; - } + send_event_sockets(uzbl.comm.connect_chan, msg); + if(uzbl.state.event_buffer) + replay_buffered_events(); } /* buffer events until a socket is set and connected * or a timeout is encountered @@ -118,22 +115,8 @@ send_event_socket(GString *msg) { } /* write to all client sockets */ - i=0; if(msg && uzbl.comm.client_chan) { - while(i < uzbl.comm.client_chan->len) { - gio = g_ptr_array_index(uzbl.comm.client_chan, i++); - - if(gio && gio->is_writeable && msg) { - ret = g_io_channel_write_chars (gio, - msg->str, msg->len, - &len, &error); - - if (ret == G_IO_STATUS_ERROR) - g_warning ("Error sending event to socket: %s", error->message); - else - g_io_channel_flush(gio, &error); - } - } + send_event_sockets(uzbl.comm.client_chan, msg); } } diff --git a/src/uzbl-browser b/src/uzbl-browser index de4f7af..fabefc4 100755 --- a/src/uzbl-browser +++ b/src/uzbl-browser @@ -40,10 +40,16 @@ done # if no config exists yet in the recommended location, put the default (recommended) config there if [ ! -f $XDG_CONFIG_HOME/uzbl/config ] then + if [ ! -r $PREFIX/share/uzbl/examples/config/config ] + then + echo "Error: Global config not found; please check if your distribution ships them separately" + exit 3 + fi if ! cp $PREFIX/share/uzbl/examples/config/config $XDG_CONFIG_HOME/uzbl/config then echo "Could not copy default config to $XDG_CONFIG_HOME/uzbl/config" >&2 - exit 3 + # Run with the global configs as a last resort + config="--config $PREFIX/share/uzbl/examples/config/config" fi fi @@ -63,4 +69,4 @@ DAEMON_PID=${DAEMON_SOCKET}.pid uzbl-event-manager -va start #fi -exec uzbl-core "$@" --connect-socket $DAEMON_SOCKET +exec uzbl-core "$@" $config --connect-socket $DAEMON_SOCKET diff --git a/src/uzbl-core.c b/src/uzbl-core.c index 7be98c3..70d6f50 100644 --- a/src/uzbl-core.c +++ b/src/uzbl-core.c @@ -98,7 +98,7 @@ const struct var_name_to_ptr_t { { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, NULL)}, { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)}, { "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)}, - { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, NULL)}, + { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_set_cookie_handler)}, { "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)}, { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)}, { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)}, @@ -679,7 +679,6 @@ struct {const char *key; CommandInfo value;} cmdlist[] = { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler { "sh", {spawn_sh, 0} }, { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler - { "talk_to_socket", {talk_to_socket, 0} }, { "exit", {close_uzbl, 0} }, { "search", {search_forward_text, TRUE} }, { "search_reverse", {search_reverse_text, TRUE} }, @@ -1263,6 +1262,29 @@ sharg_append(GArray *a, const gchar *str) { g_array_append_val(a, s); } +gboolean +uzbl_setup_environ() { + gchar *util_dirs = expand("@scripts_util_dir", 0); + gchar *util_dir = NULL; + gboolean succeed = FALSE; + + if(!util_dirs) { + g_free(util_dirs); + return succeed; + } + + if(!(util_dir = find_existing_file(util_dirs))) { + g_free(util_dirs); + return succeed; + } + + succeed = g_setenv("UZBL_UTIL_DIR", util_dir, TRUE); + + g_free(util_dirs); + g_free(util_dir); + return succeed; +} + // 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, @@ -1274,6 +1296,8 @@ run_command (const gchar *command, const guint npre, const gchar **args, gchar *pid = itos(getpid()); gchar *xwin = itos(uzbl.xwin); guint i; + gboolean environ_set = uzbl_setup_environ(); + sharg_append(a, command); for (i = 0; i < npre; i++) /* add n args before the default vars */ sharg_append(a, args[i]); @@ -1312,6 +1336,9 @@ run_command (const gchar *command, const guint npre, const gchar **args, printf("Stdout: %s\n", *output_stdout); } } + if (!environ_set) { + g_printerr("failed to set the environment for scripts"); + } if (err) { g_printerr("error on run_command: %s\n", err->message); g_error_free (err); @@ -1432,118 +1459,6 @@ spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) { } void -talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - - int fd, len; - struct sockaddr_un sa; - char* sockpath; - ssize_t ret; - struct pollfd pfd; - struct iovec* iov; - guint i; - - if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - - /* This function could be optimised by storing a hash table of socket paths - and associated connected file descriptors rather than closing and - re-opening for every call. Also we could launch a script if socket connect - fails. */ - - /* First element argv[0] is path to socket. Following elements are tokens to - write to the socket. We write them as a single packet with each token - separated by an ASCII nul (\0). */ - if(argv->len < 2) { - g_printerr("talk_to_socket called with only %d args (need at least two).\n", - (int)argv->len); - return; - } - - /* copy socket path, null terminate result */ - sockpath = g_array_index(argv, char*, 0); - g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path)); - sa.sun_family = AF_UNIX; - - /* create socket file descriptor and connect it to path */ - fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); - if(fd == -1) { - g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno)); - return; - } - if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) { - g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* build request vector */ - iov = g_malloc(sizeof(struct iovec) * (argv->len - 1)); - if(!iov) { - g_printerr("talk_to_socket: unable to allocated memory for token vector\n"); - close(fd); - return; - } - for(i = 1; i < argv->len; ++i) { - iov[i - 1].iov_base = g_array_index(argv, char*, i); - iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */ - } - - /* write request */ - ret = writev(fd, iov, argv->len - 1); - g_free(iov); - if(ret == -1) { - g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* wait for a response, with a 500ms timeout */ - pfd.fd = fd; - pfd.events = POLLIN; - while(1) { - ret = poll(&pfd, 1, 500); - if(ret == 1) break; - if(ret == 0) errno = ETIMEDOUT; - if(errno == EINTR) continue; - g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n", - strerror(errno)); - close(fd); - return; - } - - /* get length of response */ - if(ioctl(fd, FIONREAD, &len) == -1) { - g_printerr("talk_to_socket: cannot find daemon response length, " - "ioctl failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* if there is a response, read it */ - if(len) { - uzbl.comm.sync_stdout = g_malloc(len + 1); - if(!uzbl.comm.sync_stdout) { - g_printerr("talk_to_socket: failed to allocate %d bytes\n", len); - close(fd); - return; - } - uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */ - - ret = read(fd, uzbl.comm.sync_stdout, len); - if(ret == -1) { - g_printerr("talk_to_socket: failed to read from socket (%s)\n", - strerror(errno)); - close(fd); - return; - } - } - - /* clean up */ - close(fd); - return; -} - -void parse_command(const char *cmd, const char *param, GString *result) { CommandInfo *c; GString *tmp = g_string_new(""); @@ -2125,8 +2040,7 @@ inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *ne if ((g_strcmp0(actname, "spawn") == 0) || (g_strcmp0(actname, "sh") == 0) || (g_strcmp0(actname, "sync_spawn") == 0) || - (g_strcmp0(actname, "sync_sh") == 0) || - (g_strcmp0(actname, "talk_to_socket") == 0)) { + (g_strcmp0(actname, "sync_sh") == 0)) { guint i; GString *a = g_string_new(""); gchar **spawnparts = split_quoted(origargs, FALSE); @@ -2313,7 +2227,6 @@ settings_init () { if(s->connect_socket_names) init_connect_socket(); - g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL); g_signal_connect(n->soup_session, "authenticate", G_CALLBACK(handle_authentication), NULL); } @@ -2373,57 +2286,6 @@ void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *au } } -void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data) { - (void) session; - (void) user_data; - - soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies_http), NULL); - GString *s = g_string_new (""); - SoupURI * soup_uri = soup_message_get_uri(msg); - g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path); - - if(uzbl.behave.cookie_handler) - run_handler(uzbl.behave.cookie_handler, s->str); - - if(uzbl.behave.cookie_handler && - uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { - char *p = strchr(uzbl.comm.sync_stdout, '\n' ); - if ( p != NULL ) *p = '\0'; - soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout); - - int len = strlen(uzbl.comm.sync_stdout); - - if(len > 0) { - SoupCookie *soup_cookie; - char *cookies = (char *) g_malloc(len+1); - strncpy(cookies, uzbl.comm.sync_stdout, len+1); - - /* Disconnect to avoid recursion */ - g_object_disconnect(G_OBJECT(uzbl.net.soup_cookie_jar), "any_signal", G_CALLBACK(save_cookies_js), NULL, NULL); - - p = cookies - 1; - while(p != NULL) { - p = p + 1; - soup_cookie = soup_cookie_parse((const char *) p, soup_uri); - if (soup_cookie) { - if(soup_cookie->domain == NULL) - soup_cookie->domain = soup_uri->host; - soup_cookie_jar_add_cookie(uzbl.net.soup_cookie_jar, soup_cookie); - } - p = strchr(p, ';'); - } - - g_object_connect(G_OBJECT(uzbl.net.soup_cookie_jar), "signal::changed", G_CALLBACK(save_cookies_js), NULL, NULL); - g_free(cookies); - } - } - - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - - g_string_free(s, TRUE); -} - void dump_var_hash(gpointer k, gpointer v, gpointer ud) { (void) ud; @@ -2522,9 +2384,8 @@ initialize(int argc, char *argv[]) { uzbl.net.soup_session = webkit_get_default_session(); - uzbl.net.soup_cookie_jar = soup_cookie_jar_new(); + uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new(); soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar)); - g_object_connect(G_OBJECT(uzbl.net.soup_cookie_jar), "signal::changed", G_CALLBACK(save_cookies_js), NULL, NULL); for(i=0; sigs[i]; i++) { if(setup_signal(sigs[i], catch_signal) == SIG_ERR) @@ -2548,6 +2409,7 @@ initialize(int argc, char *argv[]) { void load_uri_imp(gchar *uri) { GString* newuri; + SoupURI* soup_uri; /* Strip leading whitespaces */ while (*uri) { @@ -2559,26 +2421,28 @@ load_uri_imp(gchar *uri) { eval_js(uzbl.gui.web_view, uri, NULL, "javascript:"); return; } + newuri = g_string_new (uri); - if (!soup_uri_new(uri)) { - GString* fullpath = g_string_new (""); + soup_uri = soup_uri_new(uri); + + if (!soup_uri) { + gchar* fullpath; if (g_path_is_absolute (newuri->str)) - g_string_assign (fullpath, newuri->str); + fullpath = newuri->str; else { - gchar* wd; - wd = g_get_current_dir (); - g_string_assign (fullpath, g_build_filename (wd, newuri->str, NULL)); - free(wd); + gchar* wd = g_get_current_dir (); + fullpath = g_build_filename (wd, newuri->str, NULL); + g_free(wd); } struct stat stat_result; - if (! g_stat(fullpath->str, &stat_result)) { - g_string_prepend (fullpath, "file://"); - g_string_assign (newuri, fullpath->str); - } + if (! g_stat(fullpath, &stat_result)) + g_string_printf (newuri, "file://%s", fullpath); else g_string_prepend (newuri, "http://"); - g_string_free (fullpath, TRUE); + } else { + soup_uri_free(soup_uri); } + /* if we do handle cookies, ask our handler for them */ webkit_web_view_load_uri (uzbl.gui.web_view, newuri->str); g_string_free (newuri, TRUE); diff --git a/src/uzbl-core.h b/src/uzbl-core.h index 5760423..a9e8fe2 100644 --- a/src/uzbl-core.h +++ b/src/uzbl-core.h @@ -40,6 +40,8 @@ #include <sys/ioctl.h> #include <assert.h> +#include "cookie-jar.h" + #define LENGTH(x) (sizeof x / sizeof x[0]) /* gui elements */ @@ -104,8 +106,8 @@ typedef struct { /* networking */ typedef struct { - SoupSession *soup_session; - SoupCookieJar *soup_cookie_jar; + SoupSession *soup_session; + UzblCookieJar *soup_cookie_jar; SoupLogger *soup_logger; char *proxy_url; char *useragent; @@ -274,13 +276,13 @@ void close_uzbl (WebKitWebView *page, GArray *argv, GString *result); gboolean +uzbl_setup_environ(); + +gboolean run_command(const gchar *command, const guint npre, const gchar **args, const gboolean sync, char **output_stdout); void -talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result); - -void spawn(WebKitWebView *web_view, GArray *argv, GString *result); void |