kmlprmanager.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 "kmlprmanager.h"
00021 #include "printcapreader.h"
00022 #include "printcapentry.h"
00023 #include "lpchelper.h"
00024 #include "matichandler.h"
00025 #include "apshandler.h"
00026 #include "lprngtoolhandler.h"
00027 #include "lprsettings.h"
00028 #include "driver.h"
00029 #include "editentrydialog.h"
00030 
00031 #include <qfileinfo.h>
00032 #include <qptrlist.h>
00033 #include <klocale.h>
00034 #include <kstandarddirs.h>
00035 #include <kdebug.h>
00036 #include <kprinter.h>
00037 #include <kprocess.h>
00038 #include <kaction.h>
00039 #include <kmessagebox.h>
00040 #include <klibloader.h>
00041 
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 
00045 KMLprManager::KMLprManager(QObject *parent, const char *name, const QStringList & /*args*/)
00046 : KMManager(parent,name)
00047 {
00048     m_handlers.setAutoDelete(true);
00049     m_handlerlist.setAutoDelete(false);
00050     m_entries.setAutoDelete(true);
00051 
00052     m_lpchelper = new LpcHelper(this);
00053     m_currentprinter = 0;
00054 
00055     setHasManagement(getuid() == 0);
00056     setPrinterOperationMask(
00057         KMManager::PrinterEnabling |
00058         KMManager::PrinterConfigure |
00059         KMManager::PrinterTesting |
00060         KMManager::PrinterCreation |
00061         KMManager::PrinterRemoval |
00062         KMManager::PrinterTesting
00063     );
00064 
00065     initHandlers();
00066 }
00067 
00068 void KMLprManager::listPrinters()
00069 {
00070     QFileInfo   fi(LprSettings::self()->printcapFile());
00071 
00072     if (m_lpchelper)
00073         m_lpchelper->updateStates();
00074 
00075     // update only if needed
00076     if (!m_updtime.isValid() || m_updtime < fi.lastModified())
00077     {
00078         // cleanup previous entries
00079         m_entries.clear();
00080         // notify handlers
00081         QPtrListIterator<LprHandler>    hit(m_handlerlist);
00082         for (; hit.current(); ++hit)
00083             hit.current()->reset();
00084 
00085         // try to open the printcap file and parse it
00086         PrintcapReader  reader;
00087         QFile   f(fi.absFilePath());
00088         PrintcapEntry   *entry;
00089         if (f.exists() && f.open(IO_ReadOnly))
00090         {
00091             reader.setPrintcapFile(&f);
00092             while ((entry = reader.nextEntry()) != NULL)
00093             {
00094                 QPtrListIterator<LprHandler>    it(m_handlerlist);
00095                 for (; it.current(); ++it)
00096                     if (it.current()->validate(entry))
00097                     {
00098                         KMPrinter   *prt = it.current()->createPrinter(entry);
00099                         checkPrinterState(prt);
00100                         prt->setOption("kde-lpr-handler", it.current()->name());
00101                         addPrinter(prt);
00102                         break;
00103                     }
00104                 m_entries.insert(entry->name, entry);
00105             }
00106         }
00107 
00108         // save update time
00109         m_updtime = fi.lastModified();
00110     }
00111     else
00112     {
00113         QPtrListIterator<KMPrinter> it(m_printers);
00114         for (; it.current(); ++it)
00115             if (!it.current()->isSpecial())
00116             {
00117                 it.current()->setDiscarded(false);
00118                 checkPrinterState(it.current());
00119             }
00120     }
00121 }
00122 
00123 void KMLprManager::insertHandler(LprHandler *handler)
00124 {
00125     m_handlers.insert(handler->name(), handler);
00126     m_handlerlist.append(handler);
00127     kdDebug() << "Handler: " << handler->name() << endl;
00128 }
00129 
00130 void KMLprManager::initHandlers()
00131 {
00132     m_handlers.clear();
00133     m_handlerlist.clear();
00134 
00135     insertHandler(new MaticHandler(this));
00136     insertHandler(new ApsHandler(this));
00137     insertHandler(new LPRngToolHandler(this));
00138 
00139     // now load external handlers
00140     QStringList l = KGlobal::dirs()->findAllResources("data", "kdeprint/lpr/*.so");
00141     for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it)
00142     {
00143         KLibrary    *library = KLibLoader::self()->library(QFile::encodeName(*it));
00144         if (library)
00145         {
00146             kdDebug() << "loading external handler from " << *it << endl;
00147             LprHandler*(*func)(KMManager*) = (LprHandler*(*)(KMManager*))(library->symbol("create_handler"));
00148             if (func)
00149                 insertHandler(func(this));
00150             else
00151                 kdDebug() << "couldn't find the symbol 'create_handler'" << endl;
00152         }
00153     }
00154 
00155     // default handler
00156     insertHandler(new LprHandler("default", this));
00157 }
00158 
00159 LprHandler* KMLprManager::findHandler(KMPrinter *prt)
00160 {
00161     QString handlerstr(prt->option("kde-lpr-handler"));
00162     LprHandler  *handler(0);
00163     if (handlerstr.isEmpty() || (handler = m_handlers.find(handlerstr)) == NULL)
00164     {
00165         return NULL;
00166     }
00167     return handler;
00168 }
00169 
00170 PrintcapEntry* KMLprManager::findEntry(KMPrinter *prt)
00171 {
00172     PrintcapEntry   *entry = m_entries.find(prt->printerName());
00173     if (!entry)
00174     {
00175         return NULL;
00176     }
00177     return entry;
00178 }
00179 
00180 bool KMLprManager::completePrinter(KMPrinter *prt)
00181 {
00182     LprHandler  *handler = findHandler(prt);
00183     PrintcapEntry   *entry = findEntry(prt);
00184     if (handler && entry)
00185         return handler->completePrinter(prt, entry, false);
00186     return false;
00187 }
00188 
00189 bool KMLprManager::completePrinterShort(KMPrinter *prt)
00190 {
00191     LprHandler  *handler = findHandler(prt);
00192     PrintcapEntry   *entry = findEntry(prt);
00193     if (!handler || !entry)
00194         return false;
00195 
00196     return handler->completePrinter(prt, entry, true);
00197 }
00198 
00199 void KMLprManager::checkPrinterState(KMPrinter *prt)
00200 {
00201     if (m_lpchelper)
00202     {
00203         KMPrinter::PrinterState st = m_lpchelper->state(prt);
00204         prt->setState(st);
00205         prt->setAcceptJobs(!(st & KMPrinter::Rejecting));
00206     }
00207     else
00208     {
00209         prt->setState(KMPrinter::Idle);
00210         prt->setAcceptJobs(true);
00211     }
00212 }
00213 
00214 DrMain* KMLprManager::loadPrinterDriver(KMPrinter *prt, bool config)
00215 {
00216     if (!prt)
00217         return NULL;
00218 
00219     LprHandler  *handler = findHandler(prt);
00220     PrintcapEntry   *entry = findEntry(prt);
00221     if (handler && entry)
00222     {
00223         DrMain  *driver = handler->loadDriver(prt, entry, config);
00224         if (driver)
00225             driver->set("handler", handler->name());
00226         return driver;
00227     }
00228     return NULL;
00229 }
00230 
00231 DrMain* KMLprManager::loadFileDriver(const QString& filename)
00232 {
00233     int p = filename.find('/');
00234     QString handler_str = (p != -1 ? filename.left(p) : QString::fromLatin1("default"));
00235     LprHandler  *handler = m_handlers.find(handler_str);
00236     if (handler)
00237     {
00238         DrMain  *driver = handler->loadDbDriver(filename);
00239         if (driver)
00240             driver->set("handler", handler->name());
00241         return driver;
00242     }
00243     return NULL;
00244 }
00245 
00246 bool KMLprManager::enablePrinter(KMPrinter *prt, bool state)
00247 {
00248     QString msg;
00249     if (!m_lpchelper->enable(prt, state, msg))
00250     {
00251         setErrorMsg(msg);
00252         return false;
00253     }
00254     return true;
00255 }
00256 
00257 bool KMLprManager::startPrinter(KMPrinter *prt, bool state)
00258 {
00259     QString msg;
00260     if (!m_lpchelper->start(prt, state, msg))
00261     {
00262         setErrorMsg(msg);
00263         return false;
00264     }
00265     return true;
00266 }
00267 
00268 bool KMLprManager::savePrinterDriver(KMPrinter *prt, DrMain *driver)
00269 {
00270     LprHandler  *handler = findHandler(prt);
00271     PrintcapEntry   *entry = findEntry(prt);
00272     if (handler && entry)
00273     {
00274         bool    mustSave(false);
00275         if (handler->savePrinterDriver(prt, entry, driver, &mustSave))
00276         {
00277             if (mustSave)
00278                 return savePrintcapFile();
00279             return true;
00280         }
00281     }
00282     return false;
00283 }
00284 
00285 bool KMLprManager::savePrintcapFile()
00286 {
00287     if (!LprSettings::self()->isLocalPrintcap())
00288     {
00289         setErrorMsg(i18n("The printcap file is a remote file (NIS). It cannot be written."));
00290         return false;
00291     }
00292     QFile   f(LprSettings::self()->printcapFile());
00293     if (f.open(IO_WriteOnly))
00294     {
00295         QTextStream t(&f);
00296         QDictIterator<PrintcapEntry>    it(m_entries);
00297         for (; it.current(); ++it)
00298         {
00299             it.current()->writeEntry(t);
00300         }
00301         return true;
00302     }
00303     else
00304     {
00305         setErrorMsg(i18n("Unable to save printcap file. Check that "
00306                          "you have write permissions for that file."));
00307         return false;
00308     }
00309 }
00310 
00311 bool KMLprManager::createPrinter(KMPrinter *prt)
00312 {
00313     // remove existing printcap entry
00314     PrintcapEntry   *oldEntry = m_entries.find(prt->printerName());
00315 
00316     // look for the handler and re-create entry
00317     LprHandler  *handler(0);
00318     // To look for the handler, either we base ourselves
00319     // on the driver (1: new printer, 2: modifying driver)
00320     // or we use the handler of the existing printer
00321     // (modifying something else, handler stays the same)
00322     if (prt->driver())
00323         handler = m_handlers.find(prt->driver()->get("handler"));
00324     else if (oldEntry)
00325         handler = findHandler(prt);
00326     else
00327         handler = m_handlers.find("default");
00328     if (!handler)
00329     {
00330         setErrorMsg(i18n("Internal error: no handler defined."));
00331         return false;
00332     }
00333     prt->setOption("kde-lpr-handler", handler->name());
00334 
00335     // we reload the driver if the printer object doesn't have one
00336     // and there's an old entry (sometimes needed to keep the backend
00337     // like in Foomatic)
00338     if (!prt->driver() && oldEntry)
00339         prt->setDriver(handler->loadDriver(prt, oldEntry, true));
00340 
00341     QString sd = LprSettings::self()->baseSpoolDir();
00342     if (sd.isEmpty())
00343     {
00344         setErrorMsg(i18n("Couldn't determine spool directory. See options dialog."));
00345         return false;
00346     }
00347     sd.append("/").append(prt->printerName());
00348     if (!KStandardDirs::makeDir(sd, 0755))
00349     {
00350         setErrorMsg(i18n("Unable to create the spool directory %1. Check that you "
00351                          "have the required permissions for that operation.").arg(sd));
00352         return false;
00353     }
00354     PrintcapEntry   *entry = handler->createEntry(prt);
00355     if (!entry)
00356         return false;   // error should be set in the handler
00357     // old entry can be removed now
00358     m_entries.remove(prt->printerName());
00359     entry->name = prt->printerName();
00360     entry->addField("sh", Field::Boolean);
00361     entry->addField("mx", Field::Integer, "0");
00362     entry->addField("sd", Field::String, sd);
00363     if (!prt->option("kde-aliases").isEmpty())
00364         entry->aliases += QStringList::split("|", prt->option("kde-aliases"), false);
00365 
00366     // insert the new entry and save printcap file
00367     m_entries.insert(prt->printerName(), entry);
00368     bool    result = savePrintcapFile();
00369     if (result)
00370     {
00371         if (prt->driver())
00372         {
00373             result = handler->savePrinterDriver(prt, entry, prt->driver());
00374         }
00375 
00376         // in case of LPRng, we need to tell the daemon about new printer
00377         if (LprSettings::self()->mode() == LprSettings::LPRng)
00378         {
00379             QString msg;
00380             if (!m_lpchelper->restart(msg))
00381             {
00382                 setErrorMsg(i18n("The printer has been created but the print daemon "
00383                                  "could not be restarted. %1").arg(msg));
00384                 return false;
00385             }
00386         }
00387     }
00388     return result;
00389 }
00390 
00391 bool KMLprManager::removePrinter(KMPrinter *prt)
00392 {
00393     LprHandler  *handler = findHandler(prt);
00394     PrintcapEntry   *entry = findEntry(prt);
00395     if (handler && entry)
00396     {
00397         if (handler->removePrinter(prt, entry))
00398         {
00399             QString sd = entry->field("sd");
00400             // first try to save the printcap file, and if
00401             // successful, remove the spool directory
00402             m_entries.take(prt->printerName());
00403             bool    status = savePrintcapFile();
00404             if (status)
00405             {
00406                 // printcap file saved, entry can be deleted now
00407                 delete entry;
00408                 status =  (::system(QFile::encodeName("rm -rf " + KProcess::quote(sd))) == 0);
00409                 if (!status)
00410                     setErrorMsg(i18n("Unable to remove spool directory %1. "
00411                                      "Check that you have write permissions "
00412                                      "for that directory.").arg(sd));
00413                 return status;
00414             }
00415             else
00416                 // push back the non-removed entry
00417                 m_entries.insert(prt->printerName(), entry);
00418         }
00419     }
00420     return false;
00421 }
00422 
00423 QString KMLprManager::driverDbCreationProgram()
00424 {
00425     return QString::fromLatin1("make_driver_db_lpr");
00426 }
00427 
00428 QString KMLprManager::driverDirectory()
00429 {
00430     QPtrListIterator<LprHandler>    it(m_handlerlist);
00431     QString dbDirs;
00432     for (; it.current(); ++it)
00433     {
00434         QString dir = it.current()->driverDirectory();
00435         if (!dir.isEmpty())
00436             dbDirs.append(dir).append(":");
00437     }
00438     if (!dbDirs.isEmpty())
00439         dbDirs.truncate(dbDirs.length()-1);
00440     return dbDirs;
00441 }
00442 
00443 QString KMLprManager::printOptions(KPrinter *prt)
00444 {
00445     KMPrinter   *mprt = findPrinter(prt->printerName());
00446     QString opts;
00447     if (mprt)
00448     {
00449         LprHandler  *handler = findHandler(mprt);
00450         if (handler)
00451             return handler->printOptions(prt);
00452     }
00453     return QString::null;
00454 }
00455 
00456 void KMLprManager::createPluginActions(KActionCollection *coll)
00457 {
00458     KAction *act = new KAction(i18n("&Edit printcap Entry..."), "kdeprint_report", 0, this, SLOT(slotEditPrintcap()), coll, "plugin_editprintcap");
00459     act->setGroup("plugin");
00460 }
00461 
00462 void KMLprManager::validatePluginActions(KActionCollection *coll, KMPrinter *prt)
00463 {
00464     m_currentprinter = prt;
00465     // FIXME: disabled until completion
00466     coll->action("plugin_editprintcap")->setEnabled(0 && hasManagement() && prt && !prt->isSpecial());
00467 }
00468 
00469 void KMLprManager::slotEditPrintcap()
00470 {
00471     if (!m_currentprinter ||
00472         KMessageBox::warningContinueCancel(NULL,
00473         i18n("Editing a printcap entry manually should only be "
00474          "done by confirmed system administrator. This may "
00475          "prevent your printer from working. Do you want to "
00476          "continue?"), QString::null, KStdGuiItem::cont(),
00477         "editPrintcap") == KMessageBox::Cancel)
00478         return;
00479 
00480     PrintcapEntry   *entry = findEntry(m_currentprinter);
00481     EditEntryDialog dlg(entry, NULL);
00482     if (dlg.exec())
00483     {
00484     }
00485 }
00486 
00487 QString KMLprManager::stateInformation()
00488 {
00489     return i18n("Spooler type: %1").arg(LprSettings::self()->mode() == LprSettings::LPR ? "LPR (BSD compatible)" : "LPRng");
00490 }
00491 
00492 #include "kmlprmanager.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys