diff options
Diffstat (limited to 'tdeprint/cups/ipprequest.cpp')
-rw-r--r-- | tdeprint/cups/ipprequest.cpp | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/tdeprint/cups/ipprequest.cpp b/tdeprint/cups/ipprequest.cpp new file mode 100644 index 000000000..16cbe3308 --- /dev/null +++ b/tdeprint/cups/ipprequest.cpp @@ -0,0 +1,544 @@ +/* + * This file is part of the KDE libraries + * Copyright (c) 2001 Michael Goffioul <tdeprint@swing.be> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + **/ + +#include "ipprequest.h" +#include "cupsinfos.h" + +#include <stdlib.h> +#include <cups/language.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <tqdatetime.h> +#include <tqregexp.h> +#include <cups/cups.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_CUPS_NO_PWD_CACHE +#include <tqcstring.h> +static TQCString cups_authstring = ""; +#endif + +void dumpRequest(ipp_t *req, bool answer = false, const TQString& s = TQString::null) +{ + kdDebug(500) << "==========" << endl; + if (s.isEmpty()) + kdDebug(500) << (answer ? "Answer" : "Request") << endl; + else + kdDebug(500) << s << endl; + kdDebug(500) << "==========" << endl; + if (!req) + { + kdDebug(500) << "Null request" << endl; + return; + } + kdDebug(500) << "State = 0x" << TQString::number(req->state, 16) << endl; + kdDebug(500) << "ID = 0x" << TQString::number(req->request.status.request_id, 16) << endl; + if (answer) + { + kdDebug(500) << "Status = 0x" << TQString::number(req->request.status.status_code, 16) << endl; + kdDebug(500) << "Status message = " << ippErrorString(req->request.status.status_code) << endl; + } + else + kdDebug(500) << "Operation = 0x" << TQString::number(req->request.op.operation_id, 16) << endl; + kdDebug(500) << "Version = " << (int)(req->request.status.version[0]) << "." << (int)(req->request.status.version[1]) << endl; + kdDebug(500) << endl; + + ipp_attribute_t *attr = req->attrs; + while (attr) + { + TQString s = TQString::tqfromLatin1("%1 (0x%2) = ").arg(attr->name).arg(attr->value_tag, 0, 16); + for (int i=0;i<attr->num_values;i++) + { + switch (attr->value_tag) + { + case IPP_TAG_INTEGER: + case IPP_TAG_ENUM: + s += ("0x"+TQString::number(attr->values[i].integer, 16)); + break; + case IPP_TAG_BOOLEAN: + s += (attr->values[i].boolean ? "true" : "false"); + break; + case IPP_TAG_STRING: + case IPP_TAG_TEXT: + case IPP_TAG_NAME: + case IPP_TAG_KEYWORD: + case IPP_TAG_URI: + case IPP_TAG_MIMETYPE: + case IPP_TAG_NAMELANG: + case IPP_TAG_TEXTLANG: + case IPP_TAG_CHARSET: + case IPP_TAG_LANGUAGE: + s += attr->values[i].string.text; + break; + default: + break; + } + if (i != (attr->num_values-1)) + s += ", "; + } + kdDebug(500) << s << endl; + attr = attr->next; + } +} + +TQString errorString(int status) +{ + TQString str; + switch (status) + { + case IPP_FORBIDDEN: + str = i18n("You don't have access to the requested resource."); + break; + case IPP_NOT_AUTHORIZED: + str = i18n("You are not authorized to access the requested resource."); + break; + case IPP_NOT_POSSIBLE: + str = i18n("The requested operation cannot be completed."); + break; + case IPP_SERVICE_UNAVAILABLE: + str = i18n("The requested service is currently unavailable."); + break; + case IPP_NOT_ACCEPTING: + str = i18n("The target printer is not accepting print jobs."); + break; + default: + str = TQString::fromLocal8Bit(ippErrorString((ipp_status_t)status)); + break; + } + return str; +} + +//************************************************************************************* + +IppRequest::IppRequest() +{ + request_ = 0; + port_ = -1; + host_ = TQString(); + dump_ = 0; + init(); +} + +IppRequest::~IppRequest() +{ + ippDelete(request_); +} + +void IppRequest::init() +{ + connect_ = true; + + if (request_) + { + ippDelete(request_); + request_ = 0; + } + request_ = ippNew(); + //kdDebug(500) << "tdeprint: IPP request, lang=" << KGlobal::locale()->language() << endl; + TQCString langstr = KGlobal::locale()->language().latin1(); + cups_lang_t* lang = cupsLangGet(langstr.data()); + // default charset to UTF-8 (ugly hack) + lang->encoding = CUPS_UTF8; + ippAddString(request_, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, cupsLangEncoding(lang)); + ippAddString(request_, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, lang->language); + cupsLangFree(lang); +} + +void IppRequest::addString_p(int group, int type, const TQString& name, const TQString& value) +{ + if (!name.isEmpty()) + ippAddString(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),NULL,(value.isEmpty() ? "" : value.local8Bit().data())); +} + +void IppRequest::addStringList_p(int group, int type, const TQString& name, const TQStringList& values) +{ + if (!name.isEmpty()) + { + ipp_attribute_t *attr = ippAddStrings(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),(int)(values.count()),NULL,NULL); + int i(0); + for (TQStringList::ConstIterator it=values.begin(); it != values.end(); ++it, i++) + attr->values[i].string.text = strdup((*it).local8Bit()); + } +} + +void IppRequest::addInteger_p(int group, int type, const TQString& name, int value) +{ + if (!name.isEmpty()) ippAddInteger(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),value); +} + +void IppRequest::addIntegerList_p(int group, int type, const TQString& name, const TQValueList<int>& values) +{ + if (!name.isEmpty()) + { + ipp_attribute_t *attr = ippAddIntegers(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),(int)(values.count()),NULL); + int i(0); + for (TQValueList<int>::ConstIterator it=values.begin(); it != values.end(); ++it, i++) + attr->values[i].integer = *it; + } +} + +void IppRequest::addBoolean(int group, const TQString& name, bool value) +{ + if (!name.isEmpty()) ippAddBoolean(request_,(ipp_tag_t)group,name.latin1(),(char)value); +} + +void IppRequest::addBoolean(int group, const TQString& name, const TQValueList<bool>& values) +{ + if (!name.isEmpty()) + { + ipp_attribute_t *attr = ippAddBooleans(request_,(ipp_tag_t)group,name.latin1(),(int)(values.count()),NULL); + int i(0); + for (TQValueList<bool>::ConstIterator it=values.begin(); it != values.end(); ++it, i++) + attr->values[i].boolean = (char)(*it); + } +} + +void IppRequest::setOperation(int op) +{ + request_->request.op.operation_id = (ipp_op_t)op; + request_->request.op.request_id = 1; // 0 is not RFC-compliant, should be at least 1 +} + +int IppRequest::status() +{ + return (request_ ? request_->request.status.status_code : (connect_ ? cupsLastError() : -2)); +} + +TQString IppRequest::statusMessage() +{ + TQString msg; + switch (status()) + { + case -2: + msg = i18n("Connection to CUPS server failed. Check that the CUPS server is correctly installed and running."); + break; + case -1: + msg = i18n("The IPP request failed for an unknown reason."); + break; + default: + msg = errorString(status()); + break; + } + return msg; +} + +bool IppRequest::integerValue_p(const TQString& name, int& value, int type) +{ + if (!request_ || name.isEmpty()) return false; + ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), (ipp_tag_t)type); + if (attr) + { + value = attr->values[0].integer; + return true; + } + else return false; +} + +bool IppRequest::stringValue_p(const TQString& name, TQString& value, int type) +{ + if (!request_ || name.isEmpty()) return false; + ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), (ipp_tag_t)type); + if (attr) + { + value = TQString::fromLocal8Bit(attr->values[0].string.text); + return true; + } + else return false; +} + +bool IppRequest::stringListValue_p(const TQString& name, TQStringList& values, int type) +{ + if (!request_ || name.isEmpty()) return false; + ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), (ipp_tag_t)type); + values.clear(); + if (attr) + { + for (int i=0;i<attr->num_values;i++) + values.append(TQString::fromLocal8Bit(attr->values[i].string.text)); + return true; + } + else return false; +} + +bool IppRequest::boolean(const TQString& name, bool& value) +{ + if (!request_ || name.isEmpty()) return false; + ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), IPP_TAG_BOOLEAN); + if (attr) + { + value = (bool)attr->values[0].boolean; + return true; + } + else return false; +} + +bool IppRequest::doFileRequest(const TQString& res, const TQString& filename) +{ + TQString myHost = host_; + int myPort = port_; + if (myHost.isEmpty()) myHost = CupsInfos::self()->host(); + if (myPort <= 0) myPort = CupsInfos::self()->port(); + http_t *HTTP = httpConnect(myHost.latin1(),myPort); + + connect_ = (HTTP != NULL); + + if (HTTP == NULL) + { + ippDelete(request_); + request_ = 0; + return false; + } + +#ifdef HAVE_CUPS_NO_PWD_CACHE +#if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR <= 2 + strncpy( HTTP->authstring, cups_authstring.data(), HTTP_MAX_VALUE ); +#else + httpSetAuthString( HTTP, NULL, cups_authstring.data() ); +#endif +#endif + + if (dump_ > 0) + { + dumpRequest(request_, false, "Request to "+myHost+":"+TQString::number(myPort)); + } + + request_ = cupsDoFileRequest(HTTP, request_, (res.isEmpty() ? "/" : res.latin1()), (filename.isEmpty() ? NULL : filename.latin1())); +#ifdef HAVE_CUPS_NO_PWD_CACHE +#if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR <= 2 + cups_authstring = HTTP->authstring; +#else + cups_authstring = httpGetAuthString( HTTP ); +#endif +#endif + httpClose(HTTP); + + if (dump_ > 1) + { + dumpRequest(request_, true); + } + + /* No printers found */ + if ( request_ && request_->request.status.status_code == 0x406 ) + return true; + + if (!request_ || request_->state == IPP_ERROR || (request_->request.status.status_code & 0x0F00)) + return false; + + + return true; +} + +bool IppRequest::htmlReport(int group, TQTextStream& output) +{ + if (!request_) return false; + // start table + output << "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">" << endl; + output << "<tr><th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Attribute") << "</font></th>" << endl; + output << "<th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Values") << "</font></th></tr>" << endl; + // go to the first attribute of the specified group + ipp_attribute_t *attr = request_->attrs; + while (attr && attr->group_tag != group) + attr = attr->next; + // print each attribute + ipp_uchar_t *d; + TQCString dateStr; + TQDateTime dt; + bool bg(false); + while (attr && attr->group_tag == group) + { + output << " <tr bgcolor=\"" << (bg ? "#ffffd9" : "#ffffff") << "\">\n <td><b>" << attr->name << "</b></td>\n <td>" << endl; + bg = !bg; + for (int i=0; i<attr->num_values; i++) + { + switch (attr->value_tag) + { + case IPP_TAG_INTEGER: + if (attr->name && strstr(attr->name, "time")) + { + dt.setTime_t((unsigned int)(attr->values[i].integer)); + output << dt.toString(); + } + else + output << attr->values[i].integer; + break; + case IPP_TAG_ENUM: + output << "0x" << hex << attr->values[i].integer << dec; + break; + case IPP_TAG_BOOLEAN: + output << (attr->values[i].boolean ? i18n("True") : i18n("False")); + break; + case IPP_TAG_STRING: + case IPP_TAG_TEXTLANG: + case IPP_TAG_NAMELANG: + case IPP_TAG_TEXT: + case IPP_TAG_NAME: + case IPP_TAG_KEYWORD: + case IPP_TAG_URI: + case IPP_TAG_CHARSET: + case IPP_TAG_LANGUAGE: + case IPP_TAG_MIMETYPE: + output << attr->values[i].string.text; + break; + case IPP_TAG_RESOLUTION: + output << "( " << attr->values[i].resolution.xres + << ", " << attr->values[i].resolution.yres << " )"; + break; + case IPP_TAG_RANGE: + output << "[ " << (attr->values[i].range.lower > 0 ? attr->values[i].range.lower : 1) + << ", " << (attr->values[i].range.upper > 0 ? attr->values[i].range.upper : 65535) << " ]"; + break; + case IPP_TAG_DATE: + d = attr->values[i].date; + dateStr.sprintf("%.4d-%.2d-%.2d, %.2d:%.2d:%.2d %c%.2d%.2d", + d[0]*256+d[1], d[2], d[3], + d[4], d[5], d[6], + d[8], d[9], d[10]); + output << dateStr; + break; + default: + continue; + } + if (i < attr->num_values-1) + output << "<br>"; + } + output << "</td>\n </tr>" << endl; + attr = attr->next; + } + // end table + output << "</table>" << endl; + + return true; +} + +TQMap<TQString,TQString> IppRequest::toMap(int group) +{ + TQMap<TQString,TQString> opts; + if (request_) + { + ipp_attribute_t *attr = first(); + while (attr) + { + if (group != -1 && attr->group_tag != group) + { + attr = attr->next; + continue; + } + TQString value; + for (int i=0; i<attr->num_values; i++) + { + switch (attr->value_tag) + { + case IPP_TAG_INTEGER: + case IPP_TAG_ENUM: + value.append(TQString::number(attr->values[i].integer)).append(","); + break; + case IPP_TAG_BOOLEAN: + value.append((attr->values[i].boolean ? "true" : "false")).append(","); + break; + case IPP_TAG_RANGE: + if (attr->values[i].range.lower > 0) + value.append(TQString::number(attr->values[i].range.lower)); + if (attr->values[i].range.lower != attr->values[i].range.upper) + { + value.append("-"); + if (attr->values[i].range.upper > 0) + value.append(TQString::number(attr->values[i].range.upper)); + } + value.append(","); + break; + case IPP_TAG_STRING: + case IPP_TAG_TEXT: + case IPP_TAG_NAME: + case IPP_TAG_KEYWORD: + case IPP_TAG_URI: + case IPP_TAG_MIMETYPE: + case IPP_TAG_NAMELANG: + case IPP_TAG_TEXTLANG: + case IPP_TAG_CHARSET: + case IPP_TAG_LANGUAGE: + value.append(TQString::fromLocal8Bit(attr->values[i].string.text)).append(","); + break; + default: + break; + } + } + if (!value.isEmpty()) + value.truncate(value.length()-1); + opts[TQString::fromLocal8Bit(attr->name)] = value; + attr = attr->next; + } + } + return opts; +} + +void IppRequest::setMap(const TQMap<TQString,TQString>& opts) +{ + if (!request_) + return; + + TQRegExp re("^\"|\"$"); + cups_option_t *options = NULL; + int n = 0; + for (TQMap<TQString,TQString>::ConstIterator it=opts.begin(); it!=opts.end(); ++it) + { + if (it.key().startsWith("kde-") || it.key().startsWith("app-")) + continue; + TQString value = it.data().stripWhiteSpace(), lovalue; + value.replace(re, ""); + lovalue = value.lower(); + + // handles specific cases: boolean, empty strings, or option that has that boolean + // keyword as value (to prevent them from conversion to real boolean) + if (value == "true" || value == "false") + addBoolean(IPP_TAG_JOB, it.key(), (value == "true")); + else if (value.isEmpty() || lovalue == "off" || lovalue == "on" + || lovalue == "yes" || lovalue == "no" + || lovalue == "true" || lovalue == "false") + addName(IPP_TAG_JOB, it.key(), value); + else + n = cupsAddOption(it.key().local8Bit(), value.local8Bit(), n, &options); + } + if (n > 0) + cupsEncodeOptions(request_, n, options); + cupsFreeOptions(n, options); + + // find an remove that annoying "document-format" attribute +#if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2 + ipp_attribute_t *attr = ippFindAttribute(request_, "document-format", IPP_TAG_NAME); + ippDeleteAttribute(request_, attr); +#else + // (can't use IppDeleteAttribute as older cups doesn't have that) + ipp_attribute_t *attr = request_->attrs; + while (attr) + { + if (attr->next && strcmp(attr->next->name, "document-format") == 0) + { + ipp_attribute_t *attr2 = attr->next; + attr->next = attr2->next; + _ipp_free_attr(attr2); + break; + } + attr = attr->next; + } +#endif +} |