From 684eb9669bfe382a5fda656f9eb559490e9e23fa Mon Sep 17 00:00:00 2001 From: Anton Thomasson Date: Sun, 5 Jan 2020 18:41:24 +0100 Subject: [PATCH] Make ippdiscovery a QQuickImageProvider... ...so that SSL errors can be ignored, and .local-addresses can be resolved --- qml/pages/FirstPage.qml | 22 +++++------- src/harbour-seaprint.cpp | 30 ++++++++++------ src/ippdiscovery.cpp | 76 +++++++++++++++++++++++++++++++++++++++- src/ippdiscovery.h | 22 ++++++++++-- 4 files changed, 122 insertions(+), 28 deletions(-) diff --git a/qml/pages/FirstPage.qml b/qml/pages/FirstPage.qml index 866ccfd..4ec8511 100644 --- a/qml/pages/FirstPage.qml +++ b/qml/pages/FirstPage.qml @@ -14,10 +14,6 @@ Page { property string selectedFile: "" property string selectedFileType - IppDiscovery { - id: discovery - } - WifiChecker { id: wifi onConnectedChanged: { @@ -25,10 +21,10 @@ Page { if(connected) { var favourites = db.getFavourites(ssid); console.log(favourites); - discovery.favourites = favourites; + IppDiscovery.favourites = favourites; } else { - discovery.favourites = [] + IppDiscovery.favourites = [] } } @@ -39,7 +35,7 @@ Page { console.log("ssid changed", ssid); if(!initialSSIDchange) { - discovery.reset(); + IppDiscovery.reset(); } initialSSIDchange = false; } @@ -48,7 +44,7 @@ Page { signal refreshed() Component.onCompleted: { - discovery.discover(); + IppDiscovery.discover(); if(selectedFile != "") { // Until i can convince FilePickerPage to do its magic without user interaction if(Utils.endsWith(".pdf", selectedFile)) @@ -85,14 +81,14 @@ Page { dialog.accepted.connect(function() { console.log("add", wifi.ssid, dialog.value); db.addFavourite(wifi.ssid, dialog.value); - discovery.favourites = db.getFavourites(wifi.ssid); + IppDiscovery.favourites = db.getFavourites(wifi.ssid); }) } } MenuItem { text: qsTr("Refresh") onClicked: { - discovery.discover(); + IppDiscovery.discover(); page.refreshed(); } } @@ -101,7 +97,7 @@ Page { SilicaListView { anchors.fill: parent id: listView - model: discovery + model: IppDiscovery spacing: Theme.paddingSmall @@ -162,7 +158,7 @@ Page { height: Theme.itemSizeLarge width: Theme.itemSizeLarge - source: printer.attrs["printer-icons"] ? printer.attrs["printer-icons"].value[0] : "icon-seaprint-nobg.svg" + source: printer.attrs["printer-icons"] ? "image://ippdiscovery/"+printer.attrs["printer-icons"].value[0] : "icon-seaprint-nobg.svg" // Some printers serve their icons over https with invalid certs... onStatusChanged: if (status == Image.Error) source = "icon-seaprint-nobg.svg" } @@ -215,7 +211,7 @@ Page { onClicked: { removeRemorse.execute(delegate, qsTr("Removing printer"), function() {db.removeFavourite(wifi.ssid, model.display); - discovery.favourites = db.getFavourites()}) + IppDiscovery.favourites = db.getFavourites()}) } } } diff --git a/src/harbour-seaprint.cpp b/src/harbour-seaprint.cpp index 23b5446..422372d 100644 --- a/src/harbour-seaprint.cpp +++ b/src/harbour-seaprint.cpp @@ -5,24 +5,32 @@ #include #include +static QObject* ippdiscovery_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + IppDiscovery *ippdiscovery = IppDiscovery::instance(); + return ippdiscovery; + +} + int main(int argc, char *argv[]) { QGuiApplication* app = SailfishApp::application(argc, argv); app->setApplicationVersion(QStringLiteral(SEAPRINT_VERSION)); - qmlRegisterType("seaprint.ippdiscovery", 1, 0, "IppDiscovery"); + qmlRegisterSingletonType("seaprint.ippdiscovery", 1, 0, "IppDiscovery", ippdiscovery_singletontype_provider); qmlRegisterType("seaprint.ippprinter", 1, 0, "IppPrinter"); - // SailfishApp::main() will display "qml/harbour-printtool.qml", if you need more - // control over initialization, you can use: - // - // - SailfishApp::application(int, char *[]) to get the QGuiApplication * - // - SailfishApp::createView() to get a new QQuickView * instance - // - SailfishApp::pathTo(QString) to get a QUrl to a resource file - // - SailfishApp::pathToMainQml() to get a QUrl to the main QML file - // - // To display the view, call "show()" (will show fullscreen on device). + QQuickView* view = SailfishApp::createView(); + + view->engine()->addImportPath(SailfishApp::pathTo("qml/pages").toString()); + view->engine()->addImageProvider(QLatin1String("ippdiscovery"), IppDiscovery::instance()); + + view->setSource(SailfishApp::pathToMainQml()); + view->show(); + return app->exec(); - return SailfishApp::main(argc, argv); } diff --git a/src/ippdiscovery.cpp b/src/ippdiscovery.cpp index ba6969f..4ccfd0a 100644 --- a/src/ippdiscovery.cpp +++ b/src/ippdiscovery.cpp @@ -44,7 +44,7 @@ QStringList get_addr(Bytestream& bts) return addr; } -IppDiscovery::IppDiscovery() : QStringListModel() +IppDiscovery::IppDiscovery() : QStringListModel(), QQuickImageProvider(QQuickImageProvider::Image) { socket = new QUdpSocket(this); connect(socket, SIGNAL(readyRead()), @@ -57,6 +57,24 @@ IppDiscovery::~IppDiscovery() { delete socket; } +IppDiscovery* IppDiscovery::m_Instance = 0; + +IppDiscovery* IppDiscovery::instance() +{ + static QMutex mutex; + if (!m_Instance) + { + mutex.lock(); + + if (!m_Instance) + m_Instance = new IppDiscovery; + + mutex.unlock(); + } + + return m_Instance; +} + void IppDiscovery::discover() { sendQuery(PTR, {"_ipp","_tcp","local"}); } @@ -231,3 +249,59 @@ void IppDiscovery::readPendingDatagrams() this->update(); } + +void IppDiscovery::ignoreKnownSslErrors(QNetworkReply *reply, const QList &errors) +{ + QList IgnoredSslErrors = {QSslError::NoError, + QSslError::SelfSignedCertificate, + QSslError::HostNameMismatch, + QSslError::UnableToGetLocalIssuerCertificate, + QSslError::UnableToVerifyFirstCertificate + }; + + qDebug() << errors; + for (QList::const_iterator it = errors.constBegin(); it != errors.constEnd(); it++) { + if(!IgnoredSslErrors.contains(it->error())) { + qDebug() << "Bad error: " << int(it->error()) << it->error(); + return; + } + } + // For whatever reason, it doesn't work to pass IgnoredSslErrors here + reply->ignoreSslErrors(errors); +} + +QImage IppDiscovery::requestImage(const QString &id, QSize *size, const QSize &requestedSize) +{ //TODO: consider caching images (doesn't appear to be needed currently) + Q_UNUSED(size); + Q_UNUSED(requestedSize); + qDebug() << "requesting image" << id; + + QImage img; + + QNetworkAccessManager* nam = new QNetworkAccessManager(this); + QUrl url(id); + qDebug() << url.host() << _AAs; + // TODO IPv6 + if(_AAs.contains(url.host())) + { // TODO: retry potential other IPs + url.setHost(_AAs.value(url.host())); + } + + QNetworkReply* reply = nam->get(QNetworkRequest(url)); + + QEventLoop el; + connect(reply, SIGNAL(finished()),&el,SLOT(quit())); + connect(nam, SIGNAL(sslErrors(QNetworkReply*,QList)), + this, SLOT(ignoreKnownSslErrors(QNetworkReply*, const QList&))); + el.exec(); + + if (reply->error() == QNetworkReply::NoError) + { + QImageReader imageReader(reply); + img = imageReader.read(); + } + + delete nam; + return img; + +} diff --git a/src/ippdiscovery.h b/src/ippdiscovery.h index d0d59e8..470a2fd 100644 --- a/src/ippdiscovery.h +++ b/src/ippdiscovery.h @@ -1,15 +1,21 @@ #ifndef IPPDISCOVERY_H #define IPPDISCOVERY_H #include +#include #include +#include +#include +#include +#include +#include #include "bytestream.h" -class IppDiscovery : public QStringListModel +class IppDiscovery : public QStringListModel, public QQuickImageProvider { Q_OBJECT public: - IppDiscovery(); - ~IppDiscovery(); + static IppDiscovery* instance(); + Q_PROPERTY(QStringList favourites MEMBER _favourites NOTIFY favouritesChanged) Q_INVOKABLE void discover(); Q_INVOKABLE void reset(); @@ -20,11 +26,21 @@ signals: public slots: void readPendingDatagrams(); void update(); + void ignoreKnownSslErrors(QNetworkReply *reply, const QList &errors); protected: private: + static IppDiscovery* m_Instance; + + IppDiscovery(); + ~IppDiscovery(); + IppDiscovery(const IppDiscovery &); + IppDiscovery& operator=(const IppDiscovery &); + void sendQuery(quint16 qtype, QStringList addr); + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override; + QStringList _ipp; QMap _rps; QMap _ports;