ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #00561
[Merge] lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04 into lp:ubuntu-filemanager-app
Carlos Jose Mazieri has proposed merging lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04 into lp:ubuntu-filemanager-app with lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-03 as a prerequisite.
Commit message:
Intoduces the SmbUtil class which provides the basic open/close/listing operations for Samba items.
Requested reviews:
Ubuntu File Manager Developers (ubuntu-filemanager-dev)
For more details, see:
https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04/+merge/252220
Intoduces the SmbUtil class which provides the basic open/close/listing operations for Samba items.
it comes separated in a "qsambaclient" directory which is intended to be a generic Qt Samba client library.
--
Your team Ubuntu File Manager Developers is requested to review the proposed merge of lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04 into lp:ubuntu-filemanager-app.
=== modified file 'src/plugin/folderlistmodel/CMakeLists.txt'
--- src/plugin/folderlistmodel/CMakeLists.txt 2015-03-08 12:43:13 +0000
+++ src/plugin/folderlistmodel/CMakeLists.txt 2015-03-08 12:43:13 +0000
@@ -3,6 +3,8 @@
disk
trash
net
+ smb
+ smb/qsambaclient/src
)
set(PLUGIN_DIR org/nemomobile/folderlistmodel)
@@ -55,8 +57,12 @@
trash/trashiteminfo.h
trash/trashlocation.cpp
trash/trashlocation.h
+ smb/qsambaclient/src/smbutil.cpp
+ smb/qsambaclient/src/smbutil.h
net/netauthenticationdata.cpp
- net/netauthenticationdata.h
+ net/netauthenticationdata.h
+ net/netutil.cpp
+ net/netutil.h
)
add_library(nemofolderlistmodel MODULE
@@ -65,6 +71,24 @@
qt5_use_modules(nemofolderlistmodel Gui Qml Quick Widgets)
+## samba requires libsmbclient
+find_path(SAMBA_INCLUDE_DIR
+ NAMES libsmbclient.h
+ HINTS /usr/include/smbclient /usr/include/samba /usr/include/samba-3.0 /usr/include/samba-4.0
+ )
+find_library(SAMBA_LIBRARIES NAMES smbclient )
+message(STATUS "samba include=${SAMBA_INCLUDE_DIR}")
+message(STATUS "samba lib=${SAMBA_LIBRARIES}=${SAMBA_LIBRARIES}")
+
+if(SAMBA_INCLUDE_DIR AND SAMBA_LIBRARIES)
+ message(STATUS "Found samba: include=${SAMBA_INCLUDE_DIR} library=${SAMBA_LIBRARIES}")
+ INCLUDE_DIRECTORIES(${SAMBA_INCLUDE_DIR})
+ TARGET_LINK_LIBRARIES(nemofolderlistmodel ${SAMBA_LIBRARIES})
+else(SAMBA_INCLUDE_DIR AND SAMBA_LIBRARIES)
+ message(FATAL_ERROR "Could not find Samba libsmbclient")
+endif(SAMBA_INCLUDE_DIR AND SAMBA_LIBRARIES)
+mark_as_advanced(SAMBA_INCLUDE_DIR SAMBA_LIBRARIES)
+## end samba confiuration
# Copy the plugin, the qmldir file and other assets to the build dir for running in QtCreator
if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
=== modified file 'src/plugin/folderlistmodel/folderlistmodel.pri'
--- src/plugin/folderlistmodel/folderlistmodel.pri 2015-03-08 12:43:13 +0000
+++ src/plugin/folderlistmodel/folderlistmodel.pri 2015-03-08 12:43:13 +0000
@@ -40,8 +40,8 @@
HEADERS += $$PWD/trash/qtrashdir.h $$PWD/trash/trashiteminfo.h \
$$PWD/trash/qtrashutilinfo.h $$PWD/trash/trashlocation.h
-SOURCES += $$PWD/net/netauthenticationdata.cpp
-HEADERS += $$PWD/net/netauthenticationdata.h
+SOURCES += $$PWD/net/netutil.cpp $$PWD/net/netauthenticationdata.cpp
+HEADERS += $$PWD/net/netutil.h $$PWD/net/netauthenticationdata.h
INCLUDEPATH += $$PWD $$PWD/trash $$PWD/disk $$PWD/net
=== modified file 'src/plugin/folderlistmodel/location.cpp'
--- src/plugin/folderlistmodel/location.cpp 2015-03-08 12:43:13 +0000
+++ src/plugin/folderlistmodel/location.cpp 2015-03-08 12:43:13 +0000
@@ -43,6 +43,8 @@
#include "ioworkerthread.h"
#include "netauthenticationdata.h"
+#include <QDebug>
+
Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
=== modified file 'src/plugin/folderlistmodel/locationurl.cpp'
--- src/plugin/folderlistmodel/locationurl.cpp 2014-05-02 10:42:48 +0000
+++ src/plugin/folderlistmodel/locationurl.cpp 2015-03-08 12:43:13 +0000
@@ -23,8 +23,9 @@
const QString LocationUrl::TrashRootURL("trash:///");
const QString LocationUrl::DiskRootURL("file:///");
+const QString LocationUrl::SmbURL("smb://");
+const QString LocationUrl::CifsURL("cifs://");
#if 0
-QString LocationURL::SmbURL("smb://");
QString LocationURL::FishURL("fish:///");
#endif
=== modified file 'src/plugin/folderlistmodel/locationurl.h'
--- src/plugin/folderlistmodel/locationurl.h 2014-05-02 10:42:48 +0000
+++ src/plugin/folderlistmodel/locationurl.h 2015-03-08 12:43:13 +0000
@@ -29,8 +29,9 @@
public:
static const QString DiskRootURL;
static const QString TrashRootURL;
+ static const QString SmbURL;
+ static const QString CifsURL;
#if 0
- static const QString SmbURL;
static const QString FishURL;
#endif
private:
=== added file 'src/plugin/folderlistmodel/net/netutil.cpp'
--- src/plugin/folderlistmodel/net/netutil.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/folderlistmodel/net/netutil.cpp 2015-03-08 12:43:13 +0000
@@ -0,0 +1,89 @@
+/**************************************************************************
+ *
+ * Copyright 2014 Canonical Ltd.
+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * File: netutil.cpp
+ * Date: 29/11/2014
+ */
+
+#include "netutil.h"
+#include <QHostAddress>
+#include <QHostInfo>
+#include <QUrl>
+
+#include <QDebug>
+
+NetUtil::NetUtil()
+{
+}
+
+
+QString NetUtil::normalizeHostName(const QString& name)
+{
+ QString host(name.toLower());
+ bool isLoopBack = false;
+ QHostInfo info = QHostInfo::fromName(host);
+ // take advantage of network with Bonjour/Avahi
+ // as winbind looks like harder to configure or does not work
+ if (info.error() == QHostInfo::HostNotFound)
+ {
+ host += QLatin1String(".local");
+ info = QHostInfo::fromName(host);
+ }
+ if (info.error() == QHostInfo::NoError)
+ {
+ host = info.hostName();
+ QList<QHostAddress> addrs = info.addresses();
+ int counter = addrs.count();
+ while (!isLoopBack && counter--)
+ {
+ isLoopBack = addrs.at(counter).isLoopback();
+ }
+ }
+ if (isLoopBack)
+ {
+ host = QLatin1String("localhost");
+ }
+ return host;
+}
+
+/*!
+ * \brief NetUtil::urlConvertHostnameToIP() Tries to convert an url like protocol://hostname/blavbla to protocol://ip-address/blavbla
+ * \param url
+ * \return the url using IP numbers or an empty string saying that was not possible to get its IP number
+ */
+QString NetUtil::urlConvertHostnameToIP(const QString &url)
+{
+ QString ret;
+ QUrl tmpUrl(url);
+ if (tmpUrl.isValid() && !tmpUrl.host().isEmpty() && tmpUrl.host() != QLatin1String("localhost"))
+ {
+ QString host = tmpUrl.host();
+ QHostInfo info = QHostInfo::fromName(host);
+ if (info.error() == QHostInfo::HostNotFound)
+ {
+ // take advantage of network with Bonjour/Avahi
+ // as winbind looks like harder to configure or does not work
+ info = QHostInfo::fromName(host + QLatin1String(".local"));
+ }
+ if (info.error() == QHostInfo::NoError)
+ {
+ tmpUrl.setHost(info.addresses().at(0).toString());
+ ret = tmpUrl.toString();
+ }
+ }
+ return ret;
+}
=== added file 'src/plugin/folderlistmodel/net/netutil.h'
--- src/plugin/folderlistmodel/net/netutil.h 1970-01-01 00:00:00 +0000
+++ src/plugin/folderlistmodel/net/netutil.h 2015-03-08 12:43:13 +0000
@@ -0,0 +1,36 @@
+/**************************************************************************
+ *
+ * Copyright 2014 Canonical Ltd.
+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * File: netutil.h
+ * Date: 29/11/2014
+ */
+
+#ifndef NETUTIL_H
+#define NETUTIL_H
+
+#include <QString>
+
+class NetUtil
+{
+private:
+ NetUtil();
+public:
+ static QString normalizeHostName(const QString& name);
+ static QString urlConvertHostnameToIP(const QString& url);
+};
+
+#endif // NETUTIL_H
=== added directory 'src/plugin/folderlistmodel/smb'
=== added directory 'src/plugin/folderlistmodel/smb/qsambaclient'
=== added file 'src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri'
--- src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri 1970-01-01 00:00:00 +0000
+++ src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri 2015-03-08 12:43:13 +0000
@@ -0,0 +1,14 @@
+
+SOURCES += $$PWD/src/smbutil.cpp
+
+
+
+HEADERS += $$PWD/src/smbutil.h
+
+
+QT *= core network
+
+CONFIG *= link_pkgconfig
+PKGCONFIG *= smbclient
+
+INCLUDEPATH += $$PWD/src
=== added directory 'src/plugin/folderlistmodel/smb/qsambaclient/src'
=== added file 'src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp'
--- src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp 2015-03-08 12:43:13 +0000
@@ -0,0 +1,704 @@
+/**************************************************************************
+ *
+ * Copyright 2014 Canonical Ltd.
+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * File: smbutil.cpp
+ * Date: 20/11/2014
+ */
+
+#include "smbutil.h"
+#include "locationurl.h"
+#include "netutil.h"
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <errno.h>
+
+#include <QUrl>
+#include <QDebug>
+#include <QRegExp>
+
+// set debug level at compilation time
+#ifndef SMB_DEBUG_LEVEL
+#define SMB_DEBUG_LEVEL 0
+#endif
+
+
+#if defined(SHOW_MESSAGES)
+# define DBG(more_items) qDebug() << Q_FUNC_INFO more_items
+#else
+#define DBG(none)
+#endif
+
+static QByteArray s_user("guest");
+static QByteArray s_passwd;
+static QByteArray s_workGroup("WORKGROUP");
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::SmbUtil() This is the default constructor that provides the default authentication method
+ *
+ * The user is the current user, password is "passwd" and the authentication function is \ref authenticateCallBack()
+ */
+SmbUtil::SmbUtil()
+{
+ init(::qgetenv("USER"), QLatin1String("passwd"), &SmbUtil::authenticateCallBack);
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::SmbUtil() This constructor accepts an \a user and \a password for authentication
+ *
+ * The authentication function is \ref authenticateCallBack()
+ *
+ * \param authUser
+ * \param authPassword
+ */
+SmbUtil::SmbUtil(const QString& authUser, const QString& authPassword)
+{
+ init(authUser, authPassword, &SmbUtil::authenticateCallBack);
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::SmbUtil() This constructor accepts another authentication function other than the default
+ *
+ * No users no password is providedm the function should be able to provide everything
+ *
+ * \param ptAuthenticateCallBack
+ */
+SmbUtil::SmbUtil(Smb::AuthenticationFunction ptAuthenticateCallBack):
+ m_authCallBack(ptAuthenticateCallBack)
+{
+
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::SmbUtil() This is the more complete constructor where user and password can come from the \a smbUrl
+ * \param smbUrl
+ * \param fn
+ */
+SmbUtil::SmbUtil(const QUrl& smbUrl, Smb::AuthenticationFunction fn)
+{
+ m_authCallBack = fn ? fn : &SmbUtil::authenticateCallBack;
+ if (!smbUrl.userName().isEmpty())
+ {
+ init(smbUrl.userName(), smbUrl.password(), m_authCallBack);
+ }
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::~SmbUtil() destructor
+ */
+SmbUtil::~SmbUtil()
+{
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::authenticateCallBack() Default authentication function, it uses static variables to keep user/password
+ * \param server
+ * \param share
+ * \param wrkgrp
+ * \param wrkgrplen
+ * \param user
+ * \param userlen
+ * \param passwd
+ * \param passwdlen
+ */
+void SmbUtil::authenticateCallBack( const char *server,
+ const char *share,
+ char *wrkgrp,
+ int wrkgrplen,
+ char *user,
+ int userlen,
+ char *passwd,
+ int passwdlen)
+{
+ Q_UNUSED(server);
+ Q_UNUSED(share);
+ DBG(<< "server:" << server << "share:" << share << "wrkgrp:" << wrkgrp << "user:" << user << "passwd:" << passwd);
+
+#if 0
+ //this may not be necessary
+ ::strncpy(wrkgrp, s_workGroup.constData(), --wrkgrplen);
+#else
+ Q_UNUSED(wrkgrp);
+ Q_UNUSED(wrkgrplen);
+#endif
+
+ // check some environment variables to help test authentication
+#if defined(REGRESSION_TEST_QSAMBACLIENT)
+ QByteArray env = ::qgetenv("SMB_DEFAULT_USER");
+ if (env.size() > 0)
+ {
+ s_user = env;
+ }
+ env = ::qgetenv("SMB_DEFAULT_PASSWORD");
+ if (env.size() > 0)
+ {
+ s_passwd = env;
+ }
+#endif
+
+ ::strncpy(user, s_user.constData(), --userlen);
+ ::strncpy(passwd, s_passwd.constData(), --passwdlen);
+}
+
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::init() Just stores user/password and authentication function
+ * \param user
+ * \param password
+ * \param fn
+ */
+void SmbUtil::init(const QString &user, const QString &password, Smb::AuthenticationFunction fn)
+{
+ s_user = user.toLocal8Bit();
+ s_passwd = password.toLocal8Bit();
+ m_authCallBack = fn;
+}
+
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::createContext() It creates a SMB context which is necessary to all operations
+ *
+ * It sets the current authentication function callback
+ *
+ * \return the context created
+ */
+Smb::Context SmbUtil::createContext()
+{
+ Smb::Context ctx = smbc_new_context();
+ if (ctx)
+ {
+ smbc_setDebug(ctx, SMB_DEBUG_LEVEL);
+ smbc_setFunctionAuthData(ctx, m_authCallBack);
+ if (smbc_init_context(ctx) == NULL)
+ {
+ smbc_free_context(ctx, 1);
+ ctx = 0;
+ }
+ }
+ DBG(<< "ctx:" << ctx);
+ return ctx;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::deleteContext() Just deletes a context created by \ref createContext()
+ * \param context
+ */
+void SmbUtil::deleteContext(Smb::Context context)
+{
+ smbc_getFunctionPurgeCachedServers(context)(context);
+ smbc_free_context(context, 1);
+ DBG();
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::openFile() opens a file
+ * \param context
+ * \param smb_path it must point to a file full pathname
+ * \param flags
+ * \param mode
+ * \return the FileHandler or NULL when it is not possible to open the file
+ */
+Smb::FileHandler
+SmbUtil::openFile(Smb::Context context, const QString &smb_path, int flags , mode_t mode)
+{
+ Smb::FileHandler fd = ::smbc_getFunctionOpen(context)
+ (context, smb_path.toLocal8Bit().constData(), flags, mode);
+
+ if (fd == 0 && errno != EISDIR)
+ {
+ QString ipUrl = NetUtil::urlConvertHostnameToIP(smb_path);
+ if (!ipUrl.isEmpty())
+ {
+ fd = ::smbc_getFunctionOpen(context)
+ (context, ipUrl.toLocal8Bit().constData(), flags, mode);
+ }
+ }
+ if (fd == 0)
+ {
+ qWarning() << Q_FUNC_INFO << "errno:" << errno << smb_path;
+ }
+ return fd;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::openDir() opens a directory
+ * \param context
+ * \param smb_string it must point to a directory full pathname
+ * \return the FileHandler or NULL when it is not possible to open the directory
+ */
+Smb::FileHandler
+SmbUtil::openDir(Smb::Context context, const QString &smb_string)
+{
+ Smb::FileHandler fd = ::smbc_getFunctionOpendir(context)
+ (context, smb_string.toLocal8Bit().constData());
+
+ if (fd == 0)
+ {
+ //try to use an IP address if possible
+ QString ipUrl = NetUtil::urlConvertHostnameToIP(smb_string);
+ if (!ipUrl.isEmpty())
+ {
+ fd = ::smbc_getFunctionOpendir(context)
+ (context, ipUrl.toLocal8Bit().constData());
+ }
+ }
+ if (fd == 0)
+ {
+ qWarning() << Q_FUNC_INFO << "errno:" << errno << smb_string;
+ }
+ return fd;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::closeHandle() closes a open FileHandler created by \ref openDir() or \ref openFile()
+ * \param context
+ * \param fd
+ */
+void SmbUtil::closeHandle(Smb::Context context, Smb::FileHandler fd)
+{
+ if (fd)
+ {
+ ::smbc_getFunctionClose(context)(context, fd);
+ }
+}
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::setAuthenticationCallback() Just sets the authentication function
+ * \param fn
+ */
+void SmbUtil::setAuthenticationCallback(Smb::AuthenticationFunction fn)
+{
+ m_authCallBack = fn;
+}
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::getStatInfo() It gets information about files and directories, similar to POSIX stat(2)
+ *
+ * It looks like smbclient brings no information for directories, it works only for files, in this case the caller
+ * must set valid information in the struct stat.
+ *
+ * The distintion between files and directories is made by \ref openDir() and \ref openFile(), as just one
+ * of them should open the \a smb_path.
+ * For directories which it is supposed to have a content it is necessary to know if it is a
+ * host/share/workgroup or a single directory, for this the \ref guessDirType() is used.
+ *
+ * \param smb_path it must point to a file full pathname file or directory
+ * \param st pointer to a struct stat which will receive the information
+ * \return one of the \ref StatReturn
+ */
+SmbUtil::StatReturn
+SmbUtil::getStatInfo(const QString &smb_path, struct stat* st)
+{
+ Smb::Context context = createContext();
+ Q_ASSERT(context);
+ ::memset(st, 0 , sizeof(struct stat));
+ StatReturn ret = StatInvalid;
+ int slashes = smb_path.count(QDir::separator());
+ Smb::FileHandler fd = 0;
+ // smb:// -> slahes=2 smb/workgroup -> slahes=2 smb://host/share -> slashes=3
+ if ((fd=openDir(context, smb_path)))
+ {
+ if ((ret = guessDirType(context,fd)) == StatDir && slashes == 3)
+ {
+ ret = StatShare;
+ }
+ if (slashes > 2 && (ret == StatShare || ret == StatDir))
+ {
+ /* smbc_getFunctionFstatdir does not work
+ ret = static_cast<StatReturn>(::smbc_getFunctionFstatdir(context)(context,fd, st));
+ */
+ QString ipUrl = NetUtil::urlConvertHostnameToIP(smb_path);
+ if (ipUrl.isEmpty())
+ {
+ ipUrl = smb_path;
+ }
+ (void)static_cast<StatReturn> (::smbc_getFunctionStat(context)(context,ipUrl.toLocal8Bit().constData(), st));
+ }
+ }
+ else
+ if (errno != EACCES && errno != ECONNREFUSED )
+ {
+ if ((fd = openFile(context,smb_path)))
+ {
+ ret = static_cast<StatReturn> (::smbc_getFunctionFstat(context)(context,fd, st));
+ }
+ }
+
+ if (fd)
+ {
+ closeHandle(context, fd);
+ }
+ else
+ {
+ qDebug() << Q_FUNC_INFO << "path:" << smb_path << "errno:" << errno << strerror(errno);
+ switch(errno)
+ {
+ case EACCES:
+ ret = StatNoAccess;
+ break;
+ case ENOENT:
+ case ENODEV:
+ case ECONNREFUSED:
+ ret = StatDoesNotExist;
+ break;
+ default:
+ break;
+ }
+ }
+ deleteContext(context);
+ return ret;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::guessDirType() gets the first directory item to guess the content type
+ * \param context
+ * \param fd an already opened FileHandler of a directory
+ * \return the item type in \ref StatReturn
+ */
+SmbUtil::StatReturn
+SmbUtil::guessDirType(Smb::Context context, Smb::FileHandler fd)
+{
+ struct smbc_dirent *dirent=0;
+ StatReturn ret = StatDone;
+ while (ret == StatDone &&
+ (dirent = smbc_getFunctionReaddir(context)(context, fd)) )
+ {
+ if (!dirent->name[0] && dirent->smbc_type != SMBC_SERVER )
+ {
+ continue;
+ }
+ switch(dirent->smbc_type)
+ {
+ //current item is a Host
+ case SMBC_FILE_SHARE:
+ ret = StatHost;
+ break;
+ //current item is a Workgroup
+ case SMBC_SERVER:
+ ret = StatWorkgroup;
+ break;
+ //current item is Root smb://
+ case SMBC_WORKGROUP:
+ break;
+ //ignore system shares
+ case SMBC_PRINTER_SHARE:
+ case SMBC_COMMS_SHARE:
+ case SMBC_IPC_SHARE:
+ break;
+ //current item is Common directory
+ // or a share, shares are handdled by the caller
+ default:
+ ret = StatDir;
+ break;
+ }
+ }
+ return ret;
+}
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::listContent() Just lists the content of a directory/share/workgroup/hostname
+ * \param smb_path it must point to full pathname directory/share/workgroup/hostname
+ * \param recursive
+ * \param filters a QDir like filter
+ * \return The string list that matches \a filters
+ */
+QStringList SmbUtil::listContent(QString smb_path, bool recursive, QDir::Filters filters , const QStringList &filterNames)
+{
+ QStringList content;
+ Smb::Context context = createContext();
+ Q_ASSERT(context);
+ Smb::FileHandler fd = openDir(context,smb_path);
+ if (fd)
+ {
+ struct smbc_dirent *dirent = 0;
+ const char *cur_name = 0;
+ while ((dirent = smbc_getFunctionReaddir(context)(context, fd)) )
+ {
+ //first check for hidden files
+ if (!(filters & QDir::Hidden) && dirent->name[0] == '.')
+ {
+ continue;
+ }
+ if ( !dirent->name[0] && dirent->smbc_type != SMBC_SERVER)
+ {
+ //it may be a libsmbclient bug
+ continue;
+ }
+ cur_name = dirent->name;
+ QString path;
+ bool itemHasContent = false;
+ switch(dirent->smbc_type)
+ {
+ case SMBC_PRINTER_SHARE:
+ case SMBC_COMMS_SHARE:
+ case SMBC_IPC_SHARE:
+ continue;
+ break;
+ case SMBC_WORKGROUP:
+ case SMBC_SERVER:
+ itemHasContent = true;
+ path = LocationUrl::SmbURL;
+ if (dirent->smbc_type == SMBC_SERVER)
+ {
+ QString goodHostName = findSmBServer(*dirent);
+ //path += NetUtil::normalizeHostName(goodHostName);
+ path += goodHostName;
+ }
+ else
+ {
+ path += cur_name;
+ }
+ break;
+ case SMBC_DIR:
+ if (filters & QDir::Dirs)
+ {
+ bool isDot = ::strcmp(".", cur_name) == 0;
+ bool isDotDot = ::strcmp("..", cur_name) == 0;
+ if( !((filters & QDir::NoDot) && isDot)
+ && !((filters & QDir::NoDotDot) && isDotDot) )
+ {
+ path = smb_path + QDir::separator() + cur_name;
+ if (!isDot && !isDotDot)
+ {
+ itemHasContent = true;
+ }
+ }
+ }
+ break;
+ case SMBC_FILE:
+ case SMBC_LINK:
+ if (filters & QDir::Files)
+ {
+ path = smb_path + QDir::separator() + cur_name;
+ }
+ break;
+ case SMBC_FILE_SHARE:
+ if (checkValidShareName(cur_name))
+ {
+ itemHasContent = true;
+ path = smb_path + QDir::separator() + cur_name;
+ }
+ break;
+ }//switch
+ if (!path.isEmpty())
+ {
+ if (filterNames.isEmpty() || namesMatchFilter(cur_name, filterNames))
+ {
+ content.append(path);
+ }
+ if (recursive && itemHasContent )
+ {
+ content += listContent(path, true, filters, filterNames);
+ }
+ }
+ }//while
+ closeHandle(context, fd);
+ }//if (fd)
+ else
+ {
+ qDebug() << Q_FUNC_INFO << "could not open directory" << smb_path << "errno:" << errno;
+ }
+ deleteContext(context);
+ return content;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::lisShares() Brings the list of all available file shares in the network
+ * \return all available file shares
+ */
+QStringList SmbUtil::lisShares()
+{
+ return walkForShares(LocationUrl::SmbURL);
+}
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::walkForShares() Just a helper function that can be recursive, called by \ref lisShares()
+ * \param smb_path
+ * \return list of shares from a single hostname
+ */
+QStringList SmbUtil::walkForShares(QString smb_path)
+{
+ QStringList content;
+ Smb::Context context = createContext();
+ Q_ASSERT(context);
+ Smb::FileHandler fd = openDir(context,smb_path);
+ if (fd)
+ {
+ struct smbc_dirent *dirent = 0;
+ const char *cur_name = 0;
+ QString path;
+ while ((dirent = smbc_getFunctionReaddir(context)(context, fd)))
+ {
+ cur_name = dirent->name;
+ if ( !dirent->name[0] && dirent->smbc_type != SMBC_SERVER)
+ {
+ //it may be a libsmbclient bug
+ continue;
+ }
+ switch(dirent->smbc_type)
+ {
+ case SMBC_WORKGROUP:
+ case SMBC_SERVER:
+ path = LocationUrl::SmbURL;
+ if (dirent->smbc_type == SMBC_SERVER)
+ {
+ QString goodHostName = findSmBServer(*dirent);
+ //path += NetUtil::normalizeHostName(goodHostName);
+ path += goodHostName;
+ }
+ else
+ {
+ path += cur_name;
+ }
+ content += walkForShares(path);
+ break;
+ case SMBC_FILE_SHARE:
+ if (checkValidShareName(cur_name))
+ {
+ path = smb_path + QDir::separator() + cur_name;
+ content.append(path);
+ }
+ break;
+ }//switch
+ }//while
+ }//if (fd)
+ deleteContext(context);
+ return content;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::checkValidShareName() Helper function to ignore some system shares that should not contain any file
+ *
+ * It is used for \ref lisShares() and \ref listContent()
+ *
+ * \param shareName
+ * \return TRUE if the share has a good name (should contain files), FALSE if it is supposed to be a system share
+ */
+bool SmbUtil::checkValidShareName(const char *shareName)
+{
+ if (::strcmp(shareName, "print$") == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+//===============================================================================================
+/*!
+ * \brief SmbUtil::getStatvfsInfo
+ * \param smb_path it must point to a file full pathname file or directory
+ * \param st pointer to a struct statvfs
+ * \return StatDone in case of success or StatInvalid.
+ */
+SmbUtil::StatReturn
+SmbUtil::getStatvfsInfo(const QString &smb_path, struct statvfs *st)
+{
+ Smb::Context context = createContext();
+ Q_ASSERT(context);
+ ::memset(st, 0 , sizeof(struct statvfs));
+ StatReturn ret = StatInvalid;
+ Smb::FileHandler fd = openDir(context,smb_path);
+ if (fd == 0)
+ {
+ fd = openFile(context, smb_path);
+ }
+ if (fd)
+ {
+ ret = static_cast<StatReturn> (::smbc_getFunctionFstatVFS(context)(context,fd, st));
+ closeHandle(context, fd);
+ }
+ deleteContext(context);
+ return ret;
+}
+
+
+bool SmbUtil::namesMatchFilter(const QString & str, const QStringList &filterNames)
+{
+ bool ret = true;
+ int counter = filterNames.count();
+ while (ret && counter--)
+ {
+ QRegExp regExp(filterNames.at(counter), Qt::CaseSensitive, QRegExp::Wildcard);
+ ret = regExp.exactMatch(str);
+ }
+ return ret;
+}
+
+/*!
+ * \brief SmbUtil::findSmBServer() Helper function to find the server name
+ * \param dirent smbc_dirent & dirent result of smbc_getFunctionReaddir()
+ *
+ * 1. Some smbclient versions (or host configuration) bring dirent.name empty when browsing localhost
+ *
+ * 2. When dirent.name brings the hostname, usually it is limited to 16 characters which will not reacheable in the network
+ * in this case try to get the name from the comment
+ *
+ * \return the hostname
+ */
+QString SmbUtil::findSmBServer(const smbc_dirent & dirent)
+{
+ QString host("localhost");
+ if (dirent.name[0] != 0)
+ {
+ QString name(dirent.name);
+ host = name;
+ QString comment(dirent.comment);
+ if (!comment.isEmpty())
+ {
+ QString fullName = comment.split(QLatin1Char(' '), QString::SkipEmptyParts).first();
+ if (!fullName.isEmpty() && fullName.startsWith(name), Qt::CaseSensitive)
+ {
+ host = fullName;
+ }
+ }
+ }
+ return host.toLower();
+}
=== added file 'src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h'
--- src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h 1970-01-01 00:00:00 +0000
+++ src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h 2015-03-08 12:43:13 +0000
@@ -0,0 +1,130 @@
+/**************************************************************************
+ *
+ * Copyright 2014 Canonical Ltd.
+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * File: smbutil.h
+ * Date: 20/11/2014
+ */
+
+#ifndef SMBUTIL_H
+#define SMBUTIL_H
+
+#include <libsmbclient.h>
+
+#include <QStringList>
+#include <QDir>
+
+class QUrl;
+class NetAuthenticationData;
+class NetAuthenticationDataList;
+struct stat;
+
+
+namespace Smb
+{
+ typedef SMBCCTX * Context;
+ typedef SMBCFILE * FileHandler;
+ typedef void (*AuthenticationFunction) (const char *server,
+ const char *share,
+ char *wrkgrp,
+ int wrkgrplen,
+ char *user,
+ int userlen,
+ char *passwd,
+ int passwdlen);
+}
+
+
+/*!
+ * \brief The SmbUtil class provides the interface through the libsmbclient functions
+ *
+ * Some documentation can found at:
+ * \link http://www.samba.org/samba/docs/man/manpages-3/libsmbclient.7.html
+ * \link https://github.com/Zentyal/samba/tree/master/examples/libsmbclient
+ *
+ */
+class SmbUtil
+{
+public:
+ SmbUtil();
+ SmbUtil(Smb::AuthenticationFunction fn);
+ SmbUtil(const QString& authUser, const QString& authPassword);
+ SmbUtil(const QUrl& smbUrl, Smb::AuthenticationFunction fn = 0); //may have smb:://user::password@host/..
+ ~SmbUtil();
+
+public:
+ enum StatReturn
+ {
+ StatInvalid = -3,
+ StatDoesNotExist= -2,
+ StatNoAccess= -1,
+ StatDone=0, // already done
+ StatDir,
+ StatHost,
+ StatWorkgroup,
+ StatShare
+ };
+
+public:
+ Smb::Context createContext();
+ void deleteContext(Smb::Context context);
+ void setAuthenticationCallback(Smb::AuthenticationFunction fn);
+ StatReturn getStatInfo(const QString &smb_path, struct stat *st);
+ StatReturn getStatvfsInfo(const QString& smb_path, struct statvfs *st);
+ Smb::FileHandler openDir(Smb::Context context, const QString& smb_string);
+ Smb::FileHandler openFile(Smb::Context context,const QString& smb_path,
+ int flags = O_RDONLY, mode_t mode = 0);
+ void closeHandle(Smb::Context context, Smb::FileHandler fd);
+ QStringList lisShares();
+ QStringList listContent(QString smb_path,
+ bool recursive = false,
+ QDir::Filters filters = QDir::AllEntries | QDir::NoDotAndDotDot,
+ const QStringList& filterNames = QStringList());
+
+
+private:
+ StatReturn guessDirType(Smb::Context context, Smb::FileHandler fd);
+ bool checkValidShareName(const char *shareName);
+ QStringList walkForShares(QString smb_path);
+ QString findSmBServer(const smbc_dirent&);
+
+
+private:
+ static void authenticateCallBack(
+ const char *server,
+ const char *share,
+ char *wrkgrp,
+ int wrkgrplen,
+ char *user,
+ int userlen,
+ char *passwd,
+ int passwdlen);
+
+protected:
+ void init(const QString& user, const QString& password, Smb::AuthenticationFunction fn);
+ bool namesMatchFilter(const QString& str, const QStringList& filterNames);
+
+private:
+ Smb::AuthenticationFunction m_authCallBack;
+
+
+#if defined(REGRESSION_TEST_QSAMBACLIENT)
+ friend class TestQSambaSuite;
+#endif
+
+};
+
+#endif // SMBUTIL_H
Follow ups