eric6/Helpviewer/Network/FtpReply.py

changeset 7220
5cf645f6daab
parent 7218
eaf2cf171f3a
parent 7211
1c97f3142fa8
child 7221
0485ccdf7877
diff -r eaf2cf171f3a -r 5cf645f6daab eric6/Helpviewer/Network/FtpReply.py
--- a/eric6/Helpviewer/Network/FtpReply.py	Sat Sep 07 14:45:27 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,510 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2010 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a network reply class for FTP resources.
-"""
-
-from __future__ import unicode_literals
-try:
-    str = unicode
-except NameError:
-    pass
-
-import ftplib
-import socket
-import errno
-import mimetypes
-
-from PyQt5.QtCore import QByteArray, QIODevice, Qt, QUrl, QTimer, QBuffer, \
-    QCoreApplication
-from PyQt5.QtGui import QPixmap
-from PyQt5.QtWidgets import QDialog
-from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest, QAuthenticator
-from PyQt5.QtWebKit import QWebSettings
-
-from E5Network.E5Ftp import E5Ftp, E5FtpProxyError, E5FtpProxyType
-
-import UI.PixmapCache
-
-from Utilities.FtpUtilities import FtpDirLineParser, FtpDirLineParserError
-import Utilities
-
-import Preferences
-
-ftpListPage_html = """\
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
-<head>
-<title>{0}</title>
-<style type="text/css">
-body {{
-  padding: 3em 0em;
-  background: -webkit-gradient(linear, left top, left bottom, from(#85784A),
-                               to(#FDFDFD), color-stop(0.5, #FDFDFD));
-  background-repeat: repeat-x;
-}}
-#box {{
-  background: white;
-  border: 1px solid #85784A;
-  width: 80%;
-  padding: 30px;
-  margin: auto;
-  -webkit-border-radius: 0.8em;
-}}
-h1 {{
-  font-size: 130%;
-  font-weight: bold;
-  border-bottom: 1px solid #85784A;
-}}
-th {{
-  background-color: #B8B096;
-  color: black;
-}}
-table {{
-  border: solid 1px #85784A;
-  margin: 5px 0;
-  width: 100%;
-}}
-tr.odd {{
-  background-color: white;
-  color: black;
-}}
-tr.even {{
-  background-color: #CEC9B8;
-  color: black;
-}}
-.modified {{
-  text-align: left;
-  vertical-align: top;
-  white-space: nowrap;
-}}
-.size {{
-  text-align: right;
-  vertical-align: top;
-  white-space: nowrap;
-  padding-right: 22px;
-}}
-.name {{
-  text-align: left;
-  vertical-align: top;
-  white-space: pre-wrap;
-  width: 100%
-}}
-{1}
-</style>
-</head>
-<body>
-  <div id="box">
-  <h1>{2}</h1>
-{3}
-  <table align="center" cellspacing="0" width="90%">
-{4}
-  </table>
-  </div>
-</body>
-</html>
-"""
-
-
-class FtpReply(QNetworkReply):
-    """
-    Class implementing a network reply for FTP resources.
-    """
-    def __init__(self, url, accessHandler, parent=None):
-        """
-        Constructor
-        
-        @param url requested FTP URL (QUrl)
-        @param accessHandler reference to the access handler (FtpAccessHandler)
-        @param parent reference to the parent object (QObject)
-        """
-        super(FtpReply, self).__init__(parent)
-        
-        self.__manager = parent
-        self.__handler = accessHandler
-        
-        self.__ftp = E5Ftp()
-        
-        self.__items = []
-        self.__content = QByteArray()
-        self.__units = ["Bytes", "KB", "MB", "GB", "TB",
-                        "PB", "EB", "ZB", "YB"]
-        self.__dirLineParser = FtpDirLineParser()
-        self.__fileBytesReceived = 0
-        
-        if url.path() == "":
-            url.setPath("/")
-        self.setUrl(url)
-        
-        # do proxy setup
-        if not Preferences.getUI("UseProxy"):
-            proxyType = E5FtpProxyType.NoProxy
-        else:
-            proxyType = Preferences.getUI("ProxyType/Ftp")
-        if proxyType != E5FtpProxyType.NoProxy:
-            self.__ftp.setProxy(
-                proxyType,
-                Preferences.getUI("ProxyHost/Ftp"),
-                Preferences.getUI("ProxyPort/Ftp"))
-            if proxyType != E5FtpProxyType.NonAuthorizing:
-                self.__ftp.setProxyAuthentication(
-                    Preferences.getUI("ProxyUser/Ftp"),
-                    Preferences.getUI("ProxyPassword/Ftp"),
-                    Preferences.getUI("ProxyAccount/Ftp"))
-        
-        QTimer.singleShot(0, self.__doFtpCommands)
-    
-    def abort(self):
-        """
-        Public slot to abort the operation.
-        """
-        # do nothing
-        pass
-    
-    def bytesAvailable(self):
-        """
-        Public method to determined the bytes available for being read.
-        
-        @return bytes available (integer)
-        """
-        return self.__content.size()
-    
-    def isSequential(self):
-        """
-        Public method to check for sequential access.
-        
-        @return flag indicating sequential access (boolean)
-        """
-        return True
-    
-    def readData(self, maxlen):
-        """
-        Public method to retrieve data from the reply object.
-        
-        @param maxlen maximum number of bytes to read (integer)
-        @return string containing the data (bytes)
-        """
-        if self.__content.size():
-            len_ = min(maxlen, self.__content.size())
-            buffer = bytes(self.__content[:len_])
-            self.__content.remove(0, len_)
-            return buffer
-        else:
-            return b""
-    
-    def __doFtpCommands(self):
-        """
-        Private slot doing the sequence of FTP commands to get the requested
-        result.
-        """
-        retry = True
-        try:
-            username = self.url().userName()
-            password = self.url().password()
-            byAuth = False
-            
-            while retry:
-                try:
-                    self.__ftp.connect(self.url().host(),
-                                       self.url().port(ftplib.FTP_PORT),
-                                       timeout=10)
-                except E5FtpProxyError as err:
-                    self.setError(QNetworkReply.ProxyNotFoundError, str(err))
-                    self.error.emit(QNetworkReply.ProxyNotFoundError)
-                    self.finished.emit()
-                ok, retry = self.__doFtpLogin(username, password, byAuth)
-                if not ok and retry:
-                    auth = self.__handler.getAuthenticator(self.url().host())
-                    if auth and not auth.isNull() and auth.user():
-                        username = auth.user()
-                        password = auth.password()
-                        byAuth = True
-                    else:
-                        retry = False
-            if ok:
-                self.__ftp.retrlines("LIST " + self.url().path(),
-                                     self.__dirCallback)
-                if len(self.__items) == 1 and \
-                   self.__items[0].isFile():
-                    self.__fileBytesReceived = 0
-                    self.__setContent()
-                    self.__ftp.retrbinary(
-                        "RETR " + self.url().path(), self.__retrCallback)
-                    self.__content.append(512 * b' ')
-                    self.readyRead.emit()
-                else:
-                    self.__setListContent()
-                self.__ftp.quit()
-        except ftplib.all_errors as err:
-            if isinstance(err, socket.gaierror):
-                errCode = QNetworkReply.HostNotFoundError
-            elif isinstance(err, socket.error) and \
-                    err.errno == errno.ECONNREFUSED:
-                errCode = QNetworkReply.ConnectionRefusedError
-            else:
-                errCode = QNetworkReply.ProtocolFailure
-            self.setError(errCode, str(err))
-            self.error.emit(errCode)
-        self.finished.emit()
-    
-    def __doFtpLogin(self, username, password, byAuth=False):
-        """
-        Private method to do the FTP login with asking for a username and
-        password, if the login fails with an error 530.
-        
-        @param username user name to use for the login (string)
-        @param password password to use for the login (string)
-        @param byAuth flag indicating that the login data was provided by an
-            authenticator (boolean)
-        @return tuple of two flags indicating a successful login and
-            if the login should be retried (boolean, boolean)
-        """
-        try:
-            self.__ftp.login(username, password)
-            return True, False
-        except E5FtpProxyError as err:
-            code = str(err)[:3]
-            if code[1] == "5":
-                # could be a 530, check second line
-                lines = str(err).splitlines()
-                if lines[1][:3] == "530":
-                    if "usage" in "\n".join(lines[1:].lower()):
-                        # found a not supported proxy
-                        self.setError(
-                            QNetworkReply.ProxyConnectionRefusedError,
-                            self.tr("The proxy type seems to be wrong."
-                                    " If it is not in the list of"
-                                    " supported proxy types please report"
-                                    " it with the instructions given by"
-                                    " the proxy.\n{0}").format(
-                                "\n".join(lines[1:])))
-                        self.error.emit(
-                            QNetworkReply.ProxyConnectionRefusedError)
-                        return False, False
-                    else:
-                        from UI.AuthenticationDialog import \
-                            AuthenticationDialog
-                        info = self.tr(
-                            "<b>Connect to proxy '{0}' using:</b>")\
-                            .format(Utilities.html_encode(
-                                Preferences.getUI("ProxyHost/Ftp")))
-                        dlg = AuthenticationDialog(
-                            info, Preferences.getUI("ProxyUser/Ftp"), True)
-                        dlg.setData(Preferences.getUI("ProxyUser/Ftp"),
-                                    Preferences.getUI("ProxyPassword/Ftp"))
-                        if dlg.exec_() == QDialog.Accepted:
-                            username, password = dlg.getData()
-                            if dlg.shallSave():
-                                Preferences.setUI("ProxyUser/Ftp", username)
-                                Preferences.setUI(
-                                    "ProxyPassword/Ftp", password)
-                            self.__ftp.setProxyAuthentication(username,
-                                                              password)
-                            return False, True
-            return False, False
-        except (ftplib.error_perm, ftplib.error_temp) as err:
-            code = err.args[0].strip()[:3]
-            if code in ["530", "421"]:
-                # error 530 -> Login incorrect
-                # error 421 -> Login may be incorrect (reported by some
-                # proxies)
-                if byAuth:
-                    self.__handler.setAuthenticator(self.url().host(), None)
-                    auth = None
-                else:
-                    auth = self.__handler.getAuthenticator(self.url().host())
-                if not auth or auth.isNull() or not auth.user():
-                    auth = QAuthenticator()
-                    self.__manager.authenticationRequired.emit(self, auth)
-                    if not auth.isNull():
-                        if auth.user():
-                            self.__handler.setAuthenticator(self.url().host(),
-                                                            auth)
-                            return False, True
-                    return False, False
-                return False, True
-            else:
-                raise
-    
-    def __dirCallback(self, line):
-        """
-        Private slot handling the receipt of directory listings.
-        
-        @param line the received line of the directory listing (string)
-        """
-        try:
-            urlInfo = self.__dirLineParser.parseLine(line)
-        except FtpDirLineParserError:
-            # silently ignore parser errors
-            urlInfo = None
-        
-        if urlInfo:
-            self.__items.append(urlInfo)
-        
-        QCoreApplication.processEvents()
-    
-    def __retrCallback(self, data):
-        """
-        Private slot handling the reception of data.
-        
-        @param data data received from the FTP server (bytes)
-        """
-        self.__content += QByteArray(data)
-        self.__fileBytesReceived += len(data)
-        self.downloadProgress.emit(
-            self.__fileBytesReceived, self.__items[0].size())
-        self.readyRead.emit()
-        
-        QCoreApplication.processEvents()
-    
-    def __setContent(self):
-        """
-        Private method to finish the setup of the data.
-        """
-        mtype, encoding = mimetypes.guess_type(self.url().toString())
-        self.open(QIODevice.ReadOnly | QIODevice.Unbuffered)
-        self.setHeader(QNetworkRequest.ContentLengthHeader,
-                       self.__items[0].size())
-        if mtype:
-            self.setHeader(QNetworkRequest.ContentTypeHeader, mtype)
-        self.setAttribute(QNetworkRequest.HttpStatusCodeAttribute, 200)
-        self.setAttribute(QNetworkRequest.HttpReasonPhraseAttribute, "Ok")
-        self.metaDataChanged.emit()
-    
-    def __cssLinkClass(self, icon, size=32):
-        """
-        Private method to generate a link class with an icon.
-        
-        @param icon icon to be included (QIcon)
-        @param size size of the icon to be generated (integer)
-        @return CSS class string (string)
-        """
-        cssString = \
-            """a.{{0}} {{{{\n"""\
-            """  padding-left: {0}px;\n"""\
-            """  background: transparent url(data:image/png;base64,{1})"""\
-            """ no-repeat center left;\n"""\
-            """  font-weight: bold;\n"""\
-            """}}}}\n"""
-        pixmap = icon.pixmap(size, size)
-        imageBuffer = QBuffer()
-        imageBuffer.open(QIODevice.ReadWrite)
-        if not pixmap.save(imageBuffer, "PNG"):
-            # write a blank pixmap on error
-            pixmap = QPixmap(size, size)
-            pixmap.fill(Qt.transparent)
-            imageBuffer.buffer().clear()
-            pixmap.save(imageBuffer, "PNG")
-        return cssString.format(
-            size + 4,
-            str(imageBuffer.buffer().toBase64(), encoding="ascii"))
-    
-    def __setListContent(self):
-        """
-        Private method to prepare the content for the reader.
-        """
-        u = self.url()
-        if not u.path().endswith("/"):
-            u.setPath(u.path() + "/")
-        
-        baseUrl = self.url().toString()
-        basePath = u.path()
-        
-        linkClasses = {}
-        iconSize = QWebSettings.globalSettings().fontSize(
-            QWebSettings.DefaultFontSize)
-        
-        parent = u.resolved(QUrl(".."))
-        if parent.isParentOf(u):
-            icon = UI.PixmapCache.getIcon("up.png")
-            linkClasses["link_parent"] = \
-                self.__cssLinkClass(icon, iconSize).format("link_parent")
-            parentStr = self.tr(
-                """  <p><a class="link_parent" href="{0}">"""
-                """Change to parent directory</a></p>"""
-            ).format(parent.toString())
-        else:
-            parentStr = ""
-        
-        row = \
-            """    <tr class="{0}">"""\
-            """<td class="name"><a class="{1}" href="{2}">{3}</a></td>"""\
-            """<td class="size">{4}</td>"""\
-            """<td class="modified">{5}</td>"""\
-            """</tr>\n"""
-        table = self.tr(
-            """    <tr>"""
-            """<th align="left">Name</th>"""
-            """<th>Size</th>"""
-            """<th align="left">Last modified</th>"""
-            """</tr>\n"""
-        )
-        
-        i = 0
-        for item in self.__items:
-            name = item.name()
-            if item.isDir() and not name.endswith("/"):
-                name += "/"
-            child = u.resolved(QUrl(name.replace(":", "%3A")))
-            
-            if item.isFile():
-                size = item.size()
-                unit = 0
-                while size:
-                    newSize = size // 1024
-                    if newSize and unit < len(self.__units):
-                        size = newSize
-                        unit += 1
-                    else:
-                        break
-                
-                sizeStr = self.tr("{0} {1}", "size unit")\
-                    .format(size, self.__units[unit])
-                linkClass = "link_file"
-                if linkClass not in linkClasses:
-                    icon = UI.PixmapCache.getIcon("fileMisc.png")
-                    linkClasses[linkClass] = \
-                        self.__cssLinkClass(icon, iconSize).format(linkClass)
-            else:
-                sizeStr = ""
-                linkClass = "link_dir"
-                if linkClass not in linkClasses:
-                    icon = UI.PixmapCache.getIcon("dirClosed.png")
-                    linkClasses[linkClass] = \
-                        self.__cssLinkClass(icon, iconSize).format(linkClass)
-            table += row.format(
-                i == 0 and "odd" or "even",
-                linkClass,
-                child.toString(),
-                Utilities.html_encode(item.name()),
-                sizeStr,
-                item.lastModified().toString("yyyy-MM-dd hh:mm"),
-            )
-            i = 1 - i
-        
-        content = ftpListPage_html.format(
-            Utilities.html_encode(baseUrl),
-            "".join(linkClasses.values()),
-            self.tr("Listing of {0}").format(basePath),
-            parentStr,
-            table
-        )
-        self.__content = QByteArray(content.encode("utf8"))
-        self.__content.append(512 * b' ')
-        
-        self.open(QIODevice.ReadOnly | QIODevice.Unbuffered)
-        self.setHeader(
-            QNetworkRequest.ContentTypeHeader, "text/html; charset=UTF-8")
-        self.setHeader(
-            QNetworkRequest.ContentLengthHeader, self.__content.size())
-        self.setAttribute(QNetworkRequest.HttpStatusCodeAttribute, 200)
-        self.setAttribute(QNetworkRequest.HttpReasonPhraseAttribute, "Ok")
-        self.metaDataChanged.emit()
-        self.downloadProgress.emit(
-            self.__content.size(), self.__content.size())
-        self.readyRead.emit()

eric ide

mercurial