File indexing completed on 2025-01-05 05:09:28
0001 /* 0002 SPDX-FileCopyrightText: 2010-2018 Daniel Nicoletti <dantti12@gmail.com> 0003 SPDX-FileCopyrightText: 2023 Mike Noe <noeerover@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "NewPrinterNotification.h" 0009 #include "newprinternotificationadaptor.h" 0010 0011 #include "pmkded_log.h" 0012 0013 #include <KLocalizedString> 0014 #include <KNotification> 0015 0016 #include <KCupsRequest.h> 0017 #include <ProcessRunner.h> 0018 0019 #include <QDBusConnection> 0020 #include <QDBusMessage> 0021 #include <QDBusPendingCallWatcher> 0022 #include <QDBusPendingReply> 0023 #include <QDBusServiceWatcher> 0024 0025 #define STATUS_SUCCESS 0 0026 #define STATUS_MODEL_MISMATCH 1 0027 #define STATUS_GENERIC_DRIVER 2 0028 #define STATUS_NO_DRIVER 3 0029 0030 #define PRINTER_NAME "PrinterName" 0031 0032 NewPrinterNotification::NewPrinterNotification(QObject *parent) 0033 : QObject(parent) 0034 { 0035 // Creates our new adaptor 0036 (void)new NewPrinterNotificationAdaptor(this); 0037 0038 // Register the com.redhat.NewPrinterNotification interface 0039 if (!registerService()) { 0040 // in case registration fails due to another user or application running 0041 // keep an eye on it so we can register when available 0042 auto watcher = new QDBusServiceWatcher(QLatin1String("com.redhat.NewPrinterNotification"), 0043 QDBusConnection::systemBus(), 0044 QDBusServiceWatcher::WatchForUnregistration, 0045 this); 0046 connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &NewPrinterNotification::registerService); 0047 } 0048 } 0049 0050 NewPrinterNotification::~NewPrinterNotification() 0051 { 0052 } 0053 0054 void NewPrinterNotification::GetReady() 0055 { 0056 qCDebug(PMKDED) << "GetReady"; 0057 // This method is all about telling the user a new printer was detected 0058 auto notify = new KNotification(QLatin1String("GetReady")); 0059 notify->setComponentName(QLatin1String("printmanager")); 0060 notify->setIconName(QLatin1String("printer")); 0061 notify->setTitle(i18n("A New Printer was detected")); 0062 notify->setText(i18n("Configuring new printer...")); 0063 notify->sendEvent(); 0064 } 0065 0066 // status: 0 0067 // name: PSC_1400_series 0068 // mfg: HP 0069 // mdl: PSC 1400 series 0070 // des: 0071 // cmd: LDL,MLC,PML,DYN 0072 void NewPrinterNotification::NewPrinter(int status, 0073 const QString &name, 0074 const QString &make, 0075 const QString &model, 0076 const QString &description, 0077 const QString &cmd) 0078 { 0079 qCDebug(PMKDED) << status << name << make << model << description << cmd; 0080 0081 // 1 0082 // "usb://Samsung/SCX-3400%20Series?serial=Z6Y1BQAC500079K&interface=1" 0083 // mfg "Samsung" 0084 // mdl "SCX-3400 Series" "" "SPL,FWV,PIC,BDN,EXT" 0085 // This method is all about telling the user a new printer was detected 0086 auto notify = new KNotification(QLatin1String("NewPrinterNotification")); 0087 notify->setComponentName(QLatin1String("printmanager")); 0088 notify->setIconName(QLatin1String("printer")); 0089 notify->setFlags(KNotification::Persistent); 0090 0091 if (name.contains(QLatin1Char('/'))) { 0092 const QString devid = QString::fromLatin1("MFG:%1;MDL:%2;DES:%3;CMD:%4;").arg(make, model, description, cmd); 0093 setupPrinterNotification(notify, make, model, description, name + QLatin1Char('/') + devid); 0094 } else { 0095 notify->setProperty(PRINTER_NAME, name); 0096 // name is the name of the queue which hal_lpadmin has set up 0097 // automatically. 0098 0099 if (status < STATUS_GENERIC_DRIVER) { 0100 notify->setTitle(i18n("The New Printer was Added")); 0101 } else { 0102 notify->setTitle(i18n("The New Printer is Missing Drivers")); 0103 } 0104 0105 auto request = new KCupsRequest; 0106 connect(request, &KCupsRequest::finished, this, [this, notify, status, name](KCupsRequest *request) { 0107 const QString ppdFileName = request->printerPPD(); 0108 // Get a list of missing executables 0109 getMissingExecutables(notify, status, name, ppdFileName); 0110 request->deleteLater(); 0111 }); 0112 request->getPrinterPPD(name); 0113 } 0114 } 0115 0116 bool NewPrinterNotification::registerService() 0117 { 0118 if (!QDBusConnection::systemBus().registerService(QLatin1String("com.redhat.NewPrinterNotification"))) { 0119 qCWarning(PMKDED) << "unable to register service to dbus"; 0120 return false; 0121 } 0122 0123 if (!QDBusConnection::systemBus().registerObject(QLatin1String("/com/redhat/NewPrinterNotification"), this)) { 0124 qCWarning(PMKDED) << "unable to register object to dbus"; 0125 return false; 0126 } 0127 return true; 0128 } 0129 0130 void NewPrinterNotification::configurePrinter() 0131 { 0132 const QString printerName = sender()->property(PRINTER_NAME).toString(); 0133 qCDebug(PMKDED) << "configure printer tool" << printerName; 0134 ProcessRunner::configurePrinter(printerName); 0135 } 0136 0137 void NewPrinterNotification::printTestPage() 0138 { 0139 const QString printerName = sender()->property(PRINTER_NAME).toString(); 0140 qCDebug(PMKDED) << "printing test page for" << printerName; 0141 0142 auto request = new KCupsRequest; 0143 connect(request, &KCupsRequest::finished, request, &KCupsRequest::deleteLater); 0144 request->printTestPage(printerName, false); 0145 } 0146 0147 void NewPrinterNotification::findDriver() 0148 { 0149 const QString printerName = sender()->property(PRINTER_NAME).toString(); 0150 qCDebug(PMKDED) << "find driver for" << printerName; 0151 0152 // This function will show the PPD browser dialog 0153 // to choose a better PPD to the already added printer 0154 ProcessRunner::changePrinterPPD(printerName); 0155 } 0156 0157 void NewPrinterNotification::setupPrinterNotification(KNotification *notify, 0158 const QString &make, 0159 const QString &model, 0160 const QString &description, 0161 const QString &arg) 0162 { 0163 // name is a URI, no queue was generated, because no suitable 0164 // driver was found 0165 notify->setTitle(i18n("Missing printer driver")); 0166 if (!make.isEmpty() && !model.isEmpty()) { 0167 notify->setText(i18n("No printer driver for %1 %2.", make, model)); 0168 } else if (!description.isEmpty()) { 0169 notify->setText(i18n("No printer driver for %1.", description)); 0170 } else { 0171 notify->setText(i18n("No driver for this printer.")); 0172 } 0173 auto searchAction = notify->addAction(i18n("Search")); 0174 connect(searchAction, &KNotificationAction::activated, this, [arg]() { 0175 qCDebug(PMKDED); 0176 // This function will show the PPD browser dialog 0177 // to choose a better PPD, queue name, location 0178 // in this case the printer was not added 0179 ProcessRunner::addPrinterFromDevice(arg); 0180 }); 0181 0182 notify->sendEvent(); 0183 } 0184 0185 void NewPrinterNotification::getMissingExecutables(KNotification *notify, int status, const QString &name, const QString &ppdFileName) 0186 { 0187 qCDebug(PMKDED) << "get missing executables" << ppdFileName; 0188 QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.fedoraproject.Config.Printing"), 0189 QLatin1String("/org/fedoraproject/Config/Printing"), 0190 QLatin1String("org.fedoraproject.Config.Printing"), 0191 QLatin1String("MissingExecutables")); 0192 message << ppdFileName; 0193 0194 QDBusPendingReply<QStringList> reply = QDBusConnection::sessionBus().asyncCall(message); 0195 auto watcher = new QDBusPendingCallWatcher(reply, this); 0196 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, notify, status, name]() { 0197 watcher->deleteLater(); 0198 QDBusPendingReply<QStringList> reply = *watcher; 0199 if (!reply.isValid()) { 0200 qCWarning(PMKDED) << "Invalid reply" << reply.error(); 0201 notify->deleteLater(); 0202 return; 0203 } 0204 0205 const QStringList missingExecutables = reply; 0206 if (!missingExecutables.isEmpty()) { 0207 // TODO check with PackageKit about missing drivers 0208 qCWarning(PMKDED) << "Missing executables:" << missingExecutables; 0209 notify->deleteLater(); 0210 return; 0211 } else if (status == STATUS_SUCCESS) { 0212 printerReadyNotification(notify, name); 0213 } else { 0214 // Model mismatch 0215 checkPrinterCurrentDriver(notify, name); 0216 } 0217 }); 0218 } 0219 0220 void NewPrinterNotification::checkPrinterCurrentDriver(KNotification *notify, const QString &name) 0221 { 0222 // Get the new printer attributes 0223 auto request = new KCupsRequest; 0224 connect(request, &KCupsRequest::finished, this, [this, notify, name](KCupsRequest *request) { 0225 request->deleteLater(); 0226 0227 QString driver; 0228 // Get the new printer driver 0229 if (!request->printers().isEmpty()) { 0230 const KCupsPrinter &printer = request->printers().first(); 0231 driver = printer.makeAndModel(); 0232 } 0233 0234 // The cups request might have failed 0235 if (driver.isEmpty()) { 0236 notify->setText(i18n("'%1' has been added, please check its driver.", name)); 0237 auto configAction = notify->addAction(i18n("Configure")); 0238 connect(configAction, &KNotificationAction::activated, this, &NewPrinterNotification::configurePrinter); 0239 } else { 0240 notify->setText(i18n("'%1' has been added, using the '%2' driver.", name, driver)); 0241 auto testAction = notify->addAction(i18n("Print test page")); 0242 connect(testAction, &KNotificationAction::activated, this, &NewPrinterNotification::printTestPage); 0243 auto findAction = notify->addAction(i18n("Find driver")); 0244 connect(findAction, &KNotificationAction::activated, this, &NewPrinterNotification::findDriver); 0245 } 0246 notify->sendEvent(); 0247 }); 0248 request->getPrinterAttributes(name, false, {KCUPS_PRINTER_MAKE_AND_MODEL}); 0249 } 0250 0251 void NewPrinterNotification::printerReadyNotification(KNotification *notify, const QString &name) 0252 { 0253 notify->setText(i18n("'%1' is ready for printing.", name)); 0254 0255 auto testAction = notify->addAction(i18n("Print test page")); 0256 connect(testAction, &KNotificationAction::activated, this, &NewPrinterNotification::printTestPage); 0257 0258 auto configAction = notify->addAction(i18n("Configure")); 0259 connect(configAction, &KNotificationAction::activated, this, &NewPrinterNotification::configurePrinter); 0260 0261 notify->sendEvent(); 0262 } 0263 0264 #include "moc_NewPrinterNotification.cpp"