Make ippdiscovery a QQuickImageProvider...

...so that SSL errors can be ignored,
and .local-addresses can be resolved
This commit is contained in:
Anton Thomasson 2020-01-05 18:41:24 +01:00
parent 3e8da3f488
commit 684eb9669b
4 changed files with 122 additions and 28 deletions

View file

@ -14,10 +14,6 @@ Page {
property string selectedFile: "" property string selectedFile: ""
property string selectedFileType property string selectedFileType
IppDiscovery {
id: discovery
}
WifiChecker { WifiChecker {
id: wifi id: wifi
onConnectedChanged: { onConnectedChanged: {
@ -25,10 +21,10 @@ Page {
if(connected) { if(connected) {
var favourites = db.getFavourites(ssid); var favourites = db.getFavourites(ssid);
console.log(favourites); console.log(favourites);
discovery.favourites = favourites; IppDiscovery.favourites = favourites;
} }
else { else {
discovery.favourites = [] IppDiscovery.favourites = []
} }
} }
@ -39,7 +35,7 @@ Page {
console.log("ssid changed", ssid); console.log("ssid changed", ssid);
if(!initialSSIDchange) if(!initialSSIDchange)
{ {
discovery.reset(); IppDiscovery.reset();
} }
initialSSIDchange = false; initialSSIDchange = false;
} }
@ -48,7 +44,7 @@ Page {
signal refreshed() signal refreshed()
Component.onCompleted: { Component.onCompleted: {
discovery.discover(); IppDiscovery.discover();
if(selectedFile != "") if(selectedFile != "")
{ // Until i can convince FilePickerPage to do its magic without user interaction { // Until i can convince FilePickerPage to do its magic without user interaction
if(Utils.endsWith(".pdf", selectedFile)) if(Utils.endsWith(".pdf", selectedFile))
@ -85,14 +81,14 @@ Page {
dialog.accepted.connect(function() { dialog.accepted.connect(function() {
console.log("add", wifi.ssid, dialog.value); console.log("add", wifi.ssid, dialog.value);
db.addFavourite(wifi.ssid, dialog.value); db.addFavourite(wifi.ssid, dialog.value);
discovery.favourites = db.getFavourites(wifi.ssid); IppDiscovery.favourites = db.getFavourites(wifi.ssid);
}) })
} }
} }
MenuItem { MenuItem {
text: qsTr("Refresh") text: qsTr("Refresh")
onClicked: { onClicked: {
discovery.discover(); IppDiscovery.discover();
page.refreshed(); page.refreshed();
} }
} }
@ -101,7 +97,7 @@ Page {
SilicaListView { SilicaListView {
anchors.fill: parent anchors.fill: parent
id: listView id: listView
model: discovery model: IppDiscovery
spacing: Theme.paddingSmall spacing: Theme.paddingSmall
@ -162,7 +158,7 @@ Page {
height: Theme.itemSizeLarge height: Theme.itemSizeLarge
width: 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... // Some printers serve their icons over https with invalid certs...
onStatusChanged: if (status == Image.Error) source = "icon-seaprint-nobg.svg" onStatusChanged: if (status == Image.Error) source = "icon-seaprint-nobg.svg"
} }
@ -215,7 +211,7 @@ Page {
onClicked: { onClicked: {
removeRemorse.execute(delegate, qsTr("Removing printer"), removeRemorse.execute(delegate, qsTr("Removing printer"),
function() {db.removeFavourite(wifi.ssid, model.display); function() {db.removeFavourite(wifi.ssid, model.display);
discovery.favourites = db.getFavourites()}) IppDiscovery.favourites = db.getFavourites()})
} }
} }
} }

View file

@ -5,24 +5,32 @@
#include <src/ippdiscovery.h> #include <src/ippdiscovery.h>
#include <src/ippprinter.h> #include <src/ippprinter.h>
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[]) int main(int argc, char *argv[])
{ {
QGuiApplication* app = SailfishApp::application(argc, argv); QGuiApplication* app = SailfishApp::application(argc, argv);
app->setApplicationVersion(QStringLiteral(SEAPRINT_VERSION)); app->setApplicationVersion(QStringLiteral(SEAPRINT_VERSION));
qmlRegisterType<IppDiscovery>("seaprint.ippdiscovery", 1, 0, "IppDiscovery"); qmlRegisterSingletonType<IppDiscovery>("seaprint.ippdiscovery", 1, 0, "IppDiscovery", ippdiscovery_singletontype_provider);
qmlRegisterType<IppPrinter>("seaprint.ippprinter", 1, 0, "IppPrinter"); qmlRegisterType<IppPrinter>("seaprint.ippprinter", 1, 0, "IppPrinter");
// SailfishApp::main() will display "qml/harbour-printtool.qml", if you need more QQuickView* view = SailfishApp::createView();
// control over initialization, you can use:
// view->engine()->addImportPath(SailfishApp::pathTo("qml/pages").toString());
// - SailfishApp::application(int, char *[]) to get the QGuiApplication * view->engine()->addImageProvider(QLatin1String("ippdiscovery"), IppDiscovery::instance());
// - SailfishApp::createView() to get a new QQuickView * instance
// - SailfishApp::pathTo(QString) to get a QUrl to a resource file view->setSource(SailfishApp::pathToMainQml());
// - SailfishApp::pathToMainQml() to get a QUrl to the main QML file view->show();
// return app->exec();
// To display the view, call "show()" (will show fullscreen on device).
return SailfishApp::main(argc, argv);
} }

View file

@ -44,7 +44,7 @@ QStringList get_addr(Bytestream& bts)
return addr; return addr;
} }
IppDiscovery::IppDiscovery() : QStringListModel() IppDiscovery::IppDiscovery() : QStringListModel(), QQuickImageProvider(QQuickImageProvider::Image)
{ {
socket = new QUdpSocket(this); socket = new QUdpSocket(this);
connect(socket, SIGNAL(readyRead()), connect(socket, SIGNAL(readyRead()),
@ -57,6 +57,24 @@ IppDiscovery::~IppDiscovery() {
delete socket; 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() { void IppDiscovery::discover() {
sendQuery(PTR, {"_ipp","_tcp","local"}); sendQuery(PTR, {"_ipp","_tcp","local"});
} }
@ -231,3 +249,59 @@ void IppDiscovery::readPendingDatagrams()
this->update(); this->update();
} }
void IppDiscovery::ignoreKnownSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{
QList<QSslError> IgnoredSslErrors = {QSslError::NoError,
QSslError::SelfSignedCertificate,
QSslError::HostNameMismatch,
QSslError::UnableToGetLocalIssuerCertificate,
QSslError::UnableToVerifyFirstCertificate
};
qDebug() << errors;
for (QList<QSslError>::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<QSslError>)),
this, SLOT(ignoreKnownSslErrors(QNetworkReply*, const QList<QSslError>&)));
el.exec();
if (reply->error() == QNetworkReply::NoError)
{
QImageReader imageReader(reply);
img = imageReader.read();
}
delete nam;
return img;
}

View file

@ -1,15 +1,21 @@
#ifndef IPPDISCOVERY_H #ifndef IPPDISCOVERY_H
#define IPPDISCOVERY_H #define IPPDISCOVERY_H
#include <QStringListModel> #include <QStringListModel>
#include <QQuickImageProvider>
#include <QUdpSocket> #include <QUdpSocket>
#include <QMutex>
#include <QImageReader>
#include <QtNetwork>
#include <QNetworkAccessManager>
#include <QEventLoop>
#include "bytestream.h" #include "bytestream.h"
class IppDiscovery : public QStringListModel class IppDiscovery : public QStringListModel, public QQuickImageProvider
{ {
Q_OBJECT Q_OBJECT
public: public:
IppDiscovery(); static IppDiscovery* instance();
~IppDiscovery();
Q_PROPERTY(QStringList favourites MEMBER _favourites NOTIFY favouritesChanged) Q_PROPERTY(QStringList favourites MEMBER _favourites NOTIFY favouritesChanged)
Q_INVOKABLE void discover(); Q_INVOKABLE void discover();
Q_INVOKABLE void reset(); Q_INVOKABLE void reset();
@ -20,11 +26,21 @@ signals:
public slots: public slots:
void readPendingDatagrams(); void readPendingDatagrams();
void update(); void update();
void ignoreKnownSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
protected: protected:
private: private:
static IppDiscovery* m_Instance;
IppDiscovery();
~IppDiscovery();
IppDiscovery(const IppDiscovery &);
IppDiscovery& operator=(const IppDiscovery &);
void sendQuery(quint16 qtype, QStringList addr); void sendQuery(quint16 qtype, QStringList addr);
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
QStringList _ipp; QStringList _ipp;
QMap<QString,QString> _rps; QMap<QString,QString> _rps;
QMap<QString,quint16> _ports; QMap<QString,quint16> _ports;