2 /////////////////////////////////////////////////////////////////////////////
4 // Project: SMB kioslave for KDE2
6 // File: kio_smb_browse.cpp
8 // Abstract: member function implementations for SMBSlave that deal with
11 // Author(s): Matthew Peterson <mpeterson@caldera.com>
13 //---------------------------------------------------------------------------
15 // Copyright (c) 2000 Caldera Systems, Inc.
17 // This program is free software; you can redistribute it and/or modify it
18 // under the terms of the GNU General Public License as published by the
19 // Free Software Foundation; either version 2.1 of the License, or
20 // (at your option) any later version.
22 // This program is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU Lesser General Public License for more details.
27 // You should have received a copy of the GNU General Public License
28 // along with this program; see the file COPYING. If not, please obtain
29 // a copy from http://www.gnu.org/copyleft/gpl.html
31 /////////////////////////////////////////////////////////////////////////////
41 #include "kio_smb_internal.h"
45 int SMBSlave::cache_stat(const SMBUrl
&url
, struct stat
* st
)
48 int result
= smbc_stat( url
.toSmbcUrl(), st
);
54 kDebug(KIO_SMB
) << "size " << (KIO::filesize_t
)st
->st_size
;
58 //---------------------------------------------------------------------------
59 bool SMBSlave::browse_stat_path(const SMBUrl
& _url
, UDSEntry
& udsentry
, bool ignore_errors
)
60 // Returns: true on success, false on failure
64 int cacheStatErr
= cache_stat(url
, &st
);
67 if(!S_ISDIR(st
.st_mode
) && !S_ISREG(st
.st_mode
))
69 kDebug(KIO_SMB
)<<"SMBSlave::browse_stat_path mode: "<<st
.st_mode
;
71 "Unknown file type, neither directory or file.", url
.prettyUrl()));
75 udsentry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, st
.st_mode
& S_IFMT
);
76 udsentry
.insert(KIO::UDSEntry::UDS_SIZE
, st
.st_size
);
79 uid_t uid
= st
.st_uid
;
80 struct passwd
*user
= getpwuid( uid
);
84 str
= QString::number( uid
);
85 udsentry
.insert(KIO::UDSEntry::UDS_USER
, str
);
87 gid_t gid
= st
.st_gid
;
88 struct group
*grp
= getgrgid( gid
);
92 str
= QString::number( gid
);
93 udsentry
.insert(KIO::UDSEntry::UDS_GROUP
, str
);
95 udsentry
.insert(KIO::UDSEntry::UDS_ACCESS
, st
.st_mode
& 07777);
96 udsentry
.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME
, st
.st_mtime
);
97 udsentry
.insert(KIO::UDSEntry::UDS_ACCESS_TIME
, st
.st_atime
);
98 // No, st_ctime is not UDS_CREATION_TIME...
102 if (!ignore_errors
) {
103 if (cacheStatErr
== EPERM
|| cacheStatErr
== EACCES
)
104 if (checkPassword(url
)) {
109 reportError(url
, cacheStatErr
);
110 } else if (cacheStatErr
== ENOENT
|| cacheStatErr
== ENOTDIR
) {
111 warning(i18n("File does not exist: %1", url
.url()));
113 kDebug(KIO_SMB
) << "SMBSlave::browse_stat_path ERROR!!";
120 //===========================================================================
121 void SMBSlave::stat( const KUrl
& kurl
)
123 kDebug(KIO_SMB
) << "SMBSlave::stat on "<< kurl
;
125 KUrl url
= checkURL(kurl
);
127 // if URL is not valid we have to redirect to correct URL
130 kDebug() << "redirection " << url
;
140 udsentry
.insert( KIO::UDSEntry::UDS_NAME
, kurl
.fileName() );
142 switch(m_current_url
.getType())
144 case SMBURLTYPE_UNKNOWN
:
145 error(ERR_MALFORMED_URL
,m_current_url
.prettyUrl());
149 case SMBURLTYPE_ENTIRE_NETWORK
:
150 case SMBURLTYPE_WORKGROUP_OR_SERVER
:
151 udsentry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
154 case SMBURLTYPE_SHARE_OR_PATH
:
155 if (browse_stat_path(m_current_url
, udsentry
, false))
158 kDebug(KIO_SMB
) << "SMBSlave::stat ERROR!!";
163 kDebug(KIO_SMB
) << "SMBSlave::stat UNKNOWN " << url
;
172 //===========================================================================
173 // TODO: complete checking
174 KUrl
SMBSlave::checkURL(const KUrl
& kurl
) const
176 kDebug(KIO_SMB
) << "checkURL " << kurl
;
177 QString surl
= kurl
.url();
178 if (surl
.startsWith("smb:/")) {
179 if (surl
.length() == 5) // just the above
180 return kurl
; // unchanged
182 if (surl
.at(5) != '/') {
183 surl
= "smb://" + surl
.mid(5);
184 kDebug(KIO_SMB
) << "checkURL return1 " << surl
<< " " << KUrl(surl
);
189 // smb:/ normaly have no userinfo
190 // we must redirect ourself to remove the username and password
191 if (surl
.contains('@') && !surl
.contains("smb://")) {
193 url
.setPath('/'+kurl
.url().right( kurl
.url().length()-kurl
.url().indexOf('@') -1));
194 QString userinfo
= kurl
.url().mid(5, kurl
.url().indexOf('@')-5);
195 if(userinfo
.contains(':')) {
196 url
.setUser(userinfo
.left(userinfo
.indexOf(':')));
197 url
.setPass(userinfo
.right(userinfo
.length()-userinfo
.indexOf(':')-1));
199 url
.setUser(userinfo
);
201 kDebug(KIO_SMB
) << "checkURL return2 " << url
;
208 if (url
.path().isEmpty())
211 kDebug(KIO_SMB
) << "checkURL return3 " << url
;
215 void SMBSlave::reportError(const SMBUrl
&url
, const int &errNum
)
217 kDebug(KIO_SMB
) << "errNum" << errNum
;
222 if (url
.getType() == SMBURLTYPE_ENTIRE_NETWORK
)
223 error( ERR_SLAVE_DEFINED
, i18n("Unable to find any workgroups in your local network. This might be caused by an enabled firewall."));
225 error( ERR_DOES_NOT_EXIST
, url
.prettyUrl());
229 error( ERR_SLAVE_DEFINED
,
230 i18n( "No media in device for %1", url
.prettyUrl() ) );
237 error( ERR_SLAVE_DEFINED
,
238 i18n( "Could not connect to host for %1", url
.prettyUrl() ) );
241 error( ERR_CANNOT_ENTER_DIRECTORY
, url
.prettyUrl());
245 error( ERR_DOES_NOT_EXIST
, url
.prettyUrl());
249 error( ERR_ACCESS_DENIED
, url
.prettyUrl() );
253 if ( url
.getType() == SMBURLTYPE_ENTIRE_NETWORK
|| url
.getType() == SMBURLTYPE_WORKGROUP_OR_SERVER
)
254 error( ERR_SLAVE_DEFINED
, i18n( "Error while connecting to server responsible for %1", url
.prettyUrl() ) );
256 error( ERR_CONNECTION_BROKEN
, url
.prettyUrl());
259 error( ERR_OUT_OF_MEMORY
, url
.prettyUrl() );
262 error( ERR_SLAVE_DEFINED
, i18n("Share could not be found on given server"));
265 error( ERR_INTERNAL
, i18n("BAD File descriptor"));
268 error( ERR_SERVER_TIMEOUT
, url
.host() );
272 error( ERR_SLAVE_DEFINED
, i18n( "The given name could not be resolved to a unique server. "
273 "Make sure your network is setup without any name conflicts "
274 "between names used by Windows and by UNIX name resolution." ) );
278 error( ERR_INTERNAL
, i18n("libsmbclient reported an error, but did not specify "
279 "what the problem is. This might indicate a severe problem "
280 "with your network - but also might indicate a problem with "
282 "If you want to help us, please provide a tcpdump of the "
283 "network interface while you try to browse (be aware that "
284 "it might contain private data, so do not post it if you are "
285 "unsure about that - you can send it privately to the developers "
286 "if they ask for it)") );
289 error( ERR_INTERNAL
, i18n("Unknown error condition in stat: %1", QString::fromLocal8Bit( strerror(errNum
))) );
293 //===========================================================================
294 void SMBSlave::listDir( const KUrl
& kurl
)
296 kDebug(KIO_SMB
) << "SMBSlave::listDir on " << kurl
;
299 // check (correct) URL
300 KUrl url
= checkURL(kurl
);
301 // if URL is not valid we have to redirect to correct URL
309 m_current_url
= kurl
;
312 struct smbc_dirent
*dirp
= NULL
;
315 dirfd
= smbc_opendir( m_current_url
.toSmbcUrl() );
322 kDebug(KIO_SMB
) << "SMBSlave::listDir open " << m_current_url
.toSmbcUrl() << " " << m_current_url
.getType() << " " << dirfd
;
326 kDebug(KIO_SMB
) << "smbc_readdir ";
327 dirp
= smbc_readdir(dirfd
);
333 QString dirpName
= QString::fromUtf8( dirp
->name
);
334 // We cannot trust dirp->commentlen has it might be with or without the NUL character
335 // See KDE bug #111430 and Samba bug #3030
336 QString comment
= QString::fromUtf8( dirp
->comment
);
337 if ( dirp
->smbc_type
== SMBC_SERVER
|| dirp
->smbc_type
== SMBC_WORKGROUP
) {
338 udsName
= dirpName
.toLower();
339 udsName
[0] = dirpName
.at( 0 ).toUpper();
340 if ( !comment
.isEmpty() && dirp
->smbc_type
== SMBC_SERVER
)
341 udsName
+= " (" + comment
+ ')';
345 kDebug(KIO_SMB
) << "dirp->name " << dirp
->name
<< " " << dirpName
<< " '" << comment
<< "'" << " " << dirp
->smbc_type
;
347 udsentry
.insert( KIO::UDSEntry::UDS_NAME
, udsName
);
349 if (udsName
.toUpper()=="IPC$" || udsName
=="." || udsName
== ".." ||
350 udsName
.toUpper() == "ADMIN$" || udsName
.toLower() == "printer$" || udsName
.toLower() == "print$" )
352 // fprintf(stderr,"----------- hide: -%s-\n",dirp->name);
353 // do nothing and hide the hidden shares
355 else if(dirp
->smbc_type
== SMBC_FILE
)
357 // Set stat information
358 m_current_url
.addPath(dirpName
);
359 browse_stat_path(m_current_url
, udsentry
, true);
360 m_current_url
.cd("..");
362 // Call base class to list entry
363 listEntry(udsentry
, false);
365 else if(dirp
->smbc_type
== SMBC_DIR
)
367 m_current_url
.addPath(dirpName
);
368 browse_stat_path(m_current_url
, udsentry
, true);
369 m_current_url
.cd("..");
371 // Call base class to list entry
372 listEntry(udsentry
, false);
374 else if(dirp
->smbc_type
== SMBC_SERVER
||
375 dirp
->smbc_type
== SMBC_FILE_SHARE
)
378 udsentry
.insert( KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
381 udsentry
.insert(KIO::UDSEntry::UDS_ACCESS
, (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
| S_IXOTH
));
383 if (dirp
->smbc_type
== SMBC_SERVER
) {
384 // QString workgroup = m_current_url.host().toUpper();
388 // when libsmbclient knows
389 // u = QString("smb://%1?WORKGROUP=%2").arg(dirpName).arg(workgroup.toUpper());
390 kDebug(KIO_SMB
) << "list item " << u
;
391 udsentry
.insert(KIO::UDSEntry::UDS_URL
, u
.url());
393 udsentry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1("application/x-smb-server"));
396 // Call base class to list entry
397 listEntry(udsentry
, false);
399 else if(dirp
->smbc_type
== SMBC_WORKGROUP
)
402 udsentry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
405 udsentry
.insert(KIO::UDSEntry::UDS_ACCESS
, (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
| S_IXOTH
));
407 udsentry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1("application/x-smb-workgroup"));
409 // QString workgroup = m_current_url.host().toUpper();
412 udsentry
.insert(KIO::UDSEntry::UDS_URL
, u
.url());
414 // Call base class to list entry
415 listEntry(udsentry
, false);
419 kDebug(KIO_SMB
) << "SMBSlave::listDir SMBC_UNKNOWN :" << dirpName
;
420 // TODO: we don't handle SMBC_IPC_SHARE, SMBC_PRINTER_SHARE
421 // SMBC_LINK, SMBC_COMMS_SHARE
422 //SlaveBase::error(ERR_INTERNAL, TEXT_UNSUPPORTED_FILE_TYPE);
426 } while (dirp
); // checked already in the head
429 smbc_closedir(dirfd
);
433 if (errNum
== EPERM
|| errNum
== EACCES
) {
434 if (checkPassword(m_current_url
)) {
435 redirection( m_current_url
);
441 reportError(m_current_url
, errNum
);
446 listEntry(udsentry
, true);