kmlpdunixmanager.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 "kmlpdunixmanager.h"
00021 #include "kmfactory.h"
00022 #include "kmprinter.h"
00023 
00024 #include <qfile.h>
00025 #include <qdir.h>
00026 #include <qfileinfo.h>
00027 #include <qtextstream.h>
00028 #include <qregexp.h>
00029 #include <klocale.h>
00030 #include <kstandarddirs.h>
00031 #include <kdebug.h>
00032 
00033 #include <stdlib.h>
00034 
00035 /*****************
00036  * Utility class *
00037  *****************/
00038 class KTextBuffer
00039 {
00040 public:
00041     KTextBuffer(QIODevice *dev) : m_stream(dev) {}
00042     bool eof() const { return (m_stream.eof() && m_linebuf.isEmpty()); }
00043     QString readLine();
00044     void unreadLine(const QString& l) { m_linebuf = l; }
00045 private:
00046     QTextStream m_stream;
00047     QString     m_linebuf;
00048 };
00049 
00050 QString KTextBuffer::readLine()
00051 {
00052     QString line;
00053     if (!m_linebuf.isEmpty())
00054     {
00055         line = m_linebuf;
00056         m_linebuf = QString::null;
00057     }
00058     else
00059         line = m_stream.readLine();
00060     return line;
00061 }
00062 
00063 /*****************************
00064  * Various parsing functions *
00065  *****************************/
00066 
00067 // Extract a line from a KTextBuffer:
00068 //  '#' -> comments
00069 //  '\' -> line continue
00070 //  ':' or '|' -> line continue (LPRng)
00071 //
00072 // New entry is detected by a line which have first character different from
00073 // '#', '|', ':'. The line is then put back in the IODevice.
00074 QString readLine(KTextBuffer& t)
00075 {
00076     QString line, buffer;
00077     bool    lineContinue(false);
00078 
00079     while (!t.eof())
00080     {
00081         buffer = t.readLine().stripWhiteSpace();
00082         if (buffer.isEmpty() || buffer[0] == '#')
00083             continue;
00084         if (buffer[0] == '|' || buffer[0] == ':' || lineContinue || line.isEmpty())
00085         {
00086             line.append(buffer);
00087             if (line.right(1) == "\\")
00088             {
00089                 line.truncate(line.length()-1);
00090                 line = line.stripWhiteSpace();
00091                 lineContinue = true;
00092             }
00093             else
00094                 lineContinue = false;
00095         }
00096         else
00097         {
00098             t.unreadLine(buffer);
00099             break;
00100         }
00101     }
00102     return line;
00103 }
00104 
00105 // extact an entry (printcap-like)
00106 QMap<QString,QString> readEntry(KTextBuffer& t)
00107 {
00108     QString line = readLine(t);
00109     QMap<QString,QString>   entry;
00110 
00111     if (!line.isEmpty())
00112     {
00113         QStringList l = QStringList::split(':',line,false);
00114         if (l.count() > 0)
00115         {
00116             int     p(-1);
00117             if ((p=l[0].find('|')) != -1)
00118                 entry["printer-name"] = l[0].left(p);   // only keep first name (discard aliases
00119             else
00120                 entry["printer-name"] = l[0];
00121             for (uint i=1; i<l.count(); i++)
00122                 if ((p=l[i].find('=')) != -1)
00123                     entry[l[i].left(p).stripWhiteSpace()] = l[i].right(l[i].length()-p-1).stripWhiteSpace();
00124                 else
00125                     entry[l[i].stripWhiteSpace()] = QString::null;
00126         }
00127     }
00128     return entry;
00129 }
00130 
00131 // create basic printer from entry
00132 KMPrinter* createPrinter(const QMap<QString,QString>& entry)
00133 {
00134     KMPrinter   *printer = new KMPrinter();
00135     printer->setName(entry["printer-name"]);
00136     printer->setPrinterName(entry["printer-name"]);
00137     printer->setType(KMPrinter::Printer);
00138     printer->setState(KMPrinter::Idle);
00139     return printer;
00140 }
00141 KMPrinter* createPrinter(const QString& prname)
00142 {
00143     QMap<QString,QString>   map;
00144     map["printer-name"] = prname;
00145     return createPrinter(map);
00146 }
00147 
00148 // this function support LPRng piping feature, it defaults to
00149 // /etc/printcap in any other cases (basic support)
00150 QString getPrintcapFileName()
00151 {
00152     // check if LPRng system
00153     QString printcap("/etc/printcap");
00154     QFile   f("/etc/lpd.conf");
00155     if (f.exists() && f.open(IO_ReadOnly))
00156     {
00157         kdDebug() << "/etc/lpd.conf found: probably LPRng system" << endl;
00158         QTextStream t(&f);
00159         QString     line;
00160         while (!t.eof())
00161         {
00162             line = t.readLine().stripWhiteSpace();
00163             if (line.startsWith("printcap_path="))
00164             {
00165                 kdDebug() << "printcap_path entry found: " << line << endl;
00166                 QString pcentry = line.mid(14).stripWhiteSpace();
00167                 kdDebug() << "printcap_path value: " << pcentry << endl;
00168                 if (pcentry[0] == '|')
00169                 { // printcap through pipe
00170                     printcap = locateLocal("tmp","printcap");
00171                     QString cmd = QString::fromLatin1("echo \"all\" | %1 > %2").arg(pcentry.mid(1)).arg(printcap);
00172                     kdDebug() << "printcap obtained through pipe" << endl << "executing: " << cmd << endl;
00173                     ::system(cmd.local8Bit());
00174                 }
00175                 break;
00176             }
00177         }
00178     }
00179     kdDebug() << "printcap file returned: " << printcap << endl;
00180     return printcap;
00181 }
00182 
00183 // "/etc/printcap" file parsing (Linux/LPR)
00184 void KMLpdUnixManager::parseEtcPrintcap()
00185 {
00186     QFile   f(getPrintcapFileName());
00187     if (f.exists() && f.open(IO_ReadOnly))
00188     {
00189         KTextBuffer t(&f);
00190         QMap<QString,QString>   entry;
00191 
00192         while (!t.eof())
00193         {
00194             entry = readEntry(t);
00195             if (entry.isEmpty() || !entry.contains("printer-name") || entry.contains("server"))
00196                 continue;
00197             if (entry["printer-name"] == "all")
00198             {
00199                 if (entry.contains("all"))
00200                 {
00201                     // find separator
00202                     int p = entry["all"].find(QRegExp("[^a-zA-Z0-9_\\s-]"));
00203                     if (p != -1)
00204                     {
00205                         QChar   c = entry["all"][p];
00206                         QStringList prs = QStringList::split(c,entry["all"],false);
00207                         for (QStringList::ConstIterator it=prs.begin(); it!=prs.end(); ++it)
00208                         {
00209                             KMPrinter   *printer = ::createPrinter(*it);
00210                             printer->setDescription(i18n("Description unavailable"));
00211                             addPrinter(printer);
00212                         }
00213                     }
00214                 }
00215             }
00216             else
00217             {
00218                 KMPrinter   *printer = ::createPrinter(entry);
00219                 if (entry.contains("rm"))
00220                     printer->setDescription(i18n("Remote printer queue on %1").arg(entry["rm"]));
00221                 else
00222                     printer->setDescription(i18n("Local printer"));
00223                 addPrinter(printer);
00224             }
00225         }
00226     }
00227 }
00228 
00229 // helper function for NIS support in Solaris-2.6 (use "ypcat printers.conf.byname")
00230 QString getEtcPrintersConfName()
00231 {
00232     QString printersconf("/etc/printers.conf");
00233     if (!QFile::exists(printersconf) && !KStandardDirs::findExe( "ypcat" ).isEmpty())
00234     {
00235         // standard file not found, try NIS
00236         printersconf = locateLocal("tmp","printers.conf");
00237         QString cmd = QString::fromLatin1("ypcat printers.conf.byname > %1").arg(printersconf);
00238         kdDebug() << "printers.conf obtained from NIS server: " << cmd << endl;
00239         ::system(QFile::encodeName(cmd));
00240     }
00241     return printersconf;
00242 }
00243 
00244 // "/etc/printers.conf" file parsing (Solaris 2.6)
00245 void KMLpdUnixManager::parseEtcPrintersConf()
00246 {
00247     QFile   f(getEtcPrintersConfName());
00248     if (f.exists() && f.open(IO_ReadOnly))
00249     {
00250         KTextBuffer t(&f);
00251         QMap<QString,QString>   entry;
00252         QString     default_printer;
00253 
00254         while (!t.eof())
00255         {
00256             entry = readEntry(t);
00257             if (entry.isEmpty() || !entry.contains("printer-name"))
00258                 continue;
00259             QString prname = entry["printer-name"];
00260             if (prname == "_default")
00261             {
00262                 if (entry.contains("use"))
00263                     default_printer = entry["use"];
00264             }
00265             else if (prname != "_all")
00266             {
00267                 KMPrinter   *printer = ::createPrinter(entry);
00268                 if (entry.contains("bsdaddr"))
00269                 {
00270                     QStringList l = QStringList::split(',',entry["bsdaddr"],false);
00271                     printer->setDescription(i18n("Remote printer queue on %1").arg(l[0]));
00272                 }
00273                 else
00274                     printer->setDescription(i18n("Local printer"));
00275                 addPrinter(printer);
00276             }
00277         }
00278 
00279         if (!default_printer.isEmpty())
00280             setSoftDefault(findPrinter(default_printer));
00281     }
00282 }
00283 
00284 // "/etc/lp/printers/" directory parsing (Solaris non-2.6)
00285 void KMLpdUnixManager::parseEtcLpPrinters()
00286 {
00287     QDir    d("/etc/lp/printers");
00288     const QFileInfoList *prlist = d.entryInfoList(QDir::Dirs);
00289     if (!prlist)
00290         return;
00291 
00292     QFileInfoListIterator   it(*prlist);
00293     for (;it.current();++it)
00294     {
00295         if (it.current()->fileName() == "." || it.current()->fileName() == "..")
00296             continue;
00297         QFile   f(it.current()->absFilePath() + "/configuration");
00298         if (f.exists() && f.open(IO_ReadOnly))
00299         {
00300             KTextBuffer t(&f);
00301             QString     line, remote;
00302             while (!t.eof())
00303             {
00304                 line = readLine(t);
00305                 if (line.isEmpty()) continue;
00306                 if (line.startsWith("Remote:"))
00307                 {
00308                     QStringList l = QStringList::split(':',line,false);
00309                     if (l.count() > 1) remote = l[1];
00310                 }
00311             }
00312             KMPrinter   *printer = new KMPrinter;
00313             printer->setName(it.current()->fileName());
00314             printer->setPrinterName(it.current()->fileName());
00315             printer->setType(KMPrinter::Printer);
00316             printer->setState(KMPrinter::Idle);
00317             if (!remote.isEmpty())
00318                 printer->setDescription(i18n("Remote printer queue on %1").arg(remote));
00319             else
00320                 printer->setDescription(i18n("Local printer"));
00321             addPrinter(printer);
00322         }
00323     }
00324 }
00325 
00326 // "/etc/lp/member/" directory parsing (HP-UX)
00327 void KMLpdUnixManager::parseEtcLpMember()
00328 {
00329     QDir    d("/etc/lp/member");
00330     const QFileInfoList *prlist = d.entryInfoList(QDir::Files);
00331     if (!prlist)
00332         return;
00333 
00334     QFileInfoListIterator   it(*prlist);
00335     for (;it.current();++it)
00336     {
00337         KMPrinter   *printer = new KMPrinter;
00338         printer->setName(it.current()->fileName());
00339         printer->setPrinterName(it.current()->fileName());
00340         printer->setType(KMPrinter::Printer);
00341         printer->setState(KMPrinter::Idle);
00342         printer->setDescription(i18n("Local printer"));
00343         addPrinter(printer);
00344     }
00345 }
00346 
00347 // "/usr/spool/lp/interfaces/" directory parsing (IRIX 6.x)
00348 void KMLpdUnixManager::parseSpoolInterface()
00349 {
00350     QDir    d("/usr/spool/interfaces/lp");
00351     const QFileInfoList *prlist = d.entryInfoList(QDir::Files);
00352     if (!prlist)
00353         return;
00354 
00355     QFileInfoListIterator   it(*prlist);
00356     for (;it.current();++it)
00357     {
00358         QFile   f(it.current()->absFilePath());
00359         if (f.exists() && f.open(IO_ReadOnly))
00360         {
00361             KTextBuffer t(&f);
00362             QString     line, remote;
00363 
00364             while (!t.eof())
00365             {
00366                 line = t.readLine().stripWhiteSpace();
00367                 if (line.startsWith("HOSTNAME"))
00368                 {
00369                     QStringList l = QStringList::split('=',line,false);
00370                     if (l.count() > 1) remote = l[1];
00371                 }
00372             }
00373 
00374             KMPrinter   *printer = new KMPrinter;
00375             printer->setName(it.current()->fileName());
00376             printer->setPrinterName(it.current()->fileName());
00377             printer->setType(KMPrinter::Printer);
00378             printer->setState(KMPrinter::Idle);
00379             if (!remote.isEmpty())
00380                 printer->setDescription(i18n("Remote printer queue on %1").arg(remote));
00381             else
00382                 printer->setDescription(i18n("Local printer"));
00383             addPrinter(printer);
00384         }
00385     }
00386 }
00387 
00388 //*********************************************************************************************************
00389 
00390 KMLpdUnixManager::KMLpdUnixManager(QObject *parent, const char *name, const QStringList & /*args*/)
00391 : KMManager(parent,name)
00392 {
00393     m_loaded = false;
00394 }
00395 
00396 void KMLpdUnixManager::listPrinters()
00397 {
00398     // load only once, if already loaded, just keep them (remove discard flag)
00399     if (!m_loaded)
00400     {
00401         parseEtcPrintcap();
00402         parseEtcPrintersConf();
00403         parseEtcLpPrinters();
00404         parseEtcLpMember();
00405         parseSpoolInterface();
00406         m_loaded = true;
00407     }
00408     else
00409         discardAllPrinters(false);
00410 }
KDE Home | KDE Accessibility Home | Description of Access Keys