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

tdeprint

  • tdeprint
  • cups
kmcupsmanager.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 <config.h>
21
22#include "kmcupsmanager.h"
23#include "kmprinter.h"
24#include "ipprequest.h"
25#include "cupsinfos.h"
26#include "driver.h"
27#include "kmfactory.h"
28#include "kmdbentry.h"
29#include "cupsaddsmb2.h"
30#include "ippreportdlg.h"
31#include "kpipeprocess.h"
32#include "util.h"
33#include "foomatic2loader.h"
34#include "ppdloader.h"
35
36#include <tqfile.h>
37#include <tqtextstream.h>
38#include <tqregexp.h>
39#include <tqtimer.h>
40#include <tqsocket.h>
41#include <tqdatetime.h>
42
43#include <kdebug.h>
44#include <tdeapplication.h>
45#include <tdelocale.h>
46#include <tdeconfig.h>
47#include <tdestandarddirs.h>
48#include <tdesocketbase.h>
49#include <klibloader.h>
50#include <tdemessagebox.h>
51#include <tdeaction.h>
52#include <kdialogbase.h>
53#include <kextendedsocket.h>
54#include <tdeprocess.h>
55#include <kbufferedsocket.h>
56#include <kfilterdev.h>
57#include <cups/cups.h>
58#include <cups/ppd.h>
59#include <math.h>
60
61#define ppdi18n(s) i18n(TQString::fromLocal8Bit(s).utf8())
62
63static void extractMaticData(TQString& buf, const TQString& filename);
64static TQString printerURI(KMPrinter *p, bool useExistingURI);
65static TQString downloadDriver(KMPrinter *p);
66
67static int trials = 5;
68
69//*****************************************************************************************************
70
71 KMCupsManager::KMCupsManager(TQObject *parent, const char *name, const TQStringList & /*args*/)
72: KMManager(parent,name)
73{
74 // be sure to create the CupsInfos object -> password
75 // management is handled correctly.
76 CupsInfos::self();
77 m_cupsdconf = 0;
78 m_currentprinter = 0;
79 m_socket = 0;
80
81 setHasManagement(true);
82 setPrinterOperationMask(KMManager::PrinterAll);
83 setServerOperationMask(KMManager::ServerAll);
84
85 // change LANG variable so that CUPS is always using
86 // english language: translation may only come from the PPD
87 // itself, or from KDE.
88 setenv("LANG", "en_US.UTF-8", 1);
89}
90
91KMCupsManager::~KMCupsManager()
92{
93 delete m_socket;
94}
95
96TQString KMCupsManager::driverDbCreationProgram()
97{
98 return TQString(__TDE_BINDIR).append(TQString::fromLatin1("/make_driver_db_cups"));
99}
100
101TQString KMCupsManager::driverDirectory()
102{
103 TQString d = cupsInstallDir();
104 if (d.isEmpty()) {
105#if defined(__OpenBSD__) || defined(__FreeBSD__)
106 d = "/usr/local";
107#else
108 d = "/usr";
109#endif
110 }
111 d.append("/share/cups/model");
112 // raw foomatic support
113#if defined(__OpenBSD__) || defined(__FreeBSD__)
114 d.append(":/usr/local/share/foomatic/db/source");
115#else
116 d.append(":/usr/share/foomatic/db/source");
117 // compressed foomatic support
118 d.append(":/usr/lib/cups/driver/foomatic-db-compressed-ppds");
119#endif
120 return d;
121}
122
123TQString KMCupsManager::cupsInstallDir()
124{
125 TDEConfig *conf= KMFactory::self()->printConfig();
126 conf->setGroup("CUPS");
127 TQString dir = conf->readPathEntry("InstallDir");
128 return dir;
129}
130
131void KMCupsManager::reportIppError(IppRequest *req)
132{
133 setErrorMsg(req->statusMessage());
134}
135
136bool KMCupsManager::createPrinter(KMPrinter *p)
137{
138 bool isclass = p->isClass(false), result(false);
139 IppRequest req;
140 TQString uri;
141
142 uri = printerURI(p,false);
143 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
144 // needed to avoid problems when changing printer name
145 p->setUri(KURL(uri));
146
147 if (isclass)
148 {
149 req.setOperation(CUPS_ADD_CLASS);
150 TQStringList members = p->members(), uris;
151 TQString s;
152 s = TQString::fromLocal8Bit("ipp://%1/printers/").arg(CupsInfos::self()->hostaddr());
153 for (TQStringList::ConstIterator it=members.begin(); it!=members.end(); ++it)
154 uris.append(s+(*it));
155 req.addURI(IPP_TAG_PRINTER,"member-uris",uris);
156 }
157 else
158 {
159 req.setOperation(CUPS_ADD_PRINTER);
160 // only set the device-uri if needed, otherwise you may loose authentification
161 // data (login/password in URI's like smb or ipp).
162 KMPrinter *otherP = findPrinter(p->printerName());
163 if (!otherP || otherP->device() != p->device())
164 {
170 req.addURI(IPP_TAG_PRINTER,"device-uri",p->device());
171 }
172 if (!p->option("kde-banners").isEmpty())
173 {
174 TQStringList bans = TQStringList::split(',',p->option("kde-banners"),false);
175 while (bans.count() < 2)
176 bans.append("none");
177 req.addName(IPP_TAG_PRINTER,"job-sheets-default",bans);
178 }
179 req.addInteger(IPP_TAG_PRINTER,"job-quota-period",p->option("job-quota-period").toInt());
180 req.addInteger(IPP_TAG_PRINTER,"job-k-limit",p->option("job-k-limit").toInt());
181 req.addInteger(IPP_TAG_PRINTER,"job-page-limit",p->option("job-page-limit").toInt());
182 if (!p->option("requesting-user-name-denied").isEmpty())
183 req.addName(IPP_TAG_PRINTER,"requesting-user-name-denied",TQStringList::split(",",p->option("requesting-user-name-denied"),false));
184 else if (!p->option("requesting-user-name-allowed").isEmpty())
185 req.addName(IPP_TAG_PRINTER,"requesting-user-name-allowed",TQStringList::split(",",p->option("requesting-user-name-allowed"),false));
186 else
187 req.addName(IPP_TAG_PRINTER,"requesting-user-name-allowed",TQString::fromLatin1("all"));
188 }
189 req.addText(IPP_TAG_PRINTER,"printer-info",p->description());
190 req.addText(IPP_TAG_PRINTER,"printer-location",p->location());
191
192 if (req.doRequest("/admin/"))
193 {
194 result = true;
195 if (p->driver())
196 result = savePrinterDriver(p,p->driver());
197 if (result)
198 upPrinter(p, true);
199 }
200 else reportIppError(&req);
201
202 return result;
203}
204
205bool KMCupsManager::removePrinter(KMPrinter *p)
206{
207 bool result = setPrinterState(p,CUPS_DELETE_PRINTER);
208 return result;
209}
210
211bool KMCupsManager::enablePrinter(KMPrinter *p, bool state)
212{
213 return setPrinterState(p, (state ? CUPS_ACCEPT_JOBS : CUPS_REJECT_JOBS));
214}
215
216bool KMCupsManager::startPrinter(KMPrinter *p, bool state)
217{
218 return setPrinterState(p, (state ? IPP_RESUME_PRINTER : IPP_PAUSE_PRINTER));
219}
220
221bool KMCupsManager::setDefaultPrinter(KMPrinter *p)
222{
223 return setPrinterState(p,CUPS_SET_DEFAULT);
224}
225
226bool KMCupsManager::setPrinterState(KMPrinter *p, int state)
227{
228 IppRequest req;
229 TQString uri;
230
231 req.setOperation(state);
232 uri = printerURI(p, true);
233 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
234 if (req.doRequest("/admin/"))
235 return true;
236 reportIppError(&req);
237 return false;
238}
239
240bool KMCupsManager::completePrinter(KMPrinter *p)
241{
242 if (completePrinterShort(p))
243 {
244 // driver informations
245 TQString ppdname = downloadDriver(p);
246 ppd_file_t *ppd = (ppdname.isEmpty() ? NULL : ppdOpenFile(ppdname.local8Bit()));
247 if (ppd)
248 {
249 KMDBEntry entry;
250 // use the validation mechanism of KMDBEntry to
251 // fill possible missing entries like manufacturer
252 // or model.
253 entry.manufacturer = ppd->manufacturer;
254 entry.model = ppd->shortnickname;
255 entry.modelname = ppd->modelname;
256 // do not check the driver regarding the manager
257 entry.validate(false);
258 // update the KMPrinter object
259 p->setManufacturer(entry.manufacturer);
260 p->setModel(entry.model);
261 p->setDriverInfo(TQString::fromLocal8Bit(ppd->nickname));
262 ppdClose(ppd);
263 }
264 if (!ppdname.isEmpty())
265 TQFile::remove(ppdname);
266
267 return true;
268 }
269 return false;
270}
271
272bool KMCupsManager::completePrinterShort(KMPrinter *p)
273{
274 IppRequest req;
275 TQStringList keys;
276 TQString uri;
277
278 req.setOperation(IPP_GET_PRINTER_ATTRIBUTES);
279 uri = printerURI(p, true);
280 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
281
282 /*
283 // change host and port for remote stuffs
284 if (!p->uri().isEmpty())
285 {
286 // THIS IS AN UGLY HACK!! FIXME
287 // This attempts a "pre-connection" to see if the host is
288 // actually reachable. It times out after 2 seconds at most,
289 // preventing application freezes.
290 m_hostSuccess = false;
291 m_lookupDone = false;
292 // Give 2 seconds to connect to the printer, or abort
293 KExtendedSocket *kes = new KExtendedSocket(p->uri().host(),
294 p->uri().port());
295 connect(kes, TQ_SIGNAL(connectionSuccess()), this, TQ_SLOT(hostPingSlot()));
296 connect(kes, TQ_SIGNAL(connectionFailed(int)), this, TQ_SLOT(hostPingFailedSlot()));
297 if (kes->startAsyncConnect() != 0) {
298 delete kes;
299 m_hostSuccess = false;
300 } else {
301 TQDateTime tm = TQDateTime::currentDateTime().addSecs(2);
302 while (!m_lookupDone && (TQDateTime::currentDateTime() < tm))
303 tqApp->processEvents();
304
305 kes->cancelAsyncConnect();
306
307 delete kes;
308
309 if (!m_lookupDone)
310 m_hostSuccess = false;
311 }
312
313 if (m_hostSuccess == true) {
314 req.setHost(p->uri().host());
315 req.setPort(p->uri().port());
316 }
317 }
318 */
319
320 // disable location as it has been transferred to listing (for filtering)
321 //keys.append("printer-location");
322 keys.append("printer-info");
323 keys.append("printer-make-and-model");
324 keys.append("job-sheets-default");
325 keys.append("job-sheets-supported");
326 keys.append("job-quota-period");
327 keys.append("job-k-limit");
328 keys.append("job-page-limit");
329 keys.append("requesting-user-name-allowed");
330 keys.append("requesting-user-name-denied");
331 if (p->isClass(true))
332 {
333 keys.append("member-uris");
334 keys.append("member-names");
335 }
336 else
337 keys.append("device-uri");
338 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys);
339
340 if (req.doRequest("/printers/"))
341 {
342 TQString value;
343 if (req.text("printer-info",value)) p->setDescription(value);
344 // disabled location
345 //if (req.text("printer-location",value)) p->setLocation(value);
346 if (req.text("printer-make-and-model",value)) p->setDriverInfo(value);
347 if (req.uri("device-uri",value))
348 {
353 p->setDevice( value );
354 }
355 TQStringList values;
356 /* if (req.uri("member-uris",values))
357 {
358 TQStringList members;
359 for (TQStringList::ConstIterator it=values.begin(); it!=values.end(); ++it)
360 {
361 int p = (*it).findRev('/');
362 if (p != -1)
363 members.append((*it).right((*it).length()-p-1));
364 }
365 p->setMembers(members);
366 }*/
367 if (req.name("member-names",values))
368 p->setMembers(values);
369 // banners
370 req.name("job-sheets-default",values);
371 while (values.count() < 2) values.append("none");
372 p->setOption("kde-banners",values.join(TQString::fromLatin1(",")));
373 if (req.name("job-sheets-supported",values)) p->setOption("kde-banners-supported",values.join(TQString::fromLatin1(",")));
374
375 // quotas
376 int ival;
377 if (req.integer("job-quota-period",ival)) p->setOption("job-quota-period",TQString::number(ival));
378 if (req.integer("job-k-limit",ival)) p->setOption("job-k-limit",TQString::number(ival));
379 if (req.integer("job-page-limit",ival)) p->setOption("job-page-limit",TQString::number(ival));
380
381 // access permissions (allow and deny are mutually exclusives)
382 if (req.name("requesting-user-name-allowed",values) && values.count() > 0)
383 {
384 p->removeOption("requesting-user-name-denied");
385 p->setOption("requesting-user-name-allowed",values.join(","));
386 }
387 if (req.name("requesting-user-name-denied",values) && values.count() > 0)
388 {
389 p->removeOption("requesting-user-name-allowed");
390 p->setOption("requesting-user-name-denied",values.join(","));
391 }
392
393 return true;
394 }
395
396 reportIppError(&req);
397 return false;
398}
399
400bool KMCupsManager::testPrinter(KMPrinter *p)
401{
402 return KMManager::testPrinter(p);
403 /*
404 TQString testpage = testPage();
405 if (testpage.isEmpty())
406 {
407 setErrorMsg(i18n("Unable to locate test page."));
408 return false;
409 }
410
411 IppRequest req;
412 TQString uri;
413
414 req.setOperation(IPP_PRINT_JOB);
415 uri = printerURI(p);
416 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
417 req.addMime(IPP_TAG_OPERATION,"document-format","application/postscript");
418 if (!CupsInfos::self()->login().isEmpty()) req.addName(IPP_TAG_OPERATION,"requesting-user-name",CupsInfos::self()->login());
419 req.addName(IPP_TAG_OPERATION,"job-name",TQString::fromLatin1("TDE Print Test"));
420 if (req.doFileRequest("/printers/",testpage))
421 return true;
422 reportIppError(&req);
423 return false;
424 */
425}
426
427void KMCupsManager::listPrinters()
428{
429 loadServerPrinters();
430}
431
432void KMCupsManager::loadServerPrinters()
433{
434 IppRequest req;
435 TQStringList keys;
436
437 // get printers
438 req.setOperation(CUPS_GET_PRINTERS);
439 keys.append("printer-name");
440 keys.append("printer-type");
441 keys.append("printer-state");
442 // location needed for filtering
443 keys.append("printer-location");
444 keys.append("printer-uri-supported");
445 keys.append("printer-is-accepting-jobs");
446 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys);
447
448 // filtering by username (hides printers user doesn't have allowance to use)
449 req.addName(IPP_TAG_OPERATION, "requesting-user-name", TQString(cupsUser()));
450
451 if (req.doRequest("/printers/"))
452 {
453 processRequest(&req);
454
455 // get classes
456 req.init();
457 req.setOperation(CUPS_GET_CLASSES);
458 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",keys);
459
460 if (req.doRequest("/classes/"))
461 {
462 processRequest(&req);
463
464 // load default
465 req.init();
466 req.setOperation(CUPS_GET_DEFAULT);
467 req.addKeyword(IPP_TAG_OPERATION,"requested-attributes",TQString::fromLatin1("printer-name"));
468 if (req.doRequest("/printers/"))
469 {
470 TQString s = TQString::null;
471 req.name("printer-name",s);
472 setHardDefault(findPrinter(s));
473 }
474 // This request may fails for example if no printer is defined. Just
475 // discard the error message. Indeed as we successfully got printers
476 // and classes, the most probable reason why this request may fail is
477 // because of no printer defined. The best would be to actually check
478 // there's no printer (TODO).
479 return;
480 }
481 }
482
483 // something went wrong if we get there, report the error
484 reportIppError(&req);
485}
486
487void KMCupsManager::processRequest(IppRequest* req)
488{
489 ipp_attribute_t *attr = req->first();
490 ipp_attribute_t *nextAttr;
491 KMPrinter *printer = new KMPrinter();
492 while (attr)
493 {
494#ifdef HAVE_CUPS_1_6
495 TQString attrname(ippGetName(attr));
496 if (attrname == "printer-name")
497 {
498 TQString value = TQString::fromLocal8Bit(ippGetString(attr, 0, NULL));
499 printer->setName(value);
500 printer->setPrinterName(value);
501 }
502 else if (attrname == "printer-type")
503 {
504 int value = ippGetInteger(attr, 0);
505 printer->setType(0);
506 printer->addType(((value & CUPS_PRINTER_CLASS) || (value & CUPS_PRINTER_IMPLICIT) ? KMPrinter::Class : KMPrinter::Printer));
507 if ((value & CUPS_PRINTER_REMOTE)) printer->addType(KMPrinter::Remote);
508 if ((value & CUPS_PRINTER_IMPLICIT)) printer->addType(KMPrinter::Implicit);
509
510 // convert printer-type attribute
511 printer->setPrinterCap( ( value & CUPS_PRINTER_OPTIONS ) >> 2 );
512 }
513 else if (attrname == "printer-state")
514 {
515 switch (ippGetInteger(attr, 0))
516 {
517 case IPP_PRINTER_IDLE: printer->setState(KMPrinter::Idle); break;
518 case IPP_PRINTER_PROCESSING: printer->setState(KMPrinter::Processing); break;
519 case IPP_PRINTER_STOPPED: printer->setState(KMPrinter::Stopped); break;
520 }
521 }
522 else if (attrname == "printer-uri-supported")
523 {
524 printer->setUri(KURL(ippGetString(attr, 0, NULL)));
525 }
526 else if (attrname == "printer-location")
527 {
528 printer->setLocation(TQString::fromLocal8Bit(ippGetString(attr, 0, NULL)));
529 }
530 else if (attrname == "printer-is-accepting-jobs")
531 {
532 printer->setAcceptJobs(ippGetBoolean(attr, 0));
533 }
534
535 nextAttr = ippNextAttribute(req->request());
536 if (attrname.isEmpty() || (!nextAttr))
537 {
538 addPrinter(printer);
539 printer = new KMPrinter();
540 }
541 attr = nextAttr;
542#else // HAVE_CUPS_1_6
543 TQString attrname(attr->name);
544 if (attrname == "printer-name")
545 {
546 TQString value = TQString::fromLocal8Bit(attr->values[0].string.text);
547 printer->setName(value);
548 printer->setPrinterName(value);
549 }
550 else if (attrname == "printer-type")
551 {
552 int value = attr->values[0].integer;
553 printer->setType(0);
554 printer->addType(((value & CUPS_PRINTER_CLASS) || (value & CUPS_PRINTER_IMPLICIT) ? KMPrinter::Class : KMPrinter::Printer));
555 if ((value & CUPS_PRINTER_REMOTE)) printer->addType(KMPrinter::Remote);
556 if ((value & CUPS_PRINTER_IMPLICIT)) printer->addType(KMPrinter::Implicit);
557
558 // convert printer-type attribute
559 printer->setPrinterCap( ( value & CUPS_PRINTER_OPTIONS ) >> 2 );
560 }
561 else if (attrname == "printer-state")
562 {
563 switch (attr->values[0].integer)
564 {
565 case IPP_PRINTER_IDLE: printer->setState(KMPrinter::Idle); break;
566 case IPP_PRINTER_PROCESSING: printer->setState(KMPrinter::Processing); break;
567 case IPP_PRINTER_STOPPED: printer->setState(KMPrinter::Stopped); break;
568 }
569 }
570 else if (attrname == "printer-uri-supported")
571 {
572 printer->setUri(KURL(attr->values[0].string.text));
573 }
574 else if (attrname == "printer-location")
575 {
576 printer->setLocation(TQString::fromLocal8Bit(attr->values[0].string.text));
577 }
578 else if (attrname == "printer-is-accepting-jobs")
579 {
580 printer->setAcceptJobs(attr->values[0].boolean);
581 }
582 if (attrname.isEmpty() || attr == req->last())
583 {
584 addPrinter(printer);
585 printer = new KMPrinter();
586 }
587 attr = attr->next;
588#endif // HAVE_CUPS_1_6
589 }
590 delete printer;
591}
592
593DrMain* KMCupsManager::loadPrinterDriver(KMPrinter *p, bool)
594{
595 if (!p)
596 return NULL;
597
598 if (p->isClass(true))
599 {
600 KMPrinter *first_class_member = NULL;
601 /* find the first printer in the class */
602 first_class_member = findPrinter(p->members().first());
603
604 if (first_class_member == NULL)
605 {
606 /* we didn't find a printer in the class */
607 return NULL;
608 }
609 else
610 {
611 p = first_class_member;
612 }
613 }
614
615 TQString fname = downloadDriver(p);
616 DrMain *driver(0);
617 if (!fname.isEmpty())
618 {
619 driver = loadDriverFile(fname);
620 if (driver)
621 driver->set("temporary",fname);
622 }
623
624 return driver;
625}
626
627DrMain* KMCupsManager::loadFileDriver(const TQString& filename)
628{
629 if (filename.startsWith("ppd:"))
630 return loadDriverFile(filename.mid(4));
631 else if (filename.startsWith("compressed-ppd:"))
632 return loadDriverFile(filename);
633 else if (filename.startsWith("foomatic/"))
634 return loadMaticDriver(filename);
635 else
636 return loadDriverFile(filename);
637}
638
639DrMain* KMCupsManager::loadMaticDriver(const TQString& drname)
640{
641 TQStringList comps = TQStringList::split('/', drname, false);
642 TQString tmpFile = locateLocal("tmp", "foomatic_" + tdeApp->randomString(8));
643#if defined(__OpenBSD__) || defined(__FreeBSD__)
644 TQString PATH = getenv("PATH") + TQString::fromLatin1(":/usr/local/bin:/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
645#else
646 TQString PATH = getenv("PATH") + TQString::fromLatin1(":/usr/sbin:/usr/local/sbin:/opt/sbin:/opt/local/sbin");
647#endif
648 TQString exe = TDEStandardDirs::findExe("foomatic-datafile", PATH);
649 if (exe.isEmpty())
650 {
651 setErrorMsg(i18n("Unable to find the executable foomatic-datafile "
652 "in your PATH. Check that Foomatic is correctly installed."));
653 return NULL;
654 }
655
656 KPipeProcess in;
657 TQFile out(tmpFile);
658 TQString cmd = TDEProcess::quote(exe);
659 cmd += " -t cups -d ";
660 cmd += TDEProcess::quote(comps[2]);
661 cmd += " -p ";
662 cmd += TDEProcess::quote(comps[1]);
663 if (in.open(cmd) && out.open(IO_WriteOnly))
664 {
665 TQTextStream tin(&in), tout(&out);
666 TQString line;
667 while (!tin.atEnd())
668 {
669 line = tin.readLine();
670 tout << line << endl;
671 }
672 in.close();
673 out.close();
674
675 DrMain *driver = loadDriverFile(tmpFile);
676 if (driver)
677 {
678 driver->set("template", tmpFile);
679 driver->set("temporary", tmpFile);
680 return driver;
681 }
682 }
683 setErrorMsg(i18n("Unable to create the Foomatic driver [%1,%2]. "
684 "Either that driver does not exist, or you don't have "
685 "the required permissions to perform that operation.").arg(comps[1]).arg(comps[2]));
686 TQFile::remove(tmpFile);
687 return NULL;
688}
689
690DrMain* KMCupsManager::loadDriverFile(const TQString& fname)
691{
692 if ((fname.startsWith("compressed-ppd:")) || TQFile::exists(fname))
693 {
694 TQString msg; /* possible error message */
695 DrMain *driver = PPDLoader::loadDriver( fname, &msg );
696 if ( driver )
697 {
698 driver->set( "template", fname );
699 // FIXME: should fix option in group "install"
700 }
701 else
702 setErrorMsg( msg );
703 return driver;
704 }
705 return NULL;
706}
707
708void KMCupsManager::saveDriverFile(DrMain *driver, const TQString& filename)
709{
710 kdDebug( 500 ) << "Saving PPD file with template=" << driver->get( "template" ) << endl;
711 TQString templateFile = driver->get( "template" );
712 if (templateFile.startsWith("compressed-ppd:")) {
713 templateFile = driver->get( "temporary-cppd" );
714 }
715 TQIODevice *in = KFilterDev::deviceForFile( templateFile );
716 TQFile out(filename);
717 if (in && in->open(IO_ReadOnly) && out.open(IO_WriteOnly))
718 {
719 TQTextStream tin(in), tout(&out);
720 TQString line, keyword;
721 bool isnumeric(false);
722 DrBase *opt(0);
723
724 while (!tin.eof())
725 {
726 line = tin.readLine();
727 if (line.startsWith("*% COMDATA #"))
728 {
729 int p(-1), q(-1);
730 if ((p=line.find("'name'")) != -1)
731 {
732 p = line.find('\'',p+6)+1;
733 q = line.find('\'',p);
734 keyword = line.mid(p,q-p);
735 opt = driver->findOption(keyword);
736 if (opt && (opt->type() == DrBase::Integer || opt->type() == DrBase::Float))
737 isnumeric = true;
738 else
739 isnumeric = false;
740 }
741 /*else if ((p=line.find("'type'")) != -1)
742 {
743 p = line.find('\'',p+6)+1;
744 if (line.find("float",p) != -1 || line.find("int",p) != -1)
745 isnumeric = true;
746 else
747 isnumeric = false;
748 }*/
749 else if ((p=line.find("'default'")) != -1 && !keyword.isEmpty() && opt && isnumeric)
750 {
751 TQString prefix = line.left(p+9);
752 tout << prefix << " => '" << opt->valueText() << '\'';
753 if (line.find(',',p) != -1)
754 tout << ',';
755 tout << endl;
756 continue;
757 }
758 tout << line << endl;
759 }
760 else if (line.startsWith("*Default"))
761 {
762 int p = line.find(':',8);
763 keyword = line.mid(8,p-8);
764 DrBase *bopt = 0;
765 if ( keyword == "PageRegion" || keyword == "ImageableArea" || keyword == "PaperDimension" )
766 bopt = driver->findOption( TQString::fromLatin1( "PageSize" ) );
767 else
768 bopt = driver->findOption( keyword );
769 if (bopt)
770 switch (bopt->type())
771 {
772 case DrBase::List:
773 case DrBase::Boolean:
774 {
775 DrListOption *opt = static_cast<DrListOption*>(bopt);
776 if (opt && opt->currentChoice())
777 tout << "*Default" << keyword << ": " << opt->currentChoice()->name() << endl;
778 else
779 tout << line << endl;
780 }
781 break;
782 case DrBase::Integer:
783 {
784 DrIntegerOption *opt = static_cast<DrIntegerOption*>(bopt);
785 tout << "*Default" << keyword << ": " << opt->fixedVal() << endl;
786 }
787 break;
788 case DrBase::Float:
789 {
790 DrFloatOption *opt = static_cast<DrFloatOption*>(bopt);
791 tout << "*Default" << keyword << ": " << opt->fixedVal() << endl;
792 }
793 break;
794 default:
795 tout << line << endl;
796 break;
797 }
798 else
799 tout << line << endl;
800 }
801 else
802 tout << line << endl;
803 }
804 }
805 delete in;
806}
807
808bool KMCupsManager::savePrinterDriver(KMPrinter *p, DrMain *d)
809{
810 TQString tmpfilename = locateLocal("tmp","print_") + tdeApp->randomString(8);
811
812 // first save the driver in a temporary file
813 saveDriverFile(d,tmpfilename);
814
815 // then send a request
816 IppRequest req;
817 TQString uri;
818 bool result(false);
819
820 req.setOperation(CUPS_ADD_PRINTER);
821 uri = printerURI(p, true);
822 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
823 result = req.doFileRequest("/admin/",tmpfilename);
824
825 // remove temporary file
826 TQFile::remove(tmpfilename);
827
828 if (!result)
829 reportIppError(&req);
830 return result;
831}
832
833void* KMCupsManager::loadCupsdConfFunction(const char *name)
834{
835 if (!m_cupsdconf)
836 {
837 m_cupsdconf = KLibLoader::self()->library("cupsdconf");
838 if (!m_cupsdconf)
839 {
840 setErrorMsg(i18n("Library cupsdconf not found. Check your installation."));
841 return NULL;
842 }
843 }
844 void* func = m_cupsdconf->symbol(name);
845 if (!func)
846 setErrorMsg(i18n("Symbol %1 not found in cupsdconf library.").arg(name));
847 return func;
848}
849
850void KMCupsManager::unloadCupsdConf()
851{
852 if (m_cupsdconf)
853 {
854 KLibLoader::self()->unloadLibrary("libcupsdconf");
855 m_cupsdconf = 0;
856 }
857}
858
859bool KMCupsManager::restartServer()
860{
861 TQString msg;
862 bool (*f1)(TQString&) = (bool(*)(TQString&))loadCupsdConfFunction("restartServer");
863 bool result(false);
864 if (f1)
865 {
866 result = f1(msg);
867 if (!result) setErrorMsg(msg);
868 }
869 unloadCupsdConf();
870 return result;
871}
872
873bool KMCupsManager::configureServer(TQWidget *parent)
874{
875 TQString msg;
876 bool (*f2)(TQWidget*, TQString&) = (bool(*)(TQWidget*, TQString&))loadCupsdConfFunction("configureServer");
877 bool result(false);
878 if (f2)
879 {
880 result = f2(parent, msg);
881 if ( !result )
882 setErrorMsg( msg );
883 }
884 unloadCupsdConf();
885 return result;
886}
887
888TQStringList KMCupsManager::detectLocalPrinters()
889{
890 TQStringList list;
891 IppRequest req;
892 ipp_attribute_t *nextAttr;
893 req.setOperation(CUPS_GET_DEVICES);
894 if (req.doRequest("/"))
895 {
896 TQString desc, uri, printer, cl;
897 ipp_attribute_t *attr = req.first();
898 while (attr)
899 {
900#ifdef HAVE_CUPS_1_6
901 TQString attrname(ippGetName(attr));
902 if (attrname == "device-info") desc = ippGetString(attr, 0, NULL);
903 else if (attrname == "device-make-and-model") printer = ippGetString(attr, 0, NULL);
904 else if (attrname == "device-uri") uri = ippGetString(attr, 0, NULL);
905 else if ( attrname == "device-class" ) cl = ippGetString(attr, 0, NULL);
906 nextAttr = ippNextAttribute(req.request());
907 if (attrname.isEmpty() || (!nextAttr))
908 {
909 if (!uri.isEmpty())
910 {
911 if (printer == "Unknown") printer = TQString::null;
912 list << cl << uri << desc << printer;
913 }
914 uri = desc = printer = cl = TQString::null;
915 }
916 attr = nextAttr;
917#else // HAVE_CUPS_1_6
918 TQString attrname(attr->name);
919 if (attrname == "device-info") desc = attr->values[0].string.text;
920 else if (attrname == "device-make-and-model") printer = attr->values[0].string.text;
921 else if (attrname == "device-uri") uri = attr->values[0].string.text;
922 else if ( attrname == "device-class" ) cl = attr->values[ 0 ].string.text;
923 if (attrname.isEmpty() || attr == req.last())
924 {
925 if (!uri.isEmpty())
926 {
927 if (printer == "Unknown") printer = TQString::null;
928 list << cl << uri << desc << printer;
929 }
930 uri = desc = printer = cl = TQString::null;
931 }
932 attr = attr->next;
933#endif // HAVE_CUPS_1_6
934 }
935 }
936 return list;
937}
938
939void KMCupsManager::createPluginActions(TDEActionCollection *coll)
940{
941 TDEAction *act = new TDEAction(i18n("&Export Driver..."), "tdeprint_uploadsmb", 0, this, TQ_SLOT(exportDriver()), coll, "plugin_export_driver");
942 act->setGroup("plugin");
943 act = new TDEAction(i18n("&Printer IPP Report"), "tdeprint_report", 0, this, TQ_SLOT(printerIppReport()), coll, "plugin_printer_ipp_report");
944 act->setGroup("plugin");
945}
946
947void KMCupsManager::validatePluginActions(TDEActionCollection *coll, KMPrinter *pr)
948{
949 // save selected printer for future use in slots
950 m_currentprinter = pr;
951 coll->action("plugin_export_driver")->setEnabled(pr && pr->isLocal() && !pr->isClass(true) && !pr->isSpecial());
952 coll->action("plugin_printer_ipp_report")->setEnabled(pr && !pr->isSpecial());
953}
954
955void KMCupsManager::exportDriver()
956{
957 if (m_currentprinter && m_currentprinter->isLocal() &&
958 !m_currentprinter->isClass(true) && !m_currentprinter->isSpecial())
959 {
960 TQString path = cupsInstallDir();
961 if (path.isEmpty()) {
962#if defined(__OpenBSD__) || defined(__FreeBSD__)
963 path = "/usr/local/share/cups";
964#else
965 path = "/usr/share/cups";
966#endif
967 } else {
968 path += "/share/cups";
969 }
970 CupsAddSmb::exportDest(m_currentprinter->printerName(), path);
971 }
972}
973
974void KMCupsManager::printerIppReport()
975{
976 if (m_currentprinter && !m_currentprinter->isSpecial())
977 {
978 IppRequest req;
979 TQString uri;
980
981 req.setOperation(IPP_GET_PRINTER_ATTRIBUTES);
982 uri = printerURI(m_currentprinter, true);
983 req.addURI(IPP_TAG_OPERATION,"printer-uri",uri);
984 /*
985 if (!m_currentprinter->uri().isEmpty())
986 {
987 req.setHost(m_currentprinter->uri().host());
988 req.setPort(m_currentprinter->uri().port());
989 }
990 */
991 req.dump(2);
992 if (req.doRequest("/printers/"))
993 {
994 ippReport(req, IPP_TAG_PRINTER, i18n("IPP Report for %1").arg(m_currentprinter->printerName()));
995 }
996 else
997 {
998 KMessageBox::error(0, "<p>"+i18n("Unable to retrieve printer information. Error received:")+"</p>"+req.statusMessage());
999 }
1000 }
1001}
1002
1003void KMCupsManager::ippReport(IppRequest& req, int group, const TQString& caption)
1004{
1005 IppReportDlg::report(&req, group, caption);
1006}
1007
1008TQString KMCupsManager::stateInformation()
1009{
1010 return TQString("%1: %2")
1011 .arg(i18n("Server"))
1012 .arg(CupsInfos::self()->host()[0] != '/' ?
1013 TQString(TQString("%1:%2").arg(CupsInfos::self()->host()).arg(CupsInfos::self()->port()))
1014 : CupsInfos::self()->host());
1015}
1016
1017void KMCupsManager::checkUpdatePossibleInternal()
1018{
1019 kdDebug(500) << "Checking for update possible" << endl;
1020 delete m_socket;
1021 m_socket = new KNetwork::TDEBufferedSocket;
1022 m_socket->setTimeout( 1500 );
1023 connect( m_socket, TQ_SIGNAL( connected(const KResolverEntry&) ),
1024 TQ_SLOT( slotConnectionSuccess() ) );
1025 connect( m_socket, TQ_SIGNAL( gotError( int ) ), TQ_SLOT( slotConnectionFailed( int ) ) );
1026
1027 trials = 5;
1028 TQTimer::singleShot( 1, this, TQ_SLOT( slotAsyncConnect() ) );
1029}
1030
1031void KMCupsManager::slotConnectionSuccess()
1032{
1033 kdDebug(500) << "Connection success, trying to send a request..." << endl;
1034 m_socket->close();
1035
1036 IppRequest req;
1037 req.setOperation( CUPS_GET_PRINTERS );
1038 req.addKeyword( IPP_TAG_OPERATION, "requested-attributes", TQString::fromLatin1( "printer-name" ) );
1039 if ( req.doRequest( "/printers/" ) )
1040 setUpdatePossible( true );
1041 else
1042 {
1043 kdDebug(500) << "Unable to get printer list" << endl;
1044 if ( trials > 0 )
1045 {
1046 trials--;
1047 TQTimer::singleShot( 1000, this, TQ_SLOT( slotAsyncConnect() ) );
1048 }
1049 else
1050 {
1051 setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. "
1052 "Error: %1." ).arg( i18n( "the IPP request failed for an unknown reason" ) ) );
1053 setUpdatePossible( false );
1054 }
1055 }
1056}
1057
1058void KMCupsManager::slotAsyncConnect()
1059{
1060 kdDebug(500) << "Starting async connect to " << CupsInfos::self()->hostaddr() << endl;
1061 //m_socket->startAsyncConnect();
1062 if (CupsInfos::self()->host().startsWith("/"))
1063 m_socket->connect( TQString(), CupsInfos::self()->host());
1064 else
1065 m_socket->connectToHost( CupsInfos::self()->host(), CupsInfos::self()->port() );
1066}
1067
1068void KMCupsManager::slotConnectionFailed( int errcode )
1069{
1070 kdDebug(500) << "Connection failed trials=" << trials << endl;
1071 if ( trials > 0 )
1072 {
1073 //m_socket->setTimeout( ++to );
1074 //m_socket->cancelAsyncConnect();
1075 trials--;
1076 m_socket->close();
1077 TQTimer::singleShot( 1000, this, TQ_SLOT( slotAsyncConnect() ) );
1078 return;
1079 }
1080
1081 TQString einfo;
1082
1083 switch (errcode) {
1084 case KNetwork::TDESocketBase::ConnectionRefused:
1085 case KNetwork::TDESocketBase::ConnectionTimedOut:
1086 einfo = i18n("connection refused") + TQString(" (%1)").arg(errcode);
1087 break;
1088 case KNetwork::TDESocketBase::LookupFailure:
1089 einfo = i18n("host not found") + TQString(" (%1)").arg(errcode);
1090 break;
1091 case KNetwork::TDESocketBase::WouldBlock:
1092 default:
1093 einfo = i18n("read failed (%1)").arg(errcode);
1094 break;
1095 }
1096
1097 setErrorMsg( i18n( "Connection to CUPS server failed. Check that the CUPS server is correctly installed and running. "
1098 "Error: %2: %1." ).arg( einfo, CupsInfos::self()->host()));
1099 setUpdatePossible( false );
1100}
1101
1102void KMCupsManager::hostPingSlot() {
1103 m_hostSuccess = true;
1104 m_lookupDone = true;
1105}
1106
1107void KMCupsManager::hostPingFailedSlot() {
1108 m_hostSuccess = false;
1109 m_lookupDone = true;
1110}
1111
1112//*****************************************************************************************************
1113
1114static void extractMaticData(TQString& buf, const TQString& filename)
1115{
1116 TQFile f(filename);
1117 if (f.exists() && f.open(IO_ReadOnly))
1118 {
1119 TQTextStream t(&f);
1120 TQString line;
1121 while (!t.eof())
1122 {
1123 line = t.readLine();
1124 if (line.startsWith("*% COMDATA #"))
1125 buf.append(line.right(line.length()-12)).append('\n');
1126 }
1127 }
1128}
1129
1130static TQString printerURI(KMPrinter *p, bool use)
1131{
1132 TQString uri;
1133 if (use && !p->uri().isEmpty())
1134 uri = p->uri().prettyURL();
1135 else
1136 uri = TQString("ipp://%1/%3/%2").arg(CupsInfos::self()->hostaddr()).arg(p->printerName()).arg((p->isClass(false) ? "classes" : "printers"));
1137 return uri;
1138}
1139
1140static TQString downloadDriver(KMPrinter *p)
1141{
1142 TQString driverfile, prname = p->printerName();
1143 bool changed(false);
1144
1145 /*
1146 if (!p->uri().isEmpty())
1147 {
1148 // try to load the driver from the host:port
1149 // specified in its URI. Doing so may also change
1150 // the printer name to use. Note that for remote
1151 // printer, this operation is read-only, no counterpart
1152 // for saving operation.
1153 cupsSetServer(p->uri().host().local8Bit());
1154 ippSetPort(p->uri().port());
1155 // strip any "@..." from the printer name
1156 prname = prname.replace(TQRegExp("@.*"), "");
1157 changed = true;
1158 }
1159 */
1160
1161 // download driver
1162 driverfile = cupsGetPPD(prname.local8Bit());
1163
1164 // restore host:port (if they have changed)
1165 if (changed)
1166 {
1167 cupsSetServer(CupsInfos::self()->host().local8Bit());
1168 ippSetPort(CupsInfos::self()->port());
1169 }
1170
1171 return driverfile;
1172}
1173
1174#include "kmcupsmanager.moc"

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.