File indexing completed on 2024-04-14 15:05:26

0001 /***************************************************************************
0002     Manage custom options
0003                              -------------------
0004     begin                : Fr 29 Apr 2011
0005     copyright            : (C) 2011-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 "smb4kcustomoptionsmanager.h"
0032 #include "smb4kcustomoptionsmanager_p.h"
0033 #include "smb4kcustomoptions.h"
0034 #include "smb4khomesshareshandler.h"
0035 #include "smb4knotification.h"
0036 #include "smb4khost.h"
0037 #include "smb4kshare.h"
0038 #include "smb4ksettings.h"
0039 #include "smb4kglobal.h"
0040 #include "smb4kprofilemanager.h"
0041 
0042 #if defined(Q_OS_LINUX)
0043 #include "smb4kmountsettings_linux.h"
0044 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
0045 #include "smb4kmountsettings_bsd.h"
0046 #endif
0047 
0048 // Qt includes
0049 #include <QXmlStreamReader>
0050 #include <QXmlStreamWriter>
0051 #include <QDebug>
0052 #include <QApplication>
0053 #include <QPointer>
0054 
0055 // KDE includes
0056 #define TRANSLATION_DOMAIN "smb4k-core"
0057 #include <KI18n/KLocalizedString>
0058 
0059 using namespace Smb4KGlobal;
0060 
0061 Q_GLOBAL_STATIC(Smb4KCustomOptionsManagerStatic, p);
0062 
0063 
0064 Smb4KCustomOptionsManager::Smb4KCustomOptionsManager(QObject *parent)
0065 : QObject(parent), d(new Smb4KCustomOptionsManagerPrivate)
0066 {
0067   // First we need the directory.
0068   QString path = dataLocation();
0069   
0070   QDir dir;
0071   
0072   if (!dir.exists(path))
0073   {
0074     dir.mkpath(path);
0075   }
0076   
0077   readCustomOptions();
0078   
0079   // Connections
0080   connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(slotAboutToQuit()));
0081 }
0082 
0083 
0084 Smb4KCustomOptionsManager::~Smb4KCustomOptionsManager()
0085 {
0086 }
0087 
0088 
0089 Smb4KCustomOptionsManager *Smb4KCustomOptionsManager::self()
0090 {
0091   return &p->instance;
0092 }
0093 
0094 
0095 void Smb4KCustomOptionsManager::addRemount(const SharePtr &share, bool always)
0096 {
0097   if (share)
0098   {
0099     //
0100     // Find the right custom options, if they exist
0101     // 
0102     OptionsPtr options = findOptions(share, true);
0103     
0104     if (options)
0105     {
0106       // If the options are already in the list, check if the share is
0107       // always to be remounted. If so, ignore the 'always' argument
0108       // and leave that option untouched.
0109       if (options->remount() != Smb4KCustomOptions::RemountAlways)
0110       {
0111         options->setRemount(always ? Smb4KCustomOptions::RemountAlways : Smb4KCustomOptions::RemountOnce);
0112       }
0113     }
0114     else
0115     {
0116       options = OptionsPtr(new Smb4KCustomOptions(share.data()));
0117       options->setProfile(Smb4KProfileManager::self()->activeProfile());
0118       options->setRemount(always ? Smb4KCustomOptions::RemountAlways : Smb4KCustomOptions::RemountOnce);
0119       d->options << options;
0120     }
0121     
0122     //
0123     // Write the custom options
0124     // 
0125     writeCustomOptions();
0126   }
0127 }
0128 
0129 
0130 void Smb4KCustomOptionsManager::removeRemount(const SharePtr &share, bool force)
0131 {
0132   if (share)
0133   {
0134     //
0135     // Get the remount
0136     // 
0137     OptionsPtr options = findOptions(share, true);
0138     
0139     //
0140     // Remove the remount flag and, if there are no more options defined,
0141     // the options object itself. Save the modified list to the file afterwards.
0142     // 
0143     if (options)
0144     {
0145       if (options->remount() == Smb4KCustomOptions::RemountOnce)
0146       {
0147         options->setRemount(Smb4KCustomOptions::UndefinedRemount);
0148       }
0149       else if (options->remount() == Smb4KCustomOptions::RemountAlways && force)
0150       {
0151         options->setRemount(Smb4KCustomOptions::UndefinedRemount);
0152       }
0153       
0154       if (!options->hasOptions())
0155       {
0156         removeCustomOptions(options, false);
0157       }
0158     }
0159     
0160     //
0161     // Write the options
0162     //
0163     writeCustomOptions();
0164   }
0165 }
0166 
0167 
0168 void Smb4KCustomOptionsManager::clearRemounts(bool force)
0169 {
0170   //
0171   // Remove the remount flag and, if there are nomore options defined,
0172   // also the options object. Write everything to the file afterwards.
0173   //
0174   for (const OptionsPtr &o : d->options)
0175   {
0176     if (o->type() == Share)
0177     {
0178       if (o->remount() == Smb4KCustomOptions::RemountOnce)
0179       {
0180         o->setRemount(Smb4KCustomOptions::UndefinedRemount);
0181       }
0182       else if (o->remount() == Smb4KCustomOptions::RemountAlways && force)
0183       {
0184         o->setRemount(Smb4KCustomOptions::UndefinedRemount);
0185       }
0186     }
0187     
0188     if (!o->hasOptions())
0189     {
0190       removeCustomOptions(o, false);
0191     }
0192   }
0193   
0194   //
0195   // Write the options
0196   //
0197   writeCustomOptions();
0198 }
0199 
0200 
0201 QList<OptionsPtr> Smb4KCustomOptionsManager::sharesToRemount()
0202 {
0203   //
0204   // List of relevant custom options
0205   //
0206   QList<OptionsPtr> options = customOptions(false);
0207   
0208   //
0209   // List of remounts
0210   //
0211   QList<OptionsPtr> remounts;
0212   
0213   //
0214   // Get the list of remounts
0215   //
0216   for (const OptionsPtr &o : options)
0217   {
0218     if (o->remount() == Smb4KCustomOptions::RemountOnce)
0219     {
0220       remounts << o;
0221     }
0222     else if (o->remount() == Smb4KCustomOptions::RemountAlways)
0223     {
0224       remounts << o;
0225     }
0226   }
0227   
0228   //
0229   // Return relevant options
0230   //
0231   return remounts;
0232 }
0233 
0234 
0235 OptionsPtr Smb4KCustomOptionsManager::findOptions(const NetworkItemPtr &networkItem, bool exactMatch)
0236 {
0237   //
0238   // The options that are to be returned
0239   //
0240   OptionsPtr options;
0241   
0242   //
0243   // Get the list of options
0244   // 
0245   QList<OptionsPtr> optionsList = customOptions(false);
0246   
0247   //
0248   // Only do something if the list of options is not empty.
0249   // 
0250   if (!optionsList.isEmpty())
0251   {
0252     for (const OptionsPtr &opt : optionsList)
0253     {
0254       //
0255       // If we want to have an exact match, skip all options that do not match
0256       // 
0257       if (exactMatch)
0258       {
0259         if (networkItem->type() != opt->type() || 
0260             QString::compare(networkItem->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash), 
0261                              opt->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash), Qt::CaseInsensitive) != 0)
0262         {
0263           continue;
0264         }
0265       }
0266       
0267       //
0268       // Now assign the options
0269       // 
0270       if (networkItem->type() == Host && opt->type() == Host)
0271       {
0272         HostPtr host = networkItem.staticCast<Smb4KHost>();
0273         
0274         if (host)
0275         {
0276           if (QString::compare(host->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash), 
0277                                opt->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash), Qt::CaseInsensitive) == 0 ||
0278               (host->url().isEmpty() && host->ipAddress() == opt->ipAddress()))
0279           {
0280             options = opt;
0281             break;
0282           }
0283         }
0284       }
0285       else if (networkItem->type() == Share)
0286       {
0287         SharePtr share = networkItem.staticCast<Smb4KShare>();
0288         
0289         if (share)
0290         {
0291           if (opt->type() == Share &&
0292               QString::compare(share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash), 
0293                                opt->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash), Qt::CaseInsensitive) == 0)
0294           {
0295             // Since this is the exact match, break here
0296             options = opt;
0297             break;
0298           }
0299           else if (opt->type() == Host &&
0300                    QString::compare(share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::RemovePath|QUrl::StripTrailingSlash), 
0301                                     opt->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::RemovePath|QUrl::StripTrailingSlash), Qt::CaseInsensitive) == 0)
0302           {
0303             // These options belong to the host. Do not break here, 
0304             // because there might still be an exact match
0305             options = opt;
0306           }
0307         }
0308       }
0309     }
0310   }
0311   
0312   //
0313   // Return the options
0314   // 
0315   return options;
0316 }
0317 
0318 
0319 OptionsPtr Smb4KCustomOptionsManager::findOptions(const QUrl &url)
0320 {
0321   //
0322   // The options that are to be returned
0323   //
0324   OptionsPtr options;
0325   
0326   //
0327   // Search the options for the given URL
0328   //
0329   if (url.isValid() && url.scheme() == "smb")
0330   {
0331     //
0332     // Get the relevant options
0333     //
0334     QList<OptionsPtr> optionsList = customOptions(false);    
0335     
0336     //
0337     // Get the options
0338     //
0339     for (const OptionsPtr &o : optionsList)
0340     {
0341       if (o->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash) == 
0342           url.toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash))
0343       {
0344         options = o;
0345         break;
0346       }
0347     }
0348   }
0349   
0350   //
0351   // Return the options
0352   //
0353   return options;  
0354 }
0355 
0356 
0357 void Smb4KCustomOptionsManager::readCustomOptions()
0358 {
0359   //
0360   // Clear the list of options
0361   //
0362   while (!d->options.isEmpty())
0363   {
0364     d->options.takeFirst().clear();
0365   }
0366   
0367   //
0368   // Set the XML file
0369   //
0370   QFile xmlFile(dataLocation()+QDir::separator()+"custom_options.xml");
0371 
0372   if (xmlFile.open(QIODevice::ReadOnly | QIODevice::Text))
0373   {
0374     QXmlStreamReader xmlReader(&xmlFile);
0375 
0376     while (!xmlReader.atEnd())
0377     {
0378       xmlReader.readNext();
0379 
0380       if (xmlReader.isStartElement())
0381       {
0382         if (xmlReader.name() == "custom_options" && 
0383             (xmlReader.attributes().value("version") != "1.2" && xmlReader.attributes().value("version") != "2.0"))
0384         {
0385           xmlReader.raiseError(i18n("The format of %1 is not supported.", xmlFile.fileName()));
0386           break;
0387         }
0388         else
0389         {
0390           if (xmlReader.name() == "options")
0391           {
0392             OptionsPtr options = OptionsPtr(new Smb4KCustomOptions());
0393             options->setProfile(xmlReader.attributes().value("profile").toString());
0394             
0395             //
0396             // Initialize the options 
0397             // 
0398             if (QString::compare(xmlReader.attributes().value("type").toString(), "host", Qt::CaseInsensitive) == 0)
0399             {
0400               options->setHost(new Smb4KHost());
0401             }
0402             else
0403             {
0404               options->setShare(new Smb4KShare());
0405             }
0406 
0407             while (!(xmlReader.isEndElement() && xmlReader.name() == "options"))
0408             {
0409               xmlReader.readNext();
0410   
0411               if (xmlReader.isStartElement())
0412               {
0413                 if (xmlReader.name() == "workgroup")
0414                 {
0415                   options->setWorkgroupName(xmlReader.readElementText());
0416                 }
0417                 else if (xmlReader.name() == "url")
0418                 {
0419                   QUrl url(xmlReader.readElementText());
0420                   options->setUrl(url);
0421                 }
0422                 else if (xmlReader.name() == "unc")
0423                 {
0424                   QUrl url = QUrl::fromUserInput(xmlReader.readElementText());
0425                   url.setScheme("smb");
0426                   options->setUrl(url);
0427                 }
0428                 else if (xmlReader.name() == "ip")
0429                 {
0430                   options->setIpAddress(xmlReader.readElementText());
0431                 }
0432                 else if (xmlReader.name() == "custom")
0433                 {
0434                   while (!(xmlReader.isEndElement() && xmlReader.name() == "custom"))
0435                   {
0436                     xmlReader.readNext();
0437                     
0438                     if (xmlReader.isStartElement())
0439                     {
0440                       if (xmlReader.name() == "smb_port")
0441                       {
0442                         bool ok = false;
0443                         
0444                         int portNumber = xmlReader.readElementText().toInt(&ok);
0445                         
0446                         if (ok)
0447                         {
0448                           options->setSmbPort(portNumber);
0449                         }
0450                       }
0451                       else if (xmlReader.name() == "use_smb_port")
0452                       {
0453                         QString useSmbPort = xmlReader.readElementText();
0454                         
0455                         if (useSmbPort == "true")
0456                         {
0457                           options->setUseSmbPort(true);
0458                         }
0459                         else
0460                         {
0461                           options->setUseSmbPort(false);
0462                         }
0463                       }
0464                       else if (xmlReader.name() == "kerberos")
0465                       {
0466                         QString useKerberos = xmlReader.readElementText();
0467                         
0468                         if (useKerberos == "true")
0469                         {
0470                           options->setUseKerberos(true);
0471                         }
0472                         else
0473                         {
0474                           options->setUseKerberos(false);
0475                         }
0476                       }
0477                       else if (xmlReader.name() == "mac_address")
0478                       {
0479                         QString macAddress = xmlReader.readElementText();
0480                         
0481                         QRegExp exp("..\\:..\\:..\\:..\\:..\\:..");
0482   
0483                         if (exp.exactMatch(macAddress))
0484                         {
0485                           options->setMACAddress(macAddress);
0486                         }
0487                       }
0488                       else if (xmlReader.name() == "wol_send_before_first_scan")
0489                       {
0490                         QString send = xmlReader.readElementText();
0491                         
0492                         if (send == "true")
0493                         {
0494                           options->setWOLSendBeforeNetworkScan(true);
0495                         }
0496                         else
0497                         {
0498                           options->setWOLSendBeforeNetworkScan(false);
0499                         }
0500                       }
0501                       else if (xmlReader.name() == "wol_send_before_mount")
0502                       {
0503                         QString send = xmlReader.readElementText();
0504                         
0505                         if (send == "true")
0506                         {
0507                           options->setWOLSendBeforeMount(true);
0508                         }
0509                         else
0510                         {
0511                           options->setWOLSendBeforeMount(false);
0512                         }
0513                       }
0514                       else if (xmlReader.name() == "remount")
0515                       {
0516                         QString remount = xmlReader.readElementText();
0517                         
0518                         if (remount == "once")
0519                         {
0520                           options->setRemount(Smb4KCustomOptions::RemountOnce);
0521                         }
0522                         else if (remount == "always")
0523                         {
0524                           options->setRemount(Smb4KCustomOptions::RemountAlways);
0525                         }
0526                         else
0527                         {
0528                           options->setRemount(Smb4KCustomOptions::UndefinedRemount);
0529                         }
0530                       }
0531                       else if (xmlReader.name() == "use_user")
0532                       {
0533                         QString useUser = xmlReader.readElementText();
0534                         
0535                         if (useUser == "true")
0536                         {
0537                           options->setUseUser(true);
0538                         }
0539                         else
0540                         {
0541                           options->setUseUser(false);
0542                         }
0543                       }
0544                       else if (xmlReader.name() == "uid")
0545                       {
0546                         KUser user((K_UID)xmlReader.readElementText().toInt());
0547                         
0548                         if (user.isValid())
0549                         {
0550                           options->setUser(user);
0551                         }
0552                       }
0553                       else if (xmlReader.name() == "use_group")
0554                       {
0555                         QString useGroup = xmlReader.readElementText();
0556                         
0557                         if (useGroup == "true")
0558                         {
0559                           options->setUseGroup(true);
0560                         }
0561                         else
0562                         {
0563                           options->setUseGroup(false);
0564                         }
0565                       }
0566                       else if (xmlReader.name() == "gid")
0567                       {
0568                         KUserGroup group((K_GID)xmlReader.readElementText().toInt());
0569                         
0570                         if (group.isValid())
0571                         {
0572                           options->setGroup(group);
0573                         }
0574                       }
0575                       else if (xmlReader.name() == "use_file_mode")
0576                       {
0577                         QString useFileMode = xmlReader.readElementText();
0578                         
0579                         if (useFileMode == "true")
0580                         {
0581                           options->setUseFileMode(true);
0582                         }
0583                         else
0584                         {
0585                           options->setUseFileMode(false);
0586                         }
0587                       }
0588                       else if (xmlReader.name() == "file_mode")
0589                       {
0590                         options->setFileMode(xmlReader.readElementText());
0591                       }
0592                       else if (xmlReader.name() == "use_directory_mode")
0593                       {
0594                         QString useDirectoryMode = xmlReader.readElementText();
0595                         
0596                         if (useDirectoryMode == "true")
0597                         {
0598                           options->setUseDirectoryMode(true);
0599                         }
0600                         else
0601                         {
0602                           options->setUseDirectoryMode(false);
0603                         }
0604                       }
0605                       else if (xmlReader.name() == "directory_mode")
0606                       {
0607                         options->setDirectoryMode(xmlReader.readElementText());
0608                       }
0609 #if defined(Q_OS_LINUX)
0610                       else if (xmlReader.name() == "cifs_unix_extensions_support")
0611                       {
0612                         QString support = xmlReader.readElementText();
0613                         
0614                         if (support == "true")
0615                         {
0616                           options->setCifsUnixExtensionsSupport(true);
0617                         }
0618                         else
0619                         {
0620                           options->setCifsUnixExtensionsSupport(false);
0621                         }
0622                       }
0623                       else if (xmlReader.name() == "use_filesystem_port")
0624                       {
0625                         QString useFilesystemPort = xmlReader.readElementText();
0626                         
0627                         if (useFilesystemPort == "true")
0628                         {
0629                           options->setUseFileSystemPort(true);
0630                         }
0631                         else
0632                         {
0633                           options->setUseFileSystemPort(false);
0634                         }
0635                       }
0636                       else if (xmlReader.name() == "filesystem_port")
0637                       {
0638                         bool ok = false;
0639                         
0640                         int portNumber = xmlReader.readElementText().toInt(&ok);
0641                         
0642                         if (ok)
0643                         {
0644                           options->setFileSystemPort(portNumber);
0645                         }
0646                       }
0647                       else if (xmlReader.name() == "use_security_mode")
0648                       {
0649                         QString useSecurityMode = xmlReader.readElementText();
0650                         
0651                         if (useSecurityMode == "true")
0652                         {
0653                           options->setUseSecurityMode(true);
0654                         }
0655                         else
0656                         {
0657                           options->setUseSecurityMode(false);
0658                         }
0659                       }
0660                       else if (xmlReader.name() == "security_mode")
0661                       {
0662                         QString securityMode = xmlReader.readElementText();
0663                         
0664                         if (securityMode == "none")
0665                         {
0666                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::None);
0667                         }
0668                         else if (securityMode == "krb5")
0669                         {
0670                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Krb5);
0671                         }
0672                         else if (securityMode == "krb5i")
0673                         {
0674                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Krb5i);
0675                         }
0676                         else if (securityMode == "ntlm")
0677                         {
0678                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Ntlm);
0679                         }
0680                         else if (securityMode == "ntlmi")
0681                         {
0682                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Ntlmi);
0683                         }
0684                         else if (securityMode == "ntlmv2")
0685                         {
0686                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Ntlmv2);
0687                         }
0688                         else if (securityMode == "ntlmv2i")
0689                         {
0690                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Ntlmv2i);
0691                         }
0692                         else if (securityMode == "ntlmssp")
0693                         {
0694                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Ntlmssp);
0695                         }
0696                         else if (securityMode == "ntlmsspi")
0697                         {
0698                           options->setSecurityMode(Smb4KMountSettings::EnumSecurityMode::Ntlmsspi);
0699                         }
0700                       }
0701                       else if (xmlReader.name() == "use_write_access")
0702                       {
0703                         QString useWriteAccess = xmlReader.readElementText();
0704                         
0705                         if (useWriteAccess == "true")
0706                         {
0707                           options->setUseWriteAccess(true);
0708                         }
0709                         else
0710                         {
0711                           options->setUseWriteAccess(false);
0712                         }
0713                       }
0714                       else if (xmlReader.name() == "write_access")
0715                       {
0716                         QString writeAccess = xmlReader.readElementText();
0717                         
0718                         if (writeAccess == "true")
0719                         {
0720                           options->setWriteAccess(Smb4KMountSettings::EnumWriteAccess::ReadWrite);
0721                         }
0722                         else if (writeAccess == "false")
0723                         {
0724                           options->setWriteAccess(Smb4KMountSettings::EnumWriteAccess::ReadWrite);
0725                         }
0726                       }
0727 #endif
0728                     }
0729                   }
0730                 }
0731   
0732                 continue;
0733               }
0734               else
0735               {
0736                 continue;
0737               }
0738             }            
0739               
0740             d->options << options;  
0741           }
0742         }
0743       }
0744     }
0745 
0746     xmlFile.close();
0747 
0748     if (xmlReader.hasError())
0749     {
0750       Smb4KNotification::readingFileFailed(xmlFile, xmlReader.errorString());
0751     }
0752   }
0753   else
0754   {
0755     if (xmlFile.exists())
0756     {
0757       Smb4KNotification::openingFileFailed(xmlFile);
0758     }
0759   }
0760 }
0761 
0762 
0763 void Smb4KCustomOptionsManager::writeCustomOptions()
0764 {
0765   //
0766   // Set the XML file
0767   //
0768   QFile xmlFile(dataLocation()+QDir::separator()+"custom_options.xml");
0769   
0770   //
0771   // Write the options to the file
0772   //
0773   if (!d->options.isEmpty())
0774   {
0775     if (xmlFile.open(QIODevice::WriteOnly|QIODevice::Text))
0776     {
0777       QXmlStreamWriter xmlWriter(&xmlFile);
0778       xmlWriter.setAutoFormatting(true);
0779       xmlWriter.writeStartDocument();
0780       xmlWriter.writeStartElement("custom_options");
0781       xmlWriter.writeAttribute("version", "2.0");
0782       
0783       for (const OptionsPtr &options : d->options)
0784       {
0785         if (options->hasOptions() || options->remount() == Smb4KCustomOptions::RemountOnce)
0786         {
0787           xmlWriter.writeStartElement("options");
0788           xmlWriter.writeAttribute("type", options->type() == Host ? "host" : "share");
0789           xmlWriter.writeAttribute("profile", options->profile());
0790 
0791           xmlWriter.writeTextElement("workgroup", options->workgroupName());
0792           xmlWriter.writeTextElement("url", options->url().toDisplayString());
0793           xmlWriter.writeTextElement("ip", options->ipAddress());
0794           
0795           xmlWriter.writeStartElement("custom");
0796 
0797           QMap<QString,QString> map = options->customOptions();
0798           QMapIterator<QString,QString> it(map);
0799 
0800           while (it.hasNext())
0801           {
0802             it.next();
0803 
0804             if (!it.value().isEmpty())
0805             {
0806               xmlWriter.writeTextElement(it.key(), it.value());
0807             }
0808           }
0809 
0810           xmlWriter.writeEndElement();
0811           xmlWriter.writeEndElement();
0812         }
0813       }
0814       
0815       xmlWriter.writeEndDocument();
0816       xmlFile.close();
0817     }
0818     else
0819     {
0820       Smb4KNotification::openingFileFailed(xmlFile);
0821     }      
0822   }
0823   else
0824   {
0825     xmlFile.remove();
0826   }
0827 }
0828 
0829 
0830 QList<OptionsPtr> Smb4KCustomOptionsManager::customOptions(bool optionsOnly)
0831 {
0832   //
0833   // Options list
0834   //
0835   QList<OptionsPtr> options;
0836 
0837   //
0838   // Get this list of options
0839   //
0840   for (const OptionsPtr &o : d->options)
0841   {
0842     if (Smb4KSettings::useProfiles() && o->profile() != Smb4KProfileManager::self()->activeProfile())
0843     {
0844       continue;
0845     }
0846 
0847     if (o->hasOptions() || (!optionsOnly && o->remount() == Smb4KCustomOptions::RemountOnce))
0848     {
0849       options << o;
0850     }
0851   }
0852   
0853   //
0854   // Return the list of relevant options
0855   //
0856   return options;
0857 }
0858 
0859 
0860 void Smb4KCustomOptionsManager::replaceCustomOptions(const QList<OptionsPtr> &optionsList)
0861 {
0862   //
0863   // Clear the list of options. Honor profiles.
0864   //
0865   QMutableListIterator<OptionsPtr> it(d->options);
0866   
0867   while (it.hasNext())
0868   {
0869     OptionsPtr options = it.next();
0870     
0871     if (Smb4KSettings::useProfiles() && options->profile() != Smb4KProfileManager::self()->activeProfile())
0872     {
0873       continue;
0874     }
0875     
0876     it.remove();
0877   }
0878   
0879   //
0880   // Append the new list
0881   //
0882   if (!optionsList.isEmpty())
0883   {
0884     for (const OptionsPtr &options : optionsList)
0885     {
0886       if (Smb4KSettings::useProfiles())
0887       {
0888         options->setProfile(Smb4KProfileManager::self()->activeProfile());
0889       }
0890       
0891       if (options->hasOptions() || options->remount() == Smb4KCustomOptions::RemountOnce)
0892       {
0893         d->options << options;
0894       }
0895     }
0896   }
0897   
0898   writeCustomOptions();
0899 }
0900 
0901 
0902 void Smb4KCustomOptionsManager::openCustomOptionsDialog(const NetworkItemPtr &item)
0903 {
0904   if (item)
0905   {
0906     OptionsPtr options;
0907     
0908     switch (item->type())
0909     {
0910       case Host:
0911       {
0912         HostPtr host = item.staticCast<Smb4KHost>();
0913         
0914         if (host)
0915         {
0916           options = findOptions(host);
0917           
0918           if (!options)
0919           {
0920             options = OptionsPtr(new Smb4KCustomOptions(host.data()));
0921             options->setProfile(Smb4KProfileManager::self()->activeProfile());
0922           }
0923         }
0924         
0925         break;
0926       }
0927       case Share:
0928       {
0929         SharePtr share = item.staticCast<Smb4KShare>();
0930         
0931         if (share && !share->isPrinter())
0932         {
0933           if (share->isHomesShare())
0934           {
0935             if (!Smb4KHomesSharesHandler::self()->specifyUser(share, true))
0936             {
0937               return;
0938             }
0939           }
0940           
0941           options = findOptions(share);
0942           
0943           if (!options)
0944           {
0945             options = OptionsPtr(new Smb4KCustomOptions(share.data()));
0946             options->setProfile(Smb4KProfileManager::self()->activeProfile());
0947             
0948             // Get rid of the 'homes' share
0949             if (share->isHomesShare())
0950             {
0951               options->setUrl(share->homeUrl());
0952             }
0953           }
0954           else
0955           {
0956             // In case the custom options object for the host has been 
0957             // returned, change its internal network item, otherwise we
0958             // will change the host's custom options...
0959             options->setShare(share.data());
0960           }
0961         }
0962         
0963         break;
0964       }
0965       default:
0966       {
0967         break;
0968       }
0969     }
0970     
0971     if (options)
0972     {
0973       QPointer<Smb4KCustomOptionsDialog> dlg = new Smb4KCustomOptionsDialog(options, QApplication::activeWindow());
0974         
0975       if (dlg->exec() == QDialog::Accepted)
0976       {
0977         if (options->hasOptions())
0978         {
0979           addCustomOptions(options, true);
0980         }
0981         else
0982         {
0983           removeCustomOptions(options, true);
0984         }
0985       }
0986       else
0987       {
0988         resetCustomOptions();
0989       }
0990       
0991       delete dlg;
0992     }
0993   }
0994 }
0995 
0996 
0997 void Smb4KCustomOptionsManager::addCustomOptions(const OptionsPtr &options, bool write)
0998 {
0999   if (options)
1000   {
1001     //
1002     // Check if options for the URL already exist
1003     // 
1004     OptionsPtr knownOptions = findOptions(options->url());
1005     
1006     if (knownOptions)
1007     {
1008       //
1009       // Update the options
1010       // 
1011       knownOptions->update(options.data());
1012     }
1013     else
1014     {
1015       // 
1016       // Add the options
1017       //
1018       if (options->profile().isEmpty())
1019       {
1020         options->setProfile(Smb4KProfileManager::self()->activeProfile());
1021       }
1022         
1023       d->options << options;
1024     }
1025     
1026     //
1027     // In case the options are defined for a host, propagate them 
1028     // to the options of shares belonging to that host. Overwrite 
1029     // the settings
1030     // 
1031     if (options->type() == Host)
1032     {
1033       for (const OptionsPtr &o : d->options)
1034       {
1035         if (o->type() == Share && o->hostName() == options->hostName() && o->workgroupName() == options->workgroupName())
1036         {
1037           o->setIpAddress(options->ipAddress());
1038           o->setUseUser(options->useUser());
1039           o->setUser(options->user());
1040           o->setUseGroup(options->useGroup());
1041           o->setGroup(options->group());
1042           o->setUseFileMode(options->useFileMode());
1043           o->setFileMode(options->fileMode());
1044           o->setUseDirectoryMode(options->useDirectoryMode());
1045           o->setDirectoryMode(options->directoryMode());
1046 #if defined(Q_OS_LINUX)
1047           o->setCifsUnixExtensionsSupport(options->cifsUnixExtensionsSupport());
1048           o->setUseFileSystemPort(options->useFileSystemPort());
1049           o->setFileSystemPort(options->fileSystemPort());
1050           o->setUseSecurityMode(options->useSecurityMode());
1051           o->setSecurityMode(options->securityMode());
1052           o->setUseWriteAccess(options->useWriteAccess());
1053           o->setWriteAccess(options->writeAccess());
1054 #endif
1055           o->setUseSmbPort(options->useSmbPort());
1056           o->setSmbPort(options->smbPort());
1057           o->setUseKerberos(options->useKerberos());
1058           o->setMACAddress(options->macAddress());
1059           o->setWOLSendBeforeNetworkScan(options->wolSendBeforeNetworkScan());
1060           o->setWOLSendBeforeMount(options->wolSendBeforeMount());
1061         }
1062       }
1063     }
1064     
1065     //
1066     // Write the custom options to the file, if desired
1067     //
1068     if (write)
1069     {
1070       writeCustomOptions();
1071     }
1072   }
1073 }
1074 
1075 
1076 void Smb4KCustomOptionsManager::removeCustomOptions(const OptionsPtr &options, bool write)
1077 {
1078   if (options)
1079   {
1080     // 
1081     // Find the custom options and remove them
1082     //
1083     for (int i = 0; i < d->options.size(); ++i)
1084     {
1085       if ((!Smb4KSettings::useProfiles() || Smb4KProfileManager::self()->activeProfile() == d->options.at(i)->profile()) &&
1086           d->options.at(i)->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash) == 
1087           options->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::StripTrailingSlash))
1088       {
1089         d->options.takeAt(i).clear();
1090         break;
1091       }
1092     }
1093     
1094     //
1095     // Write the custom options to the file, if desired
1096     //
1097     if (write)
1098     {
1099       writeCustomOptions();
1100     }
1101   }
1102 }
1103 
1104 
1105 QList<OptionsPtr> Smb4KCustomOptionsManager::wakeOnLanEntries() const
1106 {
1107   QList<OptionsPtr> list;
1108   
1109   //
1110   // Get the Wake-On-LAN entries
1111   //
1112   for (const OptionsPtr &options : d->options)
1113   {
1114     if (!options->macAddress().isEmpty() && (options->wolSendBeforeNetworkScan() || options->wolSendBeforeMount()))
1115     {
1116       list << options;
1117     }
1118   }
1119   
1120   // 
1121   // Return them
1122   //
1123   return list;
1124 }
1125 
1126 
1127 void Smb4KCustomOptionsManager::resetCustomOptions()
1128 {
1129   readCustomOptions();
1130 }
1131 
1132 
1133 void Smb4KCustomOptionsManager::migrateProfile(const QString& from, const QString& to)
1134 {
1135   //
1136   // Replace the old with the new profile
1137   //
1138   for (const OptionsPtr &options : d->options)
1139   {
1140     if (options->profile() == from)
1141     {
1142       options->setProfile(to);
1143     }
1144   }
1145   
1146   //
1147   // Write all custom options to the file.
1148   //
1149   writeCustomOptions();
1150 }
1151 
1152 
1153 void Smb4KCustomOptionsManager::removeProfile(const QString& name)
1154 {
1155   //
1156   // Remove all entries belonging to the profile
1157   // 
1158   QMutableListIterator<OptionsPtr> it(d->options);
1159   
1160   while (it.hasNext())
1161   {
1162     OptionsPtr options = it.next();
1163     
1164     if (QString::compare(options->profile(), name, Qt::CaseSensitive) == 0)
1165     {
1166       it.remove();
1167     }
1168   }
1169   
1170   // 
1171   // Write all custom options to the file.
1172   // 
1173   writeCustomOptions();
1174 }
1175 
1176 
1177 /////////////////////////////////////////////////////////////////////////////
1178 // SLOT IMPLEMENTATIONS
1179 /////////////////////////////////////////////////////////////////////////////
1180 
1181 void Smb4KCustomOptionsManager::slotAboutToQuit()
1182 {
1183   writeCustomOptions();
1184 }
1185 
1186