PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/qt/src/gui/painting/qprinterinfo_unix.cpp

https://github.com/justinanastos/phantomjs
C++ | 927 lines | 787 code | 64 blank | 76 comment | 197 complexity | d4e9f1bed3fe68666853e14dfa899ba1 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0, CC-BY-SA-4.0, GPL-3.0, LGPL-2.1
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the QtGui module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qprinterinfo.h"
  42. #include "qprinterinfo_p.h"
  43. #include <qfile.h>
  44. #include <qfileinfo.h>
  45. #include <qdir.h>
  46. #include <qprintdialog.h>
  47. #include <qlibrary.h>
  48. #include <qtextstream.h>
  49. #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
  50. # include <private/qcups_p.h>
  51. # include <cups/cups.h>
  52. # include <private/qpdf_p.h>
  53. #endif
  54. #include <private/qprinterinfo_unix_p.h>
  55. QT_BEGIN_NAMESPACE
  56. #ifndef QT_NO_PRINTER
  57. #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
  58. // preserver names in ascending order for the binary search
  59. static const struct NamedPaperSize {
  60. const char *const name;
  61. QPrinter::PaperSize size;
  62. } named_sizes_map[QPrinter::NPageSize] = {
  63. { "A0", QPrinter::A0 },
  64. { "A1", QPrinter::A1 },
  65. { "A2", QPrinter::A2 },
  66. { "A3", QPrinter::A3 },
  67. { "A4", QPrinter::A4 },
  68. { "A5", QPrinter::A5 },
  69. { "A6", QPrinter::A6 },
  70. { "A7", QPrinter::A7 },
  71. { "A8", QPrinter::A8 },
  72. { "A9", QPrinter::A9 },
  73. { "B0", QPrinter::B0 },
  74. { "B1", QPrinter::B1 },
  75. { "B10", QPrinter::B10 },
  76. { "B2", QPrinter::B2 },
  77. { "B4", QPrinter::B4 },
  78. { "B5", QPrinter::B5 },
  79. { "B6", QPrinter::B6 },
  80. { "B7", QPrinter::B7 },
  81. { "B8", QPrinter::B8 },
  82. { "B9", QPrinter::B9 },
  83. { "C5E", QPrinter::C5E },
  84. { "Comm10E", QPrinter::Comm10E },
  85. { "Custom", QPrinter::Custom },
  86. { "DLE", QPrinter::DLE },
  87. { "Executive", QPrinter::Executive },
  88. { "Folio", QPrinter::Folio },
  89. { "Ledger", QPrinter::Ledger },
  90. { "Legal", QPrinter::Legal },
  91. { "Letter", QPrinter::Letter },
  92. { "Tabloid", QPrinter::Tabloid }
  93. };
  94. inline bool operator<(const char *name, const NamedPaperSize &data)
  95. { return qstrcmp(name, data.name) < 0; }
  96. inline bool operator<(const NamedPaperSize &data, const char *name)
  97. { return qstrcmp(data.name, name) < 0; }
  98. static inline QPrinter::PaperSize string2PaperSize(const char *name)
  99. {
  100. const NamedPaperSize *r = qBinaryFind(named_sizes_map, named_sizes_map + QPrinter::NPageSize, name);
  101. if (r - named_sizes_map != QPrinter::NPageSize)
  102. return r->size;
  103. return QPrinter::Custom;
  104. }
  105. static inline const char *paperSize2String(QPrinter::PaperSize size)
  106. {
  107. for (int i = 0; i < QPrinter::NPageSize; ++i) {
  108. if (size == named_sizes_map[i].size)
  109. return named_sizes_map[i].name;
  110. }
  111. return 0;
  112. }
  113. #endif
  114. void qt_perhapsAddPrinter(QList<QPrinterDescription> *printers, const QString &name,
  115. QString host, QString comment,
  116. QStringList aliases)
  117. {
  118. for (int i = 0; i < printers->size(); ++i)
  119. if (printers->at(i).samePrinter(name))
  120. return;
  121. #ifndef QT_NO_PRINTDIALOG
  122. if (host.isEmpty())
  123. host = QPrintDialog::tr("locally connected");
  124. #endif
  125. printers->append(QPrinterDescription(name.simplified(), host.simplified(), comment.simplified(), aliases));
  126. }
  127. void qt_parsePrinterDesc(QString printerDesc, QList<QPrinterDescription> *printers)
  128. {
  129. if (printerDesc.length() < 1)
  130. return;
  131. printerDesc = printerDesc.simplified();
  132. int i = printerDesc.indexOf(QLatin1Char(':'));
  133. QString printerName, printerComment, printerHost;
  134. QStringList aliases;
  135. if (i >= 0) {
  136. // have ':' want '|'
  137. int j = printerDesc.indexOf(QLatin1Char('|'));
  138. if (j > 0 && j < i) {
  139. printerName = printerDesc.left(j);
  140. aliases = printerDesc.mid(j + 1, i - j - 1).split(QLatin1Char('|'));
  141. #ifndef QT_NO_PRINTDIALOG
  142. // try extracting a comment from the aliases
  143. printerComment = QPrintDialog::tr("Aliases: %1")
  144. .arg(aliases.join(QLatin1String(", ")));
  145. #endif
  146. } else {
  147. printerName = printerDesc.left(i);
  148. }
  149. // look for lprng pseudo all printers entry
  150. i = printerDesc.indexOf(QRegExp(QLatin1String(": *all *=")));
  151. if (i >= 0)
  152. printerName = QString();
  153. // look for signs of this being a remote printer
  154. i = printerDesc.indexOf(QRegExp(QLatin1String(": *rm *=")));
  155. if (i >= 0) {
  156. // point k at the end of remote host name
  157. while (printerDesc[i] != QLatin1Char('='))
  158. i++;
  159. while (printerDesc[i] == QLatin1Char('=') || printerDesc[i].isSpace())
  160. i++;
  161. j = i;
  162. while (j < (int)printerDesc.length() && printerDesc[j] != QLatin1Char(':'))
  163. j++;
  164. // and stuff that into the string
  165. printerHost = printerDesc.mid(i, j - i);
  166. }
  167. }
  168. if (printerName.length())
  169. qt_perhapsAddPrinter(printers, printerName, printerHost, printerComment,
  170. aliases);
  171. }
  172. int qt_parsePrintcap(QList<QPrinterDescription> *printers, const QString& fileName)
  173. {
  174. QFile printcap(fileName);
  175. if (!printcap.open(QIODevice::ReadOnly))
  176. return NotFound;
  177. char *line_ascii = new char[1025];
  178. line_ascii[1024] = '\0';
  179. QString printerDesc;
  180. bool atEnd = false;
  181. while (!atEnd) {
  182. if (printcap.atEnd() || printcap.readLine(line_ascii, 1024) <= 0)
  183. atEnd = true;
  184. QString line = QString::fromLocal8Bit(line_ascii);
  185. line = line.trimmed();
  186. if (line.length() >= 1 && line[int(line.length()) - 1] == QLatin1Char('\\'))
  187. line.chop(1);
  188. if (line[0] == QLatin1Char('#')) {
  189. if (!atEnd)
  190. continue;
  191. } else if (line[0] == QLatin1Char('|') || line[0] == QLatin1Char(':')
  192. || line.isEmpty()) {
  193. printerDesc += line;
  194. if (!atEnd)
  195. continue;
  196. }
  197. qt_parsePrinterDesc(printerDesc, printers);
  198. // add the first line of the new printer definition
  199. printerDesc = line;
  200. }
  201. delete[] line_ascii;
  202. return Success;
  203. }
  204. /*!
  205. \internal
  206. Checks $HOME/.printers for a line matching '_default <name>' (where
  207. <name> does not contain any white space). The first such match
  208. results in <name> being returned.
  209. If no lines match then an empty string is returned.
  210. */
  211. QString qt_getDefaultFromHomePrinters()
  212. {
  213. QFile file(QDir::homePath() + QLatin1String("/.printers"));
  214. if (!file.open(QIODevice::ReadOnly))
  215. return QString();
  216. QString all(QLatin1String(file.readAll()));
  217. QStringList words = all.split(QRegExp(QLatin1String("\\W+")), QString::SkipEmptyParts);
  218. const int i = words.indexOf(QLatin1String("_default"));
  219. if (i != -1 && i < words.size() - 1)
  220. return words.at(i + 1);
  221. return QString();
  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. QString tmp;
  231. for (int i = 0; i < dirs.size(); ++i) {
  232. QFileInfo printer = dirs.at(i);
  233. if (printer.isDir()) {
  234. tmp.sprintf("/etc/lp/printers/%s/configuration",
  235. printer.fileName().toAscii().data());
  236. QFile configuration(tmp);
  237. char *line = new char[1025];
  238. QString remote(QLatin1String("Remote:"));
  239. QString contentType(QLatin1String("Content types:"));
  240. QString printerHost;
  241. bool canPrintPostscript = false;
  242. if (configuration.open(QIODevice::ReadOnly)) {
  243. while (!configuration.atEnd() &&
  244. configuration.readLine(line, 1024) > 0) {
  245. if (QString::fromLatin1(line).startsWith(remote)) {
  246. const char *p = line;
  247. while (*p != ':')
  248. p++;
  249. p++;
  250. while (isspace((uchar) *p))
  251. p++;
  252. printerHost = QString::fromLocal8Bit(p);
  253. printerHost = printerHost.simplified();
  254. } else if (QString::fromLatin1(line).startsWith(contentType)) {
  255. char *p = line;
  256. while (*p != ':')
  257. p++;
  258. p++;
  259. char *e;
  260. while (*p) {
  261. while (isspace((uchar) *p))
  262. p++;
  263. if (*p) {
  264. char s;
  265. e = p;
  266. while (isalnum((uchar) *e))
  267. e++;
  268. s = *e;
  269. *e = '\0';
  270. if (!qstrcmp(p, "postscript") ||
  271. !qstrcmp(p, "any"))
  272. canPrintPostscript = true;
  273. *e = s;
  274. if (s == ',')
  275. e++;
  276. p = e;
  277. }
  278. }
  279. }
  280. }
  281. if (canPrintPostscript)
  282. qt_perhapsAddPrinter(printers, printer.fileName(),
  283. printerHost, QLatin1String(""));
  284. }
  285. delete[] line;
  286. }
  287. }
  288. }
  289. // solaris 2.6
  290. char *qt_parsePrintersConf(QList<QPrinterDescription> *printers, bool *found)
  291. {
  292. QFile pc(QLatin1String("/etc/printers.conf"));
  293. if (!pc.open(QIODevice::ReadOnly)) {
  294. if (found)
  295. *found = false;
  296. return 0;
  297. }
  298. if (found)
  299. *found = true;
  300. char *line = new char[1025];
  301. line[1024] = '\0';
  302. QString printerDesc;
  303. int lineLength = 0;
  304. char *defaultPrinter = 0;
  305. while (!pc.atEnd() &&
  306. (lineLength=pc.readLine(line, 1024)) > 0) {
  307. if (*line == '#') {
  308. *line = '\0';
  309. lineLength = 0;
  310. }
  311. if (lineLength >= 2 && line[lineLength-2] == '\\') {
  312. line[lineLength-2] = '\0';
  313. printerDesc += QString::fromLocal8Bit(line);
  314. } else {
  315. printerDesc += QString::fromLocal8Bit(line);
  316. printerDesc = printerDesc.simplified();
  317. int i = printerDesc.indexOf(QLatin1Char(':'));
  318. QString printerName, printerHost, printerComment;
  319. QStringList aliases;
  320. if (i >= 0) {
  321. // have : want |
  322. int j = printerDesc.indexOf(QLatin1Char('|'));
  323. if (j >= i)
  324. j = -1;
  325. printerName = printerDesc.mid(0, j < 0 ? i : j);
  326. if (printerName == QLatin1String("_default")) {
  327. i = printerDesc.indexOf(
  328. QRegExp(QLatin1String(": *use *=")));
  329. while (printerDesc[i] != QLatin1Char('='))
  330. i++;
  331. while (printerDesc[i] == QLatin1Char('=') || printerDesc[i].isSpace())
  332. i++;
  333. j = i;
  334. while (j < (int)printerDesc.length() &&
  335. printerDesc[j] != QLatin1Char(':') && printerDesc[j] != QLatin1Char(','))
  336. j++;
  337. // that's our default printer
  338. defaultPrinter =
  339. qstrdup(printerDesc.mid(i, j-i).toAscii().data());
  340. printerName = QString();
  341. printerDesc = QString();
  342. } else if (printerName == QLatin1String("_all")) {
  343. // skip it.. any other cases we want to skip?
  344. printerName = QString();
  345. printerDesc = QString();
  346. }
  347. if (j > 0) {
  348. // try extracting a comment from the aliases
  349. aliases = printerDesc.mid(j + 1, i - j - 1).split(QLatin1Char('|'));
  350. #ifndef QT_NO_PRINTDIALOG
  351. printerComment = QPrintDialog::tr("Aliases: %1")
  352. .arg(aliases.join(QLatin1String(", ")));
  353. #endif
  354. }
  355. // look for signs of this being a remote printer
  356. i = printerDesc.indexOf(
  357. QRegExp(QLatin1String(": *bsdaddr *=")));
  358. if (i >= 0) {
  359. // point k at the end of remote host name
  360. while (printerDesc[i] != QLatin1Char('='))
  361. i++;
  362. while (printerDesc[i] == QLatin1Char('=') || printerDesc[i].isSpace())
  363. i++;
  364. j = i;
  365. while (j < (int)printerDesc.length() &&
  366. printerDesc[j] != QLatin1Char(':') && printerDesc[j] != QLatin1Char(','))
  367. j++;
  368. // and stuff that into the string
  369. printerHost = printerDesc.mid(i, j-i);
  370. // maybe stick the remote printer name into the comment
  371. if (printerDesc[j] == QLatin1Char(',')) {
  372. i = ++j;
  373. while (printerDesc[i].isSpace())
  374. i++;
  375. j = i;
  376. while (j < (int)printerDesc.length() &&
  377. printerDesc[j] != QLatin1Char(':') && printerDesc[j] != QLatin1Char(','))
  378. j++;
  379. if (printerName != printerDesc.mid(i, j-i)) {
  380. printerComment =
  381. QLatin1String("Remote name: ");
  382. printerComment += printerDesc.mid(i, j-i);
  383. }
  384. }
  385. }
  386. }
  387. if (printerComment == QLatin1String(":"))
  388. printerComment = QString(); // for cups
  389. if (printerName.length())
  390. qt_perhapsAddPrinter(printers, printerName, printerHost,
  391. printerComment, aliases);
  392. // chop away the line, for processing the next one
  393. printerDesc = QString();
  394. }
  395. }
  396. delete[] line;
  397. return defaultPrinter;
  398. }
  399. #ifndef QT_NO_NIS
  400. #if defined(Q_C_CALLBACKS)
  401. extern "C" {
  402. #endif
  403. int qt_pd_foreach(int /*status */, char * /*key */, int /*keyLen */,
  404. char *val, int valLen, char *data)
  405. {
  406. qt_parsePrinterDesc(QString::fromLatin1(val, valLen), (QList<QPrinterDescription> *)data);
  407. return 0;
  408. }
  409. #if defined(Q_C_CALLBACKS)
  410. }
  411. #endif
  412. int qt_retrieveNisPrinters(QList<QPrinterDescription> *printers)
  413. {
  414. #ifndef QT_NO_LIBRARY
  415. typedef int (*WildCast)(int, char *, int, char *, int, char *);
  416. char printersConfByname[] = "printers.conf.byname";
  417. char *domain;
  418. int err;
  419. QLibrary lib(QLatin1String("nsl"));
  420. typedef int (*ypGetDefaultDomain)(char **);
  421. ypGetDefaultDomain _ypGetDefaultDomain = (ypGetDefaultDomain)lib.resolve("yp_get_default_domain");
  422. typedef int (*ypAll)(const char *, const char *, const struct ypall_callback *);
  423. ypAll _ypAll = (ypAll)lib.resolve("yp_all");
  424. if (_ypGetDefaultDomain && _ypAll) {
  425. err = _ypGetDefaultDomain(&domain);
  426. if (err == 0) {
  427. ypall_callback cb;
  428. // wild cast to support K&R-style system headers
  429. (WildCast &) cb.foreach = (WildCast) qt_pd_foreach;
  430. cb.data = (char *) printers;
  431. err = _ypAll(domain, printersConfByname, &cb);
  432. }
  433. if (!err)
  434. return Success;
  435. }
  436. #endif //QT_NO_LIBRARY
  437. return Unavail;
  438. }
  439. #endif // QT_NO_NIS
  440. char *qt_parseNsswitchPrintersEntry(QList<QPrinterDescription> *printers, char *line)
  441. {
  442. #define skipSpaces() \
  443. while (line[k] != '\0' && isspace((uchar) line[k])) \
  444. k++
  445. char *defaultPrinter = 0;
  446. bool stop = false;
  447. int lastStatus = NotFound;
  448. int k = 8;
  449. skipSpaces();
  450. if (line[k] != ':')
  451. return 0;
  452. k++;
  453. char *cp = strchr(line, '#');
  454. if (cp != 0)
  455. *cp = '\0';
  456. while (line[k] != '\0') {
  457. if (isspace((uchar) line[k])) {
  458. k++;
  459. } else if (line[k] == '[') {
  460. k++;
  461. skipSpaces();
  462. while (line[k] != '\0') {
  463. char status = tolower(line[k]);
  464. char action = '?';
  465. while (line[k] != '=' && line[k] != ']' && line[k] != '\0')
  466. k++;
  467. if (line[k] == '=') {
  468. k++;
  469. skipSpaces();
  470. action = tolower(line[k]);
  471. while (line[k] != '\0' && !isspace((uchar) line[k]) && line[k] != ']')
  472. k++;
  473. } else if (line[k] == ']') {
  474. k++;
  475. break;
  476. }
  477. skipSpaces();
  478. if (lastStatus == status)
  479. stop = (action == (char) Return);
  480. }
  481. } else {
  482. if (stop)
  483. break;
  484. QByteArray source;
  485. while (line[k] != '\0' && !isspace((uchar) line[k]) && line[k] != '[') {
  486. source += line[k];
  487. k++;
  488. }
  489. if (source == "user") {
  490. lastStatus = qt_parsePrintcap(printers,
  491. QDir::homePath() + QLatin1String("/.printers"));
  492. } else if (source == "files") {
  493. bool found;
  494. defaultPrinter = qt_parsePrintersConf(printers, &found);
  495. if (found)
  496. lastStatus = Success;
  497. #ifndef QT_NO_NIS
  498. } else if (source == "nis") {
  499. lastStatus = qt_retrieveNisPrinters(printers);
  500. #endif
  501. } else {
  502. // nisplus, dns, etc., are not implemented yet
  503. lastStatus = NotFound;
  504. }
  505. stop = (lastStatus == Success);
  506. }
  507. }
  508. return defaultPrinter;
  509. }
  510. char *qt_parseNsswitchConf(QList<QPrinterDescription> *printers)
  511. {
  512. QFile nc(QLatin1String("/etc/nsswitch.conf"));
  513. if (!nc.open(QIODevice::ReadOnly))
  514. return 0;
  515. char *defaultPrinter = 0;
  516. char *line = new char[1025];
  517. line[1024] = '\0';
  518. while (!nc.atEnd() &&
  519. nc.readLine(line, 1024) > 0) {
  520. if (qstrncmp(line, "printers", 8) == 0) {
  521. defaultPrinter = qt_parseNsswitchPrintersEntry(printers, line);
  522. delete[] line;
  523. return defaultPrinter;
  524. }
  525. }
  526. strcpy(line, "printers: user files nis nisplus xfn");
  527. defaultPrinter = qt_parseNsswitchPrintersEntry(printers, line);
  528. delete[] line;
  529. return defaultPrinter;
  530. }
  531. // HP-UX
  532. void qt_parseEtcLpMember(QList<QPrinterDescription> *printers)
  533. {
  534. QDir lp(QLatin1String("/etc/lp/member"));
  535. if (!lp.exists())
  536. return;
  537. QFileInfoList dirs = lp.entryInfoList();
  538. if (dirs.isEmpty())
  539. return;
  540. #ifdef QT_NO_PRINTDIALOG
  541. Q_UNUSED(printers);
  542. #else
  543. QString tmp;
  544. for (int i = 0; i < dirs.size(); ++i) {
  545. QFileInfo printer = dirs.at(i);
  546. // I haven't found any real documentation, so I'm guessing that
  547. // since lpstat uses /etc/lp/member rather than one of the
  548. // other directories, it's the one to use. I did not find a
  549. // decent way to locate aliases and remote printers.
  550. if (printer.isFile())
  551. qt_perhapsAddPrinter(printers, printer.fileName(),
  552. QPrintDialog::tr("unknown"),
  553. QLatin1String(""));
  554. }
  555. #endif
  556. }
  557. // IRIX 6.x
  558. void qt_parseSpoolInterface(QList<QPrinterDescription> *printers)
  559. {
  560. QDir lp(QLatin1String("/usr/spool/lp/interface"));
  561. if (!lp.exists())
  562. return;
  563. QFileInfoList files = lp.entryInfoList();
  564. if(files.isEmpty())
  565. return;
  566. for (int i = 0; i < files.size(); ++i) {
  567. QFileInfo printer = files.at(i);
  568. if (!printer.isFile())
  569. continue;
  570. // parse out some information
  571. QFile configFile(printer.filePath());
  572. if (!configFile.open(QIODevice::ReadOnly))
  573. continue;
  574. QByteArray line;
  575. line.resize(1025);
  576. QString namePrinter;
  577. QString hostName;
  578. QString hostPrinter;
  579. QString printerType;
  580. QString nameKey(QLatin1String("NAME="));
  581. QString typeKey(QLatin1String("TYPE="));
  582. QString hostKey(QLatin1String("HOSTNAME="));
  583. QString hostPrinterKey(QLatin1String("HOSTPRINTER="));
  584. while (!configFile.atEnd() &&
  585. (configFile.readLine(line.data(), 1024)) > 0) {
  586. QString uline = QString::fromLocal8Bit(line);
  587. if (uline.startsWith(typeKey) ) {
  588. printerType = uline.mid(nameKey.length());
  589. printerType = printerType.simplified();
  590. } else if (uline.startsWith(hostKey)) {
  591. hostName = uline.mid(hostKey.length());
  592. hostName = hostName.simplified();
  593. } else if (uline.startsWith(hostPrinterKey)) {
  594. hostPrinter = uline.mid(hostPrinterKey.length());
  595. hostPrinter = hostPrinter.simplified();
  596. } else if (uline.startsWith(nameKey)) {
  597. namePrinter = uline.mid(nameKey.length());
  598. namePrinter = namePrinter.simplified();
  599. }
  600. }
  601. configFile.close();
  602. printerType = printerType.trimmed();
  603. if (printerType.indexOf(QLatin1String("postscript"), 0, Qt::CaseInsensitive) < 0)
  604. continue;
  605. int ii = 0;
  606. while ((ii = namePrinter.indexOf(QLatin1Char('"'), ii)) >= 0)
  607. namePrinter.remove(ii, 1);
  608. if (hostName.isEmpty() || hostPrinter.isEmpty()) {
  609. qt_perhapsAddPrinter(printers, printer.fileName(),
  610. QLatin1String(""), namePrinter);
  611. } else {
  612. QString comment;
  613. comment = namePrinter;
  614. comment += QLatin1String(" (");
  615. comment += hostPrinter;
  616. comment += QLatin1Char(')');
  617. qt_perhapsAddPrinter(printers, printer.fileName(),
  618. hostName, comment);
  619. }
  620. }
  621. }
  622. // Every unix must have its own. It's a standard. Here is AIX.
  623. void qt_parseQconfig(QList<QPrinterDescription> *printers)
  624. {
  625. QFile qconfig(QLatin1String("/etc/qconfig"));
  626. if (!qconfig.open(QIODevice::ReadOnly))
  627. return;
  628. QTextStream ts(&qconfig);
  629. QString line;
  630. QString stanzaName; // either a queue or a device name
  631. bool up = true; // queue up? default true, can be false
  632. QString remoteHost; // null if local
  633. QString deviceName; // null if remote
  634. QRegExp newStanza(QLatin1String("^[0-z\\-]*:$"));
  635. // our basic strategy here is to process each line, detecting new
  636. // stanzas. each time we see a new stanza, we check if the
  637. // previous stanza was a valid queue for a) a remote printer or b)
  638. // a local printer. if it wasn't, we assume that what we see is
  639. // the start of the first stanza, or that the previous stanza was
  640. // a device stanza, or that there is some syntax error (we don't
  641. // report those).
  642. do {
  643. line = ts.readLine();
  644. bool indented = line[0].isSpace();
  645. line = line.simplified();
  646. int i = line.indexOf(QLatin1Char('='));
  647. if (indented && i != -1) { // line in stanza
  648. QString variable = line.left(i).simplified();
  649. QString value=line.mid(i+1, line.length()).simplified();
  650. if (variable == QLatin1String("device"))
  651. deviceName = value;
  652. else if (variable == QLatin1String("host"))
  653. remoteHost = value;
  654. else if (variable == QLatin1String("up"))
  655. up = !(value.toLower() == QLatin1String("false"));
  656. } else if (line[0] == QLatin1Char('*')) { // comment
  657. // nothing to do
  658. } else if (ts.atEnd() || // end of file, or beginning of new stanza
  659. (!indented && line.contains(newStanza))) {
  660. if (up && stanzaName.length() > 0 && stanzaName.length() < 21) {
  661. if (remoteHost.length()) // remote printer
  662. qt_perhapsAddPrinter(printers, stanzaName, remoteHost,
  663. QString());
  664. else if (deviceName.length()) // local printer
  665. qt_perhapsAddPrinter(printers, stanzaName, QString(),
  666. QString());
  667. }
  668. line.chop(1);
  669. if (line.length() >= 1 && line.length() <= 20)
  670. stanzaName = line;
  671. up = true;
  672. remoteHost.clear();
  673. deviceName.clear();
  674. } else {
  675. // syntax error? ignore.
  676. }
  677. } while (!ts.atEnd());
  678. }
  679. int qt_getLprPrinters(QList<QPrinterDescription>& printers)
  680. {
  681. QByteArray etcLpDefault;
  682. qt_parsePrintcap(&printers, QLatin1String("/etc/printcap"));
  683. qt_parseEtcLpMember(&printers);
  684. qt_parseSpoolInterface(&printers);
  685. qt_parseQconfig(&printers);
  686. QFileInfo f;
  687. f.setFile(QLatin1String("/etc/lp/printers"));
  688. if (f.isDir()) {
  689. qt_parseEtcLpPrinters(&printers);
  690. QFile def(QLatin1String("/etc/lp/default"));
  691. if (def.open(QIODevice::ReadOnly)) {
  692. etcLpDefault.resize(1025);
  693. if (def.readLine(etcLpDefault.data(), 1024) > 0) {
  694. QRegExp rx(QLatin1String("^(\\S+)"));
  695. if (rx.indexIn(QString::fromLatin1(etcLpDefault)) != -1)
  696. etcLpDefault = rx.cap(1).toAscii();
  697. }
  698. }
  699. }
  700. char *def = 0;
  701. f.setFile(QLatin1String("/etc/nsswitch.conf"));
  702. if (f.isFile()) {
  703. def = qt_parseNsswitchConf(&printers);
  704. } else {
  705. f.setFile(QLatin1String("/etc/printers.conf"));
  706. if (f.isFile())
  707. def = qt_parsePrintersConf(&printers);
  708. }
  709. if (def) {
  710. etcLpDefault = def;
  711. delete [] def;
  712. }
  713. QString homePrintersDefault = qt_getDefaultFromHomePrinters();
  714. // all printers hopefully known. try to find a good default
  715. QString dollarPrinter;
  716. {
  717. dollarPrinter = QString::fromLocal8Bit(qgetenv("PRINTER"));
  718. if (dollarPrinter.isEmpty())
  719. dollarPrinter = QString::fromLocal8Bit(qgetenv("LPDEST"));
  720. if (dollarPrinter.isEmpty())
  721. dollarPrinter = QString::fromLocal8Bit(qgetenv("NPRINTER"));
  722. if (dollarPrinter.isEmpty())
  723. dollarPrinter = QString::fromLocal8Bit(qgetenv("NGPRINTER"));
  724. #ifndef QT_NO_PRINTDIALOG
  725. if (!dollarPrinter.isEmpty())
  726. qt_perhapsAddPrinter(&printers, dollarPrinter,
  727. QPrintDialog::tr("unknown"),
  728. QLatin1String(""));
  729. #endif
  730. }
  731. QRegExp ps(QLatin1String("[^a-z]ps(?:[^a-z]|$)"));
  732. QRegExp lp(QLatin1String("[^a-z]lp(?:[^a-z]|$)"));
  733. int quality = 0;
  734. int best = 0;
  735. for (int i = 0; i < printers.size(); ++i) {
  736. QString name = printers.at(i).name;
  737. QString comment = printers.at(i).comment;
  738. if (quality < 5 && name == dollarPrinter) {
  739. best = i;
  740. quality = 5;
  741. } else if (quality < 4 && !homePrintersDefault.isEmpty() &&
  742. name == homePrintersDefault) {
  743. best = i;
  744. quality = 4;
  745. } else if (quality < 3 && !etcLpDefault.isEmpty() &&
  746. name == QLatin1String(etcLpDefault)) {
  747. best = i;
  748. quality = 3;
  749. } else if (quality < 2 &&
  750. (name == QLatin1String("ps") ||
  751. ps.indexIn(comment) != -1)) {
  752. best = i;
  753. quality = 2;
  754. } else if (quality < 1 &&
  755. (name == QLatin1String("lp") ||
  756. lp.indexIn(comment) > -1)) {
  757. best = i;
  758. quality = 1;
  759. }
  760. }
  761. return best;
  762. }
  763. /////////////////////////////////////////////////////////////////////////////
  764. /////////////////////////////////////////////////////////////////////////////
  765. QList<QPrinterInfo> QPrinterInfo::availablePrinters()
  766. {
  767. QList<QPrinterInfo> printers;
  768. #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
  769. if (QCUPSSupport::isAvailable()) {
  770. QCUPSSupport cups;
  771. int cupsPrinterCount = cups.availablePrintersCount();
  772. const cups_dest_t* cupsPrinters = cups.availablePrinters();
  773. for (int i = 0; i < cupsPrinterCount; ++i) {
  774. QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
  775. if (cupsPrinters[i].instance)
  776. printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
  777. QPrinterInfo printerInfo(printerName);
  778. if (cupsPrinters[i].is_default)
  779. printerInfo.d_ptr->isDefault = true;
  780. printerInfo.d_ptr->cupsPrinterIndex = i;
  781. printers.append(printerInfo);
  782. }
  783. } else
  784. #endif
  785. {
  786. QList<QPrinterDescription> lprPrinters;
  787. int defprn = qt_getLprPrinters(lprPrinters);
  788. // populating printer combo
  789. foreach (const QPrinterDescription &description, lprPrinters)
  790. printers.append(QPrinterInfo(description.name));
  791. if (defprn >= 0 && defprn < printers.size())
  792. printers[defprn].d_ptr->isDefault = true;
  793. }
  794. return printers;
  795. }
  796. QPrinterInfo QPrinterInfo::defaultPrinter()
  797. {
  798. QList<QPrinterInfo> printers = availablePrinters();
  799. foreach (const QPrinterInfo &printerInfo, printers) {
  800. if (printerInfo.isDefault())
  801. return printerInfo;
  802. }
  803. return printers.value(0);
  804. }
  805. QList<QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const
  806. {
  807. #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
  808. const Q_D(QPrinterInfo);
  809. if (isNull())
  810. return d->paperSizes;
  811. if (!d->hasPaperSizes) {
  812. d->hasPaperSizes = true;
  813. if (QCUPSSupport::isAvailable()) {
  814. // Find paper sizes from CUPS.
  815. QCUPSSupport cups;
  816. cups.setCurrentPrinter(d->cupsPrinterIndex);
  817. const ppd_option_t* sizes = cups.pageSizes();
  818. if (sizes) {
  819. for (int j = 0; j < sizes->num_choices; ++j)
  820. d->paperSizes.append(string2PaperSize(sizes->choices[j].choice));
  821. }
  822. }
  823. }
  824. return d->paperSizes;
  825. #else
  826. return QList<QPrinter::PaperSize>();
  827. #endif
  828. }
  829. #endif // QT_NO_PRINTER
  830. QT_END_NAMESPACE