aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/data
diff options
context:
space:
mode:
authorGravatar Brendan Taylor <whateley@gmail.com>2011-02-14 22:51:46 -0700
committerGravatar Brendan Taylor <whateley@gmail.com>2011-02-14 22:54:54 -0700
commitdb3984b609153ff213233f1a78c8895fdb525350 (patch)
tree24e6b2959d08b8cadb93853cb3620681f6f05e64 /examples/data
parent59af2a8499160a369aceed1bd5cb32109fb5e77c (diff)
parent700332fac498169927ced24731ce1278369b1425 (diff)
Merge branch 'experimental' into cleaning-commenting
Conflicts: src/callbacks.c src/uzbl-core.c src/uzbl-core.h
Diffstat (limited to 'examples/data')
-rw-r--r--examples/data/plugins/bind.py4
-rw-r--r--examples/data/plugins/cookies.py56
-rw-r--r--examples/data/plugins/history.py129
-rw-r--r--examples/data/plugins/keycmd.py5
-rwxr-xr-xexamples/data/scripts/follow.sh2
-rwxr-xr-xexamples/data/scripts/uzbl-cookie-daemon677
6 files changed, 175 insertions, 698 deletions
diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py
index 5b13476..41f96c5 100644
--- a/examples/data/plugins/bind.py
+++ b/examples/data/plugins/bind.py
@@ -379,7 +379,6 @@ def mode_changed(uzbl, mode):
if mode != 'stack':
uzbl.bindlet.reset()
- uzbl.clear_keycmd()
def match_and_exec(uzbl, bind, depth, keylet, bindlet):
@@ -421,7 +420,6 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet):
if not has_args or on_exec:
del uzbl.config['mode']
bindlet.reset()
- uzbl.clear_current()
return True
@@ -469,3 +467,5 @@ def init(uzbl):
'mode_bind': mode_bind,
'bindlet': Bindlet(uzbl),
})
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/cookies.py b/examples/data/plugins/cookies.py
index c9fe2c3..6ee8798 100644
--- a/examples/data/plugins/cookies.py
+++ b/examples/data/plugins/cookies.py
@@ -38,24 +38,38 @@ class TextStore(object):
self.filename = filename
def as_event(self, cookie):
+ """Convert cookie.txt row to uzbls cookie event format"""
+ scheme = {
+ 'TRUE' : 'https',
+ 'FALSE' : 'http'
+ }
if cookie[0].startswith("#HttpOnly_"):
domain = cookie[0][len("#HttpOnly_"):]
elif cookie[0].startswith('#'):
return None
else:
domain = cookie[0]
- return (domain,
- cookie[2],
- cookie[5],
- cookie[6],
- 'https' if cookie[3] == 'TRUE' else 'http',
- cookie[4])
+ try:
+ return (domain,
+ cookie[2],
+ cookie[5],
+ cookie[6],
+ scheme[cookie[3]],
+ cookie[4])
+ except (KeyError,IndexError):
+ # Let malformed rows pass through like comments
+ return None
def as_file(self, cookie):
+ """Convert cookie event to cookie.txt row"""
+ secure = {
+ 'https' : 'TRUE',
+ 'http' : 'FALSE'
+ }
return (cookie[0],
'TRUE' if cookie[0].startswith('.') else 'FALSE',
cookie[1],
- 'TRUE' if cookie[4] == 'https' else 'FALSE',
+ secure[cookie[4]],
cookie[5],
cookie[2],
cookie[3])
@@ -92,8 +106,11 @@ DefaultStore = TextStore(os.path.join(xdg_data_home, 'uzbl/cookies.txt'))
SessionStore = TextStore(os.path.join(xdg_data_home, 'uzbl/session-cookies.txt'))
def match_list(_list, cookie):
- for component, match in _list:
- if match(cookie[component]) is not None:
+ for matcher in _list:
+ for component, match in matcher:
+ if match(cookie[component]) is None:
+ break
+ else:
return True
return False
@@ -144,18 +161,21 @@ def delete_cookie(uzbl, cookie):
store.delete_cookie(cookie, splitted)
# add a cookie matcher to a whitelist or a blacklist.
-# a matcher is a (component, re) tuple that matches a cookie when the
+# a matcher is a list of (component, re) tuples that matches a cookie when the
# "component" part of the cookie matches the regular expression "re".
# "component" is one of the keys defined in the variable "symbolic" above,
# or the index of a component of a cookie tuple.
def add_cookie_matcher(_list, arg):
- component, regexp = splitquoted(arg)
- try:
- component = symbolic[component]
- except KeyError:
- component = int(component)
- assert component <= 5
- _list.append((component, re.compile(regexp).search))
+ args = splitquoted(arg)
+ mlist = []
+ for (component, regexp) in zip(args[0::2], args[1::2]):
+ try:
+ component = symbolic[component]
+ except KeyError:
+ component = int(component)
+ assert component <= 5
+ mlist.append((component, re.compile(regexp).search))
+ _list.append(mlist)
def blacklist(uzbl, arg):
add_cookie_matcher(uzbl.cookie_blacklist, arg)
@@ -174,3 +194,5 @@ def init(uzbl):
'cookie_blacklist' : [],
'cookie_whitelist' : []
})
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/history.py b/examples/data/plugins/history.py
new file mode 100644
index 0000000..5e9e4e1
--- /dev/null
+++ b/examples/data/plugins/history.py
@@ -0,0 +1,129 @@
+import random
+
+shared_history = {'':[]}
+
+class History(object):
+ def __init__(self, uzbl):
+ self.uzbl = uzbl
+ self._temporary = []
+ self.prompt = ''
+ self.cursor = None
+ self.__temp_tail = False
+ self.search_key = None
+
+ def prev(self):
+ if self.cursor is None:
+ self.cursor = len(self) - 1
+ else:
+ self.cursor -= 1
+
+ if self.search_key:
+ while self.cursor >= 0 and self.search_key not in self[self.cursor]:
+ self.cursor -= 1
+
+ if self.cursor < 0 or len(self) == 0:
+ self.cursor = -1
+ return random.choice(end_messages)
+
+ return self[self.cursor]
+
+ def next(self):
+ if self.cursor is None:
+ return ''
+
+ self.cursor += 1
+
+ if self.search_key:
+ while self.cursor < len(self) and self.search_key not in self[self.cursor]:
+ self.cursor += 1
+
+ if self.cursor >= len(shared_history[self.prompt]):
+ self.cursor = None
+ self.search_key = None
+
+ if self._temporary:
+ return self._temporary.pop()
+ return ''
+
+ return self[self.cursor]
+
+ def change_prompt(self, prompt):
+ self.prompt = prompt
+ self._temporary = []
+ self.__temp_tail = False
+ if prompt not in shared_history:
+ shared_history[prompt] = []
+
+ def search(self, key):
+ self.search_key = key
+ self.cursor = None
+
+ def add(self, cmd):
+ if self._temporary:
+ self._temporary.pop()
+
+ shared_history[self.prompt].append(cmd)
+ self.cursor = None
+ self.search_key = None
+
+ def add_temporary(self, cmd):
+ assert not self._temporary
+
+ self._temporary.append(cmd)
+ self.cursor = len(self) - 1
+
+ def __getitem__(self, i):
+ if i < len(shared_history[self.prompt]):
+ return shared_history[self.prompt][i]
+ return self._temporary[i-len(shared_history)+1]
+
+ def __len__(self):
+ return len(shared_history[self.prompt]) + len(self._temporary)
+
+ def __str__(self):
+ return "(History %s, %s)" % (self.cursor, self.prompt)
+
+def keycmd_exec(uzbl, keylet):
+ cmd = keylet.get_keycmd()
+ if cmd:
+ uzbl.history.add(cmd)
+
+def history_prev(uzbl, _x):
+ cmd = uzbl.keylet.get_keycmd()
+ if uzbl.history.cursor is None and cmd:
+ uzbl.history.add_temporary(cmd)
+
+ uzbl.set_keycmd(uzbl.history.prev())
+ uzbl.logger.debug('PREV %s' % uzbl.history)
+
+def history_next(uzbl, _x):
+ cmd = uzbl.keylet.get_keycmd()
+
+ uzbl.set_keycmd(uzbl.history.next())
+ uzbl.logger.debug('NEXT %s' % uzbl.history)
+
+def history_search(uzbl, key):
+ uzbl.history.search(key)
+ uzbl.send('event HISTORY_PREV')
+ uzbl.logger.debug('SEARCH %s %s' % (key, uzbl.history))
+
+end_messages = ('Look behind you, A three-headed monkey!', 'error #4: static from nylon underwear.', 'error #5: static from plastic slide rules.', 'error #6: global warming.', 'error #9: doppler effect.', 'error #16: somebody was calculating pi on the server.', 'error #19: floating point processor overflow.', 'error #21: POSIX compliance problem.', 'error #25: Decreasing electron flux.', 'error #26: first Saturday after first full moon in Winter.', 'error #64: CPU needs recalibration.', 'error #116: the real ttys became pseudo ttys and vice-versa.', 'error #229: wrong polarity of neutron flow.', 'error #330: quantum decoherence.', 'error #388: Bad user karma.', 'error #407: Route flapping at the NAP.', 'error #435: Internet shut down due to maintenance.')
+
+# plugin init hook
+def init(uzbl):
+ connect_dict(uzbl, {
+ 'KEYCMD_EXEC': keycmd_exec,
+ 'HISTORY_PREV': history_prev,
+ 'HISTORY_NEXT': history_next,
+ 'HISTORY_SEARCH': history_search
+ })
+
+ export_dict(uzbl, {
+ 'history' : History(uzbl)
+ })
+
+# plugin after hook
+def after(uzbl):
+ uzbl.on_set('keycmd_prompt', lambda uzbl, k, v: uzbl.history.change_prompt(v))
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/keycmd.py b/examples/data/plugins/keycmd.py
index 2fb2283..928c597 100644
--- a/examples/data/plugins/keycmd.py
+++ b/examples/data/plugins/keycmd.py
@@ -210,7 +210,7 @@ def modkey_addition_parse(uzbl, modkeys):
add_modkey_addition(uzbl, keys[:-1], keys[-1])
-def clear_keycmd(uzbl):
+def clear_keycmd(uzbl, *args):
'''Clear the keycmd for this uzbl instance.'''
k = uzbl.keylet
@@ -493,6 +493,7 @@ def init(uzbl):
'KEYCMD_DELETE': keycmd_delete,
'KEYCMD_EXEC_CURRENT': keycmd_exec_current,
'KEYCMD_STRIP_WORD': keycmd_strip_word,
+ 'KEYCMD_CLEAR': clear_keycmd,
'KEY_PRESS': key_press,
'KEY_RELEASE': key_release,
'MODKEY_ADDITION': modkey_addition_parse,
@@ -514,3 +515,5 @@ def init(uzbl):
'set_cursor_pos': set_cursor_pos,
'set_keycmd': set_keycmd,
})
+
+# vi: set et ts=4:
diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh
index d1560bf..d7fe117 100755
--- a/examples/data/scripts/follow.sh
+++ b/examples/data/scripts/follow.sh
@@ -17,5 +17,5 @@ case $result in
echo 'event FORM_ACTIVE' > "$UZBL_FIFO" ;;
*XXXRESET_MODEXXX*)
# a link was selected, reset uzbl's input mode
- echo 'set mode=' > "$UZBL_FIFO" ;;
+ printf 'set mode=\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO" ;;
esac
diff --git a/examples/data/scripts/uzbl-cookie-daemon b/examples/data/scripts/uzbl-cookie-daemon
deleted file mode 100755
index 0b9bef9..0000000
--- a/examples/data/scripts/uzbl-cookie-daemon
+++ /dev/null
@@ -1,677 +0,0 @@
-#!/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)
-
- if sys.stdout.isatty():
- 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)
-
- # Create cookie daemon socket.
- self.create_socket()
-
- # 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:
- 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()
- # Create cookie daemon socket.
- self.create_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'])
-
- connections = []
-
- while self._running:
- # This line tells the socket how many pending incoming connections
- # to enqueue at once. Raising this number may or may not increase
- # performance.
- self.server_socket.listen(1)
-
- r, w, x = select.select([self.server_socket]+connections, [], [], 1)
-
- for socket in r:
- if self.server_socket == socket:
- client_socket, _ = socket.accept()
- connections.append(client_socket)
- else:
- if not self.handle_request(socket):
- # connection was closed, forget about the client socket
- connections.remove(socket)
-
- self.last_request = time.time()
-
- 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 False
-
- # 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 False
-
- # Catch whitelist RELOAD command.
- elif action == "RELOAD":
- self.reload_whitelist()
- return True
-
- # Return if command unknown.
- elif action not in ['GET', 'PUT']:
- error("unknown command %r." % argv)
- return True
-
- # 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._policy._now = self._now = int(time.time())
- cookies = self.jar._cookies_for_request(req)
- attrs = self.jar._cookie_attrs(cookies)
- if attrs:
- cookie = "; ".join(attrs)
- client_socket.send(cookie)
- if print_cookie:
- print cookie
- else:
- client_socket.send("\0")
-
- elif action == "PUT":
- cookie = argv[4] if len(argv) > 3 else None
- if print_cookie:
- print cookie
-
- self.put_cookie(req, cookie)
- client_socket.send("\0")
-
- if print_cookie:
- print
-
- return True
-
-
- def put_cookie(self, req, cookie=None):
- '''Put a cookie in the cookie jar.'''
-
- 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()