tdefileitem.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 1999 David Faure <faure@kde.org> 00003 2001 Carsten Pfeiffer <pfeiffer@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 // $Id$ 00021 00022 #include <config.h> 00023 00024 #include <sys/time.h> 00025 #include <pwd.h> 00026 #include <grp.h> 00027 #include <sys/types.h> 00028 00029 #include <assert.h> 00030 #include <unistd.h> 00031 00032 #include "tdefileitem.h" 00033 00034 #include <tqdir.h> 00035 #include <tqfile.h> 00036 #include <tqmap.h> 00037 #include <tqstylesheet.h> 00038 #include <tqimage.h> 00039 00040 #include <kdebug.h> 00041 #include <tdefilemetainfo.h> 00042 #include <ksambashare.h> 00043 #include <knfsshare.h> 00044 #include <tdeglobal.h> 00045 #include <tdeglobalsettings.h> 00046 #include <kiconloader.h> 00047 #include <klargefile.h> 00048 #include <tdelocale.h> 00049 #include <kmimetype.h> 00050 #include <krun.h> 00051 00052 #include "netaccess.h" 00053 00054 #ifdef HAVE_ELFICON 00055 #include "tdelficon.h" 00056 #endif // HAVE_ELFICON 00057 00058 class KFileItem::KFileItemPrivate { 00059 public: 00060 KFileItemPrivate() : commentCached(false) {} 00061 00062 public: 00063 TQString iconName; 00064 TQString comment; 00065 bool commentCached; 00066 }; 00067 00068 KFileItem::KFileItem( const TDEIO::UDSEntry& _entry, const KURL& _url, 00069 bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) : 00070 m_entry( _entry ), 00071 m_url( _url ), 00072 m_pMimeType( 0 ), 00073 m_fileMode( KFileItem::Unknown ), 00074 m_permissions( KFileItem::Unknown ), 00075 m_bMarked( false ), 00076 m_bLink( false ), 00077 m_bIsLocalURL( _url.isLocalFile() ), 00078 m_bMimeTypeKnown( false ), 00079 m_hidden( Auto ), 00080 d(0) 00081 { 00082 readUDSEntry( _urlIsDirectory ); 00083 init( _determineMimeTypeOnDemand ); 00084 } 00085 00086 KFileItem::KFileItem( mode_t _mode, mode_t _permissions, const KURL& _url, bool _determineMimeTypeOnDemand ) : 00087 m_entry(), // warning ! 00088 m_url( _url ), 00089 m_strName( _url.fileName() ), 00090 m_strText( TDEIO::decodeFileName( m_strName ) ), 00091 m_pMimeType( 0 ), 00092 m_fileMode ( _mode ), 00093 m_permissions( _permissions ), 00094 m_bMarked( false ), 00095 m_bLink( false ), 00096 m_bIsLocalURL( _url.isLocalFile() ), 00097 m_bMimeTypeKnown( false ), 00098 m_hidden( Auto ), 00099 d(0) 00100 { 00101 init( _determineMimeTypeOnDemand ); 00102 } 00103 00104 KFileItem::KFileItem( const KURL &url, const TQString &mimeType, mode_t mode ) 00105 : m_url( url ), 00106 m_strName( url.fileName() ), 00107 m_strText( TDEIO::decodeFileName( m_strName ) ), 00108 m_pMimeType( 0 ), 00109 m_fileMode( mode ), 00110 m_permissions( KFileItem::Unknown ), 00111 m_bMarked( false ), 00112 m_bLink( false ), 00113 m_bIsLocalURL( url.isLocalFile() ), 00114 m_bMimeTypeKnown( !mimeType.isEmpty() ), 00115 m_hidden( Auto ), 00116 d(0) 00117 { 00118 if (m_bMimeTypeKnown) { 00119 m_pMimeType = KMimeType::mimeType( mimeType ); 00120 } 00121 00122 init( false ); 00123 } 00124 00125 KFileItem::KFileItem( const KFileItem & item ) : 00126 d(0) 00127 { 00128 assign( item ); 00129 } 00130 00131 KFileItem& KFileItem::operator=( const KFileItem & item ) 00132 { 00133 assign( item ); 00134 return *this; 00135 } 00136 00137 KFileItem::~KFileItem() 00138 { 00139 delete d; 00140 } 00141 00142 void KFileItem::init( bool _determineMimeTypeOnDemand ) 00143 { 00144 m_access = TQString::null; 00145 m_size = (TDEIO::filesize_t) -1; 00146 // metaInfo = KFileMetaInfo(); 00147 for ( int i = 0; i < NumFlags; i++ ) { 00148 m_time[i] = (time_t) -1; 00149 } 00150 00151 // determine mode and/or permissions if unknown 00152 if ( m_fileMode == KFileItem::Unknown || m_permissions == KFileItem::Unknown ) 00153 { 00154 mode_t mode = 0; 00155 if ( m_url.isLocalFile() ) 00156 { 00157 /* directories may not have a slash at the end if 00158 * we want to stat() them; it requires that we 00159 * change into it .. which may not be allowed 00160 * stat("/is/unaccessible") -> rwx------ 00161 * stat("/is/unaccessible/") -> EPERM H.Z. 00162 * This is the reason for the -1 00163 */ 00164 KDE_struct_stat buf; 00165 TQCString path = TQFile::encodeName(m_url.path( -1 )); 00166 if ( KDE_lstat( path.data(), &buf ) == 0 ) 00167 { 00168 mode = buf.st_mode; 00169 if ( S_ISLNK( mode ) ) 00170 { 00171 m_bLink = true; 00172 if ( KDE_stat( path.data(), &buf ) == 0 ) { 00173 mode = buf.st_mode; 00174 } 00175 else { // link pointing to nowhere (see tdeio/file/file.cc) 00176 mode = (S_IFMT-1) | S_IRWXU | S_IRWXG | S_IRWXO; 00177 } 00178 } 00179 // While we're at it, store the times 00180 m_time[ Modification ] = buf.st_mtime; 00181 m_time[ Access ] = buf.st_atime; 00182 if ( m_fileMode == KFileItem::Unknown ) { 00183 m_fileMode = mode & S_IFMT; // extract file type 00184 } 00185 if ( m_permissions == KFileItem::Unknown ) { 00186 m_permissions = mode & 07777; // extract permissions 00187 } 00188 } 00189 } 00190 } 00191 00192 // determine the mimetype 00193 if (!m_pMimeType && !m_url.isEmpty()) 00194 { 00195 bool accurate = false; 00196 bool isLocalURL; 00197 KURL url = mostLocalURL(isLocalURL); 00198 00199 m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL, 00200 // use fast mode if not mimetype on demand 00201 _determineMimeTypeOnDemand, &accurate ); 00202 //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl; 00203 // if we didn't use fast mode, or if we got a result, then this is the mimetype 00204 // otherwise, determineMimeType will be able to do better. 00205 m_bMimeTypeKnown = (!_determineMimeTypeOnDemand) || accurate; 00206 } 00207 } 00208 00209 void KFileItem::readUDSEntry( bool _urlIsDirectory ) 00210 { 00211 // extract the mode and the filename from the TDEIO::UDS Entry 00212 bool UDS_URL_seen = false; 00213 00214 if (&m_entry == NULL) return; 00215 00216 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00217 for( ; it != m_entry.end(); ++it ) { 00218 switch ((*it).m_uds) { 00219 00220 case TDEIO::UDS_FILE_TYPE: 00221 m_fileMode = (mode_t)((*it).m_long); 00222 break; 00223 00224 case TDEIO::UDS_ACCESS: 00225 m_permissions = (mode_t)((*it).m_long); 00226 break; 00227 00228 case TDEIO::UDS_USER: 00229 m_user = ((*it).m_str); 00230 break; 00231 00232 case TDEIO::UDS_GROUP: 00233 m_group = ((*it).m_str); 00234 break; 00235 00236 case TDEIO::UDS_NAME: 00237 m_strName = (*it).m_str; 00238 m_strText = TDEIO::decodeFileName( m_strName ); 00239 break; 00240 00241 case TDEIO::UDS_URL: 00242 UDS_URL_seen = true; 00243 m_url = KURL((*it).m_str); 00244 if ( m_url.isLocalFile() ) { 00245 m_bIsLocalURL = true; 00246 } 00247 break; 00248 00249 case TDEIO::UDS_MIME_TYPE: 00250 m_pMimeType = KMimeType::mimeType((*it).m_str); 00251 m_bMimeTypeKnown = true; 00252 break; 00253 00254 case TDEIO::UDS_GUESSED_MIME_TYPE: 00255 m_guessedMimeType = (*it).m_str; 00256 break; 00257 00258 case TDEIO::UDS_LINK_DEST: 00259 m_bLink = !(*it).m_str.isEmpty(); // we don't store the link dest 00260 break; 00261 00262 case TDEIO::UDS_ICON_NAME: 00263 if ( !d ) { 00264 d = new KFileItemPrivate(); 00265 } 00266 d->iconName = (*it).m_str; 00267 break; 00268 00269 case TDEIO::UDS_HIDDEN: 00270 if ( (*it).m_long ) 00271 m_hidden = Hidden; 00272 else 00273 m_hidden = Shown; 00274 break; 00275 } 00276 } 00277 00278 // avoid creating these QStrings again and again 00279 static const TQString& dot = TDEGlobal::staticQString("."); 00280 if ( _urlIsDirectory && !UDS_URL_seen && !m_strName.isEmpty() && m_strName != dot ) { 00281 m_url.addPath( m_strName ); 00282 } 00283 } 00284 00285 void KFileItem::refresh() 00286 { 00287 m_fileMode = KFileItem::Unknown; 00288 m_permissions = KFileItem::Unknown; 00289 m_pMimeType = 0L; 00290 m_user = TQString::null; 00291 m_group = TQString::null; 00292 m_metaInfo = KFileMetaInfo(); 00293 m_hidden = Auto; 00294 00295 // Basically, we can't trust any information we got while listing. 00296 // Everything could have changed... 00297 // Clearing m_entry makes it possible to detect changes in the size of the file, 00298 // the time information, etc. 00299 m_entry = TDEIO::UDSEntry(); 00300 init( false ); 00301 } 00302 00303 void KFileItem::refreshMimeType() 00304 { 00305 if ( d ) { 00306 d->iconName = TQString::null; 00307 d->comment = TQString::null; 00308 d->commentCached = false; 00309 } 00310 m_pMimeType = 0L; 00311 init( false ); // Will determine the mimetype 00312 } 00313 00314 void KFileItem::setURL( const KURL &url ) 00315 { 00316 m_url = url; 00317 setName( url.fileName() ); 00318 m_bIsLocalURL = m_url.isLocalFile(); 00319 } 00320 00321 void KFileItem::setListerURL( const KURL &url ) 00322 { 00323 m_listerURL = url; 00324 } 00325 00326 void KFileItem::setName( const TQString& name ) 00327 { 00328 m_strName = name; 00329 m_strText = TDEIO::decodeFileName( m_strName ); 00330 } 00331 00332 TQString KFileItem::linkDest() const 00333 { 00334 if (&m_entry == NULL) return TQString::null; 00335 00336 // Extract it from the TDEIO::UDSEntry 00337 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00338 for( ; it != m_entry.end(); ++it ) 00339 if ( (*it).m_uds == TDEIO::UDS_LINK_DEST ) 00340 return (*it).m_str; 00341 // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL] 00342 if ( m_bIsLocalURL ) 00343 { 00344 char buf[1000]; 00345 int n = readlink( TQFile::encodeName(m_url.path( -1 )), buf, sizeof(buf)-1 ); 00346 if ( n != -1 ) 00347 { 00348 buf[ n ] = 0; 00349 return TQFile::decodeName( buf ); 00350 } 00351 } 00352 return TQString::null; 00353 } 00354 00355 TQString KFileItem::localPath() const 00356 { 00357 if ( m_bIsLocalURL ) { 00358 return m_url.path(); 00359 } 00360 else { 00361 if (&m_entry == NULL) { 00362 return TQString::null; 00363 } 00364 00365 // Extract the local path from the TDEIO::UDSEntry 00366 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00367 const TDEIO::UDSEntry::ConstIterator end = m_entry.end(); 00368 for( ; it != end; ++it ) { 00369 if ( (*it).m_uds == TDEIO::UDS_LOCAL_PATH ) { 00370 return (*it).m_str; 00371 } 00372 } 00373 } 00374 00375 // If we still do not have a local URL, use the lister URL 00376 // Without this, Trash functionality will not work with the media:/ tdeioslave! 00377 if ((!m_url.isLocalFile())/* && (m_url.protocol() == "media")*/) { 00378 if (m_listerURL.isLocalFile()) { 00379 return m_listerURL.path(); 00380 } 00381 } 00382 00383 return TQString::null; 00384 } 00385 00386 TDEIO::filesize_t KFileItem::size(bool &exists) const 00387 { 00388 exists = true; 00389 if ( m_size != (TDEIO::filesize_t) -1 ) 00390 return m_size; 00391 00392 if (&m_entry == NULL) return 0L; 00393 00394 // Extract it from the TDEIO::UDSEntry 00395 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00396 for( ; it != m_entry.end(); ++it ) 00397 if ( (*it).m_uds == TDEIO::UDS_SIZE ) { 00398 m_size = (*it).m_long; 00399 return m_size; 00400 } 00401 // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] 00402 if ( m_bIsLocalURL ) 00403 { 00404 KDE_struct_stat buf; 00405 if ( KDE_stat( TQFile::encodeName(m_url.path( -1 )), &buf ) == 0 ) 00406 return buf.st_size; 00407 } 00408 exists = false; 00409 return 0L; 00410 } 00411 00412 bool KFileItem::hasExtendedACL() const 00413 { 00414 if (&m_entry == NULL) return false; 00415 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00416 for( ; it != m_entry.end(); it++ ) 00417 if ( (*it).m_uds == TDEIO::UDS_EXTENDED_ACL ) { 00418 return true; 00419 } 00420 return false; 00421 } 00422 00423 KACL KFileItem::ACL() const 00424 { 00425 if ( hasExtendedACL() ) { 00426 if (&m_entry == NULL) return KACL( m_permissions ); 00427 00428 // Extract it from the TDEIO::UDSEntry 00429 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00430 for( ; it != m_entry.end(); ++it ) 00431 if ( (*it).m_uds == TDEIO::UDS_ACL_STRING ) 00432 return KACL((*it).m_str); 00433 } 00434 // create one from the basic permissions 00435 return KACL( m_permissions ); 00436 } 00437 00438 KACL KFileItem::defaultACL() const 00439 { 00440 if (&m_entry == NULL) return KACL(); 00441 00442 // Extract it from the TDEIO::UDSEntry 00443 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00444 for( ; it != m_entry.end(); ++it ) 00445 if ( (*it).m_uds == TDEIO::UDS_DEFAULT_ACL_STRING ) 00446 return KACL((*it).m_str); 00447 return KACL(); 00448 } 00449 00450 TDEIO::filesize_t KFileItem::size() const 00451 { 00452 bool exists; 00453 return size(exists); 00454 } 00455 00456 time_t KFileItem::time( unsigned int which ) const 00457 { 00458 bool hasTime; 00459 return time(which, hasTime); 00460 } 00461 time_t KFileItem::time( unsigned int which, bool &hasTime ) const 00462 { 00463 hasTime = true; 00464 unsigned int mappedWhich = 0; 00465 00466 switch( which ) { 00467 case TDEIO::UDS_MODIFICATION_TIME: 00468 mappedWhich = Modification; 00469 break; 00470 case TDEIO::UDS_ACCESS_TIME: 00471 mappedWhich = Access; 00472 break; 00473 case TDEIO::UDS_CREATION_TIME: 00474 mappedWhich = Creation; 00475 break; 00476 } 00477 00478 if ( m_time[mappedWhich] != (time_t) -1 ) 00479 return m_time[mappedWhich]; 00480 00481 if (&m_entry == NULL) return static_cast<time_t>(0); 00482 00483 // Extract it from the TDEIO::UDSEntry 00484 TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); 00485 for( ; it != m_entry.end(); ++it ) 00486 if ( (*it).m_uds == which ) { 00487 m_time[mappedWhich] = static_cast<time_t>((*it).m_long); 00488 return m_time[mappedWhich]; 00489 } 00490 00491 // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] 00492 if ( m_bIsLocalURL ) 00493 { 00494 KDE_struct_stat buf; 00495 if ( KDE_stat( TQFile::encodeName(m_url.path(-1)), &buf ) == 0 ) 00496 { 00497 if(which == TDEIO::UDS_CREATION_TIME) { 00498 // We can't determine creation time for local files 00499 hasTime = false; 00500 m_time[mappedWhich] = static_cast<time_t>(0); 00501 return m_time[mappedWhich]; 00502 } 00503 m_time[mappedWhich] = (which == TDEIO::UDS_MODIFICATION_TIME) ? 00504 buf.st_mtime : 00505 /* which == TDEIO::UDS_ACCESS_TIME)*/ 00506 buf.st_atime; 00507 return m_time[mappedWhich]; 00508 } 00509 } 00510 hasTime = false; 00511 return static_cast<time_t>(0); 00512 } 00513 00514 00515 TQString KFileItem::user() const 00516 { 00517 if ( m_user.isEmpty() && m_bIsLocalURL ) 00518 { 00519 KDE_struct_stat buff; 00520 if ( KDE_lstat( TQFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link 00521 { 00522 struct passwd *user = getpwuid( buff.st_uid ); 00523 if ( user != 0L ) 00524 m_user = TQString::fromLocal8Bit(user->pw_name); 00525 } 00526 } 00527 return m_user; 00528 } 00529 00530 TQString KFileItem::group() const 00531 { 00532 #ifdef Q_OS_UNIX 00533 if (m_group.isEmpty() && m_bIsLocalURL ) 00534 { 00535 KDE_struct_stat buff; 00536 if ( KDE_lstat( TQFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link 00537 { 00538 struct group *ge = getgrgid( buff.st_gid ); 00539 if ( ge != 0L ) { 00540 m_group = TQString::fromLocal8Bit(ge->gr_name); 00541 if (m_group.isEmpty()) 00542 m_group.sprintf("%d",ge->gr_gid); 00543 } else 00544 m_group.sprintf("%d",buff.st_gid); 00545 } 00546 } 00547 #endif 00548 return m_group; 00549 } 00550 00551 TQString KFileItem::mimetype() const 00552 { 00553 KFileItem * that = const_cast<KFileItem *>(this); 00554 return that->determineMimeType()->name(); 00555 } 00556 00557 TQString KFileItem::mimetypeFast() const 00558 { 00559 if (isMimeTypeKnown()) { 00560 return mimetype(); 00561 } 00562 else { 00563 return m_pMimeType->name(); 00564 } 00565 } 00566 00567 KMimeType::Ptr KFileItem::mimeTypePtrFast() 00568 { 00569 return m_pMimeType; 00570 } 00571 00572 KMimeType::Ptr KFileItem::determineMimeType() 00573 { 00574 if ( !m_pMimeType || !m_bMimeTypeKnown ) 00575 { 00576 bool isLocalURL; 00577 KURL url = mostLocalURL(isLocalURL); 00578 00579 m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL ); 00580 //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl; 00581 m_bMimeTypeKnown = true; 00582 } 00583 00584 return m_pMimeType; 00585 } 00586 00587 bool KFileItem::isMimeTypeKnown() const 00588 { 00589 // The mimetype isn't known if determineMimeType was never called (on-demand determination) 00590 // or if this fileitem has a guessed mimetype (e.g. ftp symlink) - in which case 00591 // it always remains "not fully determined" 00592 return m_bMimeTypeKnown && m_guessedMimeType.isEmpty(); 00593 } 00594 00595 TQString KFileItem::mimeComment() 00596 { 00597 if (d && (d->commentCached)) return d->comment; 00598 00599 KMimeType::Ptr mType = determineMimeType(); 00600 00601 bool isLocalURL; 00602 KURL url = mostLocalURL(isLocalURL); 00603 00604 TQString comment = mType->comment( url, isLocalURL ); 00605 //kdDebug() << "finding comment for " << url.url() << " : " << m_pMimeType->name() << endl; 00606 if ( !d ) { 00607 d = new KFileItemPrivate(); 00608 } 00609 if (!comment.isEmpty()) { 00610 d->comment = comment; 00611 d->commentCached = true; 00612 } 00613 else { 00614 d->comment = mType->name(); 00615 d->commentCached = true; 00616 } 00617 00618 return d->comment; 00619 } 00620 00621 TQString KFileItem::iconName() 00622 { 00623 if (d && (!d->iconName.isEmpty())) return d->iconName; 00624 00625 bool isLocalURL; 00626 KURL url = mostLocalURL(isLocalURL); 00627 00628 //kdDebug() << "finding icon for " << url.url() << " : " << m_pMimeType->name() << endl; 00629 return determineMimeType()->icon(url, isLocalURL); 00630 } 00631 00632 int KFileItem::overlays() const 00633 { 00634 int _state = 0; 00635 if ( m_bLink ) 00636 _state |= TDEIcon::LinkOverlay; 00637 00638 if ( !S_ISDIR( m_fileMode ) // Locked dirs have a special icon, use the overlay for files only 00639 && !isReadable()) 00640 _state |= TDEIcon::LockOverlay; 00641 00642 if ( isHidden() ) 00643 _state |= TDEIcon::HiddenOverlay; 00644 00645 if( S_ISDIR( m_fileMode ) && m_bIsLocalURL) 00646 { 00647 if (KSambaShare::instance()->isDirectoryShared( m_url.path() ) || 00648 KNFSShare::instance()->isDirectoryShared( m_url.path() )) 00649 { 00650 //kdDebug()<<"KFileShare::isDirectoryShared : "<<m_url.path()<<endl; 00651 _state |= TDEIcon::ShareOverlay; 00652 } 00653 } 00654 00655 if ( m_pMimeType->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" ) 00656 _state |= TDEIcon::ZipOverlay; 00657 return _state; 00658 } 00659 00660 TQPixmap KFileItem::pixmap( int _size, int _state ) const 00661 { 00662 if (d && (!d->iconName.isEmpty())) 00663 return DesktopIcon(d->iconName,_size,_state); 00664 00665 if ( !m_pMimeType ) 00666 { 00667 static const TQString & defaultFolderIcon = 00668 TDEGlobal::staticQString(KMimeType::mimeType( "inode/directory" )->KServiceType::icon()); 00669 00670 if ( S_ISDIR( m_fileMode ) ) 00671 return DesktopIcon( defaultFolderIcon, _size, _state ); 00672 00673 return DesktopIcon( "unknown", _size, _state ); 00674 } 00675 00676 _state |= overlays(); 00677 00678 KMimeType::Ptr mime; 00679 // Use guessed mimetype if the main one hasn't been determined for sure 00680 if ( !m_bMimeTypeKnown && !m_guessedMimeType.isEmpty() ) 00681 mime = KMimeType::mimeType( m_guessedMimeType ); 00682 else 00683 mime = m_pMimeType; 00684 00685 // Support for gzipped files: extract mimetype of contained file 00686 // See also the relevant code in overlays, which adds the zip overlay. 00687 if ( mime->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" ) 00688 { 00689 KURL sf; 00690 sf.setPath( m_url.path().left( m_url.path().length() - 3 ) ); 00691 //kdDebug() << "KFileItem::pixmap subFileName=" << subFileName << endl; 00692 mime = KMimeType::findByURL( sf, 0, m_bIsLocalURL ); 00693 } 00694 00695 bool isLocalURL; 00696 KURL url = mostLocalURL(isLocalURL); 00697 00698 TQPixmap p = mime->pixmap( url, TDEIcon::Desktop, _size, _state ); 00699 //kdDebug() << "finding pixmap for " << url.url() << " : " << mime->name() << endl; 00700 if (p.isNull()) 00701 kdWarning() << "Pixmap not found for mimetype " << m_pMimeType->name() << endl; 00702 00703 if ( mime->name() == "application/x-executable" ) { 00704 // At first glance it might seem to be a good idea to 00705 // look for .desktop files for this executable before resorting to the embedded icon 00706 // in the same fashion as the minicli, but on close examination this is NOT A GOOD IDEA. 00707 // Specifically it allows one executable to mimic another purely based on filename, 00708 // which could at certain times fool any user regardless of experience level. 00709 #ifdef HAVE_ELFICON 00710 // Check for an embedded icon 00711 unsigned int icon_size; 00712 libr_icon *icon = NULL; 00713 libr_file *handle = NULL; 00714 libr_access_t access = LIBR_READ; 00715 00716 if((handle = libr_open(const_cast<char*>(url.path().ascii()), access)) == NULL) 00717 { 00718 kdWarning() << "failed to open file" << url.path() << endl; 00719 return p; 00720 } 00721 00722 icon_size = _size; 00723 icon = libr_icon_geticon_bysize(handle, icon_size); 00724 00725 // See if the embedded icon name matches any icon file names already on the system 00726 // If it does, use the system icon instead of the embedded one 00727 int iconresnamefound = 0; 00728 iconentry *entry = NULL; 00729 iconlist icons; 00730 if(!get_iconlist(handle, &icons)) 00731 { 00732 // Failed to obtain a list of ELF icons 00733 kdDebug() << "failed to obtain ELF icon from " << url.path() << ": " << libr_errmsg() << endl; 00734 00735 // See if there is a system icon we can use 00736 TQString sysIconName = elf_get_resource(handle, ".metadata_sysicon"); 00737 if (!sysIconName.isEmpty()) { 00738 if (TDEGlobal::iconLoader()->iconPath(sysIconName.ascii(), 0, true) != "") { 00739 p = DesktopIcon( sysIconName.ascii(), _size, _state ); 00740 } 00741 } 00742 00743 libr_close(handle); 00744 return p; 00745 } 00746 else { 00747 while((entry = get_nexticon(&icons, entry)) != NULL) 00748 { 00749 if(icon == NULL) 00750 { 00751 // Try loading this icon as fallback 00752 icon = libr_icon_geticon_byname(handle, entry->name); 00753 } 00754 if (TDEGlobal::iconLoader()->iconPath(entry->name, 0, true) != "") { 00755 iconresnamefound = 1; 00756 p = DesktopIcon( entry->name, _size, _state ); 00757 break; 00758 } 00759 } 00760 } 00761 00762 if ((iconresnamefound == 0) && (icon)) { 00763 // Extract the embedded icon 00764 size_t icon_data_length; 00765 char* icondata = libr_icon_malloc(icon, &icon_data_length); 00766 p.loadFromData(static_cast<uchar*>(static_cast<void*>(icondata)), icon_data_length); // EVIL CAST 00767 if (icon_size != 0) { 00768 TQImage ip = p.convertToImage(); 00769 ip = ip.smoothScale(icon_size, icon_size); 00770 p.convertFromImage(ip); 00771 } 00772 free(icondata); 00773 libr_icon_close(icon); 00774 } 00775 00776 libr_close(handle); 00777 #endif // HAVE_ELFICON 00778 } 00779 00780 return p; 00781 } 00782 00783 bool KFileItem::isReadable() const 00784 { 00785 /* 00786 struct passwd * user = getpwuid( geteuid() ); 00787 bool isMyFile = (TQString::fromLocal8Bit(user->pw_name) == m_user); 00788 // This gets ugly for the group.... 00789 // Maybe we want a static TQString for the user and a static QStringList 00790 // for the groups... then we need to handle the deletion properly... 00791 */ 00792 00793 if ( m_permissions != KFileItem::Unknown ) { 00794 // No read permission at all 00795 if ( !(S_IRUSR & m_permissions) && !(S_IRGRP & m_permissions) && !(S_IROTH & m_permissions) ) 00796 return false; 00797 00798 // Read permissions for all: save a stat call 00799 if ( (S_IRUSR|S_IRGRP|S_IROTH) & m_permissions ) 00800 return true; 00801 } 00802 00803 // Or if we can't read it [using ::access()] - not network transparent 00804 if ( m_bIsLocalURL && ::access( TQFile::encodeName(m_url.path()), R_OK ) == -1 ) 00805 return false; 00806 00807 return true; 00808 } 00809 00810 bool KFileItem::isWritable() const 00811 { 00812 /* 00813 struct passwd * user = getpwuid( geteuid() ); 00814 bool isMyFile = (TQString::fromLocal8Bit(user->pw_name) == m_user); 00815 // This gets ugly for the group.... 00816 // Maybe we want a static TQString for the user and a static QStringList 00817 // for the groups... then we need to handle the deletion properly... 00818 */ 00819 00820 if ( m_permissions != KFileItem::Unknown ) { 00821 // No write permission at all 00822 if ( !(S_IWUSR & m_permissions) && !(S_IWGRP & m_permissions) && !(S_IWOTH & m_permissions) ) 00823 return false; 00824 } 00825 00826 // Or if we can't read it [using ::access()] - not network transparent 00827 if ( m_bIsLocalURL && ::access( TQFile::encodeName(m_url.path()), W_OK ) == -1 ) 00828 return false; 00829 00830 return true; 00831 } 00832 00833 bool KFileItem::isHidden() const 00834 { 00835 if ( m_hidden != Auto ) 00836 return m_hidden == Hidden; 00837 00838 if ( !m_url.isEmpty() ) 00839 return m_url.fileName()[0] == '.'; 00840 else // should never happen 00841 return m_strName[0] == '.'; 00842 } 00843 00844 bool KFileItem::isDir() const 00845 { 00846 if ( m_fileMode == KFileItem::Unknown ) 00847 { 00848 kdDebug() << " KFileItem::isDir can't say -> false " << endl; 00849 return false; // can't say for sure, so no 00850 } 00851 return (S_ISDIR(m_fileMode)); 00852 /* 00853 if (!S_ISDIR(m_fileMode)) { 00854 if (m_url.isLocalFile()) { 00855 KMimeType::Ptr ptr=KMimeType::findByURL(m_url,0,true,true); 00856 if ((ptr!=0) && (ptr->is("directory/inode"))) return true; 00857 } 00858 return false 00859 } else return true;*/ 00860 } 00861 00862 bool KFileItem::acceptsDrops() 00863 { 00864 // A directory ? 00865 if ( S_ISDIR( mode() ) ) { 00866 return isWritable(); 00867 } 00868 00869 // But only local .desktop files and executables 00870 if ( !m_bIsLocalURL ) 00871 return false; 00872 00873 if (( mimetype() == "application/x-desktop") || 00874 ( mimetype() == "media/builtin-mydocuments") || 00875 ( mimetype() == "media/builtin-mycomputer") || 00876 ( mimetype() == "media/builtin-mynetworkplaces") || 00877 ( mimetype() == "media/builtin-printers") || 00878 ( mimetype() == "media/builtin-trash") || 00879 ( mimetype() == "media/builtin-webbrowser")) 00880 return true; 00881 00882 // Executable, shell script ... ? 00883 if ( ::access( TQFile::encodeName(m_url.path()), X_OK ) == 0 ) 00884 return true; 00885 00886 return false; 00887 } 00888 00889 TQString KFileItem::getStatusBarInfo() 00890 { 00891 TQString text = m_strText; 00892 00893 if ( m_bLink ) 00894 { 00895 if ( !d ) { 00896 d = new KFileItemPrivate(); 00897 } 00898 if (!d->commentCached) { 00899 d->comment = determineMimeType()->comment( m_url, m_bIsLocalURL ); 00900 d->commentCached = true; 00901 } 00902 TQString tmp; 00903 if ( d->comment.isEmpty() ) 00904 tmp = i18n ( "Symbolic Link" ); 00905 else 00906 tmp = i18n("%1 (Link)").arg(d->comment); 00907 text += "->"; 00908 text += linkDest(); 00909 text += " "; 00910 text += tmp; 00911 } 00912 else if ( S_ISREG( m_fileMode ) ) 00913 { 00914 bool hasSize; 00915 TDEIO::filesize_t sizeValue = size(hasSize); 00916 if(hasSize) 00917 text += TQString(" (%1) ").arg( TDEIO::convertSize( sizeValue ) ); 00918 text += mimeComment(); 00919 } 00920 else if ( S_ISDIR ( m_fileMode ) ) 00921 { 00922 text += "/ "; 00923 text += mimeComment(); 00924 } 00925 else 00926 { 00927 text += " "; 00928 text += mimeComment(); 00929 } 00930 text.replace('\n', " "); // replace any newlines with a space, so the statusbar doesn't get a two-line string which messes the display up, Alex 00931 return text; 00932 } 00933 00934 TQString KFileItem::getToolTipText(int maxcount) 00935 { 00936 // we can return TQString::null if no tool tip should be shown 00937 TQString tip; 00938 KFileMetaInfo info = metaInfo(); 00939 00940 // the font tags are a workaround for the fact that the tool tip gets 00941 // screwed if the color scheme uses white as default text color 00942 const char* start = "<tr><td><nobr><font color=\"black\">"; 00943 const char* mid = "</font></nobr></td><td><nobr><font color=\"black\">"; 00944 const char* end = "</font></nobr></td></tr>"; 00945 00946 tip = "<table cellspacing=0 cellpadding=0>"; 00947 00948 tip += start + i18n("Name:") + mid + text() + end; 00949 tip += start + i18n("Type:") + mid; 00950 00951 TQString type = TQStyleSheet::escape(mimeComment()); 00952 if ( m_bLink ) { 00953 tip += i18n("Link to %1 (%2)").arg(linkDest(), type) + end; 00954 } else 00955 tip += type + end; 00956 00957 if ( !S_ISDIR ( m_fileMode ) ) { 00958 bool hasSize; 00959 TDEIO::filesize_t sizeValue = size(hasSize); 00960 if(hasSize) 00961 tip += start + i18n("Size:") + mid + 00962 TDEIO::convertSizeWithBytes(sizeValue) + end; 00963 } 00964 TQString timeStr = timeString( TDEIO::UDS_MODIFICATION_TIME); 00965 if(!timeStr.isEmpty()) 00966 tip += start + i18n("Modified:") + mid + 00967 timeStr + end; 00968 #ifndef Q_WS_WIN //TODO: show win32-specific permissions 00969 TQString userStr = user(); 00970 TQString groupStr = group(); 00971 if(!userStr.isEmpty() || !groupStr.isEmpty()) 00972 tip += start + i18n("Owner:") + mid + userStr + " - " + groupStr + end + 00973 start + i18n("Permissions:") + mid + 00974 parsePermissions(m_permissions) + end; 00975 #endif 00976 00977 if (info.isValid() && !info.isEmpty() ) 00978 { 00979 tip += "<tr><td colspan=2><center><s> </s></center></td></tr>"; 00980 TQStringList keys = info.preferredKeys(); 00981 00982 // now the rest 00983 TQStringList::Iterator it = keys.begin(); 00984 for (int count = 0; count<maxcount && it!=keys.end() ; ++it) 00985 { 00986 KFileMetaInfoItem item = info.item( *it ); 00987 if ( item.isValid() ) 00988 { 00989 TQString s = item.string(); 00990 if ( ( item.attributes() & KFileMimeTypeInfo::SqueezeText ) 00991 && s.length() > 50) { 00992 s.truncate(47); 00993 s.append("..."); 00994 } 00995 if ( !s.isEmpty() ) 00996 { 00997 count++; 00998 tip += start + 00999 TQStyleSheet::escape( item.translatedKey() ) + ":" + 01000 mid + 01001 TQStyleSheet::escape( s ) + 01002 end; 01003 } 01004 01005 } 01006 } 01007 } 01008 tip += "</table>"; 01009 01010 //kdDebug() << "making this the tool tip rich text:\n"; 01011 //kdDebug() << tip << endl; 01012 01013 return tip; 01014 } 01015 01016 void KFileItem::run() 01017 { 01018 // It might be faster to pass skip that when we know the mimetype, 01019 // and just call KRun::runURL. But then we need to use mostLocalURL() 01020 // for application/x-desktop files, to be able to execute them. 01021 (void) new KRun( m_url, m_fileMode, m_bIsLocalURL ); 01022 } 01023 01024 bool KFileItem::cmp( const KFileItem & item ) 01025 { 01026 bool hasSize1,hasSize2,hasTime1,hasTime2; 01027 hasSize1 = hasSize2 = hasTime1 = hasTime2 = false; 01028 return ( m_strName == item.m_strName 01029 && m_bIsLocalURL == item.m_bIsLocalURL 01030 && m_fileMode == item.m_fileMode 01031 && m_permissions == item.m_permissions 01032 && m_user == item.m_user 01033 && m_group == item.m_group 01034 && m_bLink == item.m_bLink 01035 && m_hidden == item.m_hidden 01036 && size(hasSize1) == item.size(hasSize2) 01037 && hasSize1 == hasSize2 01038 && time(TDEIO::UDS_MODIFICATION_TIME, hasTime1) == item.time(TDEIO::UDS_MODIFICATION_TIME, hasTime2) 01039 && hasTime1 == hasTime2 01040 && (!d || !item.d || d->iconName == item.d->iconName) 01041 && (!isMimeTypeKnown() || !item.isMimeTypeKnown() || mimetype() == item.mimetype()) ); 01042 01043 // Don't compare the mimetypes here. They might not be known, and we don't want to 01044 // do the slow operation of determining them here. 01045 } 01046 01047 void KFileItem::assign( const KFileItem & item ) 01048 { 01049 if ( this == &item ) 01050 return; 01051 m_entry = item.m_entry; 01052 m_url = item.m_url; 01053 m_bIsLocalURL = item.m_bIsLocalURL; 01054 m_strName = item.m_strName; 01055 m_strText = item.m_strText; 01056 m_fileMode = item.m_fileMode; 01057 m_permissions = item.m_permissions; 01058 m_user = item.m_user; 01059 m_group = item.m_group; 01060 m_bLink = item.m_bLink; 01061 m_pMimeType = item.m_pMimeType; 01062 m_strLowerCaseName = item.m_strLowerCaseName; 01063 m_bMimeTypeKnown = item.m_bMimeTypeKnown; 01064 m_hidden = item.m_hidden; 01065 m_guessedMimeType = item.m_guessedMimeType; 01066 m_access = item.m_access; 01067 m_metaInfo = item.m_metaInfo; 01068 for ( int i = 0; i < NumFlags; i++ ) 01069 m_time[i] = item.m_time[i]; 01070 m_size = item.m_size; 01071 // note: m_extra is NOT copied, as we'd have no control over who is 01072 // deleting the data or not. 01073 01074 // We had a mimetype previously (probably), so we need to re-determine it 01075 determineMimeType(); 01076 01077 if ( item.d ) { 01078 if ( !d ) { 01079 d = new KFileItemPrivate; 01080 } 01081 d->iconName = item.d->iconName; 01082 d->comment = item.d->comment; 01083 d->commentCached = item.d->commentCached; 01084 } else { 01085 delete d; 01086 d = 0; 01087 } 01088 } 01089 01090 void KFileItem::setUDSEntry( const TDEIO::UDSEntry& _entry, const KURL& _url, 01091 bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) 01092 { 01093 m_entry = _entry; 01094 m_url = _url; 01095 m_strName = TQString::null; 01096 m_strText = TQString::null; 01097 m_user = TQString::null; 01098 m_group = TQString::null; 01099 m_strLowerCaseName = TQString::null; 01100 m_pMimeType = 0; 01101 m_fileMode = KFileItem::Unknown; 01102 m_permissions = KFileItem::Unknown; 01103 m_bMarked = false; 01104 m_bLink = false; 01105 m_bIsLocalURL = _url.isLocalFile(); 01106 m_bMimeTypeKnown = false; 01107 m_hidden = Auto; 01108 m_guessedMimeType = TQString::null; 01109 m_metaInfo = KFileMetaInfo(); 01110 01111 if ( d ) { 01112 d->iconName = TQString::null; 01113 d->comment = TQString::null; 01114 d->commentCached = false; 01115 } 01116 01117 readUDSEntry( _urlIsDirectory ); 01118 init( _determineMimeTypeOnDemand ); 01119 } 01120 01121 void KFileItem::setFileMode( mode_t m ) 01122 { 01123 m_fileMode = m; 01124 } 01125 01126 void KFileItem::setMimeType( const TQString& mimetype ) 01127 { 01128 m_pMimeType = KMimeType::mimeType( mimetype ); 01129 } 01130 01131 void KFileItem::setExtraData( const void *key, void *value ) 01132 { 01133 if ( !key ) 01134 return; 01135 01136 m_extra.replace( key, value ); 01137 } 01138 01139 const void * KFileItem::extraData( const void *key ) const 01140 { 01141 TQMapConstIterator<const void*,void*> it = m_extra.find( key ); 01142 if ( it != m_extra.end() ) 01143 return it.data(); 01144 return 0L; 01145 } 01146 01147 void * KFileItem::extraData( const void *key ) 01148 { 01149 TQMapIterator<const void*,void*> it = m_extra.find( key ); 01150 if ( it != m_extra.end() ) 01151 return it.data(); 01152 return 0L; 01153 } 01154 01155 void KFileItem::removeExtraData( const void *key ) 01156 { 01157 m_extra.remove( key ); 01158 } 01159 01160 TQString KFileItem::permissionsString() const 01161 { 01162 if (m_access.isNull()) 01163 m_access = parsePermissions( m_permissions ); 01164 01165 return m_access; 01166 } 01167 01168 TQString KFileItem::parsePermissions(mode_t perm) const 01169 { 01170 char p[] = "---------- "; 01171 01172 if (isDir()) 01173 p[0]='d'; 01174 else if (isLink()) 01175 p[0]='l'; 01176 01177 if (perm & TQFileInfo::ReadUser) 01178 p[1]='r'; 01179 if (perm & TQFileInfo::WriteUser) 01180 p[2]='w'; 01181 if ((perm & TQFileInfo::ExeUser) && !(perm & S_ISUID)) p[3]='x'; 01182 else if ((perm & TQFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='s'; 01183 else if (!(perm & TQFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='S'; 01184 01185 if (perm & TQFileInfo::ReadGroup) 01186 p[4]='r'; 01187 if (perm & TQFileInfo::WriteGroup) 01188 p[5]='w'; 01189 if ((perm & TQFileInfo::ExeGroup) && !(perm & S_ISGID)) p[6]='x'; 01190 else if ((perm & TQFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='s'; 01191 else if (!(perm & TQFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='S'; 01192 01193 if (perm & TQFileInfo::ReadOther) 01194 p[7]='r'; 01195 if (perm & TQFileInfo::WriteOther) 01196 p[8]='w'; 01197 if ((perm & TQFileInfo::ExeOther) && !(perm & S_ISVTX)) p[9]='x'; 01198 else if ((perm & TQFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='t'; 01199 else if (!(perm & TQFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='T'; 01200 01201 if (hasExtendedACL()) 01202 p[10]='+'; 01203 01204 return TQString::fromLatin1(p); 01205 } 01206 01207 // check if we need to cache this 01208 TQString KFileItem::timeString( unsigned int which ) const 01209 { 01210 bool hasTime; 01211 time_t time_ = time(which, hasTime); 01212 if(!hasTime) return TQString::null; 01213 01214 TQDateTime t; 01215 t.setTime_t( time_); 01216 return TDEGlobal::locale()->formatDateTime( t ); 01217 } 01218 01219 void KFileItem::setMetaInfo( const KFileMetaInfo & info ) 01220 { 01221 m_metaInfo = info; 01222 } 01223 01224 const KFileMetaInfo & KFileItem::metaInfo(bool autoget, int) const 01225 { 01226 bool isLocalURL; 01227 KURL url = mostLocalURL(isLocalURL); 01228 01229 if ( autoget && !m_metaInfo.isValid() && 01230 TDEGlobalSettings::showFilePreview(url) ) 01231 { 01232 m_metaInfo = KFileMetaInfo( url, mimetype() ); 01233 } 01234 01235 return m_metaInfo; 01236 } 01237 01238 KURL KFileItem::mostLocalURL(bool &local) const 01239 { 01240 TQString local_path = localPath(); 01241 01242 if ( !local_path.isEmpty() ) 01243 { 01244 local = true; 01245 KURL url; 01246 url.setPath(local_path); 01247 return url; 01248 } 01249 else 01250 { 01251 local = m_bIsLocalURL; 01252 return m_url; 01253 } 01254 } 01255 01256 void KFileItem::virtual_hook( int, void* ) 01257 { /*BASE::virtual_hook( id, data );*/ } 01258 01259 TQDataStream & operator<< ( TQDataStream & s, const KFileItem & a ) 01260 { 01261 // We don't need to save/restore anything that refresh() invalidates, 01262 // since that means we can re-determine those by ourselves. 01263 s << a.m_url; 01264 s << a.m_strName; 01265 s << a.m_strText; 01266 return s; 01267 } 01268 01269 TQDataStream & operator>> ( TQDataStream & s, KFileItem & a ) 01270 { 01271 s >> a.m_url; 01272 s >> a.m_strName; 01273 s >> a.m_strText; 01274 a.m_bIsLocalURL = a.m_url.isLocalFile(); 01275 a.m_bMimeTypeKnown = false; 01276 a.refresh(); 01277 return s; 01278 }