# kdeprint Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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"

This file is part of the documentation for kdeprint Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:31:02 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003