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