File indexing completed on 2024-04-28 12:45:24
0001 /* 0002 Private classes for the SMB client 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_p.h" 0010 #include "smb4kcustomsettings.h" 0011 #include "smb4kcustomsettingsmanager.h" 0012 #include "smb4knotification.h" 0013 #include "smb4ksettings.h" 0014 #include "smb4kwalletmanager.h" 0015 0016 // System includes 0017 #include <errno.h> 0018 #include <sys/stat.h> 0019 0020 // Qt includes 0021 #include <QAbstractSocket> 0022 #include <QDebug> 0023 #include <QDir> 0024 #include <QHostInfo> 0025 #include <QNetworkInterface> 0026 #include <QPrinter> 0027 #include <QTemporaryDir> 0028 #include <QTextDocument> 0029 #include <QUuid> 0030 0031 // KDE includes 0032 #include <KFileItem> 0033 #include <KLocalizedString> 0034 0035 #ifdef USE_WS_DISCOVERY 0036 #include <KDSoapClient/KDQName> 0037 #include <KDSoapClient/KDSoapClientInterface> 0038 #include <KDSoapClient/KDSoapMessage> 0039 #include <KDSoapClient/KDSoapMessageAddressingProperties> 0040 #include <WSDiscoveryTargetService> 0041 #endif 0042 0043 #define SMBC_DEBUG 0 0044 0045 using namespace Smb4KGlobal; 0046 0047 // 0048 // Client base job 0049 // 0050 0051 Smb4KClientBaseJob::Smb4KClientBaseJob(QObject *parent) 0052 : KJob(parent) 0053 , m_process(Smb4KGlobal::NoProcess) 0054 { 0055 pProcess = &m_process; 0056 pNetworkItem = &m_networkItem; 0057 pWorkgroups = &m_workgroups; 0058 pHosts = &m_hosts; 0059 pShares = &m_shares; 0060 pFiles = &m_files; 0061 } 0062 0063 Smb4KClientBaseJob::~Smb4KClientBaseJob() 0064 { 0065 while (!m_workgroups.isEmpty()) { 0066 m_workgroups.takeFirst().clear(); 0067 } 0068 0069 while (!m_hosts.isEmpty()) { 0070 m_hosts.takeFirst().clear(); 0071 } 0072 0073 while (!m_shares.isEmpty()) { 0074 m_shares.takeFirst().clear(); 0075 } 0076 0077 while (!m_files.isEmpty()) { 0078 m_files.takeFirst().clear(); 0079 } 0080 } 0081 0082 void Smb4KClientBaseJob::setProcess(Smb4KGlobal::Process process) 0083 { 0084 m_process = process; 0085 } 0086 0087 Smb4KGlobal::Process Smb4KClientBaseJob::process() const 0088 { 0089 return m_process; 0090 } 0091 0092 void Smb4KClientBaseJob::setNetworkItem(NetworkItemPtr networkItem) 0093 { 0094 m_networkItem = networkItem; 0095 } 0096 0097 NetworkItemPtr Smb4KClientBaseJob::networkItem() const 0098 { 0099 return m_networkItem; 0100 } 0101 0102 QList<WorkgroupPtr> Smb4KClientBaseJob::workgroups() 0103 { 0104 return m_workgroups; 0105 } 0106 0107 QList<HostPtr> Smb4KClientBaseJob::hosts() 0108 { 0109 return m_hosts; 0110 } 0111 0112 QList<SharePtr> Smb4KClientBaseJob::shares() 0113 { 0114 return m_shares; 0115 } 0116 0117 QList<FilePtr> Smb4KClientBaseJob::files() 0118 { 0119 return m_files; 0120 } 0121 0122 QHostAddress Smb4KClientBaseJob::lookupIpAddress(const QString &name) 0123 { 0124 // 0125 // The IP address object 0126 // 0127 QHostAddress ipAddress; 0128 0129 // 0130 // Get the IP address 0131 // 0132 // If the IP address is not to be determined for the local machine, we can use QHostInfo to 0133 // determine it. Otherwise we need to use QNetworkInterface for it. 0134 // 0135 if (name.toUpper() == QHostInfo::localHostName().toUpper() || name.toUpper() == machineNetbiosName().toUpper()) { 0136 // FIXME: Do we need to honor 'interfaces' here? 0137 QList<QHostAddress> addresses = QNetworkInterface::allAddresses(); 0138 0139 // Get the IP address for the host. For the time being, prefer the 0140 // IPv4 address over the IPv6 address. 0141 for (const QHostAddress &addr : qAsConst(addresses)) { 0142 // We only use global addresses. 0143 if (addr.isGlobal()) { 0144 if (addr.protocol() == QAbstractSocket::IPv4Protocol) { 0145 ipAddress = addr; 0146 break; 0147 } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { 0148 // FIXME: Use the right address here. 0149 ipAddress = addr; 0150 } 0151 } 0152 } 0153 } else { 0154 // Get the IP address 0155 QHostInfo hostInfo = QHostInfo::fromName(name); 0156 0157 if (hostInfo.error() == QHostInfo::NoError) { 0158 QList<QHostAddress> addresses = hostInfo.addresses(); 0159 0160 // Get the IP address for the host. For the time being, prefer the 0161 // IPv4 address over the IPv6 address. 0162 for (const QHostAddress &addr : qAsConst(addresses)) { 0163 // We only use global addresses. 0164 if (addr.isGlobal()) { 0165 if (addr.protocol() == QAbstractSocket::IPv4Protocol) { 0166 ipAddress = addr; 0167 break; 0168 } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { 0169 // FIXME: Use the right address here. 0170 ipAddress = addr; 0171 } 0172 } 0173 } 0174 } 0175 } 0176 0177 return ipAddress; 0178 } 0179 0180 // 0181 // Authentication function for libsmbclient 0182 // 0183 static void get_auth_data_with_context_fn(SMBCCTX *context, 0184 const char *server, 0185 const char *share, 0186 char *workgroup, 0187 int maxLenWorkgroup, 0188 char *username, 0189 int maxLenUsername, 0190 char *password, 0191 int maxLenPassword) 0192 { 0193 if (context != nullptr) { 0194 Smb4KClientJob *job = static_cast<Smb4KClientJob *>(smbc_getOptionUserData(context)); 0195 0196 if (job) { 0197 job->get_auth_data_fn(server, share, workgroup, maxLenWorkgroup, username, maxLenUsername, password, maxLenPassword); 0198 } 0199 } 0200 } 0201 0202 // 0203 // Client job 0204 // 0205 Smb4KClientJob::Smb4KClientJob(QObject *parent) 0206 : Smb4KClientBaseJob(parent) 0207 { 0208 } 0209 0210 Smb4KClientJob::~Smb4KClientJob() 0211 { 0212 } 0213 0214 void Smb4KClientJob::start() 0215 { 0216 QTimer::singleShot(50, this, SLOT(slotStartJob())); 0217 connect(this, &KJob::finished, this, &Smb4KClientJob::slotFinishJob); 0218 } 0219 0220 void Smb4KClientJob::setPrintFileItem(const KFileItem &item) 0221 { 0222 m_fileItem = item; 0223 } 0224 0225 KFileItem Smb4KClientJob::printFileItem() const 0226 { 0227 return m_fileItem; 0228 } 0229 0230 void Smb4KClientJob::setPrintCopies(int copies) 0231 { 0232 m_copies = copies; 0233 } 0234 0235 int Smb4KClientJob::printCopies() const 0236 { 0237 return m_copies; 0238 } 0239 0240 void Smb4KClientJob::get_auth_data_fn(const char *server, 0241 const char * /*share*/, 0242 char *workgroup, 0243 int /*maxLenWorkgroup*/, 0244 char *username, 0245 int maxLenUsername, 0246 char *password, 0247 int maxLenPassword) 0248 { 0249 // 0250 // Authentication 0251 // 0252 switch ((*pNetworkItem)->type()) { 0253 case Network: { 0254 // 0255 // No authentication needed 0256 // 0257 break; 0258 } 0259 case Workgroup: { 0260 // 0261 // Only request authentication data, if the master browsers require 0262 // authentication data. 0263 // 0264 if (Smb4KSettings::masterBrowsersRequireAuth()) { 0265 if (QString::fromUtf8(server, -1).toUpper() != QString::fromUtf8(workgroup, -1).toUpper()) { 0266 // 0267 // This is the master browser. Create a host object for it. 0268 // 0269 HostPtr masterBrowser = HostPtr(new Smb4KHost()); 0270 masterBrowser->setWorkgroupName(QString::fromUtf8(workgroup, -1)); 0271 masterBrowser->setHostName(QString::fromUtf8(server, -1)); 0272 0273 // 0274 // Get the authentication data 0275 // 0276 Smb4KWalletManager::self()->readLoginCredentials(masterBrowser); 0277 0278 // 0279 // Copy the authentication data 0280 // 0281 if (masterBrowser->hasUserInfo()) { 0282 qstrncpy(username, masterBrowser->userName().toUtf8().data(), maxLenUsername); 0283 qstrncpy(password, masterBrowser->password().toUtf8().data(), maxLenPassword); 0284 } 0285 } 0286 } 0287 0288 break; 0289 } 0290 case Host: { 0291 // 0292 // The host object 0293 // 0294 HostPtr host = (*pNetworkItem).staticCast<Smb4KHost>(); 0295 0296 // 0297 // Get the authentication data 0298 // 0299 Smb4KWalletManager::self()->readLoginCredentials(host); 0300 0301 // 0302 // Copy the authentication data 0303 // 0304 if (host->hasUserInfo()) { 0305 qstrncpy(username, host->userName().toUtf8().data(), maxLenUsername); 0306 qstrncpy(password, host->password().toUtf8().data(), maxLenPassword); 0307 } 0308 0309 break; 0310 } 0311 case Share: { 0312 // 0313 // The share object 0314 // 0315 SharePtr share = (*pNetworkItem).staticCast<Smb4KShare>(); 0316 0317 // 0318 // Get the authentication data 0319 // 0320 Smb4KWalletManager::self()->readLoginCredentials(share); 0321 0322 // 0323 // Copy the authentication data 0324 // 0325 if (share->hasUserInfo()) { 0326 qstrncpy(username, share->userName().toUtf8().data(), maxLenUsername); 0327 qstrncpy(password, share->password().toUtf8().data(), maxLenPassword); 0328 } 0329 0330 break; 0331 } 0332 case FileOrDirectory: { 0333 // 0334 // The file object 0335 // 0336 FilePtr file = (*pNetworkItem).staticCast<Smb4KFile>(); 0337 0338 if (file->isDirectory()) { 0339 SharePtr share = SharePtr(new Smb4KShare()); 0340 share->setWorkgroupName(file->workgroupName()); 0341 share->setHostName(file->hostName()); 0342 share->setShareName(file->shareName()); 0343 share->setUserName(file->userName()); 0344 share->setPassword(file->password()); 0345 0346 // 0347 // Get the authentication data 0348 // 0349 Smb4KWalletManager::self()->readLoginCredentials(share); 0350 0351 // 0352 // Copy the authentication data 0353 // 0354 if (share->hasUserInfo()) { 0355 qstrncpy(username, share->userName().toUtf8().data(), maxLenUsername); 0356 qstrncpy(password, share->password().toUtf8().data(), maxLenPassword); 0357 } 0358 } 0359 0360 break; 0361 } 0362 default: { 0363 break; 0364 } 0365 } 0366 } 0367 0368 void Smb4KClientJob::initClientLibrary() 0369 { 0370 // 0371 // Get new context 0372 // 0373 m_context = smbc_new_context(); 0374 0375 if (!m_context) { 0376 int errorCode = errno; 0377 0378 setError(ClientError); 0379 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0380 0381 emitResult(); 0382 return; 0383 } 0384 0385 // 0386 // Init the context 0387 // 0388 m_context = smbc_init_context(m_context); 0389 0390 if (!m_context) { 0391 int errorCode = errno; 0392 0393 setError(ClientError); 0394 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0395 emitResult(); 0396 return; 0397 } 0398 0399 // 0400 // Get the custom options 0401 // 0402 CustomSettingsPtr options = Smb4KCustomSettingsManager::self()->findCustomSettings(*pNetworkItem); 0403 0404 // 0405 // Set debug level 0406 // 0407 smbc_setDebug(m_context, SMBC_DEBUG); 0408 0409 // 0410 // Set the NetBIOS name and the workgroup to make connections 0411 // 0412 switch ((*pNetworkItem)->type()) { 0413 case Network: { 0414 // 0415 // We do not know about the servers and the domains/workgroups 0416 // present. So, do not set anything and use the default. 0417 // 0418 break; 0419 } 0420 case Workgroup: { 0421 WorkgroupPtr workgroup = (*pNetworkItem).staticCast<Smb4KWorkgroup>(); 0422 0423 // 0424 // Only set the NetBIOS name, if the workgroup entry has a master browser 0425 // 0426 if (workgroup->hasMasterBrowser()) { 0427 smbc_setNetbiosName(m_context, workgroup->masterBrowserName().toUtf8().data()); 0428 } 0429 0430 // 0431 // In case this domain/workgroup was discovered by the DNS-SD service, the workgroup/domain 0432 // might not be identical with the one defined in the network neighborhood. Thus, only set 0433 // the workgroup if no DNS-SD discovery was used. 0434 // 0435 if (!workgroup->dnsDiscovered()) { 0436 smbc_setWorkgroup(m_context, workgroup->workgroupName().toUtf8().data()); 0437 } 0438 0439 break; 0440 } 0441 case Host: { 0442 // 0443 // In case the domain/workgroup was discovered by the DNS-SD service, the 0444 // workgroup/domain might not be identical with the one defined in the network 0445 // neighborhood. Thus, only set the workgroup if no DNS-SD discovery was used. 0446 // 0447 HostPtr host = (*pNetworkItem).staticCast<Smb4KHost>(); 0448 WorkgroupPtr workgroup = findWorkgroup(host->workgroupName()); 0449 0450 if (workgroup && !workgroup->dnsDiscovered()) { 0451 smbc_setWorkgroup(m_context, host->workgroupName().toUtf8().data()); 0452 } 0453 0454 // 0455 // Set the NetBIOS name 0456 // 0457 smbc_setNetbiosName(m_context, host->hostName().toUtf8().data()); 0458 0459 break; 0460 } 0461 case Share: { 0462 // 0463 // In case the domain/workgroup was discovered by the DNS-SD service, the 0464 // workgroup/domain might not be identical with the one defined in the network 0465 // neighborhood. Thus, only set the workgroup if no DNS-SD discovery was used. 0466 // 0467 SharePtr share = (*pNetworkItem).staticCast<Smb4KShare>(); 0468 WorkgroupPtr workgroup = findWorkgroup(share->workgroupName()); 0469 0470 if (workgroup && !workgroup->dnsDiscovered()) { 0471 smbc_setWorkgroup(m_context, share->workgroupName().toUtf8().data()); 0472 } 0473 0474 // 0475 // Set the NetBIOS name 0476 // 0477 smbc_setNetbiosName(m_context, share->hostName().toUtf8().data()); 0478 0479 break; 0480 } 0481 case FileOrDirectory: { 0482 // 0483 // In case the domain/workgroup was discovered by the DNS-SD service, the 0484 // workgroup/domain might not be identical with the one defined in the network 0485 // neighborhood. Thus, only set the workgroup if no DNS-SD discovery was used. 0486 // 0487 FilePtr file = (*pNetworkItem).staticCast<Smb4KFile>(); 0488 0489 if (file->isDirectory()) { 0490 WorkgroupPtr workgroup = findWorkgroup(file->workgroupName()); 0491 0492 if (workgroup && !workgroup->dnsDiscovered()) { 0493 smbc_setWorkgroup(m_context, file->workgroupName().toUtf8().data()); 0494 } 0495 0496 // 0497 // Set the NetBIOS name 0498 // 0499 smbc_setNetbiosName(m_context, file->hostName().toUtf8().data()); 0500 } 0501 0502 break; 0503 } 0504 default: { 0505 break; 0506 } 0507 } 0508 0509 // 0510 // Set the user for making the connection 0511 // 0512 // To be able to connect to a Windows 10 server and get the list 0513 // of shared resources, use the 'guest' user here, if the URL 0514 // does not provide a user name. 0515 // 0516 if (!(*pNetworkItem)->url().userName().isEmpty()) { 0517 smbc_setUser(m_context, (*pNetworkItem)->url().userName().toUtf8().data()); 0518 } else { 0519 smbc_setUser(m_context, "guest"); 0520 } 0521 0522 // 0523 // Set the port 0524 // 0525 if (options) { 0526 if (options->useSmbPort()) { 0527 smbc_setPort(m_context, options->smbPort()); 0528 } else { 0529 smbc_setPort(m_context, 0 /* use the default */); 0530 } 0531 } else { 0532 if (Smb4KSettings::useRemoteSmbPort()) { 0533 smbc_setPort(m_context, Smb4KSettings::remoteSmbPort()); 0534 } else { 0535 smbc_setPort(m_context, 0 /* use the default */); 0536 } 0537 } 0538 0539 // 0540 // Set the user data (this class) 0541 // 0542 smbc_setOptionUserData(m_context, this); 0543 0544 // 0545 // Set number of master browsers to be used 0546 // 0547 if (Smb4KSettings::largeNetworkNeighborhood()) { 0548 smbc_setOptionBrowseMaxLmbCount(m_context, 3); 0549 } else { 0550 smbc_setOptionBrowseMaxLmbCount(m_context, 0 /* all master browsers */); 0551 } 0552 0553 // 0554 // Set the protocol version if desired 0555 // 0556 int minimal = -1; 0557 int maximal = -1; 0558 QString minimalClientProtocolVersionString, maximalClientProtocolVersionString; 0559 0560 if (options) { 0561 if (options->useClientProtocolVersions()) { 0562 minimal = options->minimalClientProtocolVersion(); 0563 maximal = options->maximalClientProtocolVersion(); 0564 } 0565 } else { 0566 if (Smb4KSettings::useClientProtocolVersions()) { 0567 minimal = Smb4KSettings::minimalClientProtocolVersion(); 0568 maximal = Smb4KSettings::maximalClientProtocolVersion(); 0569 } 0570 } 0571 0572 if (minimal != -1 && maximal != -1) { 0573 switch (minimal) { 0574 case Smb4KSettings::EnumMinimalClientProtocolVersion::NT1: { 0575 minimalClientProtocolVersionString = QStringLiteral("NT1"); 0576 break; 0577 } 0578 case Smb4KSettings::EnumMinimalClientProtocolVersion::SMB2: { 0579 minimalClientProtocolVersionString = QStringLiteral("SMB2"); 0580 break; 0581 } 0582 case Smb4KSettings::EnumMinimalClientProtocolVersion::SMB3: { 0583 minimalClientProtocolVersionString = QStringLiteral("SMB3"); 0584 break; 0585 } 0586 default: { 0587 break; 0588 } 0589 } 0590 0591 switch (Smb4KSettings::maximalClientProtocolVersion()) { 0592 case Smb4KSettings::EnumMaximalClientProtocolVersion::NT1: { 0593 maximalClientProtocolVersionString = QStringLiteral("NT1"); 0594 break; 0595 } 0596 case Smb4KSettings::EnumMaximalClientProtocolVersion::SMB2: { 0597 maximalClientProtocolVersionString = QStringLiteral("SMB2"); 0598 break; 0599 } 0600 case Smb4KSettings::EnumMaximalClientProtocolVersion::SMB3: { 0601 maximalClientProtocolVersionString = QStringLiteral("SMB3"); 0602 break; 0603 } 0604 default: { 0605 break; 0606 } 0607 } 0608 } 0609 0610 if (!minimalClientProtocolVersionString.isEmpty() && !maximalClientProtocolVersionString.isEmpty()) { 0611 smbc_setOptionProtocols(m_context, minimalClientProtocolVersionString.toLatin1().data(), maximalClientProtocolVersionString.toLatin1().data()); 0612 } else { 0613 smbc_setOptionProtocols(m_context, nullptr, nullptr); 0614 } 0615 0616 // 0617 // Set the encryption level 0618 // 0619 if (Smb4KSettings::useEncryptionLevel()) { 0620 switch (Smb4KSettings::encryptionLevel()) { 0621 case Smb4KSettings::EnumEncryptionLevel::None: { 0622 smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_NONE); 0623 break; 0624 } 0625 case Smb4KSettings::EnumEncryptionLevel::Request: { 0626 smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUEST); 0627 break; 0628 } 0629 case Smb4KSettings::EnumEncryptionLevel::Require: { 0630 smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUIRE); 0631 break; 0632 } 0633 default: { 0634 break; 0635 } 0636 } 0637 } 0638 0639 // 0640 // Set the usage of anonymous login 0641 // 0642 smbc_setOptionNoAutoAnonymousLogin(m_context, false); 0643 0644 // 0645 // Set the usage of the winbind ccache 0646 // 0647 smbc_setOptionUseCCache(m_context, Smb4KSettings::useWinbindCCache()); 0648 0649 // 0650 // Set usage of Kerberos 0651 // 0652 if (options) { 0653 smbc_setOptionUseKerberos(m_context, options->useKerberos()); 0654 } else { 0655 smbc_setOptionUseKerberos(m_context, Smb4KSettings::useKerberos()); 0656 } 0657 0658 smbc_setOptionFallbackAfterKerberos(m_context, 1); 0659 0660 // 0661 // Set the channel for debug output 0662 // 0663 smbc_setOptionDebugToStderr(m_context, 1); 0664 0665 // 0666 // Set auth callback function 0667 // 0668 smbc_setFunctionAuthDataWithContext(m_context, get_auth_data_with_context_fn); 0669 } 0670 0671 void Smb4KClientJob::doLookups() 0672 { 0673 // 0674 // Set the new context 0675 // 0676 (void)smbc_set_context(m_context); 0677 0678 // 0679 // Get the function to open the directory. 0680 // 0681 smbc_opendir_fn openDirectory = smbc_getFunctionOpendir(m_context); 0682 0683 if (!openDirectory) { 0684 int errorCode = errno; 0685 setError(ClientError); 0686 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0687 return; 0688 } 0689 0690 // 0691 // Open the directory 0692 // 0693 // If we use DNS-SD, the workgroup/domain name will most likely be unknown 0694 // for Samba and the following function fails. Since we do not want the lookup 0695 // to stop here in that case, do not throw an error when using DNS-SD and 0696 // Network and Workgroup (parent) items. 0697 // 0698 SMBCFILE *directory = openDirectory(m_context, (*pNetworkItem)->url().toString().toUtf8().data()); 0699 0700 if (!directory) { 0701 if (!(*pNetworkItem)->dnsDiscovered() && !((*pNetworkItem)->type() == Network || (*pNetworkItem)->type() == Workgroup)) { 0702 int errorCode = errno; 0703 0704 switch (errorCode) { 0705 case EACCES: 0706 case EPERM: { 0707 setError(AccessDeniedError); 0708 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0709 break; 0710 } 0711 case ENOENT: { 0712 if ((*pNetworkItem)->type() != Network) { 0713 setError(ClientError); 0714 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0715 } 0716 break; 0717 } 0718 default: { 0719 setError(ClientError); 0720 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0721 break; 0722 } 0723 } 0724 } 0725 0726 return; 0727 } 0728 0729 // 0730 // Read the directory 0731 // 0732 struct smbc_dirent *directoryEntry = nullptr; 0733 smbc_readdir_fn readDirectory = smbc_getFunctionReaddir(m_context); 0734 0735 if (!readDirectory) { 0736 int errorCode = errno; 0737 setError(ClientError); 0738 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 0739 return; 0740 } 0741 0742 while ((directoryEntry = readDirectory(m_context, directory)) != nullptr) { 0743 switch (directoryEntry->smbc_type) { 0744 case SMBC_WORKGROUP: { 0745 // 0746 // Create a workgroup pointer 0747 // 0748 WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); 0749 0750 // 0751 // Set the workgroup name 0752 // 0753 QString workgroupName = QString::fromUtf8(directoryEntry->name, -1); 0754 workgroup->setWorkgroupName(workgroupName); 0755 0756 // 0757 // Set the master browser 0758 // 0759 QString masterBrowserName = QString::fromUtf8(directoryEntry->comment, -1); 0760 workgroup->setMasterBrowserName(masterBrowserName); 0761 0762 // 0763 // Lookup IP address 0764 // 0765 QHostAddress address = lookupIpAddress(masterBrowserName); 0766 0767 // 0768 // Process the IP address. 0769 // If the address is null, the server most likely went offline. So, skip the 0770 // workgroup and delete the pointer. 0771 // 0772 if (!address.isNull()) { 0773 workgroup->setMasterBrowserIpAddress(address); 0774 *pWorkgroups << workgroup; 0775 } else { 0776 workgroup.clear(); 0777 } 0778 0779 break; 0780 } 0781 case SMBC_SERVER: { 0782 // 0783 // Create a host pointer 0784 // 0785 HostPtr host = HostPtr(new Smb4KHost()); 0786 0787 // 0788 // Set the workgroup name 0789 // 0790 host->setWorkgroupName((*pNetworkItem)->url().host()); 0791 0792 // 0793 // Set the host name 0794 // 0795 QString hostName = QString::fromUtf8(directoryEntry->name, -1); 0796 host->setHostName(hostName); 0797 0798 // 0799 // Set the comment 0800 // 0801 QString comment = QString::fromUtf8(directoryEntry->comment, -1); 0802 host->setComment(comment); 0803 0804 // 0805 // Lookup IP address 0806 // 0807 QHostAddress address = lookupIpAddress(hostName); 0808 0809 // 0810 // Process the IP address. 0811 // If the address is null, the server most likely went offline. So, skip it 0812 // and delete the pointer. 0813 // 0814 if (!address.isNull()) { 0815 host->setIpAddress(address); 0816 *pHosts << host; 0817 } else { 0818 host.clear(); 0819 } 0820 0821 break; 0822 } 0823 case SMBC_FILE_SHARE: { 0824 // 0825 // Create a share pointer 0826 // 0827 SharePtr share = SharePtr(new Smb4KShare()); 0828 0829 // 0830 // Set the workgroup name 0831 // 0832 share->setWorkgroupName((*pNetworkItem).staticCast<Smb4KHost>()->workgroupName()); 0833 0834 // 0835 // Set the host name 0836 // 0837 share->setHostName((*pNetworkItem)->url().host()); 0838 0839 // 0840 // Set the share name 0841 // 0842 share->setShareName(QString::fromUtf8(directoryEntry->name, -1)); 0843 0844 // 0845 // Set the comment 0846 // 0847 share->setComment(QString::fromUtf8(directoryEntry->comment, -1)); 0848 0849 // 0850 // Set share type 0851 // 0852 share->setShareType(FileShare); 0853 0854 // 0855 // Set the authentication data 0856 // 0857 share->setUserName((*pNetworkItem)->url().userName()); 0858 share->setPassword((*pNetworkItem)->url().password()); 0859 0860 // 0861 // Lookup IP address 0862 // 0863 QHostAddress address = lookupIpAddress((*pNetworkItem)->url().host()); 0864 0865 // 0866 // Process the IP address. 0867 // If the address is null, the server most likely went offline. So, skip it 0868 // and delete the pointer. 0869 // 0870 if (!address.isNull()) { 0871 share->setHostIpAddress(address); 0872 *pShares << share; 0873 } else { 0874 share.clear(); 0875 } 0876 0877 break; 0878 } 0879 case SMBC_PRINTER_SHARE: { 0880 // 0881 // Create a share pointer 0882 // 0883 SharePtr share = SharePtr(new Smb4KShare()); 0884 0885 // 0886 // Set the workgroup name 0887 // 0888 share->setWorkgroupName((*pNetworkItem).staticCast<Smb4KHost>()->workgroupName()); 0889 0890 // 0891 // Set the host name 0892 // 0893 share->setHostName((*pNetworkItem)->url().host()); 0894 0895 // 0896 // Set the share name 0897 // 0898 share->setShareName(QString::fromUtf8(directoryEntry->name, -1)); 0899 0900 // 0901 // Set the comment 0902 // 0903 share->setComment(QString::fromUtf8(directoryEntry->comment, -1)); 0904 0905 // 0906 // Set share type 0907 // 0908 share->setShareType(PrinterShare); 0909 0910 // 0911 // Set the authentication data 0912 // 0913 share->setUserName((*pNetworkItem)->url().userName()); 0914 share->setPassword((*pNetworkItem)->url().password()); 0915 0916 // 0917 // Lookup IP address 0918 // 0919 QHostAddress address = lookupIpAddress((*pNetworkItem)->url().host()); 0920 0921 // 0922 // Process the IP address. 0923 // If the address is null, the server most likely went offline. So, skip it 0924 // and delete the pointer. 0925 // 0926 if (!address.isNull()) { 0927 share->setHostIpAddress(address); 0928 *pShares << share; 0929 } else { 0930 share.clear(); 0931 } 0932 0933 break; 0934 } 0935 case SMBC_IPC_SHARE: { 0936 // 0937 // Create a share pointer 0938 // 0939 SharePtr share = SharePtr(new Smb4KShare()); 0940 0941 // 0942 // Set the workgroup name 0943 // 0944 share->setWorkgroupName((*pNetworkItem).staticCast<Smb4KHost>()->workgroupName()); 0945 0946 // 0947 // Set the host name 0948 // 0949 share->setHostName((*pNetworkItem)->url().host()); 0950 0951 // 0952 // Set the share name 0953 // 0954 share->setShareName(QString::fromUtf8(directoryEntry->name, -1)); 0955 0956 // 0957 // Set the comment 0958 // 0959 share->setComment(QString::fromUtf8(directoryEntry->comment, -1)); 0960 0961 // 0962 // Set share type 0963 // 0964 share->setShareType(IpcShare); 0965 0966 // 0967 // Set the authentication data 0968 // 0969 share->setUserName((*pNetworkItem)->url().userName()); 0970 share->setPassword((*pNetworkItem)->url().password()); 0971 0972 // 0973 // Lookup IP address 0974 // 0975 QHostAddress address = lookupIpAddress((*pNetworkItem)->url().host()); 0976 0977 // 0978 // Process the IP address. 0979 // If the address is null, the server most likely went offline. So, skip it 0980 // and delete the pointer. 0981 // 0982 if (!address.isNull()) { 0983 share->setHostIpAddress(address); 0984 *pShares << share; 0985 } else { 0986 share.clear(); 0987 } 0988 0989 break; 0990 } 0991 case SMBC_DIR: { 0992 // 0993 // Do not process '.' and '..' directories 0994 // 0995 QString name = QString::fromUtf8(directoryEntry->name, -1); 0996 0997 if (name != QStringLiteral(".") && name != QStringLiteral("..")) { 0998 // 0999 // Create the URL for the discovered item 1000 // 1001 QUrl u = (*pNetworkItem)->url(); 1002 u.setPath((*pNetworkItem)->url().path() + QDir::separator() + QString::fromUtf8(directoryEntry->name, -1)); 1003 1004 // 1005 // We do not stat directories. Directly create the directory object 1006 // 1007 FilePtr dir = FilePtr(new Smb4KFile(u)); 1008 dir->setDirectory(true); 1009 1010 // 1011 // Set the workgroup name 1012 // 1013 dir->setWorkgroupName((*pNetworkItem).staticCast<Smb4KShare>()->workgroupName()); 1014 1015 // 1016 // Set the authentication data 1017 // 1018 dir->setUserName((*pNetworkItem)->url().userName()); 1019 dir->setPassword((*pNetworkItem)->url().password()); 1020 1021 // 1022 // Lookup IP address 1023 // 1024 QHostAddress address = lookupIpAddress((*pNetworkItem)->url().host()); 1025 1026 // 1027 // Process the IP address. 1028 // If the address is null, the server most likely went offline. So, skip it 1029 // and delete the pointer. 1030 // 1031 if (!address.isNull()) { 1032 dir->setHostIpAddress(address); 1033 *pFiles << dir; 1034 } else { 1035 dir.clear(); 1036 } 1037 } 1038 1039 break; 1040 } 1041 case SMBC_FILE: { 1042 // 1043 // Create the URL for the discovered item 1044 // 1045 QUrl u = (*pNetworkItem)->url(); 1046 u.setPath((*pNetworkItem)->url().path() + QDir::separator() + QString::fromUtf8(directoryEntry->name, -1)); 1047 1048 // 1049 // Create the file object 1050 // 1051 FilePtr file = FilePtr(new Smb4KFile(u)); 1052 1053 // 1054 // Set the workgroup name 1055 // 1056 file->setWorkgroupName((*pNetworkItem).staticCast<Smb4KShare>()->workgroupName()); 1057 1058 // 1059 // Stat the file 1060 // 1061 // FIXME 1062 1063 // 1064 // Set the authentication data 1065 // 1066 file->setUserName((*pNetworkItem)->url().userName()); 1067 file->setPassword((*pNetworkItem)->url().password()); 1068 1069 // 1070 // Lookup IP address 1071 // 1072 QHostAddress address = lookupIpAddress((*pNetworkItem)->url().host()); 1073 1074 // 1075 // Process the IP address. 1076 // If the address is null, the server most likely went offline. So, skip it 1077 // and delete the pointer. 1078 // 1079 if (!address.isNull()) { 1080 file->setHostIpAddress(address); 1081 *pFiles << file; 1082 } else { 1083 file.clear(); 1084 } 1085 1086 break; 1087 } 1088 case SMBC_LINK: { 1089 qDebug() << "Processing links is not implemented."; 1090 qDebug() << directoryEntry->name; 1091 qDebug() << directoryEntry->comment; 1092 break; 1093 } 1094 default: { 1095 qDebug() << "Need to process network item " << directoryEntry->name; 1096 break; 1097 } 1098 } 1099 } 1100 1101 // 1102 // Close the directory 1103 // 1104 smbc_closedir_fn closeDirectory = smbc_getFunctionClosedir(m_context); 1105 1106 if (!closeDirectory) { 1107 int errorCode = errno; 1108 1109 setError(ClientError); 1110 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 1111 return; 1112 } 1113 1114 (void)closeDirectory(m_context, directory); 1115 } 1116 1117 void Smb4KClientJob::doPrinting() 1118 { 1119 // 1120 // Set the new context 1121 // 1122 (void)smbc_set_context(m_context); 1123 1124 // 1125 // The URL that is to be printed 1126 // 1127 QUrl fileUrl; 1128 1129 // 1130 // Set the temporary directory 1131 // 1132 QTemporaryDir tempDir; 1133 1134 // 1135 // Check if we can directly print the file 1136 // 1137 if (m_fileItem.mimetype() == QStringLiteral("application/postscript") || m_fileItem.mimetype() == QStringLiteral("application/pdf") 1138 || m_fileItem.mimetype().startsWith(QStringLiteral("image"))) { 1139 // 1140 // Set the URL to the incoming file 1141 // 1142 fileUrl = m_fileItem.url(); 1143 } else if (m_fileItem.mimetype() == QStringLiteral("application/x-shellscript") || m_fileItem.mimetype().startsWith(QStringLiteral("text")) 1144 || m_fileItem.mimetype().startsWith(QStringLiteral("message"))) { 1145 // 1146 // Set a printer object 1147 // 1148 QPrinter printer(QPrinter::HighResolution); 1149 printer.setCreator(QStringLiteral("Smb4K")); 1150 printer.setOutputFormat(QPrinter::PdfFormat); 1151 printer.setOutputFileName(tempDir.path() + QDir::separator() + QStringLiteral("smb4k_print.pdf")); 1152 1153 // 1154 // Open the file that is to be printed and read it 1155 // 1156 QStringList contents; 1157 1158 QFile file(m_fileItem.url().path()); 1159 1160 if (file.open(QFile::ReadOnly | QFile::Text)) { 1161 QTextStream ts(&file); 1162 1163 while (!ts.atEnd()) { 1164 contents << ts.readLine(); 1165 } 1166 } else { 1167 return; 1168 } 1169 1170 // 1171 // Convert the file to PDF 1172 // 1173 QTextDocument doc; 1174 1175 if (m_fileItem.mimetype().endsWith(QStringLiteral("html"))) { 1176 doc.setHtml(contents.join(QStringLiteral(" "))); 1177 } else { 1178 doc.setPlainText(contents.join(QStringLiteral("\n"))); 1179 } 1180 1181 doc.print(&printer); 1182 1183 // 1184 // Set the URL to the converted file 1185 // 1186 fileUrl.setUrl(printer.outputFileName()); 1187 fileUrl.setScheme(QStringLiteral("file")); 1188 } else { 1189 Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype()); 1190 return; 1191 } 1192 1193 // 1194 // Get the open function for the printer 1195 // 1196 smbc_open_print_job_fn openPrinter = smbc_getFunctionOpenPrintJob(m_context); 1197 1198 if (!openPrinter) { 1199 int errorCode = errno; 1200 setError(ClientError); 1201 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 1202 return; 1203 } 1204 1205 // 1206 // Open the printer for printing 1207 // 1208 SMBCFILE *printer = openPrinter(m_context, (*pNetworkItem)->url().toString().toUtf8().data()); 1209 1210 if (!printer) { 1211 int errorCode = errno; 1212 1213 switch (errorCode) { 1214 case EACCES: { 1215 setError(AccessDeniedError); 1216 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 1217 break; 1218 } 1219 default: { 1220 setError(ClientError); 1221 setErrorText(QString::fromUtf8(strerror(errorCode), -1)); 1222 break; 1223 } 1224 } 1225 1226 return; 1227 } 1228 1229 // 1230 // Open the file 1231 // 1232 QFile file(fileUrl.path()); 1233 1234 if (!file.open(QFile::ReadOnly)) { 1235 setError(FileAccessError); 1236 setErrorText(i18n("The file %1 could not be read", fileUrl.path())); 1237 return; 1238 } 1239 1240 // 1241 // Write X copies of the file to the printer 1242 // 1243 char buffer[4096]; 1244 qint64 bytes = 0; 1245 int copy = 0; 1246 1247 while (copy < m_copies) { 1248 while ((bytes = file.read(buffer, sizeof(buffer))) > 0) { 1249 smbc_write_fn writeFile = smbc_getFunctionWrite(m_context); 1250 1251 if (writeFile(m_context, printer, buffer, bytes) < 0) { 1252 setError(PrintFileError); 1253 setErrorText(i18n("The file %1 could not be printed to %2", fileUrl.path(), (*pNetworkItem).staticCast<Smb4KShare>()->displayString())); 1254 1255 smbc_close_fn closePrinter = smbc_getFunctionClose(m_context); 1256 closePrinter(m_context, printer); 1257 } 1258 } 1259 1260 copy++; 1261 } 1262 1263 // 1264 // Close the printer 1265 // 1266 smbc_close_fn closePrinter = smbc_getFunctionClose(m_context); 1267 closePrinter(m_context, printer); 1268 } 1269 1270 void Smb4KClientJob::slotStartJob() 1271 { 1272 // 1273 // Initialize the client library 1274 // 1275 initClientLibrary(); 1276 1277 // 1278 // Process the given URL according to the passed process 1279 // 1280 switch (*pProcess) { 1281 case LookupDomains: 1282 case LookupDomainMembers: 1283 case LookupShares: 1284 case LookupFiles: { 1285 // 1286 // Do lookups using the client library 1287 // 1288 doLookups(); 1289 break; 1290 } 1291 case PrintFile: { 1292 // 1293 // Print files using the client library 1294 // 1295 doPrinting(); 1296 break; 1297 } 1298 default: { 1299 break; 1300 } 1301 } 1302 1303 // 1304 // Emit the result 1305 // 1306 emitResult(); 1307 } 1308 1309 void Smb4KClientJob::slotFinishJob() 1310 { 1311 if (m_context != nullptr) { 1312 smbc_free_context(m_context, 1); 1313 } 1314 } 1315 1316 Smb4KDnsDiscoveryJob::Smb4KDnsDiscoveryJob(QObject *parent) 1317 : Smb4KClientBaseJob(parent) 1318 { 1319 // 1320 // Set up the DNS-SD browser 1321 // 1322 m_serviceBrowser = new KDNSSD::ServiceBrowser(QStringLiteral("_smb._tcp")); 1323 1324 // 1325 // Connections 1326 // 1327 connect(m_serviceBrowser, &KDNSSD::ServiceBrowser::serviceAdded, this, &Smb4KDnsDiscoveryJob::slotServiceAdded); 1328 connect(m_serviceBrowser, &KDNSSD::ServiceBrowser::finished, this, &Smb4KDnsDiscoveryJob::slotFinished); 1329 } 1330 1331 Smb4KDnsDiscoveryJob::~Smb4KDnsDiscoveryJob() 1332 { 1333 delete m_serviceBrowser; 1334 } 1335 1336 void Smb4KDnsDiscoveryJob::start() 1337 { 1338 switch (m_serviceBrowser->isAvailable()) { 1339 case KDNSSD::ServiceBrowser::Working: { 1340 break; 1341 } 1342 case KDNSSD::ServiceBrowser::Stopped: { 1343 Smb4KNotification::zeroconfError(i18n("The Zeroconf daemon is not running. No servers are discovered using DNS-SD.")); 1344 break; 1345 } 1346 case KDNSSD::ServiceBrowser::Unsupported: { 1347 Smb4KNotification::zeroconfError(i18n("Zeroconf support is not available in this version of KDE.")); 1348 break; 1349 } 1350 default: { 1351 Smb4KNotification::zeroconfError(i18n("An unknown error with Zeroconf occurred.")); 1352 break; 1353 } 1354 } 1355 1356 QTimer::singleShot(50, this, SLOT(slotStartJob())); 1357 } 1358 1359 void Smb4KDnsDiscoveryJob::slotStartJob() 1360 { 1361 m_serviceBrowser->startBrowse(); 1362 } 1363 1364 void Smb4KDnsDiscoveryJob::slotServiceAdded(KDNSSD::RemoteService::Ptr service) 1365 { 1366 switch (*pProcess) { 1367 case LookupDomains: { 1368 // 1369 // Check if the workgroup/domain is already known 1370 // 1371 bool foundWorkgroup = false; 1372 1373 for (const WorkgroupPtr &w : qAsConst(*pWorkgroups)) { 1374 if (QString::compare(w->workgroupName(), service->domain(), Qt::CaseInsensitive) == 0) { 1375 foundWorkgroup = true; 1376 break; 1377 } 1378 } 1379 1380 // 1381 // If the workgroup is not known yet, add it to the list 1382 // 1383 if (!foundWorkgroup) { 1384 // 1385 // Create the workgroup item 1386 // 1387 WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); 1388 1389 // 1390 // Set the _DNS-SD_ domain name 1391 // 1392 workgroup->setWorkgroupName(service->domain()); 1393 1394 // 1395 // Tell the program that the workgroup was discovered by DNS-SD 1396 // 1397 workgroup->setDnsDiscovered(true); 1398 1399 // 1400 // Add the workgroup 1401 // 1402 *pWorkgroups << workgroup; 1403 } 1404 break; 1405 } 1406 case LookupDomainMembers: { 1407 // 1408 // Check if the server is already known 1409 // 1410 bool foundServer = false; 1411 1412 for (const HostPtr &h : qAsConst(*pHosts)) { 1413 // 1414 // On a local network there will most likely be no two servers with 1415 // identical name, thus, to avoid duplicates, only test the hostname 1416 // here. 1417 // 1418 if (QString::compare(h->hostName(), service->serviceName(), Qt::CaseInsensitive) == 0) { 1419 foundServer = true; 1420 break; 1421 } 1422 } 1423 1424 // 1425 // If the server is not known yet, add it to the list 1426 // 1427 if (!foundServer) { 1428 // 1429 // Create the host item 1430 // 1431 HostPtr host = HostPtr(new Smb4KHost()); 1432 1433 // 1434 // Set the _DNS-SD_ host name 1435 // 1436 host->setHostName(service->serviceName()); 1437 1438 // 1439 // Set the _DNS-SD_ domain name 1440 // 1441 host->setWorkgroupName(service->domain()); 1442 1443 // 1444 // Tell the program that the host was discovered by DNS-SD 1445 // 1446 host->setDnsDiscovered(true); 1447 1448 // 1449 // Lookup IP address 1450 // 1451 QHostAddress address = lookupIpAddress(service->serviceName()); 1452 1453 // 1454 // Process the IP address. 1455 // 1456 if (!address.isNull()) { 1457 host->setIpAddress(address); 1458 } 1459 1460 // 1461 // Add the host 1462 // 1463 *pHosts << host; 1464 } 1465 1466 break; 1467 } 1468 default: { 1469 break; 1470 } 1471 } 1472 } 1473 1474 void Smb4KDnsDiscoveryJob::slotFinished() 1475 { 1476 emitResult(); 1477 } 1478 1479 #ifdef USE_WS_DISCOVERY 1480 Smb4KWsDiscoveryJob::Smb4KWsDiscoveryJob(QObject *parent) 1481 : Smb4KClientBaseJob(parent) 1482 { 1483 m_discoveryClient = new WSDiscoveryClient(this); 1484 1485 m_timer = new QTimer(this); 1486 m_timer->setSingleShot(true); 1487 m_timer->setInterval(2000); 1488 1489 connect(m_discoveryClient, &WSDiscoveryClient::probeMatchReceived, this, &Smb4KWsDiscoveryJob::slotProbeMatchReceived); 1490 connect(m_discoveryClient, &WSDiscoveryClient::resolveMatchReceived, this, &Smb4KWsDiscoveryJob::slotResolveMatchReceived); 1491 connect(m_timer, &QTimer::timeout, this, &Smb4KWsDiscoveryJob::slotDiscoveryFinished); 1492 } 1493 1494 Smb4KWsDiscoveryJob::~Smb4KWsDiscoveryJob() 1495 { 1496 } 1497 1498 void Smb4KWsDiscoveryJob::start() 1499 { 1500 QTimer::singleShot(50, this, SLOT(slotStartJob())); 1501 } 1502 1503 void Smb4KWsDiscoveryJob::slotStartJob() 1504 { 1505 // 1506 // Start the client 1507 // 1508 m_discoveryClient->start(); 1509 1510 // 1511 // Define the type 1512 // 1513 KDQName type(QStringLiteral("wsdp:Device")); 1514 type.setNameSpace(QStringLiteral("http://schemas.xmlsoap.org/ws/2006/02/devprof")); 1515 1516 // 1517 // Send the probe 1518 // 1519 m_discoveryClient->sendProbe({type}, {}); 1520 1521 // 1522 // Start the timer 1523 // 1524 m_timer->start(); 1525 } 1526 1527 void Smb4KWsDiscoveryJob::slotProbeMatchReceived(const WSDiscoveryTargetService &service) 1528 { 1529 // 1530 // Stop the timer 1531 // 1532 m_timer->stop(); 1533 1534 // 1535 // If there is no address, we need to resolve it. Otherwise, 1536 // resolve the available addresses and add the discovered network 1537 // items to the respective lists. 1538 // 1539 if (service.xAddrList().isEmpty()) { 1540 m_discoveryClient->sendResolve(service.endpointReference()); 1541 } else { 1542 if (!service.xAddrList().isEmpty()) { 1543 for (const QUrl &address : service.xAddrList()) { 1544 KDSoapClientInterface clientInterface(address.toString(), QStringLiteral("http://schemas.xmlsoap.org/ws/2004/09/transfer")); 1545 clientInterface.setSoapVersion(KDSoapClientInterface::SoapVersion::SOAP1_2); 1546 clientInterface.setTimeout(5000); 1547 1548 KDSoapMessage soapMessage; 1549 KDSoapMessageAddressingProperties soapMessageProperties; 1550 soapMessageProperties.setAddressingNamespace(KDSoapMessageAddressingProperties::Addressing200408); 1551 soapMessageProperties.setAction(QStringLiteral("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get")); 1552 soapMessageProperties.setMessageID(QStringLiteral("urn:uuid:") + QUuid::createUuid().toString(QUuid::WithoutBraces)); 1553 soapMessageProperties.setDestination(service.endpointReference()); 1554 soapMessageProperties.setReplyEndpointAddress( 1555 KDSoapMessageAddressingProperties::predefinedAddressToString(KDSoapMessageAddressingProperties::Anonymous, 1556 KDSoapMessageAddressingProperties::Addressing200408)); 1557 soapMessageProperties.setSourceEndpointAddress(QStringLiteral("urn:uuid:") + QUuid::createUuid().toString(QUuid::WithoutBraces)); 1558 soapMessage.setMessageAddressingProperties(soapMessageProperties); 1559 1560 KDSoapMessage response = clientInterface.call(QString(), soapMessage); 1561 1562 if (!response.isFault()) { 1563 KDSoapValueList childValues = response.childValues(); 1564 1565 for (const KDSoapValue &value : qAsConst(childValues)) { 1566 QString entry = value.childValues() 1567 .child(QStringLiteral("Relationship")) 1568 .childValues() 1569 .child(QStringLiteral("Host")) 1570 .childValues() 1571 .child(QStringLiteral("Computer")) 1572 .value() 1573 .toString(); 1574 1575 switch (*pProcess) { 1576 case LookupDomains: { 1577 // 1578 // Get the name of the workgroup or domain 1579 // 1580 QString workgroupName = entry.section(QStringLiteral(":"), 1, -1); 1581 1582 // 1583 // Work around an empty workgroup/domain name. Use the "LOCAL" domain from 1584 // DNS-SD for that. 1585 // 1586 if (workgroupName.isEmpty()) { 1587 workgroupName = QStringLiteral("LOCAL"); 1588 } 1589 1590 // 1591 // Process the workgroup name. Only add a new workgroup, if it 1592 // is not present already. 1593 // 1594 bool foundWorkgroup = false; 1595 1596 for (const WorkgroupPtr &w : qAsConst(*pWorkgroups)) { 1597 if (QString::compare(w->workgroupName(), workgroupName, Qt::CaseInsensitive) == 0) { 1598 foundWorkgroup = true; 1599 break; 1600 } 1601 } 1602 1603 // 1604 // If the workgroup is unknown, add it to the list 1605 // 1606 if (!foundWorkgroup) { 1607 // 1608 // Create the workgroup object 1609 // 1610 WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); 1611 1612 // 1613 // Set the workgroup/domain name 1614 // 1615 workgroup->setWorkgroupName(workgroupName); 1616 1617 // 1618 // Add the workgroup 1619 // 1620 *pWorkgroups << workgroup; 1621 } 1622 1623 break; 1624 } 1625 case LookupDomainMembers: { 1626 // 1627 // Get the workgroup name 1628 // 1629 QString workgroupName = entry.section(QStringLiteral(":"), 1, -1); 1630 1631 // 1632 // Work around an empty workgroup/domain name. Use the "LOCAL" domain from 1633 // DNS-SD for that. 1634 // 1635 if (workgroupName.isEmpty()) { 1636 workgroupName = QStringLiteral("LOCAL"); 1637 } 1638 1639 // 1640 // Get the host name. Unfortunately, the delimiter depends on 1641 // whether the host is member of a workgroup (/) or domain (\). 1642 // 1643 QString hostName; 1644 1645 if (entry.contains(QStringLiteral("/"))) { 1646 hostName = entry.section(QStringLiteral("/"), 0, 0); 1647 } else if (entry.contains(QStringLiteral("\\"))) { 1648 hostName = entry.section(QStringLiteral("\\"), 0, 0); 1649 } 1650 1651 // 1652 // Process the host name. Only add a new host, if it 1653 // is not present already. 1654 // 1655 if (!hostName.isEmpty()) { 1656 // 1657 // Check if the server is already known 1658 // 1659 bool foundServer = false; 1660 1661 for (const HostPtr &h : qAsConst(*pHosts)) { 1662 if (QString::compare(h->hostName(), hostName, Qt::CaseInsensitive) == 0 1663 && QString::compare(h->workgroupName(), workgroupName, Qt::CaseInsensitive) == 0) { 1664 foundServer = true; 1665 break; 1666 } 1667 } 1668 1669 // 1670 // If the server is unknown, add it to the list 1671 // 1672 if (!foundServer) { 1673 // 1674 // Create the host object 1675 // 1676 HostPtr host = HostPtr(new Smb4KHost()); 1677 1678 // 1679 // Set the workgroup/domain name 1680 // 1681 host->setWorkgroupName(workgroupName); 1682 1683 // 1684 // Set the host name 1685 // 1686 host->setHostName(hostName); 1687 1688 // 1689 // Lookup IP address 1690 // 1691 QHostAddress address = lookupIpAddress(hostName); 1692 1693 // 1694 // Process the IP address. 1695 // 1696 if (!address.isNull()) { 1697 host->setIpAddress(address); 1698 } 1699 1700 // 1701 // Add the host 1702 // 1703 *pHosts << host; 1704 } 1705 } 1706 1707 break; 1708 } 1709 default: { 1710 break; 1711 } 1712 } 1713 } 1714 } 1715 } 1716 } 1717 } 1718 1719 // 1720 // Restart the timer 1721 // 1722 m_timer->start(); 1723 } 1724 1725 void Smb4KWsDiscoveryJob::slotResolveMatchReceived(const WSDiscoveryTargetService &service) 1726 { 1727 // 1728 // Stop the timer 1729 // 1730 m_timer->stop(); 1731 1732 // 1733 // If there are addresses available, resolve them and add the 1734 // discovered network items to the respective lists. 1735 // 1736 if (!service.xAddrList().isEmpty()) { 1737 for (const QUrl &address : service.xAddrList()) { 1738 KDSoapClientInterface clientInterface(address.toString(), QStringLiteral("http://schemas.xmlsoap.org/ws/2004/09/transfer")); 1739 clientInterface.setSoapVersion(KDSoapClientInterface::SoapVersion::SOAP1_2); 1740 clientInterface.setTimeout(5000); 1741 1742 KDSoapMessage soapMessage; 1743 KDSoapMessageAddressingProperties soapMessageProperties; 1744 soapMessageProperties.setAddressingNamespace(KDSoapMessageAddressingProperties::Addressing200408); 1745 soapMessageProperties.setAction(QStringLiteral("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get")); 1746 soapMessageProperties.setMessageID(QStringLiteral("urn:uuid:") + QUuid::createUuid().toString(QUuid::WithoutBraces)); 1747 soapMessageProperties.setDestination(service.endpointReference()); 1748 soapMessageProperties.setReplyEndpointAddress( 1749 KDSoapMessageAddressingProperties::predefinedAddressToString(KDSoapMessageAddressingProperties::Anonymous, 1750 KDSoapMessageAddressingProperties::Addressing200408)); 1751 soapMessageProperties.setSourceEndpointAddress(QStringLiteral("urn:uuid:") + QUuid::createUuid().toString(QUuid::WithoutBraces)); 1752 soapMessage.setMessageAddressingProperties(soapMessageProperties); 1753 1754 KDSoapMessage response = clientInterface.call(QString(), soapMessage); 1755 1756 if (!response.isFault()) { 1757 KDSoapValueList childValues = response.childValues(); 1758 1759 for (const KDSoapValue &value : qAsConst(childValues)) { 1760 QString entry = value.childValues() 1761 .child(QStringLiteral("Relationship")) 1762 .childValues() 1763 .child(QStringLiteral("Host")) 1764 .childValues() 1765 .child(QStringLiteral("Computer")) 1766 .value() 1767 .toString(); 1768 1769 switch (*pProcess) { 1770 case LookupDomains: { 1771 // 1772 // Get the name of the workgroup or domain 1773 // 1774 QString workgroupName = entry.section(QStringLiteral(":"), 1, -1); 1775 1776 // 1777 // Work around an empty workgroup/domain name. Use the "LOCAL" domain from 1778 // DNS-SD for that. 1779 // 1780 if (workgroupName.isEmpty()) { 1781 workgroupName = QStringLiteral("LOCAL"); 1782 } 1783 1784 // 1785 // Process the workgroup name. Only add a new workgroup, if it 1786 // is not present already. 1787 // 1788 bool foundWorkgroup = false; 1789 1790 for (const WorkgroupPtr &w : qAsConst(*pWorkgroups)) { 1791 if (QString::compare(w->workgroupName(), workgroupName, Qt::CaseInsensitive) == 0) { 1792 foundWorkgroup = true; 1793 break; 1794 } 1795 } 1796 1797 // 1798 // If the workgroup is unknown, add it to the list 1799 // 1800 if (!foundWorkgroup) { 1801 // 1802 // Create the workgroup object 1803 // 1804 WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); 1805 1806 // 1807 // Set the workgroup/domain name 1808 // 1809 workgroup->setWorkgroupName(workgroupName); 1810 1811 // 1812 // Add the workgroup 1813 // 1814 *pWorkgroups << workgroup; 1815 } 1816 1817 break; 1818 } 1819 case LookupDomainMembers: { 1820 // 1821 // Get the workgroup name 1822 // 1823 QString workgroupName = entry.section(QStringLiteral(":"), 1, -1); 1824 1825 // 1826 // Work around an empty workgroup/domain name. Use the "LOCAL" domain from 1827 // DNS-SD for that. 1828 // 1829 if (workgroupName.isEmpty()) { 1830 workgroupName = QStringLiteral("LOCAL"); 1831 } 1832 1833 // 1834 // Get the host name. Unfortunately, the delimiter depends on 1835 // whether the host is member of a workgroup (/) or domain (\). 1836 // 1837 QString hostName; 1838 1839 if (entry.contains(QStringLiteral("/"))) { 1840 hostName = entry.section(QStringLiteral("/"), 0, 0); 1841 } else if (entry.contains(QStringLiteral("\\"))) { 1842 hostName = entry.section(QStringLiteral("\\"), 0, 0); 1843 } 1844 1845 // 1846 // Process the host name. Only add a new host, if it 1847 // is not present already. 1848 // 1849 if (!hostName.isEmpty()) { 1850 // 1851 // Check if the server is already known 1852 // 1853 bool foundServer = false; 1854 1855 for (const HostPtr &h : qAsConst(*pHosts)) { 1856 if (QString::compare(h->hostName(), hostName, Qt::CaseInsensitive) == 0 1857 && QString::compare(h->workgroupName(), workgroupName, Qt::CaseInsensitive) == 0) { 1858 foundServer = true; 1859 break; 1860 } 1861 } 1862 1863 // 1864 // If the server is unknown, add it to the list 1865 // 1866 if (!foundServer) { 1867 // 1868 // Create the host object 1869 // 1870 HostPtr host = HostPtr(new Smb4KHost()); 1871 1872 // 1873 // Set the workgroup/domain name 1874 // 1875 host->setWorkgroupName(workgroupName); 1876 1877 // 1878 // Set the host name 1879 // 1880 host->setHostName(hostName); 1881 1882 // 1883 // Lookup IP address 1884 // 1885 QHostAddress address = lookupIpAddress(hostName); 1886 1887 // 1888 // Process the IP address. 1889 // 1890 if (!address.isNull()) { 1891 host->setIpAddress(address); 1892 } 1893 1894 // 1895 // Add the host 1896 // 1897 *pHosts << host; 1898 } 1899 } 1900 1901 break; 1902 } 1903 default: { 1904 break; 1905 } 1906 } 1907 } 1908 } 1909 } 1910 } 1911 1912 // 1913 // Restart the timer 1914 // 1915 m_timer->start(); 1916 } 1917 1918 void Smb4KWsDiscoveryJob::slotDiscoveryFinished() 1919 { 1920 emitResult(); 1921 } 1922 #endif