summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Carrez <thierry@openstack.org>2012-02-07 16:37:34 +0100
committerThierry Carrez <thierry@openstack.org>2012-02-07 21:14:31 +0100
commit71410724cd1516608ee58c37077bf9080da38de2 (patch)
tree89d1b1c2930cef01565da8e5436ad8c2edb8a1bf
parentae377f42e95b18438f4855c13230e077a870c64b (diff)
downloadnova-71410724cd1516608ee58c37077bf9080da38de2.tar.gz
nova-71410724cd1516608ee58c37077bf9080da38de2.tar.xz
nova-71410724cd1516608ee58c37077bf9080da38de2.zip
Remove ajaxterm from Nova
Removes copy of ajaxterm code, nova-ajax-console-proxy, and support for get_ajax_console from Nova proper. Implements blueprint remove-ajaxterm Fixes bug 917963 Change-Id: I2c0ff427c53c0f63a18b10475d6b4cbe9a085d83
-rwxr-xr-xbin/nova-ajax-console-proxy146
-rw-r--r--nova/compute/api.py13
-rw-r--r--nova/compute/manager.py9
-rw-r--r--nova/flags.py9
-rw-r--r--nova/tests/fake_libvirt_utils.py4
-rw-r--r--nova/tests/policy.json1
-rw-r--r--nova/tests/test_compute.py21
-rw-r--r--nova/tests/test_libvirt.py14
-rw-r--r--nova/tests/test_virt_drivers.py8
-rw-r--r--nova/tests/test_vmwareapi.py3
-rw-r--r--nova/virt/driver.py4
-rw-r--r--nova/virt/fake.py5
-rw-r--r--nova/virt/libvirt/connection.py26
-rw-r--r--nova/virt/libvirt/utils.py12
-rw-r--r--nova/virt/vmwareapi/vmops.py4
-rw-r--r--nova/virt/vmwareapi_conn.py4
-rw-r--r--nova/virt/xenapi/vmops.py5
-rw-r--r--nova/virt/xenapi_conn.py6
-rwxr-xr-xrun_tests.sh6
-rw-r--r--setup.py1
-rw-r--r--tools/ajaxterm/README.txt120
-rw-r--r--tools/ajaxterm/ajaxterm.135
-rw-r--r--tools/ajaxterm/ajaxterm.css64
-rw-r--r--tools/ajaxterm/ajaxterm.html25
-rw-r--r--tools/ajaxterm/ajaxterm.js279
-rwxr-xr-xtools/ajaxterm/ajaxterm.py586
-rwxr-xr-xtools/ajaxterm/configure32
-rw-r--r--tools/ajaxterm/configure.ajaxterm.bin2
-rw-r--r--tools/ajaxterm/configure.initd.debian33
-rw-r--r--tools/ajaxterm/configure.initd.gentoo27
-rw-r--r--tools/ajaxterm/configure.initd.redhat75
-rw-r--r--tools/ajaxterm/configure.makefile20
-rw-r--r--tools/ajaxterm/qweb.py1356
-rw-r--r--tools/ajaxterm/sarissa.js647
-rw-r--r--tools/ajaxterm/sarissa_dhtml.js105
-rwxr-xr-xtools/euca-get-ajax-console169
36 files changed, 3 insertions, 3873 deletions
diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy
deleted file mode 100755
index 94d93cd0e..000000000
--- a/bin/nova-ajax-console-proxy
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=C0103
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Ajax Console Proxy Server"""
-
-from eventlet import greenthread
-from eventlet.green import urllib2
-
-import exceptions
-import os
-import sys
-import time
-import urlparse
-
-# If ../nova/__init__.py exists, add ../ to Python search path, so that
-# it will override what happens to be installed in /usr/(local/)lib/python...
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
- sys.path.insert(0, possible_topdir)
-
-
-from nova import flags
-from nova import log as logging
-from nova.openstack.common import cfg
-from nova import rpc
-from nova import service
-from nova import utils
-from nova import wsgi
-
-
-ajax_console_idle_timeout_opt = \
- cfg.IntOpt('ajax_console_idle_timeout',
- default=300,
- help='Seconds before idle connection destroyed')
-
-FLAGS = flags.FLAGS
-FLAGS.add_option(ajax_console_idle_timeout_opt)
-
-LOG = logging.getLogger('nova.ajax_console_proxy')
-
-
-class AjaxConsoleProxy(object):
- tokens = {}
-
- def __call__(self, env, start_response):
- try:
- if 'QUERY_STRING' in env:
- req_url = '%s://%s%s?%s' % (env['wsgi.url_scheme'],
- env['HTTP_HOST'],
- env['PATH_INFO'],
- env['QUERY_STRING'])
- else:
- req_url = '%s://%s%s' % (env['wsgi.url_scheme'],
- env['HTTP_HOST'],
- env['PATH_INFO'])
-
- if 'HTTP_REFERER' in env:
- auth_url = env['HTTP_REFERER']
- else:
- auth_url = req_url
-
- auth_params = urlparse.parse_qs(urlparse.urlparse(auth_url).query)
- parsed_url = urlparse.urlparse(req_url)
-
- auth_info = AjaxConsoleProxy.tokens[auth_params['token'][0]]
- args = auth_info['args']
- auth_info['last_activity'] = time.time()
-
- remote_url = ("http://%s:%s%s?token=%s" % (
- str(args['host']),
- str(args['port']),
- parsed_url.path,
- str(args['token'])))
-
- opener = urllib2.urlopen(remote_url, env['wsgi.input'].read())
- body = opener.read()
- info = opener.info()
-
- start_response("200 OK", info.dict.items())
- return body
- except (exceptions.KeyError):
- if env['PATH_INFO'] != '/favicon.ico':
- LOG.audit("Unauthorized request %s, %s"
- % (req_url, str(env)))
- start_response("401 NOT AUTHORIZED", [])
- return "Not Authorized"
- except Exception, exc:
- LOG.exception(exc)
- start_response("500 ERROR", [])
- return "Server Error"
-
- def register_listeners(self):
- class TopicProxy():
- @staticmethod
- def authorize_ajax_console(context, **kwargs):
- AjaxConsoleProxy.tokens[kwargs['token']] = \
- {'args': kwargs, 'last_activity': time.time()}
-
- self.conn = rpc.create_connection(new=True)
- self.conn.create_consumer(
- FLAGS.ajax_console_proxy_topic,
- TopicProxy)
-
- def delete_expired_tokens():
- now = time.time()
- to_delete = []
- for k, v in AjaxConsoleProxy.tokens.items():
- if now - v['last_activity'] > FLAGS.ajax_console_idle_timeout:
- to_delete.append(k)
-
- for k in to_delete:
- del AjaxConsoleProxy.tokens[k]
-
- self.conn.consume_in_thread()
- utils.LoopingCall(delete_expired_tokens).start(1)
-
-if __name__ == '__main__':
- utils.default_flagfile()
- FLAGS(sys.argv)
- logging.setup()
- acp_port = FLAGS.ajax_console_proxy_port
- acp = AjaxConsoleProxy()
- acp.register_listeners()
- server = wsgi.Server("AJAX Console Proxy", acp, port=acp_port)
- service.serve(server)
- service.wait()
- acp.conn.close()
diff --git a/nova/compute/api.py b/nova/compute/api.py
index f54d184dd..2f4d3e200 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -1574,19 +1574,6 @@ class API(base.Base):
instance, params=params)
@wrap_check_policy
- def get_ajax_console(self, context, instance):
- """Get a url to an AJAX Console."""
- output = self._call_compute_message('get_ajax_console',
- context,
- instance)
- rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic,
- {'method': 'authorize_ajax_console',
- 'args': {'token': output['token'], 'host': output['host'],
- 'port': output['port']}})
- return {'url': '%s/?token=%s' % (FLAGS.ajax_console_proxy_url,
- output['token'])}
-
- @wrap_check_policy
def get_vnc_console(self, context, instance, console_type):
"""Get a url to an instance Console."""
connect_info = self._call_compute_message('get_vnc_console',
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index e5600af32..c7cd1baaf 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1553,15 +1553,6 @@ class ComputeManager(manager.SchedulerDependentManager):
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@wrap_instance_fault
- def get_ajax_console(self, context, instance_uuid):
- """Return connection information for an ajax console."""
- context = context.elevated()
- LOG.debug(_("instance %s: getting ajax console"), instance_uuid)
- instance_ref = self.db.instance_get_by_uuid(context, instance_uuid)
- return self.driver.get_ajax_console(instance_ref)
-
- @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
- @wrap_instance_fault
def get_vnc_console(self, context, instance_uuid, console_type):
"""Return connection information for a vnc console."""
context = context.elevated()
diff --git a/nova/flags.py b/nova/flags.py
index 3f3560057..a76a2328c 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -250,15 +250,6 @@ global_opts = [
cfg.StrOpt('network_topic',
default='network',
help='the topic network nodes listen on'),
- cfg.StrOpt('ajax_console_proxy_topic',
- default='ajax_proxy',
- help='the topic ajax proxy nodes listen on'),
- cfg.StrOpt('ajax_console_proxy_url',
- default='http://127.0.0.1:8000',
- help='URL of ajax console proxy, in the form http://host:port'),
- cfg.IntOpt('ajax_console_proxy_port',
- default=8000,
- help='port that ajax_console_proxy binds'),
cfg.StrOpt('vsa_topic',
default='vsa',
help='the topic that nova-vsa service listens on'),
diff --git a/nova/tests/fake_libvirt_utils.py b/nova/tests/fake_libvirt_utils.py
index 27b753a64..726e28a1d 100644
--- a/nova/tests/fake_libvirt_utils.py
+++ b/nova/tests/fake_libvirt_utils.py
@@ -93,10 +93,6 @@ def get_open_port(start_port, end_port):
return int((start_port + end_port) / 2)
-def run_ajaxterm(cmd, token, port):
- pass
-
-
def get_fs_info(path):
return {'total': 128 * (1024 ** 3),
'used': 44 * (1024 ** 3),
diff --git a/nova/tests/policy.json b/nova/tests/policy.json
index 4175d758e..99a97bba5 100644
--- a/nova/tests/policy.json
+++ b/nova/tests/policy.json
@@ -20,7 +20,6 @@
"compute:lock": [],
"compute:unlock": [],
- "compute:get_ajax_console": [],
"compute:get_vnc_console": [],
"compute:get_console_output": [],
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index d99aed310..221f86fe7 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -724,16 +724,6 @@ class ComputeTestCase(BaseTestCase):
self.assertEqual(output, 'ANOTHER\nLAST LINE')
self.compute.terminate_instance(self.context, instance['uuid'])
- def test_ajax_console(self):
- """Make sure we can get console output from instance"""
- instance = self._create_fake_instance()
- self.compute.run_instance(self.context, instance['uuid'])
-
- console = self.compute.get_ajax_console(self.context,
- instance['uuid'])
- self.assert_(set(['token', 'host', 'port']).issubset(console.keys()))
- self.compute.terminate_instance(self.context, instance['uuid'])
-
def test_novnc_vnc_console(self):
"""Make sure we can a vnc console for an instance."""
instance = self._create_fake_instance()
@@ -2990,17 +2980,6 @@ class ComputeAPITestCase(BaseTestCase):
'novnc')
self.compute_api.delete(self.context, instance)
- def test_ajax_console(self):
- """Make sure we can an ajax console for an instance."""
- def ajax_rpc_call_wrapper(*args, **kwargs):
- return {'token': 'asdf', 'host': '0.0.0.0', 'port': 8080}
-
- self.stubs.Set(rpc, 'call', ajax_rpc_call_wrapper)
-
- instance = self._create_fake_instance()
- console = self.compute_api.get_ajax_console(self.context, instance)
- self.compute_api.delete(self.context, instance)
-
def test_console_output(self):
instance = self._create_fake_instance()
console = self.compute_api.get_console_output(self.context, instance)
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 72c9f8802..61d920ff1 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -1925,20 +1925,6 @@ disk size: 4.4M''', ''))
finally:
os.unlink(dst_path)
- def test_run_ajaxterm(self):
- self.mox.StubOutWithMock(utils, 'execute')
- token = 's3cr3tt0ken'
- shell_cmd = 'shell-cmd.py'
- port = 2048
- utils.execute(mox.IgnoreArg(),
- '--command', shell_cmd,
- '-t', token,
- '-p', port)
-
- # Start test
- self.mox.ReplayAll()
- libvirt_utils.run_ajaxterm(shell_cmd, token, port)
-
def test_get_fs_info(self):
# Use a 1024-byte block size (df -k) because OS X does not support
# the -B flag
diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py
index 2cda7a61e..43dde697d 100644
--- a/nova/tests/test_virt_drivers.py
+++ b/nova/tests/test_virt_drivers.py
@@ -289,14 +289,6 @@ class _VirtDriverTestCase(test.TestCase):
self.assertTrue(isinstance(console_output, basestring))
@catch_notimplementederror
- def test_get_ajax_console(self):
- instance_ref, network_info = self._get_running_instance()
- ajax_console = self.connection.get_ajax_console(instance_ref)
- self.assertIn('token', ajax_console)
- self.assertIn('host', ajax_console)
- self.assertIn('port', ajax_console)
-
- @catch_notimplementederror
def test_get_vnc_console(self):
instance_ref, network_info = self._get_running_instance()
vnc_console = self.connection.get_vnc_console(instance_ref)
diff --git a/nova/tests/test_vmwareapi.py b/nova/tests/test_vmwareapi.py
index a1d0af440..bf8bcbe2f 100644
--- a/nova/tests/test_vmwareapi.py
+++ b/nova/tests/test_vmwareapi.py
@@ -259,6 +259,3 @@ class VMWareAPIVMTestCase(test.TestCase):
def test_get_console_output(self):
pass
-
- def test_get_ajax_console(self):
- pass
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index d87a7286a..34ce9613b 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -191,10 +191,6 @@ class ComputeDriver(object):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def get_ajax_console(self, instance):
- # TODO(Vek): Need to pass context in for access to auth_token
- raise NotImplementedError()
-
def get_vnc_console(self, instance):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index ff8da4724..ef3d392ba 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -219,11 +219,6 @@ class FakeConnection(driver.ComputeDriver):
def get_console_output(self, instance):
return 'FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE'
- def get_ajax_console(self, instance):
- return {'token': 'FAKETOKEN',
- 'host': 'fakeajaxconsole.com',
- 'port': 6969}
-
def get_vnc_console(self, instance):
return {'internal_access_path': 'FAKE',
'host': 'fakevncconsole.com',
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 37ad07736..ac3d1fb41 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -102,9 +102,6 @@ libvirt_opts = [
cfg.BoolOpt('use_cow_images',
default=True,
help='Whether to use cow images'),
- cfg.StrOpt('ajaxterm_portrange',
- default='10000-12000',
- help='Range of ports that ajaxterm should try to bind'),
cfg.StrOpt('cpuinfo_xml_template',
default=utils.abspath('virt/cpuinfo.xml.template'),
help='CpuInfo XML Template (Used only live migration now)'),
@@ -777,29 +774,6 @@ class LibvirtConnection(driver.ComputeDriver):
return libvirt_utils.load_file(fpath)
- @exception.wrap_exception()
- def get_ajax_console(self, instance):
- def get_pty_for_instance(instance_name):
- virt_dom = self._lookup_by_name(instance_name)
- xml = virt_dom.XMLDesc(0)
- dom = minidom.parseString(xml)
-
- for serial in dom.getElementsByTagName('serial'):
- if serial.getAttribute('type') == 'pty':
- source = serial.getElementsByTagName('source')[0]
- return source.getAttribute('path')
-
- start_port, end_port = FLAGS.ajaxterm_portrange.split("-")
- port = libvirt_utils.get_open_port(int(start_port), int(end_port))
- token = str(uuid.uuid4())
- host = instance['host']
-
- ajaxterm_cmd = 'sudo netcat - %s' \
- % get_pty_for_instance(instance['name'])
-
- libvirt_utils.run_ajaxterm(ajaxterm_cmd, token, port)
- return {'token': token, 'host': host, 'port': port}
-
@staticmethod
def get_host_ip_addr():
return FLAGS.my_ip
diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
index f96128124..7b0e85f38 100644
--- a/nova/virt/libvirt/utils.py
+++ b/nova/virt/libvirt/utils.py
@@ -237,18 +237,6 @@ def get_open_port(start_port, end_port):
raise Exception(_('Unable to find an open port'))
-def run_ajaxterm(cmd, token, port):
- """Run ajaxterm
-
- :param cmd: Command to connect to
- :param token: Token to require for authentication
- :param port: Port to run on
- """
- cmd = ['%s/tools/ajaxterm/ajaxterm.py' % utils.novadir(),
- '--command', cmd, '-t', token, '-p', port]
- execute(*cmd)
-
-
def get_fs_info(path):
"""Get free/used/total space info for a filesystem
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py
index af867dc6a..39d24479f 100644
--- a/nova/virt/vmwareapi/vmops.py
+++ b/nova/virt/vmwareapi/vmops.py
@@ -719,10 +719,6 @@ class VMWareVMOps(object):
else:
return ""
- def get_ajax_console(self, instance):
- """Return link to instance's ajax console."""
- return 'http://fakeajaxconsole/fake_url'
-
def _set_machine_id(self, client_factory, instance, network_info):
"""
Set the machine id of the VM for guest tools to pick up and reconfigure
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index 909969fac..7275b363e 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -174,10 +174,6 @@ class VMWareESXConnection(driver.ComputeDriver):
"""Return snapshot of console."""
return self._vmops.get_console_output(instance)
- def get_ajax_console(self, instance):
- """Return link to instance's ajax console."""
- return self._vmops.get_ajax_console(instance)
-
def get_volume_connector(self, _instance):
"""Return volume connector information"""
# TODO(vish): When volume attaching is supported, return the
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index c2960b86a..30d77369b 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -1425,11 +1425,6 @@ class VMOps(object):
# TODO: implement this to fix pylint!
return 'FAKE CONSOLE OUTPUT of instance'
- def get_ajax_console(self, instance):
- """Return link to instance's ajax console."""
- # TODO: implement this!
- return 'http://fakeajaxconsole/fake_url'
-
def get_vnc_console(self, instance):
"""Return connection info for a vnc console."""
vm_ref = self._get_vm_opaque_ref(instance)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index e034cb3ca..bbbc62df7 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -337,12 +337,8 @@ class XenAPIConnection(driver.ComputeDriver):
"""Return snapshot of console"""
return self._vmops.get_console_output(instance)
- def get_ajax_console(self, instance):
- """Return link to instance's ajax console"""
- return self._vmops.get_ajax_console(instance)
-
def get_vnc_console(self, instance):
- """Return link to instance's ajax console"""
+ """Return link to instance's VNC console"""
return self._vmops.get_vnc_console(instance)
def get_volume_connector(self, _instance):
diff --git a/run_tests.sh b/run_tests.sh
index e3cf69a36..070b89179 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -94,8 +94,7 @@ function run_pep8 {
# Opt-out files from pep8
ignore_scripts="*.sh:*nova-debug:*clean-vlans"
ignore_files="*eventlet-patch:*pip-requires"
- ignore_dirs="*ajaxterm*"
- GLOBIGNORE="$ignore_scripts:$ignore_files:$ignore_dirs"
+ GLOBIGNORE="$ignore_scripts:$ignore_files"
srcfiles=`find bin -type f ! -name "nova.conf*"`
srcfiles+=" `find tools/*`"
srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance"
@@ -124,8 +123,7 @@ function run_hacking {
# Opt-out files from pep8
ignore_scripts="*.sh:*nova-debug:*clean-vlans:*.swp"
ignore_files="*eventlet-patch:*pip-requires"
- ignore_dirs="*ajaxterm*"
- GLOBIGNORE="$ignore_scripts:$ignore_files:$ignore_dirs"
+ GLOBIGNORE="$ignore_scripts:$ignore_files"
srcfiles=`find bin -type f ! -name "nova.conf*"`
srcfiles+=" `find tools/*`"
srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance"
diff --git a/setup.py b/setup.py
index d98918968..1276e0aee 100644
--- a/setup.py
+++ b/setup.py
@@ -82,7 +82,6 @@ setup(name='nova',
data_files=find_data_files('share/nova', 'tools'),
scripts=['bin/clear_rabbit_queues',
'bin/instance-usage-audit',
- 'bin/nova-ajax-console-proxy',
'bin/nova-all',
'bin/nova-api',
'bin/nova-api-ec2',
diff --git a/tools/ajaxterm/README.txt b/tools/ajaxterm/README.txt
deleted file mode 100644
index 4b0ae99af..000000000
--- a/tools/ajaxterm/README.txt
+++ /dev/null
@@ -1,120 +0,0 @@
-= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] =
-
-Ajaxterm is a web based terminal. It was totally inspired and works almost
-exactly like http://anyterm.org/ except it's much easier to install (see
-comparaison with anyterm below).
-
-Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]]
-Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]]
-Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain.
-
-Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark.
-
-== News ==
-
- * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init
- * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer)
- * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256
- * 2006-05-31: v0.7 minor fixes, daemon option
- * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022
-
-== Download and Install ==
-
- * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz]
- * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/]
-
-To install Ajaxterm issue the following commands:
-{{{
-wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz
-tar zxvf Ajaxterm-0.10.tar.gz
-cd Ajaxterm-0.10
-./ajaxterm.py
-}}}
-Then point your browser to this URL : http://localhost:8022/
-
-== Screenshot ==
-
-{{{
-#!html
-<center><img src="/qweb/trac/attachment/wiki/AjaxTerm/scr.png?format=raw" alt="ajaxterm screenshot" style=""/></center>
-}}}
-
-== Documentation and Caveats ==
-
- * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG".
-
- * If run as root ajaxterm will run /bin/login, otherwise it will run ssh
- localhost. To use an other command use the -c option.
-
- * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is
- strongly recommended to use '''https SSL/TLS''', and that is simple to
- configure if you use the apache web server using mod_proxy.[[BR]][[BR]]
- Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]]
- Here is an configuration example:
-
-{{{
- Listen 443
- NameVirtualHost *:443
-
- <VirtualHost *:443>
- ServerName localhost
- SSLEngine On
- SSLCertificateKeyFile ssl/apache.pem
- SSLCertificateFile ssl/apache.pem
-
- ProxyRequests Off
- <Proxy *>
- Order deny,allow
- Allow from all
- </Proxy>
- ProxyPass /ajaxterm/ http://localhost:8022/
- ProxyPassReverse /ajaxterm/ http://localhost:8022/
- </VirtualHost>
-}}}
-
- * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the
- interface, but be warned that your keystrokes might be loggued (by apache or
- any proxy). I usually enable it after the login.
-
- * Ajaxterm commandline usage:
-
-{{{
-usage: ajaxterm.py [options]
-
-options:
- -h, --help show this help message and exit
- -pPORT, --port=PORT Set the TCP port (default: 8022)
- -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost)
- -l, --log log requests to stderr (default: quiet mode)
- -d, --daemon run as daemon in the background
- -PPIDFILE, --pidfile=PIDFILE
- set the pidfile (default: /var/run/ajaxterm.pid)
- -iINDEX_FILE, --index=INDEX_FILE
- default index file (default: ajaxterm.html)
- -uUID, --uid=UID Set the daemon's user id
-}}}
-
- * Ajaxterm was first written as a demo for qweb (my web framework), but
- actually doesn't use many features of qweb.
-
- * Compared to anyterm:
- * There are no partial updates, ajaxterm updates either all the screen or
- nothing. That make the code simpler and I also think it's faster. HTTP
- replies are always gzencoded. When used in 80x25 mode, almost all of
- them are below the 1500 bytes (size of an ethernet frame) and we just
- replace the screen with the reply (no javascript string handling).
- * Ajaxterm polls the server for updates with an exponentially growing
- timeout when the screen hasn't changed. The timeout is also resetted as
- soon as a key is pressed. Anyterm blocks on a pending request and use a
- parallel connection for keypresses. The anyterm approch is better
- when there aren't any keypress.
-
- * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL).
-
-== TODO ==
-
- * insert mode ESC [ 4 h
- * change size x,y from gui (sending signal)
- * vt102 graphic codepage
- * use innerHTML or prototype instead of sarissa
-
diff --git a/tools/ajaxterm/ajaxterm.1 b/tools/ajaxterm/ajaxterm.1
deleted file mode 100644
index 46f2acb33..000000000
--- a/tools/ajaxterm/ajaxterm.1
+++ /dev/null
@@ -1,35 +0,0 @@
-.TH ajaxterm "1" "May 2006" "ajaxterm 0.5" "User commands"
-.SH NAME
-ajaxterm \- Web based terminal written in python
-
-.SH DESCRITPION
-\fBajaxterm\fR is a web based terminal written in python and some AJAX
-javascript for client side.
-It can use almost any web browser and even works through firewalls.
-
-.SH USAGE
-\fBajaxterm.py\fR [options]
-
-.SH OPTIONS
-A summary of the options supported by \fBajaxterm\fR is included below.
- \fB-h, --help\fR show this help message and exit
- \fB-pPORT, --port=PORT\fR Set the TCP port (default: 8022)
- \fB-cCMD, --command=CMD\fR set the command (default: /bin/login or ssh localhost)
- \fB-l, --log\fR log requests to stderr (default: quiet mode)
-
-.SH AUTHOR
-Antony Lesuisse <al@udev.org>
-
-This manual page was written for the Debian system by
-Julien Valroff <julien@kirya.net> (but may be used by others).
-
-.SH "REPORTING BUGS"
-Report any bugs to the author: Antony Lesuisse <al@udev.org>
-
-.SH COPYRIGHT
-Copyright Antony Lesuisse <al@udev.org>
-
-.SH SEE ALSO
-- \fBajaxterm\fR wiki page: http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm
-.br
-- \fBajaxterm\fR forum: http://antony.lesuisse.org/qweb/forum/viewforum.php?id=2
diff --git a/tools/ajaxterm/ajaxterm.css b/tools/ajaxterm/ajaxterm.css
deleted file mode 100644
index b9a5f8771..000000000
--- a/tools/ajaxterm/ajaxterm.css
+++ /dev/null
@@ -1,64 +0,0 @@
-pre.stat {
- margin: 0px;
- padding: 4px;
- display: block;
- font-family: monospace;
- white-space: pre;
- background-color: black;
- border-top: 1px solid black;
- color: white;
-}
-pre.stat span {
- padding: 0px;
-}
-pre.stat .on {
- background-color: #080;
- font-weight: bold;
- color: white;
- cursor: pointer;
-}
-pre.stat .off {
- background-color: #888;
- font-weight: bold;
- color: white;
- cursor: pointer;
-}
-pre.term {
- margin: 0px;
- padding: 4px;
- display: block;
- font-family: monospace;
- white-space: pre;
- background-color: black;
- border-top: 1px solid white;
- color: #eee;
-}
-pre.term span.f0 { color: #000; }
-pre.term span.f1 { color: #b00; }
-pre.term span.f2 { color: #0b0; }
-pre.term span.f3 { color: #bb0; }
-pre.term span.f4 { color: #00b; }
-pre.term span.f5 { color: #b0b; }
-pre.term span.f6 { color: #0bb; }
-pre.term span.f7 { color: #bbb; }
-pre.term span.f8 { color: #666; }
-pre.term span.f9 { color: #f00; }
-pre.term span.f10 { color: #0f0; }
-pre.term span.f11 { color: #ff0; }
-pre.term span.f12 { color: #00f; }
-pre.term span.f13 { color: #f0f; }
-pre.term span.f14 { color: #0ff; }
-pre.term span.f15 { color: #fff; }
-pre.term span.b0 { background-color: #000; }
-pre.term span.b1 { background-color: #b00; }
-pre.term span.b2 { background-color: #0b0; }
-pre.term span.b3 { background-color: #bb0; }
-pre.term span.b4 { background-color: #00b; }
-pre.term span.b5 { background-color: #b0b; }
-pre.term span.b6 { background-color: #0bb; }
-pre.term span.b7 { background-color: #bbb; }
-
-body { background-color: #888; }
-#term {
- float: left;
-}
diff --git a/tools/ajaxterm/ajaxterm.html b/tools/ajaxterm/ajaxterm.html
deleted file mode 100644
index 7fdef5e94..000000000
--- a/tools/ajaxterm/ajaxterm.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
- <title>Ajaxterm</title>
- <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
- <link rel="stylesheet" type="text/css" href="ajaxterm.css"/>
- <script type="text/javascript" src="sarissa.js"></script>
- <script type="text/javascript" src="sarissa_dhtml.js"></script>
- <script type="text/javascript" src="ajaxterm.js"></script>
- <script type="text/javascript">
- /*
- ajaxterm.py creates a random session_id to demultiplex multiple connections,
- and to add a layer of security - in its shipping form, ajaxterm accepted any session_id
- and was susceptible to an easy exploit
- */
- SESSION_ID = '$session_id';
- window.onload=function() {
- t=ajaxterm.Terminal("term",80,25);
- };
- </script>
-</head>
-<body>
-<div id="term"></div>
-</body>
-</html>
diff --git a/tools/ajaxterm/ajaxterm.js b/tools/ajaxterm/ajaxterm.js
deleted file mode 100644
index 32b401930..000000000
--- a/tools/ajaxterm/ajaxterm.js
+++ /dev/null
@@ -1,279 +0,0 @@
-ajaxterm={};
-ajaxterm.Terminal_ctor=function(id,width,height) {
- var ie=0;
- if(window.ActiveXObject)
- ie=1;
- var sid=""+SESSION_ID;
- var query0="s="+sid+"&w="+width+"&h="+height;
- var query1=query0+"&c=1&k=";
- var buf="";
- var timeout;
- var error_timeout;
- var keybuf=[];
- var sending=0;
- var rmax=1;
-
- var div=document.getElementById(id);
- var dstat=document.createElement('pre');
- var sled=document.createElement('span');
- var opt_get=document.createElement('a');
- var opt_color=document.createElement('a');
- var opt_paste=document.createElement('a');
- var sdebug=document.createElement('span');
- var dterm=document.createElement('div');
-
- function debug(s) {
- sdebug.innerHTML=s;
- }
- function error() {
- sled.className='off';
- debug("Connection lost timeout ts:"+((new Date).getTime()));
- }
- function opt_add(opt,name) {
- opt.className='off';
- opt.innerHTML=' '+name+' ';
- dstat.appendChild(opt);
- dstat.appendChild(document.createTextNode(' '));
- }
- function do_get(event) {
- opt_get.className=(opt_get.className=='off')?'on':'off';
- debug('GET '+opt_get.className);
- }
- function do_color(event) {
- var o=opt_color.className=(opt_color.className=='off')?'on':'off';
- if(o=='on')
- query1=query0+"&c=1&k=";
- else
- query1=query0+"&k=";
- debug('Color '+opt_color.className);
- }
- function mozilla_clipboard() {
- // mozilla sucks
- try {
- netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- } catch (err) {
- debug('Access denied, <a href="http://kb.mozillazine.org/Granting_JavaScript_access_to_the_clipboard" target="_blank">more info</a>');
- return undefined;
- }
- var clip = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
- var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
- if (!clip || !trans) {
- return undefined;
- }
- trans.addDataFlavor("text/unicode");
- clip.getData(trans,clip.kGlobalClipboard);
- var str=new Object();
- var strLength=new Object();
- try {
- trans.getTransferData("text/unicode",str,strLength);
- } catch(err) {
- return "";
- }
- if (str) {
- str=str.value.QueryInterface(Components.interfaces.nsISupportsString);
- }
- if (str) {
- return str.data.substring(0,strLength.value / 2);
- } else {
- return "";
- }
- }
- function do_paste(event) {
- var p=undefined;
- if (window.clipboardData) {
- p=window.clipboardData.getData("Text");
- } else if(window.netscape) {
- p=mozilla_clipboard();
- }
- if (p) {
- debug('Pasted');
- queue(encodeURIComponent(p));
- } else {
- }
- }
- function update() {
-// debug("ts: "+((new Date).getTime())+" rmax:"+rmax);
- if(sending==0) {
- sending=1;
- sled.className='on';
- var r=new XMLHttpRequest();
- var send="";
- while(keybuf.length>0) {
- send+=keybuf.pop();
- }
- var query=query1+send;
- if(opt_get.className=='on') {
- r.open("GET","u?"+query,true);
- if(ie) {
- r.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
- }
- } else {
- r.open("POST","u",true);
- }
- r.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
- r.onreadystatechange = function () {
-// debug("xhr:"+((new Date).getTime())+" state:"+r.readyState+" status:"+r.status+" statusText:"+r.statusText);
- if (r.readyState==4) {
- if(r.status==200) {
- window.clearTimeout(error_timeout);
- de=r.responseXML.documentElement;
- if(de.tagName=="pre") {
- if(ie) {
- Sarissa.updateContentFromNode(de, dterm);
- } else {
- Sarissa.updateContentFromNode(de, dterm);
-// old=div.firstChild;
-// div.replaceChild(de,old);
- }
- rmax=100;
- } else {
- rmax*=2;
- if(rmax>2000)
- rmax=2000;
- }
- sending=0;
- sled.className='off';
- timeout=window.setTimeout(update,rmax);
- } else {
- debug("Connection error status:"+r.status);
- }
- }
- }
- error_timeout=window.setTimeout(error,5000);
- if(opt_get.className=='on') {
- r.send(null);
- } else {
- r.send(query);
- }
- }
- }
- function queue(s) {
- keybuf.unshift(s);
- if(sending==0) {
- window.clearTimeout(timeout);
- timeout=window.setTimeout(update,1);
- }
- }
- function keypress(ev) {
- if (!ev) var ev=window.event;
-// s="kp keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey;
-// debug(s);
-// return false;
-// else { if (!ev.ctrlKey || ev.keyCode==17) { return; }
- var kc;
- var k="";
- if (ev.keyCode)
- kc=ev.keyCode;
- if (ev.which)
- kc=ev.which;
- if (ev.altKey) {
- if (kc>=65 && kc<=90)
- kc+=32;
- if (kc>=97 && kc<=122) {
- k=String.fromCharCode(27)+String.fromCharCode(kc);
- }
- } else if (ev.ctrlKey) {
- if (kc>=65 && kc<=90) k=String.fromCharCode(kc-64); // Ctrl-A..Z
- else if (kc>=97 && kc<=122) k=String.fromCharCode(kc-96); // Ctrl-A..Z
- else if (kc==54) k=String.fromCharCode(30); // Ctrl-^
- else if (kc==109) k=String.fromCharCode(31); // Ctrl-_
- else if (kc==219) k=String.fromCharCode(27); // Ctrl-[
- else if (kc==220) k=String.fromCharCode(28); // Ctrl-\
- else if (kc==221) k=String.fromCharCode(29); // Ctrl-]
- else if (kc==219) k=String.fromCharCode(29); // Ctrl-]
- else if (kc==219) k=String.fromCharCode(0); // Ctrl-@
- } else if (ev.which==0) {
- if (kc==9) k=String.fromCharCode(9); // Tab
- else if (kc==8) k=String.fromCharCode(127); // Backspace
- else if (kc==27) k=String.fromCharCode(27); // Escape
- else {
- if (kc==33) k="[5~"; // PgUp
- else if (kc==34) k="[6~"; // PgDn
- else if (kc==35) k="[4~"; // End
- else if (kc==36) k="[1~"; // Home
- else if (kc==37) k="[D"; // Left
- else if (kc==38) k="[A"; // Up
- else if (kc==39) k="[C"; // Right
- else if (kc==40) k="[B"; // Down
- else if (kc==45) k="[2~"; // Ins
- else if (kc==46) k="[3~"; // Del
- else if (kc==112) k="[[A"; // F1
- else if (kc==113) k="[[B"; // F2
- else if (kc==114) k="[[C"; // F3
- else if (kc==115) k="[[D"; // F4
- else if (kc==116) k="[[E"; // F5
- else if (kc==117) k="[17~"; // F6
- else if (kc==118) k="[18~"; // F7
- else if (kc==119) k="[19~"; // F8
- else if (kc==120) k="[20~"; // F9
- else if (kc==121) k="[21~"; // F10
- else if (kc==122) k="[23~"; // F11
- else if (kc==123) k="[24~"; // F12
- if (k.length) {
- k=String.fromCharCode(27)+k;
- }
- }
- } else {
- if (kc==8)
- k=String.fromCharCode(127); // Backspace
- else
- k=String.fromCharCode(kc);
- }
- if(k.length) {
-// queue(encodeURIComponent(k));
- if(k=="+") {
- queue("%2B");
- } else {
- queue(escape(k));
- }
- }
- ev.cancelBubble=true;
- if (ev.stopPropagation) ev.stopPropagation();
- if (ev.preventDefault) ev.preventDefault();
- return false;
- }
- function keydown(ev) {
- if (!ev) var ev=window.event;
- if (ie) {
-// s="kd keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey;
-// debug(s);
- o={9:1,8:1,27:1,33:1,34:1,35:1,36:1,37:1,38:1,39:1,40:1,45:1,46:1,112:1,
- 113:1,114:1,115:1,116:1,117:1,118:1,119:1,120:1,121:1,122:1,123:1};
- if (o[ev.keyCode] || ev.ctrlKey || ev.altKey) {
- ev.which=0;
- return keypress(ev);
- }
- }
- }
- function init() {
- sled.appendChild(document.createTextNode('\xb7'));
- sled.className='off';
- dstat.appendChild(sled);
- dstat.appendChild(document.createTextNode(' '));
- opt_add(opt_color,'Colors');
- opt_color.className='on';
- opt_add(opt_get,'GET');
- opt_add(opt_paste,'Paste');
- dstat.appendChild(sdebug);
- dstat.className='stat';
- div.appendChild(dstat);
- div.appendChild(dterm);
- if(opt_color.addEventListener) {
- opt_get.addEventListener('click',do_get,true);
- opt_color.addEventListener('click',do_color,true);
- opt_paste.addEventListener('click',do_paste,true);
- } else {
- opt_get.attachEvent("onclick", do_get);
- opt_color.attachEvent("onclick", do_color);
- opt_paste.attachEvent("onclick", do_paste);
- }
- document.onkeypress=keypress;
- document.onkeydown=keydown;
- timeout=window.setTimeout(update,100);
- }
- init();
-}
-ajaxterm.Terminal=function(id,width,height) {
- return new this.Terminal_ctor(id,width,height);
-}
-
diff --git a/tools/ajaxterm/ajaxterm.py b/tools/ajaxterm/ajaxterm.py
deleted file mode 100755
index bf27b264a..000000000
--- a/tools/ajaxterm/ajaxterm.py
+++ /dev/null
@@ -1,586 +0,0 @@
-#!/usr/bin/env python
-
-""" Ajaxterm """
-
-import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd
-
-os.chdir(os.path.normpath(os.path.dirname(__file__)))
-# Optional: Add QWeb in sys path
-sys.path[0:0]=glob.glob('../../python')
-
-import qweb
-import string, subprocess, uuid
-
-global g_server
-TIMEOUT=300
-
-class Terminal:
- def __init__(self,width=80,height=24):
- self.width=width
- self.height=height
- self.init()
- self.reset()
- def init(self):
- self.esc_seq={
- "\x00": None,
- "\x05": self.esc_da,
- "\x07": None,
- "\x08": self.esc_0x08,
- "\x09": self.esc_0x09,
- "\x0a": self.esc_0x0a,
- "\x0b": self.esc_0x0a,
- "\x0c": self.esc_0x0a,
- "\x0d": self.esc_0x0d,
- "\x0e": None,
- "\x0f": None,
- "\x1b#8": None,
- "\x1b=": None,
- "\x1b>": None,
- "\x1b(0": None,
- "\x1b(A": None,
- "\x1b(B": None,
- "\x1b[c": self.esc_da,
- "\x1b[0c": self.esc_da,
- "\x1b]R": None,
- "\x1b7": self.esc_save,
- "\x1b8": self.esc_restore,
- "\x1bD": None,
- "\x1bE": None,
- "\x1bH": None,
- "\x1bM": self.esc_ri,
- "\x1bN": None,
- "\x1bO": None,
- "\x1bZ": self.esc_da,
- "\x1ba": None,
- "\x1bc": self.reset,
- "\x1bn": None,
- "\x1bo": None,
- }
- for k,v in self.esc_seq.items():
- if v==None:
- self.esc_seq[k]=self.esc_ignore
- # regex
- d={
- r'\[\??([0-9;]*)([@ABCDEFGHJKLMPXacdefghlmnqrstu`])' : self.csi_dispatch,
- r'\]([^\x07]+)\x07' : self.esc_ignore,
- }
- self.esc_re=[]
- for k,v in d.items():
- self.esc_re.append((re.compile('\x1b'+k),v))
- # define csi sequences
- self.csi_seq={
- '@': (self.csi_at,[1]),
- '`': (self.csi_G,[1]),
- 'J': (self.csi_J,[0]),
- 'K': (self.csi_K,[0]),
- }
- for i in [i[4] for i in dir(self) if i.startswith('csi_') and len(i)==5]:
- if not self.csi_seq.has_key(i):
- self.csi_seq[i]=(getattr(self,'csi_'+i),[1])
- # Init 0-256 to latin1 and html translation table
- self.trl1=""
- for i in range(256):
- if i<32:
- self.trl1+=" "
- elif i<127 or i>160:
- self.trl1+=chr(i)
- else:
- self.trl1+="?"
- self.trhtml=""
- for i in range(256):
- if i==0x0a or (i>32 and i<127) or i>160:
- self.trhtml+=chr(i)
- elif i<=32:
- self.trhtml+="\xa0"
- else:
- self.trhtml+="?"
- def reset(self,s=""):
- self.scr=array.array('i',[0x000700]*(self.width*self.height))
- self.st=0
- self.sb=self.height-1
- self.cx_bak=self.cx=0
- self.cy_bak=self.cy=0
- self.cl=0
- self.sgr=0x000700
- self.buf=""
- self.outbuf=""
- self.last_html=""
- def peek(self,y1,x1,y2,x2):
- return self.scr[self.width*y1+x1:self.width*y2+x2]
- def poke(self,y,x,s):
- pos=self.width*y+x
- self.scr[pos:pos+len(s)]=s
- def zero(self,y1,x1,y2,x2):
- w=self.width*(y2-y1)+x2-x1+1
- z=array.array('i',[0x000700]*w)
- self.scr[self.width*y1+x1:self.width*y2+x2+1]=z
- def scroll_up(self,y1,y2):
- self.poke(y1,0,self.peek(y1+1,0,y2,self.width))
- self.zero(y2,0,y2,self.width-1)
- def scroll_down(self,y1,y2):
- self.poke(y1+1,0,self.peek(y1,0,y2-1,self.width))
- self.zero(y1,0,y1,self.width-1)
- def scroll_right(self,y,x):
- self.poke(y,x+1,self.peek(y,x,y,self.width))
- self.zero(y,x,y,x)
- def cursor_down(self):
- if self.cy>=self.st and self.cy<=self.sb:
- self.cl=0
- q,r=divmod(self.cy+1,self.sb+1)
- if q:
- self.scroll_up(self.st,self.sb)
- self.cy=self.sb
- else:
- self.cy=r
- def cursor_right(self):
- q,r=divmod(self.cx+1,self.width)
- if q:
- self.cl=1
- else:
- self.cx=r
- def echo(self,c):
- if self.cl:
- self.cursor_down()
- self.cx=0
- self.scr[(self.cy*self.width)+self.cx]=self.sgr|ord(c)
- self.cursor_right()
- def esc_0x08(self,s):
- self.cx=max(0,self.cx-1)
- def esc_0x09(self,s):
- x=self.cx+8
- q,r=divmod(x,8)
- self.cx=(q*8)%self.width
- def esc_0x0a(self,s):
- self.cursor_down()
- def esc_0x0d(self,s):
- self.cl=0
- self.cx=0
- def esc_save(self,s):
- self.cx_bak=self.cx
- self.cy_bak=self.cy
- def esc_restore(self,s):
- self.cx=self.cx_bak
- self.cy=self.cy_bak
- self.cl=0
- def esc_da(self,s):
- self.outbuf="\x1b[?6c"
- def esc_ri(self,s):
- self.cy=max(self.st,self.cy-1)
- if self.cy==self.st:
- self.scroll_down(self.st,self.sb)
- def esc_ignore(self,*s):
- pass
-# print "term:ignore: %s"%repr(s)
- def csi_dispatch(self,seq,mo):
- # CSI sequences
- s=mo.group(1)
- c=mo.group(2)
- f=self.csi_seq.get(c,None)
- if f:
- try:
- l=[min(int(i),1024) for i in s.split(';') if len(i)<4]
- except ValueError:
- l=[]
- if len(l)==0:
- l=f[1]
- f[0](l)
-# else:
-# print 'csi ignore',c,l
- def csi_at(self,l):
- for i in range(l[0]):
- self.scroll_right(self.cy,self.cx)
- def csi_A(self,l):
- self.cy=max(self.st,self.cy-l[0])
- def csi_B(self,l):
- self.cy=min(self.sb,self.cy+l[0])
- def csi_C(self,l):
- self.cx=min(self.width-1,self.cx+l[0])
- self.cl=0
- def csi_D(self,l):
- self.cx=max(0,self.cx-l[0])
- self.cl=0
- def csi_E(self,l):
- self.csi_B(l)
- self.cx=0
- self.cl=0
- def csi_F(self,l):
- self.csi_A(l)
- self.cx=0
- self.cl=0
- def csi_G(self,l):
- self.cx=min(self.width,l[0])-1
- def csi_H(self,l):
- if len(l)<2: l=[1,1]
- self.cx=min(self.width,l[1])-1
- self.cy=min(self.height,l[0])-1
- self.cl=0
- def csi_J(self,l):
- if l[0]==0:
- self.zero(self.cy,self.cx,self.height-1,self.width-1)
- elif l[0]==1:
- self.zero(0,0,self.cy,self.cx)
- elif l[0]==2:
- self.zero(0,0,self.height-1,self.width-1)
- def csi_K(self,l):
- if l[0]==0:
- self.zero(self.cy,self.cx,self.cy,self.width-1)
- elif l[0]==1:
- self.zero(self.cy,0,self.cy,self.cx)
- elif l[0]==2:
- self.zero(self.cy,0,self.cy,self.width-1)
- def csi_L(self,l):
- for i in range(l[0]):
- if self.cy<self.sb:
- self.scroll_down(self.cy,self.sb)
- def csi_M(self,l):
- if self.cy>=self.st and self.cy<=self.sb:
- for i in range(l[0]):
- self.scroll_up(self.cy,self.sb)
- def csi_P(self,l):
- w,cx,cy=self.width,self.cx,self.cy
- end=self.peek(cy,cx,cy,w)
- self.csi_K([0])
- self.poke(cy,cx,end[l[0]:])
- def csi_X(self,l):
- self.zero(self.cy,self.cx,self.cy,self.cx+l[0])
- def csi_a(self,l):
- self.csi_C(l)
- def csi_c(self,l):
- #'\x1b[?0c' 0-8 cursor size
- pass
- def csi_d(self,l):
- self.cy=min(self.height,l[0])-1
- def csi_e(self,l):
- self.csi_B(l)
- def csi_f(self,l):
- self.csi_H(l)
- def csi_h(self,l):
- if l[0]==4:
- pass
-# print "insert on"
- def csi_l(self,l):
- if l[0]==4:
- pass
-# print "insert off"
- def csi_m(self,l):
- for i in l:
- if i==0 or i==39 or i==49 or i==27:
- self.sgr=0x000700
- elif i==1:
- self.sgr=(self.sgr|0x000800)
- elif i==7:
- self.sgr=0x070000
- elif i>=30 and i<=37:
- c=i-30
- self.sgr=(self.sgr&0xff08ff)|(c<<8)
- elif i>=40 and i<=47:
- c=i-40
- self.sgr=(self.sgr&0x00ffff)|(c<<16)
-# else:
-# print "CSI sgr ignore",l,i
-# print 'sgr: %r %x'%(l,self.sgr)
- def csi_r(self,l):
- if len(l)<2: l=[0,self.height]
- self.st=min(self.height-1,l[0]-1)
- self.sb=min(self.height-1,l[1]-1)
- self.sb=max(self.st,self.sb)
- def csi_s(self,l):
- self.esc_save(0)
- def csi_u(self,l):
- self.esc_restore(0)
- def escape(self):
- e=self.buf
- if len(e)>32:
-# print "error %r"%e
- self.buf=""
- elif e in self.esc_seq:
- self.esc_seq[e](e)
- self.buf=""
- else:
- for r,f in self.esc_re:
- mo=r.match(e)
- if mo:
- f(e,mo)
- self.buf=""
- break
-# if self.buf=='': print "ESC %r\n"%e
- def write(self,s):
- for i in s:
- if len(self.buf) or (i in self.esc_seq):
- self.buf+=i
- self.escape()
- elif i == '\x1b':
- self.buf+=i
- else:
- self.echo(i)
- def read(self):
- b=self.outbuf
- self.outbuf=""
- return b
- def dump(self):
- r=''
- for i in self.scr:
- r+=chr(i&255)
- return r
- def dumplatin1(self):
- return self.dump().translate(self.trl1)
- def dumphtml(self,color=1):
- h=self.height
- w=self.width
- r=""
- span=""
- span_bg,span_fg=-1,-1
- for i in range(h*w):
- q,c=divmod(self.scr[i],256)
- if color:
- bg,fg=divmod(q,256)
- else:
- bg,fg=0,7
- if i==self.cy*w+self.cx:
- bg,fg=1,7
- if (bg!=span_bg or fg!=span_fg or i==h*w-1):
- if len(span):
- r+='<span class="f%d b%d">%s</span>'%(span_fg,span_bg,cgi.escape(span.translate(self.trhtml)))
- span=""
- span_bg,span_fg=bg,fg
- span+=chr(c)
- if i%w==w-1:
- span+='\n'
- r='<?xml version="1.0" encoding="ISO-8859-1"?><pre class="term">%s</pre>'%r
- if self.last_html==r:
- return '<?xml version="1.0"?><idem></idem>'
- else:
- self.last_html=r
-# print self
- return r
- def __repr__(self):
- d=self.dumplatin1()
- r=""
- for i in range(self.height):
- r+="|%s|\n"%d[self.width*i:self.width*(i+1)]
- return r
-
-class SynchronizedMethod:
- def __init__(self,lock,orig):
- self.lock=lock
- self.orig=orig
- def __call__(self,*l):
- self.lock.acquire()
- r=self.orig(*l)
- self.lock.release()
- return r
-
-class Multiplex:
- def __init__(self,cmd=None):
- signal.signal(signal.SIGCHLD, signal.SIG_IGN)
- self.cmd=cmd
- self.proc={}
- self.lock=threading.RLock()
- self.thread=threading.Thread(target=self.loop)
- self.alive=1
- self.lastActivity=time.time()
- # synchronize methods
- for name in ['create','fds','proc_read','proc_write','dump','die','run']:
- orig=getattr(self,name)
- setattr(self,name,SynchronizedMethod(self.lock,orig))
- self.thread.start()
- def create(self,w=80,h=25):
- pid,fd=pty.fork()
- if pid==0:
- try:
- fdl=[int(i) for i in os.listdir('/proc/self/fd')]
- except OSError:
- fdl=range(256)
- for i in [i for i in fdl if i>2]:
- try:
- os.close(i)
- except OSError:
- pass
- if self.cmd:
- cmd=['/bin/sh','-c',self.cmd]
- elif os.getuid()==0:
- cmd=['/bin/login']
- else:
- sys.stdout.write("Login: ")
- login=sys.stdin.readline().strip()
- if re.match('^[0-9A-Za-z-_. ]+$',login):
- cmd=['ssh']
- cmd+=['-oPreferredAuthentications=keyboard-interactive,password']
- cmd+=['-oNoHostAuthenticationForLocalhost=yes']
- cmd+=['-oLogLevel=FATAL']
- cmd+=['-F/dev/null','-l',login,'localhost']
- else:
- os._exit(0)
- env={}
- env["COLUMNS"]=str(w)
- env["LINES"]=str(h)
- env["TERM"]="linux"
- env["PATH"]=os.environ['PATH']
- os.execvpe(cmd[0],cmd,env)
- else:
- fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK)
- # python bug http://python.org/sf/1112949 on amd64
- fcntl.ioctl(fd, struct.unpack('i',struct.pack('I',termios.TIOCSWINSZ))[0], struct.pack("HHHH",h,w,0,0))
- self.proc[fd]={'pid':pid,'term':Terminal(w,h),'buf':'','time':time.time()}
- return fd
- def die(self):
- self.alive=0
- def run(self):
- return self.alive
- def fds(self):
- return self.proc.keys()
- def proc_kill(self,fd):
- if fd in self.proc:
- self.proc[fd]['time']=0
- t=time.time()
- for i in self.proc.keys():
- t0=self.proc[i]['time']
- if (t-t0)>TIMEOUT:
- try:
- os.close(i)
- os.kill(self.proc[i]['pid'],signal.SIGTERM)
- except (IOError,OSError):
- pass
- del self.proc[i]
- def proc_read(self,fd):
- try:
- t=self.proc[fd]['term']
- t.write(os.read(fd,65536))
- reply=t.read()
- if reply:
- os.write(fd,reply)
- self.proc[fd]['time']=time.time()
- except (KeyError,IOError,OSError):
- self.proc_kill(fd)
- def proc_write(self,fd,s):
- try:
- os.write(fd,s)
- except (IOError,OSError):
- self.proc_kill(fd)
- def dump(self,fd,color=1):
- try:
- return self.proc[fd]['term'].dumphtml(color)
- except KeyError:
- return False
- def loop(self):
- while self.run():
- fds=self.fds()
- i,o,e=select.select(fds, [], [], 1.0)
- if time.time() - self.lastActivity > TIMEOUT:
- global g_server
- g_server.shutdown()
- for fd in i:
- self.proc_read(fd)
- if len(i):
- time.sleep(0.002)
- for i in self.proc.keys():
- try:
- os.close(i)
- os.kill(self.proc[i]['pid'],signal.SIGTERM)
- except (IOError,OSError):
- pass
-
-class AjaxTerm:
- def __init__(self,cmd=None,index_file='ajaxterm.html',token=None):
- self.files={}
- self.token=token
- for i in ['css','html','js']:
- for j in glob.glob('*.%s'%i):
- self.files[j]=file(j).read()
- self.files['index']=file(index_file).read()
- self.mime = mimetypes.types_map.copy()
- self.mime['.html']= 'text/html; charset=UTF-8'
- self.multi = Multiplex(cmd)
- self.session = {}
- def __call__(self, environ, start_response):
- req = qweb.QWebRequest(environ, start_response,session=None)
- if req.PATH_INFO.endswith('/u'):
- s=req.REQUEST["s"]
- k=req.REQUEST["k"]
- c=req.REQUEST["c"]
- w=req.REQUEST.int("w")
- h=req.REQUEST.int("h")
- if s in self.session:
- term=self.session[s]
- else:
- raise Exception('Not Authorized')
- # The original code below was insecure, because it allowed unauthorized sessions to be created
- # if not (w>2 and w<256 and h>2 and h<100):
- # w,h=80,25
- # term=self.session[s]=self.multi.create(w,h)
- if k:
- self.multi.proc_write(term,k)
- time.sleep(0.002)
- self.multi.lastActivity = time.time();
- dump=self.multi.dump(term,c)
- req.response_headers['Content-Type']='text/xml'
- if isinstance(dump,str):
- req.write(dump)
- req.response_gzencode=1
- else:
- del self.session[s]
- req.write('<?xml version="1.0"?><idem></idem>')
-# print "sessions %r"%self.session
- else:
- n=os.path.basename(req.PATH_INFO)
- if n in self.files:
- req.response_headers['Content-Type'] = self.mime.get(os.path.splitext(n)[1].lower(), 'application/octet-stream')
- req.write(self.files[n])
- elif req.REQUEST['token'] == self.token:
- req.response_headers['Content-Type'] = 'text/html; charset=UTF-8'
- session_id = str(uuid.uuid4())
- req.write(string.Template(self.files['index']).substitute(session_id=session_id))
- term=self.session[session_id]=self.multi.create(80,25)
- else:
- raise Exception("Not Authorized")
- return req
-
-def main():
- parser = optparse.OptionParser()
- parser.add_option("-p", "--port", dest="port", default="8022", help="Set the TCP port (default: 8022)")
- parser.add_option("-c", "--command", dest="cmd", default=None,help="set the command (default: /bin/login or ssh 0.0.0.0)")
- parser.add_option("-l", "--log", action="store_true", dest="log",default=0,help="log requests to stderr (default: quiet mode)")
- parser.add_option("-d", "--daemon", action="store_true", dest="daemon", default=0, help="run as daemon in the background")
- parser.add_option("-P", "--pidfile",dest="pidfile",default="/var/run/ajaxterm.pid",help="set the pidfile (default: /var/run/ajaxterm.pid)")
- parser.add_option("-i", "--index", dest="index_file", default="ajaxterm.html",help="default index file (default: ajaxterm.html)")
- parser.add_option("-u", "--uid", dest="uid", help="Set the daemon's user id")
- parser.add_option("-t", "--token", dest="token", help="Set authorization token")
- (o, a) = parser.parse_args()
- if o.daemon:
- pid=os.fork()
- if pid == 0:
- #os.setsid() ?
- os.setpgrp()
- nullin = file('/dev/null', 'r')
- nullout = file('/dev/null', 'w')
- os.dup2(nullin.fileno(), sys.stdin.fileno())
- os.dup2(nullout.fileno(), sys.stdout.fileno())
- os.dup2(nullout.fileno(), sys.stderr.fileno())
- if os.getuid()==0 and o.uid:
- try:
- os.setuid(int(o.uid))
- except:
- os.setuid(pwd.getpwnam(o.uid).pw_uid)
- else:
- try:
- file(o.pidfile,'w+').write(str(pid)+'\n')
- except:
- pass
- print 'AjaxTerm at http://0.0.0.0:%s/ pid: %d' % (o.port,pid)
- sys.exit(0)
- else:
- print 'AjaxTerm at http://0.0.0.0:%s/' % o.port
- at=AjaxTerm(o.cmd,o.index_file,o.token)
-# f=lambda:os.system('firefox http://localhost:%s/&'%o.port)
-# qweb.qweb_wsgi_autorun(at,ip='localhost',port=int(o.port),threaded=0,log=o.log,callback_ready=None)
- try:
- global g_server
- g_server = qweb.QWebWSGIServer(at,ip='0.0.0.0',port=int(o.port),threaded=0,log=o.log)
- g_server.serve_forever()
- except KeyboardInterrupt,e:
- sys.excepthook(*sys.exc_info())
- at.multi.die()
-
-if __name__ == '__main__':
- main()
-
diff --git a/tools/ajaxterm/configure b/tools/ajaxterm/configure
deleted file mode 100755
index 45391f484..000000000
--- a/tools/ajaxterm/configure
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-
-import optparse,os
-
-parser = optparse.OptionParser()
-parser.add_option("", "--prefix", dest="prefix",default="/usr/local",help="installation prefix (default: /usr/local)")
-parser.add_option("", "--confdir", dest="confdir", default="/etc",help="configuration files directory prefix (default: /etc)")
-parser.add_option("", "--port", dest="port", default="8022", help="set the listening TCP port (default: 8022)")
-parser.add_option("", "--command", dest="cmd", default=None,help="set the command (default: /bin/login or ssh localhost)")
-(o, a) = parser.parse_args()
-
-print "Configuring prefix=",o.prefix," port=",o.port
-
-etc=o.confdir
-port=o.port
-cmd=o.cmd
-bin=os.path.join(o.prefix,"bin")
-lib=os.path.join(o.prefix,"share/ajaxterm")
-man=os.path.join(o.prefix,"share/man/man1")
-
-file("ajaxterm.bin","w").write(file("configure.ajaxterm.bin").read()%locals())
-file("Makefile","w").write(file("configure.makefile").read()%locals())
-
-if os.path.isfile("/etc/gentoo-release"):
- file("ajaxterm.initd","w").write(file("configure.initd.gentoo").read()%locals())
-elif os.path.isfile("/etc/fedora-release") or os.path.isfile("/etc/redhat-release"):
- file("ajaxterm.initd","w").write(file("configure.initd.redhat").read()%locals())
-else:
- file("ajaxterm.initd","w").write(file("configure.initd.debian").read()%locals())
-
-os.system("chmod a+x ajaxterm.bin")
-os.system("chmod a+x ajaxterm.initd")
diff --git a/tools/ajaxterm/configure.ajaxterm.bin b/tools/ajaxterm/configure.ajaxterm.bin
deleted file mode 100644
index 4d1f5a98f..000000000
--- a/tools/ajaxterm/configure.ajaxterm.bin
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-PYTHONPATH=%(lib)s exec %(lib)s/ajaxterm.py $@
diff --git a/tools/ajaxterm/configure.initd.debian b/tools/ajaxterm/configure.initd.debian
deleted file mode 100644
index 901082707..000000000
--- a/tools/ajaxterm/configure.initd.debian
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-
-PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
-DAEMON=%(bin)s/ajaxterm
-PORT=%(port)s
-PIDFILE=/var/run/ajaxterm.pid
-
-[ -x "$DAEMON" ] || exit 0
-
-#. /lib/lsb/init-functions
-
-case "$1" in
- start)
- echo "Starting ajaxterm on port $PORT"
- start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- --daemon --port=$PORT --uid=nobody || return 2
- ;;
- stop)
- echo "Stopping ajaxterm"
- start-stop-daemon --stop --pidfile $PIDFILE
- rm -f $PIDFILE
- ;;
- restart|force-reload)
- $0 stop
- sleep 1
- $0 start
- ;;
- *)
- echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
- exit 3
- ;;
-esac
-
-:
diff --git a/tools/ajaxterm/configure.initd.gentoo b/tools/ajaxterm/configure.initd.gentoo
deleted file mode 100644
index ac28ef0b6..000000000
--- a/tools/ajaxterm/configure.initd.gentoo
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/sbin/runscript
-
-# AjaxTerm Gentoo script, 08 May 2006 Mark Gillespie
-
-DAEMON=%(bin)s/ajaxterm
-PORT=%(port)s
-PIDFILE=/var/run/ajaxterm.pid
-
-depend()
-{
- need net
-}
-
-start()
-{
- ebegin "Starting AjaxTerm on port $PORT"
- start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- --daemon --port=$PORT --uid=nobody
- eend $?
-}
-
-stop()
-{
- ebegin "Stopping AjaxTerm"
- start-stop-daemon --stop --pidfile $PIDFILE
- rm -f $PIDFILE
- eend $?
-}
diff --git a/tools/ajaxterm/configure.initd.redhat b/tools/ajaxterm/configure.initd.redhat
deleted file mode 100644
index 5c9788574..000000000
--- a/tools/ajaxterm/configure.initd.redhat
+++ /dev/null
@@ -1,75 +0,0 @@
-#
-# ajaxterm Startup script for ajaxterm
-#
-# chkconfig: - 99 99
-# description: Ajaxterm is a yadda yadda yadda
-# processname: ajaxterm
-# pidfile: /var/run/ajaxterm.pid
-# version: 1.0 Kevin Reichhart - ajaxterminit at lastname dot org
-
-# Source function library.
-. /etc/rc.d/init.d/functions
-
-if [ -f /etc/sysconfig/ajaxterm ]; then
- . /etc/sysconfig/ajaxterm
-fi
-
-ajaxterm=/usr/local/bin/ajaxterm
-prog=ajaxterm
-pidfile=${PIDFILE-/var/run/ajaxterm.pid}
-lockfile=${LOCKFILE-/var/lock/subsys/ajaxterm}
-port=${PORT-8022}
-user=${xUSER-nobody}
-RETVAL=0
-
-
-start() {
- echo -n $"Starting $prog: "
- daemon $ajaxterm --daemon --port=$port --uid=$user $OPTIONS
- RETVAL=$?
- echo
- [ $RETVAL = 0 ] && touch ${lockfile}
- return $RETVAL
-}
-stop() {
- echo -n $"Stopping $prog: "
- killproc $ajaxterm
- RETVAL=$?
- echo
- [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
-}
-reload() {
- echo -n $"Reloading $prog: "
- killproc $ajaxterm -HUP
- RETVAL=$?
- echo
-}
-
-# See how we were called.
-case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- status)
- status python ajaxterm
- RETVAL=$?
- ;;
- restart)
- stop
- start
- ;;
- condrestart)
- if [ -f ${pidfile} ] ; then
- stop
- start
- fi
- ;;
- *)
- echo $"Usage: $prog {start|stop|restart|condrestart}"
- exit 1
-esac
-
-exit $RETVAL
diff --git a/tools/ajaxterm/configure.makefile b/tools/ajaxterm/configure.makefile
deleted file mode 100644
index 6bd80853d..000000000
--- a/tools/ajaxterm/configure.makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-build:
- true
-
-install:
- install -d "%(bin)s"
- install -d "%(lib)s"
- install ajaxterm.bin "%(bin)s/ajaxterm"
- install ajaxterm.initd "%(etc)s/init.d/ajaxterm"
- install -m 644 ajaxterm.css ajaxterm.html ajaxterm.js qweb.py sarissa.js sarissa_dhtml.js "%(lib)s"
- install -m 755 ajaxterm.py "%(lib)s"
- gzip --best -c ajaxterm.1 > ajaxterm.1.gz
- install -d "%(man)s"
- install ajaxterm.1.gz "%(man)s"
-
-clean:
- rm ajaxterm.bin
- rm ajaxterm.initd
- rm ajaxterm.1.gz
- rm Makefile
-
diff --git a/tools/ajaxterm/qweb.py b/tools/ajaxterm/qweb.py
deleted file mode 100644
index 630325c95..000000000
--- a/tools/ajaxterm/qweb.py
+++ /dev/null
@@ -1,1356 +0,0 @@
-#!/usr/bin/python2.3
-#
-# vim:set et ts=4 fdc=0 fdn=2 fdl=0:
-#
-# There are no blank lines between blocks beacause i use folding from:
-# http://www.vim.org/scripts/script.php?script_id=515
-#
-
-"""= QWeb Framework =
-
-== What is QWeb ? ==
-
-QWeb is a python based [http://www.python.org/doc/peps/pep-0333/ WSGI]
-compatible web framework, it provides an infratructure to quickly build web
-applications consisting of:
-
- * A lightweight request handler (QWebRequest)
- * An xml templating engine (QWebXml and QWebHtml)
- * A simple name based controler (qweb_control)
- * A standalone WSGI Server (QWebWSGIServer)
- * A cgi and fastcgi WSGI wrapper (taken from flup)
- * A startup function that starts cgi, factgi or standalone according to the
- evironement (qweb_autorun).
-
-QWeb applications are runnable in standalone mode (from commandline), via
-FastCGI, Regular CGI or by any python WSGI compliant server.
-
-QWeb doesn't provide any database access but it integrates nicely with ORMs
-such as SQLObject, SQLAlchemy or plain DB-API.
-
-Written by Antony Lesuisse (email al AT udev.org)
-
-Homepage: http://antony.lesuisse.org/qweb/trac/
-
-Forum: [http://antony.lesuisse.org/qweb/forum/viewforum.php?id=1 Forum]
-
-== Quick Start (for Linux, MacOS X and cygwin) ==
-
-Make sure you have at least python 2.3 installed and run the following commands:
-
-{{{
-$ wget http://antony.lesuisse.org/qweb/files/QWeb-0.7.tar.gz
-$ tar zxvf QWeb-0.7.tar.gz
-$ cd QWeb-0.7/examples/blog
-$ ./blog.py
-}}}
-
-And point your browser to http://localhost:8080/
-
-You may also try AjaxTerm which uses qweb request handler.
-
-== Download ==
-
- * Version 0.7:
- * Source [/qweb/files/QWeb-0.7.tar.gz QWeb-0.7.tar.gz]
- * Python 2.3 Egg [/qweb/files/QWeb-0.7-py2.3.egg QWeb-0.7-py2.3.egg]
- * Python 2.4 Egg [/qweb/files/QWeb-0.7-py2.4.egg QWeb-0.7-py2.4.egg]
-
- * [/qweb/trac/browser Browse the source repository]
-
-== Documentation ==
-
- * [/qweb/trac/browser/trunk/README.txt?format=raw Read the included documentation]
- * QwebTemplating
-
-== Mailin-list ==
-
- * Forum: [http://antony.lesuisse.org/qweb/forum/viewforum.php?id=1 Forum]
- * No mailing-list exists yet, discussion should happen on: [http://mail.python.org/mailman/listinfo/web-sig web-sig] [http://mail.python.org/pipermail/web-sig/ archives]
-
-QWeb Components:
-----------------
-
-QWeb also feature a simple components api, that enables developers to easily
-produces reusable components.
-
-Default qweb components:
-
- - qweb_static:
- A qweb component to serve static content from the filesystem or from
- zipfiles.
-
- - qweb_dbadmin:
- scaffolding for sqlobject
-
-License
--------
-qweb/fcgi.py wich is BSD-like from saddi.com.
-Everything else is put in the public domain.
-
-
-TODO
-----
- Announce QWeb to python-announce-list@python.org web-sig@python.org
- qweb_core
- rename request methods into
- request_save_files
- response_404
- response_redirect
- response_download
- request callback_generator, callback_function ?
- wsgi callback_server_local
- xml tags explicitly call render_attributes(t_att)?
- priority form-checkbox over t-value (for t-option)
-
-"""
-
-import BaseHTTPServer,SocketServer,Cookie
-import cgi,datetime,email,email.Message,errno,gzip,os,random,re,socket,sys,tempfile,time,types,urllib,urlparse,xml.dom
-try:
- import cPickle as pickle
-except ImportError:
- import pickle
-try:
- import cStringIO as StringIO
-except ImportError:
- import StringIO
-
-#----------------------------------------------------------
-# Qweb Xml t-raw t-esc t-if t-foreach t-set t-call t-trim
-#----------------------------------------------------------
-class QWebEval:
- def __init__(self,data):
- self.data=data
- def __getitem__(self,expr):
- if self.data.has_key(expr):
- return self.data[expr]
- r=None
- try:
- r=eval(expr,self.data)
- except NameError,e:
- pass
- except AttributeError,e:
- pass
- except Exception,e:
- print "qweb: expression error '%s' "%expr,e
- if self.data.has_key("__builtins__"):
- del self.data["__builtins__"]
- return r
- def eval_object(self,expr):
- return self[expr]
- def eval_str(self,expr):
- if expr=="0":
- return self.data[0]
- if isinstance(self[expr],unicode):
- return self[expr].encode("utf8")
- return str(self[expr])
- def eval_format(self,expr):
- try:
- return str(expr%self)
- except:
- return "qweb: format error '%s' "%expr
-# if isinstance(r,unicode):
-# return r.encode("utf8")
- def eval_bool(self,expr):
- if self.eval_object(expr):
- return 1
- else:
- return 0
-class QWebXml:
- """QWeb Xml templating engine
-
- The templating engine use a very simple syntax, "magic" xml attributes, to
- produce any kind of texutal output (even non-xml).
-
- QWebXml:
- the template engine core implements the basic magic attributes:
-
- t-att t-raw t-esc t-if t-foreach t-set t-call t-trim
-
- """
- def __init__(self,x=None,zipname=None):
- self.node=xml.dom.Node
- self._t={}
- self._render_tag={}
- prefix='render_tag_'
- for i in [j for j in dir(self) if j.startswith(prefix)]:
- name=i[len(prefix):].replace('_','-')
- self._render_tag[name]=getattr(self.__class__,i)
-
- self._render_att={}
- prefix='render_att_'
- for i in [j for j in dir(self) if j.startswith(prefix)]:
- name=i[len(prefix):].replace('_','-')
- self._render_att[name]=getattr(self.__class__,i)
-
- if x!=None:
- if zipname!=None:
- import zipfile
- zf=zipfile.ZipFile(zipname, 'r')
- self.add_template(zf.read(x))
- else:
- self.add_template(x)
- def register_tag(self,tag,func):
- self._render_tag[tag]=func
- def add_template(self,x):
- if hasattr(x,'documentElement'):
- dom=x
- elif x.startswith("<?xml"):
- import xml.dom.minidom
- dom=xml.dom.minidom.parseString(x)
- else:
- import xml.dom.minidom
- dom=xml.dom.minidom.parse(x)
- for n in dom.documentElement.childNodes:
- if n.nodeName=="t":
- self._t[str(n.getAttribute("t-name"))]=n
- def get_template(self,name):
- return self._t[name]
-
- def eval_object(self,expr,v):
- return QWebEval(v).eval_object(expr)
- def eval_str(self,expr,v):
- return QWebEval(v).eval_str(expr)
- def eval_format(self,expr,v):
- return QWebEval(v).eval_format(expr)
- def eval_bool(self,expr,v):
- return QWebEval(v).eval_bool(expr)
-
- def render(self,tname,v={},out=None):
- if self._t.has_key(tname):
- return self.render_node(self._t[tname],v)
- else:
- return 'qweb: template "%s" not found'%tname
- def render_node(self,e,v):
- r=""
- if e.nodeType==self.node.TEXT_NODE or e.nodeType==self.node.CDATA_SECTION_NODE:
- r=e.data.encode("utf8")
- elif e.nodeType==self.node.ELEMENT_NODE:
- pre=""
- g_att=""
- t_render=None
- t_att={}
- for (an,av) in e.attributes.items():
- an=str(an)
- if isinstance(av,types.UnicodeType):
- av=av.encode("utf8")
- else:
- av=av.nodeValue.encode("utf8")
- if an.startswith("t-"):
- for i in self._render_att:
- if an[2:].startswith(i):
- g_att+=self._render_att[i](self,e,an,av,v)
- break
- else:
- if self._render_tag.has_key(an[2:]):
- t_render=an[2:]
- t_att[an[2:]]=av
- else:
- g_att+=' %s="%s"'%(an,cgi.escape(av,1));
- if t_render:
- if self._render_tag.has_key(t_render):
- r=self._render_tag[t_render](self,e,t_att,g_att,v)
- else:
- r=self.render_element(e,g_att,v,pre,t_att.get("trim",0))
- return r
- def render_element(self,e,g_att,v,pre="",trim=0):
- g_inner=[]
- for n in e.childNodes:
- g_inner.append(self.render_node(n,v))
- name=str(e.nodeName)
- inner="".join(g_inner)
- if trim==0:
- pass
- elif trim=='left':
- inner=inner.lstrip()
- elif trim=='right':
- inner=inner.rstrip()
- elif trim=='both':
- inner=inner.strip()
- if name=="t":
- return inner
- elif len(inner):
- return "<%s%s>%s%s</%s>"%(name,g_att,pre,inner,name)
- else:
- return "<%s%s/>"%(name,g_att)
-
- # Attributes
- def render_att_att(self,e,an,av,v):
- if an.startswith("t-attf-"):
- att,val=an[7:],self.eval_format(av,v)
- elif an.startswith("t-att-"):
- att,val=(an[6:],self.eval_str(av,v))
- else:
- att,val=self.eval_object(av,v)
- return ' %s="%s"'%(att,cgi.escape(val,1))
-
- # Tags
- def render_tag_raw(self,e,t_att,g_att,v):
- return self.eval_str(t_att["raw"],v)
- def render_tag_rawf(self,e,t_att,g_att,v):
- return self.eval_format(t_att["rawf"],v)
- def render_tag_esc(self,e,t_att,g_att,v):
- return cgi.escape(self.eval_str(t_att["esc"],v))
- def render_tag_escf(self,e,t_att,g_att,v):
- return cgi.escape(self.eval_format(t_att["escf"],v))
- def render_tag_foreach(self,e,t_att,g_att,v):
- expr=t_att["foreach"]
- enum=self.eval_object(expr,v)
- if enum!=None:
- var=t_att.get('as',expr).replace('.','_')
- d=v.copy()
- size=-1
- if isinstance(enum,types.ListType):
- size=len(enum)
- elif isinstance(enum,types.TupleType):
- size=len(enum)
- elif hasattr(enum,'count'):
- size=enum.count()
- d["%s_size"%var]=size
- d["%s_all"%var]=enum
- index=0
- ru=[]
- for i in enum:
- d["%s_value"%var]=i
- d["%s_index"%var]=index
- d["%s_first"%var]=index==0
- d["%s_even"%var]=index%2
- d["%s_odd"%var]=(index+1)%2
- d["%s_last"%var]=index+1==size
- if index%2:
- d["%s_parity"%var]='odd'
- else:
- d["%s_parity"%var]='even'
- if isinstance(i,types.DictType):
- d.update(i)
- else:
- d[var]=i
- ru.append(self.render_element(e,g_att,d))
- index+=1
- return "".join(ru)
- else:
- return "qweb: t-foreach %s not found."%expr
- def render_tag_if(self,e,t_att,g_att,v):
- if self.eval_bool(t_att["if"],v):
- return self.render_element(e,g_att,v)
- else:
- return ""
- def render_tag_call(self,e,t_att,g_att,v):
- # TODO t-prefix
- if t_att.has_key("import"):
- d=v
- else:
- d=v.copy()
- d[0]=self.render_element(e,g_att,d)
- return self.render(t_att["call"],d)
- def render_tag_set(self,e,t_att,g_att,v):
- if t_att.has_key("eval"):
- v[t_att["set"]]=self.eval_object(t_att["eval"],v)
- else:
- v[t_att["set"]]=self.render_element(e,g_att,v)
- return ""
-
-#----------------------------------------------------------
-# QWeb HTML (+deprecated QWebFORM and QWebOLD)
-#----------------------------------------------------------
-class QWebURL:
- """ URL helper
- assert req.PATH_INFO== "/site/admin/page_edit"
- u = QWebURL(root_path="/site/",req_path=req.PATH_INFO)
- s=u.url2_href("user/login",{'a':'1'})
- assert s=="../user/login?a=1"
-
- """
- def __init__(self, root_path="/", req_path="/",defpath="",defparam={}):
- self.defpath=defpath
- self.defparam=defparam
- self.root_path=root_path
- self.req_path=req_path
- self.req_list=req_path.split("/")[:-1]
- self.req_len=len(self.req_list)
- def decode(self,s):
- h={}
- for k,v in cgi.parse_qsl(s,1):
- h[k]=v
- return h
- def encode(self,h):
- return urllib.urlencode(h.items())
- def request(self,req):
- return req.REQUEST
- def copy(self,path=None,param=None):
- npath=self.defpath
- if path:
- npath=path
- nparam=self.defparam.copy()
- if param:
- nparam.update(param)
- return QWebURL(self.root_path,self.req_path,npath,nparam)
- def path(self,path=''):
- if not path:
- path=self.defpath
- pl=(self.root_path+path).split('/')
- i=0
- for i in range(min(len(pl), self.req_len)):
- if pl[i]!=self.req_list[i]:
- break
- else:
- i+=1
- dd=self.req_len-i
- if dd<0:
- dd=0
- return '/'.join(['..']*dd+pl[i:])
- def href(self,path='',arg={}):
- p=self.path(path)
- tmp=self.defparam.copy()
- tmp.update(arg)
- s=self.encode(tmp)
- if len(s):
- return p+"?"+s
- else:
- return p
- def form(self,path='',arg={}):
- p=self.path(path)
- tmp=self.defparam.copy()
- tmp.update(arg)
- r=''.join(['<input type="hidden" name="%s" value="%s"/>'%(k,cgi.escape(str(v),1)) for k,v in tmp.items()])
- return (p,r)
-class QWebField:
- def __init__(self,name=None,default="",check=None):
- self.name=name
- self.default=default
- self.check=check
- # optional attributes
- self.type=None
- self.trim=1
- self.required=1
- self.cssvalid="form_valid"
- self.cssinvalid="form_invalid"
- # set by addfield
- self.form=None
- # set by processing
- self.input=None
- self.css=None
- self.value=None
- self.valid=None
- self.invalid=None
- self.validate(1)
- def validate(self,val=1,update=1):
- if val:
- self.valid=1
- self.invalid=0
- self.css=self.cssvalid
- else:
- self.valid=0
- self.invalid=1
- self.css=self.cssinvalid
- if update and self.form:
- self.form.update()
- def invalidate(self,update=1):
- self.validate(0,update)
-class QWebForm:
- class QWebFormF:
- pass
- def __init__(self,e=None,arg=None,default=None):
- self.fields={}
- # all fields have been submitted
- self.submitted=False
- self.missing=[]
- # at least one field is invalid or missing
- self.invalid=False
- self.error=[]
- # all fields have been submitted and are valid
- self.valid=False
- # fields under self.f for convenience
- self.f=self.QWebFormF()
- if e:
- self.add_template(e)
- # assume that the fields are done with the template
- if default:
- self.set_default(default,e==None)
- if arg!=None:
- self.process_input(arg)
- def __getitem__(self,k):
- return self.fields[k]
- def set_default(self,default,add_missing=1):
- for k,v in default.items():
- if self.fields.has_key(k):
- self.fields[k].default=str(v)
- elif add_missing:
- self.add_field(QWebField(k,v))
- def add_field(self,f):
- self.fields[f.name]=f
- f.form=self
- setattr(self.f,f.name,f)
- def add_template(self,e):
- att={}
- for (an,av) in e.attributes.items():
- an=str(an)
- if an.startswith("t-"):
- att[an[2:]]=av.encode("utf8")
- for i in ["form-text", "form-password", "form-radio", "form-checkbox", "form-select","form-textarea"]:
- if att.has_key(i):
- name=att[i].split(".")[-1]
- default=att.get("default","")
- check=att.get("check",None)
- f=QWebField(name,default,check)
- if i=="form-textarea":
- f.type="textarea"
- f.trim=0
- if i=="form-checkbox":
- f.type="checkbox"
- f.required=0
- self.add_field(f)
- for n in e.childNodes:
- if n.nodeType==n.ELEMENT_NODE:
- self.add_template(n)
- def process_input(self,arg):
- for f in self.fields.values():
- if arg.has_key(f.name):
- f.input=arg[f.name]
- f.value=f.input
- if f.trim:
- f.input=f.input.strip()
- f.validate(1,False)
- if f.check==None:
- continue
- elif callable(f.check):
- pass
- elif isinstance(f.check,str):
- v=f.check
- if f.check=="email":
- v=r"/^[^@#!& ]+@[A-Za-z0-9-][.A-Za-z0-9-]{0,64}\.[A-Za-z]{2,5}$/"
- if f.check=="date":
- v=r"/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/"
- if not re.match(v[1:-1],f.input):
- f.validate(0,False)
- else:
- f.value=f.default
- self.update()
- def validate_all(self,val=1):
- for f in self.fields.values():
- f.validate(val,0)
- self.update()
- def invalidate_all(self):
- self.validate_all(0)
- def update(self):
- self.submitted=True
- self.valid=True
- self.errors=[]
- for f in self.fields.values():
- if f.required and f.input==None:
- self.submitted=False
- self.valid=False
- self.missing.append(f.name)
- if f.invalid:
- self.valid=False
- self.error.append(f.name)
- # invalid have been submitted and
- self.invalid=self.submitted and self.valid==False
- def collect(self):
- d={}
- for f in self.fields.values():
- d[f.name]=f.value
- return d
-class QWebURLEval(QWebEval):
- def __init__(self,data):
- QWebEval.__init__(self,data)
- def __getitem__(self,expr):
- r=QWebEval.__getitem__(self,expr)
- if isinstance(r,str):
- return urllib.quote_plus(r)
- else:
- return r
-class QWebHtml(QWebXml):
- """QWebHtml
- QWebURL:
- QWebField:
- QWebForm:
- QWebHtml:
- an extended template engine, with a few utility class to easily produce
- HTML, handle URLs and process forms, it adds the following magic attributes:
-
- t-href t-action t-form-text t-form-password t-form-textarea t-form-radio
- t-form-checkbox t-form-select t-option t-selected t-checked t-pager
-
- # explication URL:
- # v['tableurl']=QWebUrl({p=afdmin,saar=,orderby=,des=,mlink;meta_active=})
- # t-href="tableurl?desc=1"
- #
- # explication FORM: t-if="form.valid()"
- # Foreach i
- # email: <input type="text" t-esc-name="i" t-esc-value="form[i].value" t-esc-class="form[i].css"/>
- # <input type="radio" name="spamtype" t-esc-value="i" t-selected="i==form.f.spamtype.value"/>
- # <option t-esc-value="cc" t-selected="cc==form.f.country.value"><t t-esc="cname"></option>
- # Simple forms:
- # <input t-form-text="form.email" t-check="email"/>
- # <input t-form-password="form.email" t-check="email"/>
- # <input t-form-radio="form.email" />
- # <input t-form-checkbox="form.email" />
- # <textarea t-form-textarea="form.email" t-check="email"/>
- # <select t-form-select="form.email"/>
- # <option t-value="1">
- # <input t-form-radio="form.spamtype" t-value="1"/> Cars
- # <input t-form-radio="form.spamtype" t-value="2"/> Sprt
- """
- # QWebForm from a template
- def form(self,tname,arg=None,default=None):
- form=QWebForm(self._t[tname],arg,default)
- return form
-
- # HTML Att
- def eval_url(self,av,v):
- s=QWebURLEval(v).eval_format(av)
- a=s.split('?',1)
- arg={}
- if len(a)>1:
- for k,v in cgi.parse_qsl(a[1],1):
- arg[k]=v
- b=a[0].split('/',1)
- path=''
- if len(b)>1:
- path=b[1]
- u=b[0]
- return u,path,arg
- def render_att_url_(self,e,an,av,v):
- u,path,arg=self.eval_url(av,v)
- if not isinstance(v.get(u,0),QWebURL):
- out='qweb: missing url %r %r %r'%(u,path,arg)
- else:
- out=v[u].href(path,arg)
- return ' %s="%s"'%(an[6:],cgi.escape(out,1))
- def render_att_href(self,e,an,av,v):
- return self.render_att_url_(e,"t-url-href",av,v)
- def render_att_checked(self,e,an,av,v):
- if self.eval_bool(av,v):
- return ' %s="%s"'%(an[2:],an[2:])
- else:
- return ''
- def render_att_selected(self,e,an,av,v):
- return self.render_att_checked(e,an,av,v)
-
- # HTML Tags forms
- def render_tag_rawurl(self,e,t_att,g_att,v):
- u,path,arg=self.eval_url(t_att["rawurl"],v)
- return v[u].href(path,arg)
- def render_tag_escurl(self,e,t_att,g_att,v):
- u,path,arg=self.eval_url(t_att["escurl"],v)
- return cgi.escape(v[u].href(path,arg))
- def render_tag_action(self,e,t_att,g_att,v):
- u,path,arg=self.eval_url(t_att["action"],v)
- if not isinstance(v.get(u,0),QWebURL):
- action,input=('qweb: missing url %r %r %r'%(u,path,arg),'')
- else:
- action,input=v[u].form(path,arg)
- g_att+=' action="%s"'%action
- return self.render_element(e,g_att,v,input)
- def render_tag_form_text(self,e,t_att,g_att,v):
- f=self.eval_object(t_att["form-text"],v)
- g_att+=' type="text" name="%s" value="%s" class="%s"'%(f.name,cgi.escape(f.value,1),f.css)
- return self.render_element(e,g_att,v)
- def render_tag_form_password(self,e,t_att,g_att,v):
- f=self.eval_object(t_att["form-password"],v)
- g_att+=' type="password" name="%s" value="%s" class="%s"'%(f.name,cgi.escape(f.value,1),f.css)
- return self.render_element(e,g_att,v)
- def render_tag_form_textarea(self,e,t_att,g_att,v):
- type="textarea"
- f=self.eval_object(t_att["form-textarea"],v)
- g_att+=' name="%s" class="%s"'%(f.name,f.css)
- r="<%s%s>%s</%s>"%(type,g_att,cgi.escape(f.value,1),type)
- return r
- def render_tag_form_radio(self,e,t_att,g_att,v):
- f=self.eval_object(t_att["form-radio"],v)
- val=t_att["value"]
- g_att+=' type="radio" name="%s" value="%s"'%(f.name,val)
- if f.value==val:
- g_att+=' checked="checked"'
- return self.render_element(e,g_att,v)
- def render_tag_form_checkbox(self,e,t_att,g_att,v):
- f=self.eval_object(t_att["form-checkbox"],v)
- val=t_att["value"]
- g_att+=' type="checkbox" name="%s" value="%s"'%(f.name,val)
- if f.value==val:
- g_att+=' checked="checked"'
- return self.render_element(e,g_att,v)
- def render_tag_form_select(self,e,t_att,g_att,v):
- f=self.eval_object(t_att["form-select"],v)
- g_att+=' name="%s" class="%s"'%(f.name,f.css)
- return self.render_element(e,g_att,v)
- def render_tag_option(self,e,t_att,g_att,v):
- f=self.eval_object(e.parentNode.getAttribute("t-form-select"),v)
- val=t_att["option"]
- g_att+=' value="%s"'%(val)
- if f.value==val:
- g_att+=' selected="selected"'
- return self.render_element(e,g_att,v)
-
- # HTML Tags others
- def render_tag_pager(self,e,t_att,g_att,v):
- pre=t_att["pager"]
- total=int(self.eval_str(t_att["total"],v))
- start=int(self.eval_str(t_att["start"],v))
- step=int(self.eval_str(t_att.get("step","100"),v))
- scope=int(self.eval_str(t_att.get("scope","5"),v))
- # Compute Pager
- p=pre+"_"
- d={}
- d[p+"tot_size"]=total
- d[p+"tot_page"]=tot_page=total/step
- d[p+"win_start0"]=total and start
- d[p+"win_start1"]=total and start+1
- d[p+"win_end0"]=max(0,min(start+step-1,total-1))
- d[p+"win_end1"]=min(start+step,total)
- d[p+"win_page0"]=win_page=start/step
- d[p+"win_page1"]=win_page+1
- d[p+"prev"]=(win_page!=0)
- d[p+"prev_start"]=(win_page-1)*step
- d[p+"next"]=(tot_page>=win_page+1)
- d[p+"next_start"]=(win_page+1)*step
- l=[]
- begin=win_page-scope
- end=win_page+scope
- if begin<0:
- end-=begin
- if end>tot_page:
- begin-=(end-tot_page)
- i=max(0,begin)
- while i<=min(end,tot_page) and total!=step:
- l.append( { p+"page0":i, p+"page1":i+1, p+"start":i*step, p+"sel":(win_page==i) })
- i+=1
- d[p+"active"]=len(l)>1
- d[p+"list"]=l
- # Update v
- v.update(d)
- return ""
-
-#----------------------------------------------------------
-# QWeb Simple Controller
-#----------------------------------------------------------
-def qweb_control(self,jump='main',p=[]):
- """ qweb_control(self,jump='main',p=[]):
- A simple function to handle the controler part of your application. It
- dispatch the control to the jump argument, while ensuring that prefix
- function have been called.
-
- qweb_control replace '/' to '_' and strip '_' from the jump argument.
-
- name1
- name1_name2
- name1_name2_name3
-
- """
- jump=jump.replace('/','_').strip('_')
- if not hasattr(self,jump):
- return 0
- done={}
- todo=[]
- while 1:
- if jump!=None:
- tmp=""
- todo=[]
- for i in jump.split("_"):
- tmp+=i+"_";
- if not done.has_key(tmp[:-1]):
- todo.append(tmp[:-1])
- jump=None
- elif len(todo):
- i=todo.pop(0)
- done[i]=1
- if hasattr(self,i):
- f=getattr(self,i)
- r=f(*p)
- if isinstance(r,types.StringType):
- jump=r
- else:
- break
- return 1
-
-#----------------------------------------------------------
-# QWeb WSGI Request handler
-#----------------------------------------------------------
-class QWebSession(dict):
- def __init__(self,environ,**kw):
- dict.__init__(self)
- default={
- "path" : tempfile.gettempdir(),
- "cookie_name" : "QWEBSID",
- "cookie_lifetime" : 0,
- "cookie_path" : '/',
- "cookie_domain" : '',
- "limit_cache" : 1,
- "probability" : 0.01,
- "maxlifetime" : 3600,
- "disable" : 0,
- }
- for k,v in default.items():
- setattr(self,'session_%s'%k,kw.get(k,v))
- # Try to find session
- self.session_found_cookie=0
- self.session_found_url=0
- self.session_found=0
- self.session_orig=""
- # Try cookie
- c=Cookie.SimpleCookie()
- c.load(environ.get('HTTP_COOKIE', ''))
- if c.has_key(self.session_cookie_name):
- sid=c[self.session_cookie_name].value[:64]
- if re.match('[a-f0-9]+$',sid) and self.session_load(sid):
- self.session_id=sid
- self.session_found_cookie=1
- self.session_found=1
- # Try URL
- if not self.session_found_cookie:
- mo=re.search('&%s=([a-f0-9]+)'%self.session_cookie_name,environ.get('QUERY_STRING',''))
- if mo and self.session_load(mo.group(1)):
- self.session_id=mo.group(1)
- self.session_found_url=1
- self.session_found=1
- # New session
- if not self.session_found:
- self.session_id='%032x'%random.randint(1,2**128)
- self.session_trans_sid="&amp;%s=%s"%(self.session_cookie_name,self.session_id)
- # Clean old session
- if random.random() < self.session_probability:
- self.session_clean()
- def session_get_headers(self):
- h=[]
- if (not self.session_disable) and (len(self) or len(self.session_orig)):
- self.session_save()
- if not self.session_found_cookie:
- c=Cookie.SimpleCookie()
- c[self.session_cookie_name] = self.session_id
- c[self.session_cookie_name]['path'] = self.session_cookie_path
- if self.session_cookie_domain:
- c[self.session_cookie_name]['domain'] = self.session_cookie_domain
-# if self.session_cookie_lifetime:
-# c[self.session_cookie_name]['expires'] = TODO date localtime or not, datetime.datetime(1970, 1, 1)
- h.append(("Set-Cookie", c[self.session_cookie_name].OutputString()))
- if self.session_limit_cache:
- h.append(('Cache-Control','no-store, no-cache, must-revalidate, post-check=0, pre-check=0'))
- h.append(('Expires','Thu, 19 Nov 1981 08:52:00 GMT'))
- h.append(('Pragma','no-cache'))
- return h
- def session_load(self,sid):
- fname=os.path.join(self.session_path,'qweb_sess_%s'%sid)
- try:
- orig=file(fname).read()
- d=pickle.loads(orig)
- except:
- return
- self.session_orig=orig
- self.update(d)
- return 1
- def session_save(self):
- if not os.path.isdir(self.session_path):
- os.makedirs(self.session_path)
- fname=os.path.join(self.session_path,'qweb_sess_%s'%self.session_id)
- try:
- oldtime=os.path.getmtime(fname)
- except OSError,IOError:
- oldtime=0
- dump=pickle.dumps(self.copy())
- if (dump != self.session_orig) or (time.time() > oldtime+self.session_maxlifetime/4):
- tmpname=os.path.join(self.session_path,'qweb_sess_%s_%x'%(self.session_id,random.randint(1,2**32)))
- f=file(tmpname,'wb')
- f.write(dump)
- f.close()
- if sys.platform=='win32' and os.path.isfile(fname):
- os.remove(fname)
- os.rename(tmpname,fname)
- def session_clean(self):
- t=time.time()
- try:
- for i in [os.path.join(self.session_path,i) for i in os.listdir(self.session_path) if i.startswith('qweb_sess_')]:
- if (t > os.path.getmtime(i)+self.session_maxlifetime):
- os.unlink(i)
- except OSError,IOError:
- pass
-class QWebSessionMem(QWebSession):
- def session_load(self,sid):
- global _qweb_sessions
- if not "_qweb_sessions" in globals():
- _qweb_sessions={}
- if _qweb_sessions.has_key(sid):
- self.session_orig=_qweb_sessions[sid]
- self.update(self.session_orig)
- return 1
- def session_save(self):
- global _qweb_sessions
- if not "_qweb_sessions" in globals():
- _qweb_sessions={}
- _qweb_sessions[self.session_id]=self.copy()
-class QWebSessionService:
- def __init__(self, wsgiapp, url_rewrite=0):
- self.wsgiapp=wsgiapp
- self.url_rewrite_tags="a=href,area=href,frame=src,form=,fieldset="
- def __call__(self, environ, start_response):
- # TODO
- # use QWebSession to provide environ["qweb.session"]
- return self.wsgiapp(environ,start_response)
-class QWebDict(dict):
- def __init__(self,*p):
- dict.__init__(self,*p)
- def __getitem__(self,key):
- return self.get(key,"")
- def int(self,key):
- try:
- return int(self.get(key,"0"))
- except ValueError:
- return 0
-class QWebListDict(dict):
- def __init__(self,*p):
- dict.__init__(self,*p)
- def __getitem__(self,key):
- return self.get(key,[])
- def appendlist(self,key,val):
- if self.has_key(key):
- self[key].append(val)
- else:
- self[key]=[val]
- def get_qwebdict(self):
- d=QWebDict()
- for k,v in self.items():
- d[k]=v[-1]
- return d
-class QWebRequest:
- """QWebRequest a WSGI request handler.
-
- QWebRequest is a WSGI request handler that feature GET, POST and POST
- multipart methods, handles cookies and headers and provide a dict-like
- SESSION Object (either on the filesystem or in memory).
-
- It is constructed with the environ and start_response WSGI arguments:
-
- req=qweb.QWebRequest(environ, start_response)
-
- req has the folowing attributes :
-
- req.environ standard WSGI dict (CGI and wsgi ones)
-
- Some CGI vars as attributes from environ for convenience:
-
- req.SCRIPT_NAME
- req.PATH_INFO
- req.REQUEST_URI
-
- Some computed value (also for convenience)
-
- req.FULL_URL full URL recontructed (http://host/query)
- req.FULL_PATH (URL path before ?querystring)
-
- Dict constructed from querystring and POST datas, PHP-like.
-
- req.GET contains GET vars
- req.POST contains POST vars
- req.REQUEST contains merge of GET and POST
- req.FILES contains uploaded files
- req.GET_LIST req.POST_LIST req.REQUEST_LIST req.FILES_LIST multiple arguments versions
- req.debug() returns an HTML dump of those vars
-
- A dict-like session object.
-
- req.SESSION the session start when the dict is not empty.
-
- Attribute for handling the response
-
- req.response_headers dict-like to set headers
- req.response_cookies a SimpleCookie to set cookies
- req.response_status a string to set the status like '200 OK'
-
- req.write() to write to the buffer
-
- req itselfs is an iterable object with the buffer, it will also also call
- start_response automatically before returning anything via the iterator.
-
- To make it short, it means that you may use
-
- return req
-
- at the end of your request handling to return the reponse to any WSGI
- application server.
- """
- #
- # This class contains part ripped from colubrid (with the permission of
- # mitsuhiko) see http://wsgiarea.pocoo.org/colubrid/
- #
- # - the class HttpHeaders
- # - the method load_post_data (tuned version)
- #
- class HttpHeaders(object):
- def __init__(self):
- self.data = [('Content-Type', 'text/html')]
- def __setitem__(self, key, value):
- self.set(key, value)
- def __delitem__(self, key):
- self.remove(key)
- def __contains__(self, key):
- key = key.lower()
- for k, v in self.data:
- if k.lower() == key:
- return True
- return False
- def add(self, key, value):
- self.data.append((key, value))
- def remove(self, key, count=-1):
- removed = 0
- data = []
- for _key, _value in self.data:
- if _key.lower() != key.lower():
- if count > -1:
- if removed >= count:
- break
- else:
- removed += 1
- data.append((_key, _value))
- self.data = data
- def clear(self):
- self.data = []
- def set(self, key, value):
- self.remove(key)
- self.add(key, value)
- def get(self, key=False, httpformat=False):
- if not key:
- result = self.data
- else:
- result = []
- for _key, _value in self.data:
- if _key.lower() == key.lower():
- result.append((_key, _value))
- if httpformat:
- return '\n'.join(['%s: %s' % item for item in result])
- return result
- def load_post_data(self,environ,POST,FILES):
- length = int(environ['CONTENT_LENGTH'])
- DATA = environ['wsgi.input'].read(length)
- if environ.get('CONTENT_TYPE', '').startswith('multipart'):
- lines = ['Content-Type: %s' % environ.get('CONTENT_TYPE', '')]
- for key, value in environ.items():
- if key.startswith('HTTP_'):
- lines.append('%s: %s' % (key, value))
- raw = '\r\n'.join(lines) + '\r\n\r\n' + DATA
- msg = email.message_from_string(raw)
- for sub in msg.get_payload():
- if not isinstance(sub, email.Message.Message):
- continue
- name_dict = cgi.parse_header(sub['Content-Disposition'])[1]
- if 'filename' in name_dict:
- # Nested MIME Messages are not supported'
- if isinstance(sub.get_payload(), list):
- continue
- if not name_dict['filename'].strip():
- continue
- filename = name_dict['filename']
- # why not keep all the filename? because IE always send 'C:\documents and settings\blub\blub.png'
- filename = filename[filename.rfind('\\') + 1:]
- if 'Content-Type' in sub:
- content_type = sub['Content-Type']
- else:
- content_type = None
- s = { "name":filename, "type":content_type, "data":sub.get_payload() }
- FILES.appendlist(name_dict['name'], s)
- else:
- POST.appendlist(name_dict['name'], sub.get_payload())
- else:
- POST.update(cgi.parse_qs(DATA,keep_blank_values=1))
- return DATA
-
- def __init__(self,environ,start_response,session=QWebSession):
- self.environ=environ
- self.start_response=start_response
- self.buffer=[]
-
- self.SCRIPT_NAME = environ.get('SCRIPT_NAME', '')
- self.PATH_INFO = environ.get('PATH_INFO', '')
- # extensions:
- self.FULL_URL = environ['FULL_URL'] = self.get_full_url(environ)
- # REQUEST_URI is optional, fake it if absent
- if not environ.has_key("REQUEST_URI"):
- environ["REQUEST_URI"]=urllib.quote(self.SCRIPT_NAME+self.PATH_INFO)
- if environ.get('QUERY_STRING'):
- environ["REQUEST_URI"]+='?'+environ['QUERY_STRING']
- self.REQUEST_URI = environ["REQUEST_URI"]
- # full quote url path before the ?
- self.FULL_PATH = environ['FULL_PATH'] = self.REQUEST_URI.split('?')[0]
-
- self.request_cookies=Cookie.SimpleCookie()
- self.request_cookies.load(environ.get('HTTP_COOKIE', ''))
-
- self.response_started=False
- self.response_gzencode=False
- self.response_cookies=Cookie.SimpleCookie()
- # to delete a cookie use: c[key]['expires'] = datetime.datetime(1970, 1, 1)
- self.response_headers=self.HttpHeaders()
- self.response_status="200 OK"
-
- self.php=None
- if self.environ.has_key("php"):
- self.php=environ["php"]
- self.SESSION=self.php._SESSION
- self.GET=self.php._GET
- self.POST=self.php._POST
- self.REQUEST=self.php._ARG
- self.FILES=self.php._FILES
- else:
- if isinstance(session,QWebSession):
- self.SESSION=session
- elif session:
- self.SESSION=session(environ)
- else:
- self.SESSION=None
- self.GET_LIST=QWebListDict(cgi.parse_qs(environ.get('QUERY_STRING', ''),keep_blank_values=1))
- self.POST_LIST=QWebListDict()
- self.FILES_LIST=QWebListDict()
- self.REQUEST_LIST=QWebListDict(self.GET_LIST)
- if environ['REQUEST_METHOD'] == 'POST':
- self.DATA=self.load_post_data(environ,self.POST_LIST,self.FILES_LIST)
- self.REQUEST_LIST.update(self.POST_LIST)
- self.GET=self.GET_LIST.get_qwebdict()
- self.POST=self.POST_LIST.get_qwebdict()
- self.FILES=self.FILES_LIST.get_qwebdict()
- self.REQUEST=self.REQUEST_LIST.get_qwebdict()
- def get_full_url(environ):
- # taken from PEP 333
- if 'FULL_URL' in environ:
- return environ['FULL_URL']
- url = environ['wsgi.url_scheme']+'://'
- if environ.get('HTTP_HOST'):
- url += environ['HTTP_HOST']
- else:
- url += environ['SERVER_NAME']
- if environ['wsgi.url_scheme'] == 'https':
- if environ['SERVER_PORT'] != '443':
- url += ':' + environ['SERVER_PORT']
- else:
- if environ['SERVER_PORT'] != '80':
- url += ':' + environ['SERVER_PORT']
- if environ.has_key('REQUEST_URI'):
- url += environ['REQUEST_URI']
- else:
- url += urllib.quote(environ.get('SCRIPT_NAME', ''))
- url += urllib.quote(environ.get('PATH_INFO', ''))
- if environ.get('QUERY_STRING'):
- url += '?' + environ['QUERY_STRING']
- return url
- get_full_url=staticmethod(get_full_url)
- def save_files(self):
- for k,v in self.FILES.items():
- if not v.has_key("tmp_file"):
- f=tempfile.NamedTemporaryFile()
- f.write(v["data"])
- f.flush()
- v["tmp_file"]=f
- v["tmp_name"]=f.name
- def debug(self):
- body=''
- for name,d in [
- ("GET",self.GET), ("POST",self.POST), ("REQUEST",self.REQUEST), ("FILES",self.FILES),
- ("GET_LIST",self.GET_LIST), ("POST_LIST",self.POST_LIST), ("REQUEST_LIST",self.REQUEST_LIST), ("FILES_LIST",self.FILES_LIST),
- ("SESSION",self.SESSION), ("environ",self.environ),
- ]:
- body+='<table border="1" width="100%" align="center">\n'
- body+='<tr><th colspan="2" align="center">%s</th></tr>\n'%name
- keys=d.keys()
- keys.sort()
- body+=''.join(['<tr><td>%s</td><td>%s</td></tr>\n'%(k,cgi.escape(repr(d[k]))) for k in keys])
- body+='</table><br><br>\n\n'
- return body
- def write(self,s):
- self.buffer.append(s)
- def echo(self,*s):
- self.buffer.extend([str(i) for i in s])
- def response(self):
- if not self.response_started:
- if not self.php:
- for k,v in self.FILES.items():
- if v.has_key("tmp_file"):
- try:
- v["tmp_file"].close()
- except OSError:
- pass
- if self.response_gzencode and self.environ.get('HTTP_ACCEPT_ENCODING','').find('gzip')!=-1:
- zbuf=StringIO.StringIO()
- zfile=gzip.GzipFile(mode='wb', fileobj=zbuf)
- zfile.write(''.join(self.buffer))
- zfile.close()
- zbuf=zbuf.getvalue()
- self.buffer=[zbuf]
- self.response_headers['Content-Encoding']="gzip"
- self.response_headers['Content-Length']=str(len(zbuf))
- headers = self.response_headers.get()
- if isinstance(self.SESSION, QWebSession):
- headers.extend(self.SESSION.session_get_headers())
- headers.extend([('Set-Cookie', self.response_cookies[i].OutputString()) for i in self.response_cookies])
- self.start_response(self.response_status, headers)
- self.response_started=True
- return self.buffer
- def __iter__(self):
- return self.response().__iter__()
- def http_redirect(self,url,permanent=1):
- if permanent:
- self.response_status="301 Moved Permanently"
- else:
- self.response_status="302 Found"
- self.response_headers["Location"]=url
- def http_404(self,msg="<h1>404 Not Found</h1>"):
- self.response_status="404 Not Found"
- if msg:
- self.write(msg)
- def http_download(self,fname,fstr,partial=0):
-# allow fstr to be a file-like object
-# if parital:
-# say accept ranages
-# parse range headers...
-# if range:
-# header("HTTP/1.1 206 Partial Content");
-# header("Content-Range: bytes $offset-".($fsize-1)."/".$fsize);
-# header("Content-Length: ".($fsize-$offset));
-# fseek($fd,$offset);
-# else:
- self.response_headers["Content-Type"]="application/octet-stream"
- self.response_headers["Content-Disposition"]="attachment; filename=\"%s\""%fname
- self.response_headers["Content-Transfer-Encoding"]="binary"
- self.response_headers["Content-Length"]="%d"%len(fstr)
- self.write(fstr)
-
-#----------------------------------------------------------
-# QWeb WSGI HTTP Server to run any WSGI app
-# autorun, run an app as FCGI or CGI otherwise launch the server
-#----------------------------------------------------------
-class QWebWSGIHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def log_message(self,*p):
- if self.server.log:
- return BaseHTTPServer.BaseHTTPRequestHandler.log_message(self,*p)
- def address_string(self):
- return self.client_address[0]
- def start_response(self,status,headers):
- l=status.split(' ',1)
- self.send_response(int(l[0]),l[1])
- ctype_sent=0
- for i in headers:
- if i[0].lower()=="content-type":
- ctype_sent=1
- self.send_header(*i)
- if not ctype_sent:
- self.send_header("Content-type", "text/html")
- self.end_headers()
- return self.write
- def write(self,data):
- try:
- self.wfile.write(data)
- except (socket.error, socket.timeout),e:
- print e
- def bufferon(self):
- if not getattr(self,'wfile_buf',0):
- self.wfile_buf=1
- self.wfile_bak=self.wfile
- self.wfile=StringIO.StringIO()
- def bufferoff(self):
- if self.wfile_buf:
- buf=self.wfile
- self.wfile=self.wfile_bak
- self.write(buf.getvalue())
- self.wfile_buf=0
- def serve(self,type):
- path_info, parameters, query = urlparse.urlparse(self.path)[2:5]
- environ = {
- 'wsgi.version': (1,0),
- 'wsgi.url_scheme': 'http',
- 'wsgi.input': self.rfile,
- 'wsgi.errors': sys.stderr,
- 'wsgi.multithread': 0,
- 'wsgi.multiprocess': 0,
- 'wsgi.run_once': 0,
- 'REQUEST_METHOD': self.command,
- 'SCRIPT_NAME': '',
- 'QUERY_STRING': query,
- 'CONTENT_TYPE': self.headers.get('Content-Type', ''),
- 'CONTENT_LENGTH': self.headers.get('Content-Length', ''),
- 'REMOTE_ADDR': self.client_address[0],
- 'REMOTE_PORT': str(self.client_address[1]),
- 'SERVER_NAME': self.server.server_address[0],
- 'SERVER_PORT': str(self.server.server_address[1]),
- 'SERVER_PROTOCOL': self.request_version,
- # extention
- 'FULL_PATH': self.path,
- 'qweb.mode': 'standalone',
- }
- if path_info:
- environ['PATH_INFO'] = urllib.unquote(path_info)
- for key, value in self.headers.items():
- environ['HTTP_' + key.upper().replace('-', '_')] = value
- # Hack to avoid may TCP packets
- self.bufferon()
- appiter=self.server.wsgiapp(environ, self.start_response)
- for data in appiter:
- self.write(data)
- self.bufferoff()
- self.bufferoff()
- def do_GET(self):
- self.serve('GET')
- def do_POST(self):
- self.serve('GET')
-class QWebWSGIServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
- """ QWebWSGIServer
- qweb_wsgi_autorun(wsgiapp,ip='127.0.0.1',port=8080,threaded=1)
- A WSGI HTTP server threaded or not and a function to automatically run your
- app according to the environement (either standalone, CGI or FastCGI).
-
- This feature is called QWeb autorun. If you want to To use it on your
- application use the following lines at the end of the main application
- python file:
-
- if __name__ == '__main__':
- qweb.qweb_wsgi_autorun(your_wsgi_app)
-
- this function will select the approriate running mode according to the
- calling environement (http-server, FastCGI or CGI).
- """
- def __init__(self, wsgiapp, ip, port, threaded=1, log=1):
- BaseHTTPServer.HTTPServer.__init__(self, (ip, port), QWebWSGIHandler)
- self.wsgiapp = wsgiapp
- self.threaded = threaded
- self.log = log
- def process_request(self,*p):
- if self.threaded:
- return SocketServer.ThreadingMixIn.process_request(self,*p)
- else:
- return BaseHTTPServer.HTTPServer.process_request(self,*p)
-def qweb_wsgi_autorun(wsgiapp,ip='127.0.0.1',port=8080,threaded=1,log=1,callback_ready=None):
- if sys.platform=='win32':
- fcgi=0
- else:
- fcgi=1
- sock = socket.fromfd(0, socket.AF_INET, socket.SOCK_STREAM)
- try:
- sock.getpeername()
- except socket.error, e:
- if e[0] == errno.ENOTSOCK:
- fcgi=0
- if fcgi or os.environ.has_key('REQUEST_METHOD'):
- import fcgi
- fcgi.WSGIServer(wsgiapp,multithreaded=False).run()
- else:
- if log:
- print 'Serving on %s:%d'%(ip,port)
- s=QWebWSGIServer(wsgiapp,ip=ip,port=port,threaded=threaded,log=log)
- if callback_ready:
- callback_ready()
- try:
- s.serve_forever()
- except KeyboardInterrupt,e:
- sys.excepthook(*sys.exc_info())
-
-#----------------------------------------------------------
-# Qweb Documentation
-#----------------------------------------------------------
-def qweb_doc():
- body=__doc__
- for i in [QWebXml ,QWebHtml ,QWebForm ,QWebURL ,qweb_control ,QWebRequest ,QWebSession ,QWebWSGIServer ,qweb_wsgi_autorun]:
- n=i.__name__
- d=i.__doc__
- body+='\n\n%s\n%s\n\n%s'%(n,'-'*len(n),d)
- return body
-
- print qweb_doc()
-
-#
diff --git a/tools/ajaxterm/sarissa.js b/tools/ajaxterm/sarissa.js
deleted file mode 100644
index 6d13aa2e2..000000000
--- a/tools/ajaxterm/sarissa.js
+++ /dev/null
@@ -1,647 +0,0 @@
-/**
- * ====================================================================
- * About
- * ====================================================================
- * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.
- * The library supports Gecko based browsers like Mozilla and Firefox,
- * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera
- * @version 0.9.6.1
- * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
- * ====================================================================
- * Licence
- * ====================================================================
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 or
- * the GNU Lesser General Public License version 2.1 as published by
- * the Free Software Foundation (your choice between the two).
- *
- * 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 or GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * or GNU Lesser General Public License along with this program; if not,
- * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * or visit http://www.gnu.org
- *
- */
-/**
- * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument and
- * XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p>
- * @constructor
- */
-function Sarissa(){};
-/** @private */
-Sarissa.PARSED_OK = "Document contains no parsing errors";
-/**
- * Tells you whether transformNode and transformNodeToObject are available. This functionality
- * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations
- * use the XSLTProcessor
- * @deprecated
- * @type boolean
- */
-Sarissa.IS_ENABLED_TRANSFORM_NODE = false;
-/**
- * tells you whether XMLHttpRequest (or equivalent) is available
- * @type boolean
- */
-Sarissa.IS_ENABLED_XMLHTTP = false;
-/**
- * tells you whether selectNodes/selectSingleNode is available
- * @type boolean
- */
-Sarissa.IS_ENABLED_SELECT_NODES = false;
-var _sarissa_iNsCounter = 0;
-var _SARISSA_IEPREFIX4XSLPARAM = "";
-var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
-var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
-var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
-var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
-var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));
-var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1;
-if(!window.Node || !window.Node.ELEMENT_NODE){
- var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
-};
-
-// IE initialization
-if(_SARISSA_IS_IE){
- // for XSLT parameter names, prefix needed by IE
- _SARISSA_IEPREFIX4XSLPARAM = "xsl:";
- // used to store the most recent ProgID available out of the above
- var _SARISSA_DOM_PROGID = "";
- var _SARISSA_XMLHTTP_PROGID = "";
- /**
- * Called when the Sarissa_xx.js file is parsed, to pick most recent
- * ProgIDs for IE, then gets destroyed.
- * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
- * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
- */
- pickRecentProgID = function (idList, enabledList){
- // found progID flag
- var bFound = false;
- for(var i=0; i < idList.length && !bFound; i++){
- try{
- var oDoc = new ActiveXObject(idList[i]);
- o2Store = idList[i];
- bFound = true;
- for(var j=0;j<enabledList.length;j++)
- if(i <= enabledList[j][1])
- Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;
- }catch (objException){
- // trap; try next progID
- };
- };
- if (!bFound)
- throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
- idList = null;
- return o2Store;
- };
- // pick best available MSXML progIDs
- _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);
- _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);
- _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
- _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);
- // we dont need this anymore
- pickRecentProgID = null;
- //============================================
- // Factory methods (IE)
- //============================================
- // see non-IE version
- Sarissa.getDomDocument = function(sUri, sName){
- var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
- // if a root tag name was provided, we need to load it in the DOM
- // object
- if (sName){
- // if needed, create an artifical namespace prefix the way Moz
- // does
- if (sUri){
- oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");
- // don't use the same prefix again
- ++_sarissa_iNsCounter;
- }
- else
- oDoc.loadXML("<" + sName + "/>");
- };
- return oDoc;
- };
- // see non-IE version
- Sarissa.getParseErrorText = function (oDoc) {
- var parseErrorText = Sarissa.PARSED_OK;
- if(oDoc.parseError != 0){
- parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason +
- "\nLocation: " + oDoc.parseError.url +
- "\nLine Number " + oDoc.parseError.line + ", Column " +
- oDoc.parseError.linepos +
- ":\n" + oDoc.parseError.srcText +
- "\n";
- for(var i = 0; i < oDoc.parseError.linepos;i++){
- parseErrorText += "-";
- };
- parseErrorText += "^\n";
- };
- return parseErrorText;
- };
- // see non-IE version
- Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
- oDoc.setProperty("SelectionLanguage", "XPath");
- oDoc.setProperty("SelectionNamespaces", sNsSet);
- };
- /**
- * Basic implementation of Mozilla's XSLTProcessor for IE.
- * Reuses the same XSLT stylesheet for multiple transforms
- * @constructor
- */
- XSLTProcessor = function(){
- this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
- this.processor = null;
- };
- /**
- * Impoprts the given XSLT DOM and compiles it to a reusable transform
- * @argument xslDoc The XSLT DOMDocument to import
- */
- XSLTProcessor.prototype.importStylesheet = function(xslDoc){
- // convert stylesheet to free threaded
- var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID);
- converted.loadXML(xslDoc.xml);
- this.template.stylesheet = converted;
- this.processor = this.template.createProcessor();
- // (re)set default param values
- this.paramsSet = new Array();
- };
- /**
- * Transform the given XML DOM
- * @argument sourceDoc The XML DOMDocument to transform
- * @return The transformation result as a DOM Document
- */
- XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
- this.processor.input = sourceDoc;
- var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
- this.processor.output = outDoc;
- this.processor.transform();
- return outDoc;
- };
- /**
- * Set global XSLT parameter of the imported stylesheet
- * @argument nsURI The parameter namespace URI
- * @argument name The parameter base name
- * @argument value The new parameter value
- */
- XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
- /* nsURI is optional but cannot be null */
- if(nsURI){
- this.processor.addParameter(name, value, nsURI);
- }else{
- this.processor.addParameter(name, value);
- };
- /* update updated params for getParameter */
- if(!this.paramsSet[""+nsURI]){
- this.paramsSet[""+nsURI] = new Array();
- };
- this.paramsSet[""+nsURI][name] = value;
- };
- /**
- * Gets a parameter if previously set by setParameter. Returns null
- * otherwise
- * @argument name The parameter base name
- * @argument value The new parameter value
- * @return The parameter value if reviously set by setParameter, null otherwise
- */
- XSLTProcessor.prototype.getParameter = function(nsURI, name){
- nsURI = nsURI || "";
- if(nsURI in this.paramsSet && name in this.paramsSet[nsURI]){
- return this.paramsSet[nsURI][name];
- }else{
- return null;
- };
- };
-}
-else{ /* end IE initialization, try to deal with real browsers now ;-) */
- if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
- /**
- * <p>Ensures the document was loaded correctly, otherwise sets the
- * parseError to -1 to indicate something went wrong. Internal use</p>
- * @private
- */
- Sarissa.__handleLoad__ = function(oDoc){
- if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")
- oDoc.parseError = -1;
- Sarissa.__setReadyState__(oDoc, 4);
- };
- /**
- * <p>Attached by an event handler to the load event. Internal use.</p>
- * @private
- */
- _sarissa_XMLDocument_onload = function(){
- Sarissa.__handleLoad__(this);
- };
- /**
- * <p>Sets the readyState property of the given DOM Document object.
- * Internal use.</p>
- * @private
- * @argument oDoc the DOM Document object to fire the
- * readystatechange event
- * @argument iReadyState the number to change the readystate property to
- */
- Sarissa.__setReadyState__ = function(oDoc, iReadyState){
- oDoc.readyState = iReadyState;
- if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
- oDoc.onreadystatechange();
- };
- Sarissa.getDomDocument = function(sUri, sName){
- var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
- oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
- return oDoc;
- };
- if(false && window.XMLDocument){
- /**
- * <p>Emulate IE's onreadystatechange attribute</p>
- */
- XMLDocument.prototype.onreadystatechange = null;
- /**
- * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
- * <ul><li>1 == LOADING,</li>
- * <li>2 == LOADED,</li>
- * <li>3 == INTERACTIVE,</li>
- * <li>4 == COMPLETED</li></ul>
- */
- XMLDocument.prototype.readyState = 0;
- /**
- * <p>Emulate IE's parseError attribute</p>
- */
- XMLDocument.prototype.parseError = 0;
-
- // NOTE: setting async to false will only work with documents
- // called over HTTP (meaning a server), not the local file system,
- // unless you are using Moz 1.4+.
- // BTW the try>catch block is for 1.4; I haven't found a way to check if
- // the property is implemented without
- // causing an error and I dont want to use user agent stuff for that...
- var _SARISSA_SYNC_NON_IMPLEMENTED = false;// ("async" in XMLDocument.prototype) ? false: true;
- /**
- * <p>Keeps a handle to the original load() method. Internal use and only
- * if Mozilla version is lower than 1.4</p>
- * @private
- */
- XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;
-
- /**
- * <p>Overrides the original load method to provide synchronous loading for
- * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if
- * async is set to false)</p>
- * @returns the DOM Object as it was before the load() call (may be empty)
- */
- XMLDocument.prototype.load = function(sURI) {
- var oDoc = document.implementation.createDocument("", "", null);
- Sarissa.copyChildNodes(this, oDoc);
- this.parseError = 0;
- Sarissa.__setReadyState__(this, 1);
- try {
- if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {
- var tmp = new XMLHttpRequest();
- tmp.open("GET", sURI, false);
- tmp.send(null);
- Sarissa.__setReadyState__(this, 2);
- Sarissa.copyChildNodes(tmp.responseXML, this);
- Sarissa.__setReadyState__(this, 3);
- }
- else {
- this._sarissa_load(sURI);
- };
- }
- catch (objException) {
- this.parseError = -1;
- }
- finally {
- if(this.async == false){
- Sarissa.__handleLoad__(this);
- };
- };
- return oDoc;
- };
-
-
- }//if(window.XMLDocument)
- else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){
- Document.prototype.async = true;
- Document.prototype.onreadystatechange = null;
- Document.prototype.parseError = 0;
- Document.prototype.load = function(sURI) {
- var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);
- if(this.async){
- var self = this;
- parser.addEventListener("load",
- function(e) {
- self.readyState = 4;
- Sarissa.copyChildNodes(e.newDocument, self.documentElement, false);
- self.onreadystatechange.call();
- },
- false);
- };
- try {
- var oDoc = parser.parseURI(sURI);
- }
- catch(e){
- this.parseError = -1;
- };
- if(!this.async)
- Sarissa.copyChildNodes(oDoc, this.documentElement, false);
- return oDoc;
- };
- /**
- * <p>Factory method to obtain a new DOM Document object</p>
- * @argument sUri the namespace of the root node (if any)
- * @argument sUri the local name of the root node (if any)
- * @returns a new DOM Document
- */
- Sarissa.getDomDocument = function(sUri, sName){
- return document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
- };
- };
- };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
-};
-//==========================================
-// Common stuff
-//==========================================
-if(!window.DOMParser){
- /*
- * DOMParser is a utility class, used to construct DOMDocuments from XML strings
- * @constructor
- */
- DOMParser = function() {
- };
- if(_SARISSA_IS_SAFARI){
- /**
- * Construct a new DOM Document from the given XMLstring
- * @param sXml the given XML string
- * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml).
- * @return a new DOM Document from the given XML string
- */
- DOMParser.prototype.parseFromString = function(sXml, contentType){
- if(contentType.toLowerCase() != "application/xml"){
- throw "Cannot handle content type: \"" + contentType + "\"";
- };
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(str), false);
- xmlhttp.send(null);
- return xmlhttp.responseXML;
- };
- }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && "loadXML" in Sarissa.getDomDocument()){
- DOMParser.prototype.parseFromString = function(sXml, contentType){
- var doc = Sarissa.getDomDocument();
- doc.loadXML(sXml);
- return doc;
- };
- };
-};
-
-if(window.XMLHttpRequest){
- Sarissa.IS_ENABLED_XMLHTTP = true;
-}
-else if(_SARISSA_IS_IE){
- /**
- * Emulate XMLHttpRequest
- * @constructor
- */
- XMLHttpRequest = function() {
- return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
- };
- Sarissa.IS_ENABLED_XMLHTTP = true;
-};
-
-if(!window.document.importNode && _SARISSA_IS_IE){
- try{
- /**
- * Implements importNode for the current window document in IE using innerHTML.
- * Testing showed that DOM was multiple times slower than innerHTML for this,
- * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)
- * please gimme a call.
- * @param oNode the Node to import
- * @param bChildren whether to include the children of oNode
- * @returns the imported node for further use
- */
- window.document.importNode = function(oNode, bChildren){
- var importNode = document.createElement("div");
- if(bChildren)
- importNode.innerHTML = Sarissa.serialize(oNode);
- else
- importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));
- return importNode.firstChild;
- };
- }catch(e){};
-};
-if(!Sarissa.getParseErrorText){
- /**
- * <p>Returns a human readable description of the parsing error. Usefull
- * for debugging. Tip: append the returned error string in a &lt;pre&gt;
- * element if you want to render it.</p>
- * <p>Many thanks to Christian Stocker for the initial patch.</p>
- * @argument oDoc The target DOM document
- * @returns The parsing error description of the target Document in
- * human readable form (preformated text)
- */
- Sarissa.getParseErrorText = function (oDoc){
- var parseErrorText = Sarissa.PARSED_OK;
- if(oDoc && oDoc.parseError && oDoc.parseError != 0){
- /*moz*/
- if(oDoc.documentElement.tagName == "parsererror"){
- parseErrorText = oDoc.documentElement.firstChild.data;
- parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data;
- }/*konq*/
- else{
- parseErrorText = Sarissa.getText(oDoc.documentElement);/*.getElementsByTagName("h1")[0], false) + "\n";
- parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";
- parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);*/
- };
- };
- return parseErrorText;
- };
-};
-Sarissa.getText = function(oNode, deep){
- var s = "";
- var nodes = oNode.childNodes;
- for(var i=0; i < nodes.length; i++){
- var node = nodes[i];
- var nodeType = node.nodeType;
- if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
- s += node.data;
- }else if(deep == true
- && (nodeType == Node.ELEMENT_NODE
- || nodeType == Node.DOCUMENT_NODE
- || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
- s += Sarissa.getText(node, true);
- };
- };
- return s;
-};
-if(window.XMLSerializer){
- /**
- * <p>Factory method to obtain the serialization of a DOM Node</p>
- * @returns the serialized Node as an XML string
- */
- Sarissa.serialize = function(oDoc){
- var s = null;
- if(oDoc){
- s = oDoc.innerHTML?oDoc.innerHTML:(new XMLSerializer()).serializeToString(oDoc);
- };
- return s;
- };
-}else{
- if(Sarissa.getDomDocument && (Sarissa.getDomDocument("","foo", null)).xml){
- // see non-IE version
- Sarissa.serialize = function(oDoc) {
- var s = null;
- if(oDoc){
- s = oDoc.innerHTML?oDoc.innerHTML:oDoc.xml;
- };
- return s;
- };
- /**
- * Utility class to serialize DOM Node objects to XML strings
- * @constructor
- */
- XMLSerializer = function(){};
- /**
- * Serialize the given DOM Node to an XML string
- * @param oNode the DOM Node to serialize
- */
- XMLSerializer.prototype.serializeToString = function(oNode) {
- return oNode.xml;
- };
- };
-};
-
-/**
- * strips tags from a markup string
- */
-Sarissa.stripTags = function (s) {
- return s.replace(/<[^>]+>/g,"");
-};
-/**
- * <p>Deletes all child nodes of the given node</p>
- * @argument oNode the Node to empty
- */
-Sarissa.clearChildNodes = function(oNode) {
- // need to check for firstChild due to opera 8 bug with hasChildNodes
- while(oNode.firstChild){
- oNode.removeChild(oNode.firstChild);
- };
-};
-/**
- * <p> Copies the childNodes of nodeFrom to nodeTo</p>
- * <p> <b>Note:</b> The second object's original content is deleted before
- * the copy operation, unless you supply a true third parameter</p>
- * @argument nodeFrom the Node to copy the childNodes from
- * @argument nodeTo the Node to copy the childNodes to
- * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false
- */
-Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
- if((!nodeFrom) || (!nodeTo)){
- throw "Both source and destination nodes must be provided";
- };
- if(!bPreserveExisting){
- Sarissa.clearChildNodes(nodeTo);
- };
- var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
- var nodes = nodeFrom.childNodes;
- if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
- for(var i=0;i < nodes.length;i++) {
- nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
- };
- }
- else{
- for(var i=0;i < nodes.length;i++) {
- nodeTo.appendChild(nodes[i].cloneNode(true));
- };
- };
-};
-
-/**
- * <p> Moves the childNodes of nodeFrom to nodeTo</p>
- * <p> <b>Note:</b> The second object's original content is deleted before
- * the move operation, unless you supply a true third parameter</p>
- * @argument nodeFrom the Node to copy the childNodes from
- * @argument nodeTo the Node to copy the childNodes to
- * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is
- */
-Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
- if((!nodeFrom) || (!nodeTo)){
- throw "Both source and destination nodes must be provided";
- };
- if(!bPreserveExisting){
- Sarissa.clearChildNodes(nodeTo);
- };
- var nodes = nodeFrom.childNodes;
- // if within the same doc, just move, else copy and delete
- if(nodeFrom.ownerDocument == nodeTo.ownerDocument){
- while(nodeFrom.firstChild){
- nodeTo.appendChild(nodeFrom.firstChild);
- };
- }else{
- var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
- if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
- for(var i=0;i < nodes.length;i++) {
- nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
- };
- }else{
- for(var i=0;i < nodes.length;i++) {
- nodeTo.appendChild(nodes[i].cloneNode(true));
- };
- };
- Sarissa.clearChildNodes(nodeFrom);
- };
-};
-
-/**
- * <p>Serialize any object to an XML string. All properties are serialized using the property name
- * as the XML element name. Array elements are rendered as <code>array-item</code> elements,
- * using their index/key as the value of the <code>key</code> attribute.</p>
- * @argument anyObject the object to serialize
- * @argument objectName a name for that object
- * @return the XML serializationj of the given object as a string
- */
-Sarissa.xmlize = function(anyObject, objectName, indentSpace){
- indentSpace = indentSpace?indentSpace:'';
- var s = indentSpace + '<' + objectName + '>';
- var isLeaf = false;
- if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String
- || anyObject instanceof Boolean || anyObject instanceof Date){
- s += Sarissa.escape(""+anyObject);
- isLeaf = true;
- }else{
- s += "\n";
- var itemKey = '';
- var isArrayItem = anyObject instanceof Array;
- for(var name in anyObject){
- s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + " ");
- };
- s += indentSpace;
- };
- return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
-};
-
-/**
- * Escape the given string chacters that correspond to the five predefined XML entities
- * @param sXml the string to escape
- */
-Sarissa.escape = function(sXml){
- return sXml.replace(/&/g, "&amp;")
- .replace(/</g, "&lt;")
- .replace(/>/g, "&gt;")
- .replace(/"/g, "&quot;")
- .replace(/'/g, "&apos;");
-};
-
-/**
- * Unescape the given string. This turns the occurences of the predefined XML
- * entities to become the characters they represent correspond to the five predefined XML entities
- * @param sXml the string to unescape
- */
-Sarissa.unescape = function(sXml){
- return sXml.replace(/&apos;/g,"'")
- .replace(/&quot;/g,"\"")
- .replace(/&gt;/g,">")
- .replace(/&lt;/g,"<")
- .replace(/&amp;/g,"&");
-};
-// EOF
diff --git a/tools/ajaxterm/sarissa_dhtml.js b/tools/ajaxterm/sarissa_dhtml.js
deleted file mode 100644
index 2d85c817e..000000000
--- a/tools/ajaxterm/sarissa_dhtml.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * ====================================================================
- * About
- * ====================================================================
- * Sarissa cross browser XML library - AJAX module
- * @version 0.9.6.1
- * @author: Copyright Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
- *
- * This module contains some convinient AJAX tricks based on Sarissa
- *
- * ====================================================================
- * Licence
- * ====================================================================
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 or
- * the GNU Lesser General Public License version 2.1 as published by
- * the Free Software Foundation (your choice between the two).
- *
- * 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 or GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * or GNU Lesser General Public License along with this program; if not,
- * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * or visit http://www.gnu.org
- *
- */
-/**
- * Update an element with response of a GET request on the given URL.
- * @addon
- * @param sFromUrl the URL to make the request to
- * @param oTargetElement the element to update
- * @param xsltproc (optional) the transformer to use on the returned
- * content before updating the target element with it
- */
-Sarissa.updateContentFromURI = function(sFromUrl, oTargetElement, xsltproc) {
- try{
- oTargetElement.style.cursor = "wait";
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open("GET", sFromUrl);
- function sarissa_dhtml_loadHandler() {
- if (xmlhttp.readyState == 4) {
- oTargetElement.style.cursor = "auto";
- Sarissa.updateContentFromNode(xmlhttp.responseXML, oTargetElement, xsltproc);
- };
- };
- xmlhttp.onreadystatechange = sarissa_dhtml_loadHandler;
- xmlhttp.send(null);
- oTargetElement.style.cursor = "auto";
- }
- catch(e){
- oTargetElement.style.cursor = "auto";
- throw e;
- };
-};
-
-/**
- * Update an element's content with the given DOM node.
- * @addon
- * @param sFromUrl the URL to make the request to
- * @param oTargetElement the element to update
- * @param xsltproc (optional) the transformer to use on the given
- * DOM node before updating the target element with it
- */
-Sarissa.updateContentFromNode = function(oNode, oTargetElement, xsltproc) {
- try {
- oTargetElement.style.cursor = "wait";
- Sarissa.clearChildNodes(oTargetElement);
- // check for parsing errors
- var ownerDoc = oNode.nodeType == Node.DOCUMENT_NODE?oNode:oNode.ownerDocument;
- if(ownerDoc.parseError && ownerDoc.parseError != 0) {
- var pre = document.createElement("pre");
- pre.appendChild(document.createTextNode(Sarissa.getParseErrorText(ownerDoc)));
- oTargetElement.appendChild(pre);
- }
- else {
- // transform if appropriate
- if(xsltproc) {
- oNode = xsltproc.transformToDocument(oNode);
- };
- // be smart, maybe the user wants to display the source instead
- if(oTargetElement.tagName.toLowerCase == "textarea" || oTargetElement.tagName.toLowerCase == "input") {
- oTargetElement.value = Sarissa.serialize(oNode);
- }
- else {
- // ok that was not smart; it was paranoid. Keep up the good work by trying to use DOM instead of innerHTML
- if(oNode.nodeType == Node.DOCUMENT_NODE || oNode.ownerDocument.documentElement == oNode) {
- oTargetElement.innerHTML = Sarissa.serialize(oNode);
- }
- else{
- oTargetElement.appendChild(oTargetElement.ownerDocument.importNode(oNode, true));
- };
- };
- };
- }
- catch(e) {
- throw e;
- }
- finally{
- oTargetElement.style.cursor = "auto";
- };
-};
-
diff --git a/tools/euca-get-ajax-console b/tools/euca-get-ajax-console
deleted file mode 100755
index 26236f1d9..000000000
--- a/tools/euca-get-ajax-console
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=C0103
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Euca add-on to use ajax console"""
-
-import getopt
-import os
-import sys
-
-# If ../nova/__init__.py exists, add ../ to Python search path, so that
-# it will override what happens to be installed in /usr/(local/)lib/python...
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
- sys.path.insert(0, possible_topdir)
-
-import boto
-import nova
-import boto.ec2.connection
-import euca2ools
-
-usage_string = """
-Retrieves a url to an ajax console terminal
-
-euca-get-ajax-console [-h, --help] [--version] [--debug] instance_id
-
-REQUIRED PARAMETERS
-
-instance_id: unique identifier for the instance show the console output for.
-
-OPTIONAL PARAMETERS
-
-"""
-
-
-# This class extends boto to add AjaxConsole functionality
-class NovaEC2Connection(boto.ec2.connection.EC2Connection):
-
- def get_ajax_console(self, instance_id):
- """
- Retrieves a console connection for the specified instance.
-
- :type instance_id: string
- :param instance_id: The instance ID of a running instance on the cloud.
-
- :rtype: :class:`AjaxConsole`
- """
-
- class AjaxConsole:
- def __init__(self, parent=None):
- self.parent = parent
- self.instance_id = None
- self.url = None
-
- def startElement(self, name, attrs, connection):
- return None
-
- def endElement(self, name, value, connection):
- if name == 'instanceId':
- self.instance_id = value
- elif name == 'url':
- self.url = value
- else:
- setattr(self, name, value)
-
- params = {}
- self.build_list_params(params, [instance_id], 'InstanceId')
- return self.get_object('GetAjaxConsole', params, AjaxConsole)
- pass
-
-
-def override_connect_ec2(aws_access_key_id=None,
- aws_secret_access_key=None, **kwargs):
- return NovaEC2Connection(aws_access_key_id,
- aws_secret_access_key, **kwargs)
-
-# override boto's connect_ec2 method, so that we can use NovaEC2Connection
-# (This is for Euca2ools 1.2)
-boto.connect_ec2 = override_connect_ec2
-
-# Override Euca2ools' EC2Connection class (which it gets from boto)
-# (This is for Euca2ools 1.3)
-euca2ools.EC2Connection = NovaEC2Connection
-
-
-def usage(status=1):
- print usage_string
- euca2ools.Util().usage()
- sys.exit(status)
-
-
-def version():
- print euca2ools.Util().version()
- sys.exit()
-
-
-def display_console_output(console_output):
- print console_output.instance_id
- print console_output.timestamp
- print console_output.output
-
-
-def display_ajax_console_output(console_output):
- print console_output.url
-
-
-def main():
- try:
- euca = euca2ools.Euca2ool()
- except Exception, e:
- print e
- usage()
-
- instance_id = None
-
- for name, value in euca.opts:
- if name in ('-h', '--help'):
- usage(0)
- elif name == '--version':
- version()
- elif name == '--debug':
- debug = True
-
- for arg in euca.args:
- instance_id = arg
- break
-
- if instance_id:
- try:
- euca.validate_instance_id(instance_id)
- except euca2ools.InstanceValidationError:
- print 'Invalid instance id'
- sys.exit(1)
-
- try:
- euca_conn = euca.make_connection()
- except Exception, e:
- print e.message
- sys.exit(1)
- try:
- console_output = euca_conn.get_ajax_console(instance_id)
- except Exception, ex:
- euca.display_error_and_exit('%s' % ex)
-
- display_ajax_console_output(console_output)
- else:
- print 'instance_id must be specified'
- usage()
-
-if __name__ == "__main__":
- main()