23 #include <sys/types.h>
33 #include <kprotocolinfo.h>
34 #include <kio/global.h>
35 #include "kmimetype.h"
36 #include "kservicetypefactory.h"
37 #include "kmimemagic.h"
40 #include "kautomount.h"
41 #include <kdirnotify_stub.h>
45 #include <kmessageboxwrapper.h>
47 #include <dcopclient.h>
49 #include <kapplication.h>
52 #include <kdesktopfile.h>
53 #include <kdirwatch.h>
54 #include <kiconloader.h>
56 #include <ksimpleconfig.h>
57 #include <kstandarddirs.h>
62 template class KSharedPtr<KMimeType>;
63 template class TQValueList<KMimeType::Ptr>;
65 KMimeType::Ptr KMimeType::s_pDefaultType = 0L;
70 assert ( !s_pDefaultType );
75 if (mime && mime->isType( KST_KMimeType ))
77 s_pDefaultType = KMimeType::Ptr((
KMimeType *) mime);
82 KStandardDirs stdDirs;
83 TQString sDefaultMimeType = stdDirs.resourceDirs(
"mime").first()+
defaultMimeType()+
".desktop";
85 "unknown",
"mime", TQStringList() );
91 if ( !s_pDefaultType )
93 return s_pDefaultType;
101 if ( !s_pDefaultType )
108 if ( !KServiceTypeFactory::self()->checkMimeTypes() )
110 KMessageBoxWrapper::error( 0L, i18n(
"No mime types installed." ) );
136 TQString tmp = i18n(
"Could not find mime type\n%1" ).arg( _type );
138 KMessageBoxWrapper::sorry( 0, tmp );
143 KServiceType * mime = KServiceTypeFactory::self()->findServiceTypeByName( _name );
145 if ( !mime || !mime->isType( KST_KMimeType ) )
149 if ( !KSycoca::self()->isBuilding() )
151 if ( !s_pDefaultType )
153 return s_pDefaultType;
157 return KMimeType::Ptr((
KMimeType *) mime);
162 return KServiceTypeFactory::self()->allMimeTypes();
166 bool _is_local_file,
bool _fast_mode )
169 TQString path = _url.path();
171 if ( !_fast_mode && !_is_local_file && _url.isLocalFile() )
172 _is_local_file =
true;
174 if ( !_fast_mode && _is_local_file && (_mode == 0 || _mode == (mode_t)-1) )
176 KDE_struct_stat buff;
177 if ( KDE_stat( TQFile::encodeName(path), &buff ) != -1 )
178 _mode = buff.st_mode;
182 if ( S_ISDIR( _mode ) )
186 if ( _is_local_file )
188 if ( access( TQFile::encodeName(path), R_OK ) == -1 )
189 return mimeType(
"inode/directory-locked" );
191 return mimeType(
"inode/directory" );
193 if ( S_ISCHR( _mode ) )
194 return mimeType(
"inode/chardevice" );
195 if ( S_ISBLK( _mode ) )
196 return mimeType(
"inode/blockdevice" );
197 if ( S_ISFIFO( _mode ) )
199 if ( S_ISSOCK( _mode ) )
202 if ( !_is_local_file && S_ISREG( _mode ) && ( _mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
203 return mimeType(
"application/x-executable" );
205 TQString fileName ( _url.fileName() );
207 static const TQString& slash = KGlobal::staticQString(
"/");
208 if ( ! fileName.isNull() && !path.endsWith( slash ) )
211 KMimeType::Ptr mime = KServiceTypeFactory::self()->findFromPattern( fileName );
215 if ( _is_local_file || _url.hasSubURL() ||
218 if ( _is_local_file && !_fast_mode ) {
219 if ( mime->patternsAccuracy()<100 )
233 static const TQString& dotdesktop = KGlobal::staticQString(
".desktop");
234 static const TQString& dotkdelnk = KGlobal::staticQString(
".kdelnk");
235 static const TQString& dotdirectory = KGlobal::staticQString(
".directory");
238 if ( fileName.endsWith( dotdesktop ) )
239 return mimeType(
"application/x-desktop" );
242 if ( fileName.endsWith( dotkdelnk ) )
243 return mimeType(
"application/x-desktop" );
246 if ( fileName == dotdirectory )
250 if ( !_is_local_file || _fast_mode )
258 if ( path.endsWith( slash ) || path.isEmpty() )
268 return mimeType( TQString::fromLatin1(
"inode/directory") );
283 if ( !result || !result->
isValid() )
291 bool _is_local_file,
bool _fast_mode,
294 KMimeType::Ptr mime =
findByURL(_url, _mode, _is_local_file, _fast_mode);
295 if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime !=
defaultMimeTypePtr());
299 KMimeType::Ptr KMimeType::diagnoseFileName(
const TQString &fileName, TQString &pattern)
301 return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern );
308 return findByURL( u, mode,
true, fast_mode );
327 #define GZIP_MAGIC1 0x1f
328 #define GZIP_MAGIC2 0x8b
332 KMimeType::Format result;
333 result.compression = Format::NoCompression;
336 result.text = mime->name().startsWith(
"text/");
337 TQVariant v = mime->property(
"X-KDE-text");
339 result.text = v.toBool();
341 if (mime->name().startsWith(
"inode/"))
345 if (f.open(IO_ReadOnly))
347 unsigned char buf[10+1];
348 int l = f.readBlock((
char *)buf, 10);
349 if ((l > 2) && (buf[0] == GZIP_MAGIC1) && (buf[1] == GZIP_MAGIC2))
350 result.compression = Format::GZipCompression;
356 const TQString& _comment,
const TQStringList& _patterns )
359 m_lstPatterns = _patterns;
364 KDesktopFile _cfg( _fullpath,
true );
368 kdWarning(7009) <<
"mimetype not valid '" << m_strName <<
"' (missing entry in the file ?)" << endl;
376 kdWarning(7009) <<
"mimetype not valid '" << m_strName <<
"' (missing entry in the file ?)" << endl;
379 void KMimeType::init( KDesktopFile * config )
381 config->setDesktopGroup();
382 m_lstPatterns = config->readListEntry(
"Patterns",
';' );
385 TQString XKDEAutoEmbed = TQString::fromLatin1(
"X-KDE-AutoEmbed");
386 if ( config->hasKey( XKDEAutoEmbed ) )
387 m_mapProps.insert( XKDEAutoEmbed, TQVariant( config->readBoolEntry( XKDEAutoEmbed ), 0 ) );
389 TQString XKDEText = TQString::fromLatin1(
"X-KDE-text");
390 if ( config->hasKey( XKDEText ) )
391 m_mapProps.insert( XKDEText, config->readBoolEntry( XKDEText ) );
393 TQString XKDEIsAlso = TQString::fromLatin1(
"X-KDE-IsAlso");
394 if ( config->hasKey( XKDEIsAlso ) ) {
395 TQString
inherits = config->readEntry( XKDEIsAlso );
396 if ( inherits !=
name() )
397 m_mapProps.insert( XKDEIsAlso, inherits );
399 kdWarning(7009) <<
"Error: " << inherits <<
" inherits from itself!!!!" << endl;
402 TQString XKDEPatternsAccuracy = TQString::fromLatin1(
"X-KDE-PatternsAccuracy");
403 if ( config->hasKey( XKDEPatternsAccuracy ) )
404 m_mapProps.insert( XKDEPatternsAccuracy, config->readEntry( XKDEPatternsAccuracy ) );
410 loadInternal( _str );
415 KServiceType::load( _str );
416 loadInternal( _str );
419 void KMimeType::loadInternal( TQDataStream& _str )
422 _str >> m_lstPatterns;
427 KServiceType::save( _str );
430 _str << m_lstPatterns;
435 if ( _name ==
"Patterns" )
436 return TQVariant( m_lstPatterns );
444 res.append(
"Patterns" );
449 KMimeType::~KMimeType()
454 TQString * _path )
const
456 KIconLoader *iconLoader=KGlobal::iconLoader();
457 TQString iconName=
icon( TQString::null,
false );
458 if (!iconLoader->extraDesktopThemesAdded())
460 TQPixmap
pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path,
true );
461 if (!pixmap.isNull() )
return pixmap;
463 iconLoader->addExtraDesktopThemes();
466 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path,
false );
470 int _state, TQString * _path )
const
472 KIconLoader *iconLoader=KGlobal::iconLoader();
473 TQString iconName=
icon( _url, _url.isLocalFile() );
474 if (!iconLoader->extraDesktopThemesAdded())
476 TQPixmap
pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path,
true );
477 if (!pixmap.isNull() )
return pixmap;
479 iconLoader->addExtraDesktopThemes();
482 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path,
false );
486 int _force_size,
int _state, TQString * _path )
488 KIconLoader *iconLoader=KGlobal::iconLoader();
489 TQString iconName =
iconForURL( _url, _mode );
491 if (!iconLoader->extraDesktopThemesAdded())
493 TQPixmap
pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path,
true );
494 if (!pixmap.isNull() )
return pixmap;
496 iconLoader->addExtraDesktopThemes();
499 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path,
false );
505 const KMimeType::Ptr mt =
findByURL( _url, _mode, _url.isLocalFile(),
507 static const TQString& unknown = KGlobal::staticQString(
"unknown");
508 const TQString mimeTypeIcon = mt->icon( _url, _url.isLocalFile() );
509 TQString i = mimeTypeIcon;
514 || _url.path().length() <= 1 )
522 if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
532 static bool useFavIcons =
true;
533 static bool check =
true;
536 KConfig *config = KGlobal::config();
537 KConfigGroupSaver cs( config,
"HTML Settings" );
538 useFavIcons = config->readBoolEntry(
"EnableFavicon",
true );
541 if ( url.isLocalFile() || !url.protocol().startsWith(
"http")
543 return TQString::null;
545 DCOPRef kded(
"kded",
"favicons" );
546 DCOPReply result = kded.call(
"iconForURL(KURL)", url );
547 if ( result.isValid() )
550 return TQString::null;
555 TQVariant v =
property(
"X-KDE-IsAlso");
561 if (
name() == mimeTypeName )
565 while ( !st.isEmpty() )
569 if (!ptr)
return false;
570 if ( ptr->name() == mimeTypeName )
572 st = ptr->parentMimeType();
577 int KMimeType::patternsAccuracy()
const {
578 TQVariant v =
property(
"X-KDE-PatternsAccuracy");
579 if (!v.isValid())
return 100;
593 if ( !_is_local || _url.isEmpty() )
605 u.addPath(
".directory" );
610 if ( KStandardDirs::exists( u.path() ) )
612 KSimpleConfig cfg( u.path(), true );
613 cfg.setDesktopGroup();
614 icon = cfg.readEntry(
"Icon" );
615 TQString empty_icon = cfg.readEntry(
"EmptyIcon" );
617 if ( !empty_icon.isEmpty() )
619 bool isempty =
false;
622 dp = opendir( TQFile::encodeName(_url.path()) );
625 TQValueList<TQCString> entries;
627 ep=readdir( dp );
if ( ep ) entries.append( ep->d_name );
628 ep=readdir( dp );
if ( ep ) entries.append( ep->d_name );
629 if ( (ep=readdir( dp )) == 0L )
632 entries.append( ep->d_name );
633 if ( readdir( dp ) == 0 ) {
635 isempty = entries.find(
"." ) != entries.end() &&
636 entries.find(
".." ) != entries.end() &&
637 entries.find(
".directory" ) != entries.end();
640 if (!isempty && !strcmp(ep->d_name,
".directory"))
641 isempty = (readdir(dp) == 0L);
650 if ( icon.isEmpty() )
653 if ( icon.startsWith(
"./" ) ) {
657 v.addPath( icon.mid( 2 ) );
666 if ( !_is_local || _url.isEmpty() )
678 u.addPath(
".directory" );
680 KDesktopFile cfg( u.path(), true );
681 TQString
comment = cfg.readComment();
682 if ( comment.isEmpty() )
696 if ( !_is_local || _url.isEmpty() )
700 return icon( u, _is_local );
708 KSimpleConfig cfg( _url.path(), true );
709 cfg.setDesktopGroup();
710 TQString
icon = cfg.readEntry(
"Icon" );
711 TQString type = cfg.readEntry(
"Type" );
713 if ( type ==
"FSDevice" || type ==
"FSDev")
716 TQString unmount_icon = cfg.readEntry(
"UnmountIcon" );
717 TQString dev = cfg.readEntry(
"Dev" );
718 if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() )
725 }
else if ( type ==
"Link" ) {
726 const TQString emptyIcon = cfg.readEntry(
"EmptyIcon" );
727 if ( !emptyIcon.isEmpty() ) {
728 const TQString u = cfg.readPathEntry(
"URL" );
730 if ( url.protocol() ==
"trash" ) {
733 KSimpleConfig trashConfig(
"trashrc",
true );
734 trashConfig.setGroup(
"Status" );
735 if ( trashConfig.readBoolEntry(
"Empty",
true ) ) {
742 if ( icon.isEmpty() )
749 int _state, TQString * _path )
const
751 TQString _icon =
icon( _url, _url.isLocalFile() );
752 TQPixmap pix = KGlobal::iconLoader()->loadIcon( _icon, _group,
753 _force_size, _state, _path,
false );
755 pix = KGlobal::iconLoader()->loadIcon(
"unknown", _group,
756 _force_size, _state, _path,
false );
762 if ( !_is_local || _url.isEmpty() )
766 return comment( u, _is_local );
774 KDesktopFile cfg( _url.path(), true );
775 TQString
comment = cfg.readComment();
776 if ( comment.isEmpty() )
789 KSimpleConfig cfg( u.path(), true );
790 cfg.setDesktopGroup();
791 TQString type = cfg.readEntry(
"Type" );
792 if ( type.isEmpty() )
794 TQString tmp = i18n(
"The desktop entry file %1 "
795 "has no Type=... entry.").arg(u.path() );
796 KMessageBoxWrapper::error( 0, tmp);
802 if ( type ==
"FSDevice" )
803 return runFSDevice( u, cfg );
804 else if ( type ==
"Application" )
805 return runApplication( u, u.path() );
806 else if ( type ==
"Link" )
808 cfg.setDollarExpansion(
true );
809 return runLink( u, cfg );
811 else if ( type ==
"MimeType" )
812 return runMimeType( u, cfg );
815 TQString tmp = i18n(
"The desktop entry of type\n%1\nis unknown.").arg( type );
816 KMessageBoxWrapper::error( 0, tmp);
821 pid_t KDEDesktopMimeType::runFSDevice(
const KURL& _url,
const KSimpleConfig &cfg )
825 TQString dev = cfg.readEntry(
"Dev" );
829 TQString tmp = i18n(
"The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
830 KMessageBoxWrapper::error( 0, tmp);
841 retval =
KRun::runURL( mpURL, TQString::fromLatin1(
"inode/directory") );
845 bool ro = cfg.readBoolEntry(
"ReadOnly",
false );
846 TQString fstype = cfg.readEntry(
"FSType" );
847 if ( fstype ==
"Default" )
848 fstype = TQString::null;
849 TQString point = cfg.readEntry(
"MountPoint" );
851 (void)
new KAutoMount( ro, fstype, dev, point, _url.path() );
859 pid_t KDEDesktopMimeType::runApplication(
const KURL& ,
const TQString & _serviceFile )
870 pid_t KDEDesktopMimeType::runLink(
const KURL& _url,
const KSimpleConfig &cfg )
872 TQString u = cfg.readPathEntry(
"URL" );
875 TQString tmp = i18n(
"The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() );
876 KMessageBoxWrapper::error( 0, tmp );
886 TQString lastOpenedWidth = cfg.readEntry(
"X-KDE-LastOpenedWith" );
887 if ( !lastOpenedWidth.isEmpty() )
893 pid_t KDEDesktopMimeType::runMimeType(
const KURL& url ,
const KSimpleConfig & )
899 args <<
"openProperties";
903 if ( !KApplication::kdeinitExec(
"kfmclient", args, 0, &pid) )
907 p <<
"kfmclient" << args;
908 p.start(KProcess::DontCare);
914 TQValueList<Service> result;
916 if ( !_url.isLocalFile() )
919 KSimpleConfig cfg( _url.path(), true );
920 cfg.setDesktopGroup();
921 TQString type = cfg.readEntry(
"Type" );
923 if ( type.isEmpty() )
926 if ( type ==
"FSDevice" )
928 TQString dev = cfg.readEntry(
"Dev" );
931 TQString tmp = i18n(
"The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
932 KMessageBoxWrapper::error( 0, tmp);
941 mount.m_strName = i18n(
"Mount");
942 mount.m_type = ST_MOUNT;
943 result.append( mount );
952 unmount.m_strName = i18n(
"Eject");
954 unmount.m_strName = i18n(
"Unmount");
956 unmount.m_type = ST_UNMOUNT;
957 result.append( unmount );
967 KSimpleConfig cfg( path,
true );
978 TQValueList<Service> result;
980 cfg.setDesktopGroup();
982 if ( !cfg.hasKey(
"Actions" ) && !cfg.hasKey(
"X-KDE-GetActionMenu") )
985 if ( cfg.hasKey(
"TryExec" ) )
987 TQString tryexec = cfg.readPathEntry(
"TryExec" );
988 TQString exe = KStandardDirs::findExe( tryexec );
996 if( cfg.hasKey(
"X-KDE-GetActionMenu" )) {
997 TQString dcopcall = cfg.readEntry(
"X-KDE-GetActionMenu" );
998 const TQCString app = TQString(dcopcall.section(
' ', 0,0)).utf8();
1000 TQByteArray dataToSend;
1001 TQDataStream dataStream(dataToSend, IO_WriteOnly);
1002 dataStream << file_list;
1003 TQCString replyType;
1004 TQByteArray replyData;
1005 TQCString
object = TQString(dcopcall.section(
' ', 1,-2)).utf8();
1006 TQString
function = dcopcall.section(
' ', -1);
1007 if(!
function.endsWith(
"(KURL::List)")) {
1008 kdWarning() <<
"Desktop file " << path <<
" contains an invalid X-KDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
1010 if(kapp->dcopClient()->call( app,
object,
1012 dataToSend, replyType, replyData,
true, -1)
1013 && replyType ==
"TQStringList" ) {
1015 TQDataStream dataStreamIn(replyData, IO_ReadOnly);
1016 dataStreamIn >> keys;
1021 keys += cfg.readListEntry(
"Actions",
';' );
1023 if ( keys.count() == 0 )
1026 TQStringList::ConstIterator it = keys.begin();
1027 TQStringList::ConstIterator end = keys.end();
1028 for ( ; it != end; ++it )
1032 TQString group = *it;
1034 if (group ==
"_SEPARATOR_")
1041 group.prepend(
"Desktop Action " );
1043 bool bInvalidMenu =
false;
1045 if ( cfg.hasGroup( group ) )
1047 cfg.setGroup( group );
1049 if ( !cfg.hasKey(
"Name" ) || !cfg.hasKey(
"Exec" ) )
1050 bInvalidMenu =
true;
1053 TQString exec = cfg.readPathEntry(
"Exec" );
1054 if ( bLocalFiles || exec.contains(
"%U") || exec.contains(
"%u") )
1057 s.m_strName = cfg.readEntry(
"Name" );
1058 s.m_strIcon = cfg.readEntry(
"Icon" );
1060 s.m_type = ST_USER_DEFINED;
1061 s.m_display = !cfg.readBoolEntry(
"NoDisplay" );
1067 bInvalidMenu =
true;
1071 TQString tmp = i18n(
"The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it );
1072 KMessageBoxWrapper::error( 0, tmp );
1092 if ( _service.m_type == ST_USER_DEFINED )
1094 kdDebug() <<
"KDEDesktopMimeType::executeService " << _service.m_strName
1095 <<
" first url's path=" << urls.first().path() <<
" exec=" << _service.m_strExec << endl;
1096 KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon );
1098 KDirNotify_stub allDirNotify(
"*",
"KDirNotify*");
1099 allDirNotify.FilesChanged( urls );
1102 else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT )
1104 Q_ASSERT( urls.count() == 1 );
1105 TQString path = urls.first().path();
1108 KSimpleConfig cfg( path,
true );
1109 cfg.setDesktopGroup();
1110 TQString dev = cfg.readEntry(
"Dev" );
1111 if ( dev.isEmpty() )
1113 TQString tmp = i18n(
"The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path );
1114 KMessageBoxWrapper::error( 0, tmp );
1119 if ( _service.m_type == ST_MOUNT )
1122 if ( !mp.isEmpty() )
1124 kdDebug(7009) <<
"ALREADY Mounted" << endl;
1128 bool ro = cfg.readBoolEntry(
"ReadOnly",
false );
1129 TQString fstype = cfg.readEntry(
"FSType" );
1130 if ( fstype ==
"Default" )
1131 fstype = TQString::null;
1132 TQString point = cfg.readEntry(
"MountPoint" );
1134 (void)
new KAutoMount( ro, fstype, dev, point, path,
false );
1137 else if ( _service.m_type == ST_UNMOUNT )
1154 static const TQString & s_strDefaultMimeType =
1155 KGlobal::staticQString(
"application/octet-stream" );
1156 return s_strDefaultMimeType;
1159 void KMimeType::virtual_hook(
int id,
void* data )
1160 { KServiceType::virtual_hook(
id, data ); }
1162 void KFolderType::virtual_hook(
int id,
void* data )
1163 { KMimeType::virtual_hook(
id, data ); }
1165 void KDEDesktopMimeType::virtual_hook(
int id,
void* data )
1166 { KMimeType::virtual_hook(
id, data ); }
1168 void KExecMimeType::virtual_hook(
int id,
void* data )
1169 { KMimeType::virtual_hook(
id, data ); }
1171 #include "kmimetyperesolver.moc"