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

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 38.0 KB
Line 
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
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