|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Project: SMB kioslave for KDE2
|
|
|
|
//
|
|
|
|
// File: kio_smb_browse.cpp
|
|
|
|
//
|
|
|
|
// Abstract: member function implementations for SMBSlave that deal with
|
|
|
|
// SMB browsing
|
|
|
|
//
|
|
|
|
// Author(s): Matthew Peterson <mpeterson@caldera.com>
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright (c) 2000 Caldera Systems, Inc.
|
|
|
|
//
|
|
|
|
// 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.1 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 Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; see the file COPYING. If not, please obtain
|
|
|
|
// a copy from http://www.gnu.org/copyleft/gpl.html
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <grp.h>
|
|
|
|
|
|
|
|
#include <tqtextcodec.h>
|
|
|
|
|
|
|
|
#include <kglobal.h>
|
|
|
|
|
|
|
|
#include "kio_smb.h"
|
|
|
|
#include "kio_smb_internal.h"
|
|
|
|
|
|
|
|
using namespace KIO;
|
|
|
|
|
|
|
|
int SMBSlave::cache_stat(const SMBUrl &url, struct stat* st )
|
|
|
|
{
|
|
|
|
int result = smbc_stat( url.toSmbcUrl(), st);
|
|
|
|
kdDebug(KIO_SMB) << "smbc_stat " << url << " " << errno << " " << result << endl;
|
|
|
|
kdDebug(KIO_SMB) << "size " << (KIO::filesize_t)st->st_size << endl;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool SMBSlave::browse_stat_path(const SMBUrl& _url, UDSEntry& udsentry, bool ignore_errors)
|
|
|
|
// Returns: true on success, false on failure
|
|
|
|
{
|
|
|
|
UDSAtom udsatom;
|
|
|
|
|
|
|
|
SMBUrl url = _url;
|
|
|
|
|
|
|
|
if(cache_stat(url, &st) == 0)
|
|
|
|
{
|
|
|
|
if(!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
|
|
|
|
{
|
|
|
|
kdDebug(KIO_SMB)<<"SMBSlave::browse_stat_path mode: "<<st.st_mode<<endl;
|
|
|
|
warning(i18n("%1:\n"
|
|
|
|
"Unknown file type, neither directory or file.").arg(url.prettyURL()));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
udsatom.m_uds = KIO::UDS_FILE_TYPE;
|
|
|
|
udsatom.m_long = st.st_mode & S_IFMT;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = KIO::UDS_SIZE;
|
|
|
|
udsatom.m_long = st.st_size;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = KIO::UDS_USER;
|
|
|
|
uid_t uid = st.st_uid;
|
|
|
|
struct passwd *user = getpwuid( uid );
|
|
|
|
if ( user )
|
|
|
|
udsatom.m_str = user->pw_name;
|
|
|
|
else
|
|
|
|
udsatom.m_str = TQString::number( uid );
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = KIO::UDS_GROUP;
|
|
|
|
gid_t gid = st.st_gid;
|
|
|
|
struct group *grp = getgrgid( gid );
|
|
|
|
if ( grp )
|
|
|
|
udsatom.m_str = grp->gr_name;
|
|
|
|
else
|
|
|
|
udsatom.m_str = TQString::number( gid );
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = KIO::UDS_ACCESS;
|
|
|
|
udsatom.m_long = st.st_mode & 07777;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = UDS_MODIFICATION_TIME;
|
|
|
|
udsatom.m_long = st.st_mtime;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = UDS_ACCESS_TIME;
|
|
|
|
udsatom.m_long = st.st_atime;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
udsatom.m_uds = UDS_CREATION_TIME;
|
|
|
|
udsatom.m_long = st.st_ctime;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!ignore_errors) {
|
|
|
|
if (errno == EPERM || errno == EACCES)
|
|
|
|
if (checkPassword(url)) {
|
|
|
|
redirection( url );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
reportError(url);
|
|
|
|
} else if (errno == ENOENT || errno == ENOTDIR) {
|
|
|
|
warning(i18n("File does not exist: %1").arg(url.url()));
|
|
|
|
}
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::browse_stat_path ERROR!!"<< endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void SMBSlave::stat( const KURL& kurl )
|
|
|
|
{
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::stat on "<< kurl << endl;
|
|
|
|
// make a valid URL
|
|
|
|
KURL url = checkURL(kurl);
|
|
|
|
|
|
|
|
// if URL is not valid we have to redirect to correct URL
|
|
|
|
if (url != kurl)
|
|
|
|
{
|
|
|
|
kdDebug() << "redirection " << url << endl;
|
|
|
|
redirection(url);
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_current_url = url;
|
|
|
|
|
|
|
|
UDSAtom udsatom;
|
|
|
|
UDSEntry udsentry;
|
|
|
|
// Set name
|
|
|
|
udsatom.m_uds = KIO::UDS_NAME;
|
|
|
|
udsatom.m_str = kurl.fileName();
|
|
|
|
udsentry.append( udsatom );
|
|
|
|
|
|
|
|
switch(m_current_url.getType())
|
|
|
|
{
|
|
|
|
case SMBURLTYPE_UNKNOWN:
|
|
|
|
error(ERR_MALFORMED_URL,m_current_url.prettyURL());
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case SMBURLTYPE_ENTIRE_NETWORK:
|
|
|
|
case SMBURLTYPE_WORKGROUP_OR_SERVER:
|
|
|
|
udsatom.m_uds = KIO::UDS_FILE_TYPE;
|
|
|
|
udsatom.m_long = S_IFDIR;
|
|
|
|
udsentry.append(udsatom);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SMBURLTYPE_SHARE_OR_PATH:
|
|
|
|
if (browse_stat_path(m_current_url, udsentry, false))
|
|
|
|
break;
|
|
|
|
else {
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::stat ERROR!!"<< endl;
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::stat UNKNOWN " << url << endl;
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
statEntry(udsentry);
|
|
|
|
finished();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
// TODO: complete checking
|
|
|
|
KURL SMBSlave::checkURL(const KURL& kurl) const
|
|
|
|
{
|
|
|
|
kdDebug(KIO_SMB) << "checkURL " << kurl << endl;
|
|
|
|
TQString surl = kurl.url();
|
|
|
|
if (surl.startsWith("smb:/")) {
|
|
|
|
if (surl.length() == 5) // just the above
|
|
|
|
return kurl; // unchanged
|
|
|
|
|
|
|
|
if (surl.at(5) != '/') {
|
|
|
|
surl = "smb://" + surl.mid(5);
|
|
|
|
kdDebug(KIO_SMB) << "checkURL return1 " << surl << " " << KURL(surl) << endl;
|
|
|
|
return KURL(surl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// smb:/ normaly have no userinfo
|
|
|
|
// we must redirect ourself to remove the username and password
|
|
|
|
if (surl.tqcontains('@') && !surl.tqcontains("smb://")) {
|
|
|
|
KURL url(kurl);
|
|
|
|
url.setPath("/"+kurl.url().right( kurl.url().length()-kurl.url().tqfind('@') -1));
|
|
|
|
TQString userinfo = kurl.url().mid(5, kurl.url().tqfind('@')-5);
|
|
|
|
if(userinfo.tqcontains(':')) {
|
|
|
|
url.setUser(userinfo.left(userinfo.tqfind(':')));
|
|
|
|
url.setPass(userinfo.right(userinfo.length()-userinfo.tqfind(':')-1));
|
|
|
|
} else {
|
|
|
|
url.setUser(userinfo);
|
|
|
|
}
|
|
|
|
kdDebug(KIO_SMB) << "checkURL return2 " << url << endl;
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no emtpy path
|
|
|
|
KURL url(kurl);
|
|
|
|
|
|
|
|
if (url.path().isEmpty())
|
|
|
|
url.setPath("/");
|
|
|
|
|
|
|
|
kdDebug(KIO_SMB) << "checkURL return3 " << url << endl;
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SMBSlave::reportError(const SMBUrl &url)
|
|
|
|
{
|
|
|
|
kdDebug(KIO_SMB) << "reportError " << url << " " << perror << endl;
|
|
|
|
switch(errno)
|
|
|
|
{
|
|
|
|
case ENOENT:
|
|
|
|
if (url.getType() == SMBURLTYPE_ENTIRE_NETWORK)
|
|
|
|
error( ERR_SLAVE_DEFINED, i18n("Unable to find any workgroups in your local network. This might be caused by an enabled firewall."));
|
|
|
|
else
|
|
|
|
error( ERR_DOES_NOT_EXIST, url.prettyURL());
|
|
|
|
break;
|
|
|
|
#ifdef ENOMEDIUM
|
|
|
|
case ENOMEDIUM:
|
|
|
|
error( ERR_SLAVE_DEFINED,
|
|
|
|
i18n( "No media in device for %1" ).arg( url.prettyURL() ) );
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef EHOSTDOWN
|
|
|
|
case EHOSTDOWN:
|
|
|
|
#endif
|
|
|
|
case ECONNREFUSED:
|
|
|
|
error( ERR_SLAVE_DEFINED,
|
|
|
|
i18n( "Could not connect to host for %1" ).arg( url.prettyURL() ) );
|
|
|
|
break;
|
|
|
|
case ENOTDIR:
|
|
|
|
error( ERR_CANNOT_ENTER_DIRECTORY, url.prettyURL());
|
|
|
|
break;
|
|
|
|
case EFAULT:
|
|
|
|
case EINVAL:
|
|
|
|
error( ERR_DOES_NOT_EXIST, url.prettyURL());
|
|
|
|
break;
|
|
|
|
case EPERM:
|
|
|
|
case EACCES:
|
|
|
|
error( ERR_ACCESS_DENIED, url.prettyURL() );
|
|
|
|
break;
|
|
|
|
case EIO:
|
|
|
|
case ENETUNREACH:
|
|
|
|
if ( url.getType() == SMBURLTYPE_ENTIRE_NETWORK || url.getType() == SMBURLTYPE_WORKGROUP_OR_SERVER )
|
|
|
|
error( ERR_SLAVE_DEFINED, i18n( "Error while connecting to server responsible for %1" ).arg( url.prettyURL() ) );
|
|
|
|
else
|
|
|
|
error( ERR_CONNECTION_BROKEN, url.prettyURL());
|
|
|
|
break;
|
|
|
|
case ENOMEM:
|
|
|
|
error( ERR_OUT_OF_MEMORY, url.prettyURL() );
|
|
|
|
break;
|
|
|
|
case ENODEV:
|
|
|
|
error( ERR_SLAVE_DEFINED, i18n("Share could not be found on given server"));
|
|
|
|
break;
|
|
|
|
case EBADF:
|
|
|
|
error( ERR_INTERNAL, i18n("BAD File descriptor"));
|
|
|
|
break;
|
|
|
|
case ETIMEDOUT:
|
|
|
|
error( ERR_SERVER_TIMEOUT, url.host() );
|
|
|
|
break;
|
|
|
|
#ifdef ENOTUNIQ
|
|
|
|
case ENOTUNIQ:
|
|
|
|
error( ERR_SLAVE_DEFINED, i18n( "The given name could not be resolved to a unique server. "
|
|
|
|
"Make sure your network is setup without any name conflicts "
|
|
|
|
"between names used by Windows and by UNIX name resolution." ) );
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 0: // success
|
|
|
|
error( ERR_INTERNAL, i18n("libsmbclient reported an error, but did not specify "
|
|
|
|
"what the problem is. This might indicate a severe problem "
|
|
|
|
"with your network - but also might indicate a problem with "
|
|
|
|
"libsmbclient.\n"
|
|
|
|
"If you want to help us, please provide a tcpdump of the "
|
|
|
|
"network interface while you try to browse (be aware that "
|
|
|
|
"it might contain private data, so do not post it if you are "
|
|
|
|
"unsure about that - you can send it privately to the developers "
|
|
|
|
"if they ask for it)") );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error( ERR_INTERNAL, i18n("Unknown error condition in stat: %1").arg(TQString::fromLocal8Bit( strerror(errno))) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void SMBSlave::listDir( const KURL& kurl )
|
|
|
|
{
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::listDir on " << kurl << endl;
|
|
|
|
|
|
|
|
// check (correct) URL
|
|
|
|
KURL url = checkURL(kurl);
|
|
|
|
// if URL is not valid we have to redirect to correct URL
|
|
|
|
if (url != kurl)
|
|
|
|
{
|
|
|
|
redirection(url);
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_current_url = kurl;
|
|
|
|
|
|
|
|
int dirfd;
|
|
|
|
struct smbc_dirent *dirp = NULL;
|
|
|
|
UDSEntry udsentry;
|
|
|
|
UDSAtom atom;
|
|
|
|
|
|
|
|
dirfd = smbc_opendir( m_current_url.toSmbcUrl() );
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::listDir open " << m_current_url.toSmbcUrl() << " " << m_current_url.getType() << " " << dirfd << endl;
|
|
|
|
if(dirfd >= 0)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
kdDebug(KIO_SMB) << "smbc_readdir " << endl;
|
|
|
|
dirp = smbc_readdir(dirfd);
|
|
|
|
if(dirp == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Set name
|
|
|
|
atom.m_uds = KIO::UDS_NAME;
|
|
|
|
TQString dirpName = TQString::fromUtf8( dirp->name );
|
|
|
|
// We cannot trust dirp->commentlen has it might be with or without the NUL character
|
|
|
|
// See KDE bug #111430 and Samba bug #3030
|
|
|
|
TQString comment = TQString::fromUtf8( dirp->comment );
|
|
|
|
if ( dirp->smbc_type == SMBC_SERVER || dirp->smbc_type == SMBC_WORKGROUP ) {
|
|
|
|
atom.m_str = dirpName.lower();
|
|
|
|
atom.m_str.at( 0 ) = dirpName.at( 0 ).upper();
|
|
|
|
if ( !comment.isEmpty() && dirp->smbc_type == SMBC_SERVER )
|
|
|
|
atom.m_str += " (" + comment + ")";
|
|
|
|
} else
|
|
|
|
atom.m_str = dirpName;
|
|
|
|
|
|
|
|
kdDebug(KIO_SMB) << "dirp->name " << dirp->name << " " << dirpName << " '" << comment << "'" << " " << dirp->smbc_type << endl;
|
|
|
|
|
|
|
|
udsentry.append( atom );
|
|
|
|
if (atom.m_str.upper()=="IPC$" || atom.m_str=="." || atom.m_str == ".." ||
|
|
|
|
atom.m_str.upper() == "ADMIN$" || atom.m_str.lower() == "printer$" || atom.m_str.lower() == "print$" )
|
|
|
|
{
|
|
|
|
// fprintf(stderr,"----------- hide: -%s-\n",dirp->name);
|
|
|
|
// do nothing and hide the hidden shares
|
|
|
|
}
|
|
|
|
else if(dirp->smbc_type == SMBC_FILE)
|
|
|
|
{
|
|
|
|
// Set stat information
|
|
|
|
m_current_url.addPath(dirpName);
|
|
|
|
browse_stat_path(m_current_url, udsentry, true);
|
|
|
|
m_current_url.cd("..");
|
|
|
|
|
|
|
|
// Call base class to list entry
|
|
|
|
listEntry(udsentry, false);
|
|
|
|
}
|
|
|
|
else if(dirp->smbc_type == SMBC_DIR)
|
|
|
|
{
|
|
|
|
m_current_url.addPath(dirpName);
|
|
|
|
browse_stat_path(m_current_url, udsentry, true);
|
|
|
|
m_current_url.cd("..");
|
|
|
|
|
|
|
|
// Call base class to list entry
|
|
|
|
listEntry(udsentry, false);
|
|
|
|
}
|
|
|
|
else if(dirp->smbc_type == SMBC_SERVER ||
|
|
|
|
dirp->smbc_type == SMBC_FILE_SHARE)
|
|
|
|
{
|
|
|
|
// Set type
|
|
|
|
atom.m_uds = KIO::UDS_FILE_TYPE;
|
|
|
|
atom.m_long = S_IFDIR;
|
|
|
|
udsentry.append( atom );
|
|
|
|
|
|
|
|
// Set permissions
|
|
|
|
atom.m_uds = KIO::UDS_ACCESS;
|
|
|
|
atom.m_long = (S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH);
|
|
|
|
udsentry.append(atom);
|
|
|
|
|
|
|
|
if (dirp->smbc_type == SMBC_SERVER) {
|
|
|
|
atom.m_uds = KIO::UDS_URL;
|
|
|
|
// TQString workgroup = m_current_url.host().upper();
|
|
|
|
KURL u("smb:/");
|
|
|
|
u.setHost(dirpName);
|
|
|
|
atom.m_str = u.url();
|
|
|
|
|
|
|
|
// when libsmbclient knows
|
|
|
|
// atom.m_str = TQString("smb://%1?WORKGROUP=%2").arg(dirpName).arg(workgroup.upper());
|
|
|
|
kdDebug(KIO_SMB) << "list item " << atom.m_str << endl;
|
|
|
|
udsentry.append(atom);
|
|
|
|
|
|
|
|
atom.m_uds = KIO::UDS_MIME_TYPE;
|
|
|
|
atom.m_str = TQString::tqfromLatin1("application/x-smb-server");
|
|
|
|
udsentry.append(atom);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call base class to list entry
|
|
|
|
listEntry(udsentry, false);
|
|
|
|
}
|
|
|
|
else if(dirp->smbc_type == SMBC_WORKGROUP)
|
|
|
|
{
|
|
|
|
// Set type
|
|
|
|
atom.m_uds = KIO::UDS_FILE_TYPE;
|
|
|
|
atom.m_long = S_IFDIR;
|
|
|
|
udsentry.append( atom );
|
|
|
|
|
|
|
|
// Set permissions
|
|
|
|
atom.m_uds = KIO::UDS_ACCESS;
|
|
|
|
atom.m_long = (S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH);
|
|
|
|
udsentry.append(atom);
|
|
|
|
|
|
|
|
atom.m_uds = KIO::UDS_MIME_TYPE;
|
|
|
|
atom.m_str = TQString::tqfromLatin1("application/x-smb-workgroup");
|
|
|
|
udsentry.append(atom);
|
|
|
|
|
|
|
|
atom.m_uds = KIO::UDS_URL;
|
|
|
|
// TQString workgroup = m_current_url.host().upper();
|
|
|
|
KURL u("smb:/");
|
|
|
|
u.setHost(dirpName);
|
|
|
|
atom.m_str = u.url();
|
|
|
|
udsentry.append(atom);
|
|
|
|
|
|
|
|
// Call base class to list entry
|
|
|
|
listEntry(udsentry, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdDebug(KIO_SMB) << "SMBSlave::listDir SMBC_UNKNOWN :" << dirpName << endl;
|
|
|
|
// TODO: we don't handle SMBC_IPC_SHARE, SMBC_PRINTER_SHARE
|
|
|
|
// SMBC_LINK, SMBC_COMMS_SHARE
|
|
|
|
//SlaveBase::error(ERR_INTERNAL, TEXT_UNSUPPORTED_FILE_TYPE);
|
|
|
|
// continue;
|
|
|
|
}
|
|
|
|
udsentry.clear();
|
|
|
|
} while (dirp); // checked already in the head
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
smbc_closedir(dirfd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (errno == EPERM || errno == EACCES)
|
|
|
|
if (checkPassword(m_current_url)) {
|
|
|
|
redirection( m_current_url );
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reportError(m_current_url);
|
|
|
|
finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
listEntry(udsentry, true);
|
|
|
|
finished();
|
|
|
|
}
|
|
|
|
|