File indexing completed on 2024-04-14 15:05:28
0001 /*************************************************************************** 0002 This is the global namespace for Smb4K. 0003 ------------------- 0004 begin : Sa Apr 2 2005 0005 copyright : (C) 2005-2019 by Alexander Reinholdt 0006 email : alexander.reinholdt@kdemail.net 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * This program is free software; you can redistribute it and/or modify * 0011 * it under the terms of the GNU General Public License as published by * 0012 * the Free Software Foundation; either version 2 of the License, or * 0013 * (at your option) any later version. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, but * 0016 * WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0018 * General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program; if not, write to the * 0022 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* 0023 * MA 02110-1335, USA * 0024 ***************************************************************************/ 0025 0026 #ifdef HAVE_CONFIG_H 0027 #include <config.h> 0028 #endif 0029 0030 // application specific includes 0031 #include "smb4kglobal.h" 0032 #include "smb4kglobal_p.h" 0033 #include "smb4knotification.h" 0034 #include "smb4ksynchronizer.h" 0035 #include "smb4kclient.h" 0036 #include "smb4kmounter.h" 0037 0038 // Qt includes 0039 #include <QMutex> 0040 #include <QUrl> 0041 #include <QStandardPaths> 0042 #include <QDebug> 0043 0044 // KDE includes 0045 #include <KCoreAddons/KShell> 0046 #include <KIOWidgets/KRun> 0047 0048 Q_GLOBAL_STATIC(Smb4KGlobalPrivate, p); 0049 QMutex mutex(QMutex::Recursive /* needed to avoid dead-locks */); 0050 0051 0052 void Smb4KGlobal::initCore(bool modifyCursor, bool initClasses) 0053 { 0054 if (!p->coreInitialized) 0055 { 0056 // 0057 // Busy cursor 0058 // 0059 p->modifyCursor = modifyCursor; 0060 0061 // 0062 // Initialize the necessary core classes 0063 // 0064 if (initClasses) 0065 { 0066 Smb4KClient::self()->start(); 0067 Smb4KMounter::self()->start(); 0068 } 0069 0070 p->coreInitialized = true; 0071 } 0072 } 0073 0074 0075 void Smb4KGlobal::abortCore() 0076 { 0077 Smb4KClient::self()->abort(); 0078 Smb4KMounter::self()->abort(); 0079 Smb4KSynchronizer::self()->abort(); 0080 } 0081 0082 0083 bool Smb4KGlobal::coreIsRunning() 0084 { 0085 return (Smb4KClient::self()->isRunning() || 0086 Smb4KMounter::self()->isRunning() || 0087 Smb4KSynchronizer::self()->isRunning()); 0088 } 0089 0090 0091 bool Smb4KGlobal::coreIsInitialized() 0092 { 0093 return p->coreInitialized; 0094 } 0095 0096 0097 const QList<WorkgroupPtr> &Smb4KGlobal::workgroupsList() 0098 { 0099 return p->workgroupsList; 0100 } 0101 0102 0103 WorkgroupPtr Smb4KGlobal::findWorkgroup(const QString &name) 0104 { 0105 WorkgroupPtr workgroup; 0106 0107 mutex.lock(); 0108 0109 for (const WorkgroupPtr &w : p->workgroupsList) 0110 { 0111 if (QString::compare(w->workgroupName(), name, Qt::CaseInsensitive) == 0) 0112 { 0113 workgroup = w; 0114 break; 0115 } 0116 } 0117 0118 mutex.unlock(); 0119 0120 return workgroup; 0121 } 0122 0123 0124 bool Smb4KGlobal::addWorkgroup(WorkgroupPtr workgroup) 0125 { 0126 Q_ASSERT(workgroup); 0127 0128 bool added = false; 0129 0130 if (workgroup) 0131 { 0132 mutex.lock(); 0133 0134 if (!findWorkgroup(workgroup->workgroupName())) 0135 { 0136 p->workgroupsList.append(workgroup); 0137 added = true; 0138 } 0139 0140 mutex.unlock(); 0141 } 0142 0143 return added; 0144 } 0145 0146 0147 bool Smb4KGlobal::updateWorkgroup(WorkgroupPtr workgroup) 0148 { 0149 Q_ASSERT(workgroup); 0150 0151 bool updated = false; 0152 0153 if (workgroup) 0154 { 0155 mutex.lock(); 0156 0157 WorkgroupPtr existingWorkgroup = findWorkgroup(workgroup->workgroupName()); 0158 0159 if (existingWorkgroup) 0160 { 0161 existingWorkgroup->update(workgroup.data()); 0162 updated = true; 0163 } 0164 0165 mutex.unlock(); 0166 } 0167 0168 return updated; 0169 } 0170 0171 0172 0173 bool Smb4KGlobal::removeWorkgroup(WorkgroupPtr workgroup) 0174 { 0175 Q_ASSERT(workgroup); 0176 0177 bool removed = false; 0178 0179 if (workgroup) 0180 { 0181 mutex.lock(); 0182 0183 int index = p->workgroupsList.indexOf(workgroup); 0184 0185 if (index != -1) 0186 { 0187 // The workgroup was found. Remove it. 0188 p->workgroupsList.takeAt(index).clear(); 0189 removed = true; 0190 } 0191 else 0192 { 0193 // Try harder to find the workgroup. 0194 WorkgroupPtr wg = findWorkgroup(workgroup->workgroupName()); 0195 0196 if (wg) 0197 { 0198 index = p->workgroupsList.indexOf(wg); 0199 0200 if (index != -1) 0201 { 0202 p->workgroupsList.takeAt(index).clear(); 0203 removed = true; 0204 } 0205 } 0206 0207 workgroup.clear(); 0208 } 0209 0210 mutex.unlock(); 0211 } 0212 0213 return removed; 0214 } 0215 0216 0217 void Smb4KGlobal::clearWorkgroupsList() 0218 { 0219 mutex.lock(); 0220 0221 while (!p->workgroupsList.isEmpty()) 0222 { 0223 p->workgroupsList.takeFirst().clear(); 0224 } 0225 0226 mutex.unlock(); 0227 } 0228 0229 0230 const QList<HostPtr> &Smb4KGlobal::hostsList() 0231 { 0232 return p->hostsList; 0233 } 0234 0235 0236 HostPtr Smb4KGlobal::findHost(const QString &name, const QString &workgroup) 0237 { 0238 HostPtr host; 0239 0240 mutex.lock(); 0241 0242 for (const HostPtr &h : p->hostsList) 0243 { 0244 if ((workgroup.isEmpty() || QString::compare(h->workgroupName(), workgroup, Qt::CaseInsensitive) == 0) && 0245 QString::compare(h->hostName(), name, Qt::CaseInsensitive) == 0) 0246 { 0247 host = h; 0248 break; 0249 } 0250 } 0251 0252 mutex.unlock(); 0253 0254 return host; 0255 } 0256 0257 0258 bool Smb4KGlobal::addHost(HostPtr host) 0259 { 0260 Q_ASSERT(host); 0261 0262 bool added = false; 0263 0264 if (host) 0265 { 0266 mutex.lock(); 0267 0268 if (!findHost(host->hostName(), host->workgroupName())) 0269 { 0270 p->hostsList.append(host); 0271 added = true; 0272 } 0273 0274 mutex.unlock(); 0275 } 0276 0277 return added; 0278 } 0279 0280 0281 bool Smb4KGlobal::updateHost(HostPtr host) 0282 { 0283 Q_ASSERT(host); 0284 0285 bool updated = false; 0286 0287 if (host) 0288 { 0289 mutex.lock(); 0290 0291 HostPtr existingHost = findHost(host->hostName(), host->workgroupName()); 0292 0293 if (existingHost) 0294 { 0295 existingHost->update(host.data()); 0296 updated = true; 0297 } 0298 0299 mutex.unlock(); 0300 } 0301 0302 return updated; 0303 } 0304 0305 0306 0307 bool Smb4KGlobal::removeHost(HostPtr host) 0308 { 0309 Q_ASSERT(host); 0310 0311 bool removed = false; 0312 0313 if (host) 0314 { 0315 mutex.lock(); 0316 0317 int index = p->hostsList.indexOf(host); 0318 0319 if (index != -1) 0320 { 0321 // The host was found. Remove it. 0322 p->hostsList.takeAt(index).clear(); 0323 removed = true; 0324 } 0325 else 0326 { 0327 // Try harder to find the host. 0328 HostPtr h = findHost(host->hostName(), host->workgroupName()); 0329 0330 if (h) 0331 { 0332 index = p->hostsList.indexOf(h); 0333 0334 if (index != -1) 0335 { 0336 p->hostsList.takeAt(index).clear(); 0337 removed = true; 0338 } 0339 } 0340 0341 host.clear(); 0342 } 0343 0344 mutex.unlock(); 0345 } 0346 0347 return removed; 0348 } 0349 0350 0351 void Smb4KGlobal::clearHostsList() 0352 { 0353 mutex.lock(); 0354 0355 while (!p->hostsList.isEmpty()) 0356 { 0357 p->hostsList.takeFirst().clear(); 0358 } 0359 0360 mutex.unlock(); 0361 } 0362 0363 0364 QList<HostPtr> Smb4KGlobal::workgroupMembers(WorkgroupPtr workgroup) 0365 { 0366 QList<HostPtr> hosts; 0367 0368 mutex.lock(); 0369 0370 for (const HostPtr &h : p->hostsList) 0371 { 0372 if (QString::compare(h->workgroupName(), workgroup->workgroupName(), Qt::CaseInsensitive) == 0) 0373 { 0374 hosts << h; 0375 } 0376 } 0377 0378 mutex.unlock(); 0379 0380 return hosts; 0381 } 0382 0383 0384 const QList<SharePtr> &Smb4KGlobal::sharesList() 0385 { 0386 return p->sharesList; 0387 } 0388 0389 0390 SharePtr Smb4KGlobal::findShare(const QUrl& url, const QString& workgroup) 0391 { 0392 SharePtr share; 0393 0394 mutex.lock(); 0395 0396 for (const SharePtr &s : p->sharesList) 0397 { 0398 if (QString::compare(s->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), 0399 url.toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0 && 0400 (workgroup.isEmpty() || QString::compare(s->workgroupName(), workgroup, Qt::CaseInsensitive) == 0)) 0401 { 0402 share = s; 0403 break; 0404 } 0405 } 0406 0407 mutex.unlock(); 0408 0409 return share; 0410 } 0411 0412 0413 0414 bool Smb4KGlobal::addShare(SharePtr share) 0415 { 0416 Q_ASSERT(share); 0417 0418 bool added = false; 0419 0420 if (share) 0421 { 0422 mutex.lock(); 0423 0424 // 0425 // Add the share 0426 // 0427 if (!findShare(share->url(), share->workgroupName())) 0428 { 0429 // 0430 // Set the share mounted 0431 // Only honor shares that are owned by the user 0432 // 0433 QList<SharePtr> mountedShares = findShareByUrl(share->url()); 0434 0435 if (!mountedShares.isEmpty()) 0436 { 0437 for (const SharePtr &s : mountedShares) 0438 { 0439 if (!s->isForeign()) 0440 { 0441 share->setMountData(s.data()); 0442 break; 0443 } 0444 else 0445 { 0446 continue; 0447 } 0448 } 0449 } 0450 0451 // 0452 // Add it 0453 // 0454 p->sharesList.append(share); 0455 added = true; 0456 } 0457 } 0458 0459 mutex.unlock(); 0460 0461 return added; 0462 } 0463 0464 0465 bool Smb4KGlobal::updateShare(SharePtr share) 0466 { 0467 Q_ASSERT(share); 0468 0469 bool updated = false; 0470 0471 if (share) 0472 { 0473 mutex.lock(); 0474 0475 // 0476 // Updated the share 0477 // 0478 SharePtr existingShare = findShare(share->url(), share->workgroupName()); 0479 0480 if (existingShare) 0481 { 0482 // 0483 // Set the share mounted 0484 // Only honor shares that are owned by the user 0485 // 0486 QList<SharePtr> mountedShares = findShareByUrl(share->url()); 0487 0488 if (!mountedShares.isEmpty()) 0489 { 0490 for (const SharePtr &s : mountedShares) 0491 { 0492 if (!s->isForeign()) 0493 { 0494 share->setMountData(s.data()); 0495 break; 0496 } 0497 else 0498 { 0499 continue; 0500 } 0501 } 0502 } 0503 0504 // 0505 // Update it 0506 // 0507 existingShare->update(share.data()); 0508 updated = true; 0509 } 0510 0511 mutex.unlock(); 0512 } 0513 0514 return updated; 0515 } 0516 0517 0518 0519 bool Smb4KGlobal::removeShare(SharePtr share) 0520 { 0521 Q_ASSERT(share); 0522 0523 bool removed = false; 0524 0525 if (share) 0526 { 0527 mutex.lock(); 0528 0529 int index = p->sharesList.indexOf(share); 0530 0531 if (index != -1) 0532 { 0533 // The share was found. Remove it. 0534 p->sharesList.takeAt(index).clear(); 0535 removed = true; 0536 } 0537 else 0538 { 0539 // Try harder to find the share. 0540 SharePtr s = findShare(share->url(), share->workgroupName()); 0541 0542 if (s) 0543 { 0544 index = p->sharesList.indexOf(s); 0545 0546 if (index != -1) 0547 { 0548 p->sharesList.takeAt(index).clear(); 0549 removed = true; 0550 } 0551 } 0552 0553 share.clear(); 0554 } 0555 0556 mutex.unlock(); 0557 } 0558 0559 return removed; 0560 } 0561 0562 0563 void Smb4KGlobal::clearSharesList() 0564 { 0565 mutex.lock(); 0566 0567 while (!p->sharesList.isEmpty()) 0568 { 0569 p->sharesList.takeFirst().clear(); 0570 } 0571 0572 mutex.unlock(); 0573 } 0574 0575 0576 QList<SharePtr> Smb4KGlobal::sharedResources(HostPtr host) 0577 { 0578 QList<SharePtr> shares; 0579 0580 mutex.lock(); 0581 0582 for (const SharePtr &s : p->sharesList) 0583 { 0584 if (QString::compare(s->hostName(), host->hostName(), Qt::CaseInsensitive) == 0 && 0585 QString::compare(s->workgroupName(), host->workgroupName(), Qt::CaseInsensitive) == 0) 0586 { 0587 shares += s; 0588 } 0589 } 0590 0591 mutex.unlock(); 0592 0593 return shares; 0594 } 0595 0596 0597 const QList<SharePtr> &Smb4KGlobal::mountedSharesList() 0598 { 0599 return p->mountedSharesList; 0600 } 0601 0602 0603 SharePtr Smb4KGlobal::findShareByPath(const QString &path) 0604 { 0605 SharePtr share; 0606 0607 mutex.lock(); 0608 0609 if (!path.isEmpty() && !p->mountedSharesList.isEmpty()) 0610 { 0611 for (const SharePtr &s : p->mountedSharesList) 0612 { 0613 if (QString::compare(s->path(), path, Qt::CaseInsensitive) == 0 || 0614 QString::compare(s->canonicalPath(), path, Qt::CaseInsensitive) == 0) 0615 { 0616 share = s; 0617 break; 0618 } 0619 } 0620 } 0621 0622 mutex.unlock(); 0623 0624 return share; 0625 } 0626 0627 0628 QList<SharePtr> Smb4KGlobal::findShareByUrl(const QUrl &url) 0629 { 0630 QList<SharePtr> shares; 0631 0632 mutex.lock(); 0633 0634 if (!url.isEmpty() && url.isValid() && !p->mountedSharesList.isEmpty()) 0635 { 0636 for (const SharePtr &s : p->mountedSharesList) 0637 { 0638 if (QString::compare(s->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), 0639 url.toString(QUrl::RemoveUserInfo|QUrl::RemovePort), 0640 Qt::CaseInsensitive) == 0) 0641 { 0642 shares << s; 0643 } 0644 } 0645 } 0646 0647 mutex.unlock(); 0648 0649 return shares; 0650 } 0651 0652 0653 QList<SharePtr> Smb4KGlobal::findInaccessibleShares() 0654 { 0655 QList<SharePtr> inaccessibleShares; 0656 0657 mutex.lock(); 0658 0659 for (const SharePtr &s : p->mountedSharesList) 0660 { 0661 if (s->isInaccessible()) 0662 { 0663 inaccessibleShares += s; 0664 } 0665 } 0666 0667 mutex.unlock(); 0668 0669 return inaccessibleShares; 0670 } 0671 0672 0673 bool Smb4KGlobal::addMountedShare(SharePtr share) 0674 { 0675 Q_ASSERT(share); 0676 0677 bool added = false; 0678 0679 if (share) 0680 { 0681 mutex.lock(); 0682 0683 // 0684 // Copy the mount data to the network share if available. 0685 // Only honor shares that were mounted by the user. 0686 // 0687 if (!share->isForeign()) 0688 { 0689 // Network share 0690 SharePtr networkShare = findShare(share->url(), share->workgroupName()); 0691 0692 if (networkShare) 0693 { 0694 networkShare->setMountData(share.data()); 0695 } 0696 } 0697 0698 if (!findShareByPath(share->path())) 0699 { 0700 // 0701 // Check if we have to add a workgroup name and/or IP address 0702 // 0703 HostPtr networkHost = findHost(share->hostName(), share->workgroupName()); 0704 0705 if (networkHost) 0706 { 0707 // Set the IP address 0708 if (!share->hasHostIpAddress() || networkHost->ipAddress() != share->hostIpAddress()) 0709 { 0710 share->setHostIpAddress(networkHost->ipAddress()); 0711 } 0712 0713 // Set the workgroup name 0714 if (share->workgroupName().isEmpty()) 0715 { 0716 share->setWorkgroupName(networkHost->workgroupName()); 0717 } 0718 } 0719 0720 p->mountedSharesList.append(share); 0721 added = true; 0722 0723 p->onlyForeignShares = true; 0724 0725 for (const SharePtr &s : p->mountedSharesList) 0726 { 0727 if (!s->isForeign()) 0728 { 0729 p->onlyForeignShares = false; 0730 break; 0731 } 0732 } 0733 } 0734 0735 mutex.unlock(); 0736 } 0737 0738 return added; 0739 } 0740 0741 0742 bool Smb4KGlobal::updateMountedShare(SharePtr share) 0743 { 0744 Q_ASSERT(share); 0745 0746 bool updated = false; 0747 0748 if (share) 0749 { 0750 mutex.lock(); 0751 0752 // 0753 // Copy the mount data to the network share (needed for unmounting from the network browser) 0754 // Only honor shares that were mounted by the user. 0755 // 0756 if (!share->isForeign()) 0757 { 0758 SharePtr networkShare = findShare(share->url(), share->workgroupName()); 0759 0760 if (networkShare) 0761 { 0762 networkShare->setMountData(share.data()); 0763 } 0764 } 0765 0766 SharePtr mountedShare = findShareByPath(share->path()); 0767 0768 if (mountedShare) 0769 { 0770 // 0771 // Check if we have to add a workgroup name and/or IP address 0772 // 0773 HostPtr networkHost = findHost(share->hostName(), share->workgroupName()); 0774 0775 if (networkHost) 0776 { 0777 // Set the IP address 0778 if (!share->hasHostIpAddress() || networkHost->ipAddress() != share->hostIpAddress()) 0779 { 0780 share->setHostIpAddress(networkHost->ipAddress()); 0781 } 0782 0783 // Set the workgroup name 0784 if (share->workgroupName().isEmpty()) 0785 { 0786 share->setWorkgroupName(networkHost->workgroupName()); 0787 } 0788 } 0789 0790 // 0791 // Update share 0792 // 0793 mountedShare->setMountData(share.data()); 0794 updated = true; 0795 } 0796 0797 mutex.unlock(); 0798 } 0799 0800 return updated; 0801 } 0802 0803 0804 bool Smb4KGlobal::removeMountedShare(SharePtr share) 0805 { 0806 Q_ASSERT(share); 0807 0808 bool removed = false; 0809 0810 if (share) 0811 { 0812 mutex.lock(); 0813 0814 // 0815 // Reset the mount data for the network share and the 0816 // search result 0817 // 0818 if (!share->isForeign()) 0819 { 0820 // Network share 0821 SharePtr networkShare = findShare(share->url(), share->workgroupName()); 0822 0823 if (networkShare) 0824 { 0825 networkShare->resetMountData(); 0826 } 0827 } 0828 0829 // 0830 // Remove the mounted share 0831 // 0832 int index = p->mountedSharesList.indexOf(share); 0833 0834 if (index != -1) 0835 { 0836 // The share was found. Remove it. 0837 p->mountedSharesList.takeAt(index).clear(); 0838 removed = true; 0839 } 0840 else 0841 { 0842 // Try harder to find the share. 0843 SharePtr s = findShareByPath(share->isInaccessible() ? share->path() : share->canonicalPath()); 0844 0845 if (s) 0846 { 0847 index = p->mountedSharesList.indexOf(s); 0848 0849 if (index != -1) 0850 { 0851 p->mountedSharesList.takeAt(index).clear(); 0852 removed = true; 0853 } 0854 } 0855 0856 share.clear(); 0857 } 0858 0859 for (const SharePtr &s : p->mountedSharesList) 0860 { 0861 if (!s->isForeign()) 0862 { 0863 p->onlyForeignShares = false; 0864 break; 0865 } 0866 } 0867 0868 mutex.unlock(); 0869 } 0870 0871 return removed; 0872 } 0873 0874 0875 bool Smb4KGlobal::onlyForeignMountedShares() 0876 { 0877 return p->onlyForeignShares; 0878 } 0879 0880 0881 void Smb4KGlobal::openShare(SharePtr share, OpenWith openWith) 0882 { 0883 if (!share || share->isInaccessible()) 0884 { 0885 return; 0886 } 0887 0888 switch (openWith) 0889 { 0890 case FileManager: 0891 { 0892 QUrl url = QUrl::fromLocalFile(share->canonicalPath()); 0893 0894 (void) new KRun(url, 0); 0895 0896 break; 0897 } 0898 case Konsole: 0899 { 0900 QString konsole = QStandardPaths::findExecutable("konsole"); 0901 0902 if (konsole.isEmpty()) 0903 { 0904 Smb4KNotification::commandNotFound("konsole"); 0905 } 0906 else 0907 { 0908 KRun::runCommand(konsole+" --workdir "+KShell::quoteArg(share->canonicalPath()), 0); 0909 } 0910 0911 break; 0912 } 0913 default: 0914 { 0915 break; 0916 } 0917 } 0918 } 0919 0920 0921 const QMap<QString,QString> &Smb4KGlobal::globalSambaOptions() 0922 { 0923 return p->globalSambaOptions(); 0924 } 0925 0926 0927 bool Smb4KGlobal::modifyCursor() 0928 { 0929 return p->modifyCursor; 0930 } 0931 0932 0933 #if defined(Q_OS_LINUX) 0934 QStringList Smb4KGlobal::whitelistedMountArguments() 0935 { 0936 return p->whitelistedMountArguments; 0937 } 0938 #endif 0939 0940 0941 const QString Smb4KGlobal::findMountExecutable() 0942 { 0943 QStringList paths; 0944 paths << "/bin"; 0945 paths << "/sbin"; 0946 paths << "/usr/bin"; 0947 paths << "/usr/sbin"; 0948 paths << "/usr/local/bin"; 0949 paths << "/usr/local/sbin"; 0950 0951 #if defined(Q_OS_LINUX) 0952 return QStandardPaths::findExecutable("mount.cifs", paths); 0953 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0954 return QStandardPaths::findExecutable("mount_smbfs", paths); 0955 #else 0956 return QString(); 0957 #endif 0958 } 0959 0960 0961 const QString Smb4KGlobal::findUmountExecutable() 0962 { 0963 QStringList paths; 0964 paths << "/bin"; 0965 paths << "/sbin"; 0966 paths << "/usr/bin"; 0967 paths << "/usr/sbin"; 0968 paths << "/usr/local/bin"; 0969 paths << "/usr/local/sbin"; 0970 0971 return QStandardPaths::findExecutable("umount", paths); 0972 } 0973 0974 0975 const QString Smb4KGlobal::dataLocation() 0976 { 0977 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)+QDir::separator()+"smb4k"; 0978 } 0979