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

kdeprint

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

kdeprint

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

kdeprint

Skip menu "kdeprint"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdeprint by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |