819 lines
25 KiB
C++
819 lines
25 KiB
C++
#include "ippprinter.h"
|
|
#include <seaprint_version.h>
|
|
#include "mimer.h"
|
|
#include "papersizes.h"
|
|
#include "overrider.h"
|
|
#include "settings.h"
|
|
|
|
IppPrinter::IppPrinter()
|
|
{
|
|
_nam = new QNetworkAccessManager(this);
|
|
_print_nam = new QNetworkAccessManager(this);
|
|
_jobs_nam = new QNetworkAccessManager(this);
|
|
_job_cancel_nam = new QNetworkAccessManager(this);
|
|
|
|
connect(_nam, &QNetworkAccessManager::finished, this, &IppPrinter::getPrinterAttributesFinished);
|
|
connect(_nam, &QNetworkAccessManager::sslErrors, this, &IppPrinter::onSslErrors);
|
|
|
|
connect(_print_nam, &QNetworkAccessManager::finished, this, &IppPrinter::printRequestFinished);
|
|
connect(_print_nam, &QNetworkAccessManager::sslErrors, this, &IppPrinter::onSslErrors);
|
|
|
|
connect(_jobs_nam, &QNetworkAccessManager::finished,this, &IppPrinter::getJobsRequestFinished);
|
|
connect(_jobs_nam, &QNetworkAccessManager::sslErrors, this, &IppPrinter::onSslErrors);
|
|
|
|
connect(_job_cancel_nam, &QNetworkAccessManager::finished,this, &IppPrinter::cancelJobFinished);
|
|
connect(_job_cancel_nam, &QNetworkAccessManager::sslErrors, this, &IppPrinter::onSslErrors);
|
|
|
|
QObject::connect(this, &IppPrinter::urlChanged, this, &IppPrinter::onUrlChanged);
|
|
qRegisterMetaType<QTemporaryFile*>("QTemporaryFile*");
|
|
|
|
_worker = new ConvertWorker;
|
|
_worker->moveToThread(&_workerThread);
|
|
|
|
connect(&_workerThread, &QThread::finished, _worker, &QObject::deleteLater);
|
|
|
|
connect(this, &IppPrinter::doConvertPdf, _worker, &ConvertWorker::convertPdf);
|
|
connect(this, &IppPrinter::doConvertImage, _worker, &ConvertWorker::convertImage);
|
|
connect(this, &IppPrinter::doConvertOfficeDocument, _worker, &ConvertWorker::convertOfficeDocument);
|
|
connect(this, &IppPrinter::doConvertPlaintext, _worker, &ConvertWorker::convertPlaintext);
|
|
connect(_worker, &ConvertWorker::done, this, &IppPrinter::convertDone);
|
|
connect(_worker, &ConvertWorker::progress, this, &IppPrinter::setProgress);
|
|
connect(_worker, &ConvertWorker::failed, this, &IppPrinter::convertFailed);
|
|
|
|
_workerThread.start();
|
|
_tainted = false;
|
|
}
|
|
|
|
IppPrinter::~IppPrinter() {
|
|
delete _nam;
|
|
delete _print_nam;
|
|
delete _jobs_nam;
|
|
delete _job_cancel_nam;
|
|
}
|
|
|
|
QJsonObject IppPrinter::opAttrs() {
|
|
QString name = qgetenv("USER");
|
|
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}}},
|
|
};
|
|
return o;
|
|
}
|
|
|
|
void IppPrinter::setUrl(QString url_s)
|
|
{
|
|
QUrl url = QUrl(url_s);
|
|
|
|
qDebug() << url.scheme();
|
|
|
|
// 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");
|
|
}
|
|
else if (url.scheme() == "https") {
|
|
url.setScheme("ipps");
|
|
}
|
|
else {
|
|
url = QUrl();
|
|
}
|
|
}
|
|
|
|
qDebug() << url_s << url;
|
|
|
|
if(url != _url)
|
|
{
|
|
_url = url;
|
|
emit urlChanged();
|
|
}
|
|
}
|
|
|
|
void IppPrinter::onUrlChanged()
|
|
{
|
|
refresh();
|
|
}
|
|
|
|
void IppPrinter::refresh() {
|
|
// _attrs = QJsonObject();
|
|
// emit attrsChanged();
|
|
|
|
// _additionalDocumentFormats = QStringList();
|
|
// emit additionalDocumentFormatsChanged();
|
|
|
|
// FFFFUUUU
|
|
_nam->clearAccessCache();
|
|
_jobs_nam->clearAccessCache();
|
|
_job_cancel_nam->clearAccessCache();
|
|
_print_nam->clearAccessCache();
|
|
|
|
if(_url.scheme() == "file")
|
|
{
|
|
_attrs = QJsonObject();
|
|
|
|
QFile file(_url.toLocalFile());
|
|
if(file.open(QIODevice::ReadOnly))
|
|
{
|
|
QJsonDocument JsonDocument = QJsonDocument::fromJson(file.readAll());
|
|
|
|
_attrs = JsonDocument.object();
|
|
// These won't load anyway...r
|
|
_attrs.remove("printer-icons");
|
|
file.close();
|
|
Overrider::instance()->apply(_attrs);
|
|
}
|
|
emit attrsChanged();
|
|
UpdateAdditionalDocumentFormats();
|
|
}
|
|
else
|
|
{
|
|
QNetworkRequest request = mkReq();
|
|
QJsonObject o = opAttrs();
|
|
|
|
IppMsg msg = IppMsg(o);
|
|
_nam->post(request, msg.encode(IppMsg::GetPrinterAttrs));
|
|
}
|
|
}
|
|
|
|
void IppPrinter::UpdateAdditionalDocumentFormats()
|
|
{
|
|
_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(":");
|
|
if(kv.length()==2 && (kv[0]=="CMD" || kv[0]=="COMMAND SET"))
|
|
{
|
|
if(!supportedMimeTypes.contains(Mimer::PDF) && kv[1].contains("PDF"))
|
|
{
|
|
_additionalDocumentFormats.append(Mimer::PDF);
|
|
}
|
|
if(!supportedMimeTypes.contains(Mimer::Postscript) &&
|
|
kv[1].contains("Postscript", Qt::CaseInsensitive))
|
|
{
|
|
_additionalDocumentFormats.append(Mimer::Postscript);
|
|
}
|
|
}
|
|
}
|
|
qDebug() << "additionalDocumentFormats" << _additionalDocumentFormats;
|
|
}
|
|
emit additionalDocumentFormatsChanged();
|
|
}
|
|
|
|
void IppPrinter::getPrinterAttributesFinished(QNetworkReply *reply)
|
|
{
|
|
qDebug() << reply->request().url() << reply->error() << reply->errorString() << reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();
|
|
_attrs = QJsonObject();
|
|
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
{
|
|
try {
|
|
IppMsg resp(reply);
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getPrinterAttrs();
|
|
_attrs = resp.getPrinterAttrs();
|
|
Overrider::instance()->apply(_attrs);
|
|
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
qDebug() << e.what();
|
|
}
|
|
}
|
|
|
|
emit attrsChanged();
|
|
|
|
UpdateAdditionalDocumentFormats();
|
|
}
|
|
|
|
void IppPrinter::printRequestFinished(QNetworkReply *reply)
|
|
{
|
|
_jobAttrs = QJsonObject();
|
|
bool status = false;
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
{
|
|
try {
|
|
IppMsg resp(reply);
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getJobAttrs();
|
|
_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"];
|
|
}
|
|
status = resp.getStatus() <= 0xff;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
qDebug() << e.what();
|
|
}
|
|
}
|
|
else {
|
|
_jobAttrs.insert("job-state-message", QJsonObject {{"tag", IppMsg::TextWithoutLanguage},
|
|
{"value", "Network error"}});
|
|
}
|
|
emit jobAttrsChanged();
|
|
emit jobFinished(status);
|
|
}
|
|
|
|
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(const std::exception& e)
|
|
{
|
|
qDebug() << e.what();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void IppPrinter::cancelJobFinished(QNetworkReply *reply)
|
|
{
|
|
bool status = false;
|
|
if(reply->error() == QNetworkReply::NoError)
|
|
{
|
|
try {
|
|
IppMsg resp(reply);
|
|
qDebug() << resp.getStatus() << resp.getOpAttrs() << resp.getJobAttrs();
|
|
status = resp.getStatus() <= 0xff;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
qDebug() << e.what();
|
|
}
|
|
}
|
|
emit cancelStatus(status);
|
|
getJobs();
|
|
}
|
|
|
|
void IppPrinter::onSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
|
|
{
|
|
_tainted = true;
|
|
emit taintedChanged();
|
|
return ignoreSslErrors(reply, errors);
|
|
}
|
|
|
|
void IppPrinter::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
|
|
{
|
|
bool ignore = Settings::instance()->ignoreSslErrors();
|
|
qDebug() << reply->request().url() << "SSL handshake failed" << errors << ignore;
|
|
if(ignore)
|
|
{
|
|
reply->ignoreSslErrors(errors);
|
|
}
|
|
}
|
|
|
|
void IppPrinter::convertDone(QNetworkRequest request, QTemporaryFile* data)
|
|
{
|
|
connect(_print_nam, SIGNAL(finished(QNetworkReply*)), data, SLOT(deleteLater()));
|
|
data->open();
|
|
|
|
setBusyMessage(tr("Transferring"));
|
|
|
|
QNetworkReply* reply = _print_nam->post(request, data);
|
|
|
|
connect(reply, &QNetworkReply::uploadProgress, this, &IppPrinter::setProgress);
|
|
|
|
}
|
|
|
|
void IppPrinter::convertFailed(QString message)
|
|
{
|
|
_jobAttrs = QJsonObject();
|
|
_jobAttrs.insert("job-state-message", QJsonObject {{"tag", IppMsg::TextWithoutLanguage}, {"value", message}});
|
|
emit jobAttrsChanged();
|
|
emit jobFinished(false);
|
|
}
|
|
|
|
QString firstMatch(QJsonArray supported, QStringList wanted)
|
|
{
|
|
for(QStringList::iterator it = wanted.begin(); it != wanted.end(); it++)
|
|
{
|
|
if(supported.contains(*it))
|
|
{
|
|
return *it;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
QString targetFormatIfAuto(QString documentFormat, QString mimeType, QJsonArray supportedMimeTypes)
|
|
{
|
|
if(documentFormat == Mimer::OctetStream)
|
|
{
|
|
if(mimeType == Mimer::PDF || mimeType == Mimer::Plaintext)
|
|
{
|
|
return firstMatch(supportedMimeTypes, {Mimer::PDF, Mimer::Postscript, Mimer::PWG, Mimer::URF });
|
|
}
|
|
else if(mimeType == Mimer::Postscript)
|
|
{
|
|
return firstMatch(supportedMimeTypes, {Mimer::Postscript});
|
|
}
|
|
else if(Mimer::isOffice(mimeType))
|
|
{
|
|
return firstMatch(supportedMimeTypes, {Mimer::PDF, Mimer::Postscript, Mimer::PWG, Mimer::URF });
|
|
}
|
|
else if(Mimer::isImage(mimeType))
|
|
{
|
|
QStringList ImageFormatPrioList {Mimer::PNG, Mimer::PWG, Mimer::URF, Mimer::PDF, Mimer::Postscript, Mimer::JPEG};
|
|
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, quint32& HwResX, quint32& HwResY,
|
|
bool& BackHFlip, bool& BackVFlip)
|
|
{
|
|
if(documentFormat != Mimer::PWG && documentFormat != Mimer::URF)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//TODO? jobAttrs.remove("printer-resolution");
|
|
|
|
if(documentFormat == Mimer::PWG)
|
|
{
|
|
quint32 diff = std::numeric_limits<quint32>::max();
|
|
quint32 AdjustedHwResX = HwResX;
|
|
quint32 AdjustedHwResY = HwResY;
|
|
foreach(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(HwResX-resObj["x"].toInt())) + std::abs(int(HwResY-resObj["y"].toInt()));
|
|
if(tmpDiff < diff)
|
|
{
|
|
diff = tmpDiff;
|
|
AdjustedHwResX = resObj["x"].toInt();
|
|
AdjustedHwResY = resObj["y"].toInt();
|
|
}
|
|
}
|
|
HwResX = AdjustedHwResX;
|
|
HwResY = AdjustedHwResY;
|
|
}
|
|
|
|
if(documentFormat == Mimer::URF)
|
|
{ // Ensure symmetric resolution for URF
|
|
HwResX = HwResY = std::min(HwResX, HwResY);
|
|
|
|
quint32 diff = std::numeric_limits<quint32>::max();
|
|
quint32 AdjustedHwRes = HwResX;
|
|
|
|
QJsonArray urfSupported = _attrs["urf-supported"].toObject()["value"].toArray();
|
|
foreach(QJsonValue us, urfSupported)
|
|
{
|
|
if(us.toString().startsWith("RS"))
|
|
{ //RS300[-600]
|
|
QStringList resolutions = us.toString().mid(2).split("-");
|
|
foreach(QString res, resolutions)
|
|
{
|
|
int intRes = res.toInt();
|
|
quint32 tmpDiff = std::abs(int(HwResX - intRes));
|
|
if(tmpDiff < diff)
|
|
{
|
|
diff = tmpDiff;
|
|
AdjustedHwRes = intRes;
|
|
}
|
|
}
|
|
|
|
HwResX = HwResY = 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")
|
|
{
|
|
BackVFlip=true;
|
|
}
|
|
else if(DocumentSheetBack=="rotated")
|
|
{
|
|
BackHFlip=true;
|
|
BackVFlip=true;
|
|
}
|
|
}
|
|
else if(Sides=="two-sided-short-edge")
|
|
{
|
|
if(DocumentSheetBack=="flipped")
|
|
{
|
|
BackHFlip=true;
|
|
}
|
|
else if(DocumentSheetBack=="manual-tumble")
|
|
{
|
|
BackHFlip=true;
|
|
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"))
|
|
{
|
|
BackVFlip=true;
|
|
}
|
|
else if(URfSupported.contains("DM3"))
|
|
{
|
|
BackHFlip=true;
|
|
BackVFlip=true;
|
|
}
|
|
}
|
|
else if(Sides=="two-sided-short-edge")
|
|
{
|
|
if(URfSupported.contains("DM2"))
|
|
{
|
|
BackHFlip=true;
|
|
}
|
|
else if(URfSupported.contains("DM4"))
|
|
{
|
|
BackHFlip=true;
|
|
BackVFlip=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void IppPrinter::print(QJsonObject jobAttrs, QString filename)
|
|
{
|
|
qDebug() << "printing" << filename << jobAttrs;
|
|
|
|
_progress = "";
|
|
emit progressChanged();
|
|
|
|
QFile file(filename);
|
|
bool file_ok = file.open(QIODevice::ReadOnly);
|
|
if(!file_ok)
|
|
{
|
|
emit convertFailed(tr("Failed to open file"));
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
QFileInfo fileinfo(file);
|
|
|
|
QJsonObject o = opAttrs();
|
|
o.insert("job-name", QJsonObject {{"tag", IppMsg::NameWithoutLanguage}, {"value", fileinfo.fileName()}});
|
|
|
|
QString PaperSize = getAttrOrDefault(jobAttrs, "media").toString();
|
|
bool alwaysUseMediaCol = Settings::instance()->alwaysUseMediaCol();
|
|
|
|
if((jobAttrs.contains("media-col") || alwaysUseMediaCol) && jobAttrs.contains("media"))
|
|
{
|
|
qDebug() << "moving media to media-col" << PaperSize;
|
|
if(!PaperSizes.contains(PaperSize))
|
|
{
|
|
emit convertFailed(tr("Unknown document format dimensions"));
|
|
return;
|
|
}
|
|
|
|
int x = PaperSizes[PaperSize].first*100;
|
|
int y = PaperSizes[PaperSize].second*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;
|
|
MediaCol["tag"] = IppMsg::BeginCollection;
|
|
jobAttrs["media-col"] = MediaCol;
|
|
|
|
jobAttrs.remove("media");
|
|
}
|
|
|
|
QString documentFormat = getAttrOrDefault(jobAttrs, "document-format").toString();
|
|
qDebug() << "target format:" << documentFormat;
|
|
|
|
// document-format goes in the op-attrs and not the job-attrs
|
|
o.insert("document-format", QJsonObject {{"tag", IppMsg::MimeMediaType}, {"value", documentFormat}});
|
|
jobAttrs.remove("document-format");
|
|
|
|
documentFormat = targetFormatIfAuto(documentFormat, mimeType, supportedMimeTypes);
|
|
qDebug() << "adjusted target format:" << documentFormat;
|
|
|
|
if(documentFormat == "" || documentFormat == Mimer::OctetStream)
|
|
{
|
|
emit convertFailed(tr("Unknown document format"));
|
|
return;
|
|
}
|
|
|
|
qDebug() << "Printing job" << o << jobAttrs;
|
|
|
|
QNetworkRequest request = mkReq();
|
|
|
|
QJsonValue PrinterResolutionRef = getAttrOrDefault(jobAttrs, "printer-resolution");
|
|
quint32 HwResX = PrinterResolutionRef.toObject()["x"].toInt();
|
|
quint32 HwResY = PrinterResolutionRef.toObject()["y"].toInt();
|
|
bool BackHFlip = false;
|
|
bool BackVFlip = false;
|
|
|
|
adjustRasterSettings(documentFormat, jobAttrs, HwResX, HwResY, BackHFlip, BackVFlip);
|
|
|
|
quint32 Quality = getAttrOrDefault(jobAttrs, "print-quality").toInt();
|
|
|
|
QString PrintColorMode = getAttrOrDefault(jobAttrs, "print-color-mode").toString();
|
|
quint32 Colors = PrintColorMode.contains("color") ? 3 : PrintColorMode.contains("monochrome") ? 1 : 0;
|
|
bool pdfPageRangeAdjustNeeded = false;
|
|
|
|
quint32 PageRangeLow = 0;
|
|
quint32 PageRangeHigh = 0;
|
|
if(jobAttrs.contains("page-ranges"))
|
|
{
|
|
QJsonObject PageRanges = getAttrOrDefault(jobAttrs, "page-ranges").toObject();
|
|
PageRangeLow = PageRanges["low"].toInt();
|
|
PageRangeHigh = PageRanges["high"].toInt();
|
|
}
|
|
|
|
QString Sides = getAttrOrDefault(jobAttrs, "sides").toString();
|
|
if(documentFormat == Mimer::PWG || documentFormat == Mimer::URF || documentFormat == Mimer::Postscript || Mimer::isOffice(mimeType))
|
|
{ // Effected locally
|
|
jobAttrs.remove("page-ranges");
|
|
}
|
|
else if (documentFormat == Mimer::PDF)
|
|
{ // Only effected locally if really needed
|
|
if(jobAttrs.contains("page-ranges") && !_attrs.contains("page-ranges-supported"))
|
|
{
|
|
pdfPageRangeAdjustNeeded = true;
|
|
jobAttrs.remove("page-ranges");
|
|
}
|
|
}
|
|
|
|
qDebug() << "Final op attributes:" << o;
|
|
qDebug() << "Final job attributes:" << jobAttrs;
|
|
|
|
IppMsg job = mk_msg(o, jobAttrs);
|
|
QByteArray contents = job.encode(IppMsg::PrintJob);
|
|
|
|
// Non-jpeg images, Postscript and PDF (when not adjusting pages locally)
|
|
// Always convert non-jpeg images to get resizing
|
|
// TODO: make this sane
|
|
if((mimeType == documentFormat)
|
|
&& (documentFormat == Mimer::JPEG || !Mimer::isImage(mimeType))
|
|
&& !((documentFormat == Mimer::PDF) && pdfPageRangeAdjustNeeded))
|
|
{
|
|
QByteArray filedata = file.readAll();
|
|
contents = contents.append(filedata);
|
|
file.close();
|
|
|
|
setBusyMessage(tr("Transferring"));
|
|
QNetworkReply* reply = _print_nam->post(request, contents);
|
|
connect(reply, &QNetworkReply::uploadProgress, this, &IppPrinter::setProgress);
|
|
}
|
|
else
|
|
{
|
|
file.close();
|
|
|
|
if(PaperSize == "")
|
|
{
|
|
PaperSize = "iso_a4_210x297mm";
|
|
}
|
|
else if(!PaperSizes.contains(PaperSize))
|
|
{
|
|
emit convertFailed(tr("Unsupported print media"));
|
|
return;
|
|
}
|
|
|
|
QTemporaryFile* tempfile = new QTemporaryFile();
|
|
tempfile->open();
|
|
tempfile->write(contents);
|
|
qDebug() << tempfile->fileName();
|
|
tempfile->close();
|
|
|
|
bool TwoSided = false;
|
|
bool Tumble = false;
|
|
if(Sides=="two-sided-long-edge")
|
|
{
|
|
TwoSided = true;
|
|
}
|
|
else if(Sides=="two-sided-short-edge")
|
|
{
|
|
TwoSided = true;
|
|
Tumble = true;
|
|
}
|
|
|
|
setBusyMessage(tr("Converting"));
|
|
|
|
if(mimeType == Mimer::PDF)
|
|
{
|
|
emit doConvertPdf(request, filename, tempfile, documentFormat, Colors, Quality,
|
|
PaperSize, HwResX, HwResY, TwoSided, Tumble, PageRangeLow, PageRangeHigh,
|
|
BackHFlip, BackVFlip);
|
|
}
|
|
else if(mimeType == Mimer::Plaintext)
|
|
{
|
|
emit doConvertPlaintext(request, filename, tempfile, documentFormat, Colors, Quality,
|
|
PaperSize, HwResX, HwResY, TwoSided, Tumble, BackHFlip, BackVFlip);
|
|
}
|
|
else if (Mimer::isImage(mimeType))
|
|
{
|
|
emit doConvertImage(request, filename, tempfile, documentFormat, Colors, Quality,
|
|
PaperSize, HwResX, HwResY);
|
|
}
|
|
else if(Mimer::isOffice(mimeType))
|
|
{
|
|
emit doConvertOfficeDocument(request, filename, tempfile, documentFormat, Colors, Quality,
|
|
PaperSize, HwResX, HwResY, TwoSided, Tumble, PageRangeLow, PageRangeHigh,
|
|
BackHFlip, BackVFlip);
|
|
}
|
|
else
|
|
{
|
|
emit convertFailed(tr("Cannot convert this file format"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool IppPrinter::getJobs() {
|
|
|
|
qDebug() << "getting jobs";
|
|
QJsonObject o = opAttrs();
|
|
o.insert("requested-attributes", QJsonObject {{"tag", IppMsg::Keyword}, {"value", "all"}});
|
|
|
|
IppMsg job = IppMsg(o, QJsonObject());
|
|
|
|
QNetworkRequest request = mkReq();
|
|
|
|
QByteArray contents = job.encode(IppMsg::GetJobs);
|
|
|
|
_jobs_nam->post(request, contents);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IppPrinter::cancelJob(qint32 jobId) {
|
|
|
|
qDebug() << "cancelling jobs";
|
|
|
|
QJsonObject o = opAttrs();
|
|
o.insert("job-id", QJsonObject {{"tag", IppMsg::Integer}, {"value", jobId}});
|
|
|
|
IppMsg job = IppMsg(o, QJsonObject());
|
|
|
|
QNetworkRequest request = mkReq();
|
|
|
|
QByteArray contents = job.encode(IppMsg::CancelJob);
|
|
|
|
|
|
_job_cancel_nam->post(request, contents);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IppPrinter::isIpps()
|
|
{
|
|
return _url.scheme() == "ipps";
|
|
}
|
|
|
|
bool IppPrinter::correctSuffix()
|
|
{
|
|
foreach(QJsonValue u, _attrs["printer-uri-supported"].toObject()["value"].toArray())
|
|
{
|
|
QUrl url(u.toString());
|
|
if(url.path() == _url.path())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QStringList IppPrinter::suffixes()
|
|
{
|
|
QStringList res;
|
|
foreach(QJsonValue u, _attrs["printer-uri-supported"].toObject()["value"].toArray())
|
|
{
|
|
QUrl url(u.toString());
|
|
if(!res.contains(url.path()))
|
|
{
|
|
res.append(url.path());
|
|
}
|
|
}
|
|
res.sort();
|
|
return res;
|
|
}
|
|
|
|
QUrl IppPrinter::httpUrl() {
|
|
qDebug() << _url;
|
|
QUrl url = _url;
|
|
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;
|
|
}
|
|
|
|
QNetworkRequest IppPrinter::mkReq() {
|
|
QNetworkRequest request;
|
|
request.setUrl(httpUrl());
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/ipp");
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint " SEAPRINT_VERSION);
|
|
request.setRawHeader("Accept-Encoding", "identity");
|
|
request.setSslConfiguration(QSslConfiguration());
|
|
return request;
|
|
}
|
|
|
|
void IppPrinter::setBusyMessage(QString msg)
|
|
{
|
|
_busyMessage = msg;
|
|
emit busyMessageChanged();
|
|
}
|
|
|
|
void IppPrinter::setProgress(qint64 sent, qint64 total)
|
|
{
|
|
if(total == 0)
|
|
return;
|
|
|
|
_progress = QString::number(100*sent/total);
|
|
_progress += "%";
|
|
emit progressChanged();
|
|
}
|
|
|
|
QJsonValue IppPrinter::getAttrOrDefault(QJsonObject jobAttrs, QString name)
|
|
{
|
|
if(jobAttrs.contains(name))
|
|
{
|
|
return jobAttrs[name].toObject()["value"];
|
|
}
|
|
else {
|
|
return _attrs[name+"-default"].toObject()["value"];
|
|
}
|
|
}
|
|
|
|
IppMsg IppPrinter::mk_msg(QJsonObject opAttrs, QJsonObject jobAttrs)
|
|
{
|
|
if(_attrs.contains("ipp-versions-supported") &&
|
|
_attrs["ipp-versions-supported"].toObject()["value"].toArray().contains("2.0"))
|
|
{
|
|
qDebug() << "TWO-POINT-ZERO";
|
|
return IppMsg(opAttrs, jobAttrs, 2, 0);
|
|
}
|
|
return IppMsg(opAttrs, jobAttrs);
|
|
}
|