• 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 <tdestandarddirs.h>
37#include <tdeconfig.h>
38#include <tdeprocess.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
47TQString lpdprefix = "";
48TQString ptPrinterType(KMPrinter*);
49
50//************************************************************************************************
51
52KMLpdManager::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
62KMLpdManager::~KMLpdManager()
63{
64}
65
66TQString KMLpdManager::driverDbCreationProgram()
67{
68 return TQString::fromLatin1("make_driver_db_lpd");
69}
70
71TQString KMLpdManager::driverDirectory()
72{
73 return TQString::fromLatin1("/usr/lib/rhs/rhs-printfilters");
74}
75
76bool KMLpdManager::completePrinter(KMPrinter *printer)
77{
78 return completePrinterShort(printer);
79}
80
81bool KMLpdManager::completePrinterShort(KMPrinter *printer)
82{
83 PrintcapEntry *entry = m_entries.find(printer->name());
84 if (entry)
85 {
86 TQString 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
127bool 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
200bool 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
221bool KMLpdManager::enablePrinter(KMPrinter *printer, bool state)
222{
223 KPipeProcess proc;
224 TQString 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 TQString 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
249bool KMLpdManager::enablePrinter(KMPrinter *printer)
250{
251 return enablePrinter(printer,true);
252}
253
254bool KMLpdManager::disablePrinter(KMPrinter *printer)
255{
256 return enablePrinter(printer,false);
257}
258
259void 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
274TQString 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
287void KMLpdManager::checkStatus()
288{
289 KPipeProcess proc;
290 TQString cmd = programName(0) + " status all";
291 if (proc.open(cmd))
292 {
293 QTextStream t(&proc);
294 TQString 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
313bool 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
323void KMLpdManager::loadPrintcapFile(const TQString& filename)
324{
325 QFile f(filename);
326 if (f.exists() && f.open(IO_ReadOnly))
327 {
328 QTextStream t(&f);
329 TQString 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
351bool 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
366PrinttoolEntry* 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
376void 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
392DrMain* KMLpdManager::loadDbDriver(KMDBEntry *entry)
393{
394 TQString 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
407PrintcapEntry* 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
415DrMain* 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 TQString 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
446bool 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
458TQMap<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 TQString 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
488bool KMLpdManager::savePrinttoolCfgFile(const TQString& templatefile, const TQString& dirname, const TQMap<TQString,TQString>& options)
489{
490 // defines input and output file
491 TQString 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 TQString 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
524bool 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 TQString 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 TQString 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
565bool KMLpdManager::createPrinttoolEntry(KMPrinter *printer, PrintcapEntry *entry)
566{
567 KURL dev(printer->device());
568 TQString 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
617bool 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 TQString 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
634bool KMLpdManager::validateDbDriver(KMDBEntry *entry)
635{
636 PrinttoolEntry *ptentry = findPrinttoolEntry(entry->modelname);
637 return (ptentry && checkGsDriver(ptentry->m_gsdriver));
638}
639
640//************************************************************************************************
641
642TQString ptPrinterType(KMPrinter *p)
643{
644 TQString 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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeprint by doxygen 1.9.4
This website is maintained by Timothy Pearson.