File indexing completed on 2025-01-05 05:09:31

0001 /*
0002     SPDX-FileCopyrightText: 2010-2018 Daniel Nicoletti <dantti12@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "KIppRequest.h"
0008 #include "KIppRequest_p.h"
0009 
0010 #include "kcupslib_log.h"
0011 
0012 KIppRequest::KIppRequest()
0013     : d_ptr(new KIppRequestPrivate)
0014 {
0015 }
0016 
0017 KIppRequest::KIppRequest(const KIppRequest &other)
0018     : d_ptr(new KIppRequestPrivate)
0019 {
0020     *this = other;
0021 }
0022 
0023 KIppRequest::KIppRequest(ipp_op_t operation, const QString &resource, const QString &filename)
0024     : d_ptr(new KIppRequestPrivate)
0025 {
0026     Q_D(KIppRequest);
0027 
0028     d->operation = operation;
0029     d->resource = resource;
0030     d->filename = filename;
0031 
0032     // send our user name on the request too
0033     addString(IPP_TAG_OPERATION, IPP_TAG_NAME, QLatin1String(KCUPS_REQUESTING_USER_NAME), QString::fromUtf8(cupsUser()));
0034 }
0035 
0036 KIppRequest::~KIppRequest()
0037 {
0038     delete d_ptr;
0039 }
0040 
0041 ipp_op_t KIppRequest::operation() const
0042 {
0043     Q_D(const KIppRequest);
0044     return d->operation;
0045 }
0046 
0047 QString KIppRequest::resource() const
0048 {
0049     Q_D(const KIppRequest);
0050     return d->resource;
0051 }
0052 
0053 QString KIppRequest::filename() const
0054 {
0055     Q_D(const KIppRequest);
0056     return d->filename;
0057 }
0058 
0059 ipp_t *KIppRequest::sendIppRequest() const
0060 {
0061     Q_D(const KIppRequest);
0062 
0063     ipp_t *request = ippNewRequest(d->operation);
0064 
0065     d->addRawRequestsToIpp(request);
0066 
0067     if (d->filename.isNull()) {
0068         return cupsDoRequest(CUPS_HTTP_DEFAULT, request, qUtf8Printable(d->resource));
0069     } else {
0070         return cupsDoFileRequest(CUPS_HTTP_DEFAULT, request, qUtf8Printable(d->resource), qUtf8Printable(d->filename));
0071     }
0072 }
0073 
0074 void KIppRequest::addString(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, const QString &value)
0075 {
0076     Q_D(KIppRequest);
0077 
0078     d->addRequest(group, valueTag, name, value);
0079 }
0080 
0081 void KIppRequest::addStringList(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, const QStringList &value)
0082 {
0083     Q_D(KIppRequest);
0084 
0085     d->addRequest(group, valueTag, name, value);
0086 }
0087 
0088 void KIppRequest::addInteger(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, int value)
0089 {
0090     Q_D(KIppRequest);
0091 
0092     d->addRequest(group, valueTag, name, value);
0093 }
0094 
0095 void KIppRequest::addBoolean(ipp_tag_t group, const QString &name, bool value)
0096 {
0097     Q_D(KIppRequest);
0098 
0099     d->addRequest(group, IPP_TAG_ZERO, name, value);
0100 }
0101 
0102 void KIppRequest::addVariantValues(const QVariantMap &values)
0103 {
0104     auto i = values.constBegin();
0105     while (i != values.constEnd()) {
0106         const QString &key = i.key();
0107         const QVariant &value = i.value();
0108         switch (value.type()) {
0109         case QVariant::Bool:
0110             // Still in use at add-printer/PageAddPrinter.cpp
0111             if (key == QLatin1String(KCUPS_PRINTER_IS_ACCEPTING_JOBS)) {
0112                 addBoolean(IPP_TAG_PRINTER, key, value.toBool());
0113             } else {
0114                 addBoolean(IPP_TAG_OPERATION, key, value.toBool());
0115             }
0116             break;
0117         case QVariant::Int:
0118             // Still in use at add-printer/PageAddPrinter.cpp
0119             if (key == QLatin1String(KCUPS_PRINTER_STATE)) {
0120                 addInteger(IPP_TAG_PRINTER, IPP_TAG_ENUM, key, value.toInt());
0121             } else {
0122                 addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, key, value.toInt());
0123             }
0124             break;
0125         case QVariant::String:
0126             // Still in use at add-printer/*
0127             if (key == QLatin1String(KCUPS_DEVICE_URI)) {
0128                 // device uri has a different TAG
0129                 addString(IPP_TAG_PRINTER, IPP_TAG_URI, key, value.toString());
0130             } else if (key == QLatin1String(KCUPS_PRINTER_OP_POLICY) || key == QLatin1String(KCUPS_PRINTER_ERROR_POLICY) || key == QLatin1String("ppd-name")) {
0131                 // printer-op-policy has a different TAG
0132                 addString(IPP_TAG_PRINTER, IPP_TAG_NAME, key, value.toString());
0133             } else if (key == QLatin1String(KCUPS_JOB_NAME)) {
0134                 addString(IPP_TAG_OPERATION, IPP_TAG_NAME, key, value.toString());
0135             } else if (key == QLatin1String(KCUPS_WHICH_JOBS)) {
0136                 addString(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, key, value.toString());
0137             } else {
0138                 addString(IPP_TAG_PRINTER, IPP_TAG_TEXT, key, value.toString());
0139             }
0140             break;
0141         case QVariant::StringList:
0142             if (key == QLatin1String(KCUPS_MEMBER_URIS)) {
0143                 addStringList(IPP_TAG_PRINTER, IPP_TAG_URI, key, value.toStringList());
0144             } else {
0145                 addStringList(IPP_TAG_PRINTER, IPP_TAG_NAME, key, value.toStringList());
0146             }
0147             break;
0148         case QVariant::UInt:
0149             addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, key, value.toInt());
0150             break;
0151         default:
0152             qCWarning(LIBKCUPS) << "type NOT recognized! This will be ignored:" << key << "values" << i.value();
0153         }
0154         ++i;
0155     }
0156 }
0157 
0158 void KIppRequest::addPrinterUri(const QString &printerName, bool isClass)
0159 {
0160     QString uri = assembleUrif(printerName, isClass);
0161     addString(IPP_TAG_OPERATION, IPP_TAG_URI, QLatin1String(KCUPS_PRINTER_URI), uri);
0162 }
0163 
0164 QString KIppRequest::assembleUrif(const QString &name, bool isClass)
0165 {
0166     char uri[HTTP_MAX_URI]; // printer URI
0167 
0168     QString destination;
0169     if (isClass) {
0170         destination = QLatin1String("/classes/") + name;
0171     } else {
0172         destination = QLatin1String("/printers/") + name;
0173     }
0174 
0175     httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", cupsUser(), "localhost", ippPort(), destination.toUtf8().constData());
0176     return QString::fromLatin1(uri);
0177 }
0178 
0179 KIppRequest &KIppRequest::operator=(const KIppRequest &other)
0180 {
0181     Q_D(KIppRequest);
0182     if (this == &other)
0183         return *this;
0184 
0185     *d = *other.d_ptr;
0186 
0187     return *this;
0188 }
0189 
0190 void KIppRequestPrivate::addRequest(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, const QVariant &value)
0191 {
0192     KCupsRawRequest request;
0193     request.group = group;
0194     request.valueTag = valueTag;
0195     request.name = name;
0196     request.value = value;
0197 
0198     rawRequests << request;
0199 }
0200 
0201 void KIppRequestPrivate::addRawRequestsToIpp(ipp_t *ipp) const
0202 {
0203     // sort the values as CUPS requires it
0204     std::sort(rawRequests.begin(), rawRequests.end(), [](const KCupsRawRequest &a, const KCupsRawRequest &b) {
0205         return a.group < b.group;
0206     });
0207 
0208     const QList<KCupsRawRequest> &requests = rawRequests;
0209     for (const KCupsRawRequest &request : requests) {
0210         switch (request.value.type()) {
0211         case QVariant::Bool:
0212             ippAddBoolean(ipp, request.group, request.name.toUtf8().constData(), request.value.toBool());
0213             break;
0214         case QVariant::Int:
0215         case QVariant::UInt:
0216             ippAddInteger(ipp, request.group, request.valueTag, request.name.toUtf8().constData(), request.value.toInt());
0217             break;
0218         case QVariant::String:
0219             ippAddString(ipp, request.group, request.valueTag, request.name.toUtf8().constData(), "utf-8", request.value.toString().toUtf8().constData());
0220             break;
0221         case QVariant::StringList: {
0222             QStringList list = request.value.toStringList();
0223             QList<QByteArray> valuesQByteArrayList;
0224             const char **values = qStringListToCharPtrPtr(list, valuesQByteArrayList);
0225 
0226             ippAddStrings(ipp, request.group, request.valueTag, request.name.toUtf8().constData(), list.size(), "utf-8", values);
0227 
0228             // ippAddStrings deep copies everything so we can throw away the values.
0229             // the QBAList and content is auto discarded when going out of scope.
0230             delete[] values;
0231             break;
0232         }
0233         default:
0234             qCWarning(LIBKCUPS) << "type NOT recognized! This will be ignored:" << request.name << "values" << request.value;
0235         }
0236     }
0237 }