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 <tqfileinfo.h> 00032 #include <tqptrlist.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(TQObject *parent, const char *name, const TQStringList & /*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 TQFileInfo 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 TQPtrListIterator<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 TQFile 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 TQPtrListIterator<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 TQPtrListIterator<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 TQStringList l = KGlobal::dirs()->findAllResources("data", "kdeprint/lpr/*.la"); 00141 for (TQStringList::ConstIterator it=l.begin(); it!=l.end(); ++it) 00142 { 00143 KLibrary *library = KLibLoader::self()->library(TQFile::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 TQString 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 TQString& filename) 00232 { 00233 int p = filename.find('/'); 00234 TQString handler_str = (p != -1 ? filename.left(p) : TQString::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 TQString 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 TQString 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 TQFile f(LprSettings::self()->printcapFile()); 00293 if (f.open(IO_WriteOnly)) 00294 { 00295 TQTextStream t(&f); 00296 TQDictIterator<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 TQString 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 += TQStringList::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 TQString 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 TQString 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(TQFile::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 TQString KMLprManager::driverDbCreationProgram() 00424 { 00425 return TQString::fromLatin1("make_driver_db_lpr"); 00426 } 00427 00428 TQString KMLprManager::driverDirectory() 00429 { 00430 TQPtrListIterator<LprHandler> it(m_handlerlist); 00431 TQString dbDirs; 00432 for (; it.current(); ++it) 00433 { 00434 TQString 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 TQString KMLprManager::printOptions(KPrinter *prt) 00444 { 00445 KMPrinter *mprt = findPrinter(prt->printerName()); 00446 TQString opts; 00447 if (mprt) 00448 { 00449 LprHandler *handler = findHandler(mprt); 00450 if (handler) 00451 return handler->printOptions(prt); 00452 } 00453 return TQString::null; 00454 } 00455 00456 void KMLprManager::createPluginActions(KActionCollection *coll) 00457 { 00458 KAction *act = new KAction(i18n("&Edit printcap Entry..."), "kdeprint_report", 0, this, TQT_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?"), TQString::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 TQString 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"