Continued porting the web browser. QtWebEngine

Sat, 20 Feb 2016 14:34:32 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 20 Feb 2016 14:34:32 +0100
branch
QtWebEngine
changeset 4753
8d2ea02ed785
parent 4752
a3bcc42a82a9
child 4754
1ff6d0ecb2fd

Continued porting the web browser.

- added the VirusTotal code

Preferences/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/UrlBar/UrlBar.py file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalApi.py file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalDomainReportDialog.py file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalDomainReportDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalIpReportDialog.py file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalIpReportDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalWhoisDialog.py file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/VirusTotalWhoisDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/VirusTotal/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserPage.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserView.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- a/Preferences/__init__.py	Sat Feb 20 12:26:28 2016 +0100
+++ b/Preferences/__init__.py	Sat Feb 20 14:34:32 2016 +0100
@@ -2652,7 +2652,7 @@
     """
     # the following entries are identical to the ones of the help viewer
     # and are being redirected there
-    if key.startswith(("FlashCookies", "Pim", "VirusTotal")):
+    if key.startswith(("FlashCookie", "Pim", "VirusTotal")):
         return getHelp(key, prefClass)
     
     if not prefClass.webEngineSettingsIntitialized:
@@ -2784,7 +2784,7 @@
     """
     # the following entries are identical to the ones of the help viewer
     # and are being redirected there
-    if key.startswith(("FlashCookies", "Pim", "VirusTotal")):
+    if key.startswith(("FlashCookie", "Pim", "VirusTotal")):
         setHelp(key, value, prefClass)
     
     if key in ["StandardFont", "FixedFont"]:
--- a/WebBrowser/UrlBar/UrlBar.py	Sat Feb 20 12:26:28 2016 +0100
+++ b/WebBrowser/UrlBar/UrlBar.py	Sat Feb 20 14:34:32 2016 +0100
@@ -165,7 +165,7 @@
         if manager.bookmarkForUrl(self.__browser.url()) is not None:
             self.__bookmarkButton.setIcon(self.__bmActiveIcon)
             bookmarks = manager.bookmarksForUrl(self.__browser.url())
-            from Helpviewer.Bookmarks.BookmarkNode import BookmarkNode
+            from WebBrowser.Bookmarks.BookmarkNode import BookmarkNode
             for bookmark in bookmarks:
                 manager.setTimestamp(bookmark, BookmarkNode.TsVisited,
                                      QDateTime.currentDateTime())
@@ -461,7 +461,7 @@
 ##        """
 ##        Private slot to handle clicking the RSS icon.
 ##        """
-##        from Helpviewer.Feeds.FeedsDialog import FeedsDialog
+##        from WebBrowser.Feeds.FeedsDialog import FeedsDialog
 ##        feeds = self.__browser.getRSS()
 ##        dlg = FeedsDialog(feeds, self.__browser)
 ##        dlg.exec_()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalApi.py	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,416 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the <a href="http://www.virustotal.com">VirusTotal</a>
+API class.
+"""
+
+from __future__ import unicode_literals
+try:
+    str = unicode       # __IGNORE_EXCEPTION__
+except NameError:
+    pass
+
+import json
+
+from PyQt5.QtCore import QObject, QUrl, QByteArray, pyqtSignal, qVersion
+from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
+
+from E5Gui import E5MessageBox
+
+import Preferences
+
+
+class VirusTotalAPI(QObject):
+    """
+    Class implementing the <a href="http://www.virustotal.com">VirusTotal</a>
+    API.
+    
+    @signal checkServiceKeyFinished(bool, str) emitted after the service key
+        check has been performed. It gives a flag indicating validity
+        (boolean) and an error message in case of a network error (string).
+    @signal submitUrlError(str) emitted with the error string, if the URL scan
+        submission returned an error.
+    @signal urlScanReport(str) emitted with the URL of the URL scan report page
+    @signal fileScanReport(str) emitted with the URL of the file scan report
+        page
+    """
+    checkServiceKeyFinished = pyqtSignal(bool, str)
+    submitUrlError = pyqtSignal(str)
+    urlScanReport = pyqtSignal(str)
+    fileScanReport = pyqtSignal(str)
+    
+    TestServiceKeyScanID = \
+        "4feed2c2e352f105f6188efd1d5a558f24aee6971bdf96d5fdb19c197d6d3fad"
+    
+    ServiceResult_ItemQueued = -2
+    ServiceResult_ItemNotPresent = 0
+    ServiceResult_ItemPresent = 1
+    
+    # HTTP Status Codes
+    ServiceCode_InvalidKey = 202
+    ServiceCode_RateLimitExceeded = 204
+    ServiceCode_InvalidPrivilege = 403
+    
+    GetFileReportPattern = "{0}://www.virustotal.com/vtapi/v2/file/report"
+    ScanUrlPattern = "{0}://www.virustotal.com/vtapi/v2/url/scan"
+    GetUrlReportPattern = "{0}://www.virustotal.com/vtapi/v2/url/report"
+    GetIpAddressReportPattern = \
+        "{0}://www.virustotal.com/vtapi/v2/ip-address/report"
+    GetDomainReportPattern = "{0}://www.virustotal.com/vtapi/v2/domain/report"
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object (QObject)
+        """
+        super(VirusTotalAPI, self).__init__(parent)
+        
+        self.__replies = []
+        
+        self.__loadSettings()
+        
+        self.__lastIP = ""
+        self.__lastDomain = ""
+        self.__ipReportDlg = None
+        self.__domainReportDlg = None
+    
+    def __loadSettings(self):
+        """
+        Private method to load the settings.
+        """
+        if Preferences.getHelp("VirusTotalSecure"):
+            protocol = "https"
+        else:
+            protocol = "http"
+        self.GetFileReportUrl = self.GetFileReportPattern.format(protocol)
+        self.ScanUrlUrl = self.ScanUrlPattern.format(protocol)
+        self.GetUrlReportUrl = self.GetUrlReportPattern.format(protocol)
+        self.GetIpAddressReportUrl = self.GetIpAddressReportPattern.format(
+            protocol)
+        self.GetDomainReportUrl = self.GetDomainReportPattern.format(protocol)
+        
+        self.errorMessages = {
+            204: self.tr("Request limit has been reached."),
+            0: self.tr("Requested item is not present."),
+            -2: self.tr("Requested item is still queued."),
+        }
+    
+    def preferencesChanged(self):
+        """
+        Public slot to handle a change of preferences.
+        """
+        self.__loadSettings()
+    
+    def checkServiceKeyValidity(self, key, protocol=""):
+        """
+        Public method to check the validity of the given service key.
+        
+        @param key service key (string)
+        @param protocol protocol used to access VirusTotal (string)
+        """
+        if protocol == "":
+            urlStr = self.GetFileReportUrl
+        else:
+            urlStr = self.GetFileReportPattern.format(protocol)
+        request = QNetworkRequest(QUrl(urlStr))
+        request.setHeader(QNetworkRequest.ContentTypeHeader,
+                          "application/x-www-form-urlencoded")
+        params = QByteArray("apikey={0}&resource={1}".format(
+            key, self.TestServiceKeyScanID).encode("utf-8"))
+        
+        import WebBrowser.WebBrowserWindow
+        nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\
+            .networkManager()
+        reply = nam.post(request, params)
+        reply.finished.connect(self.__checkServiceKeyValidityFinished)
+        self.__replies.append(reply)
+    
+    def __checkServiceKeyValidityFinished(self):
+        """
+        Private slot to determine the result of the service key validity check.
+        """
+        res = False
+        msg = ""
+        
+        reply = self.sender()
+        if reply.error() == QNetworkReply.NoError:
+            res = True
+        elif reply.error() == self.ServiceCode_InvalidKey:
+            res = False
+        else:
+            msg = reply.errorString()
+        self.__replies.remove(reply)
+        reply.deleteLater()
+        
+        self.checkServiceKeyFinished.emit(res, msg)
+    
+    def submitUrl(self, url):
+        """
+        Public method to submit an URL to be scanned.
+        
+        @param url url to be scanned (QUrl)
+        """
+        request = QNetworkRequest(QUrl(self.ScanUrlUrl))
+        request.setHeader(QNetworkRequest.ContentTypeHeader,
+                          "application/x-www-form-urlencoded")
+        params = QByteArray("apikey={0}&url=".format(
+            Preferences.getHelp("VirusTotalServiceKey")).encode("utf-8"))\
+            .append(QUrl.toPercentEncoding(url.toString()))
+        
+        import WebBrowser.WebBrowserWindow
+        nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\
+            .networkManager()
+        reply = nam.post(request, params)
+        reply.finished.connect(self.__submitUrlFinished)
+        self.__replies.append(reply)
+    
+    def __submitUrlFinished(self):
+        """
+        Private slot to determine the result of the URL scan submission.
+        """
+        reply = self.sender()
+        if reply.error() == QNetworkReply.NoError:
+            result = json.loads(str(reply.readAll(), "utf-8"))
+            if result["response_code"] == self.ServiceResult_ItemPresent:
+                self.urlScanReport.emit(result["permalink"])
+                self.__getUrlScanReportUrl(result["scan_id"])
+            else:
+                if result["response_code"] in self.errorMessages:
+                    msg = self.errorMessages[result["response_code"]]
+                else:
+                    msg = result["verbose_msg"]
+                self.submitUrlError.emit(msg)
+        elif reply.error() == self.ServiceCode_RateLimitExceeded:
+            self.submitUrlError.emit(
+                self.errorMessages[result[self.ServiceCode_RateLimitExceeded]])
+        else:
+            self.submitUrlError.emit(reply.errorString())
+        self.__replies.remove(reply)
+        reply.deleteLater()
+    
+    def __getUrlScanReportUrl(self, scanId):
+        """
+        Private method to get the report URL for a URL scan.
+        
+        @param scanId ID of the scan to get the report URL for (string)
+        """
+        request = QNetworkRequest(QUrl(self.GetUrlReportUrl))
+        request.setHeader(QNetworkRequest.ContentTypeHeader,
+                          "application/x-www-form-urlencoded")
+        params = QByteArray("apikey={0}&resource={1}".format(
+            Preferences.getHelp("VirusTotalServiceKey"), scanId)
+            .encode("utf-8"))
+        
+        import WebBrowser.WebBrowserWindow
+        nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\
+            .networkManager()
+        reply = nam.post(request, params)
+        reply.finished.connect(self.__getUrlScanReportUrlFinished)
+        self.__replies.append(reply)
+    
+    def __getUrlScanReportUrlFinished(self):
+        """
+        Private slot to determine the result of the URL scan report URL
+        request.
+        """
+        reply = self.sender()
+        if reply.error() == QNetworkReply.NoError:
+            result = json.loads(str(reply.readAll(), "utf-8"))
+            if "filescan_id" in result and result["filescan_id"] is not None:
+                self.__getFileScanReportUrl(result["filescan_id"])
+        self.__replies.remove(reply)
+        reply.deleteLater()
+    
+    def __getFileScanReportUrl(self, scanId):
+        """
+        Private method to get the report URL for a file scan.
+        
+        @param scanId ID of the scan to get the report URL for (string)
+        """
+        request = QNetworkRequest(QUrl(self.GetFileReportUrl))
+        request.setHeader(QNetworkRequest.ContentTypeHeader,
+                          "application/x-www-form-urlencoded")
+        params = QByteArray("apikey={0}&resource={1}".format(
+            Preferences.getHelp("VirusTotalServiceKey"), scanId)
+            .encode("utf-8"))
+        
+        import WebBrowser.WebBrowserWindow
+        nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\
+            .networkManager()
+        reply = nam.post(request, params)
+        reply.finished.connect(self.__getFileScanReportUrlFinished)
+        self.__replies.append(reply)
+    
+    def __getFileScanReportUrlFinished(self):
+        """
+        Private slot to determine the result of the file scan report URL
+        request.
+        """
+        reply = self.sender()
+        if reply.error() == QNetworkReply.NoError:
+            result = json.loads(str(reply.readAll(), "utf-8"))
+            self.fileScanReport.emit(result["permalink"])
+        self.__replies.remove(reply)
+        reply.deleteLater()
+    
+    def getIpAddressReport(self, ipAddress):
+        """
+        Public method to retrieve a report for an IP address.
+        
+        @param ipAddress valid IPv4 address in dotted quad notation
+        @type str
+        """
+        self.__lastIP = ipAddress
+        
+        queryItems = [
+            ("apikey", Preferences.getHelp("VirusTotalServiceKey")),
+            ("ip", ipAddress),
+        ]
+        url = QUrl(self.GetIpAddressReportUrl)
+        if qVersion() >= "5.0.0":
+            from PyQt5.QtCore import QUrlQuery
+            query = QUrlQuery()
+            query.setQueryItems(queryItems)
+            url.setQuery(query)
+        else:
+            url.setQueryItems(queryItems)
+        request = QNetworkRequest(url)
+        
+        import WebBrowser.WebBrowserWindow
+        nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\
+            .networkManager()
+        reply = nam.get(request)
+        reply.finished.connect(self.__getIpAddressReportFinished)
+        self.__replies.append(reply)
+    
+    def __getIpAddressReportFinished(self):
+        """
+        Private slot to process the IP address report data.
+        """
+        reply = self.sender()
+        if reply.error() == QNetworkReply.NoError:
+            result = json.loads(str(reply.readAll(), "utf-8"))
+            if result["response_code"] == 0:
+                E5MessageBox.information(
+                    None,
+                    self.tr("VirusTotal IP Address Report"),
+                    self.tr("""VirusTotal does not have any information for"""
+                            """ the given IP address."""))
+            elif result["response_code"] == -1:
+                E5MessageBox.information(
+                    None,
+                    self.tr("VirusTotal IP Address Report"),
+                    self.tr("""The submitted IP address is invalid."""))
+            else:
+                owner = result["as_owner"]
+                resolutions = result["resolutions"]
+                try:
+                    urls = result["detected_urls"]
+                except KeyError:
+                    urls = []
+                
+                from .VirusTotalIpReportDialog import VirusTotalIpReportDialog
+                self.__ipReportDlg = VirusTotalIpReportDialog(
+                    self.__lastIP, owner, resolutions, urls)
+                self.__ipReportDlg.show()
+        self.__replies.remove(reply)
+        reply.deleteLater()
+    
+    def getDomainReport(self, domain):
+        """
+        Public method to retrieve a report for a domain.
+        
+        @param domain domain name
+        @type str
+        """
+        self.__lastDomain = domain
+        
+        queryItems = [
+            ("apikey", Preferences.getHelp("VirusTotalServiceKey")),
+            ("domain", domain),
+        ]
+        url = QUrl(self.GetDomainReportUrl)
+        if qVersion() >= "5.0.0":
+            from PyQt5.QtCore import QUrlQuery
+            query = QUrlQuery()
+            query.setQueryItems(queryItems)
+            url.setQuery(query)
+        else:
+            url.setQueryItems(queryItems)
+        request = QNetworkRequest(url)
+        
+        import WebBrowser.WebBrowserWindow
+        nam = WebBrowser.WebBrowserWindow.WebBrowserWindow\
+            .networkManager()
+        reply = nam.get(request)
+        reply.finished.connect(self.__getDomainReportFinished)
+        self.__replies.append(reply)
+    
+    def __getDomainReportFinished(self):
+        """
+        Private slot to process the IP address report data.
+        """
+        reply = self.sender()
+        if reply.error() == QNetworkReply.NoError:
+            result = json.loads(str(reply.readAll(), "utf-8"))
+            if result["response_code"] == 0:
+                E5MessageBox.information(
+                    None,
+                    self.tr("VirusTotal Domain Report"),
+                    self.tr("""VirusTotal does not have any information for"""
+                            """ the given domain."""))
+            elif result["response_code"] == -1:
+                E5MessageBox.information(
+                    None,
+                    self.tr("VirusTotal Domain Report"),
+                    self.tr("""The submitted domain address is invalid."""))
+            else:
+                resolutions = result["resolutions"]
+                try:
+                    urls = result["detected_urls"]
+                except KeyError:
+                    urls = []
+                try:
+                    subdomains = result["subdomains"]
+                except KeyError:
+                    subdomains = []
+                try:
+                    bdCategory = result["BitDefender category"]
+                except KeyError:
+                    bdCategory = self.tr("not available")
+                try:
+                    tmCategory = result["TrendMicro category"]
+                except KeyError:
+                    tmCategory = self.tr("not available")
+                try:
+                    wtsCategory = result["Websense ThreatSeeker category"]
+                except KeyError:
+                    wtsCategory = self.tr("not available")
+                try:
+                    whois = result["whois"]
+                except KeyError:
+                    whois = ""
+                
+                from .VirusTotalDomainReportDialog import \
+                    VirusTotalDomainReportDialog
+                self.__domainReportDlg = VirusTotalDomainReportDialog(
+                    self.__lastDomain, resolutions, urls, subdomains,
+                    bdCategory, tmCategory, wtsCategory, whois)
+                self.__domainReportDlg.show()
+        self.__replies.remove(reply)
+        reply.deleteLater()
+    
+    def close(self):
+        """
+        Public slot to close the API.
+        """
+        for reply in self.__replies:
+            reply.abort()
+        
+        self.__ipReportDlg and self.__ipReportDlg.close()
+        self.__domainReportDlg and self.__domainReportDlg.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalDomainReportDialog.py	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show the VirusTotal domain report.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSlot, Qt
+from PyQt5.QtWidgets import QDialog, QTreeWidgetItem
+
+from .Ui_VirusTotalDomainReportDialog import Ui_VirusTotalDomainReportDialog
+
+import UI.PixmapCache
+
+
+class VirusTotalDomainReportDialog(QDialog, Ui_VirusTotalDomainReportDialog):
+    """
+    Class implementing a dialog to show the VirusTotal domain report.
+    """
+    def __init__(self, domain, resolutions, urls, subdomains,
+                 bdCategory, tmCategory, wtsCategory, whois, parent=None):
+        """
+        Constructor
+        
+        @param domain domain name
+        @type str
+        @param resolutions list of resolved host names
+        @type list of dict
+        @param urls list of detected URLs
+        @type list of dict
+        @param subdomains list of subdomains
+        @type list of str
+        @param bdCategory BitDefender categorization
+        @type str
+        @param tmCategory TrendMicro categorization
+        @type str
+        @param wtsCategory Websense ThreatSeeker categorization
+        @type str
+        @param whois whois information
+        @type str
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(VirusTotalDomainReportDialog, self).__init__(parent)
+        self.setupUi(self)
+        self.setWindowFlags(Qt.Window)
+        
+        self.headerLabel.setText(
+            self.tr("<b>Report for domain {0}</b>").format(domain))
+        self.headerPixmap.setPixmap(
+            UI.PixmapCache.getPixmap("virustotal.png"))
+        
+        for resolution in resolutions:
+            QTreeWidgetItem(
+                self.resolutionsList,
+                [resolution["ip_address"],
+                 resolution["last_resolved"].split()[0]]
+            )
+        self.resolutionsList.resizeColumnToContents(0)
+        self.resolutionsList.resizeColumnToContents(1)
+        self.resolutionsList.sortByColumn(0, Qt.AscendingOrder)
+        
+        if not urls:
+            self.detectedUrlsGroup.setVisible(False)
+        for url in urls:
+            QTreeWidgetItem(
+                self.urlsList,
+                [url["url"],
+                 self.tr("{0}/{1}", "positives / total").format(
+                    url["positives"], url["total"]),
+                 url["scan_date"].split()[0]]
+            )
+        self.urlsList.resizeColumnToContents(0)
+        self.urlsList.resizeColumnToContents(1)
+        self.urlsList.resizeColumnToContents(2)
+        self.urlsList.sortByColumn(0, Qt.AscendingOrder)
+        
+        if not subdomains:
+            self.subdomainsGroup.setVisible(False)
+        else:
+            self.subdomainsList.addItems(subdomains)
+            self.subdomainsList.sortItems()
+        
+        self.bdLabel.setText(bdCategory)
+        self.tmLabel.setText(tmCategory)
+        self.wtsLabel.setText(wtsCategory)
+        
+        self.__whois = whois
+        self.__whoisDomain = domain
+        self.whoisButton.setEnabled(bool(whois))
+    
+    @pyqtSlot()
+    def on_whoisButton_clicked(self):
+        """
+        Private slot to show the whois information.
+        """
+        from .VirusTotalWhoisDialog import VirusTotalWhoisDialog
+        dlg = VirusTotalWhoisDialog(self.__whoisDomain, self.__whois)
+        dlg.exec_()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalDomainReportDialog.ui	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VirusTotalDomainReportDialog</class>
+ <widget class="QDialog" name="VirusTotalDomainReportDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>900</width>
+    <height>700</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Domain Report</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_4">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QLabel" name="headerPixmap"/>
+     </item>
+     <item>
+      <widget class="QLabel" name="headerLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line9_3">
+     <property name="frameShape">
+      <enum>QFrame::HLine</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Sunken</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QGroupBox" name="groupBox">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="title">
+        <string>Categorizations</string>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <layout class="QGridLayout" name="gridLayout">
+          <item row="0" column="0">
+           <widget class="QLabel" name="label">
+            <property name="text">
+             <string notr="true">BitDefender:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QLabel" name="bdLabel">
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_2">
+            <property name="text">
+             <string notr="true">TrendMicro:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QLabel" name="tmLabel">
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="0">
+           <widget class="QLabel" name="label_3">
+            <property name="text">
+             <string notr="true">Websense ThreatSeeker:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1">
+           <widget class="QLabel" name="wtsLabel">
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>690</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="whoisButton">
+       <property name="text">
+        <string>Whois</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QGroupBox" name="resolutionsGroup">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>4</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="title">
+        <string>Resolutions</string>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <item>
+         <widget class="QTreeWidget" name="resolutionsList">
+          <property name="alternatingRowColors">
+           <bool>true</bool>
+          </property>
+          <property name="rootIsDecorated">
+           <bool>false</bool>
+          </property>
+          <property name="sortingEnabled">
+           <bool>true</bool>
+          </property>
+          <property name="allColumnsShowFocus">
+           <bool>true</bool>
+          </property>
+          <column>
+           <property name="text">
+            <string>IP-Address</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>Resolved Date</string>
+           </property>
+          </column>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="subdomainsGroup">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>4</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="title">
+        <string>Subdomains</string>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QListWidget" name="subdomainsList">
+          <property name="alternatingRowColors">
+           <bool>true</bool>
+          </property>
+          <property name="sortingEnabled">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="detectedUrlsGroup">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>2</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Detected URLs</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <item>
+       <widget class="QTreeWidget" name="urlsList">
+        <property name="alternatingRowColors">
+         <bool>true</bool>
+        </property>
+        <property name="rootIsDecorated">
+         <bool>false</bool>
+        </property>
+        <property name="sortingEnabled">
+         <bool>true</bool>
+        </property>
+        <property name="allColumnsShowFocus">
+         <bool>true</bool>
+        </property>
+        <column>
+         <property name="text">
+          <string>URL</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Scan Result</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Scan Date</string>
+         </property>
+        </column>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>whoisButton</tabstop>
+  <tabstop>resolutionsList</tabstop>
+  <tabstop>subdomainsList</tabstop>
+  <tabstop>urlsList</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>VirusTotalDomainReportDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>VirusTotalDomainReportDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalIpReportDialog.py	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show the VirusTotal IP address report.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import Qt
+from PyQt5.QtWidgets import QDialog, QTreeWidgetItem
+
+from .Ui_VirusTotalIpReportDialog import Ui_VirusTotalIpReportDialog
+
+import UI.PixmapCache
+
+
+class VirusTotalIpReportDialog(QDialog, Ui_VirusTotalIpReportDialog):
+    """
+    Class implementing a dialog to show the VirusTotal IP address report.
+    """
+    def __init__(self, ip, owner, resolutions, urls, parent=None):
+        """
+        Constructor
+        
+        @param ip IP address
+        @type str
+        @param owner owner of the IP address
+        @type str
+        @param resolutions list of resolved host names
+        @type list of dict
+        @param urls list of detected URLs
+        @type list of dict
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(VirusTotalIpReportDialog, self).__init__(parent)
+        self.setupUi(self)
+        self.setWindowFlags(Qt.Window)
+        
+        self.headerLabel.setText(
+            self.tr("<b>Report for IP {0}</b>").format(ip))
+        self.headerPixmap.setPixmap(
+            UI.PixmapCache.getPixmap("virustotal.png"))
+        self.ownerLabel.setText(owner)
+        
+        for resolution in resolutions:
+            QTreeWidgetItem(
+                self.resolutionsList,
+                [resolution["hostname"],
+                 resolution["last_resolved"].split()[0]]
+            )
+        self.resolutionsList.resizeColumnToContents(0)
+        self.resolutionsList.resizeColumnToContents(1)
+        self.resolutionsList.sortByColumn(0, Qt.AscendingOrder)
+        
+        if not urls:
+            self.detectedUrlsGroup.setVisible(False)
+        for url in urls:
+            QTreeWidgetItem(
+                self.urlsList,
+                [url["url"],
+                 self.tr("{0}/{1}", "positives / total").format(
+                    url["positives"], url["total"]),
+                 url["scan_date"].split()[0]]
+            )
+        self.urlsList.resizeColumnToContents(0)
+        self.urlsList.resizeColumnToContents(1)
+        self.urlsList.resizeColumnToContents(2)
+        self.urlsList.sortByColumn(0, Qt.AscendingOrder)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalIpReportDialog.ui	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VirusTotalIpReportDialog</class>
+ <widget class="QDialog" name="VirusTotalIpReportDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>800</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>IP Address Report</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QLabel" name="headerPixmap"/>
+     </item>
+     <item>
+      <widget class="QLabel" name="headerLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line9_3">
+     <property name="frameShape">
+      <enum>QFrame::HLine</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Sunken</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Owner:</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="ownerLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="resolutionsGroup">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>4</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Resolutions</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <widget class="QTreeWidget" name="resolutionsList">
+        <property name="alternatingRowColors">
+         <bool>true</bool>
+        </property>
+        <property name="rootIsDecorated">
+         <bool>false</bool>
+        </property>
+        <property name="sortingEnabled">
+         <bool>true</bool>
+        </property>
+        <property name="allColumnsShowFocus">
+         <bool>true</bool>
+        </property>
+        <column>
+         <property name="text">
+          <string>Hostname</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Resolved Date</string>
+         </property>
+        </column>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="detectedUrlsGroup">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>2</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Detected URLs</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <item>
+       <widget class="QTreeWidget" name="urlsList">
+        <property name="alternatingRowColors">
+         <bool>true</bool>
+        </property>
+        <property name="rootIsDecorated">
+         <bool>false</bool>
+        </property>
+        <property name="sortingEnabled">
+         <bool>true</bool>
+        </property>
+        <property name="allColumnsShowFocus">
+         <bool>true</bool>
+        </property>
+        <column>
+         <property name="text">
+          <string>URL</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Scan Result</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Scan Date</string>
+         </property>
+        </column>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>VirusTotalIpReportDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>VirusTotalIpReportDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalWhoisDialog.py	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show the 'whois' information.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtWidgets import QDialog
+
+from .Ui_VirusTotalWhoisDialog import Ui_VirusTotalWhoisDialog
+
+import UI.PixmapCache
+
+
+class VirusTotalWhoisDialog(QDialog, Ui_VirusTotalWhoisDialog):
+    """
+    Class implementing a dialog to show the 'whois' information.
+    """
+    def __init__(self, domain, whois, parent=None):
+        """
+        Constructor
+        
+        @param domain domain name
+        @type str
+        @param whois whois information
+        @type str
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(VirusTotalWhoisDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.headerLabel.setText(
+            self.tr("<b>Whois information for domain {0}</b>").format(domain))
+        self.headerPixmap.setPixmap(
+            UI.PixmapCache.getPixmap("virustotal.png"))
+        self.whoisEdit.setPlainText(whois)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/VirusTotalWhoisDialog.ui	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VirusTotalWhoisDialog</class>
+ <widget class="QDialog" name="VirusTotalWhoisDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>500</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Whois Information</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QLabel" name="headerPixmap"/>
+     </item>
+     <item>
+      <widget class="QLabel" name="headerLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line9_3">
+     <property name="frameShape">
+      <enum>QFrame::HLine</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Sunken</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPlainTextEdit" name="whoisEdit">
+     <property name="tabChangesFocus">
+      <bool>true</bool>
+     </property>
+     <property name="lineWrapMode">
+      <enum>QPlainTextEdit::NoWrap</enum>
+     </property>
+     <property name="readOnly">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>VirusTotalWhoisDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>VirusTotalWhoisDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/VirusTotal/__init__.py	Sat Feb 20 14:34:32 2016 +0100
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package containing the VirusTotal interface.
+"""
--- a/WebBrowser/WebBrowserPage.py	Sat Feb 20 12:26:28 2016 +0100
+++ b/WebBrowser/WebBrowserPage.py	Sat Feb 20 14:34:32 2016 +0100
@@ -140,13 +140,13 @@
 ##        self.__lastRequest = None
 ##        self.__lastRequestType = QWebPage.NavigationTypeOther
 ##        
-##        import Helpviewer.HelpWindow
+##        import WebBrowser.WebBrowserWindow
 ##        from .Network.NetworkAccessManagerProxy import \
 ##            NetworkAccessManagerProxy
 ##        self.__proxy = NetworkAccessManagerProxy(self)
 ##        self.__proxy.setWebPage(self)
 ##        self.__proxy.setPrimaryNetworkAccessManager(
-##            Helpviewer.HelpWindow.HelpWindow.networkAccessManager())
+##            WebBrowser.WebBrowserWindow.WebBrowserWindow.networkAccessManager())
 ##        self.setNetworkAccessManager(self.__proxy)
         
         self.__sslConfiguration = None
@@ -452,8 +452,8 @@
 ##        @param url URL to determine user agent for (QUrl)
 ##        @return user agent string (string)
 ##        """
-##        import Helpviewer.HelpWindow
-##        agent = Helpviewer.HelpWindow.HelpWindow.userAgentsManager()\
+##        import WebBrowser.WebBrowserWindow
+##        agent = WebBrowser.WebBrowserWindow.WebBrowserWindow.userAgentsManager()\
 ##            .userAgentForUrl(url)
 ##        if agent == "":
 ##            # no agent string specified for the given host -> use global one
@@ -463,6 +463,7 @@
 ##                agent = QWebPage.userAgentForUrl(self, url)
 ##        return agent
 ##    
+    # TODO: SSL
 ##    def __managerFinished(self, reply):
 ##        """
 ##        Private slot to handle a finished reply.
@@ -496,8 +497,8 @@
 ##           reply.url() == self.mainFrame().url():
 ##            modified = reply.header(QNetworkRequest.LastModifiedHeader)
 ##            if modified and modified.isValid():
-##                import Helpviewer.HelpWindow
-##                manager = Helpviewer.HelpWindow.HelpWindow.bookmarksManager()
+##                import WebBrowser.WebBrowserWindow
+##                manager = WebBrowser.WebBrowserWindow.WebBrowserWindow.bookmarksManager()
 ##                from .Bookmarks.BookmarkNode import BookmarkNode
 ##                for bookmark in manager.bookmarksForUrl(reply.url()):
 ##                    manager.setTimestamp(bookmark, BookmarkNode.TsModified,
--- a/WebBrowser/WebBrowserView.py	Sat Feb 20 12:26:28 2016 +0100
+++ b/WebBrowser/WebBrowserView.py	Sat Feb 20 14:34:32 2016 +0100
@@ -88,8 +88,8 @@
         self.installEventFilter(self)
         
         # TODO: Speeddial
-##        import Helpviewer.HelpWindow
-##        self.__speedDial = Helpviewer.HelpWindow.HelpWindow.speedDial()
+##        import WebBrowser.WebBrowserWindow
+##        self.__speedDial = WebBrowser.WebBrowserWindow.WebBrowserWindow.speedDial()
         
         self.__page = WebBrowserPage(self)
         self.setPage(self.__page)
@@ -105,9 +105,6 @@
         
         self.__currentZoom = 100
         self.__zoomLevels = WebBrowserView.ZoomLevels[:]
-##        
-##        self.__javaScriptBinding = None
-##        self.__javaScriptEricObject = None
         
 ##        self.__mw.zoomTextOnlyChanged.connect(self.__applyZoom)
         
@@ -126,9 +123,6 @@
 ##        self.page().setForwardUnsupportedContent(True)
 ##        self.page().unsupportedContent.connect(self.__unsupportedContent)
         
-##        self.page().frameCreated.connect(self.__addExternalBinding)
-##        self.__addExternalBinding(self.page().mainFrame())
-        
 ##        self.page().databaseQuotaExceeded.connect(self.__databaseQuotaExceeded)
         
         self.__mw.openSearchManager().currentEngineChanged.connect(
@@ -330,11 +324,6 @@
                         """ for URL <b>{0}</b>.</p>""")
                     .format(name.toString()))
             return
-##        elif name.scheme() == "javascript":
-##            scriptSource = QUrl.fromPercentEncoding(name.toString(
-##                QUrl.FormattingOptions(QUrl.TolerantMode | QUrl.RemoveScheme)))
-##            self.page().mainFrame().evaluateJavaScript(scriptSource)
-##            return
         else:
             if name.toString().endswith(".pdf") or \
                name.toString().endswith(".PDF") or \
@@ -689,13 +678,12 @@
             UI.PixmapCache.getIcon("mailSend.png"),
             self.tr("Send Link"),
             self.__sendLink).setData(hitTest.linkUrl())
-        # TODO: VirusTotal
-##        if Preferences.getWebBrowser("VirusTotalEnabled") and \
-##           Preferences.getWebBrowser("VirusTotalServiceKey") != "":
-##            menu.addAction(
-##                UI.PixmapCache.getIcon("virustotal.png"),
-##                self.tr("Scan Link with VirusTotal"),
-##                self.__virusTotal).setData(hitTest.linkUrl())
+        if Preferences.getWebBrowser("VirusTotalEnabled") and \
+           Preferences.getWebBrowser("VirusTotalServiceKey") != "":
+            menu.addAction(
+                UI.PixmapCache.getIcon("virustotal.png"),
+                self.tr("Scan Link with VirusTotal"),
+                self.__virusTotal).setData(hitTest.linkUrl())
         
     def __createImageContextMenu(self, menu, hitTest):
         """
@@ -735,13 +723,12 @@
 ##            UI.PixmapCache.getIcon("adBlockPlus.png"),
 ##            self.tr("Block Image"), self.__blockImage)\
 ##            .setData(hitTest.imageUrl().toString())
-        # TODO: VirusTotal
-##        if Preferences.getWebBrowser("VirusTotalEnabled") and \
-##           Preferences.getWebBrowser("VirusTotalServiceKey") != "":
-##            menu.addAction(
-##                UI.PixmapCache.getIcon("virustotal.png"),
-##                self.tr("Scan Image with VirusTotal"),
-##                self.__virusTotal).setData(hitTest.imageUrl())
+        if Preferences.getWebBrowser("VirusTotalEnabled") and \
+           Preferences.getWebBrowser("VirusTotalServiceKey") != "":
+            menu.addAction(
+                UI.PixmapCache.getIcon("virustotal.png"),
+                self.tr("Scan Image with VirusTotal"),
+                self.__virusTotal).setData(hitTest.imageUrl())
     
     def __createMediaContextMenu(self, menu, hitTest):
         """
@@ -1029,10 +1016,10 @@
 ##        """
 ##        Private slot to add a block rule for an image URL.
 ##        """
-##        import Helpviewer.HelpWindow
+##        import WebBrowser.WebBrowserWindow
 ##        act = self.sender()
 ##        url = act.data()
-##        dlg = Helpviewer.HelpWindow.HelpWindow.adBlockManager().showDialog()
+##        dlg = WebBrowser.WebBrowserWindow.WebBrowserWindow.adBlockManager().showDialog()
 ##        dlg.addCustomRule(url)
     
     # TODO: DownloadManager
@@ -1060,14 +1047,13 @@
         script = Scripts.toggleMediaMute(self.__clickedPos)
         self.page().runJavaScript(script)
     
-    # TODO: VirusTotal
-##    def __virusTotal(self):
-##        """
-##        Private slot to scan the selected URL with VirusTotal.
-##        """
-##        act = self.sender()
-##        url = act.data()
-##        self.__mw.requestVirusTotalScan(url)
+    def __virusTotal(self):
+        """
+        Private slot to scan the selected URL with VirusTotal.
+        """
+        act = self.sender()
+        url = act.data()
+        self.__mw.requestVirusTotalScan(url)
     
     def __searchRequested(self, act):
         """
@@ -1152,14 +1138,6 @@
         dlg.setTitle(self.title())
         dlg.setDescription(description)
         dlg.exec_()
-##        from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog
-##        dlg = AddBookmarkDialog()
-##        dlg.setUrl(bytes(self.url().toEncoded()).decode())
-##        dlg.setTitle(self.title())
-##        meta = self.page().mainFrame().metaData()
-##        if "description" in meta:
-##            dlg.setDescription(meta["description"][0])
-##        dlg.exec_()
     
     def dragEnterEvent(self, evt):
         """
--- a/WebBrowser/WebBrowserWindow.py	Sat Feb 20 12:26:28 2016 +0100
+++ b/WebBrowser/WebBrowserWindow.py	Sat Feb 20 14:34:32 2016 +0100
@@ -38,7 +38,7 @@
 from E5Gui.E5Application import e5App
 from E5Gui.E5ZoomWidget import E5ZoomWidget
 
-##from E5Network.E5NetworkIcon import E5NetworkIcon
+from E5Network.E5NetworkIcon import E5NetworkIcon
 
 import Preferences
 from Preferences import Shortcuts
@@ -137,21 +137,6 @@
             self.__initActions()
         else:
             self.webProfile(private)
-##            if self.isPrivate():
-##                self.__webProfile = QWebEngineProfile(self)
-##            else:
-##                self.__webProfile = QWebEngineProfile.defaultProfile()
-##            self.__webProfile.downloadRequested.connect(
-##                self.__downloadRequested)
-##            
-##            # Setup QWebChannel user script
-##            script = QWebEngineScript()
-##            script.setName("_eric_webchannel")
-##            script.setInjectionPoint(QWebEngineScript.DocumentCreation)
-##            script.setWorldId(QWebEngineScript.MainWorld)
-##            script.setRunsOnSubFrames(True)
-##            script.setSourceCode(Scripts.setupWebChannel())
-##            self.__webProfile.scripts().insert(script)
             
             from .SearchWidget import SearchWidget
             # TODO: QtHelp
@@ -162,8 +147,7 @@
             from .WebBrowserTabWidget import WebBrowserTabWidget
             # TODO: AdBlock
 ##            from .AdBlock.AdBlockIcon import AdBlockIcon
-            # TODO: VirusTotal
-##            from .VirusTotal.VirusTotalApi import VirusTotalAPI
+            from .VirusTotal.VirusTotalApi import VirusTotalAPI
             
             # TODO: allow using Qt Help even if not called from eric6
             WebBrowserWindow.setUseQtHelp(self.__fromEric)
@@ -268,8 +252,9 @@
             self.__initMenus()
             self.__initToolbars()
             
-##            self.historyManager()
-##            
+            self.historyManager()
+            
+            # TODO: Sync
 ##            syncMgr = self.syncManager()
 ##            syncMgr.syncMessage.connect(self.statusBar().showMessage)
 ##            syncMgr.syncError.connect(self.statusBar().showMessage)
@@ -279,6 +264,7 @@
             
             WebBrowserWindow.BrowserWindows.append(self)
             
+            # TODO: AdBlock
 ##            self.__adBlockIcon = AdBlockIcon(self)
 ##            self.statusBar().addPermanentWidget(self.__adBlockIcon)
 ##            self.__adBlockIcon.setEnabled(
@@ -288,9 +274,9 @@
 ##            self.__tabWidget.sourceChanged.connect(
 ##                self.__adBlockIcon.sourceChanged)
 ##            
-##            self.networkIcon = E5NetworkIcon(self)
-##            self.statusBar().addPermanentWidget(self.networkIcon)
-##            
+            self.networkIcon = E5NetworkIcon(self)
+            self.statusBar().addPermanentWidget(self.networkIcon)
+            
             QDesktopServices.setUrlHandler("http", self.__linkActivated)
             QDesktopServices.setUrlHandler("https", self.__linkActivated)
             
@@ -317,21 +303,22 @@
             state = Preferences.getWebBrowser("WebBrowserState")
             self.restoreState(state)
             
+            # TODO: QtHelp
 ##            self.__initHelpDb()
             
-##            self.__virusTotal = VirusTotalAPI(self)
-##            self.__virusTotal.submitUrlError.connect(
-##                self.__virusTotalSubmitUrlError)
-##            self.__virusTotal.urlScanReport.connect(
-##                self.__virusTotalUrlScanReport)
-##            self.__virusTotal.fileScanReport.connect(
-##                self.__virusTotalFileScanReport)
-##            
+            self.__virusTotal = VirusTotalAPI(self)
+            self.__virusTotal.submitUrlError.connect(
+                self.__virusTotalSubmitUrlError)
+            self.__virusTotal.urlScanReport.connect(
+                self.__virusTotalUrlScanReport)
+            self.__virusTotal.fileScanReport.connect(
+                self.__virusTotalFileScanReport)
+            
             self.__previewer = None
             self.__shutdownCalled = False
             
-##            self.flashCookieManager()
-##            
+            self.flashCookieManager()
+            
             # TODO: QtHelp, do these once Qt 5.6 is available
 ##            if WebBrowserWindow.UseQtHelp:
 ##                QTimer.singleShot(0, self.__lookForNewDocumentation)
@@ -341,6 +328,7 @@
             self.__lastActiveWindow = None
             e5App().focusChanged[QWidget, QWidget].connect(
                 self.__appFocusChanged)
+            #TODO: Sync
 ##            
 ##            QTimer.singleShot(0, syncMgr.loadSettings)
     
@@ -386,6 +374,7 @@
         """
         standardFont = Preferences.getWebBrowser("StandardFont")
         fixedFont = Preferences.getWebBrowser("FixedFont")
+        # TODO: Fonts: add support for other font types
 
         settings = QWebEngineSettings.globalSettings()
 ##        settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
@@ -578,6 +567,7 @@
         if not self.__initShortcutsOnly:
             self.openTabAct.triggered.connect(self.__openFileNewTab)
         self.__actions.append(self.openTabAct)
+        # TODO: Save
 ##        
 ##        self.saveAsAct = E5Action(
 ##            self.tr('Save As'),
@@ -1386,7 +1376,7 @@
                 self.__showFeaturePermissionDialog)
         self.__actions.append(self.featurePermissionAct)
         
-        # TODO: re-enable once Qt 5.6 is available
+        # TODO: QtHelp: re-enable once Qt 5.6 is available
 ##        if WebBrowserWindow.UseQtHelp or self.__initShortcutsOnly:
 ##            self.syncTocAct = E5Action(
 ##                self.tr('Sync with Table of Contents'),
@@ -1883,6 +1873,7 @@
 ##        menu.addAction(self.userAgentManagerAct)
 ##        menu.addSeparator()
         
+        # TODO: QtHelp
 ##        if WebBrowserWindow.UseQtHelp:
 ##            menu.addAction(self.manageQtHelpDocsAct)
 ##            menu.addAction(self.manageQtHelpFiltersAct)
@@ -1891,8 +1882,8 @@
         menu.addAction(self.clearPrivateDataAct)
         menu.addAction(self.clearIconsAct)
         
-##        menu = mb.addMenu(self.tr("&Tools"))
-##        menu.setTearOffEnabled(True)
+        menu = mb.addMenu(self.tr("&Tools"))
+        menu.setTearOffEnabled(True)
 ##        menu.addAction(self.feedsManagerAct)
 ##        menu.addAction(self.siteInfoAct)
 ##        menu.addSeparator()
@@ -1975,6 +1966,7 @@
         findtb.addAction(self.findNextAct)
         findtb.addAction(self.findPrevAct)
         
+        # TODO: QtHelp
 ##        if WebBrowserWindow.UseQtHelp:
 ##            filtertb = self.addToolBar(self.tr("Filter"))
 ##            filtertb.setObjectName("FilterToolBar")
@@ -2000,9 +1992,9 @@
 ##        settingstb.addAction(self.greaseMonkeyAct)
         settingstb.addAction(self.featurePermissionAct)
         
-##        toolstb = self.addToolBar(self.tr("Tools"))
-##        toolstb.setObjectName("ToolsToolBar")
-##        toolstb.setIconSize(UI.Config.ToolBarIconSize)
+        toolstb = self.addToolBar(self.tr("Tools"))
+        toolstb.setObjectName("ToolsToolBar")
+        toolstb.setIconSize(UI.Config.ToolBarIconSize)
 ##        toolstb.addAction(self.feedsManagerAct)
 ##        toolstb.addAction(self.siteInfoAct)
 ##        toolstb.addSeparator()
@@ -2067,28 +2059,28 @@
         self.addToolBarBreak()
         self.addToolBar(self.bookmarksToolBar)
         
-##        self.addToolBarBreak()
-##        vttb = self.addToolBar(self.tr("VirusTotal"))
-##        vttb.setObjectName("VirusTotalToolBar")
-##        vttb.setIconSize(UI.Config.ToolBarIconSize)
-##        vttb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
-##        self.virustotalScanCurrentAct = vttb.addAction(
-##            UI.PixmapCache.getIcon("virustotal.png"),
-##            self.tr("Scan current site"),
-##            self.__virusTotalScanCurrentSite)
-##        self.virustotalIpReportAct = vttb.addAction(
-##            UI.PixmapCache.getIcon("virustotal.png"),
-##            self.tr("IP Address Report"),
-##            self.__virusTotalIpAddressReport)
-##        self.virustotalDomainReportAct = vttb.addAction(
-##            UI.PixmapCache.getIcon("virustotal.png"),
-##            self.tr("Domain Report"),
-##            self.__virusTotalDomainReport)
-##        if not Preferences.getWebBrowser("VirusTotalEnabled") or \
-##           Preferences.getWebBrowser("VirusTotalServiceKey") == "":
-##            self.virustotalScanCurrentAct.setEnabled(False)
-##            self.virustotalIpReportAct.setEnabled(False)
-##            self.virustotalDomainReportAct.setEnabled(False)
+        self.addToolBarBreak()
+        vttb = self.addToolBar(self.tr("VirusTotal"))
+        vttb.setObjectName("VirusTotalToolBar")
+        vttb.setIconSize(UI.Config.ToolBarIconSize)
+        vttb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
+        self.virustotalScanCurrentAct = vttb.addAction(
+            UI.PixmapCache.getIcon("virustotal.png"),
+            self.tr("Scan current site"),
+            self.__virusTotalScanCurrentSite)
+        self.virustotalIpReportAct = vttb.addAction(
+            UI.PixmapCache.getIcon("virustotal.png"),
+            self.tr("IP Address Report"),
+            self.__virusTotalIpAddressReport)
+        self.virustotalDomainReportAct = vttb.addAction(
+            UI.PixmapCache.getIcon("virustotal.png"),
+            self.tr("Domain Report"),
+            self.__virusTotalDomainReport)
+        if not Preferences.getWebBrowser("VirusTotalEnabled") or \
+           Preferences.getWebBrowser("VirusTotalServiceKey") == "":
+            self.virustotalScanCurrentAct.setEnabled(False)
+            self.virustotalIpReportAct.setEnabled(False)
+            self.virustotalDomainReportAct.setEnabled(False)
         
     def __nextTab(self):
         """
@@ -2480,8 +2472,8 @@
         self.bookmarksToolBar.setModel(None)
         self.bookmarksManager().close()
         
-##        self.historyManager().close()
-##        
+        self.historyManager().close()
+        
         self.passwordManager().close()
         
 ##        self.adBlockManager().close()
@@ -2495,13 +2487,14 @@
         ZoomManager.instance().close()
         
         WebIconProvider.instance().close()
-##        
-##        self.__virusTotal.close()
-##        
-##        self.flashCookieManager().shutdown()
-##        
+        
+        self.__virusTotal.close()
+        
+        self.flashCookieManager().shutdown()
+        
         self.searchEdit.openSearchManager().close()
         
+        # TODO: QtHelp
 ##        if WebBrowserWindow.UseQtHelp:
 ##            self.__searchEngine.cancelIndexing()
 ##            self.__searchEngine.cancelSearching()
@@ -2669,6 +2662,7 @@
         Private slot to handle the select all action.
         """
         self.currentBrowser().selectAll()
+    # TODO: Private Browsing
 ##    
 ##    def __privateBrowsing(self):
 ##        """
@@ -2803,17 +2797,16 @@
         
         self.searchEdit.preferencesChanged()
         
-        # TODO: VirusTotal
-##        self.__virusTotal.preferencesChanged()
-##        if not Preferences.getWebBrowser("VirusTotalEnabled") or \
-##           Preferences.getWebBrowser("VirusTotalServiceKey") == "":
-##            self.virustotalScanCurrentAct.setEnabled(False)
-##            self.virustotalIpReportAct.setEnabled(False)
-##            self.virustotalDomainReportAct.setEnabled(False)
-##        else:
-##            self.virustotalScanCurrentAct.setEnabled(True)
-##            self.virustotalIpReportAct.setEnabled(True)
-##            self.virustotalDomainReportAct.setEnabled(True)
+        self.__virusTotal.preferencesChanged()
+        if not Preferences.getWebBrowser("VirusTotalEnabled") or \
+           Preferences.getWebBrowser("VirusTotalServiceKey") == "":
+            self.virustotalScanCurrentAct.setEnabled(False)
+            self.virustotalIpReportAct.setEnabled(False)
+            self.virustotalDomainReportAct.setEnabled(False)
+        else:
+            self.virustotalScanCurrentAct.setEnabled(True)
+            self.virustotalIpReportAct.setEnabled(True)
+            self.virustotalDomainReportAct.setEnabled(True)
     
     def masterPasswordChanged(self, oldPassword, newPassword):
         """
@@ -2876,6 +2869,7 @@
         else:
             cls.useQtHelp = False
     
+    # TODO: QtHelp
 ##    @classmethod
 ##    def helpEngine(cls):
 ##        """
@@ -2938,6 +2932,7 @@
             self.currentBrowser().setUrl(url)
             self.__activating = False
         
+    # TODO: QtHelp
 ##    def __linksActivated(self, links, keyword):
 ##        """
 ##        Private slot to select a topic to be shown.
@@ -2960,6 +2955,7 @@
         """
         self.currentBrowser().setFocus()
         
+    # TODO: QtHelp
 ##    def __syncTOC(self):
 ##        """
 ##        Private slot to synchronize the TOC with the currently shown page.
@@ -3771,7 +3767,8 @@
             self.currentBrowser().triggerPageAction(QWebEnginePage.Forward)
         else:
             super(WebBrowserWindow, self).mousePressEvent(evt)
-
+    
+    # TODO: RSS
 ##    @classmethod
 ##    def feedsManager(cls):
 ##        """
@@ -3804,6 +3801,7 @@
 ##        feedsManager.newUrl.disconnect(self.openUrlNewTab)
 ##        feedsManager.rejected.disconnect(self.__feedsManagerClosed)
 ##    
+    # TODO: Site Info
 ##    def __showSiteinfoDialog(self):
 ##        """
 ##        Private slot to show the site info dialog.
@@ -3812,6 +3810,7 @@
 ##        self.__siteinfoDialog = SiteInfoDialog(self.currentBrowser(), self)
 ##        self.__siteinfoDialog.show()
 ##
+    # TODO: User Agents
 ##    @classmethod
 ##    def userAgentsManager(cls):
 ##        """
@@ -3834,6 +3833,7 @@
 ##        dlg = UserAgentsDialog(self)
 ##        dlg.exec_()
 ##    
+    # TODO: Sync
 ##    @classmethod
 ##    def syncManager(cls):
 ##        """
@@ -3853,6 +3853,7 @@
 ##        """
 ##        self.syncManager().showSyncDialog()
 ##    
+    # TODO: SpeedDial
 ##    @classmethod
 ##    def speedDial(cls):
 ##        """
@@ -3902,6 +3903,7 @@
                     number = self.__tabWidget.count()
                 self.__tabWidget.setCurrentIndex(number - 1)
                 return
+        # TODO: SpeeedDial
 ##            
 ##            if evt.modifiers() == Qt.KeyboardModifiers(Qt.MetaModifier):
 ##                url = self.speedDial().urlForShortcut(number - 1)
@@ -3911,87 +3913,87 @@
         
         super(WebBrowserWindow, self).keyPressEvent(evt)
     
-##    ###########################################################################
-##    ## Interface to VirusTotal below                                         ##
-##    ###########################################################################
-##    
-##    def __virusTotalScanCurrentSite(self):
-##        """
-##        Private slot to ask VirusTotal for a scan of the URL of the current
-##        browser.
-##        """
-##        cb = self.currentBrowser()
-##        if cb is not None:
-##            url = cb.url()
-##            if url.scheme() in ["http", "https", "ftp"]:
-##                self.requestVirusTotalScan(url)
-##    
-##    def requestVirusTotalScan(self, url):
-##        """
-##        Public method to submit a request to scan an URL by VirusTotal.
-##        
-##        @param url URL to be scanned (QUrl)
-##        """
-##        self.__virusTotal.submitUrl(url)
-##    
-##    def __virusTotalSubmitUrlError(self, msg):
-##        """
-##        Private slot to handle an URL scan submission error.
-##        
-##        @param msg error message (str)
-##        """
-##        E5MessageBox.critical(
-##            self,
-##            self.tr("VirusTotal Scan"),
-##            self.tr("""<p>The VirusTotal scan could not be"""
-##                    """ scheduled.<p>\n<p>Reason: {0}</p>""").format(msg))
-##    
-##    def __virusTotalUrlScanReport(self, url):
-##        """
-##        Private slot to initiate the display of the URL scan report page.
-##        
-##        @param url URL of the URL scan report page (string)
-##        """
-##        self.newTab(url)
-##    
-##    def __virusTotalFileScanReport(self, url):
-##        """
-##        Private slot to initiate the display of the file scan report page.
-##        
-##        @param url URL of the file scan report page (string)
-##        """
-##        self.newTab(url)
-##    
-##    def __virusTotalIpAddressReport(self):
-##        """
-##        Private slot to retrieve an IP address report.
-##        """
-##        ip, ok = QInputDialog.getText(
-##            self,
-##            self.tr("IP Address Report"),
-##            self.tr("Enter a valid IPv4 address in dotted quad notation:"),
-##            QLineEdit.Normal)
-##        if ok and ip:
-##            if ip.count(".") == 3:
-##                self.__virusTotal.getIpAddressReport(ip)
-##            else:
-##                E5MessageBox.information(
-##                    self,
-##                    self.tr("IP Address Report"),
-##                    self.tr("""The given IP address is not in dotted quad"""
-##                            """ notation."""))
-##    
-##    def __virusTotalDomainReport(self):
-##        """
-##        Private slot to retrieve a domain report.
-##        """
-##        domain, ok = QInputDialog.getText(
-##            self,
-##            self.tr("Domain Report"),
-##            self.tr("Enter a valid domain name:"),
-##            QLineEdit.Normal)
-##        if ok and domain:
-##            self.__virusTotal.getDomainReport(domain)
+    ###########################################################################
+    ## Interface to VirusTotal below                                         ##
+    ###########################################################################
+    
+    def __virusTotalScanCurrentSite(self):
+        """
+        Private slot to ask VirusTotal for a scan of the URL of the current
+        browser.
+        """
+        cb = self.currentBrowser()
+        if cb is not None:
+            url = cb.url()
+            if url.scheme() in ["http", "https", "ftp"]:
+                self.requestVirusTotalScan(url)
+    
+    def requestVirusTotalScan(self, url):
+        """
+        Public method to submit a request to scan an URL by VirusTotal.
+        
+        @param url URL to be scanned (QUrl)
+        """
+        self.__virusTotal.submitUrl(url)
+    
+    def __virusTotalSubmitUrlError(self, msg):
+        """
+        Private slot to handle an URL scan submission error.
+        
+        @param msg error message (str)
+        """
+        E5MessageBox.critical(
+            self,
+            self.tr("VirusTotal Scan"),
+            self.tr("""<p>The VirusTotal scan could not be"""
+                    """ scheduled.<p>\n<p>Reason: {0}</p>""").format(msg))
+    
+    def __virusTotalUrlScanReport(self, url):
+        """
+        Private slot to initiate the display of the URL scan report page.
+        
+        @param url URL of the URL scan report page (string)
+        """
+        self.newTab(url)
+    
+    def __virusTotalFileScanReport(self, url):
+        """
+        Private slot to initiate the display of the file scan report page.
+        
+        @param url URL of the file scan report page (string)
+        """
+        self.newTab(url)
+    
+    def __virusTotalIpAddressReport(self):
+        """
+        Private slot to retrieve an IP address report.
+        """
+        ip, ok = QInputDialog.getText(
+            self,
+            self.tr("IP Address Report"),
+            self.tr("Enter a valid IPv4 address in dotted quad notation:"),
+            QLineEdit.Normal)
+        if ok and ip:
+            if ip.count(".") == 3:
+                self.__virusTotal.getIpAddressReport(ip)
+            else:
+                E5MessageBox.information(
+                    self,
+                    self.tr("IP Address Report"),
+                    self.tr("""The given IP address is not in dotted quad"""
+                            """ notation."""))
+    
+    def __virusTotalDomainReport(self):
+        """
+        Private slot to retrieve a domain report.
+        """
+        domain, ok = QInputDialog.getText(
+            self,
+            self.tr("Domain Report"),
+            self.tr("Enter a valid domain name:"),
+            QLineEdit.Normal)
+        if ok and domain:
+            self.__virusTotal.getDomainReport(domain)
     
     ###########################################################################
     ## Style sheet handling below                                            ##
--- a/eric6.e4p	Sat Feb 20 12:26:28 2016 +0100
+++ b/eric6.e4p	Sat Feb 20 14:34:32 2016 +0100
@@ -1348,6 +1348,11 @@
     <Source>WebBrowser/UrlBar/StackedUrlBar.py</Source>
     <Source>WebBrowser/UrlBar/UrlBar.py</Source>
     <Source>WebBrowser/UrlBar/__init__.py</Source>
+    <Source>WebBrowser/VirusTotal/VirusTotalApi.py</Source>
+    <Source>WebBrowser/VirusTotal/VirusTotalDomainReportDialog.py</Source>
+    <Source>WebBrowser/VirusTotal/VirusTotalIpReportDialog.py</Source>
+    <Source>WebBrowser/VirusTotal/VirusTotalWhoisDialog.py</Source>
+    <Source>WebBrowser/VirusTotal/__init__.py</Source>
     <Source>WebBrowser/WebBrowserClearPrivateDataDialog.py</Source>
     <Source>WebBrowser/WebBrowserPage.py</Source>
     <Source>WebBrowser/WebBrowserTabBar.py</Source>
@@ -1772,6 +1777,9 @@
     <Form>WebBrowser/SearchWidget.ui</Form>
     <Form>WebBrowser/UrlBar/BookmarkActionSelectionDialog.ui</Form>
     <Form>WebBrowser/UrlBar/BookmarkInfoDialog.ui</Form>
+    <Form>WebBrowser/VirusTotal/VirusTotalDomainReportDialog.ui</Form>
+    <Form>WebBrowser/VirusTotal/VirusTotalIpReportDialog.ui</Form>
+    <Form>WebBrowser/VirusTotal/VirusTotalWhoisDialog.ui</Form>
     <Form>WebBrowser/WebBrowserClearPrivateDataDialog.ui</Form>
     <Form>WebBrowser/ZoomManager/ZoomValuesDialog.ui</Form>
   </Forms>

eric ide

mercurial