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