delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kioslave / smb / kio_smb_browse.cpp
blobe874da37a20fda7be8157b3a9adf330320ebf91c
2 /////////////////////////////////////////////////////////////////////////////
3 //
4 // Project: SMB kioslave for KDE2
5 //
6 // File: kio_smb_browse.cpp
7 //
8 // Abstract: member function implementations for SMBSlave that deal with
9 // SMB browsing
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 /////////////////////////////////////////////////////////////////////////////
33 #include <pwd.h>
34 #include <grp.h>
36 #include <QTextCodec>
38 #include <kglobal.h>
40 #include "kio_smb.h"
41 #include "kio_smb_internal.h"
43 using namespace KIO;
45 int SMBSlave::cache_stat(const SMBUrl &url, struct stat* st )
47 int cacheStatErr;
48 int result = smbc_stat( url.toSmbcUrl(), st);
49 if (result == 0){
50 cacheStatErr = 0;
51 } else {
52 cacheStatErr = errno;
54 kDebug(KIO_SMB) << "size " << (KIO::filesize_t)st->st_size;
55 return cacheStatErr;
58 //---------------------------------------------------------------------------
59 bool SMBSlave::browse_stat_path(const SMBUrl& _url, UDSEntry& udsentry, bool ignore_errors)
60 // Returns: true on success, false on failure
62 SMBUrl url = _url;
64 int cacheStatErr = cache_stat(url, &st);
65 if(cacheStatErr == 0)
67 if(!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
69 kDebug(KIO_SMB)<<"SMBSlave::browse_stat_path mode: "<<st.st_mode;
70 warning(i18n("%1:\n"
71 "Unknown file type, neither directory or file.", url.prettyUrl()));
72 return false;
75 udsentry.insert(KIO::UDSEntry::UDS_FILE_TYPE, st.st_mode & S_IFMT);
76 udsentry.insert(KIO::UDSEntry::UDS_SIZE, st.st_size);
78 QString str;
79 uid_t uid = st.st_uid;
80 struct passwd *user = getpwuid( uid );
81 if ( user )
82 str = user->pw_name;
83 else
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 );
89 if ( grp )
90 str = grp->gr_name;
91 else
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...
100 else
102 if (!ignore_errors) {
103 if (cacheStatErr == EPERM || cacheStatErr == EACCES)
104 if (checkPassword(url)) {
105 redirection( url );
106 return false;
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!!";
114 return false;
117 return true;
120 //===========================================================================
121 void SMBSlave::stat( const KUrl& kurl )
123 kDebug(KIO_SMB) << "SMBSlave::stat on "<< kurl;
124 // make a valid URL
125 KUrl url = checkURL(kurl);
127 // if URL is not valid we have to redirect to correct URL
128 if (url != kurl)
130 kDebug() << "redirection " << url;
131 redirection(url);
132 finished();
133 return;
136 m_current_url = url;
138 UDSEntry udsentry;
139 // Set name
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());
146 finished();
147 return;
149 case SMBURLTYPE_ENTIRE_NETWORK:
150 case SMBURLTYPE_WORKGROUP_OR_SERVER:
151 udsentry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
152 break;
154 case SMBURLTYPE_SHARE_OR_PATH:
155 if (browse_stat_path(m_current_url, udsentry, false))
156 break;
157 else {
158 kDebug(KIO_SMB) << "SMBSlave::stat ERROR!!";
159 finished();
160 return;
162 default:
163 kDebug(KIO_SMB) << "SMBSlave::stat UNKNOWN " << url;
164 finished();
165 return;
168 statEntry(udsentry);
169 finished();
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);
185 return 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://")) {
192 KUrl url(kurl);
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));
198 } else {
199 url.setUser(userinfo);
201 kDebug(KIO_SMB) << "checkURL return2 " << url;
202 return url;
205 // no emtpy path
206 KUrl url(kurl);
208 if (url.path().isEmpty())
209 url.setPath("/");
211 kDebug(KIO_SMB) << "checkURL return3 " << url;
212 return url;
215 void SMBSlave::reportError(const SMBUrl &url, const int &errNum)
217 kDebug(KIO_SMB) << "errNum" << errNum;
219 switch(errNum)
221 case ENOENT:
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."));
224 else
225 error( ERR_DOES_NOT_EXIST, url.prettyUrl());
226 break;
227 #ifdef ENOMEDIUM
228 case ENOMEDIUM:
229 error( ERR_SLAVE_DEFINED,
230 i18n( "No media in device for %1", url.prettyUrl() ) );
231 break;
232 #endif
233 #ifdef EHOSTDOWN
234 case EHOSTDOWN:
235 #endif
236 case ECONNREFUSED:
237 error( ERR_SLAVE_DEFINED,
238 i18n( "Could not connect to host for %1", url.prettyUrl() ) );
239 break;
240 case ENOTDIR:
241 error( ERR_CANNOT_ENTER_DIRECTORY, url.prettyUrl());
242 break;
243 case EFAULT:
244 case EINVAL:
245 error( ERR_DOES_NOT_EXIST, url.prettyUrl());
246 break;
247 case EPERM:
248 case EACCES:
249 error( ERR_ACCESS_DENIED, url.prettyUrl() );
250 break;
251 case EIO:
252 case ENETUNREACH:
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() ) );
255 else
256 error( ERR_CONNECTION_BROKEN, url.prettyUrl());
257 break;
258 case ENOMEM:
259 error( ERR_OUT_OF_MEMORY, url.prettyUrl() );
260 break;
261 case ENODEV:
262 error( ERR_SLAVE_DEFINED, i18n("Share could not be found on given server"));
263 break;
264 case EBADF:
265 error( ERR_INTERNAL, i18n("BAD File descriptor"));
266 break;
267 case ETIMEDOUT:
268 error( ERR_SERVER_TIMEOUT, url.host() );
269 break;
270 #ifdef ENOTUNIQ
271 case ENOTUNIQ:
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." ) );
275 break;
276 #endif
277 case 0: // success
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 "
281 "libsmbclient.\n"
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)") );
287 break;
288 default:
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;
297 int errNum = 0;
299 // check (correct) URL
300 KUrl url = checkURL(kurl);
301 // if URL is not valid we have to redirect to correct URL
302 if (url != kurl)
304 redirection(url);
305 finished();
306 return;
309 m_current_url = kurl;
311 int dirfd;
312 struct smbc_dirent *dirp = NULL;
313 UDSEntry udsentry;
315 dirfd = smbc_opendir( m_current_url.toSmbcUrl() );
316 if (dirfd > 0){
317 errNum = 0;
318 } else {
319 errNum = errno;
322 kDebug(KIO_SMB) << "SMBSlave::listDir open " << m_current_url.toSmbcUrl() << " " << m_current_url.getType() << " " << dirfd;
323 if(dirfd >= 0)
325 do {
326 kDebug(KIO_SMB) << "smbc_readdir ";
327 dirp = smbc_readdir(dirfd);
328 if(dirp == 0)
329 break;
331 // Set name
332 QString udsName;
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 + ')';
342 } else
343 udsName = dirpName;
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)
377 // Set type
378 udsentry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
380 // Set permissions
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();
385 KUrl u("smb:/");
386 u.setHost(dirpName);
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)
401 // Set type
402 udsentry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
404 // Set permissions
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();
410 KUrl u("smb:/");
411 u.setHost(dirpName);
412 udsentry.insert(KIO::UDSEntry::UDS_URL, u.url());
414 // Call base class to list entry
415 listEntry(udsentry, false);
417 else
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);
423 // continue;
425 udsentry.clear();
426 } while (dirp); // checked already in the head
428 // clean up
429 smbc_closedir(dirfd);
431 else
433 if (errNum == EPERM || errNum == EACCES) {
434 if (checkPassword(m_current_url)) {
435 redirection( m_current_url );
436 finished();
437 return;
441 reportError(m_current_url, errNum);
442 finished();
443 return;
446 listEntry(udsentry, true);
447 finished();