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 <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 & )
00070 : KMManager(parent,name)
00071 {
00072     
00073     
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     
00084     
00085     
00086     setenv("LANG", "en", 1);
00087 }
00088 
00089 KMCupsManager::~KMCupsManager()
00090 {
00091     
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     
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     
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         
00147         
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         
00231         QString ppdname = downloadDriver(p);
00232         ppd_file_t  *ppd = (ppdname.isEmpty() ? NULL : ppdOpenFile(ppdname.local8Bit()));
00233         if (ppd)
00234         {
00235             KMDBEntry   entry;
00236             
00237             
00238             
00239             entry.manufacturer = ppd->manufacturer;
00240             entry.model = ppd->shortnickname;
00241             entry.modelname = ppd->modelname;
00242             
00243             entry.validate(false);
00244             
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 
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     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         
00331         
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         
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 
00351 
00352 
00353         if (req.name("member-names",values))
00354             p->setMembers(values);
00355         
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         
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         
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 
00391 
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 
00407 
00408 
00409 
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     
00424     req.setOperation(CUPS_GET_PRINTERS);
00425     keys.append("printer-name");
00426     keys.append("printer-type");
00427     keys.append("printer-state");
00428     
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         
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             
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             
00458             
00459             
00460             
00461             
00462             return;
00463         }
00464     }
00465 
00466     
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             
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             
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                 
00644 
00645 
00646 
00647 
00648 
00649 
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     
00715     saveDriverFile(d,tmpfilename);
00716 
00717     
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     
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("libcupsdconf");
00740         if (!m_cupsdconf)
00741         {
00742             setErrorMsg(i18n("Library libcupsdconf 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 libcupsdconf 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     
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 
00863 
00864 
00865 
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     
00895 
00896 
00897 
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     
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         
00945         
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 
01002 
01003 
01004 
01005 
01006 
01007 
01008 
01009 
01010 
01011 
01012 
01013 
01014 
01015 
01016     
01017     driverfile = cupsGetPPD(prname.local8Bit());
01018 
01019     
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"