• 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 <kstandarddirs.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 
63 static void extractMaticData(TQString& buf, const TQString& filename);
64 static TQString printerURI(KMPrinter *p, bool useExistingURI);
65 static TQString downloadDriver(KMPrinter *p);
66 
67 static 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 
91 KMCupsManager::~KMCupsManager()
92 {
93  delete m_socket;
94 }
95 
96 TQString KMCupsManager::driverDbCreationProgram()
97 {
98  return TQString(__TDE_BINDIR).append(TQString::fromLatin1("/make_driver_db_cups"));
99 }
100 
101 TQString 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 
123 TQString KMCupsManager::cupsInstallDir()
124 {
125  TDEConfig *conf= KMFactory::self()->printConfig();
126  conf->setGroup("CUPS");
127  TQString dir = conf->readPathEntry("InstallDir");
128  return dir;
129 }
130 
131 void KMCupsManager::reportIppError(IppRequest *req)
132 {
133  setErrorMsg(req->statusMessage());
134 }
135 
136 bool 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 
205 bool KMCupsManager::removePrinter(KMPrinter *p)
206 {
207  bool result = setPrinterState(p,CUPS_DELETE_PRINTER);
208  return result;
209 }
210 
211 bool KMCupsManager::enablePrinter(KMPrinter *p, bool state)
212 {
213  return setPrinterState(p, (state ? CUPS_ACCEPT_JOBS : CUPS_REJECT_JOBS));
214 }
215 
216 bool KMCupsManager::startPrinter(KMPrinter *p, bool state)
217 {
218  return setPrinterState(p, (state ? IPP_RESUME_PRINTER : IPP_PAUSE_PRINTER));
219 }
220 
221 bool KMCupsManager::setDefaultPrinter(KMPrinter *p)
222 {
223  return setPrinterState(p,CUPS_SET_DEFAULT);
224 }
225 
226 bool 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 
240 bool 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 
272 bool 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 
400 bool 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 
427 void KMCupsManager::listPrinters()
428 {
429  loadServerPrinters();
430 }
431 
432 void 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 
487 void 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 
593 DrMain* 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 
627 DrMain* 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 
639 DrMain* KMCupsManager::loadMaticDriver(const TQString& drname)
640 {
641  TQStringList comps = TQStringList::split('/', drname, false);
642  TQString tmpFile = locateLocal("tmp", "foomatic_" + kapp->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 
690 DrMain* 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 
708 void 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 
808 bool KMCupsManager::savePrinterDriver(KMPrinter *p, DrMain *d)
809 {
810  TQString tmpfilename = locateLocal("tmp","print_") + kapp->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 
833 void* 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 
850 void KMCupsManager::unloadCupsdConf()
851 {
852  if (m_cupsdconf)
853  {
854  KLibLoader::self()->unloadLibrary("libcupsdconf");
855  m_cupsdconf = 0;
856  }
857 }
858 
859 bool 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 
873 bool 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 
888 TQStringList 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 
939 void 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 
947 void 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 
955 void 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 
974 void 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 
1003 void KMCupsManager::ippReport(IppRequest& req, int group, const TQString& caption)
1004 {
1005  IppReportDlg::report(&req, group, caption);
1006 }
1007 
1008 TQString 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 
1017 void 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 
1031 void 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 
1058 void 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 
1068 void 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 
1102 void KMCupsManager::hostPingSlot() {
1103  m_hostSuccess = true;
1104  m_lookupDone = true;
1105 }
1106 
1107 void KMCupsManager::hostPingFailedSlot() {
1108  m_hostSuccess = false;
1109  m_lookupDone = true;
1110 }
1111 
1112 //*****************************************************************************************************
1113 
1114 static 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 
1130 static 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 
1140 static 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.1
This website is maintained by Timothy Pearson.