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