File indexing completed on 2024-04-21 15:12:13

0001 /************************************************************************
0002  *                                  *
0003  *  This file is part of Kooka, a scanning/OCR application using    *
0004  *  Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>.  *
0005  *                                  *
0006  *  Copyright (C) 1999-2016 Klaas Freitag <freitag@suse.de>     *
0007  *                          Jonathan Marten <jjm@keelhaul.me.uk>    *
0008  *                                  *
0009  *  Kooka is free software; you can redistribute it and/or modify it    *
0010  *  under the terms of the GNU Library General Public License as    *
0011  *  published by the Free Software Foundation and appearing in the  *
0012  *  file COPYING included in the packaging of this file;  either    *
0013  *  version 2 of the License, or (at your option) any later version.    *
0014  *                                  *
0015  *  As a special exception, permission is given to link this program    *
0016  *  with any version of the KADMOS OCR/ICR engine (a product of     *
0017  *  reRecognition GmbH, Kreuzlingen), and distribute the resulting  *
0018  *  executable without including the source code for KADMOS in the  *
0019  *  source distribution.                        *
0020  *                                  *
0021  *  This program is distributed in the hope that it will be useful, *
0022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  *
0023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
0024  *  GNU General Public License for more details.            *
0025  *                                  *
0026  *  You should have received a copy of the GNU General Public       *
0027  *  License along with this program;  see the file COPYING.  If     *
0028  *  not, see <http://www.gnu.org/licenses/>.                *
0029  *                                  *
0030  ************************************************************************/
0031 
0032 #include "scandevices.h"
0033 
0034 #include <klocalizedstring.h>
0035 
0036 #include "scanglobal.h"
0037 #include "scansettings.h"
0038 #include "libkookascan_logging.h"
0039 
0040 
0041 ScanDevices *sInstance = nullptr;
0042 
0043 ScanDevices *ScanDevices::self()
0044 {
0045     if (sInstance == nullptr) {
0046         sInstance = new ScanDevices();
0047     }
0048     return (sInstance);
0049 }
0050 
0051 ScanDevices::ScanDevices()
0052 {
0053     qCDebug(LIBKOOKASCAN_LOG);
0054 
0055     if (!ScanGlobal::self()->init()) {
0056         return;    // do sane_init() if necessary
0057     }
0058 
0059     bool netaccess = ScanSettings::startupOnlyLocal();
0060     qCDebug(LIBKOOKASCAN_LOG) << "Query for network scanners?" << netaccess;
0061 
0062     SANE_Device const **dev_list = nullptr;
0063     SANE_Status status = sane_get_devices(&dev_list, (netaccess ? SANE_TRUE : SANE_FALSE));
0064     if (status != SANE_STATUS_GOOD)
0065     {
0066         qCWarning(LIBKOOKASCAN_LOG) << "sane_get_devices() failed, status" << status;
0067         return;                     // no point carrying on
0068     }
0069 
0070     const SANE_Device *dev;
0071     for (int devno = 0; (dev = dev_list[devno]) != nullptr; ++devno) {
0072         mScannerNames.append(dev->name);
0073         mScannerDevices.insert(dev->name, dev);
0074         qCDebug(LIBKOOKASCAN_LOG) << "SANE found scanner:" << dev->name << "=" << deviceDescription(dev->name);
0075     }
0076 
0077     QStringList devs = ScanSettings::userDevices();
0078     if (!devs.isEmpty())
0079     {
0080         QStringList descs = ScanSettings::userDescriptions();
0081         if (descs.count()<devs.count())         // ensure list correct length
0082         {
0083             for (int i = descs.count(); i<devs.count(); ++i) descs.append("Unknown");
0084             ScanSettings::setUserDescriptions(descs);
0085             ScanSettings::self()->save();
0086         }
0087 
0088         QStringList types = ScanSettings::userTypes();
0089         if (types.count()<devs.count())         // ensure list correct length
0090         {
0091             for (int i = types.count(); i<devs.count(); ++i) types.append("scanner");
0092             ScanSettings::setUserTypes(types);
0093             ScanSettings::self()->save();
0094         }
0095 
0096         QStringList::const_iterator it2 = descs.constBegin();
0097         QStringList::const_iterator it3 = types.constBegin();
0098         for (QStringList::const_iterator it1 = devs.constBegin();
0099                 it1 != devs.constEnd(); ++it1, ++it2, ++it3) {
0100             // avoid duplication
0101             QByteArray name = (*it1).toLocal8Bit();
0102             if (mScannerNames.contains(name)) {
0103                 continue;
0104             }
0105             addUserSpecifiedDevice(name, (*it2), (*it3).toLocal8Bit(), true);
0106             qCDebug(LIBKOOKASCAN_LOG) << "Configured scanner:" << name << "=" << deviceDescription(name);
0107         }
0108     }
0109 }
0110 
0111 ScanDevices::~ScanDevices()
0112 {
0113 }
0114 
0115 void ScanDevices::addUserSpecifiedDevice(const QByteArray &backend,
0116         const QString &description,
0117         const QByteArray &type,
0118         bool dontSave)
0119 {
0120     if (backend.isEmpty()) {
0121         return;
0122     }
0123 
0124     if (mScannerNames.contains(backend)) {
0125         qCDebug(LIBKOOKASCAN_LOG) << "device" << backend << "already exists, not adding";
0126         return;
0127     }
0128 
0129     QByteArray devtype = (!type.isEmpty() ? type : "scanner");
0130     qCDebug(LIBKOOKASCAN_LOG) << "adding" << backend << "desc" << description
0131                               << "type" << devtype << "dontSave" << dontSave;
0132 
0133     if (!dontSave)                  // add new device to config
0134     {                           // get existing device lists
0135         QStringList devs = ScanSettings::userDevices();
0136         QStringList descs = ScanSettings::userDescriptions();
0137         QStringList types = ScanSettings::userTypes();
0138 
0139         int i = devs.indexOf(backend);
0140         if (i >= 0) {                   // see if already in list
0141             descs[i] = description;         // if so just update
0142             types[i] = devtype;
0143         } else {
0144             devs.append(backend);           // add new entry to lists
0145             descs.append(description);
0146             types.append(devtype);
0147         }
0148 
0149         ScanSettings::setUserDevices(devs);
0150         ScanSettings::setUserDescriptions(descs);
0151         ScanSettings::setUserTypes(types);
0152         ScanSettings::self()->save();
0153     }
0154 
0155     SANE_Device *userdev = new SANE_Device;
0156 
0157     // Need a permanent copy of the strings, because SANE_Device only holds
0158     // pointers to them.  Unfortunately there is a memory leak here, the
0159     // 'userdev' object and its three QByteArray's are never deleted.
0160     // There is only a limited number of these objects in most applications,
0161     // so hopefully it won't matter too much.
0162 
0163     userdev->name = (new QByteArray(backend))->constData();
0164     userdev->model = (new QByteArray(description.toLocal8Bit()))->constData();
0165     userdev->type = (new QByteArray(devtype))->constData();
0166     userdev->vendor = "";
0167 
0168     mScannerNames.append(backend);
0169     mScannerDevices.insert(backend, userdev);
0170 }
0171 
0172 const SANE_Device *ScanDevices::deviceInfo(const QByteArray &backend) const
0173 {
0174     if (!mScannerNames.contains(backend)) {
0175         return (nullptr);
0176     }
0177     return (mScannerDevices[backend]);
0178 }
0179 
0180 QString ScanDevices::deviceDescription(const QByteArray &backend) const
0181 {
0182     if (!mScannerNames.contains(backend)) return (i18n("Unknown device '%1'", backend.constData()));
0183 
0184     const SANE_Device *scanner = mScannerDevices[backend];
0185     QString result = QString::fromLocal8Bit(scanner->vendor);
0186     if (!result.isEmpty()) result += ' ';
0187     result += QString::fromLocal8Bit(scanner->model);
0188     return (result);
0189 }