1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2014 John Layt <jlayt@kde.org>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qcupsprintersupport_p.h"
42
43#include "qcupsprintengine_p.h"
44#include "qppdprintdevice.h"
45#include <private/qprinterinfo_p.h>
46#include <private/qprintdevice_p.h>
47
48#include <QtPrintSupport/QPrinterInfo>
49
50#if QT_CONFIG(dialogbuttonbox)
51#include <QGuiApplication>
52#include <QDialog>
53#include <QDialogButtonBox>
54#include <QFormLayout>
55#include <QLabel>
56#include <QLineEdit>
57#endif // QT_CONFIG(dialogbuttonbox)
58
59#include <cups/ppd.h>
60#ifndef QT_LINUXBASE // LSB merges everything into cups.h
61# include <cups/language.h>
62#endif
63
64QT_BEGIN_NAMESPACE
65
66#if QT_CONFIG(dialogbuttonbox)
67static const char *getPasswordCB(const char */*prompt*/, http_t *http, const char */*method*/, const char *resource, void */*user_data*/)
68{
69 // cups doesn't free the const char * we return so keep around
70 // the last password so we don't leak memory if called multiple times.
71 static QByteArray password;
72
73 // prompt is always "Password for %s on %s? " but we can't use it since we allow the user to change the user.
74 // That is fine because cups always calls cupsUser after calling this callback.
75 // We build our own prompt with the hostname (if not localhost) and the resource that is being used
76
77 char hostname[HTTP_MAX_HOST];
78 httpGetHostname(http, s: hostname, HTTP_MAX_HOST);
79
80 const QString username = QString::fromLocal8Bit(str: cupsUser());
81
82 QDialog dialog;
83 dialog.setWindowTitle(QCoreApplication::translate(context: "QCupsPrinterSupport", key: "Authentication Needed"));
84
85 QFormLayout *layout = new QFormLayout(&dialog);
86 layout->setSizeConstraint(QLayout::SetFixedSize);
87
88 QLineEdit *usernameLE = new QLineEdit();
89 usernameLE->setText(username);
90
91 QLineEdit *passwordLE = new QLineEdit();
92 passwordLE->setEchoMode(QLineEdit::Password);
93
94 QString resourceString = QString::fromLocal8Bit(str: resource);
95 if (resourceString.startsWith(QStringLiteral("/printers/")))
96 resourceString = resourceString.mid(QStringLiteral("/printers/").length());
97
98 QLabel *label = new QLabel();
99 if (hostname == QStringLiteral("localhost")) {
100 label->setText(QCoreApplication::translate(context: "QCupsPrinterSupport", key: "Authentication needed to use %1.").arg(a: resourceString));
101 } else {
102 label->setText(QCoreApplication::translate(context: "QCupsPrinterSupport", key: "Authentication needed to use %1 on %2.").arg(a: resourceString).arg(a: hostname));
103 label->setWordWrap(true);
104 }
105
106 layout->addRow(widget: label);
107 layout->addRow(label: new QLabel(QCoreApplication::translate(context: "QCupsPrinterSupport", key: "Username:")), field: usernameLE);
108 layout->addRow(label: new QLabel(QCoreApplication::translate(context: "QCupsPrinterSupport", key: "Password:")), field: passwordLE);
109
110 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
111 layout->addRow(widget: buttonBox);
112
113 QObject::connect(sender: buttonBox, signal: &QDialogButtonBox::accepted, receiver: &dialog, slot: &QDialog::accept);
114 QObject::connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, receiver: &dialog, slot: &QDialog::reject);
115
116 passwordLE->setFocus();
117
118 if (dialog.exec() != QDialog::Accepted)
119 return nullptr;
120
121 if (usernameLE->text() != username)
122 cupsSetUser(user: usernameLE->text().toLocal8Bit().constData());
123
124 password = passwordLE->text().toLocal8Bit();
125
126 return password.constData();
127}
128#endif // QT_CONFIG(dialogbuttonbox)
129
130QCupsPrinterSupport::QCupsPrinterSupport()
131 : QPlatformPrinterSupport()
132{
133#if QT_CONFIG(dialogbuttonbox)
134 // Only show password dialog if GUI application
135 if (qobject_cast<QGuiApplication*>(object: QCoreApplication::instance()))
136 cupsSetPasswordCB2(cb: getPasswordCB, user_data: nullptr /* user_data */ );
137#endif // QT_CONFIG(dialogbuttonbox)
138}
139
140QCupsPrinterSupport::~QCupsPrinterSupport()
141{
142}
143
144QPrintEngine *QCupsPrinterSupport::createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId)
145{
146 return new QCupsPrintEngine(printerMode, (deviceId.isEmpty() ? defaultPrintDeviceId() : deviceId));
147}
148
149QPaintEngine *QCupsPrinterSupport::createPaintEngine(QPrintEngine *engine, QPrinter::PrinterMode printerMode)
150{
151 Q_UNUSED(printerMode)
152 return static_cast<QCupsPrintEngine *>(engine);
153}
154
155QPrintDevice QCupsPrinterSupport::createPrintDevice(const QString &id)
156{
157 return QPlatformPrinterSupport::createPrintDevice(device: new QPpdPrintDevice(id));
158}
159
160QStringList QCupsPrinterSupport::availablePrintDeviceIds() const
161{
162 QStringList list;
163 cups_dest_t *dests;
164 int count = cupsGetDests(dests: &dests);
165 list.reserve(alloc: count);
166 for (int i = 0; i < count; ++i) {
167 QString printerId = QString::fromLocal8Bit(str: dests[i].name);
168 if (dests[i].instance)
169 printerId += QLatin1Char('/') + QString::fromLocal8Bit(str: dests[i].instance);
170 list.append(t: printerId);
171 }
172 cupsFreeDests(num_dests: count, dests);
173 return list;
174}
175
176QString QCupsPrinterSupport::defaultPrintDeviceId() const
177{
178 return staticDefaultPrintDeviceId();
179}
180
181QString QCupsPrinterSupport::staticDefaultPrintDeviceId()
182{
183 QString printerId;
184 cups_dest_t *dests;
185 int count = cupsGetDests(dests: &dests);
186 for (int i = 0; i < count; ++i) {
187 if (dests[i].is_default) {
188 printerId = QString::fromLocal8Bit(str: dests[i].name);
189 if (dests[i].instance) {
190 printerId += QLatin1Char('/') + QString::fromLocal8Bit(str: dests[i].instance);
191 break;
192 }
193 }
194 }
195 cupsFreeDests(num_dests: count, dests);
196 return printerId;
197}
198
199QT_END_NAMESPACE
200

source code of qtbase/src/plugins/printsupport/cups/qcupsprintersupport.cpp