Beispiel #1
0
    def download_collection(self, id, register_name):
        """Download a collection given its ID.

        For zip collection, we will download the zip, and extract the
        collection to collections dir.

        :param id: The ID of the collection.
        :type id: str

        :param register_name: The register name of the collection (the
            section name of the collection)
        :type register_name: unicode
        """
        # Download the zip first
        collection_path = 'collections/%s.zip' % register_name
        network_manager = NetworkManager(self.file_url(collection_path))
        status, description = network_manager.fetch()

        if not status:
            return False, description

        # Create the zip file
        zip_file = QTemporaryFile()
        if zip_file.open():
            zip_file.write(network_manager.content)
            zip_file.close()

        zf = ZipFile(zip_file.fileName())
        zf.extractall(path=local_collection_path(id))
        return True, None
Beispiel #2
0
    def fetch_online_directories(self):
        """Fetch online directory of repositories."""
        downloader = NetworkManager(self.DIRECTORY_URL)
        status, _ = downloader.fetch()
        if status:
            directory_file = QTemporaryFile()
            if directory_file.open():
                directory_file.write(downloader.content)
                directory_file.close()

            with open(directory_file.fileName()) as csv_file:
                reader = csv.DictReader(csv_file, fieldnames=('name', 'url'))
                for row in reader:
                    self._online_directories[row['name']] = row['url'].strip()
            # Save it to cache
            settings = QSettings()
            settings.beginGroup(repo_settings_group())
            settings.setValue('online_directories', self._online_directories)
            settings.endGroup()
        else:
            # Just use cache from previous use
            settings = QSettings()
            settings.beginGroup(repo_settings_group())
            self._online_directories = settings.value('online_directories', {})
            settings.endGroup()
Beispiel #3
0
    def display_downloaded_content(self):
        """
        Called when an unsupported content type is finished downloading.
        """
        file_path = QDir.toNativeSeparators(QDir.tempPath() + "/XXXXXX_" + self.content_filename)
        myfile = QTemporaryFile(file_path)
        myfile.setAutoRemove(False)
        if (myfile.open()):
            myfile.write(self.reply.readAll())
            myfile.close()
            subprocess.Popen([self.content_handlers.get(str(self.content_type)), myfile.fileName()])

            #Sometimes downloading files opens an empty window.
            #So if the current window has no URL, close it.
            if(str(self.url().toString()) in ('', 'about:blank')):
                self.close()
    def parse_metadata(self):
        """Parse str metadata to collection dict."""
        if not self.metadata:
            msg = 'The metadata content is None'
            LOGGER.error(msg)
            raise MetadataError(msg)

        collections = []
        metadata_file = QTemporaryFile()
        if metadata_file.open():
            metadata_file.write(self.metadata)
            metadata_file.close()

        try:
            parser = SafeConfigParser()
            metadata_path = metadata_file.fileName()
            with codecs.open(metadata_path, 'r', encoding='utf-8') as f:
                parser.readfp(f)
            collections_str = parser.get('general', 'collections')
        except Exception as e:
            raise MetadataError('Error parsing metadata: %s' % e)

        collection_list = [
            collection.strip() for collection in collections_str.split(',')
        ]
        # Read all the collections
        for collection in collection_list:
            # Parse the version
            qgis_min_version = parser.has_option(
                collection, 'qgis_minimum_version') and parser.get(
                    collection, 'qgis_minimum_version') or None
            qgis_max_version = parser.has_option(
                collection, 'qgis_maximum_version') and parser.get(
                    collection, 'qgis_maximum_version') or None
            if not qgis_min_version:
                qgis_min_version = '2.0'
            if not qgis_max_version:
                qgis_max_version = '3.99'
            if not isCompatible(QGis.QGIS_VERSION, qgis_min_version,
                                qgis_max_version):
                LOGGER.info(
                    'Collection %s is not compatible with current QGIS '
                    'version. QGIS ver:%s, QGIS min ver:%s, QGIS max ver: '
                    '%s' % (collection, QGis.QGIS_VERSION, qgis_min_version,
                            qgis_max_version))
                break

            # Collection is compatible, continue parsing
            try:
                # Parse general information
                author = parser.get(collection, 'author')
                email = parser.get(collection, 'email')
                name = parser.get(collection, 'name')
                tags = parser.get(collection, 'tags')
                description = parser.get(collection, 'description')

                # Parse licensing stuffs
                license_str = parser.has_option(
                    collection, 'license') and parser.get(
                        collection, 'license') or None
                license_path = parser.has_option(
                    collection, 'license_file') and parser.get(
                        collection, 'license_file') or None
                license_url = None
                if license_path:
                    license_url = self.collection_file_url(
                        collection, license_path.strip())

                # Parse the preview urls
                preview_str = parser.has_option(collection, 'preview') and \
                    parser.get(collection, 'preview') or ''
                preview_list = []
                for preview in preview_str.split(','):
                    if preview.strip() != '':
                        preview_url = self.collection_file_url(
                            collection, preview.strip())
                        preview_list.append(preview_url)

            except Exception as e:
                raise MetadataError('Error parsing metadata: %s' % e)

            collection_dict = {
                'register_name': collection,
                'author': author,
                'author_email': email,
                'repository_url': self.url,
                'status': COLLECTION_NOT_INSTALLED_STATUS,
                'name': name,
                'tags': tags,
                'description': description,
                'qgis_min_version': qgis_min_version,
                'qgis_max_version': qgis_max_version,
                'preview': preview_list,
                'license': license_str,
                'license_url': license_url
            }
            collections.append(collection_dict)

        return collections
Beispiel #5
0
class DocumentSharingStream(MSRPStreamBase):
    type = 'document-sharing'
    priority = 1
    msrp_session_class = MSRPSession

    media_type = 'application'
    accept_types = ['application/x-webodf-documentsharing', 'application/x-webodf-genesisdocument']
    accept_wrapped_types = None

    def __init__(self, filename = None, document_title = None, session_uuid = None, continue_session = None):
        super(DocumentSharingStream, self).__init__()
        self.notification_center = NotificationCenter()
        self.mode = continue_session if continue_session is not None else 'guest' if filename is None else 'host'
        self.filename = filename
        if session_uuid is None:
            session_uuid =  str(uuid.uuid4())
        self.session_uuid = session_uuid
        self.continue_session = continue_session
        self.document_title = document_title if document_title is not None else os.path.basename(filename) if filename is not None else None
        self.receivedGenesisFile = None
        self.genesisFileSender = None
        print "NEW DocumentSharingStream - filename: ", self.filename, "session_uuid: ", self.session_uuid, "continue_session: ", self.continue_session

    @classmethod
    def new_from_sdp(cls, session, remote_sdp, stream_index):
        remote_stream = remote_sdp.media[stream_index]
        if remote_stream.media != 'application':
            raise UnknownStreamError

        remote_accept_types = remote_stream.attributes.getfirst('accept-types', None)
        if remote_accept_types is None:
            raise InvalidStreamError("remote SDP media does not have 'accept-types' attribute")
        if 'application/x-webodf-documentsharing' not in remote_accept_types.split(): # TODO: check both needed mimetypes
            raise InvalidStreamError("no compatible media types found")

        expected_transport = 'TCP/TLS/MSRP' if session.account.msrp.transport=='tls' else 'TCP/MSRP'
        if remote_stream.transport != expected_transport:
            raise InvalidStreamError("expected %s transport in chat stream, got %s" % (expected_transport, remote_stream.transport))
        if remote_stream.formats != ['*']:
            raise InvalidStreamError("wrong format list specified")

        document_title = remote_stream.attributes.getfirst('document-title', None)
        session_uuid = remote_stream.attributes.getfirst('docsession-uuid', None)
        continue_session = remote_stream.attributes.getfirst('docsession-continue', None)
        # revert on reception side
        if continue_session == "host":
            continue_session = "guest"
        elif continue_session == "guest":
            continue_session = "host"

        return cls(filename = None, document_title = document_title, session_uuid = session_uuid, continue_session = continue_session)

    def _create_local_media(self, uri_path):
        local_media = super(DocumentSharingStream, self)._create_local_media(uri_path)
        # TODO: .encode('utf8') only works with filenames with latin1 chars, investigate proper fix
        local_media.attributes.append(SDPAttribute('document-title', self.document_title.encode('utf8')))
        local_media.attributes.append(SDPAttribute('docsession-uuid', self.session_uuid))
        if self.continue_session is not None:
            local_media.attributes.append(SDPAttribute('docsession-continue', self.continue_session))
        return local_media

    def _handle_SEND(self, chunk):
        if chunk.size == 0:
            # keep-alive
            self.msrp_session.send_report(chunk, 200, 'OK')
            return

        if chunk.content_type not in self.accept_types:
            self.msrp_session.send_report(chunk, 415, 'Invalid content-type')
            return

        if chunk.content_type == 'application/x-webodf-genesisdocument':
            if self.receivedGenesisFile is None:
                print "------- creating file for genesis"
                self.receivedGenesisFile = QTemporaryFile()
                self.receivedGenesisFile.open()

            fro, to, total = chunk.byte_range
            print "------- got x-webodf-genesisdocument - fro, to, total:", fro, to, total
            self.receivedGenesisFile.seek(fro-1)
            self.receivedGenesisFile.write(chunk.data)

            if fro+chunk.size-1 == total:
                print "------- got x-webodf-genesisdocument - complete, size:", fro+chunk.size-1
                self.receivedGenesisFile.flush()
                ndata = NotificationData(filename = self.receivedGenesisFile.fileName())
                self.notification_center.post_notification('DocumentSharingStreamGenesisDocument', sender = self, data = ndata)

            return

        self.msrp_session.send_report(chunk, 200, 'OK')

        message = cjson.decode(chunk.data)
        messageType = message['type']
        messageBody = message['body']

        print "------- got x-webodf-documentsharing:", messageType

        if messageType == 'InitRequest':
            ndata = NotificationData(content = messageBody)
            self.notification_center.post_notification('DocumentSharingStreamInitRequest', sender = self, data = ndata)
            return

        if messageType == 'InitRequestReply':
            ndata = NotificationData(content = messageBody)
            self.notification_center.post_notification('DocumentSharingStreamInitRequestReply', sender = self, data = ndata)
            return

        if messageType == 'ReplayRequest':
            ndata = NotificationData(content = messageBody)
            self.notification_center.post_notification('DocumentSharingStreamReplayRequest', sender = self, data = ndata)
            return

        if messageType == 'ReplayRequestReply':
            ndata = NotificationData(content = messageBody)
            self.notification_center.post_notification('DocumentSharingStreamReplayRequestReply', sender = self, data = ndata)
            return

        if messageType == 'error':
            ndata = NotificationData(content = messageBody['error'])
            self.notification_center.post_notification('DocumentSharingStreamError', sender = self, data = ndata)
            return

        if messageType == 'NewOps':
            ndata = NotificationData(content = messageBody, content_type = chunk.content_type)
            self.notification_center.post_notification('DocumentSharingStreamNewOps', sender = self, data = ndata)

        if messageType == 'NewOpsReply':
            ndata = NotificationData(content = messageBody)
            self.notification_center.post_notification('DocumentSharingStreamNewOpsReply', sender = self, data = ndata)

    def _handle_REPORT(self, chunk):
        if self.genesisFileSender:
            self.genesisFileSender.handleReportChunk(chunk)

    def _dropGenesisFileSender(self):
        # thanks for all the file, and bye
        self.notification_center.remove_observer(self, sender=self.genesisFileSender)
        self.genesisFileSender = None

    @run_in_green_thread
    def sendMessage(self, messageType, messageBody):
        print "------- sendMessage:", messageType
        if self.msrp_session:
            message = {
                'type': messageType,
                'body': messageBody
            }

            message = cjson.encode(message)
            self.msrp_session.send_message(message, 'application/x-webodf-documentsharing')

    @run_in_green_thread
    def sendGenesisFile(self, filename):
        print "------- sendGenesisFile:", filename
        if self.msrp_session:
            self.genesisFileSender = GenesisFileSender(filename, self.msrp_session, self.msrp)
            self.notification_center.add_observer(self, sender=self.genesisFileSender)
            self.genesisFileSender.startFileSending()

    def _NH_MediaStreamDidStart(self, notification):
        self.notification_center.post_notification('DocumentSharingStreamConnected', sender = self)

    def _NH_MediaStreamDidFail(self, notification):
        if self.genesisFileSender:
            self.genesisFileSender.end()
            self._dropGenesisFileSender()
        self.notification_center.post_notification('DocumentSharingStreamDisconnected', sender = self)

    def _NH_MediaStreamDidEnd(self, notification):
        if self.genesisFileSender:
            self.genesisFileSender.end()
            self._dropGenesisFileSender()
        self.notification_center.post_notification('DocumentSharingStreamDisconnected', sender = self)

    @run_in_twisted_thread
    def _NH_FileTransferHandlerDidEnd(self, notification):
        self._dropGenesisFileSender()

    @run_in_twisted_thread
    def _NH_FileTransferHandlerError(self, notification):
        self._failure_reason = notification.data.error
        notification.center.post_notification('MediaStreamDidFail', sender=self, data=NotificationData(context='transferring', reason=self._failure_reason))