kdeprint Library API Documentation

ipprequest.cpp

00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (c) 2001 Michael Goffioul <kdeprint@swing.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 #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 //kdDebug(500) << "kdeprint: IPP request, lang=" << KGlobal::locale()->language() << endl; 00158 QCString langstr = KGlobal::locale()->language().latin1(); 00159 cups_lang_t* lang = cupsLangGet(langstr.data()); 00160 // default charset to UTF-8 (ugly hack) 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; // 0 is not RFC-compliant, should be at least 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 if (!request_ || request_->state == IPP_ERROR || (request_->request.status.status_code & 0x0F00)) 00333 return false; 00334 00335 00336 return true; 00337 } 00338 00339 bool IppRequest::htmlReport(int group, QTextStream& output) 00340 { 00341 if (!request_) return false; 00342 // start table 00343 output << "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">" << endl; 00344 output << "<tr><th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Attribute") << "</font></th>" << endl; 00345 output << "<th bgcolor=\"dark blue\"><font color=\"white\">" << i18n("Values") << "</font></th></tr>" << endl; 00346 // go to the first attribute of the specified group 00347 ipp_attribute_t *attr = request_->attrs; 00348 while (attr && attr->group_tag != group) 00349 attr = attr->next; 00350 // print each attribute 00351 ipp_uchar_t *d; 00352 QCString dateStr; 00353 QDateTime dt; 00354 bool bg(false); 00355 while (attr && attr->group_tag == group) 00356 { 00357 output << " <tr bgcolor=\"" << (bg ? "#ffffd9" : "#ffffff") << "\">\n <td><b>" << attr->name << "</b></td>\n <td>" << endl; 00358 bg = !bg; 00359 for (int i=0; i<attr->num_values; i++) 00360 { 00361 switch (attr->value_tag) 00362 { 00363 case IPP_TAG_INTEGER: 00364 if (attr->name && strstr(attr->name, "time")) 00365 { 00366 dt.setTime_t((unsigned int)(attr->values[i].integer)); 00367 output << dt.toString(); 00368 } 00369 else 00370 output << attr->values[i].integer; 00371 break; 00372 case IPP_TAG_ENUM: 00373 output << "0x" << hex << attr->values[i].integer << dec; 00374 break; 00375 case IPP_TAG_BOOLEAN: 00376 output << (attr->values[i].boolean ? i18n("True") : i18n("False")); 00377 break; 00378 case IPP_TAG_STRING: 00379 case IPP_TAG_TEXTLANG: 00380 case IPP_TAG_NAMELANG: 00381 case IPP_TAG_TEXT: 00382 case IPP_TAG_NAME: 00383 case IPP_TAG_KEYWORD: 00384 case IPP_TAG_URI: 00385 case IPP_TAG_CHARSET: 00386 case IPP_TAG_LANGUAGE: 00387 case IPP_TAG_MIMETYPE: 00388 output << attr->values[i].string.text; 00389 break; 00390 case IPP_TAG_RESOLUTION: 00391 output << "( " << attr->values[i].resolution.xres 00392 << ", " << attr->values[i].resolution.yres << " )"; 00393 break; 00394 case IPP_TAG_RANGE: 00395 output << "[ " << (attr->values[i].range.lower > 0 ? attr->values[i].range.lower : 1) 00396 << ", " << (attr->values[i].range.upper > 0 ? attr->values[i].range.upper : 65535) << " ]"; 00397 break; 00398 case IPP_TAG_DATE: 00399 d = attr->values[i].date; 00400 dateStr.sprintf("%.4d-%.2d-%.2d, %.2d:%.2d:%.2d %c%.2d%.2d", 00401 d[0]*256+d[1], d[2], d[3], 00402 d[4], d[5], d[6], 00403 d[8], d[9], d[10]); 00404 output << dateStr; 00405 break; 00406 default: 00407 continue; 00408 } 00409 if (i < attr->num_values-1) 00410 output << "<br>"; 00411 } 00412 output << "</td>\n </tr>" << endl; 00413 attr = attr->next; 00414 } 00415 // end table 00416 output << "</table>" << endl; 00417 00418 return true; 00419 } 00420 00421 QMap<QString,QString> IppRequest::toMap(int group) 00422 { 00423 QMap<QString,QString> opts; 00424 if (request_) 00425 { 00426 ipp_attribute_t *attr = first(); 00427 while (attr) 00428 { 00429 if (group != -1 && attr->group_tag != group) 00430 { 00431 attr = attr->next; 00432 continue; 00433 } 00434 QString value; 00435 for (int i=0; i<attr->num_values; i++) 00436 { 00437 switch (attr->value_tag) 00438 { 00439 case IPP_TAG_INTEGER: 00440 case IPP_TAG_ENUM: 00441 value.append(QString::number(attr->values[i].integer)).append(","); 00442 break; 00443 case IPP_TAG_BOOLEAN: 00444 value.append((attr->values[i].boolean ? "true" : "false")).append(","); 00445 break; 00446 case IPP_TAG_RANGE: 00447 if (attr->values[i].range.lower > 0) 00448 value.append(QString::number(attr->values[i].range.lower)); 00449 if (attr->values[i].range.lower != attr->values[i].range.upper) 00450 { 00451 value.append("-"); 00452 if (attr->values[i].range.upper > 0) 00453 value.append(QString::number(attr->values[i].range.upper)); 00454 } 00455 value.append(","); 00456 break; 00457 case IPP_TAG_STRING: 00458 case IPP_TAG_TEXT: 00459 case IPP_TAG_NAME: 00460 case IPP_TAG_KEYWORD: 00461 case IPP_TAG_URI: 00462 case IPP_TAG_MIMETYPE: 00463 case IPP_TAG_NAMELANG: 00464 case IPP_TAG_TEXTLANG: 00465 case IPP_TAG_CHARSET: 00466 case IPP_TAG_LANGUAGE: 00467 value.append(QString::fromLocal8Bit(attr->values[i].string.text)).append(","); 00468 break; 00469 default: 00470 break; 00471 } 00472 } 00473 if (!value.isEmpty()) 00474 value.truncate(value.length()-1); 00475 opts[QString::fromLocal8Bit(attr->name)] = value; 00476 attr = attr->next; 00477 } 00478 } 00479 return opts; 00480 } 00481 00482 void IppRequest::setMap(const QMap<QString,QString>& opts) 00483 { 00484 if (!request_) 00485 return; 00486 00487 QRegExp re("^\"|\"$"); 00488 cups_option_t *options = NULL; 00489 int n = 0; 00490 for (QMap<QString,QString>::ConstIterator it=opts.begin(); it!=opts.end(); ++it) 00491 { 00492 if (it.key().startsWith("kde-") || it.key().startsWith("app-")) 00493 continue; 00494 QString value = it.data().stripWhiteSpace(), lovalue; 00495 value.replace(re, ""); 00496 lovalue = value.lower(); 00497 00498 // handles specific cases: boolean, empty strings, or option that has that boolean 00499 // keyword as value (to prevent them from conversion to real boolean) 00500 if (value == "true" || value == "false") 00501 addBoolean(IPP_TAG_JOB, it.key(), (value == "true")); 00502 else if (value.isEmpty() || lovalue == "off" || lovalue == "on" 00503 || lovalue == "yes" || lovalue == "no" 00504 || lovalue == "true" || lovalue == "false") 00505 addName(IPP_TAG_JOB, it.key(), value); 00506 else 00507 n = cupsAddOption(it.key().local8Bit(), value.local8Bit(), n, &options); 00508 } 00509 if (n > 0) 00510 cupsEncodeOptions(request_, n, options); 00511 cupsFreeOptions(n, options); 00512 00513 // find an remove that annoying "document-format" attribute 00514 ipp_attribute_t *attr = request_->attrs; 00515 while (attr) 00516 { 00517 if (attr->next && strcmp(attr->next->name, "document-format") == 0) 00518 { 00519 ipp_attribute_t *attr2 = attr->next; 00520 attr->next = attr2->next; 00521 _ipp_free_attr(attr2); 00522 break; 00523 } 00524 attr = attr->next; 00525 } 00526 }
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 16 17:23:16 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003