00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kmlpdmanager.h"
00021 #include "kmprinter.h"
00022 #include "kmdbentry.h"
00023 #include "driver.h"
00024 #include "kmfactory.h"
00025 #include "lpdtools.h"
00026 #include "gschecker.h"
00027 #include "kpipeprocess.h"
00028
00029 #include <qfile.h>
00030 #include <qfileinfo.h>
00031 #include <qtextstream.h>
00032 #include <qmap.h>
00033 #include <qregexp.h>
00034
00035 #include <klocale.h>
00036 #include <kstandarddirs.h>
00037 #include <kconfig.h>
00038 #include <kprocess.h>
00039
00040 #include <pwd.h>
00041 #include <unistd.h>
00042 #include <stdlib.h>
00043 #include <sys/stat.h>
00044
00045
00046
00047 QString lpdprefix = "";
00048 QString ptPrinterType(KMPrinter*);
00049
00050
00051
00052 KMLpdManager::KMLpdManager(QObject *parent, const char *name)
00053 : KMManager(parent,name)
00054 {
00055 m_entries.setAutoDelete(true);
00056 m_ptentries.setAutoDelete(true);
00057 setHasManagement(getuid() == 0);
00058 setPrinterOperationMask(KMManager::PrinterCreation|KMManager::PrinterConfigure|KMManager::PrinterRemoval|KMManager::PrinterEnabling);
00059 m_gschecker = new GsChecker(this,"GsChecker");
00060 }
00061
00062 KMLpdManager::~KMLpdManager()
00063 {
00064 }
00065
00066 QString KMLpdManager::driverDbCreationProgram()
00067 {
00068 return QString::fromLatin1("make_driver_db_lpd");
00069 }
00070
00071 QString KMLpdManager::driverDirectory()
00072 {
00073 return QString::fromLatin1("/usr/lib/rhs/rhs-printfilters");
00074 }
00075
00076 bool KMLpdManager::completePrinter(KMPrinter *printer)
00077 {
00078 return completePrinterShort(printer);
00079 }
00080
00081 bool KMLpdManager::completePrinterShort(KMPrinter *printer)
00082 {
00083 PrintcapEntry *entry = m_entries.find(printer->name());
00084 if (entry)
00085 {
00086 QString type(entry->comment(2)), driver(entry->comment(7)), lp(entry->arg("lp"));
00087 printer->setDescription(i18n("Local printer queue (%1)").arg(type.isEmpty() ? i18n("Unknown type of local printer queue", "Unknown") : type));
00088 printer->setLocation(i18n("<Not available>"));
00089 printer->setDriverInfo(driver.isEmpty() ? i18n("Unknown Driver", "Unknown") : driver);
00090
00091 KURL url;
00092 if (!entry->arg("rm").isEmpty())
00093 {
00094 url = QString::fromLatin1("lpd://%1/%2").arg(entry->arg("rm")).arg(entry->arg("rp"));
00095 printer->setDescription(i18n("Remote LPD queue %1@%2").arg(entry->arg("rp")).arg(entry->arg("rm")));
00096 }
00097 else if (!lp.isEmpty() && lp != "/dev/null")
00098 url = QString::fromLatin1("parallel:%1").arg(lp);
00099 else if (QFile::exists(entry->arg("sd")+"/.config"))
00100 {
00101 QMap<QString,QString> map = loadPrinttoolCfgFile(entry->arg("sd")+"/.config");
00102 if (type == "SMB")
00103 {
00104 QStringList l = QStringList::split('\\',map["share"],false);
00105 if (map["workgroup"].isEmpty())
00106 url = QString::fromLatin1("smb://%1/%2").arg(l[0]).arg(l[1]);
00107 else
00108 url = QString::fromLatin1("smb://%1/%2/%3").arg(map["workgroup"]).arg(l[0]).arg(l[1]);
00109 url.setUser(map["user"]);
00110 url.setPass(map["password"]);
00111 }
00112 else if (type == "DIRECT")
00113 url = QString::fromLatin1("socket://%1:%2").arg(map["printer_ip"]).arg(map["port"]);
00114 else if (type == "NCP")
00115 {
00116 url = QString::fromLatin1("ncp://%1/%2").arg(map["server"]).arg(map["queue"]);
00117 url.setUser(map["user"]);
00118 url.setPass(map["password"]);
00119 }
00120 }
00121 printer->setDevice(url);
00122 return true;
00123 }
00124 else return false;
00125 }
00126
00127 bool KMLpdManager::createPrinter(KMPrinter *printer)
00128 {
00129
00130 PrintcapEntry *ent = findPrintcapEntry(printer->printerName());
00131 if (!ent)
00132 {
00133 ent = new PrintcapEntry();
00134 ent->m_name = printer->printerName();
00135 }
00136 else
00137 {
00138 if (!printer->driver() && printer->option("kde-driver") != "raw")
00139 printer->setDriver(loadPrinterDriver(printer,true));
00140
00141 ent = m_entries.take(ent->m_name);
00142 ent->m_args.clear();
00143 }
00144
00145 if (printer->device().protocol() == "lpd")
00146 {
00147
00148 ent->m_args["rm"] = printer->device().host();
00149 ent->m_args["rp"] = printer->device().path().replace("/",QString::fromLatin1(""));
00150 ent->m_args["lpd_bounce"] = "true";
00151 ent->m_comment = QString::fromLatin1("##PRINTTOOL3## REMOTE");
00152 }
00153 ent->m_args["mx"] = (printer->option("mx").isEmpty() ? "#0" : printer->option("mx"));
00154 ent->m_args["sh"] = QString::null;
00155
00156 if (!createSpooldir(ent))
00157 {
00158 setErrorMsg(i18n("Unable to create spool directory %1 for printer %2.").arg(ent->arg("sd")).arg(ent->m_name));
00159 delete ent;
00160 return false;
00161 }
00162 if (!printer->driver() || printer->driver()->get("drtype") == "printtool")
00163 if (!createPrinttoolEntry(printer,ent))
00164 {
00165 setErrorMsg(i18n("Unable to save information for printer <b>%1</b>.").arg(printer->printerName()));
00166 delete ent;
00167 return false;
00168 }
00169
00170
00171 m_entries.insert(ent->m_name,ent);
00172 if (!writePrinters())
00173 return false;
00174
00175
00176 if (printer->driver())
00177 {
00178 if (!savePrinterDriver(printer,printer->driver()))
00179 {
00180 m_entries.remove(ent->m_name);
00181 writePrinters();
00182 return false;
00183 }
00184 }
00185
00186
00187 QCString cmd = "chmod -R o-rwx,g+rwX ";
00188 cmd += QFile::encodeName(KProcess::quote(ent->arg("sd")));
00189 cmd += "&& chown -R lp.lp ";
00190 cmd += QFile::encodeName(KProcess::quote(ent->arg("sd")));
00191 if (system(cmd.data()) != 0)
00192 {
00193 setErrorMsg(i18n("Unable to set correct permissions on spool directory %1 for printer <b>%2</b>.").arg(ent->arg("sd")).arg(ent->m_name));
00194 return false;
00195 }
00196
00197 return true;
00198 }
00199
00200 bool KMLpdManager::removePrinter(KMPrinter *printer)
00201 {
00202 PrintcapEntry *ent = findPrintcapEntry(printer->printerName());
00203 if (ent)
00204 {
00205 ent = m_entries.take(printer->printerName());
00206 if (!writePrinters())
00207 {
00208 m_entries.insert(ent->m_name,ent);
00209 return false;
00210 }
00211 QCString cmd = "rm -rf ";
00212 cmd += QFile::encodeName(KProcess::quote(ent->arg("sd")));
00213 system(cmd.data());
00214 delete ent;
00215 return true;
00216 }
00217 else
00218 return false;
00219 }
00220
00221 bool KMLpdManager::enablePrinter(KMPrinter *printer, bool state)
00222 {
00223 KPipeProcess proc;
00224 QString cmd = programName(0);
00225 cmd += " ";
00226 cmd += state ? "up" : "down";
00227 cmd += " ";
00228 cmd += KProcess::quote(printer->printerName());
00229 if (proc.open(cmd))
00230 {
00231 QTextStream t(&proc);
00232 QString buffer;
00233 while (!t.eof())
00234 buffer.append(t.readLine());
00235 if (buffer.startsWith("?Privilege"))
00236 {
00237 setErrorMsg(i18n("Permission denied: you must be root."));
00238 return false;
00239 }
00240 return true;
00241 }
00242 else
00243 {
00244 setErrorMsg(i18n("Unable to execute command \"%1\".").arg(cmd));
00245 return false;
00246 }
00247 }
00248
00249 bool KMLpdManager::enablePrinter(KMPrinter *printer)
00250 {
00251 return enablePrinter(printer,true);
00252 }
00253
00254 bool KMLpdManager::disablePrinter(KMPrinter *printer)
00255 {
00256 return enablePrinter(printer,false);
00257 }
00258
00259 void KMLpdManager::listPrinters()
00260 {
00261 m_entries.clear();
00262 loadPrintcapFile(QString::fromLatin1("%1/etc/printcap").arg(lpdprefix));
00263
00264 QDictIterator<PrintcapEntry> it(m_entries);
00265 for (;it.current();++it)
00266 {
00267 KMPrinter *printer = it.current()->createPrinter();
00268 addPrinter(printer);
00269 }
00270
00271 checkStatus();
00272 }
00273
00274 QString KMLpdManager::programName(int f)
00275 {
00276 KConfig *conf = KMFactory::self()->printConfig();
00277 conf->setGroup("LPD");
00278 switch (f)
00279 {
00280 case 0: return conf->readPathEntry("LpdCommand","/usr/sbin/lpc");
00281 case 1: return conf->readPathEntry("LpdQueue","lpq");
00282 case 2: return conf->readPathEntry("LpdRemove","lprm");
00283 }
00284 return QString::null;
00285 }
00286
00287 void KMLpdManager::checkStatus()
00288 {
00289 KPipeProcess proc;
00290 QString cmd = programName(0) + " status all";
00291 if (proc.open(cmd))
00292 {
00293 QTextStream t(&proc);
00294 QString line;
00295 KMPrinter *printer(0);
00296 int p(-1);
00297 while (!t.eof())
00298 {
00299 line = t.readLine().stripWhiteSpace();
00300 if (line.isEmpty())
00301 continue;
00302 if ((p=line.find(':')) != -1)
00303 printer = findPrinter(line.left(p));
00304 else if (line.startsWith("printing") && printer)
00305 printer->setState(line.find("enabled") != -1 ? KMPrinter::Idle : KMPrinter::Stopped);
00306 else if (line.find("entries") != -1 && printer)
00307 if (!line.startsWith("no") && printer->state() == KMPrinter::Idle)
00308 printer->setState(KMPrinter::Processing);
00309 }
00310 }
00311 }
00312
00313 bool KMLpdManager::writePrinters()
00314 {
00315 if (!writePrintcapFile(QString::fromLatin1("%1/etc/printcap").arg(lpdprefix)))
00316 {
00317 setErrorMsg(i18n("Unable to write printcap file."));
00318 return false;
00319 }
00320 return true;
00321 }
00322
00323 void KMLpdManager::loadPrintcapFile(const QString& filename)
00324 {
00325 QFile f(filename);
00326 if (f.exists() && f.open(IO_ReadOnly))
00327 {
00328 QTextStream t(&f);
00329 QString line, comment;
00330 PrintcapEntry *entry;
00331 while (!t.eof())
00332 {
00333 line = getPrintcapLine(t,&comment);
00334 if (line.isEmpty())
00335 continue;
00336 entry = new PrintcapEntry;
00337 if (entry->readLine(line))
00338 {
00339 m_entries.insert(entry->m_name,entry);
00340 entry->m_comment = comment;
00341 }
00342 else
00343 {
00344 delete entry;
00345 break;
00346 }
00347 }
00348 }
00349 }
00350
00351 bool KMLpdManager::writePrintcapFile(const QString& filename)
00352 {
00353 QFile f(filename);
00354 if (f.open(IO_WriteOnly))
00355 {
00356 QTextStream t(&f);
00357 t << "# File generated by KDE print (LPD plugin).\n#Don't edit by hand." << endl << endl;
00358 QDictIterator<PrintcapEntry> it(m_entries);
00359 for (;it.current();++it)
00360 it.current()->writeEntry(t);
00361 return true;
00362 }
00363 return false;
00364 }
00365
00366 PrinttoolEntry* KMLpdManager::findPrinttoolEntry(const QString& name)
00367 {
00368 if (m_ptentries.count() == 0)
00369 loadPrinttoolDb(driverDirectory()+"/printerdb");
00370 PrinttoolEntry *ent = m_ptentries.find(name);
00371 if (!ent)
00372 setErrorMsg(i18n("Couldn't find driver <b>%1</b> in printtool database.").arg(name));
00373 return ent;
00374 }
00375
00376 void KMLpdManager::loadPrinttoolDb(const QString& filename)
00377 {
00378 QFile f(filename);
00379 if (f.exists() && f.open(IO_ReadOnly))
00380 {
00381 QTextStream t(&f);
00382 PrinttoolEntry *entry = new PrinttoolEntry;
00383 while (entry->readEntry(t))
00384 {
00385 m_ptentries.insert(entry->m_name,entry);
00386 entry = new PrinttoolEntry;
00387 }
00388 delete entry;
00389 }
00390 }
00391
00392 DrMain* KMLpdManager::loadDbDriver(KMDBEntry *entry)
00393 {
00394 QString ptdbfilename = driverDirectory() + "/printerdb";
00395 if (entry->file == ptdbfilename)
00396 {
00397 PrinttoolEntry *ptentry = findPrinttoolEntry(entry->modelname);
00398 if (ptentry)
00399 {
00400 DrMain *dr = ptentry->createDriver();
00401 return dr;
00402 }
00403 }
00404 return NULL;
00405 }
00406
00407 PrintcapEntry* KMLpdManager::findPrintcapEntry(const QString& name)
00408 {
00409 PrintcapEntry *ent = m_entries.find(name);
00410 if (!ent)
00411 setErrorMsg(i18n("Couldn't find printer <b>%1</b> in printcap file.").arg(name));
00412 return ent;
00413 }
00414
00415 DrMain* KMLpdManager::loadPrinterDriver(KMPrinter *printer, bool config)
00416 {
00417 PrintcapEntry *entry = findPrintcapEntry(printer->name());
00418 if (!entry)
00419 return NULL;
00420
00421
00422 QString sd = entry->arg("sd"), dr(entry->comment(7));
00423 if (QFile::exists(sd+"/postscript.cfg") && config && !dr.isEmpty())
00424 {
00425 QMap<QString,QString> map = loadPrinttoolCfgFile(sd+"/postscript.cfg");
00426 PrinttoolEntry *ptentry = findPrinttoolEntry(dr);
00427 if (!ptentry)
00428 return NULL;
00429 DrMain *dr = ptentry->createDriver();
00430 dr->setOptions(map);
00431 map = loadPrinttoolCfgFile(sd+"/general.cfg");
00432 dr->setOptions(map);
00433 map = loadPrinttoolCfgFile(sd+"/textonly.cfg");
00434 dr->setOptions(map);
00435 return dr;
00436 }
00437
00438
00439 if (entry->m_comment.startsWith("##PRINTTOOL3##"))
00440 setErrorMsg(i18n("No driver found (raw printer)"));
00441 else
00442 setErrorMsg(i18n("Printer type not recognized."));
00443 return NULL;
00444 }
00445
00446 bool KMLpdManager::checkGsDriver(const QString& gsdriver)
00447 {
00448 if (gsdriver == "ppa" || gsdriver == "POSTSCRIPT" || gsdriver == "TEXT")
00449 return true;
00450 else if (!m_gschecker->checkGsDriver(gsdriver))
00451 {
00452 setErrorMsg(i18n("The driver device <b>%1</b> is not compiled in your GhostScript distribution. Check your installation or use another driver.").arg(gsdriver));
00453 return false;
00454 }
00455 return true;
00456 }
00457
00458 QMap<QString,QString> KMLpdManager::loadPrinttoolCfgFile(const QString& filename)
00459 {
00460 QFile f(filename);
00461 QMap<QString,QString> map;
00462 if (f.exists() && f.open(IO_ReadOnly))
00463 {
00464 QTextStream t(&f);
00465 QString line, name, val;
00466 int p(-1);
00467 while (!t.eof())
00468 {
00469 line = getPrintcapLine(t);
00470 if (line.isEmpty())
00471 break;
00472 if (line.startsWith("export "))
00473 line.replace(0,7,"");
00474 if ((p=line.find('=')) != -1)
00475 {
00476 name = line.left(p);
00477 val = line.right(line.length()-p-1);
00478 val.replace("\"","");
00479 val.replace("'","");
00480 if (!name.isEmpty() && !val.isEmpty())
00481 map[name] = val;
00482 }
00483 }
00484 }
00485 return map;
00486 }
00487
00488 bool KMLpdManager::savePrinttoolCfgFile(const QString& templatefile, const QString& dirname, const QMap<QString,QString>& options)
00489 {
00490
00491 QString fname = QFileInfo(templatefile).fileName();
00492 fname.replace(QRegExp("\\.in$"),QString::fromLatin1(""));
00493 QFile fin(templatefile);
00494 QFile fout(dirname + "/" + fname);
00495 if (fin.exists() && fin.open(IO_ReadOnly) && fout.open(IO_WriteOnly))
00496 {
00497 QTextStream tin(&fin), tout(&fout);
00498 QString line, name;
00499 int p(-1);
00500 while (!tin.eof())
00501 {
00502 line = tin.readLine().stripWhiteSpace();
00503 if (line.isEmpty() || line[0] == '#')
00504 {
00505 tout << line << endl;
00506 continue;
00507 }
00508 if (line.startsWith("export "))
00509 {
00510 tout << "export ";
00511 line.replace(0,7,QString::fromLatin1(""));
00512 }
00513 if ((p=line.find('=')) != -1)
00514 {
00515 name = line.left(p);
00516 tout << name << '=' << options[name] << endl;
00517 }
00518 }
00519 return true;
00520 }
00521 else return false;
00522 }
00523
00524 bool KMLpdManager::savePrinterDriver(KMPrinter *printer, DrMain *driver)
00525 {
00526
00527
00528 QString spooldir;
00529 PrintcapEntry *ent = findPrintcapEntry(printer->printerName());
00530 if (!ent)
00531 return false;
00532 spooldir = ent->arg("sd");
00533
00534 if (driver->get("drtype") == "printtool" && !spooldir.isEmpty())
00535 {
00536 QMap<QString,QString> options;
00537 driver->getOptions(options,true);
00538
00539 options["DESIRED_TO"] = "ps";
00540 options["PRINTER_TYPE"] = ent->comment(2);
00541 options["PS_SEND_EOF"] = "NO";
00542 if (!checkGsDriver(options["GSDEVICE"]))
00543 return false;
00544 QString resol(options["RESOLUTION"]), color(options["COLOR"]);
00545
00546 ent->m_comment = QString::fromLatin1("##PRINTTOOL3## %1 %2 %3 %4 {} {%5} %6 {}").arg(options["PRINTER_TYPE"]).arg(options["GSDEVICE"]).arg((resol.isEmpty() ? QString::fromLatin1("NAxNA") : resol)).arg(options["PAPERSIZE"]).arg(driver->name()).arg((color.isEmpty() ? QString::fromLatin1("Default") : color.right(color.length()-15)));
00547 ent->m_args["if"] = spooldir+QString::fromLatin1("/filter");
00548 if (!writePrinters())
00549 return false;
00550
00551 QCString cmd = "cp ";
00552 cmd += QFile::encodeName(KProcess::quote(driverDirectory()+"/master-filter"));
00553 cmd += " ";
00554 cmd += QFile::encodeName(KProcess::quote(spooldir + "/filter"));
00555 if (system(cmd.data()) == 0 &&
00556 savePrinttoolCfgFile(driverDirectory()+"/general.cfg.in",spooldir,options) &&
00557 savePrinttoolCfgFile(driverDirectory()+"/postscript.cfg.in",spooldir,options) &&
00558 savePrinttoolCfgFile(driverDirectory()+"/textonly.cfg.in",spooldir,options))
00559 return true;
00560 setErrorMsg(i18n("Unable to write driver associated files in spool directory."));
00561 }
00562 return false;
00563 }
00564
00565 bool KMLpdManager::createPrinttoolEntry(KMPrinter *printer, PrintcapEntry *entry)
00566 {
00567 KURL dev(printer->device());
00568 QString prot = dev.protocol(), sd(entry->arg("sd"));
00569 entry->m_comment = QString::fromLatin1("##PRINTTOOL3## %1").arg(ptPrinterType(printer));
00570 if (prot == "smb" || prot == "ncp" || prot == "socket")
00571 {
00572 entry->m_args["af"] = sd+QString::fromLatin1("/acct");
00573 QFile f(sd+QString::fromLatin1("/.config"));
00574 if (f.open(IO_WriteOnly))
00575 {
00576 QTextStream t(&f);
00577 if (prot == "socket")
00578 {
00579 t << "printer_ip=" << dev.host() << endl;
00580 t << "port=" << dev.port() << endl;
00581 entry->m_args["if"] = driverDirectory()+QString::fromLatin1("/directprint");
00582 }
00583 else if (prot == "smb")
00584 {
00585 QStringList l = QStringList::split('/',dev.path(),false);
00586 if (l.count() == 2)
00587 {
00588 t << "share='\\\\" << l[0] << '\\' << l[1] << '\'' << endl;
00589 }
00590 else if (l.count() == 1)
00591 {
00592 t << "share='\\\\" << dev.host() << '\\' << l[0] << '\'' << endl;
00593 }
00594 t << "hostip=" << endl;
00595 t << "user='" << dev.user() << '\'' << endl;
00596 t << "password='" << dev.pass() << '\'' << endl;
00597 t << "workgroup='" << (l.count() == 2 ? dev.host() : QString::fromLatin1("")) << '\'' << endl;
00598 entry->m_args["if"] = driverDirectory()+QString::fromLatin1("/smbprint");
00599 }
00600 else if (prot == "ncp")
00601 {
00602 t << "server=" << dev.host() << endl;
00603 t << "queue=" << dev.path().replace("/",QString::fromLatin1("")) << endl;
00604 t << "user=" << dev.user() << endl;
00605 t << "password=" << dev.pass() << endl;
00606 entry->m_args["if"] = driverDirectory()+QString::fromLatin1("/ncpprint");
00607 }
00608 }
00609 else return false;
00610 entry->m_args["lp"] = QString::fromLatin1("/dev/null");
00611 }
00612 else if (prot != "lpd")
00613 entry->m_args["lp"] = dev.path();
00614 return true;
00615 }
00616
00617 bool KMLpdManager::createSpooldir(PrintcapEntry *entry)
00618 {
00619
00620 if (entry->arg("sd").isEmpty())
00621 entry->m_args["sd"] = QString::fromLatin1("/var/spool/lpd/")+entry->m_name;
00622 QString sd = entry->arg("sd");
00623 if (!KStandardDirs::exists(sd))
00624 {
00625 if (!KStandardDirs::makeDir(sd,0750))
00626 return false;
00627 struct passwd *lp_pw = getpwnam("lp");
00628 if (lp_pw && chown(QFile::encodeName(sd),lp_pw->pw_uid,lp_pw->pw_gid) != 0)
00629 return false;
00630 }
00631 return true;
00632 }
00633
00634 bool KMLpdManager::validateDbDriver(KMDBEntry *entry)
00635 {
00636 PrinttoolEntry *ptentry = findPrinttoolEntry(entry->modelname);
00637 return (ptentry && checkGsDriver(ptentry->m_gsdriver));
00638 }
00639
00640
00641
00642 QString ptPrinterType(KMPrinter *p)
00643 {
00644 QString type, prot = p->device().protocol();
00645 if (prot == "lpd") type = "REMOTE";
00646 else if (prot == "smb") type = "SMB";
00647 else if (prot == "ncp") type = "NCP";
00648 else if (prot == "socket") type = "DIRECT";
00649 else type = "LOCAL";
00650 return type;
00651 }