• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeprint
 

tdeprint

  • tdeprint
  • lpd
kmlpdmanager.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 2001 Michael Goffioul <tdeprint@swing.be>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License version 2 as published by the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  **/
19 
20 #include "kmlpdmanager.h"
21 #include "kmprinter.h"
22 #include "kmdbentry.h"
23 #include "driver.h"
24 #include "kmfactory.h"
25 #include "lpdtools.h"
26 #include "gschecker.h"
27 #include "kpipeprocess.h"
28 
29 #include <tqfile.h>
30 #include <tqfileinfo.h>
31 #include <tqtextstream.h>
32 #include <tqmap.h>
33 #include <tqregexp.h>
34 
35 #include <tdelocale.h>
36 #include <kstandarddirs.h>
37 #include <tdeconfig.h>
38 #include <kprocess.h>
39 
40 #include <pwd.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <sys/stat.h>
44 
45 // only there to allow testing on my system. Should be removed
46 // when everything has proven to be working and stable
47 QString lpdprefix = "";
48 TQString ptPrinterType(KMPrinter*);
49 
50 //************************************************************************************************
51 
52 KMLpdManager::KMLpdManager(TQObject *parent, const char *name)
53 : KMManager(parent,name)
54 {
55  m_entries.setAutoDelete(true);
56  m_ptentries.setAutoDelete(true);
57  setHasManagement(getuid() == 0);
58  setPrinterOperationMask(KMManager::PrinterCreation|KMManager::PrinterConfigure|KMManager::PrinterRemoval|KMManager::PrinterEnabling);
59  m_gschecker = new GsChecker(this,"GsChecker");
60 }
61 
62 KMLpdManager::~KMLpdManager()
63 {
64 }
65 
66 TQString KMLpdManager::driverDbCreationProgram()
67 {
68  return TQString::fromLatin1("make_driver_db_lpd");
69 }
70 
71 TQString KMLpdManager::driverDirectory()
72 {
73  return TQString::fromLatin1("/usr/lib/rhs/rhs-printfilters");
74 }
75 
76 bool KMLpdManager::completePrinter(KMPrinter *printer)
77 {
78  return completePrinterShort(printer);
79 }
80 
81 bool KMLpdManager::completePrinterShort(KMPrinter *printer)
82 {
83  PrintcapEntry *entry = m_entries.find(printer->name());
84  if (entry)
85  {
86  QString type(entry->comment(2)), driver(entry->comment(7)), lp(entry->arg("lp"));
87  printer->setDescription(i18n("Local printer queue (%1)").arg(type.isEmpty() ? i18n("Unknown type of local printer queue", "Unknown") : type));
88  printer->setLocation(i18n("<Not available>"));
89  printer->setDriverInfo(driver.isEmpty() ? i18n("Unknown Driver", "Unknown") : driver);
90  // device
91  KURL url;
92  if (!entry->arg("rm").isEmpty())
93  {
94  url = TQString::fromLatin1("lpd://%1/%2").arg(entry->arg("rm")).arg(entry->arg("rp"));
95  printer->setDescription(i18n("Remote LPD queue %1@%2").arg(entry->arg("rp")).arg(entry->arg("rm")));
96  }
97  else if (!lp.isEmpty() && lp != "/dev/null")
98  url = TQString::fromLatin1("parallel:%1").arg(lp);
99  else if (TQFile::exists(entry->arg("sd")+"/.config"))
100  {
101  TQMap<TQString,TQString> map = loadPrinttoolCfgFile(entry->arg("sd")+"/.config");
102  if (type == "SMB")
103  {
104  QStringList l = TQStringList::split('\\',map["share"],false);
105  if (map["workgroup"].isEmpty())
106  url = TQString::fromLatin1("smb://%1/%2").arg(l[0]).arg(l[1]);
107  else
108  url = TQString::fromLatin1("smb://%1/%2/%3").arg(map["workgroup"]).arg(l[0]).arg(l[1]);
109  url.setUser(map["user"]);
110  url.setPass(map["password"]);
111  }
112  else if (type == "DIRECT")
113  url = TQString::fromLatin1("socket://%1:%2").arg(map["printer_ip"]).arg(map["port"]);
114  else if (type == "NCP")
115  {
116  url = TQString::fromLatin1("ncp://%1/%2").arg(map["server"]).arg(map["queue"]);
117  url.setUser(map["user"]);
118  url.setPass(map["password"]);
119  }
120  }
121  printer->setDevice(url);
122  return true;
123  }
124  else return false;
125 }
126 
127 bool KMLpdManager::createPrinter(KMPrinter *printer)
128 {
129  // 1) create the printcap entry
130  PrintcapEntry *ent = findPrintcapEntry(printer->printerName());
131  if (!ent)
132  {
133  ent = new PrintcapEntry();
134  ent->m_name = printer->printerName();
135  }
136  else
137  {
138  if (!printer->driver() && printer->option("kde-driver") != "raw")
139  printer->setDriver(loadPrinterDriver(printer,true));
140  // remove it from current entries
141  ent = m_entries.take(ent->m_name);
142  ent->m_args.clear();
143  }
144  // Standard options
145  if (printer->device().protocol() == "lpd")
146  {
147  // remote lpd queue
148  ent->m_args["rm"] = printer->device().host();
149  ent->m_args["rp"] = printer->device().path().replace("/",TQString::fromLatin1(""));
150  ent->m_args["lpd_bounce"] = "true";
151  ent->m_comment = TQString::fromLatin1("##PRINTTOOL3## REMOTE");
152  }
153  ent->m_args["mx"] = (printer->option("mx").isEmpty() ? "#0" : printer->option("mx"));
154  ent->m_args["sh"] = TQString::null;
155  // create spool directory (if necessary) and update PrintcapEntry object
156  if (!createSpooldir(ent))
157  {
158  setErrorMsg(i18n("Unable to create spool directory %1 for printer %2.").arg(ent->arg("sd")).arg(ent->m_name));
159  delete ent;
160  return false;
161  }
162  if (!printer->driver() || printer->driver()->get("drtype") == "printtool")
163  if (!createPrinttoolEntry(printer,ent))
164  {
165  setErrorMsg(i18n("Unable to save information for printer <b>%1</b>.").arg(printer->printerName()));
166  delete ent;
167  return false;
168  }
169 
170  // 2) write the printcap file
171  m_entries.insert(ent->m_name,ent);
172  if (!writePrinters())
173  return false;
174 
175  // 3) save the printer driver (if any)
176  if (printer->driver())
177  {
178  if (!savePrinterDriver(printer,printer->driver()))
179  {
180  m_entries.remove(ent->m_name);
181  writePrinters();
182  return false;
183  }
184  }
185 
186  // 4) change permissions of spool directory
187  TQCString cmd = "chmod -R o-rwx,g+rwX ";
188  cmd += TQFile::encodeName(TDEProcess::quote(ent->arg("sd")));
189  cmd += "&& chown -R lp.lp ";
190  cmd += TQFile::encodeName(TDEProcess::quote(ent->arg("sd")));
191  if (system(cmd.data()) != 0)
192  {
193  setErrorMsg(i18n("Unable to set correct permissions on spool directory %1 for printer <b>%2</b>.").arg(ent->arg("sd")).arg(ent->m_name));
194  return false;
195  }
196 
197  return true;
198 }
199 
200 bool KMLpdManager::removePrinter(KMPrinter *printer)
201 {
202  PrintcapEntry *ent = findPrintcapEntry(printer->printerName());
203  if (ent)
204  {
205  ent = m_entries.take(printer->printerName());
206  if (!writePrinters())
207  {
208  m_entries.insert(ent->m_name,ent);
209  return false;
210  }
211  TQCString cmd = "rm -rf ";
212  cmd += TQFile::encodeName(TDEProcess::quote(ent->arg("sd")));
213  system(cmd.data());
214  delete ent;
215  return true;
216  }
217  else
218  return false;
219 }
220 
221 bool KMLpdManager::enablePrinter(KMPrinter *printer, bool state)
222 {
223  KPipeProcess proc;
224  QString cmd = programName(0);
225  cmd += " ";
226  cmd += state ? "up" : "down";
227  cmd += " ";
228  cmd += TDEProcess::quote(printer->printerName());
229  if (proc.open(cmd))
230  {
231  QTextStream t(&proc);
232  QString buffer;
233  while (!t.eof())
234  buffer.append(t.readLine());
235  if (buffer.startsWith("?Privilege"))
236  {
237  setErrorMsg(i18n("Permission denied: you must be root."));
238  return false;
239  }
240  return true;
241  }
242  else
243  {
244  setErrorMsg(i18n("Unable to execute command \"%1\".").arg(cmd));
245  return false;
246  }
247 }
248 
249 bool KMLpdManager::enablePrinter(KMPrinter *printer)
250 {
251  return enablePrinter(printer,true);
252 }
253 
254 bool KMLpdManager::disablePrinter(KMPrinter *printer)
255 {
256  return enablePrinter(printer,false);
257 }
258 
259 void KMLpdManager::listPrinters()
260 {
261  m_entries.clear();
262  loadPrintcapFile(TQString::fromLatin1("%1/etc/printcap").arg(lpdprefix));
263 
264  TQDictIterator<PrintcapEntry> it(m_entries);
265  for (;it.current();++it)
266  {
267  KMPrinter *printer = it.current()->createPrinter();
268  addPrinter(printer);
269  }
270 
271  checkStatus();
272 }
273 
274 TQString KMLpdManager::programName(int f)
275 {
276  TDEConfig *conf = KMFactory::self()->printConfig();
277  conf->setGroup("LPD");
278  switch (f)
279  {
280  case 0: return conf->readPathEntry("LpdCommand","/usr/sbin/lpc");
281  case 1: return conf->readPathEntry("LpdQueue","lpq");
282  case 2: return conf->readPathEntry("LpdRemove","lprm");
283  }
284  return TQString::null;
285 }
286 
287 void KMLpdManager::checkStatus()
288 {
289  KPipeProcess proc;
290  QString cmd = programName(0) + " status all";
291  if (proc.open(cmd))
292  {
293  QTextStream t(&proc);
294  QString line;
295  KMPrinter *printer(0);
296  int p(-1);
297  while (!t.eof())
298  {
299  line = t.readLine().stripWhiteSpace();
300  if (line.isEmpty())
301  continue;
302  if ((p=line.find(':')) != -1)
303  printer = findPrinter(line.left(p));
304  else if (line.startsWith("printing") && printer)
305  printer->setState(line.find("enabled") != -1 ? KMPrinter::Idle : KMPrinter::Stopped);
306  else if (line.find("entries") != -1 && printer)
307  if (!line.startsWith("no") && printer->state() == KMPrinter::Idle)
308  printer->setState(KMPrinter::Processing);
309  }
310  }
311 }
312 
313 bool KMLpdManager::writePrinters()
314 {
315  if (!writePrintcapFile(TQString::fromLatin1("%1/etc/printcap").arg(lpdprefix)))
316  {
317  setErrorMsg(i18n("Unable to write printcap file."));
318  return false;
319  }
320  return true;
321 }
322 
323 void KMLpdManager::loadPrintcapFile(const TQString& filename)
324 {
325  QFile f(filename);
326  if (f.exists() && f.open(IO_ReadOnly))
327  {
328  QTextStream t(&f);
329  QString line, comment;
330  PrintcapEntry *entry;
331  while (!t.eof())
332  {
333  line = getPrintcapLine(t,&comment);
334  if (line.isEmpty())
335  continue;
336  entry = new PrintcapEntry;
337  if (entry->readLine(line))
338  {
339  m_entries.insert(entry->m_name,entry);
340  entry->m_comment = comment;
341  }
342  else
343  {
344  delete entry;
345  break;
346  }
347  }
348  }
349 }
350 
351 bool KMLpdManager::writePrintcapFile(const TQString& filename)
352 {
353  QFile f(filename);
354  if (f.open(IO_WriteOnly))
355  {
356  QTextStream t(&f);
357  t << "# File generated by TDE print (LPD plugin).\n#Don't edit by hand." << endl << endl;
358  TQDictIterator<PrintcapEntry> it(m_entries);
359  for (;it.current();++it)
360  it.current()->writeEntry(t);
361  return true;
362  }
363  return false;
364 }
365 
366 PrinttoolEntry* KMLpdManager::findPrinttoolEntry(const TQString& name)
367 {
368  if (m_ptentries.count() == 0)
369  loadPrinttoolDb(driverDirectory()+"/printerdb");
370  PrinttoolEntry *ent = m_ptentries.find(name);
371  if (!ent)
372  setErrorMsg(i18n("Couldn't find driver <b>%1</b> in printtool database.").arg(name));
373  return ent;
374 }
375 
376 void KMLpdManager::loadPrinttoolDb(const TQString& filename)
377 {
378  QFile f(filename);
379  if (f.exists() && f.open(IO_ReadOnly))
380  {
381  QTextStream t(&f);
382  PrinttoolEntry *entry = new PrinttoolEntry;
383  while (entry->readEntry(t))
384  {
385  m_ptentries.insert(entry->m_name,entry);
386  entry = new PrinttoolEntry;
387  }
388  delete entry;
389  }
390 }
391 
392 DrMain* KMLpdManager::loadDbDriver(KMDBEntry *entry)
393 {
394  QString ptdbfilename = driverDirectory() + "/printerdb";
395  if (entry->file == ptdbfilename)
396  {
397  PrinttoolEntry *ptentry = findPrinttoolEntry(entry->modelname);
398  if (ptentry)
399  {
400  DrMain *dr = ptentry->createDriver();
401  return dr;
402  }
403  }
404  return NULL;
405 }
406 
407 PrintcapEntry* KMLpdManager::findPrintcapEntry(const TQString& name)
408 {
409  PrintcapEntry *ent = m_entries.find(name);
410  if (!ent)
411  setErrorMsg(i18n("Couldn't find printer <b>%1</b> in printcap file.").arg(name));
412  return ent;
413 }
414 
415 DrMain* KMLpdManager::loadPrinterDriver(KMPrinter *printer, bool config)
416 {
417  PrintcapEntry *entry = findPrintcapEntry(printer->name());
418  if (!entry)
419  return NULL;
420 
421  // check for printtool driver (only for configuration)
422  QString sd = entry->arg("sd"), dr(entry->comment(7));
423  if (TQFile::exists(sd+"/postscript.cfg") && config && !dr.isEmpty())
424  {
425  TQMap<TQString,TQString> map = loadPrinttoolCfgFile(sd+"/postscript.cfg");
426  PrinttoolEntry *ptentry = findPrinttoolEntry(dr);
427  if (!ptentry)
428  return NULL;
429  DrMain *dr = ptentry->createDriver();
430  dr->setOptions(map);
431  map = loadPrinttoolCfgFile(sd+"/general.cfg");
432  dr->setOptions(map);
433  map = loadPrinttoolCfgFile(sd+"/textonly.cfg");
434  dr->setOptions(map);
435  return dr;
436  }
437 
438  // default
439  if (entry->m_comment.startsWith("##PRINTTOOL3##"))
440  setErrorMsg(i18n("No driver found (raw printer)"));
441  else
442  setErrorMsg(i18n("Printer type not recognized."));
443  return NULL;
444 }
445 
446 bool KMLpdManager::checkGsDriver(const TQString& gsdriver)
447 {
448  if (gsdriver == "ppa" || gsdriver == "POSTSCRIPT" || gsdriver == "TEXT")
449  return true;
450  else if (!m_gschecker->checkGsDriver(gsdriver))
451  {
452  setErrorMsg(i18n("The driver device <b>%1</b> is not compiled in your GhostScript distribution. Check your installation or use another driver.").arg(gsdriver));
453  return false;
454  }
455  return true;
456 }
457 
458 TQMap<TQString,TQString> KMLpdManager::loadPrinttoolCfgFile(const TQString& filename)
459 {
460  QFile f(filename);
461  TQMap<TQString,TQString> map;
462  if (f.exists() && f.open(IO_ReadOnly))
463  {
464  QTextStream t(&f);
465  QString line, name, val;
466  int p(-1);
467  while (!t.eof())
468  {
469  line = getPrintcapLine(t);
470  if (line.isEmpty())
471  break;
472  if (line.startsWith("export "))
473  line.replace(0,7,"");
474  if ((p=line.find('=')) != -1)
475  {
476  name = line.left(p);
477  val = line.right(line.length()-p-1);
478  val.replace("\"","");
479  val.replace("'","");
480  if (!name.isEmpty() && !val.isEmpty())
481  map[name] = val;
482  }
483  }
484  }
485  return map;
486 }
487 
488 bool KMLpdManager::savePrinttoolCfgFile(const TQString& templatefile, const TQString& dirname, const TQMap<TQString,TQString>& options)
489 {
490  // defines input and output file
491  QString fname = TQFileInfo(templatefile).fileName();
492  fname.replace(TQRegExp("\\.in$"),TQString::fromLatin1(""));
493  QFile fin(templatefile);
494  QFile fout(dirname + "/" + fname);
495  if (fin.exists() && fin.open(IO_ReadOnly) && fout.open(IO_WriteOnly))
496  {
497  QTextStream tin(&fin), tout(&fout);
498  QString line, name;
499  int p(-1);
500  while (!tin.eof())
501  {
502  line = tin.readLine().stripWhiteSpace();
503  if (line.isEmpty() || line[0] == '#')
504  {
505  tout << line << endl;
506  continue;
507  }
508  if (line.startsWith("export "))
509  {
510  tout << "export ";
511  line.replace(0,7,TQString::fromLatin1(""));
512  }
513  if ((p=line.find('=')) != -1)
514  {
515  name = line.left(p);
516  tout << name << '=' << options[name] << endl;
517  }
518  }
519  return true;
520  }
521  else return false;
522 }
523 
524 bool KMLpdManager::savePrinterDriver(KMPrinter *printer, DrMain *driver)
525 {
526  // To be able to save a printer driver, a printcap entry MUST exist.
527  // We can then retrieve the spool directory from it.
528  QString spooldir;
529  PrintcapEntry *ent = findPrintcapEntry(printer->printerName());
530  if (!ent)
531  return false;
532  spooldir = ent->arg("sd");
533 
534  if (driver->get("drtype") == "printtool" && !spooldir.isEmpty())
535  {
536  TQMap<TQString,TQString> options;
537  driver->getOptions(options,true);
538  // add some standard options
539  options["DESIRED_TO"] = "ps";
540  options["PRINTER_TYPE"] = ent->comment(2); // get type from printcap entry (works in anycases)
541  options["PS_SEND_EOF"] = "NO";
542  if (!checkGsDriver(options["GSDEVICE"]))
543  return false;
544  QString resol(options["RESOLUTION"]), color(options["COLOR"]);
545  // update entry comment to make printtool happy and save printcap file
546  ent->m_comment = TQString::fromLatin1("##PRINTTOOL3## %1 %2 %3 %4 {} {%5} %6 {}").arg(options["PRINTER_TYPE"]).arg(options["GSDEVICE"]).arg((resol.isEmpty() ? TQString::fromLatin1("NAxNA") : resol)).arg(options["PAPERSIZE"]).arg(driver->name()).arg((color.isEmpty() ? TQString::fromLatin1("Default") : color.right(color.length()-15)));
547  ent->m_args["if"] = spooldir+TQString::fromLatin1("/filter");
548  if (!writePrinters())
549  return false;
550  // write various driver files using templates
551  TQCString cmd = "cp ";
552  cmd += TQFile::encodeName(TDEProcess::quote(driverDirectory()+"/master-filter"));
553  cmd += " ";
554  cmd += TQFile::encodeName(TDEProcess::quote(spooldir + "/filter"));
555  if (system(cmd.data()) == 0 &&
556  savePrinttoolCfgFile(driverDirectory()+"/general.cfg.in",spooldir,options) &&
557  savePrinttoolCfgFile(driverDirectory()+"/postscript.cfg.in",spooldir,options) &&
558  savePrinttoolCfgFile(driverDirectory()+"/textonly.cfg.in",spooldir,options))
559  return true;
560  setErrorMsg(i18n("Unable to write driver associated files in spool directory."));
561  }
562  return false;
563 }
564 
565 bool KMLpdManager::createPrinttoolEntry(KMPrinter *printer, PrintcapEntry *entry)
566 {
567  KURL dev(printer->device());
568  QString prot = dev.protocol(), sd(entry->arg("sd"));
569  entry->m_comment = TQString::fromLatin1("##PRINTTOOL3## %1").arg(ptPrinterType(printer));
570  if (prot == "smb" || prot == "ncp" || prot == "socket")
571  {
572  entry->m_args["af"] = sd+TQString::fromLatin1("/acct");
573  QFile f(sd+TQString::fromLatin1("/.config"));
574  if (f.open(IO_WriteOnly))
575  {
576  QTextStream t(&f);
577  if (prot == "socket")
578  {
579  t << "printer_ip=" << dev.host() << endl;
580  t << "port=" << dev.port() << endl;
581  entry->m_args["if"] = driverDirectory()+TQString::fromLatin1("/directprint");
582  }
583  else if (prot == "smb")
584  {
585  QStringList l = TQStringList::split('/',dev.path(),false);
586  if (l.count() == 2)
587  {
588  t << "share='\\\\" << l[0] << '\\' << l[1] << '\'' << endl;
589  }
590  else if (l.count() == 1)
591  {
592  t << "share='\\\\" << dev.host() << '\\' << l[0] << '\'' << endl;
593  }
594  t << "hostip=" << endl;
595  t << "user='" << dev.user() << '\'' << endl;
596  t << "password='" << dev.pass() << '\'' << endl;
597  t << "workgroup='" << (l.count() == 2 ? dev.host() : TQString::fromLatin1("")) << '\'' << endl;
598  entry->m_args["if"] = driverDirectory()+TQString::fromLatin1("/smbprint");
599  }
600  else if (prot == "ncp")
601  {
602  t << "server=" << dev.host() << endl;
603  t << "queue=" << dev.path().replace("/",TQString::fromLatin1("")) << endl;
604  t << "user=" << dev.user() << endl;
605  t << "password=" << dev.pass() << endl;
606  entry->m_args["if"] = driverDirectory()+TQString::fromLatin1("/ncpprint");
607  }
608  }
609  else return false;
610  entry->m_args["lp"] = TQString::fromLatin1("/dev/null");
611  }
612  else if (prot != "lpd")
613  entry->m_args["lp"] = dev.path();
614  return true;
615 }
616 
617 bool KMLpdManager::createSpooldir(PrintcapEntry *entry)
618 {
619  // first check if it has a "sd" defined
620  if (entry->arg("sd").isEmpty())
621  entry->m_args["sd"] = TQString::fromLatin1("/var/spool/lpd/")+entry->m_name;
622  QString sd = entry->arg("sd");
623  if (!TDEStandardDirs::exists(sd))
624  {
625  if (!TDEStandardDirs::makeDir(sd,0750))
626  return false;
627  struct passwd *lp_pw = getpwnam("lp");
628  if (lp_pw && chown(TQFile::encodeName(sd),lp_pw->pw_uid,lp_pw->pw_gid) != 0)
629  return false;
630  }
631  return true;
632 }
633 
634 bool KMLpdManager::validateDbDriver(KMDBEntry *entry)
635 {
636  PrinttoolEntry *ptentry = findPrinttoolEntry(entry->modelname);
637  return (ptentry && checkGsDriver(ptentry->m_gsdriver));
638 }
639 
640 //************************************************************************************************
641 
642 TQString ptPrinterType(KMPrinter *p)
643 {
644  QString type, prot = p->device().protocol();
645  if (prot == "lpd") type = "REMOTE";
646  else if (prot == "smb") type = "SMB";
647  else if (prot == "ncp") type = "NCP";
648  else if (prot == "socket") type = "DIRECT";
649  else type = "LOCAL";
650  return type;
651 }

tdeprint

Skip menu "tdeprint"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tdeprint

Skip menu "tdeprint"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeprint by doxygen 1.8.8
This website is maintained by Timothy Pearson.