Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@activitycentral.com>2012-09-12 19:28:25 (GMT)
committer Ruben Rodriguez <ruben@activitycentral.com>2012-09-12 19:28:25 (GMT)
commit3981a3e0228ae0a844a4cc7b4ac6c5d1309b1fcd (patch)
tree0b3f734c15bc892d03510ba6c33915891f1ebb4d
parent306b9d67461493f2a0d903eba0b9318e33a2b075 (diff)
Removed 0130 patches in AU branch
-rw-r--r--rpms/sugar/0130-1-to-N-feature-via-School-Server.patch1954
-rw-r--r--rpms/sugar/0130-Remove-1-to-N-feature-for-AU.patch6700
2 files changed, 0 insertions, 8654 deletions
diff --git a/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch b/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
deleted file mode 100644
index 81cd2f8..0000000
--- a/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
+++ /dev/null
@@ -1,1954 +0,0 @@
-From d56362d85ecd6ce9921a67c2f4252d01c26a71af Mon Sep 17 00:00:00 2001
-From: Ajay Garg <ajay@activitycentral.com>
-Date: Tue, 4 Sep 2012 18:16:19 +0530
-Subject: [sugar PATCH] 1-to-N-feature via Peer-to-Peer mechanism; and Via-School-Server mechanism.
-Organization: Sugar Labs Foundation
-Signed-off-by: Ajay Garg <ajay@activitycentral.com>
----
- src/jarabe/frame/activitiestray.py | 5 +
- src/jarabe/frame/frame.py | 3 +
- src/jarabe/intro/window.py | 12 +
- src/jarabe/journal/expandedentry.py | 24 ++-
- src/jarabe/journal/journalactivity.py | 17 ++-
- src/jarabe/journal/journaltoolbox.py | 44 ++++-
- src/jarabe/journal/model.py | 375 ++++++++++++++++++++++-----------
- src/jarabe/journal/palettes.py | 283 ++++++++++++++++++++++---
- src/jarabe/journal/volumestoolbar.py | 92 ++++++---
- src/jarabe/journal/webdavmanager.py | 172 ++++++++++-----
- src/jarabe/view/buddymenu.py | 45 ++++-
- src/jarabe/view/palettes.py | 38 ++--
- src/webdav/Connection.py | 11 +-
- src/webdav/WebdavClient.py | 16 +-
- src/webdav/davlib.py | 9 +-
- 15 files changed, 867 insertions(+), 279 deletions(-)
-
-diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py
-index 55e0c31..7cbeefb 100644
---- a/src/jarabe/frame/activitiestray.py
-+++ b/src/jarabe/frame/activitiestray.py
-@@ -249,6 +249,8 @@ class ActivitiesTray(HTray):
- # JournalActivity is always the first activity to be added.
- # Broadcast the signal-of-its-creation.
- if group is None:
-+ self._journal_button = button
-+ self._journal_activity = home_activity
- self._signal_addition_of_journal_activity()
-
- def _signal_addition_of_journal_activity(self):
-@@ -306,6 +308,9 @@ class ActivitiesTray(HTray):
- if window:
- window.activate(gtk.get_current_event_time())
-
-+ def _show_journal_activity(self):
-+ self.__activity_clicked_cb(self._journal_button, self._journal_activity)
-+
- def __remove_invite_cb(self, icon, invite):
- self._invites.remove_invite(invite)
-
-diff --git a/src/jarabe/frame/frame.py b/src/jarabe/frame/frame.py
-index cd1dc20..821e31f 100644
---- a/src/jarabe/frame/frame.py
-+++ b/src/jarabe/frame/frame.py
-@@ -449,3 +449,6 @@ class Frame(object):
- # Do nothing for now. Our notification UI is so simple, there's no
- # point yet.
- pass
-+
-+ def switch_to_journal_activity(self):
-+ self._activities_tray._show_journal_activity()
-diff --git a/src/jarabe/intro/window.py b/src/jarabe/intro/window.py
-index df19fbf..c4ae56e 100644
---- a/src/jarabe/intro/window.py
-+++ b/src/jarabe/intro/window.py
-@@ -56,6 +56,18 @@ def create_profile(name, color=None):
- else:
- logging.error('Keypair exists, skip generation.')
-
-+ # Also, generate SSL key and cert pair; to be used in secure
-+ # sharing of webdav entries via httpd.
-+ keypath = os.path.join(env.get_profile_path(), 'ssl.key')
-+ certpath = os.path.join(env.get_profile_path(), 'ssl.crt')
-+
-+ cmd = 'openssl req -new -newkey rsa:1024 -days 365 -nodes ' + \
-+ '-x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" ' + \
-+ '-keyout %s -out %s' % (keypath, certpath)
-+ (s, o) = commands.getstatusoutput(cmd)
-+ if s != 0:
-+ logging.error('Could not generate ssl key and cert: %d %s', s, o)
-+
-
- class _Page(hippo.CanvasBox):
- __gproperties__ = {
-diff --git a/src/jarabe/journal/expandedentry.py b/src/jarabe/journal/expandedentry.py
-index 03f8cd1..1e857ba 100644
---- a/src/jarabe/journal/expandedentry.py
-+++ b/src/jarabe/journal/expandedentry.py
-@@ -166,13 +166,35 @@ class ExpandedEntry(hippo.CanvasBox):
- self._buddy_list.append(self._create_buddy_list())
-
- description = self._description.text_view_widget
-- description.props.buffer.props.text = metadata.get('description', '')
-+
-+ # TRANS: Do not translate the """%s""".
-+ uploader_nick_text = self.__create_text_description(
-+ _('Source XO Nick :: \n%s'), metadata.get('uploader-nick', ''))
-+
-+ # TRANS: Do not translate the """%s""".
-+ uploader_serial_text = self.__create_text_description(
-+ _('Source XO Serial Number :: \n%s'), metadata.get('uploader-serial', ''))
-+
-+ # TRANS: Do not translate the """%s""".
-+ misc_info_text = self.__create_text_description(
-+ _('Misellaneous Information :: \n%s'), metadata.get('description', ''))
-+
-+ description.props.buffer.props.text = uploader_nick_text + \
-+ uploader_serial_text + \
-+ misc_info_text
-+
- description.props.editable = model.is_editable(metadata)
-
- tags = self._tags.text_view_widget
- tags.props.buffer.props.text = metadata.get('tags', '')
- tags.props.editable = model.is_editable(metadata)
-
-+ def __create_text_description(self, heading, value):
-+ if (value == '') or (value is None):
-+ return ''
-+
-+ return ((heading % value) + '\n\n')
-+
- def _create_keep_icon(self):
- keep_icon = KeepIcon(False)
- keep_icon.connect('activated', self._keep_icon_activated_cb)
-diff --git a/src/jarabe/journal/journalactivity.py b/src/jarabe/journal/journalactivity.py
-index fc4773d..5f2a734 100644
---- a/src/jarabe/journal/journalactivity.py
-+++ b/src/jarabe/journal/journalactivity.py
-@@ -180,10 +180,14 @@ class JournalActivity(JournalWindow):
- self._check_available_space()
-
- def __volume_error_cb(self, gobject, message, severity):
-- alert = ErrorAlert(title=severity, msg=message)
-- alert.connect('response', self.__alert_response_cb)
-- self.add_alert(alert)
-- alert.show()
-+ self.update_title_and_message(self._error_alert, severity,
-+ message)
-+ self._callback = None
-+ self._data = None
-+ self.update_alert(self._error_alert)
-+
-+ def _show_alert(self, message, severity):
-+ self.__volume_error_cb(None, message, severity)
-
- def _volume_error_cb(self, gobject, message, severity):
- self.update_error_alert(severity, message, None, None)
-@@ -449,6 +453,8 @@ class JournalActivity(JournalWindow):
- self.remove_alert(self._current_alert)
- self.add_alert(alert)
-
-+ self.remove_alert(self._current_alert)
-+ self.add_alert(alert)
- self._current_alert = alert
- self._current_alert.show()
- show_normal_cursor()
-@@ -475,6 +481,9 @@ class JournalActivity(JournalWindow):
- self._data = data
- self.update_alert(self._confirmation_alert)
-
-+ def update_progress(self, fraction):
-+ self.get_toolbar_box().update_progress(fraction)
-+
- def get_metadata_list(self, selected_state):
- metadata_list = []
-
-diff --git a/src/jarabe/journal/journaltoolbox.py b/src/jarabe/journal/journaltoolbox.py
-index 6b2494e..b1c0cac 100644
---- a/src/jarabe/journal/journaltoolbox.py
-+++ b/src/jarabe/journal/journaltoolbox.py
-@@ -78,6 +78,16 @@ class MainToolbox(Toolbox):
- self.add_toolbar(_('Search'), self.search_toolbar)
- self.search_toolbar.show()
-
-+ self._info_widget = MultiSelectEntriesInfoWidget()
-+ self.add(self._info_widget)
-+ self._info_widget.hide()
-+
-+ def update_progress(self, fraction):
-+ self._info_widget.update_progress(fraction)
-+
-+ def hide_info_widget(self):
-+ self._info_widget.hide()
-+
-
- class SearchToolbar(gtk.Toolbar):
- __gtype_name__ = 'SearchToolbar'
-@@ -532,6 +542,9 @@ class EditToolbox(Toolbox):
- def get_current_entry_number(self):
- return self.edit_toolbar._get_current_entry_number()
-
-+ def update_progress(self, fraction):
-+ self.edit_toolbar.get_multi_select_info_widget().update_progress(fraction)
-+
-
- class EditToolbar(gtk.Toolbar):
- def __init__(self):
-@@ -552,6 +565,9 @@ class EditToolbar(gtk.Toolbar):
-
- self.show_all()
-
-+ def get_multi_select_info_widget(self):
-+ return self._multi_select_info_widget
-+
- def _set_total_number_of_entries(self, total):
- self._multi_select_info_widget.set_total_number_of_entries(total)
-
-@@ -703,16 +719,40 @@ class MultiSelectEntriesInfoWidget(gtk.ToolItem):
- def __init__(self):
- gtk.ToolItem.__init__(self)
-
-+ self._box = gtk.VBox()
- self._selected_entries = 0
-
- self._label = gtk.Label()
-- self.add(self._label)
-+ self._box.pack_start(self._label, expand=False)
-+
-+ self._progress_label = gtk.Label()
-+ self._box.pack_start(self._progress_label, expand=False)
-+
-+ self.add(self._box)
-
- self.show_all()
-+ self._box.show_all()
-+ self._progress_label.hide()
-
- def set_total_number_of_entries(self, total):
- self._total = total
-
-+ def update_progress(self, fraction):
-+ percent = '%.02f' % (fraction * 100)
-+
-+ # TRANS: Do not translate %.02f
-+ text = '%.02f%% complete' % (fraction * 100)
-+ if (str(percent) != '100.00') and (str(percent).endswith('00')):
-+ self._progress_label.set_text(text)
-+ self._progress_label.show()
-+ self.show_all()
-+ gtk.gdk.window_process_all_updates()
-+ else:
-+ self._progress_label.hide()
-+ from jarabe.journal.journalactivity import get_journal
-+ if not get_journal().is_editing_mode_present():
-+ self.hide()
-+
- def update_text(self, primary_text, secondary_text, special_action,
- update_selected_entries):
- # If "special_action" is None,
-@@ -749,6 +789,8 @@ class MultiSelectEntriesInfoWidget(gtk.ToolItem):
- self._label.set_text(message)
- self._label.show()
-
-+ gtk.gdk.window_process_all_updates()
-+
- def get_current_entry_number(self):
- return self._selected_entries
-
-diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py
-index 422e947..c06b2ee 100644
---- a/src/jarabe/journal/model.py
-+++ b/src/jarabe/journal/model.py
-@@ -43,7 +43,7 @@ from sugar import dispatch
- from sugar import mime
- from sugar import util
-
--from jarabe.journal.webdavmanager import get_remote_webdav_share_metadata
-+from jarabe.journal import webdavmanager
-
- DS_DBUS_SERVICE = 'org.laptop.sugar.DataStore'
- DS_DBUS_INTERFACE = 'org.laptop.sugar.DataStore'
-@@ -58,6 +58,9 @@ PROPERTIES = ['activity', 'activity_id', 'buddies', 'bundle_id',
- MIN_PAGES_TO_CACHE = 3
- MAX_PAGES_TO_CACHE = 5
-
-+WEBDAV_MOUNT_POINT = '/tmp/'
-+LOCAL_SHARES_MOUNT_POINT = '/var/www/web1/web/'
-+
- JOURNAL_METADATA_DIR = '.Sugar-Metadata'
-
- _datastore = None
-@@ -66,6 +69,52 @@ updated = dispatch.Signal()
- deleted = dispatch.Signal()
-
-
-+SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME_PATH = \
-+ '/desktop/sugar/network/school_server_ip_address_or_dns_name'
-+
-+client = gconf.client_get_default()
-+SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME = client.get_string(SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME_PATH) or '127.0.0.1'
-+
-+
-+def _get_mount_point(path):
-+ dir_path = os.path.dirname(path)
-+ while dir_path:
-+ if os.path.ismount(dir_path):
-+ return dir_path
-+ else:
-+ dir_path = dir_path.rsplit(os.sep, 1)[0]
-+ return None
-+
-+
-+def is_mount_point_for_school_server(mount_point):
-+ from jarabe.journal.journalactivity import get_journal
-+ from jarabe.journal.volumestoolbar import SHARE_TYPE_SCHOOL_SERVER
-+
-+ mount_point_button = get_journal().get_volumes_toolbar()._get_button_for_mount_point(mount_point)
-+ if mount_point_button._share_type == SHARE_TYPE_SCHOOL_SERVER:
-+ return True
-+ return False
-+
-+
-+def extract_ip_address_or_dns_name_from_locally_mounted_remote_share_path(path):
-+ """
-+ Path is of type ::
-+
-+ /tmp/1.2.3.4/webdav/a.txt; OR
-+ /tmp/this.is.dns.name/a.txt
-+ """
-+ return path.split('/')[2]
-+
-+
-+def is_mount_point_for_locally_mounted_remote_share(mount_point):
-+ """
-+ The mount-point can be either of the ip-Address, or the DNS name.
-+ More importantly, whatever the "name" be, it does NOT have a
-+ forward-slash.
-+ """
-+ return mount_point.find(WEBDAV_MOUNT_POINT) == 0
-+
-+
- class _Cache(object):
-
- __gtype_name__ = 'model_Cache'
-@@ -430,8 +479,8 @@ class InplaceResultSet(BaseResultSet):
-
-
- class RemoteShareResultSet(object):
-- def __init__(self, ip_address, query):
-- self._ip_address = ip_address
-+ def __init__(self, ip_address_or_dns_name, query):
-+ self._ip_address_or_dns_name = ip_address_or_dns_name
- self._file_list = []
-
- self.ready = dispatch.Signal()
-@@ -464,7 +513,11 @@ class RemoteShareResultSet(object):
- self._sort = query.get('order_by', ['+timestamp'])[0]
-
- def setup(self):
-- metadata_list_complete = get_remote_webdav_share_metadata(self._ip_address)
-+ try:
-+ metadata_list_complete = webdavmanager.get_remote_webdav_share_metadata(self._ip_address_or_dns_name)
-+ except Exception, e:
-+ metadata_list_complete = []
-+
- for metadata in metadata_list_complete:
-
- add_to_list = False
-@@ -553,15 +606,8 @@ def _get_file_metadata(path, stat, fetch_preview=True):
- metadata based on the file properties.
-
- """
-- filename = os.path.basename(path)
-- dir_path = os.path.dirname(path)
-- metadata = _get_file_metadata_from_json(dir_path, filename, fetch_preview)
-+ metadata = _get_file_metadata_from_json(path, fetch_preview)
- if metadata:
-- # For Documents/Shares/Mounted-Drives.
-- # Special case: for locally-mounted-remote-files, ensure that
-- # "metadata['filesize' is already present before-hand. This
-- # will have to be done at the time of fetching
-- # webdav-properties per resource.
- if 'filesize' not in metadata:
- if stat is not None:
- metadata['filesize'] = stat.st_size
-@@ -582,17 +628,26 @@ def _get_file_metadata(path, stat, fetch_preview=True):
- 'description': path}
-
-
--def _get_file_metadata_from_json(dir_path, filename, fetch_preview):
-+def _get_file_metadata_from_json(path, fetch_preview):
- """Read the metadata from the json file and the preview
- stored on the external device.
-
- If the metadata is corrupted we do remove it and the preview as well.
-
- """
-+ filename = os.path.basename(path)
-+ dir_path = os.path.dirname(path)
-+
-+ # In case of nested mount-points, (eg. ~/Documents/in1/in2/in3.txt),
-+ # "dir_path = ~/Documents/in1/in2"; while
-+ # "metadata_dir_path = ~/Documents".
-+ from jarabe.journal.journalactivity import get_mount_point
-+ metadata_dir_path = get_mount_point()
-+
- metadata = None
-- metadata_path = os.path.join(dir_path, JOURNAL_METADATA_DIR,
-+ metadata_path = os.path.join(metadata_dir_path, JOURNAL_METADATA_DIR,
- filename + '.metadata')
-- preview_path = os.path.join(dir_path, JOURNAL_METADATA_DIR,
-+ preview_path = os.path.join(metadata_dir_path, JOURNAL_METADATA_DIR,
- filename + '.preview')
-
- if not os.path.exists(metadata_path):
-@@ -670,7 +725,8 @@ def find(query_, page_size):
- Regex Matching is used, to ensure that the mount-point is an
- IP-Address.
- """
-- return RemoteShareResultSet(mount_points[0], query)
-+ ip_address = extract_ip_address_or_dns_name_from_locally_mounted_remote_share_path(mount_points[0])
-+ return RemoteShareResultSet(ip_address, query)
- else:
- """
- For Documents/Shares/Mounted-Drives.
-@@ -678,56 +734,13 @@ def find(query_, page_size):
- return InplaceResultSet(query, page_size, mount_points[0])
-
-
--def is_mount_point_for_locally_mounted_remote_share(mount_point):
-- import re
--
-- pattern = '[1-9][0-9]{0,2}\.[0-9]{0,3}\.[0-9]{0,3}\.[0-9]{0,3}'
-- if re.match(pattern, mount_point) is None:
-- return False
-- return True
--
--
--def _get_mount_point(path):
-- dir_path = os.path.dirname(path)
-- while dir_path:
-- if os.path.ismount(dir_path):
-- return dir_path
-- else:
-- dir_path = dir_path.rsplit(os.sep, 1)[0]
-- return None
--
--
--def is_locally_mounted_remote_share(path):
-- return string.find(path, '/tmp/') == 0
--
--
--def extract_ip_address_from_locally_mounted_remote_share_path(path):
-- """
-- Path is of type ::
--
-- /tmp/127.0.0.1/webdav/a.txt
-- """
-- return path.split('/')[2]
--
--
- def get(object_id):
- """Returns the metadata for an object
- """
- if (object_id[0] == '/'):
-- """
-- For Documents/Shares/Mounted-Drives/Locally-Mounted-Remote-Shares,
-- where ".Sugar-Metadata" folder exists.
--
-- The only thing is that, for locally-mounted-remote-shares, the
-- "file" is not physically present.
-- """
- if os.path.exists(object_id):
-- # if the file is physically present, derive filesize-metadata
-- # by physical examination of the file.
- stat = os.stat(object_id)
- else:
-- # if the file is remote, derive file-metadata by fetching
-- # properties remotely (webdav properties).
- stat = None
-
- metadata = _get_file_metadata(object_id, stat)
-@@ -812,7 +825,21 @@ def delete(object_id):
- def copy(metadata, mount_point):
- """Copies an object to another mount point
- """
-+ # In all cases (except one), "copy" means the actual duplication of
-+ # the content.
-+ # Only in case of remote downloading, the content is first copied
-+ # to "/tmp" folder. In those cases, copying would refer to a mere
-+ # renaming.
-+ transfer_ownership = False
-+
-+ from jarabe.journal.journalactivity import get_mount_point
-+ current_mount_point = get_mount_point()
-+
-+ if is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-+ transfer_ownership = True
-+
- metadata = get(metadata['uid'])
-+
- if mount_point == '/' and metadata['icon-color'] == '#000000,#ffffff':
- client = gconf.client_get_default()
- metadata['icon-color'] = client.get_string('/desktop/sugar/user/color')
-@@ -823,7 +850,7 @@ def copy(metadata, mount_point):
- metadata['mountpoint'] = mount_point
- del metadata['uid']
-
-- return write(metadata, file_path, transfer_ownership=False)
-+ return write(metadata, file_path, transfer_ownership=transfer_ownership)
-
-
- def write(metadata, file_path='', update_mtime=True, transfer_ownership=True):
-@@ -845,27 +872,105 @@ def write(metadata, file_path='', update_mtime=True, transfer_ownership=True):
- object_id = _get_datastore().create(dbus.Dictionary(metadata),
- file_path,
- transfer_ownership)
-- else:
-- # HACK: For documents: modify the mount-point
-- from jarabe.journal.journalactivity import get_mount_point
-- if get_mount_point() == get_documents_path():
-- metadata['mountpoint'] = get_documents_path()
-+ elif metadata.get('mountpoint', '/') == WEBDAV_MOUNT_POINT:
-+ filename = metadata['title']
-+
-+ ip_address_or_dns_name = SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME
-+ webdavmanager.get_remote_webdav_share_metadata(ip_address_or_dns_name)
-+
-+ data_webdav_manager = \
-+ webdavmanager.get_data_webdav_manager(ip_address_or_dns_name)
-+ metadata_webdav_manager = \
-+ webdavmanager.get_metadata_webdav_manager(ip_address_or_dns_name)
-+
-+
-+ # If we get a resource by this name, there is already an entry
-+ # on the server with this name; we do not want to do any
-+ # overwrites.
-+ data_resource = webdavmanager.get_resource_by_resource_key(data_webdav_manager,
-+ '/webdav/' + filename)
-+ metadata_resource = webdavmanager.get_resource_by_resource_key(metadata_webdav_manager,
-+ '/webdav/.Sugar-Metadata/' + filename + '.metadata')
-+ if (data_resource is not None) or (metadata_resource is not None):
-+ raise Exception(_('Entry already present on the server with '
-+ 'this name. Try again after renaming.'))
-+
-+ # No entry for this name present.
-+ # So, first write the metadata- and preview-file to temporary
-+ # locations.
-+ metadata_file_path, preview_file_path = \
-+ _write_metadata_and_preview_files_and_return_file_paths(metadata,
-+ filename)
-+
-+ # Finally,
-+ # Upload the data file.
-+ webdavmanager.add_resource_by_resource_key(data_webdav_manager,
-+ filename,
-+ file_path)
-+
-+ # Upload the preview file.
-+ if preview_file_path is not None:
-+ webdavmanager.add_resource_by_resource_key(metadata_webdav_manager,
-+ filename + '.preview',
-+ preview_file_path)
-+
-+ # Upload the metadata file.
-+ #
-+ # Note that this needs to be the last step. If there was any
-+ # error uploading the data- or the preview-file, control would
-+ # not reach here.
-+ #
-+ # In other words, the control reaches here only if the data-
-+ # and the preview- files have been uploaded. Finally, IF this
-+ # file is successfully uploaded, we have the guarantee that all
-+ # files for a particular journal entry are in place.
-+ webdavmanager.add_resource_by_resource_key(metadata_webdav_manager,
-+ filename + '.metadata',
-+ metadata_file_path)
-+
-+
-+ object_id = 'doesn\'t matter'
-
-- object_id = _write_entry_on_external_device(metadata, file_path)
-+ else:
-+ object_id = _write_entry_on_external_device(metadata,
-+ file_path,
-+ transfer_ownership)
-
- return object_id
-
-
--def _rename_entry_on_external_device(file_path, destination_path,
-- metadata_dir_path):
-+def make_file_fully_permissible(file_path):
-+ fd = os.open(file_path, os.O_RDONLY)
-+ os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG |stat.S_IRWXO)
-+ os.close(fd)
-+
-+
-+def _rename_entry_on_external_device(file_path, destination_path):
- """Rename an entry with the associated metadata on an external device."""
- old_file_path = file_path
- if old_file_path != destination_path:
-- os.rename(file_path, destination_path)
-+ # Strangely, "os.rename" works fine on sugar-jhbuild, but fails
-+ # on XOs, wih the OSError 13 ("invalid cross-device link"). So,
-+ # using the system call "mv".
-+ os.system('mv "%s" "%s"' % (file_path, destination_path))
-+ make_file_fully_permissible(destination_path)
-+
-+
-+ # In renaming, we want to delete the metadata-, and preview-
-+ # files of the current mount-point, and not the destination
-+ # mount-point.
-+ # But we also need to ensure that the directory of
-+ # 'old_file_path' and 'destination_path' are not same.
-+ if os.path.dirname(old_file_path) == os.path.dirname(destination_path):
-+ return
-+
-+ from jarabe.journal.journalactivity import get_mount_point
-+ source_metadata_dir_path = get_mount_point() + '/.Sugar-Metadata'
-+
- old_fname = os.path.basename(file_path)
-- old_files = [os.path.join(metadata_dir_path,
-+ old_files = [os.path.join(source_metadata_dir_path,
- old_fname + '.metadata'),
-- os.path.join(metadata_dir_path,
-+ os.path.join(source_metadata_dir_path,
- old_fname + '.preview')]
- for ofile in old_files:
- if os.path.exists(ofile):
-@@ -876,41 +981,32 @@ def _rename_entry_on_external_device(file_path, destination_path,
- 'for file=%s', ofile, old_fname)
-
-
--def _write_entry_on_external_device(metadata, file_path):
-- """Create and update an entry copied from the
-- DS to an external storage device.
--
-- Besides copying the associated file a file for the preview
-- and one for the metadata are stored in the hidden directory
-- .Sugar-Metadata.
--
-- This function handles renames of an entry on the
-- external device and avoids name collisions. Renames are
-- handled failsafe.
-+def _write_metadata_and_preview_files_and_return_file_paths(metadata,
-+ file_name):
-+ metadata_copy = metadata.copy()
-+ metadata_copy.pop('mountpoint', None)
-+ metadata_copy.pop('uid', None)
-
-- """
-- if 'uid' in metadata and os.path.exists(metadata['uid']):
-- file_path = metadata['uid']
-
-- if not file_path or not os.path.exists(file_path):
-- raise ValueError('Entries without a file cannot be copied to '
-- 'removable devices')
-+ # For copying to School-Server, we need to retain this property.
-+ # Else wise, I have no idea why this property is being removed !!
-+ if (metadata.get('mountpoint', '/') != WEBDAV_MOUNT_POINT) and \
-+ (metadata.get('mountpoint', '/') != LOCAL_SHARES_MOUNT_POINT):
-+ metadata_copy.pop('filesize', None)
-
-- if not metadata.get('title'):
-- metadata['title'] = _('Untitled')
-- file_name = get_file_name(metadata['title'], metadata['mime_type'])
--
-- destination_path = os.path.join(metadata['mountpoint'], file_name)
-- if destination_path != file_path:
-- file_name = get_unique_file_name(metadata['mountpoint'], file_name)
-- destination_path = os.path.join(metadata['mountpoint'], file_name)
-- clean_name, extension_ = os.path.splitext(file_name)
-- metadata['title'] = clean_name
-+ # For journal case, there is the special treatment.
-+ if metadata.get('mountpoint', '/') == '/':
-+ if metadata.get('uid', ''):
-+ object_id = _get_datastore().update(metadata['uid'],
-+ dbus.Dictionary(metadata),
-+ '',
-+ False)
-+ else:
-+ object_id = _get_datastore().create(dbus.Dictionary(metadata),
-+ '',
-+ False)
-+ return
-
-- metadata_copy = metadata.copy()
-- metadata_copy.pop('mountpoint', None)
-- metadata_copy.pop('uid', None)
-- metadata_copy.pop('filesize', None)
-
- metadata_dir_path = os.path.join(metadata['mountpoint'],
- JOURNAL_METADATA_DIR)
-@@ -939,25 +1035,64 @@ def _write_entry_on_external_device(metadata, file_path):
- os.close(fh)
- os.rename(fn, os.path.join(metadata_dir_path, preview_fname))
-
-- if not os.path.dirname(destination_path) == os.path.dirname(file_path):
-- shutil.copy(file_path, destination_path)
-+ metadata_destination_path = os.path.join(metadata_dir_path, file_name + '.metadata')
-+ make_file_fully_permissible(metadata_destination_path)
-+ if preview:
-+ preview_destination_path = os.path.join(metadata_dir_path, preview_fname)
-+ make_file_fully_permissible(preview_destination_path)
- else:
-- _rename_entry_on_external_device(file_path, destination_path,
-- metadata_dir_path)
-+ preview_destination_path = None
-
-- # For "Shares" folder, we need to set the permissions of the newly
-- # copied file to 0777, else it will not be accessible by "httpd"
-- # service.
-- if metadata['mountpoint'] == '/var/www/web1/web':
-- fd = os.open(destination_path, os.O_RDONLY)
-- os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
-- os.close(fd)
-+ return (metadata_destination_path, preview_destination_path)
-
-- metadata_file_path = os.path.join(metadata_dir_path, file_name + '.metadata')
-- fd = os.open(metadata_file_path, os.O_RDONLY)
-- os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
-- os.close(fd)
-
-+def update_only_metadata_and_preview_files_and_return_file_paths(metadata):
-+ file_name = get_file_name(metadata['title'], metadata['mime_type'])
-+ _write_metadata_and_preview_files_and_return_file_paths(metadata,
-+ file_name)
-+
-+
-+def _write_entry_on_external_device(metadata, file_path,
-+ transfer_ownership):
-+ """Create and update an entry copied from the
-+ DS to an external storage device.
-+
-+ Besides copying the associated file a file for the preview
-+ and one for the metadata are stored in the hidden directory
-+ .Sugar-Metadata.
-+
-+ This function handles renames of an entry on the
-+ external device and avoids name collisions. Renames are
-+ handled failsafe.
-+
-+ """
-+ if 'uid' in metadata and os.path.exists(metadata['uid']):
-+ file_path = metadata['uid']
-+
-+ if not file_path or not os.path.exists(file_path):
-+ raise ValueError('Entries without a file cannot be copied to '
-+ 'removable devices')
-+
-+ if not metadata.get('title'):
-+ metadata['title'] = _('Untitled')
-+ file_name = get_file_name(metadata['title'], metadata['mime_type'])
-+
-+ destination_path = os.path.join(metadata['mountpoint'], file_name)
-+ if destination_path != file_path:
-+ file_name = get_unique_file_name(metadata['mountpoint'], file_name)
-+ destination_path = os.path.join(metadata['mountpoint'], file_name)
-+ clean_name, extension_ = os.path.splitext(file_name)
-+ metadata['title'] = clean_name
-+
-+ _write_metadata_and_preview_files_and_return_file_paths(metadata,
-+ file_name)
-+
-+ if (os.path.dirname(destination_path) == os.path.dirname(file_path)) or \
-+ (transfer_ownership == True):
-+ _rename_entry_on_external_device(file_path, destination_path)
-+ else:
-+ shutil.copy(file_path, destination_path)
-+ make_file_fully_permissible(destination_path)
-
- object_id = destination_path
- created.send(None, object_id=object_id)
-@@ -1013,7 +1148,11 @@ def is_editable(metadata):
- # called, upon an entry in the context of a singular
- # mount-point.
- from jarabe.journal.journalactivity import get_mount_point
-- return os.access(get_mount_point(), os.W_OK)
-+ mount_point = get_mount_point()
-+
-+ if is_mount_point_for_locally_mounted_remote_share(mount_point):
-+ return False
-+ return os.access(mount_point, os.W_OK)
-
-
- def get_documents_path():
-diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py
-index 66dcadc..91e5460 100644
---- a/src/jarabe/journal/palettes.py
-+++ b/src/jarabe/journal/palettes.py
-@@ -30,6 +30,7 @@ import gio
- import glib
- import time
- import socket
-+import dbus
-
- from sugar import _sugarext
-
-@@ -44,14 +45,13 @@ from jarabe.model import friends
- from jarabe.model import filetransfer
- from jarabe.model import mimeregistry
- from jarabe.journal import misc
--from jarabe.journal import model
-+from jarabe.journal import model, webdavmanager
- from jarabe.journal.journalwindow import freeze_ui, \
- unfreeze_ui, \
- show_normal_cursor, \
- show_waiting_cursor
-
- from webdav.Connection import WebdavError
--from jarabe.journal.webdavmanager import get_resource_by_ip_address_and_resource_key
-
-
- friends_model = friends.get_model()
-@@ -59,6 +59,49 @@ friends_model = friends.get_model()
- _copy_menu_helper = None
- _current_action_item = None
-
-+
-+class PassphraseDialog(gtk.Dialog):
-+ def __init__(self, callback, metadata):
-+ gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
-+ self._callback = callback
-+ self._metadata = metadata
-+ self.set_title(_('Passphrase required'))
-+ self.set_has_separator(False)
-+
-+ # TRANS: Please do not translate the '%s'.
-+ label_text = _('Please enter the passphrase for %s' % metadata['title'])
-+ label = gtk.Label(label_text)
-+ self.vbox.pack_start(label)
-+
-+ self.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK)
-+ self.set_default_response(gtk.RESPONSE_OK)
-+ self.set_has_separator(True)
-+ self.add_key_entry()
-+
-+ self.connect('response', self._key_dialog_response_cb)
-+ self.show_all()
-+
-+ def add_key_entry(self):
-+ self._entry = gtk.Entry()
-+ self._entry.connect('activate', self._entry_activate_cb)
-+ self.vbox.pack_start(self._entry)
-+ self.vbox.set_spacing(6)
-+ self.vbox.show_all()
-+
-+ self._entry.grab_focus()
-+
-+ def _entry_activate_cb(self, entry):
-+ self.response(gtk.RESPONSE_OK)
-+
-+ def get_response_object(self):
-+ return self._response
-+
-+ def _key_dialog_response_cb(self, widget, response_id):
-+ self.hide()
-+ gobject.idle_add(self._callback, self._metadata,
-+ self._entry.get_text())
-+
-+
- class ObjectPalette(Palette):
-
- __gtype_name__ = 'ObjectPalette'
-@@ -528,6 +571,7 @@ class ActionItem(gobject.GObject):
- This is the stage, just after EVERY metadata has been
- processed.
- """
-+ self._hide_info_widget_for_single_mode()
-
- # Toggle the corresponding checkbox - but only for batch-mode.
- if self._batch_mode and self._auto_deselect_source_entries:
-@@ -573,6 +617,25 @@ class ActionItem(gobject.GObject):
- from jarabe.journal.journalactivity import get_journal
- get_journal().get_list_view().refresh()
-
-+ def _handle_single_mode_notification(self, message, severity):
-+ from jarabe.journal.journalactivity import get_journal
-+ journal = get_journal()
-+
-+ journal._show_alert(message, severity)
-+ self._hide_info_widget_for_single_mode()
-+
-+ def _hide_info_widget_for_single_mode(self):
-+ if (not self._batch_mode):
-+ from jarabe.journal.journalactivity import get_journal
-+ journal = get_journal()
-+
-+ journal.get_toolbar_box().hide_info_widget()
-+
-+ def _unhide_info_widget_for_single_mode(self):
-+ if not self._batch_mode:
-+ from jarabe.journal.journalactivity import get_journal
-+ get_journal().update_progress(0)
-+
- def _handle_error_alert(self, error_message, metadata):
- """
- This handles any error scenarios. Examples are of entries that
-@@ -593,19 +656,11 @@ class ActionItem(gobject.GObject):
-
- current_len = len(self._metadata_list)
-
-- # TRANS: Do not translate the two %d, and the three %s.
-- info_alert_message = _('( %d / %d ) Error while %s %s : %s') % (
-- self._metadata_list_initial_len - current_len,
-- self._metadata_list_initial_len,
-- self._get_info_alert_title(),
-- metadata['title'],
-- error_message)
--
- # Only show the alert, if allowed to.
- if self._show_not_completed_ops_info:
- from jarabe.journal.journalactivity import get_journal
-- get_journal().update_confirmation_alert(self._get_info_alert_title() + ' ...',
-- info_alert_message,
-+ get_journal().update_confirmation_alert(_('Error'),
-+ error_message,
- self._process_error_skipping,
- metadata)
- else:
-@@ -639,19 +694,55 @@ class ActionItem(gobject.GObject):
- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
- file_path = metadata['uid']
- filename = os.path.basename(file_path)
-- ip_address = model.extract_ip_address_from_locally_mounted_remote_share_path(file_path)
-- resource = get_resource_by_ip_address_and_resource_key(ip_address, '/webdav/' + filename)
-- download_file_path = '/tmp/' + ip_address + '/' + filename
-+ ip_address_or_dns_name = \
-+ model.extract_ip_address_or_dns_name_from_locally_mounted_remote_share_path(file_path)
-+
-+ data_webdav_manager = \
-+ webdavmanager.get_data_webdav_manager(ip_address_or_dns_name)
-+ metadata_webdav_manager = \
-+ webdavmanager.get_metadata_webdav_manager(ip_address_or_dns_name)
-+
-+ # Download the preview file, if it exists.
-+ preview_resource = \
-+ webdavmanager.get_resource_by_resource_key(metadata_webdav_manager,
-+ '/webdav/.Sugar-Metadata/' + filename + '.preview')
-+ preview_path = os.path.dirname(file_path) + '/.Sugar-Metadata/'+ filename + '.preview'
-+
-+ if preview_resource is not None:
-+ try:
-+ preview_resource.downloadFile(preview_path,
-+ show_progress=False,
-+ filesize=0)
-+ except (WebdavError, socket.error), e:
-+ error_message = e
-+ logging.warn(error_message)
-+ if self._batch_mode:
-+ self._handle_error_alert(error_message, metadata)
-+ else:
-+ self._handle_single_mode_notification(error_message,
-+ _('Error'))
-+ return False
-+
-+ # If we manage to reach here, download the data file.
-+ data_resource = \
-+ webdavmanager.get_resource_by_resource_key(data_webdav_manager,
-+ '/webdav/'+ filename)
- try:
-- resource.downloadFile(download_file_path)
-+ data_resource.downloadFile(metadata['uid'],
-+ show_progress=True,
-+ filesize=int(metadata['filesize']))
- return True
- except (WebdavError, socket.error), e:
-+ # Delete the downloaded preview file, if it exists.
-+ if os.path.exists(preview_path):
-+ os.unlink(preview_path)
-+
- error_message = e
- logging.warn(error_message)
- if self._batch_mode:
- self._handle_error_alert(error_message, metadata)
- else:
-- self.emit('volume-error', error_message,
-+ self._handle_single_mode_notification(error_message,
- _('Error'))
- return False
-
-@@ -662,7 +753,7 @@ class ActionItem(gobject.GObject):
- if self._batch_mode:
- self._handle_error_alert(error_message, metadata)
- else:
-- self.emit('volume-error', error_message, _('Warning'))
-+ self._handle_single_mode_notification(error_message, _('Warning'))
- return False
- else:
- return True
-@@ -674,12 +765,12 @@ class ActionItem(gobject.GObject):
- model.copy(metadata, mount_point)
- return True
- except Exception, e:
-- logging.exception('Error while copying the entry. %s', e)
-+ logging.exception(e)
- error_message = _('Error while copying the entry. %s') % e
- if self._batch_mode:
- self._handle_error_alert(error_message, metadata)
- else:
-- self.emit('volume-error', error_message, _('Error'))
-+ self._handle_single_mode_notification(error_message, _('Error'))
- return False
- finally:
- self._set_bundle_installation_allowed(True)
-@@ -689,7 +780,7 @@ class ActionItem(gobject.GObject):
- self._set_bundle_installation_allowed(False)
-
- try:
-- model.write(metadata, update_mtime=False)
-+ model.update_only_metadata_and_preview_files_and_return_file_paths(metadata)
- return True
- except Exception, e:
- logging.exception('Error while writing the metadata. %s', e)
-@@ -698,7 +789,7 @@ class ActionItem(gobject.GObject):
- if self._batch_mode:
- self._handle_error_alert(error_message, metadata)
- else:
-- self.emit('volume-error', error_message, _('Error'))
-+ self._handle_single_mode_notification(error_message, _('Error'))
- return False
- finally:
- self._set_bundle_installation_allowed(True)
-@@ -751,6 +842,30 @@ class BaseCopyMenuItem(MenuItem, ActionItem):
- def _get_info_alert_title(self):
- return _('Copying')
-
-+ def _operate(self, metadata):
-+ from jarabe.journal.journalactivity import get_mount_point
-+ if(model.is_mount_point_for_locally_mounted_remote_share(get_mount_point())) \
-+ and (model.is_mount_point_for_school_server(get_mount_point()) == True):
-+ PassphraseDialog(self._proceed_after_receiving_passphrase, metadata)
-+ else:
-+ self._proceed_with_copy(metadata)
-+
-+ def _proceed_after_receiving_passphrase(self, metadata, passphrase):
-+ if metadata['passphrase'] != passphrase:
-+ error_message = _('Passphrase does not match.')
-+ if self._batch_mode:
-+ self._handle_error_alert(error_message, metadata)
-+ else:
-+ self._handle_single_mode_notification(error_message, _('Error'))
-+ return False
-+ else:
-+ self._unhide_info_widget_for_single_mode()
-+ gobject.idle_add(self._proceed_with_copy, metadata)
-+
-+ def _proceed_with_copy(self, metadata):
-+ return NotImplementedError
-+
-+
-
- class VolumeMenu(BaseCopyMenuItem):
- def __init__(self, metadata_list, label, mount_point,
-@@ -761,9 +876,10 @@ class VolumeMenu(BaseCopyMenuItem):
- show_progress_info_alert, batch_mode)
- self._mount_point = mount_point
-
-- def _operate(self, metadata):
-+ def _proceed_with_copy(self, metadata):
- if not self._file_path_valid(metadata):
- return False
-+
- if not self._metadata_copy_valid(metadata, self._mount_point):
- return False
-
-@@ -780,7 +896,7 @@ class ClipboardMenu(BaseCopyMenuItem):
- batch_mode)
- self._temp_file_path_list = []
-
-- def _operate(self, metadata):
-+ def _proceed_with_copy(self, metadata):
- if not self._file_path_valid(metadata):
- return False
-
-@@ -813,9 +929,10 @@ class DocumentsMenu(BaseCopyMenuItem):
- show_progress_info_alert,
- batch_mode)
-
-- def _operate(self, metadata):
-+ def _proceed_with_copy(self, metadata):
- if not self._file_path_valid(metadata):
- return False
-+
- if not self._metadata_copy_valid(metadata,
- model.get_documents_path()):
- return False
-@@ -824,10 +941,41 @@ class DocumentsMenu(BaseCopyMenuItem):
- self._post_operate_per_metadata_per_action(metadata)
-
-
--class SharesMenu(BaseCopyMenuItem):
-+class LocalSharesMenu(BaseCopyMenuItem):
-+ def __init__(self, metadata_list, show_editing_alert,
-+ show_progress_info_alert, batch_mode):
-+ BaseCopyMenuItem.__init__(self, metadata_list, _('Local Shares'),
-+ show_editing_alert,
-+ show_progress_info_alert,
-+ batch_mode)
-+
-+ def _proceed_with_copy(self, metadata):
-+ if not self._file_path_valid(metadata):
-+ return False
-+
-+ # Attach the filesize.
-+ file_path = model.get_file(metadata['uid'])
-+ metadata['filesize'] = os.stat(file_path).st_size
-+
-+ # Attach the current mount-point.
-+ from jarabe.journal.journalactivity import get_mount_point
-+ metadata['mountpoint'] = get_mount_point()
-+
-+ if not self._metadata_write_valid(metadata):
-+ return False
-+
-+ if not self._metadata_copy_valid(metadata,
-+ model.LOCAL_SHARES_MOUNT_POINT):
-+ return False
-+
-+ # This is sync-operation. Call the post-operation now.
-+ self._post_operate_per_metadata_per_action(metadata)
-+
-+
-+class SchoolServerMenu(BaseCopyMenuItem):
- def __init__(self, metadata_list, show_editing_alert,
- show_progress_info_alert, batch_mode):
-- BaseCopyMenuItem.__init__(self, metadata_list, _('Shares'),
-+ BaseCopyMenuItem.__init__(self, metadata_list, _('School Server'),
- show_editing_alert,
- show_progress_info_alert,
- batch_mode)
-@@ -835,13 +983,75 @@ class SharesMenu(BaseCopyMenuItem):
- def _operate(self, metadata):
- if not self._file_path_valid(metadata):
- return False
-+
-+ # If the entry is copyable, proceed with asking the
-+ # upload-passphrase.
-+ PassphraseDialog(self._proceed_after_receiving_passphrase, metadata)
-+
-+ def _proceed_after_receiving_passphrase(self, metadata, passphrase):
-+ self._unhide_info_widget_for_single_mode()
-+ gobject.idle_add(self._proceed_with_uploading, metadata,
-+ passphrase)
-+
-+ def _proceed_with_uploading(self, metadata, passphrase):
-+ #
-+ # Attach the passphrase.
-+ metadata['passphrase'] = passphrase
-+
-+ # Attach the filesize.
-+ file_path = model.get_file(metadata['uid'])
-+ metadata['filesize'] = os.stat(file_path).st_size
-+
-+ # Attach the current mount-point.
-+ from jarabe.journal.journalactivity import get_mount_point, \
-+ get_journal
-+ metadata['mountpoint'] = get_mount_point()
-+
-+ # Attach the info of the uploader.
-+ from jarabe.model.buddy import get_owner_instance
-+ metadata['uploader-nick'] = get_owner_instance().props.nick
-+ metadata['uploader-serial'] = self.__get_serial_number()
-+
-+ if not self._metadata_write_valid(metadata):
-+ return False
-+
- if not self._metadata_copy_valid(metadata,
-- '/var/www/web1/web'):
-+ model.WEBDAV_MOUNT_POINT):
- return False
-
- # This is sync-operation. Call the post-operation now.
- self._post_operate_per_metadata_per_action(metadata)
-
-+ def __get_serial_number(self):
-+ _OFW_TREE = '/ofw'
-+ _PROC_TREE = '/proc/device-tree'
-+ _SN = 'serial-number'
-+ _not_available = _('Not available')
-+
-+ serial_no = None
-+ if os.path.exists(os.path.join(_OFW_TREE, _SN)):
-+ serial_no = self.__read_file(os.path.join(_OFW_TREE, _SN))
-+ elif os.path.exists(os.path.join(_PROC_TREE, _SN)):
-+ serial_no = self.__read_file(os.path.join(_PROC_TREE, _SN))
-+
-+ if serial_no is None:
-+ serial_no = _not_available
-+ return serial_no
-+
-+ def __read_file(self, path):
-+ if os.access(path, os.R_OK) == 0:
-+ return None
-+
-+ fd = open(path, 'r')
-+ value = fd.read()
-+ fd.close()
-+ if value:
-+ value = value.strip('\n')
-+ return value
-+ else:
-+ logging.debug('No information in file or directory: %s', path)
-+ return None
-+
-
- class FriendsMenu(gtk.Menu):
- __gtype_name__ = 'JournalFriendsMenu'
-@@ -970,12 +1180,23 @@ class CopyMenuHelper(gtk.Menu):
- menu.append(documents_menu)
- documents_menu.show()
-
-- if get_mount_point() != '/var/www/web1/web':
-- documents_menu = SharesMenu(metadata_list,
-+ if get_mount_point() != model.LOCAL_SHARES_MOUNT_POINT:
-+ local_shares_menu = LocalSharesMenu(metadata_list,
-+ show_editing_alert,
-+ show_progress_info_alert,
-+ batch_mode)
-+ local_shares_menu.set_image(Icon(icon_name='emblem-neighborhood-shared',
-+ icon_size=gtk.ICON_SIZE_MENU))
-+ local_shares_menu.connect('volume-error', self.__volume_error_cb)
-+ menu.append(local_shares_menu)
-+ local_shares_menu.show()
-+
-+ if not model.is_mount_point_for_locally_mounted_remote_share(get_mount_point()):
-+ documents_menu = SchoolServerMenu(metadata_list,
- show_editing_alert,
- show_progress_info_alert,
- batch_mode)
-- documents_menu.set_image(Icon(icon_name='emblem-neighborhood-shared',
-+ documents_menu.set_image(Icon(icon_name='school-server',
- icon_size=gtk.ICON_SIZE_MENU))
- documents_menu.connect('volume-error', self.__volume_error_cb)
- menu.append(documents_menu)
-diff --git a/src/jarabe/journal/volumestoolbar.py b/src/jarabe/journal/volumestoolbar.py
-index c24475d..b004657 100644
---- a/src/jarabe/journal/volumestoolbar.py
-+++ b/src/jarabe/journal/volumestoolbar.py
-@@ -37,7 +37,6 @@ from sugar.graphics.palette import Palette
- from sugar.graphics.xocolor import XoColor
- from sugar import env
-
--from jarabe.frame.notification import NotificationIcon
- from jarabe.journal import model
- from jarabe.view.palettes import JournalVolumePalette, JournalXSPalette, RemoteSharePalette
- import jarabe.frame
-@@ -45,6 +44,9 @@ import jarabe.frame
-
- _JOURNAL_0_METADATA_DIR = '.olpc.store'
-
-+SHARE_TYPE_PEER = 1
-+SHARE_TYPE_SCHOOL_SERVER = 2
-+
-
- def _get_id(document):
- """Get the ID for the document in the xapian database."""
-@@ -211,7 +213,13 @@ class VolumesToolbar(gtk.Toolbar):
-
- def _set_up_volumes(self):
- self._set_up_documents_button()
-- self._set_up_shares_button()
-+ self._set_up_local_shares_button()
-+
-+ client = gconf.client_get_default()
-+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
-+ self._add_remote_share_button(_('School-Server Shares'),
-+ model.SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME,
-+ color, SHARE_TYPE_SCHOOL_SERVER)
-
- volume_monitor = gio.volume_monitor_get()
- self._mount_added_hid = volume_monitor.connect('mount-added',
-@@ -242,18 +250,28 @@ class VolumesToolbar(gtk.Toolbar):
- 'user-documents',
- _('Documents'))
-
-- def _set_up_shares_button(self):
-- shares_dir_path = '/var/www/web1/web'
-- self._set_up_directory_button(shares_dir_path,
-+ def _set_up_local_shares_button(self):
-+ local_shares_path = model.LOCAL_SHARES_MOUNT_POINT
-+ self._set_up_directory_button(local_shares_path,
- 'emblem-neighborhood-shared',
-- _('Shares'))
--
-- def _add_remote_share_button(self, buddy):
-- button = RemoteSharesButton(buddy)
-+ _('Local Shares'))
-+
-+ def _add_remote_share_button(self, primary_text,
-+ ip_address_or_dns_name, color,
-+ share_type):
-+ button = RemoteSharesButton(primary_text, ip_address_or_dns_name,
-+ color, share_type)
-+ button._share_type = share_type
- button.props.group = self._volume_buttons[0]
-- label = glib.markup_escape_text(_('%s\'s share') % \
-- buddy.props.nick)
-- button.set_palette(RemoteSharePalette(buddy, button))
-+
-+ show_unmount_option = None
-+ if share_type == SHARE_TYPE_PEER:
-+ show_unmount_option = True
-+ else:
-+ show_unmount_option = False
-+ button.set_palette(RemoteSharePalette(primary_text,
-+ ip_address_or_dns_name, button,
-+ show_unmount_option))
- button.connect('toggled', self._button_toggled_cb)
- button.show()
-
-@@ -262,12 +280,7 @@ class VolumesToolbar(gtk.Toolbar):
- self._volume_buttons.append(button)
- self.show()
-
-- frame = jarabe.frame.get_view()
-- notif_icon = NotificationIcon()
-- notif_icon.props.icon_name = 'emblem-neighborhood-shared'
-- notif_icon.props.xo_color = buddy.props.color
-- frame.add_notification(notif_icon,
-- gtk.CORNER_BOTTOM_RIGHT)
-+ return button
-
- def __mount_added_cb(self, volume_monitor, mount):
- self._add_button(mount)
-@@ -302,13 +315,13 @@ class VolumesToolbar(gtk.Toolbar):
-
- def _button_toggled_cb(self, button, force_toggle=False):
- if button.props.active or force_toggle:
-+ button.set_active(True)
- from jarabe.journal.journalactivity import get_journal
- journal = get_journal()
-
- journal.get_list_view()._selected_entries = 0
- journal.switch_to_editing_mode(False)
- journal.get_list_view().inhibit_refresh(False)
-- journal.get_list_view().refresh()
-
- self.emit('volume-changed', button.mount_point)
-
-@@ -328,6 +341,14 @@ class VolumesToolbar(gtk.Toolbar):
- logging.error('Couldnt find button with mount_point %r', mount_point)
- return None
-
-+ def _get_button_for_mount_point(self, mount_point):
-+ for button in self.get_children():
-+ if button.mount_point == mount_point:
-+ return button
-+ logging.error('Couldnt find button with mount_point %r', mount_point)
-+ return None
-+
-+
- def _remove_button(self, mount):
- button = self._get_button_for_mount(mount)
- self._volume_buttons.remove(button)
-@@ -337,16 +358,20 @@ class VolumesToolbar(gtk.Toolbar):
- if len(self.get_children()) < 2:
- self.hide()
-
-- def _remove_remote_share_button(self, mount_point):
-- # Here, IP_Address is the mount_point.
-+ def _remove_remote_share_button(self, ip_address_or_dns_name):
- for button in self.get_children():
- if type(button) == RemoteSharesButton and \
-- button.mount_point == mount_point:
-+ button.mount_point == (model.WEBDAV_MOUNT_POINT + ip_address_or_dns_name):
- self._volume_buttons.remove(button)
- self.remove(button)
-+
-+ from jarabe.journal.webdavmanager import \
-+ unmount_share_from_backend
-+ unmount_share_from_backend(ip_address_or_dns_name)
-+
- self.get_children()[0].props.active = True
-
-- if len(sel.get_children()) < 2:
-+ if len(self.get_children()) < 2:
- self.hide()
- break;
-
-@@ -478,6 +503,7 @@ class DirectoryButton(BaseButton):
-
- def __init__(self, dir_path, icon_name):
- BaseButton.__init__(self, mount_point=dir_path)
-+ self._mount = dir_path
-
- self.props.named_icon = icon_name
-
-@@ -488,16 +514,22 @@ class DirectoryButton(BaseButton):
-
- class RemoteSharesButton(BaseButton):
-
-- def __init__(self, buddy):
-- BaseButton.__init__(self, mount_point=buddy.props.ip_address)
-+ def __init__(self, primary_text, ip_address_or_dns_name, color,
-+ share_type):
-+ BaseButton.__init__(self, mount_point=(model.WEBDAV_MOUNT_POINT + ip_address_or_dns_name))
-+
-+ self._primary_text = primary_text
-+ self._ip_address_or_dns_name = ip_address_or_dns_name
-
-- self._buddy = buddy
-- self.props.named_icon = 'emblem-neighborhood-shared'
-- self.props.xo_color = buddy.props.color
-- self._buddy_ip_address = buddy.props.ip_address
-+ if share_type == SHARE_TYPE_PEER:
-+ self.props.named_icon = 'emblem-neighborhood-shared'
-+ elif share_type == SHARE_TYPE_SCHOOL_SERVER:
-+ self.props.named_icon = 'school-server'
-+ self.props.xo_color = color
-
- def create_palette(self):
-- palette = RemoteSharePalette(self._buddy)
-+ palette = RemoteSharePalette(self._primary_text, self._ip_address_or_dns_name,
-+ self, True)
- return palette
-
-
-diff --git a/src/jarabe/journal/webdavmanager.py b/src/jarabe/journal/webdavmanager.py
-index 6cd0713..3ff9990 100644
---- a/src/jarabe/journal/webdavmanager.py
-+++ b/src/jarabe/journal/webdavmanager.py
-@@ -1,5 +1,6 @@
- from gettext import gettext as _
-
-+import logging
- import os
- import sys
-
-@@ -13,11 +14,6 @@ from webdav.WebdavClient import CollectionStorer
- def get_key_from_resource(resource):
- return resource.path
-
--def ensure_correct_remote_webdav_hierarchy(remote_webdav_share_resources,
-- remote_webdav_share_collections):
-- pass
-- #assert len(remote_webdav_share_collections.keys()) == 1
--
- class WebDavUrlManager(gobject.GObject):
- """
- This class holds all data, relevant to a WebDavUrl.
-@@ -50,6 +46,9 @@ class WebDavUrlManager(gobject.GObject):
- def _get_number_of_collections(self):
- return len(self._remote_webdav_share_collections)
-
-+ def _get_root(self):
-+ return self._root
-+
- def _get_resources_dict(self):
- return self._remote_webdav_share_resources
-
-@@ -57,7 +56,13 @@ class WebDavUrlManager(gobject.GObject):
- return self._remote_webdav_share_collections
-
- def _get_resource_by_key(self, key):
-- return self._remote_webdav_share_resources[key]['resource']
-+ if key in self._remote_webdav_share_resources.keys():
-+ return self._remote_webdav_share_resources[key]['resource']
-+ return None
-+
-+ def _add_or_replace_resource_by_key(self, key, resource):
-+ self._remote_webdav_share_resources[key] = {}
-+ self._remote_webdav_share_resources[key]['resource'] = resource
-
- def _get_metadata_list(self):
- metadata_list = []
-@@ -69,11 +74,9 @@ class WebDavUrlManager(gobject.GObject):
- resource_container = self._remote_webdav_share_resources[resource_key]
- return resource_container['webdav-properties']
-
-- def _set_metadata_for_resource(self, key, metadata):
-- self._remote_webdav_share_resources[key]['metadata'] = metadata
--
- def _fetch_resources_and_collections(self):
- webdavConnection = CollectionStorer(self._WebDavUrl, validateResourceNames=False)
-+ self._root = webdavConnection
-
- authFailures = 0
- while authFailures < 2:
-@@ -111,8 +114,13 @@ class WebDavUrlManager(gobject.GObject):
- error_message = e
- get_journal()._volume_error_cb(None, error_message,_('Error'))
-
-- # Simply return, in case of connection-not-available.
-- return False
-+ # Re-raise this error.
-+ # Note that since this is not an
-+ # "AuthorizationError", this will not be caught
-+ # by the outer except-block. Instead, it will
-+ # navigate all the way back up, and will report
-+ # the error in the enclosing except block.
-+ raise e
-
- else:
- # If this indeed is an Authorization Error,
-@@ -138,25 +146,54 @@ class WebDavUrlManager(gobject.GObject):
-
- webdav_manager = {}
-
-+def get_data_webdav_manager(ip_address_or_dns_name):
-+ return webdav_manager[ip_address_or_dns_name]['data']
-+
-+
-+def get_metadata_webdav_manager(ip_address_or_dns_name):
-+ return webdav_manager[ip_address_or_dns_name]['metadata']
-
--def get_resource_by_ip_address_and_resource_key(ip_address, key):
-- global webdav_manager
-
-- if ip_address in webdav_manager.keys():
-- root_webdav = webdav_manager[ip_address]
-- resources_dict = root_webdav._get_resources_dict()
-+def get_resource_by_resource_key(root_webdav, key):
-+ resources_dict = root_webdav._get_resources_dict()
-+ if key in resources_dict.keys():
- resource_dict = resources_dict[key]
- resource = resource_dict['resource']
--
- return resource
-+ return None
-
-
--def get_remote_webdav_share_metadata(ip_address):
-- protocol = 'dav://'
-+def add_resource_by_resource_key(root_webdav, key,
-+ content_file_path):
-+ root = root_webdav._get_root()
-
-- root_webdav_url = '/webdav'
-+ resource = root.addResource(key)
-+
-+ # Procure the resource-lock.
-+ lockToken = resource.lock('olpc')
-+
-+ input_stream = open(content_file_path)
-
-- complete_root_url = protocol + ip_address + root_webdav_url
-+ # Now, upload the data; but it's necessary to enclose this in a
-+ # try-except-finally block here, since we need to close the
-+ # input-stream, whatever may happen.
-+ try:
-+ resource.uploadFile(input_stream, lockToken)
-+ root_webdav._add_or_replace_resource_by_key(key, resource)
-+ except Exception, e:
-+ logging.exception(e)
-+ resource.delete(lockToken)
-+ raise e
-+ else:
-+ resource.unlock(lockToken)
-+ finally:
-+ input_stream.close()
-+
-+
-+def get_remote_webdav_share_metadata(ip_address_or_dns_name):
-+ protocol = 'davs://'
-+ root_webdav_url = '/webdav'
-+ complete_root_url = protocol + ip_address_or_dns_name + root_webdav_url
-
- root_webdav = WebDavUrlManager(complete_root_url, 'test', 'olpc')
- if root_webdav._fetch_resources_and_collections() is False:
-@@ -165,7 +202,8 @@ def get_remote_webdav_share_metadata(ip_address):
-
- # Keep reference to the "WebDavUrlManager", keyed by IP-Address.
- global webdav_manager
-- webdav_manager[ip_address] = root_webdav
-+ webdav_manager[ip_address_or_dns_name] = {}
-+ webdav_manager[ip_address_or_dns_name]['data'] = root_webdav
-
-
- # Assert that the number of collections is only one at this url
-@@ -174,12 +212,14 @@ def get_remote_webdav_share_metadata(ip_address):
-
- root_sugar_metadata_url = root_webdav_url + '/.Sugar-Metadata'
-
-- complete_root_sugar_metadata_url = protocol + ip_address + root_sugar_metadata_url
-+ complete_root_sugar_metadata_url = protocol + ip_address_or_dns_name + root_sugar_metadata_url
- root_webdav_sugar_metadata = WebDavUrlManager(complete_root_sugar_metadata_url, 'test', 'olpc')
- if root_webdav_sugar_metadata._fetch_resources_and_collections() is False:
- # Return empty metadata list.
- return []
-
-+ webdav_manager[ip_address_or_dns_name]['metadata'] = root_webdav_sugar_metadata
-+
- # assert that the number of collections is zero at this url.
- assert root_webdav_sugar_metadata._get_number_of_collections() == 0
-
-@@ -189,68 +229,82 @@ def get_remote_webdav_share_metadata(ip_address):
- root_webdav_sugar_metadata_resources = root_webdav_sugar_metadata._get_resources_dict()
-
- # Prepare the metadata-download folder.
-- downloaded_data_root_dir = '/tmp/' + ip_address
-+ downloaded_data_root_dir = '/tmp/' + ip_address_or_dns_name
- downloaded_metadata_file_dir = downloaded_data_root_dir + '/.Sugar-Metadata'
- if os.path.isdir(downloaded_data_root_dir):
- shutil.rmtree(downloaded_data_root_dir)
- os.makedirs(downloaded_metadata_file_dir)
-
-- for root_webdav_resource_name in root_webdav_resources.keys():
-- """
-- root_webdav_resource_name is of the type ::
-+ metadata_list = []
-
-- /webdav/a.txt
-+ # Note that the presence of a resource in the metadata directory,
-+ # is the only assurance of the entry (and its constituents) being
-+ # present in entirety. Thus, always proceed taking the metadata as
-+ # the "key".
-+ for root_webdav_sugar_metadata_resource_name in root_webdav_sugar_metadata_resources.keys():
- """
-- split_tokens_array = root_webdav_resource_name.split('/')
-+ root_webdav_sugar_metadata_resource_name is of the type ::
-
-- # This will provide us with "a.txt"
-- basename = split_tokens_array[len(split_tokens_array) - 1]
-+ /webdav/.Sugar-Metadata/a.txt.metadata, OR
-+ /webdav/.Sugar-Metadata/a.txt.preview
-+ """
-
-- # This will provide us with "a.txt.metadata"
-- sugar_metadata_basename = basename + '.metadata'
-+ # If this is a "preview" resource, continue forward, as we only
-+ # want the metadata list. The "preview" resources are anyways
-+ # already present in the manager DS.
-+ if root_webdav_sugar_metadata_resource_name.endswith('.preview'):
-+ continue
-
-- # Thus will provide us with "/webdav/.Sugar-Metadata/a.txt.metadata"
-- sugar_metadata_url = root_sugar_metadata_url + '/' + sugar_metadata_basename
-+ split_tokens_array = root_webdav_sugar_metadata_resource_name.split('/')
-
-- # Ensure that "sugar_metadata_url" is present as one of the
-- # keys in "root_webdav_sugar_metadata_resources"
-- assert sugar_metadata_url in root_webdav_sugar_metadata_resources.keys()
-+ # This will provide us with "a.txt.metadata"
-+ sugar_metadata_basename = split_tokens_array[len(split_tokens_array) - 1]
-
-- # Now download the metadata file, read its contents, and store
-- # the metadata in memory.
-- # It is assumed that the metadata-file is small enough to be
-- # read in one call to "read".
-+ # This will provide us with "a.txt"
-+ basename = sugar_metadata_basename[0:sugar_metadata_basename.index('.metadata')]
-
- downloaded_metadata_file_path = downloaded_metadata_file_dir + '/' + sugar_metadata_basename
-- metadata_resource = root_webdav_sugar_metadata._get_resource_by_key(sugar_metadata_url)
-+ metadata_resource = \
-+ root_webdav_sugar_metadata._get_resource_by_key(root_webdav_sugar_metadata_resource_name)
- metadata_resource.downloadFile(downloaded_metadata_file_path)
-
-+
-+ # We need to download the preview-file as well at this stage,
-+ # so that it can be shown in the expanded entry.
-+ downloaded_preview_file_path = downloaded_metadata_file_dir + \
-+ '/' + basename + '.preview'
-+ root_webdav_sugar_preview_resource_name = \
-+ root_webdav_sugar_metadata_resource_name[0:root_webdav_sugar_metadata_resource_name.index('.metadata')] + \
-+ '.preview'
-+ preview_resource = \
-+ root_webdav_sugar_metadata._get_resource_by_key(root_webdav_sugar_preview_resource_name)
-+ if preview_resource is not None:
-+ preview_resource.downloadFile(downloaded_preview_file_path)
-+
-+
- file_pointer = open(downloaded_metadata_file_path)
- metadata = eval(file_pointer.read())
- file_pointer.close()
-
-- # Very critical.
-- # 1. CRITICAL ONE:
-- # Fill in the uid.
-- # Note that the file is not physically present.
-+ # Fill in the missing metadata properties.
-+ # Note that the file is not physically present.
- metadata['uid'] = downloaded_data_root_dir + '/' + basename
--
-- # 2. CRITICAL TWO:
-- # Fill in the properties, that can only be done by reading
-- # in the webdav-properties.
-- live_properties = root_webdav._get_live_properties(root_webdav_resource_name)
-- metadata['filesize'] = live_properties.getContentLength()
-- metadata['timestamp'] = live_properties.getLastModified()
-- metadata['creation_time'] = live_properties.getCreationDate()
-+ metadata['creation_time'] = metadata['timestamp']
-
- # Now, write this to the metadata-file, so that
- # webdav-properties get gelled into sugar-metadata.
--
- file_pointer = open(downloaded_metadata_file_path, 'w')
- file_pointer.write(simplejson.dumps(metadata))
- file_pointer.close()
-
-- root_webdav._set_metadata_for_resource(root_webdav_resource_name,
-- metadata)
-+ metadata_list.append(metadata)
-+
-+ return metadata_list
-+
-+
-+def is_remote_webdav_loaded(ip_address_or_dns_name):
-+ return ip_address_or_dns_name in webdav_manager.keys()
-+
-
-- return root_webdav._get_metadata_list()
-+def unmount_share_from_backend(ip_address_or_dns_name):
-+ del webdav_manager[ip_address_or_dns_name]
-diff --git a/src/jarabe/view/buddymenu.py b/src/jarabe/view/buddymenu.py
-index dfbcfa3..f6af1b5 100644
---- a/src/jarabe/view/buddymenu.py
-+++ b/src/jarabe/view/buddymenu.py
-@@ -27,6 +27,7 @@ from sugar.graphics.palette import Palette
- from sugar.graphics.menuitem import MenuItem
- from sugar.graphics.icon import Icon
-
-+from jarabe.frame.notification import NotificationIcon
- from jarabe.model import shell
- from jarabe.model import friends
- from jarabe.model.session import get_session_manager
-@@ -73,11 +74,17 @@ class BuddyMenu(Palette):
- self.menu.append(menu_item)
- menu_item.show()
-
-- access_buddy_remote_share_menu_item = MenuItem(_('Access Share'), 'list-add')
-- access_buddy_remote_share_menu_item.connect('activate',
-- self._access_share_cb)
-- self.menu.append(access_buddy_remote_share_menu_item)
-- access_buddy_remote_share_menu_item.show()
-+ remote_share_menu_item = None
-+ from jarabe.journal import webdavmanager
-+ if not webdavmanager.is_remote_webdav_loaded(self._buddy.props.ip_address):
-+ remote_share_menu_item = MenuItem(_('Access Share'), 'list-add')
-+ remote_share_menu_item.connect('activate', self._access_share_cb)
-+ else:
-+ remote_share_menu_item = MenuItem(_('Unmount Share'), 'list-remove')
-+ remote_share_menu_item.connect('activate', self.__unmount_cb)
-+
-+ self.menu.append(remote_share_menu_item)
-+ remote_share_menu_item.show()
-
- self._invite_menu = MenuItem('')
- self._invite_menu.connect('activate', self._invite_friend_cb)
-@@ -89,10 +96,36 @@ class BuddyMenu(Palette):
- activity = home_model.get_active_activity()
- self._update_invite_menu(activity)
-
-+ def __unmount_cb(self, menuitem):
-+ from jarabe.journal.journalactivity import get_journal
-+ singleton_volumes_toolbar = get_journal().get_volumes_toolbar()
-+ singleton_volumes_toolbar._remove_remote_share_button(self._buddy.props.ip_address)
-+
- def _access_share_cb(self, menuitem):
- from jarabe.journal.journalactivity import get_journal
- volumes_toolbar = get_journal().get_volumes_toolbar()
-- volumes_toolbar._add_remote_share_button(self._buddy)
-+
-+ # TRANS: Do not translate the """%s""".
-+ primary_text = _('%s\'s Shares') % self._buddy.props.nick
-+ button = volumes_toolbar._add_remote_share_button(primary_text,
-+ self._buddy.props.ip_address,
-+ self._buddy.props.color,
-+ jarabe.journal.volumestoolbar.SHARE_TYPE_PEER)
-+
-+ # Now, make three levels of transitions, from the
-+ # Neighborhood-view.
-+
-+ # 1. Switch to the home-view.
-+ from jarabe.model import shell
-+ from jarabe.model.shell import ShellModel
-+ shell.get_model().set_zoom_level(ShellModel.ZOOM_HOME)
-+
-+ # 2. Switch to the journal-activity-view.
-+ top_frame = jarabe.frame.get_view()
-+ top_frame.switch_to_journal_activity()
-+
-+ # 3. Switch to the newly mounted-view.
-+ volumes_toolbar._button_toggled_cb(button, force_toggle=True)
-
- def _add_my_items(self):
- item = MenuItem(_('Shutdown'), 'system-shutdown')
-diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
-index 3b26faf..f6bca48 100644
---- a/src/jarabe/view/palettes.py
-+++ b/src/jarabe/view/palettes.py
-@@ -339,33 +339,35 @@ class JournalXSPalette(Palette):
-
-
- class RemoteSharePalette(Palette):
-- def __init__(self, buddy, button):
-- Palette.__init__(self, label=('%s\'s share' % buddy.props.nick))
-- self._buddy = buddy
-+ def __init__(self, primary_text, ip_address_or_dns_name, button,
-+ show_unmount_option):
-+ Palette.__init__(self, label=primary_text)
- self._button = button
-+ self._ip_address_or_dns_name = ip_address_or_dns_name
-
-- self.props.secondary_text = glib.markup_escape_text(buddy.props.ip_address)
-+ self.props.secondary_text = \
-+ glib.markup_escape_text(self._ip_address_or_dns_name)
-
-- vbox = gtk.VBox()
-- self.set_content(vbox)
-- vbox.show()
-+ if show_unmount_option == True:
-+ vbox = gtk.VBox()
-+ self.set_content(vbox)
-+ vbox.show()
-
-- self.connect('popup', self.__popup_cb)
-+ self.connect('popup', self.__popup_cb)
-+ menu_item = MenuItem(pgettext('Share', 'Unmount'))
-+ icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
-+ menu_item.set_image(icon)
-+ icon.show()
-
-- menu_item = MenuItem(pgettext('Share', 'Unmount'))
--
-- icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
-- menu_item.set_image(icon)
-- icon.show()
--
-- menu_item.connect('activate', self.__unmount_activate_cb)
-- self.menu.append(menu_item)
-- menu_item.show()
-+ menu_item.connect('activate', self.__unmount_activate_cb)
-+ self.menu.append(menu_item)
-+ menu_item.show()
-
- def __unmount_activate_cb(self, menu_item):
- from jarabe.journal.journalactivity import get_journal
-+
- singleton_volumes_toolbar = get_journal().get_volumes_toolbar()
-- singleton_volumes_toolbar._remove_remote_share_button(self._buddy.props.ip_address)
-+ singleton_volumes_toolbar._remove_remote_share_button(self._ip_address_or_dns_name)
-
- def __popup_cb(self, palette):
- pass
-diff --git a/src/webdav/Connection.py b/src/webdav/Connection.py
-index 66f7833..33719f9 100644
---- a/src/webdav/Connection.py
-+++ b/src/webdav/Connection.py
-@@ -197,7 +197,9 @@ class Connection(DAV):
- path = _urlEncode(path)
- try:
- HTTPConnection.request(self, 'PUT', path, "", header)
-- self._blockCopySocket(srcfile, self, Connection.blockSize)
-+ filesize = os.path.getsize(srcfile.name)
-+ self._blockCopySocket(srcfile, self,
-+ Connection.blockSize,filesize)
- srcfile.close()
- response = self.getresponse()
- except (CannotSendRequest, socket.error, BadStatusLine, ResponseNotReady), exc:
-@@ -215,14 +217,15 @@ class Connection(DAV):
- finally:
- self._lock.release()
-
-- def _blockCopySocket(self, source, toSocket, blockSize):
-+ def _blockCopySocket(self, source, toSocket, blockSize, filesize):
- transferedBytes = 0
- block = source.read(blockSize)
-- #while source.readinto(block, blockSize):
- while len(block):
-- toSocket.send(block)
- self.logger.debug("Wrote %d bytes." % len(block))
- transferedBytes += len(block)
-+ toSocket.send(block)
-+ from jarabe.journal.journalactivity import get_journal
-+ get_journal().update_progress(transferedBytes/(filesize*1.0))
- block = source.read(blockSize)
- self.logger.info("Transfered %d bytes." % transferedBytes)
-
-diff --git a/src/webdav/WebdavClient.py b/src/webdav/WebdavClient.py
-index ab5cec3..8ce5c77 100644
---- a/src/webdav/WebdavClient.py
-+++ b/src/webdav/WebdavClient.py
-@@ -336,6 +336,9 @@ class ResourceStorer(object):
- else:
- header["Content-length"] = 0
-
-+ # We need to change the header["Content-length"] to a string.
-+ header["Content-length"] = str(header["Content-length"])
-+
- try:
- response = self.connection.put(self.path, content, extra_hdrs=header)
- finally:
-@@ -367,7 +370,8 @@ class ResourceStorer(object):
- # TODO: Other interface ? return self.connection.getfile()
- return response
-
-- def downloadFile(self, localFileName):
-+ def downloadFile(self, localFileName, show_progress=False,
-+ filesize=0):
- """
- Copy binary data from permanent storage to a local file.
-
-@@ -377,7 +381,8 @@ class ResourceStorer(object):
- remoteFile = self.downloadContent()
- try:
- socket.setdefaulttimeout(SOCKET_DEFAULT_TIMEOUT)
-- _blockCopyFile(remoteFile, localFile, Connection.blockSize)
-+ _blockCopyFile(remoteFile, localFile, Connection.blockSize,
-+ show_progress, filesize)
- except socket.error, e:
- raise e
- remoteFile.close()
-@@ -807,7 +812,7 @@ class LockToken(object):
- return self.value()
-
-
--def _blockCopyFile(source, dest, blockSize):
-+def _blockCopyFile(source, dest, blockSize, show_progress, filesize):
- """
- Copies a file in chunks of C{blockSize}.
-
-@@ -821,8 +826,11 @@ def _blockCopyFile(source, dest, blockSize):
- transferedBytes = 0
- block = source.read(blockSize)
- while len(block):
-- dest.write(block)
- transferedBytes += len(block);
-+ dest.write(block)
-+ if show_progress:
-+ from jarabe.journal.journalactivity import get_journal
-+ get_journal().update_progress(transferedBytes/(filesize * 1.0))
- block = source.read(blockSize)
-
- def _checkUrl(url):
-diff --git a/src/webdav/davlib.py b/src/webdav/davlib.py
-index f4dac91..a611e51 100644
---- a/src/webdav/davlib.py
-+++ b/src/webdav/davlib.py
-@@ -31,7 +31,7 @@ BLOCKSIZE = 16384
- class HTTPProtocolChooser(httplib.HTTPSConnection):
- def __init__(self, *args, **kw):
- self.protocol = kw.pop('protocol')
-- if self.protocol == "https":
-+ if self.__is_secure_protocol():
- self.default_port = 443
- else:
- self.default_port = 80
-@@ -39,11 +39,14 @@ class HTTPProtocolChooser(httplib.HTTPSConnection):
- apply(httplib.HTTPSConnection.__init__, (self,) + args, kw)
-
- def connect(self):
-- if self.protocol == "https":
-+ if self.__is_secure_protocol():
- httplib.HTTPSConnection.connect(self)
- else:
- httplib.HTTPConnection.connect(self)
-
-+ def __is_secure_protocol(self):
-+ return (self.protocol == 'https') or (self.protocol == 'davs')
-+
-
- class HTTPConnectionAuth(HTTPProtocolChooser):
- def __init__(self, *args, **kw):
-@@ -333,4 +336,4 @@ class DAV(HTTPConnectionAuth):
- response = self.lock(url, owner, timeout, depth)
- response.parse_lock_response()
- return response.locktoken
--
-\ No newline at end of file
-+
---
-1.7.4.4
-
diff --git a/rpms/sugar/0130-Remove-1-to-N-feature-for-AU.patch b/rpms/sugar/0130-Remove-1-to-N-feature-for-AU.patch
deleted file mode 100644
index 39fb40f..0000000
--- a/rpms/sugar/0130-Remove-1-to-N-feature-for-AU.patch
+++ /dev/null
@@ -1,6700 +0,0 @@
-From 242544979105932b4e47e81d54b7032dc4ad650c Mon Sep 17 00:00:00 2001
-From: Ajay Garg <ajay@activitycentral.com>
-Date: Sat, 18 Aug 2012 23:13:22 +0530
-Subject: [PATCH] Remove 1-to-N feature for AU.
-Organization: Sugar Labs Foundation
-
-
-Signed-off-by: Ajay Garg <ajay@activitycentral.com>
----
- configure.ac | 2 -
- src/Makefile.am | 3 +-
- src/jarabe/journal/Makefile.am | 3 +-
- src/jarabe/journal/journaltoolbox.py | 7 -
- src/jarabe/journal/listview.py | 9 -
- src/jarabe/journal/model.py | 162 -------
- src/jarabe/journal/palettes.py | 71 ---
- src/jarabe/journal/volumestoolbar.py | 59 +---
- src/jarabe/journal/webdavmanager.py | 256 -----------
- src/jarabe/view/buddymenu.py | 11 -
- src/jarabe/view/palettes.py | 33 --
- src/webdav/Condition.py | 475 -------------------
- src/webdav/Connection.py | 321 -------------
- src/webdav/Constants.py | 199 --------
- src/webdav/Makefile.am | 20 -
- src/webdav/NameCheck.py | 193 --------
- src/webdav/Utils.py | 154 -------
- src/webdav/VersionHandler.py | 198 --------
- src/webdav/WebdavClient.py | 840 ----------------------------------
- src/webdav/WebdavRequests.py | 205 ---------
- src/webdav/WebdavResponse.py | 525 ---------------------
- src/webdav/__init__.py | 16 -
- src/webdav/acp/Ace.py | 293 ------------
- src/webdav/acp/AceHandler.py | 182 --------
- src/webdav/acp/Acl.py | 311 -------------
- src/webdav/acp/GrantDeny.py | 241 ----------
- src/webdav/acp/Makefile.am | 12 -
- src/webdav/acp/Principal.py | 189 --------
- src/webdav/acp/Privilege.py | 125 -----
- src/webdav/acp/__init__.py | 33 --
- src/webdav/davlib.py | 336 --------------
- src/webdav/logger.py | 51 --
- src/webdav/qp_xml.py | 240 ----------
- src/webdav/uuid_.py | 476 -------------------
- 34 files changed, 3 insertions(+), 6248 deletions(-)
- delete mode 100644 src/jarabe/journal/webdavmanager.py
- delete mode 100644 src/webdav/Condition.py
- delete mode 100644 src/webdav/Connection.py
- delete mode 100644 src/webdav/Constants.py
- delete mode 100644 src/webdav/Makefile.am
- delete mode 100644 src/webdav/NameCheck.py
- delete mode 100644 src/webdav/Utils.py
- delete mode 100644 src/webdav/VersionHandler.py
- delete mode 100644 src/webdav/WebdavClient.py
- delete mode 100644 src/webdav/WebdavRequests.py
- delete mode 100644 src/webdav/WebdavResponse.py
- delete mode 100644 src/webdav/__init__.py
- delete mode 100644 src/webdav/acp/Ace.py
- delete mode 100644 src/webdav/acp/AceHandler.py
- delete mode 100644 src/webdav/acp/Acl.py
- delete mode 100644 src/webdav/acp/GrantDeny.py
- delete mode 100644 src/webdav/acp/Makefile.am
- delete mode 100644 src/webdav/acp/Principal.py
- delete mode 100644 src/webdav/acp/Privilege.py
- delete mode 100644 src/webdav/acp/__init__.py
- delete mode 100644 src/webdav/davlib.py
- delete mode 100644 src/webdav/logger.py
- delete mode 100644 src/webdav/qp_xml.py
- delete mode 100644 src/webdav/uuid_.py
-
-diff --git a/configure.ac b/configure.ac
-index e04bdec..b7ef245 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -77,8 +77,6 @@ src/jarabe/model/Makefile
- src/jarabe/util/Makefile
- src/jarabe/util/telepathy/Makefile
- src/jarabe/view/Makefile
--src/webdav/acp/Makefile
--src/webdav/Makefile
- src/Makefile
- ])
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 765da8b..dcaaec6 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1,3 +1,2 @@
- SUBDIRS = \
-- jarabe \
-- webdav
-+ jarabe
-diff --git a/src/jarabe/journal/Makefile.am b/src/jarabe/journal/Makefile.am
-index 8efca6d..96d6ee8 100644
---- a/src/jarabe/journal/Makefile.am
-+++ b/src/jarabe/journal/Makefile.am
-@@ -16,5 +16,4 @@ sugar_PYTHON = \
- objectchooser.py \
- palettes.py \
- volumestoolbar.py \
-- processdialog.py \
-- webdavmanager.py
-+ processdialog.py
-diff --git a/src/jarabe/journal/journaltoolbox.py b/src/jarabe/journal/journaltoolbox.py
-index 6b2494e..18b523f 100644
---- a/src/jarabe/journal/journaltoolbox.py
-+++ b/src/jarabe/journal/journaltoolbox.py
-@@ -637,13 +637,6 @@ class BatchEraseButton(ToolButton, palettes.ActionItem):
- show_not_completed_ops_info=True)
- self.props.tooltip = _('Erase')
-
-- # De-sensitize Batch-Erase button, for locally-mounted-remote-shares.
-- from jarabe.journal.journalactivity import get_mount_point
-- current_mount_point = get_mount_point()
--
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- self.set_sensitive(False)
--
- def _get_actionable_signal(self):
- return 'clicked'
-
-diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py
-index 333d88a..7ff0709 100644
---- a/src/jarabe/journal/listview.py
-+++ b/src/jarabe/journal/listview.py
-@@ -728,15 +728,6 @@ class ListView(BaseListView):
- self.emit('volume-error', message, severity)
-
- def __icon_clicked_cb(self, cell, path):
-- # For locally-mounted remote shares, we do not want to launch
-- # by clicking on the icons.
-- # So, check if this is a part of locally-mounted-remote share,
-- # and if yes, return, without doing anything.
-- from jarabe.journal.journalactivity import get_mount_point
-- current_mount_point = get_mount_point()
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- return
--
- row = self.tree_view.get_model()[path]
- metadata = model.get(row[ListModel.COLUMN_UID])
- misc.resume(metadata)
-diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py
-index 422e947..7cd0a79 100644
---- a/src/jarabe/journal/model.py
-+++ b/src/jarabe/journal/model.py
-@@ -43,8 +43,6 @@ from sugar import dispatch
- from sugar import mime
- from sugar import util
-
--from jarabe.journal.webdavmanager import get_remote_webdav_share_metadata
--
- DS_DBUS_SERVICE = 'org.laptop.sugar.DataStore'
- DS_DBUS_INTERFACE = 'org.laptop.sugar.DataStore'
- DS_DBUS_PATH = '/org/laptop/sugar/DataStore'
-@@ -429,123 +427,6 @@ class InplaceResultSet(BaseResultSet):
- return
-
-
--class RemoteShareResultSet(object):
-- def __init__(self, ip_address, query):
-- self._ip_address = ip_address
-- self._file_list = []
--
-- self.ready = dispatch.Signal()
-- self.progress = dispatch.Signal()
--
-- # First time, query is none.
-- if query is None:
-- return
--
-- query_text = query.get('query', '')
-- if query_text.startswith('"') and query_text.endswith('"'):
-- self._regex = re.compile('*%s*' % query_text.strip(['"']))
-- elif query_text:
-- expression = ''
-- for word in query_text.split(' '):
-- expression += '(?=.*%s.*)' % word
-- self._regex = re.compile(expression, re.IGNORECASE)
-- else:
-- self._regex = None
--
-- if query.get('timestamp', ''):
-- self._date_start = int(query['timestamp']['start'])
-- self._date_end = int(query['timestamp']['end'])
-- else:
-- self._date_start = None
-- self._date_end = None
--
-- self._mime_types = query.get('mime_type', [])
--
-- self._sort = query.get('order_by', ['+timestamp'])[0]
--
-- def setup(self):
-- metadata_list_complete = get_remote_webdav_share_metadata(self._ip_address)
-- for metadata in metadata_list_complete:
--
-- add_to_list = False
-- if self._regex is not None:
-- for f in ['fulltext', 'title',
-- 'description', 'tags']:
-- if f in metadata and \
-- self._regex.match(metadata[f]):
-- add_to_list = True
-- break
-- else:
-- add_to_list = True
-- if not add_to_list:
-- continue
--
-- add_to_list = False
-- if self._date_start is not None:
-- if metadata['timestamp'] > self._date_start:
-- add_to_list = True
-- else:
-- add_to_list = True
-- if not add_to_list:
-- continue
--
-- add_to_list = False
-- if self._date_end is not None:
-- if metadata['timestamp'] < self._date_end:
-- add_to_list = True
-- else:
-- add_to_list = True
-- if not add_to_list:
-- continue
--
-- add_to_list = False
-- if self._mime_types:
-- mime_type = metadata['mime_type']
-- if mime_type in self._mime_types:
-- add_to_list = True
-- else:
-- add_to_list = True
-- if not add_to_list:
-- continue
--
-- # If control reaches here, the current metadata has passed
-- # out all filter-tests.
-- file_info = (metadata['timestamp'],
-- metadata['creation_time'],
-- metadata['filesize'],
-- metadata)
-- self._file_list.append(file_info)
--
-- if self._sort[1:] == 'filesize':
-- keygetter = itemgetter(2)
-- elif self._sort[1:] == 'creation_time':
-- keygetter = itemgetter(1)
-- else:
-- # timestamp
-- keygetter = itemgetter(0)
--
-- self._file_list.sort(lambda a, b: cmp(b, a),
-- key=keygetter,
-- reverse=(self._sort[0] == '-'))
--
-- self.ready.send(self)
--
-- def get_length(self):
-- return len(self._file_list)
--
-- length = property(get_length)
--
-- def seek(self, position):
-- self._position = position
--
-- def read(self):
-- modified_timestamp, creation_timestamp, filesize, metadata = self._file_list[self._position]
-- return metadata
--
-- def stop(self):
-- self._stopped = True
--
--
- def _get_file_metadata(path, stat, fetch_preview=True):
- """Return the metadata from the corresponding file.
-
-@@ -664,13 +545,6 @@ def find(query_, page_size):
- For Journal.
- """
- return DatastoreResultSet(query, page_size)
-- elif is_mount_point_for_locally_mounted_remote_share(mount_points[0]):
-- """
-- For Locally-Mounted-Remote-Shares.
-- Regex Matching is used, to ensure that the mount-point is an
-- IP-Address.
-- """
-- return RemoteShareResultSet(mount_points[0], query)
- else:
- """
- For Documents/Shares/Mounted-Drives.
-@@ -678,15 +552,6 @@ def find(query_, page_size):
- return InplaceResultSet(query, page_size, mount_points[0])
-
-
--def is_mount_point_for_locally_mounted_remote_share(mount_point):
-- import re
--
-- pattern = '[1-9][0-9]{0,2}\.[0-9]{0,3}\.[0-9]{0,3}\.[0-9]{0,3}'
-- if re.match(pattern, mount_point) is None:
-- return False
-- return True
--
--
- def _get_mount_point(path):
- dir_path = os.path.dirname(path)
- while dir_path:
-@@ -697,19 +562,6 @@ def _get_mount_point(path):
- return None
-
-
--def is_locally_mounted_remote_share(path):
-- return string.find(path, '/tmp/') == 0
--
--
--def extract_ip_address_from_locally_mounted_remote_share_path(path):
-- """
-- Path is of type ::
--
-- /tmp/127.0.0.1/webdav/a.txt
-- """
-- return path.split('/')[2]
--
--
- def get(object_id):
- """Returns the metadata for an object
- """
-@@ -945,20 +797,6 @@ def _write_entry_on_external_device(metadata, file_path):
- _rename_entry_on_external_device(file_path, destination_path,
- metadata_dir_path)
-
-- # For "Shares" folder, we need to set the permissions of the newly
-- # copied file to 0777, else it will not be accessible by "httpd"
-- # service.
-- if metadata['mountpoint'] == '/var/www/web1/web':
-- fd = os.open(destination_path, os.O_RDONLY)
-- os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
-- os.close(fd)
--
-- metadata_file_path = os.path.join(metadata_dir_path, file_name + '.metadata')
-- fd = os.open(metadata_file_path, os.O_RDONLY)
-- os.fchmod(fd, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
-- os.close(fd)
--
--
- object_id = destination_path
- created.send(None, object_id=object_id)
-
-diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py
-index 66dcadc..633d2ba 100644
---- a/src/jarabe/journal/palettes.py
-+++ b/src/jarabe/journal/palettes.py
-@@ -28,8 +28,6 @@ import gtk
- import gconf
- import gio
- import glib
--import time
--import socket
-
- from sugar import _sugarext
-
-@@ -50,10 +48,6 @@ from jarabe.journal.journalwindow import freeze_ui, \
- show_normal_cursor, \
- show_waiting_cursor
-
--from webdav.Connection import WebdavError
--from jarabe.journal.webdavmanager import get_resource_by_ip_address_and_resource_key
--
--
- friends_model = friends.get_model()
-
- _copy_menu_helper = None
-@@ -99,15 +93,10 @@ class ObjectPalette(Palette):
- resume_with_label = _('Start with')
- menu_item = MenuItem(resume_label, 'activity-start')
- menu_item.connect('activate', self.__start_activate_cb)
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- menu_item.set_sensitive(False)
- self.menu.append(menu_item)
- menu_item.show()
-
- menu_item = MenuItem(resume_with_label, 'activity-start')
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- menu_item.set_sensitive(False)
--
- self.menu.append(menu_item)
- menu_item.show()
- start_with_menu = StartWithMenu(self._metadata)
-@@ -146,14 +135,10 @@ class ObjectPalette(Palette):
- icon_size=gtk.ICON_SIZE_MENU)
- menu_item.set_image(icon)
- menu_item.connect('activate', self.__duplicate_activate_cb)
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- menu_item.set_sensitive(False)
- self.menu.append(menu_item)
- menu_item.show()
-
- menu_item = MenuItem(_('Send to'), 'document-send')
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- menu_item.set_sensitive(False)
- self.menu.append(menu_item)
- menu_item.show()
-
-@@ -164,15 +149,11 @@ class ObjectPalette(Palette):
- if detail == True:
- menu_item = MenuItem(_('View Details'), 'go-right')
- menu_item.connect('activate', self.__detail_activate_cb)
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- menu_item.set_sensitive(False)
- self.menu.append(menu_item)
- menu_item.show()
-
- menu_item = MenuItem(_('Erase'), 'list-remove')
- menu_item.connect('activate', self.__erase_activate_cb)
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- menu_item.set_sensitive(False)
- self.menu.append(menu_item)
- menu_item.show()
-
-@@ -633,28 +614,6 @@ class ActionItem(gobject.GObject):
- from jarabe.journal.journalactivity import get_mount_point
- current_mount_point = get_mount_point()
-
-- # Now, for locally mounted remote-shares, download the file.
-- # Note that, always download the file, to avoid the problems
-- # of stale-cache.
-- if model.is_mount_point_for_locally_mounted_remote_share(current_mount_point):
-- file_path = metadata['uid']
-- filename = os.path.basename(file_path)
-- ip_address = model.extract_ip_address_from_locally_mounted_remote_share_path(file_path)
-- resource = get_resource_by_ip_address_and_resource_key(ip_address, '/webdav/' + filename)
-- download_file_path = '/tmp/' + ip_address + '/' + filename
-- try:
-- resource.downloadFile(download_file_path)
-- return True
-- except (WebdavError, socket.error), e:
-- error_message = e
-- logging.warn(error_message)
-- if self._batch_mode:
-- self._handle_error_alert(error_message, metadata)
-- else:
-- self.emit('volume-error', error_message,
-- _('Error'))
-- return False
--
- file_path = model.get_file(metadata['uid'])
- if not file_path or not os.path.exists(file_path):
- logging.warn('Entries without a file cannot be copied.')
-@@ -824,25 +783,6 @@ class DocumentsMenu(BaseCopyMenuItem):
- self._post_operate_per_metadata_per_action(metadata)
-
-
--class SharesMenu(BaseCopyMenuItem):
-- def __init__(self, metadata_list, show_editing_alert,
-- show_progress_info_alert, batch_mode):
-- BaseCopyMenuItem.__init__(self, metadata_list, _('Shares'),
-- show_editing_alert,
-- show_progress_info_alert,
-- batch_mode)
--
-- def _operate(self, metadata):
-- if not self._file_path_valid(metadata):
-- return False
-- if not self._metadata_copy_valid(metadata,
-- '/var/www/web1/web'):
-- return False
--
-- # This is sync-operation. Call the post-operation now.
-- self._post_operate_per_metadata_per_action(metadata)
--
--
- class FriendsMenu(gtk.Menu):
- __gtype_name__ = 'JournalFriendsMenu'
-
-@@ -970,17 +910,6 @@ class CopyMenuHelper(gtk.Menu):
- menu.append(documents_menu)
- documents_menu.show()
-
-- if get_mount_point() != '/var/www/web1/web':
-- documents_menu = SharesMenu(metadata_list,
-- show_editing_alert,
-- show_progress_info_alert,
-- batch_mode)
-- documents_menu.set_image(Icon(icon_name='emblem-neighborhood-shared',
-- icon_size=gtk.ICON_SIZE_MENU))
-- documents_menu.connect('volume-error', self.__volume_error_cb)
-- menu.append(documents_menu)
-- documents_menu.show()
--
- if get_mount_point() != '/':
- client = gconf.client_get_default()
- color = XoColor(client.get_string('/desktop/sugar/user/color'))
-diff --git a/src/jarabe/journal/volumestoolbar.py b/src/jarabe/journal/volumestoolbar.py
-index c24475d..209fbfd 100644
---- a/src/jarabe/journal/volumestoolbar.py
-+++ b/src/jarabe/journal/volumestoolbar.py
-@@ -39,7 +39,7 @@ from sugar import env
-
- from jarabe.frame.notification import NotificationIcon
- from jarabe.journal import model
--from jarabe.view.palettes import JournalVolumePalette, JournalXSPalette, RemoteSharePalette
-+from jarabe.view.palettes import JournalVolumePalette, JournalXSPalette
- import jarabe.frame
-
-
-@@ -211,7 +211,6 @@ class VolumesToolbar(gtk.Toolbar):
-
- def _set_up_volumes(self):
- self._set_up_documents_button()
-- self._set_up_shares_button()
-
- volume_monitor = gio.volume_monitor_get()
- self._mount_added_hid = volume_monitor.connect('mount-added',
-@@ -242,33 +241,6 @@ class VolumesToolbar(gtk.Toolbar):
- 'user-documents',
- _('Documents'))
-
-- def _set_up_shares_button(self):
-- shares_dir_path = '/var/www/web1/web'
-- self._set_up_directory_button(shares_dir_path,
-- 'emblem-neighborhood-shared',
-- _('Shares'))
--
-- def _add_remote_share_button(self, buddy):
-- button = RemoteSharesButton(buddy)
-- button.props.group = self._volume_buttons[0]
-- label = glib.markup_escape_text(_('%s\'s share') % \
-- buddy.props.nick)
-- button.set_palette(RemoteSharePalette(buddy, button))
-- button.connect('toggled', self._button_toggled_cb)
-- button.show()
--
-- position = self.get_item_index(self._volume_buttons[-1]) + 1
-- self.insert(button, position)
-- self._volume_buttons.append(button)
-- self.show()
--
-- frame = jarabe.frame.get_view()
-- notif_icon = NotificationIcon()
-- notif_icon.props.icon_name = 'emblem-neighborhood-shared'
-- notif_icon.props.xo_color = buddy.props.color
-- frame.add_notification(notif_icon,
-- gtk.CORNER_BOTTOM_RIGHT)
--
- def __mount_added_cb(self, volume_monitor, mount):
- self._add_button(mount)
-
-@@ -337,19 +309,6 @@ class VolumesToolbar(gtk.Toolbar):
- if len(self.get_children()) < 2:
- self.hide()
-
-- def _remove_remote_share_button(self, mount_point):
-- # Here, IP_Address is the mount_point.
-- for button in self.get_children():
-- if type(button) == RemoteSharesButton and \
-- button.mount_point == mount_point:
-- self._volume_buttons.remove(button)
-- self.remove(button)
-- self.get_children()[0].props.active = True
--
-- if len(sel.get_children()) < 2:
-- self.hide()
-- break;
--
- def set_active_volume(self, mount):
- button = self._get_button_for_mount(mount)
- button.props.active = True
-@@ -486,22 +445,6 @@ class DirectoryButton(BaseButton):
- self.props.xo_color = color
-
-
--class RemoteSharesButton(BaseButton):
--
-- def __init__(self, buddy):
-- BaseButton.__init__(self, mount_point=buddy.props.ip_address)
--
-- self._buddy = buddy
-- self.props.named_icon = 'emblem-neighborhood-shared'
-- self.props.xo_color = buddy.props.color
-- self._buddy_ip_address = buddy.props.ip_address
--
-- def create_palette(self):
-- palette = RemoteSharePalette(self._buddy)
-- return palette
--
--
--
- class XSButton(ToolButton):
- def __init__(self):
- ToolButton.__init__(self)
-diff --git a/src/jarabe/journal/webdavmanager.py b/src/jarabe/journal/webdavmanager.py
-deleted file mode 100644
-index 6cd0713..0000000
---- a/src/jarabe/journal/webdavmanager.py
-+++ /dev/null
-@@ -1,256 +0,0 @@
--from gettext import gettext as _
--
--import os
--import sys
--
--import gobject
--import simplejson
--import shutil
--
--from webdav.Connection import AuthorizationError, WebdavError
--from webdav.WebdavClient import CollectionStorer
--
--def get_key_from_resource(resource):
-- return resource.path
--
--def ensure_correct_remote_webdav_hierarchy(remote_webdav_share_resources,
-- remote_webdav_share_collections):
-- pass
-- #assert len(remote_webdav_share_collections.keys()) == 1
--
--class WebDavUrlManager(gobject.GObject):
-- """
-- This class holds all data, relevant to a WebDavUrl.
--
-- One thing must be noted, that a valid WebDavUrl is the one which
-- may contain zero or more resources (files), or zero or more
-- collections (directories).
--
-- Thus, following are valid WebDavUrls ::
--
-- dav://1.2.3.4/webdav
-- dav://1.2.3.4/webdav/dir_1
-- dav://1.2.3.4/webdav/dir_1/dir_2
--
-- but following are not ::
--
-- dav://1.2.3.4/webdav/a.txt
-- dav://1.2.3.4/webdav/dir_1/b.jpg
-- dav://1.2.3.4/webdab/dir_1/dir_2/c.avi
-- """
--
-- def __init__(self, WebDavUrl, username, password):
-- self._WebDavUrl = WebDavUrl
-- self._username = username
-- self._password = password
--
-- def _get_key_from_resource(self, resource):
-- return resource.path.encode(sys.getfilesystemencoding())
--
-- def _get_number_of_collections(self):
-- return len(self._remote_webdav_share_collections)
--
-- def _get_resources_dict(self):
-- return self._remote_webdav_share_resources
--
-- def _get_collections_dict(self):
-- return self._remote_webdav_share_collections
--
-- def _get_resource_by_key(self, key):
-- return self._remote_webdav_share_resources[key]['resource']
--
-- def _get_metadata_list(self):
-- metadata_list = []
-- for key in self._remote_webdav_share_resources.keys():
-- metadata_list.append(self._remote_webdav_share_resources[key]['metadata'])
-- return metadata_list
--
-- def _get_live_properties(self, resource_key):
-- resource_container = self._remote_webdav_share_resources[resource_key]
-- return resource_container['webdav-properties']
--
-- def _set_metadata_for_resource(self, key, metadata):
-- self._remote_webdav_share_resources[key]['metadata'] = metadata
--
-- def _fetch_resources_and_collections(self):
-- webdavConnection = CollectionStorer(self._WebDavUrl, validateResourceNames=False)
--
-- authFailures = 0
-- while authFailures < 2:
-- try:
-- self._remote_webdav_share_resources = {}
-- self._remote_webdav_share_collections = {}
--
-- try:
-- self._collection_contents = webdavConnection.getCollectionContents()
-- for resource, properties in self._collection_contents:
-- try:
-- key = self._get_key_from_resource(resource)
-- selected_dict = None
--
-- if properties.getResourceType() == 'resource':
-- selected_dict = self._remote_webdav_share_resources
-- else:
-- selected_dict = self._remote_webdav_share_collections
--
-- selected_dict[key] = {}
-- selected_dict[key]['resource'] = resource
-- selected_dict[key]['webdav-properties'] = properties
-- except UnicodeEncodeError:
-- print("Cannot encode resource path or properties.")
--
-- return True
--
-- except WebdavError, e:
-- # Note that, we need to deal with all errors,
-- # except "AuthorizationError", as that is not
-- # really an error from our perspective.
-- if not type(e) == AuthorizationError:
-- from jarabe.journal.journalactivity import get_journal
--
-- error_message = e
-- get_journal()._volume_error_cb(None, error_message,_('Error'))
--
-- # Simply return, in case of connection-not-available.
-- return False
--
-- else:
-- # If this indeed is an Authorization Error,
-- # re-raise it, so that it is caught by the outer
-- # "except" block.
-- raise e
--
--
-- except AuthorizationError, e:
-- if self._username is None or self._password is None:
-- raise Exception("WebDav username or password is None. Please specify appropriate values.")
--
-- if e.authType == "Basic":
-- webdavConnection.connection.addBasicAuthorization(self._username, self._password)
-- elif e.authType == "Digest":
-- info = parseDigestAuthInfo(e.authInfo)
-- webdavConnection.connection.addDigestAuthorization(self._username, self._password, realm=info["realm"], qop=info["qop"], nonce=info["nonce"])
-- else:
-- raise
-- authFailures += 1
--
-- return False
--
--webdav_manager = {}
--
--
--def get_resource_by_ip_address_and_resource_key(ip_address, key):
-- global webdav_manager
--
-- if ip_address in webdav_manager.keys():
-- root_webdav = webdav_manager[ip_address]
-- resources_dict = root_webdav._get_resources_dict()
-- resource_dict = resources_dict[key]
-- resource = resource_dict['resource']
--
-- return resource
--
--
--def get_remote_webdav_share_metadata(ip_address):
-- protocol = 'dav://'
--
-- root_webdav_url = '/webdav'
--
-- complete_root_url = protocol + ip_address + root_webdav_url
--
-- root_webdav = WebDavUrlManager(complete_root_url, 'test', 'olpc')
-- if root_webdav._fetch_resources_and_collections() is False:
-- # Return empty metadata list.
-- return []
--
-- # Keep reference to the "WebDavUrlManager", keyed by IP-Address.
-- global webdav_manager
-- webdav_manager[ip_address] = root_webdav
--
--
-- # Assert that the number of collections is only one at this url
-- # (i.e. only ".Sugar-Metadata" is present).
-- assert root_webdav._get_number_of_collections() == 1
--
-- root_sugar_metadata_url = root_webdav_url + '/.Sugar-Metadata'
--
-- complete_root_sugar_metadata_url = protocol + ip_address + root_sugar_metadata_url
-- root_webdav_sugar_metadata = WebDavUrlManager(complete_root_sugar_metadata_url, 'test', 'olpc')
-- if root_webdav_sugar_metadata._fetch_resources_and_collections() is False:
-- # Return empty metadata list.
-- return []
--
-- # assert that the number of collections is zero at this url.
-- assert root_webdav_sugar_metadata._get_number_of_collections() == 0
--
-- # Now. associate sugar-metadata with each of the "root-webdav"
-- # resource.
-- root_webdav_resources = root_webdav._get_resources_dict()
-- root_webdav_sugar_metadata_resources = root_webdav_sugar_metadata._get_resources_dict()
--
-- # Prepare the metadata-download folder.
-- downloaded_data_root_dir = '/tmp/' + ip_address
-- downloaded_metadata_file_dir = downloaded_data_root_dir + '/.Sugar-Metadata'
-- if os.path.isdir(downloaded_data_root_dir):
-- shutil.rmtree(downloaded_data_root_dir)
-- os.makedirs(downloaded_metadata_file_dir)
--
-- for root_webdav_resource_name in root_webdav_resources.keys():
-- """
-- root_webdav_resource_name is of the type ::
--
-- /webdav/a.txt
-- """
-- split_tokens_array = root_webdav_resource_name.split('/')
--
-- # This will provide us with "a.txt"
-- basename = split_tokens_array[len(split_tokens_array) - 1]
--
-- # This will provide us with "a.txt.metadata"
-- sugar_metadata_basename = basename + '.metadata'
--
-- # Thus will provide us with "/webdav/.Sugar-Metadata/a.txt.metadata"
-- sugar_metadata_url = root_sugar_metadata_url + '/' + sugar_metadata_basename
--
-- # Ensure that "sugar_metadata_url" is present as one of the
-- # keys in "root_webdav_sugar_metadata_resources"
-- assert sugar_metadata_url in root_webdav_sugar_metadata_resources.keys()
--
-- # Now download the metadata file, read its contents, and store
-- # the metadata in memory.
-- # It is assumed that the metadata-file is small enough to be
-- # read in one call to "read".
--
-- downloaded_metadata_file_path = downloaded_metadata_file_dir + '/' + sugar_metadata_basename
-- metadata_resource = root_webdav_sugar_metadata._get_resource_by_key(sugar_metadata_url)
-- metadata_resource.downloadFile(downloaded_metadata_file_path)
--
-- file_pointer = open(downloaded_metadata_file_path)
-- metadata = eval(file_pointer.read())
-- file_pointer.close()
--
-- # Very critical.
-- # 1. CRITICAL ONE:
-- # Fill in the uid.
-- # Note that the file is not physically present.
-- metadata['uid'] = downloaded_data_root_dir + '/' + basename
--
-- # 2. CRITICAL TWO:
-- # Fill in the properties, that can only be done by reading
-- # in the webdav-properties.
-- live_properties = root_webdav._get_live_properties(root_webdav_resource_name)
-- metadata['filesize'] = live_properties.getContentLength()
-- metadata['timestamp'] = live_properties.getLastModified()
-- metadata['creation_time'] = live_properties.getCreationDate()
--
-- # Now, write this to the metadata-file, so that
-- # webdav-properties get gelled into sugar-metadata.
--
-- file_pointer = open(downloaded_metadata_file_path, 'w')
-- file_pointer.write(simplejson.dumps(metadata))
-- file_pointer.close()
--
-- root_webdav._set_metadata_for_resource(root_webdav_resource_name,
-- metadata)
--
-- return root_webdav._get_metadata_list()
-diff --git a/src/jarabe/view/buddymenu.py b/src/jarabe/view/buddymenu.py
-index dfbcfa3..de5a772 100644
---- a/src/jarabe/view/buddymenu.py
-+++ b/src/jarabe/view/buddymenu.py
-@@ -73,12 +73,6 @@ class BuddyMenu(Palette):
- self.menu.append(menu_item)
- menu_item.show()
-
-- access_buddy_remote_share_menu_item = MenuItem(_('Access Share'), 'list-add')
-- access_buddy_remote_share_menu_item.connect('activate',
-- self._access_share_cb)
-- self.menu.append(access_buddy_remote_share_menu_item)
-- access_buddy_remote_share_menu_item.show()
--
- self._invite_menu = MenuItem('')
- self._invite_menu.connect('activate', self._invite_friend_cb)
- self.menu.append(self._invite_menu)
-@@ -89,11 +83,6 @@ class BuddyMenu(Palette):
- activity = home_model.get_active_activity()
- self._update_invite_menu(activity)
-
-- def _access_share_cb(self, menuitem):
-- from jarabe.journal.journalactivity import get_journal
-- volumes_toolbar = get_journal().get_volumes_toolbar()
-- volumes_toolbar._add_remote_share_button(self._buddy)
--
- def _add_my_items(self):
- item = MenuItem(_('Shutdown'), 'system-shutdown')
- item.connect('activate', self.__shutdown_activate_cb)
-diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
-index 3b26faf..7a17f32 100644
---- a/src/jarabe/view/palettes.py
-+++ b/src/jarabe/view/palettes.py
-@@ -336,36 +336,3 @@ class JournalXSPalette(Palette):
- def __journal_restore_activate_cb(self, menu_item, xs_hostname):
- dialog = XSRestoreDialog(xs_hostname)
- dialog.show()
--
--
--class RemoteSharePalette(Palette):
-- def __init__(self, buddy, button):
-- Palette.__init__(self, label=('%s\'s share' % buddy.props.nick))
-- self._buddy = buddy
-- self._button = button
--
-- self.props.secondary_text = glib.markup_escape_text(buddy.props.ip_address)
--
-- vbox = gtk.VBox()
-- self.set_content(vbox)
-- vbox.show()
--
-- self.connect('popup', self.__popup_cb)
--
-- menu_item = MenuItem(pgettext('Share', 'Unmount'))
--
-- icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
-- menu_item.set_image(icon)
-- icon.show()
--
-- menu_item.connect('activate', self.__unmount_activate_cb)
-- self.menu.append(menu_item)
-- menu_item.show()
--
-- def __unmount_activate_cb(self, menu_item):
-- from jarabe.journal.journalactivity import get_journal
-- singleton_volumes_toolbar = get_journal().get_volumes_toolbar()
-- singleton_volumes_toolbar._remove_remote_share_button(self._buddy.props.ip_address)
--
-- def __popup_cb(self, palette):
-- pass
-diff --git a/src/webdav/Condition.py b/src/webdav/Condition.py
-deleted file mode 100644
-index 76acf94..0000000
---- a/src/webdav/Condition.py
-+++ /dev/null
-@@ -1,475 +0,0 @@
--# pylint: disable-msg=R0921,W0704,R0901,W0511,R0201
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--This module contains classes for creating a search condition according to the DASL draft.
--The classes will output the WHERE part of a search request to a WebDAV server.
--
--Instances of the classes defined in this module form a tree data structure which represents
--a search condition. This tree is made up of AND-nodes, OR-nodes, Operator- and comparison-
--nodes and from property (i.e. variable) and constant leaf nodes.
--"""
--
--
--import types
--from time import strftime
--from calendar import timegm
--from rfc822 import formatdate
--
--from webdav.Constants import NS_DAV, PROP_LAST_MODIFIED, DATE_FORMAT_ISO8601
--
--
--__version__ = "$Revision$"[11:-2]
--
--
--class ConditionTerm(object):
-- """
-- This is the abstact base class for all condition terms.
-- """
-- def __init__(self):
-- pass
--
-- def toXML(self):
-- """
-- Abstact method which return a XML string which can be passed to a WebDAV server
-- for a search condition.
-- """
-- raise NotImplementedError
--
-- # start Tamino workaround for missing like-op:
-- def postFilter(self, resultSet):
-- """
-- Abstact method for temporary workaround for Tamino's absense of the like-operator.
-- This method shall filter the given result set for those resources which match
-- all Contains-trems.
-- """
-- return resultSet
-- # end of workaround
--
--
--class IsCollectionTerm(ConditionTerm):
-- """ Leaf condition. Checks if the matching resources are collections. """
--
-- def __init__(self):
-- """ Constructor. """
--
-- ConditionTerm.__init__(self)
--
-- def toXML(self):
-- """
-- Returns XML encoding.
-- """
--
-- return "<D:is-collection/>"
--
--
--class Literal(ConditionTerm):
-- """
-- A leaf class for condition expressions representing a constant value.
-- """
-- def __init__(self, literal):
-- ConditionTerm.__init__(self)
-- self.literal = literal
--
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:literal>" + self.literal + "</D:literal>"
--
--
--class UnaryTerm(ConditionTerm):
-- """
-- Base class of all nodes with a single child node.
-- """
-- def __init__(self, child):
-- ConditionTerm.__init__(self)
-- self.child = child
--
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return self.child.toXML()
--
--
--class BinaryTerm(ConditionTerm):
-- """
-- Base class of all nodes with two child nodes
-- """
-- def __init__(self, left, right):
-- ConditionTerm.__init__(self)
-- self.left = left
-- self.right = right
--
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return self.left.toXML() + self.right.toXML()
--
--class TupleTerm(ConditionTerm):
-- """
-- Base class of all nodes with multiple single child nodes.
-- """
-- def __init__(self, terms):
-- ConditionTerm.__init__(self)
-- self.terms = terms
--
-- def addTerm(self, term):
-- '''
-- Removes a term.
--
-- @param term: term to add
-- '''
-- self.terms.append(term)
--
-- def removeTerm(self, term):
-- '''
-- Adds a term.
--
-- @param term: term to remove
-- '''
-- try:
-- self.terms.remove(term)
-- except ValueError:
-- pass
--
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- result = ""
-- for term in self.terms:
-- result += term.toXML()
-- return result
--
--
--class AndTerm(TupleTerm):
-- """
-- This class represents and logical AND-condition with multiple sub terms.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:and>" + TupleTerm.toXML(self) + "</D:and>"
--
-- # start Tamino workaround for missing like-op:
-- def postFilter(self, resultSet):
-- '''
-- Filters the given result set. This is a TAMINO WebDav server workaround
-- for the missing 'like' tag.
--
-- @param resultSet: the result set that needs to be filtered.
-- '''
-- for term in self.terms:
-- filtered = term.postFilter(resultSet)
-- resultSet = filtered
-- return resultSet
-- # end of workaround
--
--class OrTerm(TupleTerm):
-- """
-- This class represents and logical OR-condition with multiple sub terms.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:or>" + TupleTerm.toXML(self) + "</D:or>"
--
-- # start Tamino workaround for missing like-op:
-- def postFilter(self, resultSet):
-- '''
-- Filters the given result set. This is a TAMINO WebDav server workaround
-- for the missing 'like' tag.
--
-- @param resultSet: the result set that needs to be filtered.
-- '''
-- raise NotImplementedError
--
--
--class NotTerm(UnaryTerm):
-- """
-- This class represents a negation term for the contained sub term.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- # start Tamino workaround for missing like-op:
-- if isinstance(self.child, ContainsTerm):
-- return ""
-- # end of workaround
-- return "<D:not>" + UnaryTerm.toXML(self) + "</D:not>"
--
-- # start Tamino workaround for missing like-op:
-- def postFilter(self, resultSet):
-- '''
-- Filters the given result set. This is a TAMINO WebDav server workaround
-- for the missing 'like' tag.
--
-- @param resultSet: the result set that needs to be filtered.
-- '''
-- if isinstance(self.child, ContainsTerm):
-- self.child.negate = 1
-- # TODO: pass on filter
-- return self.child.postFilter(resultSet)
--
--
--class ExistsTerm(UnaryTerm):
-- """
-- Nodes of this class must have a single child with tuple type (of len 2) representing a
-- WebDAV property.
-- This leaf term evaluates to true if the (child) property exists.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return '<D:is-defined><D:prop xmlns="%s"><%s' % self.child + ' /></D:prop></D:is-defined>'
--
--class ContentContainsTerm(UnaryTerm):
-- """
-- This class can be used to search for a given phrase in resources' contents.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:contains>" + self.child + "</D:contains>"
--
--
--
--class BinaryRelationTerm(BinaryTerm):
-- """
-- This is the abstact base class for the following relation operands.
-- """
-- def __init__(self, left, right):
-- BinaryTerm.__init__(self, left, right)
-- if isinstance(self.left, types.StringType): # Must be namespace + name pair
-- self.left = ('DAV:', self.left)
-- if not isinstance(self.right, Literal):
-- self.right = Literal(self.right) # Must be Literal instance
--
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- ## TODO: extract name space and create shortcut for left element
-- return '<D:prop xmlns="%s"><%s /></D:prop>' % self.left + self.right.toXML()
--
--
--class StringRelationTerm(BinaryRelationTerm):
-- """
-- This is the abstact base class for the following string relation classes.
-- """
-- def __init__(self, left, right, caseless=None):
-- """
-- @param left: webdav property (namespace, name)
-- @param right: string/unicode literal
-- qparam caseless: 1 for case sensitive comparison
-- """
-- BinaryRelationTerm.__init__(self, left, Literal(right))
-- self.caseless = caseless
-- if self.caseless:
-- self.attrCaseless = "yes"
-- else:
-- self.attrCaseless = "no"
--
--class NumberRelationTerm(BinaryRelationTerm):
-- """
-- This is the abstact base class for the following number comparison classes.
-- """
-- def __init__(self, left, right):
-- """
-- @param left: webdav property (namespace, name)
-- @param right: constant number
-- """
-- ## TODO: implemet typed literal
-- BinaryRelationTerm.__init__(self, left, Literal(str(right)))
--
--class DateRelationTerm(BinaryRelationTerm):
-- """
-- This is the abstact base class for the following date comparison classes.
-- """
-- def __init__(self, left, right):
-- """
-- @param left: webdav property (namespace, name)
-- @param right: string literal containing a date in ISO8601 format
-- """
-- ## TODO: implemet typed literal
-- assert len(right) == 9, "No time is specified for literal: " + str(right)
-- BinaryRelationTerm.__init__(self, left, right)
-- if self.left == (NS_DAV, PROP_LAST_MODIFIED):
-- rfc822Time = formatdate(timegm(right)) # must not use locale setting
-- self.right = Literal(rfc822Time)
-- else:
-- self.right = Literal(strftime(DATE_FORMAT_ISO8601, right))
--
--
--class MatchesTerm(StringRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (child) property's value matches the (child) string.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return '<D:eq caseless="%s">' % self.attrCaseless + StringRelationTerm.toXML(self) + "</D:eq>"
--
--class ContainsTerm(StringRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) property's value contains the
-- (right child) string.
-- """
-- def __init__(self, left, right, isTaminoWorkaround=False):
-- right = unicode(right)
-- StringRelationTerm.__init__(self, left, "%" + right + "%")
-- # Tamino workaround: operator like is not yet implemented:
-- self.negate = 0
-- self.isTaminoWorkaround = isTaminoWorkaround
--
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- # Tamino workaround: operator like is not yet implemented:
-- # Produce a is-defined-condition instead
-- if self.isTaminoWorkaround:
-- return "<D:isdefined><D:prop xmlns='%s'><%s" % self.left + " /></D:prop></D:isdefined>"
-- else:
-- return '<D:like caseless="%s">' % self.attrCaseless + StringRelationTerm.toXML(self) + "</D:like>"
--
-- # start Tamino workaround for missing like-op:
-- def postFilter(self, resultSet):
-- '''
-- Filters the given result set. This is a TAMINO WebDav server workaround
-- for the missing 'like' tag.
--
-- @param resultSet: the result set that needs to be filtered.
-- '''
-- newResult = {}
-- word = self.right.literal[1:-1] # remove leading and trailing '%' characters (see __init__())
-- for url, properties in resultSet.items():
-- value = properties.get(self.left)
-- if self.negate:
-- if not value or value.textof().find(word) < 0:
-- newResult[url] = properties
-- else:
-- if value and value.textof().find(word) >= 0:
-- newResult[url] = properties
-- return newResult
-- # end of workaround
--
--class IsEqualTerm(NumberRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) numerical property's value is equal
-- to the (right child) number.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:eq>" + NumberRelationTerm.toXML(self) + "</D:eq>"
--
--class IsGreaterTerm(NumberRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) numerical property's value is greater
-- than the (right child) number.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:gt>" + NumberRelationTerm.toXML(self) + "</D:gt>"
--
--class IsGreaterOrEqualTerm(NumberRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) numerical property's value is greater
-- than or equal to the (right child) number.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:gte>" + NumberRelationTerm.toXML(self) + "</D:gte>"
--
--class IsSmallerTerm(NumberRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) numerical property's value is less
-- than the (right child) number.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:lt>" + NumberRelationTerm.toXML(self) + "</D:lt>"
--
--class IsSmallerOrEqualTerm(NumberRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) numerical property's value is less
-- than or equal to the (right child) number.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:lte>" + NumberRelationTerm.toXML(self) + "</D:lte>"
--
--
--class OnTerm(DateRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) property's value is a date
-- equal to the (right child) date.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:eq>" + DateRelationTerm.toXML(self) + "</D:eq>"
--
--class AfterTerm(DateRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) property's value is a date
-- succeeding the (right child) date.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:gt>" + DateRelationTerm.toXML(self) + "</D:gt>"
--
--class BeforeTerm(DateRelationTerm):
-- """
-- Nodes of this class evaluate to true if the (left child) property's value is a date
-- preceeding the (right child) date.
-- """
-- def toXML(self):
-- '''
-- Returns XML encoding.
-- '''
-- return "<D:lt>" + DateRelationTerm.toXML(self) + "</D:lt>"
--
--
--
--# Simple module test
--if __name__ == '__main__':
-- # use the example from the webdav specification
-- condition = AndTerm( (MatchesTerm('getcontenttype', 'image/gif'), \
-- IsGreaterTerm('getcontentlength', 4096)) )
-- print "Where: " + condition.toXML()
-diff --git a/src/webdav/Connection.py b/src/webdav/Connection.py
-deleted file mode 100644
-index 66f7833..0000000
---- a/src/webdav/Connection.py
-+++ /dev/null
-@@ -1,321 +0,0 @@
--# pylint: disable-msg=W0142,W0102,R0901,R0904,E0203,E1101,C0103
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--The contained class extends the HTTPConnection class for WebDAV support.
--"""
--
--
--from httplib import HTTPConnection, CannotSendRequest, BadStatusLine, ResponseNotReady
--from copy import copy
--import base64 # for basic authentication
--try:
-- import hashlib
--except ImportError: # for Python 2.4 compatibility
-- import md5
-- hashlib = md5
--import mimetypes
--import os # file handling
--import urllib
--import types
--import socket # to "catch" socket.error
--from threading import RLock
--try:
-- from uuid import uuid4
--except ImportError: # for Python 2.4 compatibility
-- from uuid_ import uuid4
--from xml.parsers.expat import ExpatError
--
--from davlib import DAV
--from qp_xml import Parser
--
--from webdav.WebdavResponse import MultiStatusResponse, ResponseFormatError
--from webdav import Constants
--from webdav.logger import getDefaultLogger
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class Connection(DAV):
-- """
-- This class handles a connection to a WebDAV server.
-- This class is used internally. Client code should prefer classes
-- L{WebdavClient.ResourceStorer} and L{WebdavClient.CollectionStorer}.
--
-- @author: Roland Betz
-- """
--
-- # Constants
-- # The following switch activates a workaround for the Tamino webdav server:
-- # Tamino expects URLs which are passed in a HTTP header to be Latin-1 encoded
-- # instead of Utf-8 encoded.
-- # Set this switch to zero in order to communicate with conformant servers.
-- blockSize = 30000
-- MaxRetries = 10
--
-- def __init__(self, *args, **kwArgs):
-- DAV.__init__(self, *args, **kwArgs)
-- self.__authorizationInfo = None
-- self.logger = getDefaultLogger()
-- self.isConnectedToCatacomb = True
-- self.serverTypeChecked = False
-- self._lock = RLock()
--
-- def _request(self, method, url, body=None, extra_hdrs={}):
--
-- self._lock.acquire()
-- try:
-- # add the authorization header
-- extraHeaders = copy(extra_hdrs)
-- if self.__authorizationInfo:
--
-- # update (digest) authorization data
-- if hasattr(self.__authorizationInfo, "update"):
-- self.__authorizationInfo.update(method=method, uri=url)
--
-- extraHeaders["AUTHORIZATION"] = self.__authorizationInfo.authorization
--
-- # encode message parts
-- body = _toUtf8(body)
-- url = _urlEncode(url)
-- for key, value in extraHeaders.items():
-- extraHeaders[key] = _toUtf8(value)
-- if key == "Destination": # copy/move header
-- if self.isConnectedToCatacomb:
-- extraHeaders[key] = _toUtf8(value.replace(Constants.SHARP, Constants.QUOTED_SHARP))
--
-- else: # in case of TAMINO 4.4
-- extraHeaders[key] = _urlEncode(value)
-- # pass message to httplib class
-- for retry in range(0, Connection.MaxRetries): # retry loop
-- try:
-- self.logger.debug("REQUEST Send %s for %s" % (method, url))
-- self.logger.debug("REQUEST Body: " + repr(body))
-- for hdr in extraHeaders.items():
-- self.logger.debug("REQUEST Header: " + repr(hdr))
-- self.request(method, url, body, extraHeaders)
-- response = self.getresponse()
-- break # no retry needed
-- except (CannotSendRequest, socket.error, BadStatusLine, ResponseNotReady), exc:
-- # Workaround, start: reconnect and retry...
-- self.logger.debug("Exception: " + str(exc) + " Retry ... ")
-- self.close()
-- try:
-- self.connect()
-- except (CannotSendRequest, socket.error, BadStatusLine, ResponseNotReady), exc:
-- raise WebdavError("Cannot perform request. Connection failed.")
-- if retry == Connection.MaxRetries - 1:
-- raise WebdavError("Cannot perform request.")
-- return self.__evaluateResponse(method, response)
-- finally:
-- self._lock.release()
--
-- def __evaluateResponse(self, method, response):
-- """ Evaluates the response of the WebDAV server. """
--
-- status, reason = response.status, response.reason
-- self.logger.debug("Method: " + method + " Status %d: " % status + reason)
--
-- if status >= Constants.CODE_LOWEST_ERROR: # error has occured ?
-- self.logger.debug("ERROR Response: " + response.read())
--
-- # identify authentication CODE_UNAUTHORIZED, throw appropriate exception
-- if status == Constants.CODE_UNAUTHORIZED:
-- raise AuthorizationError(reason, status, response.msg["www-authenticate"])
--
-- response.close()
-- raise WebdavError(reason, status)
--
-- if status == Constants.CODE_MULTISTATUS:
-- content = response.read()
-- ## check for UTF-8 encoding
-- try:
-- response.root = Parser().parse(content)
-- except ExpatError, error:
-- errorMessage = "Invalid XML document has been returned.\nReason: '%s'" % str(error.args)
-- raise WebdavError(errorMessage)
-- try:
-- response.msr = MultiStatusResponse(response.root)
-- except ResponseFormatError:
-- raise WebdavError("Invalid WebDAV response.")
-- response.close()
-- self.logger.debug("RESPONSE (Multi-Status): " + unicode(response.msr))
-- elif method == 'LOCK' and status == Constants.CODE_SUCCEEDED:
-- response.parse_lock_response()
-- response.close()
-- elif method != 'GET' and method != 'PUT':
-- self.logger.debug("RESPONSE Body: " + response.read())
-- response.close()
-- return response
--
-- def addBasicAuthorization(self, user, password, realm=None):
-- if user and len(user) > 0:
-- self.__authorizationInfo = _BasicAuthenticationInfo(realm=realm, user=user, password=password)
--
-- def addDigestAuthorization(self, user, password, realm, qop, nonce, uri = None, method = None):
-- if user and len(user) > 0:
-- # username, realm, password, uri, method, qop are required
-- self.__authorizationInfo = _DigestAuthenticationInfo(realm=realm, user=user, password=password, uri=uri, method=method, qop=qop, nonce=nonce)
--
-- def putFile(self, path, srcfile, header={}):
-- self._lock.acquire()
-- try:
-- # Assemble header
-- try:
-- size = os.path.getsize(srcfile.name)
-- except os.error, error:
-- raise WebdavError("Cannot determine file size.\nReason: ''" % str(error.args))
-- header["Content-length"] = str(size)
--
-- contentType, contentEnc = mimetypes.guess_type(path)
-- if contentType:
-- header['Content-Type'] = contentType
-- if contentEnc:
-- header['Content-Encoding'] = contentEnc
-- if self.__authorizationInfo:
-- # update (digest) authorization data
-- if hasattr(self.__authorizationInfo, "update"):
-- self.__authorizationInfo.update(method="PUT", uri=path)
-- header["AUTHORIZATION"] = self.__authorizationInfo.authorization
--
-- # send first request
-- path = _urlEncode(path)
-- try:
-- HTTPConnection.request(self, 'PUT', path, "", header)
-- self._blockCopySocket(srcfile, self, Connection.blockSize)
-- srcfile.close()
-- response = self.getresponse()
-- except (CannotSendRequest, socket.error, BadStatusLine, ResponseNotReady), exc:
-- self.logger.debug("Exception: " + str(exc) + " Retry ... ")
-- raise WebdavError("Cannot perform request.")
-- status, reason = (response.status, response.reason)
-- self.logger.debug("Status %d: %s" % (status, reason))
-- try:
-- if status >= Constants.CODE_LOWEST_ERROR: # error has occured ?
-- raise WebdavError(reason, status)
-- finally:
-- self.logger.debug("RESPONSE Body: " + response.read())
-- response.close()
-- return response
-- finally:
-- self._lock.release()
--
-- def _blockCopySocket(self, source, toSocket, blockSize):
-- transferedBytes = 0
-- block = source.read(blockSize)
-- #while source.readinto(block, blockSize):
-- while len(block):
-- toSocket.send(block)
-- self.logger.debug("Wrote %d bytes." % len(block))
-- transferedBytes += len(block)
-- block = source.read(blockSize)
-- self.logger.info("Transfered %d bytes." % transferedBytes)
--
-- def __str__(self):
-- return self.protocol + "://" + self.host + ':' + str(self.port)
--
--
--class _BasicAuthenticationInfo(object):
-- def __init__(self, **kwArgs):
-- self.__dict__.update(kwArgs)
-- self.cookie = base64.encodestring("%s:%s" % (self.user, self.password) ).strip()
-- self.authorization = "Basic " + self.cookie
-- self.password = None # protect password security
--
--class _DigestAuthenticationInfo(object):
--
-- __nc = "0000000" # in hexadecimal without leading 0x
--
-- def __init__(self, **kwArgs):
--
-- self.__dict__.update(kwArgs)
--
-- if self.qop is None:
-- raise WebdavError("Digest without qop is not implemented.")
-- if self.qop == "auth-int":
-- raise WebdavError("Digest with qop-int is not implemented.")
--
-- def update(self, **kwArgs):
-- """ Update input data between requests"""
--
-- self.__dict__.update(kwArgs)
--
-- def _makeDigest(self):
-- """ Creates the digest information. """
--
-- # increment nonce count
-- self._incrementNc()
--
-- # username, realm, password, uri, method, qop are required
--
-- a1 = "%s:%s:%s" % (self.user, self.realm, self.password)
-- ha1 = hashlib.md5(a1).hexdigest()
--
-- #qop == auth
-- a2 = "%s:%s" % (self.method, self.uri)
-- ha2 = hashlib.md5(a2).hexdigest()
--
-- cnonce = str(uuid4())
--
-- responseData = "%s:%s:%s:%s:%s:%s" % (ha1, self.nonce, _DigestAuthenticationInfo.__nc, cnonce, self.qop, ha2)
-- digestResponse = hashlib.md5(responseData).hexdigest()
--
-- authorization = "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", algorithm=MD5, response=\"%s\", qop=auth, nc=%s, cnonce=\"%s\"" \
-- % (self.user, self.realm, self.nonce, self.uri, digestResponse, _DigestAuthenticationInfo.__nc, cnonce)
-- return authorization
--
-- authorization = property(_makeDigest)
--
-- def _incrementNc(self):
-- _DigestAuthenticationInfo.__nc = self._dec2nc(self._nc2dec() + 1)
--
-- def _nc2dec(self):
-- return int(_DigestAuthenticationInfo.__nc, 16)
--
-- def _dec2nc(self, decimal):
-- return hex(decimal)[2:].zfill(8)
--
--
--class WebdavError(IOError):
-- def __init__(self, reason, code=0):
-- IOError.__init__(self, code)
-- self.code = code
-- self.reason = reason
-- def __str__(self):
-- return self.reason
--
--
--class AuthorizationError(WebdavError):
-- def __init__(self, reason, code, authHeader):
-- WebdavError.__init__(self, reason, code)
--
-- self.authType = authHeader.split(" ")[0]
-- self.authInfo = authHeader
--
--
--def _toUtf8(body):
-- if not body is None:
-- if type(body) == types.UnicodeType:
-- body = body.encode('utf-8')
-- return body
--
--
--def _urlEncode(url):
-- if type(url) == types.UnicodeType:
-- url = url.encode('utf-8')
-- return urllib.quote(url)
-diff --git a/src/webdav/Constants.py b/src/webdav/Constants.py
-deleted file mode 100644
-index 56dfd77..0000000
---- a/src/webdav/Constants.py
-+++ /dev/null
-@@ -1,199 +0,0 @@
--# pylint: disable-msg=C0103
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Contains XML tag names for the WebDAV protocol (RFC 2815)
--and further WebDAV related constants.
--"""
--
--
--__version__ = "$Revision$"[11:-2]
--
--
--QUOTED_SHARP = "%23"
--SHARP = "#"
--
--# Date formats
--DATE_FORMAT_ISO8601 = r"%Y-%m-%dT%H:%M:%SZ"
--DATE_FORMAT_HTTP = r"%a, %d %b %Y %H:%M:%S GMT" # not used, substituted by rfc822 function
--
--NS_DAV = 'DAV:'
--NS_TAMINO = 'http://namespaces.softwareag.com/tamino/response2'
--
--TAG_PROPERTY_FIND = 'propfind'
--TAG_PROPERTY_NAME = 'propname'
--TAG_PROPERTY_UPDATE = 'propertyupdate'
--TAG_PROPERTY_SET = 'set'
--TAG_PROPERTY_REMOVE = 'remove'
--TAG_ALL_PROPERTY = 'allprop'
--TAG_PROP = 'prop'
--
--TAG_MULTISTATUS = 'multistatus'
--TAG_RESPONSE = 'response'
--TAG_HREF = 'href'
--TAG_PROPERTY_STATUS = 'propstat'
--TAG_STATUS = 'status'
--TAG_RESPONSEDESCRIPTION = 'responsdescription'
--
--PROP_CREATION_DATE = 'creationdate'
--PROP_DISPLAY_NAME = 'displayname'
--PROP_CONTENT_LANGUAGE = 'getcontentlanguage'
--PROP_CONTENT_LENGTH = 'getcontentlength'
--PROP_CONTENT_TYPE = 'getcontenttype'
--PROP_ETAG = 'getetag'
--PROP_MODIFICATION_DATE = 'modificationdate' # this property is supported by
--# Tamino 4.4 but not by Catacomb; the date format is ISO8601
--PROP_LAST_MODIFIED = 'getlastmodified'
--PROP_LOCK_DISCOVERY = 'lockdiscovery'
--PROP_RESOURCE_TYPE = 'resourcetype'
--PROP_SOURCE = 'source'
--PROP_SUPPORTED_LOCK = 'supportedlock'
--PROP_OWNER = 'owner'
--
--PROP_RESOURCE_TYPE_RESOURCE = 'resource'
--PROP_RESOURCE_TYPE_COLLECTION = 'collection'
--
--TAG_LINK = 'link'
--TAG_LINK_SOURCE = 'src'
--TAG_LINK_DESTINATION = 'dst'
--
--TAG_LOCK_ENTRY = 'lockentry'
--TAG_LOCK_SCOPE = 'lockscope'
--TAG_LOCK_TYPE = 'locktype'
--TAG_LOCK_INFO = 'lockinfo'
--TAG_ACTIVE_LOCK = 'activelock'
--TAG_LOCK_DEPTH = 'depth'
--TAG_LOCK_TOKEN = 'locktoken'
--TAG_LOCK_TIMEOUT = 'timeout'
--TAG_LOCK_EXCLUSIVE = 'exclusive'
--TAG_LOCK_SHARED = 'shared'
--TAG_LOCK_OWNER = 'owner'
--
--# HTTP error code constants
--CODE_MULTISTATUS = 207
--CODE_SUCCEEDED = 200
--CODE_CREATED = 201
--CODE_NOCONTENT = 204
--
--CODE_LOWEST_ERROR = 300
--
--CODE_UNAUTHORIZED = 401
--CODE_FORBIDDEN = 403
--CODE_NOT_FOUND = 404
--CODE_CONFLICT = 409
--CODE_PRECONDITION_FAILED = 412
--CODE_LOCKED = 423 # no permission
--CODE_FAILED_DEPENDENCY = 424
--
--CODE_OUTOFMEM = 507
--
--# ?
--CONFIG_UNICODE_URL = 1
--
--# constants for WebDAV DASL according to draft
--
--TAG_SEARCH_REQUEST = 'searchrequest'
--TAG_SEARCH_BASIC = 'basicsearch'
--TAG_SEARCH_SELECT = 'select'
--TAG_SEARCH_FROM = 'from'
--TAG_SEARCH_SCOPE = 'scope'
--TAG_SEARCH_WHERE = 'where'
--
--# constants for WebDAV ACP (according to draft-ietf-webdav-acl-09) below ...
--
--TAG_ACL = 'acl'
--TAG_ACE = 'ace'
--TAG_GRANT = 'grant'
--TAG_DENY = 'deny'
--TAG_PRIVILEGE = 'privilege'
--TAG_PRINCIPAL = 'principal'
--TAG_ALL = 'all'
--TAG_AUTHENTICATED = 'authenticated'
--TAG_UNAUTHENTICATED = 'unauthenticated'
--TAG_OWNER = 'owner'
--TAG_PROPERTY = 'property'
--TAG_SELF = 'self'
--TAG_INHERITED = 'inherited'
--TAG_PROTECTED = 'protected'
--TAG_SUPPORTED_PRIVILEGE = 'supported-privilege'
--TAG_DESCRIPTION = 'description'
--
--# privileges for WebDAV ACP:
--TAG_READ = 'read'
--TAG_WRITE = 'write'
--TAG_WRITE_PROPERTIES = 'write-properties'
--TAG_WRITE_CONTENT = 'write-content'
--TAG_UNLOCK = 'unlock'
--TAG_READ_ACL = 'read-acl'
--TAG_READ_CURRENT_USER_PRIVILEGE_SET = 'read-current-user-privilege-set'
--TAG_WRITE_ACL = 'write-acl'
--TAG_ALL = 'all'
--TAG_BIND = 'bind'
--TAG_UNBIND = 'unbind'
--# Tamino-specific privileges
--TAG_TAMINO_SECURITY = 'security'
--# Limestone-specific privileges
--TAG_BIND_COLLECTION = 'bind-collection'
--TAG_UNBIND_COLLECTION = 'unbind-collection'
--TAG_READ_PRIVATE_PROPERTIES = 'read-private-properties'
--TAG_WRITE_PRIVATE_PROPERTIES = 'write-private-properties'
--
--# properties for WebDAV ACP:
--PROP_CURRENT_USER_PRIVILEGE_SET = 'current-user-privilege-set'
--PROP_SUPPORTED_PRIVILEGE_SET = 'supported-privilege-set'
--PROP_PRINCIPAL_COLLECTION_SET = 'principal-collection-set'
--
--# reports for WebDAV ACP
--REPORT_ACL_PRINCIPAL_PROP_SET = 'acl-principal-prop-set'
--
--
--
--# constants for WebDAV Delta-V
--
--# WebDAV Delta-V method names
--METHOD_REPORT = 'REPORT'
--METHOD_VERSION_CONTROL = 'VERSION-CONTROL'
--METHOD_UNCHECKOUT = 'UNCHECKOUT'
--METHOD_CHECKOUT = 'CHECKOUT'
--METHOD_CHECKIN = 'CHECKIN'
--METHOD_UPDATE = 'UPDATE'
--
--# Special properties
--PROP_SUCCESSOR_SET = (NS_DAV, 'successor-set')
--PROP_PREDECESSOR_SET = (NS_DAV, 'predecessor-set')
--PROP_VERSION_HISTORY = (NS_DAV, 'version-history')
--PROP_CREATOR = (NS_DAV, 'creator-displayname')
--PROP_VERSION_NAME = (NS_DAV, 'version-name')
--PROP_CHECKEDIN = (NS_DAV, 'checked-in')
--PROP_CHECKEDOUT = (NS_DAV, 'checked-out')
--PROP_COMMENT = (NS_DAV, 'comment')
--
--# XML tags for request body
--TAG_VERSION_TREE = 'version-tree'
--TAG_LOCATE_BY_HISTORY = 'locate-by-history'
--TAG_UPDATE = 'update'
--TAG_VERSION = 'version'
--
--# HTTP header constants
--HTTP_HEADER_DEPTH_INFINITY = 'infinity'
--HTTP_HEADER_IF = 'if'
--HTTP_HEADER_DAV = 'dav'
--HTTP_HEADER_DASL = 'dasl'
--HTTP_HEADER_OPTION_ACL = 'access-control'
--HTTP_HEADER_OPTION_DAV_BASIC_SEARCH = 'DAV:basicsearch'
--HTTP_HEADER_SERVER = 'server'
--HTTP_HEADER_SERVER_TAMINO = 'Apache/2.0.54 (Win32)'
-diff --git a/src/webdav/Makefile.am b/src/webdav/Makefile.am
-deleted file mode 100644
-index 3356daf..0000000
---- a/src/webdav/Makefile.am
-+++ /dev/null
-@@ -1,20 +0,0 @@
--SUBDIRS = acp
--
--sugardir = $(pythondir)/webdav
--sugar_PYTHON = \
-- Connection.py \
-- davlib.py \
-- logger.py \
-- NameCheck.py \
-- Utils.py \
-- VersionHandler.py \
-- WebdavRequests.py \
-- Condition.py \
-- Constants.py \
-- __init__.py \
-- qp_xml.py \
-- uuid_.py \
-- WebdavClient.py \
-- WebdavResponse.py
--
--
-diff --git a/src/webdav/NameCheck.py b/src/webdav/NameCheck.py
-deleted file mode 100644
-index 7976973..0000000
---- a/src/webdav/NameCheck.py
-+++ /dev/null
-@@ -1,193 +0,0 @@
--# pylint: disable-msg=R0904,W0142,W0511,W0104,C0321,E1103,W0212
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Check name of new collections/resources for "illegal" characters.
--"""
--
--
--import re
--import unicodedata
--
--
--__version__ = "$LastChangedRevision$"
--
--
--_unicodeUmlaut = [unicodedata.lookup("LATIN CAPITAL LETTER A WITH DIAERESIS"),
-- unicodedata.lookup("LATIN SMALL LETTER A WITH DIAERESIS"),
-- unicodedata.lookup("LATIN CAPITAL LETTER O WITH DIAERESIS"),
-- unicodedata.lookup("LATIN SMALL LETTER O WITH DIAERESIS"),
-- unicodedata.lookup("LATIN CAPITAL LETTER U WITH DIAERESIS"),
-- unicodedata.lookup("LATIN SMALL LETTER U WITH DIAERESIS"),
-- unicodedata.lookup("LATIN SMALL LETTER SHARP S")]
--
--# Define characters and character base sets
--_german = u"".join(_unicodeUmlaut)
--_alpha = "A-Za-z"
--_num = "0-9"
--_alphaNum = _alpha + _num
--_space = " "
--_under = "_"
--_dash = "\-"
--_dot = "\."
--_exclam = "\!"
--_tilde = "\~"
--_dollar = "\$"
--_plus = "+"
--_equal = "="
--_sharp = "#"
--
--# Define character groups
--_letterNum = _alphaNum + _german
--_letter = _alpha + _german
--
--# Define character sets for names
--firstPropertyChar = _letter + _under
--propertyChar = firstPropertyChar + _num + _dash + _dot
--firstResourceChar = firstPropertyChar + _num + _tilde + _exclam + _dollar + \
-- _dot + _dash + _plus + _equal + _sharp
--resourceChar = firstResourceChar + _space
--
--# Define regular expressions for name validation
--_propertyFirstRe = re.compile(u"^["+ firstPropertyChar +"]")
--
--_propertyRe = re.compile(u"[^"+ propertyChar +"]")
--_resourceFirstRe = re.compile(u"^["+ firstResourceChar +"]")
--_resourceRe = re.compile(u"[^"+ resourceChar +"]")
--
--
--def isValidPropertyName(name):
-- """
-- Check if the given property name is valid.
--
-- @param name: Property name.
-- @type name: C{unicode}
--
-- @return: Boolean indicating whether the given property name is valid or not.
-- @rtype: C{bool}
-- """
--
-- illegalChar = _propertyRe.search(name)
-- return illegalChar == None and _propertyFirstRe.match(name) != None
--
--
--def isValidResourceName(name):
-- """
-- Check if the given resource name is valid.
--
-- @param name: Resource name.
-- @type name: C{unicode}
--
-- @return: Boolean indicating whether the given resource name is valid or not.
-- @rtype: C{bool}
-- """
--
-- illegalChar = _resourceRe.search(name)
-- return illegalChar == None and _resourceFirstRe.match(name) != None
--
--
--def validatePropertyName(name):
-- """
-- Check if the given property name is valid.
--
-- @param name: Property name.
-- @type name: C{unicode}
-- @raise WrongNameError: if validation fails (see L{datafinder.common.NameCheck.WrongNameError})
-- """
--
-- illegalChar = _propertyRe.search(name)
-- if illegalChar:
-- raise WrongNameError(illegalChar.start(), name[illegalChar.start()])
-- if not _propertyFirstRe.match(name):
-- if len(name) > 0:
-- raise WrongNameError(0, name[0])
-- else:
-- raise WrongNameError(0, 0)
--
--
--def validateResourceName(name):
-- """
-- Check if the given resource name is valid.
--
-- @param name: name of resource/collection
-- @type name: C{unicode}
-- @raise WrongNameError: if validation fails (@see L{datafinder.common.NameCheck.WrongNameError})
-- """
--
-- illegalChar = _resourceRe.search(name)
-- if illegalChar:
-- raise WrongNameError(illegalChar.start(), name[illegalChar.start()])
-- if not _resourceFirstRe.match(name):
-- if len(name) > 0:
-- raise WrongNameError(0, name[0])
-- else:
-- raise WrongNameError(0, 0)
--
--
--def getResourceNameErrorPosition(name):
-- """
-- Get position of illegal character (and the error-message).
-- This method can be used to get this information if L{isValidPropertyName}
-- or L{isValidResourceName} failed.
--
-- @param name: Resource name.
-- @type name: C{unicode}
--
-- @return: Tuple of error position and message.
-- @rtype: C{tuple} of C{int} and C{unicode}
-- """
--
-- result = (-1, None)
-- illegalChar = _resourceRe.search(name)
-- if illegalChar:
-- result = (illegalChar.start(), \
-- u"Illegal character '%s' at index %d." % \
-- (name[illegalChar.start()], illegalChar.start()))
-- elif not _resourceFirstRe.match(name):
-- result = (0, u"Illegal character '%s' at index %d." % (name[0], 0))
-- return result
--
--
--class WrongNameError(ValueError):
-- """
-- Exception raised if an "illegal" character was found.
--
-- @ivar character: character that caused the exception
-- @type character: C{unicode}
-- @ivar position: position of C{character}
-- @type position: C{int}
-- """
--
-- def __init__(self, position, character):
-- """
-- Constructor.
--
-- @param character: Character that caused the exception.
-- @type character: C{unicode}
-- @param position: Position of C{character}
-- @type position: C{int}
-- """
--
-- ValueError.__init__(self)
-- self.character = character
-- self.position = position
--
-- def __str__(self):
-- """ Returns string representation. """
--
-- return ValueError.__str__(self) + \
-- "Character '%s' at index %d." % (self.character, self.position)
-diff --git a/src/webdav/Utils.py b/src/webdav/Utils.py
-deleted file mode 100644
-index ec05755..0000000
---- a/src/webdav/Utils.py
-+++ /dev/null
-@@ -1,154 +0,0 @@
--# pylint: disable-msg=W0141,R0912
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--The module contains functions to support use of the WebDav functionalities.
--"""
--
--
--import os
--import sys
--
--from webdav.WebdavClient import CollectionStorer, ResourceStorer
--from webdav.Constants import NS_DAV, PROP_RESOURCE_TYPE, CODE_NOT_FOUND, PROP_RESOURCE_TYPE_RESOURCE
--from webdav.Connection import WebdavError
--
--
--__version__ = "$Revision$"[11:-2]
--
--
--def resourceExists(node, name = None, resourceType = PROP_RESOURCE_TYPE_RESOURCE):
-- """
-- Check if resource exists.
--
-- Usage:
-- - resourceExists(ResourceStorer-object):
-- check if resource exists
-- - resourceExists(CollectionStorer-object, name):
-- check if resource name exists in collection
--
-- @param node: node that has to be checked or node of collection
-- @type node: L{ResourceStorer<webdav.WebdavClient.ResourceStorer>}
-- @param name: name of resource (in collection node) that has to be checked
-- @type name: string
--
-- @return: boolean
--
-- @raise WebdavError: all WebDAV errors except WebDAV error 404 (not found)
-- """
--
-- exists = False
-- if not node:
-- return exists
-- try:
-- myResourceType = ""
-- if name:
-- # make sure it's unicode:
-- if not isinstance(name, unicode):
-- name = name.decode(sys.getfilesystemencoding())
-- url = node.url
-- if url.endswith("/"):
-- url = url + name
-- else:
-- url = url + "/" + name
-- newNode = ResourceStorer(url, node.connection)
-- element = newNode.readProperty(NS_DAV, PROP_RESOURCE_TYPE)
-- else: # name is "None":
-- element = node.readProperty(NS_DAV, PROP_RESOURCE_TYPE)
--
-- if len(element.children) > 0:
-- myResourceType = element.children[0].name
-- if resourceType == myResourceType or resourceType == PROP_RESOURCE_TYPE_RESOURCE:
-- exists = True
-- else:
-- exists = False
-- except WebdavError, wderr:
-- if wderr.code == CODE_NOT_FOUND:
-- # node doesn't exist -> exists = False:
-- exists = False
-- else:
-- # another exception occured -> "re-raise" it:
-- raise
-- return exists
--
--
--def downloadCollectionContent(destinationPath, collectionToDownload):
-- """
-- Downloads the resources contained to the given directory.
--
-- @param destinationPath: Path to download the files to, will be created if it not exists.
-- @type destinationPath: C{String}
-- @param collectionToDownload: Collection to download the content from.
-- @type collectionToDownload: instance of L{CollectionStorer<webdav.WebdavClient.CollectionStorer>}
--
-- @raise WebdavError: If something goes wrong.
-- """
--
-- from time import mktime, gmtime
--
-- downloadCount = 0
--
-- listOfItems = collectionToDownload.getCollectionContents()
--
-- if not os.path.exists(destinationPath):
-- try:
-- os.makedirs(destinationPath)
-- except OSError:
-- errorMessage = "Cannot create download destination directory '%s'." % destinationPath
-- raise WebdavError(errorMessage)
--
-- try:
-- itemsInPath = os.listdir(destinationPath)
-- except OSError:
-- errorMessage = "Cannot read the content of download destination directory '%s'." % destinationPath
-- raise WebdavError(errorMessage)
--
-- for item in listOfItems:
-- # skip collections
-- if not isinstance(item[0], CollectionStorer):
-- itemSavePath = os.path.join(destinationPath, item[0].name)
-- existsItemSavePath = os.path.exists(itemSavePath)
--
-- # update?
-- if existsItemSavePath:
-- try:
-- isUpdateNecessary = mktime(item[1].getLastModified()) > mktime(gmtime(os.path.getmtime(itemSavePath)))
-- except (ValueError, OverflowError):
-- isUpdateNecessary = True
-- # windows is not case sensitive
-- for realItem in itemsInPath:
-- if realItem.lower() == item[0].name.lower():
-- itemsInPath.remove(realItem)
-- else:
-- isUpdateNecessary = True
--
-- # download
-- if not existsItemSavePath or (existsItemSavePath and isUpdateNecessary):
-- item[0].downloadFile(itemSavePath)
-- downloadCount = downloadCount + 1
--
-- # delete old items
-- try:
-- for item in itemsInPath:
-- os.remove(os.path.join(destinationPath, item))
-- except OSError, e:
-- if e.errno == 13: # permission error
-- sys.stderr.write("permission problem on '%s' in %s\n" % (e.filename, e.strerror))
-- else:
-- raise
--
-- return downloadCount
-diff --git a/src/webdav/VersionHandler.py b/src/webdav/VersionHandler.py
-deleted file mode 100644
-index a1962c6..0000000
---- a/src/webdav/VersionHandler.py
-+++ /dev/null
-@@ -1,198 +0,0 @@
--# pylint: disable-msg=W0612,W0142
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--The WebDAV client module forwards Delta-V related method invocations to
--the following VersionHandler class.
--"""
--
--__version__ = '$Revision$'[11:-2]
--
--
--import types
--
--from webdav import Constants
--from davlib import XML_CONTENT_TYPE, XML_DOC_HEADER
--
--
--class VersionHandler(object):
-- """
-- Implements a client interface for WebDAV Delta-V methods
-- For the Delta-V see RFC 3253 at http://www.ietf.org/rfc/rfc3253.txt
-- """
--
-- # restrict instance variables
-- __slots__ = ('path', 'connection')
--
--
-- def __init__(self, connection, path):
-- """
-- Construct a VersionHandler with a URL path and a WebDAV connection.
-- This constructor must not be called outside class ResourceStorer.
--
-- @param connection: L{webdav.Connection} instance
-- @param path: resource's path part of URL
-- """
-- #assert isinstance(connection, Connection), \
-- # "Class of connection is %s." % connection.__class__.__name__
-- self.connection = connection
-- self.path = path
--
--
-- def activateVersionControl(self):
-- """
-- Turns version control on for this resource.
-- The resource becomes a version controlled resource (VCR)
-- """
-- response = self.connection._request(Constants.METHOD_VERSION_CONTROL, self.path, None, {})
-- # set auto-versioning to DAV:locked-checkout
-- ## parse response body in case of an error
--
-- def uncheckout(self, lockToken=None):
-- """
-- Undos a previous check-out operation on this VCR.
-- The VCR is reverted to the state before the checkout/lock operation.
-- Beware: Property or content changes will be lost !
-- A (optional) lock has to be removed seperatedly.
--
-- @param lockToken: returned by a preceeding lock() method invocation or None
-- """
-- headers = {}
-- if lockToken:
-- headers = lockToken.toHeader()
-- response = self.connection._request(Constants.METHOD_UNCHECKOUT, self.path, None, headers)
-- ## parse response body in case of an error
--
-- def listAllVersions(self):
-- """
-- List version history.
--
-- @return: List of versions for this VCR. Each version entry is a tuple adhering
-- to the format (URL-path, name, creator, tuple of successor URL-paths).
-- If there are no branches then there is at most one successor within the tuple.
-- """
-- # implementation is similar to the propfind method
-- headers = {}
-- headers['Content-Type'] = XML_CONTENT_TYPE
-- body = _createReportVersionTreeBody()
-- response = self.connection._request(Constants.METHOD_REPORT, self.path, body, headers)
-- # response is multi-status
-- result = []
-- for path, properties in response.msr.items():
-- # parse the successor-set value from XML into alist
-- result.append( (path, str(properties[Constants.PROP_VERSION_NAME]), \
-- str(properties[Constants.PROP_CREATOR]), \
-- _extractSuccessorList(properties[Constants.PROP_SUCCESSOR_SET])) )
-- ## TODO: sort for path and produce list
-- result.sort()
-- return result
--
-- # warning: not tested yet
-- def readVersionProperties(self):
-- """
-- Provide version related information on this VCR.
-- This include a reference to the latest version resource,
-- check-out state information and a comment.
--
-- @return: map of version properties with values.
-- """
-- versionProperties = (Constants.PROP_CHECKEDIN, Constants.PROP_CHECKEDOUT, Constants.PROP_COMMENT)
-- return self.connection.readProperties(*versionProperties)
--
--
-- def revertToVersion(self, oldVersion):
-- """
-- Revert this VCR to the given version.
-- Beware: All versions succeeding the given version are made unavailable.
--
-- @param oldVersion: URL-path of a previous version of this VCR.
-- """
-- ## send an update request
-- assert isinstance(oldVersion, types.StringType) or isinstance(oldVersion, types.UnicodeType)
-- response = self.connection._request(Constants.METHOD_UPDATE, self.path,
-- _createUpdateBody(oldVersion), {})
-- return response
--
--
-- # the following is not needed when using auto-versioning
--
-- # warning: not tested yet
-- def checkout(self):
-- """
-- Marks resource as checked-out
-- This is usually followed by a GET (download) operation.
-- """
-- response = self.connection._request(Constants.METHOD_CHECKOUT, self.path, None, {})
-- ## parse response body in case of an error
--
-- # warning: not tested yet
-- def checkin(self):
-- """
-- Creates a new version from the VCR's content.
-- This opeartion is usually preceeded by one or more write operations.
-- """
-- response = self.connection._request(Constants.METHOD_CHECKIN, self.path, None, {})
-- versionUrl = response.getheader('Location')
-- return versionUrl
-- ## parse response body in case of an error
--
--
--
--
--# Helper functions
--def _createReportVersionTreeBody():
-- """
-- TBD
--
-- @return: ...
-- @rtype: string
-- """
-- versions = 'D:' + Constants.TAG_VERSION_TREE
-- prop = 'D:' + Constants.TAG_PROP
-- nameList = [Constants.PROP_SUCCESSOR_SET, Constants.PROP_VERSION_NAME, Constants.PROP_CREATOR]
-- return XML_DOC_HEADER + \
-- '<%s xmlns:D="DAV:"><%s>' % (versions, prop) + \
-- reduce(lambda xml, name: xml + "<D:%s/>" % name[1], [''] + nameList) + \
-- '</%s></%s>' % (prop, versions)
--
--def _createUpdateBody(path):
-- """
-- TBD
--
-- @return: ...
-- @rtype: string
-- """
-- update = 'D:' + Constants.TAG_UPDATE
-- version = 'D:' + Constants.TAG_VERSION
-- href = 'D:' + Constants.TAG_HREF
-- #PROP = 'D:' + TAG_PROP
-- return XML_DOC_HEADER + \
-- '<%s xmlns:D="DAV:"><%s><%s>' % (update, version, href) + \
-- path + \
-- '</%s></%s></%s>' % (href, version, update)
--
--def _extractSuccessorList(element):
-- """
-- TBD
--
-- @return: ...
-- @rtype: tuple of strings
-- """
-- result = []
-- for href in element.children:
-- result.append(href.textof())
-- return tuple(result)
-diff --git a/src/webdav/WebdavClient.py b/src/webdav/WebdavClient.py
-deleted file mode 100644
-index ab5cec3..0000000
---- a/src/webdav/WebdavClient.py
-+++ /dev/null
-@@ -1,840 +0,0 @@
--# pylint: disable-msg=R0904,W0142,W0511,W0104,C0321,E1103,W0212
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--This module contains the classes ResourceStorer and CollectionStorer for accessing WebDAV resources.
--"""
--
--
--from davlib import XML_CONTENT_TYPE
--
--from urlparse import urlsplit
--import re
--import types
--import sys
--import os
--import shutil
--import socket
--
--from webdav import Constants
--from webdav.WebdavResponse import LiveProperties
--from webdav.WebdavRequests import createFindBody, createUpdateBody, createDeleteBody, createSearchBody
--from webdav.Condition import ConditionTerm
--from webdav.Connection import Connection, WebdavError, AuthorizationError
--from webdav.VersionHandler import VersionHandler
--
--from webdav.acp.Privilege import Privilege
--from webdav.acp.Acl import ACL
--from webdav.NameCheck import validateResourceName, WrongNameError
--
--
--__version__ = '$Revision$'[11:-2]
--
--SOCKET_DEFAULT_TIMEOUT = 10
--
--
--def switchUnicodeUrlOn(switch):
-- """
-- Configure whether to use unicode (UTF-8) encoded URLs (default) or
-- Latin-1 encoded URLs.
--
-- @param switch: 1 if unicode URLs shall be used
-- """
--
-- assert switch == 0 or switch == 1, "Pass boolean argument, please."
-- Constants.CONFIG_UNICODE_URL = switch
--
--
--def parseDigestAuthInfo(authInfo):
-- """
-- Parses the authentication information returned from a server and returns
-- a dictionary containing realm, qop, and nonce.
--
-- @see: L{AuthorizationError<webdav.Connection.AuthorizationError>}
-- or the main function of this module.
-- """
--
-- info = dict()
-- info["realm"] = re.search('realm="([^"]+)"', authInfo).group(1)
-- info["qop"] = re.search('qop="([^"]+)"', authInfo).group(1)
-- info["nonce"] = re.search('nonce="([^"]+)"', authInfo).group(1)
-- return info
--
--
--class ResourceStorer(object):
-- """
-- This class provides client access to a WebDAV resource
-- identified by an URI. It provides all WebDAV class 2 features which include
-- uploading data, getting and setting properties qualified by a XML name space,
-- locking and unlocking the resource.
-- This class does not cache resource data. This has to be performed by its clients.
--
-- @author: Roland Betz
-- """
--
-- # Instance properties
-- url = property(lambda self: str(self.connection) + self.path, None, None, "Resource's URL")
--
-- def __init__(self, url, connection=None, validateResourceNames=True):
-- """
-- Creates an instance for the given URL
-- User must invoke validate() after construction to check the resource on the server.
--
-- @param url: Unique resource location for this storer.
-- @type url: C{string}
-- @param connection: this optional parameter contains a Connection object
-- for the host part of the given URL. Passing a connection saves
-- memory by sharing this connection. (defaults to None)
-- @type connection: L{webdav.Connection}
-- @raise WebdavError: If validation of resource name path parts fails.
-- """
--
-- assert connection == None or isinstance(connection, Connection)
-- parts = urlsplit(url, allow_fragments=False)
-- self.path = parts[2]
-- self.validateResourceNames = validateResourceNames
--
-- # validate URL path
-- for part in self.path.split('/'):
-- if part != '' and not "ino:" in part: # explicitly allowing this character sequence as a part of a path (Tamino 4.4)
-- if self.validateResourceNames:
-- try:
-- validateResourceName(part)
-- except WrongNameError:
-- raise WebdavError("Found invalid resource name part.")
-- self.name = part
-- # was: filter(lambda part: part and validateResourceName(part), self.path.split('/'))
-- # but filter is deprecated
--
-- self.defaultNamespace = None # default XML name space of properties
-- if connection:
-- self.connection = connection
-- else:
-- conn = parts[1].split(":")
-- if len(conn) == 1:
-- self.connection = Connection(conn[0], protocol = parts[0]) # host and protocol
-- else:
-- self.connection = Connection(conn[0], int(conn[1]), protocol = parts[0]) # host and port and protocol
-- self.versionHandler = VersionHandler(self.connection, self.path)
--
--
-- def validate(self):
-- """
-- Check whether URL contains a WebDAV resource
-- Uses the WebDAV OPTIONS method.
--
-- @raise WebdavError: L{WebdavError} if URL does not contain a WebDAV resource
-- """
-- #davHeader = response.getheader(HTTP_HEADER_DAV)
-- davHeader = self.getSpecificOption(Constants.HTTP_HEADER_DAV)
-- self.connection.logger.debug("HEADER DAV: %s" % davHeader)
-- if not(davHeader) or davHeader.find("2") < 0: # DAV class 2 supported ?
-- raise WebdavError("URL does not support WebDAV", 0)
--
-- def options(self):
-- """
-- Send an OPTIONS request to server and return all HTTP headers.
--
-- @return: map of all HTTP headers returned by the OPTIONS method.
-- """
-- response = self.connection.options(self.path)
-- result = {}
-- result.update(response.msg)
-- self.connection.logger.debug("OPTION returns: " + str(result.keys()))
-- return result
--
-- def _getAclSupportAvailable(self):
-- """
-- Returns True if the current connection has got ACL support.
--
-- @return: ACL support (True / False)
-- @rtype: C{bool}
-- """
-- options = self.getSpecificOption(Constants.HTTP_HEADER_DAV)
-- if options.find(Constants.HTTP_HEADER_OPTION_ACL) >= 0:
-- return True
-- else:
-- return False
--
-- aclSupportAvailable = property(_getAclSupportAvailable)
--
-- def _getDaslBasicsearchSupportAvailable(self):
-- """
-- Returns True if the current connection supports DASL basic search.
--
-- @return: DASL basic search support (True / False)
-- @rtype: C{bool}
-- """
-- options = self.getSpecificOption(Constants.HTTP_HEADER_DASL)
-- if not options or \
-- not options.find(Constants.HTTP_HEADER_OPTION_DAV_BASIC_SEARCH) >= 0:
-- return False
-- else:
-- return True
--
-- daslBasicsearchSupportAvailable = property(_getDaslBasicsearchSupportAvailable)
--
-- def isConnectedToCatacombServer(self):
-- """
-- Returns True if connected to a Catacomb WebDav server.
--
-- @return: if connected to Catacomb Webdav server (True / False)
-- @rtype: C{bool}
-- """
-- if not self.connection.serverTypeChecked:
-- options = self.getSpecificOption(Constants.HTTP_HEADER_SERVER)
-- if options.find(Constants.HTTP_HEADER_SERVER_TAMINO) >= 0:
-- self.connection.isConnectedToCatacomb = False
-- else:
-- self.connection.isConnectedToCatacomb = True
-- self.connection.serverTypeChecked = True
-- return self.connection.isConnectedToCatacomb
--
-- def getSpecificOption(self, option):
-- """
-- Returns specified WebDav options.
-- @param option: name of the option
--
-- @return: String containing the value of the option.
-- @rtype: C{string}
-- """
-- options = ''
-- try:
-- options = self.options().get(option)
-- except KeyError:
-- return options
-- return options
--
-- ### delegate some method invocations
-- def __getattr__(self, name):
-- """
-- Build-in method:
-- Forwards unknow lookups (methods) to delegate object 'versionHandler'.
--
-- @param name: name of unknown attribute
-- """
-- # delegate Delta-V methods
-- return getattr(self.versionHandler, name)
--
-- def copy(self, toUrl, infinity=True):
-- """
-- Copies this resource.
--
-- @param toUrl: target URI path
-- @param infinity: Flag that indicates that the complete content of collection is copied. (default)
-- @type depth: C{boolean}
-- """
-- self.connection.logger.debug("Copy to " + repr(toUrl));
-- _checkUrl(toUrl)
-- if infinity:
-- response = self.connection.copy(self.path, toUrl)
-- else:
-- response = self.connection.copy(self.path, toUrl, 0)
-- if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
-- raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
--
-- def delete(self, lockToken=None):
-- """
-- Deletes this resource.
--
-- @param lockToken: String returned by last lock operation or null.
-- @type lockToken: L{LockToken}
-- """
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- response = self.connection.delete(self.path, header)
-- if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
-- raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
--
-- def move(self, toUrl):
-- """
-- Moves this resource to the given path or renames it.
--
-- @param toUrl: new (URI) path
-- """
-- self.connection.logger.debug("Move to " + repr(toUrl));
-- _checkUrl(toUrl)
-- response = self.connection.move(self.path, toUrl)
-- if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
-- raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
--
--
-- def lock(self, owner):
-- """
-- Locks this resource for exclusive write access. This means that for succeeding
-- write operations the returned lock token has to be passed.
-- If the methode does not throw an exception the lock has been granted.
--
-- @param owner: describes the lock holder
-- @return: lock token string (automatically generated)
-- @rtype: L{LockToken}
-- """
-- response = self.connection.lock(self.path, owner)
-- if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
-- raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
-- return LockToken(self.url, response.locktoken)
--
-- def unlock(self, lockToken):
-- """
-- Removes the lock from this resource.
--
-- @param lockToken: which has been return by the lock() methode
-- @type lockToken: L{LockToken}
-- """
-- self.connection.unlock(self.path, lockToken.token)
--
--
-- def deleteContent(self, lockToken=None):
-- """
-- Delete binary data at permanent storage.
--
-- @param lockToken: None or lock token from last lock request
-- @type lockToken: L{LockToken}
-- """
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- self.connection.put(self.path, "", extra_hdrs=header)
--
-- def uploadContent(self, content, lockToken=None):
-- """
-- Write binary data to permanent storage.
--
-- @param content: containing binary data
-- @param lockToken: None or lock token from last lock request
-- @type lockToken: L{LockToken}
-- """
-- assert not content or isinstance(content, types.UnicodeType) or\
-- isinstance(content, types.StringType), "Content is not a string: " + content.__class__.__name__
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- response = None
-- if not content is None:
-- header["Content-length"] = len(content)
-- else:
-- header["Content-length"] = 0
--
-- try:
-- response = self.connection.put(self.path, content, extra_hdrs=header)
-- finally:
-- if response:
-- self.connection.logger.debug(response.read())
-- response.close()
--
-- def uploadFile(self, newFile, lockToken=None):
-- """
-- Write binary data to permanent storage.
--
-- @param newFile: File containing binary data.
-- @param lockToken: None or lock token from last lock request
-- @type lockToken: L{LockToken}
-- """
-- assert isinstance(newFile, types.FileType), "Argument is no file: " + file.__class__.__name__
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- self.connection.putFile(self.path, newFile, header=header)
--
-- def downloadContent(self):
-- """
-- Read binary data from permanent storage.
-- """
-- response = self.connection.get(self.path)
-- # TODO: Other interface ? return self.connection.getfile()
-- return response
--
-- def downloadFile(self, localFileName):
-- """
-- Copy binary data from permanent storage to a local file.
--
-- @param localFileName: file to write binary data to
-- """
-- localFile = open(localFileName, 'wb')
-- remoteFile = self.downloadContent()
-- try:
-- socket.setdefaulttimeout(SOCKET_DEFAULT_TIMEOUT)
-- _blockCopyFile(remoteFile, localFile, Connection.blockSize)
-- except socket.error, e:
-- raise e
-- remoteFile.close()
-- localFile.close()
--
-- def readProperties(self, *names):
-- """
-- Reads the given properties.
--
-- @param names: a list of property names.
-- A property name is a (XmlNameSpace, propertyName) tuple.
-- @return: a map from property names to DOM Element or String values.
-- """
-- assert names, "Property names are missing."
-- body = createFindBody(names, self.defaultNamespace)
-- response = self.connection.propfind(self.path, body, depth=0)
-- properties = response.msr.values()[0]
-- if properties.errorCount > 0:
-- raise WebdavError("Property is missing on '%s': %s" % (self.path, properties.reason), properties.code)
-- return properties
--
-- def readProperty(self, nameSpace, name):
-- """
-- Reads the given property.
--
-- @param nameSpace: XML-namespace
-- @type nameSpace: string
-- @param name: A property name.
-- @type name: string
--
-- @return: a map from property names to DOM Element or String values.
-- """
-- results = self.readProperties((nameSpace, name))
-- if len(results) == 0:
-- raise WebdavError("Property is missing: " + results.reason)
-- return results.values()[0]
--
-- def readAllProperties(self):
-- """
-- Reads all properties of this resource.
--
-- @return: a map from property names to DOM Element or String values.
-- """
-- response = self.connection.allprops(self.path, depth=0)
-- return response.msr.values()[0]
--
-- def readAllPropertyNames(self):
-- """
-- Returns the names of all properties attached to this resource.
--
-- @return: List of property names
-- """
-- response = self.connection.propnames(self.path, depth=0)
-- return response.msr.values()[0]
--
-- def readStandardProperties(self):
-- """
-- Read all WebDAV live properties.
--
-- @return: A L{LiveProperties} instance which contains a getter method for each live property.
-- """
-- body = createFindBody(LiveProperties.NAMES, Constants.NS_DAV)
-- response = self.connection.propfind(self.path, body, depth=0)
-- properties = response.msr.values()[0]
-- return LiveProperties(properties)
--
-- def writeProperties(self, properties, lockToken=None):
-- """
-- Sets or updates the given properties.
--
-- @param lockToken: if the resource has been locked this is the lock token.
-- @type lockToken: L{LockToken}
-- @param properties: a map from property names to a String or
-- DOM element value for each property to add or update.
-- """
-- assert isinstance(properties, types.DictType)
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- body = createUpdateBody(properties, self.defaultNamespace)
-- response = self.connection.proppatch(self.path, body, header)
-- if response.msr.errorCount > 0:
-- raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
--
-- def deleteProperties(self, lockToken=None, *names):
-- """
-- Removes the given properties from this resource.
--
-- @param lockToken: if the resource has been locked this is the lock token.
-- @type lockToken: L{LockToken}
-- @param names: a collection of property names.
-- A property name is a (XmlNameSpace, propertyName) tuple.
-- """
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- body = createDeleteBody(names, self.defaultNamespace)
-- response = self.connection.proppatch(self.path, body, header)
-- if response.msr.errorCount > 0:
-- raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
--
-- # ACP extension
-- def setAcl(self, acl, lockToken=None):
-- """
-- Sets ACEs in the non-inherited and non-protected ACL or the resource.
-- This is the implementation of the ACL method of the WebDAV ACP.
--
-- @param acl: ACL to be set on resource as ACL object.
-- @param lockToken: If the resource has been locked this is the lock token (defaults to None).
-- @type lockToken: L{LockToken}
-- """
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- headers = {}
-- if lockToken:
-- headers = lockToken.toHeader()
-- headers['Content-Type'] = XML_CONTENT_TYPE
-- body = acl.toXML()
-- response = self.connection._request('ACL', self.path, body, headers)
-- return response
-- ## TODO: parse DAV:error response
--
-- def getAcl(self):
-- """
-- Returns this resource's ACL in an ACL instance.
--
-- @return: Access Control List.
-- @rtype: L{ACL<webdav.acp.Acl.ACL>}
-- """
-- xmlAcl = self.readProperty(Constants.NS_DAV, Constants.TAG_ACL)
-- return ACL(xmlAcl)
--
-- def getCurrentUserPrivileges(self):
-- """
-- Returns a tuple of the current user privileges.
--
-- @return: list of Privilege instances
-- @rtype: list of L{Privilege<webdav.acp.Privilege.Privilege>}
-- """
-- privileges = self.readProperty(Constants.NS_DAV, Constants.PROP_CURRENT_USER_PRIVILEGE_SET)
-- result = []
-- for child in privileges.children:
-- result.append(Privilege(domroot=child))
-- return result
--
-- def getPrincipalCollections(self):
-- """
-- Returns a list principal collection URLs.
--
-- @return: list of principal collection URLs
-- @rtype: C{list} of C{unicode} elements
-- """
-- webdavQueryResult = self.readProperty(Constants.NS_DAV, Constants.PROP_PRINCIPAL_COLLECTION_SET)
-- principalCollectionList = []
-- for child in webdavQueryResult.children:
-- principalCollectionList.append(child.first_cdata)
-- return principalCollectionList
--
-- def getOwnerUrl(self):
-- """ Explicitly retireve the Url of the owner. """
--
-- result = self.readProperty(Constants.NS_DAV, Constants.PROP_OWNER)
-- if result and len(result.children):
-- return result.children[0].textof()
-- return None
--
--class CollectionStorer(ResourceStorer):
-- """
-- This class provides client access to a WebDAV collection resource identified by an URI.
-- This class does not cache resource data. This has to be performed by its clients.
--
-- @author: Roland Betz
-- """
--
-- def __init__(self, url, connection=None, validateResourceNames=True):
-- """
-- Creates a CollectionStorer instance for a URL and an optional Connection object.
-- User must invoke validate() after constuction to check the resource on the server.
--
-- @see: L{webdav.WebdavClient.ResourceStorer.__init__}
-- @param url: unique resource location for this storer
-- @param connection: this optional parameter contains a Connection object for the host part
-- of the given URL. Passing a connection saves memory by sharing this connection.
-- """
-- if url[-1] != '/': # Collection URL must end with slash
-- url += '/'
-- ResourceStorer.__init__(self, url, connection, validateResourceNames)
--
-- def getResourceStorer(self, name):
-- """
-- Return a ResourceStorer instance for a child resource (member) of this Collection.
--
-- @param name: leaf name of child resource
-- @return: L{ResourceStorer} instance
-- """
-- assert isinstance(name, types.StringType) or isinstance(name, types.UnicodeType)
-- return ResourceStorer(self.url + name, self.connection, self.validateResourceNames)
--
-- def validate(self):
-- """
-- Check whether this URL contains a WebDAV collection.
-- Uses the WebDAV OPTION method.
--
-- @raise WebdavError: L{WebdavError} if URL does not contain a WebDAV collection resource.
-- """
-- super(CollectionStorer, self).validate()
-- isCollection = self.readProperty(Constants.NS_DAV, Constants.PROP_RESOURCE_TYPE)
-- if not (isCollection and isCollection.children):
-- raise WebdavError("Not a collection URL.", 0)
--
-- def addCollection(self, name, lockToken=None):
-- """
-- Make a new WebDAV collection resource within this collection.
--
-- @param name: of the new collection
-- @param lockToken: None or token returned by last lock operation
-- @type lockToken: L{LockToken}
-- """
-- assert isinstance(name, types.StringType) or isinstance(name, types.UnicodeType)
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- if self.validateResourceNames:
-- validateResourceName(name)
-- if name[-1] != '/': # Collection URL must end with slash
-- name += '/'
-- self.connection.mkcol(self.path + name, header)
-- return CollectionStorer(self.url + name, self.connection, self.validateResourceNames)
--
-- def addResource(self, name, content=None, properties=None, lockToken=None):
-- """
-- Create a new empty WebDAV resource contained in this collection with the given
-- properties.
--
-- @param name: leaf name of the new resource
-- @param content: None or initial binary content of resource
-- @param properties: name/value-map containing properties
-- @param lockToken: None or token returned by last lock operation
-- @type lockToken: L{LockToken}
-- """
-- assert isinstance(name, types.StringType) or isinstance(name, types.UnicodeType)
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- if self.validateResourceNames:
-- validateResourceName(name) # check for invalid characters
-- resource_ = ResourceStorer(self.url + name, self.connection, self.validateResourceNames)
-- resource_.uploadContent(content, lockToken)
-- if properties:
-- resource_.writeProperties(properties, lockToken)
-- return resource_
--
-- def deleteResource(self, name, lockToken=None):
-- """
-- Delete a collection which is contained within this collection
--
-- @param name: leaf name of a contained collection resource
-- @param lockToken: None or token returned by last lock operation
-- @type lockToken: L{LockToken}
-- """
-- assert isinstance(name, types.StringType) or isinstance(name, types.UnicodeType)
-- assert lockToken == None or isinstance(lockToken, LockToken), \
-- "Invalid lockToken argument %s" % type(lockToken)
-- header = {}
-- if lockToken:
-- header = lockToken.toHeader()
-- if self.validateResourceNames:
-- validateResourceName(name)
-- response = self.connection.delete(self.path + name, header)
-- if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
-- raise WebdavError("Request failed: %s" % response.msr.reason, response.msr.code)
--
-- def lockAll(self, owner):
-- """
-- Locks this collection resource for exclusive write access. This means that for
-- succeeding write operations the returned lock token has to be passed.
-- The operation is applied recursively to all contained resources.
-- If the methode does not throw an exception then the lock has been granted.
--
-- @param owner: describes the lock holder
-- @return: Lock token string (automatically generated).
-- @rtype: L{LockToken}
-- """
-- assert isinstance(owner, types.StringType) or isinstance(owner, types.UnicodeType)
-- response = self.connection.lock(self.path, owner, depth=Constants.HTTP_HEADER_DEPTH_INFINITY)
-- return LockToken(self.url, response.locktoken)
--
-- def listResources(self):
-- """
-- Describe all members within this collection.
--
-- @return: map from URI to a L{LiveProperties} instance containing the WebDAV
-- live attributes of the contained resource
-- """
-- # *LiveProperties.NAMES denotes the list of all live properties as an
-- # argument to the method call.
-- response = self.connection.getprops(self.path,
-- depth=1,
-- ns=Constants.NS_DAV,
-- *LiveProperties.NAMES)
-- result = {}
-- for path, properties in response.msr.items():
-- if path == self.path: # omit this collection resource
-- continue
-- ## some servers do not append a trailing slash to collection paths
-- if self.path.endswith('/') and self.path[0:-1] == path:
-- continue
-- result[path] = LiveProperties(properties=properties)
-- return result
--
-- def getCollectionContents(self):
-- """
-- Return a list of the tuple (resources or collection) / properties)
--
-- @return: a list of the tuple (resources or collection) / properties)
-- @rtype: C{list}
-- """
-- self.validate()
-- collectionContents = []
-- result = self.listResources()
-- for url, properties_ in result.items():
-- if not self.path == url:
-- if properties_.getResourceType() == 'resource':
-- myWebDavStorer = ResourceStorer(url, self.connection, self.validateResourceNames)
-- else:
-- myWebDavStorer = CollectionStorer(url, self.connection, self.validateResourceNames)
-- collectionContents.append((myWebDavStorer, properties_))
-- return collectionContents
--
-- def findProperties(self, *names):
-- """
-- Retrieve given properties for this collection and all directly contained resources.
--
-- @param names: a list of property names
-- @return: a map from resource URI to a map from property name to value.
-- """
-- assert isinstance(names, types.ListType) or isinstance(names, types.TupleType), \
-- "Argument name has type %s" % str(type(names))
-- body = createFindBody(names, self.defaultNamespace)
-- response = self.connection.propfind(self.path, body, depth=1)
-- return response.msr
--
-- def deepFindProperties(self, *names):
-- """
-- Retrieve given properties for this collection and all contained (nested) resources.
--
-- Note:
-- =====
-- This operation can take a long time if used with recursive=true and is therefore
-- disabled on some WebDAV servers.
--
-- @param names: a list of property names
-- @return: a map from resource URI to a map from property name to value.
-- """
-- assert isinstance(names, types.ListType.__class__) or isinstance(names, types.TupleType), \
-- "Argument name has type %s" % str(type(names))
-- body = createFindBody(names, self.defaultNamespace)
-- response = self.connection.propfind(self.path, body, depth=Constants.HTTP_HEADER_DEPTH_INFINITY)
-- return response.msr
--
-- def findAllProperties(self):
-- """
-- Retrieve all properties for this collection and all directly contained resources.
--
-- @return: a map from resource URI to a map from property name to value.
-- """
-- response = self.connection.allprops(self.path, depth=1)
-- return response.msr
--
--
-- # DASL extension
-- def search(self, conditions, selects):
-- """
-- Search for contained resources which match the given search condition.
--
-- @param conditions: tree of ConditionTerm instances representing a logical search term
-- @param selects: list of property names to retrieve for the found resources
-- """
-- assert isinstance(conditions, ConditionTerm)
-- headers = { 'Content-Type' : XML_CONTENT_TYPE, "depth": Constants.HTTP_HEADER_DEPTH_INFINITY}
-- body = createSearchBody(selects, self.path, conditions)
-- response = self.connection._request('SEARCH', self.path, body, headers)
-- return response.msr
--
--
--class LockToken(object):
-- """
-- This class provides help on handling WebDAV lock tokens.
--
-- @author: Roland Betz
-- """
-- # restrict instance variables
-- __slots__ = ('url', 'token')
--
-- def __init__(self, url, token):
-- assert isinstance(url, types.StringType) or isinstance(url, types.UnicodeType), \
-- "Invalid url argument %s" % type(url)
-- assert isinstance(token, types.StringType) or isinstance(token, types.UnicodeType), \
-- "Invalid lockToken argument %s" % type(token)
-- self.url = url
-- self.token = token
--
-- def value(self):
-- """
-- Descriptive string containing the lock token's URL and the token itself.
--
-- @return: Descriptive lock token with URL.
-- @rtype: C{string}
-- """
-- return "<" + self.url + "> (<" + self.token + ">)"
--
-- def toHeader(self):
-- """
-- Header fragment for WebDAV request.
--
-- @return: Dictionary containing an entry for the lock token query.
-- @rtype: C{dictionary}
-- """
-- return {Constants.HTTP_HEADER_IF: self.value()}
--
-- def __str__(self):
-- return self.value()
--
--
--def _blockCopyFile(source, dest, blockSize):
-- """
-- Copies a file in chunks of C{blockSize}.
--
-- @param source: Source file.
-- @type source: FileIO buffer.
-- @param dest: Destination file.
-- @type dest: FileIO buffer.
-- @param blockSize: Size of block in bytes.
-- @type blockSize: C{int}
-- """
-- transferedBytes = 0
-- block = source.read(blockSize)
-- while len(block):
-- dest.write(block)
-- transferedBytes += len(block);
-- block = source.read(blockSize)
--
--def _checkUrl(url):
-- """
-- Checks the given URL for validity.
--
-- @param url: URL to check.
-- @type url: C{string}
--
-- @raise ValueError: If the URL does not contain valid/usable content.
-- """
--
-- parts = urlsplit(url, allow_fragments=False)
-- if len(parts[0]) == 0 or len(parts[1]) == 0 or len(parts[2]) == 0:
-- raise ValueError("Invalid URL: " + repr(url))
-diff --git a/src/webdav/WebdavRequests.py b/src/webdav/WebdavRequests.py
-deleted file mode 100644
-index 79e586a..0000000
---- a/src/webdav/WebdavRequests.py
-+++ /dev/null
-@@ -1,205 +0,0 @@
--# pylint: disable-msg=W0511,W0212,E1111
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--This module handles WebDav server requests.
--"""
--
--
--import types
--from webdav import Constants
--import qp_xml
--from tempfile import TemporaryFile
--
--from davlib import XML_DOC_HEADER
--
--from webdav.NameCheck import validatePropertyName
--
--
--__version__ = "$LastChangedRevision$"
--
--
--## TODO: create a property list class
--
--class XmlNameSpaceMangler(object):
-- '''
-- Handles WebDav requests.
-- '''
--
-- # restrict instance variables
-- __slots__ = ('shortcuts', 'defaultNameSpace')
--
-- def __init__(self, nameList, defaultNameSpace = None):
-- '''
--
-- @param nameList:
-- @param defaultNameSpace:
-- '''
--
-- assert isinstance(nameList, types.ListType) or isinstance(nameList, types.TupleType), \
-- "1. argument has wrong type %s" % type(nameList)
-- self.shortcuts = {}
-- self.defaultNameSpace = defaultNameSpace
-- for name in nameList:
-- if not isinstance(name, types.TupleType):
-- name = (defaultNameSpace, name)
-- assert isinstance(name, types.TupleType) and len(name) == 2, \
-- "Name is not a namespace, name tuple: %s" % type(name)
-- validatePropertyName(name[1])
-- if name[0] and not self.shortcuts.has_key(name[0]):
-- self.shortcuts[name[0]] = 'ns%d' % len(self.shortcuts)
--
-- def getNameSpaces(self):
-- '''
-- Returns the namespace.
-- '''
--
-- result = ""
-- for namespace, short in self.shortcuts.items():
-- result += ' xmlns:%s="%s"' % (short, namespace)
-- return result
--
-- def getUpdateElements(self, valueMap):
-- '''
--
-- @param valueMap:
-- '''
--
-- elements = ""
-- for name in valueMap.keys():
-- fullname = name
-- if isinstance(name, types.StringType):
-- fullname = (self.defaultNameSpace, name)
-- if not fullname[0]:
-- tag = fullname[1]
-- else:
-- tag = self.shortcuts[fullname[0]] + ':' + fullname[1]
-- value = valueMap[name]
-- if value:
-- if isinstance(value, qp_xml._element):
-- tmpFile = TemporaryFile('w+')
-- value = qp_xml.dump(tmpFile, value)
-- tmpFile.flush()
-- tmpFile.seek(0)
-- tmpFile.readline()
-- value = tmpFile.read()
-- else:
-- value = "<![CDATA[%s]]>" % value
-- else:
-- value = ""
-- elements += "<%s>%s</%s>" % (tag, value, tag)
-- return elements
--
-- def getNameElements(self, nameList):
-- '''
--
-- @param nameList:
-- '''
--
-- elements = ""
-- for name in nameList:
-- if isinstance(name, types.StringType):
-- name = (self.defaultNameSpace, name)
-- if not name[0]:
-- tag = name[1]
-- else:
-- tag = self.shortcuts[name[0]] + ':' + name[1]
-- elements += "<%s />" % tag
-- return elements
--
--
--
--def createUpdateBody(propertyDict, defaultNameSpace = None):
-- '''
--
-- @param propertyDict:
-- @param defaultNameSpace:
-- '''
--
-- updateTag = 'D:' + Constants.TAG_PROPERTY_UPDATE
-- setTag = 'D:' + Constants.TAG_PROPERTY_SET
-- propTag = 'D:' + Constants.TAG_PROP
-- mangler = XmlNameSpaceMangler(propertyDict.keys(), defaultNameSpace)
-- return XML_DOC_HEADER + \
-- '<%s xmlns:D="DAV:"><%s><%s %s>' % (updateTag, setTag, propTag, mangler.getNameSpaces()) + \
-- mangler.getUpdateElements(propertyDict) + \
-- '</%s></%s></%s>' % (propTag, setTag, updateTag)
--
--
--def createDeleteBody(nameList, defaultNameSpace = None):
-- '''
--
-- @param nameList:
-- @param defaultNameSpace:
-- '''
--
-- updateTag = 'D:' + Constants.TAG_PROPERTY_UPDATE
-- removeTag = 'D:' + Constants.TAG_PROPERTY_REMOVE
-- propTag = 'D:' + Constants.TAG_PROP
-- mangler = XmlNameSpaceMangler(nameList, defaultNameSpace)
-- return XML_DOC_HEADER + \
-- '<%s xmlns:D="DAV:"><%s><%s %s>' % (updateTag, removeTag, propTag, mangler.getNameSpaces()) + \
-- mangler.getNameElements(nameList) + \
-- '</%s></%s></%s>' % (propTag, removeTag, updateTag)
--
--
--def createFindBody(nameList, defaultNameSpace = None):
-- '''
--
-- @param nameList:
-- @param defaultNameSpace:
-- '''
--
-- findTag = 'D:' + Constants.TAG_PROPERTY_FIND
-- propTag = 'D:' + Constants.TAG_PROP
-- mangler = XmlNameSpaceMangler(nameList, defaultNameSpace)
-- return XML_DOC_HEADER + \
-- '<%s xmlns:D="DAV:"><%s %s>' % (findTag, propTag, mangler.getNameSpaces()) + \
-- mangler.getNameElements(nameList) + \
-- '</%s></%s>' % (propTag, findTag)
--
--
--def createSearchBody(selects, path, conditions, defaultNameSpace = None):
-- '''
-- Creates DASL XML body.
--
-- @param selects: list of property names to retrieve for the found resources
-- @param path: list of conditions
-- @param conditions: tree of ConditionTerm instances representing a logical search term
-- @param defaultNameSpace: default namespace
-- '''
--
-- searchTag = 'D:' + Constants.TAG_SEARCH_REQUEST
-- basicTag = 'D:' + Constants.TAG_SEARCH_BASIC
-- selectTag = 'D:' + Constants.TAG_SEARCH_SELECT
-- fromTag = 'D:' + Constants.TAG_SEARCH_FROM
-- scopeTag = 'D:' + Constants.TAG_SEARCH_SCOPE
-- whereTag = 'D:' + Constants.TAG_SEARCH_WHERE
-- propTag = 'D:' + Constants.TAG_PROP
-- hrefTag = 'D:' + Constants.TAG_HREF
-- depthTag = 'D:' + Constants.TAG_LOCK_DEPTH
-- depthValue = Constants.HTTP_HEADER_DEPTH_INFINITY
-- mangler = XmlNameSpaceMangler(selects, defaultNameSpace)
-- return XML_DOC_HEADER + \
-- '<%s xmlns:D="DAV:"><%s>' % (searchTag, basicTag) + \
-- '<%s><%s %s>%s</%s></%s>' % (selectTag, propTag, mangler.getNameSpaces(),
-- mangler.getNameElements(selects), propTag, selectTag) + \
-- '<%s><%s><%s>%s</%s><%s>%s</%s></%s></%s>' % (fromTag, scopeTag, hrefTag, path, hrefTag,
-- depthTag, depthValue, depthTag, scopeTag, fromTag) + \
-- '<%s>%s</%s>' % (whereTag, conditions.toXML(),whereTag) + \
-- '</%s></%s>' % (basicTag, searchTag)
--
-\ No newline at end of file
-diff --git a/src/webdav/WebdavResponse.py b/src/webdav/WebdavResponse.py
-deleted file mode 100644
-index c84943d..0000000
---- a/src/webdav/WebdavResponse.py
-+++ /dev/null
-@@ -1,525 +0,0 @@
--# pylint: disable-msg=R0903,W0142,W0221,W0212,W0104,W0511,C0103,R0901
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Handles WebDAV responses.
--"""
--
--
--from davlib import _parse_status
--import qp_xml
--from webdav import Constants
--import time
--import rfc822
--import urllib
--# Handling Jython 2.5 bug concerning the date pattern
--# conversion in time.strptime
--try:
-- from java.lang import IllegalArgumentException
--except ImportError:
-- class IllegalArgumentException(object):
-- pass
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class HttpStatus(object):
-- """
-- TBD
--
-- @ivar code:
-- @type code:
-- @ivar reason:
-- @type reason:
-- @ivar errorCount:
-- @type errorCount: int
-- """
--
-- def __init__(self, elem):
-- """
-- TBD
--
-- @param elem: ...
-- @type elem: instance of L{Element}
-- """
-- self.code, self.reason = _parse_status(elem)
-- self.errorCount = (self.code >= Constants.CODE_LOWEST_ERROR)
-- def __str__(self):
-- return "HTTP status %d: %s" % (self.code, self.reason)
--
--
--class MultiStatusResponse(dict):
-- """
-- TBD
--
-- @ivar status:
-- @type status:
-- @ivar reason:
-- @type reason:
-- @ivar errorCount:
-- @type errorCount:
-- """
--
-- # restrict instance variables
-- __slots__ = ('errorCount', 'reason', 'status')
--
-- def __init__(self, domroot):
-- dict.__init__(self)
-- self.errorCount = 0
-- self.reason = None
-- self.status = Constants.CODE_MULTISTATUS
-- if (domroot.ns != Constants.NS_DAV) or (domroot.name != Constants.TAG_MULTISTATUS):
-- raise ResponseFormatError(domroot, 'Invalid response: <DAV:multistatus> expected.')
-- self._scan(domroot)
--
-- def getCode(self):
-- if self.errorCount == 0:
-- return Constants.CODE_SUCCEEDED
-- if len(self) > self.errorCount:
-- return Constants.CODE_MULTISTATUS
-- return self.values()[0].code
--
-- def getReason(self):
-- result = ""
-- for response in self.values():
-- if response.code > Constants.CODE_LOWEST_ERROR:
-- result += response.reason
-- return result
--
-- def __str__(self):
-- result = ""
-- for key, value in self.items():
-- if isinstance(value, PropertyResponse):
-- result += "Resource at %s has %d properties and %d errors.\n" % (key, len(value), value.errorCount)
-- else:
-- result += "Resource at %s returned " % key + str(value)
-- return result
--
-- def _scan(self, root):
-- for child in root.children:
-- if child.ns != Constants.NS_DAV:
-- continue
-- if child.name == Constants.TAG_RESPONSEDESCRIPTION:
-- self.reason = child.textof()
-- elif child.name == Constants.TAG_RESPONSE:
-- self._scanResponse(child)
-- ### unknown child element
--
-- def _scanResponse(self, elem):
-- hrefs = []
-- response = None
-- for child in elem.children:
-- if child.ns != Constants.NS_DAV:
-- continue
-- if child.name == Constants.TAG_HREF:
-- try:
-- href = _unquoteHref(child.textof())
-- except UnicodeDecodeError:
-- raise ResponseFormatError(child, "Invalid 'href' data encoding.")
-- hrefs.append(href)
-- elif child.name == Constants.TAG_STATUS:
-- self._scanStatus(child, *hrefs)
-- elif child.name == Constants.TAG_PROPERTY_STATUS:
-- if not response:
-- if len(hrefs) != 1:
-- raise ResponseFormatError(child, 'Invalid response: One <DAV:href> expected.')
-- response = PropertyResponse()
-- self[hrefs[0]] = response
-- response._scan(child)
-- elif child.name == Constants.TAG_RESPONSEDESCRIPTION:
-- for href in hrefs:
-- self[href].reasons.append(child.textOf())
-- ### unknown child element
-- if response and response.errorCount > 0:
-- self.errorCount += 1
--
-- def _scanStatus(self, elem, *hrefs):
-- if len(hrefs) == 0:
-- raise ResponseFormatError(elem, 'Invalid response: <DAV:href> expected.')
-- status = HttpStatus(elem)
-- for href in hrefs:
-- self[href] = status
-- if status.errorCount:
-- self.errorCount += 1
--
-- # Instance properties
-- code = property(getCode, None, None, "HTTP response code")
--
--
--
--class PropertyResponse(dict):
-- """
-- TBD
--
-- @ivar errors:
-- @type errors: list of ...
-- @ivar reasons:
-- @type reasons: list of ...
-- @ivar failedProperties:
-- @type failedProperties: dict of ...
-- """
--
-- # restrict instance variables
-- __slots__ = ('errors', 'reasons', 'failedProperties')
--
-- def __init__(self):
-- dict.__init__(self)
-- self.errors = []
-- self.reasons = []
-- self.failedProperties = {}
--
-- def __str__(self):
-- result = ""
-- for value in self.values():
-- result += value.name + '= ' + value.textof() + '\n'
-- result += self.getReason()
-- return result
--
-- def getCode(self):
-- if len(self.errors) == 0:
-- return Constants.CODE_SUCCEEDED
-- if len(self) > 0:
-- return Constants.CODE_MULTISTATUS
-- return self.errors[-1].code
--
-- def getReason(self):
-- result = ""
-- if len(self.errors) > 0:
-- result = "Failed for: " + repr(self.failedProperties.keys()) + "\n"
-- for error in self.errors:
-- result += "%s (%d). " % (error.reason, error.code)
-- for reason in self.reasons:
-- result += "%s. " % reason
-- return result
--
-- def _scan(self, element):
-- status = None
-- statusElement = element.find(Constants.TAG_STATUS, Constants.NS_DAV)
-- if statusElement:
-- status = HttpStatus(statusElement)
-- if status.errorCount:
-- self.errors.append(status)
--
-- propElement = element.find(Constants.TAG_PROP, Constants.NS_DAV)
-- if propElement:
-- for prop in propElement.children:
-- if status.errorCount:
-- self.failedProperties[(prop.ns, prop.name)]= status
-- else:
-- prop.__class__ = Element # bad, bad trick
-- self[prop.fullname] = prop
-- reasonElement = element.find(Constants.TAG_RESPONSEDESCRIPTION, Constants.NS_DAV)
-- if reasonElement:
-- self.reasons.append(reasonElement.textOf())
--
-- # Instance properties
-- code = property(getCode, None, None, "HTTP response code")
-- errorCount = property(lambda self: len(self.errors), None, None, "HTTP response code")
-- reason = property(getReason, None, None, "HTTP response code")
--
--
--
--
--class LiveProperties(object):
-- """
-- This class provides convenient access to the WebDAV 'live' properties of a resource.
-- WebDav 'live' properties are defined in RFC 2518, Section 13.
-- Each property is converted from string to its natural data type.
--
-- @version: $Revision$
-- @author: Roland Betz
-- """
--
-- # restrict instance variables
-- __slots__ = ('properties')
--
-- NAMES = (Constants.PROP_CREATION_DATE, Constants.PROP_DISPLAY_NAME,
-- Constants.PROP_CONTENT_LENGTH, Constants.PROP_CONTENT_TYPE, Constants.PROP_ETAG,
-- Constants.PROP_LAST_MODIFIED, Constants.PROP_OWNER,
-- Constants.PROP_LOCK_DISCOVERY, Constants.PROP_RESOURCE_TYPE, Constants.PROP_SUPPORTED_LOCK )
--
-- def __init__(self, properties=None, propElement=None):
-- """
-- Construct <code>StandardProperties</code> from a map of properties containing
-- live properties or from a XML 'prop' element containing live properties
--
-- @param properties: map as implemented by class L{PropertyResponse}
-- @param propElement: an C{Element} value
-- """
-- assert isinstance(properties, PropertyResponse) or \
-- isinstance(propElement, qp_xml._element), \
-- "Argument properties has type %s" % str(type(properties))
-- self.properties = {}
-- for name, value in properties.items():
-- if name[0] == Constants.NS_DAV and name[1] in self.NAMES:
-- self.properties[name[1]] = value
--
-- def getContentLanguage(self):
-- """
-- Return the language of a resource's textual content or null
--
-- @return: string
-- """
--
-- result = ""
-- if not self.properties.get(Constants.PROP_CONTENT_LANGUAGE, None) is None:
-- result = self.properties.get(Constants.PROP_CONTENT_LANGUAGE).textof()
-- return result
--
-- def getContentLength(self):
-- """
-- Returns the length of the resource's content in bytes.
--
-- @return: number of bytes
-- """
--
-- result = 0
-- if not self.properties.get(Constants.PROP_CONTENT_LENGTH, None) is None:
-- result = int(self.properties.get(Constants.PROP_CONTENT_LENGTH).textof())
-- return result
--
-- def getContentType(self):
-- """
-- Return the resource's content MIME type.
--
-- @return: MIME type string
-- """
--
-- result = ""
-- if not self.properties.get(Constants.PROP_CONTENT_TYPE, None) is None:
-- result = self.properties.get(Constants.PROP_CONTENT_TYPE).textof()
-- return result
--
-- def getCreationDate(self):
-- """
-- Return date of creation as time tuple.
--
-- @return: time tuple
-- @rtype: C{time.struct_time}
--
-- @raise ValueError: If string is not in the expected format (ISO 8601).
-- """
--
-- datetimeString = ""
-- if not self.properties.get(Constants.PROP_CREATION_DATE, None) is None:
-- datetimeString = self.properties.get(Constants.PROP_CREATION_DATE).textof()
--
-- result = rfc822.parsedate(datetimeString)
-- if result is None:
-- result = _parseIso8601String(datetimeString)
--
-- return time.mktime(result)
--
-- def getEntityTag(self):
-- """
-- Return a entity tag which is unique for a particular version of a resource.
-- Different resources or one resource before and after modification have different etags.
--
-- @return: entity tag string
-- """
--
-- result = ""
-- if not self.properties.get(Constants.PROP_ETAG, None) is None:
-- result = self.properties.get(Constants.PROP_ETAG).textof()
-- return result
--
-- def getDisplayName(self):
-- """
-- Returns a resource's display name.
--
-- @return: string
-- """
--
-- result = ""
-- if not self.properties.get(Constants.PROP_DISPLAY_NAME, None) is None:
-- result = self.properties.get(Constants.PROP_DISPLAY_NAME).textof()
-- return result
--
-- def getLastModified(self):
-- """
-- Return last modification of resource as time tuple.
--
-- @return: Modification date time.
-- @rtype: C{time.struct_time}
--
-- @raise ValueError: If the date time string is not in the expected format (RFC 822 / ISO 8601).
-- """
--
-- datetimeString = None
-- if not self.properties.get(Constants.PROP_LAST_MODIFIED, None) is None:
-- datetimeString = self.properties.get(Constants.PROP_LAST_MODIFIED).textof()
-- result = rfc822.parsedate(datetimeString)
-- if result is None:
-- result = _parseIso8601String(datetimeString)
-- return time.mktime(result)
--
-- def getLockDiscovery(self):
-- """
-- Return all current lock's applied to a resource or null if it is not locked.
--
-- @return: a lockdiscovery DOM element according to RFC 2815
-- """
--
-- xml = self.properties.get(Constants.PROP_LOCK_DISCOVERY)
-- return _scanLockDiscovery(xml)
--
-- def getResourceType(self):
-- """
-- Return a resource's WebDAV type.
--
-- @return: 'collection' or 'resource'
-- """
--
-- xml = self.properties.get(Constants.PROP_RESOURCE_TYPE)
-- if xml and xml.children:
-- return xml.children[0].name
-- return "resource"
--
-- def getSupportedLock(self):
-- """
-- Return a DOM element describing all supported lock options for a resource.
-- Usually this is shared and exclusive write lock.
--
-- @return: supportedlock DOM element according to RFC 2815
-- """
--
-- xml = self.properties.get(Constants.PROP_SUPPORTED_LOCK)
-- return xml
--
-- def getOwnerAsUrl(self):
-- """
-- Return a resource's owner in form of a URL.
--
-- @return: string
-- """
--
-- xml = self.properties.get(Constants.PROP_OWNER)
-- if xml and len(xml.children):
-- return xml.children[0].textof()
-- return None
--
-- def __str__(self):
-- result = ""
-- result += " Name=" + self.getDisplayName()
-- result += "\n Type=" + self.getResourceType()
-- result += "\n Length=" + str(self.getContentLength())
-- result += "\n Content Type="+ self.getContentType()
-- result += "\n ETag=" + self.getEntityTag()
-- result += "\n Created=" + time.strftime("%c GMT", self.getCreationDate())
-- result += "\n Modified=" + time.strftime("%c GMT", self.getLastModified())
-- return result
--
--
--def _parseIso8601String(date):
-- """
-- Parses the given ISO 8601 string and returns a time tuple.
-- The strings should be formatted according to RFC 3339 (see section 5.6).
-- But currently there are two exceptions:
-- 1. Time offset is limited to "Z".
-- 2. Fragments of seconds are ignored.
-- """
--
-- if "." in date and "Z" in date: # Contains fragments of second?
-- secondFragmentPos = date.rfind(".")
-- timeOffsetPos = date.rfind("Z")
-- date = date[:secondFragmentPos] + date[timeOffsetPos:]
-- try:
-- timeTuple = time.strptime(date, Constants.DATE_FORMAT_ISO8601)
-- except IllegalArgumentException: # Handling Jython 2.5 bug concerning the date pattern accordingly
-- import _strptime # Using the Jython fall back solution directly
-- timeTuple = _strptime.strptime(date, Constants.DATE_FORMAT_ISO8601)
-- return timeTuple
--
--
--class ResponseFormatError(IOError):
-- """
-- An instance of this class is raised when the web server returned a webdav
-- reply which does not adhere to the standard and cannot be recognized.
-- """
-- def __init__(self, element, message= None):
-- IOError.__init__(self, "ResponseFormatError at element %s: %s" % (element.name, message))
-- self.element = element
-- self.message = message
--
--
--class Element(qp_xml._element):
-- """
-- This class improves the DOM interface (i.e. element interface) provided by the qp_xml module
-- TODO: substitute qp_xml by 'real' implementation. e.g. domlette
-- """
-- def __init__(self, namespace, name, cdata=''):
-- qp_xml._element.__init__(self, ns=namespace, name=name, lang=None, parent=None,
-- children=[], ns_scope={}, attrs={},
-- first_cdata=cdata, following_cdata='')
--
-- def __str__(self):
-- return self.textof()
--
-- def __getattr__(self, name):
-- if (name == 'fullname'):
-- return (self.__dict__['ns'], self.__dict__['name'])
-- raise AttributeError, name
--
-- def add(self, child):
-- self.children.append(child)
-- return child
--
--def _scanLockDiscovery(root):
-- assert root.name == Constants.PROP_LOCK_DISCOVERY, "Invalid lock discovery XML element"
-- active = root.find(Constants.TAG_ACTIVE_LOCK, Constants.NS_DAV)
-- if active:
-- return _scanActivelock(active)
-- return None
--
--def _scanActivelock(root):
-- assert root.name == Constants.TAG_ACTIVE_LOCK, "Invalid active lock XML element"
-- token = _scanOrError(root, Constants.TAG_LOCK_TOKEN)
-- value = _scanOrError(token, Constants.TAG_HREF)
-- owner = _scanOwner(root)
-- depth = _scanOrError(root, Constants.TAG_LOCK_DEPTH)
-- return (value.textof(), owner, depth.textof())
--
--def _scanOwner(root):
-- owner = root.find(Constants.TAG_LOCK_OWNER, Constants.NS_DAV)
-- if owner:
-- href = owner.find(Constants.TAG_HREF, Constants.NS_DAV)
-- if href:
-- return href.textof()
-- return owner.textof()
-- return None
--
--def _scanOrError(elem, childName):
-- child = elem.find(childName, Constants.NS_DAV)
-- if not child:
-- raise ResponseFormatError(elem, "Invalid response: <"+childName+"> expected")
-- return child
--
--
--def _unquoteHref(href):
-- #print "*** Response HREF=", repr(href)
-- if type(href) == type(u""):
-- try:
-- href = href.encode('ascii')
-- except UnicodeError: # URL contains unescaped non-ascii character
-- # handle bug in Tamino webdav server
-- return urllib.unquote(href)
-- href = urllib.unquote(href)
-- if Constants.CONFIG_UNICODE_URL:
-- return unicode(href, 'utf-8')
-- else:
-- return unicode(href, 'latin-1')
-diff --git a/src/webdav/__init__.py b/src/webdav/__init__.py
-deleted file mode 100644
-index 3e46609..0000000
---- a/src/webdav/__init__.py
-+++ /dev/null
-@@ -1,16 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--__version__ = "$LastChangedRevision$"
-diff --git a/src/webdav/acp/Ace.py b/src/webdav/acp/Ace.py
-deleted file mode 100644
-index 8321d41..0000000
---- a/src/webdav/acp/Ace.py
-+++ /dev/null
-@@ -1,293 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--ACE object handling according to WebDAV ACP specification.
--"""
--
--
--from webdav.acp.Principal import Principal
--from webdav.acp.GrantDeny import GrantDeny
--from webdav import Constants
--from webdav.Connection import WebdavError
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class ACE(object):
-- """
-- This class provides functionality for handling ACEs
--
-- @ivar principal: A principal (user or group)
-- @type principal: L{Principal} object
-- @ivar invert: Flag indicating whether ACE should invert the principal.
-- @type invert: C{bool}
-- @ivar grantDenies: Grant or deny clauses for privileges
-- @type grantDenies: C{list} of L{GrantDeny} objects
-- @ivar protected: Flag indicating whether ACE is protected.
-- @type protected: C{bool}
-- @ivar inherited: URL indicating the source from where the ACE is inherited.
-- @type inherited: C{string}
-- """
--
-- # restrict instance variables
-- __slots__ = ('principal', 'invert', 'grantDenies', 'protected', 'inherited')
--
-- def __init__(self, domroot=None, principal=None, grantDenies=None):
-- """
-- Constructor should be called with either no parameters (create blank ACE),
-- one parameter (a DOM tree or principal), or two parameters (principal and
-- sequence of GrantDenies).
--
-- @param domroot: A DOM tree (default: None).
-- @type domroot: L{webdav.WebdavResponse.Element} object
-- @param principal: A principal (user or group), (default: None).
-- @type principal: L{Principal} object
-- @param grantDenies: Grant and deny clauses for privileges (default: None).
-- @type grantDenies: sequence of L{GrantDeny} objects
--
-- @raise WebdavError: When non-valid parameters are passed a L{WebdavError} is raised.
-- """
-- self.principal = Principal()
-- self.protected = None
-- self.inherited = None
-- self.invert = None
-- self.grantDenies = []
--
-- if domroot:
-- self.principal = Principal(domroot=domroot.find(Constants.TAG_PRINCIPAL, Constants.NS_DAV))
-- self.inherited = domroot.find(Constants.TAG_INHERITED, Constants.NS_DAV)
-- if self.inherited:
-- self.inherited = self.inherited.children[0].textof()
-- if domroot.find(Constants.TAG_PROTECTED, Constants.NS_DAV):
-- self.protected = 1
-- for child in domroot.children:
-- if child.ns == Constants.NS_DAV \
-- and (child.name == Constants.TAG_GRANT or child.name == Constants.TAG_DENY):
-- self.grantDenies.append(GrantDeny(domroot=child))
-- elif isinstance(principal, Principal):
-- newPrincipal = Principal()
-- newPrincipal.copy(principal)
-- self.principal = newPrincipal
-- if (isinstance(grantDenies, list) or isinstance(grantDenies, tuple)):
-- self.addGrantDenies(grantDenies)
-- elif domroot == None and grantDenies == None:
-- # no param ==> blank ACE
-- pass
-- else:
-- # This shouldn't happen, someone screwed up with the params ...
-- raise WebdavError('non-valid parameters handed to ACE constructor')
--
-- def __cmp__(self, other):
-- if not isinstance(other, ACE):
-- return 1
-- if self.principal == other.principal \
-- and self.invert == other.invert \
-- and self.protected == other.protected \
-- and self.inherited == other.inherited:
-- equal = 1
-- for grantDeny in self.grantDenies:
-- inList = 0
-- for otherGrantDeny in other.grantDenies:
-- if grantDeny == otherGrantDeny:
-- inList = 1
-- if inList == 0:
-- equal = 0
-- return not equal
-- else:
-- return 1
--
-- def __repr__(self):
-- repr = '<class ACE: '
-- if self.invert:
-- repr += 'inverted principal, ' % (self.invert)
-- if self.principal:
-- repr += 'principal: %s, ' % (self.principal)
-- if self.protected:
-- repr += 'protected, '
-- if self.inherited:
-- repr += 'inherited href: %s, ' % (self.inherited)
-- first = 1
-- repr += 'grantDenies: ['
-- for grantDeny in self.grantDenies:
-- if first:
-- repr += '%s' % grantDeny
-- first = 0
-- else:
-- repr += ', %s' % grantDeny
-- return '%s]>' % (repr)
--
-- def copy(self, other):
-- '''Copy an ACE object.
--
-- @param other: Another ACE to copy.
-- @type other: L{ACE} object
--
-- @raise WebdavError: When an object that is not an L{ACE} is passed
-- a L{WebdavError} is raised.
-- '''
-- if not isinstance(other, ACE):
-- raise WebdavError('Non-ACE object passed to copy method: %s.' % other.__class__)
-- self.invert = other.invert
-- self.protected = other.protected
-- self.inherited = other.inherited
-- self.principal = Principal()
-- if other.principal:
-- self.principal.copy(other.principal)
-- if other.grantDenies:
-- self.addGrantDenies(other.grantDenies)
--
-- def isValid(self):
-- """
-- Returns true/false (1/0) whether necessarry props
-- principal and grantDenies are set and whether the ACE contains one
-- grant or deny clauses.
--
-- @return: Validity of ACE.
-- @rtype: C{bool}
-- """
-- return self.principal and len(self.grantDenies) == 1
--
-- def isGrant(self):
-- '''
-- Returns true/false (1/0) if ACE contains only grant clauses.
--
-- @return: Value whether the ACE is of grant type.
-- @rtype: C{bool}
-- '''
-- if self.isMixed() or len(self.grantDenies) < 1:
-- return 0
-- else:
-- return self.grantDenies[0].isGrant()
--
-- def isDeny(self):
-- '''
-- Returns true/false (1/0) if ACE contains only deny clauses.
--
-- @return: Value whether the ACE is of deny type.
-- @rtype: C{bool}
-- '''
-- if self.isMixed() or len(self.grantDenies) < 1:
-- return 0
-- else:
-- return self.grantDenies[0].isDeny()
--
-- def isMixed(self):
-- '''
-- Returns true/false (1/0) if ACE contains both types (grant and deny) of clauses.
--
-- @return: Value whether the ACE is of mixed (grant and deny) type.
-- @rtype: C{bool}
-- '''
-- mixed = 0
-- if len(self.grantDenies):
-- first = self.grantDenies[0].grantDeny
-- for grantDeny in self.grantDenies:
-- if grantDeny.grantDeny != first:
-- mixed = 1
-- return mixed
--
-- def toXML(self, defaultNameSpace=None):
-- """
-- Returns ACE content as a string of valid XML as described in WebDAV ACP.
--
-- @param defaultNameSpace: Name space (default: None).
-- @type defaultNameSpace: C(string)
-- """
-- assert self.isValid(), "ACE is not initialized or does not contain valid content!"
--
-- ACE = 'D:' + Constants.TAG_ACE
-- res = self.principal.toXML(self.invert)
-- for grantDeny in self.grantDenies:
-- res += grantDeny.toXML()
-- if self.protected:
-- res += '<D:protected/>'
-- if self.inherited:
-- res += '<D:inherited><D:href>%s</D:href></D:inherited>' % (self.inherited)
-- return '<%s>%s</%s>' % (ACE, res, ACE)
--
-- def setPrincipal(self, principal):
-- '''
-- Sets the passed principal on the ACE.
--
-- @param principal: A principal.
-- @type principal: L{Principal} object
-- '''
-- self.principal = Principal()
-- self.principal.copy(principal)
--
-- def setInherited(self, href):
-- '''
-- Sets the passed URL on the ACE to denote from where it is inherited.
--
-- @param href: A URL.
-- @type href: C{string}
-- '''
-- self.inherited = href
--
-- def addGrantDeny(self, grantDeny):
-- '''
-- Adds the passed GrantDeny object to list if it's not in it, yet.
--
-- @param grantDeny: A grant or deny clause.
-- @type grantDeny: L{GrantDeny} object
-- '''
-- # only add it if it's not in the list, yet ...
-- inList = 0
-- for element in self.grantDenies:
-- if element == grantDeny:
-- inList = 1
-- if not inList:
-- newGrantDeny = GrantDeny()
-- newGrantDeny.copy(grantDeny)
-- self.grantDenies.append(newGrantDeny)
--
-- def addGrantDenies(self, grantDenies):
-- '''Adds the list of passed grant/deny objects to list.
--
-- @param grantDenies: Grant or deny clauses.
-- @type grantDenies: sequence of L{GrantDeny} objects
-- '''
-- map(lambda grantDeny: self.addGrantDeny(grantDeny), grantDenies)
--
-- def delGrantDeny(self, grantDeny):
-- '''Deletes the passed GrantDeny object from list.
--
-- @param grantDeny: A grant or deny clause.
-- @type grantDeny: L{GrantDeny} object
--
-- @raise WebdavError: A L{WebdavError} is raised if the clause to be
-- deleted is not present.
-- '''
-- # only add it if it's not in the list, yet ...
-- count = 0
-- index = 0
-- for element in self.grantDenies:
-- count += 1
-- if element == grantDeny:
-- index = count
-- if index:
-- self.grantDenies.pop(index - 1)
-- else:
-- raise WebdavError('GrantDeny to be deleted not in list: %s.' % grantDeny)
--
-- def delGrantDenies(self, grantDenies):
-- '''Deletes the list of passed grant/deny objects from list.
--
-- @param grantDenies: Grant or deny clauses.
-- @type grantDenies: sequence of L{GrantDeny} objects
-- '''
-- map(lambda grantDeny: self.delGrantDeny(grantDeny), grantDenies)
-diff --git a/src/webdav/acp/AceHandler.py b/src/webdav/acp/AceHandler.py
-deleted file mode 100644
-index e07b74d..0000000
---- a/src/webdav/acp/AceHandler.py
-+++ /dev/null
-@@ -1,182 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Handling of WebDAV Access Protocol Extensions and ACL preparation for UI.
--"""
--
--
--from webdav import Constants
--from webdav.WebdavClient import ResourceStorer
--from webdav.Connection import WebdavError
--
--
--__version__ = "$LastChangedRevision$"
--
--
--def extractSupportedPrivilegeSet(userPrivileges):
-- """
-- Returns a dictionary of supported privileges.
--
-- @param userPrivileges: A DOM tree.
-- @type userPrivileges: L{webdav.WebdavResponse.Element} object
--
-- @raise WebdavError: When unknown elements appear in the
-- C{DAV:supported-privilege} appear a L{WebdavError} is raised.
--
-- @return: A dictionary with privilege names as keys and privilege descriptions as values.
-- @rtype: C{dictionary}
-- """
-- result = {}
-- for element in userPrivileges.children:
-- if element.name == Constants.TAG_SUPPORTED_PRIVILEGE:
-- privName = ''
-- privDescription = ''
-- for privilege in element.children:
-- if privilege.name == Constants.TAG_PRIVILEGE:
-- privName = privilege.children[0].name
-- elif privilege.name == Constants.TAG_DESCRIPTION:
-- privDescription = privilege.textof()
-- else:
-- raise WebdavError('Unknown element in DAV:supported-privilege: ' + privilege.name)
--
-- if privName and privDescription:
-- result[privName] = privDescription
-- privName = ''
-- privDescription = ''
-- else:
-- raise WebdavError('Invalid element tag in DAV:supported-privilege-set: ' + element.name)
-- return result
--
--
--def _insertAclDisplaynames(acl):
-- """
-- Modifies the ACL by adding the human readable names
-- (DAV:displayname property) of each principal found in an ACL.
--
-- This should be done with the REPORT method, but it is not supported by
-- Jacarta Slide, yet. (As of Aug. 1, 2003 in CVS repository)
--
-- So we are going to do it differently by foot the harder way ...
--
-- @param acl: An ACL object for which the displaynames should be retrieved.
-- @type acl: L{ACL} object
-- """
-- ## This is redundant code to be still kept for the REPORT method way of doing it ...
-- ## property = '''<D:prop><D:displayname/></D:prop>'''
-- ## return self.getReport(REPORT_ACL_PRINCIPAL_PROP_SET, property)
-- for ace in acl.aces:
-- if not ace.principal.property:
-- principalConnection = \
-- ResourceStorer(ace.principal.principalURL)
-- ace.principal.displayname = \
-- principalConnection.readProperty(Constants.NS_DAV, Constants.PROP_DISPLAY_NAME)
--
--
--def prepareAcls(acls):
-- """
-- Returns all ACLs describing the behaviour of the resource. The information
-- in the ACL is modified to contain all information needed to display in the UI.
--
-- @param acls: ACL objects.
-- @type acls: C{list} of L{ACL} objects
--
-- @return: (non-valid) ACLs that contain both grant and deny clauses in an ACE.
-- Displaynames are added to the Principals where needed.
-- @rtype: C{list} of L{ACL} objects
-- """
-- for acl in acls.keys():
-- acls[acl] = acls[acl].joinGrantDeny()
-- _insertAclDisplaynames(acls[acl])
-- return acls
--
--
--def prepareAcl(acl):
-- """
-- Returns an ACL describing the behaviour of the resource. The information
-- in the ACL is modified to contain all information needed to display in the UI.
--
-- @param acl: An ACL object.
-- @type acl: L{ACL} object
--
-- @return: A (non-valid) ACL that contains both grant and deny clauses in an ACE.
-- Displaynames are added to the Principals where needed.
-- @rtype: L{ACL} object
-- """
-- acl = acl.joinGrantDeny()
-- _insertAclDisplaynames(acl)
-- return acl
--
--
--def refineAclForSet(acl):
-- """
-- Sets the ACL composed from the UI on the WebDAV server. For that purpose the
-- ACL object gets refined first to form a well accepted ACL to be set by the
-- ACL WebDAV method.
--
-- @param acl: An ACL object to be refined.
-- @type acl: L{ACL} object
--
-- @return: A valid ACL that contains only grant or deny clauses in an ACE.
-- Inherited and protected ACEs are stripped out.
-- @rtype: L{ACL} object
-- """
-- acl = acl.splitGrantDeny()
-- acl = acl.stripAces()
-- return acl
--
--
--##~ unsupported or unfinished methods:
--##~
--##~ def report(self, report, request=None, lockToken=None):
--##~ """
--##~ This method implements the WebDAV ACP method: REPORT for given report
--##~ types.
--##~
--##~ Parameters:
--##~
--##~ 'report' -- Report type as a string.
--##~
--##~ 'request' -- XML content of the request for the report (defaults to None).
--##~
--##~ 'lockToken' -- Lock token to be set (defaults to None).
--##~ """
--##~ raise WebdavError('Reports are not supported by our Jacarta Slide, yet (as of Aug. 1, 2003 in CVS).')
--##~
--##~ headers = createCondition(lockToken)
--##~ headers['Content-Type'] = XML_CONTENT_TYPE
--##~ body = '<D:%s xmlns:D="DAV:">%s</D:%s>' % (report, request, report)
--##~ #print "Body: ", body
--##~ response = self.connection._request('REPORT', self.path, body, headers)
--##~ return response
--##~ ## TODO: parse DAV:error response
--##~
--##~
--##~ def getAllAcls(self):
--##~ """
--##~ Returns a dictionary of ACL resources with respective ACL objects
--##~ that apply to the given resource.
--##~
--##~ ### This method needs to be extended for inherited ACLs when Tamino
--##~ support tells me (Guy) how to get to them.
--##~ """
--##~ acls = {self.path: self.getAcl()}
--##~ for ace in acls[self.path].aces:
--##~ if ace.inherited:
--##~ if not ace.inherited in acls:
--##~ acls[ace.inherited] = self.getAcl()
--##~
--##~ # append some more stuff here to acls for possible inherited ACLs
--##~ return acls
-diff --git a/src/webdav/acp/Acl.py b/src/webdav/acp/Acl.py
-deleted file mode 100644
-index 8f2b36f..0000000
---- a/src/webdav/acp/Acl.py
-+++ /dev/null
-@@ -1,311 +0,0 @@
--# pylint: disable-msg=W0622
--#
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--
--"""
--ACL object handling according to WebDAV ACP specification.
--"""
--
--
--from webdav.acp.Ace import ACE
--from webdav import Constants
--from webdav.Connection import WebdavError
--from webdav.davlib import XML_DOC_HEADER
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class ACL(object):
-- """
-- This class provides access to Access Control List funcionality
-- as specified in the WebDAV ACP.
--
-- @ivar aces: ACEs in ACL
-- @type aces: C{list} of L{ACE} objects
-- @ivar withInherited: Flag indicating whether ACL contains inherited ACEs.
-- @type withInherited: C{bool}
-- """
--
-- # restrict instance variables
-- __slots__ = ('aces', 'withInherited')
--
-- def __init__(self, domroot=None, aces=None):
-- """
-- Constructor should be called with either no parameters (create blank ACE),
-- or one parameter (a DOM tree or ACE list).
--
-- @param domroot: A DOM tree (default: None).
-- @type domroot: L{webdav.WebdavResponse.Element} object
-- @param aces: ACE objects (default: None)
-- @type aces: C{list} of L{ACE} objects
--
-- @raise WebdavError: When non-valid parameters are passed a L{WebdavError} is raised.
-- """
-- self.withInherited = None
-- self.aces = []
--
-- if domroot:
-- for child in domroot.children:
-- if child.name == Constants.TAG_ACE and child.ns == Constants.NS_DAV:
-- self.addAce(ACE(child))
-- else:
-- # This shouldn't happen, someone screwed up with the params ...
-- raise WebdavError('Non-ACE tag handed to ACL constructor: ' + child.ns + child.name)
-- elif isinstance(aces, list) or isinstance(aces, tuple):
-- self.addAces(aces)
-- elif domroot == None and aces == None:
-- # no param ==> blank object
-- pass
-- else:
-- # This shouldn't happen, someone screwed up with the params ...
-- raise WebdavError('non-valid parameters handed to ACL constructor')
--
-- def __cmp__(self, other):
-- if not isinstance(other, ACL):
-- return 1
-- if self.withInherited == other.withInherited:
-- equal = 1
-- for ace in self.aces:
-- inList = 0
-- for otherAce in other.aces:
-- if ace == otherAce:
-- inList = 1
-- if inList == 0:
-- equal = 0
-- return not equal
-- else:
-- return 1
--
-- def __repr__(self):
-- repr = '<class ACL: '
-- if self.withInherited:
-- repr += 'with inherited, '
-- first = 1
-- repr += 'aces: ['
-- for ace in self.aces:
-- if first:
-- repr += '%s' % ace
-- first = 0
-- else:
-- repr += ', %s' % ace
-- return '%s]>' % (repr)
--
-- def copy(self, other):
-- '''Copy an ACL object.
--
-- @param other: Another ACL to copy.
-- @type other: L{ACL} object
--
-- @raise WebdavError: When an object that is not an L{ACL} is passed
-- a L{WebdavError} is raised.
-- '''
-- if not isinstance(other, ACL):
-- raise WebdavError('Non-ACL object passed to copy method: %s' % other.__class__)
-- self.withInherited = other.withInherited
-- if other.aces:
-- self.addAces(other.aces)
--
-- def toXML(self):
-- """
-- Returns ACL content as a string of valid XML as described in WebDAV ACP.
-- """
-- aclTag = 'D:' + Constants.TAG_ACL
-- return XML_DOC_HEADER +\
-- '<' + aclTag + ' xmlns:D="DAV:">' + reduce(lambda xml, ace: xml + ace.toXML() + '\n', [''] + self.aces) +\
-- '</' + aclTag + '>'
--
-- def addAce(self, ace):
-- '''
-- Adds the passed ACE object to list if it's not in it, yet.
--
-- @param ace: An ACE.
-- @type ace: L{ACE} object
-- '''
-- newAce = ACE()
-- newAce.copy(ace)
-- # only add it if it's not in the list, yet ...
-- inList = 0
-- for element in self.aces:
-- if element == ace:
-- inList = 1
-- if not inList:
-- self.aces.append(newAce)
--
-- def addAces(self, aces):
-- '''Adds the list of passed ACE objects to list.
--
-- @param aces: ACEs
-- @type aces: sequence of L{ACE} objects
-- '''
-- for ace in aces:
-- self.addAce(ace)
--
-- def delAce(self, ace):
-- '''Deletes the passed ACE object from list.
--
-- @param ace: An ACE.
-- @type ace: L{ACE} object
--
-- @raise WebdavError: When the ACE to be deleted is not within the ACL
-- a L{WebdavError} is raised.
-- '''
-- # find where it is and delete it ...
-- count = 0
-- index = 0
-- for element in self.aces:
-- count += 1
-- if element == ace:
-- index = count
-- if index:
-- self.aces.pop(index - 1)
-- else:
-- raise WebdavError('ACE to be deleted not in list: %s.' % ace)
--
-- def delAces(self, aces):
-- '''Deletes the list of passed ACE objects from list.
--
-- @param aces: ACEs
-- @type aces: sequence of L{ACE} objects
-- '''
-- for ace in aces:
-- self.delAce(ace)
--
-- def delPrincipalsAces(self, principal):
-- """
-- Deletes all ACEs in ACL by given principal.
--
-- @param principal: A principal.
-- @type principal: L{Principal} object
-- """
-- # find where it is and delete it ...
-- index = 0
-- while index < len(self.aces):
-- if self.aces[index].principal.principalURL == principal.principalURL:
-- self.aces.pop(index)
-- else:
-- index += 1
--
-- def joinGrantDeny(self):
-- """
-- Returns a "refined" ACL of the ACL for ease of use in the UI.
-- The purpose is to post the user an ACE that can contain both, granted
-- and denied, privileges. So possible pairs of grant and deny ACEs are joined
-- to return them in one ACE. This resulting ACE then of course IS NOT valid
-- for setting ACLs anymore. They will have to be reconverted to yield valid
-- ACLs for the ACL method.
--
-- @return: A (non-valid) ACL that contains both grant and deny clauses in an ACE.
-- @rtype: L{ACL} object
-- """
-- joinedAces = {}
-- for ace in self.aces:
-- if not ace.principal.principalURL is None:
-- principalKey = ace.principal.principalURL
-- elif not ace.principal.property is None:
-- principalKey = ace.principal.property
-- else:
-- principalKey = None
-- if ace.inherited:
-- principalKey = ace.inherited + ":" + principalKey
-- if principalKey in joinedAces:
-- joinedAces[principalKey].addGrantDenies(ace.grantDenies)
-- else:
-- joinedAces[principalKey] = ACE()
-- joinedAces[principalKey].copy(ace)
-- newAcl = ACL()
-- newAcl.addAces(joinedAces.values())
-- return newAcl
--
-- def splitGrantDeny(self):
-- """
-- Returns a "refined" ACL of the ACL for ease of use in the UI.
-- The purpose is to post the user an ACE that can contain both, granted
-- and denied, privileges. So possible joined grant and deny clauses in ACEs
-- splitted to return them in separate ACEs. This resulting ACE then is valid
-- for setting ACLs again. This method is to be seen in conjunction with the
-- method joinGrantDeny as it reverts its effect.
--
-- @return: A valid ACL that contains only ACEs with either grant or deny clauses.
-- @rtype: L{ACL} object
-- """
-- acesGrant = {}
-- acesDeny = {}
-- for ace in self.aces:
-- for grantDeny in ace.grantDenies:
-- if grantDeny.isGrant():
-- if ace.principal.principalURL in acesGrant:
-- ace.addGrantDeny(grantDeny)
-- else:
-- acesGrant[ace.principal.principalURL] = ACE()
-- acesGrant[ace.principal.principalURL].copy(ace)
-- acesGrant[ace.principal.principalURL].grantDenies = []
-- acesGrant[ace.principal.principalURL].addGrantDeny(grantDeny)
-- else:
-- if ace.principal.principalURL in acesDeny:
-- ace.addGrantDeny(grantDeny)
-- else:
-- acesDeny[ace.principal.principalURL] = ACE()
-- acesDeny[ace.principal.principalURL].copy(ace)
-- acesDeny[ace.principal.principalURL].grantDenies = []
-- acesDeny[ace.principal.principalURL].addGrantDeny(grantDeny)
-- newAcl = ACL()
-- newAcl.addAces(acesGrant.values())
-- newAcl.addAces(acesDeny.values())
-- return newAcl
--
-- def isValid(self):
-- """
-- Returns true (1) if all contained ACE objects are valid,
-- otherwise false (0) is returned.
--
-- @return: Validity of ACL.
-- @rtype: C{bool}
-- """
-- valid = 1
-- if len(self.aces):
-- for ace in self.aces:
-- if not ace.isValid():
-- valid = 0
-- return valid
--
-- def stripAces(self, inherited=True, protected=True):
-- """
-- Returns an ACL object with all ACEs stripped that are inherited
-- and/or protected.
--
-- @param inherited: Flag to indicate whether inherited ACEs should
-- be stripped (default: True).
-- @type inherited: C{bool}
-- @param protected: Flag to indicate whether protected ACEs should
-- be stripped (default: True).
-- @type protected: C{bool}
--
-- @return: An ACL without the stripped ACEs.
-- @rtype: L{ACL} object
-- """
-- newAcl = ACL()
-- if len(self.aces):
-- for ace in self.aces:
-- keep = 1
-- if inherited and ace.inherited:
-- keep = 0
-- elif protected and ace.protected:
-- keep = 0
-- if keep:
-- newAcl.addAce(ace)
-- return newAcl
-diff --git a/src/webdav/acp/GrantDeny.py b/src/webdav/acp/GrantDeny.py
-deleted file mode 100644
-index 52c9b93..0000000
---- a/src/webdav/acp/GrantDeny.py
-+++ /dev/null
-@@ -1,241 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Handling of grant and deny clauses in ACEs according to WebDAV ACP specification.
--"""
--
--
--from webdav.acp.Privilege import Privilege
--from webdav import Constants
--from webdav.Connection import WebdavError
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class GrantDeny(object):
-- """
-- This class provides functionality for handling
-- grant and deny clauses in ACEs.
--
-- @ivar grantDeny: Flag indicating whether clause grants or denies.
-- @type grantDeny: C{bool}
-- @ivar privileges: Privileges to be granted or denied.
-- @type privileges: C{list} of L{Privilege} objects
-- """
--
-- def __init__(self, domroot=None):
-- """
-- Constructor should be called with either no parameters
-- (create blank GrantDeny), or one parameter (a DOM tree).
--
-- @param domroot: A DOM tree (default: None).
-- @type domroot: L{webdav.WebdavResponse.Element} object
--
-- @raise WebdavError: When non-valid parameters are passed a L{WebdavError} is raised.
-- """
-- self.grantDeny = 0 # 0: deny, 1: grant
-- self.privileges = []
--
-- if domroot:
-- self.grantDeny = (domroot.name == Constants.TAG_GRANT)
-- for child in domroot.children:
-- if child.name == Constants.TAG_PRIVILEGE and child.ns == Constants.NS_DAV:
-- self.privileges.append(Privilege(domroot=child))
-- else:
-- # This shouldn't happen, someone screwed up with the params ...
-- raise WebdavError('Non-privilege tag handed to GrantDeny constructor: %s' \
-- % child.name)
-- elif domroot == None:
-- # no param ==> blank object
-- pass
-- else:
-- # This shouldn't happen, someone screwed up with the params ...
-- raise WebdavError('Non-valid parameters handed to GrantDeny constructor.')
--
-- def __cmp__(self, other):
-- """ Compares two GrantDeny instances. """
-- if not isinstance(other, GrantDeny):
-- return 1
-- if self.grantDeny == other.grantDeny:
-- equal = 1
-- for priv in self.privileges:
-- inList = 0
-- for otherPriv in other.privileges:
-- if priv == otherPriv:
-- inList = 1
-- if inList == 0:
-- equal = 0
-- return not equal
-- else:
-- return 1
--
-- def __repr__(self):
-- """ Returns the representation of an instance. """
-- representation = '<class GrantDeny: '
-- if self.grantDeny:
-- representation += 'grant privileges: ['
-- else:
-- representation += 'deny privileges: ['
-- first = 1
-- for priv in self.privileges:
-- if first:
-- representation += '%s' % priv
-- first = 0
-- else:
-- representation += ', %s' % priv
-- return '%s]>' % (representation)
--
-- def copy(self, other):
-- """
-- Copy a GrantDeny object.
--
-- @param other: Another grant or deny clause to copy.
-- @type other: L{GrantDeny} object
--
-- @raise WebdavError: When an object that is not an L{GrantDeny} is passed
-- a L{WebdavError} is raised.
-- """
-- if not isinstance(other, GrantDeny):
-- raise WebdavError('Non-GrantDeny object passed to copy method: %s' \
-- % other)
-- self.grantDeny = other.grantDeny
-- if other.privileges:
-- self.addPrivileges(other.privileges)
--
-- def isGrant(self):
-- """
-- Returns whether the set of privileges is of type "grant"
-- indicating true or false.
--
-- @return: Value whether the clause is of grant type.
-- @rtype: C{bool}
-- """
-- return self.grantDeny
--
-- def isDeny(self):
-- """
-- Returns whether the set of privileges is of type "deny"
-- indicating true or false.
--
-- @return: Value whether the clause is of deny type.
-- @rtype: C{bool}
-- """
-- return not self.grantDeny
--
-- def setGrantDeny(self, grantDeny):
-- """
-- Sets the set of privileges to given value for grantDeny.
--
-- @param grantDeny: Grant/deny value for clause (grant: True/1, deny: False/0).
-- @type grantDeny: C{bool}
-- """
-- if grantDeny == 0 or grantDeny == 1:
-- self.grantDeny = grantDeny
--
-- def setGrant(self):
-- """ Sets the set of privileges to type "grant". """
-- self.grantDeny = 1
--
-- def setDeny(self):
-- """ Sets the set of privileges to type "deny". """
-- self.grantDeny = 0
--
-- def isAll(self):
-- """
-- Checks whether the privileges contained are equal
-- to aggregate DAV:all privilege.
--
-- @return: Value whether all un-aggregated privileges are present.
-- @rtype: C{bool}
-- """
--
-- if len(self.privileges) == 1 and self.privileges[0].name == Constants.TAG_ALL:
-- return 1
-- return 0
--
-- def addPrivilege(self, privilege):
-- """
-- Adds the passed privilege to list if it's not in it, yet.
--
-- @param privilege: A privilege.
-- @type privilege: L{Privilege} object
-- """
-- inList = False
-- for priv in self.privileges:
-- if priv == privilege:
-- inList = True
-- if not inList:
-- newPrivilege = Privilege()
-- newPrivilege.copy(privilege)
-- self.privileges.append(newPrivilege)
--
-- def addPrivileges(self, privileges):
-- """
-- Adds the list of passed privileges to list.
--
-- @param privileges: Several privileges.
-- @type privileges: sequence of L{Privilege} objects
-- """
-- for priv in privileges:
-- self.addPrivilege(priv)
--
-- def delPrivilege(self, privilege):
-- """
-- Deletes the passed privilege from list if it's in it.
--
-- @param privilege: A privilege.
-- @type privilege: L{Privilege} object
--
-- @raise WebdavError: A L{WebdavError} is raised if the privilege to be
-- deleted is not present.
-- """
-- count = 0
-- index = 0
-- for priv in self.privileges:
-- count += 1
-- if priv == privilege:
-- index = count
-- if index:
-- self.privileges.pop(index - 1)
-- else:
-- raise WebdavError('Privilege to be deleted not in list: %s' % privilege)
--
-- def delPrivileges(self, privileges):
-- """
-- Deletes the list of passed privileges from list.
--
-- @param privileges: Several privileges.
-- @type privileges: sequence of L{Privilege} objects
-- """
-- for priv in privileges:
-- self.delPrivilege(priv)
--
-- def toXML(self):
-- """
-- Returns string of GrantDeny content to valid XML as described in WebDAV ACP.
-- """
-- assert self.privileges, "GrantDeny object is not initialized or does not contain content!"
--
-- if self.isGrant():
-- tag = 'D:' + Constants.TAG_GRANT
-- else:
-- tag = 'D:' + Constants.TAG_DENY
--
-- res = ''
-- for privilege in self.privileges:
-- res += privilege.toXML()
-- return '<%s>%s</%s>' % (tag, res, tag)
-diff --git a/src/webdav/acp/Makefile.am b/src/webdav/acp/Makefile.am
-deleted file mode 100644
-index 506eb92..0000000
---- a/src/webdav/acp/Makefile.am
-+++ /dev/null
-@@ -1,12 +0,0 @@
--sugardir = $(pythondir)/webdav/acp
--sugar_PYTHON = \
-- AceHandler.py \
-- Ace.py \
-- Acl.py \
-- GrantDeny.py \
-- __init__.py \
-- Principal.py \
-- Privilege.py
--
--
--
-diff --git a/src/webdav/acp/Principal.py b/src/webdav/acp/Principal.py
-deleted file mode 100644
-index a0d5ec9..0000000
---- a/src/webdav/acp/Principal.py
-+++ /dev/null
-@@ -1,189 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Handling of principals for ACEs according to WebDAV ACP specification.
--"""
--
--
--from webdav import Constants
--from webdav.Connection import WebdavError
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class Principal(object):
-- """
-- This class provides functionality for handling
-- principals according to the WebDAV ACP.
--
-- @ivar displayname: Name of the principal for output
-- @type displayname: C{string}
-- @ivar principalURL: URL under which the principal can be referenced on the server.
-- @type principalURL: C{string}
-- @ivar property: Information on type of a pseudo/jproperty principal, e. g.
-- DAV:owner, DAV:authenticated, etc.
-- @type property: C{string}
--
-- @cvar _TAG_LIST_PRINCIPALS: List of allowed XML tags within a principal declaration.
-- @type _TAG_LIST_PRINCIPALS: C{tuple} of C{string}s
-- @cvar _TAG_LIST_STATUS: List of XML tags for the status of a pseudo principal.
-- @type _TAG_LIST_STATUS: C{tuple} of C{string}s
-- """
--
-- # some local constants for this class to make things easier/more readable:
-- _TAG_LIST_PRINCIPALS = (Constants.TAG_HREF, # directly by URL
-- Constants.TAG_ALL, Constants.TAG_AUTHENTICATED, Constants.TAG_UNAUTHENTICATED,
-- # by log-in status
-- Constants.TAG_PROPERTY, # for property info, e. g. 'owner'
-- Constants.TAG_SELF, # only if the resource is the principal itself
-- Constants.TAG_PROP) # contains property info like 'displayname'
-- _TAG_LIST_STATUS = (Constants.TAG_ALL, Constants.TAG_AUTHENTICATED, Constants.TAG_UNAUTHENTICATED)
--
-- # restrict instance variables
-- __slots__ = ('displayname', 'principalURL', 'property')
--
-- def __init__(self, domroot=None, displayname=None, principalURL=None):
-- """
-- Constructor should be called with either no parameters (create blank Principal),
-- one parameter (a DOM tree), or two parameters (displayname and URL or property tag).
--
-- @param domroot: A DOM tree (default: None).
-- @type domroot: L{webdav.WebdavResponse.Element} object
-- @param displayname: The display name of a principal (default: None).
-- @type displayname: C{string}
-- @param principalURL: The URL representing a principal (default: None).
-- @type principalURL: C{string}
--
-- @raise WebdavError: When non-valid parameters or sets of parameters are
-- passed a L{WebdavError} is raised.
-- """
-- self.displayname = None
-- self.principalURL = None
-- self.property = None
--
-- if domroot:
-- for child in domroot.children:
-- if child.ns == Constants.NS_DAV and (child.name in self._TAG_LIST_PRINCIPALS):
-- if child.name == Constants.TAG_PROP:
-- self.displayname = \
-- child.find(Constants.PROP_DISPLAY_NAME, Constants.NS_DAV)
-- elif child.name == Constants.TAG_HREF:
-- self.principalURL = child.textof()
-- if self.principalURL and self.property in self._TAG_LIST_STATUS:
-- raise WebdavError('Principal cannot contain a URL and "%s"' % (self.property))
-- elif child.name == Constants.TAG_PROPERTY:
-- if child.count() == 1:
-- if self.property:
-- raise WebdavError('Property for principal has already been set: old "%s", new "%s"' \
-- % (self.property, child.pop().name))
-- elif self.principalURL:
-- raise WebdavError('Principal cannot contain a URL and "%s"' % (self.property))
-- else:
-- self.property = child.pop().name
-- else:
-- raise WebdavError("There should be only one value in the property for a principal, we have: %s" \
-- % child.name)
-- else:
-- if self.property:
-- raise WebdavError('Property for principal has already been set: old "%s", new "%s"' \
-- % (self.property, child.name))
-- else:
-- self.property = child.name
-- if self.principalURL and self.property in self._TAG_LIST_STATUS:
-- raise WebdavError('Principal cannot contain a URL and "%s"' % (self.property))
-- else: # This shouldn't happen, something's wrong with the DOM tree
-- raise WebdavError('Non-valid tag in principal DOM tree for constructor: %s' % child.name)
-- elif displayname == None or principalURL == None:
-- if displayname:
-- self.displayname = displayname
-- if principalURL:
-- self.principalURL = principalURL
-- else:
-- # This shouldn't happen, someone screwed up with the params ...
-- raise WebdavError('Non-valid parameters handed to Principal constructor.')
--
-- def __cmp__(self, other):
-- if not isinstance(other, Principal):
-- return 1
-- if self.displayname == other.displayname \
-- and self.principalURL == other.principalURL \
-- and self.property == other.property:
-- return 0
-- else:
-- return 1
--
-- def __repr__(self):
-- return '<class Principal: displayname: "%s", principalURL: "%s", property: "%s">' \
-- % (self.displayname, self.principalURL, self.property)
--
-- def copy(self, other):
-- """Copy Principal object.
--
-- @param other: Another principal to copy.
-- @type other: L{Principal} object
--
-- @raise WebdavError: When an object that is not a L{Principal} is passed
-- a L{WebdavError} is raised.
-- """
-- if not isinstance(other, Principal):
-- raise WebdavError('Non-Principal object passed to copy method: ' % other.__class__)
-- self.displayname = other.displayname
-- self.principalURL = other.principalURL
-- self.property = other.property
--
-- def isValid(self):
-- """
-- Checks whether necessarry props for principal are set.
--
-- @return: Validity of principal.
-- @rtype: C{bool}
-- """
-- return (self.displayname and
-- (self.principalURL or self.property) and
-- not (self.principalURL and self.property))
--
-- def toXML(self, invert=False, displayname=False, defaultNameSpace=None):
-- """Returns string of Principal content in valid XML as described in WebDAV ACP.
--
-- @param defaultNameSpace: Name space (default: None).
-- @type defaultNameSpace: C(string)
-- @param invert: True if principal should be inverted (default: False).
-- @type invert: C{bool}
-- @param displayname: True if displayname should be in output (default: False).
-- @type displayname: C{bool}
-- """
-- # this check is needed for setting principals only:
-- # assert self.isValid(), "principal is not initialized or does not contain valid content!"
--
-- PRINCIPAL = 'D:' + Constants.TAG_PRINCIPAL
-- res = ''
-- if self.principalURL:
-- res += '<D:%s>%s</D:%s>' % (Constants.TAG_HREF, self.principalURL, Constants.TAG_HREF)
-- elif self.property in self._TAG_LIST_STATUS \
-- or self.property == Constants.TAG_SELF:
-- res += '<D:%s/>' % (self.property)
-- elif self.property:
-- res += '<D:%s><D:%s/></D:%s>' \
-- % (Constants.TAG_PROPERTY, self.property, Constants.TAG_PROPERTY)
-- if self.displayname and displayname:
-- res += '<D:%s><D:%s>%s</D:%s></D:%s>' \
-- % (Constants.TAG_PROP, Constants.PROP_DISPLAY_NAME,
-- self.displayname,
-- Constants.PROP_DISPLAY_NAME, Constants.TAG_PROP)
-- if invert:
-- res = '<D:invert>%s</D:invert>' % (res)
-- return '<%s>%s</%s>' % (PRINCIPAL, res, PRINCIPAL)
-diff --git a/src/webdav/acp/Privilege.py b/src/webdav/acp/Privilege.py
-deleted file mode 100644
-index abfdcf9..0000000
---- a/src/webdav/acp/Privilege.py
-+++ /dev/null
-@@ -1,125 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--"""
--Handling for privileges for grant and deny clauses in ACEs
--according to WebDAV ACP specification.
--"""
--
--
--from webdav import Constants
--from webdav.Connection import WebdavError
--
--
--__version__ = "$LastChangedRevision$"
--
--
--class Privilege(object):
-- """This class provides functionality for handling privileges for ACEs.
--
-- @ivar name: Name of the privilege.
-- @type name: C{string}
--
-- @cvar __privileges: List of allowed XML tags for privileges.
-- @type __privileges: C{tuple} of C{string}s
-- """
--
--
-- __privileges = list()
--
--
-- def __init__(self, privilege=None, domroot=None):
-- """
-- Constructor should be called with either no parameters (create blank Privilege),
-- one parameter (a DOM tree or privilege name to initialize it directly).
--
-- @param domroot: A DOM tree (default: None).
-- @type domroot: L{webdav.WebdavResponse.Element} object
-- @param privilege: The valid name of a privilege (default: None).
-- @type privilege: C{string}
--
-- @raise WebdavError: When non-valid parameters or sets of parameters are
-- passed a L{WebdavError} is raised.
-- """
--
-- self.name = None
--
-- if domroot:
-- if len(domroot.children) != 1:
-- raise WebdavError('Wrong number of elements for Privilege constructor, we have: %i' \
-- % (len(domroot.children)))
-- else:
-- child = domroot.children[0]
-- if child.ns == Constants.NS_DAV and child.name in self.__privileges:
-- self.name = child.name
-- else:
-- raise WebdavError('Not a valid privilege tag, we have: %s%s' \
-- % (child.ns, child.name))
-- elif privilege:
-- if privilege in self.__privileges:
-- self.name = privilege
-- else:
-- raise WebdavError('Not a valid privilege tag, we have: %s.' % str(privilege))
--
-- @classmethod
-- def registerPrivileges(cls, privileges):
-- """
-- Registers supported privilege tags.
--
-- @param privileges: List of privilege tags.
-- @type privileges: C{list} of C{unicode}
-- """
--
-- for privilege in privileges:
-- cls.__privileges.append(privilege)
--
-- def __cmp__(self, other):
-- """ Compares two Privilege instances. """
-- if not isinstance(other, Privilege):
-- return 1
-- if self.name != other.name:
-- return 1
-- else:
-- return 0
--
-- def __repr__(self):
-- """ Returns the string representation of an instance. """
-- return '<class Privilege: name: "%s">' % (self.name)
--
-- def copy(self, other):
-- """
-- Copy Privilege object.
--
-- @param other: Another privilege to copy.
-- @type other: L{Privilege} object
--
-- @raise WebdavError: When an object that is not a L{Privilege} is passed
-- a L{WebdavError} is raised.
-- """
-- if not isinstance(other, Privilege):
-- raise WebdavError('Non-Privilege object passed to copy method: %s' % other.__class__)
-- self.name = other.name
--
-- def toXML(self):
-- """
-- Returns privilege content as string in valid XML as described in WebDAV ACP.
--
-- @param defaultNameSpace: Name space (default: None).
-- @type defaultNameSpace: C(string)
-- """
-- assert self.name != None, "privilege is not initialized or does not contain valid content!"
--
-- privilege = 'D:' + Constants.TAG_PRIVILEGE
-- return '<%s><D:%s/></%s>' % (privilege, self.name, privilege)
-diff --git a/src/webdav/acp/__init__.py b/src/webdav/acp/__init__.py
-deleted file mode 100644
-index b5af299..0000000
---- a/src/webdav/acp/__init__.py
-+++ /dev/null
-@@ -1,33 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--from webdav import Constants
--from webdav.acp.Acl import ACL
--from webdav.acp.Ace import ACE
--from webdav.acp.GrantDeny import GrantDeny
--from webdav.acp.Privilege import Privilege
--from webdav.acp.Principal import Principal
--
--
--__version__ = "$LastChangedRevision$"
--
--
--privileges = [Constants.TAG_READ, Constants.TAG_WRITE, Constants.TAG_WRITE_PROPERTIES,
-- Constants.TAG_WRITE_CONTENT, Constants.TAG_UNLOCK, Constants.TAG_READ_ACL,
-- Constants.TAG_READ_CURRENT_USER_PRIVILEGE_SET, Constants.TAG_WRITE_ACL, Constants.TAG_ALL,
-- Constants.TAG_BIND, Constants.TAG_UNBIND, Constants.TAG_TAMINO_SECURITY,
-- Constants.TAG_BIND_COLLECTION, Constants.TAG_UNBIND_COLLECTION, Constants.TAG_READ_PRIVATE_PROPERTIES,
-- Constants.TAG_WRITE_PRIVATE_PROPERTIES]
--Privilege.registerPrivileges(privileges)
-diff --git a/src/webdav/davlib.py b/src/webdav/davlib.py
-deleted file mode 100644
-index f4dac91..0000000
---- a/src/webdav/davlib.py
-+++ /dev/null
-@@ -1,336 +0,0 @@
--# pylint: disable-msg=W0402,W0231,W0141,R0903,C0321,W0701,R0904,C0103,W0201,W0102,R0913,W0622,E1101,C0111,C0121,R0901
--# DAV client library
--#
--# Copyright (C) 1998-2000 Guido van Rossum. All Rights Reserved.
--# Written by Greg Stein. Given to Guido. Licensed using the Python license.
--#
--# This module is maintained by Greg and is available at:
--# http://www.lyra.org/greg/python/davlib.py
--#
--# Since this isn't in the Python distribution yet, we'll use the CVS ID
--# for tracking:
--# $Id: davlib.py 3182 2008-02-22 15:57:55 +0000 (Fr, 22 Feb 2008) schlauch $
--#
--
--import httplib
--import urllib
--import string
--import types
--import mimetypes
--import qp_xml
--
--
--INFINITY = 'infinity'
--XML_DOC_HEADER = '<?xml version="1.0" encoding="utf-8"?>'
--XML_CONTENT_TYPE = 'text/xml; charset="utf-8"'
--
--# block size for copying files up to the server
--BLOCKSIZE = 16384
--
--
--class HTTPProtocolChooser(httplib.HTTPSConnection):
-- def __init__(self, *args, **kw):
-- self.protocol = kw.pop('protocol')
-- if self.protocol == "https":
-- self.default_port = 443
-- else:
-- self.default_port = 80
--
-- apply(httplib.HTTPSConnection.__init__, (self,) + args, kw)
--
-- def connect(self):
-- if self.protocol == "https":
-- httplib.HTTPSConnection.connect(self)
-- else:
-- httplib.HTTPConnection.connect(self)
--
--
--class HTTPConnectionAuth(HTTPProtocolChooser):
-- def __init__(self, *args, **kw):
-- apply(HTTPProtocolChooser.__init__, (self,) + args, kw)
--
-- self.__username = None
-- self.__password = None
-- self.__nonce = None
-- self.__opaque = None
--
-- def setauth(self, username, password):
-- self.__username = username
-- self.__password = password
--
--
--def _parse_status(elem):
-- text = elem.textof()
-- idx1 = string.find(text, ' ')
-- idx2 = string.find(text, ' ', idx1+1)
-- return int(text[idx1:idx2]), text[idx2+1:]
--
--class _blank:
-- def __init__(self, **kw):
-- self.__dict__.update(kw)
--class _propstat(_blank): pass
--class _response(_blank): pass
--class _multistatus(_blank): pass
--
--def _extract_propstat(elem):
-- ps = _propstat(prop={}, status=None, responsedescription=None)
-- for child in elem.children:
-- if child.ns != 'DAV:':
-- continue
-- if child.name == 'prop':
-- for prop in child.children:
-- ps.prop[(prop.ns, prop.name)] = prop
-- elif child.name == 'status':
-- ps.status = _parse_status(child)
-- elif child.name == 'responsedescription':
-- ps.responsedescription = child.textof()
-- ### unknown element name
--
-- return ps
--
--def _extract_response(elem):
-- resp = _response(href=[], status=None, responsedescription=None, propstat=[])
-- for child in elem.children:
-- if child.ns != 'DAV:':
-- continue
-- if child.name == 'href':
-- resp.href.append(child.textof())
-- elif child.name == 'status':
-- resp.status = _parse_status(child)
-- elif child.name == 'responsedescription':
-- resp.responsedescription = child.textof()
-- elif child.name == 'propstat':
-- resp.propstat.append(_extract_propstat(child))
-- ### unknown child element
--
-- return resp
--
--def _extract_msr(root):
-- if root.ns != 'DAV:' or root.name != 'multistatus':
-- raise 'invalid response: <DAV:multistatus> expected'
--
-- msr = _multistatus(responses=[ ], responsedescription=None)
--
-- for child in root.children:
-- if child.ns != 'DAV:':
-- continue
-- if child.name == 'responsedescription':
-- msr.responsedescription = child.textof()
-- elif child.name == 'response':
-- msr.responses.append(_extract_response(child))
-- ### unknown child element
--
-- return msr
--
--def _extract_locktoken(root):
-- if root.ns != 'DAV:' or root.name != 'prop':
-- raise 'invalid response: <DAV:prop> expected'
-- elem = root.find('lockdiscovery', 'DAV:')
-- if not elem:
-- raise 'invalid response: <DAV:lockdiscovery> expected'
-- elem = elem.find('activelock', 'DAV:')
-- if not elem:
-- raise 'invalid response: <DAV:activelock> expected'
-- elem = elem.find('locktoken', 'DAV:')
-- if not elem:
-- raise 'invalid response: <DAV:locktoken> expected'
-- elem = elem.find('href', 'DAV:')
-- if not elem:
-- raise 'invalid response: <DAV:href> expected'
-- return elem.textof()
--
--
--class DAVResponse(httplib.HTTPResponse):
-- def parse_multistatus(self):
-- self.root = qp_xml.Parser().parse(self)
-- self.msr = _extract_msr(self.root)
--
-- def parse_lock_response(self):
-- self.root = qp_xml.Parser().parse(self)
-- self.locktoken = _extract_locktoken(self.root)
--
--
--class DAV(HTTPConnectionAuth):
--
-- response_class = DAVResponse
--
-- def get(self, url, extra_hdrs={ }):
-- return self._request('GET', url, extra_hdrs=extra_hdrs)
--
-- def head(self, url, extra_hdrs={ }):
-- return self._request('HEAD', url, extra_hdrs=extra_hdrs)
--
-- def post(self, url, data={ }, body=None, extra_hdrs={ }):
-- headers = extra_hdrs.copy()
--
-- assert body or data, "body or data must be supplied"
-- assert not (body and data), "cannot supply both body and data"
-- if data:
-- body = ''
-- for key, value in data.items():
-- if isinstance(value, types.ListType):
-- for item in value:
-- body = body + '&' + key + '=' + urllib.quote(str(item))
-- else:
-- body = body + '&' + key + '=' + urllib.quote(str(value))
-- body = body[1:]
-- headers['Content-Type'] = 'application/x-www-form-urlencoded'
--
-- return self._request('POST', url, body, headers)
--
-- def options(self, url='*', extra_hdrs={ }):
-- return self._request('OPTIONS', url, extra_hdrs=extra_hdrs)
--
-- def trace(self, url, extra_hdrs={ }):
-- return self._request('TRACE', url, extra_hdrs=extra_hdrs)
--
-- def put(self, url, contents,
-- content_type=None, content_enc=None, extra_hdrs={ }):
--
-- if not content_type:
-- content_type, content_enc = mimetypes.guess_type(url)
--
-- headers = extra_hdrs.copy()
-- if content_type:
-- headers['Content-Type'] = content_type
-- if content_enc:
-- headers['Content-Encoding'] = content_enc
-- return self._request('PUT', url, contents, headers)
--
-- def delete(self, url, extra_hdrs={ }):
-- return self._request('DELETE', url, extra_hdrs=extra_hdrs)
--
-- def propfind(self, url, body=None, depth=None, extra_hdrs={ }):
-- headers = extra_hdrs.copy()
-- headers['Content-Type'] = XML_CONTENT_TYPE
-- if depth is not None:
-- headers['Depth'] = str(depth)
-- return self._request('PROPFIND', url, body, headers)
--
-- def proppatch(self, url, body, extra_hdrs={ }):
-- headers = extra_hdrs.copy()
-- headers['Content-Type'] = XML_CONTENT_TYPE
-- return self._request('PROPPATCH', url, body, headers)
--
-- def mkcol(self, url, extra_hdrs={ }):
-- return self._request('MKCOL', url, extra_hdrs=extra_hdrs)
--
-- def move(self, src, dst, extra_hdrs={ }):
-- headers = extra_hdrs.copy()
-- headers['Destination'] = dst
-- return self._request('MOVE', src, extra_hdrs=headers)
--
-- def copy(self, src, dst, depth=None, extra_hdrs={ }):
-- headers = extra_hdrs.copy()
-- headers['Destination'] = dst
-- if depth is not None:
-- headers['Depth'] = str(depth)
-- return self._request('COPY', src, extra_hdrs=headers)
--
-- def lock(self, url, owner='', timeout=None, depth=None,
-- scope='exclusive', type='write', extra_hdrs={ }):
-- headers = extra_hdrs.copy()
-- headers['Content-Type'] = XML_CONTENT_TYPE
-- if depth is not None:
-- headers['Depth'] = str(depth)
-- if timeout is not None:
-- headers['Timeout'] = timeout
-- body = XML_DOC_HEADER + \
-- '<DAV:lockinfo xmlns:DAV="DAV:">' + \
-- '<DAV:lockscope><DAV:%s/></DAV:lockscope>' % scope + \
-- '<DAV:locktype><DAV:%s/></DAV:locktype>' % type + \
-- '<DAV:owner>' + owner + '</DAV:owner>' + \
-- '</DAV:lockinfo>'
-- return self._request('LOCK', url, body, extra_hdrs=headers)
--
-- def unlock(self, url, locktoken, extra_hdrs={ }):
-- headers = extra_hdrs.copy()
-- if locktoken[0] != '<':
-- locktoken = '<' + locktoken + '>'
-- headers['Lock-Token'] = locktoken
-- return self._request('UNLOCK', url, extra_hdrs=headers)
--
-- def _request(self, method, url, body=None, extra_hdrs={}):
-- "Internal method for sending a request."
--
-- self.request(method, url, body, extra_hdrs)
-- return self.getresponse()
--
--
-- #
-- # Higher-level methods for typical client use
-- #
--
-- def allprops(self, url, depth=None):
-- body = XML_DOC_HEADER + \
-- '<DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
-- return self.propfind(url, body, depth=depth)
--
-- def propnames(self, url, depth=None):
-- body = XML_DOC_HEADER + \
-- '<DAV:propfind xmlns:DAV="DAV:"><DAV:propname/></DAV:propfind>'
-- return self.propfind(url, body, depth)
--
-- def getprops(self, url, *names, **kw):
-- assert names, 'at least one property name must be provided'
-- if kw.has_key('ns'):
-- xmlns = ' xmlns:NS="' + kw['ns'] + '"'
-- ns = 'NS:'
-- del kw['ns']
-- else:
-- xmlns = ns = ''
-- if kw.has_key('depth'):
-- depth = kw['depth']
-- del kw['depth']
-- else:
-- depth = 0
-- assert not kw, 'unknown arguments'
-- body = XML_DOC_HEADER + \
-- '<DAV:propfind xmlns:DAV="DAV:"' + xmlns + '><DAV:prop><' + ns + \
-- string.joinfields(names, '/><' + ns) + \
-- '/></DAV:prop></DAV:propfind>'
-- return self.propfind(url, body, depth)
--
-- def delprops(self, url, *names, **kw):
-- assert names, 'at least one property name must be provided'
-- if kw.has_key('ns'):
-- xmlns = ' xmlns:NS="' + kw['ns'] + '"'
-- ns = 'NS:'
-- del kw['ns']
-- else:
-- xmlns = ns = ''
-- assert not kw, 'unknown arguments'
-- body = XML_DOC_HEADER + \
-- '<DAV:propertyupdate xmlns:DAV="DAV:"' + xmlns + \
-- '><DAV:remove><DAV:prop><' + ns + \
-- string.joinfields(names, '/><' + ns) + \
-- '/></DAV:prop></DAV:remove></DAV:propertyupdate>'
-- return self.proppatch(url, body)
--
-- def setprops(self, url, *xmlprops, **props):
-- assert xmlprops or props, 'at least one property must be provided'
-- xmlprops = list(xmlprops)
-- if props.has_key('ns'):
-- xmlns = ' xmlns:NS="' + props['ns'] + '"'
-- ns = 'NS:'
-- del props['ns']
-- else:
-- xmlns = ns = ''
-- for key, value in props.items():
-- if value:
-- xmlprops.append('<%s%s>%s</%s%s>' % (ns, key, value, ns, key))
-- else:
-- xmlprops.append('<%s%s/>' % (ns, key))
-- elems = string.joinfields(xmlprops, '')
-- body = XML_DOC_HEADER + \
-- '<DAV:propertyupdate xmlns:DAV="DAV:"' + xmlns + \
-- '><DAV:set><DAV:prop>' + \
-- elems + \
-- '</DAV:prop></DAV:set></DAV:propertyupdate>'
-- return self.proppatch(url, body)
--
-- def get_lock(self, url, owner='', timeout=None, depth=None):
-- response = self.lock(url, owner, timeout, depth)
-- response.parse_lock_response()
-- return response.locktoken
--
-\ No newline at end of file
-diff --git a/src/webdav/logger.py b/src/webdav/logger.py
-deleted file mode 100644
-index d2538ef..0000000
---- a/src/webdav/logger.py
-+++ /dev/null
-@@ -1,51 +0,0 @@
--# Copyright 2008 German Aerospace Center (DLR)
--#
--# Licensed under the Apache License, Version 2.0 (the "License");
--# you may not use this file except in compliance with the License.
--# You may obtain a copy of the License at
--#
--# http://www.apache.org/licenses/LICENSE-2.0
--#
--# Unless required by applicable law or agreed to in writing, software
--# distributed under the License is distributed on an "AS IS" BASIS,
--# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--# See the License for the specific language governing permissions and
--# limitations under the License.
--
--
--""""
--Module provides access to a configured logger instance.
--The logger writes C{sys.stdout}.
--"""
--
--
--import logging
--import sys
--
--
--__version__ = "$LastChangedRevision$"[11:-2]
--
--
--_defaultLoggerName = "webdavLogger"
--_fileLogFormat = "%(asctime)s: %(levelname)s: %(message)s"
--
--
--def getDefaultLogger(handler=None):
-- """
-- Returns a configured logger object.
--
-- @return: Logger instance.
-- @rtype: C{logging.Logger}
-- """
--
-- myLogger = logging.getLogger(_defaultLoggerName)
-- if len(myLogger.handlers) == 0:
-- myLogger.level = logging.DEBUG
-- formatter = logging.Formatter(_fileLogFormat)
-- if handler is None:
-- stdoutHandler = logging.StreamHandler(sys.stdout)
-- stdoutHandler.setFormatter(formatter)
-- myLogger.addHandler(stdoutHandler)
-- else:
-- myLogger.addHandler(handler)
-- return myLogger
-diff --git a/src/webdav/qp_xml.py b/src/webdav/qp_xml.py
-deleted file mode 100644
-index f167e1b..0000000
---- a/src/webdav/qp_xml.py
-+++ /dev/null
-@@ -1,240 +0,0 @@
--# pylint: disable-msg=W0311,E1101,E1103,W0201,C0103,W0622,W0402,W0706,R0911,W0613,W0612,R0912,W0141,C0111,C0121
--
--# qp_xml: Quick Parsing for XML
--#
--# Written by Greg Stein. Public Domain.
--# No Copyright, no Rights Reserved, and no Warranties.
--#
--# This module is maintained by Greg and is available as part of the XML-SIG
--# distribution. This module and its changelog can be fetched at:
--# http://www.lyra.org/cgi-bin/viewcvs.cgi/xml/xml/utils/qp_xml.py
--#
--# Additional information can be found on Greg's Python page at:
--# http://www.lyra.org/greg/python/
--#
--# This module was added to the XML-SIG distribution on February 14, 2000.
--# As part of that distribution, it falls under the XML distribution license.
--#
--
--import string
--from xml.parsers import expat
--
--
--error = __name__ + '.error'
--
--
--#
--# The parsing class. Instantiate and pass a string/file to .parse()
--#
--class Parser:
-- def __init__(self):
-- self.reset()
--
-- def reset(self):
-- self.root = None
-- self.cur_elem = None
--
-- def find_prefix(self, prefix):
-- elem = self.cur_elem
-- while elem:
-- if elem.ns_scope.has_key(prefix):
-- return elem.ns_scope[prefix]
-- elem = elem.parent
--
-- if prefix == '':
-- return '' # empty URL for "no namespace"
--
-- return None
--
-- def process_prefix(self, name, use_default):
-- idx = string.find(name, ':')
-- if idx == -1:
-- if use_default:
-- return self.find_prefix(''), name
-- return '', name # no namespace
--
-- if string.lower(name[:3]) == 'xml':
-- return '', name # name is reserved by XML. don't break out a NS.
--
-- ns = self.find_prefix(name[:idx])
-- if ns is None:
-- raise error, 'namespace prefix ("%s") not found' % name[:idx]
--
-- return ns, name[idx+1:]
--
-- def start(self, name, attrs):
-- elem = _element(name=name, lang=None, parent=None,
-- children=[], ns_scope={}, attrs={},
-- first_cdata='', following_cdata='')
--
-- if self.cur_elem:
-- elem.parent = self.cur_elem
-- elem.parent.children.append(elem)
-- self.cur_elem = elem
-- else:
-- self.cur_elem = self.root = elem
--
-- work_attrs = [ ]
--
-- # scan for namespace declarations (and xml:lang while we're at it)
-- for name, value in attrs.items():
-- if name == 'xmlns':
-- elem.ns_scope[''] = value
-- elif name[:6] == 'xmlns:':
-- elem.ns_scope[name[6:]] = value
-- elif name == 'xml:lang':
-- elem.lang = value
-- else:
-- work_attrs.append((name, value))
--
-- # inherit xml:lang from parent
-- if elem.lang is None and elem.parent:
-- elem.lang = elem.parent.lang
--
-- # process prefix of the element name
-- elem.ns, elem.name = self.process_prefix(elem.name, 1)
--
-- # process attributes' namespace prefixes
-- for name, value in work_attrs:
-- elem.attrs[self.process_prefix(name, 0)] = value
--
-- def end(self, name):
-- parent = self.cur_elem.parent
--
-- del self.cur_elem.ns_scope
-- del self.cur_elem.parent
--
-- self.cur_elem = parent
--
-- def cdata(self, data):
-- elem = self.cur_elem
-- if elem.children:
-- last = elem.children[-1]
-- last.following_cdata = last.following_cdata + data
-- else:
-- elem.first_cdata = elem.first_cdata + data
--
-- def parse(self, input):
-- self.reset()
--
-- p = expat.ParserCreate()
-- p.StartElementHandler = self.start
-- p.EndElementHandler = self.end
-- p.CharacterDataHandler = self.cdata
--
-- try:
-- if type(input) == type(''):
-- p.Parse(input, 1)
-- else:
-- while 1:
-- s = input.read(_BLOCKSIZE)
-- if not s:
-- p.Parse('', 1)
-- break
--
-- p.Parse(s, 0)
--
-- finally:
-- if self.root:
-- _clean_tree(self.root)
--
-- return self.root
--
--
--#
--# handy function for dumping a tree that is returned by Parser
--#
--def dump(f, root):
-- f.write('<?xml version="1.0"?>\n')
-- namespaces = _collect_ns(root)
-- _dump_recurse(f, root, namespaces, dump_ns=1)
-- f.write('\n')
--
--
--#
--# This function returns the element's CDATA. Note: this is not recursive --
--# it only returns the CDATA immediately within the element, excluding the
--# CDATA in child elements.
--#
--def textof(elem):
-- return elem.textof()
--
--
--#########################################################################
--#
--# private stuff for qp_xml
--#
--
--_BLOCKSIZE = 16384 # chunk size for parsing input
--
--class _element:
-- def __init__(self, **kw):
-- self.__dict__.update(kw)
--
-- def textof(self):
-- '''Return the CDATA of this element.
--
-- Note: this is not recursive -- it only returns the CDATA immediately
-- within the element, excluding the CDATA in child elements.
-- '''
-- s = self.first_cdata
-- for child in self.children:
-- s = s + child.following_cdata
-- return s
--
-- def find(self, name, ns=''):
-- for elem in self.children:
-- if elem.name == name and elem.ns == ns:
-- return elem
-- return None
--
--
--def _clean_tree(elem):
-- elem.parent = None
-- del elem.parent
-- map(_clean_tree, elem.children)
--
--
--def _collect_recurse(elem, dict):
-- dict[elem.ns] = None
-- for ns, name in elem.attrs.keys():
-- dict[ns] = None
-- for child in elem.children:
-- _collect_recurse(child, dict)
--
--def _collect_ns(elem):
-- "Collect all namespaces into a NAMESPACE -> PREFIX mapping."
-- d = { '' : None }
-- _collect_recurse(elem, d)
-- del d[''] # make sure we don't pick up no-namespace entries
-- keys = d.keys()
-- for i in range(len(keys)):
-- d[keys[i]] = i
-- return d
--
--def _dump_recurse(f, elem, namespaces, lang=None, dump_ns=0):
-- if elem.ns:
-- f.write('<ns%d:%s' % (namespaces[elem.ns], elem.name))
-- else:
-- f.write('<' + elem.name)
-- for (ns, name), value in elem.attrs.items():
-- if ns:
-- f.write(' ns%d:%s="%s"' % (namespaces[ns], name, value))
-- else:
-- f.write(' %s="%s"' % (name, value))
-- if dump_ns:
-- for ns, id in namespaces.items():
-- f.write(' xmlns:ns%d="%s"' % (id, ns))
-- if elem.lang != lang:
-- f.write(' xml:lang="%s"' % elem.lang)
-- if elem.children or elem.first_cdata:
-- f.write('>' + elem.first_cdata)
-- for child in elem.children:
-- _dump_recurse(f, child, namespaces, elem.lang)
-- f.write(child.following_cdata)
-- if elem.ns:
-- f.write('</ns%d:%s>' % (namespaces[elem.ns], elem.name))
-- else:
-- f.write('</%s>' % elem.name)
-- else:
-- f.write('/>')
-diff --git a/src/webdav/uuid_.py b/src/webdav/uuid_.py
-deleted file mode 100644
-index 3b590e8..0000000
---- a/src/webdav/uuid_.py
-+++ /dev/null
-@@ -1,476 +0,0 @@
--r"""UUID objects (universally unique identifiers) according to RFC 4122.
--
--This module provides immutable UUID objects (class UUID) and the functions
--uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
--UUIDs as specified in RFC 4122.
--
--If all you want is a unique ID, you should probably call uuid1() or uuid4().
--Note that uuid1() may compromise privacy since it creates a UUID containing
--the computer's network address. uuid4() creates a random UUID.
--
--Typical usage:
--
-- >>> import uuid
--
-- # make a UUID based on the host ID and current time
-- >>> uuid.uuid1()
-- UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
--
-- # make a UUID using an MD5 hash of a namespace UUID and a name
-- >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
-- UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
--
-- # make a random UUID
-- >>> uuid.uuid4()
-- UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
--
-- # make a UUID using a SHA-1 hash of a namespace UUID and a name
-- >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
-- UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
--
-- # make a UUID from a string of hex digits (braces and hyphens ignored)
-- >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
--
-- # convert a UUID to a string of hex digits in standard form
-- >>> str(x)
-- '00010203-0405-0607-0809-0a0b0c0d0e0f'
--
-- # get the raw 16 bytes of the UUID
-- >>> x.bytes
-- '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
--
-- # make a UUID from a 16-byte string
-- >>> uuid.UUID(bytes=x.bytes)
-- UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
--"""
--
--__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
--__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
--__version__ = '$Revision: 1.30 $'.split()[1]
--
--RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
-- 'reserved for NCS compatibility', 'specified in RFC 4122',
-- 'reserved for Microsoft compatibility', 'reserved for future definition']
--
--class UUID(object):
-- """Instances of the UUID class represent UUIDs as specified in RFC 4122.
-- UUID objects are immutable, hashable, and usable as dictionary keys.
-- Converting a UUID to a string with str() yields something in the form
-- '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
-- four possible forms: a similar string of hexadecimal digits, or a
-- string of 16 raw bytes as an argument named 'bytes', or a tuple of
-- six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
-- 48-bit values respectively) as an argument named 'fields', or a single
-- 128-bit integer as an argument named 'int'.
--
-- UUIDs have these read-only attributes:
--
-- bytes the UUID as a 16-byte string
--
-- fields a tuple of the six integer fields of the UUID,
-- which are also available as six individual attributes
-- and two derived attributes:
--
-- time_low the first 32 bits of the UUID
-- time_mid the next 16 bits of the UUID
-- time_hi_version the next 16 bits of the UUID
-- clock_seq_hi_variant the next 8 bits of the UUID
-- clock_seq_low the next 8 bits of the UUID
-- node the last 48 bits of the UUID
--
-- time the 60-bit timestamp
-- clock_seq the 14-bit sequence number
--
-- hex the UUID as a 32-character hexadecimal string
--
-- int the UUID as a 128-bit integer
--
-- urn the UUID as a URN as specified in RFC 4122
--
-- variant the UUID variant (one of the constants RESERVED_NCS,
-- RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
--
-- version the UUID version number (1 through 5, meaningful only
-- when the variant is RFC_4122)
-- """
--
-- def __init__(self, hex=None, bytes=None, fields=None, int=None,
-- version=None):
-- r"""Create a UUID from either a string of 32 hexadecimal digits,
-- a string of 16 bytes as the 'bytes' argument, a tuple of six
-- integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
-- 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
-- the 'fields' argument, or a single 128-bit integer as the 'int'
-- argument. When a string of hex digits is given, curly braces,
-- hyphens, and a URN prefix are all optional. For example, these
-- expressions all yield the same UUID:
--
-- UUID('{12345678-1234-5678-1234-567812345678}')
-- UUID('12345678123456781234567812345678')
-- UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
-- UUID(bytes='\x12\x34\x56\x78'*4)
-- UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
-- UUID(int=0x12345678123456781234567812345678)
--
-- Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
-- The 'version' argument is optional; if given, the resulting UUID
-- will have its variant and version number set according to RFC 4122,
-- overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
-- """
--
-- if [hex, bytes, fields, int].count(None) != 3:
-- raise TypeError('need just one of hex, bytes, fields, or int')
-- if hex is not None:
-- hex = hex.replace('urn:', '').replace('uuid:', '')
-- hex = hex.strip('{}').replace('-', '')
-- if len(hex) != 32:
-- raise ValueError('badly formed hexadecimal UUID string')
-- int = long(hex, 16)
-- if bytes is not None:
-- if len(bytes) != 16:
-- raise ValueError('bytes is not a 16-char string')
-- int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
-- if fields is not None:
-- if len(fields) != 6:
-- raise ValueError('fields is not a 6-tuple')
-- (time_low, time_mid, time_hi_version,
-- clock_seq_hi_variant, clock_seq_low, node) = fields
-- if not 0 <= time_low < 1<<32L:
-- raise ValueError('field 1 out of range (need a 32-bit value)')
-- if not 0 <= time_mid < 1<<16L:
-- raise ValueError('field 2 out of range (need a 16-bit value)')
-- if not 0 <= time_hi_version < 1<<16L:
-- raise ValueError('field 3 out of range (need a 16-bit value)')
-- if not 0 <= clock_seq_hi_variant < 1<<8L:
-- raise ValueError('field 4 out of range (need an 8-bit value)')
-- if not 0 <= clock_seq_low < 1<<8L:
-- raise ValueError('field 5 out of range (need an 8-bit value)')
-- if not 0 <= node < 1<<48L:
-- raise ValueError('field 6 out of range (need a 48-bit value)')
-- clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
-- int = ((time_low << 96L) | (time_mid << 80L) |
-- (time_hi_version << 64L) | (clock_seq << 48L) | node)
-- if int is not None:
-- if not 0 <= int < 1<<128L:
-- raise ValueError('int is out of range (need a 128-bit value)')
-- if version is not None:
-- if not 1 <= version <= 5:
-- raise ValueError('illegal version number')
-- # Set the variant to RFC 4122.
-- int &= ~(0xc000 << 48L)
-- int |= 0x8000 << 48L
-- # Set the version number.
-- int &= ~(0xf000 << 64L)
-- int |= version << 76L
-- self.__dict__['int'] = int
--
-- def __cmp__(self, other):
-- if isinstance(other, UUID):
-- return cmp(self.int, other.int)
-- return NotImplemented
--
-- def __hash__(self):
-- return hash(self.int)
--
-- def __int__(self):
-- return self.int
--
-- def __repr__(self):
-- return 'UUID(%r)' % str(self)
--
-- def __setattr__(self, name, value):
-- raise TypeError('UUID objects are immutable')
--
-- def __str__(self):
-- hex = '%032x' % self.int
-- return '%s-%s-%s-%s-%s' % (
-- hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
--
-- def get_bytes(self):
-- bytes = ''
-- for shift in range(0, 128, 8):
-- bytes = chr((self.int >> shift) & 0xff) + bytes
-- return bytes
--
-- bytes = property(get_bytes)
--
-- def get_fields(self):
-- return (self.time_low, self.time_mid, self.time_hi_version,
-- self.clock_seq_hi_variant, self.clock_seq_low, self.node)
--
-- fields = property(get_fields)
--
-- def get_time_low(self):
-- return self.int >> 96L
--
-- time_low = property(get_time_low)
--
-- def get_time_mid(self):
-- return (self.int >> 80L) & 0xffff
--
-- time_mid = property(get_time_mid)
--
-- def get_time_hi_version(self):
-- return (self.int >> 64L) & 0xffff
--
-- time_hi_version = property(get_time_hi_version)
--
-- def get_clock_seq_hi_variant(self):
-- return (self.int >> 56L) & 0xff
--
-- clock_seq_hi_variant = property(get_clock_seq_hi_variant)
--
-- def get_clock_seq_low(self):
-- return (self.int >> 48L) & 0xff
--
-- clock_seq_low = property(get_clock_seq_low)
--
-- def get_time(self):
-- return (((self.time_hi_version & 0x0fffL) << 48L) |
-- (self.time_mid << 32L) | self.time_low)
--
-- time = property(get_time)
--
-- def get_clock_seq(self):
-- return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
-- self.clock_seq_low)
--
-- clock_seq = property(get_clock_seq)
--
-- def get_node(self):
-- return self.int & 0xffffffffffff
--
-- node = property(get_node)
--
-- def get_hex(self):
-- return '%032x' % self.int
--
-- hex = property(get_hex)
--
-- def get_urn(self):
-- return 'urn:uuid:' + str(self)
--
-- urn = property(get_urn)
--
-- def get_variant(self):
-- if not self.int & (0x8000 << 48L):
-- return RESERVED_NCS
-- elif not self.int & (0x4000 << 48L):
-- return RFC_4122
-- elif not self.int & (0x2000 << 48L):
-- return RESERVED_MICROSOFT
-- else:
-- return RESERVED_FUTURE
--
-- variant = property(get_variant)
--
-- def get_version(self):
-- # The version bits are only meaningful for RFC 4122 UUIDs.
-- if self.variant == RFC_4122:
-- return int((self.int >> 76L) & 0xf)
--
-- version = property(get_version)
--
--def _ifconfig_getnode():
-- """Get the hardware address on Unix by running ifconfig."""
-- import os
-- for dir in ['', '/sbin/', '/usr/sbin']:
-- try:
-- pipe = os.popen(os.path.join(dir, 'ifconfig'))
-- except IOError:
-- continue
-- for line in pipe:
-- words = line.lower().split()
-- for i in range(len(words)):
-- if words[i] in ['hwaddr', 'ether']:
-- return int(words[i + 1].replace(':', ''), 16)
--
--def _ipconfig_getnode():
-- """Get the hardware address on Windows by running ipconfig.exe."""
-- import os, re
-- dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
-- try:
-- import ctypes
-- buffer = ctypes.create_string_buffer(300)
-- ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
-- dirs.insert(0, buffer.value.decode('mbcs'))
-- except:
-- pass
-- for dir in dirs:
-- try:
-- pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
-- except IOError:
-- continue
-- for line in pipe:
-- value = line.split(':')[-1].strip().lower()
-- if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
-- return int(value.replace('-', ''), 16)
--
--def _netbios_getnode():
-- """Get the hardware address on Windows using NetBIOS calls.
-- See http://support.microsoft.com/kb/118623 for details."""
-- import win32wnet, netbios
-- ncb = netbios.NCB()
-- ncb.Command = netbios.NCBENUM
-- ncb.Buffer = adapters = netbios.LANA_ENUM()
-- adapters._pack()
-- if win32wnet.Netbios(ncb) != 0:
-- return
-- adapters._unpack()
-- for i in range(adapters.length):
-- ncb.Reset()
-- ncb.Command = netbios.NCBRESET
-- ncb.Lana_num = ord(adapters.lana[i])
-- if win32wnet.Netbios(ncb) != 0:
-- continue
-- ncb.Reset()
-- ncb.Command = netbios.NCBASTAT
-- ncb.Lana_num = ord(adapters.lana[i])
-- ncb.Callname = '*'.ljust(16)
-- ncb.Buffer = status = netbios.ADAPTER_STATUS()
-- if win32wnet.Netbios(ncb) != 0:
-- continue
-- status._unpack()
-- bytes = map(ord, status.adapter_address)
-- return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
-- (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
--
--# Thanks to Thomas Heller for ctypes and for his help with its use here.
--
--# If ctypes is available, use it to find system routines for UUID generation.
--_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
--try:
-- import ctypes, ctypes.util
-- _buffer = ctypes.create_string_buffer(16)
--
-- # The uuid_generate_* routines are provided by libuuid on at least
-- # Linux and FreeBSD, and provided by libc on Mac OS X.
-- for libname in ['uuid', 'c']:
-- try:
-- lib = ctypes.CDLL(ctypes.util.find_library(libname))
-- except:
-- continue
-- if hasattr(lib, 'uuid_generate_random'):
-- _uuid_generate_random = lib.uuid_generate_random
-- if hasattr(lib, 'uuid_generate_time'):
-- _uuid_generate_time = lib.uuid_generate_time
--
-- # On Windows prior to 2000, UuidCreate gives a UUID containing the
-- # hardware address. On Windows 2000 and later, UuidCreate makes a
-- # random UUID and UuidCreateSequential gives a UUID containing the
-- # hardware address. These routines are provided by the RPC runtime.
-- try:
-- lib = ctypes.windll.rpcrt4
-- except:
-- lib = None
-- _UuidCreate = getattr(lib, 'UuidCreateSequential',
-- getattr(lib, 'UuidCreate', None))
--except:
-- pass
--
--def _unixdll_getnode():
-- """Get the hardware address on Unix using ctypes."""
-- _uuid_generate_time(_buffer)
-- return UUID(bytes=_buffer.raw).node
--
--def _windll_getnode():
-- """Get the hardware address on Windows using ctypes."""
-- if _UuidCreate(_buffer) == 0:
-- return UUID(bytes=_buffer.raw).node
--
--def _random_getnode():
-- """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
-- import random
-- return random.randrange(0, 1<<48L) | 0x010000000000L
--
--_node = None
--
--def getnode():
-- """Get the hardware address as a 48-bit integer. The first time this
-- runs, it may launch a separate program, which could be quite slow. If
-- all attempts to obtain the hardware address fail, we choose a random
-- 48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
--
-- global _node
-- if _node is not None:
-- return _node
--
-- import sys
-- if sys.platform == 'win32':
-- getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
-- else:
-- getters = [_unixdll_getnode, _ifconfig_getnode]
--
-- for getter in getters + [_random_getnode]:
-- try:
-- _node = getter()
-- except:
-- continue
-- if _node is not None:
-- return _node
--
--def uuid1(node=None, clock_seq=None):
-- """Generate a UUID from a host ID, sequence number, and the current time.
-- If 'node' is not given, getnode() is used to obtain the hardware
-- address. If 'clock_seq' is given, it is used as the sequence number;
-- otherwise a random 14-bit sequence number is chosen."""
--
-- # When the system provides a version-1 UUID generator, use it (but don't
-- # use UuidCreate here because its UUIDs don't conform to RFC 4122).
-- if _uuid_generate_time and node is clock_seq is None:
-- _uuid_generate_time(_buffer)
-- return UUID(bytes=_buffer.raw)
--
-- import time
-- nanoseconds = int(time.time() * 1e9)
-- # 0x01b21dd213814000 is the number of 100-ns intervals between the
-- # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
-- timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
-- if clock_seq is None:
-- import random
-- clock_seq = random.randrange(1<<14L) # instead of stable storage
-- time_low = timestamp & 0xffffffffL
-- time_mid = (timestamp >> 32L) & 0xffffL
-- time_hi_version = (timestamp >> 48L) & 0x0fffL
-- clock_seq_low = clock_seq & 0xffL
-- clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
-- if node is None:
-- node = getnode()
-- return UUID(fields=(time_low, time_mid, time_hi_version,
-- clock_seq_hi_variant, clock_seq_low, node), version=1)
--
--def uuid3(namespace, name):
-- """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
-- import md5
-- hash = md5.md5(namespace.bytes + name).digest()
-- return UUID(bytes=hash[:16], version=3)
--
--def uuid4():
-- """Generate a random UUID."""
--
-- # When the system provides a version-4 UUID generator, use it.
-- if _uuid_generate_random:
-- _uuid_generate_random(_buffer)
-- return UUID(bytes=_buffer.raw)
--
-- # Otherwise, get randomness from urandom or the 'random' module.
-- try:
-- import os
-- return UUID(bytes=os.urandom(16), version=4)
-- except:
-- import random
-- bytes = [chr(random.randrange(256)) for i in range(16)]
-- return UUID(bytes=bytes, version=4)
--
--def uuid5(namespace, name):
-- """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
-- import sha
-- hash = sha.sha(namespace.bytes + name).digest()
-- return UUID(bytes=hash[:16], version=5)
--
--# The following standard UUIDs are for use with uuid3() or uuid5().
--
--NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
--NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
--NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
--NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
---
-1.7.4.4
-