kdeprint Library API Documentation

kmcupsmanager.cpp

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