kdeprint Library API Documentation

kmcupsmanager.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 <config.h> 00021 00022 #include "kmcupsmanager.h" 00023 #include "kmprinter.h" 00024 #include "ipprequest.h" 00025 #include "cupsinfos.h" 00026 #include "driver.h" 00027 #include "kmfactory.h" 00028 #include "kmdbentry.h" 00029 #include "cupsaddsmb2.h" 00030 #include "ippreportdlg.h" 00031 #include "kpipeprocess.h" 00032 #include "util.h" 00033 #include "foomatic2loader.h" 00034 #include "ppdloader.h" 00035 00036 #include <qfile.h> 00037 #include <qtextstream.h> 00038 #include <qregexp.h> 00039 #include <qtimer.h> 00040 #include <qsocket.h> 00041 #include <qdatetime.h> 00042 00043 #include <kdebug.h> 00044 #include <kapplication.h> 00045 #include <klocale.h> 00046 #include <kconfig.h> 00047 #include <kstandarddirs.h> 00048 #include <klibloader.h> 00049 #include <kmessagebox.h> 00050 #include <kaction.h> 00051 #include <kdialogbase.h> 00052 #include <kextendedsocket.h> 00053 #include <kprocess.h> 00054 #include <kfilterdev.h> 00055 #include <cups/cups.h> 00056 #include <cups/ppd.h> 00057 #include <math.h> 00058 00059 #define ppdi18n(s) i18n(QString::fromLocal8Bit(s).utf8()) 00060 00061 void extractMaticData(QString& buf, const QString& filename); 00062 QString printerURI(KMPrinter *p, bool useExistingURI = false); 00063 QString downloadDriver(KMPrinter *p); 00064 00065 static int trials = 5; 00066 00067 //***************************************************************************************************** 00068 00069 KMCupsManager::KMCupsManager(QObject *parent, const char *name, const QStringList & /*args*/) 00070 : KMManager(parent,name) 00071 { 00072 // be sure to create the CupsInfos object -> password 00073 // management is handled correctly. 00074 CupsInfos::self(); 00075 m_cupsdconf = 0; 00076 m_currentprinter = 0; 00077 m_socket = 0; 00078 00079 setHasManagement(true); 00080 setPrinterOperationMask(KMManager::PrinterAll); 00081 setServerOperationMask(KMManager::ServerAll); 00082 00083 // change LANG variable so that CUPS is always using 00084 // english language: translation may only come from the PPD 00085 // itself, or from KDE. 00086 setenv("LANG", "en", 1); 00087 } 00088 00089 KMCupsManager::~KMCupsManager() 00090 { 00091 //delete m_socket; 00092 } 00093 00094 QString KMCupsManager::driverDbCreationProgram() 00095 { 00096 return QString::fromLatin1("make_driver_db_cups"); 00097 } 00098 00099 QString KMCupsManager::driverDirectory() 00100 { 00101 QString d = cupsInstallDir(); 00102 if (d.isEmpty()) 00103 d = "/usr"; 00104 d.append("/share/cups/model"); 00105 // raw foomatic support 00106 d.append(":/usr/share/foomatic/db/source"); 00107 return d; 00108 } 00109 00110 QString KMCupsManager::cupsInstallDir() 00111 { 00112 KConfig *conf= KMFactory::self()->printConfig(); 00113 conf->setGroup("CUPS"); 00114 QString dir = conf->readPathEntry("InstallDir"); 00115 return dir; 00116 } 00117 00118 void KMCupsManager::reportIppError(IppRequest *req) 00119 { 00120 setErrorMsg(req->statusMessage()); 00121 } 00122 00123 bool KMCupsManager::createPrinter(KMPrinter *p) 00124 { 00125 bool isclass = p->isClass(false), result(false); 00126 IppRequest req; 00127 QString uri; 00128 00129 uri = printerURI(p,false); 00130 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00131 // needed to avoid problems when changing printer name 00132 p->setUri(KURL(uri)); 00133 00134 if (isclass) 00135 { 00136 req.setOperation(CUPS_ADD_CLASS); 00137 QStringList members = p->members(), uris; 00138 QString s = QString::fromLocal8Bit("ipp://%1:%2/printers/").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()); 00139 for (QStringList::ConstIterator it=members.begin(); it!=members.end(); ++it) 00140 uris.append(s+(*it)); 00141 req.addURI(IPP_TAG_PRINTER,"member-uris",uris); 00142 } 00143 else 00144 { 00145 req.setOperation(CUPS_ADD_PRINTER); 00146 // only set the device-uri if needed, otherwise you may loose authentification 00147 // data (login/password in URI's like smb or ipp). 00148 KMPrinter *otherP = findPrinter(p->printerName()); 00149 if (!otherP || otherP->device() != p->device()) 00150 { 00156 req.addURI(IPP_TAG_PRINTER,"device-uri",p->device()); 00157 } 00158 if (!p->option("kde-banners").isEmpty()) 00159 { 00160 QStringList bans = QStringList::split(',',p->option("kde-banners"),false); 00161 while (bans.count() < 2) 00162 bans.append("none"); 00163 req.addName(IPP_TAG_PRINTER,"job-sheets-default",bans); 00164 } 00165 req.addInteger(IPP_TAG_PRINTER,"job-quota-period",p->option("job-quota-period").toInt()); 00166 req.addInteger(IPP_TAG_PRINTER,"job-k-limit",p->option("job-k-limit").toInt()); 00167 req.addInteger(IPP_TAG_PRINTER,"job-page-limit",p->option("job-page-limit").toInt()); 00168 if (!p->option("requesting-user-name-denied").isEmpty()) 00169 req.addName(IPP_TAG_PRINTER,"requesting-user-name-denied",QStringList::split(",",p->option("requesting-user-name-denied"),false)); 00170 else if (!p->option("requesting-user-name-allowed").isEmpty()) 00171 req.addName(IPP_TAG_PRINTER,"requesting-user-name-allowed",QStringList::split(",",p->option("requesting-user-name-allowed"),false)); 00172 else 00173 req.addName(IPP_TAG_PRINTER,"requesting-user-name-allowed",QString::fromLatin1("all")); 00174 } 00175 req.addText(IPP_TAG_PRINTER,"printer-info",p->description()); 00176 req.addText(IPP_TAG_PRINTER,"printer-location",p->location()); 00177 00178 if (req.doRequest("/admin/")) 00179 { 00180 result = true; 00181 if (p->driver()) 00182 result = savePrinterDriver(p,p->driver()); 00183 if (result) 00184 upPrinter(p, true); 00185 } 00186 else reportIppError(&req); 00187 00188 return result; 00189 } 00190 00191 bool KMCupsManager::removePrinter(KMPrinter *p) 00192 { 00193 bool result = setPrinterState(p,CUPS_DELETE_PRINTER); 00194 return result; 00195 } 00196 00197 bool KMCupsManager::enablePrinter(KMPrinter *p, bool state) 00198 { 00199 return setPrinterState(p, (state ? CUPS_ACCEPT_JOBS : CUPS_REJECT_JOBS)); 00200 } 00201 00202 bool KMCupsManager::startPrinter(KMPrinter *p, bool state) 00203 { 00204 return setPrinterState(p, (state ? IPP_RESUME_PRINTER : IPP_PAUSE_PRINTER)); 00205 } 00206 00207 bool KMCupsManager::setDefaultPrinter(KMPrinter *p) 00208 { 00209 return setPrinterState(p,CUPS_SET_DEFAULT); 00210 } 00211 00212 bool KMCupsManager::setPrinterState(KMPrinter *p, int state) 00213 { 00214 IppRequest req; 00215 QString uri; 00216 00217 req.setOperation(state); 00218 uri = printerURI(p); 00219 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00220 if (req.doRequest("/admin/")) 00221 return true; 00222 reportIppError(&req); 00223 return false; 00224 } 00225 00226 bool KMCupsManager::completePrinter(KMPrinter *p) 00227 { 00228 if (completePrinterShort(p)) 00229 { 00230 // driver informations 00231 QString ppdname = downloadDriver(p); 00232 ppd_file_t *ppd = (ppdname.isEmpty() ? NULL : ppdOpenFile(ppdname.local8Bit())); 00233 if (ppd) 00234 { 00235 KMDBEntry entry; 00236 // use the validation mechanism of KMDBEntry to 00237 // fill possible missing entries like manufacturer 00238 // or model. 00239 entry.manufacturer = ppd->manufacturer; 00240 entry.model = ppd->shortnickname; 00241 entry.modelname = ppd->modelname; 00242 // do not check the driver regarding the manager 00243 entry.validate(false); 00244 // update the KMPrinter object 00245 p->setManufacturer(entry.manufacturer); 00246 p->setModel(entry.model); 00247 p->setDriverInfo(QString::fromLocal8Bit(ppd->nickname)); 00248 ppdClose(ppd); 00249 } 00250 if (!ppdname.isEmpty()) 00251 QFile::remove(ppdname); 00252 00253 return true; 00254 } 00255 return false; 00256 } 00257 00258 bool KMCupsManager::completePrinterShort(KMPrinter *p) 00259 { 00260 IppRequest req; 00261 QStringList keys; 00262 QString uri; 00263 00264 req.setOperation(IPP_GET_PRINTER_ATTRIBUTES); 00265 uri = printerURI(p, true); 00266 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00267 00268 /* 00269 // change host and port for remote stuffs 00270 if (!p->uri().isEmpty()) 00271 { 00272 // THIS IS AN UGLY HACK!! FIXME 00273 // This attempts a "pre-connection" to see if the host is 00274 // actually reachable. It times out after 2 seconds at most, 00275 // preventing application freezes. 00276 m_hostSuccess = false; 00277 m_lookupDone = false; 00278 // Give 2 seconds to connect to the printer, or abort 00279 KExtendedSocket *kes = new KExtendedSocket(p->uri().host(), 00280 p->uri().port()); 00281 connect(kes, SIGNAL(connectionSuccess()), this, SLOT(hostPingSlot())); 00282 connect(kes, SIGNAL(connectionFailed(int)), this, SLOT(hostPingFailedSlot())); 00283 if (kes->startAsyncConnect() != 0) { 00284 delete kes; 00285 m_hostSuccess = false; 00286 } else { 00287 QDateTime tm = QDateTime::currentDateTime().addSecs(2); 00288 while (!m_lookupDone && (QDateTime::currentDateTime() < tm)) 00289 qApp->processEvents(); 00290 00291 kes->cancelAsyncConnect(); 00292 00293 delete kes; 00294 00295 if (!m_lookupDone) 00296 m_hostSuccess = false; 00297 } 00298 00299 if (m_hostSuccess == true) { 00300 req.setHost(p->uri().host()); 00301 req.setPort(p->uri().port()); 00302 } 00303 } 00304 */ 00305 00306 // disable location as it has been transferred to listing (for filtering) 00307 //keys.append("printer-location"); 00308 keys.append("printer-info"); 00309 keys.append("printer-make-and-model"); 00310 keys.append("job-sheets-default"); 00311 keys.append("job-sheets-supported"); 00312 keys.append("job-quota-period"); 00313 keys.append("job-k-limit"); 00314 keys.append("job-page-limit"); 00315 keys.append("requesting-user-name-allowed"); 00316 keys.append("requesting-user-name-denied"); 00317 if (p->isClass(true)) 00318 { 00319 keys.append("member-uris"); 00320 keys.append("member-names"); 00321 } 00322 else 00323 keys.append("device-uri"); 00324 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys); 00325 00326 if (req.doRequest("/printers/")) 00327 { 00328 QString value; 00329 if (req.text("printer-info",value)) p->setDescription(value); 00330 // disabled location 00331 //if (req.text("printer-location",value)) p->setLocation(value); 00332 if (req.text("printer-make-and-model",value)) p->setDriverInfo(value); 00333 if (req.uri("device-uri",value)) 00334 { 00339 p->setDevice( value ); 00340 } 00341 QStringList values; 00342 /* if (req.uri("member-uris",values)) 00343 { 00344 QStringList members; 00345 for (QStringList::ConstIterator it=values.begin(); it!=values.end(); ++it) 00346 { 00347 int p = (*it).findRev('/'); 00348 if (p != -1) 00349 members.append((*it).right((*it).length()-p-1)); 00350 } 00351 p->setMembers(members); 00352 }*/ 00353 if (req.name("member-names",values)) 00354 p->setMembers(values); 00355 // banners 00356 req.name("job-sheets-default",values); 00357 while (values.count() < 2) values.append("none"); 00358 p->setOption("kde-banners",values.join(QString::fromLatin1(","))); 00359 if (req.name("job-sheets-supported",values)) p->setOption("kde-banners-supported",values.join(QString::fromLatin1(","))); 00360 00361 // quotas 00362 int ival; 00363 if (req.integer("job-quota-period",ival)) p->setOption("job-quota-period",QString::number(ival)); 00364 if (req.integer("job-k-limit",ival)) p->setOption("job-k-limit",QString::number(ival)); 00365 if (req.integer("job-page-limit",ival)) p->setOption("job-page-limit",QString::number(ival)); 00366 00367 // access permissions (allow and deny are mutually exclusives) 00368 if (req.name("requesting-user-name-allowed",values) && values.count() > 0) 00369 { 00370 p->removeOption("requesting-user-name-denied"); 00371 p->setOption("requesting-user-name-allowed",values.join(",")); 00372 } 00373 if (req.name("requesting-user-name-denied",values) && values.count() > 0) 00374 { 00375 p->removeOption("requesting-user-name-allowed"); 00376 p->setOption("requesting-user-name-denied",values.join(",")); 00377 } 00378 00379 return true; 00380 } 00381 00382 reportIppError(&req); 00383 return false; 00384 } 00385 00386 bool KMCupsManager::testPrinter(KMPrinter *p) 00387 { 00388 return KMManager::testPrinter(p); 00389 /* 00390 QString testpage = testPage(); 00391 if (testpage.isEmpty()) 00392 { 00393 setErrorMsg(i18n("Unable to locate test page.")); 00394 return false; 00395 } 00396 00397 IppRequest req; 00398 QString uri; 00399 00400 req.setOperation(IPP_PRINT_JOB); 00401 uri = printerURI(p); 00402 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00403 req.addMime(IPP_TAG_OPERATION,"document-format","application/postscript"); 00404 if (!CupsInfos::self()->login().isEmpty()) req.addName(IPP_TAG_OPERATION,"requesting-user-name",CupsInfos::self()->login()); 00405 req.addName(IPP_TAG_OPERATION,"job-name",QString::fromLatin1("KDE Print Test")); 00406 if (req.doFileRequest("/printers/",testpage)) 00407 return true; 00408 reportIppError(&req); 00409 return false; 00410 */ 00411 } 00412 00413 void KMCupsManager::listPrinters() 00414 { 00415 loadServerPrinters(); 00416 } 00417 00418 void KMCupsManager::loadServerPrinters() 00419 { 00420 IppRequest req; 00421 QStringList keys; 00422 00423 // get printers 00424 req.setOperation(CUPS_GET_PRINTERS); 00425 keys.append("printer-name"); 00426 keys.append("printer-type"); 00427 keys.append("printer-state"); 00428 // location needed for filtering 00429 keys.append("printer-location"); 00430 keys.append("printer-uri-supported"); 00431 keys.append("printer-is-accepting-jobs"); 00432 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys); 00433 00434 if (req.doRequest("/printers/")) 00435 { 00436 processRequest(&req); 00437 00438 // get classes 00439 req.init(); 00440 req.setOperation(CUPS_GET_CLASSES); 00441 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys); 00442 00443 if (req.doRequest("/classes/")) 00444 { 00445 processRequest(&req); 00446 00447 // load default 00448 req.init(); 00449 req.setOperation(CUPS_GET_DEFAULT); 00450 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",QString::fromLatin1("printer-name")); 00451 if (req.doRequest("/printers/")) 00452 { 00453 QString s = QString::null; 00454 req.name("printer-name",s); 00455 setHardDefault(findPrinter(s)); 00456 } 00457 // This request may fails for example if no printer is defined. Just 00458 // discard the error message. Indeed as we successfully got printers 00459 // and classes, the most probable reason why this request may fail is 00460 // because of no printer defined. The best would be to actually check 00461 // there's no printer (TODO). 00462 return; 00463 } 00464 } 00465 00466 // something went wrong if we get there, report the error 00467 reportIppError(&req); 00468 } 00469 00470 void KMCupsManager::processRequest(IppRequest* req) 00471 { 00472 ipp_attribute_t *attr = req->first(); 00473 KMPrinter *printer = new KMPrinter(); 00474 while (attr) 00475 { 00476 QString attrname(attr->name); 00477 if (attrname == "printer-name") 00478 { 00479 QString value = QString::fromLocal8Bit(attr->values[0].string.text); 00480 printer->setName(value); 00481 printer->setPrinterName(value); 00482 } 00483 else if (attrname == "printer-type") 00484 { 00485 int value = attr->values[0].integer; 00486 printer->setType(0); 00487 printer->addType(((value & CUPS_PRINTER_CLASS) || (value & CUPS_PRINTER_IMPLICIT) ? KMPrinter::Class : KMPrinter::Printer)); 00488 if ((value & CUPS_PRINTER_REMOTE)) printer->addType(KMPrinter::Remote); 00489 if ((value & CUPS_PRINTER_IMPLICIT)) printer->addType(KMPrinter::Implicit); 00490 00491 // convert printer-type attribute 00492 printer->setPrinterCap( ( value & CUPS_PRINTER_OPTIONS ) >> 2 ); 00493 } 00494 else if (attrname == "printer-state") 00495 { 00496 switch (attr->values[0].integer) 00497 { 00498 case IPP_PRINTER_IDLE: printer->setState(KMPrinter::Idle); break; 00499 case IPP_PRINTER_PROCESSING: printer->setState(KMPrinter::Processing); break; 00500 case IPP_PRINTER_STOPPED: printer->setState(KMPrinter::Stopped); break; 00501 } 00502 } 00503 else if (attrname == "printer-uri-supported") 00504 { 00505 printer->setUri(KURL(attr->values[0].string.text)); 00506 } 00507 else if (attrname == "printer-location") 00508 { 00509 printer->setLocation(QString::fromLocal8Bit(attr->values[0].string.text)); 00510 } 00511 else if (attrname == "printer-is-accepting-jobs") 00512 { 00513 printer->setAcceptJobs(attr->values[0].boolean); 00514 } 00515 if (attrname.isEmpty() || attr == req->last()) 00516 { 00517 addPrinter(printer); 00518 printer = new KMPrinter(); 00519 } 00520 attr = attr->next; 00521 } 00522 delete printer; 00523 } 00524 00525 DrMain* KMCupsManager::loadPrinterDriver(KMPrinter *p, bool) 00526 { 00527 if (!p || p->isClass(true)) 00528 return NULL; 00529 00530 QString fname = downloadDriver(p); 00531 DrMain *driver(0); 00532 if (!fname.isEmpty()) 00533 { 00534 driver = loadDriverFile(fname); 00535 if (driver) 00536 driver->set("temporary",fname); 00537 } 00538 00539 return driver; 00540 } 00541 00542 DrMain* KMCupsManager::loadFileDriver(const QString& filename) 00543 { 00544 if (filename.startsWith("ppd:")) 00545 return loadDriverFile(filename.mid(4)); 00546 else if (filename.startsWith("foomatic/")) 00547 return loadMaticDriver(filename); 00548 else 00549 return loadDriverFile(filename); 00550 } 00551 00552 DrMain* KMCupsManager::loadMaticDriver(const QString& drname) 00553 { 00554 QStringList comps = QStringList::split('/', drname, false); 00555 QString tmpFile = locateLocal("tmp", "foomatic_" + kapp->randomString(8)); 00556 QString PATH = getenv("PATH") + QString::fromLatin1(":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin"); 00557 QString exe = KStandardDirs::findExe("foomatic-datafile", PATH); 00558 if (exe.isEmpty()) 00559 { 00560 setErrorMsg(i18n("Unable to find the executable foomatic-datafile " 00561 "in your PATH. Check that Foomatic is correctly installed.")); 00562 return NULL; 00563 } 00564 00565 KPipeProcess in; 00566 QFile out(tmpFile); 00567 QString cmd = KProcess::quote(exe); 00568 cmd += " -t cups -d "; 00569 cmd += KProcess::quote(comps[2]); 00570 cmd += " -p "; 00571 cmd += KProcess::quote(comps[1]); 00572 if (in.open(cmd) && out.open(IO_WriteOnly)) 00573 { 00574 QTextStream tin(&in), tout(&out); 00575 QString line; 00576 while (!tin.atEnd()) 00577 { 00578 line = tin.readLine(); 00579 tout << line << endl; 00580 } 00581 in.close(); 00582 out.close(); 00583 00584 DrMain *driver = loadDriverFile(tmpFile); 00585 if (driver) 00586 { 00587 driver->set("template", tmpFile); 00588 driver->set("temporary", tmpFile); 00589 return driver; 00590 } 00591 } 00592 setErrorMsg(i18n("Unable to create the Foomatic driver [%1,%2]. " 00593 "Either that driver does not exist, or you don't have " 00594 "the required permissions to perform that operation.").arg(comps[1]).arg(comps[2])); 00595 QFile::remove(tmpFile); 00596 return NULL; 00597 } 00598 00599 DrMain* KMCupsManager::loadDriverFile(const QString& fname) 00600 { 00601 if (QFile::exists(fname)) 00602 { 00603 DrMain *driver = PPDLoader::loadDriver( fname ); 00604 if ( driver ) 00605 { 00606 driver->set( "template", fname ); 00607 // FIXME: should fix option in group "install" 00608 } 00609 return driver; 00610 } 00611 return NULL; 00612 } 00613 00614 void KMCupsManager::saveDriverFile(DrMain *driver, const QString& filename) 00615 { 00616 kdDebug( 500 ) << "Saving PPD file with template=" << driver->get( "template" ) << endl; 00617 QIODevice *in = KFilterDev::deviceForFile( driver->get( "template" ) ); 00618 QFile out(filename); 00619 if (in && in->open(IO_ReadOnly) && out.open(IO_WriteOnly)) 00620 { 00621 QTextStream tin(in), tout(&out); 00622 QString line, keyword; 00623 bool isnumeric(false); 00624 DrBase *opt(0); 00625 00626 while (!tin.eof()) 00627 { 00628 line = tin.readLine(); 00629 if (line.startsWith("*% COMDATA #")) 00630 { 00631 int p(-1), q(-1); 00632 if ((p=line.find("'name'")) != -1) 00633 { 00634 p = line.find('\'',p+6)+1; 00635 q = line.find('\'',p); 00636 keyword = line.mid(p,q-p); 00637 opt = driver->findOption(keyword); 00638 if (opt && (opt->type() == DrBase::Integer || opt->type() == DrBase::Float)) 00639 isnumeric = true; 00640 else 00641 isnumeric = false; 00642 } 00643 /*else if ((p=line.find("'type'")) != -1) 00644 { 00645 p = line.find('\'',p+6)+1; 00646 if (line.find("float",p) != -1 || line.find("int",p) != -1) 00647 isnumeric = true; 00648 else 00649 isnumeric = false; 00650 }*/ 00651 else if ((p=line.find("'default'")) != -1 && !keyword.isEmpty() && opt && isnumeric) 00652 { 00653 QString prefix = line.left(p+9); 00654 tout << prefix << " => '" << opt->valueText() << '\''; 00655 if (line.find(',',p) != -1) 00656 tout << ','; 00657 tout << endl; 00658 continue; 00659 } 00660 tout << line << endl; 00661 } 00662 else if (line.startsWith("*Default")) 00663 { 00664 int p = line.find(':',8); 00665 keyword = line.mid(8,p-8); 00666 DrBase *bopt = 0; 00667 if ( keyword == "PageRegion" || keyword == "ImageableArea" || keyword == "PaperDimension" ) 00668 bopt = driver->findOption( QString::fromLatin1( "PageSize" ) ); 00669 else 00670 bopt = driver->findOption( keyword ); 00671 if (bopt) 00672 switch (bopt->type()) 00673 { 00674 case DrBase::List: 00675 case DrBase::Boolean: 00676 { 00677 DrListOption *opt = static_cast<DrListOption*>(bopt); 00678 if (opt && opt->currentChoice()) 00679 tout << "*Default" << keyword << ": " << opt->currentChoice()->name() << endl; 00680 else 00681 tout << line << endl; 00682 } 00683 break; 00684 case DrBase::Integer: 00685 { 00686 DrIntegerOption *opt = static_cast<DrIntegerOption*>(bopt); 00687 tout << "*Default" << keyword << ": " << opt->fixedVal() << endl; 00688 } 00689 break; 00690 case DrBase::Float: 00691 { 00692 DrFloatOption *opt = static_cast<DrFloatOption*>(bopt); 00693 tout << "*Default" << keyword << ": " << opt->fixedVal() << endl; 00694 } 00695 break; 00696 default: 00697 tout << line << endl; 00698 break; 00699 } 00700 else 00701 tout << line << endl; 00702 } 00703 else 00704 tout << line << endl; 00705 } 00706 } 00707 delete in; 00708 } 00709 00710 bool KMCupsManager::savePrinterDriver(KMPrinter *p, DrMain *d) 00711 { 00712 QString tmpfilename = locateLocal("tmp","print_") + kapp->randomString(8); 00713 00714 // first save the driver in a temporary file 00715 saveDriverFile(d,tmpfilename); 00716 00717 // then send a request 00718 IppRequest req; 00719 QString uri; 00720 bool result(false); 00721 00722 req.setOperation(CUPS_ADD_PRINTER); 00723 uri = printerURI(p, true); 00724 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00725 result = req.doFileRequest("/admin/",tmpfilename); 00726 00727 // remove temporary file 00728 QFile::remove(tmpfilename); 00729 00730 if (!result) 00731 reportIppError(&req); 00732 return result; 00733 } 00734 00735 void* KMCupsManager::loadCupsdConfFunction(const char *name) 00736 { 00737 if (!m_cupsdconf) 00738 { 00739 m_cupsdconf = KLibLoader::self()->library("cupsdconf"); 00740 if (!m_cupsdconf) 00741 { 00742 setErrorMsg(i18n("Library cupsdconf not found. Check your installation.")); 00743 return NULL; 00744 } 00745 } 00746 void* func = m_cupsdconf->symbol(name); 00747 if (!func) 00748 setErrorMsg(i18n("Symbol %1 not found in cupsdconf library.").arg(name)); 00749 return func; 00750 } 00751 00752 void KMCupsManager::unloadCupsdConf() 00753 { 00754 if (m_cupsdconf) 00755 { 00756 KLibLoader::self()->unloadLibrary("libcupsdconf"); 00757 m_cupsdconf = 0; 00758 } 00759 } 00760 00761 bool KMCupsManager::restartServer() 00762 { 00763 QString msg; 00764 bool (*f1)(QString&) = (bool(*)(QString&))loadCupsdConfFunction("restartServer"); 00765 bool result(false); 00766 if (f1) 00767 { 00768 result = f1(msg); 00769 if (!result) setErrorMsg(msg); 00770 } 00771 unloadCupsdConf(); 00772 return result; 00773 } 00774 00775 bool KMCupsManager::configureServer(QWidget *parent) 00776 { 00777 QString msg; 00778 bool (*f2)(QWidget*, QString&) = (bool(*)(QWidget*, QString&))loadCupsdConfFunction("configureServer"); 00779 bool result(false); 00780 if (f2) 00781 { 00782 result = f2(parent, msg); 00783 if ( !result ) 00784 setErrorMsg( msg ); 00785 } 00786 unloadCupsdConf(); 00787 return result; 00788 } 00789 00790 QStringList KMCupsManager::detectLocalPrinters() 00791 { 00792 QStringList list; 00793 IppRequest req; 00794 req.setOperation(CUPS_GET_DEVICES); 00795 if (req.doRequest("/")) 00796 { 00797 QString desc, uri, printer, cl; 00798 ipp_attribute_t *attr = req.first(); 00799 while (attr) 00800 { 00801 QString attrname(attr->name); 00802 if (attrname == "device-info") desc = attr->values[0].string.text; 00803 else if (attrname == "device-make-and-model") printer = attr->values[0].string.text; 00804 else if (attrname == "device-uri") uri = attr->values[0].string.text; 00805 else if ( attrname == "device-class" ) cl = attr->values[ 0 ].string.text; 00806 if (attrname.isEmpty() || attr == req.last()) 00807 { 00808 if (!uri.isEmpty()) 00809 { 00810 if (printer == "Unknown") printer = QString::null; 00811 list << cl << uri << desc << printer; 00812 } 00813 uri = desc = printer = cl = QString::null; 00814 } 00815 attr = attr->next; 00816 } 00817 } 00818 return list; 00819 } 00820 00821 void KMCupsManager::createPluginActions(KActionCollection *coll) 00822 { 00823 KAction *act = new KAction(i18n("&Export Driver..."), "kdeprint_uploadsmb", 0, this, SLOT(exportDriver()), coll, "plugin_export_driver"); 00824 act->setGroup("plugin"); 00825 act = new KAction(i18n("&Printer IPP Report..."), "kdeprint_report", 0, this, SLOT(printerIppReport()), coll, "plugin_printer_ipp_report"); 00826 act->setGroup("plugin"); 00827 } 00828 00829 void KMCupsManager::validatePluginActions(KActionCollection *coll, KMPrinter *pr) 00830 { 00831 // save selected printer for future use in slots 00832 m_currentprinter = pr; 00833 coll->action("plugin_export_driver")->setEnabled(pr && pr->isLocal() && !pr->isClass(true) && !pr->isSpecial()); 00834 coll->action("plugin_printer_ipp_report")->setEnabled(pr && !pr->isSpecial()); 00835 } 00836 00837 void KMCupsManager::exportDriver() 00838 { 00839 if (m_currentprinter && m_currentprinter->isLocal() && 00840 !m_currentprinter->isClass(true) && !m_currentprinter->isSpecial()) 00841 { 00842 QString path = cupsInstallDir(); 00843 if (path.isEmpty()) 00844 path = "/usr/share/cups"; 00845 else 00846 path += "/share/cups"; 00847 CupsAddSmb::exportDest(m_currentprinter->printerName(), path); 00848 } 00849 } 00850 00851 void KMCupsManager::printerIppReport() 00852 { 00853 if (m_currentprinter && !m_currentprinter->isSpecial()) 00854 { 00855 IppRequest req; 00856 QString uri; 00857 00858 req.setOperation(IPP_GET_PRINTER_ATTRIBUTES); 00859 uri = printerURI(m_currentprinter, true); 00860 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00861 /* 00862 if (!m_currentprinter->uri().isEmpty()) 00863 { 00864 req.setHost(m_currentprinter->uri().host()); 00865 req.setPort(m_currentprinter->uri().port()); 00866 } 00867 */ 00868 req.dump(2); 00869 if (req.doRequest("/printers/")) 00870 { 00871 ippReport(req, IPP_TAG_PRINTER, i18n("IPP report for %1").arg(m_currentprinter->printerName())); 00872 } 00873 else 00874 { 00875 KMessageBox::error(0, "<p>"+i18n("Unable to retrieve printer information. Error received:")+"</p>"+req.statusMessage()); 00876 } 00877 } 00878 } 00879 00880 void KMCupsManager::ippReport(IppRequest& req, int group, const QString& caption) 00881 { 00882 IppReportDlg::report(&req, group, caption); 00883 } 00884 00885 QString KMCupsManager::stateInformation() 00886 { 00887 return i18n("Connected to %1:%2").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()); 00888 } 00889 00890 void KMCupsManager::checkUpdatePossibleInternal() 00891 { 00892 kdDebug(500) << "Checking for update possible" << endl; 00893 delete m_socket; 00894 /*m_socket = new KExtendedSocket( CupsInfos::self()->host(), CupsInfos::self()->port() ); 00895 connect( m_socket, SIGNAL( connectionSuccess() ), SLOT( slotConnectionSuccess() ) ); 00896 connect( m_socket, SIGNAL( connectionFailed( int ) ), SLOT( slotConnectionFailed( int ) ) ); 00897 m_socket->setTimeout( 1 );*/ 00898 m_socket = new QSocket( this ); 00899 connect( m_socket, SIGNAL( connected() ), SLOT( slotConnectionSuccess() ) ); 00900 connect( m_socket, SIGNAL( error( int ) ), SLOT( slotConnectionFailed( int ) ) ); 00901 trials = 5; 00902 QTimer::singleShot( 1, this, SLOT( slotAsyncConnect() ) ); 00903 } 00904 00905 void KMCupsManager::slotConnectionSuccess() 00906 { 00907 kdDebug(500) << "Connection success, trying to send a request..." << endl; 00908 m_socket->close(); 00909 00910 IppRequest req; 00911 req.setOperation( CUPS_GET_PRINTERS ); 00912 req.addKeyword( IPP_TAG_OPERATION, "requested-attributes", QString::fromLatin1( "printer-name" ) ); 00913 if ( req.doRequest( "/printers/" ) ) 00914 setUpdatePossible( true ); 00915 else 00916 { 00917 kdDebug(500) << "Unable to get printer list" << endl; 00918 if ( trials > 0 ) 00919 { 00920 trials--; 00921 QTimer::singleShot( 1000, this, SLOT( slotAsyncConnect() ) ); 00922 } 00923 else 00924 { 00925 setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. " 00926 "Error: %1." ).arg( i18n( "the IPP request failed for an unknown reason" ) ) ); 00927 setUpdatePossible( false ); 00928 } 00929 } 00930 } 00931 00932 void KMCupsManager::slotAsyncConnect() 00933 { 00934 kdDebug(500) << "Starting async connect" << endl; 00935 //m_socket->startAsyncConnect(); 00936 m_socket->connectToHost( CupsInfos::self()->host(), CupsInfos::self()->port() ); 00937 } 00938 00939 void KMCupsManager::slotConnectionFailed( int errcode ) 00940 { 00941 kdDebug(500) << "Connection failed trials=" << trials << endl; 00942 if ( trials > 0 ) 00943 { 00944 //m_socket->setTimeout( ++to ); 00945 //m_socket->cancelAsyncConnect(); 00946 trials--; 00947 m_socket->close(); 00948 QTimer::singleShot( 1000, this, SLOT( slotAsyncConnect() ) ); 00949 return; 00950 } 00951 00952 setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. " 00953 "Error: %1." ).arg( errcode == QSocket::ErrConnectionRefused ? i18n( "connection refused" ) : i18n( "host not found" ) ) ); 00954 setUpdatePossible( false ); 00955 } 00956 00957 void KMCupsManager::hostPingSlot() { 00958 m_hostSuccess = true; 00959 m_lookupDone = true; 00960 } 00961 00962 void KMCupsManager::hostPingFailedSlot() { 00963 m_hostSuccess = false; 00964 m_lookupDone = true; 00965 } 00966 00967 //***************************************************************************************************** 00968 00969 void extractMaticData(QString& buf, const QString& filename) 00970 { 00971 QFile f(filename); 00972 if (f.exists() && f.open(IO_ReadOnly)) 00973 { 00974 QTextStream t(&f); 00975 QString line; 00976 while (!t.eof()) 00977 { 00978 line = t.readLine(); 00979 if (line.startsWith("*% COMDATA #")) 00980 buf.append(line.right(line.length()-12)).append('\n'); 00981 } 00982 } 00983 } 00984 00985 QString printerURI(KMPrinter *p, bool use) 00986 { 00987 QString uri; 00988 if (use && !p->uri().isEmpty()) 00989 uri = p->uri().prettyURL(); 00990 else 00991 uri = QString("ipp://%1:%2/%4/%3").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()).arg(p->printerName()).arg((p->isClass(false) ? "classes" : "printers")); 00992 return uri; 00993 } 00994 00995 QString downloadDriver(KMPrinter *p) 00996 { 00997 QString driverfile, prname = p->printerName(); 00998 bool changed(false); 00999 01000 /* 01001 if (!p->uri().isEmpty()) 01002 { 01003 // try to load the driver from the host:port 01004 // specified in its URI. Doing so may also change 01005 // the printer name to use. Note that for remote 01006 // printer, this operation is read-only, no counterpart 01007 // for saving operation. 01008 cupsSetServer(p->uri().host().local8Bit()); 01009 ippSetPort(p->uri().port()); 01010 // strip any "@..." from the printer name 01011 prname = prname.replace(QRegExp("@.*"), ""); 01012 changed = true; 01013 } 01014 */ 01015 01016 // download driver 01017 driverfile = cupsGetPPD(prname.local8Bit()); 01018 01019 // restore host:port (if they have changed) 01020 if (changed) 01021 { 01022 cupsSetServer(CupsInfos::self()->host().local8Bit()); 01023 ippSetPort(CupsInfos::self()->port()); 01024 } 01025 01026 return driverfile; 01027 } 01028 01029 #include "kmcupsmanager.moc"
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