diff options
Diffstat (limited to 'src/jarabe/journal/webdavmanager.py')
-rw-r--r-- | src/jarabe/journal/webdavmanager.py | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/jarabe/journal/webdavmanager.py b/src/jarabe/journal/webdavmanager.py new file mode 100644 index 0000000..6cd0713 --- /dev/null +++ b/src/jarabe/journal/webdavmanager.py @@ -0,0 +1,256 @@ +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() |