source: trunk/src/gui/painting/qprinterinfo_unix.cpp@ 574

Last change on this file since 574 was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 38.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qprinterinfo.h"
43
44#include <qfile.h>
45#include <qfileinfo.h>
46#include <qdir.h>
47#include <qprintdialog.h>
48#include <qlibrary.h>
49#include <qtextstream.h>
50
51#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
52# include <private/qcups_p.h>
53# include <cups/cups.h>
54# include <private/qpdf_p.h>
55#endif
56
57#include <private/qprinterinfo_unix_p.h>
58
59QT_BEGIN_NAMESPACE
60
61#ifndef QT_NO_PRINTER
62
63class QPrinterInfoPrivate
64{
65Q_DECLARE_PUBLIC(QPrinterInfo)
66public:
67 QPrinterInfoPrivate();
68 QPrinterInfoPrivate(const QString& name);
69 ~QPrinterInfoPrivate();
70
71 static QPrinter::PaperSize string2PaperSize(const QString& str);
72 static QString pageSize2String(QPrinter::PaperSize size);
73
74private:
75 QString m_name;
76 bool m_isNull;
77 bool m_default;
78 mutable bool m_mustGetPaperSizes;
79 mutable QList<QPrinter::PaperSize> m_paperSizes;
80 int m_cupsPrinterIndex;
81
82 QPrinterInfo* q_ptr;
83};
84
85static QPrinterInfoPrivate nullQPrinterInfoPrivate;
86
87class QPrinterInfoPrivateDeleter
88{
89public:
90 static inline void cleanup(QPrinterInfoPrivate *d)
91 {
92 if (d != &nullQPrinterInfoPrivate)
93 delete d;
94 }
95};
96
97/////////////////////////////////////////////////////////////////////////////
98/////////////////////////////////////////////////////////////////////////////
99
100void qt_perhapsAddPrinter(QList<QPrinterDescription> *printers, const QString &name,
101 QString host, QString comment,
102 QStringList aliases)
103{
104 for (int i = 0; i < printers->size(); ++i)
105 if (printers->at(i).samePrinter(name))
106 return;
107
108#ifndef QT_NO_PRINTDIALOG
109 if (host.isEmpty())
110 host = QPrintDialog::tr("locally connected");
111#endif
112 printers->append(QPrinterDescription(name.simplified(), host.simplified(), comment.simplified(), aliases));
113}
114
115void qt_parsePrinterDesc(QString printerDesc, QList<QPrinterDescription> *printers)
116{
117 if (printerDesc.length() < 1)
118 return;
119
120 printerDesc = printerDesc.simplified();
121 int i = printerDesc.indexOf(QLatin1Char(':'));
122 QString printerName, printerComment, printerHost;
123 QStringList aliases;
124
125 if (i >= 0) {
126 // have ':' want '|'
127 int j = printerDesc.indexOf(QLatin1Char('|'));
128 if (j > 0 && j < i) {
129 printerName = printerDesc.left(j);
130 aliases = printerDesc.mid(j + 1, i - j - 1).split(QLatin1Char('|'));
131#ifndef QT_NO_PRINTDIALOG
132 // try extracting a comment from the aliases
133 printerComment = QPrintDialog::tr("Aliases: %1")
134 .arg(aliases.join(QLatin1String(", ")));
135#endif
136 } else {
137 printerName = printerDesc.left(i);
138 }
139 // look for lprng pseudo all printers entry
140 i = printerDesc.indexOf(QRegExp(QLatin1String(": *all *=")));
141 if (i >= 0)
142 printerName = QString();
143 // look for signs of this being a remote printer
144 i = printerDesc.indexOf(QRegExp(QLatin1String(": *rm *=")));
145 if (i >= 0) {
146 // point k at the end of remote host name
147 while (printerDesc[i] != QLatin1Char('='))
148 i++;
149 while (printerDesc[i] == QLatin1Char('=') || printerDesc[i].isSpace())
150 i++;
151 j = i;
152 while (j < (int)printerDesc.length() && printerDesc[j] != QLatin1Char(':'))
153 j++;
154
155 // and stuff that into the string
156 printerHost = printerDesc.mid(i, j - i);
157 }
158 }
159 if (printerName.length())
160 qt_perhapsAddPrinter(printers, printerName, printerHost, printerComment,
161 aliases);
162}
163
164int qt_parsePrintcap(QList<QPrinterDescription> *printers, const QString& fileName)
165{
166 QFile printcap(fileName);
167 if (!printcap.open(QIODevice::ReadOnly))
168 return NotFound;
169
170 char *line_ascii = new char[1025];
171 line_ascii[1024] = '\0';
172
173 QString printerDesc;
174 bool atEnd = false;
175
176 while (!atEnd) {
177 if (printcap.atEnd() || printcap.readLine(line_ascii, 1024) <= 0)
178 atEnd = true;
179 QString line = QString::fromLocal8Bit(line_ascii);
180 line = line.trimmed();
181 if (line.length() >= 1 && line[int(line.length()) - 1] == QLatin1Char('\\'))
182 line.chop(1);
183 if (line[0] == QLatin1Char('#')) {
184 if (!atEnd)
185 continue;
186 } else if (line[0] == QLatin1Char('|') || line[0] == QLatin1Char(':')
187 || line.isEmpty()) {
188 printerDesc += line;
189 if (!atEnd)
190 continue;
191 }
192
193 qt_parsePrinterDesc(printerDesc, printers);
194
195 // add the first line of the new printer definition
196 printerDesc = line;
197 }
198 delete[] line_ascii;
199 return Success;
200}
201
202/*!
203 \internal
204
205 Checks $HOME/.printers for a line matching '_default <name>' (where
206 <name> does not contain any white space). The first such match
207 results in <name> being returned.
208 If no lines match then an empty string is returned.
209*/
210QString qt_getDefaultFromHomePrinters()
211{
212 QFile file(QDir::homePath() + QLatin1String("/.printers"));
213 if (!file.open(QIODevice::ReadOnly))
214 return QString();
215 QString all(QLatin1String(file.readAll()));
216 QStringList words = all.split(QRegExp(QLatin1String("\\W+")), QString::SkipEmptyParts);
217 const int i = words.indexOf(QLatin1String("_default"));
218 if (i != -1 && i < words.size() - 1)
219 return words.at(i + 1);
220 return QString();
221}
222
223// solaris, not 2.6
224void qt_parseEtcLpPrinters(QList<QPrinterDescription> *printers)
225{
226 QDir lp(QLatin1String("/etc/lp/printers"));
227 QFileInfoList dirs = lp.entryInfoList();
228 if (dirs.isEmpty())
229 return;
230
231 QString tmp;
232 for (int i = 0; i < dirs.size(); ++i) {
233 QFileInfo printer = dirs.at(i);
234 if (printer.isDir()) {
235 tmp.sprintf("/etc/lp/printers/%s/configuration",
236 printer.fileName().toAscii().data());
237 QFile configuration(tmp);
238 char *line = new char[1025];
239 QString remote(QLatin1String("Remote:"));
240 QString contentType(QLatin1String("Content types:"));
241 QString printerHost;
242 bool canPrintPostscript = false;
243 if (configuration.open(QIODevice::ReadOnly)) {
244 while (!configuration.atEnd() &&
245 configuration.readLine(line, 1024) > 0) {
246 if (QString::fromLatin1(line).startsWith(remote)) {
247 const char *p = line;
248 while (*p != ':')
249 p++;
250 p++;
251 while (isspace((uchar) *p))
252 p++;
253 printerHost = QString::fromLocal8Bit(p);
254 printerHost = printerHost.simplified();
255 } else if (QString::fromLatin1(line).startsWith(contentType)) {
256 char *p = line;
257 while (*p != ':')
258 p++;
259 p++;
260 char *e;
261 while (*p) {
262 while (isspace((uchar) *p))
263 p++;
264 if (*p) {
265 char s;
266 e = p;
267 while (isalnum((uchar) *e))
268 e++;
269 s = *e;
270 *e = '\0';
271 if (!qstrcmp(p, "postscript") ||
272 !qstrcmp(p, "any"))
273 canPrintPostscript = true;
274 *e = s;
275 if (s == ',')
276 e++;
277 p = e;
278 }
279 }
280 }
281 }
282 if (canPrintPostscript)
283 qt_perhapsAddPrinter(printers, printer.fileName(),
284 printerHost, QLatin1String(""));
285 }
286 delete[] line;
287 }
288 }
289}
290
291// solaris 2.6
292char *qt_parsePrintersConf(QList<QPrinterDescription> *printers, bool *found)
293{
294 QFile pc(QLatin1String("/etc/printers.conf"));
295 if (!pc.open(QIODevice::ReadOnly)) {
296 if (found)
297 *found = false;
298 return 0;
299 }
300 if (found)
301 *found = true;
302
303 char *line = new char[1025];
304 line[1024] = '\0';
305
306 QString printerDesc;
307 int lineLength = 0;
308
309 char *defaultPrinter = 0;
310
311 while (!pc.atEnd() &&
312 (lineLength=pc.readLine(line, 1024)) > 0) {
313 if (*line == '#') {
314 *line = '\0';
315 lineLength = 0;
316 }
317 if (lineLength >= 2 && line[lineLength-2] == '\\') {
318 line[lineLength-2] = '\0';
319 printerDesc += QString::fromLocal8Bit(line);
320 } else {
321 printerDesc += QString::fromLocal8Bit(line);
322 printerDesc = printerDesc.simplified();
323 int i = printerDesc.indexOf(QLatin1Char(':'));
324 QString printerName, printerHost, printerComment;
325 QStringList aliases;
326 if (i >= 0) {
327 // have : want |
328 int j = printerDesc.indexOf(QLatin1Char('|'));
329 if (j >= i)
330 j = -1;
331 printerName = printerDesc.mid(0, j < 0 ? i : j);
332 if (printerName == QLatin1String("_default")) {
333 i = printerDesc.indexOf(
334 QRegExp(QLatin1String(": *use *=")));
335 while (printerDesc[i] != QLatin1Char('='))
336 i++;
337 while (printerDesc[i] == QLatin1Char('=') || printerDesc[i].isSpace())
338 i++;
339 j = i;
340 while (j < (int)printerDesc.length() &&
341 printerDesc[j] != QLatin1Char(':') && printerDesc[j] != QLatin1Char(','))
342 j++;
343 // that's our default printer
344 defaultPrinter =
345 qstrdup(printerDesc.mid(i, j-i).toAscii().data());
346 printerName = QString();
347 printerDesc = QString();
348 } else if (printerName == QLatin1String("_all")) {
349 // skip it.. any other cases we want to skip?
350 printerName = QString();
351 printerDesc = QString();
352 }
353
354 if (j > 0) {
355 // try extracting a comment from the aliases
356 aliases = printerDesc.mid(j + 1, i - j - 1).split(QLatin1Char('|'));
357#ifndef QT_NO_PRINTDIALOG
358 printerComment = QPrintDialog::tr("Aliases: %1")
359 .arg(aliases.join(QLatin1String(", ")));
360#endif
361 }
362 // look for signs of this being a remote printer
363 i = printerDesc.indexOf(
364 QRegExp(QLatin1String(": *bsdaddr *=")));
365 if (i >= 0) {
366 // point k at the end of remote host name
367 while (printerDesc[i] != QLatin1Char('='))
368 i++;
369 while (printerDesc[i] == QLatin1Char('=') || printerDesc[i].isSpace())
370 i++;
371 j = i;
372 while (j < (int)printerDesc.length() &&
373 printerDesc[j] != QLatin1Char(':') && printerDesc[j] != QLatin1Char(','))
374 j++;
375 // and stuff that into the string
376 printerHost = printerDesc.mid(i, j-i);
377 // maybe stick the remote printer name into the comment
378 if (printerDesc[j] == QLatin1Char(',')) {
379 i = ++j;
380 while (printerDesc[i].isSpace())
381 i++;
382 j = i;
383 while (j < (int)printerDesc.length() &&
384 printerDesc[j] != QLatin1Char(':') && printerDesc[j] != QLatin1Char(','))
385 j++;
386 if (printerName != printerDesc.mid(i, j-i)) {
387 printerComment =
388 QLatin1String("Remote name: ");
389 printerComment += printerDesc.mid(i, j-i);
390 }
391 }
392 }
393 }
394 if (printerComment == QLatin1String(":"))
395 printerComment = QString(); // for cups
396 if (printerName.length())
397 qt_perhapsAddPrinter(printers, printerName, printerHost,
398 printerComment, aliases);
399 // chop away the line, for processing the next one
400 printerDesc = QString();
401 }
402 }
403 delete[] line;
404 return defaultPrinter;
405}
406
407#ifndef QT_NO_NIS
408
409#if defined(Q_C_CALLBACKS)
410extern "C" {
411#endif
412
413int qt_pd_foreach(int /*status */, char * /*key */, int /*keyLen */,
414 char *val, int valLen, char *data)
415{
416 qt_parsePrinterDesc(QString::fromLatin1(val, valLen), (QList<QPrinterDescription> *)data);
417 return 0;
418}
419
420#if defined(Q_C_CALLBACKS)
421}
422#endif
423
424int qt_retrieveNisPrinters(QList<QPrinterDescription> *printers)
425{
426#ifndef QT_NO_LIBRARY
427 typedef int (*WildCast)(int, char *, int, char *, int, char *);
428 char printersConfByname[] = "printers.conf.byname";
429 char *domain;
430 int err;
431
432 QLibrary lib(QLatin1String("nsl"));
433 typedef int (*ypGetDefaultDomain)(char **);
434 ypGetDefaultDomain _ypGetDefaultDomain = (ypGetDefaultDomain)lib.resolve("yp_get_default_domain");
435 typedef int (*ypAll)(const char *, const char *, const struct ypall_callback *);
436 ypAll _ypAll = (ypAll)lib.resolve("yp_all");
437
438 if (_ypGetDefaultDomain && _ypAll) {
439 err = _ypGetDefaultDomain(&domain);
440 if (err == 0) {
441 ypall_callback cb;
442 // wild cast to support K&R-style system headers
443 (WildCast &) cb.foreach = (WildCast) qt_pd_foreach;
444 cb.data = (char *) printers;
445 err = _ypAll(domain, printersConfByname, &cb);
446 }
447 if (!err)
448 return Success;
449 }
450#endif //QT_NO_LIBRARY
451 return Unavail;
452}
453
454#endif // QT_NO_NIS
455
456char *qt_parseNsswitchPrintersEntry(QList<QPrinterDescription> *printers, char *line)
457{
458#define skipSpaces() \
459 while (line[k] != '\0' && isspace((uchar) line[k])) \
460 k++
461
462 char *defaultPrinter = 0;
463 bool stop = false;
464 int lastStatus = NotFound;
465
466 int k = 8;
467 skipSpaces();
468 if (line[k] != ':')
469 return 0;
470 k++;
471
472 char *cp = strchr(line, '#');
473 if (cp != 0)
474 *cp = '\0';
475
476 while (line[k] != '\0') {
477 if (isspace((uchar) line[k])) {
478 k++;
479 } else if (line[k] == '[') {
480 k++;
481 skipSpaces();
482 while (line[k] != '\0') {
483 char status = tolower(line[k]);
484 char action = '?';
485
486 while (line[k] != '=' && line[k] != ']' && line[k] != '\0')
487 k++;
488 if (line[k] == '=') {
489 k++;
490 skipSpaces();
491 action = tolower(line[k]);
492 while (line[k] != '\0' && !isspace((uchar) line[k]) && line[k] != ']')
493 k++;
494 } else if (line[k] == ']') {
495 k++;
496 break;
497 }
498 skipSpaces();
499
500 if (lastStatus == status)
501 stop = (action == (char) Return);
502 }
503 } else {
504 if (stop)
505 break;
506
507 QByteArray source;
508 while (line[k] != '\0' && !isspace((uchar) line[k]) && line[k] != '[') {
509 source += line[k];
510 k++;
511 }
512
513 if (source == "user") {
514 lastStatus = qt_parsePrintcap(printers,
515 QDir::homePath() + QLatin1String("/.printers"));
516 } else if (source == "files") {
517 bool found;
518 defaultPrinter = qt_parsePrintersConf(printers, &found);
519 if (found)
520 lastStatus = Success;
521#ifndef QT_NO_NIS
522 } else if (source == "nis") {
523 lastStatus = qt_retrieveNisPrinters(printers);
524#endif
525 } else {
526 // nisplus, dns, etc., are not implemented yet
527 lastStatus = NotFound;
528 }
529 stop = (lastStatus == Success);
530 }
531 }
532 return defaultPrinter;
533}
534
535char *qt_parseNsswitchConf(QList<QPrinterDescription> *printers)
536{
537 QFile nc(QLatin1String("/etc/nsswitch.conf"));
538 if (!nc.open(QIODevice::ReadOnly))
539 return 0;
540
541 char *defaultPrinter = 0;
542
543 char *line = new char[1025];
544 line[1024] = '\0';
545
546 while (!nc.atEnd() &&
547 nc.readLine(line, 1024) > 0) {
548 if (qstrncmp(line, "printers", 8) == 0) {
549 defaultPrinter = qt_parseNsswitchPrintersEntry(printers, line);
550 delete[] line;
551 return defaultPrinter;
552 }
553 }
554
555 strcpy(line, "printers: user files nis nisplus xfn");
556 defaultPrinter = qt_parseNsswitchPrintersEntry(printers, line);
557 delete[] line;
558 return defaultPrinter;
559}
560
561// HP-UX
562void qt_parseEtcLpMember(QList<QPrinterDescription> *printers)
563{
564 QDir lp(QLatin1String("/etc/lp/member"));
565 if (!lp.exists())
566 return;
567 QFileInfoList dirs = lp.entryInfoList();
568 if (dirs.isEmpty())
569 return;
570
571#ifdef QT_NO_PRINTDIALOG
572 Q_UNUSED(printers);
573#else
574 QString tmp;
575 for (int i = 0; i < dirs.size(); ++i) {
576 QFileInfo printer = dirs.at(i);
577 // I haven't found any real documentation, so I'm guessing that
578 // since lpstat uses /etc/lp/member rather than one of the
579 // other directories, it's the one to use. I did not find a
580 // decent way to locate aliases and remote printers.
581 if (printer.isFile())
582 qt_perhapsAddPrinter(printers, printer.fileName(),
583 QPrintDialog::tr("unknown"),
584 QLatin1String(""));
585 }
586#endif
587}
588
589// IRIX 6.x
590void qt_parseSpoolInterface(QList<QPrinterDescription> *printers)
591{
592 QDir lp(QLatin1String("/usr/spool/lp/interface"));
593 if (!lp.exists())
594 return;
595 QFileInfoList files = lp.entryInfoList();
596 if(files.isEmpty())
597 return;
598
599 for (int i = 0; i < files.size(); ++i) {
600 QFileInfo printer = files.at(i);
601
602 if (!printer.isFile())
603 continue;
604
605 // parse out some information
606 QFile configFile(printer.filePath());
607 if (!configFile.open(QIODevice::ReadOnly))
608 continue;
609
610 QByteArray line;
611 line.resize(1025);
612 QString namePrinter;
613 QString hostName;
614 QString hostPrinter;
615 QString printerType;
616
617 QString nameKey(QLatin1String("NAME="));
618 QString typeKey(QLatin1String("TYPE="));
619 QString hostKey(QLatin1String("HOSTNAME="));
620 QString hostPrinterKey(QLatin1String("HOSTPRINTER="));
621
622 while (!configFile.atEnd() &&
623 (configFile.readLine(line.data(), 1024)) > 0) {
624 QString uline = QString::fromLocal8Bit(line);
625 if (uline.startsWith(typeKey) ) {
626 printerType = uline.mid(nameKey.length());
627 printerType = printerType.simplified();
628 } else if (uline.startsWith(hostKey)) {
629 hostName = uline.mid(hostKey.length());
630 hostName = hostName.simplified();
631 } else if (uline.startsWith(hostPrinterKey)) {
632 hostPrinter = uline.mid(hostPrinterKey.length());
633 hostPrinter = hostPrinter.simplified();
634 } else if (uline.startsWith(nameKey)) {
635 namePrinter = uline.mid(nameKey.length());
636 namePrinter = namePrinter.simplified();
637 }
638 }
639 configFile.close();
640
641 printerType = printerType.trimmed();
642 if (printerType.indexOf(QLatin1String("postscript"), 0, Qt::CaseInsensitive) < 0)
643 continue;
644
645 int ii = 0;
646 while ((ii = namePrinter.indexOf(QLatin1Char('"'), ii)) >= 0)
647 namePrinter.remove(ii, 1);
648
649 if (hostName.isEmpty() || hostPrinter.isEmpty()) {
650 qt_perhapsAddPrinter(printers, printer.fileName(),
651 QLatin1String(""), namePrinter);
652 } else {
653 QString comment;
654 comment = namePrinter;
655 comment += QLatin1String(" (");
656 comment += hostPrinter;
657 comment += QLatin1Char(')');
658 qt_perhapsAddPrinter(printers, printer.fileName(),
659 hostName, comment);
660 }
661 }
662}
663
664
665// Every unix must have its own. It's a standard. Here is AIX.
666void qt_parseQconfig(QList<QPrinterDescription> *printers)
667{
668 QFile qconfig(QLatin1String("/etc/qconfig"));
669 if (!qconfig.open(QIODevice::ReadOnly))
670 return;
671
672 QTextStream ts(&qconfig);
673 QString line;
674
675 QString stanzaName; // either a queue or a device name
676 bool up = true; // queue up? default true, can be false
677 QString remoteHost; // null if local
678 QString deviceName; // null if remote
679
680 QRegExp newStanza(QLatin1String("^[0-z\\-]*:$"));
681
682 // our basic strategy here is to process each line, detecting new
683 // stanzas. each time we see a new stanza, we check if the
684 // previous stanza was a valid queue for a) a remote printer or b)
685 // a local printer. if it wasn't, we assume that what we see is
686 // the start of the first stanza, or that the previous stanza was
687 // a device stanza, or that there is some syntax error (we don't
688 // report those).
689
690 do {
691 line = ts.readLine();
692 bool indented = line[0].isSpace();
693 line = line.simplified();
694
695 int i = line.indexOf(QLatin1Char('='));
696 if (indented && i != -1) { // line in stanza
697 QString variable = line.left(i).simplified();
698 QString value=line.mid(i+1, line.length()).simplified();
699 if (variable == QLatin1String("device"))
700 deviceName = value;
701 else if (variable == QLatin1String("host"))
702 remoteHost = value;
703 else if (variable == QLatin1String("up"))
704 up = !(value.toLower() == QLatin1String("false"));
705 } else if (line[0] == QLatin1Char('*')) { // comment
706 // nothing to do
707 } else if (ts.atEnd() || // end of file, or beginning of new stanza
708 (!indented && line.contains(newStanza))) {
709 if (up && stanzaName.length() > 0 && stanzaName.length() < 21) {
710 if (remoteHost.length()) // remote printer
711 qt_perhapsAddPrinter(printers, stanzaName, remoteHost,
712 QString());
713 else if (deviceName.length()) // local printer
714 qt_perhapsAddPrinter(printers, stanzaName, QString(),
715 QString());
716 }
717 line.chop(1);
718 if (line.length() >= 1 && line.length() <= 20)
719 stanzaName = line;
720 up = true;
721 remoteHost.clear();
722 deviceName.clear();
723 } else {
724 // syntax error? ignore.
725 }
726 } while (!ts.atEnd());
727}
728
729int qt_getLprPrinters(QList<QPrinterDescription>& printers)
730{
731 QByteArray etcLpDefault;
732 qt_parsePrintcap(&printers, QLatin1String("/etc/printcap"));
733 qt_parseEtcLpMember(&printers);
734 qt_parseSpoolInterface(&printers);
735 qt_parseQconfig(&printers);
736
737 QFileInfo f;
738 f.setFile(QLatin1String("/etc/lp/printers"));
739 if (f.isDir()) {
740 qt_parseEtcLpPrinters(&printers);
741 QFile def(QLatin1String("/etc/lp/default"));
742 if (def.open(QIODevice::ReadOnly)) {
743 etcLpDefault.resize(1025);
744 if (def.readLine(etcLpDefault.data(), 1024) > 0) {
745 QRegExp rx(QLatin1String("^(\\S+)"));
746 if (rx.indexIn(QString::fromLatin1(etcLpDefault)) != -1)
747 etcLpDefault = rx.cap(1).toAscii();
748 }
749 }
750 }
751
752 char *def = 0;
753 f.setFile(QLatin1String("/etc/nsswitch.conf"));
754 if (f.isFile()) {
755 def = qt_parseNsswitchConf(&printers);
756 } else {
757 f.setFile(QLatin1String("/etc/printers.conf"));
758 if (f.isFile())
759 def = qt_parsePrintersConf(&printers);
760 }
761
762 if (def) {
763 etcLpDefault = def;
764 delete [] def;
765 }
766
767 QString homePrintersDefault = qt_getDefaultFromHomePrinters();
768
769 // all printers hopefully known. try to find a good default
770 QString dollarPrinter;
771 {
772 dollarPrinter = QString::fromLocal8Bit(qgetenv("PRINTER"));
773 if (dollarPrinter.isEmpty())
774 dollarPrinter = QString::fromLocal8Bit(qgetenv("LPDEST"));
775 if (dollarPrinter.isEmpty())
776 dollarPrinter = QString::fromLocal8Bit(qgetenv("NPRINTER"));
777 if (dollarPrinter.isEmpty())
778 dollarPrinter = QString::fromLocal8Bit(qgetenv("NGPRINTER"));
779#ifndef QT_NO_PRINTDIALOG
780 if (!dollarPrinter.isEmpty())
781 qt_perhapsAddPrinter(&printers, dollarPrinter,
782 QPrintDialog::tr("unknown"),
783 QLatin1String(""));
784#endif
785 }
786
787 int quality = 0;
788 int best = 0;
789 for (int i = 0; i < printers.size(); ++i) {
790 QRegExp ps(QLatin1String("[^a-z]ps(?:[^a-z]|$)"));
791 QRegExp lp(QLatin1String("[^a-z]lp(?:[^a-z]|$)"));
792
793 QString name = printers.at(i).name;
794 QString comment = printers.at(i).comment;
795 if (quality < 5 && name == dollarPrinter) {
796 best = i;
797 quality = 5;
798 } else if (quality < 4 && !homePrintersDefault.isEmpty() &&
799 name == homePrintersDefault) {
800 best = i;
801 quality = 4;
802 } else if (quality < 3 && !etcLpDefault.isEmpty() &&
803 name == QLatin1String(etcLpDefault)) {
804 best = i;
805 quality = 3;
806 } else if (quality < 2 &&
807 (name == QLatin1String("ps") ||
808 ps.indexIn(comment) != -1)) {
809 best = i;
810 quality = 2;
811 } else if (quality < 1 &&
812 (name == QLatin1String("lp") ||
813 lp.indexIn(comment) > -1)) {
814 best = i;
815 quality = 1;
816 }
817 }
818
819 return best;
820}
821
822/////////////////////////////////////////////////////////////////////////////
823/////////////////////////////////////////////////////////////////////////////
824
825QList<QPrinterInfo> QPrinterInfo::availablePrinters()
826{
827 QList<QPrinterInfo> list;
828
829#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
830 QCUPSSupport cups;
831 if (QCUPSSupport::isAvailable()) {
832 //const ppd_file_t* cupsPPD = cups.currentPPD();
833 int cupsPrinterCount = cups.availablePrintersCount();
834 const cups_dest_t* cupsPrinters = cups.availablePrinters();
835
836 for (int i = 0; i < cupsPrinterCount; ++i) {
837 QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
838 if (cupsPrinters[i].instance)
839 printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
840 list.append(QPrinterInfo(printerName));
841 if (cupsPrinters[i].is_default)
842 list[i].d_ptr->m_default = true;
843 list[i].d_ptr->m_cupsPrinterIndex = i;
844 }
845 } else {
846#endif
847 QList<QPrinterDescription> lprPrinters;
848 int defprn = qt_getLprPrinters(lprPrinters);
849 // populating printer combo
850 QList<QPrinterDescription>::const_iterator i = lprPrinters.constBegin();
851 for(; i != lprPrinters.constEnd(); ++i) {
852 list.append(QPrinterInfo((*i).name));
853 }
854 if (defprn >= 0 && defprn < lprPrinters.size()) {
855 list[defprn].d_ptr->m_default = true;
856 }
857#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
858 }
859#endif
860
861 return list;
862}
863
864QPrinterInfo QPrinterInfo::defaultPrinter()
865{
866 QList<QPrinterInfo> prnList = availablePrinters();
867 for (int i = 0; i < prnList.size(); ++i) {
868 if (prnList[i].isDefault())
869 return prnList[i];
870 }
871 return (prnList.size() > 0) ? prnList[0] : QPrinterInfo();
872}
873
874QPrinterInfo::QPrinterInfo()
875 : d_ptr(&nullQPrinterInfoPrivate)
876{
877}
878
879QPrinterInfo::QPrinterInfo(const QPrinterInfo& src)
880 : d_ptr(&nullQPrinterInfoPrivate)
881{
882 *this = src;
883}
884
885QPrinterInfo::QPrinterInfo(const QPrinter& printer)
886 : d_ptr(new QPrinterInfoPrivate(printer.printerName()))
887{
888
889 Q_D(QPrinterInfo);
890 d->q_ptr = this;
891
892#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
893 QCUPSSupport cups;
894 if (QCUPSSupport::isAvailable()) {
895 int cupsPrinterCount = cups.availablePrintersCount();
896 const cups_dest_t* cupsPrinters = cups.availablePrinters();
897
898 for (int i = 0; i < cupsPrinterCount; ++i) {
899 QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
900 if (cupsPrinters[i].instance)
901 printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
902 if (printerName == printer.printerName()) {
903 if (cupsPrinters[i].is_default)
904 d->m_default = true;
905 d->m_cupsPrinterIndex = i;
906 return;
907 }
908 }
909 } else {
910#endif
911 QList<QPrinterDescription> lprPrinters;
912 int defprn = qt_getLprPrinters(lprPrinters);
913 // populating printer combo
914 QList<QPrinterDescription>::const_iterator i = lprPrinters.constBegin();
915 int c;
916 for(c = 0; i != lprPrinters.constEnd(); ++i, ++c) {
917 if (i->name == printer.printerName()) {
918 if (defprn == c)
919 d->m_default = true;
920 return;
921 }
922 }
923#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
924 }
925#endif
926
927 // Printer not found.
928 d_ptr.reset(&nullQPrinterInfoPrivate);
929}
930
931QPrinterInfo::QPrinterInfo(const QString& name)
932 : d_ptr(new QPrinterInfoPrivate(name))
933{
934 d_ptr->q_ptr = this;
935}
936
937QPrinterInfo::~QPrinterInfo()
938{
939}
940
941QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src)
942{
943 Q_ASSERT(d_ptr);
944 d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr));
945 d_ptr->q_ptr = this;
946 return *this;
947}
948
949QString QPrinterInfo::printerName() const
950{
951 const Q_D(QPrinterInfo);
952 return d->m_name;
953}
954
955bool QPrinterInfo::isNull() const
956{
957 const Q_D(QPrinterInfo);
958 return d->m_isNull;
959}
960
961bool QPrinterInfo::isDefault() const
962{
963 const Q_D(QPrinterInfo);
964 return d->m_default;
965}
966
967QList< QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const
968{
969 const Q_D(QPrinterInfo);
970 if (d->m_mustGetPaperSizes) {
971 d->m_mustGetPaperSizes = false;
972
973#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
974 QCUPSSupport cups;
975 if (QCUPSSupport::isAvailable()) {
976 // Find paper sizes from CUPS.
977 cups.setCurrentPrinter(d->m_cupsPrinterIndex);
978 const ppd_option_t* sizes = cups.pageSizes();
979 if (sizes) {
980 for (int j = 0; j < sizes->num_choices; ++j) {
981 d->m_paperSizes.append(
982 QPrinterInfoPrivate::string2PaperSize(
983 QLatin1String(sizes->choices[j].choice)));
984 }
985 }
986 }
987#endif
988
989 }
990 return d->m_paperSizes;
991}
992
993/////////////////////////////////////////////////////////////////////////////
994/////////////////////////////////////////////////////////////////////////////
995
996QPrinterInfoPrivate::QPrinterInfoPrivate()
997{
998 m_isNull = true;
999 m_default = false;
1000 m_mustGetPaperSizes = true;
1001 m_cupsPrinterIndex = 0;
1002 q_ptr = 0;
1003}
1004
1005QPrinterInfoPrivate::QPrinterInfoPrivate(const QString& name)
1006{
1007 m_name = name;
1008 m_isNull = false;
1009 m_default = false;
1010 m_mustGetPaperSizes = true;
1011 m_cupsPrinterIndex = 0;
1012 q_ptr = 0;
1013}
1014
1015QPrinterInfoPrivate::~QPrinterInfoPrivate()
1016{
1017}
1018
1019QPrinter::PaperSize QPrinterInfoPrivate::string2PaperSize(const QString& str)
1020{
1021 if (str == QLatin1String("A4")) {
1022 return QPrinter::A4;
1023 } else if (str == QLatin1String("B5")) {
1024 return QPrinter::B5;
1025 } else if (str == QLatin1String("Letter")) {
1026 return QPrinter::Letter;
1027 } else if (str == QLatin1String("Legal")) {
1028 return QPrinter::Legal;
1029 } else if (str == QLatin1String("Executive")) {
1030 return QPrinter::Executive;
1031 } else if (str == QLatin1String("A0")) {
1032 return QPrinter::A0;
1033 } else if (str == QLatin1String("A1")) {
1034 return QPrinter::A1;
1035 } else if (str == QLatin1String("A2")) {
1036 return QPrinter::A2;
1037 } else if (str == QLatin1String("A3")) {
1038 return QPrinter::A3;
1039 } else if (str == QLatin1String("A5")) {
1040 return QPrinter::A5;
1041 } else if (str == QLatin1String("A6")) {
1042 return QPrinter::A6;
1043 } else if (str == QLatin1String("A7")) {
1044 return QPrinter::A7;
1045 } else if (str == QLatin1String("A8")) {
1046 return QPrinter::A8;
1047 } else if (str == QLatin1String("A9")) {
1048 return QPrinter::A9;
1049 } else if (str == QLatin1String("B0")) {
1050 return QPrinter::B0;
1051 } else if (str == QLatin1String("B1")) {
1052 return QPrinter::B1;
1053 } else if (str == QLatin1String("B10")) {
1054 return QPrinter::B10;
1055 } else if (str == QLatin1String("B2")) {
1056 return QPrinter::B2;
1057 } else if (str == QLatin1String("B3")) {
1058 return QPrinter::B3;
1059 } else if (str == QLatin1String("B4")) {
1060 return QPrinter::B4;
1061 } else if (str == QLatin1String("B6")) {
1062 return QPrinter::B6;
1063 } else if (str == QLatin1String("B7")) {
1064 return QPrinter::B7;
1065 } else if (str == QLatin1String("B8")) {
1066 return QPrinter::B8;
1067 } else if (str == QLatin1String("B9")) {
1068 return QPrinter::B9;
1069 } else if (str == QLatin1String("C5E")) {
1070 return QPrinter::C5E;
1071 } else if (str == QLatin1String("Comm10E")) {
1072 return QPrinter::Comm10E;
1073 } else if (str == QLatin1String("DLE")) {
1074 return QPrinter::DLE;
1075 } else if (str == QLatin1String("Folio")) {
1076 return QPrinter::Folio;
1077 } else if (str == QLatin1String("Ledger")) {
1078 return QPrinter::Ledger;
1079 } else if (str == QLatin1String("Tabloid")) {
1080 return QPrinter::Tabloid;
1081 } else {
1082 return QPrinter::Custom;
1083 }
1084}
1085
1086QString QPrinterInfoPrivate::pageSize2String(QPrinter::PaperSize size)
1087{
1088 switch (size) {
1089 case QPrinter::A4:
1090 return QLatin1String("A4");
1091 case QPrinter::B5:
1092 return QLatin1String("B5");
1093 case QPrinter::Letter:
1094 return QLatin1String("Letter");
1095 case QPrinter::Legal:
1096 return QLatin1String("Legal");
1097 case QPrinter::Executive:
1098 return QLatin1String("Executive");
1099 case QPrinter::A0:
1100 return QLatin1String("A0");
1101 case QPrinter::A1:
1102 return QLatin1String("A1");
1103 case QPrinter::A2:
1104 return QLatin1String("A2");
1105 case QPrinter::A3:
1106 return QLatin1String("A3");
1107 case QPrinter::A5:
1108 return QLatin1String("A5");
1109 case QPrinter::A6:
1110 return QLatin1String("A6");
1111 case QPrinter::A7:
1112 return QLatin1String("A7");
1113 case QPrinter::A8:
1114 return QLatin1String("A8");
1115 case QPrinter::A9:
1116 return QLatin1String("A9");
1117 case QPrinter::B0:
1118 return QLatin1String("B0");
1119 case QPrinter::B1:
1120 return QLatin1String("B1");
1121 case QPrinter::B10:
1122 return QLatin1String("B10");
1123 case QPrinter::B2:
1124 return QLatin1String("B2");
1125 case QPrinter::B3:
1126 return QLatin1String("B3");
1127 case QPrinter::B4:
1128 return QLatin1String("B4");
1129 case QPrinter::B6:
1130 return QLatin1String("B6");
1131 case QPrinter::B7:
1132 return QLatin1String("B7");
1133 case QPrinter::B8:
1134 return QLatin1String("B8");
1135 case QPrinter::B9:
1136 return QLatin1String("B9");
1137 case QPrinter::C5E:
1138 return QLatin1String("C5E");
1139 case QPrinter::Comm10E:
1140 return QLatin1String("Comm10E");
1141 case QPrinter::DLE:
1142 return QLatin1String("DLE");
1143 case QPrinter::Folio:
1144 return QLatin1String("Folio");
1145 case QPrinter::Ledger:
1146 return QLatin1String("Ledger");
1147 case QPrinter::Tabloid:
1148 return QLatin1String("Tabloid");
1149 default:
1150 return QLatin1String("Custom");
1151 }
1152}
1153
1154#endif // QT_NO_PRINTER
1155
1156QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.