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 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
00149 QCString langstr = KGlobal::locale()->language().latin1();
00150 cups_lang_t* lang = cupsLangGet(langstr.data());
00151
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;
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
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
00331 ipp_attribute_t *attr = request_->attrs;
00332 while (attr && attr->group_tag != group)
00333 attr = attr->next;
00334
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
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
00483
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
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 }