diff --git a/CMakeLists.txt b/CMakeLists.txt index 63680e6..fd1d536 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,170 +1,171 @@ # # Project # project(smb4k) # # Version # set(VERSION_MAJOR 3) set(VERSION_MINOR 0) set(VERSION_PATCH 70) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) # # Minimum required CMake version # cmake_minimum_required(VERSION 3.2 FATAL_ERROR) # # CMake policies # cmake_policy(SET CMP0037 NEW) if (POLICY CMP0071) cmake_policy(SET CMP0071 NEW) endif() # # Minimum required versions of Qt5 and KF5 # set(QT_MIN_VERSION "5.9.0") set(KF5_MIN_VERSION "5.44.0") # # Adjustments # if(KF5_VERSION VERSION_GREATER "5.55.0") set(AUTHLIB KF5::AuthCore) else() set(AUTHLIB KF5::Auth) endif() # # Options for building Smb4K # # Install header files option(INSTALL_HEADER_FILES "Install header files" OFF) # Install plasmoid option(INSTALL_PLASMOID "Install the plasmoid" ON) # # Required packages and includes # find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake/) include(KDEInstallDirs) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(FeatureSummary) include(ECMInstallIcons) include(ECMSetupVersion) include(CheckSymbolExists) ecm_setup_version(${VERSION} VARIABLE_PREFIX SMB4K VERSION_HEADER smb4k_version.h) # Qt5 modules find_package(Qt5Core ${QT_MIN_VERSION} REQUIRED) find_package(Qt5Gui ${QT_MIN_VERSION} REQUIRED) find_package(Qt5Network ${QT_MIN_VERSION} REQUIRED) find_package(Qt5PrintSupport ${QT_MIN_VERSION} REQUIRED) find_package(Qt5Qml ${QT_MIN_VERSION} REQUIRED) find_package(Qt5Test ${QT_MIN_VERSION} REQUIRED) find_package(Qt5Widgets ${QT_MIN_VERSION} REQUIRED) # KF5 modules find_package(KF5Auth ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Completion ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Config ${KF5_MIN_VERSION} REQUIRED) find_package(KF5ConfigWidgets ${KF5_MIN_VERSION} REQUIRED) find_package(KF5CoreAddons ${KF5_MIN_VERSION} REQUIRED) find_package(KF5DBusAddons ${KF5_MIN_VERSION} REQUIRED) find_package(KF5DocTools ${KF5_MIN_VERSION} REQUIRED) find_package(KF5I18n ${KF5_MIN_VERSION} REQUIRED) find_package(KF5IconThemes ${KF5_MIN_VERSION} REQUIRED) find_package(KF5JobWidgets ${KF5_MIN_VERSION} REQUIRED) find_package(KF5KIO ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Notifications ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Solid ${KF5_MIN_VERSION} REQUIRED) find_package(KF5Wallet ${KF5_MIN_VERSION} REQUIRED) find_package(KF5WidgetsAddons ${KF5_MIN_VERSION} REQUIRED) find_package(KF5WindowSystem ${KF5_MIN_VERSION} REQUIRED) find_package(KF5XmlGui ${KF5_MIN_VERSION} REQUIRED) -find_package(KF5Crash ${KF5_MIN_VERSION} REQUIRED) +find_package(KF5Crash ${KF5_MIN_VERSION} REQUIRED) +find_package(KF5DNSSD ${KF5_MIN_VERSION} REQUIRED) # Install the plasmoid if desired if (INSTALL_PLASMOID) find_package(KF5Plasma ${KF5_MIN_VERSION}) set_package_properties(KF5Plasma PROPERTIES TYPE RUNTIME) endif() # Find libsmbclient.h find_package(Libsmbclient REQUIRED MODULE) # Check that the required smbc_* functions are provided set(CMAKE_REQUIRED_LIBRARIES ${LIBSMBCLIENT_LIBRARIES}) set(CMAKE_REQUIRED_INCLUDES ${LIBSMBCLIENT_INCLUDE_DIRS}) check_symbol_exists(smbc_setOptionProtocols libsmbclient.h HAVE_SMBC_PROTOCOL) if (NOT HAVE_SMBC_PROTOCOL) message("The function smbc_setOptionProtocols() is missing in Samba's client library's header file." FATAL_ERROR) endif() # # Make sure that Smb4K builds when several custom targets # with the same name exist (happens in the po directory). # if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/po") set_property(GLOBAL PROPERTY ALLOW_DUPLICATE_CUSTOM_TARGETS ON) endif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/po") if (EXISTS "${CMAKE_SOURCE_DIR}/.git") add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x060000) endif() # # Make sure that all libraries, plugins, etc. are installed # into the right place. # set(KDE_INSTALL_USE_QT_SYS_PATHS ON CACHE BOOLEAN "Use Qt system paths for installation" FORCE) # # Add subdirectories # add_subdirectory(core) add_subdirectory(helpers) add_subdirectory(smb4k) add_subdirectory(data) add_subdirectory(doc) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) if(KF5DocTools_FOUND) kdoctools_install(po) endif(KF5DocTools_FOUND) endif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/po") # # Make adjustments according to the options set by the user # # Header files: Notify the user if (INSTALL_HEADER_FILES) message(STATUS "Installing core header files (-DINSTALL_HEADER_FILES=false to disable)") elseif (NOT INSTALL_HEADER_FILES) message(STATUS "Not installing core header files (-DINSTALL_HEADER_FILES=true to enable)") endif(INSTALL_HEADER_FILES) # Plasmoid: Notify the user and add the subdirectory if desired if (INSTALL_PLASMOID) message(STATUS "Installing plasmoid (-DINSTALL_PLASMOID=false to disable)") add_subdirectory(plasmoid) elseif(NOT INSTALL_PLASMOID) message(STATUS "Not installing plasmoid (-DINSTALL_PLASMOID=true to enable)") endif(INSTALL_PLASMOID) ########### install files ############### feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 02dbc95..6c2b513 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,113 +1,114 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${LIBSMBCLIENT_INCLUDE_DIRS}) set(smb4kcore_LIB_SRCS smb4kauthinfo.cpp smb4kbasicnetworkitem.cpp smb4kbookmark.cpp smb4kbookmarkhandler.cpp smb4kbookmarkhandler_p.cpp smb4kclient.cpp smb4kclient_p.cpp smb4kcustomoptions.cpp smb4kcustomoptionsmanager.cpp smb4kcustomoptionsmanager_p.cpp smb4kfile.cpp smb4kglobal.cpp smb4kglobal_p.cpp smb4khardwareinterface.cpp smb4khardwareinterface_p.cpp smb4khomesshareshandler.cpp smb4khomesshareshandler_p.cpp smb4khost.cpp smb4kmounter.cpp smb4kmounter_p.cpp smb4knotification.cpp smb4knotification_p.cpp smb4kprofilemanager.cpp smb4kprofilemanager_p.cpp smb4kshare.cpp smb4ksynchronizer.cpp smb4ksynchronizer_p.cpp smb4kwalletmanager.cpp smb4kwalletmanager_p.cpp smb4kworkgroup.cpp) if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux") kconfig_add_kcfg_files(smb4kcore_LIB_SRCS smb4ksettings.kcfgc smb4kmountsettings_linux.kcfgc) elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "FreeBSD" OR ${CMAKE_HOST_SYSTEM_NAME} MATCHES "NetBSD" OR ${CMAKE_HOST_SYSTEM_NAME} MATCHES "DragonFly") kconfig_add_kcfg_files(smb4kcore_LIB_SRCS smb4ksettings.kcfgc smb4kmountsettings_bsd.kcfgc) else () kconfig_add_kcfg_files(smb4kcore_LIB_SRCS smb4ksettings.kcfgc) endif () add_library(smb4kcore SHARED ${smb4kcore_LIB_SRCS}) target_link_libraries(smb4kcore Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Test Qt5::PrintSupport Qt5::Network Qt5::Qml KF5::ConfigCore KF5::ConfigGui ${AUTHLIB} KF5::IconThemes KF5::I18n KF5::Completion KF5::CoreAddons KF5::Solid KF5::KIOCore KF5::KIOWidgets KF5::Notifications KF5::JobWidgets KF5::Wallet KF5::XmlGui + KF5::DNSSD ${LIBSMBCLIENT_LIBRARIES}) set_target_properties(smb4kcore PROPERTIES VERSION 6.1.0 SOVERSION 6) install(TARGETS smb4kcore DESTINATION ${KDE_INSTALL_LIBDIR}) ########### install files ############### install(FILES smb4k.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) install(FILES smb4k.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) if (INSTALL_HEADER_FILES) install(FILES smb4kauthinfo.h smb4kbasicnetworkitem.h smb4kbookmark.h smb4kbookmarkhandler.h smb4kclient.h smb4kcustomoptions.h smb4kcustomoptionsmanager.h smb4kfile.h smb4kglobal.h smb4khardwareinterface.h smb4khomesshareshandler.h smb4khost.h smb4kmounter.h smb4knotification.h smb4kprocess.h smb4kprofilemanager.h smb4kshare.h smb4ksynchronizer.h smb4kwalletmanager.h smb4kworkgroup.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}) endif (INSTALL_HEADER_FILES) diff --git a/core/smb4k.kcfg b/core/smb4k.kcfg index 254b245..9521480 100644 --- a/core/smb4k.kcfg +++ b/core/smb4k.kcfg @@ -1,620 +1,625 @@ QString QDir QUrl QHostInfo smb4kglobal.h Set the tab orientation for the tabified dock widgets. Bottom Do not show the name of the share that is represented by the bookmark but the custom label that was defined in the bookmark editor. true Start the application docked to the system tray, i.e. only the system tray widget is shown and the main window is hidden. You can bring the main window up by clicking on the system tray widget or by choosing "Restore" from its popup menu. false The type of a share will be displayed in a separate column in the network neighborhood browser. It can either be Disk, Print or IPC. true The IP address of the server will be displayed in a separate column in the network neighborhood browser. true The comment describing the server or share will be displayed in a separate column in the network neighborhood browser. true The tooltip shows various information about the current network item. true Automatically expand domain and host items when a list of associated network items (domain members or shares) is added or updated. Please note that a domain or host item will always be expanded when you execute it. true The tooltip shows various information about the current share. true This setting determines the view mode of the shares view. There are two modes: the icon view and the list view. IconView + + + Use modern DNS service discovery (DNS-SD). This service is used to discover servers that provide shared SMB resources. When using this service, the discovered domains correspond to the DNS-SD domains (e. g. LOCAL) and most likely not the ones defined in the network neighborhood. If you use this option, there is no need to force Samba to use the SMB protocol version 1.0 for browsing. + true + + + + If you have trouble discovering the workgroups and domains in your network neighborhood, you might want to consider to switch this setting on. Smb4K will then force the use of the SMB protocol version 1.0 for browsing workgroups and domains. This, however, only applies to searches done using Samba's client library. Please note that, when using this option, some servers running modern Samba versions might be inaccessible. If you are using the DNS discovery service (DNS-SD), you can switch off this option. + false + This is the NetBIOS name of this computer that is used by Smb4K. By default, it is either the NetBIOS name that is defined in the smb.conf file or the host name. Smb4KGlobal::globalSambaOptions().contains("netbios name") ? Smb4KGlobal::globalSambaOptions().value("netbios name") : QHostInfo::localHostName().toUpper() This is the workgroup or domain this computer is or should be in. By default, it is the workgroup that is defined in the smb.conf file. Smb4KGlobal::globalSambaOptions().contains("workgroup") ? Smb4KGlobal::globalSambaOptions().value("workgroup") : "" This is the port that is used for connecting to remote servers with the client programs net, smbclient and smbtree. The default value is 139 (NetBIOS). Under FreeBSD, this setting is also used for mounting. false This is the port that is used for connecting to remote servers with the client programs net, smbclient and smbtree. The default value is 139 (NetBIOS). Under FreeBSD, this setting is also used for mounting. 1 65535 139 In case your computer is on a large network neighborhood, discovering all workgroups, hosts and shares might take a long time, since in the default configuration all local master browsers are queried. Enabling this setting limits the number of used local master browsers to three. This can reduced the time consumption on large network neighborhoods considerably. false The master browsers in your network neighborhood require a login to return the browse list. This setting is rarely needed. false Use Kerberos for authentication. This is only useful in an Active Directory environment. false Use the Winbind ccache for authentication. false Set the level of encryption that is used for making connections. false Set the level of encryption that is used for making connections. None - - - If you have trouble discovering the workgroups and domains in your network neighborhood, you should consider to switch this setting on. Smb4K will then force the use of the SMB 1.0 protocol for searching for workgroups and domains. - true - Preview hidden files and directories. The hidden files and directories are those whose names begin with a period. They are usually needed for very specific purposes (storing the configuration information for an application, etc.). Since they are not of any importance for your regular work, you normally do not need to enable this feature. false Printer shares are detected. true Hidden shares are detected. Hidden shares are ending with a $ sign, e.g. Musik$ or IPC$. true Wake-on-LAN (WOL) is an ethernet computer networking standard that allows a computer to be turned on or woken up by a network message. Smb4K uses a magic package send via a UDP socket to wake up remote servers. If you want to take advantage of the Wake-On-LAN feature, you need to enable this option. false This is the waiting time in seconds between the sending of the magic Wake-On-LAN packages and the scanning of the network neighborhood or the mounting of a share. 0 60 5 Use a wallet to store the login. The username and password are stored encrypted on your hard drive. If this setting is disabled, the login is not stored permanently but only temporarily. true Enable the usage of a default login. The provided data is used by default to authenticate to a remote server. This is very useful e.g. if you are working in an Active Directory environment or an NT domain. false Under this prefix the destination directory for the synchronization will be created. However, if you want to store the data of a particular share elsewhere, you will be able to choose a different path before the actual synchronization begins. QUrl::fromLocalFile(QDir::homePath()+"/smb4k_sync/") Use archive mode (-a, --archive). This is a short form of -rlptgoD. true Recurse into directories (-r, --recursive). true Update files in the destination directory that are older than in the source directory (-u, --update). false Update destination files in-place (--inplace). By default, rsync first creates a new copy of a file and moves it into place after its transfer finished. If you enable this feature, no copy will be created but the destination file will immediately be overwritten instead. An exception to this is if you combine this option with --backup. false Use relative paths (-R, --relative). This means that the full path names specified on the command line are sent to the server rather than just the last parts of the file names. false Do not send implied directories with --relative (--no-implied-dirs). This means that the corresponding path elements on the destination system are left unchanged if they exist, and any missing implied directories are created with default attributes. This even allows these implied path elements to have big differences, such as being a symlink to a directory on one side of the transfer, and a real directory on the other side. false Transfer directories without recursing (-d, --dirs). This means that all top-level subdirectories are transferred but without their contents. false Compress data during transfer (-z, --compress). This significantly reduces the amount of data that is being transferred. You may want to use this option, if you have a slow connection. false Explicitly set the compression level to use (--compress-level=NUM). If NUM is non-zero, the --compress argument is implied. false 0 9 0 Overwrite the list of file suffixes that will not be compressed (--skip-compress=LIST). The LIST should be one or more file suffixes (without the dot) separated by slashes. You may specify an empty string to indicate that no file should be skipped. The default list of suffixes will be replaced by this list. For further details, see the manual page of rsync. false Copy symlinks as symlinks (-l, --links). true Transform symlinks into the items they are pointing to (-L, --copy-links). false Transform unsafe symlinks into the items they are pointing to (--copy-unsafe-links). This means that only those symlinks are transformed that point to items that are outside the copied tree. Absolute symlinks are treated the same way. This option has no additional effect if --copy-links has also been specified. false Ignore symlinks that point outside the copied tree (--safe-links). All absolute symlinks are also ignored. If you use this option in conjunction with --relative you might get unexpected results. false This option tells rsync to (1) modify all symlinks on the receiving side in a way that makes them unusable but recoverable, or (2) to unmunge symlinks on the sending side that had been stored in a munged state (--munge-links). This is useful if you do not quite trust the source of the data to not try to slip in a symlink to an unexpected place. For more details, see the manual page of rsync. false Preserve hard links (-H, --hard-links). This options causes rsync to preserve the hard links that are found during the transfer. Without it, hard links are treated as though they were separate files. false Treat symlinks to directories on the sending side as though they were real ones (-k, --copy-dirlinks). This is useful if you do not want symlinks to non-directories to be affected, as they would be using --copy-links. Without this option, if the sending side has replaced a directory with a symlink to a directory, the receiving side will delete anything that is in the way of the new symlink, including a directory hierarchy (as long as --force or --delete is in effect). For more details, see the manual page of rsync. false Treat symlinks to directories on the receiving side as though they were real ones (-K, --keep-dirlinks). This only works if the symlink matches a real directory from the sending side. Without this option, the receiver's symlink will be deleted and replaced with a real directory. false Preserve permissions (-p, --perms). The permissions of the destination file will be same as the source file. For what happens if this option is switched off, please read rsync's manual page. true Preserve the group (-g, --group). The group of the destination file will be set to the same value as the source file. true Preserve the owner (-o, --owner). The owner of the destination file will be set to the same value as the source file, but only if the receiving rsync is run as the super user. Without this option, the owner is set to the invoking user on the receiving side. true Preserve device and special files (-D, --devices --specials). This option causes rsync to transfer character and block devices as well as special files such as named sockets and fifos. It works only partially if rsync is not run as super user and the --super option is not specified. true Preserve times (-t, --times). The modification times are transferred along with the files. For what happens if this option is switched off, please read rsync's manual page. true Omit directories when preserving times (-O, --omit-dir-times). This means that directories are omitted when modification times are being preserved. Thus, this feature only works in conjunction with --times. false Remove all synchronized source files (--remove-source-files). This tells rsync to remove from the sending side the non-directory items that are a part of the transfer and have been successfully duplicated on the receiving side. false Delete extraneous files from destination (--delete). This tells rsync to delete all files from the receiving side that are not present on the sending side, but only for the directories that are being synchronized. false Delete files on the receiving side before the transfer starts (--delete-before). This is the default behavior if --delete or --delete-excluded is specified without one of the --delete-WHEN options. false Delete files on the receiving side after the transfer has completed (--delete-after, --del). false Delete files on the receiving side during the transfer (--delete-during). This method is faster than --delete-before or --delete-after, but it is only supported with rsync 2.6.4 or later. false Also delete excluded files from destination directory (--delete-excluded). In addition to deleting the files on the receiving side that are not on the sending side, this tells rsync to also delete any files on the receiving side that are excluded. Refer to rsync's manual page for further information. false Delete even if I/O errors occur (--ignore-errors). This option has to be specified in conjunction with --delete to take effect. false Force deletion of directories even if they are not empty (--force). This option tells rsync to delete a non-empty directory when it is to be replaced by a non-directory. This is only relevant if deletions are not active. false Only delete as many files as defined here (--max-delete=NUM). This tells rsync not to delete more than NUM files or directories (NUM must be non-zero). This is useful when mirroring very large trees to prevent disasters. false 0 0 This option causes rsync to not transfer any file that is smaller than the specified size (--min-size=SIZE). false 0 0 This option causes rsync to not transfer any file that is larger than the specified size (--max-size=SIZE). false 0 0 Keep partially transferred files (--partial). The default behavior is that any partially transferred file is deleted if the transfer is interrupted. false Put a partially transferred file into this directory (--partial-dir=DIR). This is a better way than the --partial option to keep partial files, because the partially transferred file is kept in a different directory and the destination file is not overwritten. false QUrl::fromLocalFile(QDir::homePath()) Auto-ignore files in the same way CVS does (-C, --cvs-exclude). This is a useful shorthand for excluding a broad range of files that you often do not want to transfer between systems. This option uses the same algorithm that CVS uses to determine if a file should be ignored. false Exclude files that match a certain pattern (--exclude=PATTERN). This is a special filter rule. For further information on filter rules see rsync's manual page. false Read exclude patterns from a file (--exclude-from=FILE). This option is similar to the --exclude=PATTERN option except that the exclude patterns are read from a file. This is a special filter rule. For further information on filter rules see rsync's manual page. false QUrl::fromLocalFile(QDir::homePath()+"/exclude.txt") Do not exclude files matching a certain pattern (--include=PATTERN). This is a special filter rule. For further information on filter rules see rsync's manual page. false Read include patterns from a file (--include-from=FILE). This option is similar to the --include=PATTERN option except that the include patterns are read from a file. This is a special filter rule. For further information on filter rules see rsync's manual page. false QUrl::fromLocalFile(QDir::homePath()+"/include.txt") Add custom file-filtering rules (-f, --filter=RULE). This option allows you to add rules to selectively exclude certain files from the list of files to be transferred. These rules will be added to the rsync command as they are. Thus, each rule has to start with the --filter=... argument. This filter rule tells rsync to look for per-directory .rsync-filter files that have been sprinkled through the hierarchy and use their rules to filter the files in the transfer. It has no effect, if you also choose to use the --filter='exclude .rsync-filter' rule. false This rule filters out the .rsync-filter files from the transfer. These files normally contain filter rules that can be activated by choosing the --filter='dir-merge /.rsync-filter' rule and deselecting this one. false Handle sparse files efficiently (-S, --sparse) so that they take up less space on the destination. This option conflicts with --inplace. For further information read rsync's manual page. false Copy files whole (-W, --whole-file). With this option the incremental rsync algorithm is not used and the whole file is sent as-is instead. false Do not cross file system boundaries (-x, --one-file-system). This tells rsync to avoid crossing a filesystem boundary when recursing. For further information on this option, read the manual page. false Skip creating new files on the receiving side (--existing). This tells rsync to skip creating files (including directories) that do not exist yet on the destination. If this option is combined with the --ignore-existing option, no files will be updated (which can be useful if all you want to do is to delete extraneous files). false Skip updating files that already exist on the receiving side (--ignore-existing). Existing directories are not ignored. false Delay updates until the end of the transfer (--delay-updates). This option puts the temporary file from each updated file into a holding directory until the end of the transfer, at which time all the files are renamed and copied into place in rapid succession. false Make backups (-b, --backup). With this option, preexisting destination files are renamed as each file is transferred or deleted. You can control where the backup file goes and what (if any) suffix gets appended using the --backup-dir=DIR and --suffix=SUFFIX options. false Use this suffix for backups (--suffix=SUFFIX). false ~ Store backups in this directory (--backup-dir=DIR). false QUrl::fromLocalFile(QDir::homePath()) Force a fixed checksum block-size (-B, --block-size=SIZE). This forces the block size used in the rsync algorithm to a fixed value. false 0 0 Set block/file checksum seed (--checksum-seed=NUM). Set the MD4 checksum seed to this integer. This 4 byte checksum seed is included in each block and file MD4 checksum calculation. By default the checksum seed is generated by the server and defaults to the current time. false 0 0 Skip files based on a checksum and not based on modification time and size (-c, --checksum). For further information on how this feature works read rsync's manual page. false Set the maximum data transfer rate in kilobytes per second (--bwlimit=RATE). false 0 1073741824 0 Make Smb4K use profiles. This enables you to define different bookmarks and custom options for each profile. This is especially useful if you are using a laptop in different network neighborhoods, e. g. at home and at work. false The list of profiles. QStringList defaultProfiles; defaultProfiles.append(i18nc("default profile name for use at home", "Home")); defaultProfiles.append(i18nc("default profile name for use at work", "Work")); defaultProfiles This is the currently active profile. QString() Use the profile migration assistant when profiles are removed or the use of profiles is enabled or disabled. The profile migration assistant allows you to migrate all settings that were saved for a certain profile to a different one. false diff --git a/core/smb4kbasicnetworkitem.cpp b/core/smb4kbasicnetworkitem.cpp index 7589bc6..c532ddf 100644 --- a/core/smb4kbasicnetworkitem.cpp +++ b/core/smb4kbasicnetworkitem.cpp @@ -1,169 +1,189 @@ /*************************************************************************** This class provides the basic network item for the core library of Smb4K. ------------------- begin : Do Apr 2 2009 copyright : (C) 2009-2019 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 "smb4kbasicnetworkitem.h" // Qt includes #include #include using namespace Smb4KGlobal; class Smb4KBasicNetworkItemPrivate { public: NetworkItem type; QIcon icon; QUrl url; + bool dnsDiscovered; }; Smb4KBasicNetworkItem::Smb4KBasicNetworkItem(NetworkItem type) : d(new Smb4KBasicNetworkItemPrivate) { // // Set the type // d->type = type; + // + // Initialize the dnsDiscovered variable + // + d->dnsDiscovered = false; + // // Initialize the protected variables // pUrl = &d->url; pIcon = &d->icon; } Smb4KBasicNetworkItem::Smb4KBasicNetworkItem(const Smb4KBasicNetworkItem &item) : d(new Smb4KBasicNetworkItemPrivate) { // // Copy the private variables // *d = *item.d; // // Initialize the protected variables // pUrl = &d->url; pIcon = &d->icon; } Smb4KBasicNetworkItem::~Smb4KBasicNetworkItem() { } Smb4KGlobal::NetworkItem Smb4KBasicNetworkItem::type() const { return d->type; } void Smb4KBasicNetworkItem::setIcon(const QIcon &icon) { d->icon = icon; } QIcon Smb4KBasicNetworkItem::icon() const { return d->icon; } void Smb4KBasicNetworkItem::setUrl(const QUrl& url) { // // Check that the URL is valid // if (!url.isValid()) { return; } // // Do some checks depending on the type of the network item // switch (d->type) { case Network: { break; } case Workgroup: case Host: { // // Check that the host name is present and there is no path // if (url.host().isEmpty() || !url.path().isEmpty()) { return; } break; } case Share: { // // Check that the share name is present // if (url.path().isEmpty() || (url.path().size() == 1 && url.path().endsWith('/'))) { return; } break; } default: { break; } } // // Set the URL // d->url = url; // // Force the scheme // if (d->url.scheme() != "smb") { d->url.setScheme("smb"); } } QUrl Smb4KBasicNetworkItem::url() const { return d->url; } +void Smb4KBasicNetworkItem::setDnsDiscovered(bool discovered) +{ + d->dnsDiscovered = discovered; +} + + +bool Smb4KBasicNetworkItem::dnsDiscovered() const +{ + return d->dnsDiscovered; +} + + + + diff --git a/core/smb4kbasicnetworkitem.h b/core/smb4kbasicnetworkitem.h index e4a6d37..2438269 100644 --- a/core/smb4kbasicnetworkitem.h +++ b/core/smb4kbasicnetworkitem.h @@ -1,121 +1,138 @@ /*************************************************************************** This class provides the basic network item for the core library of Smb4K. ------------------- begin : Do Apr 2 2009 copyright : (C) 2009-2019 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 * ***************************************************************************/ #ifndef SMB4KBASICNETWORKITEM_H #define SMB4KBASICNETWORKITEM_H // application specific includes #include "smb4kglobal.h" // Qt includes #include #include #include #include // forward declarations class Smb4KBasicNetworkItemPrivate; /** * This is the basic class from which all other network item classes * are derived. * * @author Alexander Reinholdt * @since 1.0.0 */ class Q_DECL_EXPORT Smb4KBasicNetworkItem { public: /** * The constructor */ explicit Smb4KBasicNetworkItem(Smb4KGlobal::NetworkItem type = Smb4KGlobal::UnknownNetworkItem); /** * The copy constructor */ Smb4KBasicNetworkItem(const Smb4KBasicNetworkItem &item); /** * The destructor */ ~Smb4KBasicNetworkItem(); /** * This function returns the type of the basic network * item. * * @returns the type. */ Smb4KGlobal::NetworkItem type() const; /** * This function sets the icon of the network item. * * @param icon The icon */ void setIcon(const QIcon &icon); /** * This function returns the icon of the network item. By default, it * is the null icon. You must set the appropriate icon either in * a class that inherits this one or from somewhere else. * * @returns the network item's icon. */ QIcon icon() const; /** * Set the URL for this network item. * * @param url The URL */ void setUrl(const QUrl &url); /** * Return the URL for this network item. * * @returns the URL */ QUrl url() const; + /** + * Set @p discovered to TRUE if this network item was discovered using + * the DNS-SD service. + * + * @param discovered Set this to TRUE if the network item was discovered + * using the DNS-SD service + */ + void setDnsDiscovered(bool discovered); + + /** + * Return TRUE if the network item was discovered using the DNS-SD + * service and FALSE otherwise. + * + * @return TRUE if discovered by DNS-SD. + */ + bool dnsDiscovered() const; + protected: /** * Expose a pointer to the private URL variable. */ QUrl *pUrl; /** * Expose a pointer to the private icon variable. */ QIcon *pIcon; private: const QScopedPointer d; }; #endif diff --git a/core/smb4kclient.cpp b/core/smb4kclient.cpp index 4c5125c..7969368 100644 --- a/core/smb4kclient.cpp +++ b/core/smb4kclient.cpp @@ -1,1022 +1,1023 @@ /*************************************************************************** This class provides the interface to the libsmbclient library. ------------------- begin : Sa Oct 20 2018 - copyright : (C) 2018-2019 by Alexander Reinholdt + 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.h" #include "smb4kclient_p.h" #include "smb4khardwareinterface.h" #include "smb4ksettings.h" #include "smb4kcustomoptionsmanager.h" #include "smb4kcustomoptions.h" #include "smb4kbasicnetworkitem.h" #include "smb4kglobal.h" #include "smb4khomesshareshandler.h" #include "smb4kwalletmanager.h" #include "smb4knotification.h" // Qt includes #include #include #include #include using namespace Smb4KGlobal; Q_GLOBAL_STATIC(Smb4KClientStatic, p); Smb4KClient::Smb4KClient(QObject* parent) : KCompositeJob(parent), d(new Smb4KClientPrivate) { // // Connections // connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(slotAboutToQuit())); } Smb4KClient::~Smb4KClient() { } Smb4KClient *Smb4KClient::self() { return &p->instance; } void Smb4KClient::start() { connect(Smb4KHardwareInterface::self(), SIGNAL(networkSessionInitialized()), this, SLOT(slotStartJobs())); } bool Smb4KClient::isRunning() { return hasSubjobs(); } void Smb4KClient::abort() { QListIterator it(subjobs()); while (it.hasNext()) { it.next()->kill(KJob::EmitResult); } } void Smb4KClient::lookupDomains() { // // Send Wakeup-On-LAN packages // if (Smb4KSettings::enableWakeOnLAN()) { QList wakeOnLanEntries = Smb4KCustomOptionsManager::self()->wakeOnLanEntries(); if (!wakeOnLanEntries.isEmpty()) { NetworkItemPtr item = NetworkItemPtr(new Smb4KBasicNetworkItem()); emit aboutToStart(item, WakeUp); QUdpSocket *socket = new QUdpSocket(this); for (int i = 0; i < wakeOnLanEntries.size(); ++i) { if (wakeOnLanEntries.at(i)->wolSendBeforeNetworkScan()) { QHostAddress addr; if (wakeOnLanEntries.at(i)->hasIpAddress()) { addr.setAddress(wakeOnLanEntries.at(i)->ipAddress()); } else { addr.setAddress("255.255.255.255"); } // Construct magic sequence QByteArray sequence; // 6 times 0xFF for (int j = 0; j < 6; ++j) { sequence.append(QChar(0xFF).toLatin1()); } // 16 times the MAC address QStringList parts = wakeOnLanEntries.at(i)->macAddress().split(':', QString::SkipEmptyParts); for (int j = 0; j < 16; ++j) { for (int k = 0; k < parts.size(); ++k) { sequence.append(QChar(QString("0x%1").arg(parts.at(k)).toInt(0, 16)).toLatin1()); } } socket->writeDatagram(sequence, addr, 9); } } delete socket; // Wait the defined time int stop = 1000 * Smb4KSettings::wakeOnLANWaitingTime() / 250; int i = 0; while (i++ < stop) { QTest::qWait(250); } emit finished(item, WakeUp); item.clear(); } } // // Emit the aboutToStart() signal // NetworkItemPtr item = NetworkItemPtr(new Smb4KBasicNetworkItem(Network)); item->setUrl(QUrl("smb://")); emit aboutToStart(item, LookupDomains); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(item); job->setProcess(LookupDomains); // // Clear the pointer // item.clear(); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::lookupDomainMembers(const WorkgroupPtr &workgroup) { // // Emit the aboutToStart() signal // emit aboutToStart(workgroup, LookupDomainMembers); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(workgroup); job->setProcess(LookupDomainMembers); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::lookupShares(const HostPtr &host) { // // Emit the aboutToStart() signal // emit aboutToStart(host, LookupShares); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(host); job->setProcess(LookupShares); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::lookupFiles(const NetworkItemPtr &item) { // // Check that the network item has the correct type and process it. // if (item->type() == Share || item->type() == Directory) { // // Emit the aboutToStart() signal // emit aboutToStart(item, LookupFiles); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(item); job->setProcess(LookupFiles); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } } void Smb4KClient::printFile(const SharePtr& share, const KFileItem& fileItem, int copies) { // // Emit the aboutToStart() signal // emit aboutToStart(share, PrintFile); // // Create the job // Smb4KClientJob *job = new Smb4KClientJob(this); job->setNetworkItem(share); job->setPrintFileItem(fileItem); job->setPrintCopies(copies); job->setProcess(PrintFile); // // Set the busy cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::setOverrideCursor(Qt::BusyCursor); } // // Add the job to the subjobs // addSubjob(job); // // Start the job // job->start(); } void Smb4KClient::search(const QString& item) { // // Create empty basic network item // NetworkItemPtr networkItem = NetworkItemPtr(new Smb4KBasicNetworkItem()); // // Emit the aboutToStart() signal // emit aboutToStart(networkItem, NetworkSearch); // // Before doing the search, lookup all domains, servers and shares in the // network neighborhood. // lookupDomains(); while(isRunning()) { QTest::qWait(50); } for (const WorkgroupPtr &workgroup : workgroupsList()) { lookupDomainMembers(workgroup); while(isRunning()) { QTest::qWait(50); } } for (const HostPtr &host : hostsList()) { lookupShares(host); while(isRunning()) { QTest::qWait(50); } } // // Do the actual search // QList results; for (const SharePtr &share : sharesList()) { if (share->shareName().contains(item, Qt::CaseInsensitive)) { results << share; } } // // Emit the search results // emit searchResults(results); // // Emit the finished() signal // emit finished(networkItem, NetworkSearch); } void Smb4KClient::openPreviewDialog(const SharePtr &share) { // // Printer share check // if (share->isPrinter()) { return; } // // 'homes' share check // if (share->isHomesShare()) { Smb4KHomesSharesHandler::self()->specifyUser(share, true); } // // Start the preview dialog // // First, check if a preview dialog has already been set up for this share // and reuse it, if possible. // QPointer dlg = 0; for (Smb4KPreviewDialog *p : d->previewDialogs) { if (share == p->share()) { dlg = p; } } // // If there was no preview dialog present, create a new one // if (!dlg) { dlg = new Smb4KPreviewDialog(share, QApplication::activeWindow()); d->previewDialogs << dlg; // // Connections // connect(dlg, SIGNAL(requestPreview(NetworkItemPtr)), this, SLOT(slotStartNetworkQuery(NetworkItemPtr))); connect(dlg, SIGNAL(aboutToClose(Smb4KPreviewDialog*)), this, SLOT(slotPreviewDialogClosed(Smb4KPreviewDialog*))); connect(dlg, SIGNAL(requestAbort()), this, SLOT(slotAbort())); connect(this, SIGNAL(files(QList)), dlg, SLOT(slotPreviewResults(QList))); connect(this, SIGNAL(aboutToStart(NetworkItemPtr,int)), dlg, SLOT(slotAboutToStart(NetworkItemPtr,int))); connect(this, SIGNAL(finished(NetworkItemPtr,int)), dlg, SLOT(slotFinished(NetworkItemPtr,int))); } // // Show the preview dialog // if (!dlg->isVisible()) { dlg->setVisible(true); } } void Smb4KClient::openPrintDialog(const SharePtr& share) { // // Printer share check // if (!share->isPrinter()) { return; } // // Start the print dialog // // First, check if a print dialog has already been set up for this share // and reuse it, if possible. // QPointer dlg = 0; for (Smb4KPrintDialog *p : d->printDialogs) { if (share == p->share()) { dlg = p; } } // // If there was no print dialog present, create a new one // if (!dlg) { Smb4KWalletManager::self()->readAuthInfo(share); dlg = new Smb4KPrintDialog(share, QApplication::activeWindow()); d->printDialogs << dlg; connect(dlg, SIGNAL(printFile(SharePtr,KFileItem,int)), this, SLOT(slotStartPrinting(SharePtr,KFileItem,int))); connect(dlg, SIGNAL(aboutToClose(Smb4KPrintDialog*)), this, SLOT(slotPrintDialogClosed(Smb4KPrintDialog*))); } // // Show the preview dialog // if (!dlg->isVisible()) { dlg->setVisible(true); } } void Smb4KClient::processErrors(Smb4KClientJob *job) { switch (job->error()) { case Smb4KClientJob::AccessDeniedError: { switch (job->networkItem()->type()) { case Host: { if (Smb4KWalletManager::self()->showPasswordDialog(job->networkItem())) { lookupShares(job->networkItem().staticCast()); } break; } case Share: { if (Smb4KWalletManager::self()->showPasswordDialog(job->networkItem())) { if (job->process() == Smb4KGlobal::PrintFile) { printFile(job->networkItem().staticCast(), job->printFileItem(), job->printCopies()); } else { lookupFiles(job->networkItem().staticCast()); } } break; } case Directory: case File: { FilePtr file = job->networkItem().staticCast(); SharePtr share = SharePtr(new Smb4KShare()); share->setWorkgroupName(file->workgroupName()); share->setHostName(file->hostName()); share->setShareName(file->shareName()); share->setLogin(file->login()); share->setPassword(file->password()); if (Smb4KWalletManager::self()->showPasswordDialog(share)) { file->setLogin(share->login()); file->setPassword(share->password()); lookupFiles(file); } break; } default: { qDebug() << "Authentication error. URL:" << job->networkItem()->url(); break; } } break; } default: { Smb4KNotification::networkCommunicationFailed(job->errorText()); break; } } } void Smb4KClient::processWorkgroups(Smb4KClientJob *job) { // // Remove obsolete workgroups and their members // QListIterator wIt(workgroupsList()); while (wIt.hasNext()) { WorkgroupPtr workgroup = wIt.next(); bool found = false; for (const WorkgroupPtr &w : job->workgroups()) { if (w->workgroupName() == workgroup->workgroupName()) { found = true; break; } else { continue; } } if (!found) { QList obsoleteHosts = workgroupMembers(workgroup); QListIterator hIt(obsoleteHosts); while (hIt.hasNext()) { removeHost(hIt.next()); } removeWorkgroup(workgroup); } } // // Add new workgroups and update existing ones. // for (const WorkgroupPtr &workgroup : job->workgroups()) { if (!findWorkgroup(workgroup->workgroupName())) { addWorkgroup(workgroup); // Since this is a new workgroup, no master browser is present. HostPtr masterBrowser = HostPtr(new Smb4KHost()); masterBrowser->setWorkgroupName(workgroup->workgroupName()); masterBrowser->setHostName(workgroup->masterBrowserName()); masterBrowser->setIpAddress(workgroup->masterBrowserIpAddress()); masterBrowser->setIsMasterBrowser(true); addHost(masterBrowser); } else { updateWorkgroup(workgroup); // Check if the master browser changed QList members = workgroupMembers(workgroup); for (const HostPtr &host : members) { if (workgroup->masterBrowserName() == host->hostName()) { host->setIsMasterBrowser(true); if (!host->hasIpAddress() && workgroup->hasMasterBrowserIpAddress()) { host->setIpAddress(workgroup->masterBrowserIpAddress()); } } else { host->setIsMasterBrowser(false); } } } } emit workgroups(); } void Smb4KClient::processHosts(Smb4KClientJob *job) { // // Get the workgroup pointer // WorkgroupPtr workgroup = job->networkItem().staticCast(); // // Remove obsolete workgroup members // QList members = workgroupMembers(workgroup); QListIterator hIt(members); while (hIt.hasNext()) { HostPtr host = hIt.next(); bool found = false; for (const HostPtr &h : job->hosts()) { if (h->workgroupName() == host->workgroupName() && h->hostName() == host->hostName()) { found = true; break; } else { continue; } } if (!found) { QList obsoleteShares = sharedResources(host); QListIterator sIt(obsoleteShares); while (sIt.hasNext()) { removeShare(sIt.next()); } removeHost(host); } } // // Add new hosts and update existing ones // for (const HostPtr &host : job->hosts()) { if (host->hostName() == workgroup->masterBrowserName()) { host->setIsMasterBrowser(true); } else { host->setIsMasterBrowser(false); } if (!findHost(host->hostName(), host->workgroupName())) { addHost(host); } else { updateHost(host); } } emit hosts(workgroup); } void Smb4KClient::processShares(Smb4KClientJob *job) { // // Get the host pointer // HostPtr host = job->networkItem().staticCast(); // // Remove obsolete shares // QList sharedRes = sharedResources(host); QListIterator sIt(sharedRes); while (sIt.hasNext()) { SharePtr share = sIt.next(); bool found = false; for (const SharePtr &s : job->shares()) { if (s->workgroupName() == share->workgroupName() && s->url().matches(share->url(), QUrl::RemoveUserInfo|QUrl::RemovePort)) { found = true; break; } else { continue; } } if (!found || (share->isHidden() && !Smb4KSettings::detectHiddenShares()) || (share->isPrinter() && !Smb4KSettings::detectPrinterShares())) { removeShare(share); } } // // Add new shares and update existing ones // for (const SharePtr &share : job->shares()) { // // Process only those shares that the user wants to see // if (share->isHidden() && !Smb4KSettings::detectHiddenShares()) { continue; } if (share->isPrinter() && !Smb4KSettings::detectPrinterShares()) { continue; } // // Add or update the shares // if (!findShare(share->url(), share->workgroupName())) { addShare(share); } else { updateShare(share); } } emit shares(host); } void Smb4KClient::processFiles(Smb4KClientJob *job) { QList list; for (const FilePtr &f : job->files()) { if (f->isHidden() && !Smb4KSettings::previewHiddenItems()) { continue; } list << f; } emit files(list); } void Smb4KClient::slotStartJobs() { // // Disconnect from Smb4KHardwareInterface // disconnect(Smb4KHardwareInterface::self(), SIGNAL(networkSessionInitialized()), this, SLOT(slotStartJobs())); // // Lookup domains as the first step // if (Smb4KHardwareInterface::self()->isOnline()) { lookupDomains(); } } void Smb4KClient::slotResult(KJob *job) { // // Get the client job // Smb4KClientJob *clientJob = qobject_cast(job); // // Define a network item pointer and the process value for the // finished() signal. // NetworkItemPtr item = clientJob->networkItem(); Smb4KGlobal::Process process = clientJob->process(); // // Get the result from the query and process it // if (clientJob) { if (clientJob->error() == 0) { switch (clientJob->networkItem()->type()) { case Network: { // Process the discovered workgroups processWorkgroups(clientJob); break; } case Workgroup: { + qDebug() << "Processing the hosts ..."; // Process the discovered workgroup members processHosts(clientJob); break; } case Host: { // Process the discovered shares processShares(clientJob); break; } case Share: case Directory: { // Process the discoveres files and directories processFiles(clientJob); break; } default: { break; } } } else { processErrors(clientJob); } } // // Remove the job // removeSubjob(job); // // Emit the finished signal // emit finished(item, process); // // Clear the network item pointer // item.clear(); // // Restore the cursor // if (!hasSubjobs() && modifyCursor()) { QApplication::restoreOverrideCursor(); } } void Smb4KClient::slotAboutToQuit() { abort(); } void Smb4KClient::slotStartNetworkQuery(NetworkItemPtr item) { // // Look up files // lookupFiles(item); } void Smb4KClient::slotPreviewDialogClosed(Smb4KPreviewDialog *dialog) { // // Remove the preview dialog from the list // if (dialog) { // Find the dialog in the list and take it from the list. // It will automatically be deleted on close, so there is // no need to delete the dialog here. int i = d->previewDialogs.indexOf(dialog); d->previewDialogs.takeAt(i); } } void Smb4KClient::slotAbort() { abort(); } void Smb4KClient::slotStartPrinting(const SharePtr& printer, const KFileItem& fileItem, int copies) { // // Start printing // printFile(printer, fileItem, copies); } void Smb4KClient::slotPrintDialogClosed(Smb4KPrintDialog* dialog) { // // Remove the print dialog from the list // if (dialog) { // Find the dialog in the list and take it from the list. // It will automatically be deleted on close, so there is // no need to delete the dialog here. int i = d->printDialogs.indexOf(dialog); d->printDialogs.takeAt(i); } } diff --git a/core/smb4kclient.h b/core/smb4kclient.h index dbbae98..48d845c 100644 --- a/core/smb4kclient.h +++ b/core/smb4kclient.h @@ -1,279 +1,279 @@ /*************************************************************************** This class provides the interface to the libsmbclient library. ------------------- begin : Sa Oct 20 2018 - copyright : (C) 2018-2019 by Alexander Reinholdt + 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 * ***************************************************************************/ #ifndef SMB4KCLIENT_H #define SMB4KCLIENT_H // application specific includes #include "smb4kglobal.h" // Qt includes #include // KDE includes #include #include // forward declarations class Smb4KClientPrivate; class Smb4KBasicNetworkItem; class Smb4KClientJob; class Smb4KPreviewDialog; class Smb4KPrintDialog; class Q_DECL_EXPORT Smb4KClient : public KCompositeJob { Q_OBJECT public: /** * The constructor */ explicit Smb4KClient(QObject *parent = 0); /** * The destructor */ ~Smb4KClient(); /** * This function returns a static pointer to this class. * * @returns a static pointer to the Smb4KClient class. */ static Smb4KClient *self(); /** * This function starts the composite job */ void start() override; /** * Returns TRUE, if jobs are running and FALSE otherwise * * @returns TRUE if jobs are running */ bool isRunning(); /** * Aborts all subjobs */ void abort(); /** * This function starts the scan for all available workgroups and domains * on the network neighborhood. */ void lookupDomains(); /** * This function looks up all hosts in a certain domain or workgroup. * * @param workgroup The workgroup object */ void lookupDomainMembers(const WorkgroupPtr &workgroup); /** * This function looks up all shared resources a certain @p host provides. * * @param host The host object */ void lookupShares(const HostPtr &host); /** * This function looks up all files and directories present at the location * @p item points to. The network item must be of type Smb4KGlobal::Share or * Smb4KGlobal::Directory. * * @param item The network item object */ void lookupFiles(const NetworkItemPtr &item); /** * This function starts the printing of a file @p file to the printer share * @p printer. * * @param share The printer share * * @param fileItem The file item * * @param copies Number of copies */ void printFile(const SharePtr &share, const KFileItem &fileItem, int copies); /** * Perform a search on the entire network neighborhood * * @param item The search item */ void search(const QString &item); /** * This function opens the preview dialog for @p share. * * @param share The share object */ void openPreviewDialog(const SharePtr &share); /** * This function opens the print dialog for @p share. * * @param share The share object (printer only) */ void openPrintDialog(const SharePtr &share); Q_SIGNALS: /** * This signal is emitted when the client starts its work. * * @param item The network item * @param type The type of work */ void aboutToStart(const NetworkItemPtr &item, int type); /** * This signal is emitted when the client finished its work. * * @param item The network item * @param type The type of work */ void finished(const NetworkItemPtr &item, int type); /** * Emitted when the requested list of workgroups was acquired */ void workgroups(); /** * Emitted when the requested list of workgroup members was acquired * * @param workgroup The workgroup that was queried */ void hosts(const WorkgroupPtr &workgroup); /** * Emitted when the requested list of shares was acquired * * @param host The host that was queried */ void shares(const HostPtr &host); /** * Emitted when the requested list of files and directories was acquired * * @param list The list of files and directories */ void files(const QList &list); /** * Emitted when a search was done * * @param list The list of search results */ void searchResults(const QList &list); protected Q_SLOTS: /** * Start the composite job */ void slotStartJobs(); /** * Called when a job finished. Reimplemented from KCompositeJob. */ void slotResult(KJob *job) override; /** * Called when the application is about to be closed */ void slotAboutToQuit(); /** * Start a network query */ void slotStartNetworkQuery(NetworkItemPtr item); /** * Called when a preview dialog closed */ void slotPreviewDialogClosed(Smb4KPreviewDialog *dialog); /** * Called when a process should be aborted */ void slotAbort(); /** * Called when a file is about to be printed */ void slotStartPrinting(const SharePtr &printer, const KFileItem &fileItem, int copies); /** * Called when a print dialog closed */ void slotPrintDialogClosed(Smb4KPrintDialog *dialog); private: /** * Process errors */ void processErrors(Smb4KClientJob *job); /** * Process the domains/workgroups retrieved from the network * * @param job The client job */ void processWorkgroups(Smb4KClientJob *job); /** * Process the domain/workgroup members * * @param job The client job */ void processHosts(Smb4KClientJob *job); /** * Process the shares * * @param job The client job */ void processShares(Smb4KClientJob *job); /** * Process the files and directories * * @param job The client job */ void processFiles(Smb4KClientJob *job); /** * Pointer to the Smb4KClientPrivate class */ QScopedPointer d; }; #endif diff --git a/core/smb4kclient_p.cpp b/core/smb4kclient_p.cpp index 5017523..bf3fcef 100644 --- a/core/smb4kclient_p.cpp +++ b/core/smb4kclient_p.cpp @@ -1,2053 +1,2289 @@ /*************************************************************************** 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 +#include // KDE includes #include #include #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(); } + + // + // Delete the context + // + if (!m_context) + { + qDebug() << "Delete the context"; + delete m_context; + } } 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() +void Smb4KClientJob::initClientLibrary() { // - // Get the function to open the directory + // Allocate new context // - smbc_opendir_fn openDirectory = smbc_getFunctionOpendir(m_context); + m_context = smbc_new_context(); - if (!openDirectory) + if (!m_context) { int errorCode = errno; setError(ClientError); setErrorText(strerror(errorCode)); - + emitResult(); return; } // - // Open the directory + // Get the custom options // - SMBCFILE *directory = openDirectory(m_context, m_item->url().toString().toUtf8().data()); + OptionsPtr options = Smb4KCustomOptionsManager::self()->findOptions(m_item); - if (!directory) + // + // Set debug level + // + smbc_setDebug(m_context, SMBC_DEBUG); + + // + // Set the NetBIOS name and the workgroup to make connections + // + switch (m_item->type()) { - int errorCode = errno; - - switch (errorCode) + case Network: { - case EACCES: + // + // We do not know about the servers and the domains/workgroups + // present. So, do not set anything and use the default. + // + break; + } + case Workgroup: + { + // + // In case this domain/workgroup was discovered by the DNS-SD service, there is + // no master browser and the workgroup/domain might not be identical with the one + // defined in the network neighborhood. Thus, only set the NetBIOS name and the + // workgroup if no DNS-SD discovery was used. + // + if (!m_item->dnsDiscovered()) { - setError(AccessDeniedError); - setErrorText(strerror(errorCode)); + WorkgroupPtr workgroup = m_item.staticCast(); + smbc_setNetbiosName(m_context, workgroup->masterBrowserName().toUtf8().data()); + smbc_setWorkgroup(m_context, workgroup->workgroupName().toUtf8().data()); + } + + break; + } + case Host: + { + // + // In case the domain/workgroup was discovered by the DNS-SD service, the + // workgroup/domain might not be identical with the one defined in the network + // neighborhood. Thus, only set the workgroup if no DNS-SD discovery was used. + // + HostPtr host = m_item.staticCast(); + WorkgroupPtr workgroup = findWorkgroup(host->workgroupName()); + + if (!workgroup->dnsDiscovered()) + { + smbc_setWorkgroup(m_context, host->workgroupName().toUtf8().data()); + } + + smbc_setNetbiosName(m_context, host->hostName().toUtf8().data()); + + break; + } + case Share: + { + // + // In case the domain/workgroup was discovered by the DNS-SD service, the + // workgroup/domain might not be identical with the one defined in the network + // neighborhood. Thus, only set the workgroup if no DNS-SD discovery was used. + // + SharePtr share = m_item.staticCast(); + WorkgroupPtr workgroup = findWorkgroup(share->workgroupName()); + + if (!workgroup->dnsDiscovered()) + { + smbc_setWorkgroup(m_context, share->workgroupName().toUtf8().data()); + } + + smbc_setNetbiosName(m_context, share->hostName().toUtf8().data()); + + break; + } + case Directory: + { + // + // In case the domain/workgroup was discovered by the DNS-SD service, the + // workgroup/domain might not be identical with the one defined in the network + // neighborhood. Thus, only set the workgroup if no DNS-SD discovery was used. + // + FilePtr file = m_item.staticCast(); + WorkgroupPtr workgroup = findWorkgroup(file->workgroupName()); + + if (!workgroup->dnsDiscovered()) + { + smbc_setWorkgroup(m_context, file->workgroupName().toUtf8().data()); + } + + smbc_setNetbiosName(m_context, file->hostName().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 ENOENT: + case Smb4KSettings::EnumEncryptionLevel::Request: { - if (m_item->type() != Network) - { - setError(ClientError); - setErrorText(strerror(errorCode)); - } + smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUEST); + break; + } + case Smb4KSettings::EnumEncryptionLevel::Require: + { + smbc_setOptionSmbEncryptionLevel(m_context, SMBC_ENCRYPTLEVEL_REQUIRE); break; } default: { - setError(ClientError); - setErrorText(strerror(errorCode)); break; } } - - emitResult(); + } + + // + // 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, 1); + + emitResult(); + return; + } +} + + +void Smb4KClientJob::doLookups() +{ + // + // Set the new context + // + (void)smbc_set_context(m_context); + + // + // 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)); + return; + } + + // + // Open the directory + // + // If we use DNS-SD, the workgroup/domain name will most likely be unknown + // for Samba and the followin function fails. Since we do not want the lookup + // to stop here in that case, do not throw an error when using DNS-SD and + // Network and Workgroup (parent) items. + // + SMBCFILE *directory = openDirectory(m_context, m_item->url().toString().toUtf8().data()); + + if (!directory) + { + if (!Smb4KSettings::useDnsServiceDiscovery() && !(m_item->type() == Network || m_item->type() == Workgroup)) + { + int errorCode = errno; + + switch (errorCode) + { + case EACCES: + { + setError(AccessDeniedError); + setErrorText(strerror(errorCode)); + break; + } + case ENOENT: + { + if (m_item->type() != Network) + { + setError(ClientError); + setErrorText(strerror(errorCode)); + } + break; + } + default: + { + setError(ClientError); + setErrorText(strerror(errorCode)); + break; + } + } + } + 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); + + // + // Free the context + // + smbc_free_context(m_context, 1); +} + + +void Smb4KClientJob::doDnsDiscovery() +{ + // + // Set up the DNS-SD browser + // + KDNSSD::ServiceBrowser serviceBrowser(QStringLiteral("_smb._tcp")); + + // + // This code is inspired by the DNS-SD discoverer of the SMB + // kio slave + // + bool browsingFinished = false; + + connect(&serviceBrowser, &KDNSSD::ServiceBrowser::serviceAdded, + this, [&] (KDNSSD::RemoteService::Ptr service) { + switch (m_process) + { + case LookupDomains: + { + // + // Check if the workgroup/domain is already known + // + bool foundWorkgroup = false; + + for (const WorkgroupPtr &w : qAsConst(m_workgroups)) + { + if (QString::compare(w->workgroupName(), service->domain(), Qt::CaseInsensitive) == 0) + { + foundWorkgroup = true; + break; + } + } + + // + // If the workgroup is not known yet, add it to the list + // + if (!foundWorkgroup) + { + // + // Create the workgroup item + // + WorkgroupPtr workgroup = WorkgroupPtr(new Smb4KWorkgroup()); + + // + // Set the _DNS-SD_ domain name + // + workgroup->setWorkgroupName(service->domain()); + + // + // Tell the program that the workgroup was discovered by DNS-SD + // + workgroup->setDnsDiscovered(true); + + // + // Add the workgroup + // + m_workgroups << workgroup; + } + break; + } + case LookupDomainMembers: + { + // + // Check if the server is already known + // + bool foundServer = false; + + for (const HostPtr &h : qAsConst(m_hosts)) + { + if (QString::compare(h->hostName(), service->serviceName(), Qt::CaseInsensitive) == 0 && + QString::compare(h->workgroupName(), service->domain(), Qt::CaseInsensitive) == 0) + { + foundServer = true; + break; + } + } + + // + // If the server is not known yet, add it to the list + // + if (!foundServer) + { + // + // Create the host item + // + HostPtr host = HostPtr(new Smb4KHost()); + + // + // Set the _DNS-SD_ host name + // + host->setHostName(service->serviceName()); + + // + // Set the _DNS-SD_ domain name + // + host->setWorkgroupName(service->domain()); + + // + // Tell the program that the workgroup was discovered by DNS-SD + // + host->setDnsDiscovered(true); + + // + // Lookup IP address + // + QHostAddress address = lookupIpAddress(service->serviceName()); + + // + // Process the IP address. + // + if (!address.isNull()) + { + host->setIpAddress(address); + } + + // + // Add the host + // + m_hosts << host; + } + + break; + } + default: + { + break; + } + } + }); + + connect(&serviceBrowser, &KDNSSD::ServiceBrowser::finished, + this, [&] () { + browsingFinished = true; + serviceBrowser.disconnect(); + }); + + serviceBrowser.startBrowse(); + + // + // Wait until the browsing finished + // + while (!browsingFinished) + { + QTest::qWait(50); + } } void Smb4KClientJob::doPrinting() { + // + // Set the new context + // + (void)smbc_set_context(m_context); + // // 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); + + // + // Free the context + // + smbc_free_context(m_context, 1); } 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 + // Initialize the client library // - smbc_setDebug(m_context, SMBC_DEBUG); + initClientLibrary(); // - // Set the NetBIOS name and the workgroup to make connections + // Process the given URL according to the passed process // - switch (m_item->type()) + switch (m_process) { - 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: + case LookupDomains: + case LookupDomainMembers: { // - // Set both the NetBIOS name of the server and the workgroup to be queried + // Do lookups using the client library // - SharePtr share = m_item.staticCast(); - smbc_setNetbiosName(m_context, share->hostName().toUtf8().data()); - smbc_setWorkgroup(m_context, share->workgroupName().toUtf8().data()); - break; - } - case Directory: - { + doLookups(); + // - // Set both the NetBIOS name of the server and the workgroup to be queried + // Do lookups using DNS service discovery // - 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: + if (Smb4KSettings::useDnsServiceDiscovery()) { - break; + doDnsDiscovery(); } + + 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: { + // + // Do lookups using the client library + // doLookups(); break; } case PrintFile: { + // + // Print files using the client library + // 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(); } diff --git a/core/smb4kclient_p.h b/core/smb4kclient_p.h index 46599d6..678b2935 100644 --- a/core/smb4kclient_p.h +++ b/core/smb4kclient_p.h @@ -1,357 +1,359 @@ /*************************************************************************** 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 * ***************************************************************************/ #ifndef SMB4KCLIENT_P_H #define SMB4KCLIENT_P_H // application specific includes #include "smb4kclient.h" #include "smb4kglobal.h" #include "smb4kworkgroup.h" #include "smb4khost.h" #include "smb4kshare.h" #include "smb4kfile.h" // Samba includes #include // Qt includes #include #include #include #include // KDE includes #include #include class Smb4KClientJob : public KJob { Q_OBJECT public: /** * Constructor */ explicit Smb4KClientJob(QObject *parent = 0); /** * Destructor */ ~Smb4KClientJob(); /** * Error enumeration * * @enum ClientError The client failed * @enum AccessDeniedError Permission denied * @enum FileAccessError The file could not be read * @enum PrintFileError The file could not be printed */ enum { ClientError = UserDefinedError, AccessDeniedError, FileAccessError, PrintFileError }; /** * Starts the job. */ void start() override; /** * Set the basic network item */ void setNetworkItem(NetworkItemPtr item); /** * Return the basic network item */ NetworkItemPtr networkItem() const; /** * Set the process */ void setProcess(Smb4KGlobal::Process process); /** * Return the process */ Smb4KGlobal::Process process() const; /** * Set the file that is to be printed */ void setPrintFileItem(const KFileItem &item); /** * Get the file that is to be printed */ KFileItem printFileItem() const; /** * Set the number of copies that are to be printed */ void setPrintCopies(int copies); /** * Get the number of copies that are to be printed */ int printCopies() const; /** * The authentication function for libsmbclient */ void get_auth_data_fn(const char *server, const char *share, char *workgroup, int maxLenWorkgroup, char *username, int maxLenUsername, char *password, int maxLenPassword); /** * The list of workgroups that was discovered. */ QList workgroups(); /** * The list of hosts that was discovered. */ QList hosts(); /** * The list shares that was discovered. */ QList shares(); /** * The ist of files and directories that were discovered. */ QList files(); /** * The workgroup */ QString workgroup(); protected Q_SLOTS: void slotStartJob(); private: + void initClientLibrary(); void doLookups(); + void doDnsDiscovery(); void doPrinting(); QHostAddress lookupIpAddress(const QString &name); Smb4KGlobal::Process m_process; SMBCCTX *m_context; NetworkItemPtr m_item; QList m_workgroups; QList m_hosts; QList m_shares; QList m_files; KFileItem m_fileItem; int m_copies; }; class Smb4KPreviewDialog : public QDialog { Q_OBJECT public: /** * Constructor */ Smb4KPreviewDialog(const SharePtr &share, QWidget *parent = 0); /** * Destructor */ ~Smb4KPreviewDialog(); /** * Returns the share that is previewed * * @returns the share */ SharePtr share() const; Q_SIGNALS: /** * Request a preview */ void requestPreview(NetworkItemPtr item); /** * Emitted when the dialog is about to close. */ void aboutToClose(Smb4KPreviewDialog *dialog); /** * Emitted when the process should be aborted */ void requestAbort(); protected Q_SLOTS: /** * Do last things before the dialog is closed */ void slotClosingDialog(); /** * Reload */ void slotReloadActionTriggered(); /** * Go up */ void slotUpActionTriggered(); /** * An URL was activated in the combo box * * @param url The activated URL */ void slotUrlActivated(const QUrl &url); /** * Process the selected item * * @param item The activated item */ void slotItemActivated(QListWidgetItem *item); /** * Initialize the preview */ void slotInitializePreview(); /** * Get the preview results and process them * * @param list The list of the preview results */ void slotPreviewResults(const QList &list); /** * Change the reload/abort dual action */ void slotAboutToStart(const NetworkItemPtr &item, int type); /** * Change the reload/abort dual action back */ void slotFinished(const NetworkItemPtr &item, int type); private: SharePtr m_share; NetworkItemPtr m_currentItem; QList m_listing; }; class Smb4KPrintDialog : public QDialog { Q_OBJECT public: /** * Constructor */ Smb4KPrintDialog(const SharePtr &share, QWidget *parent = 0); /** * Destructor */ ~Smb4KPrintDialog(); /** * Returns the share that is printed to * * @returns the share */ SharePtr share() const; /** * Returns the file item that is to be printed * * @returns the file */ KFileItem fileItem() const; Q_SIGNALS: /** * Emitted when a file is to be printed */ void printFile(const SharePtr &printer, const KFileItem &file, int copies); /** * Emitted when the dialog is about to close */ void aboutToClose(Smb4KPrintDialog *dialog); protected Q_SLOTS: /** * Print button was clicked */ void slotPrintButtonClicked(); /** * Cancel button clicked */ void slotCancelButtonClicked(); /** * Called when the URL was changed */ void slotUrlChanged(); private: SharePtr m_share; KFileItem m_fileItem; }; class Smb4KClientPrivate { public: QList previewDialogs; QList printDialogs; }; class Smb4KClientStatic { public: Smb4KClient instance; }; #endif diff --git a/core/smb4kworkgroup.cpp b/core/smb4kworkgroup.cpp index 0824f0c..9df489d 100644 --- a/core/smb4kworkgroup.cpp +++ b/core/smb4kworkgroup.cpp @@ -1,166 +1,172 @@ /*************************************************************************** Smb4K's container class for information about a workgroup. ------------------- begin : Sa Jan 26 2008 copyright : (C) 2008-2017 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 "smb4kworkgroup.h" #include "smb4kglobal.h" // Qt includes #include #include // KDE includes #include using namespace Smb4KGlobal; class Smb4KWorkgroupPrivate { public: QUrl masterURL; QHostAddress masterIP; }; Smb4KWorkgroup::Smb4KWorkgroup(const QString &name) : Smb4KBasicNetworkItem(Workgroup), d(new Smb4KWorkgroupPrivate) { // // Set the URL of the workgroup // pUrl->setScheme("smb"); pUrl->setHost(name); // // Set the icon // *pIcon = KDE::icon("network-workgroup"); } Smb4KWorkgroup::Smb4KWorkgroup(const Smb4KWorkgroup &w) : Smb4KBasicNetworkItem(Workgroup), d(new Smb4KWorkgroupPrivate) { // Copy the private variables // *d = *w.d; // // Set the icon if necessary // if (pIcon->isNull()) { *pIcon = KDE::icon("network-workgroup"); } } Smb4KWorkgroup::Smb4KWorkgroup() : Smb4KBasicNetworkItem(Workgroup), d(new Smb4KWorkgroupPrivate) { // // Set the URL // pUrl->setScheme("smb"); // // Set the icon // *pIcon = KDE::icon("network-workgroup"); } Smb4KWorkgroup::~Smb4KWorkgroup() { } void Smb4KWorkgroup::setWorkgroupName(const QString &name) { pUrl->setHost(name); pUrl->setScheme("smb"); } QString Smb4KWorkgroup::workgroupName() const { return pUrl->host().toUpper(); } void Smb4KWorkgroup::setMasterBrowserName(const QString &name) { d->masterURL.setHost(name); d->masterURL.setScheme("smb"); } QString Smb4KWorkgroup::masterBrowserName() const { return d->masterURL.host().toUpper(); } +bool Smb4KWorkgroup::hasMasterBrowser() const +{ + return !d->masterURL.host().isEmpty(); +} + + void Smb4KWorkgroup::setMasterBrowserIpAddress(const QString &ip) { d->masterIP.setAddress(ip); } void Smb4KWorkgroup::setMasterBrowserIpAddress(const QHostAddress& address) { if (!address.isNull() && address.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol) { d->masterIP = address; } } QString Smb4KWorkgroup::masterBrowserIpAddress() const { return d->masterIP.toString(); } bool Smb4KWorkgroup::hasMasterBrowserIpAddress() const { return !d->masterIP.isNull(); } void Smb4KWorkgroup::update(Smb4KWorkgroup* workgroup) { if (QString::compare(workgroupName(), workgroup->workgroupName()) == 0) { setMasterBrowserName(workgroup->masterBrowserName()); setMasterBrowserIpAddress(workgroup->masterBrowserIpAddress()); } } diff --git a/core/smb4kworkgroup.h b/core/smb4kworkgroup.h index 57be993..407f5a0 100644 --- a/core/smb4kworkgroup.h +++ b/core/smb4kworkgroup.h @@ -1,155 +1,163 @@ /*************************************************************************** Smb4K's container class for information about a workgroup. ------------------- begin : Sa Jan 26 2008 copyright : (C) 2008-2017 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 * ***************************************************************************/ #ifndef SMB4KWORKGROUP_H #define SMB4KWORKGROUP_H // application specific includes #include "smb4kbasicnetworkitem.h" // Qt includes #include #include #include // forward declarations class Smb4KWorkgroupPrivate; /** * This class is a container that carries information about a workgroup or * domain found in the network neighborhood. It is part of the core classes * of Smb4K. * * @author Alexander Reinholdt */ class Q_DECL_EXPORT Smb4KWorkgroup : public Smb4KBasicNetworkItem { friend class Smb4KWorkgroupPrivate; public: /** * The default constructor. It takes the name of the workgroup as only * argument. You have to set all other information by the other functions * provided by this class. * * @param name The name of the workgroup or domain. */ explicit Smb4KWorkgroup(const QString &name); /** * The copy constructor. This constructor takes another Smb4KWorkgroup item * as argument and copies its values. * * @param workgroup The Smb4KWorkgroup item that is to be copied. */ Smb4KWorkgroup(const Smb4KWorkgroup &workgroup); /** * The empty constructor. It does not take any argument and you have to * set all information by the other functions provided by this class. */ Smb4KWorkgroup(); /** * The destructor. */ ~Smb4KWorkgroup(); /** * Sets the name of the workgroup. * * @param name The name of the workgroup */ void setWorkgroupName(const QString &name); /** * This function returns the name of the workgroup. * * @returns the workgroup name. */ QString workgroupName() const; /** * Sets the name of the master browser of this workgroup or domain. * * @param masterName The name of the master browser */ void setMasterBrowserName(const QString &name); /** * Returns the name of the master browser of this workgroup or domain. * * @returns the name of the master browser. */ QString masterBrowserName() const; + + /** + * Returns TRUE if there is a master browser and FALSE otherwise. No master + * browser might be defined, if the DNS-SD method is used. + * + * @returns TRUE if there is a master browser. + */ + bool hasMasterBrowser() const; /** * Set the IP address of the master browser. @p ip will only be accepted * if it is compatible with either IPv4 or IPv6. * * @param ip The master browser's IP address */ void setMasterBrowserIpAddress(const QString &ip); /** * Set the IP address of the master browser. @p address will only be accepted * if it is compatible with either IPv4 or IPv6. * * @param address The master browser's IP address */ void setMasterBrowserIpAddress(const QHostAddress &address); /** * Returns the IP address of the master browser of this workgroup * or domain. If the IP address was not compatible with IPv4 and * IPv6 or if no IP address was supplied, an empty string is returned. * * @returns the IP address of the master browser or an empty string. */ QString masterBrowserIpAddress() const; /** * Returns TRUE if the workgroup/domain master browsers IP address is set and * FALSE otherwise. * * @returns TRUE if the master browsers IP address is known. */ bool hasMasterBrowserIpAddress() const; /** * Updates the workgroup item if the workgroup name of @p workgroup and * of this item is equal. Otherwise it does nothing. * @param workgroup The workgroup object that is used to update * this object */ void update(Smb4KWorkgroup *workgroup); private: const QScopedPointer d; }; #endif diff --git a/smb4k/smb4kconfigpagenetwork.cpp b/smb4k/smb4kconfigpagenetwork.cpp index 3642f3b..42385a4 100644 --- a/smb4k/smb4kconfigpagenetwork.cpp +++ b/smb4k/smb4kconfigpagenetwork.cpp @@ -1,242 +1,245 @@ /*************************************************************************** smb4knetworkoptions - The configuration page for the network settings of Smb4K ------------------- begin : Sa Nov 15 2003 copyright : (C) 2003-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 "smb4kconfigpagenetwork.h" #include "core/smb4ksettings.h" // Qt includes #include #include #include #include #include #include // KDE includes #include #include #include #include Smb4KConfigPageNetwork::Smb4KConfigPageNetwork(QWidget *parent) : QTabWidget(parent) { // // Basic Samba Settings // - QWidget *commonSambaTab = new QWidget(this); - QVBoxLayout *commonSambaTabLayout = new QVBoxLayout(commonSambaTab); + QWidget *commonTab = new QWidget(this); + QVBoxLayout *commonTabLayout = new QVBoxLayout(commonTab); + + // + // Browse Settings group box + // + QGroupBox *browseSettingsBox = new QGroupBox(i18n("Browse Settings"), commonTab); + QVBoxLayout *browseSettingsBoxLayout = new QVBoxLayout(browseSettingsBox); + + QCheckBox *useDnsServiceDiscovery = new QCheckBox(Smb4KSettings::self()->useDnsServiceDiscoveryItem()->label(), browseSettingsBox); + useDnsServiceDiscovery->setObjectName("kcfg_UseDnsServiceDiscovery"); + + QCheckBox *forceSmb1Protocol = new QCheckBox(Smb4KSettings::self()->forceSmb1ProtocolItem()->label(), browseSettingsBox); + forceSmb1Protocol->setObjectName("kcfg_ForceSmb1Protocol"); + + browseSettingsBoxLayout->addWidget(useDnsServiceDiscovery, 0); + browseSettingsBoxLayout->addWidget(forceSmb1Protocol, 0); // // Basic Settings group box // - QGroupBox *basicSettingsBox = new QGroupBox(i18n("Basic Settings"), commonSambaTab); + QGroupBox *basicSettingsBox = new QGroupBox(i18n("Basic Samba Settings"), commonTab); QGridLayout *basicSettingsBoxLayout = new QGridLayout(basicSettingsBox); QLabel *nebiosNameLabel = new QLabel(Smb4KSettings::self()->netBIOSNameItem()->label(), basicSettingsBox); KLineEdit *netbiosName = new KLineEdit(basicSettingsBox); netbiosName->setObjectName("kcfg_NetBIOSName"); netbiosName->setClearButtonEnabled(true); nebiosNameLabel->setBuddy(netbiosName); QLabel *domainLabel = new QLabel(Smb4KSettings::self()->domainNameItem()->label(), basicSettingsBox); KLineEdit *domain = new KLineEdit(basicSettingsBox); domain->setObjectName("kcfg_DomainName"); domain->setClearButtonEnabled(true); domainLabel->setBuddy(domain); QCheckBox *useRemoteSmbPort = new QCheckBox(Smb4KSettings::self()->useRemoteSmbPortItem()->label(), basicSettingsBox); useRemoteSmbPort->setObjectName("kcfg_UseRemoteSmbPort"); QSpinBox *remoteSmbPort = new QSpinBox(basicSettingsBox); remoteSmbPort->setObjectName("kcfg_RemoteSmbPort"); // remoteSmbPort->setSliderEnabled(true); QCheckBox *largeNetworkNeighborhood = new QCheckBox(Smb4KSettings::self()->largeNetworkNeighborhoodItem()->label(), basicSettingsBox); largeNetworkNeighborhood->setObjectName("kcfg_LargeNetworkNeighborhood"); basicSettingsBoxLayout->addWidget(nebiosNameLabel, 0, 0, 0); basicSettingsBoxLayout->addWidget(netbiosName, 0, 1, 0); basicSettingsBoxLayout->addWidget(domainLabel, 1, 0, 0); basicSettingsBoxLayout->addWidget(domain, 1, 1, 0); basicSettingsBoxLayout->addWidget(useRemoteSmbPort, 2, 0, 0); basicSettingsBoxLayout->addWidget(remoteSmbPort, 2, 1, 0); basicSettingsBoxLayout->addWidget(largeNetworkNeighborhood, 3, 0, 1, 2, 0); // // Behavior group box // - QGroupBox *behaviorBox = new QGroupBox(i18n("Behavior"), commonSambaTab); + QGroupBox *behaviorBox = new QGroupBox(i18n("Behavior"), commonTab); QGridLayout *behaviorBoxLayout = new QGridLayout(behaviorBox); QCheckBox *detectPrinters = new QCheckBox(Smb4KSettings::self()->detectPrinterSharesItem()->label(), behaviorBox); detectPrinters->setObjectName("kcfg_DetectPrinterShares"); QCheckBox *detectHiddenShares = new QCheckBox(Smb4KSettings::self()->detectHiddenSharesItem()->label(), behaviorBox); detectHiddenShares->setObjectName("kcfg_DetectHiddenShares"); QCheckBox *previewHiddenItems = new QCheckBox(Smb4KSettings::self()->previewHiddenItemsItem()->label(), behaviorBox); previewHiddenItems->setObjectName("kcfg_PreviewHiddenItems"); behaviorBoxLayout->addWidget(detectPrinters, 0, 0, 0); behaviorBoxLayout->addWidget(detectHiddenShares, 0, 1, 0); behaviorBoxLayout->addWidget(previewHiddenItems, 1, 0, 0); - commonSambaTabLayout->addWidget(basicSettingsBox, 0); - commonSambaTabLayout->addWidget(behaviorBox, 0); - commonSambaTabLayout->addStretch(100); + commonTabLayout->addWidget(browseSettingsBox, 0); + commonTabLayout->addWidget(basicSettingsBox, 0); + commonTabLayout->addWidget(behaviorBox, 0); + commonTabLayout->addStretch(100); - addTab(commonSambaTab, i18n("Common Samba Settings")); + addTab(commonTab, i18n("Common Settings")); // // Advanced Samba Settings // QWidget *advancedSambaTab = new QWidget(this); QVBoxLayout *advancedSambaTabLayout = new QVBoxLayout(advancedSambaTab); - // - // Protocol group box - // - QGroupBox *protocolsBox = new QGroupBox(i18n("Protocols"), basicSettingsBox); - QVBoxLayout *protocolsBoxLayout = new QVBoxLayout(protocolsBox); - - // Force SMBv1 protocol for workgroup lookups - QCheckBox *forceSMB1Protocol = new QCheckBox(Smb4KSettings::self()->forceSMB1ProtocolItem()->label(), protocolsBox); - forceSMB1Protocol->setObjectName("kcfg_ForceSMB1Protocol"); - - protocolsBoxLayout->addWidget(forceSMB1Protocol, 0); - // // Authentication group box // QGroupBox *authenticationBox = new QGroupBox(i18n("Authentication"), advancedSambaTab); QGridLayout *authenticationBoxLayout = new QGridLayout(authenticationBox); QCheckBox *masterBrowsersRequireAuth = new QCheckBox(Smb4KSettings::self()->masterBrowsersRequireAuthItem()->label(), authenticationBox); masterBrowsersRequireAuth->setObjectName("kcfg_MasterBrowsersRequireAuth"); QCheckBox *useKerberos = new QCheckBox(Smb4KSettings::self()->useKerberosItem()->label(), authenticationBox); useKerberos->setObjectName("kcfg_UseKerberos"); QCheckBox *useCCache = new QCheckBox(Smb4KSettings::self()->useWinbindCCacheItem()->label(), authenticationBox); useCCache->setObjectName("kcfg_UseWinbindCCache"); authenticationBoxLayout->addWidget(masterBrowsersRequireAuth, 0, 0, 0); authenticationBoxLayout->addWidget(useKerberos, 0, 1, 0); authenticationBoxLayout->addWidget(useCCache, 1, 0, 0); // // Security group box // QGroupBox *securityBox = new QGroupBox(i18n("Security"), advancedSambaTab); QGridLayout *securityBoxLayout = new QGridLayout(securityBox); // Encryption level QCheckBox *useEncryptionLevel = new QCheckBox(Smb4KSettings::self()->useEncryptionLevelItem()->label(), securityBox); useEncryptionLevel->setObjectName("kcfg_UseEncryptionLevel"); KComboBox *encryptionLevel = new KComboBox(securityBox); encryptionLevel->setObjectName("kcfg_EncryptionLevel"); QList encryptionLevelChoices = Smb4KSettings::self()->encryptionLevelItem()->choices(); for (const KCoreConfigSkeleton::ItemEnum::Choice &c : encryptionLevelChoices) { encryptionLevel->addItem(c.label); } securityBoxLayout->addWidget(useEncryptionLevel, 0, 0, 0); securityBoxLayout->addWidget(encryptionLevel, 0, 1, 0); - advancedSambaTabLayout->addWidget(protocolsBox, 0); advancedSambaTabLayout->addWidget(authenticationBox, 0); advancedSambaTabLayout->addWidget(securityBox, 0); advancedSambaTabLayout->addStretch(100); - addTab(advancedSambaTab, i18n("Advanced Samba Settings")); + addTab(advancedSambaTab, i18n("Advanced Settings")); // // Wake-On-LAN tab // QWidget *wakeOnLanTab = new QWidget(this); QVBoxLayout *wakeOnLanTabLayout = new QVBoxLayout(wakeOnLanTab); // // Wake-On-LAN group box // QGroupBox *wakeOnLanBox = new QGroupBox(i18n("Wake-On-LAN"), wakeOnLanTab); QGridLayout *wakeOnLanBoxLayout = new QGridLayout(wakeOnLanBox); QCheckBox *enableWakeOnLan = new QCheckBox(Smb4KSettings::self()->enableWakeOnLANItem()->label(), wakeOnLanBox); enableWakeOnLan->setObjectName("kcfg_EnableWakeOnLAN"); QLabel *wakeOnLanWaitingTimeLabel = new QLabel(Smb4KSettings::self()->wakeOnLANWaitingTimeItem()->label(), wakeOnLanBox); wakeOnLanWaitingTimeLabel->setIndent(25); QSpinBox *wakeOnLanWaitingTime = new QSpinBox(wakeOnLanBox); wakeOnLanWaitingTime->setObjectName("kcfg_WakeOnLANWaitingTime"); wakeOnLanWaitingTime->setSuffix(i18n(" s")); wakeOnLanWaitingTime->setSingleStep(1); // wakeOnLanWaitingTime->setSliderEnabled(true); wakeOnLanWaitingTimeLabel->setBuddy(wakeOnLanWaitingTime); QFrame *wakeOnLanNote = new QFrame(wakeOnLanBox); QGridLayout *wakeOnLanNoteLayout = new QGridLayout(wakeOnLanNote); wakeOnLanNoteLayout->setSpacing(10); wakeOnLanNoteLayout->setContentsMargins(5, 5, 5, 5); QLabel *importantPixmap = new QLabel(wakeOnLanNote); importantPixmap->setPixmap(KIconLoader::global()->loadIcon("emblem-important", KIconLoader::Desktop, KIconLoader::SizeMedium)); importantPixmap->adjustSize(); QLabel *message = new QLabel(wakeOnLanNote); message->setText(i18n("Define the hosts that should be woken up via the custom options dialog.")); message->setTextFormat(Qt::AutoText); message->setWordWrap(true); message->setAlignment(Qt::AlignJustify); wakeOnLanNoteLayout->addWidget(importantPixmap, 0, 0, Qt::AlignVCenter); wakeOnLanNoteLayout->addWidget(message, 0, 1, Qt::AlignVCenter); wakeOnLanNoteLayout->setColumnStretch(1, 1); wakeOnLanBoxLayout->addWidget(enableWakeOnLan, 0, 0, 1, 2, 0); wakeOnLanBoxLayout->addWidget(wakeOnLanWaitingTimeLabel, 1, 0, 0); wakeOnLanBoxLayout->addWidget(wakeOnLanWaitingTime, 1, 1, 0); wakeOnLanBoxLayout->addWidget(wakeOnLanNote, 2, 0, 1, 2, 0); wakeOnLanTabLayout->addWidget(wakeOnLanBox, 0); wakeOnLanTabLayout->addStretch(100); addTab(wakeOnLanTab, i18n("Wake-On-LAN")); } Smb4KConfigPageNetwork::~Smb4KConfigPageNetwork() { } diff --git a/smb4k/smb4ktooltip.cpp b/smb4k/smb4ktooltip.cpp index d913572..bd52e71 100644 --- a/smb4k/smb4ktooltip.cpp +++ b/smb4k/smb4ktooltip.cpp @@ -1,612 +1,626 @@ /*************************************************************************** smb4ktooltip - Provides tooltips for Smb4K ------------------- begin : Mi Mai 2020 copyright : (C) 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 "smb4ktooltip.h" #include "smb4kbasicnetworkitem.h" #include "smb4kworkgroup.h" #include "smb4khost.h" #include "smb4kshare.h" #include "smb4kglobal.h" // Qt includes #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) #include #else #include #endif // KDE includes #include #include #include using namespace Smb4KGlobal; Smb4KToolTip::Smb4KToolTip(QWidget* parent) : KToolTipWidget(parent) { m_contentsWidget = new QWidget(parent); m_type = Unknown; } Smb4KToolTip::~Smb4KToolTip() { } void Smb4KToolTip::setupToolTip(Smb4KToolTip::Type type, NetworkItemPtr item) { // // Copy the type // m_type = type; // // Copy the item // m_item = item; // // Clear the contents widget // qDeleteAll(m_contentsWidget->children()); // // Set the layout // m_mainLayout = new QHBoxLayout(m_contentsWidget); // // Setup the contents widget // switch (m_type) { case NetworkItem: { setupNetworkItemContents(); break; } case MountedShare: { setupMountedShareContents(); break; } default: { break; } } } void Smb4KToolTip::update() { // // Return if there is no item // if (!m_item.isNull() || m_type == Unknown) { return; } // // Update the contents widget // switch (m_type) { case NetworkItem: { setupNetworkItemContents(); break; } case MountedShare: { setupMountedShareContents(); break; } default: { break; } } } void Smb4KToolTip::show(const QPoint& pos, QWindow *transientParent) { QPoint tooltipPos = pos; int testWidth = m_contentsWidget->width() + cursor().pos().x() + layout()->contentsMargins().left() + layout()->contentsMargins().right() + 5; int testHeight = m_contentsWidget->height() + cursor().pos().y() + layout()->contentsMargins().top() + layout()->contentsMargins().bottom() + 5; #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) if (QApplication::desktop()->screenGeometry(pos).width() < testWidth) { tooltipPos.setX(pos.x() - m_contentsWidget->width() - layout()->contentsMargins().left() - layout()->contentsMargins().right() - 5); } else { tooltipPos.setX(pos.x() + 5); } if (QApplication::desktop()->screenGeometry(pos).height() < testHeight) { tooltipPos.setY(pos.y() - m_contentsWidget->height() - layout()->contentsMargins().top() - layout()->contentsMargins().bottom() - 5); } else { tooltipPos.setY(pos.y() + 5); } #else if (QApplication::screenAt(pos)->virtualSize().width() < testWidth) { tooltipPos.setX(pos.x() - m_contentsWidget->width() - layout()->contentsMargins().left() - layout()->contentsMargins().right() - 5); } else { tooltipPos.setX(pos.x() + 5); } if (QApplication::screenAt(pos)->virtualSize().height() < testHeight) { tooltipPos.setY(pos.y() - m_contentsWidget->height() - layout()->contentsMargins().top() - layout()->contentsMargins().bottom() - 5); } else { tooltipPos.setY(pos.y() + 5); } #endif showAt(tooltipPos, m_contentsWidget, transientParent); } void Smb4KToolTip::setupNetworkItemContents() { // // Update the contents, if possible // if (!m_contentsWidget->layout()->isEmpty()) { switch (m_item->type()) { case Workgroup: { WorkgroupPtr workgroup = m_item.staticCast(); QLabel *masterBrowserName = m_contentsWidget->findChild("MasterBrowserName"); - - if (workgroup->hasMasterBrowserIpAddress()) + + if (workgroup->hasMasterBrowser()) { - masterBrowserName->setText(workgroup->masterBrowserName()+" ("+workgroup->masterBrowserIpAddress()+')'); + if (workgroup->hasMasterBrowserIpAddress()) + { + masterBrowserName->setText(workgroup->masterBrowserName()+" ("+workgroup->masterBrowserIpAddress()+')'); + } + else + { + masterBrowserName->setText(workgroup->masterBrowserName()); + } } else { - masterBrowserName->setText(workgroup->masterBrowserName()); + masterBrowserName->setText("-"); } break; } case Host: { HostPtr host = m_item.staticCast(); m_contentsWidget->findChild("CommentString")->setText(!host->comment().isEmpty() ? host->comment() : "-"); m_contentsWidget->findChild("IPAddressString")->setText(host->hasIpAddress() ? host->ipAddress() : "-"); break; } case Share: { SharePtr share = m_item.staticCast(); m_contentsWidget->findChild("CommentString")->setText(!share->comment().isEmpty() ? share->comment() : "-"); m_contentsWidget->findChild("IPAddressString")->setText(share->hasHostIpAddress() ? share->hostIpAddress() : "-"); QLabel *mountedState = m_contentsWidget->findChild("MountedState"); if (!share->isPrinter()) { mountedState->setText(share->isMounted() ? i18n("yes") : i18n("no")); } else { mountedState->setText("-"); } break; } default: { break; } } return; } // // Set up the widget // // Icon QLabel *iconLabel = new QLabel(m_contentsWidget); iconLabel->setPixmap(m_item->icon().pixmap(KIconLoader::SizeEnormous)); m_mainLayout->addWidget(iconLabel, Qt::AlignHCenter); // Header QGridLayout *descriptionLayout = new QGridLayout(); m_mainLayout->addLayout(descriptionLayout); QLabel *caption = new QLabel(m_contentsWidget); caption->setForegroundRole(QPalette::ToolTipText); caption->setBackgroundRole(QPalette::AlternateBase); QFont captionFont = caption->font(); captionFont.setBold(true); caption->setFont(captionFont); descriptionLayout->addWidget(caption, 0, 0, 1, 2, Qt::AlignHCenter); KSeparator *separator = new KSeparator(Qt::Horizontal, m_contentsWidget); separator->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(separator, 1, 0, 1, 2, 0); // Type QLabel *typeCaption = new QLabel(i18n("Type:"), m_contentsWidget); typeCaption->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(typeCaption, 2, 0, Qt::AlignRight); QLabel *typeName = new QLabel(m_contentsWidget); typeName->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(typeName, 2, 1, 0); switch (m_item->type()) { case Workgroup: { WorkgroupPtr workgroup = m_item.staticCast(); caption->setText(workgroup->workgroupName()); typeName->setText(i18n("Workgroup")); // Master browser QLabel *masterBrowserLabel = new QLabel(i18n("Master Browser:"), m_contentsWidget); masterBrowserLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(masterBrowserLabel, 3, 0, Qt::AlignRight); QLabel *masterBrowserName = new QLabel(m_contentsWidget); masterBrowserName->setObjectName("MasterBrowserName"); masterBrowserName->setForegroundRole(QPalette::ToolTipText); - if (workgroup->hasMasterBrowserIpAddress()) + if (workgroup->hasMasterBrowser()) { - masterBrowserName->setText(QString("%1 (%2)").arg(workgroup->masterBrowserName(), workgroup->masterBrowserIpAddress())); + if (workgroup->hasMasterBrowserIpAddress()) + { + masterBrowserName->setText(workgroup->masterBrowserName()+" ("+workgroup->masterBrowserIpAddress()+')'); + } + else + { + masterBrowserName->setText(workgroup->masterBrowserName()); + } } else { - masterBrowserName->setText(workgroup->masterBrowserName()); + masterBrowserName->setText("-"); } descriptionLayout->addWidget(masterBrowserName, 3, 1, 0); descriptionLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 4, 0, 2, 1, 0); break; } case Host: { HostPtr host = m_item.staticCast(); caption->setText(host->hostName()); typeName->setText(i18n("Host")); // Comment QLabel *commentLabel = new QLabel(i18n("Comment:"), m_contentsWidget); commentLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(commentLabel, 3, 0, Qt::AlignRight); QLabel *commentString = new QLabel(!host->comment().isEmpty() ? host->comment() : "-", m_contentsWidget); commentString->setObjectName("CommentString"); commentString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(commentString, 3, 1, 0); // IP address QLabel *ipAddressLabel = new QLabel(i18n("IP Address:"), m_contentsWidget); ipAddressLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(ipAddressLabel, 4, 0, Qt::AlignRight); QLabel *ipAddress = new QLabel(host->hasIpAddress() ? host->ipAddress() : "-", m_contentsWidget); ipAddress->setObjectName("IPAddressString"); ipAddress->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(ipAddress, 4, 1, 0); // Workgroup QLabel *workgroupLabel = new QLabel(i18n("Workgroup:"), m_contentsWidget); workgroupLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(workgroupLabel, 5, 0, Qt::AlignRight); QLabel *workgroupName = new QLabel(host->workgroupName(), m_contentsWidget); workgroupName->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(workgroupName, 5, 1, 0); descriptionLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 6, 0, 2, 1, 0); break; } case Share: { SharePtr share = m_item.staticCast(); caption->setText(share->shareName()); typeName->setText(i18n("Share (%1)", share->shareTypeString())); // Comment QLabel *commentLabel = new QLabel(i18n("Comment:"), m_contentsWidget); commentLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(commentLabel, 3, 0, Qt::AlignRight); QLabel *commentString = new QLabel(!share->comment().isEmpty() ? share->comment() : "-", m_contentsWidget); commentString->setObjectName("CommentString"); commentString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(commentString, 3, 1, 0); // State (mounted/not mounted) QLabel *mountedLabel = new QLabel(i18n("Mounted:"), m_contentsWidget); mountedLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(mountedLabel, 4, 0, Qt::AlignRight); QLabel *mountedState = nullptr; if (!share->isPrinter()) { mountedState = new QLabel(share->isMounted() ? i18n("yes") : i18n("no"), m_contentsWidget); } else { mountedState = new QLabel("-", m_contentsWidget); } mountedState->setObjectName("MountedState"); mountedState->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(mountedState, 4, 1, 0); // Host QLabel *hostLabel = new QLabel(i18n("Host:"), m_contentsWidget); hostLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(hostLabel, 5, 0, Qt::AlignRight); QLabel *hostName = new QLabel(share->hostName(), m_contentsWidget); hostName->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(hostName, 5, 1, 0); // IP address QLabel *ipAddressLabel = new QLabel(i18n("IP Address:"), m_contentsWidget); ipAddressLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(ipAddressLabel, 6, 0, Qt::AlignRight); QLabel *ipAddressString = new QLabel(share->hasHostIpAddress() ? share->hostIpAddress() : "-", m_contentsWidget); ipAddressString->setObjectName("IPAddressString"); ipAddressString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(ipAddressString, 6, 1, 0); // Location QLabel *locationLabel = new QLabel(i18n("Location:"), m_contentsWidget); locationLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(locationLabel, 7, 0, Qt::AlignRight); QLabel *locationString = new QLabel(share->displayString(), m_contentsWidget); locationString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(locationString, 7, 1, 0); descriptionLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 8, 0, 2, 1, 0); break; } default: { break; } } m_contentsWidget->adjustSize(); m_contentsWidget->ensurePolished(); } void Smb4KToolTip::setupMountedShareContents() { // // Cast the item // SharePtr share = m_item.staticCast(); // // Update the contents, if possible // if (!m_contentsWidget->layout()->isEmpty()) { m_contentsWidget->findChild("IconLabel")->setPixmap(share->icon().pixmap(KIconLoader::SizeEnormous)); m_contentsWidget->findChild("LoginString")->setText(!share->login().isEmpty() ? share->login() : i18n("unknown")); QString sizeIndication; if (share->totalDiskSpace() != 0 && share->freeDiskSpace() != 0) { sizeIndication = i18n("%1 free of %2 (%3 used)", share->freeDiskSpaceString(), share->totalDiskSpaceString(), share->diskUsageString()); } else { sizeIndication = i18n("unknown"); } m_contentsWidget->findChild("SizeString")->setText(sizeIndication); return; } // // Set up the widget // // Icon QLabel *iconLabel = new QLabel(m_contentsWidget); iconLabel->setPixmap(share->icon().pixmap(KIconLoader::SizeEnormous)); iconLabel->setObjectName("IconLabel"); m_mainLayout->addWidget(iconLabel, Qt::AlignHCenter); // Header QGridLayout *descriptionLayout = new QGridLayout(); m_mainLayout->addLayout(descriptionLayout); QLabel *caption = new QLabel(share->shareName(), m_contentsWidget); caption->setForegroundRole(QPalette::ToolTipText); caption->setBackgroundRole(QPalette::AlternateBase); QFont captionFont = caption->font(); captionFont.setBold(true); caption->setFont(captionFont); descriptionLayout->addWidget(caption, 0, 0, 1, 2, Qt::AlignHCenter); KSeparator *separator = new KSeparator(Qt::Horizontal, m_contentsWidget); separator->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(separator, 1, 0, 1, 2, 0); // Location QLabel *locationLabel = new QLabel(i18n("Location:"), m_contentsWidget); locationLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(locationLabel, 2, 0, Qt::AlignRight); QLabel *locationString = new QLabel(share->displayString(), m_contentsWidget); locationString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(locationString, 2, 1, 0); // Mount point QLabel *mountpointLabel = new QLabel(i18n("Mountpoint:"), m_contentsWidget); mountpointLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(mountpointLabel, 3, 0, Qt::AlignRight); QLabel *mountpointString = new QLabel(share->path(), m_contentsWidget); mountpointString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(mountpointString, 3, 1, 0); // Login QLabel *loginLabel = new QLabel(i18n("Login:"), m_contentsWidget); loginLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(loginLabel, 4, 0, Qt::AlignRight); QLabel *loginString = new QLabel(!share->login().isEmpty() ? share->login() : i18n("unknown"), m_contentsWidget); loginString->setObjectName("LoginString"); loginString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(loginString, 4, 1, 0); // Owner QLabel *ownerLabel = new QLabel(i18n("Owner:"), m_contentsWidget); ownerLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(ownerLabel, 5, 0, Qt::AlignRight); QString owner(!share->user().loginName().isEmpty() ? share->user().loginName() : i18n("unknown")); QString group(!share->group().name().isEmpty() ? share->group().name() : i18n("unknown")); QLabel *ownerString = new QLabel(QString("%1 - %2").arg(owner, group),m_contentsWidget); ownerString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(ownerString, 5, 1, 0); // File system QLabel *fileSystemLabel = new QLabel(i18n("File system:"), m_contentsWidget); fileSystemLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(fileSystemLabel, 6, 0, Qt::AlignRight); QLabel *fileSystemString = new QLabel(share->fileSystemString(), m_contentsWidget); fileSystemString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(fileSystemString, 6, 1, 0); // Size QLabel *sizeLabel = new QLabel(i18n("Size:"), m_contentsWidget); sizeLabel->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(sizeLabel, 7, 0, Qt::AlignRight); QString sizeIndication; if (share->totalDiskSpace() != 0 && share->freeDiskSpace() != 0) { sizeIndication = i18n("%1 free of %2 (%3 used)", share->freeDiskSpaceString(), share->totalDiskSpaceString(), share->diskUsageString()); } else { sizeIndication = i18n("unknown"); } QLabel *sizeString = new QLabel(sizeIndication, m_contentsWidget); sizeString->setObjectName("SizeString"); sizeString->setForegroundRole(QPalette::ToolTipText); descriptionLayout->addWidget(sizeString, 7, 1, 0); descriptionLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 8, 0, 2, 1, 0); m_contentsWidget->adjustSize(); m_contentsWidget->ensurePolished(); }