harbour-seaprint/src/ippprinter.cpp

955 lines
29 KiB
C++
Raw Normal View History

2019-12-01 22:27:00 +03:00
#include "ippprinter.h"
2022-01-15 00:44:55 +03:00
#include "ippdiscovery.h"
2020-05-03 15:13:44 +03:00
#include "mimer.h"
2022-07-31 20:48:14 +03:00
#include "convertchecker.h"
2020-05-16 16:17:42 +03:00
#include "papersizes.h"
#include "overrider.h"
#include "settings.h"
2022-06-04 15:43:53 +03:00
#include <fstream>
2019-12-01 22:27:00 +03:00
2021-07-14 16:07:55 +03:00
Q_DECLARE_METATYPE(QMargins)
Q_DECLARE_METATYPE(IppMsg)
2021-07-14 16:07:55 +03:00
IppPrinter::IppPrinter()
2019-12-01 22:27:00 +03:00
{
_worker = new PrinterWorker(this);
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*");
connect(this, &IppPrinter::doDoGetPrinterAttributes, _worker, &PrinterWorker::getPrinterAttributes);
connect(this, &IppPrinter::doGetJobs, _worker, &PrinterWorker::getJobs);
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);
2022-01-15 00:14:06 +03:00
connect(this, &IppPrinter::doGetStrings, _worker, &PrinterWorker::getStrings);
connect(this, &IppPrinter::doGetImage, _worker, &PrinterWorker::getImage);
2022-01-15 00:14:06 +03:00
connect(_worker, &PrinterWorker::progress, this, &IppPrinter::setProgress);
connect(_worker, &PrinterWorker::busyMessage, this, &IppPrinter::setBusyMessage);
connect(_worker, &PrinterWorker::failed, this, &IppPrinter::convertFailed);
2021-07-14 16:07:55 +03:00
qRegisterMetaType<QMargins>();
qRegisterMetaType<IppMsg>();
2019-12-01 22:27:00 +03:00
}
IppPrinter::~IppPrinter() {
2019-12-12 22:53:46 +03:00
}
QJsonObject IppPrinter::opAttrs() {
QString name = qgetenv("USER");
2019-12-12 22:53:46 +03:00
QJsonObject o
{
{"attributes-charset", QJsonObject {{"tag", IppMsg::Charset}, {"value", "utf-8"}}},
{"attributes-natural-language", QJsonObject {{"tag", IppMsg::NaturalLanguage}, {"value", "en-us"}}},
{"printer-uri", QJsonObject {{"tag", IppMsg::Uri}, {"value", _url.toString()}}},
{"requesting-user-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", name}}},
2019-12-12 22:53:46 +03:00
};
return o;
2019-12-01 22:27:00 +03:00
}
void IppPrinter::setUrl(QString url_s)
2019-12-01 22:27:00 +03:00
{
QUrl url = QUrl(url_s);
2021-06-19 19:16:42 +03:00
// If not already a good scheme, try to fixup, or give an empty url
if(url.scheme() != "ipp" && url.scheme() != "ipps" && url.scheme() != "file")
{
if(url.scheme() == "")
{
url = QUrl("ipp://"+url_s); // Why isn't setScheme working?
}
else if (url.scheme() == "http") {
url.setScheme("ipp");
}
2021-06-19 19:16:42 +03:00
else if (url.scheme() == "https") {
url.setScheme("ipps");
}
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()
{
QMetaObject::invokeMethod(_worker, "urlChanged", Q_ARG(QUrl, httpUrl()));
2019-12-17 22:20:09 +03:00
refresh();
}
void IppPrinter::refresh() {
2021-06-19 19:16:42 +03:00
2021-02-13 16:59:38 +03:00
if(_url.scheme() == "file")
{
_attrs = QJsonObject();
2022-06-04 15:43:53 +03:00
QString localFile = _url.toLocalFile();
2022-06-04 15:43:53 +03:00
if(localFile.endsWith(".raw") || localFile.endsWith(".bin"))
2021-02-13 16:59:38 +03:00
{
2022-06-04 15:43:53 +03:00
try
{
std::ifstream ifs = std::ifstream(localFile.toStdString(), std::ios::in | std::ios::binary);
Bytestream InBts(ifs);
IppMsg resp(InBts);
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getPrinterAttrs();
_attrs = resp.getPrinterAttrs();
}
catch(const std::exception& e)
{
qDebug() << e.what();
}
}
else
{
QFile file(localFile);
if(file.open(QIODevice::ReadOnly))
{
QJsonDocument JsonDocument = QJsonDocument::fromJson(file.readAll());
_attrs = JsonDocument.object();
file.close();
}
2021-02-13 16:59:38 +03:00
}
2022-06-04 15:43:53 +03:00
Overrider::instance()->apply(_attrs);
2021-02-13 16:59:38 +03:00
emit attrsChanged();
2022-01-15 00:14:06 +03:00
// For testing fake file-prinetrs with a strings file hosted elsewhere
// MaybeGetIcon();
// MaybeGetStrings();
2021-02-13 16:59:38 +03:00
UpdateAdditionalDocumentFormats();
}
else
{
QJsonObject o = opAttrs();
2019-12-01 22:27:00 +03:00
2022-07-10 12:36:21 +03:00
IppMsg msg = IppMsg(IppMsg::GetPrinterAttrs, o);
emit doDoGetPrinterAttributes(msg.encode());
2021-02-13 16:59:38 +03:00
}
2019-12-01 22:27:00 +03:00
}
2022-01-15 00:14:06 +03:00
void IppPrinter::MaybeGetStrings()
{
if(_attrs.contains("printer-strings-uri") && _strings.empty())
{
2022-01-15 00:44:55 +03:00
QUrl url(_attrs["printer-strings-uri"].toObject()["value"].toString());
2022-05-26 15:42:01 +03:00
resolveUrl(url);
if(isAllowedAddress(url))
{
emit doGetStrings(url);
}
2022-01-15 00:14:06 +03:00
}
}
void IppPrinter::MaybeGetIcon(bool retry)
{
2022-05-19 21:49:57 +03:00
if(_attrs.contains("printer-icons") && (_icon.isNull() || retry) && !_iconRetried)
{
QUrl url;
QJsonArray icons = _attrs["printer-icons"].toObject()["value"].toArray();
if(retry)
{ // If there were more than one icon, try the last one on the retry
if(icons.size() > 1)
{
url = icons.last().toString();
}
}
else
{
if(icons.size() == 3)
{ // If there are 3 icons, the first will be the 48px one, ignore it
url = icons.at(1).toString();
}
else
{
url = icons.at(0).toString();
}
}
2022-05-26 15:42:01 +03:00
resolveUrl(url);
if(isAllowedAddress(url))
{
emit doGetImage(url);
}
}
2022-05-19 21:49:57 +03:00
_iconRetried = retry;
}
2021-02-13 16:59:38 +03:00
void IppPrinter::UpdateAdditionalDocumentFormats()
2019-12-01 22:27:00 +03:00
{
_additionalDocumentFormats = QStringList();
if(_attrs.contains("printer-device-id"))
{
QJsonArray supportedMimeTypes = _attrs["document-format-supported"].toObject()["value"].toArray();
QStringList printerDeviceId = _attrs["printer-device-id"].toObject()["value"].toString().split(";");
for (QStringList::iterator it = printerDeviceId.begin(); it != printerDeviceId.end(); it++)
{
QStringList kv = it->split(":");
2020-06-13 14:05:33 +03:00
if(kv.length()==2 && (kv[0]=="CMD" || kv[0]=="COMMAND SET"))
{
2021-03-04 23:49:27 +03:00
if(!supportedMimeTypes.contains(Mimer::PDF) && kv[1].contains("PDF"))
{
2021-03-04 23:49:27 +03:00
_additionalDocumentFormats.append(Mimer::PDF);
}
2021-03-04 23:49:27 +03:00
if(!supportedMimeTypes.contains(Mimer::Postscript) &&
2020-06-13 14:05:33 +03:00
kv[1].contains("Postscript", Qt::CaseInsensitive))
{
2021-03-04 23:49:27 +03:00
_additionalDocumentFormats.append(Mimer::Postscript);
}
}
}
qDebug() << "additionalDocumentFormats" << _additionalDocumentFormats;
}
2021-02-13 16:59:38 +03:00
emit additionalDocumentFormatsChanged();
}
void IppPrinter::getPrinterAttributesFinished(CURLcode res, Bytestream data)
2021-02-13 16:59:38 +03:00
{
2021-08-28 23:16:26 +03:00
qDebug() << res;
2021-02-13 16:59:38 +03:00
_attrs = QJsonObject();
2021-08-28 23:16:26 +03:00
if(res == CURLE_OK)
2021-02-13 16:59:38 +03:00
{
try {
2021-08-28 23:16:26 +03:00
IppMsg resp(data);
2021-02-13 16:59:38 +03:00
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getPrinterAttrs();
_attrs = resp.getPrinterAttrs();
Overrider::instance()->apply(_attrs);
2021-02-13 16:59:38 +03:00
}
catch(const std::exception& e)
{
qDebug() << e.what();
}
}
emit attrsChanged();
2022-01-15 00:14:06 +03:00
MaybeGetStrings();
MaybeGetIcon();
2021-02-13 16:59:38 +03:00
UpdateAdditionalDocumentFormats();
2019-12-01 22:27:00 +03:00
}
void IppPrinter::printRequestFinished(CURLcode res, Bytestream data)
2019-12-01 22:27:00 +03:00
{
2019-12-17 22:18:57 +03:00
_jobAttrs = QJsonObject();
bool status = false;
2021-08-28 23:16:26 +03:00
if(res == CURLE_OK)
2019-12-01 22:27:00 +03:00
{
try {
2021-08-28 23:16:26 +03:00
IppMsg resp(data);
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();
if(resp.getOpAttrs().keys().contains("status-message"))
{ // Sometimes there are no response attributes at all,
// maybe status-message from the operation attributes is somewhat useful
_jobAttrs["status-message"] = resp.getOpAttrs()["status-message"];
}
2019-12-17 22:18:57 +03:00
status = resp.getStatus() <= 0xff;
2019-12-01 22:27:00 +03:00
}
2020-08-29 18:32:11 +03:00
catch(const std::exception& e)
2019-12-01 22:27:00 +03:00
{
qDebug() << e.what();
}
}
2019-12-17 22:18:57 +03:00
else {
2020-06-13 14:05:33 +03:00
_jobAttrs.insert("job-state-message", QJsonObject {{"tag", IppMsg::TextWithoutLanguage},
{"value", "Network error"}});
2019-12-17 22:18:57 +03:00
}
2021-08-28 23:16:26 +03:00
2019-12-17 22:18:57 +03:00
emit jobAttrsChanged();
2020-04-04 14:56:36 +03:00
emit jobFinished(status);
2019-12-01 22:27:00 +03:00
}
void IppPrinter::getJobsRequestFinished(CURLcode res, Bytestream data)
2019-12-08 15:55:56 +03:00
{
2021-08-28 23:16:26 +03:00
if(res == CURLE_OK)
2019-12-08 15:55:56 +03:00
{
try {
2021-08-28 23:16:26 +03:00
IppMsg resp(data);
2019-12-08 15:55:56 +03:00
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getJobAttrs();
_jobs = resp.getJobAttrs();
emit jobsChanged();
}
2020-08-29 18:32:11 +03:00
catch(const std::exception& e)
2019-12-08 15:55:56 +03:00
{
qDebug() << e.what();
}
}
}
2019-12-01 22:27:00 +03:00
void IppPrinter::cancelJobFinished(CURLcode res, Bytestream data)
2019-12-12 22:53:46 +03:00
{
2020-02-23 15:11:28 +03:00
bool status = false;
2021-08-28 23:16:26 +03:00
if(res == CURLE_OK)
2019-12-12 22:53:46 +03:00
{
try {
2021-08-28 23:16:26 +03:00
IppMsg resp(data);
2019-12-12 22:53:46 +03:00
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
}
2020-08-29 18:32:11 +03:00
catch(const std::exception& e)
2019-12-12 22:53:46 +03:00
{
qDebug() << e.what();
}
}
2020-02-23 15:11:28 +03:00
emit cancelStatus(status);
2019-12-12 22:53:46 +03:00
getJobs();
}
2022-05-16 21:29:53 +03:00
void IppPrinter::identifyFinished(CURLcode /*res*/, Bytestream /*data*/)
{
}
2022-01-15 00:14:06 +03:00
void IppPrinter::getStringsFinished(CURLcode res, Bytestream data)
{
qDebug() << res << data.size();
if(res == CURLE_OK)
{
QByteArray ba((char*)data.raw(), data.size());
// "media-type.com.epson-coated" = "Epson Photo Quality Ink Jet";
QRegularExpression re("^\\\"(.*)\\\"\\s*=\\s*\\\"(.*)\\\";");
QList<QByteArray> bl = ba.split('\n');
2022-05-22 12:00:32 +03:00
for(QByteArray l : bl)
2022-01-15 00:14:06 +03:00
{
QRegularExpressionMatch match = re.match(l);
if(match.hasMatch())
{
_strings[match.captured(1)] = match.captured(2);
}
}
}
}
void IppPrinter::getImageFinished(CURLcode res, Bytestream data)
{
qDebug() << res << data.size();
if(res == CURLE_OK)
{
QImage tmp;
if(tmp.loadFromData(data.raw(), data.size(), "PNG"))
{
_icon = tmp;
qDebug() << "image loaded" << _icon;
emit iconChanged();
if(tmp.size().width() < 128)
{
MaybeGetIcon(true);
}
}
}
}
void IppPrinter::convertFailed(QString message)
{
_jobAttrs = QJsonObject();
_jobAttrs.insert("job-state-message", QJsonObject {{"tag", IppMsg::TextWithoutLanguage}, {"value", message}});
emit jobAttrsChanged();
emit jobFinished(false);
}
2020-01-04 13:55:22 +03:00
QString firstMatch(QJsonArray supported, QStringList wanted)
{
for(QStringList::iterator it = wanted.begin(); it != wanted.end(); it++)
{
if(supported.contains(*it))
{
return *it;
}
}
return "";
}
2021-03-21 19:10:40 +03:00
QString targetFormatIfAuto(QString documentFormat, QString mimeType, QJsonArray supportedMimeTypes)
{
2021-03-21 19:10:40 +03:00
if(documentFormat == Mimer::OctetStream)
{
QStringList PdfPrioList = {Mimer::PDF, Mimer::Postscript, Mimer::PWG, Mimer::URF};
if(mimeType == Mimer::PDF)
{
return firstMatch(supportedMimeTypes, PdfPrioList);
}
2021-03-04 23:49:27 +03:00
else if(mimeType == Mimer::Postscript)
2021-02-13 23:59:46 +03:00
{
2021-03-04 23:49:27 +03:00
return firstMatch(supportedMimeTypes, {Mimer::Postscript});
2021-02-13 23:59:46 +03:00
}
else if(mimeType == Mimer::Plaintext)
{
return firstMatch(supportedMimeTypes, PdfPrioList << Mimer::Plaintext);
}
else if(Mimer::isOffice(mimeType))
{
return firstMatch(supportedMimeTypes, PdfPrioList);
}
2022-05-29 16:54:11 +03:00
else if(documentFormat == Mimer::SVG)
{
QStringList SvgPrioList {Mimer::PWG, Mimer::URF, Mimer::PDF, Mimer::Postscript};
return firstMatch(supportedMimeTypes, SvgPrioList);
}
2021-03-04 23:49:27 +03:00
else if(Mimer::isImage(mimeType))
{
2021-06-13 14:56:44 +03:00
QStringList ImageFormatPrioList {Mimer::PNG, Mimer::PWG, Mimer::URF, Mimer::PDF, Mimer::Postscript, Mimer::JPEG};
2021-03-04 23:49:27 +03:00
if(mimeType == Mimer::JPEG)
{
// Prioritize transferring JPEG as JPEG, as it will not be transcoded
// Normally, it is the last choice (as the others are lossless)
ImageFormatPrioList.prepend(mimeType);
}
return firstMatch(supportedMimeTypes, ImageFormatPrioList);
}
return documentFormat;
}
return documentFormat;
}
void IppPrinter::adjustRasterSettings(QString documentFormat, QJsonObject& jobAttrs, PrintParameters& Params)
2020-06-04 22:31:46 +03:00
{
if(documentFormat != Mimer::PWG && documentFormat != Mimer::URF)
{
return;
}
2022-07-31 20:47:45 +03:00
jobAttrs.remove("printer-resolution");
if(documentFormat == Mimer::PWG)
{
quint32 diff = std::numeric_limits<quint32>::max();
quint32 AdjustedHwResX = Params.hwResW;
quint32 AdjustedHwResY = Params.hwResH;
2022-05-22 12:00:32 +03:00
for(QJsonValue res : _attrs["pwg-raster-document-resolution-supported"].toObject()["value"].toArray())
{
QJsonObject resObj = res.toObject();
if(resObj["units"] != 3)
{
continue;
}
quint32 tmpDiff = std::abs(int(Params.hwResW-resObj["x"].toInt())) + std::abs(int(Params.hwResH-resObj["y"].toInt()));
if(tmpDiff < diff)
{
diff = tmpDiff;
AdjustedHwResX = resObj["x"].toInt();
AdjustedHwResY = resObj["y"].toInt();
}
}
Params.hwResW = AdjustedHwResX;
Params.hwResH = AdjustedHwResY;
}
2022-07-31 20:47:45 +03:00
else if(documentFormat == Mimer::URF)
{ // Ensure symmetric resolution for URF
Params.hwResW = Params.hwResH = std::min(Params.hwResW, Params.hwResH);
quint32 diff = std::numeric_limits<quint32>::max();
quint32 AdjustedHwRes = Params.hwResW;
QJsonArray urfSupported = _attrs["urf-supported"].toObject()["value"].toArray();
2022-05-22 12:00:32 +03:00
for(QJsonValue us : urfSupported)
{
if(us.toString().startsWith("RS"))
{ //RS300[-600]
QStringList resolutions = us.toString().mid(2).split("-");
2022-05-22 12:00:32 +03:00
for(QString res : resolutions)
{
int intRes = res.toInt();
quint32 tmpDiff = std::abs(int(Params.hwResW - intRes));
if(tmpDiff < diff)
{
diff = tmpDiff;
AdjustedHwRes = intRes;
}
}
Params.hwResW = Params.hwResH = AdjustedHwRes;
break;
}
}
}
QString Sides = getAttrOrDefault(jobAttrs, "sides").toString();
if(Sides != "" && Sides != "one-sided")
{
if(documentFormat == Mimer::PWG)
{
QString DocumentSheetBack = _attrs["pwg-raster-document-sheet-back"].toObject()["value"].toString();
if(Sides=="two-sided-long-edge")
{
if(DocumentSheetBack=="flipped")
{
Params.backVFlip=true;
}
else if(DocumentSheetBack=="rotated")
{
Params.backHFlip=true;
Params.backVFlip=true;
}
}
else if(Sides=="two-sided-short-edge")
{
if(DocumentSheetBack=="flipped")
{
Params.backHFlip=true;
}
else if(DocumentSheetBack=="manual-tumble")
{
Params.backHFlip=true;
Params.backVFlip=true;
}
}
}
else if(documentFormat == Mimer::URF)
{
QJsonArray URfSupported = _attrs["urf-supported"].toObject()["value"].toArray();
if(Sides=="two-sided-long-edge")
{
if(URfSupported.contains("DM2"))
{
Params.backVFlip=true;
}
else if(URfSupported.contains("DM3"))
{
Params.backHFlip=true;
Params.backVFlip=true;
}
}
else if(Sides=="two-sided-short-edge")
{
if(URfSupported.contains("DM2"))
{
Params.backHFlip=true;
}
else if(URfSupported.contains("DM4"))
{
Params.backHFlip=true;
Params.backVFlip=true;
}
}
}
}
2022-07-31 20:48:14 +03:00
int copies_requested = getAttrOrDefault(jobAttrs, "copies").toInt(1);
QJsonArray varying_attributes = _attrs["document-format-varying-attributes"].toObject()["value"].toArray();
bool supports_copies = _attrs.contains("copies-supported")
&& _attrs["copies-supported"].toObject()["value"].toObject()["high"].toInt(1) != 1
// assume raster formats causes the variation in supported copies
&& !(varying_attributes.contains("copies-supported") || varying_attributes.contains("copies"));
if(copies_requested > 1 && !supports_copies)
{
QString copyMode = getAttrOrDefault(jobAttrs, "multiple-document-handling").toString();
qDebug() << "Doing local copies" << copyMode << copies_requested;
if(copyMode == "separate-documents-uncollated-copies")
{ // Only do silly copies if explicitly requested
Params.pageCopies = copies_requested;
}
else
{
Params.documentCopies = copies_requested;
}
jobAttrs.remove("copies");
}
}
void IppPrinter::print(QJsonObject jobAttrs, QString filename)
{
qDebug() << "printing" << filename << jobAttrs;
2019-12-01 22:27:00 +03:00
2020-06-03 21:42:18 +03:00
_progress = "";
emit progressChanged();
PrintParameters Params;
2021-08-28 23:16:26 +03:00
QFileInfo fileinfo(filename);
if(!fileinfo.exists())
2020-04-04 14:56:36 +03:00
{
emit convertFailed(tr("Failed to open file"));
2020-04-04 14:56:36 +03:00
return;
}
2019-12-01 22:27:00 +03:00
Mimer* mimer = Mimer::instance();
QString mimeType = mimer->get_type(filename);
QJsonArray supportedMimeTypes = _attrs["document-format-supported"].toObject()["value"].toArray();
for(QStringList::iterator it = _additionalDocumentFormats.begin(); it != _additionalDocumentFormats.end(); it++)
{
supportedMimeTypes.append(*it);
}
qDebug() << supportedMimeTypes << supportedMimeTypes.contains(mimeType);
Params.paperSizeName = getAttrOrDefault(jobAttrs, "media").toString(Params.paperSizeName.c_str()).toStdString();
QString targetFormat = getAttrOrDefault(jobAttrs, "document-format").toString();
qDebug() << "target format:" << targetFormat;
QMargins margins(getAttrOrDefault(jobAttrs, "media-left-margin", "media-col").toInt(),
getAttrOrDefault(jobAttrs, "media-top-margin", "media-col").toInt(),
getAttrOrDefault(jobAttrs, "media-right-margin", "media-col").toInt(),
getAttrOrDefault(jobAttrs, "media-bottom-margin", "media-col").toInt());
// Only keep margin setting for JPEG - but only attemt to remove it if media-col exists
if(!mimer->isImage(targetFormat) && jobAttrs.contains("media-col"))
{
QJsonObject MediaCol = jobAttrs["media-col"].toObject();
QJsonObject MediaColValue = MediaCol["value"].toObject();
MediaColValue.remove("media-left-margin");
MediaColValue.remove("media-top-margin");
MediaColValue.remove("media-right-margin");
MediaColValue.remove("media-bottom-margin");
if(!MediaColValue.empty())
{
MediaCol["value"] = MediaColValue;
jobAttrs["media-col"] = MediaCol;
}
else
{
jobAttrs.remove("media-col");
}
}
2021-07-31 13:59:51 +03:00
if(jobAttrs.contains("media-col") && jobAttrs.contains("media"))
{
qDebug() << "moving media to media-col" << Params.paperSizeName.c_str();
if(!PaperSizes.contains(Params.paperSizeName.c_str()))
{
emit convertFailed(tr("Unsupported paper size"));
return;
}
int x = PaperSizes[Params.paperSizeName.c_str()].width()*100;
int y = PaperSizes[Params.paperSizeName.c_str()].height()*100;
QJsonObject Dimensions =
{{"tag", IppMsg::BeginCollection},
{"value", QJsonObject { {"x-dimension", QJsonObject{{"tag", IppMsg::Integer}, {"value", x}}},
{"y-dimension", QJsonObject{{"tag", IppMsg::Integer}, {"value", y}}} }
}};
// TODO: make a setter function
QJsonObject MediaCol = jobAttrs["media-col"].toObject();
QJsonObject MediaColValue = MediaCol["value"].toObject();
MediaColValue["media-size"] = Dimensions;
MediaCol["value"] = MediaColValue;
2020-06-21 16:49:50 +03:00
MediaCol["tag"] = IppMsg::BeginCollection;
jobAttrs["media-col"] = MediaCol;
jobAttrs.remove("media");
}
2020-06-04 22:31:46 +03:00
QJsonObject jobOpAttrs = opAttrs();
// document-format goes in the op-attrs and not the job-attrs
jobOpAttrs.insert("document-format", QJsonObject {{"tag", IppMsg::MimeMediaType}, {"value", targetFormat}});
jobAttrs.remove("document-format");
targetFormat = targetFormatIfAuto(targetFormat, mimeType, supportedMimeTypes);
qDebug() << "adjusted target format:" << targetFormat;
if(targetFormat == "" || targetFormat == Mimer::OctetStream)
2020-06-04 22:31:46 +03:00
{
emit convertFailed(tr("Unknown document format"));
return;
}
2019-12-01 22:27:00 +03:00
if(targetFormat == Mimer::PDF)
{
Params.format = PrintParameters::PDF;
}
else if(targetFormat == Mimer::Postscript)
{
Params.format = PrintParameters::Postscript;
}
else if(targetFormat == Mimer::PWG)
{
Params.format = PrintParameters::PWG;
}
else if(targetFormat == Mimer::URF)
{
Params.format = PrintParameters::URF;
}
else
{
Params.format = PrintParameters::Invalid;
}
QSizeF size = PaperSizes[Params.paperSizeName.c_str()];
Params.paperSizeUnits = PrintParameters::Millimeters;
Params.paperSizeW = size.width();
Params.paperSizeH = size.height();
qDebug() << "Printing job" << jobOpAttrs << jobAttrs;
2020-01-26 14:08:57 +03:00
QJsonValue PrinterResolutionRef = getAttrOrDefault(jobAttrs, "printer-resolution");
Params.hwResW = PrinterResolutionRef.toObject()["x"].toInt(Params.hwResW);
Params.hwResH = PrinterResolutionRef.toObject()["y"].toInt(Params.hwResH);
2022-07-31 20:48:14 +03:00
bool singlePageRange = false;
if(jobAttrs.contains("page-ranges"))
{
QJsonObject PageRanges = getAttrOrDefault(jobAttrs, "page-ranges").toObject();
2022-07-31 20:48:14 +03:00
size_t fromPage = PageRanges["low"].toInt();
size_t toPage = PageRanges["high"].toInt();
if(fromPage != 0 || toPage != 0)
{
Params.pageRangeList = {{fromPage, toPage}};
singlePageRange = toPage == fromPage;
}
2021-11-15 23:50:48 +03:00
// Effected locally, unless it is Postscript which we cant't render
if(targetFormat != Mimer::Postscript)
2021-11-15 23:50:48 +03:00
{
jobAttrs.remove("page-ranges");
}
}
QString Sides = getAttrOrDefault(jobAttrs, "sides").toString();
2022-07-31 20:48:14 +03:00
int copies_requested = getAttrOrDefault(jobAttrs, "copies").toInt(1);
if((Params.format == PrintParameters::PWG || Params.format == PrintParameters::URF) &&
copies_requested > 1 &&
Sides != "one-sided" &&
(Mimer::instance()->isImage(mimeType) ||
(mimeType == Mimer::PDF && (singlePageRange || ConvertChecker::instance()->pdfPages(filename) == 1))))
{
jobAttrs.insert("sides", QJsonObject {{"tag", IppMsg::Keyword}, {"value", "one-sided"}});
qDebug() << "Optimizing one-page document to one-sided";
}
Sides = getAttrOrDefault(jobAttrs, "sides").toString();
if(Sides=="two-sided-long-edge")
2020-01-26 14:08:57 +03:00
{
Params.duplex = true;
2020-01-26 14:08:57 +03:00
}
else if(Sides=="two-sided-short-edge")
{
Params.duplex = true;
Params.tumble = true;
}
2020-01-26 14:08:57 +03:00
2022-07-31 20:48:14 +03:00
adjustRasterSettings(targetFormat, jobAttrs, Params);
Params.quality = getAttrOrDefault(jobAttrs, "print-quality").toInt();
QString PrintColorMode = getAttrOrDefault(jobAttrs, "print-color-mode").toString();
Params.colors = PrintColorMode.contains("color") ? 3 : PrintColorMode.contains("monochrome") ? 1 : Params.colors;
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);
}
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
2022-07-10 12:36:21 +03:00
IppMsg job = IppMsg(IppMsg::GetJobs, o, QJsonObject());
2019-12-08 15:55:56 +03:00
2022-07-10 12:36:21 +03:00
emit doGetJobs(job.encode());
2019-12-08 15:55:56 +03:00
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}});
2022-07-10 12:36:21 +03:00
IppMsg job = IppMsg(IppMsg::CancelJob, o, QJsonObject());
2019-12-12 22:53:46 +03:00
2022-07-10 12:36:21 +03:00
emit doCancelJob(job.encode());
2019-12-12 22:53:46 +03:00
return true;
}
2022-05-16 21:29:53 +03:00
bool IppPrinter::identify() {
qDebug() << "identifying";
QJsonObject o = opAttrs();
2022-07-10 12:36:21 +03:00
IppMsg job = IppMsg(IppMsg::IdentifyPrinter, o, QJsonObject());
2022-05-16 21:29:53 +03:00
2022-07-10 12:36:21 +03:00
emit doCancelJob(job.encode());
2022-05-16 21:29:53 +03:00
return true;
}
2021-06-28 21:15:21 +03:00
bool IppPrinter::correctSuffix()
{
2022-05-22 12:00:32 +03:00
for(QJsonValue u : _attrs["printer-uri-supported"].toObject()["value"].toArray())
2021-06-28 21:15:21 +03:00
{
QUrl url(u.toString());
if(url.path() == _url.path())
{
return true;
}
}
return false;
}
QStringList IppPrinter::suffixes()
{
QStringList res;
2022-05-22 12:00:32 +03:00
for(QJsonValue u : _attrs["printer-uri-supported"].toObject()["value"].toArray())
2021-06-28 21:15:21 +03:00
{
QUrl url(u.toString());
if(!res.contains(url.path()))
{
res.append(url.path());
}
}
res.sort();
return res;
}
QUrl IppPrinter::httpUrl() {
2021-06-19 19:16:42 +03:00
qDebug() << _url;
QUrl url = _url;
2021-06-19 19:16:42 +03:00
if(url.scheme() == "ipps")
{
url.setScheme("https");
if(url.port() == -1) {
url.setPort(443);
}
}
else
{
url.setScheme("http");
if(url.port() == -1) {
url.setPort(631);
}
}
return url;
}
2020-05-06 21:46:41 +03:00
void IppPrinter::setBusyMessage(QString msg)
{
_busyMessage = msg;
emit busyMessageChanged();
}
2020-06-03 21:42:18 +03:00
void IppPrinter::setProgress(qint64 sent, qint64 total)
{
if(total == 0)
return;
_progress = QString::number(100*sent/total);
_progress += "%";
emit progressChanged();
}
bool IppPrinter::isAllowedAddress(QUrl url)
{
bool allowed = ((url.host() == _url.host()) || Settings::instance()->allowExternalConnections());
qDebug() << url << " is allowed: " << allowed;
return allowed;
}
2021-07-14 16:07:55 +03:00
QJsonValue IppPrinter::getAttrOrDefault(QJsonObject jobAttrs, QString name, QString subkey)
{
2021-07-14 16:07:55 +03:00
if(subkey == "")
{
2021-07-14 16:07:55 +03:00
if(jobAttrs.contains(name))
{
return jobAttrs[name].toObject()["value"];
}
else
{
return _attrs[name+"-default"].toObject()["value"];
}
}
2021-07-14 16:07:55 +03:00
else
{
QJsonObject subObj = jobAttrs[subkey].toObject()["value"].toObject();
if(subObj.contains(name))
{
return subObj[name].toObject()["value"];
}
else
{
return _attrs[name+"-default"].toObject()["value"];
}
}
}
2022-07-10 12:36:21 +03:00
IppMsg IppPrinter::mk_msg(IppMsg::Operation operation, QJsonObject opAttrs, QJsonObject jobAttrs)
{
if(_attrs.contains("ipp-versions-supported") &&
_attrs["ipp-versions-supported"].toObject()["value"].toArray().contains("2.0"))
{
qDebug() << "TWO-POINT-ZERO";
2022-07-10 12:36:21 +03:00
return IppMsg(operation, opAttrs, jobAttrs, 2, 0);
}
2022-07-10 12:36:21 +03:00
return IppMsg(operation, opAttrs, jobAttrs);
}
2022-05-26 15:42:01 +03:00
void IppPrinter::resolveUrl(QUrl& url)
{
if(!IppDiscovery::instance()->resolve(url))
{ // If "proper" resolution fails, cheat...
QString host = url.host();
if(host.endsWith("."))
{
host.chop(1);
}
QString dnsSdName = _attrs["printer-dns-sd-name"].toObject()["value"].toString();
dnsSdName = dnsSdName.append(".local");
if(host.compare(dnsSdName, Qt::CaseInsensitive) == 0)
{ // This could be done unconditionally, but some might want their externally hosted stuff to work
url.setHost(_url.host());
}
}
}