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