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

0001 /***************************************************************************
0002     Private classes for the SMB client
0003                              -------------------
0004     begin                : So Oct 21 2018
0005     copyright            : (C) 2018-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 "smb4kclient_p.h"
0032 #include "smb4ksettings.h"
0033 #include "smb4kwalletmanager.h"
0034 #include "smb4kcustomoptions.h"
0035 #include "smb4kcustomoptionsmanager.h"
0036 #include "smb4knotification.h"
0037 
0038 // System includes
0039 #include <errno.h>
0040 // #include <sys/types.h>
0041 #include <sys/stat.h>
0042 // #include <unistd.h>
0043 
0044 // Qt includes
0045 #include <QTimer>
0046 #include <QDebug>
0047 #include <QHostInfo>
0048 #include <QNetworkInterface>
0049 #include <QAbstractSocket>
0050 #include <QVBoxLayout>
0051 #include <QDialogButtonBox>
0052 #include <QListWidget>
0053 #include <QWindow>
0054 #include <QPushButton>
0055 #include <QLabel>
0056 #include <QToolBar>
0057 #include <QGroupBox>
0058 #include <QDir>
0059 #include <QSpinBox>
0060 #include <QPrinter>
0061 #include <QTemporaryDir>
0062 #include <QTextDocument>
0063 
0064 // KDE includes
0065 #include <KI18n/KLocalizedString>
0066 #include <KConfigGui/KWindowConfig>
0067 #include <KIconThemes/KIconLoader>
0068 #include <KIOWidgets/KUrlComboBox>
0069 #include <KIO/Global>
0070 #include <KWidgetsAddons/KDualAction>
0071 #include <KIOWidgets/KUrlRequester>
0072 #include <KIOCore/KFileItem>
0073 
0074 #define SMBC_DEBUG 0
0075 
0076 using namespace Smb4KGlobal;
0077 
0078 
0079 //
0080 // Authentication function for libsmbclient
0081 // 
0082 static void get_auth_data_with_context_fn(SMBCCTX *context,
0083                                           const char *server, 
0084                                           const char *share,
0085                                           char *workgroup,
0086                                           int maxLenWorkgroup,
0087                                           char *username,
0088                                           int maxLenUsername,
0089                                           char *password,
0090                                           int maxLenPassword)
0091 {
0092   if (context != nullptr)
0093   {
0094     Smb4KClientJob *job = static_cast<Smb4KClientJob *>(smbc_getOptionUserData(context));
0095     
0096     if (job)
0097     {
0098       job->get_auth_data_fn(server, share, workgroup, maxLenWorkgroup, username, maxLenUsername, password, maxLenPassword);
0099     }
0100   }
0101 }
0102 
0103 
0104 //
0105 // Client job
0106 // 
0107 Smb4KClientJob::Smb4KClientJob(QObject* parent) 
0108 : KJob(parent), m_process(Smb4KGlobal::NoProcess)
0109 {
0110 }
0111 
0112 
0113 Smb4KClientJob::~Smb4KClientJob()
0114 {
0115   //
0116   // Clear the list of workgroups
0117   //
0118   while (!m_workgroups.isEmpty())
0119   {
0120     m_workgroups.takeFirst().clear();
0121   }
0122   
0123   //
0124   // Clear the list of hosts
0125   // 
0126   while (!m_hosts.isEmpty())
0127   {
0128     m_hosts.takeFirst().clear();
0129   }
0130   
0131   //
0132   // Clear the list of shares
0133   //
0134   while (!m_shares.isEmpty())
0135   {
0136     m_shares.takeFirst().clear();
0137   }
0138   
0139   //
0140   // Clear the list of files and directories
0141   //
0142   while (!m_files.isEmpty())
0143   {
0144     m_files.takeFirst().clear();
0145   }
0146 }
0147 
0148 
0149 void Smb4KClientJob::start()
0150 {
0151   QTimer::singleShot(50, this, SLOT(slotStartJob()));
0152 }
0153 
0154 
0155 void Smb4KClientJob::setNetworkItem(NetworkItemPtr item)
0156 {
0157   m_item = item;
0158 }
0159 
0160 
0161 NetworkItemPtr Smb4KClientJob::networkItem() const
0162 {
0163   return m_item;
0164 }
0165 
0166 
0167 void Smb4KClientJob::setProcess(Smb4KGlobal::Process process)
0168 {
0169   m_process = process;
0170 }
0171 
0172 
0173 Smb4KGlobal::Process Smb4KClientJob::process() const
0174 {
0175   return m_process;
0176 }
0177 
0178 
0179 void Smb4KClientJob::setPrintFileItem(const KFileItem& item)
0180 {
0181   m_fileItem = item;
0182 }
0183 
0184 
0185 KFileItem Smb4KClientJob::printFileItem() const
0186 {
0187   return m_fileItem;
0188 }
0189 
0190 
0191 void Smb4KClientJob::setPrintCopies(int copies)
0192 {
0193   m_copies = copies;
0194 }
0195 
0196 
0197 int Smb4KClientJob::printCopies() const
0198 {
0199   return m_copies;
0200 }
0201 
0202 
0203 void Smb4KClientJob::get_auth_data_fn(const char* server, const char* /*share*/, char* workgroup, int /*maxLenWorkgroup*/, char* username, int maxLenUsername, char* password, int maxLenPassword)
0204 {
0205   //
0206   // Authentication
0207   // 
0208   switch (m_item->type())
0209   {
0210     case Network:
0211     {
0212       //
0213       // No authentication needed
0214       // 
0215       break;
0216     }
0217     case Workgroup:
0218     {
0219       //
0220       // Only request authentication data, if the master browsers require 
0221       // authentication data.
0222       // 
0223       if (Smb4KSettings::masterBrowsersRequireAuth())
0224       {
0225         if (QString::fromUtf8(server).toUpper() != QString::fromUtf8(workgroup).toUpper())
0226         {
0227           // 
0228           // This is the master browser. Create a host object for it.
0229           // 
0230           HostPtr h = HostPtr(new Smb4KHost());
0231           h->setWorkgroupName(QString::fromUtf8(workgroup));
0232           h->setHostName(QString::fromUtf8(server));
0233           
0234           // 
0235           // Get the authentication data
0236           // 
0237           Smb4KWalletManager::self()->readAuthInfo(h);
0238           
0239           // 
0240           // Copy the authentication data
0241           // 
0242           qstrncpy(username, h->login().toUtf8().data(), maxLenUsername);
0243           qstrncpy(password, h->password().toUtf8().data(), maxLenPassword);
0244         }
0245       }
0246       
0247       break;
0248     }
0249     case Host:
0250     {
0251       //
0252       // The host object
0253       // 
0254       HostPtr h = m_item.staticCast<Smb4KHost>();
0255       
0256       //
0257       // Get the authentication data
0258       //
0259       Smb4KWalletManager::self()->readAuthInfo(h);
0260         
0261       // 
0262       // Copy the authentication data
0263       // 
0264       qstrncpy(username, h->login().toUtf8().data(), maxLenUsername);
0265       qstrncpy(password, h->password().toUtf8().data(), maxLenPassword);
0266       
0267       break;
0268     }
0269     case Share:
0270     {
0271       //
0272       // The share object
0273       // 
0274       SharePtr s = m_item.staticCast<Smb4KShare>();
0275       
0276       //
0277       // Get the authentication data
0278       //
0279       Smb4KWalletManager::self()->readAuthInfo(s);
0280         
0281       // 
0282       // Copy the authentication data
0283       // 
0284       qstrncpy(username, s->login().toUtf8().data(), maxLenUsername);
0285       qstrncpy(password, s->password().toUtf8().data(), maxLenPassword);
0286       
0287       break;
0288     }
0289     case Directory:
0290     {
0291       //
0292       // The file object
0293       // 
0294       FilePtr f = m_item.staticCast<Smb4KFile>();
0295       
0296       //
0297       // Create a share object
0298       // 
0299       SharePtr s = SharePtr(new Smb4KShare());
0300       s->setWorkgroupName(f->workgroupName());
0301       s->setHostName(f->hostName());
0302       s->setShareName(f->shareName());
0303       s->setLogin(f->login());
0304       s->setPassword(f->password());
0305           
0306       //
0307       // Get the authentication data
0308       //
0309       Smb4KWalletManager::self()->readAuthInfo(s);
0310         
0311       // 
0312       // Copy the authentication data
0313       // 
0314       qstrncpy(username, s->login().toUtf8().data(), maxLenUsername);
0315       qstrncpy(password, s->password().toUtf8().data(), maxLenPassword);
0316       
0317       break;
0318     }
0319     default:
0320     {
0321       break;
0322     }
0323   }
0324 }
0325 
0326 
0327 QList<WorkgroupPtr> Smb4KClientJob::workgroups()
0328 {
0329   return m_workgroups;
0330 }
0331 
0332 
0333 QList<HostPtr> Smb4KClientJob::hosts()
0334 {
0335   return m_hosts;
0336 }
0337 
0338 
0339 QList<SharePtr> Smb4KClientJob::shares()
0340 {
0341   return m_shares;
0342 }
0343 
0344 
0345 QList<FilePtr> Smb4KClientJob::files()
0346 {
0347   return m_files;
0348 }
0349 
0350 
0351 QString Smb4KClientJob::workgroup()
0352 {
0353   QString workgroup;
0354   
0355   switch (m_item->type())
0356   {
0357     case Network:
0358     {
0359       break;
0360     }
0361     case Workgroup:
0362     {
0363       workgroup = m_item->url().host().toUpper();
0364       break;
0365     }
0366     case Host:
0367     {
0368       workgroup = m_item.staticCast<Smb4KHost>()->workgroupName();
0369       break;
0370     }
0371     case Share:
0372     {
0373       workgroup = m_item.staticCast<Smb4KShare>()->workgroupName();
0374       break;
0375     }
0376     case Directory:
0377     case File:
0378     {
0379       workgroup = m_item.staticCast<Smb4KFile>()->workgroupName();
0380       break;
0381     }
0382     default:
0383     {
0384       break;
0385     }
0386   }
0387   
0388   return workgroup;
0389 }
0390 
0391 
0392 void Smb4KClientJob::doLookups()
0393 {
0394   // 
0395   // Read the given URL
0396   // 
0397   int dirfd;
0398   struct smbc_dirent *dirp = nullptr;
0399   
0400   dirfd = smbc_opendir(m_item->url().toString().toUtf8().data());
0401   
0402   if (dirfd < 0)
0403   {
0404     int errorCode = errno;
0405     
0406     switch (errorCode)
0407     {
0408       case ENOMEM:
0409       {
0410         setError(OutOfMemoryError);
0411         setErrorText(i18n("Out of memory"));
0412         break;
0413       }
0414       case EACCES:
0415       {
0416         setError(AccessDeniedError);
0417         setErrorText(i18n("Permission denied"));
0418         break;
0419       }
0420       case EINVAL:
0421       {
0422         setError(InvalidUrlError);
0423         setErrorText(i18n("An invalid URL was passed"));
0424         break;
0425       }
0426       case ENOENT:
0427       {
0428         if (!m_item->type() != Network)
0429         {
0430           setError(NonExistentUrlError);
0431           setErrorText(i18n("The URL does not exist"));
0432         }
0433         break;
0434       }
0435       case ENOTDIR:
0436       {
0437         setError(NoDirectoryError);
0438         setErrorText(i18n("Name is not a directory"));
0439         break;
0440       }
0441       case EPERM:
0442       {
0443         setError(NotPermittedError);
0444         // Is the error message correct? 
0445         setErrorText(i18n("Operation not permitted"));
0446         break;
0447       }
0448       case ENODEV:
0449       {
0450         setError(NotFoundError);
0451         setErrorText(i18n("The workgroup or server could not be found"));
0452         break;
0453       }
0454       default:
0455       {
0456         setError(UnknownError);
0457         setErrorText(i18n("Unknown error"));
0458       }
0459     }
0460 
0461     emitResult();
0462     return;
0463   }
0464   else
0465   {
0466     //
0467     // Get the entries of the "directory"
0468     // 
0469     while ((dirp = smbc_readdir(dirfd)) != nullptr)
0470     {
0471       switch (dirp->smbc_type)
0472       {
0473         case SMBC_WORKGROUP:
0474         {
0475           // 
0476           // Create a workgroup pointer
0477           // 
0478           WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup());
0479           
0480           // 
0481           // Set the workgroup name
0482           // 
0483           QString workgroupName = QString::fromUtf8(dirp->name);
0484           workgroup->setWorkgroupName(workgroupName);
0485           
0486           // 
0487           // Set the master browser
0488           // 
0489           QString masterBrowserName = QString::fromUtf8(dirp->comment);
0490           workgroup->setMasterBrowserName(masterBrowserName);
0491           
0492           // 
0493           // Lookup IP address
0494           // 
0495           QHostAddress address = lookupIpAddress(masterBrowserName);
0496           
0497           // 
0498           // Process the IP address. 
0499           // If the address is null, the server most likely went offline. So, skip the
0500           // workgroup and delete the pointer.
0501           // 
0502           if (!address.isNull())
0503           {
0504             workgroup->setMasterBrowserIpAddress(address);
0505             m_workgroups << workgroup;
0506           }
0507           else
0508           {
0509             workgroup.clear();
0510           }
0511           
0512           break;
0513         }
0514         case SMBC_SERVER:
0515         {
0516           // 
0517           // Create a host pointer
0518           // 
0519           HostPtr host = HostPtr(new Smb4KHost());
0520           
0521           // 
0522           // Set the workgroup name
0523           // 
0524           host->setWorkgroupName(m_item->url().host());
0525           
0526           // 
0527           // Set the host name
0528           // 
0529           QString hostName = QString::fromUtf8(dirp->name);
0530           host->setHostName(hostName);
0531           
0532           // 
0533           // Set the comment
0534           // 
0535           QString comment = QString::fromUtf8(dirp->comment);
0536           host->setComment(comment);
0537           
0538           // 
0539           // Lookup IP address
0540           // 
0541           QHostAddress address = lookupIpAddress(hostName);
0542           
0543           // 
0544           // Process the IP address. 
0545           // If the address is null, the server most likely went offline. So, skip it
0546           // and delete the pointer.
0547           // 
0548           if (!address.isNull())
0549           {
0550             host->setIpAddress(address);
0551             m_hosts << host;
0552           }
0553           else
0554           {
0555             host.clear();
0556           } 
0557           
0558           break;
0559         }
0560         case SMBC_FILE_SHARE:
0561         {
0562           //
0563           // Create a share pointer
0564           // 
0565           SharePtr share = SharePtr(new Smb4KShare());
0566           
0567           //
0568           // Set the workgroup name
0569           // 
0570           share->setWorkgroupName(m_item.staticCast<Smb4KHost>()->workgroupName());
0571           
0572           //
0573           // Set the host name
0574           // 
0575           share->setHostName(m_item->url().host());
0576           
0577           //
0578           // Set the share name
0579           // 
0580           share->setShareName(QString::fromUtf8(dirp->name));
0581           
0582           // 
0583           // Set the comment
0584           // 
0585           share->setComment(QString::fromUtf8(dirp->comment));
0586           
0587           //
0588           // Set share type
0589           // 
0590           share->setShareType(FileShare);
0591           
0592           //
0593           // Set the authentication data
0594           // 
0595           share->setLogin(m_item->url().userName());
0596           share->setPassword(m_item->url().password());
0597           
0598           // 
0599           // Lookup IP address
0600           // 
0601           QHostAddress address = lookupIpAddress(m_item->url().host());
0602           
0603           // 
0604           // Process the IP address. 
0605           // If the address is null, the server most likely went offline. So, skip it
0606           // and delete the pointer.
0607           // 
0608           if (!address.isNull())
0609           {
0610             share->setHostIpAddress(address);
0611             m_shares << share;
0612           }
0613           else
0614           {
0615             share.clear();
0616           } 
0617           
0618           break;
0619         }
0620         case SMBC_PRINTER_SHARE:
0621         {
0622           //
0623           // Create a share pointer
0624           // 
0625           SharePtr share = SharePtr(new Smb4KShare());
0626           
0627           //
0628           // Set the workgroup name
0629           // 
0630           share->setWorkgroupName(m_item.staticCast<Smb4KHost>()->workgroupName());
0631           
0632           //
0633           // Set the host name
0634           // 
0635           share->setHostName(m_item->url().host());
0636           
0637           //
0638           // Set the share name
0639           // 
0640           share->setShareName(QString::fromUtf8(dirp->name));
0641           
0642           // 
0643           // Set the comment
0644           // 
0645           share->setComment(QString::fromUtf8(dirp->comment));
0646           
0647           //
0648           // Set share type
0649           // 
0650           share->setShareType(PrinterShare);
0651           
0652           //
0653           // Set the authentication data
0654           // 
0655           share->setLogin(m_item->url().userName());
0656           share->setPassword(m_item->url().password());
0657           
0658           // 
0659           // Lookup IP address
0660           // 
0661           QHostAddress address = lookupIpAddress(m_item->url().host());
0662           
0663           // 
0664           // Process the IP address. 
0665           // If the address is null, the server most likely went offline. So, skip it
0666           // and delete the pointer.
0667           // 
0668           if (!address.isNull())
0669           {
0670             share->setHostIpAddress(address);
0671             m_shares << share;
0672           }
0673           else
0674           {
0675             share.clear();
0676           } 
0677           
0678           break;
0679         }
0680         case SMBC_IPC_SHARE:
0681         {
0682           //
0683           // Create a share pointer
0684           // 
0685           SharePtr share = SharePtr(new Smb4KShare());
0686           
0687           //
0688           // Set the workgroup name
0689           // 
0690           share->setWorkgroupName(m_item.staticCast<Smb4KHost>()->workgroupName());
0691           
0692           //
0693           // Set the host name
0694           // 
0695           share->setHostName(m_item->url().host());
0696           
0697           //
0698           // Set the share name
0699           // 
0700           share->setShareName(QString::fromUtf8(dirp->name));
0701           
0702           // 
0703           // Set the comment
0704           // 
0705           share->setComment(QString::fromUtf8(dirp->comment));
0706           
0707           //
0708           // Set share type
0709           // 
0710           share->setShareType(IpcShare);
0711           
0712           //
0713           // Set the authentication data
0714           // 
0715           share->setLogin(m_item->url().userName());
0716           share->setPassword(m_item->url().password());
0717           
0718           // 
0719           // Lookup IP address
0720           // 
0721           QHostAddress address = lookupIpAddress(m_item->url().host());
0722           
0723           // 
0724           // Process the IP address. 
0725           // If the address is null, the server most likely went offline. So, skip it
0726           // and delete the pointer.
0727           // 
0728           if (!address.isNull())
0729           {
0730             share->setHostIpAddress(address);
0731             m_shares << share;
0732           }
0733           else
0734           {
0735             share.clear();
0736           } 
0737           
0738           break;
0739         }
0740         case SMBC_DIR:
0741         {
0742           //
0743           // Do not process '.' and '..' directories
0744           // 
0745           QString name = QString::fromUtf8(dirp->name);
0746           
0747           if (name != "." && name != "..")
0748           {
0749             //
0750             // Create the URL for the discovered item
0751             // 
0752             QUrl u = m_item->url();
0753             u.setPath(m_item->url().path()+QDir::separator()+QString::fromUtf8(dirp->name));
0754             
0755             //
0756             // We do not stat directories. Directly create the directory object
0757             // 
0758             FilePtr dir = FilePtr(new Smb4KFile(u, Directory));
0759             
0760             //
0761             // Set the workgroup name
0762             //
0763             dir->setWorkgroupName(m_item.staticCast<Smb4KShare>()->workgroupName());
0764             
0765             //
0766             // Set the authentication data
0767             // 
0768             dir->setLogin(m_item->url().userName());
0769             dir->setPassword(m_item->url().password());
0770             
0771             // 
0772             // Lookup IP address
0773             // 
0774             QHostAddress address = lookupIpAddress(m_item->url().host());
0775             
0776             // 
0777             // Process the IP address. 
0778             // If the address is null, the server most likely went offline. So, skip it
0779             // and delete the pointer.
0780             // 
0781             if (!address.isNull())
0782             {
0783               dir->setHostIpAddress(address);
0784               m_files << dir;
0785             }
0786             else
0787             {
0788               dir.clear();
0789             } 
0790           }
0791           
0792           break;
0793         }
0794         case SMBC_FILE:
0795         {
0796           //
0797           // Create the URL for the discovered item
0798           // 
0799           QUrl u = m_item->url();
0800           u.setPath(m_item->url().path()+QDir::separator()+QString::fromUtf8(dirp->name));
0801             
0802           //
0803           // Create the directory object
0804           // 
0805           FilePtr dir = FilePtr(new Smb4KFile(u, File));
0806             
0807           //
0808           // Set the workgroup name
0809           //
0810           dir->setWorkgroupName(m_item.staticCast<Smb4KShare>()->workgroupName());
0811           
0812           //
0813           // Stat the file
0814           //
0815           // FIXME
0816             
0817           //
0818           // Set the authentication data
0819           // 
0820           dir->setLogin(m_item->url().userName());
0821           dir->setPassword(m_item->url().password());
0822             
0823           // 
0824           // Lookup IP address
0825           // 
0826           QHostAddress address = lookupIpAddress(m_item->url().host());
0827             
0828           // 
0829           // Process the IP address. 
0830           // If the address is null, the server most likely went offline. So, skip it
0831           // and delete the pointer.
0832           // 
0833           if (!address.isNull())
0834           {
0835             dir->setHostIpAddress(address);
0836             m_files << dir;
0837           }
0838           else
0839           {
0840             dir.clear();
0841           } 
0842             
0843           break;
0844         }
0845         case SMBC_LINK:
0846         {
0847           qDebug() << "Processing links is not implemented.";
0848           qDebug() << dirp->name;
0849           qDebug() << dirp->comment;
0850           break;
0851         }
0852         default:
0853         {
0854           qDebug() << "Need to process network item " << dirp->name;
0855           break;
0856         }
0857       }
0858     }
0859     
0860     smbc_closedir(dirfd);
0861   }
0862 }
0863 
0864 
0865 void Smb4KClientJob::doPrinting()
0866 {
0867   //
0868   // The URL that is to be printed
0869   // 
0870   QUrl fileUrl;
0871   
0872   //
0873   // Set the temporary directory
0874   //
0875   QTemporaryDir tempDir;
0876   
0877   //
0878   // Check if we can directly print the file
0879   // 
0880   if (m_fileItem.mimetype() == "application/postscript" || 
0881       m_fileItem.mimetype() == "application/pdf" ||
0882       m_fileItem.mimetype().startsWith(QLatin1String("image")))
0883   {
0884     //
0885     // Set the URL to the incoming file
0886     // 
0887     fileUrl = m_fileItem.url();
0888   } 
0889   else if (m_fileItem.mimetype() == "application/x-shellscript" ||
0890            m_fileItem.mimetype().startsWith(QLatin1String("text")) || 
0891            m_fileItem.mimetype().startsWith(QLatin1String("message")))
0892   {
0893     //
0894     // Set a printer object
0895     //
0896     QPrinter printer(QPrinter::HighResolution);
0897     printer.setCreator("Smb4K");
0898     printer.setOutputFormat(QPrinter::PdfFormat);
0899     printer.setOutputFileName(QString("%1/smb4k_print.pdf").arg(tempDir.path()));
0900     
0901     //
0902     // Open the file that is to be printed and read it
0903     // 
0904     QStringList contents;
0905       
0906     QFile file(m_fileItem.url().path());
0907       
0908     if (file.open(QFile::ReadOnly|QFile::Text))
0909     {
0910       QTextStream ts(&file);
0911       
0912       while (!ts.atEnd())
0913       {
0914         contents << ts.readLine();
0915       }
0916     }
0917     else
0918     {
0919       return;
0920     }
0921     
0922     //
0923     // Convert the file to PDF
0924     // 
0925     QTextDocument doc;
0926     
0927     if (m_fileItem.mimetype().endsWith(QLatin1String("html")))
0928     {
0929       doc.setHtml(contents.join(" "));
0930     }
0931     else
0932     {
0933       doc.setPlainText(contents.join("\n"));
0934     }
0935       
0936     doc.print(&printer);
0937     
0938     //
0939     // Set the URL to the converted file
0940     // 
0941     fileUrl.setUrl(printer.outputFileName());
0942     fileUrl.setScheme("file");
0943   }
0944   else
0945   {
0946     Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype());
0947     return;
0948   }
0949   
0950   //
0951   // Get the open function for the printer
0952   // 
0953   smbc_open_print_job_fn openPrinter = smbc_getFunctionOpenPrintJob(m_context);
0954   
0955   if (!openPrinter)
0956   {
0957     setError(OpenPrintJobError);
0958     setErrorText(i18n("The print job could not be set up (step 1)"));
0959     
0960     emitResult();
0961     return;
0962   }
0963   
0964   //
0965   // Open the printer for printing
0966   // 
0967   SMBCFILE *printer = openPrinter(m_context, m_item->url().toString().toUtf8().data());
0968   
0969   if (!printer)
0970   {
0971     int errorCode = errno;
0972     
0973     if (errorCode == EACCES)
0974     {
0975       setError(AccessDeniedError);
0976       setErrorText(i18n("Permission denied"));
0977     }
0978     else
0979     {
0980       setError(OpenPrintJobError);
0981       setErrorText(i18n("The print job could not be set up (step 2)"));
0982     }
0983     
0984     emitResult();
0985     return;
0986   }
0987   
0988   //
0989   // Open the file
0990   // 
0991   QFile file(fileUrl.path());
0992   
0993   if (!file.open(QFile::ReadOnly))
0994   {
0995     setError(FileAccessError);
0996     setErrorText(i18n("The file %1 could not be read", fileUrl.path()));
0997     
0998     emitResult();
0999     return;
1000   }
1001   
1002   //
1003   // Write X copies of the file to the printer
1004   // 
1005   char buffer[4096];
1006   qint64 bytes = 0;
1007   int copy = 0;
1008   
1009   while (copy < m_copies)
1010   {
1011     while ((bytes = file.read(buffer, sizeof(buffer))) > 0)
1012     {
1013       smbc_write_fn writeFile = smbc_getFunctionWrite(m_context);
1014       
1015       if (writeFile(m_context, printer, buffer, bytes) < 0)
1016       {
1017         setError(PrintFileError);
1018         setErrorText(i18n("The file %1 could not be printed to %2", fileUrl.path(), m_item.staticCast<Smb4KShare>()->displayString()));
1019         
1020         smbc_close_fn closePrinter = smbc_getFunctionClose(m_context);
1021         closePrinter(m_context, printer);
1022       }
1023     }
1024     
1025     copy++;
1026   }
1027   
1028   //
1029   // Close the printer
1030   // 
1031   smbc_close_fn closePrinter = smbc_getFunctionClose(m_context);
1032   closePrinter(m_context, printer);
1033 }
1034 
1035 
1036 QHostAddress Smb4KClientJob::lookupIpAddress(const QString& name)
1037 {
1038   //
1039   // The IP address object
1040   // 
1041   QHostAddress ipAddress;
1042   
1043   // If the IP address is not to be determined for the local machine, we can use QHostInfo to
1044   // determine it. Otherwise we need to use QNetworkInterface for it.
1045   if (name.toUpper() == QHostInfo::localHostName().toUpper() || 
1046       name.toUpper() == globalSambaOptions()["netbios name"].toUpper() || 
1047       name.toUpper() == Smb4KSettings::netBIOSName().toUpper())
1048   {
1049     // FIXME: Do we need to honor 'interfaces' here?
1050     QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
1051     
1052     // Get the IP address for the host. For the time being, prefer the 
1053     // IPv4 address over the IPv6 address.
1054     for (const QHostAddress &addr : addresses)
1055     {
1056       // We only use global addresses.
1057 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1058       if (addr.isGlobal())
1059 #else
1060       if (!addr.isLoopback() && !addr.isMulticast())
1061 #endif
1062       {
1063         if (addr.protocol() == QAbstractSocket::IPv4Protocol)
1064         {
1065           ipAddress = addr;
1066           break;
1067         }
1068         else if (addr.protocol() == QAbstractSocket::IPv6Protocol)
1069         {
1070           // FIXME: Use the right address here.
1071           ipAddress = addr;
1072         }
1073       }
1074     }
1075   }
1076   else
1077   {
1078     // Get the IP address
1079     QHostInfo hostInfo = QHostInfo::fromName(name);
1080             
1081     if (hostInfo.error() == QHostInfo::NoError)
1082     {
1083       // Get the IP address for the host. For the time being, prefer the 
1084       // IPv4 address over the IPv6 address.
1085       for (const QHostAddress &addr : hostInfo.addresses())
1086       {
1087         // We only use global addresses.
1088 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1089         if (addr.isGlobal())
1090 #else
1091         if (!addr.isLoopback() && !addr.isMulticast())
1092 #endif
1093         {
1094           if (addr.protocol() == QAbstractSocket::IPv4Protocol)
1095           {
1096             ipAddress = addr;
1097             break;
1098           }
1099           else if (addr.protocol() == QAbstractSocket::IPv6Protocol)
1100           {
1101             // FIXME: Use the right address here.
1102             ipAddress = addr;
1103           }
1104         }
1105       }
1106     }
1107   }
1108   
1109   return ipAddress;
1110 }
1111 
1112 
1113 void Smb4KClientJob::slotStartJob()
1114 {
1115   // 
1116   // Allocate new context
1117   // 
1118   m_context = smbc_new_context();
1119   
1120   if (!m_context)
1121   {
1122     int errorCode = errno;
1123     
1124     switch (errorCode)
1125     {
1126       case ENOMEM:
1127       {
1128         setError(OutOfMemoryError);
1129         setErrorText(i18n("Out of memory"));
1130         break;
1131       }
1132       default:
1133       {
1134         setError(UnknownError);
1135         setErrorText(i18n("Unknown error"));
1136         break;
1137       }
1138     }
1139     
1140     emitResult();
1141     return;
1142   }
1143   
1144   //
1145   // Get the custom options
1146   // 
1147   OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(m_item);
1148   
1149   // 
1150   // Set debug level
1151   // 
1152   smbc_setDebug(m_context, SMBC_DEBUG);
1153   
1154   //
1155   // Set the NetBIOS name and the workgroup to make connections
1156   // 
1157   switch (m_item->type())
1158   {
1159     case Network:
1160     {
1161       // 
1162       // We do not know about the servers and the domains/workgroups
1163       // present. So, do not set anything and use the default.
1164       // 
1165       break;
1166     }
1167     case Workgroup:
1168     {
1169       //
1170       // Set the NetBIOS name of the master browser and the workgroup to be queried
1171       // 
1172       WorkgroupPtr workgroup = m_item.staticCast<Smb4KWorkgroup>();
1173       smbc_setNetbiosName(m_context, workgroup->masterBrowserName().toUtf8().data());
1174       smbc_setWorkgroup(m_context, workgroup->workgroupName().toUtf8().data());
1175       break;
1176     }
1177     case Host:
1178     {
1179       //
1180       // Set both the NetBIOS name of the server and the workgroup to be queried
1181       // 
1182       HostPtr host = m_item.staticCast<Smb4KHost>();
1183       smbc_setNetbiosName(m_context, host->hostName().toUtf8().data());
1184       smbc_setWorkgroup(m_context, host->workgroupName().toUtf8().data());
1185       break;
1186     }
1187     case Share:
1188     {
1189       //
1190       // Set both the NetBIOS name of the server and the workgroup to be queried
1191       // 
1192       SharePtr share = m_item.staticCast<Smb4KShare>();
1193       smbc_setNetbiosName(m_context, share->hostName().toUtf8().data());
1194       smbc_setWorkgroup(m_context, share->workgroupName().toUtf8().data());
1195       break;
1196     }
1197     case Directory:
1198     {
1199       //
1200       // Set both the NetBIOS name of the server and the workgroup to be queried
1201       // 
1202       FilePtr file = m_item.staticCast<Smb4KFile>();
1203       smbc_setNetbiosName(m_context, file->hostName().toUtf8().data());
1204       smbc_setWorkgroup(m_context, file->workgroupName().toUtf8().data());
1205       break;      
1206     }
1207     default:
1208     {
1209       break;
1210     }
1211   }
1212 
1213   //
1214   // Set the user for making the connection
1215   // 
1216   if (!m_item->url().userName().isEmpty())
1217   {
1218     smbc_setUser(m_context, m_item->url().userName().toUtf8().data());
1219   }
1220   
1221   //
1222   // Set the port
1223   // 
1224   if (options)
1225   {
1226     if (options->useSmbPort())
1227     {
1228       smbc_setPort(m_context, options->smbPort());
1229     }
1230     else
1231     {
1232       smbc_setPort(m_context, 0 /* use the default */);
1233     }
1234   }
1235   else
1236   {
1237     if (Smb4KSettings::useRemoteSmbPort())
1238     {
1239       smbc_setPort(m_context, Smb4KSettings::remoteSmbPort());
1240     }
1241     else
1242     {
1243       smbc_setPort(m_context, 0 /* use the default */);
1244     }
1245   }
1246 
1247   //
1248   // Set the user data (this class)
1249   // 
1250   smbc_setOptionUserData(m_context, this);
1251   
1252   //
1253   // Set number of master browsers to be used
1254   // 
1255   if (Smb4KSettings::largeNetworkNeighborhood())
1256   {
1257     smbc_setOptionBrowseMaxLmbCount(m_context, 3);
1258   }
1259   else
1260   {
1261     smbc_setOptionBrowseMaxLmbCount(m_context, 0 /* all master browsers */);
1262   }
1263   
1264   //
1265   // Set the encryption level
1266   // 
1267   if (Smb4KSettings::useEncryptionLevel())
1268   {
1269     switch (Smb4KSettings::encryptionLevel())
1270     {
1271       case Smb4KSettings::EnumEncryptionLevel::None:
1272       {
1273         smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_NONE);
1274         break;
1275       }
1276       case Smb4KSettings::EnumEncryptionLevel::Request:
1277       {
1278         smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUEST);
1279         break;
1280       }
1281       case Smb4KSettings::EnumEncryptionLevel::Require:
1282       {
1283         smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUIRE);
1284         break;
1285       }
1286       default:
1287       {
1288         break;
1289       }
1290     }
1291   }
1292   
1293   //
1294   // Set the usage of anonymous login 
1295   // 
1296   smbc_setOptionNoAutoAnonymousLogin(m_context, false);
1297   
1298   //
1299   // Set the usage of the winbind ccache
1300   // 
1301   smbc_setOptionUseCCache(m_context, Smb4KSettings::useWinbindCCache());
1302   
1303   //
1304   // Set usage of Kerberos
1305   // 
1306   if (options)
1307   {
1308     smbc_setOptionUseKerberos(m_context, options->useKerberos());
1309   }
1310   else
1311   {
1312     smbc_setOptionUseKerberos(m_context, Smb4KSettings::useKerberos());
1313   }
1314   
1315   smbc_setOptionFallbackAfterKerberos(m_context, 1);
1316   
1317   //
1318   // Set the channel for debug output
1319   // 
1320   smbc_setOptionDebugToStderr(m_context, 1);
1321   
1322   //
1323   // Set auth callback function
1324   // 
1325   smbc_setFunctionAuthDataWithContext(m_context, get_auth_data_with_context_fn);
1326   
1327   // 
1328   // Initialize context with the previously defined options
1329   // 
1330   if (!smbc_init_context(m_context))
1331   {
1332     int errorCode = errno;
1333     
1334     switch (errorCode)
1335     {
1336       case ENOMEM:
1337       {
1338         setError(OutOfMemoryError);
1339         setErrorText(i18n("Out of memory"));
1340         break;
1341       }
1342       case EBADF:
1343       {
1344         setError(NullContextError);
1345         setErrorText(i18n("NULL context given"));
1346         break;
1347       }
1348       case ENOENT:
1349       {
1350         setError(SmbConfError);
1351         setErrorText(i18n("The smb.conf file would not load"));
1352         break;
1353       }
1354       default:
1355       {
1356         setError(UnknownError);
1357         setErrorText(i18n("Unknown error"));
1358       }
1359     }
1360 
1361     smbc_free_context(m_context, 0);
1362 
1363     emitResult();
1364     return;
1365   }
1366   
1367   //
1368   // Set the new context
1369   // 
1370   (void)smbc_set_context(m_context);
1371   
1372   //
1373   // Process the given URL according to the passed process
1374   // 
1375   switch (m_process)
1376   {
1377     case LookupDomains:
1378     case LookupDomainMembers:
1379     case LookupShares:
1380     case LookupFiles:
1381     {
1382       doLookups();
1383       break;
1384     }
1385     case PrintFile:
1386     {
1387       doPrinting();
1388       break;
1389     }
1390     default:
1391     {
1392       break;
1393     }
1394   }
1395   
1396   //
1397   // Free the context
1398   // 
1399   smbc_free_context(m_context, 0);
1400   
1401   //
1402   // Emit the result
1403   // 
1404   emitResult();
1405 }
1406 
1407 
1408 
1409 Smb4KPreviewDialog::Smb4KPreviewDialog(const SharePtr& share, QWidget* parent) 
1410 : QDialog(parent), m_share(share)
1411 {
1412   // 
1413   // Dialog title
1414   // 
1415   setWindowTitle(i18n("Preview of %1", share->displayString()));
1416   
1417   //
1418   // Attributes
1419   // 
1420   setAttribute(Qt::WA_DeleteOnClose, true);
1421   
1422   //
1423   // Layout
1424   // 
1425   QVBoxLayout *layout = new QVBoxLayout(this);
1426   setLayout(layout);
1427   
1428   //
1429   // The list widget
1430   // 
1431   QListWidget *listWidget = new QListWidget(this);
1432   listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
1433   connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemActivated(QListWidgetItem*)));
1434   
1435   layout->addWidget(listWidget, 0);
1436   
1437   //
1438   // Toolbar
1439   // Use QToolBar here with the settings suggested by the note provided in the 'Detailed Description'
1440   // section of KToolBar (https://api.kde.org/frameworks/kxmlgui/html/classKToolBar.html)
1441   // 
1442   QToolBar *toolBar = new QToolBar(this);
1443   toolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
1444   toolBar->setProperty("otherToolbar", true);
1445   
1446   //
1447   // Reload / cancel action
1448   // 
1449   KDualAction *reloadAction = new KDualAction(toolBar);
1450   reloadAction->setObjectName("reload_action");
1451   reloadAction->setInactiveText(i18n("Reload"));
1452   reloadAction->setInactiveIcon(KDE::icon("view-refresh"));
1453   reloadAction->setActiveText(i18n("Abort"));
1454   reloadAction->setActiveIcon(KDE::icon("process-stop"));
1455   reloadAction->setActive(false);
1456   reloadAction->setAutoToggle(false);
1457   
1458   connect(reloadAction, SIGNAL(toggled(bool)), this, SLOT(slotReloadActionTriggered()));
1459   
1460   toolBar->addAction(reloadAction);
1461   
1462   //
1463   // Up action
1464   // 
1465   QAction *upAction =toolBar->addAction(KDE::icon("go-up"), i18n("Up"), this, SLOT(slotUpActionTriggered()));
1466   upAction->setObjectName("up_action");
1467   upAction->setEnabled(false);
1468   
1469   toolBar->addSeparator();
1470   
1471   //
1472   // URL combo box
1473   // 
1474   KUrlComboBox *urlCombo = new KUrlComboBox(KUrlComboBox::Directories, toolBar);
1475   urlCombo->setEditable(false);
1476   toolBar->addWidget(urlCombo);
1477   connect(urlCombo, SIGNAL(urlActivated(QUrl)), this, SLOT(slotUrlActivated(QUrl)));
1478   
1479   layout->addWidget(toolBar, 0);
1480   
1481   //
1482   // Dialog button box
1483   // 
1484   QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
1485   buttonBox->setOrientation(Qt::Horizontal);
1486   QPushButton *closeButton = buttonBox->addButton(QDialogButtonBox::Close);
1487   connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClosingDialog()));
1488   
1489   layout->addWidget(buttonBox, 0);
1490   
1491   //
1492   // Set the minimum width
1493   // 
1494   setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350);
1495   
1496   //
1497   // Set the dialog size
1498   // 
1499   create();
1500 
1501   KConfigGroup group(Smb4KSettings::self()->config(), "PreviewDialog");
1502   QSize dialogSize;
1503   
1504   if (group.exists())
1505   {
1506     KWindowConfig::restoreWindowSize(windowHandle(), group);
1507     dialogSize = windowHandle()->size();
1508   }
1509   else
1510   {
1511     dialogSize = sizeHint();
1512   }
1513   
1514   resize(dialogSize); // workaround for QTBUG-40584
1515 
1516   //
1517   // Start the preview
1518   // 
1519   m_currentItem = m_share;
1520   QTimer::singleShot(0, this, SLOT(slotInitializePreview()));
1521 }
1522 
1523 
1524 Smb4KPreviewDialog::~Smb4KPreviewDialog()
1525 {
1526   //
1527   // Clear the share
1528   //
1529   m_share.clear();
1530   
1531   //
1532   // Clear the current item
1533   //
1534   m_currentItem.clear();
1535   
1536   //
1537   // Clear the listing
1538   // 
1539   while (!m_listing.isEmpty())
1540   {
1541     m_listing.takeFirst().clear();
1542   }
1543 }
1544 
1545 
1546 SharePtr Smb4KPreviewDialog::share() const
1547 {
1548   return m_share;
1549 }
1550 
1551 
1552 void Smb4KPreviewDialog::slotClosingDialog()
1553 {
1554   //
1555   // Save the dialog size
1556   // 
1557   KConfigGroup group(Smb4KSettings::self()->config(), "PreviewDialog");
1558   KWindowConfig::saveWindowSize(windowHandle(), group);
1559   
1560   //
1561   // Emit the aboutToClose() signal
1562   // 
1563   emit aboutToClose(this);
1564   
1565   // 
1566   // Close the dialog
1567   // 
1568   accept();
1569 }
1570 
1571 
1572 void Smb4KPreviewDialog::slotReloadActionTriggered()
1573 {
1574   KDualAction *reloadAction = findChild<KDualAction *>();
1575   
1576   if (reloadAction->isActive())
1577   {
1578     emit requestAbort();
1579   }
1580   else
1581   {
1582     emit requestPreview(m_currentItem);
1583   }
1584 }
1585 
1586 
1587 void Smb4KPreviewDialog::slotUpActionTriggered()
1588 {
1589   //
1590   // Get the new URL
1591   // 
1592   QUrl u = KIO::upUrl(m_currentItem->url());
1593   
1594   //
1595   // Create a new network item object, if necessary and set the new current
1596   // item. Also, disable the "Up" action, if necessary.
1597   // 
1598   if (m_share->url().matches(u, QUrl::StripTrailingSlash))
1599   {
1600     findChild<QAction *>("up_action")->setEnabled(false);
1601     m_currentItem = m_share;
1602   }
1603   else if (m_share->url().path().length() < u.path().length())
1604   {
1605     FilePtr file = FilePtr(new Smb4KFile(u, Directory));
1606     file->setWorkgroupName(m_share->workgroupName());
1607     m_currentItem = file;
1608   }
1609   else
1610   {
1611     return;
1612   }
1613   
1614   //
1615   // Emit the requestPreview() signal
1616   // 
1617   emit requestPreview(m_currentItem);
1618 }
1619 
1620 
1621 void Smb4KPreviewDialog::slotUrlActivated(const QUrl &url)
1622 {
1623   //
1624   // Get the full authentication information. This is needed, since the combo
1625   // box only returns sanitized URLs, i.e. without password, etc.
1626   // 
1627   QUrl u = url;
1628   u.setUserName(m_share->login());
1629   u.setPassword(m_share->password());
1630   
1631   //
1632   // Create a new network item object, if necessary and set the new current
1633   // item.
1634   // 
1635   if (m_share->url().matches(u, QUrl::StripTrailingSlash))
1636   {
1637     m_currentItem = m_share;
1638   }
1639   else
1640   {
1641     FilePtr file = FilePtr(new Smb4KFile(u, Directory));
1642     file->setWorkgroupName(m_share->workgroupName());
1643     m_currentItem = file;
1644   }
1645   
1646   //
1647   // Emit the requestPreview() signal
1648   // 
1649   emit requestPreview(m_currentItem);
1650 }
1651 
1652 
1653 void Smb4KPreviewDialog::slotItemActivated(QListWidgetItem *item)
1654 {
1655   //
1656   // Only process the item if it represents a directory
1657   // 
1658   if (item && item->type() == Directory)
1659   {
1660     //
1661     // Find the file item, make it the current one and emit the requestPreview() 
1662     // signal.
1663     // 
1664     for (const FilePtr &f : m_listing)
1665     {
1666       if (item->data(Qt::UserRole).toUrl().matches(f->url(), QUrl::None))
1667       {
1668         m_currentItem = f;
1669         emit requestPreview(m_currentItem);
1670         break;
1671       }
1672     }
1673   }
1674 }
1675 
1676 
1677 void Smb4KPreviewDialog::slotInitializePreview()
1678 {
1679   emit requestPreview(m_currentItem);
1680 }
1681 
1682 
1683 void Smb4KPreviewDialog::slotPreviewResults(const QList<FilePtr> &list)
1684 {
1685   //
1686   // Only process data the belongs to this dialog
1687   // 
1688   if (m_share->workgroupName() == list.first()->workgroupName() && m_share->hostName() == list.first()->hostName() && 
1689       list.first()->url().path().startsWith(m_share->url().path()))
1690   {
1691     //
1692     // Clear the internal listing
1693     // 
1694     while (!m_listing.isEmpty())
1695     {
1696       m_listing.takeFirst().clear();
1697     }  
1698     
1699     //
1700     // Copy the list into the private variable
1701     //
1702     m_listing = list;
1703     
1704     //
1705     // Get the list widget
1706     // 
1707     QListWidget *listWidget = findChild<QListWidget *>();
1708     
1709     //
1710     // Clear the list widget
1711     //
1712     listWidget->clear();
1713     
1714     //
1715     // Insert the new listing
1716     // 
1717     if (listWidget)
1718     {
1719       for (const FilePtr &f : list)
1720       {
1721         QListWidgetItem *item = new QListWidgetItem(f->icon(), f->name(), listWidget, f->isDirectory() ? Directory : File);
1722         item->setData(Qt::UserRole, f->url());
1723       }
1724     }
1725     
1726     //
1727     // Sort the list widget
1728     // 
1729     listWidget->sortItems();
1730     
1731     //
1732     // Add the URL to the combo box and show it. Omit duplicates.
1733     // 
1734     KUrlComboBox *urlCombo = findChild<KUrlComboBox *>();
1735     QStringList urls = urlCombo->urls();
1736     urls << m_currentItem->url().toString();
1737     urlCombo->setUrls(urls);
1738     urlCombo->setUrl(m_currentItem->url());
1739     
1740     //
1741     // Enable / disable the "Up" action
1742     //
1743     findChild<QAction *>("up_action")->setEnabled(!m_share->url().matches(m_currentItem->url(), QUrl::StripTrailingSlash));
1744   }
1745 }
1746 
1747 
1748 void Smb4KPreviewDialog::slotAboutToStart(const NetworkItemPtr &item, int type)
1749 {
1750   if (type == LookupFiles)
1751   {
1752     switch (item->type())
1753     {
1754       case Share:
1755       {
1756         SharePtr s = item.staticCast<Smb4KShare>();
1757         
1758         if (m_share->workgroupName() == s->workgroupName() && m_share->hostName() == s->hostName() && s->url().path().startsWith(m_share->url().path()))
1759         {
1760           KDualAction *reloadAction = findChild<KDualAction *>();
1761           reloadAction->setActive(true);
1762         }
1763         
1764         break;
1765       }
1766       case Directory:
1767       {
1768         FilePtr f = item.staticCast<Smb4KFile>();
1769         
1770         if (m_share->workgroupName() == f->workgroupName() && m_share->hostName() == f->hostName() && f->url().path().startsWith(m_share->url().path()))
1771         {
1772           KDualAction *reloadAction = findChild<KDualAction *>();
1773           reloadAction->setActive(true);
1774         }
1775         
1776         break;
1777       }
1778       default:
1779       {
1780         break;
1781       }
1782     }
1783   }
1784 }
1785 
1786 
1787 void Smb4KPreviewDialog::slotFinished(const NetworkItemPtr &item, int type)
1788 {
1789   if (type == LookupFiles)
1790   {
1791     switch (item->type())
1792     {
1793       case Share:
1794       {
1795         SharePtr s = item.staticCast<Smb4KShare>();
1796         
1797         if (m_share->workgroupName() == s->workgroupName() && m_share->hostName() == s->hostName() && s->url().path().startsWith(m_share->url().path()))
1798         {
1799           KDualAction *reloadAction = findChild<KDualAction *>();
1800           reloadAction->setActive(false);
1801         }
1802         
1803         break;
1804       }
1805       case Directory:
1806       {
1807         FilePtr f = item.staticCast<Smb4KFile>();
1808         
1809         if (m_share->workgroupName() == f->workgroupName() && m_share->hostName() == f->hostName() && f->url().path().startsWith(m_share->url().path()))
1810         {
1811           KDualAction *reloadAction = findChild<KDualAction *>();
1812           reloadAction->setActive(false);
1813         }
1814         
1815         break;
1816       }
1817       default:
1818       {
1819         break;
1820       }
1821     }
1822   }
1823 }
1824 
1825 
1826 Smb4KPrintDialog::Smb4KPrintDialog(const SharePtr& share, QWidget* parent)
1827 : QDialog(parent), m_share(share)
1828 {
1829   // 
1830   // Dialog title
1831   // 
1832   setWindowTitle(i18n("Print File"));
1833   
1834   //
1835   // Attributes
1836   // 
1837   setAttribute(Qt::WA_DeleteOnClose, true);
1838   
1839   //
1840   // Layout
1841   // 
1842   QVBoxLayout *layout = new QVBoxLayout(this);
1843   setLayout(layout);
1844   
1845   //
1846   // Information group box
1847   //
1848   QGroupBox *informationBox = new QGroupBox(i18n("Information"), this);
1849   QGridLayout *informationBoxLayout = new QGridLayout(informationBox);
1850   
1851   // Printer name
1852   QLabel *printerNameLabel = new QLabel(i18n("Printer:"), informationBox);
1853   QLabel *printerName = new QLabel(share->displayString(), informationBox);
1854   
1855   informationBoxLayout->addWidget(printerNameLabel, 0, 0, 0);
1856   informationBoxLayout->addWidget(printerName, 0, 1, 0);
1857   
1858   // IP address
1859   QLabel *ipAddressLabel = new QLabel(i18n("IP Address:"), informationBox);
1860   QLabel *ipAddress = new QLabel(share->hostIpAddress(), informationBox);
1861   
1862   informationBoxLayout->addWidget(ipAddressLabel, 1, 0, 0);
1863   informationBoxLayout->addWidget(ipAddress, 1, 1, 0);
1864   
1865   // Workgroup
1866   QLabel *workgroupNameLabel = new QLabel(i18n("Domain:"), informationBox);
1867   QLabel *workgroupName = new QLabel(share->workgroupName(), informationBox);
1868   
1869   informationBoxLayout->addWidget(workgroupNameLabel, 2, 0, 0);
1870   informationBoxLayout->addWidget(workgroupName, 2, 1, 0);
1871   
1872   layout->addWidget(informationBox);
1873   
1874   //
1875   // File and settings group box
1876   // 
1877   QGroupBox *fileBox = new QGroupBox(i18n("File and Settings"), this);
1878   QGridLayout *fileBoxLayout = new QGridLayout(fileBox);
1879   
1880   // File
1881   QLabel *fileLabel = new QLabel(i18n("File:"), fileBox);
1882   KUrlRequester *file = new KUrlRequester(fileBox);
1883   file->setMode(KFile::File|KFile::LocalOnly|KFile::ExistingOnly);
1884   file->setUrl(QUrl::fromLocalFile(QDir::homePath()));
1885   file->setWhatsThis(i18n("This is the file you want to print on the remote printer. " 
1886     "Currently only a few mimetypes are supported such as PDF, Postscript, plain text, and " 
1887     "images. If the file's mimetype is not supported, you need to convert it."));
1888   connect(file, SIGNAL(textChanged(QString)), this, SLOT(slotUrlChanged()));
1889   
1890   fileBoxLayout->addWidget(fileLabel, 0, 0, 0);
1891   fileBoxLayout->addWidget(file, 0, 1, 0);
1892   
1893   // Copies
1894   QLabel *copiesLabel = new QLabel(i18n("Copies:"), fileBox);
1895   QSpinBox *copies = new QSpinBox(fileBox);
1896   copies->setValue(1);
1897   copies->setMinimum(1);
1898   copies->setWhatsThis(i18n("This is the number of copies you want to print."));
1899   
1900   fileBoxLayout->addWidget(copiesLabel, 1, 0, 0);
1901   fileBoxLayout->addWidget(copies, 1, 1, 0);
1902   
1903   layout->addWidget(fileBox);
1904   
1905   //
1906   // Buttons
1907   // 
1908   QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
1909   QPushButton *printButton = buttonBox->addButton(i18n("Print"), QDialogButtonBox::ActionRole);
1910   printButton->setObjectName("print_button");
1911   printButton->setShortcut(Qt::CTRL|Qt::Key_P);
1912   connect(printButton, SIGNAL(clicked(bool)), this, SLOT(slotPrintButtonClicked()));
1913   
1914   QPushButton *cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel);
1915   cancelButton->setObjectName("cancel_button");
1916   cancelButton->setShortcut(Qt::Key_Escape);
1917   cancelButton->setDefault(true);
1918   connect(cancelButton, SIGNAL(clicked(bool)), this, SLOT(slotCancelButtonClicked()));
1919   
1920   layout->addWidget(buttonBox);
1921   
1922   //
1923   // Set the minimum width
1924   // 
1925   setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350);
1926   
1927   //
1928   // Set the dialog size
1929   // 
1930   create();
1931 
1932   KConfigGroup group(Smb4KSettings::self()->config(), "PrintDialog");
1933   QSize dialogSize;
1934   
1935   if (group.exists())
1936   {
1937     KWindowConfig::restoreWindowSize(windowHandle(), group);
1938     dialogSize = windowHandle()->size();
1939   }
1940   else
1941   {
1942     dialogSize = sizeHint();
1943   }
1944   
1945   resize(dialogSize); // workaround for QTBUG-40584
1946   
1947   //
1948   // Set the buttons
1949   // 
1950   slotUrlChanged();
1951 }
1952 
1953 
1954 Smb4KPrintDialog::~Smb4KPrintDialog()
1955 {
1956 }
1957 
1958 
1959 SharePtr Smb4KPrintDialog::share() const
1960 {
1961   return m_share;
1962 }
1963 
1964 
1965 KFileItem Smb4KPrintDialog::fileItem() const
1966 {
1967   return m_fileItem;
1968 }
1969 
1970 
1971 void Smb4KPrintDialog::slotUrlChanged()
1972 {
1973   //
1974   // Take the focus from the URL requester and give it to the dialog's 
1975   // button box
1976   // 
1977   QDialogButtonBox *buttonBox = findChild<QDialogButtonBox *>();
1978   buttonBox->setFocus();  
1979 
1980   //
1981   // Get the URL from the URL requester
1982   // 
1983   KUrlRequester *file = findChild<KUrlRequester *>();
1984   KFileItem fileItem = KFileItem(file->url());
1985   
1986   //
1987   // Apply the settings to the buttons of the dialog's button box
1988   // 
1989   QPushButton *printButton = findChild<QPushButton *>("print_button");
1990   printButton->setEnabled(fileItem.url().isValid() && fileItem.isFile());
1991   printButton->setDefault(fileItem.url().isValid() && fileItem.isFile());
1992   
1993   QPushButton *cancelButton = findChild<QPushButton *>("cancel_button");
1994   cancelButton->setDefault(!fileItem.url().isValid() || !fileItem.isFile());
1995 }
1996 
1997 
1998 void Smb4KPrintDialog::slotPrintButtonClicked()
1999 {
2000   //
2001   // Get the file item that is to be printed
2002   // 
2003   KUrlRequester *file = findChild<KUrlRequester *>();
2004   m_fileItem = KFileItem(file->url());
2005   
2006   if (m_fileItem.url().isValid())
2007   {
2008     // 
2009     // Check if the mime type is supported or if the file can be
2010     // converted into a supported mimetype
2011     // 
2012     if (m_fileItem.mimetype() != "application/postscript" &&
2013         m_fileItem.mimetype() != "application/pdf" &&
2014         m_fileItem.mimetype() != "application/x-shellscript" &&
2015         !m_fileItem.mimetype().startsWith(QLatin1String("text")) &&
2016         !m_fileItem.mimetype().startsWith(QLatin1String("message")) &&
2017         !m_fileItem.mimetype().startsWith(QLatin1String("image")))
2018     {
2019       Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype());
2020       return;
2021     }
2022 
2023     //
2024     // Save the window size
2025     // 
2026     KConfigGroup group(Smb4KSettings::self()->config(), "PrintDialog");
2027     KWindowConfig::saveWindowSize(windowHandle(), group);
2028     
2029     //
2030     // Emit the printFile() signal
2031     // 
2032     QSpinBox *copies = findChild<QSpinBox *>();
2033     emit printFile(m_share, m_fileItem, copies->value());
2034     
2035     //
2036     // Emit the aboutToClose() signal
2037     //
2038     emit aboutToClose(this);
2039     
2040     //
2041     // Close the print dialog
2042     // 
2043     accept();
2044   }
2045 }
2046 
2047 
2048 void Smb4KPrintDialog::slotCancelButtonClicked()
2049 {
2050   //
2051   // Abort the printing
2052   // 
2053   Smb4KClient::self()->abort();
2054   
2055   //
2056   // Emit the aboutToClose() signal
2057   // 
2058   emit aboutToClose(this);
2059   
2060   //
2061   // Reject the dialog
2062   // 
2063   reject();
2064 }
2065 
2066 
2067