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 QString msg; /* possible error message */ 00604 DrMain *driver = PPDLoader::loadDriver( fname, &msg ); 00605 if ( driver ) 00606 { 00607 driver->set( "template", fname ); 00608 // FIXME: should fix option in group "install" 00609 } 00610 else 00611 setErrorMsg( msg ); 00612 return driver; 00613 } 00614 return NULL; 00615 } 00616 00617 void KMCupsManager::saveDriverFile(DrMain *driver, const QString& filename) 00618 { 00619 kdDebug( 500 ) << "Saving PPD file with template=" << driver->get( "template" ) << endl; 00620 QIODevice *in = KFilterDev::deviceForFile( driver->get( "template" ) ); 00621 QFile out(filename); 00622 if (in && in->open(IO_ReadOnly) && out.open(IO_WriteOnly)) 00623 { 00624 QTextStream tin(in), tout(&out); 00625 QString line, keyword; 00626 bool isnumeric(false); 00627 DrBase *opt(0); 00628 00629 while (!tin.eof()) 00630 { 00631 line = tin.readLine(); 00632 if (line.startsWith("*% COMDATA #")) 00633 { 00634 int p(-1), q(-1); 00635 if ((p=line.find("'name'")) != -1) 00636 { 00637 p = line.find('\'',p+6)+1; 00638 q = line.find('\'',p); 00639 keyword = line.mid(p,q-p); 00640 opt = driver->findOption(keyword); 00641 if (opt && (opt->type() == DrBase::Integer || opt->type() == DrBase::Float)) 00642 isnumeric = true; 00643 else 00644 isnumeric = false; 00645 } 00646 /*else if ((p=line.find("'type'")) != -1) 00647 { 00648 p = line.find('\'',p+6)+1; 00649 if (line.find("float",p) != -1 || line.find("int",p) != -1) 00650 isnumeric = true; 00651 else 00652 isnumeric = false; 00653 }*/ 00654 else if ((p=line.find("'default'")) != -1 && !keyword.isEmpty() && opt && isnumeric) 00655 { 00656 QString prefix = line.left(p+9); 00657 tout << prefix << " => '" << opt->valueText() << '\''; 00658 if (line.find(',',p) != -1) 00659 tout << ','; 00660 tout << endl; 00661 continue; 00662 } 00663 tout << line << endl; 00664 } 00665 else if (line.startsWith("*Default")) 00666 { 00667 int p = line.find(':',8); 00668 keyword = line.mid(8,p-8); 00669 DrBase *bopt = 0; 00670 if ( keyword == "PageRegion" || keyword == "ImageableArea" || keyword == "PaperDimension" ) 00671 bopt = driver->findOption( QString::fromLatin1( "PageSize" ) ); 00672 else 00673 bopt = driver->findOption( keyword ); 00674 if (bopt) 00675 switch (bopt->type()) 00676 { 00677 case DrBase::List: 00678 case DrBase::Boolean: 00679 { 00680 DrListOption *opt = static_cast<DrListOption*>(bopt); 00681 if (opt && opt->currentChoice()) 00682 tout << "*Default" << keyword << ": " << opt->currentChoice()->name() << endl; 00683 else 00684 tout << line << endl; 00685 } 00686 break; 00687 case DrBase::Integer: 00688 { 00689 DrIntegerOption *opt = static_cast<DrIntegerOption*>(bopt); 00690 tout << "*Default" << keyword << ": " << opt->fixedVal() << endl; 00691 } 00692 break; 00693 case DrBase::Float: 00694 { 00695 DrFloatOption *opt = static_cast<DrFloatOption*>(bopt); 00696 tout << "*Default" << keyword << ": " << opt->fixedVal() << endl; 00697 } 00698 break; 00699 default: 00700 tout << line << endl; 00701 break; 00702 } 00703 else 00704 tout << line << endl; 00705 } 00706 else 00707 tout << line << endl; 00708 } 00709 } 00710 delete in; 00711 } 00712 00713 bool KMCupsManager::savePrinterDriver(KMPrinter *p, DrMain *d) 00714 { 00715 QString tmpfilename = locateLocal("tmp","print_") + kapp->randomString(8); 00716 00717 // first save the driver in a temporary file 00718 saveDriverFile(d,tmpfilename); 00719 00720 // then send a request 00721 IppRequest req; 00722 QString uri; 00723 bool result(false); 00724 00725 req.setOperation(CUPS_ADD_PRINTER); 00726 uri = printerURI(p, true); 00727 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00728 result = req.doFileRequest("/admin/",tmpfilename); 00729 00730 // remove temporary file 00731 QFile::remove(tmpfilename); 00732 00733 if (!result) 00734 reportIppError(&req); 00735 return result; 00736 } 00737 00738 void* KMCupsManager::loadCupsdConfFunction(const char *name) 00739 { 00740 if (!m_cupsdconf) 00741 { 00742 m_cupsdconf = KLibLoader::self()->library("cupsdconf"); 00743 if (!m_cupsdconf) 00744 { 00745 setErrorMsg(i18n("Library cupsdconf not found. Check your installation.")); 00746 return NULL; 00747 } 00748 } 00749 void* func = m_cupsdconf->symbol(name); 00750 if (!func) 00751 setErrorMsg(i18n("Symbol %1 not found in cupsdconf library.").arg(name)); 00752 return func; 00753 } 00754 00755 void KMCupsManager::unloadCupsdConf() 00756 { 00757 if (m_cupsdconf) 00758 { 00759 KLibLoader::self()->unloadLibrary("libcupsdconf"); 00760 m_cupsdconf = 0; 00761 } 00762 } 00763 00764 bool KMCupsManager::restartServer() 00765 { 00766 QString msg; 00767 bool (*f1)(QString&) = (bool(*)(QString&))loadCupsdConfFunction("restartServer"); 00768 bool result(false); 00769 if (f1) 00770 { 00771 result = f1(msg); 00772 if (!result) setErrorMsg(msg); 00773 } 00774 unloadCupsdConf(); 00775 return result; 00776 } 00777 00778 bool KMCupsManager::configureServer(QWidget *parent) 00779 { 00780 QString msg; 00781 bool (*f2)(QWidget*, QString&) = (bool(*)(QWidget*, QString&))loadCupsdConfFunction("configureServer"); 00782 bool result(false); 00783 if (f2) 00784 { 00785 result = f2(parent, msg); 00786 if ( !result ) 00787 setErrorMsg( msg ); 00788 } 00789 unloadCupsdConf(); 00790 return result; 00791 } 00792 00793 QStringList KMCupsManager::detectLocalPrinters() 00794 { 00795 QStringList list; 00796 IppRequest req; 00797 req.setOperation(CUPS_GET_DEVICES); 00798 if (req.doRequest("/")) 00799 { 00800 QString desc, uri, printer, cl; 00801 ipp_attribute_t *attr = req.first(); 00802 while (attr) 00803 { 00804 QString attrname(attr->name); 00805 if (attrname == "device-info") desc = attr->values[0].string.text; 00806 else if (attrname == "device-make-and-model") printer = attr->values[0].string.text; 00807 else if (attrname == "device-uri") uri = attr->values[0].string.text; 00808 else if ( attrname == "device-class" ) cl = attr->values[ 0 ].string.text; 00809 if (attrname.isEmpty() || attr == req.last()) 00810 { 00811 if (!uri.isEmpty()) 00812 { 00813 if (printer == "Unknown") printer = QString::null; 00814 list << cl << uri << desc << printer; 00815 } 00816 uri = desc = printer = cl = QString::null; 00817 } 00818 attr = attr->next; 00819 } 00820 } 00821 return list; 00822 } 00823 00824 void KMCupsManager::createPluginActions(KActionCollection *coll) 00825 { 00826 KAction *act = new KAction(i18n("&Export Driver..."), "kdeprint_uploadsmb", 0, this, SLOT(exportDriver()), coll, "plugin_export_driver"); 00827 act->setGroup("plugin"); 00828 act = new KAction(i18n("&Printer IPP Report..."), "kdeprint_report", 0, this, SLOT(printerIppReport()), coll, "plugin_printer_ipp_report"); 00829 act->setGroup("plugin"); 00830 } 00831 00832 void KMCupsManager::validatePluginActions(KActionCollection *coll, KMPrinter *pr) 00833 { 00834 // save selected printer for future use in slots 00835 m_currentprinter = pr; 00836 coll->action("plugin_export_driver")->setEnabled(pr && pr->isLocal() && !pr->isClass(true) && !pr->isSpecial()); 00837 coll->action("plugin_printer_ipp_report")->setEnabled(pr && !pr->isSpecial()); 00838 } 00839 00840 void KMCupsManager::exportDriver() 00841 { 00842 if (m_currentprinter && m_currentprinter->isLocal() && 00843 !m_currentprinter->isClass(true) && !m_currentprinter->isSpecial()) 00844 { 00845 QString path = cupsInstallDir(); 00846 if (path.isEmpty()) 00847 path = "/usr/share/cups"; 00848 else 00849 path += "/share/cups"; 00850 CupsAddSmb::exportDest(m_currentprinter->printerName(), path); 00851 } 00852 } 00853 00854 void KMCupsManager::printerIppReport() 00855 { 00856 if (m_currentprinter && !m_currentprinter->isSpecial()) 00857 { 00858 IppRequest req; 00859 QString uri; 00860 00861 req.setOperation(IPP_GET_PRINTER_ATTRIBUTES); 00862 uri = printerURI(m_currentprinter, true); 00863 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri); 00864 /* 00865 if (!m_currentprinter->uri().isEmpty()) 00866 { 00867 req.setHost(m_currentprinter->uri().host()); 00868 req.setPort(m_currentprinter->uri().port()); 00869 } 00870 */ 00871 req.dump(2); 00872 if (req.doRequest("/printers/")) 00873 { 00874 ippReport(req, IPP_TAG_PRINTER, i18n("IPP report for %1").arg(m_currentprinter->printerName())); 00875 } 00876 else 00877 { 00878 KMessageBox::error(0, "<p>"+i18n("Unable to retrieve printer information. Error received:")+"</p>"+req.statusMessage()); 00879 } 00880 } 00881 } 00882 00883 void KMCupsManager::ippReport(IppRequest& req, int group, const QString& caption) 00884 { 00885 IppReportDlg::report(&req, group, caption); 00886 } 00887 00888 QString KMCupsManager::stateInformation() 00889 { 00890 return i18n("Connected to %1:%2").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()); 00891 } 00892 00893 void KMCupsManager::checkUpdatePossibleInternal() 00894 { 00895 kdDebug(500) << "Checking for update possible" << endl; 00896 delete m_socket; 00897 /*m_socket = new KExtendedSocket( CupsInfos::self()->host(), CupsInfos::self()->port() ); 00898 connect( m_socket, SIGNAL( connectionSuccess() ), SLOT( slotConnectionSuccess() ) ); 00899 connect( m_socket, SIGNAL( connectionFailed( int ) ), SLOT( slotConnectionFailed( int ) ) ); 00900 m_socket->setTimeout( 1 );*/ 00901 m_socket = new QSocket( this ); 00902 connect( m_socket, SIGNAL( connected() ), SLOT( slotConnectionSuccess() ) ); 00903 connect( m_socket, SIGNAL( error( int ) ), SLOT( slotConnectionFailed( int ) ) ); 00904 trials = 5; 00905 QTimer::singleShot( 1, this, SLOT( slotAsyncConnect() ) ); 00906 } 00907 00908 void KMCupsManager::slotConnectionSuccess() 00909 { 00910 kdDebug(500) << "Connection success, trying to send a request..." << endl; 00911 m_socket->close(); 00912 00913 IppRequest req; 00914 req.setOperation( CUPS_GET_PRINTERS ); 00915 req.addKeyword( IPP_TAG_OPERATION, "requested-attributes", QString::fromLatin1( "printer-name" ) ); 00916 if ( req.doRequest( "/printers/" ) ) 00917 setUpdatePossible( true ); 00918 else 00919 { 00920 kdDebug(500) << "Unable to get printer list" << endl; 00921 if ( trials > 0 ) 00922 { 00923 trials--; 00924 QTimer::singleShot( 1000, this, SLOT( slotAsyncConnect() ) ); 00925 } 00926 else 00927 { 00928 setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. " 00929 "Error: %1." ).arg( i18n( "the IPP request failed for an unknown reason" ) ) ); 00930 setUpdatePossible( false ); 00931 } 00932 } 00933 } 00934 00935 void KMCupsManager::slotAsyncConnect() 00936 { 00937 kdDebug(500) << "Starting async connect" << endl; 00938 //m_socket->startAsyncConnect(); 00939 m_socket->connectToHost( CupsInfos::self()->host(), CupsInfos::self()->port() ); 00940 } 00941 00942 void KMCupsManager::slotConnectionFailed( int errcode ) 00943 { 00944 kdDebug(500) << "Connection failed trials=" << trials << endl; 00945 if ( trials > 0 ) 00946 { 00947 //m_socket->setTimeout( ++to ); 00948 //m_socket->cancelAsyncConnect(); 00949 trials--; 00950 m_socket->close(); 00951 QTimer::singleShot( 1000, this, SLOT( slotAsyncConnect() ) ); 00952 return; 00953 } 00954 00955 setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. " 00956 "Error: %1." ).arg( errcode == QSocket::ErrConnectionRefused ? i18n( "connection refused" ) : i18n( "host not found" ) ) ); 00957 setUpdatePossible( false ); 00958 } 00959 00960 void KMCupsManager::hostPingSlot() { 00961 m_hostSuccess = true; 00962 m_lookupDone = true; 00963 } 00964 00965 void KMCupsManager::hostPingFailedSlot() { 00966 m_hostSuccess = false; 00967 m_lookupDone = true; 00968 } 00969 00970 //***************************************************************************************************** 00971 00972 void extractMaticData(QString& buf, const QString& filename) 00973 { 00974 QFile f(filename); 00975 if (f.exists() && f.open(IO_ReadOnly)) 00976 { 00977 QTextStream t(&f); 00978 QString line; 00979 while (!t.eof()) 00980 { 00981 line = t.readLine(); 00982 if (line.startsWith("*% COMDATA #")) 00983 buf.append(line.right(line.length()-12)).append('\n'); 00984 } 00985 } 00986 } 00987 00988 QString printerURI(KMPrinter *p, bool use) 00989 { 00990 QString uri; 00991 if (use && !p->uri().isEmpty()) 00992 uri = p->uri().prettyURL(); 00993 else 00994 uri = QString("ipp://%1:%2/%4/%3").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()).arg(p->printerName()).arg((p->isClass(false) ? "classes" : "printers")); 00995 return uri; 00996 } 00997 00998 QString downloadDriver(KMPrinter *p) 00999 { 01000 QString driverfile, prname = p->printerName(); 01001 bool changed(false); 01002 01003 /* 01004 if (!p->uri().isEmpty()) 01005 { 01006 // try to load the driver from the host:port 01007 // specified in its URI. Doing so may also change 01008 // the printer name to use. Note that for remote 01009 // printer, this operation is read-only, no counterpart 01010 // for saving operation. 01011 cupsSetServer(p->uri().host().local8Bit()); 01012 ippSetPort(p->uri().port()); 01013 // strip any "@..." from the printer name 01014 prname = prname.replace(QRegExp("@.*"), ""); 01015 changed = true; 01016 } 01017 */ 01018 01019 // download driver 01020 driverfile = cupsGetPPD(prname.local8Bit()); 01021 01022 // restore host:port (if they have changed) 01023 if (changed) 01024 { 01025 cupsSetServer(CupsInfos::self()->host().local8Bit()); 01026 ippSetPort(CupsInfos::self()->port()); 01027 } 01028 01029 return driverfile; 01030 } 01031 01032 #include "kmcupsmanager.moc"
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:41:50 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003