kdeprint Library API Documentation

ipprequest.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2001 Michael Goffioul <goffioul@imec.be>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation.
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  *  Boston, MA 02111-1307, USA.
00018  **/
00019 
00020 #include "ipprequest.h"
00021 #include "cupsinfos.h"
00022 
00023 #include <stdlib.h>
00024 #include <cups/language.h>
00025 #include <kdebug.h>
00026 #include <kglobal.h>
00027 #include <klocale.h>
00028 #include <qdatetime.h>
00029 #include <qregexp.h>
00030 #include <cups/cups.h>
00031 
00032 void dumpRequest(ipp_t *req, bool answer = false, const QString& s = QString::null)
00033 {
00034     kdDebug(500) << "==========" << endl;
00035     if (s.isEmpty())
00036         kdDebug(500) << (answer ? "Answer" : "Request") << endl;
00037     else
00038         kdDebug(500) << s << endl;
00039     kdDebug(500) << "==========" << endl;
00040     if (!req)
00041     {
00042         kdDebug(500) << "Null request" << endl;
00043         return;
00044     }
00045     kdDebug(500) << "State = 0x" << QString::number(req->state, 16) << endl;
00046     kdDebug(500) << "ID = 0x" << QString::number(req->request.status.request_id, 16) << endl;
00047     if (answer)
00048     {
00049         kdDebug(500) << "Status = 0x" << QString::number(req->request.status.status_code, 16) << endl;
00050         kdDebug(500) << "Status message = " << ippErrorString(req->request.status.status_code) << endl;
00051     }
00052     else
00053         kdDebug(500) << "Operation = 0x" << QString::number(req->request.op.operation_id, 16) << endl;
00054     kdDebug(500) << "Version = " << (int)(req->request.status.version[0]) << "." << (int)(req->request.status.version[1]) << endl;
00055     kdDebug(500) << endl;
00056 
00057     ipp_attribute_t *attr = req->attrs;
00058     while (attr)
00059     {
00060         QString s = QString::fromLatin1("%1 (0x%2) = ").arg(attr->name).arg(attr->value_tag, 0, 16);
00061         for (int i=0;i<attr->num_values;i++)
00062         {
00063             switch (attr->value_tag)
00064             {
00065                 case IPP_TAG_INTEGER:
00066                 case IPP_TAG_ENUM:
00067                     s += ("0x"+QString::number(attr->values[i].integer, 16));
00068                     break;
00069                 case IPP_TAG_BOOLEAN:
00070                     s += (attr->values[i].boolean ? "true" : "false");
00071                     break;
00072                 case IPP_TAG_STRING:
00073                 case IPP_TAG_TEXT:
00074                 case IPP_TAG_NAME:
00075                 case IPP_TAG_KEYWORD:
00076                 case IPP_TAG_URI:
00077                 case IPP_TAG_MIMETYPE:
00078                 case IPP_TAG_NAMELANG:
00079                 case IPP_TAG_TEXTLANG:
00080                 case IPP_TAG_CHARSET:
00081                 case IPP_TAG_LANGUAGE:
00082                     s += attr->values[i].string.text;
00083                     break;
00084                 default:
00085                     break;
00086             }
00087             if (i != (attr->num_values-1))
00088                 s += ", ";
00089         }
00090         kdDebug(500) << s << endl;
00091         attr = attr->next;
00092     }
00093 }
00094 
00095 QString errorString(int status)
00096 {
00097     QString str;
00098     switch (status)
00099     {
00100         case IPP_FORBIDDEN:
00101             str = i18n("You don't have access to the requested resource.");
00102             break;
00103         case IPP_NOT_AUTHORIZED:
00104             str = i18n("You are not authorized to access the requested resource.");
00105             break;
00106         case IPP_NOT_POSSIBLE:
00107             str = i18n("The requested operation cannot be completed.");
00108             break;
00109         case IPP_SERVICE_UNAVAILABLE:
00110             str = i18n("The requested service is currently unavailable.");
00111             break;
00112         case IPP_NOT_ACCEPTING:
00113             str = i18n("The target printer is not accepting print jobs.");
00114             break;
00115         default:
00116             str = QString::fromLocal8Bit(ippErrorString((ipp_status_t)status));
00117             break;
00118     }
00119     return str;
00120 }
00121 
00122 //*************************************************************************************
00123 
00124 IppRequest::IppRequest()
00125 {
00126     request_ = 0;
00127     port_ = -1;
00128     host_ = QString::null;
00129     dump_ = 0;
00130     init();
00131 }
00132 
00133 IppRequest::~IppRequest()
00134 {
00135     ippDelete(request_);
00136 }
00137 
00138 void IppRequest::init()
00139 {
00140     connect_ = true;
00141 
00142     if (request_)
00143     {
00144         ippDelete(request_);
00145         request_ = 0;
00146     }
00147     request_ = ippNew();
00148     //kdDebug(500) << "kdeprint: IPP request, lang=" << KGlobal::locale()->language() << endl;
00149         QCString langstr = KGlobal::locale()->language().latin1();
00150     cups_lang_t*    lang = cupsLangGet(langstr.data());
00151     // default charset to UTF-8 (ugly hack)
00152     lang->encoding = CUPS_UTF8;
00153     ippAddString(request_, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, cupsLangEncoding(lang));
00154     ippAddString(request_, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, lang->language);
00155     cupsLangFree(lang);
00156 }
00157 
00158 void IppRequest::addString_p(int group, int type, const QString& name, const QString& value)
00159 {
00160     if (!name.isEmpty())
00161         ippAddString(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),NULL,(value.isEmpty() ? "" : value.local8Bit().data()));
00162 }
00163 
00164 void IppRequest::addStringList_p(int group, int type, const QString& name, const QStringList& values)
00165 {
00166     if (!name.isEmpty())
00167     {
00168         ipp_attribute_t *attr = ippAddStrings(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),(int)(values.count()),NULL,NULL);
00169         int i(0);
00170         for (QStringList::ConstIterator it=values.begin(); it != values.end(); ++it, i++)
00171             attr->values[i].string.text = strdup((*it).local8Bit());
00172     }
00173 }
00174 
00175 void IppRequest::addInteger_p(int group, int type, const QString& name, int value)
00176 {
00177     if (!name.isEmpty()) ippAddInteger(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),value);
00178 }
00179 
00180 void IppRequest::addIntegerList_p(int group, int type, const QString& name, const QValueList<int>& values)
00181 {
00182     if (!name.isEmpty())
00183     {
00184         ipp_attribute_t *attr = ippAddIntegers(request_,(ipp_tag_t)group,(ipp_tag_t)type,name.latin1(),(int)(values.count()),NULL);
00185         int i(0);
00186         for (QValueList<int>::ConstIterator it=values.begin(); it != values.end(); ++it, i++)
00187             attr->values[i].integer = *it;
00188     }
00189 }
00190 
00191 void IppRequest::addBoolean(int group, const QString& name, bool value)
00192 {
00193     if (!name.isEmpty()) ippAddBoolean(request_,(ipp_tag_t)group,name.latin1(),(char)value);
00194 }
00195 
00196 void IppRequest::addBoolean(int group, const QString& name, const QValueList<bool>& values)
00197 {
00198     if (!name.isEmpty())
00199     {
00200         ipp_attribute_t *attr = ippAddBooleans(request_,(ipp_tag_t)group,name.latin1(),(int)(values.count()),NULL);
00201         int i(0);
00202         for (QValueList<bool>::ConstIterator it=values.begin(); it != values.end(); ++it, i++)
00203             attr->values[i].boolean = (char)(*it);
00204     }
00205 }
00206 
00207 void IppRequest::setOperation(int op)
00208 {
00209     request_->request.op.operation_id = (ipp_op_t)op;
00210     request_->request.op.request_id = 1;    // 0 is not RFC-compliant, should be at least 1
00211 }
00212 
00213 int IppRequest::status()
00214 {
00215     return (request_ ? request_->request.status.status_code : (connect_ ? cupsLastError() : -2));
00216 }
00217 
00218 QString IppRequest::statusMessage()
00219 {
00220     QString msg;
00221     switch (status())
00222     {
00223         case -2:
00224             msg = i18n("Connection to CUPS server failed. Check that the CUPS server is correctly installed and running.");
00225             break;
00226         case -1:
00227             msg = i18n("The IPP request failed for an unknown reason.");
00228             break;
00229         default:
00230             msg = errorString(status());
00231             break;
00232     }
00233     return msg;
00234 }
00235 
00236 bool IppRequest::integerValue_p(const QString& name, int& value, int type)
00237 {
00238     if (!request_ || name.isEmpty()) return false;
00239     ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), (ipp_tag_t)type);
00240     if (attr)
00241     {
00242         value = attr->values[0].integer;
00243         return true;
00244     }
00245     else return false;
00246 }
00247 
00248 bool IppRequest::stringValue_p(const QString& name, QString& value, int type)
00249 {
00250     if (!request_ || name.isEmpty()) return false;
00251     ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), (ipp_tag_t)type);
00252     if (attr)
00253     {
00254         value = QString::fromLocal8Bit(attr->values[0].string.text);
00255         return true;
00256     }
00257     else return false;
00258 }
00259 
00260 bool IppRequest::stringListValue_p(const QString& name, QStringList& values, int type)
00261 {
00262     if (!request_ || name.isEmpty()) return false;
00263     ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), (ipp_tag_t)type);
00264     values.clear();
00265     if (attr)
00266     {
00267         for (int i=0;i<attr->num_values;i++)
00268             values.append(QString::fromLocal8Bit(attr->values[i].string.text));
00269         return true;
00270     }
00271     else return false;
00272 }
00273 
00274 bool IppRequest::boolean(const QString& name, bool& value)
00275 {
00276     if (!request_ || name.isEmpty()) return false;
00277     ipp_attribute_t *attr = ippFindAttribute(request_, name.latin1(), IPP_TAG_BOOLEAN);
00278     if (attr)
00279     {
00280         value = (bool)attr->values[0].boolean;
00281         return true;
00282     }
00283     else return false;
00284 }
00285 
00286 bool IppRequest::doFileRequest(const QString& res, const QString& filename)
00287 {
00288     QString myHost = host_;
00289     int     myPort = port_;
00290     if (myHost.isEmpty()) myHost = CupsInfos::self()->host();
00291     if (myPort <= 0) myPort = CupsInfos::self()->port();
00292     http_t  *HTTP = httpConnect(myHost.latin1(),myPort);
00293 
00294     connect_ = (HTTP != NULL);
00295 
00296     if (HTTP == NULL)
00297     {
00298         ippDelete(request_);
00299         request_ = 0;
00300         return false;
00301     }
00302 
00303     if (dump_ > 0)
00304     {
00305         dumpRequest(request_, false, "Request to "+myHost+":"+QString::number(myPort));
00306     }
00307 
00308     request_ = cupsDoFileRequest(HTTP, request_, (res.isEmpty() ? "/" : res.latin1()), (filename.isEmpty() ? NULL : filename.latin1()));
00309     httpClose(HTTP);
00310 
00311     if (dump_ > 1)
00312     {
00313         dumpRequest(request_, true);
00314     }
00315 
00316     if (!request_ || request_->state == IPP_ERROR || (request_->request.status.status_code & 0x0F00))
00317         return false;
00318 
00319 
00320     return true;
00321 }
00322 
00323 bool IppRequest::htmlReport(int group, QTextStream& output)
00324 {
00325     if (!request_) return false;
00326     // start table
00327     output << "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">" << endl;
00328     output << "<tr><th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Attribute") << "</font></th>" << endl;
00329     output << "<th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Values") << "</font></th></tr>" << endl;
00330     // go to the first attribute of the specified group
00331     ipp_attribute_t *attr = request_->attrs;
00332     while (attr && attr->group_tag != group)
00333         attr = attr->next;
00334     // print each attribute
00335     ipp_uchar_t *d;
00336     QCString    dateStr;
00337     QDateTime   dt;
00338     bool    bg(false);
00339     while (attr && attr->group_tag == group)
00340     {
00341         output << "  <tr bgcolor=\"" << (bg ? "#ffffd9" : "#ffffff") << "\">\n    <td><b>" << attr->name << "</b></td>\n    <td>" << endl;
00342         bg = !bg;
00343         for (int i=0; i<attr->num_values; i++)
00344         {
00345             switch (attr->value_tag)
00346             {
00347                 case IPP_TAG_INTEGER:
00348                     if (attr->name && strstr(attr->name, "time"))
00349                     {
00350                         dt.setTime_t((unsigned int)(attr->values[i].integer));
00351                         output << dt.toString();
00352                     }
00353                     else
00354                         output << attr->values[i].integer;
00355                     break;
00356                 case IPP_TAG_ENUM:
00357                     output << "0x" << hex << attr->values[i].integer << dec;
00358                     break;
00359                 case IPP_TAG_BOOLEAN:
00360                     output << (attr->values[i].boolean ? i18n("True") : i18n("False"));
00361                     break;
00362                 case IPP_TAG_STRING:
00363                 case IPP_TAG_TEXTLANG:
00364                 case IPP_TAG_NAMELANG:
00365                 case IPP_TAG_TEXT:
00366                 case IPP_TAG_NAME:
00367                 case IPP_TAG_KEYWORD:
00368                 case IPP_TAG_URI:
00369                 case IPP_TAG_CHARSET:
00370                 case IPP_TAG_LANGUAGE:
00371                 case IPP_TAG_MIMETYPE:
00372                     output << attr->values[i].string.text;
00373                     break;
00374                 case IPP_TAG_RESOLUTION:
00375                     output << "( " << attr->values[i].resolution.xres
00376                            << ", " << attr->values[i].resolution.yres << " )";
00377                     break;
00378                 case IPP_TAG_RANGE:
00379                     output << "[ " << (attr->values[i].range.lower > 0 ? attr->values[i].range.lower : 1)
00380                            << ", " << (attr->values[i].range.upper > 0 ? attr->values[i].range.upper : 65535) << " ]";
00381                     break;
00382                 case IPP_TAG_DATE:
00383                     d = attr->values[i].date;
00384                     dateStr.sprintf("%.4d-%.2d-%.2d, %.2d:%.2d:%.2d %c%.2d%.2d",
00385                             d[0]*256+d[1], d[2], d[3],
00386                             d[4], d[5], d[6],
00387                             d[8], d[9], d[10]);
00388                     output << dateStr;
00389                     break;
00390                 default:
00391                     continue;
00392             }
00393             if (i < attr->num_values-1)
00394                 output << "<br>";
00395         }
00396         output << "</td>\n  </tr>" << endl;
00397         attr = attr->next;
00398     }
00399     // end table
00400     output << "</table>" << endl;
00401 
00402     return true;
00403 }
00404 
00405 QMap<QString,QString> IppRequest::toMap(int group)
00406 {
00407     QMap<QString,QString>   opts;
00408     if (request_)
00409     {
00410         ipp_attribute_t *attr = first();
00411         while (attr)
00412         {
00413             if (group != -1 && attr->group_tag != group)
00414             {
00415                 attr = attr->next;
00416                 continue;
00417             }
00418             QString value;
00419             for (int i=0; i<attr->num_values; i++)
00420             {
00421                 switch (attr->value_tag)
00422                 {
00423                     case IPP_TAG_INTEGER:
00424                     case IPP_TAG_ENUM:
00425                         value.append(QString::number(attr->values[i].integer)).append(",");
00426                         break;
00427                     case IPP_TAG_BOOLEAN:
00428                         value.append((attr->values[i].boolean ? "true" : "false")).append(",");
00429                         break;
00430                     case IPP_TAG_RANGE:
00431                         if (attr->values[i].range.lower > 0)
00432                             value.append(QString::number(attr->values[i].range.lower));
00433                         if (attr->values[i].range.lower != attr->values[i].range.upper)
00434                         {
00435                             value.append("-");
00436                             if (attr->values[i].range.upper > 0)
00437                                 value.append(QString::number(attr->values[i].range.upper));
00438                         }
00439                         value.append(",");
00440                         break;
00441                     case IPP_TAG_STRING:
00442                     case IPP_TAG_TEXT:
00443                     case IPP_TAG_NAME:
00444                     case IPP_TAG_KEYWORD:
00445                     case IPP_TAG_URI:
00446                     case IPP_TAG_MIMETYPE:
00447                     case IPP_TAG_NAMELANG:
00448                     case IPP_TAG_TEXTLANG:
00449                     case IPP_TAG_CHARSET:
00450                     case IPP_TAG_LANGUAGE:
00451                         value.append(QString::fromLocal8Bit(attr->values[i].string.text)).append(",");
00452                         break;
00453                     default:
00454                         break;
00455                 }
00456             }
00457             if (!value.isEmpty())
00458                 value.truncate(value.length()-1);
00459             opts[QString::fromLocal8Bit(attr->name)] = value;
00460             attr = attr->next;
00461         }
00462     }
00463     return opts;
00464 }
00465 
00466 void IppRequest::setMap(const QMap<QString,QString>& opts)
00467 {
00468     if (!request_)
00469         return;
00470 
00471     QRegExp re("^\"|\"$");
00472     cups_option_t   *options = NULL;
00473     int n = 0;
00474     for (QMap<QString,QString>::ConstIterator it=opts.begin(); it!=opts.end(); ++it)
00475     {
00476         if (it.key().startsWith("kde-") || it.key().startsWith("app-"))
00477             continue;
00478         QString value = it.data().stripWhiteSpace(), lovalue;
00479         value.replace(re, "");
00480         lovalue = value.lower();
00481 
00482         // handles specific cases: boolean, empty strings, or option that has that boolean
00483         // keyword as value (to prevent them from conversion to real boolean)
00484         if (value == "true" || value == "false")
00485             addBoolean(IPP_TAG_JOB, it.key(), (value == "true"));
00486         else if (value.isEmpty() || lovalue == "off" || lovalue == "on"
00487                  || lovalue == "yes" || lovalue == "no"
00488              || lovalue == "true" || lovalue == "false")
00489             addName(IPP_TAG_JOB, it.key(), value);
00490         else
00491             n = cupsAddOption(it.key().local8Bit(), value.local8Bit(), n, &options);
00492     }
00493     if (n > 0)
00494         cupsEncodeOptions(request_, n, options);
00495     cupsFreeOptions(n, options);
00496 
00497     // find an remove that annoying "document-format" attribute
00498     ipp_attribute_t *attr = request_->attrs;
00499     while (attr)
00500     {
00501         if (attr->next && strcmp(attr->next->name, "document-format") == 0)
00502         {
00503             ipp_attribute_t *attr2 = attr->next;
00504             attr->next = attr2->next;
00505             _ipp_free_attr(attr2);
00506             break;
00507         }
00508         attr = attr->next;
00509     }
00510 }
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.2.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Feb 4 12:36:21 2004 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2003