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 <tqfile.h> 00025 #include <tqdir.h> 00026 #include <tqfileinfo.h> 00027 #include <tqtextstream.h> 00028 #include <tqregexp.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(TQIODevice *dev) : m_stream(dev) {} 00042 bool eof() const { return (m_stream.eof() && m_linebuf.isEmpty()); } 00043 TQString readLine(); 00044 void unreadLine(const TQString& l) { m_linebuf = l; } 00045 private: 00046 TQTextStream m_stream; 00047 TQString m_linebuf; 00048 }; 00049 00050 TQString KTextBuffer::readLine() 00051 { 00052 TQString line; 00053 if (!m_linebuf.isEmpty()) 00054 { 00055 line = m_linebuf; 00056 m_linebuf = TQString::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 TQString readLine(KTextBuffer& t) 00075 { 00076 TQString 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 TQMap<TQString,TQString> readEntry(KTextBuffer& t) 00107 { 00108 TQString line = readLine(t); 00109 TQMap<TQString,TQString> entry; 00110 00111 if (!line.isEmpty()) 00112 { 00113 TQStringList l = TQStringList::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()] = TQString::null; 00126 } 00127 } 00128 return entry; 00129 } 00130 00131 // create basic printer from entry 00132 KMPrinter* createPrinter(const TQMap<TQString,TQString>& 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 TQString& prname) 00142 { 00143 TQMap<TQString,TQString> 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 TQString getPrintcapFileName() 00151 { 00152 // check if LPRng system 00153 TQString printcap("/etc/printcap"); 00154 TQFile f("/etc/lpd.conf"); 00155 if (f.exists() && f.open(IO_ReadOnly)) 00156 { 00157 kdDebug() << "/etc/lpd.conf found: probably LPRng system" << endl; 00158 TQTextStream t(&f); 00159 TQString 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 TQString 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 TQString cmd = TQString::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 TQFile f(getPrintcapFileName()); 00187 if (f.exists() && f.open(IO_ReadOnly)) 00188 { 00189 KTextBuffer t(TQT_TQIODEVICE(&f)); 00190 TQMap<TQString,TQString> 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(TQRegExp("[^a-zA-Z0-9_\\s-]")); 00203 if (p != -1) 00204 { 00205 TQChar c = entry["all"][p]; 00206 TQStringList prs = TQStringList::split(c,entry["all"],false); 00207 for (TQStringList::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 TQString getEtcPrintersConfName() 00231 { 00232 TQString printersconf("/etc/printers.conf"); 00233 if (!TQFile::exists(printersconf) && !KStandardDirs::findExe( "ypcat" ).isEmpty()) 00234 { 00235 // standard file not found, try NIS 00236 printersconf = locateLocal("tmp","printers.conf"); 00237 TQString cmd = TQString::fromLatin1("ypcat printers.conf.byname > %1").arg(printersconf); 00238 kdDebug() << "printers.conf obtained from NIS server: " << cmd << endl; 00239 ::system(TQFile::encodeName(cmd)); 00240 } 00241 return printersconf; 00242 } 00243 00244 // "/etc/printers.conf" file parsing (Solaris 2.6) 00245 void KMLpdUnixManager::parseEtcPrintersConf() 00246 { 00247 TQFile f(getEtcPrintersConfName()); 00248 if (f.exists() && f.open(IO_ReadOnly)) 00249 { 00250 KTextBuffer t(TQT_TQIODEVICE(&f)); 00251 TQMap<TQString,TQString> entry; 00252 TQString default_printer; 00253 00254 while (!t.eof()) 00255 { 00256 entry = readEntry(t); 00257 if (entry.isEmpty() || !entry.contains("printer-name")) 00258 continue; 00259 TQString 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 TQStringList l = TQStringList::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 TQDir d("/etc/lp/printers"); 00288 const TQFileInfoList *prlist = d.entryInfoList(TQDir::Dirs); 00289 if (!prlist) 00290 return; 00291 00292 TQFileInfoListIterator it(*prlist); 00293 for (;it.current();++it) 00294 { 00295 if (it.current()->fileName() == "." || it.current()->fileName() == "..") 00296 continue; 00297 TQFile f(it.current()->absFilePath() + "/configuration"); 00298 if (f.exists() && f.open(IO_ReadOnly)) 00299 { 00300 KTextBuffer t(TQT_TQIODEVICE(&f)); 00301 TQString line, remote; 00302 while (!t.eof()) 00303 { 00304 line = readLine(t); 00305 if (line.isEmpty()) continue; 00306 if (line.startsWith("Remote:")) 00307 { 00308 TQStringList l = TQStringList::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 TQDir d("/etc/lp/member"); 00330 const TQFileInfoList *prlist = d.entryInfoList(TQDir::Files); 00331 if (!prlist) 00332 return; 00333 00334 TQFileInfoListIterator 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 TQDir d("/usr/spool/interfaces/lp"); 00351 const TQFileInfoList *prlist = d.entryInfoList(TQDir::Files); 00352 if (!prlist) 00353 return; 00354 00355 TQFileInfoListIterator it(*prlist); 00356 for (;it.current();++it) 00357 { 00358 TQFile f(it.current()->absFilePath()); 00359 if (f.exists() && f.open(IO_ReadOnly)) 00360 { 00361 KTextBuffer t(TQT_TQIODEVICE(&f)); 00362 TQString line, remote; 00363 00364 while (!t.eof()) 00365 { 00366 line = t.readLine().stripWhiteSpace(); 00367 if (line.startsWith("HOSTNAME")) 00368 { 00369 TQStringList l = TQStringList::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(TQObject *parent, const char *name, const TQStringList & /*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 }