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 #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR <= 2
00314 strncpy( HTTP->authstring, cups_authstring.data(), HTTP_MAX_VALUE );
00315 #else
00316 httpSetAuthString( HTTP, NULL, cups_authstring.data() );
00317 #endif
00318 #endif
00319
00320 if (dump_ > 0)
00321 {
00322 dumpRequest(request_, false, "Request to "+myHost+":"+QString::number(myPort));
00323 }
00324
00325 request_ = cupsDoFileRequest(HTTP, request_, (res.isEmpty() ? "/" : res.latin1()), (filename.isEmpty() ? NULL : filename.latin1()));
00326 #ifdef HAVE_CUPS_NO_PWD_CACHE
00327 #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR <= 2
00328 cups_authstring = HTTP->authstring;
00329 #else
00330 cups_authstring = httpGetAuthString( HTTP );
00331 #endif
00332 #endif
00333 httpClose(HTTP);
00334
00335 if (dump_ > 1)
00336 {
00337 dumpRequest(request_, true);
00338 }
00339
00340
00341 if ( request_ && request_->request.status.status_code == 0x406 )
00342 return true;
00343
00344 if (!request_ || request_->state == IPP_ERROR || (request_->request.status.status_code & 0x0F00))
00345 return false;
00346
00347
00348 return true;
00349 }
00350
00351 bool IppRequest::htmlReport(int group, QTextStream& output)
00352 {
00353 if (!request_) return false;
00354
00355 output << "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">" << endl;
00356 output << "<tr><th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Attribute") << "</font></th>" << endl;
00357 output << "<th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Values") << "</font></th></tr>" << endl;
00358
00359 ipp_attribute_t *attr = request_->attrs;
00360 while (attr && attr->group_tag != group)
00361 attr = attr->next;
00362
00363 ipp_uchar_t *d;
00364 QCString dateStr;
00365 QDateTime dt;
00366 bool bg(false);
00367 while (attr && attr->group_tag == group)
00368 {
00369 output << " <tr bgcolor=\"" << (bg ? "#ffffd9" : "#ffffff") << "\">\n <td><b>" << attr->name << "</b></td>\n <td>" << endl;
00370 bg = !bg;
00371 for (int i=0; i<attr->num_values; i++)
00372 {
00373 switch (attr->value_tag)
00374 {
00375 case IPP_TAG_INTEGER:
00376 if (attr->name && strstr(attr->name, "time"))
00377 {
00378 dt.setTime_t((unsigned int)(attr->values[i].integer));
00379 output << dt.toString();
00380 }
00381 else
00382 output << attr->values[i].integer;
00383 break;
00384 case IPP_TAG_ENUM:
00385 output << "0x" << hex << attr->values[i].integer << dec;
00386 break;
00387 case IPP_TAG_BOOLEAN:
00388 output << (attr->values[i].boolean ? i18n("True") : i18n("False"));
00389 break;
00390 case IPP_TAG_STRING:
00391 case IPP_TAG_TEXTLANG:
00392 case IPP_TAG_NAMELANG:
00393 case IPP_TAG_TEXT:
00394 case IPP_TAG_NAME:
00395 case IPP_TAG_KEYWORD:
00396 case IPP_TAG_URI:
00397 case IPP_TAG_CHARSET:
00398 case IPP_TAG_LANGUAGE:
00399 case IPP_TAG_MIMETYPE:
00400 output << attr->values[i].string.text;
00401 break;
00402 case IPP_TAG_RESOLUTION:
00403 output << "( " << attr->values[i].resolution.xres
00404 << ", " << attr->values[i].resolution.yres << " )";
00405 break;
00406 case IPP_TAG_RANGE:
00407 output << "[ " << (attr->values[i].range.lower > 0 ? attr->values[i].range.lower : 1)
00408 << ", " << (attr->values[i].range.upper > 0 ? attr->values[i].range.upper : 65535) << " ]";
00409 break;
00410 case IPP_TAG_DATE:
00411 d = attr->values[i].date;
00412 dateStr.sprintf("%.4d-%.2d-%.2d, %.2d:%.2d:%.2d %c%.2d%.2d",
00413 d[0]*256+d[1], d[2], d[3],
00414 d[4], d[5], d[6],
00415 d[8], d[9], d[10]);
00416 output << dateStr;
00417 break;
00418 default:
00419 continue;
00420 }
00421 if (i < attr->num_values-1)
00422 output << "<br>";
00423 }
00424 output << "</td>\n </tr>" << endl;
00425 attr = attr->next;
00426 }
00427
00428 output << "</table>" << endl;
00429
00430 return true;
00431 }
00432
00433 QMap<QString,QString> IppRequest::toMap(int group)
00434 {
00435 QMap<QString,QString> opts;
00436 if (request_)
00437 {
00438 ipp_attribute_t *attr = first();
00439 while (attr)
00440 {
00441 if (group != -1 && attr->group_tag != group)
00442 {
00443 attr = attr->next;
00444 continue;
00445 }
00446 QString value;
00447 for (int i=0; i<attr->num_values; i++)
00448 {
00449 switch (attr->value_tag)
00450 {
00451 case IPP_TAG_INTEGER:
00452 case IPP_TAG_ENUM:
00453 value.append(QString::number(attr->values[i].integer)).append(",");
00454 break;
00455 case IPP_TAG_BOOLEAN:
00456 value.append((attr->values[i].boolean ? "true" : "false")).append(",");
00457 break;
00458 case IPP_TAG_RANGE:
00459 if (attr->values[i].range.lower > 0)
00460 value.append(QString::number(attr->values[i].range.lower));
00461 if (attr->values[i].range.lower != attr->values[i].range.upper)
00462 {
00463 value.append("-");
00464 if (attr->values[i].range.upper > 0)
00465 value.append(QString::number(attr->values[i].range.upper));
00466 }
00467 value.append(",");
00468 break;
00469 case IPP_TAG_STRING:
00470 case IPP_TAG_TEXT:
00471 case IPP_TAG_NAME:
00472 case IPP_TAG_KEYWORD:
00473 case IPP_TAG_URI:
00474 case IPP_TAG_MIMETYPE:
00475 case IPP_TAG_NAMELANG:
00476 case IPP_TAG_TEXTLANG:
00477 case IPP_TAG_CHARSET:
00478 case IPP_TAG_LANGUAGE:
00479 value.append(QString::fromLocal8Bit(attr->values[i].string.text)).append(",");
00480 break;
00481 default:
00482 break;
00483 }
00484 }
00485 if (!value.isEmpty())
00486 value.truncate(value.length()-1);
00487 opts[QString::fromLocal8Bit(attr->name)] = value;
00488 attr = attr->next;
00489 }
00490 }
00491 return opts;
00492 }
00493
00494 void IppRequest::setMap(const QMap<QString,QString>& opts)
00495 {
00496 if (!request_)
00497 return;
00498
00499 QRegExp re("^\"|\"$");
00500 cups_option_t *options = NULL;
00501 int n = 0;
00502 for (QMap<QString,QString>::ConstIterator it=opts.begin(); it!=opts.end(); ++it)
00503 {
00504 if (it.key().startsWith("kde-") || it.key().startsWith("app-"))
00505 continue;
00506 QString value = it.data().stripWhiteSpace(), lovalue;
00507 value.replace(re, "");
00508 lovalue = value.lower();
00509
00510
00511
00512 if (value == "true" || value == "false")
00513 addBoolean(IPP_TAG_JOB, it.key(), (value == "true"));
00514 else if (value.isEmpty() || lovalue == "off" || lovalue == "on"
00515 || lovalue == "yes" || lovalue == "no"
00516 || lovalue == "true" || lovalue == "false")
00517 addName(IPP_TAG_JOB, it.key(), value);
00518 else
00519 n = cupsAddOption(it.key().local8Bit(), value.local8Bit(), n, &options);
00520 }
00521 if (n > 0)
00522 cupsEncodeOptions(request_, n, options);
00523 cupsFreeOptions(n, options);
00524
00525
00526 #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2
00527 ipp_attribute_t *attr = ippFindAttribute(request_, "document-format", IPP_TAG_NAME);
00528 ippDeleteAttribute(request_, attr);
00529 #else
00530
00531 ipp_attribute_t *attr = request_->attrs;
00532 while (attr)
00533 {
00534 if (attr->next && strcmp(attr->next->name, "document-format") == 0)
00535 {
00536 ipp_attribute_t *attr2 = attr->next;
00537 attr->next = attr2->next;
00538 _ipp_free_attr(attr2);
00539 break;
00540 }
00541 attr = attr->next;
00542 }
00543 #endif
00544 }