2019-12-01 22:27:00 +03:00
|
|
|
#include "ippprinter.h"
|
2020-01-26 14:08:57 +03:00
|
|
|
#include "ippraster.h"
|
2020-01-20 22:11:41 +03:00
|
|
|
#include <seaprint_version.h>
|
2020-01-26 14:08:57 +03:00
|
|
|
#include <QtConcurrent/QtConcurrent>
|
2019-12-01 22:27:00 +03:00
|
|
|
|
|
|
|
IppPrinter::IppPrinter()
|
|
|
|
{
|
|
|
|
_nam = new QNetworkAccessManager(this);
|
2019-12-08 15:55:56 +03:00
|
|
|
_print_nam = new QNetworkAccessManager(this);
|
|
|
|
_jobs_nam = new QNetworkAccessManager(this);
|
2019-12-12 22:53:46 +03:00
|
|
|
_job_cancel_nam = new QNetworkAccessManager(this);
|
|
|
|
|
2019-12-01 22:27:00 +03:00
|
|
|
connect(_nam, SIGNAL(finished(QNetworkReply*)),this, SLOT(getPrinterAttributesFinished(QNetworkReply*)));
|
2020-01-04 13:55:22 +03:00
|
|
|
connect(_nam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(ignoreKnownSslErrors(QNetworkReply*, const QList<QSslError>&)));
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
connect(_print_nam, SIGNAL(finished(QNetworkReply*)),this, SLOT(printRequestFinished(QNetworkReply*)));
|
2020-01-04 13:55:22 +03:00
|
|
|
connect(_print_nam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(ignoreKnownSslErrors(QNetworkReply*, const QList<QSslError>&)));
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
connect(_jobs_nam, SIGNAL(finished(QNetworkReply*)),this, SLOT(getJobsRequestFinished(QNetworkReply*)));
|
2020-01-04 13:55:22 +03:00
|
|
|
connect(_jobs_nam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(ignoreKnownSslErrors(QNetworkReply*, const QList<QSslError>&)));
|
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
connect(_job_cancel_nam, SIGNAL(finished(QNetworkReply*)),this, SLOT(cancelJobFinished(QNetworkReply*)));
|
2020-01-04 13:55:22 +03:00
|
|
|
connect(_job_cancel_nam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(ignoreKnownSslErrors(QNetworkReply*, const QList<QSslError>&)));
|
|
|
|
|
2019-12-01 22:27:00 +03:00
|
|
|
QObject::connect(this, &IppPrinter::urlChanged, this, &IppPrinter::onUrlChanged);
|
2020-05-01 14:49:17 +03:00
|
|
|
qRegisterMetaType<QTemporaryFile*>("QTemporaryFile*");
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
IppPrinter::~IppPrinter() {
|
|
|
|
delete _nam;
|
2019-12-08 15:55:56 +03:00
|
|
|
delete _print_nam;
|
|
|
|
delete _jobs_nam;
|
2019-12-12 22:53:46 +03:00
|
|
|
delete _job_cancel_nam;
|
|
|
|
}
|
|
|
|
|
|
|
|
QJsonObject IppPrinter::opAttrs() {
|
|
|
|
QJsonObject o
|
|
|
|
{
|
|
|
|
{"attributes-charset", QJsonObject {{"tag", IppMsg::Charset}, {"value", "utf-8"}}},
|
|
|
|
{"attributes-natural-language", QJsonObject {{"tag", IppMsg::NaturalLanguage}, {"value", "en-us"}}},
|
2020-01-03 18:36:24 +03:00
|
|
|
{"printer-uri", QJsonObject {{"tag", IppMsg::Uri}, {"value", _url.toString()}}},
|
2019-12-12 22:53:46 +03:00
|
|
|
{"requesting-user-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", "nemo"}}},
|
|
|
|
};
|
|
|
|
return o;
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
|
2020-01-03 18:36:24 +03:00
|
|
|
void IppPrinter::setUrl(QString url_s)
|
2019-12-01 22:27:00 +03:00
|
|
|
{
|
2020-01-03 18:36:24 +03:00
|
|
|
QUrl url = QUrl(url_s);
|
|
|
|
|
|
|
|
qDebug() << url.scheme();
|
|
|
|
|
|
|
|
if(url.scheme() != "ipp" /* or ipps */)
|
|
|
|
{
|
|
|
|
//if https -> ipps, else:
|
|
|
|
if(url.scheme() == "")
|
|
|
|
{
|
|
|
|
url = QUrl("ipp://"+url_s); // Why isn't setScheme working?
|
|
|
|
}
|
|
|
|
else if (url.scheme() == "http") {
|
|
|
|
url.setScheme("ipp");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
url = QUrl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qDebug() << url_s << url;
|
|
|
|
|
2019-12-01 22:27:00 +03:00
|
|
|
if(url != _url)
|
|
|
|
{
|
|
|
|
_url = url;
|
|
|
|
emit urlChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IppPrinter::onUrlChanged()
|
|
|
|
{
|
2019-12-17 22:20:09 +03:00
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IppPrinter::refresh() {
|
2019-12-01 22:27:00 +03:00
|
|
|
_attrs = QJsonObject();
|
|
|
|
emit attrsChanged();
|
|
|
|
|
|
|
|
QNetworkRequest request;
|
2020-01-03 18:36:24 +03:00
|
|
|
|
|
|
|
request.setUrl(httpUrl());
|
2019-12-01 22:27:00 +03:00
|
|
|
// request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
|
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/ipp");
|
2020-01-20 22:11:41 +03:00
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint "SEAPRINT_VERSION);
|
2019-12-01 22:27:00 +03:00
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
QJsonObject o = opAttrs();
|
2019-12-01 22:27:00 +03:00
|
|
|
IppMsg msg = IppMsg(o);
|
|
|
|
_nam->post(request, msg.encode(IppMsg::GetPrinterAttrs));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void IppPrinter::getPrinterAttributesFinished(QNetworkReply *reply)
|
|
|
|
{
|
2019-12-08 15:55:56 +03:00
|
|
|
qDebug() << reply->error() << reply->errorString() << reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();
|
2019-12-15 13:24:36 +03:00
|
|
|
_attrs = QJsonObject();
|
2019-12-01 22:27:00 +03:00
|
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
IppMsg resp(reply);
|
2019-12-08 15:55:56 +03:00
|
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getPrinterAttrs();
|
2019-12-01 22:27:00 +03:00
|
|
|
_attrs = resp.getPrinterAttrs();
|
|
|
|
}
|
|
|
|
catch(std::exception e)
|
|
|
|
{
|
|
|
|
qDebug() << e.what();
|
|
|
|
}
|
|
|
|
}
|
2019-12-15 13:24:36 +03:00
|
|
|
emit attrsChanged();
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
void IppPrinter::printRequestFinished(QNetworkReply *reply)
|
2019-12-01 22:27:00 +03:00
|
|
|
{
|
2019-12-17 22:18:57 +03:00
|
|
|
_jobAttrs = QJsonObject();
|
|
|
|
bool status = false;
|
2019-12-01 22:27:00 +03:00
|
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
IppMsg resp(reply);
|
2019-12-06 22:18:48 +03:00
|
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getJobAttrs();
|
2019-12-08 15:55:56 +03:00
|
|
|
_jobAttrs = resp.getJobAttrs()[0].toObject();
|
2019-12-17 22:18:57 +03:00
|
|
|
status = resp.getStatus() <= 0xff;
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
catch(std::exception e)
|
|
|
|
{
|
|
|
|
qDebug() << e.what();
|
|
|
|
}
|
|
|
|
}
|
2019-12-17 22:18:57 +03:00
|
|
|
else {
|
|
|
|
_jobAttrs.insert("job-state-message", QJsonObject {{"tag", IppMsg::TextWithoutLanguage}, {"value", "Network error"}});
|
|
|
|
}
|
|
|
|
emit jobAttrsChanged();
|
2020-04-04 14:56:36 +03:00
|
|
|
emit jobFinished(status);
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
void IppPrinter::getJobsRequestFinished(QNetworkReply *reply)
|
|
|
|
{
|
|
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
IppMsg resp(reply);
|
|
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getJobAttrs();
|
|
|
|
_jobs = resp.getJobAttrs();
|
|
|
|
emit jobsChanged();
|
|
|
|
}
|
|
|
|
catch(std::exception e)
|
|
|
|
{
|
|
|
|
qDebug() << e.what();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-01 22:27:00 +03:00
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
void IppPrinter::cancelJobFinished(QNetworkReply *reply)
|
|
|
|
{
|
2020-02-23 15:11:28 +03:00
|
|
|
bool status = false;
|
2019-12-12 22:53:46 +03:00
|
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
IppMsg resp(reply);
|
|
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getJobAttrs();
|
2020-02-23 15:11:28 +03:00
|
|
|
status = resp.getStatus() <= 0xff;
|
2019-12-12 22:53:46 +03:00
|
|
|
}
|
|
|
|
catch(std::exception e)
|
|
|
|
{
|
|
|
|
qDebug() << e.what();
|
|
|
|
}
|
|
|
|
}
|
2020-02-23 15:11:28 +03:00
|
|
|
emit cancelStatus(status);
|
2019-12-12 22:53:46 +03:00
|
|
|
getJobs();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-04 13:55:22 +03:00
|
|
|
|
|
|
|
void IppPrinter::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);
|
|
|
|
}
|
|
|
|
|
2020-01-26 14:08:57 +03:00
|
|
|
void IppPrinter::doWork(QString filename, QTemporaryFile* tempfile)
|
|
|
|
{
|
|
|
|
QNetworkRequest request;
|
|
|
|
|
|
|
|
request.setUrl(httpUrl());
|
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/ipp");
|
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint "SEAPRINT_VERSION);
|
|
|
|
|
|
|
|
QProcess* muraster = new QProcess(this);
|
|
|
|
muraster->setProgram("/home/nemo/stuff/bin/muraster");
|
|
|
|
muraster->setArguments({"-F", "pgm", filename});
|
|
|
|
|
|
|
|
|
|
|
|
QProcess* ppm2pwg = new QProcess(this);
|
|
|
|
ppm2pwg->setProgram("/home/nemo/repos/pwg/ppm2pwg");
|
|
|
|
QStringList env; // {"PREPEND_FILE="+tempfile->fileName()};
|
|
|
|
|
|
|
|
bool apple = false;
|
|
|
|
if(apple)
|
|
|
|
{
|
|
|
|
env.append("URF=true");
|
|
|
|
}
|
|
|
|
|
|
|
|
qDebug() << "Prepend file env done";
|
|
|
|
|
|
|
|
ppm2pwg->setEnvironment(env);
|
|
|
|
|
|
|
|
muraster->setStandardOutputProcess(ppm2pwg);
|
|
|
|
ppm2pwg->setStandardOutputFile(tempfile->fileName(), QIODevice::Append);
|
|
|
|
|
|
|
|
connect(muraster, SIGNAL(finished(int, QProcess::ExitStatus)), muraster, SLOT(deleteLater()));
|
|
|
|
connect(ppm2pwg, SIGNAL(finished(int, QProcess::ExitStatus)), ppm2pwg, SLOT(deleteLater()));
|
2020-05-01 14:49:17 +03:00
|
|
|
//connect(ppm2pwg, SIGNAL(finished(int, QProcess::ExitStatus)), tempfile, SLOT(deleteLater()));
|
2020-01-26 14:08:57 +03:00
|
|
|
|
|
|
|
qDebug() << "All connected";
|
|
|
|
|
|
|
|
|
|
|
|
muraster->start();
|
|
|
|
ppm2pwg->start();
|
|
|
|
|
|
|
|
qDebug() << "Starting";
|
|
|
|
|
|
|
|
|
|
|
|
if(!muraster->waitForStarted())
|
|
|
|
{
|
|
|
|
qDebug() << "muraster died";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!ppm2pwg->waitForStarted())
|
|
|
|
{
|
|
|
|
qDebug() << "ppm2pwg died";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qDebug() << "All started";
|
|
|
|
|
|
|
|
ppm2pwg->waitForFinished();
|
|
|
|
|
|
|
|
qDebug() << "Finished";
|
|
|
|
|
|
|
|
// IppRaster* raster = new IppRaster(ppm2pwg);
|
|
|
|
// raster->open(QIODevice::ReadOnly);
|
|
|
|
// request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
|
2020-05-01 14:49:17 +03:00
|
|
|
QMetaObject::invokeMethod(this, "doPost", Qt::QueuedConnection,
|
|
|
|
Q_ARG(QNetworkRequest, request), Q_ARG(QTemporaryFile*, tempfile) );
|
2020-01-26 14:08:57 +03:00
|
|
|
qDebug() << "posted";
|
|
|
|
}
|
2020-01-04 13:55:22 +03:00
|
|
|
|
2020-05-01 14:49:17 +03:00
|
|
|
void IppPrinter::doPost(QNetworkRequest request, QTemporaryFile* data)
|
|
|
|
{
|
|
|
|
data->open();
|
|
|
|
_print_nam->post(request, data);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-01-04 13:55:22 +03:00
|
|
|
|
2020-04-04 14:56:36 +03:00
|
|
|
void IppPrinter::print(QJsonObject attrs, QString filename){
|
2019-12-01 22:27:00 +03:00
|
|
|
qDebug() << "printing" << filename << attrs;
|
|
|
|
|
|
|
|
QFile file(filename);
|
|
|
|
bool file_ok = file.open(QIODevice::ReadOnly);
|
|
|
|
if(!file_ok)
|
2020-04-04 14:56:36 +03:00
|
|
|
{
|
|
|
|
emit jobFinished(false);
|
|
|
|
return;
|
|
|
|
}
|
2019-12-01 22:27:00 +03:00
|
|
|
|
|
|
|
QFileInfo fileinfo(file);
|
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
QJsonObject o = opAttrs();
|
|
|
|
o.insert("job-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", fileinfo.fileName()}});
|
|
|
|
|
2019-12-01 22:27:00 +03:00
|
|
|
|
2019-12-06 22:18:48 +03:00
|
|
|
// Only include if printer supports it
|
|
|
|
// if (filename.endsWith("pdf"))
|
|
|
|
// {
|
|
|
|
// attrs.insert("document-format", QJsonObject {{"tag", 73}, {"value", "application/pdf"}});
|
|
|
|
// }
|
|
|
|
// else if (filename.endsWith("jpg")) {
|
|
|
|
// attrs.insert("document-format", QJsonObject {{"tag", 73}, {"value", "image/jpeg"}});
|
|
|
|
// }
|
|
|
|
|
2019-12-07 16:40:36 +03:00
|
|
|
qDebug() << "Printing job" << o << attrs;
|
2019-12-01 22:27:00 +03:00
|
|
|
IppMsg job = IppMsg(o, attrs);
|
|
|
|
|
|
|
|
QByteArray contents = job.encode(IppMsg::PrintJob);
|
2020-01-26 14:08:57 +03:00
|
|
|
|
|
|
|
// TODO: do this only conditionally, and to the raster suppoerted/preferred
|
|
|
|
bool transcode = true;
|
|
|
|
if(transcode)
|
|
|
|
{
|
|
|
|
file.close();
|
|
|
|
QTemporaryFile* tempfile = new QTemporaryFile();
|
|
|
|
tempfile->open();
|
|
|
|
tempfile->write(contents);
|
|
|
|
qDebug() << tempfile->fileName();
|
|
|
|
tempfile->close();
|
|
|
|
|
|
|
|
QtConcurrent::run(this, &IppPrinter::doWork, filename, tempfile);
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
QNetworkRequest request;
|
|
|
|
|
|
|
|
request.setUrl(httpUrl());
|
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/ipp");
|
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint "SEAPRINT_VERSION);
|
|
|
|
|
|
|
|
QByteArray filedata = file.readAll();
|
|
|
|
contents = contents.append(filedata);
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
_print_nam->post(request, contents);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
2019-12-08 15:55:56 +03:00
|
|
|
|
|
|
|
bool IppPrinter::getJobs() {
|
|
|
|
|
|
|
|
qDebug() << "getting jobs";
|
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
QJsonObject o = opAttrs();
|
2020-01-03 15:37:51 +03:00
|
|
|
o.insert("requested-attributes", QJsonObject {{"tag", IppMsg::Keyword}, {"value", "all"}});
|
2019-12-08 15:55:56 +03:00
|
|
|
|
|
|
|
IppMsg job = IppMsg(o, QJsonObject());
|
|
|
|
|
|
|
|
QNetworkRequest request;
|
|
|
|
|
|
|
|
QByteArray contents = job.encode(IppMsg::GetJobs);
|
|
|
|
|
2020-01-03 18:36:24 +03:00
|
|
|
request.setUrl(httpUrl());
|
2019-12-08 15:55:56 +03:00
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/ipp");
|
2020-01-20 22:11:41 +03:00
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint "SEAPRINT_VERSION);
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
_jobs_nam->post(request, contents);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
bool IppPrinter::cancelJob(qint32 jobId) {
|
|
|
|
|
2020-02-23 15:11:28 +03:00
|
|
|
qDebug() << "cancelling jobs";
|
2019-12-08 15:55:56 +03:00
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
QJsonObject o = opAttrs();
|
|
|
|
o.insert("job-id", QJsonObject {{"tag", IppMsg::Integer}, {"value", jobId}});
|
|
|
|
|
|
|
|
IppMsg job = IppMsg(o, QJsonObject());
|
|
|
|
|
|
|
|
QNetworkRequest request;
|
|
|
|
|
|
|
|
QByteArray contents = job.encode(IppMsg::CancelJob);
|
|
|
|
|
2020-01-03 18:36:24 +03:00
|
|
|
request.setUrl(httpUrl());
|
2019-12-12 22:53:46 +03:00
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/ipp");
|
2020-01-20 22:11:41 +03:00
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint "SEAPRINT_VERSION);
|
|
|
|
|
2019-12-12 22:53:46 +03:00
|
|
|
_job_cancel_nam->post(request, contents);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2020-01-03 18:36:24 +03:00
|
|
|
|
|
|
|
QUrl IppPrinter::httpUrl() {
|
|
|
|
QUrl url = _url;
|
|
|
|
url.setScheme("http");
|
|
|
|
if(url.port() == -1) {
|
|
|
|
url.setPort(631);
|
|
|
|
}
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|