Compare commits

...

2 commits

Author SHA1 Message Date
Anton Thomasson
84aed94614 Add two-stage create/send print job support 2022-07-10 19:15:46 +02:00
Anton Thomasson
46e101f016 Don't use chunked encoding when there is no document 2022-07-10 17:05:58 +02:00
8 changed files with 98 additions and 26 deletions

View file

@ -8,7 +8,7 @@ static size_t trampoline(char* dest, size_t size, size_t nmemb, void* userp)
return cid->requestWrite(dest, size*nmemb);
}
CurlRequester::CurlRequester(QUrl addr, Role role)
CurlRequester::CurlRequester(QUrl addr, Role role, Bytestream* singleData)
: _addr(addr), _canWrite(1), _canRead(), _reading(false), _done(false), _dest(nullptr), _size(0), _offset(0), _curl(curl_easy_init())
{
@ -36,7 +36,15 @@ CurlRequester::CurlRequester(QUrl addr, Role role)
curl_easy_setopt(_curl, CURLOPT_READDATA, this);
_opts = curl_slist_append(_opts, "Expect:");
_opts = curl_slist_append(_opts, "Transfer-Encoding: chunked");
if(singleData != nullptr)
{
curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, singleData->size());
write((char*)(singleData->raw()), singleData->size());
}
else
{
_opts = curl_slist_append(_opts, "Transfer-Encoding: chunked");
}
_opts = curl_slist_append(_opts, "Content-Type: application/ipp");
_opts = curl_slist_append(_opts, "Accept-Encoding: identity");
break;
@ -121,7 +129,7 @@ size_t CurlRequester::requestWrite(char* dest, size_t size)
if(!_reading)
{
_canRead.acquire();
if(_done) // Can only have been set by write() - only relevant to check if strating to write
if(_done) // Can only have been set by await() - only relevant to check if strating to write
{
return 0;
}

View file

@ -19,7 +19,7 @@ public:
HttpGetRequest
};
CurlRequester(QUrl addr, Role role = IppRequest);
CurlRequester(QUrl addr, Role role = IppRequest, Bytestream* = nullptr);
~CurlRequester();
CURLcode await(Bytestream* = nullptr);

View file

@ -441,3 +441,8 @@ void IppMsg::encode_attr(Bytestream& msg, quint8 tag, QString name, QJsonValue v
break;
}
}
void IppMsg::setOpAttr(QString name, IppMsg::IppTag type, QJsonValue value)
{
_opAttrs.insert(name, QJsonObject {{"tag", type}, {"value", value}});
}

View file

@ -76,6 +76,8 @@ public:
QJsonArray getJobAttrs() {return _jobAttrs;}
QJsonObject getOpAttrs() {return _opAttrs;}
void setOpAttr(QString name, IppMsg::IppTag type, QJsonValue value);
quint16 getStatus() {return _status;}

View file

@ -21,6 +21,7 @@ IppPrinter::IppPrinter() : _worker(this)
connect(this, &IppPrinter::doCancelJob, &_worker, &PrinterWorker::cancelJob);
connect(this, &IppPrinter::doIdentify, &_worker, &PrinterWorker::identify);
connect(this, &IppPrinter::doPrint, &_worker, &PrinterWorker::print);
connect(this, &IppPrinter::doPrint2, &_worker, &PrinterWorker::print2);
connect(this, &IppPrinter::doGetStrings, &_worker, &PrinterWorker::getStrings);
connect(this, &IppPrinter::doGetImage, &_worker, &PrinterWorker::getImage);
@ -574,9 +575,6 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
qDebug() << supportedMimeTypes << supportedMimeTypes.contains(mimeType);
QJsonObject o = opAttrs();
o.insert("job-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", fileinfo.fileName()}});
Params.paperSizeName = getAttrOrDefault(jobAttrs, "media").toString(Params.paperSizeName.c_str()).toStdString();
QString targetFormat = getAttrOrDefault(jobAttrs, "document-format").toString();
@ -638,8 +636,9 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
jobAttrs.remove("media");
}
QJsonObject jobOpAttrs = opAttrs();
// document-format goes in the op-attrs and not the job-attrs
o.insert("document-format", QJsonObject {{"tag", IppMsg::MimeMediaType}, {"value", targetFormat}});
jobOpAttrs.insert("document-format", QJsonObject {{"tag", IppMsg::MimeMediaType}, {"value", targetFormat}});
jobAttrs.remove("document-format");
targetFormat = targetFormatIfAuto(targetFormat, mimeType, supportedMimeTypes);
@ -677,7 +676,7 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
Params.paperSizeW = size.width();
Params.paperSizeH = size.height();
qDebug() << "Printing job" << o << jobAttrs;
qDebug() << "Printing job" << jobOpAttrs << jobAttrs;
QJsonValue PrinterResolutionRef = getAttrOrDefault(jobAttrs, "printer-resolution");
Params.hwResW = PrinterResolutionRef.toObject()["x"].toInt(Params.hwResW);
@ -702,10 +701,6 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
}
}
qDebug() << "Final op attributes:" << o;
qDebug() << "Final job attributes:" << jobAttrs;
QString Sides = getAttrOrDefault(jobAttrs, "sides").toString();
if(Sides=="two-sided-long-edge")
@ -718,8 +713,34 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
Params.tumble = true;
}
IppMsg job = mk_msg(IppMsg::PrintJob, o, jobAttrs);
emit doPrint(filename, mimeType, targetFormat, job, Params, margins);
QJsonArray supportedOperations = _attrs["operations-supported"].toObject()["value"].toArray();
if(supportedOperations.contains(IppMsg::CreateJob) && supportedOperations.contains(IppMsg::SendDocument))
{
QJsonObject createJobOpAttrs = opAttrs();
createJobOpAttrs.insert("job-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", fileinfo.fileName()}});
qDebug() << "Final create op attributes:" << createJobOpAttrs;
qDebug() << "Final job attributes:" << jobAttrs;
IppMsg createJob = mk_msg(IppMsg::CreateJob, createJobOpAttrs, jobAttrs);
qDebug() << "Final job op attributes:" << jobOpAttrs;
IppMsg sendDoc = mk_msg(IppMsg::SendDocument, jobOpAttrs);
emit doPrint2(filename, mimeType, targetFormat, createJob, sendDoc, Params, margins);
}
else
{
jobOpAttrs.insert("job-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", fileinfo.fileName()}});
qDebug() << "Final op attributes:" << jobOpAttrs;
qDebug() << "Final job attributes:" << jobAttrs;
IppMsg job = mk_msg(IppMsg::PrintJob, jobOpAttrs, jobAttrs);
emit doPrint(filename, mimeType, targetFormat, job, Params, margins);
}
}
bool IppPrinter::getJobs() {

View file

@ -73,6 +73,7 @@ signals:
void doConvertPlaintext(QString filename, Bytestream header, PrintParameters Params);
void doPrint(QString filename, QString mimeType, QString targetFormat, IppMsg job, PrintParameters Params, QMargins margins);
void doPrint2(QString filename, QString mimeType, QString targetFormat, IppMsg createJob, IppMsg sendDocument, PrintParameters Params, QMargins margins);
void doGetStrings(QUrl url);
void doGetImage(QUrl url);
@ -84,7 +85,6 @@ signals:
public slots:
void print(QJsonObject attrs, QString file);
void onUrlChanged();
void MaybeGetStrings();
void MaybeGetIcon(bool retry=false);

View file

@ -38,42 +38,77 @@ void PrinterWorker::getImage(QUrl url)
void PrinterWorker::getPrinterAttributes(Bytestream msg)
{
CurlRequester cr(_printer->httpUrl());
cr.write((char*)msg.raw(), msg.size());
CurlRequester cr(_printer->httpUrl(), CurlRequester::IppRequest, &msg);
awaitResult(cr, "getPrinterAttributesFinished");
}
void PrinterWorker::getJobs(Bytestream msg)
{
CurlRequester cr(_printer->httpUrl());
cr.write((char*)msg.raw(), msg.size());
CurlRequester cr(_printer->httpUrl(), CurlRequester::IppRequest, &msg);
awaitResult(cr, "getJobsRequestFinished");
}
void PrinterWorker::cancelJob(Bytestream msg)
{
CurlRequester cr(_printer->httpUrl());
cr.write((char*)msg.raw(), msg.size());
CurlRequester cr(_printer->httpUrl(), CurlRequester::IppRequest, &msg);
awaitResult(cr, "cancelJobFinished");
}
void PrinterWorker::identify(Bytestream msg)
{
CurlRequester cr(_printer->httpUrl());
cr.write((char*)msg.raw(), msg.size());
CurlRequester cr(_printer->httpUrl(), CurlRequester::IppRequest, &msg);
awaitResult(cr, "identifyFinished");
}
void PrinterWorker::print2(QString filename, QString mimeType, QString targetFormat, IppMsg createJob, IppMsg sendDocument, PrintParameters Params, QMargins margins)
{
emit busyMessage(tr("Preparing"));
Bytestream header = createJob.encode();
CurlRequester cr(_printer->httpUrl(), CurlRequester::IppRequest, &header);
Bytestream resData;
CURLcode res = cr.await(&resData);
if(res == CURLE_OK)
{
IppMsg resMsg(resData);
qDebug() << resMsg.getOpAttrs() << resMsg.getJobAttrs();
QJsonObject resJobAttrs = resMsg.getJobAttrs()[0].toObject();
if(resMsg.getStatus() <= 0xff && resJobAttrs.contains("job-id"))
{
int jobId = resJobAttrs["job-id"].toObject()["value"].toInt();
sendDocument.setOpAttr("job-id", IppMsg::Integer, jobId);
sendDocument.setOpAttr("last-document", IppMsg::Boolean, true);
print(filename, mimeType, targetFormat, sendDocument, Params, margins);
}
else
{
QMetaObject::invokeMethod(_printer, "printRequestFinished", Qt::QueuedConnection,
Q_ARG(CURLcode, res),
Q_ARG(Bytestream, resData));
}
}
else
{
QMetaObject::invokeMethod(_printer, "printRequestFinished", Qt::QueuedConnection,
Q_ARG(CURLcode, res),
Q_ARG(Bytestream, resData));
}
}
void PrinterWorker::print(QString filename, QString mimeType, QString targetFormat, IppMsg job, PrintParameters Params, QMargins margins)
{
try {
try
{
Mimer* mimer = Mimer::instance();
Bytestream contents = job.encode();
emit busyMessage(tr("Preparing"));
if((mimeType == targetFormat) && (targetFormat == Mimer::Postscript))
{ // Can't process Postscript
justUpload(filename, contents);

View file

@ -39,6 +39,7 @@ public slots:
void cancelJob(Bytestream msg);
void identify(Bytestream msg);
void print(QString filename, QString mimeType, QString targetFormat, IppMsg job, PrintParameters Params, QMargins margins);
void print2(QString filename, QString mimeType, QString targetFormat, IppMsg createJob, IppMsg sendDocument, PrintParameters Params, QMargins margins);
signals:
void progress(qint64 done, qint64 pages);