2019-12-01 22:27:00 +03:00
|
|
|
#include "ippmsg.h"
|
|
|
|
|
|
|
|
#define MAJ_VSN 1
|
|
|
|
#define MIN_VSN 1
|
|
|
|
|
|
|
|
quint32 IppMsg::_reqid=1;
|
|
|
|
|
|
|
|
IppMsg::IppMsg()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
IppMsg::IppMsg(QJsonObject opAttrs, QJsonObject jobAttrs)
|
|
|
|
{
|
|
|
|
_opAttrs = opAttrs;
|
2019-12-08 15:55:56 +03:00
|
|
|
_jobAttrs = QJsonArray {jobAttrs};
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IppMsg::~IppMsg()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
IppMsg::IppMsg(QNetworkReply* resp)
|
|
|
|
{
|
|
|
|
QByteArray tmp = resp->readAll();
|
|
|
|
Bytestream bts(tmp.constData(), tmp.length());
|
|
|
|
|
|
|
|
quint8 majVsn;
|
|
|
|
quint8 minVsn;
|
|
|
|
quint32 reqId;
|
|
|
|
|
2019-12-06 22:18:48 +03:00
|
|
|
bts >> majVsn >> minVsn >> _status >> reqId;
|
2019-12-01 22:27:00 +03:00
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
QJsonObject attrs;
|
|
|
|
IppMsg::IppTag currentAttrType = IppTag::EndAttrs;
|
2019-12-01 22:27:00 +03:00
|
|
|
|
|
|
|
QString last_name;
|
|
|
|
|
|
|
|
while(!bts.atEnd())
|
|
|
|
{
|
2019-12-08 15:55:56 +03:00
|
|
|
if(bts.peekU8() <= IppTag::PrinterAttrs) {
|
|
|
|
|
|
|
|
if(currentAttrType == IppTag::OpAttrs) {
|
|
|
|
_opAttrs = attrs;
|
|
|
|
}
|
|
|
|
else if (currentAttrType == IppTag::JobAttrs) {
|
|
|
|
_jobAttrs.append(attrs);
|
|
|
|
}
|
|
|
|
else if (currentAttrType == IppTag::PrinterAttrs) {
|
|
|
|
_printerAttrs = attrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(bts >>= (uint8_t)IppTag::EndAttrs) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentAttrType = (IppTag)bts.getU8();
|
|
|
|
attrs = QJsonObject();
|
|
|
|
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
last_name = consume_attribute(attrs, bts, last_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
QString IppMsg::consume_attribute(QJsonObject& attrs, Bytestream& data, QString lastName)
|
2019-12-01 22:27:00 +03:00
|
|
|
{
|
|
|
|
quint8 tag;
|
|
|
|
quint16 tmp_len;
|
|
|
|
QString name;
|
|
|
|
QJsonValue value;
|
|
|
|
std::string tmp_str = "";
|
|
|
|
bool noList = false;
|
|
|
|
|
|
|
|
data >> tag >> tmp_len;
|
|
|
|
|
|
|
|
data/tmp_len >> tmp_str;
|
|
|
|
name = tmp_str!="" ? tmp_str.c_str() : lastName;
|
|
|
|
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
case OpAttrs:
|
|
|
|
case JobAttrs:
|
|
|
|
case EndAttrs:
|
|
|
|
case PrinterAttrs:
|
|
|
|
Q_ASSERT(false);
|
|
|
|
case Integer:
|
|
|
|
case Enum:
|
|
|
|
quint32 tmp_u32;
|
|
|
|
data >> tmp_len >> tmp_u32;
|
|
|
|
value = (int)tmp_u32;
|
|
|
|
break;
|
|
|
|
case Boolean:
|
|
|
|
quint8 tmp_bool;
|
|
|
|
data >> tmp_len >> tmp_bool;
|
|
|
|
value = (bool)tmp_bool;
|
|
|
|
noList = true;
|
|
|
|
break;
|
|
|
|
case DateTime:
|
|
|
|
{
|
|
|
|
quint16 year;
|
|
|
|
quint8 month, day, hour, minutes, seconds, deci_seconds,
|
|
|
|
plus_minus, utc_h_offset, utc_m_offset;
|
|
|
|
data >> tmp_len >> year >> month >> day >> hour >> minutes >> seconds >> deci_seconds
|
|
|
|
>> plus_minus >> utc_h_offset >> utc_m_offset;
|
|
|
|
QDate date(year, month, day);
|
|
|
|
QTime time(hour, minutes, seconds, deci_seconds*100);
|
|
|
|
int offset_seconds = (plus_minus == '+' ? 1 : -1)*(utc_h_offset*60*60+utc_m_offset*60);
|
|
|
|
value = QDateTime(date, time, Qt::OffsetFromUTC, offset_seconds).toString(Qt::ISODate);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Resolution:
|
|
|
|
{
|
|
|
|
qint32 x, y;
|
|
|
|
qint8 units;
|
|
|
|
QJsonObject tmp_res;
|
|
|
|
data >> tmp_len >> x >> y >> units;
|
|
|
|
tmp_res.insert("x", x);
|
|
|
|
tmp_res.insert("y", y);
|
|
|
|
tmp_res.insert("units", units);
|
|
|
|
value = tmp_res;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IntegerRange:
|
|
|
|
{
|
|
|
|
qint32 low, high;
|
|
|
|
data >> tmp_len >> low >> high;
|
|
|
|
QJsonObject tmp_range;
|
|
|
|
tmp_range.insert("low", low);
|
|
|
|
tmp_range.insert("high", high);
|
|
|
|
value = tmp_range;
|
|
|
|
noList = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OctetStringUnknown:
|
|
|
|
case TextWithLanguage:
|
|
|
|
case NameWithLanguage:
|
|
|
|
case TextWithoutLanguage:
|
|
|
|
case NameWithoutLanguage:
|
|
|
|
case Keyword:
|
|
|
|
case Uri:
|
|
|
|
case UriScheme:
|
|
|
|
case Charset:
|
|
|
|
case NaturalLanguage:
|
|
|
|
case MimeMediaType:
|
|
|
|
default:
|
|
|
|
data >> tmp_len;
|
|
|
|
data/tmp_len >> tmp_str;
|
|
|
|
value = tmp_str.c_str();
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-12-08 15:55:56 +03:00
|
|
|
if(attrs.contains(name))
|
2019-12-01 22:27:00 +03:00
|
|
|
{
|
2019-12-08 15:55:56 +03:00
|
|
|
QJsonObject tmp = attrs[name].toObject();
|
2019-12-01 22:27:00 +03:00
|
|
|
QJsonArray tmpa;
|
|
|
|
if(tmp["value"].isArray())
|
|
|
|
{
|
|
|
|
tmpa = tmp["value"].toArray();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmpa = QJsonArray {tmp["value"]};
|
|
|
|
}
|
|
|
|
tmpa.append(value);
|
|
|
|
tmp["value"] = tmpa;
|
2019-12-08 15:55:56 +03:00
|
|
|
attrs.insert(name, tmp);
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if((name.endsWith("-supported") || name == "printer-icons") && !noList)
|
|
|
|
{
|
|
|
|
value = QJsonArray {value};
|
|
|
|
}
|
2019-12-08 15:55:56 +03:00
|
|
|
attrs.insert(name, QJsonObject {{"tag", tag}, {"value", value}});
|
2019-12-01 22:27:00 +03:00
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray IppMsg::encode(Operation op)
|
|
|
|
{
|
|
|
|
Bytestream ipp;
|
|
|
|
|
|
|
|
ipp << quint8(MAJ_VSN) << quint8(MIN_VSN);
|
|
|
|
|
|
|
|
ipp << quint16(op);
|
|
|
|
ipp << _reqid++;
|
|
|
|
|
|
|
|
if(!_opAttrs.empty())
|
|
|
|
{
|
|
|
|
ipp << quint8(1);
|
|
|
|
for(QJsonObject::iterator it = _opAttrs.begin(); it != _opAttrs.end(); it++)
|
|
|
|
{
|
|
|
|
QJsonObject val = it.value().toObject();
|
|
|
|
ipp << encode_attr(val["tag"].toInt(), it.key(), val["value"]);
|
|
|
|
}
|
|
|
|
}
|
2019-12-08 15:55:56 +03:00
|
|
|
for(QJsonArray::iterator ait = _jobAttrs.begin(); ait != _jobAttrs.begin(); ait++)
|
2019-12-01 22:27:00 +03:00
|
|
|
{
|
|
|
|
ipp << quint8(2);
|
2019-12-08 15:55:56 +03:00
|
|
|
QJsonObject tmpObj = ait->toObject();
|
|
|
|
for(QJsonObject::iterator it = tmpObj.begin(); it != tmpObj.end(); it++)
|
2019-12-01 22:27:00 +03:00
|
|
|
{
|
|
|
|
QJsonObject val = it.value().toObject();
|
|
|
|
ipp << encode_attr(val["tag"].toInt(), it.key(), val["value"]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ipp << quint8(3);
|
|
|
|
|
|
|
|
return QByteArray((char*)(ipp.raw()), ipp.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
Bytestream IppMsg::encode_attr(quint8 tag, QString name, QJsonValueRef value)
|
|
|
|
{
|
|
|
|
Bytestream req;
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
case OpAttrs:
|
|
|
|
case JobAttrs:
|
|
|
|
case EndAttrs:
|
|
|
|
case PrinterAttrs:
|
|
|
|
Q_ASSERT(false);
|
|
|
|
case Integer:
|
|
|
|
case Enum:
|
|
|
|
{
|
|
|
|
quint32 tmp_u32 = value.toInt();
|
|
|
|
req << (quint16)4 << tmp_u32;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Boolean:
|
|
|
|
{
|
|
|
|
quint32 tmp_u8 = value.toBool();
|
|
|
|
req << (quint16)1 << tmp_u8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DateTime:
|
|
|
|
{
|
|
|
|
Q_ASSERT("fixme");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Resolution:
|
|
|
|
{
|
|
|
|
qDebug() << value << value.toObject();
|
|
|
|
qint32 x = value.toObject()["x"].toInt();
|
|
|
|
qint32 y = value.toObject()["y"].toInt();
|
|
|
|
qint8 units = value.toObject()["units"].toInt();
|
|
|
|
req << (quint16)9 << x << y << units;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IntegerRange:
|
|
|
|
{
|
|
|
|
qint32 low = value.toObject()["low"].toInt();
|
|
|
|
qint32 high = value.toObject()["high"].toInt();
|
|
|
|
req << (quint16)8 << low << high;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OctetStringUnknown:
|
|
|
|
case TextWithLanguage:
|
|
|
|
case NameWithLanguage:
|
|
|
|
case TextWithoutLanguage:
|
|
|
|
case NameWithoutLanguage:
|
|
|
|
case Keyword:
|
|
|
|
case Uri:
|
|
|
|
case UriScheme:
|
|
|
|
case Charset:
|
|
|
|
case NaturalLanguage:
|
|
|
|
case MimeMediaType:
|
|
|
|
req << quint16(value.toString().length()) << value.toString().toStdString();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qDebug() << "uncaught tag" << tag;
|
|
|
|
Q_ASSERT(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bytestream actual;
|
|
|
|
if(req.size() != 0)
|
|
|
|
{
|
|
|
|
actual << tag << quint16(name.length()) << name.toStdString() << req;
|
|
|
|
}
|
|
|
|
|
|
|
|
return actual;
|
|
|
|
}
|