diff --git a/core/smb4kclient_p.cpp b/core/smb4kclient_p.cpp index d491169..b8cb24e 100644 --- a/core/smb4kclient_p.cpp +++ b/core/smb4kclient_p.cpp @@ -1,2052 +1,2056 @@ /*************************************************************************** Private classes for the SMB client ------------------- begin : So Oct 21 2018 copyright : (C) 2018-2020 by Alexander Reinholdt email : alexander.reinholdt@kdemail.net ***************************************************************************/ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* * MA 02110-1335, USA * ***************************************************************************/ // application specific includes #include "smb4kclient_p.h" #include "smb4ksettings.h" #include "smb4kwalletmanager.h" #include "smb4kcustomoptions.h" #include "smb4kcustomoptionsmanager.h" #include "smb4knotification.h" // System includes #include // #include #include // #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #define SMBC_DEBUG 0 using namespace Smb4KGlobal; // // Authentication function for libsmbclient // static void get_auth_data_with_context_fn(SMBCCTX *context, const char *server, const char *share, char *workgroup, int maxLenWorkgroup, char *username, int maxLenUsername, char *password, int maxLenPassword) { if (context != nullptr) { Smb4KClientJob *job = static_cast(smbc_getOptionUserData(context)); if (job) { job->get_auth_data_fn(server, share, workgroup, maxLenWorkgroup, username, maxLenUsername, password, maxLenPassword); } } } // // Client job // Smb4KClientJob::Smb4KClientJob(QObject* parent) : KJob(parent), m_process(Smb4KGlobal::NoProcess) { } Smb4KClientJob::~Smb4KClientJob() { // // Clear the list of workgroups // while (!m_workgroups.isEmpty()) { m_workgroups.takeFirst().clear(); } // // Clear the list of hosts // while (!m_hosts.isEmpty()) { m_hosts.takeFirst().clear(); } // // Clear the list of shares // while (!m_shares.isEmpty()) { m_shares.takeFirst().clear(); } // // Clear the list of files and directories // while (!m_files.isEmpty()) { m_files.takeFirst().clear(); } } void Smb4KClientJob::start() { QTimer::singleShot(50, this, SLOT(slotStartJob())); } void Smb4KClientJob::setNetworkItem(NetworkItemPtr item) { m_item = item; } NetworkItemPtr Smb4KClientJob::networkItem() const { return m_item; } void Smb4KClientJob::setProcess(Smb4KGlobal::Process process) { m_process = process; } Smb4KGlobal::Process Smb4KClientJob::process() const { return m_process; } void Smb4KClientJob::setPrintFileItem(const KFileItem& item) { m_fileItem = item; } KFileItem Smb4KClientJob::printFileItem() const { return m_fileItem; } void Smb4KClientJob::setPrintCopies(int copies) { m_copies = copies; } int Smb4KClientJob::printCopies() const { return m_copies; } void Smb4KClientJob::get_auth_data_fn(const char* server, const char* /*share*/, char* workgroup, int /*maxLenWorkgroup*/, char* username, int maxLenUsername, char* password, int maxLenPassword) { // // Authentication // switch (m_item->type()) { case Network: { // // No authentication needed // break; } case Workgroup: { // // Only request authentication data, if the master browsers require // authentication data. // if (Smb4KSettings::masterBrowsersRequireAuth()) { if (QString::fromUtf8(server).toUpper() != QString::fromUtf8(workgroup).toUpper()) { // // This is the master browser. Create a host object for it. // HostPtr h = HostPtr(new Smb4KHost()); h->setWorkgroupName(QString::fromUtf8(workgroup)); h->setHostName(QString::fromUtf8(server)); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(h); // // Copy the authentication data // qstrncpy(username, h->login().toUtf8().data(), maxLenUsername); qstrncpy(password, h->password().toUtf8().data(), maxLenPassword); } } break; } case Host: { // // The host object // HostPtr h = m_item.staticCast(); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(h); // // Copy the authentication data // qstrncpy(username, h->login().toUtf8().data(), maxLenUsername); qstrncpy(password, h->password().toUtf8().data(), maxLenPassword); break; } case Share: { // // The share object // SharePtr s = m_item.staticCast(); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(s); // // Copy the authentication data // qstrncpy(username, s->login().toUtf8().data(), maxLenUsername); qstrncpy(password, s->password().toUtf8().data(), maxLenPassword); break; } case Directory: { // // The file object // FilePtr f = m_item.staticCast(); // // Create a share object // SharePtr s = SharePtr(new Smb4KShare()); s->setWorkgroupName(f->workgroupName()); s->setHostName(f->hostName()); s->setShareName(f->shareName()); s->setLogin(f->login()); s->setPassword(f->password()); // // Get the authentication data // Smb4KWalletManager::self()->readAuthInfo(s); // // Copy the authentication data // qstrncpy(username, s->login().toUtf8().data(), maxLenUsername); qstrncpy(password, s->password().toUtf8().data(), maxLenPassword); break; } default: { break; } } } QList Smb4KClientJob::workgroups() { return m_workgroups; } QList Smb4KClientJob::hosts() { return m_hosts; } QList Smb4KClientJob::shares() { return m_shares; } QList Smb4KClientJob::files() { return m_files; } QString Smb4KClientJob::workgroup() { QString workgroup; switch (m_item->type()) { case Network: { break; } case Workgroup: { workgroup = m_item->url().host().toUpper(); break; } case Host: { workgroup = m_item.staticCast()->workgroupName(); break; } case Share: { workgroup = m_item.staticCast()->workgroupName(); break; } case Directory: case File: { workgroup = m_item.staticCast()->workgroupName(); break; } default: { break; } } return workgroup; } void Smb4KClientJob::doLookups() { // // Get the function to open the directory // smbc_opendir_fn openDirectory = smbc_getFunctionOpendir(m_context); if (!openDirectory) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); emitResult(); return; } // // Open the directory // SMBCFILE *directory = openDirectory(m_context, m_item->url().toString().toUtf8().data()); if (!directory) { int errorCode = errno; switch (errorCode) { case EACCES: { setError(AccessDeniedError); setErrorText(strerror(errorCode)); break; } case ENOENT: { // - // Just exit silently when the query for domains - // and workgroups failed. + // Exit silently when the query for domains and workgroups failed. // + if (m_item->type() != Network) + { + setError(ClientError); + setErrorText(strerror(errorCode)); + } break; } default: { setError(ClientError); setErrorText(strerror(errorCode)); break; } } emitResult(); return; } // // Read the directory // struct smbc_dirent *directoryEntry = nullptr; smbc_readdir_fn readDirectory = smbc_getFunctionReaddir(m_context); if (!readDirectory) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); emitResult(); return; } while ((directoryEntry = readDirectory(m_context, directory)) != nullptr) { switch (directoryEntry->smbc_type) { case SMBC_WORKGROUP: { // // Create a workgroup pointer // WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); // // Set the workgroup name // QString workgroupName = QString::fromUtf8(directoryEntry->name); workgroup->setWorkgroupName(workgroupName); // // Set the master browser // QString masterBrowserName = QString::fromUtf8(directoryEntry->comment); workgroup->setMasterBrowserName(masterBrowserName); // // Lookup IP address // QHostAddress address = lookupIpAddress(masterBrowserName); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip the // workgroup and delete the pointer. // if (!address.isNull()) { workgroup->setMasterBrowserIpAddress(address); m_workgroups << workgroup; } else { workgroup.clear(); } break; } case SMBC_SERVER: { // // Create a host pointer // HostPtr host = HostPtr(new Smb4KHost()); // // Set the workgroup name // host->setWorkgroupName(m_item->url().host()); // // Set the host name // QString hostName = QString::fromUtf8(directoryEntry->name); host->setHostName(hostName); // // Set the comment // QString comment = QString::fromUtf8(directoryEntry->comment); host->setComment(comment); // // Lookup IP address // QHostAddress address = lookupIpAddress(hostName); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { host->setIpAddress(address); m_hosts << host; } else { host.clear(); } break; } case SMBC_FILE_SHARE: { // // Create a share pointer // SharePtr share = SharePtr(new Smb4KShare()); // // Set the workgroup name // share->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the host name // share->setHostName(m_item->url().host()); // // Set the share name // share->setShareName(QString::fromUtf8(directoryEntry->name)); // // Set the comment // share->setComment(QString::fromUtf8(directoryEntry->comment)); // // Set share type // share->setShareType(FileShare); // // Set the authentication data // share->setLogin(m_item->url().userName()); share->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { share->setHostIpAddress(address); m_shares << share; } else { share.clear(); } break; } case SMBC_PRINTER_SHARE: { // // Create a share pointer // SharePtr share = SharePtr(new Smb4KShare()); // // Set the workgroup name // share->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the host name // share->setHostName(m_item->url().host()); // // Set the share name // share->setShareName(QString::fromUtf8(directoryEntry->name)); // // Set the comment // share->setComment(QString::fromUtf8(directoryEntry->comment)); // // Set share type // share->setShareType(PrinterShare); // // Set the authentication data // share->setLogin(m_item->url().userName()); share->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { share->setHostIpAddress(address); m_shares << share; } else { share.clear(); } break; } case SMBC_IPC_SHARE: { // // Create a share pointer // SharePtr share = SharePtr(new Smb4KShare()); // // Set the workgroup name // share->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the host name // share->setHostName(m_item->url().host()); // // Set the share name // share->setShareName(QString::fromUtf8(directoryEntry->name)); // // Set the comment // share->setComment(QString::fromUtf8(directoryEntry->comment)); // // Set share type // share->setShareType(IpcShare); // // Set the authentication data // share->setLogin(m_item->url().userName()); share->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { share->setHostIpAddress(address); m_shares << share; } else { share.clear(); } break; } case SMBC_DIR: { // // Do not process '.' and '..' directories // QString name = QString::fromUtf8(directoryEntry->name); if (name != "." && name != "..") { // // Create the URL for the discovered item // QUrl u = m_item->url(); u.setPath(m_item->url().path()+QDir::separator()+QString::fromUtf8(directoryEntry->name)); // // We do not stat directories. Directly create the directory object // FilePtr dir = FilePtr(new Smb4KFile(u, Directory)); // // Set the workgroup name // dir->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Set the authentication data // dir->setLogin(m_item->url().userName()); dir->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { dir->setHostIpAddress(address); m_files << dir; } else { dir.clear(); } } break; } case SMBC_FILE: { // // Create the URL for the discovered item // QUrl u = m_item->url(); u.setPath(m_item->url().path()+QDir::separator()+QString::fromUtf8(directoryEntry->name)); // // Create the directory object // FilePtr dir = FilePtr(new Smb4KFile(u, File)); // // Set the workgroup name // dir->setWorkgroupName(m_item.staticCast()->workgroupName()); // // Stat the file // // FIXME // // Set the authentication data // dir->setLogin(m_item->url().userName()); dir->setPassword(m_item->url().password()); // // Lookup IP address // QHostAddress address = lookupIpAddress(m_item->url().host()); // // Process the IP address. // If the address is null, the server most likely went offline. So, skip it // and delete the pointer. // if (!address.isNull()) { dir->setHostIpAddress(address); m_files << dir; } else { dir.clear(); } break; } case SMBC_LINK: { qDebug() << "Processing links is not implemented."; qDebug() << directoryEntry->name; qDebug() << directoryEntry->comment; break; } default: { qDebug() << "Need to process network item " << directoryEntry->name; break; } } } // // Close the directory // smbc_closedir_fn closeDirectory = smbc_getFunctionClosedir(m_context); if (!closeDirectory) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); emitResult(); return; } (void)closeDirectory(m_context, directory); } void Smb4KClientJob::doPrinting() { // // The URL that is to be printed // QUrl fileUrl; // // Set the temporary directory // QTemporaryDir tempDir; // // Check if we can directly print the file // if (m_fileItem.mimetype() == "application/postscript" || m_fileItem.mimetype() == "application/pdf" || m_fileItem.mimetype().startsWith(QLatin1String("image"))) { // // Set the URL to the incoming file // fileUrl = m_fileItem.url(); } else if (m_fileItem.mimetype() == "application/x-shellscript" || m_fileItem.mimetype().startsWith(QLatin1String("text")) || m_fileItem.mimetype().startsWith(QLatin1String("message"))) { // // Set a printer object // QPrinter printer(QPrinter::HighResolution); printer.setCreator("Smb4K"); printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(QString("%1/smb4k_print.pdf").arg(tempDir.path())); // // Open the file that is to be printed and read it // QStringList contents; QFile file(m_fileItem.url().path()); if (file.open(QFile::ReadOnly|QFile::Text)) { QTextStream ts(&file); while (!ts.atEnd()) { contents << ts.readLine(); } } else { return; } // // Convert the file to PDF // QTextDocument doc; if (m_fileItem.mimetype().endsWith(QLatin1String("html"))) { doc.setHtml(contents.join(" ")); } else { doc.setPlainText(contents.join("\n")); } doc.print(&printer); // // Set the URL to the converted file // fileUrl.setUrl(printer.outputFileName()); fileUrl.setScheme("file"); } else { Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype()); return; } // // Get the open function for the printer // smbc_open_print_job_fn openPrinter = smbc_getFunctionOpenPrintJob(m_context); if (!openPrinter) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); emitResult(); return; } // // Open the printer for printing // SMBCFILE *printer = openPrinter(m_context, m_item->url().toString().toUtf8().data()); if (!printer) { int errorCode = errno; switch (errorCode) { case EACCES: { setError(AccessDeniedError); setErrorText(strerror(errorCode)); break; } default: { setError(ClientError); setErrorText(strerror(errorCode)); break; } } emitResult(); return; } // // Open the file // QFile file(fileUrl.path()); if (!file.open(QFile::ReadOnly)) { setError(FileAccessError); setErrorText(i18n("The file %1 could not be read", fileUrl.path())); emitResult(); return; } // // Write X copies of the file to the printer // char buffer[4096]; qint64 bytes = 0; int copy = 0; while (copy < m_copies) { while ((bytes = file.read(buffer, sizeof(buffer))) > 0) { smbc_write_fn writeFile = smbc_getFunctionWrite(m_context); if (writeFile(m_context, printer, buffer, bytes) < 0) { setError(PrintFileError); setErrorText(i18n("The file %1 could not be printed to %2", fileUrl.path(), m_item.staticCast()->displayString())); smbc_close_fn closePrinter = smbc_getFunctionClose(m_context); closePrinter(m_context, printer); } } copy++; } // // Close the printer // smbc_close_fn closePrinter = smbc_getFunctionClose(m_context); closePrinter(m_context, printer); } QHostAddress Smb4KClientJob::lookupIpAddress(const QString& name) { // // The IP address object // QHostAddress ipAddress; // If the IP address is not to be determined for the local machine, we can use QHostInfo to // determine it. Otherwise we need to use QNetworkInterface for it. if (name.toUpper() == QHostInfo::localHostName().toUpper() || name.toUpper() == globalSambaOptions()["netbios name"].toUpper() || name.toUpper() == Smb4KSettings::netBIOSName().toUpper()) { // FIXME: Do we need to honor 'interfaces' here? QList addresses = QNetworkInterface::allAddresses(); // Get the IP address for the host. For the time being, prefer the // IPv4 address over the IPv6 address. for (const QHostAddress &addr : addresses) { // We only use global addresses. #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) if (addr.isGlobal()) #else if (!addr.isLoopback() && !addr.isMulticast()) #endif { if (addr.protocol() == QAbstractSocket::IPv4Protocol) { ipAddress = addr; break; } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { // FIXME: Use the right address here. ipAddress = addr; } } } } else { // Get the IP address QHostInfo hostInfo = QHostInfo::fromName(name); if (hostInfo.error() == QHostInfo::NoError) { // Get the IP address for the host. For the time being, prefer the // IPv4 address over the IPv6 address. for (const QHostAddress &addr : hostInfo.addresses()) { // We only use global addresses. #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) if (addr.isGlobal()) #else if (!addr.isLoopback() && !addr.isMulticast()) #endif { if (addr.protocol() == QAbstractSocket::IPv4Protocol) { ipAddress = addr; break; } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { // FIXME: Use the right address here. ipAddress = addr; } } } } } return ipAddress; } void Smb4KClientJob::slotStartJob() { // // Allocate new context // m_context = smbc_new_context(); if (!m_context) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); emitResult(); return; } // // Get the custom options // OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(m_item); // // Set debug level // smbc_setDebug(m_context, SMBC_DEBUG); // // Set the NetBIOS name and the workgroup to make connections // switch (m_item->type()) { case Network: { // // We do not know about the servers and the domains/workgroups // present. So, do not set anything and use the default. // break; } case Workgroup: { // // Set the NetBIOS name of the master browser and the workgroup to be queried // WorkgroupPtr workgroup = m_item.staticCast(); smbc_setNetbiosName(m_context, workgroup->masterBrowserName().toUtf8().data()); smbc_setWorkgroup(m_context, workgroup->workgroupName().toUtf8().data()); break; } case Host: { // // Set both the NetBIOS name of the server and the workgroup to be queried // HostPtr host = m_item.staticCast(); smbc_setNetbiosName(m_context, host->hostName().toUtf8().data()); smbc_setWorkgroup(m_context, host->workgroupName().toUtf8().data()); break; } case Share: { // // Set both the NetBIOS name of the server and the workgroup to be queried // SharePtr share = m_item.staticCast(); smbc_setNetbiosName(m_context, share->hostName().toUtf8().data()); smbc_setWorkgroup(m_context, share->workgroupName().toUtf8().data()); break; } case Directory: { // // Set both the NetBIOS name of the server and the workgroup to be queried // FilePtr file = m_item.staticCast(); smbc_setNetbiosName(m_context, file->hostName().toUtf8().data()); smbc_setWorkgroup(m_context, file->workgroupName().toUtf8().data()); break; } default: { break; } } // // Set the user for making the connection // if (!m_item->url().userName().isEmpty()) { smbc_setUser(m_context, m_item->url().userName().toUtf8().data()); } // // Set the port // if (options) { if (options->useSmbPort()) { smbc_setPort(m_context, options->smbPort()); } else { smbc_setPort(m_context, 0 /* use the default */); } } else { if (Smb4KSettings::useRemoteSmbPort()) { smbc_setPort(m_context, Smb4KSettings::remoteSmbPort()); } else { smbc_setPort(m_context, 0 /* use the default */); } } // // Set the user data (this class) // smbc_setOptionUserData(m_context, this); // // Set number of master browsers to be used // if (Smb4KSettings::largeNetworkNeighborhood()) { smbc_setOptionBrowseMaxLmbCount(m_context, 3); } else { smbc_setOptionBrowseMaxLmbCount(m_context, 0 /* all master browsers */); } // // Set the protocol to SMB1 ("NT1") if desired so that the workgroups // and domains can be discovered. // if (Smb4KSettings::forceSMB1Protocol() && m_item->type() == Network) { smbc_setOptionProtocols(m_context, "NT1", "NT1"); } // // Set the encryption level // if (Smb4KSettings::useEncryptionLevel()) { switch (Smb4KSettings::encryptionLevel()) { case Smb4KSettings::EnumEncryptionLevel::None: { smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_NONE); break; } case Smb4KSettings::EnumEncryptionLevel::Request: { smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUEST); break; } case Smb4KSettings::EnumEncryptionLevel::Require: { smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUIRE); break; } default: { break; } } } // // Set the usage of anonymous login // smbc_setOptionNoAutoAnonymousLogin(m_context, false); // // Set the usage of the winbind ccache // smbc_setOptionUseCCache(m_context, Smb4KSettings::useWinbindCCache()); // // Set usage of Kerberos // if (options) { smbc_setOptionUseKerberos(m_context, options->useKerberos()); } else { smbc_setOptionUseKerberos(m_context, Smb4KSettings::useKerberos()); } smbc_setOptionFallbackAfterKerberos(m_context, 1); // // Set the channel for debug output // smbc_setOptionDebugToStderr(m_context, 1); // // Set auth callback function // smbc_setFunctionAuthDataWithContext(m_context, get_auth_data_with_context_fn); // // Initialize context with the previously defined options // if (!smbc_init_context(m_context)) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); smbc_free_context(m_context, 0); emitResult(); return; } // // Set the new context // (void)smbc_set_context(m_context); // // Process the given URL according to the passed process // switch (m_process) { case LookupDomains: case LookupDomainMembers: case LookupShares: case LookupFiles: { doLookups(); break; } case PrintFile: { doPrinting(); break; } default: { break; } } // // Free the context // smbc_free_context(m_context, 0); // // Emit the result // emitResult(); } Smb4KPreviewDialog::Smb4KPreviewDialog(const SharePtr& share, QWidget* parent) : QDialog(parent), m_share(share) { // // Dialog title // setWindowTitle(i18n("Preview of %1", share->displayString())); // // Attributes // setAttribute(Qt::WA_DeleteOnClose, true); // // Layout // QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); // // The list widget // QListWidget *listWidget = new QListWidget(this); listWidget->setSelectionMode(QAbstractItemView::SingleSelection); connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemActivated(QListWidgetItem*))); layout->addWidget(listWidget, 0); // // Toolbar // Use QToolBar here with the settings suggested by the note provided in the 'Detailed Description' // section of KToolBar (https://api.kde.org/frameworks/kxmlgui/html/classKToolBar.html) // QToolBar *toolBar = new QToolBar(this); toolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle); toolBar->setProperty("otherToolbar", true); // // Reload / cancel action // KDualAction *reloadAction = new KDualAction(toolBar); reloadAction->setObjectName("reload_action"); reloadAction->setInactiveText(i18n("Reload")); reloadAction->setInactiveIcon(KDE::icon("view-refresh")); reloadAction->setActiveText(i18n("Abort")); reloadAction->setActiveIcon(KDE::icon("process-stop")); reloadAction->setActive(false); reloadAction->setAutoToggle(false); connect(reloadAction, SIGNAL(toggled(bool)), this, SLOT(slotReloadActionTriggered())); toolBar->addAction(reloadAction); // // Up action // QAction *upAction =toolBar->addAction(KDE::icon("go-up"), i18n("Up"), this, SLOT(slotUpActionTriggered())); upAction->setObjectName("up_action"); upAction->setEnabled(false); toolBar->addSeparator(); // // URL combo box // KUrlComboBox *urlCombo = new KUrlComboBox(KUrlComboBox::Directories, toolBar); urlCombo->setEditable(false); toolBar->addWidget(urlCombo); connect(urlCombo, SIGNAL(urlActivated(QUrl)), this, SLOT(slotUrlActivated(QUrl))); layout->addWidget(toolBar, 0); // // Dialog button box // QDialogButtonBox *buttonBox = new QDialogButtonBox(this); buttonBox->setOrientation(Qt::Horizontal); QPushButton *closeButton = buttonBox->addButton(QDialogButtonBox::Close); connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClosingDialog())); layout->addWidget(buttonBox, 0); // // Set the minimum width // setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350); // // Set the dialog size // create(); KConfigGroup group(Smb4KSettings::self()->config(), "PreviewDialog"); QSize dialogSize; if (group.exists()) { KWindowConfig::restoreWindowSize(windowHandle(), group); dialogSize = windowHandle()->size(); } else { dialogSize = sizeHint(); } resize(dialogSize); // workaround for QTBUG-40584 // // Start the preview // m_currentItem = m_share; QTimer::singleShot(0, this, SLOT(slotInitializePreview())); } Smb4KPreviewDialog::~Smb4KPreviewDialog() { // // Clear the share // m_share.clear(); // // Clear the current item // m_currentItem.clear(); // // Clear the listing // while (!m_listing.isEmpty()) { m_listing.takeFirst().clear(); } } SharePtr Smb4KPreviewDialog::share() const { return m_share; } void Smb4KPreviewDialog::slotClosingDialog() { // // Save the dialog size // KConfigGroup group(Smb4KSettings::self()->config(), "PreviewDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); // // Emit the aboutToClose() signal // emit aboutToClose(this); // // Close the dialog // accept(); } void Smb4KPreviewDialog::slotReloadActionTriggered() { KDualAction *reloadAction = findChild(); if (reloadAction->isActive()) { emit requestAbort(); } else { emit requestPreview(m_currentItem); } } void Smb4KPreviewDialog::slotUpActionTriggered() { // // Get the new URL // QUrl u = KIO::upUrl(m_currentItem->url()); // // Create a new network item object, if necessary and set the new current // item. Also, disable the "Up" action, if necessary. // if (m_share->url().matches(u, QUrl::StripTrailingSlash)) { findChild("up_action")->setEnabled(false); m_currentItem = m_share; } else if (m_share->url().path().length() < u.path().length()) { FilePtr file = FilePtr(new Smb4KFile(u, Directory)); file->setWorkgroupName(m_share->workgroupName()); m_currentItem = file; } else { return; } // // Emit the requestPreview() signal // emit requestPreview(m_currentItem); } void Smb4KPreviewDialog::slotUrlActivated(const QUrl &url) { // // Get the full authentication information. This is needed, since the combo // box only returns sanitized URLs, i.e. without password, etc. // QUrl u = url; u.setUserName(m_share->login()); u.setPassword(m_share->password()); // // Create a new network item object, if necessary and set the new current // item. // if (m_share->url().matches(u, QUrl::StripTrailingSlash)) { m_currentItem = m_share; } else { FilePtr file = FilePtr(new Smb4KFile(u, Directory)); file->setWorkgroupName(m_share->workgroupName()); m_currentItem = file; } // // Emit the requestPreview() signal // emit requestPreview(m_currentItem); } void Smb4KPreviewDialog::slotItemActivated(QListWidgetItem *item) { // // Only process the item if it represents a directory // if (item && item->type() == Directory) { // // Find the file item, make it the current one and emit the requestPreview() // signal. // for (const FilePtr &f : m_listing) { if (item->data(Qt::UserRole).toUrl().matches(f->url(), QUrl::None)) { m_currentItem = f; emit requestPreview(m_currentItem); break; } } } } void Smb4KPreviewDialog::slotInitializePreview() { emit requestPreview(m_currentItem); } void Smb4KPreviewDialog::slotPreviewResults(const QList &list) { // // Only process data the belongs to this dialog // if (m_share->workgroupName() == list.first()->workgroupName() && m_share->hostName() == list.first()->hostName() && list.first()->url().path().startsWith(m_share->url().path())) { // // Clear the internal listing // while (!m_listing.isEmpty()) { m_listing.takeFirst().clear(); } // // Copy the list into the private variable // m_listing = list; // // Get the list widget // QListWidget *listWidget = findChild(); // // Clear the list widget // listWidget->clear(); // // Insert the new listing // if (listWidget) { for (const FilePtr &f : list) { QListWidgetItem *item = new QListWidgetItem(f->icon(), f->name(), listWidget, f->isDirectory() ? Directory : File); item->setData(Qt::UserRole, f->url()); } } // // Sort the list widget // listWidget->sortItems(); // // Add the URL to the combo box and show it. Omit duplicates. // KUrlComboBox *urlCombo = findChild(); QStringList urls = urlCombo->urls(); urls << m_currentItem->url().toString(); urlCombo->setUrls(urls); urlCombo->setUrl(m_currentItem->url()); // // Enable / disable the "Up" action // findChild("up_action")->setEnabled(!m_share->url().matches(m_currentItem->url(), QUrl::StripTrailingSlash)); } } void Smb4KPreviewDialog::slotAboutToStart(const NetworkItemPtr &item, int type) { if (type == LookupFiles) { switch (item->type()) { case Share: { SharePtr s = item.staticCast(); if (m_share->workgroupName() == s->workgroupName() && m_share->hostName() == s->hostName() && s->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(true); } break; } case Directory: { FilePtr f = item.staticCast(); if (m_share->workgroupName() == f->workgroupName() && m_share->hostName() == f->hostName() && f->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(true); } break; } default: { break; } } } } void Smb4KPreviewDialog::slotFinished(const NetworkItemPtr &item, int type) { if (type == LookupFiles) { switch (item->type()) { case Share: { SharePtr s = item.staticCast(); if (m_share->workgroupName() == s->workgroupName() && m_share->hostName() == s->hostName() && s->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(false); } break; } case Directory: { FilePtr f = item.staticCast(); if (m_share->workgroupName() == f->workgroupName() && m_share->hostName() == f->hostName() && f->url().path().startsWith(m_share->url().path())) { KDualAction *reloadAction = findChild(); reloadAction->setActive(false); } break; } default: { break; } } } } Smb4KPrintDialog::Smb4KPrintDialog(const SharePtr& share, QWidget* parent) : QDialog(parent), m_share(share) { // // Dialog title // setWindowTitle(i18n("Print File")); // // Attributes // setAttribute(Qt::WA_DeleteOnClose, true); // // Layout // QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); // // Information group box // QGroupBox *informationBox = new QGroupBox(i18n("Information"), this); QGridLayout *informationBoxLayout = new QGridLayout(informationBox); // Printer name QLabel *printerNameLabel = new QLabel(i18n("Printer:"), informationBox); QLabel *printerName = new QLabel(share->displayString(), informationBox); informationBoxLayout->addWidget(printerNameLabel, 0, 0, 0); informationBoxLayout->addWidget(printerName, 0, 1, 0); // IP address QLabel *ipAddressLabel = new QLabel(i18n("IP Address:"), informationBox); QLabel *ipAddress = new QLabel(share->hostIpAddress(), informationBox); informationBoxLayout->addWidget(ipAddressLabel, 1, 0, 0); informationBoxLayout->addWidget(ipAddress, 1, 1, 0); // Workgroup QLabel *workgroupNameLabel = new QLabel(i18n("Domain:"), informationBox); QLabel *workgroupName = new QLabel(share->workgroupName(), informationBox); informationBoxLayout->addWidget(workgroupNameLabel, 2, 0, 0); informationBoxLayout->addWidget(workgroupName, 2, 1, 0); layout->addWidget(informationBox); // // File and settings group box // QGroupBox *fileBox = new QGroupBox(i18n("File and Settings"), this); QGridLayout *fileBoxLayout = new QGridLayout(fileBox); // File QLabel *fileLabel = new QLabel(i18n("File:"), fileBox); KUrlRequester *file = new KUrlRequester(fileBox); file->setMode(KFile::File|KFile::LocalOnly|KFile::ExistingOnly); file->setUrl(QUrl::fromLocalFile(QDir::homePath())); file->setWhatsThis(i18n("This is the file you want to print on the remote printer. " "Currently only a few mimetypes are supported such as PDF, Postscript, plain text, and " "images. If the file's mimetype is not supported, you need to convert it.")); connect(file, SIGNAL(textChanged(QString)), this, SLOT(slotUrlChanged())); fileBoxLayout->addWidget(fileLabel, 0, 0, 0); fileBoxLayout->addWidget(file, 0, 1, 0); // Copies QLabel *copiesLabel = new QLabel(i18n("Copies:"), fileBox); QSpinBox *copies = new QSpinBox(fileBox); copies->setValue(1); copies->setMinimum(1); copies->setWhatsThis(i18n("This is the number of copies you want to print.")); fileBoxLayout->addWidget(copiesLabel, 1, 0, 0); fileBoxLayout->addWidget(copies, 1, 1, 0); layout->addWidget(fileBox); // // Buttons // QDialogButtonBox *buttonBox = new QDialogButtonBox(this); QPushButton *printButton = buttonBox->addButton(i18n("Print"), QDialogButtonBox::ActionRole); printButton->setObjectName("print_button"); printButton->setShortcut(Qt::CTRL|Qt::Key_P); connect(printButton, SIGNAL(clicked(bool)), this, SLOT(slotPrintButtonClicked())); QPushButton *cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel); cancelButton->setObjectName("cancel_button"); cancelButton->setShortcut(Qt::Key_Escape); cancelButton->setDefault(true); connect(cancelButton, SIGNAL(clicked(bool)), this, SLOT(slotCancelButtonClicked())); layout->addWidget(buttonBox); // // Set the minimum width // setMinimumWidth(sizeHint().width() > 350 ? sizeHint().width() : 350); // // Set the dialog size // create(); KConfigGroup group(Smb4KSettings::self()->config(), "PrintDialog"); QSize dialogSize; if (group.exists()) { KWindowConfig::restoreWindowSize(windowHandle(), group); dialogSize = windowHandle()->size(); } else { dialogSize = sizeHint(); } resize(dialogSize); // workaround for QTBUG-40584 // // Set the buttons // slotUrlChanged(); } Smb4KPrintDialog::~Smb4KPrintDialog() { } SharePtr Smb4KPrintDialog::share() const { return m_share; } KFileItem Smb4KPrintDialog::fileItem() const { return m_fileItem; } void Smb4KPrintDialog::slotUrlChanged() { // // Take the focus from the URL requester and give it to the dialog's // button box // QDialogButtonBox *buttonBox = findChild(); buttonBox->setFocus(); // // Get the URL from the URL requester // KUrlRequester *file = findChild(); KFileItem fileItem = KFileItem(file->url()); // // Apply the settings to the buttons of the dialog's button box // QPushButton *printButton = findChild("print_button"); printButton->setEnabled(fileItem.url().isValid() && fileItem.isFile()); printButton->setDefault(fileItem.url().isValid() && fileItem.isFile()); QPushButton *cancelButton = findChild("cancel_button"); cancelButton->setDefault(!fileItem.url().isValid() || !fileItem.isFile()); } void Smb4KPrintDialog::slotPrintButtonClicked() { // // Get the file item that is to be printed // KUrlRequester *file = findChild(); m_fileItem = KFileItem(file->url()); if (m_fileItem.url().isValid()) { // // Check if the mime type is supported or if the file can be // converted into a supported mimetype // if (m_fileItem.mimetype() != "application/postscript" && m_fileItem.mimetype() != "application/pdf" && m_fileItem.mimetype() != "application/x-shellscript" && !m_fileItem.mimetype().startsWith(QLatin1String("text")) && !m_fileItem.mimetype().startsWith(QLatin1String("message")) && !m_fileItem.mimetype().startsWith(QLatin1String("image"))) { Smb4KNotification::mimetypeNotSupported(m_fileItem.mimetype()); return; } // // Save the window size // KConfigGroup group(Smb4KSettings::self()->config(), "PrintDialog"); KWindowConfig::saveWindowSize(windowHandle(), group); // // Emit the printFile() signal // QSpinBox *copies = findChild(); emit printFile(m_share, m_fileItem, copies->value()); // // Emit the aboutToClose() signal // emit aboutToClose(this); // // Close the print dialog // accept(); } } void Smb4KPrintDialog::slotCancelButtonClicked() { // // Abort the printing // Smb4KClient::self()->abort(); // // Emit the aboutToClose() signal // emit aboutToClose(this); // // Reject the dialog // reject(); }