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-09-04 13:49:58 (GMT)
committer Ajay Garg <ajay@activitycentral.com>2012-09-04 15:43:47 (GMT)
commit7c231494096c2cbcd737ff477ebb5193a386a556 (patch)
tree42864e6da69444427c764af608ee07fe0f0369cb
parentb9a295182236bff4499ecaf1d2dc21e1e553bb1c (diff)
1-to-N Feature, via Peer-To-Peer mechanism; and Via-School-Server mechanism.
Details at :: http://wiki.sugarlabs.org/go/Features/Transfer_to_many_options Signed-off-by: Ajay Garg <ajay@activitycentral.com>
-rw-r--r--rpms/sugar/0130-1-to-N-feature-via-School-Server.patch491
1 files changed, 403 insertions, 88 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
index ef570a4..81cd2f8 100644
--- a/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
+++ b/rpms/sugar/0130-1-to-N-feature-via-School-Server.patch
@@ -1,23 +1,84 @@
-From ef7fc9392d515430290406bc7813987b5e661451 Mon Sep 17 00:00:00 2001
+From d56362d85ecd6ce9921a67c2f4252d01c26a71af Mon Sep 17 00:00:00 2001
From: Ajay Garg <ajay@activitycentral.com>
-Date: Wed, 29 Aug 2012 16:56:59 +0530
-Subject: [sugar PATCH] 1-to-N-feature-via-School-Server.
+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/journal/expandedentry.py | 24 +++-
+ 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 | 352 ++++++++++++++++++++++-----------
- src/jarabe/journal/palettes.py | 238 +++++++++++++++++++---
- src/jarabe/journal/volumestoolbar.py | 41 ++---
- src/jarabe/journal/webdavmanager.py | 164 ++++++++++------
- src/jarabe/view/palettes.py | 31 +---
+ 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/WebdavClient.py | 16 +-
src/webdav/davlib.py | 9 +-
- 11 files changed, 667 insertions(+), 280 deletions(-)
+ 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
@@ -194,7 +255,7 @@ index 6b2494e..b1c0cac 100644
return self._selected_entries
diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py
-index 422e947..071376b 100644
+index 422e947..c06b2ee 100644
--- a/src/jarabe/journal/model.py
+++ b/src/jarabe/journal/model.py
@@ -43,7 +43,7 @@ from sugar import dispatch
@@ -206,15 +267,17 @@ index 422e947..071376b 100644
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',
+@@ -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 +67,43 @@ updated = dispatch.Signal()
+@@ -66,6 +69,52 @@ updated = dispatch.Signal()
deleted = dispatch.Signal()
@@ -222,8 +285,7 @@ index 422e947..071376b 100644
+ '/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)
++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):
@@ -236,6 +298,16 @@ index 422e947..071376b 100644
+ 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 ::
@@ -258,7 +330,7 @@ index 422e947..071376b 100644
class _Cache(object):
__gtype_name__ = 'model_Cache'
-@@ -430,8 +468,8 @@ class InplaceResultSet(BaseResultSet):
+@@ -430,8 +479,8 @@ class InplaceResultSet(BaseResultSet):
class RemoteShareResultSet(object):
@@ -269,7 +341,7 @@ index 422e947..071376b 100644
self._file_list = []
self.ready = dispatch.Signal()
-@@ -464,7 +502,11 @@ class RemoteShareResultSet(object):
+@@ -464,7 +513,11 @@ class RemoteShareResultSet(object):
self._sort = query.get('order_by', ['+timestamp'])[0]
def setup(self):
@@ -282,7 +354,7 @@ index 422e947..071376b 100644
for metadata in metadata_list_complete:
add_to_list = False
-@@ -553,15 +595,8 @@ def _get_file_metadata(path, stat, fetch_preview=True):
+@@ -553,15 +606,8 @@ def _get_file_metadata(path, stat, fetch_preview=True):
metadata based on the file properties.
"""
@@ -299,7 +371,7 @@ index 422e947..071376b 100644
if 'filesize' not in metadata:
if stat is not None:
metadata['filesize'] = stat.st_size
-@@ -582,17 +617,26 @@ def _get_file_metadata(path, stat, fetch_preview=True):
+@@ -582,17 +628,26 @@ def _get_file_metadata(path, stat, fetch_preview=True):
'description': path}
@@ -329,7 +401,7 @@ index 422e947..071376b 100644
filename + '.preview')
if not os.path.exists(metadata_path):
-@@ -670,7 +714,8 @@ def find(query_, page_size):
+@@ -670,7 +725,8 @@ def find(query_, page_size):
Regex Matching is used, to ensure that the mount-point is an
IP-Address.
"""
@@ -339,7 +411,7 @@ index 422e947..071376b 100644
else:
"""
For Documents/Shares/Mounted-Drives.
-@@ -678,56 +723,13 @@ def find(query_, page_size):
+@@ -678,56 +734,13 @@ def find(query_, page_size):
return InplaceResultSet(query, page_size, mount_points[0])
@@ -396,7 +468,7 @@ index 422e947..071376b 100644
stat = None
metadata = _get_file_metadata(object_id, stat)
-@@ -812,7 +814,21 @@ def delete(object_id):
+@@ -812,7 +825,21 @@ def delete(object_id):
def copy(metadata, mount_point):
"""Copies an object to another mount point
"""
@@ -418,7 +490,7 @@ index 422e947..071376b 100644
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 +839,7 @@ def copy(metadata, mount_point):
+@@ -823,7 +850,7 @@ def copy(metadata, mount_point):
metadata['mountpoint'] = mount_point
del metadata['uid']
@@ -427,7 +499,7 @@ index 422e947..071376b 100644
def write(metadata, file_path='', update_mtime=True, transfer_ownership=True):
-@@ -845,27 +861,97 @@ 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)
@@ -506,6 +578,12 @@ index 422e947..071376b 100644
-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
@@ -515,6 +593,8 @@ index 422e947..071376b 100644
+ # 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
@@ -536,7 +616,7 @@ index 422e947..071376b 100644
old_fname + '.preview')]
for ofile in old_files:
if os.path.exists(ofile):
-@@ -876,41 +962,31 @@ def _rename_entry_on_external_device(file_path, destination_path,
+@@ -876,41 +981,32 @@ def _rename_entry_on_external_device(file_path, destination_path,
'for file=%s', ofile, old_fname)
@@ -566,7 +646,8 @@ index 422e947..071376b 100644
- '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:
++ 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'):
@@ -599,21 +680,21 @@ index 422e947..071376b 100644
metadata_dir_path = os.path.join(metadata['mountpoint'],
JOURNAL_METADATA_DIR)
-@@ -939,25 +1015,61 @@ def _write_entry_on_external_device(metadata, file_path):
+@@ -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
-+
-+ return (metadata_destination_path, preview_destination_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"
@@ -622,11 +703,13 @@ index 422e947..071376b 100644
- 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,
@@ -637,7 +720,7 @@ index 422e947..071376b 100644
+ 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.
@@ -673,10 +756,11 @@ index 422e947..071376b 100644
+ _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 +1125,11 @@ def is_editable(metadata):
+@@ -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
@@ -690,7 +774,7 @@ index 422e947..071376b 100644
def get_documents_path():
diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py
-index 66dcadc..f8a437e 100644
+index 66dcadc..91e5460 100644
--- a/src/jarabe/journal/palettes.py
+++ b/src/jarabe/journal/palettes.py
@@ -30,6 +30,7 @@ import gio
@@ -926,13 +1010,14 @@ index 66dcadc..f8a437e 100644
return False
finally:
self._set_bundle_installation_allowed(True)
-@@ -751,6 +842,29 @@ class BaseCopyMenuItem(MenuItem, ActionItem):
+@@ -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()):
++ 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)
@@ -956,7 +1041,7 @@ index 66dcadc..f8a437e 100644
class VolumeMenu(BaseCopyMenuItem):
def __init__(self, metadata_list, label, mount_point,
-@@ -761,9 +875,10 @@ class VolumeMenu(BaseCopyMenuItem):
+@@ -761,9 +876,10 @@ class VolumeMenu(BaseCopyMenuItem):
show_progress_info_alert, batch_mode)
self._mount_point = mount_point
@@ -968,7 +1053,7 @@ index 66dcadc..f8a437e 100644
if not self._metadata_copy_valid(metadata, self._mount_point):
return False
-@@ -780,7 +895,7 @@ class ClipboardMenu(BaseCopyMenuItem):
+@@ -780,7 +896,7 @@ class ClipboardMenu(BaseCopyMenuItem):
batch_mode)
self._temp_file_path_list = []
@@ -977,7 +1062,7 @@ index 66dcadc..f8a437e 100644
if not self._file_path_valid(metadata):
return False
-@@ -813,9 +928,10 @@ class DocumentsMenu(BaseCopyMenuItem):
+@@ -813,9 +929,10 @@ class DocumentsMenu(BaseCopyMenuItem):
show_progress_info_alert,
batch_mode)
@@ -989,11 +1074,42 @@ index 66dcadc..f8a437e 100644
if not self._metadata_copy_valid(metadata,
model.get_documents_path()):
return False
-@@ -824,10 +940,10 @@ class DocumentsMenu(BaseCopyMenuItem):
+@@ -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):
@@ -1002,7 +1118,7 @@ index 66dcadc..f8a437e 100644
show_editing_alert,
show_progress_info_alert,
batch_mode)
-@@ -835,13 +951,75 @@ class SharesMenu(BaseCopyMenuItem):
+@@ -835,13 +983,75 @@ class SharesMenu(BaseCopyMenuItem):
def _operate(self, metadata):
if not self._file_path_valid(metadata):
return False
@@ -1079,53 +1195,110 @@ index 66dcadc..f8a437e 100644
class FriendsMenu(gtk.Menu):
__gtype_name__ = 'JournalFriendsMenu'
-@@ -970,8 +1148,8 @@ class CopyMenuHelper(gtk.Menu):
+@@ -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..e251300 100644
+index c24475d..b004657 100644
--- a/src/jarabe/journal/volumestoolbar.py
+++ b/src/jarabe/journal/volumestoolbar.py
-@@ -211,7 +211,7 @@ class VolumesToolbar(gtk.Toolbar):
+@@ -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._add_remote_share_button(model.SCHOOL_SERVER_IP_ADDRESS_OR_DNS_NAME)
++ 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 +242,10 @@ class VolumesToolbar(gtk.Toolbar):
+@@ -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,
-- 'emblem-neighborhood-shared',
++ 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)
-+ def _add_remote_share_button(self, ip_address_or_dns_name):
-+ button = RemoteSharesButton(ip_address_or_dns_name)
++ _('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))
-+ button.set_palette(RemoteSharePalette(_('Shares'), 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,13 +254,6 @@ class VolumesToolbar(gtk.Toolbar):
+@@ -262,12 +280,7 @@ class VolumesToolbar(gtk.Toolbar):
self._volume_buttons.append(button)
self.show()
@@ -1135,11 +1308,18 @@ index c24475d..e251300 100644
- 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()
-@@ -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)
@@ -1147,16 +1327,47 @@ index c24475d..e251300 100644
self.emit('volume-changed', button.mount_point)
-@@ -338,7 +322,7 @@ class VolumesToolbar(gtk.Toolbar):
+@@ -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):
+- 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.
++ 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:
-@@ -478,6 +462,7 @@ class DirectoryButton(BaseButton):
+- 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)
@@ -1164,33 +1375,38 @@ index c24475d..e251300 100644
self.props.named_icon = icon_name
-@@ -488,16 +473,18 @@ class DirectoryButton(BaseButton):
+@@ -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, ip_address_or_dns_name):
++ 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._ip_address_or_dns_name = ip_address_or_dns_name
- self.props.named_icon = 'emblem-neighborhood-shared'
+- 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'))
++ 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._ip_address_or_dns_name)
++ 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..39c1c30 100644
+index 6cd0713..3ff9990 100644
--- a/src/jarabe/journal/webdavmanager.py
+++ b/src/jarabe/journal/webdavmanager.py
@@ -1,5 +1,6 @@
@@ -1272,6 +1488,10 @@ index 6cd0713..39c1c30 100644
+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
@@ -1279,10 +1499,6 @@ index 6cd0713..39c1c30 100644
- 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():
@@ -1304,10 +1520,10 @@ index 6cd0713..39c1c30 100644
+
+ # Procure the resource-lock.
+ lockToken = resource.lock('olpc')
++
++ input_stream = open(content_file_path)
- complete_root_url = protocol + ip_address + root_webdav_url
-+ input_stream = open(content_file_path)
-+
+ # 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.
@@ -1357,7 +1573,7 @@ index 6cd0713..39c1c30 100644
# assert that the number of collections is zero at this url.
assert root_webdav_sugar_metadata._get_number_of_collections() == 0
-@@ -189,68 +229,74 @@ def get_remote_webdav_share_metadata(ip_address):
+@@ -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.
@@ -1465,32 +1681,126 @@ index 6cd0713..39c1c30 100644
- 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()
-+ return 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..b753a5a 100644
+index 3b26faf..f6bca48 100644
--- a/src/jarabe/view/palettes.py
+++ b/src/jarabe/view/palettes.py
-@@ -339,33 +339,6 @@ class JournalXSPalette(Palette):
+@@ -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, button):
++ 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)
@@ -1500,14 +1810,19 @@ index 3b26faf..b753a5a 100644
- 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()
++ 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
++ 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