Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAjay Garg <ajay@activitycentral.com>2012-08-26 11:34:32 (GMT)
committer Ajay Garg <ajay@activitycentral.com>2012-08-26 11:34:32 (GMT)
commit55db4d555690d3ef1700d9e19eb999c95ddb2f3d (patch)
tree6669c03a2698fd9c45c049c6ce3176a5ebee9a83
parentf51090169d96f46ba3fcee16baeb467b6159dabc (diff)
1-to-N feature via School Server
-rw-r--r--rpms/sugar/0130-1-to-N-feature-via-School-Server.patch1426
1 files changed, 1426 insertions, 0 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
new file mode 100644
index 0000000..b2babe3
--- /dev/null
+++ b/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
@@ -0,0 +1,1426 @@
+From 5a3da2cb5bea8c15b2cbc0ba76d1cb96e4beaced Mon Sep 17 00:00:00 2001
+From: Ajay Garg <ajay@activitycentral.com>
+Date: Sun, 26 Aug 2012 14:53:11 +0530
+Subject: [sugar PATCH] 1-to-N feature via School Server
+Organization: Sugar Labs Foundation
+Signed-off-by: Ajay Garg <ajay@activitycentral.com>
+---
+
+
+
+ src/jarabe/journal/journalactivity.py | 17 ++-
+ src/jarabe/journal/journaltoolbox.py | 44 +++++-
+ src/jarabe/journal/model.py | 285 +++++++++++++++++++++------------
+ src/jarabe/journal/palettes.py | 201 ++++++++++++++++++++----
+ src/jarabe/journal/volumestoolbar.py | 41 ++---
+ src/jarabe/journal/webdavmanager.py | 146 ++++++++++-------
+ src/jarabe/view/palettes.py | 31 +----
+ src/webdav/Connection.py | 11 +-
+ src/webdav/WebdavClient.py | 16 ++-
+ src/webdav/davlib.py | 9 +-
+ 10 files changed, 536 insertions(+), 265 deletions(-)
+
+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..cc17956 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,7 @@ PROPERTIES = ['activity', 'activity_id', 'buddies', 'bundle_id',
+ MIN_PAGES_TO_CACHE = 3
+ MAX_PAGES_TO_CACHE = 5
+
++WEBDAV_MOUNT_POINT = '/tmp'
+ JOURNAL_METADATA_DIR = '.Sugar-Metadata'
+
+ _datastore = None
+@@ -66,6 +67,43 @@ 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)
++
++
++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 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('/') == -1
++
++
+ class _Cache(object):
+
+ __gtype_name__ = 'model_Cache'
+@@ -430,8 +468,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 +502,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
+@@ -557,11 +599,6 @@ def _get_file_metadata(path, stat, fetch_preview=True):
+ dir_path = os.path.dirname(path)
+ metadata = _get_file_metadata_from_json(dir_path, filename, 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
+@@ -678,56 +715,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 +806,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 +831,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,13 +853,69 @@ 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
+
+@@ -876,41 +940,17 @@ 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.
+-
+- """
+- 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
+-
++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)
+- metadata_copy.pop('filesize', None)
++
++
++ # 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:
++ metadata_copy.pop('filesize', None)
+
+ metadata_dir_path = os.path.join(metadata['mountpoint'],
+ JOURNAL_METADATA_DIR)
+@@ -939,25 +979,58 @@ 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')
++ if preview:
++ preview_destination_path = os.path.join(metadata_dir_path, preview_fname)
+ else:
+- _rename_entry_on_external_device(file_path, destination_path,
+- metadata_dir_path)
++ preview_destination_path = None
++
++ return (metadata_destination_path, preview_destination_path)
++
++
++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.
+
+- # 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)
++ Besides copying the associated file a file for the preview
++ and one for the metadata are stored in the hidden directory
++ .Sugar-Metadata.
+
+- 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)
++ 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)
++ metadata_dir_path = os.path.join(metadata['mountpoint'],
++ JOURNAL_METADATA_DIR)
++
++ if (os.path.dirname(destination_path) == os.path.dirname(file_path)) or \
++ (transfer_ownership == True):
++ _rename_entry_on_external_device(file_path, destination_path,
++ metadata_dir_path)
++ else:
++ shutil.copy(file_path, destination_path)
+
+ 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..dc3a691 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,50 @@ 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):
++ if response_id == gtk.RESPONSE_OK:
++ self.hide()
++ gobject.idle_add(self._callback, self._metadata,
++ self._entry.get_text())
++
++
+ class ObjectPalette(Palette):
+
+ __gtype_name__ = 'ObjectPalette'
+@@ -528,6 +572,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 +618,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 +657,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 +695,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 +754,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 +766,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)
+@@ -698,7 +790,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 +843,29 @@ 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()):
++ 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,10 @@ class DocumentsMenu(BaseCopyMenuItem):
+ self._post_operate_per_metadata_per_action(metadata)
+
+
+-class SharesMenu(BaseCopyMenuItem):
++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,8 +952,34 @@ 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()
++ 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.
+@@ -970,8 +1113,8 @@ 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 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)
+diff --git a/src/jarabe/journal/volumestoolbar.py b/src/jarabe/journal/volumestoolbar.py
+index c24475d..8453682 100644
+--- a/src/jarabe/journal/volumestoolbar.py
++++ b/src/jarabe/journal/volumestoolbar.py
+@@ -211,7 +211,7 @@ class VolumesToolbar(gtk.Toolbar):
+
+ def _set_up_volumes(self):
+ self._set_up_documents_button()
+- self._set_up_shares_button()
++ self._add_remote_share_button(model.SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME)
+
+ volume_monitor = gio.volume_monitor_get()
+ self._mount_added_hid = volume_monitor.connect('mount-added',
+@@ -242,18 +242,10 @@ 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)
++ def _add_remote_share_button(self, ip_address_or_dns_name):
++ button = RemoteSharesButton(ip_address_or_dns_name)
+ 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.set_palette(RemoteSharePalette(_('Shares'), button))
+ button.connect('toggled', self._button_toggled_cb)
+ button.show()
+
+@@ -262,13 +254,6 @@ 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)
+-
+ def __mount_added_cb(self, volume_monitor, mount):
+ self._add_button(mount)
+
+@@ -308,7 +293,6 @@ class VolumesToolbar(gtk.Toolbar):
+ 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)
+
+@@ -338,7 +322,7 @@ class VolumesToolbar(gtk.Toolbar):
+ self.hide()
+
+ def _remove_remote_share_button(self, mount_point):
+- # Here, IP_Address is the mount_point.
++ # Here, ip_address_or_dns_name is the mount_point.
+ for button in self.get_children():
+ if type(button) == RemoteSharesButton and \
+ button.mount_point == mount_point:
+@@ -478,6 +462,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 +473,18 @@ class DirectoryButton(BaseButton):
+
+ class RemoteSharesButton(BaseButton):
+
+- def __init__(self, buddy):
+- BaseButton.__init__(self, mount_point=buddy.props.ip_address)
++ def __init__(self, ip_address_or_dns_name):
++ BaseButton.__init__(self, mount_point=ip_address_or_dns_name)
+
+- self._buddy = buddy
++ self._ip_address_or_dns_name = ip_address_or_dns_name
+ self.props.named_icon = 'emblem-neighborhood-shared'
+- self.props.xo_color = buddy.props.color
+- self._buddy_ip_address = buddy.props.ip_address
++
++ client = gconf.client_get_default()
++ color = XoColor(client.get_string('/desktop/sugar/user/color'))
++ self.props.xo_color = color
+
+ def create_palette(self):
+- palette = RemoteSharePalette(self._buddy)
++ palette = RemoteSharePalette(self._ip_address_or_dns_name)
+ return palette
+
+
+diff --git a/src/jarabe/journal/webdavmanager.py b/src/jarabe/journal/webdavmanager.py
+index 6cd0713..db99504 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
+
+@@ -59,6 +58,10 @@ class WebDavUrlManager(gobject.GObject):
+ def _get_resource_by_key(self, key):
+ return self._remote_webdav_share_resources[key]['resource']
+
++ 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 = []
+ for key in self._remote_webdav_share_resources.keys():
+@@ -69,11 +72,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 +112,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 +144,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_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_metadata_webdav_manager(ip_address_or_dns_name):
++ return webdav_manager[ip_address_or_dns_name]['metadata']
++
++
++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 +200,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 +210,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 +227,60 @@ 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.rstrip('.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)
+
+ 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 root_webdav._get_metadata_list()
++ return metadata_list
+diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
+index 3b26faf..b753a5a 100644
+--- a/src/jarabe/view/palettes.py
++++ b/src/jarabe/view/palettes.py
+@@ -339,33 +339,6 @@ 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, button):
++ Palette.__init__(self, label=primary_text)
+ 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/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
+