File indexing completed on 2024-04-21 05:01:38
0001 /* 0002 This is the global namespace for Smb4K. 0003 0004 SPDX-FileCopyrightText: 2005-2024 Alexander Reinholdt <alexander.reinholdt@kdemail.net> 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 // application specific includes 0009 #include "smb4kglobal.h" 0010 #include "smb4kclient.h" 0011 #include "smb4kglobal_p.h" 0012 #include "smb4kglobalenums.h" 0013 #include "smb4kmounter.h" 0014 #include "smb4knotification.h" 0015 #include "smb4ksynchronizer.h" 0016 0017 // Qt includes 0018 #include <QDebug> 0019 #include <QDirIterator> 0020 #include <QEventLoop> 0021 #include <QRecursiveMutex> 0022 #include <QStandardPaths> 0023 #include <QTimer> 0024 #include <QUrl> 0025 0026 // KDE includes 0027 #include <KIO/CommandLauncherJob> 0028 #include <KIO/OpenUrlJob> 0029 0030 Q_GLOBAL_STATIC(Smb4KGlobalPrivate, p); 0031 QRecursiveMutex mutex; 0032 0033 const QList<WorkgroupPtr> &Smb4KGlobal::workgroupsList() 0034 { 0035 return p->workgroupsList; 0036 } 0037 0038 WorkgroupPtr Smb4KGlobal::findWorkgroup(const QString &name) 0039 { 0040 WorkgroupPtr workgroup; 0041 0042 mutex.lock(); 0043 0044 for (const WorkgroupPtr &w : qAsConst(p->workgroupsList)) { 0045 if (QString::compare(w->workgroupName(), name, Qt::CaseInsensitive) == 0) { 0046 workgroup = w; 0047 break; 0048 } 0049 } 0050 0051 mutex.unlock(); 0052 0053 return workgroup; 0054 } 0055 0056 bool Smb4KGlobal::addWorkgroup(WorkgroupPtr workgroup) 0057 { 0058 Q_ASSERT(workgroup); 0059 0060 bool added = false; 0061 0062 if (workgroup) { 0063 mutex.lock(); 0064 0065 if (!findWorkgroup(workgroup->workgroupName())) { 0066 p->workgroupsList.append(workgroup); 0067 added = true; 0068 } 0069 0070 mutex.unlock(); 0071 } 0072 0073 return added; 0074 } 0075 0076 bool Smb4KGlobal::updateWorkgroup(WorkgroupPtr workgroup) 0077 { 0078 Q_ASSERT(workgroup); 0079 0080 bool updated = false; 0081 0082 if (workgroup) { 0083 mutex.lock(); 0084 0085 WorkgroupPtr existingWorkgroup = findWorkgroup(workgroup->workgroupName()); 0086 0087 if (existingWorkgroup) { 0088 existingWorkgroup->update(workgroup.data()); 0089 updated = true; 0090 } 0091 0092 mutex.unlock(); 0093 } 0094 0095 return updated; 0096 } 0097 0098 bool Smb4KGlobal::removeWorkgroup(WorkgroupPtr workgroup) 0099 { 0100 Q_ASSERT(workgroup); 0101 0102 bool removed = false; 0103 0104 if (workgroup) { 0105 mutex.lock(); 0106 0107 int index = p->workgroupsList.indexOf(workgroup); 0108 0109 if (index != -1) { 0110 // The workgroup was found. Remove it. 0111 p->workgroupsList.takeAt(index).clear(); 0112 removed = true; 0113 } else { 0114 // Try harder to find the workgroup. 0115 WorkgroupPtr wg = findWorkgroup(workgroup->workgroupName()); 0116 0117 if (wg) { 0118 index = p->workgroupsList.indexOf(wg); 0119 0120 if (index != -1) { 0121 p->workgroupsList.takeAt(index).clear(); 0122 removed = true; 0123 } 0124 } 0125 0126 workgroup.clear(); 0127 } 0128 0129 mutex.unlock(); 0130 } 0131 0132 return removed; 0133 } 0134 0135 void Smb4KGlobal::clearWorkgroupsList() 0136 { 0137 mutex.lock(); 0138 0139 while (!p->workgroupsList.isEmpty()) { 0140 p->workgroupsList.takeFirst().clear(); 0141 } 0142 0143 mutex.unlock(); 0144 } 0145 0146 const QList<HostPtr> &Smb4KGlobal::hostsList() 0147 { 0148 return p->hostsList; 0149 } 0150 0151 HostPtr Smb4KGlobal::findHost(const QString &name, const QString &workgroup) 0152 { 0153 HostPtr host; 0154 0155 mutex.lock(); 0156 0157 for (const HostPtr &h : qAsConst(p->hostsList)) { 0158 if ((workgroup.isEmpty() || QString::compare(h->workgroupName(), workgroup, Qt::CaseInsensitive) == 0) 0159 && QString::compare(h->hostName(), name, Qt::CaseInsensitive) == 0) { 0160 host = h; 0161 break; 0162 } 0163 } 0164 0165 mutex.unlock(); 0166 0167 return host; 0168 } 0169 0170 bool Smb4KGlobal::addHost(HostPtr host) 0171 { 0172 Q_ASSERT(host); 0173 0174 bool added = false; 0175 0176 if (host) { 0177 mutex.lock(); 0178 0179 if (!findHost(host->hostName(), host->workgroupName())) { 0180 p->hostsList.append(host); 0181 added = true; 0182 } 0183 0184 mutex.unlock(); 0185 } 0186 0187 return added; 0188 } 0189 0190 bool Smb4KGlobal::updateHost(HostPtr host) 0191 { 0192 Q_ASSERT(host); 0193 0194 bool updated = false; 0195 0196 if (host) { 0197 mutex.lock(); 0198 0199 HostPtr existingHost = findHost(host->hostName(), host->workgroupName()); 0200 0201 if (existingHost) { 0202 existingHost->update(host.data()); 0203 updated = true; 0204 } 0205 0206 mutex.unlock(); 0207 } 0208 0209 return updated; 0210 } 0211 0212 bool Smb4KGlobal::removeHost(HostPtr host) 0213 { 0214 Q_ASSERT(host); 0215 0216 bool removed = false; 0217 0218 if (host) { 0219 mutex.lock(); 0220 0221 int index = p->hostsList.indexOf(host); 0222 0223 if (index != -1) { 0224 // The host was found. Remove it. 0225 p->hostsList.takeAt(index).clear(); 0226 removed = true; 0227 } else { 0228 // Try harder to find the host. 0229 HostPtr h = findHost(host->hostName(), host->workgroupName()); 0230 0231 if (h) { 0232 index = p->hostsList.indexOf(h); 0233 0234 if (index != -1) { 0235 p->hostsList.takeAt(index).clear(); 0236 removed = true; 0237 } 0238 } 0239 0240 host.clear(); 0241 } 0242 0243 mutex.unlock(); 0244 } 0245 0246 return removed; 0247 } 0248 0249 void Smb4KGlobal::clearHostsList() 0250 { 0251 mutex.lock(); 0252 0253 while (!p->hostsList.isEmpty()) { 0254 p->hostsList.takeFirst().clear(); 0255 } 0256 0257 mutex.unlock(); 0258 } 0259 0260 QList<HostPtr> Smb4KGlobal::workgroupMembers(WorkgroupPtr workgroup) 0261 { 0262 QList<HostPtr> hosts; 0263 0264 mutex.lock(); 0265 0266 for (const HostPtr &h : qAsConst(p->hostsList)) { 0267 if (QString::compare(h->workgroupName(), workgroup->workgroupName(), Qt::CaseInsensitive) == 0) { 0268 hosts << h; 0269 } 0270 } 0271 0272 mutex.unlock(); 0273 0274 return hosts; 0275 } 0276 0277 const QList<SharePtr> &Smb4KGlobal::sharesList() 0278 { 0279 return p->sharesList; 0280 } 0281 0282 SharePtr Smb4KGlobal::findShare(const QUrl &url, const QString &workgroup) 0283 { 0284 SharePtr share; 0285 0286 mutex.lock(); 0287 0288 for (const SharePtr &s : qAsConst(p->sharesList)) { 0289 if (QString::compare(s->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort), 0290 url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort), 0291 Qt::CaseInsensitive) 0292 == 0 0293 && (workgroup.isEmpty() || QString::compare(s->workgroupName(), workgroup, Qt::CaseInsensitive) == 0)) { 0294 share = s; 0295 break; 0296 } 0297 } 0298 0299 mutex.unlock(); 0300 0301 return share; 0302 } 0303 0304 bool Smb4KGlobal::addShare(SharePtr share) 0305 { 0306 Q_ASSERT(share); 0307 0308 bool added = false; 0309 0310 if (share) { 0311 mutex.lock(); 0312 0313 // 0314 // Add the share 0315 // 0316 if (!findShare(share->url(), share->workgroupName())) { 0317 // 0318 // Set the share mounted 0319 // Only honor shares that are owned by the user 0320 // 0321 QList<SharePtr> mountedShares = findShareByUrl(share->url()); 0322 0323 if (!mountedShares.isEmpty()) { 0324 for (const SharePtr &s : qAsConst(mountedShares)) { 0325 if (!s->isForeign()) { 0326 share->setMountData(s.data()); 0327 break; 0328 } else { 0329 continue; 0330 } 0331 } 0332 } 0333 0334 // 0335 // Add it 0336 // 0337 p->sharesList.append(share); 0338 added = true; 0339 } 0340 } 0341 0342 mutex.unlock(); 0343 0344 return added; 0345 } 0346 0347 bool Smb4KGlobal::updateShare(SharePtr share) 0348 { 0349 Q_ASSERT(share); 0350 0351 bool updated = false; 0352 0353 if (share) { 0354 mutex.lock(); 0355 0356 // 0357 // Updated the share 0358 // 0359 SharePtr existingShare = findShare(share->url(), share->workgroupName()); 0360 0361 if (existingShare) { 0362 // 0363 // Set the share mounted 0364 // Only honor shares that are owned by the user 0365 // 0366 QList<SharePtr> mountedShares = findShareByUrl(share->url()); 0367 0368 if (!mountedShares.isEmpty()) { 0369 for (const SharePtr &s : qAsConst(mountedShares)) { 0370 if (!s->isForeign()) { 0371 share->setMountData(s.data()); 0372 break; 0373 } else { 0374 continue; 0375 } 0376 } 0377 } 0378 0379 // 0380 // Update it 0381 // 0382 existingShare->update(share.data()); 0383 updated = true; 0384 } 0385 0386 mutex.unlock(); 0387 } 0388 0389 return updated; 0390 } 0391 0392 bool Smb4KGlobal::removeShare(SharePtr share) 0393 { 0394 Q_ASSERT(share); 0395 0396 bool removed = false; 0397 0398 if (share) { 0399 mutex.lock(); 0400 0401 int index = p->sharesList.indexOf(share); 0402 0403 if (index != -1) { 0404 // The share was found. Remove it. 0405 p->sharesList.takeAt(index).clear(); 0406 removed = true; 0407 } else { 0408 // Try harder to find the share. 0409 SharePtr s = findShare(share->url(), share->workgroupName()); 0410 0411 if (s) { 0412 index = p->sharesList.indexOf(s); 0413 0414 if (index != -1) { 0415 p->sharesList.takeAt(index).clear(); 0416 removed = true; 0417 } 0418 } 0419 0420 share.clear(); 0421 } 0422 0423 mutex.unlock(); 0424 } 0425 0426 return removed; 0427 } 0428 0429 void Smb4KGlobal::clearSharesList() 0430 { 0431 mutex.lock(); 0432 0433 while (!p->sharesList.isEmpty()) { 0434 p->sharesList.takeFirst().clear(); 0435 } 0436 0437 mutex.unlock(); 0438 } 0439 0440 QList<SharePtr> Smb4KGlobal::sharedResources(HostPtr host) 0441 { 0442 QList<SharePtr> shares; 0443 0444 mutex.lock(); 0445 0446 for (const SharePtr &s : qAsConst(p->sharesList)) { 0447 if (QString::compare(s->hostName(), host->hostName(), Qt::CaseInsensitive) == 0 0448 && QString::compare(s->workgroupName(), host->workgroupName(), Qt::CaseInsensitive) == 0) { 0449 shares += s; 0450 } 0451 } 0452 0453 mutex.unlock(); 0454 0455 return shares; 0456 } 0457 0458 const QList<SharePtr> &Smb4KGlobal::mountedSharesList() 0459 { 0460 return p->mountedSharesList; 0461 } 0462 0463 SharePtr Smb4KGlobal::findShareByPath(const QString &path) 0464 { 0465 SharePtr share; 0466 0467 mutex.lock(); 0468 0469 if (!path.isEmpty() && !p->mountedSharesList.isEmpty()) { 0470 for (const SharePtr &s : qAsConst(p->mountedSharesList)) { 0471 if (QString::compare(s->path(), path, Qt::CaseInsensitive) == 0 0472 || (!s->isInaccessible() && QString::compare(s->canonicalPath(), path, Qt::CaseInsensitive) == 0)) { 0473 share = s; 0474 break; 0475 } 0476 } 0477 } 0478 0479 mutex.unlock(); 0480 0481 return share; 0482 } 0483 0484 QList<SharePtr> Smb4KGlobal::findShareByUrl(const QUrl &url) 0485 { 0486 QList<SharePtr> shares; 0487 0488 mutex.lock(); 0489 0490 if (!url.isEmpty() && url.isValid() && !p->mountedSharesList.isEmpty()) { 0491 for (const SharePtr &s : qAsConst(p->mountedSharesList)) { 0492 if (QString::compare(s->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort), 0493 url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort), 0494 Qt::CaseInsensitive) 0495 == 0) { 0496 shares << s; 0497 break; 0498 } 0499 } 0500 } 0501 0502 mutex.unlock(); 0503 0504 return shares; 0505 } 0506 0507 QList<SharePtr> Smb4KGlobal::findInaccessibleShares() 0508 { 0509 QList<SharePtr> inaccessibleShares; 0510 0511 mutex.lock(); 0512 0513 for (const SharePtr &s : qAsConst(p->mountedSharesList)) { 0514 if (s->isInaccessible()) { 0515 inaccessibleShares += s; 0516 } 0517 } 0518 0519 mutex.unlock(); 0520 0521 return inaccessibleShares; 0522 } 0523 0524 bool Smb4KGlobal::addMountedShare(SharePtr share) 0525 { 0526 Q_ASSERT(share); 0527 0528 bool added = false; 0529 0530 if (share) { 0531 mutex.lock(); 0532 0533 // 0534 // Copy the mount data to the network share if available. 0535 // Only honor shares that were mounted by the user. 0536 // 0537 if (!share->isForeign()) { 0538 // Network share 0539 SharePtr networkShare = findShare(share->url(), share->workgroupName()); 0540 0541 if (networkShare) { 0542 networkShare->setMountData(share.data()); 0543 } 0544 } 0545 0546 if (!findShareByPath(share->path())) { 0547 // 0548 // Check if we have to add a workgroup name and/or IP address 0549 // 0550 HostPtr networkHost = findHost(share->hostName(), share->workgroupName()); 0551 0552 if (networkHost) { 0553 // Set the IP address 0554 if (!share->hasHostIpAddress() || networkHost->ipAddress() != share->hostIpAddress()) { 0555 share->setHostIpAddress(networkHost->ipAddress()); 0556 } 0557 0558 // Set the workgroup name 0559 if (share->workgroupName().isEmpty()) { 0560 share->setWorkgroupName(networkHost->workgroupName()); 0561 } 0562 } 0563 0564 p->mountedSharesList.append(share); 0565 added = true; 0566 0567 p->onlyForeignShares = true; 0568 0569 for (const SharePtr &s : qAsConst(p->mountedSharesList)) { 0570 if (!s->isForeign()) { 0571 p->onlyForeignShares = false; 0572 break; 0573 } 0574 } 0575 } 0576 0577 mutex.unlock(); 0578 } 0579 0580 return added; 0581 } 0582 0583 bool Smb4KGlobal::updateMountedShare(SharePtr share) 0584 { 0585 Q_ASSERT(share); 0586 0587 bool updated = false; 0588 0589 if (share) { 0590 mutex.lock(); 0591 0592 // 0593 // Copy the mount data to the network share (needed for unmounting from the network browser) 0594 // Only honor shares that were mounted by the user. 0595 // 0596 if (!share->isForeign()) { 0597 SharePtr networkShare = findShare(share->url(), share->workgroupName()); 0598 0599 if (networkShare) { 0600 networkShare->setMountData(share.data()); 0601 } 0602 } 0603 0604 SharePtr mountedShare = findShareByPath(share->path()); 0605 0606 if (mountedShare) { 0607 // 0608 // Check if we have to add a workgroup name and/or IP address 0609 // 0610 HostPtr networkHost = findHost(share->hostName(), share->workgroupName()); 0611 0612 if (networkHost) { 0613 // Set the IP address 0614 if (!share->hasHostIpAddress() || networkHost->ipAddress() != share->hostIpAddress()) { 0615 share->setHostIpAddress(networkHost->ipAddress()); 0616 } 0617 0618 // Set the workgroup name 0619 if (share->workgroupName().isEmpty()) { 0620 share->setWorkgroupName(networkHost->workgroupName()); 0621 } 0622 } 0623 0624 // 0625 // Update share 0626 // 0627 mountedShare->setMountData(share.data()); 0628 updated = true; 0629 } 0630 0631 mutex.unlock(); 0632 } 0633 0634 return updated; 0635 } 0636 0637 bool Smb4KGlobal::removeMountedShare(SharePtr share) 0638 { 0639 Q_ASSERT(share); 0640 0641 bool removed = false; 0642 0643 if (share) { 0644 mutex.lock(); 0645 0646 // 0647 // Reset the mount data for the network share and the 0648 // search result 0649 // 0650 if (!share->isForeign()) { 0651 // Network share 0652 SharePtr networkShare = findShare(share->url(), share->workgroupName()); 0653 0654 if (networkShare) { 0655 networkShare->resetMountData(); 0656 } 0657 } 0658 0659 // 0660 // Remove the mounted share 0661 // 0662 int index = p->mountedSharesList.indexOf(share); 0663 0664 if (index != -1) { 0665 // The share was found. Remove it. 0666 p->mountedSharesList.takeAt(index).clear(); 0667 removed = true; 0668 } else { 0669 // Try harder to find the share. 0670 SharePtr s = findShareByPath(share->isInaccessible() ? share->path() : share->canonicalPath()); 0671 0672 if (s) { 0673 index = p->mountedSharesList.indexOf(s); 0674 0675 if (index != -1) { 0676 p->mountedSharesList.takeAt(index).clear(); 0677 removed = true; 0678 } 0679 } 0680 0681 share.clear(); 0682 } 0683 0684 for (const SharePtr &s : qAsConst(p->mountedSharesList)) { 0685 if (!s->isForeign()) { 0686 p->onlyForeignShares = false; 0687 break; 0688 } 0689 } 0690 0691 mutex.unlock(); 0692 } 0693 0694 return removed; 0695 } 0696 0697 bool Smb4KGlobal::onlyForeignMountedShares() 0698 { 0699 return p->onlyForeignShares; 0700 } 0701 0702 void Smb4KGlobal::openShare(SharePtr share, OpenWith openWith) 0703 { 0704 if (!share || share->isInaccessible()) { 0705 return; 0706 } 0707 0708 switch (openWith) { 0709 case FileManager: { 0710 QUrl url = QUrl::fromLocalFile(share->canonicalPath()); 0711 0712 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url); 0713 job->setFollowRedirections(false); 0714 job->setAutoDelete(true); 0715 job->start(); 0716 0717 break; 0718 } 0719 case Konsole: { 0720 QString konsole = QStandardPaths::findExecutable(QStringLiteral("konsole")); 0721 0722 if (!konsole.isEmpty()) { 0723 KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(konsole); 0724 job->setWorkingDirectory(share->canonicalPath()); 0725 job->setAutoDelete(true); 0726 job->start(); 0727 } else { 0728 Smb4KNotification::commandNotFound(QStringLiteral("konsole")); 0729 } 0730 0731 break; 0732 } 0733 default: { 0734 break; 0735 } 0736 } 0737 } 0738 0739 const QString Smb4KGlobal::machineNetbiosName() 0740 { 0741 return p->machineNetbiosName; 0742 } 0743 0744 const QString Smb4KGlobal::machineWorkgroupName() 0745 { 0746 return p->machineWorkgroupName; 0747 } 0748 0749 #if defined(Q_OS_LINUX) 0750 QStringList Smb4KGlobal::allowedMountArguments() 0751 { 0752 return p->allowedMountArguments; 0753 } 0754 #endif 0755 0756 const QString Smb4KGlobal::findMountExecutable() 0757 { 0758 QStringList paths; 0759 paths << QStringLiteral("/bin"); 0760 paths << QStringLiteral("/sbin"); 0761 paths << QStringLiteral("/usr/bin"); 0762 paths << QStringLiteral("/usr/sbin"); 0763 paths << QStringLiteral("/usr/local/bin"); 0764 paths << QStringLiteral("/usr/local/sbin"); 0765 0766 #if defined(Q_OS_LINUX) 0767 return QStandardPaths::findExecutable(QStringLiteral("mount.cifs"), paths); 0768 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0769 return QStandardPaths::findExecutable(QStringLiteral("mount_smbfs"), paths); 0770 #else 0771 return QString(); 0772 #endif 0773 } 0774 0775 const QString Smb4KGlobal::findUmountExecutable() 0776 { 0777 QStringList paths; 0778 paths << QStringLiteral("/bin"); 0779 paths << QStringLiteral("/sbin"); 0780 paths << QStringLiteral("/usr/bin"); 0781 paths << QStringLiteral("/usr/sbin"); 0782 paths << QStringLiteral("/usr/local/bin"); 0783 paths << QStringLiteral("/usr/local/sbin"); 0784 0785 return QStandardPaths::findExecutable(QStringLiteral("umount"), paths); 0786 } 0787 0788 const QString Smb4KGlobal::dataLocation() 0789 { 0790 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() + QStringLiteral("smb4k"); 0791 } 0792 0793 void Smb4KGlobal::wait(int time) 0794 { 0795 QEventLoop loop; 0796 QTimer::singleShot(time, &loop, SLOT(quit())); 0797 loop.exec(); 0798 }