diff --git a/activities/browser/BrowserActivity.py b/activities/browser/BrowserActivity.py
index 0068f20c..53cf37ba 100644
--- a/activities/browser/BrowserActivity.py
+++ b/activities/browser/BrowserActivity.py
@@ -26,13 +26,53 @@ class BrowserActivity(Activity):
def __init__(self, args):
Activity.__init__(self, _BROWSER_ACTIVITY_TYPE)
- self.uri = args[0]
+ if len(args) > 0:
+ self.uri = args[0]
+ else:
+ self.uri = 'http://www.google.com'
self._mode = BrowserActivity.SOLO
self._share_service = None
self._model_service = None
self._notif_service = None
self._model = None
+
+ self.set_title("Web Page")
+
+ vbox = gtk.VBox()
+
+ self._notif_bar = NotificationBar()
+ vbox.pack_start(self._notif_bar, False)
+ self._notif_bar.connect('action', self.__notif_bar_action_cb)
+
+ self.embed = geckoembed.Embed()
+ self.embed.connect("title", self.__title_cb)
+ vbox.pack_start(self.embed)
+
+ self.embed.show()
+ self.embed.load_address(self.uri)
+
+ nav_toolbar = NavigationToolbar(self)
+ vbox.pack_start(nav_toolbar, False)
+ nav_toolbar.show()
+
+ self.add(vbox)
+ vbox.show()
+
+ logging.debug('Start presence service')
+ self._pservice = PresenceService.get_instance()
+ self._pservice.start()
+
+ logging.debug('Track browser activities')
+ self._pservice.connect('service-appeared', self._service_appeared_cb)
+ self._pservice.track_service_type(_BROWSER_ACTIVITY_TYPE)
+ self._pservice.track_service_type(LocalModel.SERVICE_TYPE)
+
+ # Join the shared activity if we were started from one
+ if self._initial_service:
+ logging.debug("BrowserActivity joining shared activity %s" %
+ self._initial_service.get_activity_id())
+ self._pservice.join_shared_activity(self._initial_service)
def _service_appeared_cb(self, pservice, buddy, service):
# Make sure the service is for our activity
@@ -75,50 +115,6 @@ class BrowserActivity(Activity):
self._notif_bar.set_icon('stock_shared-by-me')
self._notif_bar.show()
- def on_connected_to_shell(self):
- self.set_ellipsize_tab(True)
- self.set_can_close(True)
- self.set_tab_text("Web Page")
- self.set_tab_icon(name="web-browser")
- self.set_show_tab_icon(True)
-
- vbox = gtk.VBox()
-
- self._notif_bar = NotificationBar()
- vbox.pack_start(self._notif_bar, False)
- self._notif_bar.connect('action', self.__notif_bar_action_cb)
-
- self.embed = geckoembed.Embed()
- self.embed.connect("title", self.__title_cb)
- vbox.pack_start(self.embed)
-
- self.embed.show()
- self.embed.load_address(self.uri)
-
- nav_toolbar = NavigationToolbar(self)
- vbox.pack_start(nav_toolbar, False)
- nav_toolbar.show()
-
- plug = self.gtk_plug()
- plug.add(vbox)
- plug.show()
-
- vbox.show()
-
- logging.debug('Start presence service')
- self._pservice = PresenceService.get_instance()
- self._pservice.start()
-
- logging.debug('Track browser activities')
- self._pservice.connect('service-appeared', self._service_appeared_cb)
- self._pservice.track_service_type(_BROWSER_ACTIVITY_TYPE)
- self._pservice.track_service_type(LocalModel.SERVICE_TYPE)
-
- # Join the shared activity if we were started from one
- if self._initial_service:
- logging.debug("BrowserActivity joining shared activity %s" % self._initial_service.get_activity_id())
- self._pservice.join_shared_activity(self._initial_service)
-
def get_embed(self):
return self.embed
@@ -139,7 +135,7 @@ class BrowserActivity(Activity):
self.set_mode(BrowserActivity.LEADING)
def __title_cb(self, embed):
- self.set_tab_text(embed.get_title())
+ self.set_title(embed.get_title())
def __shared_location_changed_cb(self, model, key):
self.set_has_changes(True)
diff --git a/shell/ActivityContainer.py b/shell/ActivityContainer.py
deleted file mode 100644
index 1e48b955..00000000
--- a/shell/ActivityContainer.py
+++ /dev/null
@@ -1,167 +0,0 @@
-import dbus
-import gobject
-import gtk
-from gettext import gettext as _
-
-from sugar.chat.ChatWindow import ChatWindow
-from sugar.chat.MeshChat import MeshChat
-from ActivityHost import ActivityHost
-from PresenceWindow import PresenceWindow
-from WindowManager import WindowManager
-from StartPage import StartPage
-from Owner import ShellOwner
-
-class ActivityContainerSignalHelper(gobject.GObject):
- """A gobject whose sole purpose is to distribute signals for
- an ActivityContainer object."""
-
- __gsignals__ = {
- 'local-activity-started': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
- 'local-activity-ended': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, parent):
- gobject.GObject.__init__(self)
- self._parent = parent
-
- def activity_started(self, activity_id):
- self.emit('local-activity-started', self._parent, activity_id)
-
- def activity_ended(self, activity_id):
- self.emit('local-activity-ended', self._parent, activity_id)
-
-class ActivityContainer(dbus.service.Object):
-
- def __init__(self, service, bus):
- self.activities = []
-
- self.bus = bus
- self.service = service
-
- self._signal_helper = ActivityContainerSignalHelper(self)
-
- dbus.service.Object.__init__(self, self.service, "/com/redhat/Sugar/Shell/ActivityContainer")
- bus.add_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
-
- self.window = gtk.Window()
- self.window.connect("key-press-event", self.__key_press_event_cb)
- self.window.set_title("OLPC Sugar")
-
- self._fullscreen = False
-
- self.notebook = gtk.Notebook()
- self.notebook.set_scrollable(True)
-
- tab_label = gtk.Label(_("Everyone"))
- self._start_page = StartPage(self, self._signal_helper)
- self.notebook.append_page(self._start_page, tab_label)
- self._start_page.show()
-
- self.notebook.show()
- self.notebook.connect("switch-page", self.notebook_tab_changed)
- self.window.add(self.notebook)
-
- self.window.connect("destroy", lambda w: gtk.main_quit())
-
- self.current_activity = None
-
- # Create our owner service
- self._owner = ShellOwner()
-
- self._presence_window = PresenceWindow(self)
- self._presence_window.set_transient_for(self.window)
-
- wm = WindowManager(self._presence_window)
- wm.set_type(WindowManager.TYPE_POPUP)
- wm.set_animation(WindowManager.ANIMATION_SLIDE_IN)
- wm.set_geometry(0.02, 0.1, 0.25, 0.9)
- wm.set_key(gtk.keysyms.F1)
-
- self._chat_window = ChatWindow()
- self._chat_window.set_transient_for(self.window)
-
- self._chat_wm = WindowManager(self._chat_window)
- self._chat_wm.set_animation(WindowManager.ANIMATION_SLIDE_IN)
- self._chat_wm.set_type(WindowManager.TYPE_POPUP)
- self._chat_wm.set_geometry(0.28, 0.1, 0.5, 0.9)
- self._chat_wm.set_key(gtk.keysyms.F1)
-
- self._mesh_chat = MeshChat()
-
- def show(self):
- self.window.show()
-
- def set_current_activity(self, activity):
- self.current_activity = activity
- self._presence_window.set_activity(activity)
-
- if activity:
- host_chat = activity.get_chat()
- self._chat_window.set_chat(host_chat)
- else:
- self._chat_window.set_chat(self._mesh_chat)
-
- def notebook_tab_changed(self, notebook, page, page_number):
- new_activity = notebook.get_nth_page(page_number).get_data("sugar-activity")
-
- if self.current_activity != None:
- self.current_activity.lost_focus()
-
- self.set_current_activity(new_activity)
-
- if self.current_activity != None:
- self.current_activity.got_focus()
-
- def name_owner_changed(self, service_name, old_service_name, new_service_name):
- #print "in name_owner_changed: svc=%s oldsvc=%s newsvc=%s"%(service_name, old_service_name, new_service_name)
- for owner, activity in self.activities[:]:
- if owner == old_service_name:
- activity_id = activity.get_host_activity_id()
- self._signal_helper.activity_ended(activity_id)
- self.activities.remove((owner, activity))
- #self.__print_activities()
-
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
- in_signature="ss", \
- out_signature="s", \
- sender_keyword="sender")
- def add_activity(self, activity_name, default_type, sender):
- #print "hello world, activity_name = '%s', sender = '%s'"%(activity_name, sender)
- activity = ActivityHost(self, activity_name, default_type)
- self.activities.append((sender, activity))
-
- activity_id = activity.get_host_activity_id()
- self._signal_helper.activity_started(activity_id)
-
- self.current_activity = activity
- return activity_id
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
- in_signature="sss", \
- sender_keyword="sender")
- def add_activity_with_id(self, activity_name, default_type, activity_id, sender):
- activity = ActivityHost(self, activity_name, default_type, activity_id)
- self.activities.append((sender, activity))
- activity_id = activity.get_host_activity_id()
- self._signal_helper.activity_started(activity_id)
- self.current_activity = activity
-
- def __print_activities(self):
- print "__print_activities: %d activities registered" % len(self.activities)
- i = 0
- for owner, activity in self.activities:
- print " %d: owner=%s activity_object_name=%s" % (i, owner, activity.dbus_object_name)
- i += 1
-
- def __key_press_event_cb(self, window, event):
- if event.keyval == gtk.keysyms.F11:
- if self._fullscreen:
- window.unfullscreen()
- self._fullscreen = False
- else:
- window.fullscreen()
- self._fullscreen = True
-
diff --git a/shell/ActivityHost.py b/shell/ActivityHost.py
deleted file mode 100644
index 1d61bebf..00000000
--- a/shell/ActivityHost.py
+++ /dev/null
@@ -1,269 +0,0 @@
-import dbus
-import gtk
-import gobject
-
-class ActivityHostSignalHelper(gobject.GObject):
- __gsignals__ = {
- 'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
- }
-
- def __init__(self, parent):
- gobject.GObject.__init__(self)
- self._parent = parent
-
- def emit_shared(self):
- self.emit('shared')
-
-class ActivityHost(dbus.service.Object):
- def __init__(self, activity_container, activity_name, default_type, activity_id = None):
- self.peer_service = None
-
- self.activity_name = activity_name
- self.ellipsize_tab = False
- self._shared = False
-
- self._signal_helper = ActivityHostSignalHelper(self)
-
- self.activity_container = activity_container
-
- if activity_id is None:
- self.activity_id = sugar.util.unique_id()
- else:
- self.activity_id = activity_id
- self._default_type = default_type
-
- self.dbus_object_name = "/com/redhat/Sugar/Shell/Activities/%s" % self.activity_id
-
- dbus.service.Object.__init__(self, activity_container.service, self.dbus_object_name)
- self.socket = gtk.Socket()
- self.socket.set_data("sugar-activity", self)
- self.socket.show()
-
- hbox = gtk.HBox(False, 4);
-
- self.tab_activity_image = gtk.Image()
- self.tab_activity_image.set_from_stock(gtk.STOCK_CONVERT, gtk.ICON_SIZE_MENU)
- hbox.pack_start(self.tab_activity_image)
- #self.tab_activity_image.show()
-
- self.label_hbox = gtk.HBox(False, 4);
- self.label_hbox.connect("style-set", self.__tab_label_style_set_cb)
- hbox.pack_start(self.label_hbox)
-
- self.tab_label = gtk.Label(self.activity_name)
- self.tab_label.set_single_line_mode(True)
- self.tab_label.set_alignment(0.0, 0.5)
- self.tab_label.set_padding(0, 0)
- self.tab_label.show()
-
- close_image = gtk.Image()
- close_image.set_from_stock (gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
- close_image.show()
-
- self.tab_close_button = gtk.Button()
- rcstyle = gtk.RcStyle();
- rcstyle.xthickness = rcstyle.ythickness = 0;
- self.tab_close_button.modify_style (rcstyle);
- self.tab_close_button.add(close_image)
- self.tab_close_button.set_relief(gtk.RELIEF_NONE)
- self.tab_close_button.set_focus_on_click(False)
- self.tab_close_button.connect("clicked", self.tab_close_button_clicked)
-
- self.label_hbox.pack_start(self.tab_label)
- self.label_hbox.pack_start(self.tab_close_button, False, False, 0)
- self.label_hbox.show()
-
- hbox.show()
-
- self._create_chat()
-
- notebook = self.activity_container.notebook
- index = notebook.append_page(self.socket, hbox)
- notebook.set_current_page(index)
-
- def _create_chat(self):
- self._activity_chat = ActivityChat(self)
-
- def got_focus(self):
- if self.peer_service != None:
- self.peer_service.got_focus()
-
- def lost_focus(self):
- self.peer_service.lost_focus()
-
- def get_chat(self):
- return self._activity_chat
-
- def get_default_type(self):
- return self._default_type
-
- def __close_button_clicked_reply_cb(self):
- pass
-
- def __close_button_clicked_error_cb(self, error):
- pass
-
- def publish(self):
- self._activity_chat.publish()
- self.peer_service.publish()
-
- def tab_close_button_clicked(self, button):
- self.peer_service.close_from_user(reply_handler = self.__close_button_clicked_reply_cb, \
- error_handler = self.__close_button_clicked_error_cb)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="", \
- out_signature="t")
- def get_host_xembed_id(self):
- window_id = self.socket.get_id()
- #print "window_id = %d"%window_id
- return window_id
-
- def connect(self, signal, func):
- self._signal_helper.connect(signal, func)
-
- def get_shared(self):
- """Return True if this activity is shared, False if
- it has not been shared yet."""
- return self._shared
-
- def _shared_signal(self):
- self._shared = True
- self._signal_helper.emit_shared()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="ss", \
- out_signature="")
- def set_peer_service_name(self, peer_service_name, peer_object_name):
- #print "peer_service_name = %s, peer_object_name = %s"%(peer_service_name, peer_object_name)
- self.__peer_service_name = peer_service_name
- self.__peer_object_name = peer_object_name
- self.peer_service = dbus.Interface(self.activity_container.bus.get_object( \
- self.__peer_service_name, self.__peer_object_name), \
- "com.redhat.Sugar.Activity")
- self.activity_container.bus.add_signal_receiver(self._shared_signal,
- signal_name="ActivityShared",
- dbus_interface="com.redhat.Sugar.Activity",
- named_service=self.__peer_service_name,
- path=self.__peer_object_name)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_ellipsize_tab(self, ellipsize):
- self.ellipsize_tab = True
- self.update_tab_size()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_can_close(self, can_close):
- if can_close:
- self.tab_close_button.show()
- else:
- self.tab_close_button.hide()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_tab_show_icon(self, show_icon):
- if show_icon:
- self.tab_activity_image.show()
- else:
- self.tab_activity_image.hide()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_has_changes(self, has_changes):
- if has_changes:
- attrs = pango.AttrList()
- attrs.insert(pango.AttrForeground(50000, 0, 0, 0, -1))
- attrs.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
- self.tab_label.set_attributes(attrs)
- else:
- self.tab_label.set_attributes(pango.AttrList())
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="s", \
- out_signature="")
- def set_tab_text(self, text):
- self.tab_label.set_text(text)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="ayibiiii", \
- out_signature="")
- def set_tab_icon(self, data, colorspace, has_alpha, bits_per_sample, width, height, rowstride):
- #print "width=%d, height=%d"%(width, height)
- #print " data = ", data
- pixstr = ""
- for c in data:
- # Work around for a bug in dbus < 0.61 where integers
- # are not correctly marshalled
- if c < 0:
- c += 256
- pixstr += chr(c)
-
- pixbuf = gtk.gdk.pixbuf_new_from_data(pixstr, colorspace, has_alpha, bits_per_sample, width, height, rowstride)
- #print pixbuf
- self.tab_activity_image.set_from_pixbuf(pixbuf)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="", \
- out_signature="")
- def shutdown(self):
- #print "shutdown"
- for owner, activity in self.activity_container.activities[:]:
- if activity == self:
- self.activity_container.activities.remove((owner, activity))
-
- for i in range(self.activity_container.notebook.get_n_pages()):
- child = self.activity_container.notebook.get_nth_page(i)
- if child == self.socket:
- #print "found child"
- self.activity_container.notebook.remove_page(i)
- break
-
- del self
-
- def get_host_activity_id(self):
- """Real function that the shell should use for getting the
- activity's ID."""
- return self.activity_id
-
- def get_id(self):
- """Interface-type function to match activity.Activity's
- get_id() function."""
- return self.activity_id
-
- def default_type(self):
- """Interface-type function to match activity.Activity's
- default_type() function."""
- return self._default_type
-
- def get_object_path(self):
- return self.dbus_object_name
-
- def update_tab_size(self):
- if self.ellipsize_tab:
- self.tab_label.set_ellipsize(pango.ELLIPSIZE_END)
-
- context = self.label_hbox.get_pango_context()
- font_desc = self.label_hbox.style.font_desc
- metrics = context.get_metrics(font_desc, context.get_language())
- char_width = metrics.get_approximate_digit_width()
- [w, h] = self.__get_close_icon_size()
- tab_width = 15 * pango.PIXELS(char_width) + 2 * w
- self.label_hbox.set_size_request(tab_width, -1);
- else:
- self.tab_label.set_ellipsize(pango.ELLIPSIZE_NONE)
- self.label_hbox.set_size_request(-1, -1)
-
- def __get_close_icon_size(self):
- settings = self.label_hbox.get_settings()
- return gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
-
- def __tab_label_style_set_cb(self, widget, previous_style):
- [w, h] = self.__get_close_icon_size()
- self.tab_close_button.set_size_request (w + 5, h + 2)
- self.update_tab_size()
diff --git a/shell/ActivityRegistry.py b/shell/ActivityRegistry.py
new file mode 100644
index 00000000..96ec3b15
--- /dev/null
+++ b/shell/ActivityRegistry.py
@@ -0,0 +1,29 @@
+import dbus
+
+class ActivityInfo:
+ def __init__(self, name, title):
+ self._name = name
+ self._title = title
+
+ def get_name(self):
+ return self._name
+
+ def get_title(self):
+ return self._title
+
+class ActivityRegistry(dbus.service.Object):
+ """Dbus service that tracks the available activities"""
+
+ def __init__(self):
+ self._activities = []
+
+ bus = dbus.SessionBus()
+ bus_name = dbus.service.BusName('com.redhat.Sugar.ActivityRegistry', bus = bus)
+ dbus.service.Object.__init__(self, bus_name, '/com/redhat/Sugar/ActivityRegistry')
+
+ @dbus.service.method("com.redhat.Sugar.ActivityRegistry")
+ def add(self, name, title):
+ self._activities.append(ActivityInfo(name, title))
+
+ def list_activities(self):
+ return self._activities
diff --git a/shell/ConsoleLogger.py b/shell/ConsoleLogger.py
index c9c968f4..fc431ecb 100644
--- a/shell/ConsoleLogger.py
+++ b/shell/ConsoleLogger.py
@@ -1,9 +1,6 @@
import gtk
import dbus
-from WindowManager import WindowManager
-from ActivityContainer import ActivityContainer
-
class ConsoleLogger(dbus.service.Object):
def __init__(self):
session_bus = dbus.SessionBus()
@@ -21,9 +18,8 @@ class ConsoleLogger(dbus.service.Object):
self._consoles = {}
- console_wm = WindowManager(self._window)
- console_wm.set_type(WindowManager.TYPE_POPUP)
- console_wm.set_geometry(0.1, 0.1, 0.8, 0.8)
+ def get_window(self):
+ return self._window
def _create_console(self, application):
sw = gtk.ScrolledWindow()
@@ -51,4 +47,3 @@ class ConsoleLogger(dbus.service.Object):
buf = console.get_buffer()
buf.insert(buf.get_end_iter(), message)
-
diff --git a/shell/HomeWindow.py b/shell/HomeWindow.py
new file mode 100644
index 00000000..f0124b1f
--- /dev/null
+++ b/shell/HomeWindow.py
@@ -0,0 +1,102 @@
+from gettext import gettext as _
+
+import gtk
+import wnck
+
+from sugar.activity import Activity
+
+class NewActivityButton(gtk.MenuToolButton):
+ def __init__(self, home):
+ gtk.MenuToolButton.__init__(self, None, _('New Activity'))
+
+ self._home = home
+
+ self.set_menu(gtk.Menu())
+ self.connect("show-menu", self.__show_menu_cb)
+
+ def __show_menu_cb(self, button):
+ menu = gtk.Menu()
+
+ for activity_info in self._home.list_activities():
+ item = gtk.MenuItem(activity_info.get_title(), False)
+ name = activity_info.get_name()
+ item.connect('activate', self.__menu_item_activate_cb, name)
+ menu.append(item)
+ item.show()
+
+ self.set_menu(menu)
+
+ def __menu_item_activate_cb(self, item, name):
+ self._home.create(name)
+
+class Toolbar(gtk.Toolbar):
+ def __init__(self, shell):
+ gtk.Toolbar.__init__(self)
+
+ new_activity_button = NewActivityButton(shell)
+ self.insert(new_activity_button, -1)
+ new_activity_button.show()
+
+class ActivityGrid(gtk.VBox):
+ def __init__(self, home):
+ gtk.VBox.__init__(self)
+
+ self._home = home
+ self.update()
+
+ def _add_all(self):
+ screen = wnck.screen_get_default()
+ for window in screen.get_windows():
+ if not window.is_skip_tasklist():
+ self.add(window)
+
+ def _remove_all(self):
+ for child in self.get_children():
+ self.remove(child)
+
+ def add(self, window):
+ button = gtk.Button(window.get_name())
+ button.connect('clicked', self.__button_clicked_cb, window)
+ self.pack_start(button, False)
+ button.show()
+
+ def update(self):
+ self._remove_all()
+ self._add_all()
+
+ def __button_clicked_cb(self, button, window):
+ self._home.activate(window)
+
+class HomeWindow(gtk.Window):
+ def __init__(self, shell):
+ gtk.Window.__init__(self)
+
+ self._shell = shell
+
+ vbox = gtk.VBox()
+
+ toolbar = Toolbar(self)
+ vbox.pack_start(toolbar, False)
+ toolbar.show()
+
+ self._grid = ActivityGrid(self)
+ vbox.pack_start(self._grid)
+ self._grid.show()
+
+ self.add(vbox)
+ vbox.show()
+
+ def list_activities(self):
+ return self._shell.get_registry().list_activities()
+
+ def create(self, activity_name):
+ Activity.create(activity_name)
+ self.hide()
+
+ def activate(self, activity_window):
+ activity_window.activate(gtk.get_current_event_time())
+ self.hide()
+
+ def show(self):
+ self._grid.update()
+ gtk.Window.show(self)
diff --git a/shell/PresenceWindow.py b/shell/PresenceWindow.py
index 1f131450..666f86c4 100644
--- a/shell/PresenceWindow.py
+++ b/shell/PresenceWindow.py
@@ -16,11 +16,11 @@ class PresenceWindow(gtk.Window):
_MODEL_COL_BUDDY = 2
_MODEL_COL_VISIBLE = 3
- def __init__(self, activity_container):
+ def __init__(self, shell):
gtk.Window.__init__(self)
- self._activity_container = activity_container
self._activity = None
+ self._shell = shell
self._pservice = PresenceService.get_instance()
self._pservice.connect("buddy-appeared", self._on_buddy_appeared_cb)
@@ -51,7 +51,6 @@ class PresenceWindow(gtk.Window):
self._share_button.set_sensitive(False)
else:
self._share_button.set_sensitive(True)
- self._activity.connect('shared', lambda w: self._share_button.set_sensitive(False))
else:
self._share_button.set_sensitive(False)
@@ -113,7 +112,7 @@ class PresenceWindow(gtk.Window):
vbox.show()
def _share_button_clicked_cb(self, button):
- self._activity_container.current_activity.publish()
+ self._shell.get_current_activity().publish()
def _on_buddyList_buddy_selected(self, view, *args):
(model, aniter) = view.get_selection().get_selected()
diff --git a/shell/Shell.py b/shell/Shell.py
index 025ec80c..d8befd5a 100755
--- a/shell/Shell.py
+++ b/shell/Shell.py
@@ -1,10 +1,37 @@
import dbus
+import gtk
import gobject
+import wnck
from sugar.LogWriter import LogWriter
-from WindowManager import WindowManager
from ConsoleLogger import ConsoleLogger
-from ActivityContainer import ActivityContainer
+from ActivityRegistry import ActivityRegistry
+from HomeWindow import HomeWindow
+from sugar import keybindings
+from sugar.activity import Activity
+from PresenceWindow import PresenceWindow
+from sugar.chat.ActivityChat import ActivityChat
+from Owner import ShellOwner
+
+class ShellDbusService(dbus.service.Object):
+ def __init__(self, shell, bus_name):
+ dbus.service.Object.__init__(self, bus_name, '/com/redhat/Sugar/Shell')
+ self._shell = shell
+
+ def __toggle_people_idle(self):
+ self._shell.toggle_people()
+
+ @dbus.service.method('com.redhat.Sugar.Shell')
+ def toggle_people(self):
+ gobject.idle_add(self.__toggle_people_idle)
+
+ @dbus.service.method('com.redhat.Sugar.Shell')
+ def toggle_home(self):
+ self._shell.toggle_home()
+
+ @dbus.service.method('com.redhat.Sugar.Shell')
+ def toggle_console(self):
+ self._shell.toggle_console()
class Shell(gobject.GObject):
__gsignals__ = {
@@ -15,24 +42,96 @@ class Shell(gobject.GObject):
def __init__(self):
gobject.GObject.__init__(self)
+ self._screen = wnck.screen_get_default()
+
def start(self):
- console = ConsoleLogger()
+ self._console = ConsoleLogger()
+ keybindings.setup_global_keys(self._console.get_window(), self)
log_writer = LogWriter("Shell", False)
log_writer.start()
session_bus = dbus.SessionBus()
- service = dbus.service.BusName("com.redhat.Sugar.Shell", bus=session_bus)
+ bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus)
+ ShellDbusService(self, bus_name)
- activity_container = ActivityContainer(service, session_bus)
- activity_container.window.connect('destroy', self.__activity_container_destroy_cb)
- activity_container.show()
+ self._owner = ShellOwner()
- wm = WindowManager(activity_container.window)
- wm.show()
+ self._registry = ActivityRegistry()
- def __activity_container_destroy_cb(self, activity_container):
- self.emit('close')
+ self._home_window = HomeWindow(self)
+ keybindings.setup_global_keys(self._home_window, self)
+ self._home_window.show()
+
+ self._presence_window = PresenceWindow(self)
+ self._presence_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self._presence_window.set_skip_taskbar_hint(True)
+ self._presence_window.set_decorated(False)
+ keybindings.setup_global_keys(self._presence_window, self)
+
+ self._chat_windows = {}
+
+ def _toggle_window_visibility(self, window):
+ if window.get_property('visible'):
+ window.hide()
+ else:
+ window.show()
+
+ def toggle_home(self):
+ self._toggle_window_visibility(self._home_window)
+
+ def get_activity_from_xid(self, xid):
+ bus = dbus.SessionBus()
+ service = Activity.ACTIVITY_SERVICE_NAME + "%s" % xid
+ path = Activity.ACTIVITY_SERVICE_PATH + "/%s" % xid
+ proxy_obj = bus.get_object(service, path)
+
+ return dbus.Interface(proxy_obj, 'com.redhat.Sugar.Activity')
+
+ def get_current_activity(self):
+ window = self._screen.get_active_window()
+
+ if window and window.is_skip_tasklist():
+ window = self._screen.get_previously_active_window()
+
+ if window and not window.is_skip_tasklist():
+ return self.get_activity_from_xid(window.get_xid())
+ else:
+ return None
+
+ def toggle_people(self):
+ activity = self.get_current_activity()
+
+ if activity:
+ activity_id = activity.get_id()
+
+ if not self._chat_windows.has_key(activity_id):
+ window = gtk.Window()
+ window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ window.set_skip_taskbar_hint(True)
+ window.set_decorated(False)
+ keybindings.setup_global_keys(window, self)
+ chat = ActivityChat(activity)
+ window.add(chat)
+ chat.show()
+ self._chat_windows[activity_id] = window
+ else:
+ window = self._chat_windows[activity_id]
+
+ window.move(210, 10)
+ window.resize(380, 440)
+ self._toggle_window_visibility(window)
+
+ self._presence_window.move(10, 10)
+ self._presence_window.resize(180, 440)
+ self._presence_window.set_activity(activity)
+ self._toggle_window_visibility(self._presence_window)
+
+ def toggle_console(self):
+ self._toggle_window_visibility(self._console.get_window())
+
+ def get_registry(self):
+ return self._registry
if __name__ == "__main__":
shell = Shell()
diff --git a/shell/StartPage.py b/shell/StartPage.py
deleted file mode 100644
index cfde8045..00000000
--- a/shell/StartPage.py
+++ /dev/null
@@ -1,314 +0,0 @@
-import pygtk
-pygtk.require('2.0')
-import gtk
-import pango
-import cgi
-import xml.sax.saxutils
-import gobject
-import socket
-
-import dbus_bindings
-from google import google
-from sugar.presence.PresenceService import PresenceService
-from sugar.activity import Activity
-
-from gettext import gettext as _
-
-_BROWSER_ACTIVITY_TYPE = "_web_olpc._udp"
-
-_COLUMN_TITLE = 0
-_COLUMN_ADDRESS = 1
-_COLUMN_SUBTITLE = 2
-_COLUMN_SERVICE = 3
-
-class SearchHelper(object):
- def __init__(self, activity_id):
- self.search_id = activity_id
- self.found = False
-
-class SearchModel(gtk.ListStore):
- def __init__(self, activities_model, search_text):
- gtk.ListStore.__init__(self, gobject.TYPE_STRING, gobject.TYPE_STRING,
- gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
- success = False
-
- for row in activities_model:
- title = row[_COLUMN_TITLE]
- address = row[_COLUMN_ADDRESS]
- if title.find(search_text) >= 0 or address.find(search_text) >= 0:
- self.append([ title, address, row[_COLUMN_SUBTITLE], row[_COLUMN_SERVICE] ])
-
- google.LICENSE_KEY = '1As9KaJQFHIJ1L0W5EZPl6vBOFvh/Vaf'
- try:
- data = google.doGoogleSearch(search_text)
- success = True
- except socket.gaierror, exc:
- if exc[0] == -3: # Temporary failure in name resolution
- errdlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
- gtk.BUTTONS_OK, "There appears to be no network connection.")
- errdlg.connect("response", lambda d, e: d.destroy())
- errdlg.connect("close", lambda d, e: d.destroy())
- errdlg.show()
-
- if success == True:
- for result in data.results:
- title = result.title
-
- # FIXME what tags should we actually strip?
- title = title.replace('', '')
- title = title.replace('', '')
-
- # FIXME I'm sure there is a better way to
- # unescape these.
- title = title.replace('"', '"')
- title = title.replace('&', '&')
-
- self.append([ title, result.URL, None, None ])
-
-class ActivitiesModel(gtk.ListStore):
- def __init__(self):
- gtk.ListStore.__init__(self, gobject.TYPE_STRING, gobject.TYPE_STRING,
- gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
-
- def _filter_dupe_activities(self, model, path, it, user_data):
- """Search the list of list rows for an existing service that
- has the activity ID we're looking for."""
- helper = user_data
- (service, ) = model.get(it, _COLUMN_SERVICE)
- if not service:
- return False
- if service.get_activity_id() == helper.search_id:
- helper.found = True
- return True
- return False
-
- def add_activity(self, buddy, service):
- # Web Activity check
- activity_id = service.get_activity_id()
- if activity_id is None:
- return
- # Don't show dupes
- helper = SearchHelper(activity_id)
- self.foreach(self._filter_dupe_activities, helper)
- if helper.found == True:
- return
-
- # Only accept browser activities for now
- if service.get_type() == _BROWSER_ACTIVITY_TYPE:
- escaped_title = service.get_one_property('Title')
- escaped_uri = service.get_one_property('URI')
- if escaped_title and escaped_uri:
- title = xml.sax.saxutils.unescape(escaped_title)
- address = xml.sax.saxutils.unescape(escaped_uri)
- subtitle = 'Shared by %s' % buddy.get_nick_name()
- self.append([ title, address, subtitle, service ])
-
-class ActivitiesView(gtk.TreeView):
- def __init__(self, activity_controller, model):
- gtk.TreeView.__init__(self, model)
-
- self._owner = None
- self._activity_controller = activity_controller
-
- self.set_headers_visible(False)
-
- theme = gtk.icon_theme_get_default()
- size = 48
- self._web_pixbuf = theme.load_icon('emblem-web', size, 0)
- self._share_pixbuf = theme.load_icon('emblem-people', size, 0)
-
- column = gtk.TreeViewColumn('')
- self.append_column(column)
-
- cell = gtk.CellRendererPixbuf()
- column.pack_start(cell, False)
- column.set_cell_data_func(cell, self._icon_cell_data_func)
-
- cell = gtk.CellRendererText()
- column.pack_start(cell)
- column.set_cell_data_func(cell, self._cell_data_func)
-
- self.connect('row-activated', self._row_activated_cb)
-
- def _icon_cell_data_func(self, column, cell, model, it):
- if model.get_value(it, _COLUMN_SERVICE) == None:
- cell.set_property('pixbuf', self._web_pixbuf)
- else:
- cell.set_property('pixbuf', self._share_pixbuf)
-
- def _cell_data_func(self, column, cell, model, it):
- title = model.get_value(it, _COLUMN_TITLE)
- subtitle = model.get_value(it, _COLUMN_SUBTITLE)
- if subtitle is None:
- subtitle = model.get_value(it, _COLUMN_ADDRESS)
-
- markup = '' + cgi.escape(title) + ''
- markup += '\n' + cgi.escape(subtitle)
-
- cell.set_property('markup', markup)
- cell.set_property('ellipsize', pango.ELLIPSIZE_END)
-
- def set_owner(self, owner):
- self._owner = owner
-
- def _row_activated_cb(self, treeview, path, column):
- model = self.get_model()
- address = model.get_value(model.get_iter(path), _COLUMN_ADDRESS)
- service = model.get_value(model.get_iter(path), _COLUMN_SERVICE)
-
- print 'Activated row %s' % address
-
- if service is None:
- browser_shell.open_browser(address)
- return
-
- if not self._owner:
- raise RuntimeError("We don't have an owner yet!")
-
- # If the activity is already started, switch to it
- service_act_id = service.get_activity_id()
- if service_act_id and self._activity_controller.have_activity(service_act_id):
- self._activity_controller.switch_to_activity(service_act_id)
- return
-
- Activity.create('com.redhat.Sugar.BrowserActivity', service, [ address ])
-
-class StartPage(gtk.HBox):
- def __init__(self, activity_controller, ac_signal_object):
- gtk.HBox.__init__(self)
-
- self._ac_signal_object = ac_signal_object
- self._ac_signal_object.connect("local-activity-started",
- self._on_local_activity_started_cb)
- self._ac_signal_object.connect("local-activity-ended",
- self._on_local_activity_ended_cb)
-
- self._pservice = PresenceService.get_instance()
- self._pservice.connect("activity-announced", self._on_activity_announced_cb)
- self._pservice.connect("new-service-adv", self._on_new_service_adv_cb)
- self._pservice.connect("buddy-appeared", self._on_buddy_appeared_cb)
- self._pservice.connect("buddy-disappeared", self._on_buddy_disappeared_cb)
- self._pservice.start()
- self._pservice.track_service_type(_BROWSER_ACTIVITY_TYPE)
- if self._pservice.get_owner():
- self._on_buddy_appeared_cb(self._pservice, self._pservice.get_owner())
-
- vbox = gtk.VBox()
-
- search_box = gtk.HBox(False, 6)
- search_box.set_border_width(24)
-
- self._search_entry = gtk.Entry()
- self._search_entry.connect('activate', self._search_entry_activate_cb)
- search_box.pack_start(self._search_entry)
- self._search_entry.show()
-
- search_button = gtk.Button(_("Search"))
- search_button.connect('clicked', self._search_button_clicked_cb)
- search_box.pack_start(search_button, False)
- search_button.show()
-
- vbox.pack_start(search_box, False, True)
- search_box.show()
-
- exp_space = gtk.Label('')
- vbox.pack_start(exp_space)
- exp_space.show()
-
- self.pack_start(vbox)
- vbox.show()
-
- vbox = gtk.VBox()
-
- self._search_close_box = gtk.HBox()
-
- self._search_close_label = gtk.Label()
- self._search_close_label.set_alignment(0.0, 0.5)
- self._search_close_box.pack_start(self._search_close_label)
- self._search_close_label.show()
-
- close_image = gtk.Image()
- close_image.set_from_stock (gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
- close_image.show()
-
- search_close_button = gtk.Button()
- rcstyle = gtk.RcStyle();
- rcstyle.xthickness = rcstyle.ythickness = 0;
- search_close_button.modify_style (rcstyle);
- search_close_button.add(close_image)
- search_close_button.set_relief(gtk.RELIEF_NONE)
- search_close_button.set_focus_on_click(False)
- search_close_button.connect("clicked", self.__search_close_button_clicked_cb)
-
- self._search_close_box.pack_start(search_close_button, False)
- search_close_button.show()
-
- vbox.pack_start(self._search_close_box, False)
-
- sw = gtk.ScrolledWindow()
- sw.set_size_request(320, -1)
- sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
-
- self._activities_model = ActivitiesModel()
-
- owner = self._pservice.get_owner()
- self._activities = ActivitiesView(activity_controller, self._activities_model)
- sw.add(self._activities)
- self._activities.show()
-
- vbox.pack_start(sw)
- sw.show()
-
- self.pack_start(vbox)
- vbox.show()
-
- def __search_close_button_clicked_cb(self, button):
- self._search(None)
-
- def _on_local_activity_started_cb(self, helper, activity_container, activity_id):
- print "new local activity %s" % activity_id
-
- def _on_local_activity_ended_cb(self, helper, activity_container, activity_id):
- print "local activity %s disappeared" % activity_id
-
- def _on_new_service_adv_cb(self, pservice, activity_id, short_stype):
- if activity_id:
- self._pservice.track_service_type(short_stype)
-
- def _on_buddy_appeared_cb(self, pservice, buddy):
- if buddy.is_owner():
- self._activities.set_owner(buddy)
-
- def _on_buddy_disappeared_cb(self, pservice, buddy):
- if buddy.is_owner():
- self._activities.set_owner(None)
-
- def _on_activity_announced_cb(self, pservice, service, buddy):
- print "Found new activity service (activity %s of type %s)" % (service.get_activity_id(), service.get_type())
- self._activities_model.add_activity(buddy, service)
- if self._activities.get_model() != self._activities_model:
- self._search(self._last_search)
-
- def _search_entry_activate_cb(self, entry):
- self._search()
- self._search_entry.set_text('')
-
- def _search_button_clicked_cb(self, button):
- self._search()
- self._search_entry.set_text('')
-
- def _search(self, text = None):
- if text == None:
- text = self._search_entry.get_text()
-
- if text == None or len(text) == 0:
- self._activities.set_model(self._activities_model)
- self._search_close_box.hide()
- else:
- search_model = SearchModel(self._activities_model, text)
- self._activities.set_model(search_model)
-
- self._search_close_label.set_text('Search for %s' % (text))
- self._search_close_box.show()
-
- self._last_search = text
diff --git a/shell/WindowManager.py b/shell/WindowManager.py
deleted file mode 100644
index af393246..00000000
--- a/shell/WindowManager.py
+++ /dev/null
@@ -1,206 +0,0 @@
-import time
-import logging
-
-import gtk
-import gobject
-
-DEFAULT_WIDTH = 640
-DEFAULT_HEIGHT = 480
-
-SLIDING_TIME = 0.8
-
-class SlidingHelper:
- IN = 0
- OUT = 1
-
- def __init__(self, manager, direction):
- self._direction = direction
- self._cur_time = time.time()
- self._target_time = self._cur_time + SLIDING_TIME
- self._manager = manager
- self._start = True
- self._end = False
-
- (x, y, width, height) = manager.get_geometry()
- self._orig_y = y
- if direction == SlidingHelper.IN:
- self._target_y = y
- manager.set_geometry(x, y - height, width, height)
- else:
- self._target_y = y - height
-
- def get_direction(self):
- return self._direction
-
- def is_start(self):
- return self._start
-
- def is_end(self):
- return self._end
-
- def get_next_y(self):
- self._start = False
-
- (x, y, width, height) = self._manager.get_geometry()
-
- old_time = self._cur_time
- self._cur_time = time.time()
- remaining = self._target_time - self._cur_time
-
- if remaining <= 0 or \
- (y > self._target_y and self._direction == SlidingHelper.IN) or \
- (y < self._target_y and self._direction == SlidingHelper.OUT):
- self._end = True
- y = self._orig_y
- else:
- approx_time_step = float(self._cur_time - old_time)
- approx_n_steps = remaining / approx_time_step
- step = (self._target_y - y) / approx_n_steps
- y += step
-
- return y
-
-class WindowManager:
- __managers_list = []
-
- TYPE_ACTIVITY = 0
- TYPE_POPUP = 1
-
- ANIMATION_NONE = 0
- ANIMATION_SLIDE_IN = 1
-
- def __init__(self, window):
- self._window = window
- self._window_type = WindowManager.TYPE_ACTIVITY
- self._animation = WindowManager.ANIMATION_NONE
- self._key = 0
- self._animating = False
-
- window.connect("key-press-event", self.__key_press_event_cb)
-
- WindowManager.__managers_list.append(self)
-
- def __key_press_event_cb(self, window, event):
- # FIXME we should fix this to work also while animating
- if self._animating:
- return False
-
- for manager in WindowManager.__managers_list:
- if event.keyval == manager._key:
- if manager._window.get_property('visible'):
- manager.hide()
- else:
- manager.show()
-
- def get_geometry(self):
- return (self._x, self._y, self._width, self._height)
-
- def set_geometry(self, x, y, width, height):
- if self._window_type == WindowManager.TYPE_ACTIVITY:
- logging.error('The geometry will be ignored for activity windows')
-
- self._x = x
- self._y = y
- self._width = width
- self._height = height
-
- def set_animation(self, animation):
- self._animation = animation
-
- def set_type(self, window_type):
- self._window_type = window_type
-
- def set_key(self, key):
- self._key = key
-
- def show(self):
- self._update_hints()
- self._update_size()
-
- if self._animation == WindowManager.ANIMATION_SLIDE_IN:
- self._slide_in()
- else:
- self._update_position()
- self._window.show()
-
- def hide(self):
- if self._animation == WindowManager.ANIMATION_SLIDE_IN:
- self._slide_out()
- else:
- self._window.hide()
-
- def _get_screen_dimensions(self):
- screen_width = DEFAULT_WIDTH
- screen_height = DEFAULT_HEIGHT
-
- for manager in WindowManager.__managers_list:
- if manager._window_type == WindowManager.TYPE_ACTIVITY:
- screen_width = manager._window.allocation.width
- screen_height = manager._window.allocation.height
-
- return (screen_width, screen_height)
-
- def _get_screen_position(self):
- result = (0, 0)
- for manager in WindowManager.__managers_list:
- if manager._window_type == WindowManager.TYPE_ACTIVITY:
- result = manager._window.get_position()
-
- return result
-
- def _transform_position(self):
- (screen_width, screen_height) = self._get_screen_dimensions()
- (screen_x, screen_y) = self._get_screen_position()
-
- x = int(screen_width * self._x) + screen_x
- y = int(screen_height * self._y) + screen_y
-
- return (x, y)
-
- def _transform_dimensions(self):
- (screen_width, screen_height) = self._get_screen_dimensions()
-
- width = int(screen_width * self._width)
- height = int(screen_height * self._height)
-
- return (width, height)
-
- def _update_hints(self):
- if self._window_type == WindowManager.TYPE_POPUP:
- self._window.set_decorated(False)
- self._window.set_skip_taskbar_hint(True)
-
- def _update_size(self):
- if self._window_type == WindowManager.TYPE_ACTIVITY:
- self._window.resize(DEFAULT_WIDTH, DEFAULT_HEIGHT)
- else:
- (width, height) = self._transform_dimensions()
- self._window.resize(width, height)
-
- def _update_position(self):
- if self._window_type == WindowManager.TYPE_POPUP:
- (x, y) = self._transform_position()
- self._window.move(x, y)
-
- def __slide_timeout_cb(self, helper):
- start = helper.is_start()
-
- self._y = helper.get_next_y()
- self._update_position()
-
- if start and helper.get_direction() == SlidingHelper.IN:
- self._window.show()
- elif helper.is_end() and helper.get_direction() == SlidingHelper.OUT:
- self._window.hide()
-
- self._animating = not helper.is_end()
-
- return not helper.is_end()
-
- def _slide_in(self):
- helper = SlidingHelper(self, SlidingHelper.IN)
- gobject.idle_add(self.__slide_timeout_cb, helper)
-
- def _slide_out(self):
- helper = SlidingHelper(self, SlidingHelper.OUT)
- gobject.idle_add(self.__slide_timeout_cb, helper)
diff --git a/shell/google/GoogleSOAPFacade.py b/shell/google/GoogleSOAPFacade.py
deleted file mode 100644
index 0aab3cf4..00000000
--- a/shell/google/GoogleSOAPFacade.py
+++ /dev/null
@@ -1,85 +0,0 @@
-"""
-Facade that hides the differences between the SOAPpy and SOAP.py
-libraries, so that google.py doesn't have to deal with them.
-
-@author: Brian Landers
-@license: Python
-@version: 0.5.4
-"""
-
-import warnings
-from distutils.version import LooseVersion
-
-__author__ = "Brian Landers "
-__version__ = "0.6"
-__license__ = "Python"
-
-#
-# Wrapper around the python 'warnings' facility
-#
-def warn( message, level=RuntimeWarning ):
- warnings.warn( message, level, stacklevel=3 )
-
-# We can't use older version of SOAPpy, due to bugs that break the Google API
-minSOAPpyVersion = "0.11.3"
-
-#
-# Try loading SOAPpy first. If that fails, fall back to the old SOAP.py
-#
-SOAPpy = None
-try:
- import SOAPpy
- from SOAPpy import SOAPProxy, Types
-
- if LooseVersion( minSOAPpyVersion ) > \
- LooseVersion( SOAPpy.version.__version__ ):
-
- warn( "Versions of SOAPpy before %s have known bugs that prevent " +
- "PyGoogle from functioning." % minSOAPpyVersion )
- raise ImportError
-
-except ImportError:
- warn( "SOAPpy not imported. Trying legacy SOAP.py.",
- DeprecationWarning )
- try:
- import SOAP
- except ImportError:
- raise RuntimeError( "Unable to find SOAPpy or SOAP. Can't continue.\n" )
-
-#
-# Constants that differ between the modules
-#
-if SOAPpy:
- false = Types.booleanType(0)
- true = Types.booleanType(1)
- structType = Types.structType
- faultType = Types.faultType
-else:
- false = SOAP.booleanType(0)
- true = SOAP.booleanType(1)
- structType = SOAP.structType
- faultType = SOAP.faultType
-
-#
-# Get a SOAP Proxy object in the correct way for the module we're using
-#
-def getProxy( url, namespace, http_proxy ):
- if SOAPpy:
- return SOAPProxy( url,
- namespace = namespace,
- http_proxy = http_proxy )
-
- else:
- return SOAP.SOAPProxy( url,
- namespace = namespace,
- http_proxy = http_proxy )
-
-#
-# Convert an object to a dictionary in the proper way for the module
-# we're using for SOAP
-#
-def toDict( obj ):
- if SOAPpy:
- return obj._asdict()
- else:
- return obj._asdict
diff --git a/shell/google/Makefile.am b/shell/google/Makefile.am
deleted file mode 100644
index 0f6057cd..00000000
--- a/shell/google/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-googledir = $(pkgdatadir)/shell/google
-google_PYTHON = \
- __init__.py \
- google.py \
- GoogleSOAPFacade.py \
- SOAP.py
diff --git a/shell/google/SOAP.py b/shell/google/SOAP.py
deleted file mode 100755
index 032a452d..00000000
--- a/shell/google/SOAP.py
+++ /dev/null
@@ -1,3974 +0,0 @@
-#!/usr/bin/python
-################################################################################
-#
-# SOAP.py 0.9.7 - Cayce Ullman (cayce@actzero.com)
-# Brian Matthews (blm@actzero.com)
-#
-# INCLUDED:
-# - General SOAP Parser based on sax.xml (requires Python 2.0)
-# - General SOAP Builder
-# - SOAP Proxy for RPC client code
-# - SOAP Server framework for RPC server code
-#
-# FEATURES:
-# - Handles all of the types in the BDG
-# - Handles faults
-# - Allows namespace specification
-# - Allows SOAPAction specification
-# - Homogeneous typed arrays
-# - Supports multiple schemas
-# - Header support (mustUnderstand and actor)
-# - XML attribute support
-# - Multi-referencing support (Parser/Builder)
-# - Understands SOAP-ENC:root attribute
-# - Good interop, passes all client tests for Frontier, SOAP::LITE, SOAPRMI
-# - Encodings
-# - SSL clients (with OpenSSL configured in to Python)
-# - SSL servers (with OpenSSL configured in to Python and M2Crypto installed)
-#
-# TODO:
-# - Timeout on method calls - MCU
-# - Arrays (sparse, multidimensional and partial) - BLM
-# - Clean up data types - BLM
-# - Type coercion system (Builder) - MCU
-# - Early WSDL Support - MCU
-# - Attachments - BLM
-# - setup.py - MCU
-# - mod_python example - MCU
-# - medusa example - MCU
-# - Documentation - JAG
-# - Look at performance
-#
-################################################################################
-#
-# Copyright (c) 2001, Cayce Ullman.
-# Copyright (c) 2001, Brian Matthews.
-#
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-# Redistributions of source code must retain the above copyright notice, this
-# list of conditions and the following disclaimer.
-#
-# Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# Neither the name of actzero, inc. nor the names of its contributors may
-# be used to endorse or promote products derived from this software without
-# specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-################################################################################
-#
-# Additional changes:
-# 0.9.7.3 - 4/18/2002 - Mark Pilgrim (f8dy@diveintomark.org)
-# added dump_dict as alias for dump_dictionary for Python 2.2 compatibility
-# 0.9.7.2 - 4/12/2002 - Mark Pilgrim (f8dy@diveintomark.org)
-# fixed logic to unmarshal the value of "null" attributes ("true" or "1"
-# means true, others false)
-# 0.9.7.1 - 4/11/2002 - Mark Pilgrim (f8dy@diveintomark.org)
-# added "dump_str" as alias for "dump_string" for Python 2.2 compatibility
-# Between 2.1 and 2.2, type("").__name__ changed from "string" to "str"
-################################################################################
-
-import xml.sax
-import UserList
-import base64
-import cgi
-import urllib
-import exceptions
-import copy
-import re
-import socket
-import string
-import sys
-import time
-import SocketServer
-from types import *
-
-try: from M2Crypto import SSL
-except: pass
-
-ident = '$Id: SOAP.py,v 1.1.1.1 2004/01/16 16:15:18 bluecoat93 Exp $'
-
-__version__ = "0.9.7.3"
-
-# Platform hackery
-
-# Check float support
-try:
- float("NaN")
- float("INF")
- float("-INF")
- good_float = 1
-except:
- good_float = 0
-
-################################################################################
-# Exceptions
-################################################################################
-class Error(exceptions.Exception):
- def __init__(self, msg):
- self.msg = msg
- def __str__(self):
- return "" % self.msg
- __repr__ = __str__
-
-class RecursionError(Error):
- pass
-
-class UnknownTypeError(Error):
- pass
-
-class HTTPError(Error):
- # indicates an HTTP protocol error
- def __init__(self, code, msg):
- self.code = code
- self.msg = msg
- def __str__(self):
- return "" % (self.code, self.msg)
- __repr__ = __str__
-
-##############################################################################
-# Namespace Class
-################################################################################
-def invertDict(dict):
- d = {}
-
- for k, v in dict.items():
- d[v] = k
-
- return d
-
-class NS:
- XML = "http://www.w3.org/XML/1998/namespace"
-
- ENV = "http://schemas.xmlsoap.org/soap/envelope/"
- ENC = "http://schemas.xmlsoap.org/soap/encoding/"
-
- XSD = "http://www.w3.org/1999/XMLSchema"
- XSD2 = "http://www.w3.org/2000/10/XMLSchema"
- XSD3 = "http://www.w3.org/2001/XMLSchema"
-
- XSD_L = [XSD, XSD2, XSD3]
- EXSD_L= [ENC, XSD, XSD2, XSD3]
-
- XSI = "http://www.w3.org/1999/XMLSchema-instance"
- XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance"
- XSI3 = "http://www.w3.org/2001/XMLSchema-instance"
- XSI_L = [XSI, XSI2, XSI3]
-
- URN = "http://soapinterop.org/xsd"
-
- # For generated messages
- XML_T = "xml"
- ENV_T = "SOAP-ENV"
- ENC_T = "SOAP-ENC"
- XSD_T = "xsd"
- XSD2_T= "xsd2"
- XSD3_T= "xsd3"
- XSI_T = "xsi"
- XSI2_T= "xsi2"
- XSI3_T= "xsi3"
- URN_T = "urn"
-
- NSMAP = {ENV_T: ENV, ENC_T: ENC, XSD_T: XSD, XSD2_T: XSD2,
- XSD3_T: XSD3, XSI_T: XSI, XSI2_T: XSI2, XSI3_T: XSI3,
- URN_T: URN}
- NSMAP_R = invertDict(NSMAP)
-
- STMAP = {'1999': (XSD_T, XSI_T), '2000': (XSD2_T, XSI2_T),
- '2001': (XSD3_T, XSI3_T)}
- STMAP_R = invertDict(STMAP)
-
- def __init__(self):
- raise Error, "Don't instantiate this"
-
-################################################################################
-# Configuration class
-################################################################################
-
-class SOAPConfig:
- __readonly = ('SSLserver', 'SSLclient')
-
- def __init__(self, config = None, **kw):
- d = self.__dict__
-
- if config:
- if not isinstance(config, SOAPConfig):
- raise AttributeError, \
- "initializer must be SOAPConfig instance"
-
- s = config.__dict__
-
- for k, v in s.items():
- if k[0] != '_':
- d[k] = v
- else:
- # Setting debug also sets returnFaultInfo, dumpFaultInfo,
- # dumpHeadersIn, dumpHeadersOut, dumpSOAPIn, and dumpSOAPOut
- self.debug = 0
- # Setting namespaceStyle sets typesNamespace, typesNamespaceURI,
- # schemaNamespace, and schemaNamespaceURI
- self.namespaceStyle = '1999'
- self.strictNamespaces = 0
- self.typed = 1
- self.buildWithNamespacePrefix = 1
- self.returnAllAttrs = 0
-
- try: SSL; d['SSLserver'] = 1
- except: d['SSLserver'] = 0
-
- try: socket.ssl; d['SSLclient'] = 1
- except: d['SSLclient'] = 0
-
- for k, v in kw.items():
- if k[0] != '_':
- setattr(self, k, v)
-
- def __setattr__(self, name, value):
- if name in self.__readonly:
- raise AttributeError, "readonly configuration setting"
-
- d = self.__dict__
-
- if name in ('typesNamespace', 'typesNamespaceURI',
- 'schemaNamespace', 'schemaNamespaceURI'):
-
- if name[-3:] == 'URI':
- base, uri = name[:-3], 1
- else:
- base, uri = name, 0
-
- if type(value) == StringType:
- if NS.NSMAP.has_key(value):
- n = (value, NS.NSMAP[value])
- elif NS.NSMAP_R.has_key(value):
- n = (NS.NSMAP_R[value], value)
- else:
- raise AttributeError, "unknown namespace"
- elif type(value) in (ListType, TupleType):
- if uri:
- n = (value[1], value[0])
- else:
- n = (value[0], value[1])
- else:
- raise AttributeError, "unknown namespace type"
-
- d[base], d[base + 'URI'] = n
-
- try:
- d['namespaceStyle'] = \
- NS.STMAP_R[(d['typesNamespace'], d['schemaNamespace'])]
- except:
- d['namespaceStyle'] = ''
-
- elif name == 'namespaceStyle':
- value = str(value)
-
- if not NS.STMAP.has_key(value):
- raise AttributeError, "unknown namespace style"
-
- d[name] = value
- n = d['typesNamespace'] = NS.STMAP[value][0]
- d['typesNamespaceURI'] = NS.NSMAP[n]
- n = d['schemaNamespace'] = NS.STMAP[value][1]
- d['schemaNamespaceURI'] = NS.NSMAP[n]
-
- elif name == 'debug':
- d[name] = \
- d['returnFaultInfo'] = \
- d['dumpFaultInfo'] = \
- d['dumpHeadersIn'] = \
- d['dumpHeadersOut'] = \
- d['dumpSOAPIn'] = \
- d['dumpSOAPOut'] = value
-
- else:
- d[name] = value
-
-Config = SOAPConfig()
-
-################################################################################
-# Types and Wrappers
-################################################################################
-
-class anyType:
- _validURIs = (NS.XSD, NS.XSD2, NS.XSD3, NS.ENC)
-
- def __init__(self, data = None, name = None, typed = 1, attrs = None):
- if self.__class__ == anyType:
- raise Error, "anyType can't be instantiated directly"
-
- if type(name) in (ListType, TupleType):
- self._ns, self._name = name
- else:
- self._ns, self._name = self._validURIs[0], name
- self._typed = typed
- self._attrs = {}
-
- self._cache = None
- self._type = self._typeName()
-
- self._data = self._checkValueSpace(data)
-
- if attrs != None:
- self._setAttrs(attrs)
-
- def __str__(self):
- if self._name:
- return "<%s %s at %d>" % (self.__class__, self._name, id(self))
- return "<%s at %d>" % (self.__class__, id(self))
-
- __repr__ = __str__
-
- def _checkValueSpace(self, data):
- return data
-
- def _marshalData(self):
- return str(self._data)
-
- def _marshalAttrs(self, ns_map, builder):
- a = ''
-
- for attr, value in self._attrs.items():
- ns, n = builder.genns(ns_map, attr[0])
- a += n + ' %s%s="%s"' % \
- (ns, attr[1], cgi.escape(str(value), 1))
-
- return a
-
- def _fixAttr(self, attr):
- if type(attr) in (StringType, UnicodeType):
- attr = (None, attr)
- elif type(attr) == ListType:
- attr = tuple(attr)
- elif type(attr) != TupleType:
- raise AttributeError, "invalid attribute type"
-
- if len(attr) != 2:
- raise AttributeError, "invalid attribute length"
-
- if type(attr[0]) not in (NoneType, StringType, UnicodeType):
- raise AttributeError, "invalid attribute namespace URI type"
-
- return attr
-
- def _getAttr(self, attr):
- attr = self._fixAttr(attr)
-
- try:
- return self._attrs[attr]
- except:
- return None
-
- def _setAttr(self, attr, value):
- attr = self._fixAttr(attr)
-
- self._attrs[attr] = str(value)
-
- def _setAttrs(self, attrs):
- if type(attrs) in (ListType, TupleType):
- for i in range(0, len(attrs), 2):
- self._setAttr(attrs[i], attrs[i + 1])
-
- return
-
- if type(attrs) == DictType:
- d = attrs
- elif isinstance(attrs, anyType):
- d = attrs._attrs
- else:
- raise AttributeError, "invalid attribute type"
-
- for attr, value in d.items():
- self._setAttr(attr, value)
-
- def _setMustUnderstand(self, val):
- self._setAttr((NS.ENV, "mustUnderstand"), val)
-
- def _getMustUnderstand(self):
- return self._getAttr((NS.ENV, "mustUnderstand"))
-
- def _setActor(self, val):
- self._setAttr((NS.ENV, "actor"), val)
-
- def _getActor(self):
- return self._getAttr((NS.ENV, "actor"))
-
- def _typeName(self):
- return self.__class__.__name__[:-4]
-
- def _validNamespaceURI(self, URI, strict):
- if not self._typed:
- return None
- if URI in self._validURIs:
- return URI
- if not strict:
- return self._ns
- raise AttributeError, \
- "not a valid namespace for type %s" % self._type
-
-class voidType(anyType):
- pass
-
-class stringType(anyType):
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- return data
-
-class untypedType(stringType):
- def __init__(self, data = None, name = None, attrs = None):
- stringType.__init__(self, data, name, 0, attrs)
-
-class IDType(stringType): pass
-class NCNameType(stringType): pass
-class NameType(stringType): pass
-class ENTITYType(stringType): pass
-class IDREFType(stringType): pass
-class languageType(stringType): pass
-class NMTOKENType(stringType): pass
-class QNameType(stringType): pass
-
-class tokenType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3)
- __invalidre = '[\n\t]|^ | $| '
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- if type(self.__invalidre) == StringType:
- self.__invalidre = re.compile(self.__invalidre)
-
- if self.__invalidre.search(data):
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class normalizedStringType(anyType):
- _validURIs = (NS.XSD3,)
- __invalidre = '[\n\r\t]'
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- if type(self.__invalidre) == StringType:
- self.__invalidre = re.compile(self.__invalidre)
-
- if self.__invalidre.search(data):
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class CDATAType(normalizedStringType):
- _validURIs = (NS.XSD2,)
-
-class booleanType(anyType):
- def __int__(self):
- return self._data
-
- __nonzero__ = __int__
-
- def _marshalData(self):
- return ['false', 'true'][self._data]
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if data in (0, '0', 'false', ''):
- return 0
- if data in (1, '1', 'true'):
- return 1
- raise ValueError, "invalid %s value" % self._type
-
-class decimalType(anyType):
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType, FloatType):
- raise Error, "invalid %s value" % self._type
-
- return data
-
-class floatType(anyType):
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType, FloatType) or \
- data < -3.4028234663852886E+38 or \
- data > 3.4028234663852886E+38:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
- def _marshalData(self):
- return "%.18g" % self._data # More precision
-
-class doubleType(anyType):
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType, FloatType) or \
- data < -1.7976931348623158E+308 or \
- data > 1.7976931348623157E+308:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
- def _marshalData(self):
- return "%.18g" % self._data # More precision
-
-class durationType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- try:
- # A tuple or a scalar is OK, but make them into a list
-
- if type(data) == TupleType:
- data = list(data)
- elif type(data) != ListType:
- data = [data]
-
- if len(data) > 6:
- raise Exception, "too many values"
-
- # Now check the types of all the components, and find
- # the first nonzero element along the way.
-
- f = -1
-
- for i in range(len(data)):
- if data[i] == None:
- data[i] = 0
- continue
-
- if type(data[i]) not in \
- (IntType, LongType, FloatType):
- raise Exception, "element %d a bad type" % i
-
- if data[i] and f == -1:
- f = i
-
- # If they're all 0, just use zero seconds.
-
- if f == -1:
- self._cache = 'PT0S'
-
- return (0,) * 6
-
- # Make sure only the last nonzero element has a decimal fraction
- # and only the first element is negative.
-
- d = -1
-
- for i in range(f, len(data)):
- if data[i]:
- if d != -1:
- raise Exception, \
- "all except the last nonzero element must be " \
- "integers"
- if data[i] < 0 and i > f:
- raise Exception, \
- "only the first nonzero element can be negative"
- elif data[i] != long(data[i]):
- d = i
-
- # Pad the list on the left if necessary.
-
- if len(data) < 6:
- n = 6 - len(data)
- f += n
- d += n
- data = [0] * n + data
-
- # Save index of the first nonzero element and the decimal
- # element for _marshalData.
-
- self.__firstnonzero = f
- self.__decimal = d
-
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- t = 0
-
- if d[self.__firstnonzero] < 0:
- s = '-P'
- else:
- s = 'P'
-
- t = 0
-
- for i in range(self.__firstnonzero, len(d)):
- if d[i]:
- if i > 2 and not t:
- s += 'T'
- t = 1
- if self.__decimal == i:
- s += "%g" % abs(d[i])
- else:
- s += "%d" % long(abs(d[i]))
- s += ['Y', 'M', 'D', 'H', 'M', 'S'][i]
-
- self._cache = s
-
- return self._cache
-
-class timeDurationType(durationType):
- _validURIs = (NS.XSD, NS.XSD2, NS.ENC)
-
-class dateTimeType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.time()
-
- if (type(data) in (IntType, LongType)):
- data = list(time.gmtime(data)[:6])
- elif (type(data) == FloatType):
- f = data - int(data)
- data = list(time.gmtime(int(data))[:6])
- data[5] += f
- elif type(data) in (ListType, TupleType):
- if len(data) < 6:
- raise Exception, "not enough values"
- if len(data) > 9:
- raise Exception, "too many values"
-
- data = list(data[:6])
-
- cleanDate(data)
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- s = "%04d-%02d-%02dT%02d:%02d:%02d" % ((abs(d[0]),) + d[1:])
- if d[0] < 0:
- s = '-' + s
- f = d[5] - int(d[5])
- if f != 0:
- s += ("%g" % f)[1:]
- s += 'Z'
-
- self._cache = s
-
- return self._cache
-
-class recurringInstantType(anyType):
- _validURIs = (NS.XSD,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = list(time.gmtime(time.time())[:6])
- if (type(data) in (IntType, LongType)):
- data = list(time.gmtime(data)[:6])
- elif (type(data) == FloatType):
- f = data - int(data)
- data = list(time.gmtime(int(data))[:6])
- data[5] += f
- elif type(data) in (ListType, TupleType):
- if len(data) < 1:
- raise Exception, "not enough values"
- if len(data) > 9:
- raise Exception, "too many values"
-
- data = list(data[:6])
-
- if len(data) < 6:
- data += [0] * (6 - len(data))
-
- f = len(data)
-
- for i in range(f):
- if data[i] == None:
- if f < i:
- raise Exception, \
- "only leftmost elements can be none"
- else:
- f = i
- break
-
- cleanDate(data, f)
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- e = list(d)
- neg = ''
-
- if e[0] < 0:
- neg = '-'
- e[0] = abs(e[0])
-
- if not e[0]:
- e[0] = '--'
- elif e[0] < 100:
- e[0] = '-' + "%02d" % e[0]
- else:
- e[0] = "%04d" % e[0]
-
- for i in range(1, len(e)):
- if e[i] == None or (i < 3 and e[i] == 0):
- e[i] = '-'
- else:
- if e[i] < 0:
- neg = '-'
- e[i] = abs(e[i])
-
- e[i] = "%02d" % e[i]
-
- if d[5]:
- f = abs(d[5] - int(d[5]))
-
- if f:
- e[5] += ("%g" % f)[1:]
-
- s = "%s%s-%s-%sT%s:%s:%sZ" % ((neg,) + tuple(e))
-
- self._cache = s
-
- return self._cache
-
-class timeInstantType(dateTimeType):
- _validURIs = (NS.XSD, NS.XSD2, NS.ENC)
-
-class timePeriodType(dateTimeType):
- _validURIs = (NS.XSD2, NS.ENC)
-
-class timeType(anyType):
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[3:6]
- elif (type(data) == FloatType):
- f = data - int(data)
- data = list(time.gmtime(int(data))[3:6])
- data[2] += f
- elif type(data) in (IntType, LongType):
- data = time.gmtime(data)[3:6]
- elif type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[3:6]
- elif len(data) > 3:
- raise Exception, "too many values"
-
- data = [None, None, None] + list(data)
-
- if len(data) < 6:
- data += [0] * (6 - len(data))
-
- cleanDate(data, 3)
-
- data = data[3:]
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- s = ''
-
- s = time.strftime("%H:%M:%S", (0, 0, 0) + d + (0, 0, -1))
- f = d[2] - int(d[2])
- if f != 0:
- s += ("%g" % f)[1:]
- s += 'Z'
-
- self._cache = s
-
- return self._cache
-
-class dateType(anyType):
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[0:3]
- elif type(data) in (IntType, LongType, FloatType):
- data = time.gmtime(data)[0:3]
- elif type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[0:3]
- elif len(data) > 3:
- raise Exception, "too many values"
-
- data = list(data)
-
- if len(data) < 3:
- data += [1, 1, 1][len(data):]
-
- data += [0, 0, 0]
-
- cleanDate(data)
-
- data = data[:3]
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- s = "%04d-%02d-%02dZ" % ((abs(d[0]),) + d[1:])
- if d[0] < 0:
- s = '-' + s
-
- self._cache = s
-
- return self._cache
-
-class gYearMonthType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[0:2]
- elif type(data) in (IntType, LongType, FloatType):
- data = time.gmtime(data)[0:2]
- elif type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[0:2]
- elif len(data) > 2:
- raise Exception, "too many values"
-
- data = list(data)
-
- if len(data) < 2:
- data += [1, 1][len(data):]
-
- data += [1, 0, 0, 0]
-
- cleanDate(data)
-
- data = data[:2]
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- s = "%04d-%02dZ" % ((abs(d[0]),) + d[1:])
- if d[0] < 0:
- s = '-' + s
-
- self._cache = s
-
- return self._cache
-
-class gYearType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[0:1]
- elif type(data) in (IntType, LongType, FloatType):
- data = [data]
-
- if type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[0:1]
- elif len(data) < 1:
- raise Exception, "too few values"
- elif len(data) > 1:
- raise Exception, "too many values"
-
- if type(data[0]) == FloatType:
- try: s = int(data[0])
- except: s = long(data[0])
-
- if s != data[0]:
- raise Exception, "not integral"
-
- data = [s]
- elif type(data[0]) not in (IntType, LongType):
- raise Exception, "bad type"
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return data[0]
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- s = "%04dZ" % abs(d)
- if d < 0:
- s = '-' + s
-
- self._cache = s
-
- return self._cache
-
-class centuryType(anyType):
- _validURIs = (NS.XSD2, NS.ENC)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[0:1] / 100
- elif type(data) in (IntType, LongType, FloatType):
- data = [data]
-
- if type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[0:1] / 100
- elif len(data) < 1:
- raise Exception, "too few values"
- elif len(data) > 1:
- raise Exception, "too many values"
-
- if type(data[0]) == FloatType:
- try: s = int(data[0])
- except: s = long(data[0])
-
- if s != data[0]:
- raise Exception, "not integral"
-
- data = [s]
- elif type(data[0]) not in (IntType, LongType):
- raise Exception, "bad type"
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return data[0]
-
- def _marshalData(self):
- if self._cache == None:
- d = self._data
- s = "%02dZ" % abs(d)
- if d < 0:
- s = '-' + s
-
- self._cache = s
-
- return self._cache
-
-class yearType(gYearType):
- _validURIs = (NS.XSD2, NS.ENC)
-
-class gMonthDayType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[1:3]
- elif type(data) in (IntType, LongType, FloatType):
- data = time.gmtime(data)[1:3]
- elif type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[0:2]
- elif len(data) > 2:
- raise Exception, "too many values"
-
- data = list(data)
-
- if len(data) < 2:
- data += [1, 1][len(data):]
-
- data = [0] + data + [0, 0, 0]
-
- cleanDate(data, 1)
-
- data = data[1:3]
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return tuple(data)
-
- def _marshalData(self):
- if self._cache == None:
- self._cache = "--%02d-%02dZ" % self._data
-
- return self._cache
-
-class recurringDateType(gMonthDayType):
- _validURIs = (NS.XSD2, NS.ENC)
-
-class gMonthType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[1:2]
- elif type(data) in (IntType, LongType, FloatType):
- data = [data]
-
- if type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[1:2]
- elif len(data) < 1:
- raise Exception, "too few values"
- elif len(data) > 1:
- raise Exception, "too many values"
-
- if type(data[0]) == FloatType:
- try: s = int(data[0])
- except: s = long(data[0])
-
- if s != data[0]:
- raise Exception, "not integral"
-
- data = [s]
- elif type(data[0]) not in (IntType, LongType):
- raise Exception, "bad type"
-
- if data[0] < 1 or data[0] > 12:
- raise Exception, "bad value"
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return data[0]
-
- def _marshalData(self):
- if self._cache == None:
- self._cache = "--%02d--Z" % self._data
-
- return self._cache
-
-class monthType(gMonthType):
- _validURIs = (NS.XSD2, NS.ENC)
-
-class gDayType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- try:
- if data == None:
- data = time.gmtime(time.time())[2:3]
- elif type(data) in (IntType, LongType, FloatType):
- data = [data]
-
- if type(data) in (ListType, TupleType):
- if len(data) == 9:
- data = data[2:3]
- elif len(data) < 1:
- raise Exception, "too few values"
- elif len(data) > 1:
- raise Exception, "too many values"
-
- if type(data[0]) == FloatType:
- try: s = int(data[0])
- except: s = long(data[0])
-
- if s != data[0]:
- raise Exception, "not integral"
-
- data = [s]
- elif type(data[0]) not in (IntType, LongType):
- raise Exception, "bad type"
-
- if data[0] < 1 or data[0] > 31:
- raise Exception, "bad value"
- else:
- raise Exception, "invalid type"
- except Exception, e:
- raise ValueError, "invalid %s value - %s" % (self._type, e)
-
- return data[0]
-
- def _marshalData(self):
- if self._cache == None:
- self._cache = "---%02dZ" % self._data
-
- return self._cache
-
-class recurringDayType(gDayType):
- _validURIs = (NS.XSD2, NS.ENC)
-
-class hexBinaryType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- return data
-
- def _marshalData(self):
- if self._cache == None:
- self._cache = encodeHexString(self._data)
-
- return self._cache
-
-class base64BinaryType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- return data
-
- def _marshalData(self):
- if self._cache == None:
- self._cache = base64.encodestring(self._data)
-
- return self._cache
-
-class base64Type(base64BinaryType):
- _validURIs = (NS.ENC,)
-
-class binaryType(anyType):
- _validURIs = (NS.XSD, NS.ENC)
-
- def __init__(self, data, name = None, typed = 1, encoding = 'base64',
- attrs = None):
-
- anyType.__init__(self, data, name, typed, attrs)
-
- self._setAttr('encoding', encoding)
-
- def _marshalData(self):
- if self._cache == None:
- if self._getAttr((None, 'encoding')) == 'base64':
- self._cache = base64.encodestring(self._data)
- else:
- self._cache = encodeHexString(self._data)
-
- return self._cache
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- return data
-
- def _setAttr(self, attr, value):
- attr = self._fixAttr(attr)
-
- if attr[1] == 'encoding':
- if attr[0] != None or value not in ('base64', 'hex'):
- raise AttributeError, "invalid encoding"
-
- self._cache = None
-
- anyType._setAttr(self, attr, value)
-
-
-class anyURIType(anyType):
- _validURIs = (NS.XSD3,)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (StringType, UnicodeType):
- raise AttributeError, "invalid %s type" % self._type
-
- return data
-
- def _marshalData(self):
- if self._cache == None:
- self._cache = urllib.quote(self._data)
-
- return self._cache
-
-class uriType(anyURIType):
- _validURIs = (NS.XSD,)
-
-class uriReferenceType(anyURIType):
- _validURIs = (NS.XSD2,)
-
-class NOTATIONType(anyType):
- def __init__(self, data, name = None, typed = 1, attrs = None):
-
- if self.__class__ == NOTATIONType:
- raise Error, "a NOTATION can't be instantiated directly"
-
- anyType.__init__(self, data, name, typed, attrs)
-
-class ENTITIESType(anyType):
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) in (StringType, UnicodeType):
- return (data,)
-
- if type(data) not in (ListType, TupleType) or \
- filter (lambda x: type(x) not in (StringType, UnicodeType), data):
- raise AttributeError, "invalid %s type" % self._type
-
- return data
-
- def _marshalData(self):
- return ' '.join(self._data)
-
-class IDREFSType(ENTITIESType): pass
-class NMTOKENSType(ENTITIESType): pass
-
-class integerType(anyType):
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType):
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class nonPositiveIntegerType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or data > 0:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class non_Positive_IntegerType(nonPositiveIntegerType):
- _validURIs = (NS.XSD,)
-
- def _typeName(self):
- return 'non-positive-integer'
-
-class negativeIntegerType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or data >= 0:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class negative_IntegerType(negativeIntegerType):
- _validURIs = (NS.XSD,)
-
- def _typeName(self):
- return 'negative-integer'
-
-class longType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < -9223372036854775808L or \
- data > 9223372036854775807L:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class intType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < -2147483648L or \
- data > 2147483647:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class shortType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < -32768 or \
- data > 32767:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class byteType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < -128 or \
- data > 127:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class nonNegativeIntegerType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or data < 0:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class non_Negative_IntegerType(nonNegativeIntegerType):
- _validURIs = (NS.XSD,)
-
- def _typeName(self):
- return 'non-negative-integer'
-
-class unsignedLongType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < 0 or \
- data > 18446744073709551615L:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class unsignedIntType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < 0 or \
- data > 4294967295L:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class unsignedShortType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < 0 or \
- data > 65535:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class unsignedByteType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or \
- data < 0 or \
- data > 255:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class positiveIntegerType(anyType):
- _validURIs = (NS.XSD2, NS.XSD3, NS.ENC)
-
- def _checkValueSpace(self, data):
- if data == None:
- raise ValueError, "must supply initial %s value" % self._type
-
- if type(data) not in (IntType, LongType) or data <= 0:
- raise ValueError, "invalid %s value" % self._type
-
- return data
-
-class positive_IntegerType(positiveIntegerType):
- _validURIs = (NS.XSD,)
-
- def _typeName(self):
- return 'positive-integer'
-
-# Now compound types
-
-class compoundType(anyType):
- def __init__(self, data = None, name = None, typed = 1, attrs = None):
- if self.__class__ == compoundType:
- raise Error, "a compound can't be instantiated directly"
-
- anyType.__init__(self, data, name, typed, attrs)
- self._aslist = []
- self._asdict = {}
- self._keyord = []
-
- if type(data) == DictType:
- self.__dict__.update(data)
-
- def __getitem__(self, item):
- if type(item) == IntType:
- return self._aslist[item]
- return getattr(self, item)
-
- def __len__(self):
- return len(self._aslist)
-
- def __nonzero__(self):
- return 1
-
- def _keys(self):
- return filter(lambda x: x[0] != '_', self.__dict__.keys())
-
- def _addItem(self, name, value, attrs = None):
- d = self._asdict
-
- if d.has_key(name):
- if type(d[name]) != ListType:
- d[name] = [d[name]]
- d[name].append(value)
- else:
- d[name] = value
-
- self._keyord.append(name)
- self._aslist.append(value)
- self.__dict__[name] = d[name]
-
- def _placeItem(self, name, value, pos, subpos = 0, attrs = None):
- d = self._asdict
-
- if subpos == 0 and type(d[name]) != ListType:
- d[name] = value
- else:
- d[name][subpos] = value
-
- self._keyord[pos] = name
- self._aslist[pos] = value
- self.__dict__[name] = d[name]
-
- def _getItemAsList(self, name, default = []):
- try:
- d = self.__dict__[name]
- except:
- return default
-
- if type(d) == ListType:
- return d
- return [d]
-
-class structType(compoundType):
- pass
-
-class headerType(structType):
- _validURIs = (NS.ENV,)
-
- def __init__(self, data = None, typed = 1, attrs = None):
- structType.__init__(self, data, "Header", typed, attrs)
-
-class bodyType(structType):
- _validURIs = (NS.ENV,)
-
- def __init__(self, data = None, typed = 1, attrs = None):
- structType.__init__(self, data, "Body", typed, attrs)
-
-class arrayType(UserList.UserList, compoundType):
- def __init__(self, data = None, name = None, attrs = None,
- offset = 0, rank = None, asize = 0, elemsname = None):
-
- if data:
- if type(data) not in (ListType, TupleType):
- raise Error, "Data must be a sequence"
-
- UserList.UserList.__init__(self, data)
- compoundType.__init__(self, data, name, 0, attrs)
-
- self._elemsname = elemsname or "item"
-
- if data == None:
- self._rank = rank
-
- # According to 5.4.2.2 in the SOAP spec, each element in a
- # sparse array must have a position. _posstate keeps track of
- # whether we've seen a position or not. It's possible values
- # are:
- # -1 No elements have been added, so the state is indeterminate
- # 0 An element without a position has been added, so no
- # elements can have positions
- # 1 An element with a position has been added, so all elements
- # must have positions
-
- self._posstate = -1
-
- self._full = 0
-
- if asize in ('', None):
- asize = '0'
-
- self._dims = map (lambda x: int(x), str(asize).split(','))
- self._dims.reverse() # It's easier to work with this way
- self._poss = [0] * len(self._dims) # This will end up
- # reversed too
-
- for i in range(len(self._dims)):
- if self._dims[i] < 0 or \
- self._dims[i] == 0 and len(self._dims) > 1:
- raise TypeError, "invalid Array dimensions"
-
- if offset > 0:
- self._poss[i] = offset % self._dims[i]
- offset = int(offset / self._dims[i])
-
- # Don't break out of the loop if offset is 0 so we test all the
- # dimensions for > 0.
- if offset:
- raise AttributeError, "invalid Array offset"
-
- a = [None] * self._dims[0]
-
- for i in range(1, len(self._dims)):
- b = []
-
- for j in range(self._dims[i]):
- b.append(copy.deepcopy(a))
-
- a = b
-
- self.data = a
-
- def _addItem(self, name, value, attrs):
- if self._full:
- raise ValueError, "Array is full"
-
- pos = attrs.get((NS.ENC, 'position'))
-
- if pos != None:
- if self._posstate == 0:
- raise AttributeError, \
- "all elements in a sparse Array must have a " \
- "position attribute"
-
- self._posstate = 1
-
- try:
- if pos[0] == '[' and pos[-1] == ']':
- pos = map (lambda x: int(x), pos[1:-1].split(','))
- pos.reverse()
-
- if len(pos) == 1:
- pos = pos[0]
-
- curpos = [0] * len(self._dims)
-
- for i in range(len(self._dims)):
- curpos[i] = pos % self._dims[i]
- pos = int(pos / self._dims[i])
-
- if pos == 0:
- break
-
- if pos:
- raise Exception
- elif len(pos) != len(self._dims):
- raise Exception
- else:
- for i in range(len(self._dims)):
- if pos[i] >= self._dims[i]:
- raise Exception
-
- curpos = pos
- else:
- raise Exception
- except:
- raise AttributeError, \
- "invalid Array element position %s" % str(pos)
- else:
- if self._posstate == 1:
- raise AttributeError, \
- "only elements in a sparse Array may have a " \
- "position attribute"
-
- self._posstate = 0
-
- curpos = self._poss
-
- a = self.data
-
- for i in range(len(self._dims) - 1, 0, -1):
- a = a[curpos[i]]
-
- if curpos[0] >= len(a):
- a += [None] * (len(a) - curpos[0] + 1)
-
- a[curpos[0]] = value
-
- if pos == None:
- self._poss[0] += 1
-
- for i in range(len(self._dims) - 1):
- if self._poss[i] < self._dims[i]:
- break
-
- self._poss[i] = 0
- self._poss[i + 1] += 1
-
- if self._dims[-1] and self._poss[-1] >= self._dims[-1]:
- self._full = 1
-
- def _placeItem(self, name, value, pos, subpos, attrs = None):
- curpos = [0] * len(self._dims)
-
- for i in range(len(self._dims)):
- if self._dims[i] == 0:
- curpos[0] = pos
- break
-
- curpos[i] = pos % self._dims[i]
- pos = int(pos / self._dims[i])
-
- if pos == 0:
- break
-
- if self._dims[i] != 0 and pos:
- raise Error, "array index out of range"
-
- a = self.data
-
- for i in range(len(self._dims) - 1, 0, -1):
- a = a[curpos[i]]
-
- if curpos[0] >= len(a):
- a += [None] * (len(a) - curpos[0] + 1)
-
- a[curpos[0]] = value
-
-class typedArrayType(arrayType):
- def __init__(self, data = None, name = None, typed = None, attrs = None,
- offset = 0, rank = None, asize = 0, elemsname = None):
-
- arrayType.__init__(self, data, name, attrs, offset, rank, asize,
- elemsname)
-
- self._type = typed
-
-class faultType(structType, Error):
- def __init__(self, faultcode = "", faultstring = "", detail = None):
- self.faultcode = faultcode
- self.faultstring = faultstring
- if detail != None:
- self.detail = detail
-
- structType.__init__(self, None, 0)
-
- def _setDetail(self, detail = None):
- if detail != None:
- self.detail = detail
- else:
- try: del self.detail
- except AttributeError: pass
-
- def __repr__(self):
- return "" % (self.faultcode, self.faultstring)
-
- __str__ = __repr__
-
-################################################################################
-class RefHolder:
- def __init__(self, name, frame):
- self.name = name
- self.parent = frame
- self.pos = len(frame)
- self.subpos = frame.namecounts.get(name, 0)
-
- def __repr__(self):
- return "<%s %s at %d>" % (self.__class__, self.name, id(self))
-
-################################################################################
-# Utility infielders
-################################################################################
-def collapseWhiteSpace(s):
- return re.sub('\s+', ' ', s).strip()
-
-def decodeHexString(data):
- conv = {'0': 0x0, '1': 0x1, '2': 0x2, '3': 0x3, '4': 0x4,
- '5': 0x5, '6': 0x6, '7': 0x7, '8': 0x8, '9': 0x9, 'a': 0xa,
- 'b': 0xb, 'c': 0xc, 'd': 0xd, 'e': 0xe, 'f': 0xf, 'A': 0xa,
- 'B': 0xb, 'C': 0xc, 'D': 0xd, 'E': 0xe, 'F': 0xf,}
- ws = string.whitespace
-
- bin = ''
-
- i = 0
-
- while i < len(data):
- if data[i] not in ws:
- break
- i += 1
-
- low = 0
-
- while i < len(data):
- c = data[i]
-
- if c in string.whitespace:
- break
-
- try:
- c = conv[c]
- except KeyError:
- raise ValueError, \
- "invalid hex string character `%s'" % c
-
- if low:
- bin += chr(high * 16 + c)
- low = 0
- else:
- high = c
- low = 1
-
- i += 1
-
- if low:
- raise ValueError, "invalid hex string length"
-
- while i < len(data):
- if data[i] not in string.whitespace:
- raise ValueError, \
- "invalid hex string character `%s'" % c
-
- i += 1
-
- return bin
-
-def encodeHexString(data):
- h = ''
-
- for i in data:
- h += "%02X" % ord(i)
-
- return h
-
-def leapMonth(year, month):
- return month == 2 and \
- year % 4 == 0 and \
- (year % 100 != 0 or year % 400 == 0)
-
-def cleanDate(d, first = 0):
- ranges = (None, (1, 12), (1, 31), (0, 23), (0, 59), (0, 61))
- months = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
- names = ('year', 'month', 'day', 'hours', 'minutes', 'seconds')
-
- if len(d) != 6:
- raise ValueError, "date must have 6 elements"
-
- for i in range(first, 6):
- s = d[i]
-
- if type(s) == FloatType:
- if i < 5:
- try:
- s = int(s)
- except OverflowError:
- if i > 0:
- raise
- s = long(s)
-
- if s != d[i]:
- raise ValueError, "%s must be integral" % names[i]
-
- d[i] = s
- elif type(s) == LongType:
- try: s = int(s)
- except: pass
- elif type(s) != IntType:
- raise TypeError, "%s isn't a valid type" % names[i]
-
- if i == first and s < 0:
- continue
-
- if ranges[i] != None and \
- (s < ranges[i][0] or ranges[i][1] < s):
- raise ValueError, "%s out of range" % names[i]
-
- if first < 6 and d[5] >= 61:
- raise ValueError, "seconds out of range"
-
- if first < 2:
- leap = first < 1 and leapMonth(d[0], d[1])
-
- if d[2] > months[d[1]] + leap:
- raise ValueError, "day out of range"
-
-class UnderflowError(exceptions.ArithmeticError):
- pass
-
-def debugHeader(title):
- s = '*** ' + title + ' '
- print s + ('*' * (72 - len(s)))
-
-def debugFooter(title):
- print '*' * 72
- sys.stdout.flush()
-
-################################################################################
-# SOAP Parser
-################################################################################
-class SOAPParser(xml.sax.handler.ContentHandler):
- class Frame:
- def __init__(self, name, kind = None, attrs = {}, rules = {}):
- self.name = name
- self.kind = kind
- self.attrs = attrs
- self.rules = rules
-
- self.contents = []
- self.names = []
- self.namecounts = {}
- self.subattrs = []
-
- def append(self, name, data, attrs):
- self.names.append(name)
- self.contents.append(data)
- self.subattrs.append(attrs)
-
- if self.namecounts.has_key(name):
- self.namecounts[name] += 1
- else:
- self.namecounts[name] = 1
-
- def _placeItem(self, name, value, pos, subpos = 0, attrs = None):
- self.contents[pos] = value
-
- if attrs:
- self.attrs.update(attrs)
-
- def __len__(self):
- return len(self.contents)
-
- def __repr__(self):
- return "<%s %s at %d>" % (self.__class__, self.name, id(self))
-
- def __init__(self, rules = None):
- xml.sax.handler.ContentHandler.__init__(self)
- self.body = None
- self.header = None
- self.attrs = {}
- self._data = None
- self._next = "E" # Keeping state for message validity
- self._stack = [self.Frame('SOAP')]
-
- # Make two dictionaries to store the prefix <-> URI mappings, and
- # initialize them with the default
- self._prem = {NS.XML_T: NS.XML}
- self._prem_r = {NS.XML: NS.XML_T}
- self._ids = {}
- self._refs = {}
- self._rules = rules
-
- def startElementNS(self, name, qname, attrs):
- # Workaround two sax bugs
- if name[0] == None and name[1][0] == ' ':
- name = (None, name[1][1:])
- else:
- name = tuple(name)
-
- # First some checking of the layout of the message
-
- if self._next == "E":
- if name[1] != 'Envelope':
- raise Error, "expected `SOAP-ENV:Envelope', got `%s:%s'" % \
- (self._prem_r[name[0]], name[1])
- if name[0] != NS.ENV:
- raise faultType, ("%s:VersionMismatch" % NS.ENV_T,
- "Don't understand version `%s' Envelope" % name[0])
- else:
- self._next = "HorB"
- elif self._next == "HorB":
- if name[0] == NS.ENV and name[1] in ("Header", "Body"):
- self._next = None
- else:
- raise Error, \
- "expected `SOAP-ENV:Header' or `SOAP-ENV:Body', " \
- "got `%s'" % self._prem_r[name[0]] + ':' + name[1]
- elif self._next == "B":
- if name == (NS.ENV, "Body"):
- self._next = None
- else:
- raise Error, "expected `SOAP-ENV:Body', got `%s'" % \
- self._prem_r[name[0]] + ':' + name[1]
- elif self._next == "":
- raise Error, "expected nothing, got `%s'" % \
- self._prem_r[name[0]] + ':' + name[1]
-
- if len(self._stack) == 2:
- rules = self._rules
- else:
- try:
- rules = self._stack[-1].rules[name[1]]
- except:
- rules = None
-
- if type(rules) not in (NoneType, DictType):
- kind = rules
- else:
- kind = attrs.get((NS.ENC, 'arrayType'))
-
- if kind != None:
- del attrs._attrs[(NS.ENC, 'arrayType')]
-
- i = kind.find(':')
- if i >= 0:
- kind = (self._prem[kind[:i]], kind[i + 1:])
- else:
- kind = None
-
- self.pushFrame(self.Frame(name[1], kind, attrs._attrs, rules))
-
- self._data = '' # Start accumulating
-
- def pushFrame(self, frame):
- self._stack.append(frame)
-
- def popFrame(self):
- return self._stack.pop()
-
- def endElementNS(self, name, qname):
- # Workaround two sax bugs
- if name[0] == None and name[1][0] == ' ':
- ns, name = None, name[1][1:]
- else:
- ns, name = tuple(name)
-
- if self._next == "E":
- raise Error, "didn't get SOAP-ENV:Envelope"
- if self._next in ("HorB", "B"):
- raise Error, "didn't get SOAP-ENV:Body"
-
- cur = self.popFrame()
- attrs = cur.attrs
-
- idval = None
-
- if attrs.has_key((None, 'id')):
- idval = attrs[(None, 'id')]
-
- if self._ids.has_key(idval):
- raise Error, "duplicate id `%s'" % idval
-
- del attrs[(None, 'id')]
-
- root = 1
-
- if len(self._stack) == 3:
- if attrs.has_key((NS.ENC, 'root')):
- root = int(attrs[(NS.ENC, 'root')])
-
- # Do some preliminary checks. First, if root="0" is present,
- # the element must have an id. Next, if root="n" is present,
- # n something other than 0 or 1, raise an exception.
-
- if root == 0:
- if idval == None:
- raise Error, "non-root element must have an id"
- elif root != 1:
- raise Error, "SOAP-ENC:root must be `0' or `1'"
-
- del attrs[(NS.ENC, 'root')]
-
- while 1:
- href = attrs.get((None, 'href'))
- if href:
- if href[0] != '#':
- raise Error, "only do local hrefs right now"
- if self._data != None and self._data.strip() != '':
- raise Error, "hrefs can't have data"
-
- href = href[1:]
-
- if self._ids.has_key(href):
- data = self._ids[href]
- else:
- data = RefHolder(name, self._stack[-1])
-
- if self._refs.has_key(href):
- self._refs[href].append(data)
- else:
- self._refs[href] = [data]
-
- del attrs[(None, 'href')]
-
- break
-
- kind = None
-
- if attrs:
- for i in NS.XSI_L:
- if attrs.has_key((i, 'type')):
- kind = attrs[(i, 'type')]
- del attrs[(i, 'type')]
-
- if kind != None:
- i = kind.find(':')
- if i >= 0:
- kind = (self._prem[kind[:i]], kind[i + 1:])
- else:
-# XXX What to do here? (None, kind) is just going to fail in convertType
- kind = (None, kind)
-
- null = 0
-
- if attrs:
- for i in (NS.XSI, NS.XSI2):
- if attrs.has_key((i, 'null')):
- null = attrs[(i, 'null')]
- del attrs[(i, 'null')]
-
- if attrs.has_key((NS.XSI3, 'nil')):
- null = attrs[(NS.XSI3, 'nil')]
- del attrs[(NS.XSI3, 'nil')]
-
- #MAP 4/12/2002 - must also support "true"
- #null = int(null)
- null = (str(null).lower() in ['true', '1'])
-
- if null:
- if len(cur) or \
- (self._data != None and self._data.strip() != ''):
- raise Error, "nils can't have data"
-
- data = None
-
- break
-
- if len(self._stack) == 2:
- if (ns, name) == (NS.ENV, "Header"):
- self.header = data = headerType(attrs = attrs)
- self._next = "B"
- break
- elif (ns, name) == (NS.ENV, "Body"):
- self.body = data = bodyType(attrs = attrs)
- self._next = ""
- break
- elif len(self._stack) == 3 and self._next == None:
- if (ns, name) == (NS.ENV, "Fault"):
- data = faultType()
- self._next = ""
- break
-
- if cur.rules != None:
- rule = cur.rules
-
- if type(rule) in (StringType, UnicodeType):
-# XXX Need a namespace here
- rule = (None, rule)
- elif type(rule) == ListType:
- rule = tuple(rule)
-
-# XXX What if rule != kind?
- if callable(rule):
- data = rule(self._data)
- elif type(rule) == DictType:
- data = structType(name = (ns, name), attrs = attrs)
- else:
- data = self.convertType(self._data, rule, attrs)
-
- break
-
- if (kind == None and cur.kind != None) or \
- (kind == (NS.ENC, 'Array')):
- kind = cur.kind
-
- if kind == None:
- kind = 'ur-type[%d]' % len(cur)
- else:
- kind = kind[1]
-
- if len(cur.namecounts) == 1:
- elemsname = cur.names[0]
- else:
- elemsname = None
-
- data = self.startArray((ns, name), kind, attrs, elemsname)
-
- break
-
- if len(self._stack) == 3 and kind == None and \
- len(cur) == 0 and \
- (self._data == None or self._data.strip() == ''):
- data = structType(name = (ns, name), attrs = attrs)
- break
-
- if len(cur) == 0 and ns != NS.URN:
- # Nothing's been added to the current frame so it must be a
- # simple type.
-
- if kind == None:
- # If the current item's container is an array, it will
- # have a kind. If so, get the bit before the first [,
- # which is the type of the array, therefore the type of
- # the current item.
-
- kind = self._stack[-1].kind
-
- if kind != None:
- i = kind[1].find('[')
- if i >= 0:
- kind = (kind[0], kind[1][:i])
- elif ns != None:
- kind = (ns, name)
-
- if kind != None:
- try:
- data = self.convertType(self._data, kind, attrs)
- except UnknownTypeError:
- data = None
- else:
- data = None
-
- if data == None:
- data = self._data or ''
-
- if len(attrs) == 0:
- try: data = str(data)
- except: pass
-
- break
-
- data = structType(name = (ns, name), attrs = attrs)
-
- break
-
- if isinstance(data, compoundType):
- for i in range(len(cur)):
- v = cur.contents[i]
- data._addItem(cur.names[i], v, cur.subattrs[i])
-
- if isinstance(v, RefHolder):
- v.parent = data
-
- if root:
- self._stack[-1].append(name, data, attrs)
-
- if idval != None:
- self._ids[idval] = data
-
- if self._refs.has_key(idval):
- for i in self._refs[idval]:
- i.parent._placeItem(i.name, data, i.pos, i.subpos, attrs)
-
- del self._refs[idval]
-
- self.attrs[id(data)] = attrs
-
- if isinstance(data, anyType):
- data._setAttrs(attrs)
-
- self._data = None # Stop accumulating
-
- def endDocument(self):
- if len(self._refs) == 1:
- raise Error, \
- "unresolved reference " + self._refs.keys()[0]
- elif len(self._refs) > 1:
- raise Error, \
- "unresolved references " + ', '.join(self._refs.keys())
-
- def startPrefixMapping(self, prefix, uri):
- self._prem[prefix] = uri
- self._prem_r[uri] = prefix
-
- def endPrefixMapping(self, prefix):
- try:
- del self._prem_r[self._prem[prefix]]
- del self._prem[prefix]
- except:
- pass
-
- def characters(self, c):
- if self._data != None:
- self._data += c
-
- arrayre = '^(?:(?P[^:]*):)?' \
- '(?P[^[]+)' \
- '(?:\[(?P,*)\])?' \
- '(?:\[(?P\d+(?:,\d+)*)?\])$'
-
- def startArray(self, name, kind, attrs, elemsname):
- if type(self.arrayre) == StringType:
- self.arrayre = re.compile (self.arrayre)
-
- offset = attrs.get((NS.ENC, "offset"))
-
- if offset != None:
- del attrs[(NS.ENC, "offset")]
-
- try:
- if offset[0] == '[' and offset[-1] == ']':
- offset = int(offset[1:-1])
- if offset < 0:
- raise Exception
- else:
- raise Exception
- except:
- raise AttributeError, "invalid Array offset"
- else:
- offset = 0
-
- try:
- m = self.arrayre.search(kind)
-
- if m == None:
- raise Exception
-
- t = m.group('type')
-
- if t == 'ur-type':
- return arrayType(None, name, attrs, offset, m.group('rank'),
- m.group('asize'), elemsname)
- elif m.group('ns') != None:
- return typedArrayType(None, name,
- (self._prem[m.group('ns')], t), attrs, offset,
- m.group('rank'), m.group('asize'), elemsname)
- else:
- return typedArrayType(None, name, (None, t), attrs, offset,
- m.group('rank'), m.group('asize'), elemsname)
- except:
- raise AttributeError, "invalid Array type `%s'" % kind
-
- # Conversion
-
- class DATETIMECONSTS:
- SIGNre = '(?P-?)'
- CENTURYre = '(?P\d{2,})'
- YEARre = '(?P\d{2})'
- MONTHre = '(?P\d{2})'
- DAYre = '(?P\d{2})'
- HOURre = '(?P\d{2})'
- MINUTEre = '(?P\d{2})'
- SECONDre = '(?P\d{2}(?:\.\d*)?)'
- TIMEZONEre = '(?PZ)|(?P[-+])(?P\d{2}):' \
- '(?P\d{2})'
- BOSre = '^\s*'
- EOSre = '\s*$'
-
- __allres = {'sign': SIGNre, 'century': CENTURYre, 'year': YEARre,
- 'month': MONTHre, 'day': DAYre, 'hour': HOURre,
- 'minute': MINUTEre, 'second': SECONDre, 'timezone': TIMEZONEre,
- 'b': BOSre, 'e': EOSre}
-
- dateTime = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)sT' \
- '%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % __allres
- timeInstant = dateTime
- timePeriod = dateTime
- time = '%(b)s%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % \
- __allres
- date = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)s' \
- '(%(timezone)s)?%(e)s' % __allres
- century = '%(b)s%(sign)s%(century)s(%(timezone)s)?%(e)s' % __allres
- gYearMonth = '%(b)s%(sign)s%(century)s%(year)s-%(month)s' \
- '(%(timezone)s)?%(e)s' % __allres
- gYear = '%(b)s%(sign)s%(century)s%(year)s(%(timezone)s)?%(e)s' % \
- __allres
- year = gYear
- gMonthDay = '%(b)s--%(month)s-%(day)s(%(timezone)s)?%(e)s' % __allres
- recurringDate = gMonthDay
- gDay = '%(b)s---%(day)s(%(timezone)s)?%(e)s' % __allres
- recurringDay = gDay
- gMonth = '%(b)s--%(month)s--(%(timezone)s)?%(e)s' % __allres
- month = gMonth
-
- recurringInstant = '%(b)s%(sign)s(%(century)s|-)(%(year)s|-)-' \
- '(%(month)s|-)-(%(day)s|-)T' \
- '(%(hour)s|-):(%(minute)s|-):(%(second)s|-)' \
- '(%(timezone)s)?%(e)s' % __allres
-
- duration = '%(b)s%(sign)sP' \
- '((?P\d+)Y)?' \
- '((?P\d+)M)?' \
- '((?P\d+)D)?' \
- '((?PT)' \
- '((?P\d+)H)?' \
- '((?P\d+)M)?' \
- '((?P\d*(?:\.\d*)?)S)?)?%(e)s' % \
- __allres
-
- timeDuration = duration
-
- # The extra 31 on the front is:
- # - so the tuple is 1-based
- # - so months[month-1] is December's days if month is 1
-
- months = (31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
-
- def convertDateTime(self, value, kind):
- def getZoneOffset(d):
- zoffs = 0
-
- try:
- if d['zulu'] == None:
- zoffs = 60 * int(d['tzhour']) + int(d['tzminute'])
- if d['tzsign'] != '-':
- zoffs = -zoffs
- except TypeError:
- pass
-
- return zoffs
-
- def applyZoneOffset(months, zoffs, date, minfield, posday = 1):
- if zoffs == 0 and (minfield > 4 or 0 <= date[5] < 60):
- return date
-
- if minfield > 5: date[5] = 0
- if minfield > 4: date[4] = 0
-
- if date[5] < 0:
- date[4] += int(date[5]) / 60
- date[5] %= 60
-
- date[4] += zoffs
-
- if minfield > 3 or 0 <= date[4] < 60: return date
-
- date[3] += date[4] / 60
- date[4] %= 60
-
- if minfield > 2 or 0 <= date[3] < 24: return date
-
- date[2] += date[3] / 24
- date[3] %= 24
-
- if minfield > 1:
- if posday and date[2] <= 0:
- date[2] += 31 # zoffs is at most 99:59, so the
- # day will never be less than -3
- return date
-
- while 1:
- # The date[1] == 3 (instead of == 2) is because we're
- # going back a month, so we need to know if the previous
- # month is February, so we test if this month is March.
-
- leap = minfield == 0 and date[1] == 3 and \
- date[0] % 4 == 0 and \
- (date[0] % 100 != 0 or date[0] % 400 == 0)
-
- if 0 < date[2] <= months[date[1]] + leap: break
-
- date[2] += months[date[1] - 1] + leap
-
- date[1] -= 1
-
- if date[1] > 0: break
-
- date[1] = 12
-
- if minfield > 0: break
-
- date[0] -= 1
-
- return date
-
- try:
- exp = getattr(self.DATETIMECONSTS, kind)
- except AttributeError:
- return None
-
- if type(exp) == StringType:
- exp = re.compile(exp)
- setattr (self.DATETIMECONSTS, kind, exp)
-
- m = exp.search(value)
-
- try:
- if m == None:
- raise Exception
-
- d = m.groupdict()
- f = ('century', 'year', 'month', 'day',
- 'hour', 'minute', 'second')
- fn = len(f) # Index of first non-None value
- r = []
-
- if kind in ('duration', 'timeDuration'):
- if d['sep'] != None and d['hour'] == None and \
- d['minute'] == None and d['second'] == None:
- raise Exception
-
- f = f[1:]
-
- for i in range(len(f)):
- s = d[f[i]]
-
- if s != None:
- if f[i] == 'second':
- s = float(s)
- else:
- try: s = int(s)
- except ValueError: s = long(s)
-
- if i < fn: fn = i
-
- r.append(s)
-
- if fn > len(r): # Any non-Nones?
- raise Exception
-
- if d['sign'] == '-':
- r[fn] = -r[fn]
-
- return tuple(r)
-
- if kind == 'recurringInstant':
- for i in range(len(f)):
- s = d[f[i]]
-
- if s == None or s == '-':
- if i > fn:
- raise Exception
- s = None
- else:
- if i < fn:
- fn = i
-
- if f[i] == 'second':
- s = float(s)
- else:
- try:
- s = int(s)
- except ValueError:
- s = long(s)
-
- r.append(s)
-
- s = r.pop(0)
-
- if fn == 0:
- r[0] += s * 100
- else:
- fn -= 1
-
- if fn < len(r) and d['sign'] == '-':
- r[fn] = -r[fn]
-
- cleanDate(r, fn)
-
- return tuple(applyZoneOffset(self.DATETIMECONSTS.months,
- getZoneOffset(d), r, fn, 0))
-
- r = [0, 0, 1, 1, 0, 0, 0]
-
- for i in range(len(f)):
- field = f[i]
-
- s = d.get(field)
-
- if s != None:
- if field == 'second':
- s = float(s)
- else:
- try:
- s = int(s)
- except ValueError:
- s = long(s)
-
- if i < fn:
- fn = i
-
- r[i] = s
-
- if fn > len(r): # Any non-Nones?
- raise Exception
-
- s = r.pop(0)
-
- if fn == 0:
- r[0] += s * 100
- else:
- fn -= 1
-
- if d.get('sign') == '-':
- r[fn] = -r[fn]
-
- cleanDate(r, fn)
-
- zoffs = getZoneOffset(d)
-
- if zoffs:
- r = applyZoneOffset(self.DATETIMECONSTS.months, zoffs, r, fn)
-
- if kind == 'century':
- return r[0] / 100
-
- s = []
-
- for i in range(1, len(f)):
- if d.has_key(f[i]):
- s.append(r[i - 1])
-
- if len(s) == 1:
- return s[0]
- return tuple(s)
- except Exception, e:
- raise Error, "invalid %s value `%s' - %s" % (kind, value, e)
-
- intlimits = \
- {
- 'nonPositiveInteger': (0, None, 0),
- 'non-positive-integer': (0, None, 0),
- 'negativeInteger': (0, None, -1),
- 'negative-integer': (0, None, -1),
- 'long': (1, -9223372036854775808L,
- 9223372036854775807L),
- 'int': (0, -2147483648L, 2147483647),
- 'short': (0, -32768, 32767),
- 'byte': (0, -128, 127),
- 'nonNegativeInteger': (0, 0, None),
- 'non-negative-integer': (0, 0, None),
- 'positiveInteger': (0, 1, None),
- 'positive-integer': (0, 1, None),
- 'unsignedLong': (1, 0, 18446744073709551615L),
- 'unsignedInt': (0, 0, 4294967295L),
- 'unsignedShort': (0, 0, 65535),
- 'unsignedByte': (0, 0, 255),
- }
- floatlimits = \
- {
- 'float': (7.0064923216240861E-46, -3.4028234663852886E+38,
- 3.4028234663852886E+38),
- 'double': (2.4703282292062327E-324, -1.7976931348623158E+308,
- 1.7976931348623157E+308),
- }
- zerofloatre = '[1-9]'
-
- def convertType(self, d, t, attrs):
- dnn = d or ''
-
- if t[0] in NS.EXSD_L:
- if t[1] == "integer":
- try:
- d = int(d)
- if len(attrs):
- d = long(d)
- except:
- d = long(d)
- return d
- if self.intlimits.has_key (t[1]):
- l = self.intlimits[t[1]]
- try: d = int(d)
- except: d = long(d)
-
- if l[1] != None and d < l[1]:
- raise UnderflowError, "%s too small" % d
- if l[2] != None and d > l[2]:
- raise OverflowError, "%s too large" % d
-
- if l[0] or len(attrs):
- return long(d)
- return d
- if t[1] == "string":
- if len(attrs):
- return unicode(dnn)
- try:
- return str(dnn)
- except:
- return dnn
- if t[1] == "boolean":
- d = d.strip().lower()
- if d in ('0', 'false'):
- return 0
- if d in ('1', 'true'):
- return 1
- raise AttributeError, "invalid boolean value"
- if self.floatlimits.has_key (t[1]):
- l = self.floatlimits[t[1]]
- s = d.strip().lower()
- try:
- d = float(s)
- except:
- # Some platforms don't implement the float stuff. This
- # is close, but NaN won't be > "INF" as required by the
- # standard.
-
- if s in ("nan", "inf"):
- return 1e300**2
- if s == "-inf":
- return -1e300**2
-
- raise
-
- if str (d) == 'nan':
- if s != 'nan':
- raise ValueError, "invalid %s" % t[1]
- elif str (d) == '-inf':
- if s != '-inf':
- raise UnderflowError, "%s too small" % t[1]
- elif str (d) == 'inf':
- if s != 'inf':
- raise OverflowError, "%s too large" % t[1]
- elif d < 0:
- if d < l[1]:
- raise UnderflowError, "%s too small" % t[1]
- elif d > 0:
- if d < l[0] or d > l[2]:
- raise OverflowError, "%s too large" % t[1]
- elif d == 0:
- if type(self.zerofloatre) == StringType:
- self.zerofloatre = re.compile(self.zerofloatre)
-
- if self.zerofloatre.search(s):
- raise UnderflowError, "invalid %s" % t[1]
-
- return d
- if t[1] in ("dateTime", "date", "timeInstant", "time"):
- return self.convertDateTime(d, t[1])
- if t[1] == "decimal":
- return float(d)
- if t[1] in ("language", "QName", "NOTATION", "NMTOKEN", "Name",
- "NCName", "ID", "IDREF", "ENTITY"):
- return collapseWhiteSpace(d)
- if t[1] in ("IDREFS", "ENTITIES", "NMTOKENS"):
- d = collapseWhiteSpace(d)
- return d.split()
- if t[0] in NS.XSD_L:
- if t[1] in ("base64", "base64Binary"):
- return base64.decodestring(d)
- if t[1] == "hexBinary":
- return decodeHexString(d)
- if t[1] == "anyURI":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] in ("normalizedString", "token"):
- return collapseWhiteSpace(d)
- if t[0] == NS.ENC:
- if t[1] == "base64":
- return base64.decodestring(d)
- if t[0] == NS.XSD:
- if t[1] == "binary":
- try:
- e = attrs[(None, 'encoding')]
-
- if e == 'hex':
- return decodeHexString(d)
- elif e == 'base64':
- return base64.decodestring(d)
- except:
- pass
-
- raise Error, "unknown or missing binary encoding"
- if t[1] == "uri":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] == "recurringInstant":
- return self.convertDateTime(d, t[1])
- if t[0] in (NS.XSD2, NS.ENC):
- if t[1] == "uriReference":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] == "timePeriod":
- return self.convertDateTime(d, t[1])
- if t[1] in ("century", "year"):
- return self.convertDateTime(d, t[1])
- if t[0] in (NS.XSD, NS.XSD2, NS.ENC):
- if t[1] == "timeDuration":
- return self.convertDateTime(d, t[1])
- if t[0] == NS.XSD3:
- if t[1] == "anyURI":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] in ("gYearMonth", "gMonthDay"):
- return self.convertDateTime(d, t[1])
- if t[1] == "gYear":
- return self.convertDateTime(d, t[1])
- if t[1] == "gMonth":
- return self.convertDateTime(d, t[1])
- if t[1] == "gDay":
- return self.convertDateTime(d, t[1])
- if t[1] == "duration":
- return self.convertDateTime(d, t[1])
- if t[0] in (NS.XSD2, NS.XSD3):
- if t[1] == "token":
- return collapseWhiteSpace(d)
- if t[1] == "recurringDate":
- return self.convertDateTime(d, t[1])
- if t[1] == "month":
- return self.convertDateTime(d, t[1])
- if t[1] == "recurringDay":
- return self.convertDateTime(d, t[1])
- if t[0] == NS.XSD2:
- if t[1] == "CDATA":
- return collapseWhiteSpace(d)
-
- raise UnknownTypeError, "unknown type `%s'" % (t[0] + ':' + t[1])
-
-################################################################################
-# call to SOAPParser that keeps all of the info
-################################################################################
-def _parseSOAP(xml_str, rules = None):
- try:
- from cStringIO import StringIO
- except ImportError:
- from StringIO import StringIO
-
- parser = xml.sax.make_parser()
- t = SOAPParser(rules = rules)
- parser.setContentHandler(t)
- e = xml.sax.handler.ErrorHandler()
- parser.setErrorHandler(e)
-
- inpsrc = xml.sax.xmlreader.InputSource()
- inpsrc.setByteStream(StringIO(xml_str))
-
- # turn on namespace mangeling
- parser.setFeature(xml.sax.handler.feature_namespaces,1)
-
- parser.parse(inpsrc)
-
- return t
-
-################################################################################
-# SOAPParser's more public interface
-################################################################################
-def parseSOAP(xml_str, attrs = 0):
- t = _parseSOAP(xml_str)
-
- if attrs:
- return t.body, t.attrs
- return t.body
-
-
-def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None):
- t = _parseSOAP(xml_str, rules = rules)
- p = t.body._aslist[0]
-
- # Empty string, for RPC this translates into a void
- if type(p) in (type(''), type(u'')) and p in ('', u''):
- name = "Response"
- for k in t.body.__dict__.keys():
- if k[0] != "_":
- name = k
- p = structType(name)
-
- if header or body or attrs:
- ret = (p,)
- if header : ret += (t.header,)
- if body: ret += (t.body,)
- if attrs: ret += (t.attrs,)
- return ret
- else:
- return p
-
-
-################################################################################
-# SOAP Builder
-################################################################################
-class SOAPBuilder:
- _xml_top = '\n'
- _xml_enc_top = '\n'
- _env_top = '%(ENV_T)s:Envelope %(ENV_T)s:encodingStyle="%(ENC)s"' % \
- NS.__dict__
- _env_bot = '%(ENV_T)s:Envelope>\n' % NS.__dict__
-
- # Namespaces potentially defined in the Envelope tag.
-
- _env_ns = {NS.ENC: NS.ENC_T, NS.ENV: NS.ENV_T,
- NS.XSD: NS.XSD_T, NS.XSD2: NS.XSD2_T, NS.XSD3: NS.XSD3_T,
- NS.XSI: NS.XSI_T, NS.XSI2: NS.XSI2_T, NS.XSI3: NS.XSI3_T}
-
- def __init__(self, args = (), kw = {}, method = None, namespace = None,
- header = None, methodattrs = None, envelope = 1, encoding = 'UTF-8',
- use_refs = 0, config = Config):
-
- # Test the encoding, raising an exception if it's not known
- if encoding != None:
- ''.encode(encoding)
-
- self.args = args
- self.kw = kw
- self.envelope = envelope
- self.encoding = encoding
- self.method = method
- self.namespace = namespace
- self.header = header
- self.methodattrs= methodattrs
- self.use_refs = use_refs
- self.config = config
- self.out = ''
- self.tcounter = 0
- self.ncounter = 1
- self.icounter = 1
- self.envns = {}
- self.ids = {}
- self.depth = 0
- self.multirefs = []
- self.multis = 0
- self.body = not isinstance(args, bodyType)
-
- def build(self):
- ns_map = {}
-
- # Cache whether typing is on or not
- typed = self.config.typed
-
- if self.header:
- # Create a header.
- self.dump(self.header, "Header", typed = typed)
- self.header = None # Wipe it out so no one is using it.
- if self.body:
- # Call genns to record that we've used SOAP-ENV.
- self.depth += 1
- body_ns = self.genns(ns_map, NS.ENV)[0]
- self.out += "<%sBody>\n" % body_ns
-
- if self.method:
- self.depth += 1
- a = ''
- if self.methodattrs:
- for (k, v) in self.methodattrs.items():
- a += ' %s="%s"' % (k, v)
-
- if self.namespace: # Use the namespace info handed to us
- methodns, n = self.genns(ns_map, self.namespace)
- else:
- methodns, n = '', ''
-
- self.out += '<%s%s%s%s%s>\n' % \
- (methodns, self.method, n, a, self.genroot(ns_map))
-
- try:
- if type(self.args) != TupleType:
- args = (self.args,)
- else:
- args = self.args
-
- for i in args:
- self.dump(i, typed = typed, ns_map = ns_map)
-
- for (k, v) in self.kw.items():
- self.dump(v, k, typed = typed, ns_map = ns_map)
- except RecursionError:
- if self.use_refs == 0:
- # restart
- b = SOAPBuilder(args = self.args, kw = self.kw,
- method = self.method, namespace = self.namespace,
- header = self.header, methodattrs = self.methodattrs,
- envelope = self.envelope, encoding = self.encoding,
- use_refs = 1, config = self.config)
- return b.build()
- raise
-
- if self.method:
- self.out += "%s%s>\n" % (methodns, self.method)
- self.depth -= 1
-
- if self.body:
- # dump may add to self.multirefs, but the for loop will keep
- # going until it has used all of self.multirefs, even those
- # entries added while in the loop.
-
- self.multis = 1
-
- for obj, tag in self.multirefs:
- self.dump(obj, tag, typed = typed, ns_map = ns_map)
-
- self.out += "%sBody>\n" % body_ns
- self.depth -= 1
-
- if self.envelope:
- e = map (lambda ns: 'xmlns:%s="%s"' % (ns[1], ns[0]),
- self.envns.items())
-
- self.out = '<' + self._env_top + ' '.join([''] + e) + '>\n' + \
- self.out + \
- self._env_bot
-
- if self.encoding != None:
- self.out = self._xml_enc_top % self.encoding + self.out
-
- return self.out.encode(self.encoding)
-
- return self._xml_top + self.out
-
- def gentag(self):
- self.tcounter += 1
- return "v%d" % self.tcounter
-
- def genns(self, ns_map, nsURI):
- if nsURI == None:
- return ('', '')
-
- if type(nsURI) == TupleType: # already a tuple
- if len(nsURI) == 2:
- ns, nsURI = nsURI
- else:
- ns, nsURI = None, nsURI[0]
- else:
- ns = None
-
- if ns_map.has_key(nsURI):
- return (ns_map[nsURI] + ':', '')
-
- if self._env_ns.has_key(nsURI):
- ns = self.envns[nsURI] = ns_map[nsURI] = self._env_ns[nsURI]
- return (ns + ':', '')
-
- if not ns:
- ns = "ns%d" % self.ncounter
- self.ncounter += 1
- ns_map[nsURI] = ns
- if self.config.buildWithNamespacePrefix:
- return (ns + ':', ' xmlns:%s="%s"' % (ns, nsURI))
- else:
- return ('', ' xmlns="%s"' % (nsURI))
-
- def genroot(self, ns_map):
- if self.depth != 2:
- return ''
-
- ns, n = self.genns(ns_map, NS.ENC)
- return ' %sroot="%d"%s' % (ns, not self.multis, n)
-
- # checkref checks an element to see if it needs to be encoded as a
- # multi-reference element or not. If it returns None, the element has
- # been handled and the caller can continue with subsequent elements.
- # If it returns a string, the string should be included in the opening
- # tag of the marshaled element.
-
- def checkref(self, obj, tag, ns_map):
- if self.depth < 2:
- return ''
-
- if not self.ids.has_key(id(obj)):
- n = self.ids[id(obj)] = self.icounter
- self.icounter = n + 1
-
- if self.use_refs == 0:
- return ''
-
- if self.depth == 2:
- return ' id="i%d"' % n
-
- self.multirefs.append((obj, tag))
- else:
- if self.use_refs == 0:
- raise RecursionError, "Cannot serialize recursive object"
-
- n = self.ids[id(obj)]
-
- if self.multis and self.depth == 2:
- return ' id="i%d"' % n
-
- self.out += '<%s href="#i%d"%s/>\n' % (tag, n, self.genroot(ns_map))
- return None
-
- # dumpers
-
- def dump(self, obj, tag = None, typed = 1, ns_map = {}):
- ns_map = ns_map.copy()
- self.depth += 1
-
- if type(tag) not in (NoneType, StringType, UnicodeType):
- raise KeyError, "tag must be a string or None"
-
- try:
- meth = getattr(self, "dump_" + type(obj).__name__)
- meth(obj, tag, typed, ns_map)
- except AttributeError:
- if type(obj) == LongType:
- obj_type = "integer"
- else:
- obj_type = type(obj).__name__
-
- self.out += self.dumper(None, obj_type, obj, tag, typed,
- ns_map, self.genroot(ns_map))
-
- self.depth -= 1
-
- # generic dumper
- def dumper(self, nsURI, obj_type, obj, tag, typed = 1, ns_map = {},
- rootattr = '', id = '',
- xml = '<%(tag)s%(type)s%(id)s%(attrs)s%(root)s>%(data)s%(tag)s>\n'):
-
- if nsURI == None:
- nsURI = self.config.typesNamespaceURI
-
- tag = tag or self.gentag()
-
- a = n = t = ''
- if typed and obj_type:
- ns, n = self.genns(ns_map, nsURI)
- ins = self.genns(ns_map, self.config.schemaNamespaceURI)[0]
- t = ' %stype="%s%s"%s' % (ins, ns, obj_type, n)
-
- try: a = obj._marshalAttrs(ns_map, self)
- except: pass
-
- try: data = obj._marshalData()
- except: data = obj
-
- return xml % {"tag": tag, "type": t, "data": data, "root": rootattr,
- "id": id, "attrs": a}
-
- def dump_float(self, obj, tag, typed = 1, ns_map = {}):
- # Terrible windows hack
- if not good_float:
- if obj == float(1e300**2):
- obj = "INF"
- elif obj == float(-1e300**2):
- obj = "-INF"
-
- obj = str(obj)
- if obj in ('inf', '-inf'):
- obj = str(obj).upper()
- elif obj == 'nan':
- obj = 'NaN'
- self.out += self.dumper(None, "float", obj, tag, typed, ns_map,
- self.genroot(ns_map))
-
- def dump_string(self, obj, tag, typed = 0, ns_map = {}):
- tag = tag or self.gentag()
-
- id = self.checkref(obj, tag, ns_map)
- if id == None:
- return
-
- try: data = obj._marshalData()
- except: data = obj
-
- self.out += self.dumper(None, "string", cgi.escape(data), tag,
- typed, ns_map, self.genroot(ns_map), id)
-
- dump_unicode = dump_string
- dump_str = dump_string # 4/12/2002 - MAP - for Python 2.2
-
- def dump_None(self, obj, tag, typed = 0, ns_map = {}):
- tag = tag or self.gentag()
- ns = self.genns(ns_map, self.config.schemaNamespaceURI)[0]
-
- self.out += '<%s %snull="1"%s/>\n' % (tag, ns, self.genroot(ns_map))
-
- def dump_list(self, obj, tag, typed = 1, ns_map = {}):
- if type(obj) == InstanceType:
- data = obj.data
- else:
- data = obj
-
- tag = tag or self.gentag()
-
- id = self.checkref(obj, tag, ns_map)
- if id == None:
- return
-
- try:
- sample = data[0]
- empty = 0
- except:
- sample = structType()
- empty = 1
-
- # First scan list to see if all are the same type
- same_type = 1
-
- if not empty:
- for i in data[1:]:
- if type(sample) != type(i) or \
- (type(sample) == InstanceType and \
- sample.__class__ != i.__class__):
- same_type = 0
- break
-
- ndecl = ''
- if same_type:
- if (isinstance(sample, structType)) or \
- type(sample) == DictType: # force to urn struct
-
- try:
- tns = obj._ns or NS.URN
- except:
- tns = NS.URN
-
- ns, ndecl = self.genns(ns_map, tns)
-
- try:
- typename = last._typename
- except:
- typename = "SOAPStruct"
-
- t = ns + typename
-
- elif isinstance(sample, anyType):
- ns = sample._validNamespaceURI(self.config.typesNamespaceURI,
- self.config.strictNamespaces)
- if ns:
- ns, ndecl = self.genns(ns_map, ns)
- t = ns + sample._type
- else:
- t = 'ur-type'
- else:
- t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \
- type(sample).__name__
- else:
- t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \
- "ur-type"
-
- try: a = obj._marshalAttrs(ns_map, self)
- except: a = ''
-
- ens, edecl = self.genns(ns_map, NS.ENC)
- ins, idecl = self.genns(ns_map, self.config.schemaNamespaceURI)
-
- self.out += \
- '<%s %sarrayType="%s[%d]" %stype="%sArray"%s%s%s%s%s%s>\n' %\
- (tag, ens, t, len(data), ins, ens, ndecl, edecl, idecl,
- self.genroot(ns_map), id, a)
-
- typed = not same_type
-
- try: elemsname = obj._elemsname
- except: elemsname = "item"
-
- for i in data:
- self.dump(i, elemsname, typed, ns_map)
-
- self.out += '%s>\n' % tag
-
- dump_tuple = dump_list
-
- def dump_dictionary(self, obj, tag, typed = 1, ns_map = {}):
- tag = tag or self.gentag()
-
- id = self.checkref(obj, tag, ns_map)
- if id == None:
- return
-
- try: a = obj._marshalAttrs(ns_map, self)
- except: a = ''
-
- self.out += '<%s%s%s%s>\n' % \
- (tag, id, a, self.genroot(ns_map))
-
- for (k, v) in obj.items():
- if k[0] != "_":
- self.dump(v, k, 1, ns_map)
-
- self.out += '%s>\n' % tag
- dump_dict = dump_dictionary # 4/18/2002 - MAP - for Python 2.2
-
- def dump_instance(self, obj, tag, typed = 1, ns_map = {}):
- if not tag:
- # If it has a name use it.
- if isinstance(obj, anyType) and obj._name:
- tag = obj._name
- else:
- tag = self.gentag()
-
- if isinstance(obj, arrayType): # Array
- self.dump_list(obj, tag, typed, ns_map)
- return
-
- if isinstance(obj, faultType): # Fault
- cns, cdecl = self.genns(ns_map, NS.ENC)
- vns, vdecl = self.genns(ns_map, NS.ENV)
- self.out += '''<%sFault %sroot="1"%s%s>
-%s
-%s
-''' % (vns, cns, vdecl, cdecl, obj.faultcode, obj.faultstring)
- if hasattr(obj, "detail"):
- self.dump(obj.detail, "detail", typed, ns_map)
- self.out += "%sFault>\n" % vns
- return
-
- r = self.genroot(ns_map)
-
- try: a = obj._marshalAttrs(ns_map, self)
- except: a = ''
-
- if isinstance(obj, voidType): # void
- self.out += "<%s%s%s>%s>\n" % (tag, a, r, tag)
- return
-
- id = self.checkref(obj, tag, ns_map)
- if id == None:
- return
-
- if isinstance(obj, structType):
- # Check for namespace
- ndecl = ''
- ns = obj._validNamespaceURI(self.config.typesNamespaceURI,
- self.config.strictNamespaces)
- if ns:
- ns, ndecl = self.genns(ns_map, ns)
- tag = ns + tag
- self.out += "<%s%s%s%s%s>\n" % (tag, ndecl, id, a, r)
-
- # If we have order use it.
- order = 1
-
- for i in obj._keys():
- if i not in obj._keyord:
- order = 0
- break
- if order:
- for i in range(len(obj._keyord)):
- self.dump(obj._aslist[i], obj._keyord[i], 1, ns_map)
- else:
- # don't have pristine order information, just build it.
- for (k, v) in obj.__dict__.items():
- if k[0] != "_":
- self.dump(v, k, 1, ns_map)
-
- if isinstance(obj, bodyType):
- self.multis = 1
-
- for v, k in self.multirefs:
- self.dump(v, k, typed = typed, ns_map = ns_map)
-
- self.out += '%s>\n' % tag
-
- elif isinstance(obj, anyType):
- t = ''
-
- if typed:
- ns = obj._validNamespaceURI(self.config.typesNamespaceURI,
- self.config.strictNamespaces)
- if ns:
- ons, ondecl = self.genns(ns_map, ns)
- ins, indecl = self.genns(ns_map,
- self.config.schemaNamespaceURI)
- t = ' %stype="%s%s"%s%s' % \
- (ins, ons, obj._type, ondecl, indecl)
-
- self.out += '<%s%s%s%s%s>%s%s>\n' % \
- (tag, t, id, a, r, obj._marshalData(), tag)
-
- else: # Some Class
- self.out += '<%s%s%s>\n' % (tag, id, r)
-
- for (k, v) in obj.__dict__.items():
- if k[0] != "_":
- self.dump(v, k, 1, ns_map)
-
- self.out += '%s>\n' % tag
-
-
-################################################################################
-# SOAPBuilder's more public interface
-################################################################################
-def buildSOAP(args=(), kw={}, method=None, namespace=None, header=None,
- methodattrs=None,envelope=1,encoding='UTF-8',config=Config):
- t = SOAPBuilder(args=args,kw=kw, method=method, namespace=namespace,
- header=header, methodattrs=methodattrs,envelope=envelope,
- encoding=encoding, config=config)
- return t.build()
-
-################################################################################
-# RPC
-################################################################################
-
-def SOAPUserAgent():
- return "SOAP.py " + __version__ + " (actzero.com)"
-
-################################################################################
-# Client
-################################################################################
-class SOAPAddress:
- def __init__(self, url, config = Config):
- proto, uri = urllib.splittype(url)
-
- # apply some defaults
- if uri[0:2] != '//':
- if proto != None:
- uri = proto + ':' + uri
-
- uri = '//' + uri
- proto = 'http'
-
- host, path = urllib.splithost(uri)
-
- try:
- int(host)
- host = 'localhost:' + host
- except:
- pass
-
- if not path:
- path = '/'
-
- if proto not in ('http', 'https'):
- raise IOError, "unsupported SOAP protocol"
- if proto == 'https' and not config.SSLclient:
- raise AttributeError, \
- "SSL client not supported by this Python installation"
-
- self.proto = proto
- self.host = host
- self.path = path
-
- def __str__(self):
- return "%(proto)s://%(host)s%(path)s" % self.__dict__
-
- __repr__ = __str__
-
-
-class HTTPTransport:
- # Need a Timeout someday?
- def call(self, addr, data, soapaction = '', encoding = None,
- http_proxy = None, config = Config):
-
- import httplib
-
- if not isinstance(addr, SOAPAddress):
- addr = SOAPAddress(addr, config)
-
- # Build a request
- if http_proxy:
- real_addr = http_proxy
- real_path = addr.proto + "://" + addr.host + addr.path
- else:
- real_addr = addr.host
- real_path = addr.path
-
- if addr.proto == 'https':
- r = httplib.HTTPS(real_addr)
- else:
- r = httplib.HTTP(real_addr)
-
- r.putrequest("POST", real_path)
-
- r.putheader("Host", addr.host)
- r.putheader("User-agent", SOAPUserAgent())
- t = 'text/xml';
- if encoding != None:
- t += '; charset="%s"' % encoding
- r.putheader("Content-type", t)
- r.putheader("Content-length", str(len(data)))
- r.putheader("SOAPAction", '"%s"' % soapaction)
-
- if config.dumpHeadersOut:
- s = 'Outgoing HTTP headers'
- debugHeader(s)
- print "POST %s %s" % (real_path, r._http_vsn_str)
- print "Host:", addr.host
- print "User-agent: SOAP.py " + __version__ + " (actzero.com)"
- print "Content-type:", t
- print "Content-length:", len(data)
- print 'SOAPAction: "%s"' % soapaction
- debugFooter(s)
-
- r.endheaders()
-
- if config.dumpSOAPOut:
- s = 'Outgoing SOAP'
- debugHeader(s)
- print data,
- if data[-1] != '\n':
- print
- debugFooter(s)
-
- # send the payload
- r.send(data)
-
- # read response line
- code, msg, headers = r.getreply()
-
- if config.dumpHeadersIn:
- s = 'Incoming HTTP headers'
- debugHeader(s)
- if headers.headers:
- print "HTTP/1.? %d %s" % (code, msg)
- print "\n".join(map (lambda x: x.strip(), headers.headers))
- else:
- print "HTTP/0.9 %d %s" % (code, msg)
- debugFooter(s)
-
- if config.dumpSOAPIn:
- data = r.getfile().read()
-
- s = 'Incoming SOAP'
- debugHeader(s)
- print data,
- if data[-1] != '\n':
- print
- debugFooter(s)
-
- if code not in (200, 500):
- raise HTTPError(code, msg)
-
- if not config.dumpSOAPIn:
- data = r.getfile().read()
-
- # return response payload
- return data
-
-################################################################################
-# SOAP Proxy
-################################################################################
-class SOAPProxy:
- def __init__(self, proxy, namespace = None, soapaction = '',
- header = None, methodattrs = None, transport = HTTPTransport,
- encoding = 'UTF-8', throw_faults = 1, unwrap_results = 1,
- http_proxy=None, config = Config):
-
- # Test the encoding, raising an exception if it's not known
- if encoding != None:
- ''.encode(encoding)
-
- self.proxy = SOAPAddress(proxy, config)
- self.namespace = namespace
- self.soapaction = soapaction
- self.header = header
- self.methodattrs = methodattrs
- self.transport = transport()
- self.encoding = encoding
- self.throw_faults = throw_faults
- self.unwrap_results = unwrap_results
- self.http_proxy = http_proxy
- self.config = config
-
-
- def __call(self, name, args, kw, ns = None, sa = None, hd = None,
- ma = None):
-
- ns = ns or self.namespace
- ma = ma or self.methodattrs
-
- if sa: # Get soapaction
- if type(sa) == TupleType: sa = sa[0]
- else:
- sa = self.soapaction
-
- if hd: # Get header
- if type(hd) == TupleType:
- hd = hd[0]
- else:
- hd = self.header
-
- hd = hd or self.header
-
- if ma: # Get methodattrs
- if type(ma) == TupleType: ma = ma[0]
- else:
- ma = self.methodattrs
- ma = ma or self.methodattrs
-
- m = buildSOAP(args = args, kw = kw, method = name, namespace = ns,
- header = hd, methodattrs = ma, encoding = self.encoding,
- config = self.config)
- #print m
-
- r = self.transport.call(self.proxy, m, sa, encoding = self.encoding,
- http_proxy = self.http_proxy,
- config = self.config)
-
- #print r
- p, attrs = parseSOAPRPC(r, attrs = 1)
-
- try:
- throw_struct = self.throw_faults and \
- isinstance (p, faultType)
- except:
- throw_struct = 0
-
- if throw_struct:
- raise p
-
- # Bubble a regular result up, if there is only element in the
- # struct, assume that is the result and return it.
- # Otherwise it will return the struct with all the elements
- # as attributes.
- if self.unwrap_results:
- try:
- count = 0
- for i in p.__dict__.keys():
- if i[0] != "_": # don't move the private stuff
- count += 1
- t = getattr(p, i)
- if count == 1: p = t # Only one piece of data, bubble it up
- except:
- pass
-
- if self.config.returnAllAttrs:
- return p, attrs
- return p
-
- def _callWithBody(self, body):
- return self.__call(None, body, {})
-
- def __getattr__(self, name): # hook to catch method calls
- return self.__Method(self.__call, name, config = self.config)
-
- # To handle attribute wierdness
- class __Method:
- # Some magic to bind a SOAP method to an RPC server.
- # Supports "nested" methods (e.g. examples.getStateName) -- concept
- # borrowed from xmlrpc/soaplib -- www.pythonware.com
- # Altered (improved?) to let you inline namespaces on a per call
- # basis ala SOAP::LITE -- www.soaplite.com
-
- def __init__(self, call, name, ns = None, sa = None, hd = None,
- ma = None, config = Config):
-
- self.__call = call
- self.__name = name
- self.__ns = ns
- self.__sa = sa
- self.__hd = hd
- self.__ma = ma
- self.__config = config
- if self.__name[0] == "_":
- if self.__name in ["__repr__","__str__"]:
- self.__call__ = self.__repr__
- else:
- self.__call__ = self.__f_call
- else:
- self.__call__ = self.__r_call
-
- def __getattr__(self, name):
- if self.__name[0] == "_":
- # Don't nest method if it is a directive
- return self.__class__(self.__call, name, self.__ns,
- self.__sa, self.__hd, self.__ma)
-
- return self.__class__(self.__call, "%s.%s" % (self.__name, name),
- self.__ns, self.__sa, self.__hd, self.__ma)
-
- def __f_call(self, *args, **kw):
- if self.__name == "_ns": self.__ns = args
- elif self.__name == "_sa": self.__sa = args
- elif self.__name == "_hd": self.__hd = args
- elif self.__name == "_ma": self.__ma = args
- return self
-
- def __r_call(self, *args, **kw):
- return self.__call(self.__name, args, kw, self.__ns, self.__sa,
- self.__hd, self.__ma)
-
- def __repr__(self):
- return "<%s at %d>" % (self.__class__, id(self))
-
-################################################################################
-# Server
-################################################################################
-
-# Method Signature class for adding extra info to registered funcs, right now
-# used just to indicate it should be called with keywords, instead of ordered
-# params.
-class MethodSig:
- def __init__(self, func, keywords=0, context=0):
- self.func = func
- self.keywords = keywords
- self.context = context
- self.__name__ = func.__name__
-
- def __call__(self, *args, **kw):
- return apply(self.func,args,kw)
-
-class SOAPContext:
- def __init__(self, header, body, attrs, xmldata, connection, httpheaders,
- soapaction):
-
- self.header = header
- self.body = body
- self.attrs = attrs
- self.xmldata = xmldata
- self.connection = connection
- self.httpheaders= httpheaders
- self.soapaction = soapaction
-
-# A class to describe how header messages are handled
-class HeaderHandler:
- # Initially fail out if there are any problems.
- def __init__(self, header, attrs):
- for i in header.__dict__.keys():
- if i[0] == "_":
- continue
-
- d = getattr(header, i)
-
- try:
- fault = int(attrs[id(d)][(NS.ENV, 'mustUnderstand')])
- except:
- fault = 0
-
- if fault:
- raise faultType, ("%s:MustUnderstand" % NS.ENV_T,
- "Don't understand `%s' header element but "
- "mustUnderstand attribute is set." % i)
-
-
-################################################################################
-# SOAP Server
-################################################################################
-class SOAPServer(SocketServer.TCPServer):
- import BaseHTTPServer
-
- class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def version_string(self):
- return '' + \
- 'SOAP.py ' + __version__ + ' (Python ' + \
- sys.version.split()[0] + ')'
-
- def date_time_string(self):
- self.__last_date_time_string = \
- SOAPServer.BaseHTTPServer.BaseHTTPRequestHandler.\
- date_time_string(self)
-
- return self.__last_date_time_string
-
- def do_POST(self):
- try:
- if self.server.config.dumpHeadersIn:
- s = 'Incoming HTTP headers'
- debugHeader(s)
- print self.raw_requestline.strip()
- print "\n".join(map (lambda x: x.strip(),
- self.headers.headers))
- debugFooter(s)
-
- data = self.rfile.read(int(self.headers["content-length"]))
-
- if self.server.config.dumpSOAPIn:
- s = 'Incoming SOAP'
- debugHeader(s)
- print data,
- if data[-1] != '\n':
- print
- debugFooter(s)
-
- (r, header, body, attrs) = \
- parseSOAPRPC(data, header = 1, body = 1, attrs = 1)
-
- method = r._name
- args = r._aslist
- kw = r._asdict
-
- ns = r._ns
- resp = ""
- # For fault messages
- if ns:
- nsmethod = "%s:%s" % (ns, method)
- else:
- nsmethod = method
-
- try:
- # First look for registered functions
- if self.server.funcmap.has_key(ns) and \
- self.server.funcmap[ns].has_key(method):
- f = self.server.funcmap[ns][method]
- else: # Now look at registered objects
- # Check for nested attributes. This works even if
- # there are none, because the split will return
- # [method]
- f = self.server.objmap[ns]
- l = method.split(".")
- for i in l:
- f = getattr(f, i)
- except:
- resp = buildSOAP(faultType("%s:Client" % NS.ENV_T,
- "No method %s found" % nsmethod,
- "%s %s" % tuple(sys.exc_info()[0:2])),
- encoding = self.server.encoding,
- config = self.server.config)
- status = 500
- else:
- try:
- if header:
- x = HeaderHandler(header, attrs)
-
- # If it's wrapped, some special action may be needed
-
- if isinstance(f, MethodSig):
- c = None
-
- if f.context: # Build context object
- c = SOAPContext(header, body, attrs, data,
- self.connection, self.headers,
- self.headers["soapaction"])
-
- if f.keywords:
- # This is lame, but have to de-unicode
- # keywords
-
- strkw = {}
-
- for (k, v) in kw.items():
- strkw[str(k)] = v
- if c:
- strkw["_SOAPContext"] = c
- fr = apply(f, (), strkw)
- elif c:
- fr = apply(f, args, {'_SOAPContext':c})
- else:
- fr = apply(f, args, {})
- else:
- fr = apply(f, args, {})
-
- if type(fr) == type(self) and \
- isinstance(fr, voidType):
- resp = buildSOAP(kw = {'%sResponse' % method: fr},
- encoding = self.server.encoding,
- config = self.server.config)
- else:
- resp = buildSOAP(kw =
- {'%sResponse' % method: {'Result': fr}},
- encoding = self.server.encoding,
- config = self.server.config)
- except Exception, e:
- import traceback
- info = sys.exc_info()
-
- if self.server.config.dumpFaultInfo:
- s = 'Method %s exception' % nsmethod
- debugHeader(s)
- traceback.print_exception(info[0], info[1],
- info[2])
- debugFooter(s)
-
- if isinstance(e, faultType):
- f = e
- else:
- f = faultType("%s:Server" % NS.ENV_T,
- "Method %s failed." % nsmethod)
-
- if self.server.config.returnFaultInfo:
- f._setDetail("".join(traceback.format_exception(
- info[0], info[1], info[2])))
- elif not hasattr(f, 'detail'):
- f._setDetail("%s %s" % (info[0], info[1]))
-
- resp = buildSOAP(f, encoding = self.server.encoding,
- config = self.server.config)
- status = 500
- else:
- status = 200
- except faultType, e:
- import traceback
- info = sys.exc_info()
-
- if self.server.config.dumpFaultInfo:
- s = 'Received fault exception'
- debugHeader(s)
- traceback.print_exception(info[0], info[1],
- info[2])
- debugFooter(s)
-
- if self.server.config.returnFaultInfo:
- e._setDetail("".join(traceback.format_exception(
- info[0], info[1], info[2])))
- elif not hasattr(e, 'detail'):
- e._setDetail("%s %s" % (info[0], info[1]))
-
- resp = buildSOAP(e, encoding = self.server.encoding,
- config = self.server.config)
- status = 500
- except:
- # internal error, report as HTTP server error
- if self.server.config.dumpFaultInfo:
- import traceback
- s = 'Internal exception'
- debugHeader(s)
- traceback.print_exc ()
- debugFooter(s)
- self.send_response(500)
- self.end_headers()
-
- if self.server.config.dumpHeadersOut and \
- self.request_version != 'HTTP/0.9':
- s = 'Outgoing HTTP headers'
- debugHeader(s)
- if self.responses.has_key(status):
- s = ' ' + self.responses[status][0]
- else:
- s = ''
- print "%s %d%s" % (self.protocol_version, 500, s)
- print "Server:", self.version_string()
- print "Date:", self.__last_date_time_string
- debugFooter(s)
- else:
- # got a valid SOAP response
- self.send_response(status)
-
- t = 'text/xml';
- if self.server.encoding != None:
- t += '; charset="%s"' % self.server.encoding
- self.send_header("Content-type", t)
- self.send_header("Content-length", str(len(resp)))
- self.end_headers()
-
- if self.server.config.dumpHeadersOut and \
- self.request_version != 'HTTP/0.9':
- s = 'Outgoing HTTP headers'
- debugHeader(s)
- if self.responses.has_key(status):
- s = ' ' + self.responses[status][0]
- else:
- s = ''
- print "%s %d%s" % (self.protocol_version, status, s)
- print "Server:", self.version_string()
- print "Date:", self.__last_date_time_string
- print "Content-type:", t
- print "Content-length:", len(resp)
- debugFooter(s)
-
- if self.server.config.dumpSOAPOut:
- s = 'Outgoing SOAP'
- debugHeader(s)
- print resp,
- if resp[-1] != '\n':
- print
- debugFooter(s)
-
- self.wfile.write(resp)
- self.wfile.flush()
-
- # We should be able to shut down both a regular and an SSL
- # connection, but under Python 2.1, calling shutdown on an
- # SSL connections drops the output, so this work-around.
- # This should be investigated more someday.
-
- if self.server.config.SSLserver and \
- isinstance(self.connection, SSL.Connection):
- self.connection.set_shutdown(SSL.SSL_SENT_SHUTDOWN |
- SSL.SSL_RECEIVED_SHUTDOWN)
- else:
- self.connection.shutdown(1)
-
- def log_message(self, format, *args):
- if self.server.log:
- SOAPServer.BaseHTTPServer.BaseHTTPRequestHandler.\
- log_message (self, format, *args)
-
- def __init__(self, addr = ('localhost', 8000),
- RequestHandler = SOAPRequestHandler, log = 1, encoding = 'UTF-8',
- config = Config, namespace = None, ssl_context = None):
-
- # Test the encoding, raising an exception if it's not known
- if encoding != None:
- ''.encode(encoding)
-
- if ssl_context != None and not config.SSLserver:
- raise AttributeError, \
- "SSL server not supported by this Python installation"
-
- self.namespace = namespace
- self.objmap = {}
- self.funcmap = {}
- self.ssl_context = ssl_context
- self.encoding = encoding
- self.config = config
- self.log = log
-
- self.allow_reuse_address= 1
-
- SocketServer.TCPServer.__init__(self, addr, RequestHandler)
-
- def get_request(self):
- sock, addr = SocketServer.TCPServer.get_request(self)
-
- if self.ssl_context:
- sock = SSL.Connection(self.ssl_context, sock)
- sock._setup_ssl(addr)
- if sock.accept_ssl() != 1:
- raise socket.error, "Couldn't accept SSL connection"
-
- return sock, addr
-
- def registerObject(self, object, namespace = ''):
- if namespace == '': namespace = self.namespace
- self.objmap[namespace] = object
-
- def registerFunction(self, function, namespace = '', funcName = None):
- if not funcName : funcName = function.__name__
- if namespace == '': namespace = self.namespace
- if self.funcmap.has_key(namespace):
- self.funcmap[namespace][funcName] = function
- else:
- self.funcmap[namespace] = {funcName : function}
-
- def registerKWObject(self, object, namespace = ''):
- if namespace == '': namespace = self.namespace
- for i in dir(object.__class__):
- if i[0] != "_" and callable(getattr(object, i)):
- self.registerKWFunction(getattr(object,i), namespace)
-
- # convenience - wraps your func for you.
- def registerKWFunction(self, function, namespace = '', funcName = None):
- self.registerFunction(MethodSig(function,keywords=1), namespace,
- funcName)
diff --git a/shell/google/__init__.py b/shell/google/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/shell/google/google.py b/shell/google/google.py
deleted file mode 100755
index a20ba513..00000000
--- a/shell/google/google.py
+++ /dev/null
@@ -1,638 +0,0 @@
-"""
-Python wrapper for Google web APIs
-
-This module allows you to access Google's web APIs through SOAP,
-to do things like search Google and get the results programmatically.
-Described U{here }
-
-You need a Google-provided license key to use these services.
-Follow the link above to get one. These functions will look in
-several places (in this order) for the license key:
-
- - the "license_key" argument of each function
- - the module-level LICENSE_KEY variable (call setLicense once to set it)
- - an environment variable called GOOGLE_LICENSE_KEY
- - a file called ".googlekey" in the current directory
- - a file called "googlekey.txt" in the current directory
- - a file called ".googlekey" in your home directory
- - a file called "googlekey.txt" in your home directory
- - a file called ".googlekey" in the same directory as google.py
- - a file called "googlekey.txt" in the same directory as google.py
-
-Sample usage::
-
- >>> import google
- >>> google.setLicense('...') # must get your own key!
- >>> data = google.doGoogleSearch('python')
- >>> data.meta.searchTime
- 0.043221000000000002
-
- >>> data.results[0].URL
- 'http://www.python.org/'
-
- >>> data.results[0].title
- 'Python Language Website'
-
-@newfield contrib: Contributors
-@author: Mark Pilgrim
-@author: Brian Landers
-@license: Python
-@version: 0.6
-@contrib: David Ascher, for the install script
-@contrib: Erik Max Francis, for the command line interface
-@contrib: Michael Twomey, for HTTP proxy support
-@contrib: Mark Recht, for patches to support SOAPpy
-"""
-
-__author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
-__version__ = "0.6"
-__cvsversion__ = "$Revision: 1.5 $"[11:-2]
-__date__ = "$Date: 2004/02/25 23:46:07 $"[7:-2]
-__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
-__license__ = "Python"
-__credits__ = """David Ascher, for the install script
-Erik Max Francis, for the command line interface
-Michael Twomey, for HTTP proxy support"""
-
-import os, sys, getopt
-import GoogleSOAPFacade
-
-LICENSE_KEY = None
-HTTP_PROXY = None
-
-#
-# Constants
-#
-_url = 'http://api.google.com/search/beta2'
-_namespace = 'urn:GoogleSearch'
-_googlefile1 = ".googlekey"
-_googlefile2 = "googlekey.txt"
-
-_false = GoogleSOAPFacade.false
-_true = GoogleSOAPFacade.true
-
-_licenseLocations = (
- ( lambda key: key,
- 'passed to the function in license_key variable' ),
- ( lambda key: LICENSE_KEY,
- 'module-level LICENSE_KEY variable (call setLicense to set it)' ),
- ( lambda key: os.environ.get( 'GOOGLE_LICENSE_KEY', None ),
- 'an environment variable called GOOGLE_LICENSE_KEY' ),
- ( lambda key: _contentsOf( os.getcwd(), _googlefile1 ),
- '%s in the current directory' % _googlefile1),
- ( lambda key: _contentsOf( os.getcwd(), _googlefile2 ),
- '%s in the current directory' % _googlefile2),
- ( lambda key: _contentsOf( os.environ.get( 'HOME', '' ), _googlefile1 ),
- '%s in your home directory' % _googlefile1),
- ( lambda key: _contentsOf( os.environ.get( 'HOME', '' ), _googlefile2 ),
- '%s in your home directory' % _googlefile2 ),
- ( lambda key: _contentsOf( _getScriptDir(), _googlefile1 ),
- '%s in the google.py directory' % _googlefile1 ),
- ( lambda key: _contentsOf( _getScriptDir(), _googlefile2 ),
- '%s in the google.py directory' % _googlefile2 )
-)
-
-## ----------------------------------------------------------------------
-## Exceptions
-## ----------------------------------------------------------------------
-
-class NoLicenseKey(Exception):
- """
- Thrown when the API is unable to find a valid license key.
- """
- pass
-
-## ----------------------------------------------------------------------
-## administrative functions (non-API)
-## ----------------------------------------------------------------------
-
-def _version():
- """
- Display a formatted version string for the module
- """
- print """PyGoogle %(__version__)s
-%(__copyright__)s
-released %(__date__)s
-
-Thanks to:
-%(__credits__)s""" % globals()
-
-
-def _usage():
- """
- Display usage information for the command-line interface
- """
- program = os.path.basename(sys.argv[0])
- print """Usage: %(program)s [options] [querytype] query
-
-options:
- -k, --key= Google license key (see important note below)
- -1, -l, --lucky show only first hit
- -m, --meta show meta information
- -r, --reverse show results in reverse order
- -x, --proxy= use HTTP proxy
- -h, --help print this help
- -v, --version print version and copyright information
- -t, --test run test queries
-
-querytype:
- -s, --search= search (default)
- -c, --cache= retrieve cached page
- -p, --spelling= check spelling
-
-IMPORTANT NOTE: all Google functions require a valid license key;
-visit http://www.google.com/apis/ to get one. %(program)s will look in
-these places (in order) and use the first license key it finds:
- * the key specified on the command line""" % vars()
- for get, location in _licenseLocations[2:]:
- print " *", location
-
-## ----------------------------------------------------------------------
-## utility functions (API)
-## ----------------------------------------------------------------------
-
-def setLicense(license_key):
- """
- Set the U{Google APIs } license key
-
- @param license_key: The new key to use
- @type license_key: String
- @todo: validate the key?
- """
- global LICENSE_KEY
- LICENSE_KEY = license_key
-
-
-def getLicense(license_key = None):
- """
- Get the U{Google APIs } license key
-
- The key can be read from any number of locations. See the module-leve
- documentation for the search order.
-
- @return: the license key
- @rtype: String
- @raise NoLicenseKey: if no valid key could be found
- """
- for get, location in _licenseLocations:
- rc = get(license_key)
- if rc: return rc
- _usage()
- raise NoLicenseKey, 'get a license key at http://www.google.com/apis/'
-
-
-def setProxy(http_proxy):
- """
- Set the HTTP proxy to be used when accessing Google
-
- @param http_proxy: the proxy to use
- @type http_proxy: String
- @todo: validiate the input?
- """
- global HTTP_PROXY
- HTTP_PROXY = http_proxy
-
-
-def getProxy(http_proxy = None):
- """
- Get the HTTP proxy we use for accessing Google
-
- @return: the proxy
- @rtype: String
- """
- return http_proxy or HTTP_PROXY
-
-
-def _contentsOf(dirname, filename):
- filename = os.path.join(dirname, filename)
- if not os.path.exists(filename): return None
- fsock = open(filename)
- contents = fsock.read()
- fsock.close()
- return contents
-
-
-def _getScriptDir():
- if __name__ == '__main__':
- return os.path.abspath(os.path.dirname(sys.argv[0]))
- else:
- return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
-
-
-def _marshalBoolean(value):
- if value:
- return _true
- else:
- return _false
-
-
-def _getRemoteServer( http_proxy ):
- return GoogleSOAPFacade.getProxy( _url, _namespace, http_proxy )
-
-
-## ----------------------------------------------------------------------
-## search results classes
-## ----------------------------------------------------------------------
-
-class _SearchBase:
- def __init__(self, params):
- for k, v in params.items():
- if isinstance(v, GoogleSOAPFacade.structType):
- v = GoogleSOAPFacade.toDict( v )
-
- try:
- if isinstance(v[0], GoogleSOAPFacade.structType):
- v = [ SOAPProxy.toDict( node ) for node in v ]
-
- except:
- pass
- self.__dict__[str(k)] = v
-
-## ----------------------------------------------------------------------
-
-class SearchResultsMetaData(_SearchBase):
- """
- Container class for metadata about a given search query's results.
-
- @ivar documentFiltering: is duplicate page filtering active?
-
- @ivar searchComments: human-readable informational message
-
- example::
-
- "'the' is a very common word and was not included in your search"
-
- @ivar estimatedTotalResultsCount: estimated total number of results
- for this query.
-
- @ivar estimateIsExact: is estimatedTotalResultsCount an exact value?
-
- @ivar searchQuery: search string that initiated this search
-
- @ivar startIndex: index of the first result returned (zero-based)
-
- @ivar endIndex: index of the last result returned (zero-based)
-
- @ivar searchTips: human-readable informational message on how to better
- use Google.
-
- @ivar directoryCategories: list of categories for the search results
-
- This field is a list of dictionaries, like so::
-
- { 'fullViewableName': 'the Open Directory category',
- 'specialEncoding': 'encoding scheme of this directory category'
- }
-
- @ivar searchTime: total search time, in seconds
- """
- pass
-
-## ----------------------------------------------------------------------
-
-class SearchResult(_SearchBase):
- """
- Encapsulates the results from a search.
-
- @ivar URL: URL
-
- @ivar title: title (HTML)
-
- @ivar snippet: snippet showing query context (HTML
-
- @ivar cachedSize: size of cached version of this result, (KB)
-
- @ivar relatedInformationPresent: is the "related:" keyword supported?
-
- Flag indicates that the "related:" keyword is supported for this URL
-
- @ivar hostName: used when filtering occurs
-
- When filtering occurs, a maximum of two results from any given
- host is returned. When this occurs, the second resultElement
- that comes from that host contains the host name in this parameter.
-
- @ivar directoryCategory: Open Directory category information
-
- This field is a dictionary with the following values::
-
- { 'fullViewableName': 'the Open Directory category',
- 'specialEncoding' : 'encoding scheme of this directory category'
- }
-
- @ivar directoryTitle: Open Directory title of this result (or blank)
-
- @ivar summary: Open Directory summary for this result (or blank)
- """
- pass
-
-## ----------------------------------------------------------------------
-
-class SearchReturnValue:
- """
- complete search results for a single query
-
- @ivar meta: L{SearchResultsMetaData} instance for this query
-
- @ivar results: list of L{SearchResult} objects for this query
- """
- def __init__( self, metadata, results ):
- self.meta = metadata
- self.results = results
-
-## ----------------------------------------------------------------------
-## main functions
-## ----------------------------------------------------------------------
-
-def doGoogleSearch( q, start = 0, maxResults = 10, filter = 1,
- restrict='', safeSearch = 0, language = '',
- inputencoding = '', outputencoding = '',\
- license_key = None, http_proxy = None ):
- """
- Search Google using the SOAP API and return the results.
-
- You need a license key to call this function; see the
- U{Google APIs } site to get one.
- Then you can either pass it to this function every time, or
- set it globally; see the L{google} module-level docs for details.
-
- See U{http://www.google.com/help/features.html}
- for examples of advanced features. Anything that works at the
- Google web site will work as a query string in this method.
-
- You can use the C{start} and C{maxResults} parameters to page
- through multiple pages of results. Note that 'maxResults' is
- currently limited by Google to 10.
-
- See the API reference for more advanced examples and a full list of
- country codes and topics for use in the C{restrict} parameter, along
- with legal values for the C{language}, C{inputencoding}, and
- C{outputencoding} parameters.
-
- You can download the API documentation
- U{http://www.google.com/apis/download.html }.
-
- @param q: search string.
- @type q: String
-
- @param start: (optional) zero-based index of first desired result.
- @type start: int
-
- @param maxResults: (optional) maximum number of results to return.
- @type maxResults: int
-
- @param filter: (optional) flag to request filtering of similar results
- @type filter: int
-
- @param restrict: (optional) restrict results by country or topic.
- @type restrict: String
-
- @param safeSearch: (optional)
- @type safeSearch: int
-
- @param language: (optional)
- @type language: String
-
- @param inputencoding: (optional)
- @type inputencoding: String
-
- @param outputencoding: (optional)
- @type outputencoding: String
-
- @param license_key: (optional) the Google API license key to use
- @type license_key: String
-
- @param http_proxy: (optional) the HTTP proxy to use for talking to Google
- @type http_proxy: String
-
- @return: the search results encapsulated in an object
- @rtype: L{SearchReturnValue}
- """
- license_key = getLicense( license_key )
- http_proxy = getProxy( http_proxy )
- remoteserver = _getRemoteServer( http_proxy )
-
- filter = _marshalBoolean( filter )
- safeSearch = _marshalBoolean( safeSearch )
-
- data = remoteserver.doGoogleSearch( license_key, q, start, maxResults,
- filter, restrict, safeSearch,
- language, inputencoding,
- outputencoding )
-
- metadata = GoogleSOAPFacade.toDict( data )
- del metadata["resultElements"]
-
- metadata = SearchResultsMetaData( metadata )
-
- results = [ SearchResult( GoogleSOAPFacade.toDict( node ) ) \
- for node in data.resultElements ]
-
- return SearchReturnValue( metadata, results )
-
-## ----------------------------------------------------------------------
-
-def doGetCachedPage( url, license_key = None, http_proxy = None ):
- """
- Retrieve a page from the Google cache.
-
- You need a license key to call this function; see the
- U{Google APIs } site to get one.
- Then you can either pass it to this function every time, or
- set it globally; see the L{google} module-level docs for details.
-
- @param url: full URL to the page to retrieve
- @type url: String
-
- @param license_key: (optional) the Google API key to use
- @type license_key: String
-
- @param http_proxy: (optional) the HTTP proxy server to use
- @type http_proxy: String
-
- @return: full text of the cached page
- @rtype: String
- """
- license_key = getLicense( license_key )
- http_proxy = getProxy( http_proxy )
- remoteserver = _getRemoteServer( http_proxy )
-
- return remoteserver.doGetCachedPage( license_key, url )
-
-## ----------------------------------------------------------------------
-
-def doSpellingSuggestion( phrase, license_key = None, http_proxy = None ):
- """
- Get spelling suggestions from Google
-
- You need a license key to call this function; see the
- U{Google APIs } site to get one.
- Then you can either pass it to this function every time, or
- set it globally; see the L{google} module-level docs for details.
-
- @param phrase: word or phrase to spell-check
- @type phrase: String
-
- @param license_key: (optional) the Google API key to use
- @type license_key: String
-
- @param http_proxy: (optional) the HTTP proxy to use
- @type http_proxy: String
-
- @return: text of any suggested replacement, or None
- """
- license_key = getLicense( license_key )
- http_proxy = getProxy( http_proxy)
- remoteserver = _getRemoteServer( http_proxy )
-
- return remoteserver.doSpellingSuggestion( license_key, phrase )
-
-## ----------------------------------------------------------------------
-## functional test suite (see googletest.py for unit test suite)
-## ----------------------------------------------------------------------
-
-def _test():
- """
- Run functional test suite.
- """
- try:
- getLicense(None)
- except NoLicenseKey:
- return
-
- print "Searching for Python at google.com..."
- data = doGoogleSearch( "Python" )
- _output( data, { "func": "doGoogleSearch"} )
-
- print "\nSearching for 5 _French_ pages about Python, "
- print "encoded in ISO-8859-1..."
-
- data = doGoogleSearch( "Python", language = 'lang_fr',
- outputencoding = 'ISO-8859-1',
- maxResults = 5 )
-
- _output( data, { "func": "doGoogleSearch" } )
-
- phrase = "Pyhton programming languager"
- print "\nTesting spelling suggestions for '%s'..." % phrase
-
- data = doSpellingSuggestion( phrase )
-
- _output( data, { "func": "doSpellingSuggestion" } )
-
-## ----------------------------------------------------------------------
-## Command-line interface
-## ----------------------------------------------------------------------
-
-class _OutputFormatter:
- def boil(self, data):
- if type(data) == type(u""):
- return data.encode("ISO-8859-1", "replace")
- else:
- return data
-
-class _TextOutputFormatter(_OutputFormatter):
- def common(self, data, params):
- if params.get("showMeta", 0):
- meta = data.meta
- for category in meta.directoryCategories:
- print "directoryCategory: %s" % \
- self.boil(category["fullViewableName"])
- for attr in [node for node in dir(meta) if \
- node <> "directoryCategories" and node[:2] <> '__']:
- print "%s:" % attr, self.boil(getattr(meta, attr))
-
- def doGoogleSearch(self, data, params):
- results = data.results
- if params.get("feelingLucky", 0):
- results = results[:1]
- if params.get("reverseOrder", 0):
- results.reverse()
- for result in results:
- for attr in dir(result):
- if attr == "directoryCategory":
- print "directoryCategory:", \
- self.boil(result.directoryCategory["fullViewableName"])
- elif attr[:2] <> '__':
- print "%s:" % attr, self.boil(getattr(result, attr))
- print
- self.common(data, params)
-
- def doGetCachedPage(self, data, params):
- print data
- self.common(data, params)
-
- doSpellingSuggestion = doGetCachedPage
-
-def _makeFormatter(outputFormat):
- classname = "_%sOutputFormatter" % outputFormat.capitalize()
- return globals()[classname]()
-
-def _output(results, params):
- formatter = _makeFormatter(params.get("outputFormat", "text"))
- outputmethod = getattr(formatter, params["func"])
- outputmethod(results, params)
-
-def main(argv):
- """
- Command-line interface.
- """
- if not argv:
- _usage()
- return
- q = None
- func = None
- http_proxy = None
- license_key = None
- feelingLucky = 0
- showMeta = 0
- reverseOrder = 0
- runTest = 0
- outputFormat = "text"
- try:
- opts, args = getopt.getopt(argv, "s:c:p:k:lmrx:hvt1",
- ["search=", "cache=", "spelling=", "key=", "lucky", "meta",
- "reverse", "proxy=", "help", "version", "test"])
- except getopt.GetoptError:
- _usage()
- sys.exit(2)
- for opt, arg in opts:
- if opt in ("-s", "--search"):
- q = arg
- func = "doGoogleSearch"
- elif opt in ("-c", "--cache"):
- q = arg
- func = "doGetCachedPage"
- elif opt in ("-p", "--spelling"):
- q = arg
- func = "doSpellingSuggestion"
- elif opt in ("-k", "--key"):
- license_key = arg
- elif opt in ("-l", "-1", "--lucky"):
- feelingLucky = 1
- elif opt in ("-m", "--meta"):
- showMeta = 1
- elif opt in ("-r", "--reverse"):
- reverseOrder = 1
- elif opt in ("-x", "--proxy"):
- http_proxy = arg
- elif opt in ("-h", "--help"):
- _usage()
- elif opt in ("-v", "--version"):
- _version()
- elif opt in ("-t", "--test"):
- runTest = 1
- if runTest:
- setLicense(license_key)
- setProxy(http_proxy)
- _test()
- if args and not q:
- q = args[0]
- func = "doGoogleSearch"
- if func:
- results = globals()[func]( q, http_proxy=http_proxy,
- license_key=license_key )
- _output(results, locals())
-
-if __name__ == '__main__':
- main(sys.argv[1:])
diff --git a/shell/shell.py b/shell/shell.py
deleted file mode 100755
index a3f07c8f..00000000
--- a/shell/shell.py
+++ /dev/null
@@ -1,574 +0,0 @@
-import dbus
-import dbus.service
-import dbus.glib
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-import pango
-import gobject
-
-import sugar.util
-from sugar.chat.ChatWindow import ChatWindow
-from sugar.chat.ActivityChat import ActivityChat
-from sugar.chat.MeshChat import MeshChat
-from sugar.LogWriter import LogWriter
-
-from Owner import ShellOwner
-from StartPage import StartPage
-from WindowManager import WindowManager
-from PresenceWindow import PresenceWindow
-
-class ActivityHostSignalHelper(gobject.GObject):
- __gsignals__ = {
- 'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
- }
-
- def __init__(self, parent):
- gobject.GObject.__init__(self)
- self._parent = parent
-
- def emit_shared(self):
- self.emit('shared')
-
-class ActivityHost(dbus.service.Object):
- def __init__(self, activity_container, activity_name, default_type, activity_id = None):
- self.peer_service = None
-
- self.activity_name = activity_name
- self.ellipsize_tab = False
- self._shared = False
-
- self._signal_helper = ActivityHostSignalHelper(self)
-
- self.activity_container = activity_container
-
- if activity_id is None:
- self.activity_id = sugar.util.unique_id()
- else:
- self.activity_id = activity_id
- self._default_type = default_type
-
- self.dbus_object_name = "/com/redhat/Sugar/Shell/Activities/%s" % self.activity_id
-
- dbus.service.Object.__init__(self, activity_container.service, self.dbus_object_name)
- self.socket = gtk.Socket()
- self.socket.set_data("sugar-activity", self)
- self.socket.show()
-
- hbox = gtk.HBox(False, 4);
-
- self.tab_activity_image = gtk.Image()
- self.tab_activity_image.set_from_stock(gtk.STOCK_CONVERT, gtk.ICON_SIZE_MENU)
- hbox.pack_start(self.tab_activity_image)
- #self.tab_activity_image.show()
-
- self.label_hbox = gtk.HBox(False, 4);
- self.label_hbox.connect("style-set", self.__tab_label_style_set_cb)
- hbox.pack_start(self.label_hbox)
-
- self.tab_label = gtk.Label(self.activity_name)
- self.tab_label.set_single_line_mode(True)
- self.tab_label.set_alignment(0.0, 0.5)
- self.tab_label.set_padding(0, 0)
- self.tab_label.show()
-
- close_image = gtk.Image()
- close_image.set_from_stock (gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
- close_image.show()
-
- self.tab_close_button = gtk.Button()
- rcstyle = gtk.RcStyle();
- rcstyle.xthickness = rcstyle.ythickness = 0;
- self.tab_close_button.modify_style (rcstyle);
- self.tab_close_button.add(close_image)
- self.tab_close_button.set_relief(gtk.RELIEF_NONE)
- self.tab_close_button.set_focus_on_click(False)
- self.tab_close_button.connect("clicked", self.tab_close_button_clicked)
-
- self.label_hbox.pack_start(self.tab_label)
- self.label_hbox.pack_start(self.tab_close_button, False, False, 0)
- self.label_hbox.show()
-
- hbox.show()
-
- self._create_chat()
-
- notebook = self.activity_container.notebook
- index = notebook.append_page(self.socket, hbox)
- notebook.set_current_page(index)
-
- def _create_chat(self):
- self._activity_chat = ActivityChat(self)
-
- def got_focus(self):
- if self.peer_service != None:
- self.peer_service.got_focus()
-
- def lost_focus(self):
- if self.peer_service != None:
- self.peer_service.lost_focus()
-
- def get_chat(self):
- return self._activity_chat
-
- def get_default_type(self):
- return self._default_type
-
- def __close_button_clicked_reply_cb(self):
- pass
-
- def __close_button_clicked_error_cb(self, error):
- pass
-
- def publish(self):
- self._activity_chat.publish()
- self.peer_service.publish()
-
- def tab_close_button_clicked(self, button):
- self.peer_service.close_from_user(reply_handler = self.__close_button_clicked_reply_cb, \
- error_handler = self.__close_button_clicked_error_cb)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="", \
- out_signature="t")
- def get_host_xembed_id(self):
- window_id = self.socket.get_id()
- #print "window_id = %d"%window_id
- return window_id
-
- def connect(self, signal, func):
- self._signal_helper.connect(signal, func)
-
- def get_shared(self):
- """Return True if this activity is shared, False if
- it has not been shared yet."""
- return self._shared
-
- def _shared_signal(self):
- self._shared = True
- self._signal_helper.emit_shared()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="ss", \
- out_signature="")
- def set_peer_service_name(self, peer_service_name, peer_object_name):
- #print "peer_service_name = %s, peer_object_name = %s"%(peer_service_name, peer_object_name)
- self.__peer_service_name = peer_service_name
- self.__peer_object_name = peer_object_name
- self.peer_service = dbus.Interface(self.activity_container.bus.get_object( \
- self.__peer_service_name, self.__peer_object_name), \
- "com.redhat.Sugar.Activity")
- self.activity_container.bus.add_signal_receiver(self._shared_signal,
- signal_name="ActivityShared",
- dbus_interface="com.redhat.Sugar.Activity",
- named_service=self.__peer_service_name,
- path=self.__peer_object_name)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_ellipsize_tab(self, ellipsize):
- self.ellipsize_tab = True
- self.update_tab_size()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_can_close(self, can_close):
- if can_close:
- self.tab_close_button.show()
- else:
- self.tab_close_button.hide()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_tab_show_icon(self, show_icon):
- if show_icon:
- self.tab_activity_image.show()
- else:
- self.tab_activity_image.hide()
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="b", \
- out_signature="")
- def set_has_changes(self, has_changes):
- if has_changes:
- attrs = pango.AttrList()
- attrs.insert(pango.AttrForeground(50000, 0, 0, 0, -1))
- attrs.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
- self.tab_label.set_attributes(attrs)
- else:
- self.tab_label.set_attributes(pango.AttrList())
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="s", \
- out_signature="")
- def set_tab_text(self, text):
- self.tab_label.set_text(text)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="ayibiiii", \
- out_signature="")
- def set_tab_icon(self, data, colorspace, has_alpha, bits_per_sample, width, height, rowstride):
- #print "width=%d, height=%d"%(width, height)
- #print " data = ", data
- pixstr = ""
- for c in data:
- # Work around for a bug in dbus < 0.61 where integers
- # are not correctly marshalled
- if c < 0:
- c += 256
- pixstr += chr(c)
-
- pixbuf = gtk.gdk.pixbuf_new_from_data(pixstr, colorspace, has_alpha, bits_per_sample, width, height, rowstride)
- #print pixbuf
- self.tab_activity_image.set_from_pixbuf(pixbuf)
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityHost", \
- in_signature="", \
- out_signature="")
- def shutdown(self):
- #print "shutdown"
- for owner, activity in self.activity_container.activities[:]:
- if activity == self:
- self.activity_container.activities.remove((owner, activity))
-
- for i in range(self.activity_container.notebook.get_n_pages()):
- child = self.activity_container.notebook.get_nth_page(i)
- if child == self.socket:
- #print "found child"
- self.activity_container.notebook.remove_page(i)
- break
-
- del self
-
- def get_host_activity_id(self):
- """Real function that the shell should use for getting the
- activity's ID."""
- return self.activity_id
-
- def get_id(self):
- """Interface-type function to match activity.Activity's
- get_id() function."""
- return self.activity_id
-
- def default_type(self):
- """Interface-type function to match activity.Activity's
- default_type() function."""
- return self._default_type
-
- def get_object_path(self):
- return self.dbus_object_name
-
- def update_tab_size(self):
- if self.ellipsize_tab:
- self.tab_label.set_ellipsize(pango.ELLIPSIZE_END)
-
- context = self.label_hbox.get_pango_context()
- font_desc = self.label_hbox.style.font_desc
- metrics = context.get_metrics(font_desc, context.get_language())
- char_width = metrics.get_approximate_digit_width()
- [w, h] = self.__get_close_icon_size()
- tab_width = 15 * pango.PIXELS(char_width) + 2 * w
- self.label_hbox.set_size_request(tab_width, -1);
- else:
- self.tab_label.set_ellipsize(pango.ELLIPSIZE_NONE)
- self.label_hbox.set_size_request(-1, -1)
-
- def __get_close_icon_size(self):
- settings = self.label_hbox.get_settings()
- return gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
-
- def __tab_label_style_set_cb(self, widget, previous_style):
- [w, h] = self.__get_close_icon_size()
- self.tab_close_button.set_size_request (w + 5, h + 2)
- self.update_tab_size()
-
-class ActivityContainerSignalHelper(gobject.GObject):
- """A gobject whose sole purpose is to distribute signals for
- an ActivityContainer object."""
-
- __gsignals__ = {
- 'local-activity-started': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
- 'local-activity-ended': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, parent):
- gobject.GObject.__init__(self)
- self._parent = parent
-
- def activity_started(self, activity_id):
- self.emit('local-activity-started', self._parent, activity_id)
-
- def activity_ended(self, activity_id):
- self.emit('local-activity-ended', self._parent, activity_id)
-
-class ActivityContainer(dbus.service.Object):
-
- def __init__(self, service, bus):
- self.activities = []
-
- self.bus = bus
- self.service = service
-
- self._signal_helper = ActivityContainerSignalHelper(self)
-
- dbus.service.Object.__init__(self, self.service, "/com/redhat/Sugar/Shell/ActivityContainer")
- bus.add_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
-
- self.window = gtk.Window()
- self.window.connect("key-press-event", self.__key_press_event_cb)
- self.window.set_title("OLPC Sugar")
-
- self._fullscreen = False
-
- self.notebook = gtk.Notebook()
- self.notebook.set_scrollable(True)
-
- tab_label = gtk.Label("Everyone")
- self._start_page = StartPage(self, self._signal_helper)
- self.notebook.append_page(self._start_page, tab_label)
- self._start_page.show()
-
- self.notebook.show()
- self.notebook.connect("switch-page", self.notebook_tab_changed)
- self.window.add(self.notebook)
-
- self.window.connect("destroy", lambda w: gtk.main_quit())
-
- self.current_activity = None
-
- # Create our owner service
- self._owner = ShellOwner()
-
- self._presence_window = PresenceWindow(self)
- self._presence_window.set_transient_for(self.window)
- self._presence_window.set_decorated(False)
- self._presence_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
- self._presence_window.set_skip_taskbar_hint(True)
-
- wm = WindowManager(self._presence_window)
-
- wm.set_width(170, WindowManager.ABSOLUTE)
- wm.set_height(1.0, WindowManager.SCREEN_RELATIVE)
- wm.set_position(WindowManager.LEFT)
- wm.manage()
-
- self._chat_window = ChatWindow()
- self._chat_window.set_transient_for(self.window)
- self._chat_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
- self._chat_window.set_decorated(False)
- self._chat_window.set_skip_taskbar_hint(True)
-
- self._chat_wm = WindowManager(self._chat_window)
-
- self._chat_wm.set_width(420, WindowManager.ABSOLUTE)
- self._chat_wm.set_height(380, WindowManager.ABSOLUTE)
- self._chat_wm.set_position(WindowManager.TOP)
- self._chat_wm.manage()
-
- self._mesh_chat = MeshChat()
-
- def show(self):
- self.window.show()
-
- def set_current_activity(self, activity):
- if self.current_activity != None:
- self.current_activity.lost_focus()
-
- self.current_activity = activity
- self._presence_window.set_activity(activity)
-
- if activity:
- host_chat = activity.get_chat()
- self._chat_window.set_chat(host_chat)
- else:
- self._chat_window.set_chat(self._mesh_chat)
-
- # For some reason the substitution screw up window position
- self._chat_wm.update()
-
- if self.current_activity != None:
- self.current_activity.got_focus()
-
- def notebook_tab_changed(self, notebook, page, page_number):
- new_activity = notebook.get_nth_page(page_number).get_data("sugar-activity")
- self.set_current_activity(new_activity)
-
- def switch_to_activity(self, activity_id):
- found = False
- for owner, activity in self.activities:
- if activity.get_host_activity_id() == activity_id:
- found = True
- break
- if not found:
- return
-
- # Find the activity in the notebook
- activity_page = None
- npages = self.notebook.get_n_pages()
- for pageno in range(1, npages):
- activity = self.notebook.get_nth_page(pageno).get_data("sugar-activity")
- if activity and activity.get_host_activity_id() == activity_id:
- activity_page = pageno
- break
- if not activity_page:
- return
-
- print "switching to activity page %d" % activity_page
- self.notebook.set_current_page(activity_page)
-
- def name_owner_changed(self, service_name, old_service_name, new_service_name):
- #print "in name_owner_changed: svc=%s oldsvc=%s newsvc=%s"%(service_name, old_service_name, new_service_name)
- for owner, activity in self.activities[:]:
- if owner == old_service_name:
- activity_id = activity.get_host_activity_id()
- self._signal_helper.activity_ended(activity_id)
- self.activities.remove((owner, activity))
- #self.__print_activities()
-
- def have_activity(self, activity_id):
- for owner, activity in self.activities:
- list_activity_id = activity.get_host_activity_id()
- if activity_id == list_activity_id:
- return True
- return False
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
- in_signature="ss", \
- out_signature="s", \
- sender_keyword="sender")
- def add_activity(self, activity_name, default_type, sender):
- #print "hello world, activity_name = '%s', sender = '%s'"%(activity_name, sender)
- activity = ActivityHost(self, activity_name, default_type)
- self.activities.append((sender, activity))
-
- activity_id = activity.get_host_activity_id()
- self._signal_helper.activity_started(activity_id)
-
- self.current_activity = activity
- return activity_id
-
- @dbus.service.method("com.redhat.Sugar.Shell.ActivityContainer", \
- in_signature="sss", \
- sender_keyword="sender")
- def add_activity_with_id(self, activity_name, default_type, activity_id, sender):
- activity = ActivityHost(self, activity_name, default_type, activity_id)
- self.activities.append((sender, activity))
- activity_id = activity.get_host_activity_id()
- self._signal_helper.activity_started(activity_id)
- self.current_activity = activity
-
- def __print_activities(self):
- print "__print_activities: %d activities registered" % len(self.activities)
- i = 0
- for owner, activity in self.activities:
- print " %d: owner=%s activity_object_name=%s" % (i, owner, activity.dbus_object_name)
- i += 1
-
- def __key_press_event_cb(self, window, event):
- if event.keyval == gtk.keysyms.F11:
- if self._fullscreen:
- window.unfullscreen()
- self._fullscreen = False
- else:
- window.fullscreen()
- self._fullscreen = True
-
-class ConsoleLogger(dbus.service.Object):
- def __init__(self):
- session_bus = dbus.SessionBus()
- bus_name = dbus.service.BusName('com.redhat.Sugar.Logger', bus=session_bus)
- object_path = '/com/redhat/Sugar/Logger'
- dbus.service.Object.__init__(self, bus_name, object_path)
-
- self._window = gtk.Window()
- self._window.set_title("Console")
- self._window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
- self._window.set_decorated(False)
- self._window.set_skip_taskbar_hint(True)
- self._window.connect("delete_event", lambda w, e: w.hide_on_delete())
-
- self._nb = gtk.Notebook()
- self._window.add(self._nb)
- self._nb.show()
-
- self._consoles = {}
-
- console_wm = WindowManager(self._window)
-
- console_wm.set_width(0.7, WindowManager.SCREEN_RELATIVE)
- console_wm.set_height(0.9, WindowManager.SCREEN_RELATIVE)
- console_wm.set_position(WindowManager.BOTTOM)
- console_wm.manage()
-
- def _create_console(self, application):
- sw = gtk.ScrolledWindow()
- sw.set_policy(gtk.POLICY_AUTOMATIC,
- gtk.POLICY_AUTOMATIC)
-
- console = gtk.TextView()
- console.set_wrap_mode(gtk.WRAP_WORD)
-
- sw.add(console)
- console.show()
-
- self._nb.append_page(sw, gtk.Label(application))
- sw.show()
-
- return console
-
- @dbus.service.method('com.redhat.Sugar.Logger')
- def log(self, application, message):
- if self._consoles.has_key(application):
- console = self._consoles[application]
- else:
- console = self._create_console(application)
- self._consoles[application] = console
-
- buf = console.get_buffer()
- buf.insert(buf.get_end_iter(), message)
-
-class Shell(gobject.GObject):
- __gsignals__ = {
- 'close': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- }
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- def start(self):
- console = ConsoleLogger()
-
- log_writer = LogWriter("Shell", False)
- log_writer.start()
-
- session_bus = dbus.SessionBus()
- service = dbus.service.BusName("com.redhat.Sugar.Shell", bus=session_bus)
-
- activity_container = ActivityContainer(service, session_bus)
- activity_container.window.connect('destroy', self.__activity_container_destroy_cb)
- activity_container.show()
-
- wm = WindowManager(activity_container.window)
- wm.set_width(640, WindowManager.ABSOLUTE)
- wm.set_height(480, WindowManager.ABSOLUTE)
- wm.set_position(WindowManager.CENTER)
- wm.show()
- wm.manage()
-
- def __activity_container_destroy_cb(self, activity_container):
- self.emit('close')
-
-if __name__ == "__main__":
- shell = Shell()
- shell.start()
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+c pressed, exiting...'
diff --git a/shell/sugar b/shell/sugar
index a4fd0239..9a857dbd 100755
--- a/shell/sugar
+++ b/shell/sugar
@@ -9,6 +9,9 @@ import pygtk
pygtk.require('2.0')
import gobject
+# FIXME How to pick a good display number
+XEPHYR_DISPLAY = 100
+
def add_to_python_path(path):
sys.path.insert(0, path)
if os.environ.has_key('PYTHONPATH'):
@@ -23,7 +26,6 @@ def start_dbus():
dbus_file = os.fdopen(dbus_stdout)
addr = dbus_file.readline()
addr = addr.strip()
- print "dbus-daemon pid is %d, session bus address is %s" % (dbus_pid, addr)
dbus_file.close()
os.environ["DBUS_SESSION_BUS_ADDRESS"] = addr
@@ -37,6 +39,20 @@ def stop_dbus(dbus_pid):
except OSError:
pass
+def start_xephyr():
+ command = 'Xephyr :%d -ac -screen 640x480' % (XEPHYR_DISPLAY)
+ xephyr_pid = os.spawnvp(os.P_NOWAIT, 'Xephyr', command.split())
+
+def stop_xephyr():
+ os.kill(xephyr_pid)
+
+def start_matchbox():
+ command = 'matchbox-window-manager -use_titlebar no'
+ xephyr_pid = os.spawnvp(os.P_NOWAIT, 'matchbox-window-manager', command.split())
+
+def stop_matchbox():
+ os.kill(xephyr_pid)
+
i = 0
dbus_daemon_pid = None
for arg in sys.argv:
@@ -56,7 +72,6 @@ if not os.environ.has_key("SUGAR_NICK_NAME"):
os.environ['SUGAR_NICK_NAME'] = nick
os.environ['SUGAR_USER_DIR'] = os.path.expanduser('~/.sugar')
-
curdir = os.path.abspath(os.path.dirname(__file__))
basedir = os.path.dirname(curdir)
@@ -68,6 +83,10 @@ else:
import sugar.env
add_to_python_path(os.path.join(sugar.env.get_data_dir(), 'shell'))
print 'Running the installed sugar...'
+
+start_xephyr()
+os.environ['DISPLAY'] = ":%d" % (XEPHYR_DISPLAY)
+start_matchbox()
print 'Redirecting output to the console, press Ctrl+Down to open it.'
@@ -78,3 +97,6 @@ session.start()
if dbus_daemon_pid:
stop_dbus(dbus_daemon_pid)
+
+stop_matchbox()
+stop_xephyr()
diff --git a/sugar/activity/Activity.py b/sugar/activity/Activity.py
index 344e1069..b397d154 100644
--- a/sugar/activity/Activity.py
+++ b/sugar/activity/Activity.py
@@ -9,6 +9,8 @@ pygtk.require('2.0')
import gtk, gobject
from sugar.LogWriter import LogWriter
+from sugar import keybindings
+import sugar.util
SHELL_SERVICE_NAME = "com.redhat.Sugar.Shell"
SHELL_SERVICE_PATH = "/com/redhat/Sugar/Shell"
@@ -16,12 +18,6 @@ SHELL_SERVICE_PATH = "/com/redhat/Sugar/Shell"
ACTIVITY_SERVICE_NAME = "com.redhat.Sugar.Activity"
ACTIVITY_SERVICE_PATH = "/com/redhat/Sugar/Activity"
-ON_CONNECTED_TO_SHELL_CB = "connected_to_shell"
-ON_DISCONNECTED_FROM_SHELL_CB = "disconnected_from_shell"
-ON_RECONNECTED_TO_SHELL_CB = "reconnected_to_shell"
-ON_CLOSE_FROM_USER_CB = "close_from_user"
-ON_LOST_FOCUS_CB = "lost_focus"
-ON_GOT_FOCUS_CB = "got_focus"
ON_PUBLISH_CB = "publish"
def get_path(activity_name):
@@ -65,14 +61,10 @@ class ActivityFactory(dbus.service.Object):
service = Service.deserialize(serialized_service)
activity = self._class(args)
- gobject.idle_add(self._start_activity_cb, activity, service)
@dbus.service.method("com.redhat.Sugar.ActivityFactory")
- def create(self, args):
- self.create_with_service(None, args)
-
- def _start_activity_cb(self, activity, service):
- activity.connect_to_shell(service)
+ def create(self):
+ self.create_with_service(None, [])
def create(activity_name, service = None, args = None):
"""Create a new activity from his name."""
@@ -84,11 +76,21 @@ def create(activity_name, service = None, args = None):
proxy_obj = bus.get_object(factory_name, factory_path)
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
- if service:
+ if service and args:
serialized_service = service.serialize(service)
factory.create_with_service(serialized_service, args)
else:
- factory.create(args)
+ factory.create()
+
+def _get_registry():
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object("com.redhat.Sugar.ActivityRegistry",
+ "/com/redhat/Sugar/ActivityRegistry")
+ return dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityRegistry")
+
+def list_activities():
+ registry = _get_registry()
+ return registry.list_activities()
def main(activity_name, activity_class):
"""Starts the activity main loop."""
@@ -97,6 +99,9 @@ def main(activity_name, activity_class):
factory = ActivityFactory(activity_name, activity_class)
+ registry = _get_registry()
+ registry.add(activity_name, activity_name)
+
gtk.main()
class ActivityDbusService(dbus.service.Object):
@@ -105,29 +110,19 @@ class ActivityDbusService(dbus.service.Object):
The dbus service is separate from the actual Activity object so that we can
tightly control what stuff passes through the dbus python bindings."""
- _ALLOWED_CALLBACKS = [ON_CONNECTED_TO_SHELL_CB, ON_DISCONNECTED_FROM_SHELL_CB, \
- ON_RECONNECTED_TO_SHELL_CB, ON_CLOSE_FROM_USER_CB, ON_LOST_FOCUS_CB, \
- ON_GOT_FOCUS_CB, ON_PUBLISH_CB]
+ _ALLOWED_CALLBACKS = [ON_PUBLISH_CB]
- def __init__(self, activity):
+ def __init__(self, xid, activity):
self._activity = activity
- self._activity_id = None
- self._activity_object = None
- self._service = None
- self._bus = dbus.SessionBus()
- self._bus.add_signal_receiver(self.name_owner_changed, dbus_interface = "org.freedesktop.DBus", signal_name = "NameOwnerChanged")
self._callbacks = {}
for cb in self._ALLOWED_CALLBACKS:
self._callbacks[cb] = None
-
- def __del__(self):
- if self._activity_id:
- del self._service
- del self._activity_container
- del self._activity_conainer_object
- del self._activity_object
- self._bus.remove_signal_receiver(self.name_owner_changed, dbus_interface="org.freedesktop.DBus", signal_name="NameOwnerChanged")
- del self._bus
+
+ bus = dbus.SessionBus()
+ service_name = ACTIVITY_SERVICE_NAME + "%s" % xid
+ object_path = ACTIVITY_SERVICE_PATH + "/%s" % xid
+ service = dbus.service.BusName(service_name, bus=bus)
+ dbus.service.Object.__init__(self, service, object_path)
def register_callback(self, name, callback):
if name not in self._ALLOWED_CALLBACKS:
@@ -146,97 +141,33 @@ class ActivityDbusService(dbus.service.Object):
if name in self._ALLOWED_CALLBACKS and self._callbacks[name]:
gobject.idle_add(self._call_callback_cb, self._callbacks[name], *args)
- def connect_to_shell(self, service=None):
- """Register with the shell via dbus, getting an activity ID and
- and XEMBED window ID in which to display the Activity."""
- self._activity_container_object = self._bus.get_object(SHELL_SERVICE_NAME, \
- SHELL_SERVICE_PATH + "/ActivityContainer")
- self._activity_container = dbus.Interface(self._activity_container_object, \
- SHELL_SERVICE_NAME + ".ActivityContainer")
-
- if service is None:
- self._activity_id = self._activity_container.add_activity("", self._activity.default_type())
- else:
- self._activity_id = service.get_activity_id()
- self._activity_container.add_activity_with_id("", self._activity.default_type(), self._activity_id)
-
- self._object_path = SHELL_SERVICE_PATH + "/Activities/%s" % self._activity_id
-
- print "ActivityDbusService: object path is '%s'" % self._object_path
-
- self._activity_object = dbus.Interface(self._bus.get_object(SHELL_SERVICE_NAME, self._object_path), \
- SHELL_SERVICE_NAME + ".ActivityHost")
-
- # Now let us register a peer service so the Shell can poke it
- self._peer_service_name = ACTIVITY_SERVICE_NAME + "%s" % self._activity_id
- self._peer_object_path = ACTIVITY_SERVICE_PATH + "/%s" % self._activity_id
- self._service = dbus.service.BusName(self._peer_service_name, bus=self._bus)
- dbus.service.Object.__init__(self, self._service, self._peer_object_path)
-
- self._activity_object.set_peer_service_name(self._peer_service_name, self._peer_object_path)
-
- self._call_callback(ON_CONNECTED_TO_SHELL_CB, self._activity_object, self._activity_id, service)
-
- def _shutdown_reply_cb(self):
- """Shutdown was successful, tell the Activity that we're disconnected."""
- self._call_callback(ON_DISCONNECTED_FROM_SHELL_CB)
-
- def _shutdown_error_cb(self, error):
- print "ActivityDbusService: error during shutdown - '%s'" % error
-
- def shutdown(self):
- """Notify the shell that we are shutting down."""
- self._activity_object.shutdown(reply_handler=self._shutdown_reply_cb, error_handler=self._shutdown_error_cb)
-
- def name_owner_changed(self, service_name, old_service_name, new_service_name):
- """Handle dbus NameOwnerChanged signals."""
- if not self._activity_id:
- # Do nothing if we're not connected yet
- return
-
- if service_name == SHELL_SERVICE_NAME and not len(new_service_name):
- self._call_callback(ON_DISCONNECTED_FROM_SHELL_CB)
- elif service_name == SHELL_SERVICE_NAME and not len(old_service_name):
- self._call_callback(ON_RECONNECTED_TO_SHELL_CB)
-
- @dbus.service.method(ACTIVITY_SERVICE_NAME)
- def lost_focus(self):
- """Called by the shell to notify us that we've lost focus."""
- self._call_callback(ON_LOST_FOCUS_CB)
-
- @dbus.service.method(ACTIVITY_SERVICE_NAME)
- def got_focus(self):
- """Called by the shell to notify us that the user gave us focus."""
- self._call_callback(ON_GOT_FOCUS_CB)
-
- @dbus.service.method(ACTIVITY_SERVICE_NAME)
- def close_from_user(self):
- """Called by the shell to notify us that the user closed us."""
- self._call_callback(ON_CLOSE_FROM_USER_CB)
-
@dbus.service.method(ACTIVITY_SERVICE_NAME)
def publish(self):
"""Called by the shell to request the activity to publish itself on the network."""
self._call_callback(ON_PUBLISH_CB)
- @dbus.service.signal(ACTIVITY_SERVICE_NAME)
- def ActivityShared(self):
- pass
+ @dbus.service.method(ACTIVITY_SERVICE_NAME)
+ def get_id(self):
+ """Get the activity identifier"""
+ self._activity.get_id()
-class Activity(object):
+ @dbus.service.method(ACTIVITY_SERVICE_NAME)
+ def get_shared(self):
+ """Get the activity identifier"""
+ return self._activity.get_shared()
+
+class Activity(gtk.Window):
"""Base Activity class that all other Activities derive from."""
- def __init__(self, default_type):
- self._dbus_service = self._get_new_dbus_service()
- self._dbus_service.register_callback(ON_CONNECTED_TO_SHELL_CB, self._internal_on_connected_to_shell_cb)
- self._dbus_service.register_callback(ON_DISCONNECTED_FROM_SHELL_CB, self._internal_on_disconnected_from_shell_cb)
- self._dbus_service.register_callback(ON_RECONNECTED_TO_SHELL_CB, self._internal_on_reconnected_to_shell_cb)
- self._dbus_service.register_callback(ON_CLOSE_FROM_USER_CB, self._internal_on_close_from_user_cb)
- self._dbus_service.register_callback(ON_PUBLISH_CB, self._internal_on_publish_cb)
- self._dbus_service.register_callback(ON_LOST_FOCUS_CB, self._internal_on_lost_focus_cb)
- self._dbus_service.register_callback(ON_GOT_FOCUS_CB, self._internal_on_got_focus_cb)
- self._has_focus = False
- self._plug = None
+ def __init__(self, default_type, activity_id = None):
+ gtk.Window.__init__(self)
+
+ if activity_id is None:
+ self._activity_id = sugar.util.unique_id()
+ else:
+ self._activity_id = activity_id
+
+ self._dbus_service = None
self._initial_service = None
self._activity_object = None
self._shared = False
@@ -244,10 +175,21 @@ class Activity(object):
raise ValueError("Default type must be a valid string.")
self._default_type = default_type
+ keybindings.setup_global_keys(self)
+
+ self.connect('realize', self.__realize)
+
+ self.present()
+
+ def __realize(self, window):
+ if not self._dbus_service:
+ self._register_service()
+
+ def _register_service(self):
+ self._dbus_service = self._get_new_dbus_service()
+ self._dbus_service.register_callback(ON_PUBLISH_CB, self._internal_on_publish_cb)
+
def _cleanup(self):
- if self._plug:
- self._plug.destroy()
- self._plug = None
if self._dbus_service:
del self._dbus_service
self._dbus_service = None
@@ -258,7 +200,7 @@ class Activity(object):
def _get_new_dbus_service(self):
"""Create and return a new dbus service object for this Activity.
Allows subclasses to use their own dbus service object if they choose."""
- return ActivityDbusService(self)
+ return ActivityDbusService(self.window.xid, self)
def default_type(self):
return self._default_type
@@ -269,119 +211,20 @@ class Activity(object):
self._shared = True
self._dbus_service.ActivityShared()
- def shared(self):
+ def get_shared(self):
return self._shared
def has_focus(self):
"""Return whether or not this Activity is visible to the user."""
return self._has_focus
- def connect_to_shell(self, service = None):
- """Called by our controller to tell us to initialize and connect
- to the shell."""
- self._dbus_service.connect_to_shell(service)
-
- def _internal_on_connected_to_shell_cb(self, activity_object, activity_id, service=None):
- """Callback when the dbus service object has connected to the shell."""
- self._activity_object = activity_object
- self._activity_id = activity_id
- self._window_id = self._activity_object.get_host_xembed_id()
- print "Activity: XEMBED window ID is %s" % self._window_id
- self._plug = gtk.Plug(self._window_id)
- self._initial_service = service
- if service:
- self.set_shared()
- self.on_connected_to_shell()
-
- def _internal_on_disconnected_from_shell_cb(self):
- """Callback when the dbus service object has disconnected from the shell."""
- self._cleanup()
- self.on_disconnected_from_shell()
-
- def _internal_on_reconnected_to_shell_cb(self):
- """Callback when the dbus service object has reconnected to the shell."""
- self.on_reconnected_to_shell()
-
- def _internal_on_close_from_user_cb(self):
- """Callback when the dbus service object tells us the user has closed our activity."""
- self.shutdown()
- self.on_close_from_user()
-
def _internal_on_publish_cb(self):
"""Callback when the dbus service object tells us the user has closed our activity."""
self.publish()
- def _internal_on_lost_focus_cb(self):
- """Callback when the dbus service object tells us we have lost focus."""
- self._has_focus = False
- self.on_lost_focus()
-
- def _internal_on_got_focus_cb(self):
- """Callback when the dbus service object tells us we have gotten focus."""
- self._has_focus = True
- self.set_has_changes(False)
- self.on_got_focus()
-
- def gtk_plug(self):
- """Return our GtkPlug widget."""
- return self._plug
-
- def set_ellipsize_tab(self, ellipsize):
- """Sets this Activity's tab text to be ellipsized or not."""
- self._activity_object.set_ellipsize_tab(ellipsize)
-
- def set_tab_text(self, text):
- """Sets this Activity's tab text."""
- self._activity_object.set_tab_text(text)
-
- def set_can_close(self, can_close):
- """Sets whether or not this Activity can be closed by the user."""
- self._activity_object.set_can_close(can_close)
-
- def set_show_tab_icon(self, show_icon):
- """Sets whether or not an icon is shown in this Activity's tab."""
- self._activity_object.set_tab_show_icon(show_icon)
-
- def set_tab_icon(self, pixbuf=None, name=None):
- """Set the Activity's tab icon, either from pixbuf data
- or by an icon theme icon name."""
- if name:
- icon_theme = gtk.icon_theme_get_default()
- icon_info = icon_theme.lookup_icon(name, gtk.ICON_SIZE_MENU, 0)
- if icon_info:
- orig_pixbuf = icon_info.load_icon()
- pixbuf = orig_pixbuf.scale_simple(16, 16, gtk.gdk.INTERP_BILINEAR)
-
- if pixbuf:
- # Dump the pixel data into an array and shove it through dbus
- pixarray = []
- pixstr = pixbuf.get_pixels();
- for c in pixstr:
- pixarray.append(c)
- self._activity_object.set_tab_icon(pixarray, \
- pixbuf.get_colorspace(), \
- pixbuf.get_has_alpha(), \
- pixbuf.get_bits_per_sample(), \
- pixbuf.get_width(), \
- pixbuf.get_height(), \
- pixbuf.get_rowstride())
-
- def set_has_changes(self, has_changes):
- """Marks this Activity as having changes. This usually means
- that this Activity's tab turns a red color or something else
- to notify the user that this Activity needs attention."""
- if not self.has_focus() and has_changes:
- self._activity_object.set_has_changes(True)
- else:
- self._activity_object.set_has_changes(False)
-
def get_id(self):
return self._activity_id
- def shutdown(self):
- """Disconnect from the shell and clean up."""
- self._dbus_service.shutdown()
-
#############################################################
# Pure Virtual methods that subclasses may/may not implement
#############################################################
@@ -390,29 +233,5 @@ class Activity(object):
"""Called to request the activity to publish itself on the network."""
pass
- def on_lost_focus(self):
- """Triggered when this Activity loses focus."""
- pass
-
- def on_got_focus(self):
- """Triggered when this Activity gets focus."""
- pass
-
- def on_disconnected_from_shell(self):
- """Triggered when we disconnect from the shell."""
- pass
-
- def on_reconnected_to_shell(self):
- """Triggered when the shell's service comes back."""
- pass
-
- def on_connected_to_shell(self):
- """Triggered when this Activity has successfully connected to the shell."""
- pass
-
- def on_close_from_user(self):
- """Triggered when this Activity is closed by the user."""
- pass
-
if __name__ == "__main__":
main(sys.argv[1], sys.argv[2])
diff --git a/sugar/chat/ChatWindow.py b/sugar/chat/ChatWindow.py
deleted file mode 100644
index b06175d9..00000000
--- a/sugar/chat/ChatWindow.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import pygtk
-pygtk.require('2.0')
-import gtk
-
-from sugar.chat.Chat import Chat
-
-class ChatWindow(gtk.Window):
- def __init__(self):
- gtk.Window.__init__(self)
- self._chat = None
-
- def set_chat(self, chat):
- if self._chat != None:
- self.remove(self._chat)
-
- self._chat = chat
- self.add(self._chat)
- self._chat.show()
diff --git a/sugar/keybindings.py b/sugar/keybindings.py
new file mode 100644
index 00000000..fbc215db
--- /dev/null
+++ b/sugar/keybindings.py
@@ -0,0 +1,21 @@
+import gtk
+import dbus
+
+# FIXME These should be handled by the wm, but it's incovenient
+# to do that with matchbox at the moment
+
+def setup_global_keys(window, shell = None):
+ if not shell:
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object('com.redhat.Sugar.Shell', '/com/redhat/Sugar/Shell')
+ shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.Shell')
+
+ window.connect("key-press-event", __key_press_event_cb, shell)
+
+def __key_press_event_cb(window, event, shell):
+ if event.keyval == gtk.keysyms.F1:
+ shell.toggle_home()
+ if event.keyval == gtk.keysyms.F2:
+ shell.toggle_people()
+ if event.keyval == gtk.keysyms.F3:
+ shell.toggle_console()