summaryrefslogtreecommitdiff
path: root/.config
diff options
context:
space:
mode:
authorben <benjaminfranzke@gmail.com>2010-01-04 21:04:41 +0100
committerben <benjaminfranzke@gmail.com>2010-01-04 21:04:41 +0100
commitfff9c1bbfa6b120c6fd349f95b0e74c618ebb6ea (patch)
tree9e88a6ffcc78bd148410b7f1ea5e21af624c5d00 /.config
parent08a86f4d3f64917caad9ecb791e2b4f84a498fdc (diff)
downloaddotfiles-fff9c1bbfa6b120c6fd349f95b0e74c618ebb6ea.tar.gz
dotfiles-fff9c1bbfa6b120c6fd349f95b0e74c618ebb6ea.tar.bz2
dotfiles-fff9c1bbfa6b120c6fd349f95b0e74c618ebb6ea.zip
add uzbl configuration
Diffstat (limited to '.config')
-rw-r--r--.config/uzbl/bookmarks4
-rw-r--r--.config/uzbl/config121
-rw-r--r--.config/uzbl/cookies22
-rw-r--r--.config/uzbl/cookies.txt17
-rw-r--r--.config/uzbl/forms/bbs.archlinux.org5
-rw-r--r--.config/uzbl/history108
-rwxr-xr-x.config/uzbl/scripts/clipboard.sh17
-rwxr-xr-x.config/uzbl/scripts/cookie_daemon.py662
-rwxr-xr-x.config/uzbl/scripts/cookies.py37
-rwxr-xr-x.config/uzbl/scripts/cookies.sh154
-rwxr-xr-x.config/uzbl/scripts/download.sh22
-rw-r--r--.config/uzbl/scripts/follow_Numbers.js223
-rw-r--r--.config/uzbl/scripts/follow_Numbers_Strings.js205
-rwxr-xr-x.config/uzbl/scripts/formfiller.pl99
-rwxr-xr-x.config/uzbl/scripts/formfiller.sh62
-rw-r--r--.config/uzbl/scripts/hint.js26
-rwxr-xr-x.config/uzbl/scripts/history.sh5
-rwxr-xr-x.config/uzbl/scripts/insert_bookmark.sh14
-rw-r--r--.config/uzbl/scripts/linkfollow.js269
-rwxr-xr-x.config/uzbl/scripts/load_url_from_bookmarks.sh20
-rwxr-xr-x.config/uzbl/scripts/load_url_from_history.sh24
-rwxr-xr-x.config/uzbl/scripts/scheme.py23
-rwxr-xr-x.config/uzbl/scripts/session.sh62
-rwxr-xr-x.config/uzbl/scripts/uzbl_tabbed.py1474
-rwxr-xr-x.config/uzbl/scripts/uzblcat12
-rwxr-xr-x.config/uzbl/scripts/yank.sh17
-rw-r--r--.config/uzbl/style.css25
-rw-r--r--.config/uzbl/uzbl.pngbin0 -> 2185 bytes
28 files changed, 3729 insertions, 0 deletions
diff --git a/.config/uzbl/bookmarks b/.config/uzbl/bookmarks
new file mode 100644
index 0000000..13fcd48
--- /dev/null
+++ b/.config/uzbl/bookmarks
@@ -0,0 +1,4 @@
+http://www.archlinux.org linux arch
+http://www.uzbl.org uzbl browser
+http://dieter.plaetinck.be uzbl
+http://www.icanhascheezburger.com lolcats fun
diff --git a/.config/uzbl/config b/.config/uzbl/config
new file mode 100644
index 0000000..47d8839
--- /dev/null
+++ b/.config/uzbl/config
@@ -0,0 +1,121 @@
+# example uzbl config.
+# all settings are optional. you can use uzbl without any config at all (but it won't do much)
+
+# keyboard behavior in this sample config is sort of vimstyle
+
+# Handlers
+set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh
+set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py
+#set new_window = sh 'echo uri "$8" > $4' # open in same window
+set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour
+set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py
+set load_start_handler = chain 'set keycmd = ' 'set status_message = <span foreground="khaki">wait</span>'
+set load_commit_handler = set status_message = <span foreground="green">recv</span>
+set load_finish_handler = chain 'set status_message = <span foreground="gold">done</span>' 'spawn $XDG_DATA_HOME/uzbl/scripts/history.sh'
+
+
+
+# Behaviour and appearance
+set show_status = 1
+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">\@status_message</span><span foreground="#606060"> \@[\@SELECTED_URI]\@</span></span>
+set status_top = 0
+set insert_indicator = I
+set command_indicator = C
+set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT)
+
+set fifo_dir = /tmp
+set socket_dir = /tmp
+set shell_cmd = sh -c
+
+# Keyboard interface
+set modkey = Mod1
+# like this you can enter any command at runtime, interactively. prefixed by ':'
+bind :_ = chain '%s'
+
+bind j = scroll_vert 20
+bind k = scroll_vert -20
+bind h = scroll_horz -20
+bind l = scroll_horz 20
+bind << = scroll_begin
+bind >> = scroll_end
+bind b = back
+bind m = forward
+bind S = stop
+bind r = reload
+bind R = reload_ign_cache
+bind + = zoom_in
+bind - = zoom_out
+bind T = toggle_zoom_type
+bind 1 = sh "echo set zoom_level = 1.0 > $4"
+bind 2 = sh "echo set zoom_level = 2.0 > $4"
+bind t = toggle_status
+bind /* = search %s
+bind ?* = search_reverse %s
+#jump to next
+bind n = search
+bind N = search_reverse
+bind gh = uri http://www.uzbl.org
+# shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..'
+bind o _ = uri %s
+# shortcut to set variables
+bind s _ = set %s
+bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go
+bind gg _ = uri http://www.google.com/search?q=%s
+bind i = toggle_insert_mode
+# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting
+bind I = toggle_insert_mode 0
+# Enclose the executable in quotes if it has spaces. Any additional parameters you use will
+# appear AFTER the default parameters
+bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh
+bind U = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_history.sh
+bind u = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_bookmarks.sh
+# with the sample yank script, you can yank one of the arguments into clipboard/selection
+bind yurl = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 6 primary
+bind ytitle = spawn $XDG_DATA_HOME/uzbl/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
+bind p = sh 'echo "uri `xclip -selection primary -o`" > $4'
+# go to the page in clipboard
+bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4'
+# start a new uzbl instance from the page in primary selection
+bind 'p = sh 'exec uzbl --uri $(xclip -o)'
+bind ZZ = exit
+bind Xs = js alert("hi");
+# example showing how to use sh
+# it sends a command to the fifo, whose path is told via a positional param
+# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it
+# The body of the shell command should be one parameter, so if it has spaces like here,
+# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes
+# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file
+# path, fifo & socket dirs, etc.)
+bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"'
+
+bind !dump = sh "echo dump_config > $4"
+bind !reload = sh 'cat $1 > $4'
+
+# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically
+bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh
+bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit
+bind zn = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh new
+bind zl = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh load
+
+# other - more advanced - implementation using perl: (could not get this to run - Dieter )
+bind LL = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl load
+bind LN = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl new
+bind LE = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl edit
+
+# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet)
+# this is similar to how it works in vimperator (and konqueror)
+# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ?
+#hit F to toggle the Hints (now in form of link numbering)
+bind F = script $XDG_DATA_HOME/uzbl/scripts/hint.js
+# the most stable version:
+bind fl* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers.js %s
+# using strings, not polished yet:
+bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s
+
+
+# "home" page if you will
+set uri = uzbl.org
diff --git a/.config/uzbl/cookies b/.config/uzbl/cookies
new file mode 100644
index 0000000..9b7374a
--- /dev/null
+++ b/.config/uzbl/cookies
@@ -0,0 +1,22 @@
+# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script.
+# stick to this format.
+# trusted -> always store what we get, send what we have (TODO: by default, or when requested?)
+# deny -> deny storing + sending
+
+# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind...
+
+
+TRUSTED
+bbs.archlinux.org
+archlinux.org
+linux.com
+
+
+
+
+DENY
+www.icanhascheezburger.com
+
+
+
+# rest -> ask \ No newline at end of file
diff --git a/.config/uzbl/cookies.txt b/.config/uzbl/cookies.txt
new file mode 100644
index 0000000..01b900b
--- /dev/null
+++ b/.config/uzbl/cookies.txt
@@ -0,0 +1,17 @@
+ # Netscape HTTP Cookie File
+ # http://www.netscape.com/newsref/std/cookie_spec.html
+ # This is a generated file! Do not edit.
+
+.doubleclick.net TRUE / FALSE 1259497519 test_cookie CheckForPermission
+.google.com TRUE / FALSE 1319445778 PREF ID=57d7b3e6ee44dd98:TM=1256373778:LM=1256373778:S=f4EUwEgD33-bSdx3
+.google.de TRUE / FALSE 1272187286 NID 28=Qi11_cBLgQd3WrtxinBbHUvFiCdS9iUxoW4CuAt1gBkYFSBHFzDV6tzgQN-nc6LGzGKVmhXNUS-DHZqI-el0HkT3GCo4hFyEhPq-tuoRoHDyE4V7QwWn9UROyY0SCdIX
+.google.de TRUE / FALSE 1319448069 PREF ID=95f50e19f59a926d:U=ef9a2a603c860955:TM=1256373653:LM=1256376069:IG=3:S=djxWYEYsFXiww1A6
+.google.de TRUE /verify FALSE 1275307811 SNID 29=pordeA9raH2zGXlEdTj_P--E3g3thcJc2Jlp9pL9IQ=WrJLkb6makf5sarh
+.www.google.de TRUE /ig FALSE 1319448076 IGTP TP=H4sIAAAAAAAAAIWTvW_TQBjGfXYKrvtBQEIqTFGQMjSpz7VUlUZKKwZE1KGqRAeWqrr4XjnXnGPLd_loJyaGUhj4KzpDBybUgX-AAoINiZ0ZCSGB7-wo3XrDO9zpnt_zvPeebSy9eP3yW6lyquq2sCtLVsVozz77-OvvZSkx3qL9ufLzT69K9_ecra6USRPj0WjkhnEccnCDOMIsxFFMBxwEPooHctCBA5Yf46E_2XLHES__Nuu-I4CkQXcP0qhpNOYvkLH9FWVUlFGdKfUDKrDnyGlcy5Wk04eRUJC6b3Mi5MEg5c1xcZEcknFxkyRM6NtqDwtIhyzIBHJTWIlsDVurrlfrMgqtFDiRQGs9OGqxvoS0T_gKC1cKXq0PtEWhJuOEBa1uLRXHLU7SEPJcd-3ZJbOClo323CSY2t7L0ppZ2vlp2s0i7Jqzcm1WmjmSLMo7eop2T5GG7dj3spdDyxt-s3pFQyQMQuAuBSyCLifhMTAOfZwKgb3Gmr-x2mh4ntKqtheuutzRk2C2F6cuHxYusVMvCJP-uSPWYwlQRhQoMztKxCDo5h7H2h_Vb4zat6Z6O4XeY8cv9CIlQTtujwU9SLXpBAJGOA4JDUHi4kDJ_rDq_k0SyIPsMZrIy1u-r3trtstTypOCsul4V_rCSSdhYwb5MAQkSggL-9kkxTTWRTNo3beGkDbRIy2_q7_KCTIpvFHlDJnv0Hs0c4EWzmbsc3SJSizkvT_ogW3ccZ5KkkoBTEL1tuixTDzIJlOwQEl7pTNTf7kTS6mp8tn6bv2bLPTF-mktOjdE4nvr62UN_g_ZlV1OrAMAAA:LM=1256376076
+.www.google.de TRUE /search FALSE SS Q0=aGFsbG8
+.www.uzbl.org TRUE /wiki/ FALSE DokuWiki 6eb6jrd6a0a7lljgamrt7b8p97
+.youtube.com TRUE / FALSE GEO 447129ade8c2ab623ae61d089da6b282cwsAAAAzREVUjEKtSuK9rw==
+.youtube.com TRUE / FALSE 1569094311 PREF f1=50000000
+.youtube.com TRUE / FALSE 1274470311 VISITOR_INFO1_LIVE eRgRTpP213c
+.youtube.com TRUE / FALSE use_hitbox 72c46ff6cbcdb7c5585c36411b6b334edAEAAAAw
+.youtube.com TRUE / FALSE watched_video_id_list 9711faf85843bb86dd2c32b6564a5c07WwEAAABzCwAAAF9jMkgzTkhjbkJF
diff --git a/.config/uzbl/forms/bbs.archlinux.org b/.config/uzbl/forms/bbs.archlinux.org
new file mode 100644
index 0000000..73c1539
--- /dev/null
+++ b/.config/uzbl/forms/bbs.archlinux.org
@@ -0,0 +1,5 @@
+form_sent:
+redirect_url:
+req_username: <your username>
+req_password: <password>
+login:
diff --git a/.config/uzbl/history b/.config/uzbl/history
new file mode 100644
index 0000000..285f85c
--- /dev/null
+++ b/.config/uzbl/history
@@ -0,0 +1,108 @@
+2009-09-18 10:22:07 uzbl.org
+2009-09-18 10:22:19 uzbl.org
+2009-09-18 10:22:26 google.de
+2009-09-18 10:22:29 http://www.google.de/ Google
+2009-09-18 10:22:32 http://images.google.de/imghp?hl=de&tab=wi Google Bilder
+2009-09-18 10:23:26 google.de
+2009-09-18 10:23:29 http://www.google.de/ Google
+2009-09-18 10:23:42 google.de
+2009-09-18 10:23:44 http://www.google.de/ Google
+2009-09-18 10:23:54 google.de
+2009-09-18 10:23:56 http://www.google.de/ Google
+2009-09-18 10:24:15 google.de
+2009-09-18 10:24:18 http://www.google.de/ Google
+2009-09-18 10:24:21 http://www.google.de/preferences?hl=de Einstellungen
+2009-09-18 11:01:59 http://google.de
+2009-09-18 11:02:01 http://www.google.de/ Google
+2009-09-18 11:02:05 http://images.google.de/imghp?hl=de&tab=wi Google Bilder
+2009-09-18 11:30:47 http://youtube.com/html5
+2009-09-18 12:16:28 gentoo.orgh
+2009-09-18 12:16:35 gentoo.org
+2009-09-18 12:17:05 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:12 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:15 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:16 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:16 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:16 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:17 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:17 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:29 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-18 12:17:32 http://www.google.de/ Google
+2009-09-18 12:17:36 http://images.google.de/imghp?hl=de&tab=wi Google Bilder
+2009-09-18 12:44:12 output
+2009-09-18 12:44:12 http://output/ Error
+2009-09-18 12:45:26 oggguy.com
+2009-09-18 12:45:27 http://oggguy.com/ Error
+2009-09-18 12:45:30 ossguy.com
+2009-09-18 17:10:33 http://thevideobay.org/play/43/Rage+Against+The+Machine+-+Testify+-+Music+Video/
+2009-09-18 17:10:41 http://thevideobay.org/play/43/Rage+Against+The+Machine+-+Testify+-+Music+Video/ The Video Bay
+2009-09-19 17:47:46 google.de
+2009-09-19 17:47:49 http://www.google.de/ Google
+2009-09-19 17:52:51 google.de
+2009-09-19 17:52:54 http://www.google.de/ Google
+2009-09-19 17:53:10 http://images.google.de/imghp?hl=de&tab=wi Google Bilder
+2009-09-19 17:53:37 ossguy.com
+2009-09-19 17:58:30 google.de
+2009-09-19 17:58:33 http://www.google.de/ Google
+2009-09-19 17:58:42 http://images.google.de/imghp?hl=de&tab=wi Google Bilder
+2009-09-19 17:58:45 http://www.google.de/prdhp?hl=de&tab=if Google Produktsuche
+2009-09-19 18:17:40 gentoo.org
+2009-09-19 18:17:58 http://www.gentoo.org/ Gentoo Linux -- Gentoo Linux News
+2009-09-19 18:18:01 http://www.gentoo.org/proj/en/ Gentoo Linux Documentation -- Project Listing
+2009-09-19 18:18:06 http://www.gentoo.org/proj/en/council/index.xml Gentoo Linux Projects -- Gentoo Council
+2009-09-19 18:29:18 ossguy.com
+2009-09-19 18:29:26 ossguy.com
+2009-09-19 18:39:37 ossguy.com
+2009-09-19 18:42:02 uzbl.org
+2009-09-19 20:07:16 google.de
+2009-09-19 20:07:19 http://www.google.de/ Google
+2009-09-19 20:10:13 uzbl.org
+2009-09-19 20:10:25 uzbl.org
+2009-09-19 20:10:35 pro-linux.de
+2009-09-19 20:10:47 http://www.pro-linux.de/ Pro-Linux
+2009-09-19 20:12:17 http://www.pro-linux.de/berichte/ Pro-Linux: Artikel-Index
+2009-09-19 20:12:23 http://www.google.de/ Google
+2009-09-19 20:14:51 ossguy.com
+2009-09-19 22:17:53 uzbl.org
+2009-09-19 23:03:17 http://youtube.com/html5
+2009-09-19 23:03:56 uzbl.org
+2009-09-19 23:04:04 http://youtube.com/html5
+2009-09-20 00:34:02 ossguy.com
+2009-09-21 07:11:22 https://lsf.hs-wismar.de/qisserver/rds?state=qissosreports
+2009-09-23 21:31:39 youtube.com
+2009-10-24 10:40:48 google.de
+2009-10-24 10:40:51 http://www.google.de/ Google
+2009-10-24 10:40:56 http://video.google.de/?hl=de&tab=wv Google Videos
+2009-10-24 10:41:02 http://maps.google.de/maps?hl=de&tab=vl Google Maps
+2009-10-24 10:41:03 http://maps.google.de/maps?hl=de&tab=vl Google Maps
+2009-10-24 10:41:04 http://www.google.de/products?hl=de&sa=N&tab=lf Google Produktsuche
+2009-10-24 10:41:07 http://images.google.de/imghp?hl=de&tab=fi Google Bilder
+2009-10-24 10:41:09 http://www.google.de/webhp?hl=de&tab=iw Google
+2009-10-24 10:41:25 http://www.youtube.com/ YouTube - Broadcast Yourself.
+2009-10-24 10:41:30 http://www.youtube.com/ YouTube - Broadcast Yourself.
+2009-10-24 10:41:31 http://www.youtube.com/results?search_query=&search_type=&aq=f YouTube
+2009-10-24 10:41:54 http://www.youtube.com/results?search_query=beyonce&search_type=&aq=f YouTube - beyonce
+2009-10-24 10:41:55 http://www.youtube.com/results?search_query=beyonce&search_type=&aq=f YouTube - beyonce
+2009-10-24 10:42:47 http://www.youtube.com/user/beyonce?blend=1&ob=4 YouTube - Kanal von beyonce
+2009-10-24 10:43:18 http://www.google.de/ Google
+2009-10-24 10:43:29 http://www.google.de/search?hl=de&source=hp&ie=ISO-8859-1&q=hallo&btnG=Google-Suche&meta=&aq=f&oq= hallo - Google-Suche
+2009-10-24 10:51:43 youtube.com
+2009-10-24 10:51:51 http://www.youtube.com/ YouTube - Broadcast Yourself.
+2009-10-24 10:51:51 http://www.youtube.com/ YouTube - Broadcast Yourself.
+2009-10-24 10:51:57 http://www.youtube.com/results?search_query=TI+Semto&search_type= YouTube - TI Semto
+2009-10-24 10:51:57 http://www.youtube.com/results?search_query=TI+Semto&search_type= YouTube - TI Semto
+2009-10-24 10:52:04 http://www.youtube.com/watch?v=_c2H3NHcnBE YouTube - Scooter- Ti Sento (Official Video HQ) + Lyrics
+2009-10-24 10:52:04 http://www.youtube.com/watch?v=_c2H3NHcnBE YouTube - Scooter- Ti Sento (Official Video HQ) + Lyrics
+2009-10-24 10:52:29 http://www.youtube.com/watch?v=_c2H3NHcnBE YouTube - Scooter- Ti Sento (Official Video HQ) + Lyrics
+2009-10-24 11:20:41 http://www.uzbl.org/ Uzbl - a browser that adheres to the unix philosophy.
+2009-10-24 11:20:50 http://www.google.de/ Google
+2009-10-24 11:21:02 http://images.google.de/imghp?hl=de&tab=wi Google Bilder
+2009-10-24 11:21:02 http://www.google.de/webhp?hl=de&tab=iw Google
+2009-10-24 11:21:24 http://www.google.de/ig?hl=de&tab=iw&source=iglk iGoogle
+2009-10-24 11:21:49 http://www.google.de/ig?hl=de&tab=iw&source=iglk iGoogle
+2009-10-24 11:21:49 http://www.google.de/ig?hl=de&tab=iw&source=iglk iGoogle
+2009-10-24 11:21:49 http://www.google.de/ig?hl=de&tab=iw&source=iglk iGoogle
+2009-11-29 13:09:40 uzbl.org
+2009-11-29 13:09:47 http://www.uzbl.org/ Uzbl - web interface tools which adhere to the unix philosophy.
+2009-11-29 13:10:07 http://www.google.de/ig?hl=de iGoogle
+2009-11-29 13:10:09 http://www.google.de/ig?hl=de iGoogle
diff --git a/.config/uzbl/scripts/clipboard.sh b/.config/uzbl/scripts/clipboard.sh
new file mode 100755
index 0000000..60567d3
--- /dev/null
+++ b/.config/uzbl/scripts/clipboard.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard.
+
+clip=xclip
+
+fifo="$5"
+action="$1"
+url="$7"
+
+selection=`$clip -o`
+
+case $action in
+ "yank" ) echo -n "$url" | eval "$clip";;
+ "goto" ) echo "uri $selection" > "$fifo";;
+ * ) echo "clipboard.sh: invalid action";;
+esac
diff --git a/.config/uzbl/scripts/cookie_daemon.py b/.config/uzbl/scripts/cookie_daemon.py
new file mode 100755
index 0000000..87a2e87
--- /dev/null
+++ b/.config/uzbl/scripts/cookie_daemon.py
@@ -0,0 +1,662 @@
+#!/usr/bin/env python
+
+# The Python Cookie Daemon for Uzbl.
+# Copyright (c) 2009, Tom Adams <tom@holizz.com>
+# Copyright (c) 2009, Dieter Plaetinck <dieter@plaetinck.be>
+# Copyright (c) 2009, Mason Larobina <mason.larobina@gmail.com>
+# Copyright (c) 2009, Michael Fiano <axionix@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+'''
+The Python Cookie Daemon
+========================
+
+This daemon is a re-write of the original cookies.py script found in uzbl's
+master branch. This script provides more functionality than the original
+cookies.py by adding numerous command line options to specify different cookie
+jar locations, socket locations, verbose output, etc. This functionality is
+very useful as it allows you to run multiple daemons at once serving cookies
+to different groups of uzbl instances as required.
+
+Keeping up to date
+==================
+
+Check the cookie daemon uzbl-wiki page for more information on where to
+find the latest version of the cookie_daemon.py
+
+ http://www.uzbl.org/wiki/cookie_daemon.py
+
+Command line options
+====================
+
+Use the following command to get a full list of the cookie_daemon.py command
+line options:
+
+ ./cookie_daemon.py --help
+
+Talking with uzbl
+=================
+
+In order to get uzbl to talk to a running cookie daemon you add the following
+to your uzbl config:
+
+ set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket
+
+Or if you prefer using the $HOME variable:
+
+ set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket
+
+Todo list
+=========
+
+ - Use a pid file to make force killing a running daemon possible.
+
+Reporting bugs / getting help
+=============================
+
+The best way to report bugs and or get help with the cookie daemon is to
+contact the maintainers it the #uzbl irc channel found on the Freenode IRC
+network (irc.freenode.org).
+'''
+
+import cookielib
+import os
+import sys
+import urllib2
+import select
+import socket
+import time
+import atexit
+from traceback import print_exc
+from signal import signal, SIGTERM
+from optparse import OptionParser
+from os.path import join
+
+try:
+ import cStringIO as StringIO
+
+except ImportError:
+ import StringIO
+
+
+# ============================================================================
+# ::: Default configuration section ::::::::::::::::::::::::::::::::::::::::::
+# ============================================================================
+
+def xdghome(key, default):
+ '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise
+ use $HOME and the default path.'''
+
+ xdgkey = "XDG_%s_HOME" % key
+ if xdgkey in os.environ.keys() and os.environ[xdgkey]:
+ return os.environ[xdgkey]
+
+ return join(os.environ['HOME'], default)
+
+# Setup xdg paths.
+CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/')
+DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/')
+CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/')
+
+# Ensure data paths exist.
+for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]:
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+# Default config
+config = {
+
+ # Default cookie jar, whitelist, and daemon socket locations.
+ 'cookie_jar': join(DATA_DIR, 'cookies.txt'),
+ 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'),
+ 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'),
+
+ # Don't use a cookie whitelist policy by default.
+ 'use_whitelist': False,
+
+ # Time out after x seconds of inactivity (set to 0 for never time out).
+ # WARNING: Do not use this option if you are manually launching the daemon.
+ 'daemon_timeout': 0,
+
+ # Daemonise by default.
+ 'daemon_mode': True,
+
+ # Optionally print helpful debugging messages to the terminal.
+ 'verbose': False,
+
+} # End of config dictionary.
+
+
+# ============================================================================
+# ::: End of configuration section :::::::::::::::::::::::::::::::::::::::::::
+# ============================================================================
+
+
+_SCRIPTNAME = os.path.basename(sys.argv[0])
+def echo(msg):
+ '''Prints only if the verbose flag has been set.'''
+
+ if config['verbose']:
+ sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg))
+
+
+def error(msg):
+ '''Prints error message and exits.'''
+
+ sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg))
+ sys.exit(1)
+
+
+def mkbasedir(filepath):
+ '''Create the base directories of the file in the file-path if the dirs
+ don't exist.'''
+
+ dirname = os.path.dirname(filepath)
+ if not os.path.exists(dirname):
+ echo("creating dirs: %r" % dirname)
+ os.makedirs(dirname)
+
+
+def daemon_running(cookie_socket):
+ '''Check if another process (hopefully a cookie_daemon.py) is listening
+ on the cookie daemon socket. If another process is found to be
+ listening on the socket exit the daemon immediately and leave the
+ socket alone. If the connect fails assume the socket has been abandoned
+ and delete it (to be re-created in the create socket function).'''
+
+ if not os.path.exists(cookie_socket):
+ return False
+
+ if os.path.isfile(cookie_socket):
+ raise Exception("regular file at %r is not a socket" % cookie_socket)
+
+
+ if os.path.isdir(cookie_socket):
+ raise Exception("directory at %r is not a socket" % cookie_socket)
+
+ try:
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ sock.connect(cookie_socket)
+ sock.close()
+ echo("detected daemon listening on %r" % cookie_socket)
+ return True
+
+ except socket.error:
+ # Failed to connect to cookie_socket so assume it has been
+ # abandoned by another cookie daemon process.
+ if os.path.exists(cookie_socket):
+ echo("deleting abandoned socket at %r" % cookie_socket)
+ os.remove(cookie_socket)
+
+ return False
+
+
+def send_command(cookie_socket, cmd):
+ '''Send a command to a running cookie daemon.'''
+
+ if not daemon_running(cookie_socket):
+ return False
+
+ try:
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ sock.connect(cookie_socket)
+ sock.send(cmd)
+ sock.close()
+ echo("sent command %r to %r" % (cmd, cookie_socket))
+ return True
+
+ except socket.error:
+ print_exc()
+ error("failed to send message %r to %r" % (cmd, cookie_socket))
+ return False
+
+
+def kill_daemon(cookie_socket):
+ '''Send the "EXIT" command to running cookie_daemon.'''
+
+ if send_command(cookie_socket, "EXIT"):
+ # Now ensure the cookie_socket is cleaned up.
+ start = time.time()
+ while os.path.exists(cookie_socket):
+ time.sleep(0.1)
+ if (time.time() - start) > 5:
+ error("force deleting socket %r" % cookie_socket)
+ os.remove(cookie_socket)
+ return
+
+ echo("stopped daemon listening on %r"% cookie_socket)
+
+ else:
+ if os.path.exists(cookie_socket):
+ os.remove(cookie_socket)
+ echo("removed abandoned/broken socket %r" % cookie_socket)
+
+
+def daemonize():
+ '''Daemonize the process using the Stevens' double-fork magic.'''
+
+ try:
+ if os.fork():
+ os._exit(0)
+
+ except OSError:
+ print_exc()
+ sys.stderr.write("fork #1 failed")
+ sys.exit(1)
+
+ os.chdir('/')
+ os.setsid()
+ os.umask(0)
+
+ try:
+ if os.fork():
+ os._exit(0)
+
+ except OSError:
+ print_exc()
+ sys.stderr.write("fork #2 failed")
+ sys.exit(1)
+
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ devnull = '/dev/null'
+ stdin = file(devnull, 'r')
+ stdout = file(devnull, 'a+')
+ stderr = file(devnull, 'a+', 0)
+
+ os.dup2(stdin.fileno(), sys.stdin.fileno())
+ os.dup2(stdout.fileno(), sys.stdout.fileno())
+ os.dup2(stderr.fileno(), sys.stderr.fileno())
+
+
+class CookieMonster:
+ '''The uzbl cookie daemon class.'''
+
+ def __init__(self):
+ '''Initialise class variables.'''
+
+ self.server_socket = None
+ self.jar = None
+ self.last_request = time.time()
+ self._running = False
+
+
+ def run(self):
+ '''Start the daemon.'''
+
+ # The check healthy function will exit if another daemon is detected
+ # listening on the cookie socket and remove the abandoned socket if
+ # there isnt.
+ if os.path.exists(config['cookie_socket']):
+ if daemon_running(config['cookie_socket']):
+ sys.exit(1)
+
+ # Daemonize process.
+ if config['daemon_mode']:
+ echo("entering daemon mode")
+ daemonize()
+
+ # Register a function to cleanup on exit.
+ atexit.register(self.quit)
+
+ # Make SIGTERM act orderly.
+ signal(SIGTERM, lambda signum, stack_frame: sys.exit(1))
+
+ # Create cookie jar object from file.
+ self.open_cookie_jar()
+
+ # Create a way to exit nested loops by setting a running flag.
+ self._running = True
+
+ while self._running:
+ # Create cookie daemon socket.
+ self.create_socket()
+
+ try:
+ # Enter main listen loop.
+ self.listen()
+
+ except KeyboardInterrupt:
+ self._running = False
+ print
+
+ except socket.error:
+ print_exc()
+
+ except:
+ # Clean up
+ self.del_socket()
+
+ # Raise exception
+ raise
+
+ # Always delete the socket before calling create again.
+ self.del_socket()
+
+
+ def load_whitelist(self):
+ '''Load the cookie jar whitelist policy.'''
+
+ cookie_whitelist = config['cookie_whitelist']
+
+ if cookie_whitelist:
+ mkbasedir(cookie_whitelist)
+
+ # Create cookie whitelist file if it does not exist.
+ if not os.path.exists(cookie_whitelist):
+ open(cookie_whitelist, 'w').close()
+
+ # Read cookie whitelist file into list.
+ file = open(cookie_whitelist,'r')
+ domain_list = [line.rstrip('\n') for line in file]
+ file.close()
+
+ # Define policy of allowed domains
+ policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list)
+ self.jar.set_policy(policy)
+
+ # Save the last modified time of the whitelist.
+ self._whitelistmtime = os.stat(cookie_whitelist).st_mtime
+
+
+ def open_cookie_jar(self):
+ '''Open the cookie jar.'''
+
+ cookie_jar = config['cookie_jar']
+ cookie_whitelist = config['cookie_whitelist']
+
+ if cookie_jar:
+ mkbasedir(cookie_jar)
+
+ # Create cookie jar object from file.
+ self.jar = cookielib.MozillaCookieJar(cookie_jar)
+
+ # Load cookie whitelist policy.
+ if config['use_whitelist']:
+ self.load_whitelist()
+
+ if cookie_jar:
+ try:
+ # Attempt to load cookies from the cookie jar.
+ self.jar.load(ignore_discard=True)
+
+ # Ensure restrictive permissions are set on the cookie jar
+ # to prevent other users on the system from hi-jacking your
+ # authenticated sessions simply by copying your cookie jar.
+ os.chmod(cookie_jar, 0600)
+
+ except:
+ pass
+
+
+ def reload_whitelist(self):
+ '''Reload the cookie whitelist.'''
+
+ cookie_whitelist = config['cookie_whitelist']
+ if os.path.exists(cookie_whitelist):
+ echo("reloading whitelist %r" % cookie_whitelist)
+ self.open_cookie_jar()
+
+
+ def create_socket(self):
+ '''Create AF_UNIX socket for communication with uzbl instances.'''
+
+ cookie_socket = config['cookie_socket']
+ mkbasedir(cookie_socket)
+
+ self.server_socket = socket.socket(socket.AF_UNIX,
+ socket.SOCK_SEQPACKET)
+
+ self.server_socket.bind(cookie_socket)
+
+ # Set restrictive permissions on the cookie socket to prevent other
+ # users on the system from data-mining your cookies.
+ os.chmod(cookie_socket, 0600)
+
+
+ def listen(self):
+ '''Listen for incoming cookie PUT and GET requests.'''
+
+ daemon_timeout = config['daemon_timeout']
+ echo("listening on %r" % config['cookie_socket'])
+
+ 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)
+ self.last_request = time.time()
+ client_socket.close()
+ continue
+
+ if daemon_timeout:
+ # Checks if the daemon has been idling for too long.
+ idle = time.time() - self.last_request
+ if idle > daemon_timeout:
+ self._running = False
+
+
+ def handle_request(self, client_socket):
+ '''Connection made, now to serve a cookie PUT or GET request.'''
+
+ # Receive cookie request from client.
+ data = client_socket.recv(8192)
+ if not data:
+ return
+
+ # Cookie argument list in packet is null separated.
+ argv = data.split("\0")
+ action = argv[0].upper().strip()
+
+ # Catch the EXIT command sent to kill running daemons.
+ if action == "EXIT":
+ self._running = False
+ return
+
+ # Catch whitelist RELOAD command.
+ elif action == "RELOAD":
+ self.reload_whitelist()
+ return
+
+ # Return if command unknown.
+ elif action not in ['GET', 'PUT']:
+ error("unknown command %r." % argv)
+ return
+
+ # Determine whether or not to print cookie data to terminal.
+ print_cookie = (config['verbose'] and not config['daemon_mode'])
+ if print_cookie:
+ print ' '.join(argv[:4])
+
+ uri = urllib2.urlparse.ParseResult(
+ scheme=argv[1],
+ netloc=argv[2],
+ path=argv[3],
+ params='',
+ query='',
+ fragment='').geturl()
+
+ 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
+
+ else:
+ client_socket.send("\0")
+
+ elif action == "PUT":
+ cookie = argv[4] if len(argv) > 3 else None
+ if print_cookie:
+ print cookie
+
+ self.put_cookie(req, cookie)
+
+ if print_cookie:
+ print
+
+
+ def put_cookie(self, req, cookie=None):
+ '''Put a cookie in the cookie jar.'''
+
+ hdr = urllib2.httplib.HTTPMessage(\
+ StringIO.StringIO('Set-Cookie: %s' % cookie))
+ res = urllib2.addinfourl(StringIO.StringIO(), hdr,
+ req.get_full_url())
+ self.jar.extract_cookies(res, req)
+ if config['cookie_jar']:
+ self.jar.save(ignore_discard=True)
+
+
+ def del_socket(self):
+ '''Remove the cookie_socket file on exit. In a way the cookie_socket
+ is the daemons pid file equivalent.'''
+
+ if self.server_socket:
+ try:
+ self.server_socket.close()
+
+ except:
+ pass
+
+ self.server_socket = None
+
+ cookie_socket = config['cookie_socket']
+ if os.path.exists(cookie_socket):
+ echo("deleting socket %r" % cookie_socket)
+ os.remove(cookie_socket)
+
+
+ def quit(self):
+ '''Called on exit to make sure all loose ends are tied up.'''
+
+ self.del_socket()
+ sys.exit(0)
+
+
+def main():
+ '''Main function.'''
+
+ # Define command line parameters.
+ usage = "usage: %prog [options] {start|stop|restart|reload}"
+ parser = OptionParser(usage=usage)
+ parser.add_option('-n', '--no-daemon', dest='no_daemon',
+ action='store_true', help="don't daemonise the process.")
+
+ parser.add_option('-v', '--verbose', dest="verbose",
+ action='store_true', help="print verbose output.")
+
+ parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout',
+ action="store", metavar="SECONDS", help="shutdown the daemon after x "\
+ "seconds inactivity. WARNING: Do not use this when launching the "\
+ "cookie daemon manually.")
+
+ parser.add_option('-s', '--cookie-socket', dest="cookie_socket",
+ metavar="SOCKET", help="manually specify the socket location.")
+
+ parser.add_option('-j', '--cookie-jar', dest='cookie_jar',
+ metavar="FILE", help="manually specify the cookie jar location.")
+
+ parser.add_option('-m', '--memory', dest='memory', action='store_true',
+ help="store cookies in memory only - do not write to disk")
+
+ parser.add_option('-u', '--use-whitelist', dest='usewhitelist',
+ action='store_true', help="use cookie whitelist policy")
+
+ parser.add_option('-w', '--cookie-whitelist', dest='whitelist',
+ action='store', help="manually specify whitelist location",
+ metavar='FILE')
+
+ # Parse the command line arguments.
+ (options, args) = parser.parse_args()
+
+ expand = lambda p: os.path.realpath(os.path.expandvars(p))
+
+ initcommands = ['start', 'stop', 'restart', 'reload']
+ for arg in args:
+ if arg not in initcommands:
+ error("unknown argument %r" % args[0])
+ sys.exit(1)
+
+ if len(args) > 1:
+ error("the daemon only accepts one {%s} action at a time."
+ % '|'.join(initcommands))
+ sys.exit(1)
+
+ if len(args):
+ action = args[0]
+
+ else:
+ action = "start"
+
+ if options.no_daemon:
+ config['daemon_mode'] = False
+
+ if options.cookie_socket:
+ config['cookie_socket'] = expand(options.cookie_socket)
+
+ if options.cookie_jar:
+ config['cookie_jar'] = expand(options.cookie_jar)
+
+ if options.memory:
+ config['cookie_jar'] = None
+
+ if options.whitelist:
+ config['cookie_whitelist'] = expand(options.whitelist)
+
+ if options.whitelist or options.usewhitelist:
+ config['use_whitelist'] = True
+
+ if options.daemon_timeout:
+ try:
+ config['daemon_timeout'] = int(options.daemon_timeout)
+
+ except ValueError:
+ error("expected int argument for -t, --daemon-timeout")
+
+ # Expand $VAR's in config keys that relate to paths.
+ for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']:
+ if config[key]:
+ config[key] = os.path.expandvars(config[key])
+
+ if options.verbose:
+ config['verbose'] = True
+ import pprint
+ sys.stderr.write("%s\n" % pprint.pformat(config))
+
+ # It would be better if we didn't need to start this python process just
+ # to send a command to the socket, but unfortunately socat doesn't seem
+ # to support SEQPACKET.
+ if action == "reload":
+ send_command(config['cookie_socket'], "RELOAD")
+
+ if action in ['stop', 'restart']:
+ kill_daemon(config['cookie_socket'])
+
+ if action in ['start', 'restart']:
+ CookieMonster().run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.config/uzbl/scripts/cookies.py b/.config/uzbl/scripts/cookies.py
new file mode 100755
index 0000000..10f90fa
--- /dev/null
+++ b/.config/uzbl/scripts/cookies.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+import StringIO, cookielib, os, sys, urllib2
+
+if __name__ == '__main__':
+ action = sys.argv[8]
+ uri = urllib2.urlparse.ParseResult(
+ scheme=sys.argv[9],
+ netloc=sys.argv[10],
+ path=sys.argv[11],
+ params='',
+ query='',
+ fragment='').geturl()
+ set_cookie = sys.argv[12] if len(sys.argv)>12 else None
+
+ if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']:
+ f = os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt')
+ else:
+ f = os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')
+ jar = cookielib.MozillaCookieJar(f)
+
+ try:
+ jar.load(ignore_discard=True)
+ except:
+ pass
+
+ req = urllib2.Request(uri)
+
+ if action == 'GET':
+ jar.add_cookie_header(req)
+ if req.has_header('Cookie'):
+ print req.get_header('Cookie')
+ elif action == 'PUT':
+ hdr = urllib2.httplib.HTTPMessage(StringIO.StringIO('Set-Cookie: %s' % set_cookie))
+ res = urllib2.addinfourl(StringIO.StringIO(), hdr, req.get_full_url())
+ jar.extract_cookies(res,req)
+ jar.save(ignore_discard=True)
diff --git a/.config/uzbl/scripts/cookies.sh b/.config/uzbl/scripts/cookies.sh
new file mode 100755
index 0000000..339c6fc
--- /dev/null
+++ b/.config/uzbl/scripts/cookies.sh
@@ -0,0 +1,154 @@
+#!/bin/sh
+
+set -n;
+
+# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!!
+
+# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as cookies.py
+# we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt)
+# This is one textfile with entries like this:
+# kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993
+# domain alow-read-other-subdomains path http-required expiration name value
+# you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies)
+# Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session"
+# MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :(
+# TODO: different cookie paths per config (eg per group of uzbl instances)
+
+# TODO: correct implementation.
+# see http://curl.haxx.se/rfc/cookie_spec.html
+# http://en.wikipedia.org/wiki/HTTP_cookie
+
+# TODO : check expires= before sending.
+# write sample script that cleans up cookies dir based on expires attribute.
+# TODO: check uri against domain attribute. and path also.
+# implement secure attribute.
+# support blocking or not for 3rd parties
+# http://kb.mozillazine.org/Cookies.txt
+# don't always append cookies, sometimes we need to overwrite
+
+cookie_config=${XDG_CONFIG_HOME:-${HOME}/.config}/uzbl/cookies
+[ "x$cookie_config" = x ] && exit 1
+[ -d "${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/" ] &&\
+cookie_data=${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/cookies.txt || exit 1
+
+notifier=
+#notifier=notify-send
+#notify_wrapper () {
+# echo "$@" >> $HOME/cookielog
+#}
+#notifier=notifier_wrapper
+
+# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send.
+# it's primarily used for debugging
+notifier=
+which zenity &>/dev/null || exit 2
+
+# Example cookie:
+# test_cookie=CheckForPermission; expires=Thu, 07-May-2009 19:17:55 GMT; path=/; domain=.doubleclick.net
+
+# uri=$6
+# uri=${uri/http:\/\/} # strip 'http://' part
+# host=${uri/\/*/}
+action=$8 # GET/PUT
+shift
+host=$9
+shift
+path=$9
+shift
+cookie=$9
+
+field_domain=$host
+field_path=$path
+field_name=
+field_value=
+field_exp='end_session'
+
+notify() {
+ [ -n "$notifier" ] && $notifier "$@"
+}
+
+
+# FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET
+parse_cookie() {
+ IFS=$';'
+ first_pair=1
+ for pair in $cookie
+ do
+ if [ "x$first_pair" = x1 ]
+ then
+ field_name=${pair%%=*}
+ field_value=${pair#*=}
+ first_pair=0
+ else
+ echo "$pair" | read -r pair #strip leading/trailing wite space
+ key=${pair%%=*}
+ val=${pair#*=}
+ [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'`
+ # TODO: domain
+ [ "$key" == path ] && field_path=$val
+ fi
+ done
+ unset IFS
+}
+
+# match cookies in cookies.txt against hostname and path
+get_cookie() {
+ path_esc=${path//\//\\/}
+ search="^[^\t]*$host\t[^\t]*\t$path_esc"
+ cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1`
+ if [ -z "$cookie" ]
+ then
+ notify "Get_cookie: search: $search in $cookie_data -> no result"
+ false
+ else
+ notify "Get_cookie: search: $search in $cookie_data -> result: $cookie"
+ echo "$cookie" | \
+ read domain alow_read_other_subdomains path http_required expiration name \
+ value;
+ cookie="$name=$value"
+ true
+ fi
+}
+
+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_data"
+ echo -e "$data" >> $cookie_data
+ else
+ notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug"
+ fi
+}
+
+[ "x$action" = xPUT ] && save_cookie
+[ "x$action" = xGET ] && get_cookie && echo "$cookie"
+
+exit
+
+
+# TODO: implement this later.
+# $1 = section (TRUSTED or DENY)
+# $2 =url
+match() {
+ sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host"
+}
+
+fetch_cookie() {
+ cookie=`cat $cookie_data`
+}
+
+store_cookie() {
+ echo $cookie > $cookie_data
+}
+
+if match TRUSTED $host
+then
+ [ "x$action" = xPUT ] && store_cookie $host
+ [ "x$action" = xGET ] && fetch_cookie && echo "$cookie"
+elif ! match DENY $host
+then
+ [ "x$action" = xPUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host
+ [ "x$action" = xGET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie
+fi
+exit 0
diff --git a/.config/uzbl/scripts/download.sh b/.config/uzbl/scripts/download.sh
new file mode 100755
index 0000000..c8eb6ba
--- /dev/null
+++ b/.config/uzbl/scripts/download.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# just an example of how you could handle your downloads
+# try some pattern matching on the uri to determine what we should do
+
+# Some sites block the default wget --user-agent..
+GET="wget --user-agent=Firefox"
+
+dest="$HOME"
+url="$8"
+
+http_proxy="$9"
+export http_proxy
+
+test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; }
+
+# only changes the dir for the $get sub process
+if echo "$url" | grep -E '.*\.torrent' >/dev/null;
+then
+ ( cd "$dest"; eval "$GET" "$url")
+else
+ ( cd "$dest"; eval "$GET" "$url")
+fi
diff --git a/.config/uzbl/scripts/follow_Numbers.js b/.config/uzbl/scripts/follow_Numbers.js
new file mode 100644
index 0000000..efde4d7
--- /dev/null
+++ b/.config/uzbl/scripts/follow_Numbers.js
@@ -0,0 +1,223 @@
+/* This is the basic linkfollowing script.
+ * Its pretty stable, only using numbers to navigate.
+ *
+ * TODO: Some pages mess around a lot with the zIndex which
+ * lets some hints in the background.
+ * TODO: Some positions are not calculated correctly (mostly
+ * because of uber-fancy-designed-webpages. Basic HTML and CSS
+ * works good
+ * TODO: Still some links can't be followed/unexpected things
+ * happen. Blame some freaky webdesigners ;)
+ */
+
+//Just some shortcuts and globals
+var uzblid = 'uzbl_link_hint';
+var uzbldivid = uzblid + '_div_container';
+var doc = document;
+var win = window;
+var links = document.links;
+var forms = document.forms;
+//Make onlick-links "clickable"
+try {
+ HTMLElement.prototype.click = function() {
+ if (typeof this.onclick == 'function') {
+ this.onclick({
+ type: 'click'
+ });
+ }
+ };
+} catch(e) {}
+//Catch the ESC keypress to stop linkfollowing
+function keyPressHandler(e) {
+ var kC = window.event ? event.keyCode: e.keyCode;
+ var Esc = window.event ? 27 : e.DOM_VK_ESCAPE;
+ if (kC == Esc) {
+ removeAllHints();
+ }
+}
+//Calculate element position to draw the hint
+//Pretty accurate but on fails in some very fancy cases
+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;
+ }
+ return [up, left, width, height];
+}
+//Calculate if an element is visible
+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);
+}
+//Calculate if an element is on the viewport.
+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;
+}
+//Removes all hints/leftovers that might be generated
+//by this script.
+function removeAllHints() {
+ var elements = doc.getElementById(uzbldivid);
+ if (elements) {
+ elements.parentNode.removeChild(elements);
+ }
+}
+//Generate a hint for an element with the given label
+//Here you can play around with the style of the hints!
+function generateHint(el, label) {
+ var pos = elementPosition(el);
+ var hint = doc.createElement('div');
+ hint.setAttribute('name', uzblid);
+ 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 = '1000';
+ hint.style.left = pos[1] + 'px';
+ hint.style.top = pos[0] + 'px';
+ var img = el.getElementsByTagName('img');
+ if (img.length > 0) {
+ hint.style.left = pos[1] + img[0].width / 2 + 'px';
+ }
+ 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;
+}
+//Here we choose what to do with an element if we
+//want to "follow" it. On form elements we "select"
+//or pass the focus, on links we try to perform a click,
+//but at least set the href of the link. (needs some improvements)
+function clickElem(item) {
+ removeAllHints();
+ if (item) {
+ var name = item.tagName;
+ if (name == 'A') {
+ 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') {
+ item.focus();
+ item.select();
+ } else {
+ item.click();
+ window.location = item.href;
+ }
+ }
+}
+//Returns a list of all links (in this version
+//just the elements itself, but in other versions, we
+//add the label here.
+function addLinks() {
+ res = [[], []];
+ for (var l = 0; l < links.length; l++) {
+ var li = links[l];
+ if (isVisible(li) && elementInViewport(li)) {
+ res[0].push(li);
+ }
+ }
+ return res;
+}
+//Same as above, just for the form elements
+function addFormElems() {
+ res = [[], []];
+ for (var f = 0; f < forms.length; f++) {
+ for (var e = 0; e < forms[f].elements.length; e++) {
+ var el = forms[f].elements[e];
+ if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) {
+ res[0].push(el);
+ }
+ }
+ }
+ return res;
+}
+//Draw all hints for all elements passed. "len" is for
+//the number of chars we should use to avoid collisions
+function reDrawHints(elems, chars) {
+ removeAllHints();
+ var hintdiv = doc.createElement('div');
+ hintdiv.setAttribute('id', uzbldivid);
+ for (var i = 0; i < elems[0].length; i++) {
+ if (elems[0][i]) {
+ var label = elems[1][i].substring(chars);
+ var h = generateHint(elems[0][i], label);
+ hintdiv.appendChild(h);
+ }
+ }
+ if (document.body) {
+ document.body.appendChild(hintdiv);
+ }
+}
+//Put it all together
+function followLinks(follow) {
+ var s = follow.split('');
+ var linknr = parseInt(follow, 10);
+ if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)');
+ var linkelems = addLinks();
+ var formelems = addFormElems();
+ var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])];
+ var len = (elems[0].length + '').length;
+ var oldDiv = doc.getElementById(uzbldivid);
+ var leftover = [[], []];
+ if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) {
+ clickElem(elems[0][linknr]);
+ } else {
+ for (var j = 0; j < elems[0].length; j++) {
+ var b = true;
+ var label = j + '';
+ var n = label.length;
+ for (n; n < len; n++) {
+ label = '0' + label;
+ }
+ for (var k = 0; k < s.length; k++) {
+ b = b && label.charAt(k) == s[k];
+ }
+ if (b) {
+ leftover[0].push(elems[0][j]);
+ leftover[1].push(label);
+ }
+ }
+ reDrawHints(leftover, s.length);
+ }
+}
+followLinks('%s');
diff --git a/.config/uzbl/scripts/follow_Numbers_Strings.js b/.config/uzbl/scripts/follow_Numbers_Strings.js
new file mode 100644
index 0000000..67da2f9
--- /dev/null
+++ b/.config/uzbl/scripts/follow_Numbers_Strings.js
@@ -0,0 +1,205 @@
+var uzblid = 'uzbl_link_hint';
+var uzbldivid = uzblid + '_div_container';
+var doc = document;
+var win = window;
+var links = document.links;
+var forms = document.forms;
+try {
+ HTMLElement.prototype.click = function() {
+ if (typeof this.onclick == 'function') {
+ this.onclick({
+ type: 'click'
+ });
+ }
+ };
+} catch(e) {}
+function keyPressHandler(e) {
+ var kC = window.event ? event.keyCode: e.keyCode;
+ var Esc = window.event ? 27 : e.DOM_VK_ESCAPE;
+ if (kC == Esc) {
+ removeAllHints();
+ }
+}
+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;
+ }
+ return [up, left, width, height];
+}
+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 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 removeAllHints() {
+ var elements = doc.getElementById(uzbldivid);
+ if (elements) {
+ elements.parentNode.removeChild(elements);
+ }
+}
+function generateHint(el, label) {
+ var pos = elementPosition(el);
+ var hint = doc.createElement('div');
+ hint.setAttribute('name', uzblid);
+ hint.innerText = label;
+ hint.style.display = 'inline';
+ hint.style.backgroundColor = '#B9FF00';
+ hint.style.border = '2px solid #4A6600';
+ hint.style.color = 'black';
+ hint.style.zIndex = '1000';
+ 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.left = pos[1] + 'px';
+ hint.style.top = pos[0] + 'px';
+ var img = el.getElementsByTagName('img');
+ if (img.length > 0) {
+ hint.style.left = pos[1] + img[0].width / 2 + 'px';
+ }
+ hint.style.textDecoration = 'none';
+ hint.style.webkitBorderRadius = '6px';
+ hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)';
+ return hint;
+}
+function clickElem(item) {
+ removeAllHints();
+ if (item) {
+ var name = item.tagName;
+ if (name == 'A') {
+ 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') {
+ item.focus();
+ item.select();
+ } else {
+ item.click();
+ window.location = item.href;
+ }
+ }
+}
+function addLinks() {
+ res = [[], []];
+ for (var l = 0; l < links.length; l++) {
+ var li = links[l];
+ if (isVisible(li) && elementInViewport(li)) {
+ res[0].push(li);
+ res[1].push(li.innerText.toLowerCase());
+ }
+ }
+ return res;
+}
+function addFormElems() {
+ res = [[], []];
+ for (var f = 0; f < forms.length; f++) {
+ for (var e = 0; e < forms[f].elements.length; e++) {
+ var el = forms[f].elements[e];
+ if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) {
+ res[0].push(el);
+ if (el.getAttribute('value')) {
+ res[1].push(el.getAttribute('value').toLowerCase());
+ } else {
+ res[1].push(el.getAttribute('name').toLowerCase());
+ }
+ }
+ }
+ }
+ return res;
+}
+function reDrawHints(elems, len) {
+ var hintdiv = doc.createElement('div');
+ hintdiv.setAttribute('id', uzbldivid);
+ hintdiv.style.opacity = '0.0';
+ for (var i = 0; i < elems[0].length; i++) {
+ var label = i + '';
+ var n = label.length;
+ for (n; n < len; n++) {
+ label = '0' + label;
+ }
+ if (elems[0][i]) {
+ var h = generateHint(elems[0][i], label);
+ hintdiv.appendChild(h);
+ }
+ }
+ if (document.body) {
+ document.body.appendChild(hintdiv);
+ hintdiv.style.opacity = '0.7'
+ }
+}
+function followLinks(follow) {
+ var s = follow.split('');
+ var linknr = parseInt(follow, 10);
+ if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)');
+ var linkelems = addLinks();
+ var formelems = addFormElems();
+ var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])];
+ var len = (elems[0].length + '').length;
+ var oldDiv = doc.getElementById(uzbldivid);
+ var leftover = [[], []];
+ if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) {
+ clickElem(elems[0][linknr]);
+ } else {
+ for (var j = 0; j < elems[0].length; j++) {
+ var b = true;
+ for (var k = 0; k < s.length; k++) {
+ b = b && elems[1][j].charAt(k) == s[k];
+ }
+ if (!b) {
+ elems[0][j] = null;
+ elems[1][j] = null;
+ } else {
+ leftover[0].push(elems[0][j]);
+ leftover[1].push(elems[1][j]);
+ }
+ }
+ if (leftover[0].length == 1) {
+ clickElem(leftover[0][0]);
+ } else if (!oldDiv) {
+ if (linknr + 1 || s.length == 0) {
+ reDrawHints(elems, len);
+ } else {
+ reDrawHints(leftover, len);
+ }
+ }
+ }
+}
+followLinks('%s');
diff --git a/.config/uzbl/scripts/formfiller.pl b/.config/uzbl/scripts/formfiller.pl
new file mode 100755
index 0000000..23da347
--- /dev/null
+++ b/.config/uzbl/scripts/formfiller.pl
@@ -0,0 +1,99 @@
+#!/usr/bin/perl
+
+# a slightly more advanced form filler
+#
+# uses settings file like: $keydir/<domain>
+#TODO: fallback to $HOME/.local/share
+# user arg 1:
+# edit: force editing of the file (fetches if file is missing)
+# load: fill forms from file (fetches if file is missing)
+# new: fetch new file
+
+# usage example:
+# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller.pl load
+# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller.pl new
+# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit
+
+use strict;
+use warnings;
+
+my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms";
+my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV;
+if (!defined $fifoname || $fifoname eq "") { die "No fifo"; }
+
+sub domain {
+ my ($url) = @_;
+ $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#;
+ return $url;
+};
+
+my $editor = "xterm -e vim";
+#my $editor = "gvim";
+
+# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with
+# Also, you may need to fake the user-agent on some sites (like facebook)
+ my $downloader = "curl -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042810 GranParadiso/3.0.10' ";
+#my $downloader = "curl -s";
+
+my @fields = ("type","name","value");
+
+my %command;
+
+$command{load} = sub {
+ my ($domain) = @_;
+ my $filename = "$keydir/$domain";
+ if (-e $filename){
+ open(my $file, $filename) or die "Failed to open $filename: $!";
+ my (@lines) = <$file>;
+ close($file);
+ $|++;
+ open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!";
+ foreach my $line (@lines) {
+ 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";
+ }
+ $|--;
+ } else {
+ $command{new}->($domain);
+ $command{edit}->($domain);
+ }
+};
+$command{edit} = sub {
+ my ($domain) = @_;
+ my $file = "$keydir/$domain";
+ if(-e $file){
+ system ($editor, $file);
+ } else {
+ $command{new}->($domain);
+ }
+};
+$command{new} = sub {
+ my ($domain) = @_;
+ 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";
+ 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;
+ };
+ };
+ $|--;
+};
+
+$command{$cmd}->(domain($url));
diff --git a/.config/uzbl/scripts/formfiller.sh b/.config/uzbl/scripts/formfiller.sh
new file mode 100755
index 0000000..10afaba
--- /dev/null
+++ b/.config/uzbl/scripts/formfiller.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# simple html form (eg for logins) filler (and manager) for uzbl.
+# uses settings files like: $keydir/<domain>
+# files contain lines like: <fieldname>: <value>
+
+
+# user arg 1:
+# edit: force editing the file (falls back to new if not found)
+# new: start with a new file.
+# load: try to load from file into form
+
+# something else (or empty): if file not available: new, otherwise load.
+
+keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/forms
+[ -d "`dirname $keydir`" ] || exit 1
+[ -d "$keydir" ] || mkdir "$keydir"
+
+editor=${VISUAL}
+if [[ -z ${editor} ]]; then
+ #editor='gvim'
+ editor='urxvt -e vim'
+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
+
+if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' ]
+then
+ action=new
+ [[ -e $keydir/$domain ]] && action=load
+elif [ "$action" == 'edit' ] && [[ ! -e $keydir/$domain ]]
+then
+ action=new
+fi
+domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|')
+
+
+#regex='s|.*<input.*?name="([[:graph:]]+)".*?/>.*|\1: |p' # sscj's first version, does not work on http://wiki.archlinux.org/index.php?title=Special:UserLogin&returnto=Main_Page
+ regex='s|.*<input.*?name="([^"]*)".*|\1: |p' #works on arch wiki, but not on http://lists.uzbl.org/listinfo.cgi/uzbl-dev-uzbl.org TODO: improve
+
+
+if [ "$action" = 'load' ]
+then
+ [[ -e $keydir/$domain ]] || exit 2
+ gawk -F': ' '{ print "js document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo
+else
+ if [ "$action" == 'new' ]
+ then
+ curl "$url" | grep '<input' | sed -nre "$regex" > $keydir/$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
+fi
diff --git a/.config/uzbl/scripts/hint.js b/.config/uzbl/scripts/hint.js
new file mode 100644
index 0000000..ec7f1e2
--- /dev/null
+++ b/.config/uzbl/scripts/hint.js
@@ -0,0 +1,26 @@
+for (var i=0; i < document.links.length; i++) {
+ var uzblid = 'uzbl_link_hint_';
+ var li = document.links[i];
+ var pre = document.getElementById(uzblid+i);
+
+ if (pre) {
+ li.removeChild(pre);
+ } else {
+ var hint = document.createElement('div');
+ hint.setAttribute('id',uzblid+i);
+ hint.innerHTML = i;
+ hint.style.display='inline';
+ hint.style.lineHeight='90%';
+ hint.style.backgroundColor='red';
+ hint.style.color='white';
+ hint.style.fontSize='small-xx';
+ hint.style.fontWeight='light';
+ hint.style.margin='0px';
+ hint.style.padding='2px';
+ hint.style.position='absolute';
+ hint.style.textDecoration='none';
+ hint.style.left=li.style.left;
+ hint.style.top=li.style.top;
+ li.insertAdjacentElement('afterBegin',hint);
+ }
+}
diff --git a/.config/uzbl/scripts/history.sh b/.config/uzbl/scripts/history.sh
new file mode 100755
index 0000000..7c83aa6
--- /dev/null
+++ b/.config/uzbl/scripts/history.sh
@@ -0,0 +1,5 @@
+#!/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
diff --git a/.config/uzbl/scripts/insert_bookmark.sh b/.config/uzbl/scripts/insert_bookmark.sh
new file mode 100755
index 0000000..e04e6d4
--- /dev/null
+++ b/.config/uzbl/scripts/insert_bookmark.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1
+file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks
+
+which zenity &>/dev/null || exit 2
+
+entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"`
+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
+true
diff --git a/.config/uzbl/scripts/linkfollow.js b/.config/uzbl/scripts/linkfollow.js
new file mode 100644
index 0000000..0eb629b
--- /dev/null
+++ b/.config/uzbl/scripts/linkfollow.js
@@ -0,0 +1,269 @@
+// link follower for uzbl
+// 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 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 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: 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;
+
+ // Case sensitivity flag
+ var matchCase = "i";
+
+ // For case sensitive matching, uncomment:
+ // var matchCase = "";
+
+
+ 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;
+ }
+ return {up: up, left: left, width: width, height: height};
+ }
+
+ 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 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";
+
+ 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 matchAgainst(element){
+ if(element.node.nodeName == "INPUT"){
+ return element.node.value;
+ } else {
+ return element.node.textContent;
+ }
+ }
+ function test(element) {
+ // test all the regexp
+ var item = matchAgainst(element);
+ return words.every(function (regex) { return item.match(regex)});
+ }
+ }
+
+ function HintElement(node,pos){
+
+ this.node = node;
+ this.isHinted = false;
+ this.position = pos;
+ this.num = 0;
+
+ 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) {
+ var kC = window.event ? event.keyCode: e.keyCode;
+ var Esc = window.event ? 27 : e.DOM_VK_ESCAPE;
+ if (kC == Esc) {
+ 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;
+ }
+ if (item) {
+ 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();
+ }
+ } 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/.config/uzbl/scripts/load_url_from_bookmarks.sh b/.config/uzbl/scripts/load_url_from_bookmarks.sh
new file mode 100755
index 0000000..1e9f9e7
--- /dev/null
+++ b/.config/uzbl/scripts/load_url_from_bookmarks.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+#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}'`
+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`
+fi
+
+#[ -n "$goto" ] && echo "uri $goto" > $4
+[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5
diff --git a/.config/uzbl/scripts/load_url_from_history.sh b/.config/uzbl/scripts/load_url_from_history.sh
new file mode 100755
index 0000000..62e02ac
--- /dev/null
+++ b/.config/uzbl/scripts/load_url_from_history.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history
+[ -r "$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}'`
+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`
+fi
+
+[ -n "$goto" ] && echo "uri $goto" > $4
+#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5
diff --git a/.config/uzbl/scripts/scheme.py b/.config/uzbl/scripts/scheme.py
new file mode 100755
index 0000000..7286703
--- /dev/null
+++ b/.config/uzbl/scripts/scheme.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+import os, subprocess, sys, urlparse
+
+def detach_open(cmd):
+ # Thanks to the vast knowledge of Laurence Withers (lwithers) and this message:
+ # http://mail.python.org/pipermail/python-list/2006-November/587523.html
+ if not os.fork():
+ null = os.open(os.devnull,os.O_WRONLY)
+ for i in range(3): os.dup2(null,i)
+ os.close(null)
+ subprocess.Popen(cmd)
+ print 'USED'
+
+if __name__ == '__main__':
+ uri = sys.argv[8]
+ u = urlparse.urlparse(uri)
+ if u.scheme == 'mailto':
+ detach_open(['xterm', '-e', 'mail %s' % u.path])
+ elif u.scheme == 'xmpp':
+ detach_open(['gajim-remote', 'open_chat', uri])
+ elif u.scheme == 'git':
+ detach_open(['git', 'clone', uri], cwd=os.path.expanduser('~/src'))
diff --git a/.config/uzbl/scripts/session.sh b/.config/uzbl/scripts/session.sh
new file mode 100755
index 0000000..22d48a2
--- /dev/null
+++ b/.config/uzbl/scripts/session.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# Very simple session manager for uzbl. When called with "endsession" as the
+# argument, it'll backup $sessionfile, look for fifos in $fifodir and
+# instruct each of them to store their current url in $sessionfile and
+# terminate themselves. Run with "launch" as the argument and an instance of
+# uzbl will be launched for each stored url. "endinstance" is used internally
+# and doesn't need to be called manually at any point.
+# Add a line like 'bind quit = /path/to/session.sh endsession' to your config
+
+[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1
+scriptfile=$0 # this script
+sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/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 -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
+
+
+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"
+ ;;
+esac
diff --git a/.config/uzbl/scripts/uzbl_tabbed.py b/.config/uzbl/scripts/uzbl_tabbed.py
new file mode 100755
index 0000000..cd5ef4f
--- /dev/null
+++ b/.config/uzbl/scripts/uzbl_tabbed.py
@@ -0,0 +1,1474 @@
+#!/usr/bin/env python
+
+# Uzbl tabbing wrapper using a fifo socket interface
+# Copyright (c) 2009, Tom Adams <tom@holizz.com>
+# Copyright (c) 2009, Chris van Dijk <cn.vandijk@hotmail.com>
+# Copyright (c) 2009, Mason Larobina <mason.larobina@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+# Author(s):
+# Tom Adams <tom@holizz.com>
+# Wrote the original uzbl_tabbed.py as a proof of concept.
+#
+# Chris van Dijk (quigybo) <cn.vandijk@hotmail.com>
+# Made signifigant headway on the old uzbl_tabbing.py script on the
+# uzbl wiki <http://www.uzbl.org/wiki/uzbl_tabbed>
+#
+# Mason Larobina <mason.larobina@gmail.com>
+# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface
+# and inherit configuration options from the user's uzbl config.
+#
+# Contributor(s):
+# mxey <mxey@ghosthacking.net>
+# uzbl_config path now honors XDG_CONFIG_HOME if it exists.
+#
+# Romain Bignon <romain@peerfuse.org>
+# Fix for session restoration code.
+#
+# Jake Probst <jake.probst@gmail.com>
+# Wrote a patch that overflows tabs in the tablist on to new lines when
+# running of room.
+#
+# Devon Jones <devon.jones@gmail.com>
+# Fifo command bring_to_front which brings the gtk window to focus.
+
+
+# Dependencies:
+# pygtk - python bindings for gtk.
+# pango - python bindings needed for text rendering & layout in gtk widgets.
+# pygobject - GLib's GObject bindings for python.
+#
+# Optional dependencies:
+# simplejson - save uzbl_tabbed.py sessions & presets in json.
+#
+# Note: I haven't included version numbers with this dependency list because
+# I've only ever tested uzbl_tabbed.py on the latest stable versions of these
+# packages in Gentoo's portage. Package names may vary on different systems.
+
+
+# Configuration:
+# Because this version of uzbl_tabbed is able to inherit options from your main
+# uzbl configuration file you may wish to configure uzbl tabbed from there.
+# Here is a list of configuration options that can be customised and some
+# example values for each:
+#
+# General tabbing options:
+# show_tablist = 1
+# show_gtk_tabs = 0
+# tablist_top = 1
+# gtk_tab_pos = (top|left|bottom|right)
+# gtk_refresh = 1000
+# switch_to_new_tabs = 1
+# capture_new_windows = 1
+# multiline_tabs = 1
+#
+# Tab title options:
+# tab_titles = 1
+# new_tab_title = Loading
+# max_title_len = 50
+# show_ellipsis = 1
+#
+# Session options:
+# save_session = 1
+# json_session = 0
+# session_file = $HOME/.local/share/uzbl/session
+#
+# Inherited uzbl options:
+# fifo_dir = /tmp
+# socket_dir = /tmp
+# icon_path = $HOME/.local/share/uzbl/uzbl.png
+# status_background = #303030
+#
+# Misc options:
+# window_size = 800,800
+# verbose = 0
+#
+# And the key bindings:
+# bind_new_tab = gn
+# bind_tab_from_clip = gY
+# bind_tab_from_uri = go _
+# bind_close_tab = gC
+# bind_next_tab = gt
+# bind_prev_tab = gT
+# bind_goto_tab = gi_
+# bind_goto_first = g<
+# bind_goto_last = g>
+# bind_clean_slate = gQ
+# bind_exit = gZ
+#
+# Session preset key bindings:
+# bind_save_preset = gsave _
+# bind_load_preset = gload _
+# bind_del_preset = gdel _
+# bind_list_presets = glist
+#
+# And uzbl_tabbed.py takes care of the actual binding of the commands via each
+# instances fifo socket.
+#
+# Custom tab styling:
+# tab_colours = foreground = "#888" background = "#303030"
+# tab_text_colours = foreground = "#bbb"
+# selected_tab = foreground = "#fff"
+# selected_tab_text = foreground = "green"
+# tab_indicate_https = 1
+# https_colours = foreground = "#888"
+# https_text_colours = foreground = "#9c8e2d"
+# selected_https = foreground = "#fff"
+# selected_https_text = foreground = "gold"
+#
+# How these styling values are used are soley defined by the syling policy
+# handler below (the function in the config section). So you can for example
+# turn the tab text colour Firetruck-Red in the event "error" appears in the
+# tab title or some other arbitrary event. You may wish to make a trusted
+# hosts file and turn tab titles of tabs visiting trusted hosts purple.
+
+
+# Issues:
+# - new windows are not caught and opened in a new tab.
+# - when uzbl_tabbed.py crashes it takes all the children with it.
+# - when a new tab is opened when using gtk tabs the tab button itself
+# grabs focus from its child for a few seconds.
+# - when switch_to_new_tabs is not selected the notebook page is
+# maintained but the new window grabs focus (try as I might to stop it).
+
+
+# Todo:
+# - add command line options to use a different session file, not use a
+# session file and or open a uri on starup.
+# - ellipsize individual tab titles when the tab-list becomes over-crowded
+# - add "<" & ">" arrows to tablist to indicate that only a subset of the
+# currently open tabs are being displayed on the tablist.
+# - add the small tab-list display when both gtk tabs and text vim-like
+# tablist are hidden (I.e. [ 1 2 3 4 5 ])
+# - check spelling.
+# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into
+# the collective. Resistance is futile!
+
+
+import pygtk
+import gtk
+import subprocess
+import os
+import re
+import time
+import getopt
+import pango
+import select
+import sys
+import gobject
+import socket
+import random
+import hashlib
+import atexit
+import types
+
+from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP
+from signal import signal, SIGTERM, SIGINT
+from optparse import OptionParser, OptionGroup
+
+
+pygtk.require('2.0')
+
+_SCRIPTNAME = os.path.basename(sys.argv[0])
+def error(msg):
+ sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg))
+
+# ============================================================================
+# ::: Default configuration section ::::::::::::::::::::::::::::::::::::::::::
+# ============================================================================
+
+def xdghome(key, default):
+ '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise
+ use $HOME and the default path.'''
+
+ xdgkey = "XDG_%s_HOME" % key
+ if xdgkey in os.environ.keys() and os.environ[xdgkey]:
+ return os.environ[xdgkey]
+
+ return os.path.join(os.environ['HOME'], default)
+
+# Setup xdg paths.
+DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/')
+CONFIG_DIR = os.path.join(xdghome('CONFIG', '.config/'), 'uzbl/')
+
+# Ensure uzbl xdg paths exist
+for path in [DATA_DIR, CONFIG_DIR]:
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+# Path to uzbl config
+UZBL_CONFIG = os.path.join(CONFIG_DIR, 'config')
+if not os.path.exists(UZBL_CONFIG):
+ error("cannot find uzbl config file at %r" % UZBL_CONFIG)
+ sys.exit(1)
+
+# All of these settings can be inherited from your uzbl config file.
+config = {
+ # Tab options
+ 'show_tablist': True, # Show text uzbl like statusbar tab-list
+ 'show_gtk_tabs': False, # Show gtk notebook tabs
+ 'tablist_top': True, # Display tab-list at top of window
+ 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right)
+ 'gtk_refresh': 1000, # Tablist refresh millisecond interval
+ 'switch_to_new_tabs': True, # Upon opening a new tab switch to it
+ 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows
+ 'multiline_tabs': True, # Tabs overflow onto new tablist lines.
+
+ # Tab title options
+ 'tab_titles': True, # Display tab titles (else only tab-nums)
+ 'new_tab_title': 'Loading', # New tab title
+ 'max_title_len': 50, # Truncate title at n characters
+ 'show_ellipsis': True, # Show ellipsis when truncating titles
+
+ # Session options
+ 'save_session': True, # Save session in file when quit
+ 'json_session': False, # Use json to save session.
+ 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'),
+ 'session_file': os.path.join(DATA_DIR, 'session'),
+
+ # Inherited uzbl options
+ 'fifo_dir': '/tmp', # Path to look for uzbl fifo.
+ 'socket_dir': '/tmp', # Path to look for uzbl socket.
+ 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'),
+ 'status_background': "#303030", # Default background for all panels.
+
+ # Misc options
+ 'window_size': "800,800", # width,height in pixels.
+ 'verbose': False, # Print verbose output.
+
+ # Key bindings
+ 'bind_new_tab': 'gn', # Open new tab.
+ 'bind_tab_from_clip': 'gY', # Open tab from clipboard.
+ 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri.
+ 'bind_close_tab': 'gC', # Close tab.
+ 'bind_next_tab': 'gt', # Next tab.
+ 'bind_prev_tab': 'gT', # Prev tab.
+ 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title).
+ 'bind_goto_first': 'g<', # Goto first tab.
+ 'bind_goto_last': 'g>', # Goto last tab.
+ 'bind_clean_slate': 'gQ', # Close all tabs and open new tab.
+ 'bind_exit': 'gZ', # Exit nicely.
+
+ # Session preset key bindings
+ 'bind_save_preset': 'gsave _', # Save session to file %s.
+ 'bind_load_preset': 'gload _', # Load preset session from file %s.
+ 'bind_del_preset': 'gdel _', # Delete preset session %s.
+ 'bind_list_presets': 'glist', # List all session presets.
+
+ # Add custom tab style definitions to be used by the tab colour policy
+ # handler here. Because these are added to the config dictionary like
+ # any other uzbl_tabbed configuration option remember that they can
+ # be superseeded from your main uzbl config file.
+ 'tab_colours': 'foreground = "#888" background = "#303030"',
+ 'tab_text_colours': 'foreground = "#bbb"',
+ 'selected_tab': 'foreground = "#fff"',
+ 'selected_tab_text': 'foreground = "green"',
+ 'tab_indicate_https': True,
+ 'https_colours': 'foreground = "#888"',
+ 'https_text_colours': 'foreground = "#9c8e2d"',
+ 'selected_https': 'foreground = "#fff"',
+ 'selected_https_text': 'foreground = "gold"',
+
+} # End of config dict.
+
+# This is the tab style policy handler. Every time the tablist is updated
+# this function is called to determine how to colourise that specific tab
+# according the simple/complex rules as defined here. You may even wish to
+# move this function into another python script and import it using:
+# from mycustomtabbingconfig import colour_selector
+# Remember to rename, delete or comment out this function if you do that.
+
+def colour_selector(tabindex, currentpage, uzbl):
+ '''Tablist styling policy handler. This function must return a tuple of
+ the form (tab style, text style).'''
+
+ # Just as an example:
+ # if 'error' in uzbl.title:
+ # if tabindex == currentpage:
+ # return ('foreground="#fff"', 'foreground="red"')
+ # return ('foreground="#888"', 'foreground="red"')
+
+ # Style tabs to indicate connected via https.
+ if config['tab_indicate_https'] and uzbl.uri.startswith("https://"):
+ if tabindex == currentpage:
+ return (config['selected_https'], config['selected_https_text'])
+ return (config['https_colours'], config['https_text_colours'])
+
+ # Style to indicate selected.
+ if tabindex == currentpage:
+ return (config['selected_tab'], config['selected_tab_text'])
+
+ # Default tab style.
+ return (config['tab_colours'], config['tab_text_colours'])
+
+# ============================================================================
+# ::: End of configuration section :::::::::::::::::::::::::::::::::::::::::::
+# ============================================================================
+
+def echo(msg):
+ if config['verbose']:
+ sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg))
+
+
+def readconfig(uzbl_config, config):
+ '''Loads relevant config from the users uzbl config file into the global
+ config dictionary.'''
+
+ if not os.path.exists(uzbl_config):
+ error("Unable to load config %r" % uzbl_config)
+ return None
+
+ # Define parsing regular expressions
+ isint = re.compile("^(\-|)[0-9]+$").match
+ findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\
+ re.MULTILINE).findall
+
+ h = open(os.path.expandvars(uzbl_config), 'r')
+ rawconfig = h.read()
+ h.close()
+
+ configkeys, strip = config.keys(), str.strip
+ for (key, value) in findsets(rawconfig):
+ key, value = strip(key), strip(value)
+ if key not in configkeys: continue
+ if isint(value): value = int(value)
+ config[key] = value
+
+ # Ensure that config keys that relate to paths are expanded.
+ pathkeys = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path',
+ 'saved_sessions_dir']
+ for key in pathkeys:
+ config[key] = os.path.expandvars(config[key])
+
+
+def counter():
+ '''To infinity and beyond!'''
+
+ i = 0
+ while True:
+ i += 1
+ yield i
+
+
+def escape(s):
+ '''Replaces html markup in tab titles that screw around with pango.'''
+
+ for (split, glue) in [('&','&amp;'), ('<', '&lt;'), ('>', '&gt;')]:
+ s = s.replace(split, glue)
+ return s
+
+
+def gen_endmarker():
+ '''Generates a random md5 for socket message-termination endmarkers.'''
+
+ return hashlib.md5(str(random.random()*time.time())).hexdigest()
+
+
+class UzblTabbed:
+ '''A tabbed version of uzbl using gtk.Notebook'''
+
+ class UzblInstance:
+ '''Uzbl instance meta-data/meta-action object.'''
+
+ def __init__(self, parent, tab, fifo_socket, socket_file, pid,\
+ uri, title, switch):
+
+ self.parent = parent
+ self.tab = tab
+ self.fifo_socket = fifo_socket
+ self.socket_file = socket_file
+ self.pid = pid
+ self.title = title
+ self.uri = uri
+ self.timers = {}
+ self._lastprobe = 0
+ self._fifoout = []
+ self._socketout = []
+ self._socket = None
+ self._buffer = ""
+ # Switch to tab after loading
+ self._switch = switch
+ # fifo/socket files exists and socket connected.
+ self._connected = False
+ # The kill switch
+ self._kill = False
+
+ # Message termination endmarker.
+ self._marker = gen_endmarker()
+
+ # Gen probe commands string
+ probes = []
+ probe = probes.append
+ probe('print uri %d @uri %s' % (self.pid, self._marker))
+ probe('print title %d @<document.title>@ %s' % (self.pid,\
+ self._marker))
+ self._probecmds = '\n'.join(probes)
+
+ # Enqueue keybinding config for child uzbl instance
+ self.parent.config_uzbl(self)
+
+
+ def flush(self, timer_call=False):
+ '''Flush messages from the socket-out and fifo-out queues.'''
+
+ if self._kill:
+ if self._socket:
+ self._socket.close()
+ self._socket = None
+
+ error("Flush called on dead tab.")
+ return False
+
+ if len(self._fifoout):
+ if os.path.exists(self.fifo_socket):
+ h = open(self.fifo_socket, 'w')
+ while len(self._fifoout):
+ msg = self._fifoout.pop(0)
+ h.write("%s\n"%msg)
+ h.close()
+
+ if len(self._socketout):
+ if not self._socket and os.path.exists(self.socket_file):
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(self.socket_file)
+ self._socket = sock
+
+ if self._socket:
+ while len(self._socketout):
+ msg = self._socketout.pop(0)
+ self._socket.send("%s\n"%msg)
+
+ if not self._connected and timer_call:
+ if not len(self._fifoout + self._socketout):
+ self._connected = True
+
+ if timer_call in self.timers.keys():
+ source_remove(self.timers[timer_call])
+ del self.timers[timer_call]
+
+ if self._switch:
+ self.grabfocus()
+
+ return len(self._fifoout + self._socketout)
+
+
+ def grabfocus(self):
+ '''Steal parent focus and switch the notebook to my own tab.'''
+
+ tabs = list(self.parent.notebook)
+ tabid = tabs.index(self.tab)
+ self.parent.goto_tab(tabid)
+
+
+ def probe(self):
+ '''Probes the client for information about its self.'''
+
+ if self._connected:
+ self.send(self._probecmds)
+ self._lastprobe = time.time()
+
+
+ def write(self, msg):
+ '''Child fifo write function.'''
+
+ self._fifoout.append(msg)
+ # Flush messages from the queue if able.
+ return self.flush()
+
+
+ def send(self, msg):
+ '''Child socket send function.'''
+
+ self._socketout.append(msg)
+ # Flush messages from queue if able.
+ return self.flush()
+
+
+ def __init__(self):
+ '''Create tablist, window and notebook.'''
+
+ # Store information about the applications fifo_socket.
+ self._fifo = None
+
+ self._timers = {}
+ self._buffer = ""
+ self._killed = False
+
+ # A list of the recently closed tabs
+ self._closed = []
+
+ # Holds metadata on the uzbl childen open.
+ self.tabs = {}
+
+ # Generates a unique id for uzbl socket filenames.
+ self.next_pid = counter().next
+
+ # Create main window
+ self.window = gtk.Window()
+ try:
+ window_size = map(int, config['window_size'].split(','))
+ self.window.set_default_size(*window_size)
+
+ except:
+ error("Invalid value for default_size in config file.")
+
+ self.window.set_title("Uzbl Browser")
+ self.window.set_border_width(0)
+
+ # Set main window icon
+ icon_path = config['icon_path']
+ if os.path.exists(icon_path):
+ self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path))
+
+ else:
+ icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png'
+ if os.path.exists(icon_path):
+ self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path))
+
+ # Attach main window event handlers
+ self.window.connect("delete-event", self.quitrequest)
+
+ # Create tab list
+ if config['show_tablist']:
+ vbox = gtk.VBox()
+ self.window.add(vbox)
+ ebox = gtk.EventBox()
+ self.tablist = gtk.Label()
+
+ self.tablist.set_use_markup(True)
+ self.tablist.set_justify(gtk.JUSTIFY_LEFT)
+ self.tablist.set_line_wrap(False)
+ self.tablist.set_selectable(False)
+ self.tablist.set_padding(2,2)
+ self.tablist.set_alignment(0,0)
+ self.tablist.set_ellipsize(pango.ELLIPSIZE_END)
+ self.tablist.set_text(" ")
+ self.tablist.show()
+ ebox.add(self.tablist)
+ ebox.show()
+ bgcolor = gtk.gdk.color_parse(config['status_background'])
+ ebox.modify_bg(gtk.STATE_NORMAL, bgcolor)
+
+ # Create notebook
+ self.notebook = gtk.Notebook()
+ self.notebook.set_show_tabs(config['show_gtk_tabs'])
+
+ # Set tab position
+ allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT,
+ 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM}
+ if config['gtk_tab_pos'] in allposes.keys():
+ self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']])
+
+ self.notebook.set_show_border(False)
+ self.notebook.set_scrollable(True)
+ self.notebook.set_border_width(0)
+
+ self.notebook.connect("page-removed", self.tab_closed)
+ self.notebook.connect("switch-page", self.tab_changed)
+ self.notebook.connect("page-added", self.tab_opened)
+
+ self.notebook.show()
+ if config['show_tablist']:
+ if config['tablist_top']:
+ vbox.pack_start(ebox, False, False, 0)
+ vbox.pack_end(self.notebook, True, True, 0)
+
+ else:
+ vbox.pack_start(self.notebook, True, True, 0)
+ vbox.pack_end(ebox, False, False, 0)
+
+ vbox.show()
+
+ else:
+ self.window.add(self.notebook)
+
+ self.window.show()
+ self.wid = self.notebook.window.xid
+ # Generate the fifo socket filename.
+ fifo_filename = 'uzbltabbed_%d' % os.getpid()
+ self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename)
+
+ # Now initialise the fifo socket at self.fifo_socket
+ self.init_fifo_socket()
+
+ # If we are using sessions then load the last one if it exists.
+ if config['save_session']:
+ self.load_session()
+
+
+ def run(self):
+ '''UzblTabbed main function that calls the gtk loop.'''
+
+ if not len(self.tabs):
+ self.new_tab()
+
+ gtk_refresh = int(config['gtk_refresh'])
+ if gtk_refresh < 100:
+ gtk_refresh = 100
+
+ # Update tablist timer
+ timerid = timeout_add(gtk_refresh, self.update_tablist)
+ self._timers["update-tablist"] = timerid
+
+ # Probe clients every second for window titles and location
+ timerid = timeout_add(gtk_refresh, self.probe_clients)
+ self._timers["probe-clients"] = timerid
+
+ # Make SIGTERM act orderly.
+ signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM))
+
+ # Catch keyboard interrupts
+ signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT))
+
+ try:
+ gtk.main()
+
+ except:
+ error("encounted error %r" % sys.exc_info()[1])
+
+ # Unlink fifo socket
+ self.unlink_fifo_socket()
+
+ # Attempt to close all uzbl instances nicely.
+ self.quitrequest()
+
+ # Allow time for all the uzbl instances to quit.
+ time.sleep(1)
+
+ raise
+
+
+ def terminate(self, termsig=None):
+ '''Handle termination signals and exit safely and cleanly.'''
+
+ # Not required but at least it lets the user know what killed his
+ # browsing session.
+ if termsig == SIGTERM:
+ error("caught SIGTERM signal")
+
+ elif termsig == SIGINT:
+ error("caught keyboard interrupt")
+
+ else:
+ error("caught unknown signal")
+
+ error("commencing infanticide!")
+
+ # Sends the exit signal to all uzbl instances.
+ self.quitrequest()
+
+
+ def init_fifo_socket(self):
+ '''Create interprocess communication fifo socket.'''
+
+ if os.path.exists(self.fifo_socket):
+ if not os.access(self.fifo_socket, os.F_OK | os.R_OK | os.W_OK):
+ os.mkfifo(self.fifo_socket)
+
+ else:
+ basedir = os.path.dirname(self.fifo_socket)
+ if not os.path.exists(basedir):
+ os.makedirs(basedir)
+
+ os.mkfifo(self.fifo_socket)
+
+ # Add event handlers for IO_IN & IO_HUP events.
+ self.setup_fifo_watchers()
+
+ echo("listening at %r" % self.fifo_socket)
+
+ # Add atexit register to destroy the socket on program termination.
+ atexit.register(self.unlink_fifo_socket)
+
+
+ def unlink_fifo_socket(self):
+ '''Unlink the fifo socket. Note: This function is called automatically
+ on exit by an atexit register.'''
+
+ # Make sure the fifo_socket fd is closed.
+ self.close_fifo()
+
+ # And unlink if the real fifo_socket exists.
+ if os.path.exists(self.fifo_socket):
+ os.unlink(self.fifo_socket)
+ echo("unlinked %r" % self.fifo_socket)
+
+
+ def close_fifo(self):
+ '''Remove all event handlers watching the fifo and close the fd.'''
+
+ # Already closed
+ if self._fifo is None: return
+
+ (fd, watchers) = self._fifo
+ os.close(fd)
+
+ # Stop all gobject io watchers watching the fifo.
+ for gid in watchers:
+ source_remove(gid)
+
+ self._fifo = None
+
+
+ def setup_fifo_watchers(self):
+ '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event
+ handlers.'''
+
+ # Close currently open fifo_socket fd and kill all watchers
+ self.close_fifo()
+
+ fd = os.open(self.fifo_socket, os.O_RDONLY | os.O_NONBLOCK)
+
+ # Add gobject io event handlers to the fifo socket.
+ watchers = [io_add_watch(fd, IO_IN, self.main_fifo_read),\
+ io_add_watch(fd, IO_HUP, self.main_fifo_hangup)]
+
+ self._fifo = (fd, watchers)
+
+
+ def main_fifo_hangup(self, fd, cb_condition):
+ '''Handle main fifo socket hangups.'''
+
+ # Close old fd, open new fifo socket and add io event handlers.
+ self.setup_fifo_watchers()
+
+ # Kill the gobject event handler calling this handler function.
+ return False
+
+
+ def main_fifo_read(self, fd, cb_condition):
+ '''Read from main fifo socket.'''
+
+ self._buffer = os.read(fd, 1024)
+ temp = self._buffer.split("\n")
+ self._buffer = temp.pop()
+ cmds = [s.strip().split() for s in temp if len(s.strip())]
+
+ for cmd in cmds:
+ try:
+ #print cmd
+ self.parse_command(cmd)
+
+ except:
+ error("parse_command: invalid command %s" % ' '.join(cmd))
+ raise
+
+ return True
+
+
+ def probe_clients(self):
+ '''Probe all uzbl clients for up-to-date window titles and uri's.'''
+
+ save_session = config['save_session']
+
+ sockd = {}
+ tabskeys = self.tabs.keys()
+ notebooklist = list(self.notebook)
+
+ for tab in notebooklist:
+ if tab not in tabskeys: continue
+ uzbl = self.tabs[tab]
+ uzbl.probe()
+ if uzbl._socket:
+ sockd[uzbl._socket] = uzbl
+
+ sockets = sockd.keys()
+ (reading, _, errors) = select.select(sockets, [], sockets, 0)
+
+ for sock in reading:
+ uzbl = sockd[sock]
+ uzbl._buffer = sock.recv(1024).replace('\n',' ')
+ temp = uzbl._buffer.split(uzbl._marker)
+ self._buffer = temp.pop()
+ cmds = [s.strip().split() for s in temp if len(s.strip())]
+ for cmd in cmds:
+ try:
+ #print cmd
+ self.parse_command(cmd)
+
+ except:
+ error("parse_command: invalid command %s" % ' '.join(cmd))
+ raise
+
+ return True
+
+
+ def parse_command(self, cmd):
+ '''Parse instructions from uzbl child processes.'''
+
+ # Commands ( [] = optional, {} = required )
+ # new [uri]
+ # open new tab and head to optional uri.
+ # close [tab-num]
+ # close current tab or close via tab id.
+ # next [n-tabs]
+ # open next tab or n tabs down. Supports negative indexing.
+ # prev [n-tabs]
+ # open prev tab or n tabs down. Supports negative indexing.
+ # goto {tab-n}
+ # goto tab n.
+ # first
+ # goto first tab.
+ # last
+ # goto last tab.
+ # title {pid} {document-title}
+ # updates tablist title.
+ # uri {pid} {document-location}
+ # updates tablist uri
+ # bring_to_front
+ # brings the gtk window to focus.
+ # exit
+ # exits uzbl_tabbed.py
+
+ if cmd[0] == "new":
+ if len(cmd) == 2:
+ self.new_tab(cmd[1])
+
+ else:
+ self.new_tab()
+
+ elif cmd[0] == "newfromclip":
+ uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\
+ stdout=subprocess.PIPE).communicate()[0]
+ if uri:
+ self.new_tab(uri)
+
+ elif cmd[0] == "close":
+ if len(cmd) == 2:
+ self.close_tab(int(cmd[1]))
+
+ else:
+ self.close_tab()
+
+ elif cmd[0] == "next":
+ if len(cmd) == 2:
+ self.next_tab(int(cmd[1]))
+
+ else:
+ self.next_tab()
+
+ elif cmd[0] == "prev":
+ if len(cmd) == 2:
+ self.prev_tab(int(cmd[1]))
+
+ else:
+ self.prev_tab()
+
+ elif cmd[0] == "goto":
+ self.goto_tab(int(cmd[1]))
+
+ elif cmd[0] == "first":
+ self.goto_tab(0)
+
+ elif cmd[0] == "last":
+ self.goto_tab(-1)
+
+ elif cmd[0] in ["title", "uri"]:
+ if len(cmd) > 2:
+ uzbl = self.get_tab_by_pid(int(cmd[1]))
+ if uzbl:
+ old = getattr(uzbl, cmd[0])
+ new = ' '.join(cmd[2:])
+ setattr(uzbl, cmd[0], new)
+ if old != new:
+ self.update_tablist()
+
+ else:
+ error("parse_command: no uzbl with pid %r" % int(cmd[1]))
+
+ elif cmd[0] == "preset":
+ if len(cmd) < 3:
+ error("parse_command: invalid preset command")
+
+ elif cmd[1] == "save":
+ path = os.path.join(config['saved_sessions_dir'], cmd[2])
+ self.save_session(path)
+
+ elif cmd[1] == "load":
+ path = os.path.join(config['saved_sessions_dir'], cmd[2])
+ self.load_session(path)
+
+ elif cmd[1] == "del":
+ path = os.path.join(config['saved_sessions_dir'], cmd[2])
+ if os.path.isfile(path):
+ os.remove(path)
+
+ else:
+ error("parse_command: preset %r does not exist." % path)
+
+ elif cmd[1] == "list":
+ uzbl = self.get_tab_by_pid(int(cmd[2]))
+ if uzbl:
+ if not os.path.isdir(config['saved_sessions_dir']):
+ js = "js alert('No saved presets.');"
+ uzbl.send(js)
+
+ else:
+ listdir = os.listdir(config['saved_sessions_dir'])
+ listdir = "\\n".join(listdir)
+ js = "js alert('Session presets:\\n\\n%s');" % listdir
+ uzbl.send(js)
+
+ else:
+ error("parse_command: unknown tab pid.")
+
+ else:
+ error("parse_command: unknown parse command %r"\
+ % ' '.join(cmd))
+
+ elif cmd[0] == "bring_to_front":
+ self.window.present()
+
+ elif cmd[0] == "clean":
+ self.clean_slate()
+
+ elif cmd[0] == "exit":
+ self.quitrequest()
+
+ else:
+ error("parse_command: unknown command %r" % ' '.join(cmd))
+
+
+ def get_tab_by_pid(self, pid):
+ '''Return uzbl instance by pid.'''
+
+ for (tab, uzbl) in self.tabs.items():
+ if uzbl.pid == pid:
+ return uzbl
+
+ return False
+
+
+ def new_tab(self, uri='', title='', switch=None):
+ '''Add a new tab to the notebook and start a new instance of uzbl.
+ Use the switch option to negate config['switch_to_new_tabs'] option
+ when you need to load multiple tabs at a time (I.e. like when
+ restoring a session from a file).'''
+
+ pid = self.next_pid()
+ tab = gtk.Socket()
+ tab.show()
+ self.notebook.append_page(tab)
+ sid = tab.get_id()
+ uri = uri.strip()
+
+ fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid)
+ fifo_socket = os.path.join(config['fifo_dir'], fifo_filename)
+ socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid)
+ socket_file = os.path.join(config['socket_dir'], socket_filename)
+
+ if switch is None:
+ switch = config['switch_to_new_tabs']
+
+ if not title:
+ title = config['new_tab_title']
+
+ uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\
+ uri, title, switch)
+
+ if len(uri):
+ uri = "--uri %r" % uri
+
+ self.tabs[tab] = uzbl
+ cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri)
+ subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ?
+
+ # Add gobject timer to make sure the config is pushed when fifo socket
+ # has been created.
+ timerid = timeout_add(100, uzbl.flush, "flush-initial-config")
+ uzbl.timers['flush-initial-config'] = timerid
+
+ self.update_tablist()
+
+
+ def clean_slate(self):
+ '''Close all open tabs and open a fresh brand new one.'''
+
+ self.new_tab()
+ tabs = self.tabs.keys()
+ for tab in list(self.notebook)[:-1]:
+ if tab not in tabs: continue
+ uzbl = self.tabs[tab]
+ uzbl.send("exit")
+
+
+ def config_uzbl(self, uzbl):
+ '''Send bind commands for tab new/close/next/prev to a uzbl
+ instance.'''
+
+ binds = []
+ bind_format = r'bind %s = sh "echo \"%s\" > \"%s\""'
+ bind = lambda key, action: binds.append(bind_format % (key, action,\
+ self.fifo_socket))
+
+ sets = []
+ set_format = r'set %s = sh \"echo \\"%s\\" > \\"%s\\""'
+ set = lambda key, action: binds.append(set_format % (key, action,\
+ self.fifo_socket))
+
+ # Bind definitions here
+ # bind(key, command back to fifo)
+ bind(config['bind_new_tab'], 'new')
+ bind(config['bind_tab_from_clip'], 'newfromclip')
+ bind(config['bind_tab_from_uri'], 'new %s')
+ bind(config['bind_close_tab'], 'close')
+ bind(config['bind_next_tab'], 'next')
+ bind(config['bind_prev_tab'], 'prev')
+ bind(config['bind_goto_tab'], 'goto %s')
+ bind(config['bind_goto_first'], 'goto 0')
+ bind(config['bind_goto_last'], 'goto -1')
+ bind(config['bind_clean_slate'], 'clean')
+ bind(config['bind_save_preset'], 'preset save %s')
+ bind(config['bind_load_preset'], 'preset load %s')
+ bind(config['bind_del_preset'], 'preset del %s')
+ bind(config['bind_list_presets'], 'preset list %d' % uzbl.pid)
+ bind(config['bind_exit'], 'exit')
+
+ # Set definitions here
+ # set(key, command back to fifo)
+ if config['capture_new_windows']:
+ set("new_window", r'new $8')
+
+ # Send config to uzbl instance via its socket file.
+ uzbl.send("\n".join(binds+sets))
+
+
+ def goto_tab(self, index):
+ '''Goto tab n (supports negative indexing).'''
+
+ tabs = list(self.notebook)
+ if 0 <= index < len(tabs):
+ self.notebook.set_current_page(index)
+ self.update_tablist()
+ return None
+
+ try:
+ tab = tabs[index]
+ # Update index because index might have previously been a
+ # negative index.
+ index = tabs.index(tab)
+ self.notebook.set_current_page(index)
+ self.update_tablist()
+
+ except IndexError:
+ pass
+
+
+ def next_tab(self, step=1):
+ '''Switch to next tab or n tabs right.'''
+
+ if step < 1:
+ error("next_tab: invalid step %r" % step)
+ return None
+
+ ntabs = self.notebook.get_n_pages()
+ tabn = (self.notebook.get_current_page() + step) % ntabs
+ self.notebook.set_current_page(tabn)
+ self.update_tablist()
+
+
+ def prev_tab(self, step=1):
+ '''Switch to prev tab or n tabs left.'''
+
+ if step < 1:
+ error("prev_tab: invalid step %r" % step)
+ return None
+
+ ntabs = self.notebook.get_n_pages()
+ tabn = self.notebook.get_current_page() - step
+ while tabn < 0: tabn += ntabs
+ self.notebook.set_current_page(tabn)
+ self.update_tablist()
+
+
+ def close_tab(self, tabn=None):
+ '''Closes current tab. Supports negative indexing.'''
+
+ if tabn is None:
+ tabn = self.notebook.get_current_page()
+
+ else:
+ try:
+ tab = list(self.notebook)[tabn]
+
+ except IndexError:
+ error("close_tab: invalid index %r" % tabn)
+ return None
+
+ self.notebook.remove_page(tabn)
+
+
+ def tab_opened(self, notebook, tab, index):
+ '''Called upon tab creation. Called by page-added signal.'''
+
+ if config['switch_to_new_tabs']:
+ self.notebook.set_focus_child(tab)
+
+ else:
+ oldindex = self.notebook.get_current_page()
+ oldtab = self.notebook.get_nth_page(oldindex)
+ self.notebook.set_focus_child(oldtab)
+
+
+ def tab_closed(self, notebook, tab, index):
+ '''Close the window if no tabs are left. Called by page-removed
+ signal.'''
+
+ if tab in self.tabs.keys():
+ uzbl = self.tabs[tab]
+ for (timer, gid) in uzbl.timers.items():
+ error("tab_closed: removing timer %r" % timer)
+ source_remove(gid)
+ del uzbl.timers[timer]
+
+ if uzbl._socket:
+ uzbl._socket.close()
+ uzbl._socket = None
+
+ uzbl._fifoout = []
+ uzbl._socketout = []
+ uzbl._kill = True
+ self._closed.append((uzbl.uri, uzbl.title))
+ self._closed = self._closed[-10:]
+ del self.tabs[tab]
+
+ if self.notebook.get_n_pages() == 0:
+ if not self._killed and config['save_session']:
+ if os.path.exists(config['session_file']):
+ os.remove(config['session_file'])
+
+ self.quit()
+
+ self.update_tablist()
+
+ return True
+
+
+ def tab_changed(self, notebook, page, index):
+ '''Refresh tab list. Called by switch-page signal.'''
+
+ tab = self.notebook.get_nth_page(index)
+ self.notebook.set_focus_child(tab)
+ self.update_tablist(index)
+ return True
+
+
+ def update_tablist(self, curpage=None):
+ '''Upate tablist status bar.'''
+
+ show_tablist = config['show_tablist']
+ show_gtk_tabs = config['show_gtk_tabs']
+ tab_titles = config['tab_titles']
+ show_ellipsis = config['show_ellipsis']
+ multiline_tabs = config['multiline_tabs']
+
+ if multiline_tabs:
+ multiline = []
+
+ if not show_tablist and not show_gtk_tabs:
+ return True
+
+ tabs = self.tabs.keys()
+ if curpage is None:
+ curpage = self.notebook.get_current_page()
+
+ title_format = "%s - Uzbl Browser"
+ max_title_len = config['max_title_len']
+
+ if show_tablist:
+ pango = ""
+ normal = (config['tab_colours'], config['tab_text_colours'])
+ selected = (config['selected_tab'], config['selected_tab_text'])
+
+ if tab_titles:
+ tab_format = "<span %s> [ %d <span %s> %s</span> ] </span>"
+
+ else:
+ tab_format = "<span %s> [ <span %s>%d</span> ] </span>"
+
+ if show_gtk_tabs:
+ gtk_tab_format = "%d %s"
+
+ for index, tab in enumerate(self.notebook):
+ if tab not in tabs: continue
+ uzbl = self.tabs[tab]
+
+ if index == curpage:
+ self.window.set_title(title_format % uzbl.title)
+
+ # Unicode heavy strings do not like being truncated/sliced so by
+ # re-encoding the string sliced of limbs are removed.
+ tabtitle = uzbl.title[:max_title_len + int(show_ellipsis)]
+ if type(tabtitle) != types.UnicodeType:
+ tabtitle = unicode(tabtitle, 'utf-8', 'ignore')
+
+ tabtitle = tabtitle.encode('utf-8', 'ignore').strip()
+
+ if show_ellipsis and len(tabtitle) != len(uzbl.title):
+ tabtitle += "\xe2\x80\xa6"
+
+ if show_gtk_tabs:
+ if tab_titles:
+ self.notebook.set_tab_label_text(tab,
+ gtk_tab_format % (index, tabtitle))
+
+ else:
+ self.notebook.set_tab_label_text(tab, str(index))
+
+ if show_tablist:
+ style = colour_selector(index, curpage, uzbl)
+ (tabc, textc) = style
+
+ if multiline_tabs:
+ opango = pango
+
+ if tab_titles:
+ pango += tab_format % (tabc, index, textc,
+ escape(tabtitle))
+
+ else:
+ pango += tab_format % (tabc, textc, index)
+
+ self.tablist.set_markup(pango)
+ listwidth = self.tablist.get_layout().get_pixel_size()[0]
+ winwidth = self.window.get_size()[0]
+
+ if listwidth > (winwidth - 20):
+ multiline.append(opango)
+ pango = tab_format % (tabc, index, textc,
+ escape(tabtitle))
+
+ elif tab_titles:
+ pango += tab_format % (tabc, index, textc,
+ escape(tabtitle))
+
+ else:
+ pango += tab_format % (tabc, textc, index)
+
+ if show_tablist:
+ if multiline_tabs:
+ multiline.append(pango)
+ self.tablist.set_markup('&#10;'.join(multiline))
+
+ else:
+ self.tablist.set_markup(pango)
+
+ return True
+
+
+ def save_session(self, session_file=None):
+ '''Save the current session to file for restoration on next load.'''
+
+ strip = str.strip
+
+ if session_file is None:
+ session_file = config['session_file']
+
+ tabs = self.tabs.keys()
+ state = []
+ for tab in list(self.notebook):
+ if tab not in tabs: continue
+ uzbl = self.tabs[tab]
+ if not uzbl.uri: continue
+ state += [(uzbl.uri, uzbl.title),]
+
+ session = {'curtab': self.notebook.get_current_page(),
+ 'tabs': state}
+
+ if config['json_session']:
+ raw = json.dumps(session)
+
+ else:
+ lines = ["curtab = %d" % session['curtab'],]
+ for (uri, title) in session['tabs']:
+ lines += ["%s\t%s" % (strip(uri), strip(title)),]
+
+ raw = "\n".join(lines)
+
+ if not os.path.isfile(session_file):
+ dirname = os.path.dirname(session_file)
+ if not os.path.isdir(dirname):
+ os.makedirs(dirname)
+
+ h = open(session_file, 'w')
+ h.write(raw)
+ h.close()
+
+
+ def load_session(self, session_file=None):
+ '''Load a saved session from file.'''
+
+ default_path = False
+ strip = str.strip
+ json_session = config['json_session']
+ delete_loaded = False
+
+ if session_file is None:
+ default_path = True
+ delete_loaded = True
+ session_file = config['session_file']
+
+ if not os.path.isfile(session_file):
+ return False
+
+ h = open(session_file, 'r')
+ raw = h.read()
+ h.close()
+ if json_session:
+ if sum([1 for s in raw.split("\n") if strip(s)]) != 1:
+ error("Warning: The session file %r does not look json. "\
+ "Trying to load it as a non-json session file."\
+ % session_file)
+ json_session = False
+
+ if json_session:
+ try:
+ session = json.loads(raw)
+ curtab, tabs = session['curtab'], session['tabs']
+
+ except:
+ error("Failed to load jsonifed session from %r"\
+ % session_file)
+ return None
+
+ else:
+ tabs = []
+ strip = str.strip
+ curtab, tabs = 0, []
+ lines = [s for s in raw.split("\n") if strip(s)]
+ if len(lines) < 2:
+ error("Warning: The non-json session file %r looks invalid."\
+ % session_file)
+ return None
+
+ try:
+ for line in lines:
+ if line.startswith("curtab"):
+ curtab = int(line.split()[-1])
+
+ else:
+ uri, title = line.split("\t",1)
+ tabs += [(strip(uri), strip(title)),]
+
+ except:
+ error("Warning: failed to load session file %r" % session_file)
+ return None
+
+ session = {'curtab': curtab, 'tabs': tabs}
+
+ # Now populate notebook with the loaded session.
+ for (index, (uri, title)) in enumerate(tabs):
+ self.new_tab(uri=uri, title=title, switch=(curtab==index))
+
+ # A saved session has been loaded now delete it.
+ if delete_loaded and os.path.exists(session_file):
+ os.remove(session_file)
+
+ # There may be other state information in the session dict of use to
+ # other functions. Of course however the non-json session object is
+ # just a dummy object of no use to no one.
+ return session
+
+
+ def quitrequest(self, *args):
+ '''Attempt to close all uzbl instances nicely and exit.'''
+
+ self._killed = True
+
+ if config['save_session']:
+ if len(list(self.notebook)) > 1:
+ self.save_session()
+
+ else:
+ # Notebook has one page open so delete the session file.
+ if os.path.isfile(config['session_file']):
+ os.remove(config['session_file'])
+
+ for (tab, uzbl) in self.tabs.items():
+ uzbl.send("exit")
+
+ # Add a gobject timer to make sure the application force-quits after a
+ # reasonable period. Calling quit when all the tabs haven't had time to
+ # close should be a last resort.
+ timer = "force-quit"
+ timerid = timeout_add(5000, self.quit, timer)
+ self._timers[timer] = timerid
+
+
+ def quit(self, *args):
+ '''Cleanup and quit. Called by delete-event signal.'''
+
+ # Close the fifo socket, remove any gobject io event handlers and
+ # delete socket.
+ self.unlink_fifo_socket()
+
+ # Remove all gobject timers that are still ticking.
+ for (timerid, gid) in self._timers.items():
+ source_remove(gid)
+ del self._timers[timerid]
+
+ try:
+ gtk.main_quit()
+
+ except:
+ pass
+
+
+if __name__ == "__main__":
+
+ # Read from the uzbl config into the global config dictionary.
+ readconfig(UZBL_CONFIG, config)
+
+ # Build command line parser
+ usage = "usage: %prog [OPTIONS] {URIS}..."
+ parser = OptionParser(usage=usage)
+ parser.add_option('-n', '--no-session', dest='nosession',
+ action='store_true', help="ignore session saving a loading.")
+ parser.add_option('-v', '--verbose', dest='verbose',
+ action='store_true', help='print verbose output.')
+
+ # Parse command line options
+ (options, uris) = parser.parse_args()
+
+ if options.nosession:
+ config['save_session'] = False
+
+ if options.verbose:
+ config['verbose'] = True
+
+ if config['json_session']:
+ try:
+ import simplejson as json
+
+ except:
+ error("Warning: json_session set but cannot import the python "\
+ "module simplejson. Fix: \"set json_session = 0\" or "\
+ "install the simplejson python module to remove this warning.")
+ config['json_session'] = False
+
+ if config['verbose']:
+ import pprint
+ sys.stderr.write("%s\n" % pprint.pformat(config))
+
+ uzbl = UzblTabbed()
+
+ # All extra arguments given to uzbl_tabbed.py are interpreted as
+ # web-locations to opened in new tabs.
+ lasturi = len(uris)-1
+ for (index,uri) in enumerate(uris):
+ uzbl.new_tab(uri, switch=(index==lasturi))
+
+ uzbl.run()
diff --git a/.config/uzbl/scripts/uzblcat b/.config/uzbl/scripts/uzblcat
new file mode 100755
index 0000000..e955608
--- /dev/null
+++ b/.config/uzbl/scripts/uzblcat
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# uzblcat - safely push html to uzbl
+# See http://www.uzbl.org/wiki/html-mode
+
+from sys import stdin, stdout
+
+stdout.write("uri data:text/html,")
+for line in stdin:
+ stdout.write(line[0:-1])
+
+# vim: set noet ff=unix
+
diff --git a/.config/uzbl/scripts/yank.sh b/.config/uzbl/scripts/yank.sh
new file mode 100755
index 0000000..376b7e2
--- /dev/null
+++ b/.config/uzbl/scripts/yank.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# use this script to pipe any variable to xclip, so you have it in your clipboard
+# 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 6 primary
+# bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard
+
+clip=xclip
+
+which $clip &>/dev/null || exit 1
+[ "x$9" = xprimary -o "x$9" = xsecondary -o "x$9" = xclipboard ] || exit 2
+
+value=`eval "echo -n \\${$8}"` # bash: value = ${!8}
+
+echo "echo -n '${value}' | $clip -selection $9"
+echo -n "'${value}' | $clip -selection $9"
diff --git a/.config/uzbl/style.css b/.config/uzbl/style.css
new file mode 100644
index 0000000..f9b111e
--- /dev/null
+++ b/.config/uzbl/style.css
@@ -0,0 +1,25 @@
+.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/.config/uzbl/uzbl.png b/.config/uzbl/uzbl.png
new file mode 100644
index 0000000..773ea84
--- /dev/null
+++ b/.config/uzbl/uzbl.png
Binary files differ