diff --git a/qml/harbour-seaprint.qml b/qml/harbour-seaprint.qml index 7cdb91a..8431cf3 100644 --- a/qml/harbour-seaprint.qml +++ b/qml/harbour-seaprint.qml @@ -6,7 +6,7 @@ import "pages" ApplicationWindow { - initialPage: Component { FirstPage { } } + initialPage: Component { FirstPage { selectedFile: Qt.application.arguments[1] ? Qt.application.arguments[1] : "" } } cover: Qt.resolvedUrl("cover/CoverPage.qml") allowedOrientations: defaultAllowedOrientations diff --git a/qml/pages/FirstPage.qml b/qml/pages/FirstPage.qml index eace4e8..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,22 @@ 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)) + { + selectedFileType = "application/pdf" + } + else if(Utils.endsWith(".jpg", selectedFile) || Utils.endsWith(".jpeg", selectedFile)) + { + selectedFileType = "image/jpeg" + } + else + { + selectedFile = "" + } + } } // To enable PullDownMenu, place our content in a SilicaFlickable @@ -70,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(); } } @@ -86,7 +97,7 @@ Page { SilicaListView { anchors.fill: parent id: listView - model: discovery + model: IppDiscovery spacing: Theme.paddingSmall @@ -147,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" } @@ -200,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/qml/pages/utils.js b/qml/pages/utils.js index 91a5501..2567562 100644 --- a/qml/pages/utils.js +++ b/qml/pages/utils.js @@ -13,7 +13,7 @@ function supported_formats(printer) if(supported.length == 0) { - supported.push(qsTr("No relevant formats supported")) + supported.push(qsTr("No compatible formats supported")) } return supported.join(" "); @@ -86,3 +86,8 @@ function ippName(name, value) } return value; } + +function endsWith(ending, string) +{ + return string.lastIndexOf(ending) == (string.length - ending.length); +} diff --git a/rpm/harbour-seaprint.spec b/rpm/harbour-seaprint.spec index 20e41fc..7006d86 100644 --- a/rpm/harbour-seaprint.spec +++ b/rpm/harbour-seaprint.spec @@ -9,8 +9,8 @@ Name: harbour-seaprint # << macros Summary: SeaPrint -Version: 0.3.1 -Release: 1 +Version: 0.4 +Release: 3 Group: Qt/Qt License: LICENSE URL: http://example.org/ diff --git a/rpm/harbour-seaprint.yaml b/rpm/harbour-seaprint.yaml index 3edf0c6..353ab28 100644 --- a/rpm/harbour-seaprint.yaml +++ b/rpm/harbour-seaprint.yaml @@ -1,7 +1,7 @@ Name: harbour-seaprint Summary: SeaPrint -Version: 0.3.1 -Release: 1 +Version: 0.4 +Release: 3 # The contents of the Group field should be one of the groups listed here: # https://github.com/mer-tools/spectacle/blob/master/data/GROUPS Group: Qt/Qt 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 4b504e1..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"}); } @@ -136,69 +154,77 @@ void IppDiscovery::readPendingDatagrams() sender = QHostAddress(sender.toIPv4Address()); quint16 transactionid, flags, questions, answerRRs, authRRs, addRRs; - resp >> transactionid >> flags >> questions >> answerRRs >> authRRs >> addRRs; - for(quint16 i = 0; i < questions; i++) - { - quint16 qtype, qflags; - QString qaddr = get_addr(resp).join('.'); - resp >> qtype >> qflags; - } + try { - for(quint16 i = 0; i < answerRRs; i++) - { - quint16 atype, aflags, len; - quint32 ttl; + resp >> transactionid >> flags >> questions >> answerRRs >> authRRs >> addRRs; - QString aaddr = get_addr(resp).join('.'); - resp >> atype >> aflags >> ttl >> len; - - quint16 pos_before = resp.pos(); - if (atype == PTR) + for(quint16 i = 0; i < questions; i++) { - QString tmpname = get_addr(resp).join("."); - if(aaddr.endsWith("_ipp._tcp.local")) - { - ipp_ptrs.append(tmpname); - } + quint16 qtype, qflags; + QString qaddr = get_addr(resp).join('.'); + resp >> qtype >> qflags; } - else if(atype == TXT) + + for(quint16 i = 0; i < answerRRs; i++) { - Bytestream tmp; - while(resp.pos() < pos_before+len) + quint16 atype, aflags, len; + quint32 ttl; + + QString aaddr = get_addr(resp).join('.'); + resp >> atype >> aflags >> ttl >> len; + + quint16 pos_before = resp.pos(); + if (atype == PTR) { - resp/resp.getU8() >> tmp; - if(tmp >>= "rp=") + QString tmpname = get_addr(resp).join("."); + if(aaddr.endsWith("_ipp._tcp.local")) { - std::string tmprp; - tmp/tmp.remaining() >> tmprp; - _rps[aaddr] = tmprp.c_str(); + ipp_ptrs.append(tmpname); } } - } - else if (atype == SRV) - { - quint16 prio, w, port; - resp >> prio >> w >> port; - QString target = get_addr(resp).join("."); - _ports[aaddr] = port; - _targets[aaddr] = target; - } - else if(atype == A) - { - quint32 addr; - resp >> addr; - QHostAddress haddr(addr); - _AAs.insert(aaddr, haddr.toString()); - } - else - { - resp += len; - } - Q_ASSERT(resp.pos() == pos_before+len); + else if(atype == TXT) + { + Bytestream tmp; + while(resp.pos() < pos_before+len) + { + resp/resp.getU8() >> tmp; + if(tmp >>= "rp=") + { + std::string tmprp; + tmp/tmp.remaining() >> tmprp; + _rps[aaddr] = tmprp.c_str(); + } + } + } + else if (atype == SRV) + { + quint16 prio, w, port; + resp >> prio >> w >> port; + QString target = get_addr(resp).join("."); + _ports[aaddr] = port; + _targets[aaddr] = target; + } + else if(atype == A) + { + quint32 addr; + resp >> addr; + QHostAddress haddr(addr); + _AAs.insert(aaddr, haddr.toString()); + } + else + { + resp += len; + } + Q_ASSERT(resp.pos() == pos_before+len); + } + } + catch(std::exception e) + { + qDebug() << e.what(); + return; } - qDebug() << "new ipp ptrs" << ipp_ptrs; qDebug() << "ipp ptrs" << _ipp; qDebug() << "rps" << _rps; @@ -223,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; diff --git a/translations/harbour-seaprint-de.ts b/translations/harbour-seaprint-de.ts index fff0ee0..23f38dc 100644 --- a/translations/harbour-seaprint-de.ts +++ b/translations/harbour-seaprint-de.ts @@ -282,7 +282,7 @@ - No relevant formats supported + No compatible formats supported diff --git a/translations/harbour-seaprint-es.ts b/translations/harbour-seaprint-es.ts index 52192a9..500fc26 100644 --- a/translations/harbour-seaprint-es.ts +++ b/translations/harbour-seaprint-es.ts @@ -282,8 +282,8 @@ ppp - No relevant formats supported - No hay formatos relevantes compatibles + No compatible formats supported + No hay formatos compatibles diff --git a/translations/harbour-seaprint-fr.ts b/translations/harbour-seaprint-fr.ts index 22cd13e..b096ce2 100644 --- a/translations/harbour-seaprint-fr.ts +++ b/translations/harbour-seaprint-fr.ts @@ -57,11 +57,11 @@ Code and Testing - Rudi Timmermans - Rudi Timmermans - Code et test + Rudi Timmermans - Code et test Spanish - + Espagnol @@ -84,7 +84,7 @@ Unknown - Inconnu + Inconnu @@ -138,7 +138,7 @@ Unknown - Inconnu + Inconnu @@ -215,74 +215,74 @@ processing - + traitement processing-stopped - + traitement-arrêt canceled - + annulé aborted - + abandonné completed - + terminé unknown state - + état inconnu draft - brouillon + brouillon normal - normale + normale high - haute + haute unknown quality - qualité inconnue + qualité inconnue portrait - portrait + portrait landscape - paysage + paysage reverse landscape - paysage inversé + paysage inversé reverse portrait - portrait inversé + portrait inversé unknown orientation - orientation inconnue + orientation inconnue dpi - dpi + dpi dots/cm - pts/cm + pts/cm - No relevant formats supported + No compatible formats supported diff --git a/translations/harbour-seaprint-zh_CN.ts b/translations/harbour-seaprint-zh_CN.ts index 6559d79..0851332 100644 --- a/translations/harbour-seaprint-zh_CN.ts +++ b/translations/harbour-seaprint-zh_CN.ts @@ -45,7 +45,7 @@ Source code is available at GitHub. Translations, bug reports and other contributions are welcome! - 源代码位于 Github 。欢迎提供翻译,报告缺陷及其它贡献! + 源代码位于 Github 。欢迎提供翻译、报告缺陷及作出其它贡献! SeaPrint licencing is still TBD, but will be some flavor of open. @@ -57,11 +57,11 @@ Code and Testing - Rudi Timmermans - 代码及测试 - Rudi Timmermans + 代码及测试 - Rudi Timmermans Spanish - + 西班牙语 @@ -84,7 +84,7 @@ Unknown - 未知 + 未知 @@ -207,83 +207,83 @@ utils pending - + 等候 pending-held - + 等候保持 processing - + 正在处理 processing-stopped - + 处理已停止 canceled - + 已取消 aborted - + 已中止 completed - + 已完成 unknown state - + 未知状态 draft - 草稿 + 草稿 normal - 正常 + 正常 high - 高质量 + 高质量 unknown quality - 质量未知 + 质量未知 portrait - 竖屏 + 竖屏 landscape - 横屏 + 横屏 reverse landscape - 竖屏可旋转 + 竖屏可旋转 reverse portrait - 横屏可旋转 + 横屏可旋转 unknown orientation - 方向位置 + 方向位置 dpi - dpi + dpi dots/cm - 点/厘米 + 点/厘米 - No relevant formats supported - + No compatible formats supported + 不支持相关格式 diff --git a/translations/harbour-seaprint.ts b/translations/harbour-seaprint.ts index 4ed5604..7d79407 100644 --- a/translations/harbour-seaprint.ts +++ b/translations/harbour-seaprint.ts @@ -282,7 +282,7 @@ - No relevant formats supported + No compatible formats supported