File indexing completed on 2024-04-21 05:01:36

0001 /*
0002     This class provides the interface to the libsmbclient library.
0003 
0004     SPDX-FileCopyrightText: 2018-2023 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // application specific includes
0009 #include "smb4kclient.h"
0010 #include "smb4kbasicnetworkitem.h"
0011 #include "smb4kclient_p.h"
0012 #include "smb4kcustomsettings.h"
0013 #include "smb4kcustomsettingsmanager.h"
0014 #include "smb4khardwareinterface.h"
0015 #include "smb4khomesshareshandler.h"
0016 #include "smb4knotification.h"
0017 #include "smb4ksettings.h"
0018 #include "smb4kwalletmanager.h"
0019 
0020 // Qt includes
0021 #include <QApplication>
0022 #include <QHostAddress>
0023 #include <QPointer>
0024 #include <QTimer>
0025 #include <QUdpSocket>
0026 
0027 using namespace Smb4KGlobal;
0028 
0029 Q_GLOBAL_STATIC(Smb4KClientStatic, p);
0030 
0031 Smb4KClient::Smb4KClient(QObject *parent)
0032     : KCompositeJob(parent)
0033     , d(new Smb4KClientPrivate)
0034 {
0035     connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Smb4KClient::slotAboutToQuit);
0036     connect(Smb4KWalletManager::self(), &Smb4KWalletManager::credentialsUpdated, this, &Smb4KClient::slotCredentialsUpdated);
0037 }
0038 
0039 Smb4KClient::~Smb4KClient()
0040 {
0041 }
0042 
0043 Smb4KClient *Smb4KClient::self()
0044 {
0045     return &p->instance;
0046 }
0047 
0048 void Smb4KClient::start()
0049 {
0050     //
0051     // Connect to the online state monitoring
0052     //
0053     connect(Smb4KHardwareInterface::self(), &Smb4KHardwareInterface::onlineStateChanged, this, &Smb4KClient::slotOnlineStateChanged, Qt::UniqueConnection);
0054 
0055     //
0056     // Start the scanning
0057     //
0058     if (Smb4KHardwareInterface::self()->isOnline()) {
0059         QTimer::singleShot(50, this, SLOT(slotStartJobs()));
0060     }
0061 }
0062 
0063 bool Smb4KClient::isRunning()
0064 {
0065     return hasSubjobs();
0066 }
0067 
0068 void Smb4KClient::abort()
0069 {
0070     QListIterator<KJob *> it(subjobs());
0071 
0072     while (it.hasNext()) {
0073         it.next()->kill(KJob::EmitResult);
0074     }
0075 }
0076 
0077 void Smb4KClient::lookupDomains()
0078 {
0079     //
0080     // Send Wakeup-On-LAN packets
0081     //
0082     if (Smb4KSettings::enableWakeOnLAN()) {
0083         QList<CustomSettingsPtr> wakeOnLanEntries = Smb4KCustomSettingsManager::self()->wakeOnLanEntries();
0084 
0085         if (!wakeOnLanEntries.isEmpty()) {
0086             NetworkItemPtr item = NetworkItemPtr(new Smb4KBasicNetworkItem());
0087             Q_EMIT aboutToStart(item, WakeUp);
0088 
0089             QUdpSocket *socket = new QUdpSocket(this);
0090 
0091             for (int i = 0; i < wakeOnLanEntries.size(); ++i) {
0092                 if (wakeOnLanEntries.at(i)->wakeOnLanSendBeforeNetworkScan()) {
0093                     QHostAddress addr;
0094 
0095                     if (wakeOnLanEntries.at(i)->hasIpAddress()) {
0096                         addr.setAddress(wakeOnLanEntries.at(i)->ipAddress());
0097                     } else {
0098                         addr.setAddress(QStringLiteral("255.255.255.255"));
0099                     }
0100 
0101                     // Construct magic sequence
0102                     QByteArray sequence;
0103 
0104                     // 6 times 0xFF
0105                     for (int j = 0; j < 6; ++j) {
0106                         sequence.append(QChar(0xFF).toLatin1());
0107                     }
0108 
0109                     // 16 times the MAC address
0110                     QStringList parts = wakeOnLanEntries.at(i)->macAddress().split(QStringLiteral(":"), Qt::SkipEmptyParts);
0111 
0112                     for (int j = 0; j < 16; ++j) {
0113                         for (int k = 0; k < parts.size(); ++k) {
0114                             QString item = QStringLiteral("0x") + parts.at(k);
0115                             sequence.append(QChar(item.toInt(nullptr, 16)).toLatin1());
0116                         }
0117                     }
0118 
0119                     socket->writeDatagram(sequence, addr, 9);
0120                 }
0121             }
0122 
0123             delete socket;
0124 
0125             // Wait the defined time
0126             int stop = 1000 * Smb4KSettings::wakeOnLANWaitingTime() / 250;
0127             int i = 0;
0128 
0129             while (i++ < stop) {
0130                 wait(250);
0131             }
0132 
0133             Q_EMIT finished(item, WakeUp);
0134             item.clear();
0135         }
0136     }
0137 
0138     //
0139     // Emit the aboutToStart() signal
0140     //
0141     NetworkItemPtr networkItem = NetworkItemPtr(new Smb4KBasicNetworkItem(Network));
0142     networkItem->setUrl(QUrl(QStringLiteral("smb://")));
0143     Q_EMIT aboutToStart(networkItem, LookupDomains);
0144 
0145     //
0146     // Set the busy cursor
0147     //
0148     if (!hasSubjobs()) {
0149         QApplication::setOverrideCursor(Qt::BusyCursor);
0150     }
0151 
0152     //
0153     // Create the client job
0154     //
0155     Smb4KClientJob *clientJob = new Smb4KClientJob(this);
0156     clientJob->setNetworkItem(networkItem);
0157     clientJob->setProcess(LookupDomains);
0158 
0159 #ifdef USE_WS_DISCOVERY
0160     //
0161     // Create the WS Discovery job, if desired
0162     //
0163     Smb4KWsDiscoveryJob *wsDiscoveryJob = nullptr;
0164 
0165     if (Smb4KSettings::useWsDiscovery()) {
0166         wsDiscoveryJob = new Smb4KWsDiscoveryJob(this);
0167         wsDiscoveryJob->setNetworkItem(networkItem);
0168         wsDiscoveryJob->setProcess(LookupDomains);
0169     }
0170 #endif
0171 
0172     //
0173     // Create the DNS-SD job, if desired
0174     //
0175     Smb4KDnsDiscoveryJob *dnsDiscoveryJob = nullptr;
0176 
0177     if (Smb4KSettings::useDnsServiceDiscovery()) {
0178         dnsDiscoveryJob = new Smb4KDnsDiscoveryJob(this);
0179         dnsDiscoveryJob->setNetworkItem(networkItem);
0180         dnsDiscoveryJob->setProcess(LookupDomains);
0181     }
0182 
0183     //
0184     // Add the jobs to the subjobs
0185     //
0186     addSubjob(clientJob);
0187 
0188 #ifdef USE_WS_DISCOVERY
0189     if (wsDiscoveryJob) {
0190         addSubjob(wsDiscoveryJob);
0191     }
0192 #endif
0193 
0194     if (dnsDiscoveryJob) {
0195         addSubjob(dnsDiscoveryJob);
0196     }
0197 
0198     //
0199     // Start the jobs
0200     //
0201     clientJob->start();
0202 
0203 #ifdef USE_WS_DISCOVERY
0204     if (wsDiscoveryJob) {
0205         wsDiscoveryJob->start();
0206     }
0207 #endif
0208 
0209     if (dnsDiscoveryJob) {
0210         dnsDiscoveryJob->start();
0211     }
0212 
0213     //
0214     // Clear the network item
0215     //
0216     networkItem.clear();
0217 }
0218 
0219 void Smb4KClient::lookupDomainMembers(const WorkgroupPtr &workgroup)
0220 {
0221     //
0222     // Emit the aboutToStart() signal
0223     //
0224     Q_EMIT aboutToStart(workgroup, LookupDomainMembers);
0225 
0226     //
0227     // Set the busy cursor
0228     //
0229     if (!hasSubjobs()) {
0230         QApplication::setOverrideCursor(Qt::BusyCursor);
0231     }
0232 
0233     //
0234     // Create the client job
0235     //
0236     Smb4KClientJob *clientJob = new Smb4KClientJob(this);
0237     clientJob->setNetworkItem(workgroup);
0238     clientJob->setProcess(LookupDomainMembers);
0239 
0240 #ifdef USE_WS_DISCOVERY
0241     //
0242     // Create the WS Discovery job, if desired
0243     //
0244     Smb4KWsDiscoveryJob *wsDiscoveryJob = nullptr;
0245 
0246     if (Smb4KSettings::useWsDiscovery()) {
0247         wsDiscoveryJob = new Smb4KWsDiscoveryJob(this);
0248         wsDiscoveryJob->setNetworkItem(workgroup);
0249         wsDiscoveryJob->setProcess(LookupDomainMembers);
0250     }
0251 #endif
0252 
0253     //
0254     // Create the DNS-SD job, if desired
0255     //
0256     Smb4KDnsDiscoveryJob *dnsDiscoveryJob = nullptr;
0257 
0258     if (Smb4KSettings::useDnsServiceDiscovery()) {
0259         dnsDiscoveryJob = new Smb4KDnsDiscoveryJob(this);
0260         dnsDiscoveryJob->setNetworkItem(workgroup);
0261         dnsDiscoveryJob->setProcess(LookupDomainMembers);
0262     }
0263 
0264     //
0265     // Add the jobs to the subjobs
0266     //
0267     addSubjob(clientJob);
0268 
0269 #ifdef USE_WS_DISCOVERY
0270     if (wsDiscoveryJob) {
0271         addSubjob(wsDiscoveryJob);
0272     }
0273 #endif
0274 
0275     if (dnsDiscoveryJob) {
0276         addSubjob(dnsDiscoveryJob);
0277     }
0278 
0279     //
0280     // Start the job
0281     //
0282     clientJob->start();
0283 
0284 #ifdef USE_WS_DISCOVERY
0285     if (wsDiscoveryJob) {
0286         wsDiscoveryJob->start();
0287     }
0288 #endif
0289 
0290     if (dnsDiscoveryJob) {
0291         dnsDiscoveryJob->start();
0292     }
0293 }
0294 
0295 void Smb4KClient::lookupShares(const HostPtr &host)
0296 {
0297     //
0298     // Emit the aboutToStart() signal
0299     //
0300     Q_EMIT aboutToStart(host, LookupShares);
0301 
0302     //
0303     // Create the job
0304     //
0305     Smb4KClientJob *job = new Smb4KClientJob(this);
0306     job->setNetworkItem(host);
0307     job->setProcess(LookupShares);
0308 
0309     //
0310     // Set the busy cursor
0311     //
0312     if (!hasSubjobs()) {
0313         QApplication::setOverrideCursor(Qt::BusyCursor);
0314     }
0315 
0316     //
0317     // Add the job to the subjobs
0318     //
0319     addSubjob(job);
0320 
0321     //
0322     // Start the job
0323     //
0324     job->start();
0325 }
0326 
0327 void Smb4KClient::lookupFiles(const NetworkItemPtr &item)
0328 {
0329     if (item->type() == Share || (item->type() == FileOrDirectory && item.staticCast<Smb4KFile>()->isDirectory())) {
0330         Q_EMIT aboutToStart(item, LookupFiles);
0331 
0332         Smb4KClientJob *job = new Smb4KClientJob(this);
0333         job->setNetworkItem(item);
0334         job->setProcess(LookupFiles);
0335 
0336         if (!hasSubjobs()) {
0337             QApplication::setOverrideCursor(Qt::BusyCursor);
0338         }
0339 
0340         addSubjob(job);
0341 
0342         job->start();
0343     }
0344 }
0345 
0346 void Smb4KClient::printFile(const SharePtr &share, const KFileItem &fileItem, int copies)
0347 {
0348     if (fileItem.mimetype() != QStringLiteral("application/postscript") && fileItem.mimetype() != QStringLiteral("application/pdf")
0349         && fileItem.mimetype() != QStringLiteral("application/x-shellscript") && !fileItem.mimetype().startsWith(QStringLiteral("text"))
0350         && !fileItem.mimetype().startsWith(QStringLiteral("message")) && !fileItem.mimetype().startsWith(QStringLiteral("image"))) {
0351         Smb4KNotification::mimetypeNotSupported(fileItem.mimetype());
0352         return;
0353     }
0354 
0355     //
0356     // Emit the aboutToStart() signal
0357     //
0358     Q_EMIT aboutToStart(share, PrintFile);
0359 
0360     //
0361     // Create the job
0362     //
0363     Smb4KClientJob *job = new Smb4KClientJob(this);
0364     job->setNetworkItem(share);
0365     job->setPrintFileItem(fileItem);
0366     job->setPrintCopies(copies);
0367     job->setProcess(PrintFile);
0368 
0369     //
0370     // Set the busy cursor
0371     //
0372     if (!hasSubjobs()) {
0373         QApplication::setOverrideCursor(Qt::BusyCursor);
0374     }
0375 
0376     //
0377     // Add the job to the subjobs
0378     //
0379     addSubjob(job);
0380 
0381     //
0382     // Start the job
0383     //
0384     job->start();
0385 }
0386 
0387 void Smb4KClient::search(const QString &item)
0388 {
0389     //
0390     // Create empty basic network item
0391     //
0392     NetworkItemPtr networkItem = NetworkItemPtr(new Smb4KBasicNetworkItem());
0393 
0394     //
0395     // Emit the aboutToStart() signal
0396     //
0397     Q_EMIT aboutToStart(networkItem, NetworkSearch);
0398 
0399     //
0400     // Before doing the search, lookup all domains, servers and shares in the
0401     // network neighborhood.
0402     //
0403     lookupDomains();
0404 
0405     while (isRunning()) {
0406         wait(50);
0407     }
0408 
0409     for (const WorkgroupPtr &workgroup : workgroupsList()) {
0410         lookupDomainMembers(workgroup);
0411 
0412         while (isRunning()) {
0413             wait(50);
0414         }
0415     }
0416 
0417     for (const HostPtr &host : hostsList()) {
0418         lookupShares(host);
0419 
0420         while (isRunning()) {
0421             wait(50);
0422         }
0423     }
0424 
0425     //
0426     // Do the actual search
0427     //
0428     QList<SharePtr> results;
0429 
0430     for (const SharePtr &share : sharesList()) {
0431         if (share->shareName().contains(item, Qt::CaseInsensitive)) {
0432             results << share;
0433         }
0434     }
0435 
0436     //
0437     // Emit the search results
0438     //
0439     Q_EMIT searchResults(results);
0440 
0441     //
0442     // Emit the finished() signal
0443     //
0444     Q_EMIT finished(networkItem, NetworkSearch);
0445 }
0446 
0447 void Smb4KClient::processErrors(Smb4KClientBaseJob *job)
0448 {
0449     switch (job->error()) {
0450     case Smb4KClientJob::AccessDeniedError: {
0451         switch (job->networkItem()->type()) {
0452         case Host: {
0453             Smb4KClientPrivate::QueueContainer container;
0454             container.process = job->process();
0455             container.networkItem = job->networkItem();
0456             d->queue.append(container);
0457             Q_EMIT requestCredentials(job->networkItem());
0458 
0459             break;
0460         }
0461         case Share: {
0462             Smb4KClientPrivate::QueueContainer container;
0463             container.process = job->process();
0464             container.networkItem = job->networkItem();
0465 
0466             if (job->process() == Smb4KGlobal::PrintFile) {
0467                 Smb4KClientJob *clientJob = qobject_cast<Smb4KClientJob *>(job);
0468                 container.printFileItem = clientJob->printFileItem();
0469                 container.printCopies = clientJob->printCopies();
0470             }
0471 
0472             d->queue.append(container);
0473             Q_EMIT requestCredentials(job->networkItem());
0474 
0475             break;
0476         }
0477         case FileOrDirectory: {
0478             Smb4KClientPrivate::QueueContainer container;
0479             container.process = job->process();
0480             container.networkItem = job->networkItem();
0481             d->queue.append(container);
0482 
0483             FilePtr file = job->networkItem().staticCast<Smb4KFile>();
0484             SharePtr share = SharePtr(new Smb4KShare());
0485             share->setWorkgroupName(file->workgroupName());
0486             share->setHostName(file->hostName());
0487             share->setShareName(file->shareName());
0488             share->setUserName(file->userName());
0489             share->setPassword(file->password());
0490             Q_EMIT requestCredentials(share);
0491 
0492             break;
0493         }
0494         default: {
0495             qDebug() << "Authentication error. URL:" << job->networkItem()->url();
0496             break;
0497         }
0498         }
0499 
0500         break;
0501     }
0502     default: {
0503         Smb4KNotification::networkCommunicationFailed(job->errorText());
0504         break;
0505     }
0506     }
0507 }
0508 
0509 void Smb4KClient::processWorkgroups(Smb4KClientBaseJob *job)
0510 {
0511     //
0512     // Collect the workgroups found while scanning
0513     //
0514     QList<WorkgroupPtr> discoveredWorkgroups = job->workgroups();
0515 
0516     for (const WorkgroupPtr &newWorkgroup : qAsConst(discoveredWorkgroups)) {
0517         bool foundWorkgroup = false;
0518 
0519         for (const WorkgroupPtr &workgroup : qAsConst(d->tempWorkgroupList)) {
0520             if (workgroup->workgroupName() == newWorkgroup->workgroupName()) {
0521                 foundWorkgroup = true;
0522                 break;
0523             }
0524         }
0525 
0526         if (!foundWorkgroup) {
0527             d->tempWorkgroupList << newWorkgroup;
0528         }
0529     }
0530 
0531     //
0532     // When scanning finished, process the workgroups
0533     //
0534     if (!isRunning()) {
0535         // Remove obsolete workgroups and their members
0536         QListIterator<WorkgroupPtr> it(workgroupsList());
0537 
0538         while (it.hasNext()) {
0539             WorkgroupPtr workgroup = it.next();
0540 
0541             bool foundWorkgroup = false;
0542 
0543             for (const WorkgroupPtr &w : qAsConst(d->tempWorkgroupList)) {
0544                 if (w->workgroupName() == workgroup->workgroupName()) {
0545                     foundWorkgroup = true;
0546                     break;
0547                 }
0548             }
0549 
0550             if (!foundWorkgroup) {
0551                 QList<HostPtr> obsoleteHosts = workgroupMembers(workgroup);
0552 
0553                 while (!obsoleteHosts.isEmpty()) {
0554                     removeHost(obsoleteHosts.takeFirst());
0555                 }
0556 
0557                 removeWorkgroup(workgroup);
0558             }
0559         }
0560 
0561         // Add new workgroups and update existing ones
0562         for (const WorkgroupPtr &workgroup : qAsConst(d->tempWorkgroupList)) {
0563             if (!findWorkgroup(workgroup->workgroupName())) {
0564                 addWorkgroup(workgroup);
0565 
0566                 // Since this is a new workgroup, no master browser is present.
0567                 HostPtr masterBrowser = HostPtr(new Smb4KHost());
0568                 masterBrowser->setWorkgroupName(workgroup->workgroupName());
0569                 masterBrowser->setHostName(workgroup->masterBrowserName());
0570                 masterBrowser->setIpAddress(workgroup->masterBrowserIpAddress());
0571                 masterBrowser->setIsMasterBrowser(true);
0572 
0573                 addHost(masterBrowser);
0574             } else {
0575                 updateWorkgroup(workgroup);
0576 
0577                 // Check if the master browser changed
0578                 QList<HostPtr> members = workgroupMembers(workgroup);
0579 
0580                 for (const HostPtr &host : qAsConst(members)) {
0581                     if (workgroup->masterBrowserName() == host->hostName()) {
0582                         host->setIsMasterBrowser(true);
0583 
0584                         if (!host->hasIpAddress() && workgroup->hasMasterBrowserIpAddress()) {
0585                             host->setIpAddress(workgroup->masterBrowserIpAddress());
0586                         }
0587                     } else {
0588                         host->setIsMasterBrowser(false);
0589                     }
0590                 }
0591             }
0592         }
0593 
0594         // Clear the temporary workgroup list
0595         while (!d->tempWorkgroupList.isEmpty()) {
0596             d->tempWorkgroupList.takeFirst().clear();
0597         }
0598 
0599         Q_EMIT workgroups();
0600     }
0601 }
0602 
0603 void Smb4KClient::processHosts(Smb4KClientBaseJob *job)
0604 {
0605     //
0606     // Collect the hosts found while scanning. Always prefer
0607     // insertion of hosts with a real workgroup/domain over
0608     // the ones with the DNS-SD domain (e.g. LOCAL).
0609     //
0610     QList<HostPtr> discoveredHosts = job->hosts();
0611 
0612     for (const HostPtr &newHost : qAsConst(discoveredHosts)) {
0613         bool foundHost = false;
0614 
0615         QMutableListIterator<HostPtr> it(d->tempHostList);
0616 
0617         while (it.hasNext()) {
0618             HostPtr host = static_cast<HostPtr>(it.next());
0619 
0620             if (newHost->url().matches(host->url(), QUrl::RemoveUserInfo | QUrl::RemovePort)) {
0621                 if (newHost->workgroupName() == host->workgroupName()) {
0622                     foundHost = true;
0623                 } else if (host->dnsDiscovered()) {
0624                     it.remove();
0625                 }
0626 
0627                 break;
0628             }
0629         }
0630 
0631         if (!foundHost) {
0632             d->tempHostList << newHost;
0633         }
0634     }
0635 
0636     //
0637     // When scanning finished, process the hosts
0638     //
0639     if (!isRunning()) {
0640         // Get the workgroup pointer. Although several scans might have been
0641         // running, the workgroup should have been always the same.
0642         WorkgroupPtr workgroup = job->networkItem().staticCast<Smb4KWorkgroup>();
0643 
0644         // Remove obsolete workgroup/domain members
0645         QList<HostPtr> members = workgroupMembers(workgroup);
0646         QListIterator<HostPtr> it(members);
0647 
0648         while (it.hasNext()) {
0649             HostPtr host = it.next();
0650 
0651             bool foundHost = false;
0652 
0653             for (const HostPtr &h : qAsConst(d->tempHostList)) {
0654                 if (h->workgroupName() == host->workgroupName() && h->hostName() == host->hostName()) {
0655                     foundHost = true;
0656                     break;
0657                 }
0658             }
0659 
0660             if (!foundHost) {
0661                 QList<SharePtr> obsoleteShares = sharedResources(host);
0662 
0663                 while (!obsoleteShares.isEmpty()) {
0664                     removeShare(obsoleteShares.takeFirst());
0665                 }
0666 
0667                 removeHost(host);
0668             }
0669         }
0670 
0671         // Add new hosts and update existing ones
0672         for (const HostPtr &host : qAsConst(d->tempHostList)) {
0673             if (host->hostName() == workgroup->masterBrowserName()) {
0674                 host->setIsMasterBrowser(true);
0675             } else {
0676                 host->setIsMasterBrowser(false);
0677             }
0678 
0679             if (!findHost(host->hostName(), host->workgroupName())) {
0680                 addHost(host);
0681             } else {
0682                 updateHost(host);
0683             }
0684         }
0685 
0686         // Clear the temporary host list
0687         while (!d->tempHostList.isEmpty()) {
0688             d->tempHostList.takeFirst().clear();
0689         }
0690 
0691         Q_EMIT hosts(workgroup);
0692     }
0693 }
0694 
0695 void Smb4KClient::processShares(Smb4KClientBaseJob *job)
0696 {
0697     //
0698     // To look up the shared resources of a host, we only use
0699     // Samba's client library, so we do not have to wait until
0700     // several jobs finished.
0701     //
0702     // Get the host pointer
0703     //
0704     HostPtr host = job->networkItem().staticCast<Smb4KHost>();
0705 
0706     //
0707     // Copy the list of discovered shares
0708     //
0709     QList<SharePtr> discoveredShares = job->shares();
0710 
0711     //
0712     // Remove obsolete shares
0713     //
0714     QList<SharePtr> sharedRes = sharedResources(host);
0715     QListIterator<SharePtr> it(sharedRes);
0716 
0717     while (it.hasNext()) {
0718         SharePtr share = it.next();
0719 
0720         bool foundShare = false;
0721 
0722         for (const SharePtr &s : qAsConst(discoveredShares)) {
0723             if (s->workgroupName() == share->workgroupName() && s->url().matches(share->url(), QUrl::RemoveUserInfo | QUrl::RemovePort)) {
0724                 foundShare = true;
0725                 break;
0726             }
0727         }
0728 
0729         if (!foundShare || (share->isHidden() && !Smb4KSettings::detectHiddenShares()) || (share->isPrinter() && !Smb4KSettings::detectPrinterShares())) {
0730             removeShare(share);
0731         }
0732     }
0733 
0734     //
0735     // Add new shares and update existing ones
0736     //
0737     for (const SharePtr &share : qAsConst(discoveredShares)) {
0738         // Process only those shares that the user wants to see
0739         if (share->isHidden() && !Smb4KSettings::detectHiddenShares()) {
0740             continue;
0741         }
0742 
0743         if (share->isPrinter() && !Smb4KSettings::detectPrinterShares()) {
0744             continue;
0745         }
0746 
0747         // Add or update the shares
0748         if (!findShare(share->url(), share->workgroupName())) {
0749             addShare(share);
0750         } else {
0751             updateShare(share);
0752         }
0753     }
0754 
0755     Q_EMIT shares(host);
0756 }
0757 
0758 void Smb4KClient::processFiles(Smb4KClientBaseJob *job)
0759 {
0760     QList<FilePtr> discoveredFiles = job->files();
0761     QList<FilePtr> list;
0762 
0763     for (const FilePtr &file : qAsConst(discoveredFiles)) {
0764         if (file->isHidden() && !Smb4KSettings::previewHiddenItems()) {
0765             continue;
0766         }
0767 
0768         list << file;
0769     }
0770 
0771     Q_EMIT files(list);
0772 }
0773 
0774 void Smb4KClient::slotStartJobs()
0775 {
0776     lookupDomains();
0777 }
0778 
0779 void Smb4KClient::slotOnlineStateChanged(bool online)
0780 {
0781     if (online) {
0782         slotStartJobs();
0783     } else {
0784         abort();
0785     }
0786 }
0787 
0788 void Smb4KClient::slotResult(KJob *job)
0789 {
0790     //
0791     // Remove the job
0792     //
0793     removeSubjob(job);
0794 
0795     //
0796     // Get the client base job
0797     //
0798     Smb4KClientBaseJob *clientBaseJob = qobject_cast<Smb4KClientBaseJob *>(job);
0799 
0800     //
0801     // Define a network item pointer and the process value for the
0802     // finished() signal.
0803     //
0804     NetworkItemPtr networkItem = clientBaseJob->networkItem();
0805     Smb4KGlobal::Process process = clientBaseJob->process();
0806 
0807     //
0808     // Get the result from the query and process it
0809     //
0810     if (clientBaseJob->error() == 0) {
0811         switch (networkItem->type()) {
0812         case Network: {
0813             // Process the discovered workgroups
0814             processWorkgroups(clientBaseJob);
0815             break;
0816         }
0817         case Workgroup: {
0818             // Process the discovered workgroup members
0819             processHosts(clientBaseJob);
0820             break;
0821         }
0822         case Host: {
0823             // Process the discovered shares
0824             processShares(clientBaseJob);
0825             break;
0826         }
0827         case Share: {
0828             processFiles(clientBaseJob);
0829             break;
0830         }
0831         case FileOrDirectory: {
0832             if (networkItem.staticCast<Smb4KFile>()->isDirectory()) {
0833                 processFiles(clientBaseJob);
0834             }
0835             break;
0836         }
0837         default: {
0838             break;
0839         }
0840         }
0841     } else {
0842         processErrors(clientBaseJob);
0843     }
0844 
0845     //
0846     // Emit the finished signal when all subjobs finished
0847     //
0848     if (!hasSubjobs()) {
0849         Q_EMIT finished(networkItem, process);
0850     }
0851 
0852     //
0853     // Clear the network item pointer
0854     //
0855     networkItem.clear();
0856 
0857     //
0858     // Restore the cursor
0859     //
0860     if (!hasSubjobs()) {
0861         QApplication::restoreOverrideCursor();
0862     }
0863 }
0864 
0865 void Smb4KClient::slotAboutToQuit()
0866 {
0867     abort();
0868 }
0869 
0870 void Smb4KClient::slotAbort()
0871 {
0872     abort();
0873 }
0874 
0875 void Smb4KClient::slotCredentialsUpdated(const QUrl &url)
0876 {
0877     if (!url.isEmpty() && !d->queue.isEmpty()) {
0878         QMutableListIterator<Smb4KClientPrivate::QueueContainer> it(d->queue);
0879 
0880         while (it.hasNext()) {
0881             Smb4KClientPrivate::QueueContainer container = it.next();
0882 
0883             QUrl networkItemUrl = container.networkItem->url();
0884             QUrl parentNetworkItemUrl = container.networkItem->url().resolved(QUrl(QStringLiteral(".."))).adjusted(QUrl::StripTrailingSlash);
0885 
0886             if (QString::compare(networkItemUrl.toString(QUrl::RemoveUserInfo | QUrl::RemovePort),
0887                                  url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort),
0888                                  Qt::CaseInsensitive)
0889                     == 0
0890                 || QString::compare(parentNetworkItemUrl.toString(QUrl::RemoveUserInfo | QUrl::RemovePort),
0891                                     url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort),
0892                                     Qt::CaseInsensitive)
0893                     == 0) {
0894                 switch (container.networkItem->type()) {
0895                 case Host: {
0896                     HostPtr host = container.networkItem.staticCast<Smb4KHost>();
0897                     host->setUserName(url.userName());
0898                     host->setPassword(url.password());
0899                     lookupShares(host);
0900                     break;
0901                 }
0902                 case Share: {
0903                     SharePtr share = container.networkItem.staticCast<Smb4KShare>();
0904                     share->setUserName(url.userName());
0905                     share->setPassword(url.password());
0906                     if (container.process == Smb4KGlobal::PrintFile) {
0907                         printFile(share, container.printFileItem, container.printCopies);
0908                     } else {
0909                         lookupFiles(share);
0910                     }
0911                     break;
0912                 }
0913                 case FileOrDirectory: {
0914                     FilePtr file = container.networkItem.staticCast<Smb4KFile>();
0915                     file->setUserName(url.userName());
0916                     file->setPassword(url.password());
0917                     lookupFiles(file);
0918                     break;
0919                 }
0920                 default: {
0921                     break;
0922                 }
0923                 }
0924 
0925                 it.remove();
0926             }
0927         }
0928     }
0929 }