1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 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 |
|
---|
59 | QT_BEGIN_NAMESPACE
|
---|
60 |
|
---|
61 | #ifndef QT_NO_PRINTER
|
---|
62 |
|
---|
63 | class QPrinterInfoPrivate
|
---|
64 | {
|
---|
65 | Q_DECLARE_PUBLIC(QPrinterInfo)
|
---|
66 | public:
|
---|
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 |
|
---|
74 | private:
|
---|
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 |
|
---|
85 | static QPrinterInfoPrivate nullQPrinterInfoPrivate;
|
---|
86 |
|
---|
87 | class QPrinterInfoPrivateDeleter
|
---|
88 | {
|
---|
89 | public:
|
---|
90 | static inline void cleanup(QPrinterInfoPrivate *d)
|
---|
91 | {
|
---|
92 | if (d != &nullQPrinterInfoPrivate)
|
---|
93 | delete d;
|
---|
94 | }
|
---|
95 | };
|
---|
96 |
|
---|
97 | /////////////////////////////////////////////////////////////////////////////
|
---|
98 | /////////////////////////////////////////////////////////////////////////////
|
---|
99 |
|
---|
100 | void 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 |
|
---|
115 | void 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 |
|
---|
164 | int 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 | */
|
---|
210 | QString 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
|
---|
224 | void 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
|
---|
292 | char *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)
|
---|
410 | extern "C" {
|
---|
411 | #endif
|
---|
412 |
|
---|
413 | int 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 |
|
---|
424 | int 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 |
|
---|
456 | char *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 |
|
---|
|
---|