TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kmimetype.cpp 35KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  1. /* This file is part of the KDE libraries
  2. * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
  3. * David Faure <faure@kde.org>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Library General Public
  7. * License version 2 as published by the Free Software Foundation;
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public License
  15. * along with this library; see the file COPYING.LIB. If not, write to
  16. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. * Boston, MA 02110-1301, USA.
  18. **/
  19. // $Id$
  20. #include <config.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <assert.h>
  24. #include <dirent.h>
  25. #include <errno.h>
  26. #include <stddef.h>
  27. #include <unistd.h>
  28. #include <stdlib.h>
  29. #include <kprotocolinfo.h>
  30. #include <tdeio/global.h>
  31. #include "kmimetype.h"
  32. #include "kservicetypefactory.h"
  33. #include "kmimemagic.h"
  34. #include "kservice.h"
  35. #include "krun.h"
  36. #include "kautomount.h"
  37. #include <kdirnotify_stub.h>
  38. #include <tqstring.h>
  39. #include <tqfile.h>
  40. #include <kmessageboxwrapper.h>
  41. #include <dcopclient.h>
  42. #include <dcopref.h>
  43. #include <kapplication.h>
  44. #include <kprocess.h>
  45. #include <kdebug.h>
  46. #include <kdesktopfile.h>
  47. #include <kdirwatch.h>
  48. #include <kiconloader.h>
  49. #include <klocale.h>
  50. #include <ksimpleconfig.h>
  51. #include <kstandarddirs.h>
  52. #include <kurl.h>
  53. #include <tdesycoca.h>
  54. #include <kde_file.h>
  55. template class KSharedPtr<KMimeType>;
  56. template class TQValueList<KMimeType::Ptr>;
  57. KMimeType::Ptr KMimeType::s_pDefaultType = 0L;
  58. bool KMimeType::s_bChecked = false;
  59. void KMimeType::buildDefaultType()
  60. {
  61. assert ( !s_pDefaultType );
  62. // Try to find the default type
  63. KServiceType * mime = KServiceTypeFactory::self()->
  64. findServiceTypeByName( defaultMimeType() );
  65. if (mime && mime->isType( KST_KMimeType ))
  66. {
  67. s_pDefaultType = KMimeType::Ptr((KMimeType *) mime);
  68. }
  69. else
  70. {
  71. errorMissingMimeType( defaultMimeType() );
  72. KStandardDirs stdDirs;
  73. TQString sDefaultMimeType = stdDirs.resourceDirs("mime").first()+defaultMimeType()+".desktop";
  74. s_pDefaultType = new KMimeType( sDefaultMimeType, defaultMimeType(),
  75. "unknown", "mime", TQStringList() );
  76. }
  77. }
  78. KMimeType::Ptr KMimeType::defaultMimeTypePtr()
  79. {
  80. if ( !s_pDefaultType ) // we need a default type first
  81. buildDefaultType();
  82. return s_pDefaultType;
  83. }
  84. // Check for essential mimetypes
  85. void KMimeType::checkEssentialMimeTypes()
  86. {
  87. if ( s_bChecked ) // already done
  88. return;
  89. if ( !s_pDefaultType ) // we need a default type first
  90. buildDefaultType();
  91. s_bChecked = true; // must be done before building mimetypes
  92. // No Mime-Types installed ?
  93. // Lets do some rescue here.
  94. if ( !KServiceTypeFactory::self()->checkMimeTypes() )
  95. {
  96. KMessageBoxWrapper::error( 0L, i18n( "No mime types installed." ) );
  97. return; // no point in going any further
  98. }
  99. if ( KMimeType::mimeType( "inode/directory" ) == s_pDefaultType )
  100. errorMissingMimeType( "inode/directory" );
  101. if ( KMimeType::mimeType( "inode/directory-locked" ) == s_pDefaultType )
  102. errorMissingMimeType( "inode/directory-locked" );
  103. if ( KMimeType::mimeType( "inode/blockdevice" ) == s_pDefaultType )
  104. errorMissingMimeType( "inode/blockdevice" );
  105. if ( KMimeType::mimeType( "inode/chardevice" ) == s_pDefaultType )
  106. errorMissingMimeType( "inode/chardevice" );
  107. if ( KMimeType::mimeType( "inode/socket" ) == s_pDefaultType )
  108. errorMissingMimeType( "inode/socket" );
  109. if ( KMimeType::mimeType( "inode/fifo" ) == s_pDefaultType )
  110. errorMissingMimeType( "inode/fifo" );
  111. if ( KMimeType::mimeType( "application/x-shellscript" ) == s_pDefaultType )
  112. errorMissingMimeType( "application/x-shellscript" );
  113. if ( KMimeType::mimeType( "application/x-executable" ) == s_pDefaultType )
  114. errorMissingMimeType( "application/x-executable" );
  115. if ( KMimeType::mimeType( "application/x-desktop" ) == s_pDefaultType )
  116. errorMissingMimeType( "application/x-desktop" );
  117. }
  118. void KMimeType::errorMissingMimeType( const TQString& _type )
  119. {
  120. TQString tmp = i18n( "Could not find mime type\n%1" ).arg( _type );
  121. KMessageBoxWrapper::sorry( 0, tmp );
  122. }
  123. KMimeType::Ptr KMimeType::mimeType( const TQString& _name )
  124. {
  125. KServiceType * mime = KServiceTypeFactory::self()->findServiceTypeByName( _name );
  126. if ( !mime || !mime->isType( KST_KMimeType ) )
  127. {
  128. // When building tdesycoca, findServiceTypeByName doesn't create an object
  129. // but returns one from a dict.
  130. if ( !KSycoca::self()->isBuilding() )
  131. delete mime;
  132. if ( !s_pDefaultType )
  133. buildDefaultType();
  134. return s_pDefaultType;
  135. }
  136. // We got a mimetype
  137. return KMimeType::Ptr((KMimeType *) mime);
  138. }
  139. KMimeType::List KMimeType::allMimeTypes()
  140. {
  141. return KServiceTypeFactory::self()->allMimeTypes();
  142. }
  143. KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
  144. bool _is_local_file, bool _fast_mode )
  145. {
  146. checkEssentialMimeTypes();
  147. TQString path = _url.path();
  148. if ( !_fast_mode && !_is_local_file && _url.isLocalFile() )
  149. _is_local_file = true;
  150. if ( !_fast_mode && _is_local_file && (_mode == 0 || _mode == (mode_t)-1) )
  151. {
  152. KDE_struct_stat buff;
  153. if ( KDE_stat( TQFile::encodeName(path), &buff ) != -1 )
  154. _mode = buff.st_mode;
  155. }
  156. // Look at mode_t first
  157. if ( S_ISDIR( _mode ) )
  158. {
  159. // Special hack for local files. We want to see whether we
  160. // are allowed to enter the directory
  161. if ( _is_local_file )
  162. {
  163. if ( access( TQFile::encodeName(path), R_OK ) == -1 )
  164. return mimeType( "inode/directory-locked" );
  165. }
  166. return mimeType( "inode/directory" );
  167. }
  168. if ( S_ISCHR( _mode ) )
  169. return mimeType( "inode/chardevice" );
  170. if ( S_ISBLK( _mode ) )
  171. return mimeType( "inode/blockdevice" );
  172. if ( S_ISFIFO( _mode ) )
  173. return mimeType( "inode/fifo" );
  174. if ( S_ISSOCK( _mode ) )
  175. return mimeType( "inode/socket" );
  176. // KMimeMagic can do that better for local files
  177. if ( !_is_local_file && S_ISREG( _mode ) && ( _mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
  178. return mimeType( "application/x-executable" );
  179. TQString fileName ( _url.fileName() );
  180. static const TQString& slash = TDEGlobal::staticQString("/");
  181. if ( ! fileName.isNull() && !path.endsWith( slash ) )
  182. {
  183. // Try to find it out by looking at the filename
  184. KMimeType::Ptr mime = KServiceTypeFactory::self()->findFromPattern( fileName );
  185. if ( mime )
  186. {
  187. // Found something - can we trust it ? (e.g. don't trust *.pl over HTTP, could be anything)
  188. if ( _is_local_file || _url.hasSubURL() || // Explicitly trust suburls
  189. KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) )
  190. {
  191. if ( _is_local_file && !_fast_mode ) {
  192. if ( mime->patternsAccuracy()<100 )
  193. {
  194. KMimeMagicResult* result =
  195. KMimeMagic::self()->findFileType( path );
  196. if ( result && result->isValid() && result->accuracy() > 0 )
  197. return mimeType( result->mimeType() );
  198. }
  199. }
  200. return mime;
  201. }
  202. }
  203. static const TQString& dotdesktop = TDEGlobal::staticQString(".desktop");
  204. static const TQString& dotkdelnk = TDEGlobal::staticQString(".kdelnk");
  205. static const TQString& dotdirectory = TDEGlobal::staticQString(".directory");
  206. // Another filename binding, hardcoded, is .desktop:
  207. if ( fileName.endsWith( dotdesktop ) )
  208. return mimeType( "application/x-desktop" );
  209. // Another filename binding, hardcoded, is .kdelnk;
  210. // this is preserved for backwards compatibility
  211. if ( fileName.endsWith( dotkdelnk ) )
  212. return mimeType( "application/x-desktop" );
  213. // .directory files are detected as x-desktop by mimemagic
  214. // but don't have a Type= entry. Better cheat and say they are text files
  215. if ( fileName == dotdirectory )
  216. return mimeType( "text/plain" );
  217. }
  218. if ( !_is_local_file || _fast_mode )
  219. {
  220. TQString def = KProtocolInfo::defaultMimetype( _url );
  221. if ( !def.isEmpty() && def != defaultMimeType() )
  222. {
  223. // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
  224. return mimeType( def );
  225. }
  226. if ( path.endsWith( slash ) || path.isEmpty() )
  227. {
  228. // We have no filename at all. Maybe the protocol has a setting for
  229. // which mimetype this means (e.g. directory).
  230. // For HTTP (def==defaultMimeType()) we don't assume anything,
  231. // because of redirections (e.g. freshmeat downloads).
  232. if ( def.isEmpty() )
  233. {
  234. // Assume inode/directory, if the protocol supports listing.
  235. if ( KProtocolInfo::supportsListing( _url ) )
  236. return mimeType( TQString::fromLatin1("inode/directory") );
  237. else
  238. return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
  239. }
  240. }
  241. // No more chances for non local URLs
  242. return defaultMimeTypePtr();
  243. }
  244. // Do some magic for local files
  245. //kdDebug(7009) << TQString("Mime Type finding for '%1'").arg(path) << endl;
  246. KMimeMagicResult* result = KMimeMagic::self()->findFileType( path );
  247. // If we still did not find it, we must assume the default mime type
  248. if ( !result || !result->isValid() )
  249. return defaultMimeTypePtr();
  250. // The mimemagic stuff was successful
  251. return mimeType( result->mimeType() );
  252. }
  253. KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
  254. bool _is_local_file, bool _fast_mode,
  255. bool *accurate)
  256. {
  257. KMimeType::Ptr mime = findByURL(_url, _mode, _is_local_file, _fast_mode);
  258. if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime != defaultMimeTypePtr());
  259. return mime;
  260. }
  261. KMimeType::Ptr KMimeType::diagnoseFileName(const TQString &fileName, TQString &pattern)
  262. {
  263. return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern );
  264. }
  265. KMimeType::Ptr KMimeType::findByPath( const TQString& path, mode_t mode, bool fast_mode )
  266. {
  267. KURL u;
  268. u.setPath(path);
  269. return findByURL( u, mode, true, fast_mode );
  270. }
  271. KMimeType::Ptr KMimeType::findByContent( const TQByteArray &data, int *accuracy )
  272. {
  273. KMimeMagicResult *result = KMimeMagic::self()->findBufferType(data);
  274. if (accuracy)
  275. *accuracy = result->accuracy();
  276. return mimeType( result->mimeType() );
  277. }
  278. KMimeType::Ptr KMimeType::findByFileContent( const TQString &fileName, int *accuracy )
  279. {
  280. KMimeMagicResult *result = KMimeMagic::self()->findFileType(fileName);
  281. if (accuracy)
  282. *accuracy = result->accuracy();
  283. return mimeType( result->mimeType() );
  284. }
  285. #define GZIP_MAGIC1 0x1f
  286. #define GZIP_MAGIC2 0x8b
  287. KMimeType::Format KMimeType::findFormatByFileContent( const TQString &fileName )
  288. {
  289. KMimeType::Format result;
  290. result.compression = Format::NoCompression;
  291. KMimeType::Ptr mime = findByPath(fileName);
  292. result.text = mime->name().startsWith("text/");
  293. TQVariant v = mime->property("X-TDE-text");
  294. if (v.isValid())
  295. result.text = v.toBool();
  296. if (mime->name().startsWith("inode/"))
  297. return result;
  298. TQFile f(fileName);
  299. if (f.open(IO_ReadOnly))
  300. {
  301. unsigned char buf[10+1];
  302. int l = f.readBlock((char *)buf, 10);
  303. if ((l > 2) && (buf[0] == GZIP_MAGIC1) && (buf[1] == GZIP_MAGIC2))
  304. result.compression = Format::GZipCompression;
  305. }
  306. return result;
  307. }
  308. KMimeType::KMimeType( const TQString & _fullpath, const TQString& _type, const TQString& _icon,
  309. const TQString& _comment, const TQStringList& _patterns )
  310. : KServiceType( _fullpath, _type, _icon, _comment )
  311. {
  312. m_lstPatterns = _patterns;
  313. }
  314. KMimeType::KMimeType( const TQString & _fullpath ) : KServiceType( _fullpath )
  315. {
  316. KDesktopFile _cfg( _fullpath, true );
  317. init ( &_cfg );
  318. if ( !isValid() )
  319. kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl;
  320. }
  321. KMimeType::KMimeType( KDesktopFile *config ) : KServiceType( config )
  322. {
  323. init( config );
  324. if ( !isValid() )
  325. kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl;
  326. }
  327. void KMimeType::init( KDesktopFile * config )
  328. {
  329. config->setDesktopGroup();
  330. m_lstPatterns = config->readListEntry( "Patterns", ';' );
  331. // Read the X-TDE-AutoEmbed setting and store it in the properties map
  332. TQString XKDEAutoEmbed = TQString::fromLatin1("X-TDE-AutoEmbed");
  333. if ( config->hasKey( XKDEAutoEmbed ) )
  334. m_mapProps.insert( XKDEAutoEmbed, TQVariant( config->readBoolEntry( XKDEAutoEmbed ), 0 ) );
  335. TQString XKDEText = TQString::fromLatin1("X-TDE-text");
  336. if ( config->hasKey( XKDEText ) )
  337. m_mapProps.insert( XKDEText, config->readBoolEntry( XKDEText ) );
  338. TQString XKDEIsAlso = TQString::fromLatin1("X-TDE-IsAlso");
  339. if ( config->hasKey( XKDEIsAlso ) ) {
  340. TQString inherits = config->readEntry( XKDEIsAlso );
  341. if ( inherits != name() )
  342. m_mapProps.insert( XKDEIsAlso, inherits );
  343. else
  344. kdWarning(7009) << "Error: " << inherits << " inherits from itself!!!!" << endl;
  345. }
  346. TQString XKDEPatternsAccuracy = TQString::fromLatin1("X-TDE-PatternsAccuracy");
  347. if ( config->hasKey( XKDEPatternsAccuracy ) )
  348. m_mapProps.insert( XKDEPatternsAccuracy, config->readEntry( XKDEPatternsAccuracy ) );
  349. }
  350. KMimeType::KMimeType( TQDataStream& _str, int offset ) : KServiceType( _str, offset )
  351. {
  352. loadInternal( _str ); // load our specific stuff
  353. }
  354. void KMimeType::load( TQDataStream& _str )
  355. {
  356. KServiceType::load( _str );
  357. loadInternal( _str );
  358. }
  359. void KMimeType::loadInternal( TQDataStream& _str )
  360. {
  361. // kdDebug(7009) << "KMimeType::load( TQDataStream& ) : loading list of patterns" << endl;
  362. _str >> m_lstPatterns;
  363. }
  364. void KMimeType::save( TQDataStream& _str )
  365. {
  366. KServiceType::save( _str );
  367. // Warning adding/removing fields here involves a binary incompatible change - update version
  368. // number in tdesycoca.h
  369. _str << m_lstPatterns;
  370. }
  371. TQVariant KMimeType::property( const TQString& _name ) const
  372. {
  373. if ( _name == "Patterns" )
  374. return TQVariant( m_lstPatterns );
  375. return KServiceType::property( _name );
  376. }
  377. TQStringList KMimeType::propertyNames() const
  378. {
  379. TQStringList res = KServiceType::propertyNames();
  380. res.append( "Patterns" );
  381. return res;
  382. }
  383. KMimeType::~KMimeType()
  384. {
  385. }
  386. TQPixmap KMimeType::pixmap( KIcon::Group _group, int _force_size, int _state,
  387. TQString * _path ) const
  388. {
  389. KIconLoader *iconLoader=TDEGlobal::iconLoader();
  390. TQString iconName=icon( TQString::null, false );
  391. if (!iconLoader->extraDesktopThemesAdded())
  392. {
  393. TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
  394. if (!pixmap.isNull() ) return pixmap;
  395. iconLoader->addExtraDesktopThemes();
  396. }
  397. return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
  398. }
  399. TQPixmap KMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
  400. int _state, TQString * _path ) const
  401. {
  402. KIconLoader *iconLoader=TDEGlobal::iconLoader();
  403. TQString iconName=icon( _url, _url.isLocalFile() );
  404. if (!iconLoader->extraDesktopThemesAdded())
  405. {
  406. TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
  407. if (!pixmap.isNull() ) return pixmap;
  408. iconLoader->addExtraDesktopThemes();
  409. }
  410. return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
  411. }
  412. TQPixmap KMimeType::pixmapForURL( const KURL & _url, mode_t _mode, KIcon::Group _group,
  413. int _force_size, int _state, TQString * _path )
  414. {
  415. KIconLoader *iconLoader=TDEGlobal::iconLoader();
  416. TQString iconName = iconForURL( _url, _mode );
  417. if (!iconLoader->extraDesktopThemesAdded())
  418. {
  419. TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
  420. if (!pixmap.isNull() ) return pixmap;
  421. iconLoader->addExtraDesktopThemes();
  422. }
  423. return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
  424. }
  425. TQString KMimeType::iconForURL( const KURL & _url, mode_t _mode )
  426. {
  427. const KMimeType::Ptr mt = findByURL( _url, _mode, _url.isLocalFile(),
  428. false /*HACK*/);
  429. static const TQString& unknown = TDEGlobal::staticQString("unknown");
  430. const TQString mimeTypeIcon = mt->icon( _url, _url.isLocalFile() );
  431. TQString i = mimeTypeIcon;
  432. // if we don't find an icon, maybe we can use the one for the protocol
  433. if ( i == unknown || i.isEmpty() || mt == defaultMimeTypePtr()
  434. // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
  435. || _url.path().length() <= 1 )
  436. {
  437. i = favIconForURL( _url ); // maybe there is a favicon?
  438. if ( i.isEmpty() )
  439. i = KProtocolInfo::icon( _url.protocol() );
  440. // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
  441. if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
  442. i = mimeTypeIcon;
  443. }
  444. return i;
  445. }
  446. TQString KMimeType::favIconForURL( const KURL& url )
  447. {
  448. // this method will be called quite often, so better not read the config
  449. // again and again.
  450. static bool useFavIcons = true;
  451. static bool check = true;
  452. if ( check ) {
  453. check = false;
  454. TDEConfig *config = TDEGlobal::config();
  455. TDEConfigGroupSaver cs( config, "HTML Settings" );
  456. useFavIcons = config->readBoolEntry( "EnableFavicon", true );
  457. }
  458. if ( url.isLocalFile() || !url.protocol().startsWith("http")
  459. || !useFavIcons )
  460. return TQString::null;
  461. DCOPRef kded( "kded", "favicons" );
  462. DCOPReply result = kded.call( "iconForURL(KURL)", url );
  463. if ( result.isValid() )
  464. return result;
  465. return TQString::null;
  466. }
  467. TQString KMimeType::parentMimeType() const
  468. {
  469. TQVariant v = property("X-TDE-IsAlso");
  470. return v.toString();
  471. }
  472. bool KMimeType::is( const TQString& mimeTypeName ) const
  473. {
  474. if ( name() == mimeTypeName )
  475. return true;
  476. TQString st = parentMimeType();
  477. //if (st.isEmpty()) kdDebug(7009)<<"Parent mimetype is empty"<<endl;
  478. while ( !st.isEmpty() )
  479. {
  480. //kdDebug(7009)<<"Checking parent mime type: "<<st<<endl;
  481. KMimeType::Ptr ptr = KMimeType::mimeType( st );
  482. if (!ptr) return false; //error
  483. if ( ptr->name() == mimeTypeName )
  484. return true;
  485. st = ptr->parentMimeType();
  486. }
  487. return false;
  488. }
  489. int KMimeType::patternsAccuracy() const {
  490. TQVariant v = property("X-TDE-PatternsAccuracy");
  491. if (!v.isValid()) return 100;
  492. else
  493. return v.toInt();
  494. }
  495. /*******************************************************
  496. *
  497. * KFolderType
  498. *
  499. ******************************************************/
  500. TQString KFolderType::icon( const TQString& _url, bool _is_local ) const
  501. {
  502. if ( !_is_local || _url.isEmpty() )
  503. return KMimeType::icon( _url, _is_local );
  504. return KFolderType::icon( KURL(_url), _is_local );
  505. }
  506. TQString KFolderType::icon( const KURL& _url, bool _is_local ) const
  507. {
  508. if ( !_is_local )
  509. return KMimeType::icon( _url, _is_local );
  510. KURL u( _url );
  511. u.addPath( ".directory" );
  512. TQString icon;
  513. // using KStandardDirs as this one checks for path being
  514. // a file instead of a directory
  515. if ( KStandardDirs::exists( u.path() ) )
  516. {
  517. KSimpleConfig cfg( u.path(), true );
  518. cfg.setDesktopGroup();
  519. icon = cfg.readEntry( "Icon" );
  520. TQString empty_icon = cfg.readEntry( "EmptyIcon" );
  521. if ( !empty_icon.isEmpty() )
  522. {
  523. bool isempty = false;
  524. DIR *dp = 0L;
  525. struct dirent *ep;
  526. dp = opendir( TQFile::encodeName(_url.path()) );
  527. if ( dp )
  528. {
  529. TQValueList<TQCString> entries;
  530. // Note that readdir isn't guaranteed to return "." and ".." first (#79826)
  531. ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
  532. ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
  533. if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory
  534. isempty = true;
  535. else {
  536. entries.append( ep->d_name );
  537. if ( readdir( dp ) == 0 ) { // only three
  538. // check if we got "." ".." and ".directory"
  539. isempty = entries.find( "." ) != entries.end() &&
  540. entries.find( ".." ) != entries.end() &&
  541. entries.find( ".directory" ) != entries.end();
  542. }
  543. }
  544. if (!isempty && !strcmp(ep->d_name, ".directory"))
  545. isempty = (readdir(dp) == 0L);
  546. closedir( dp );
  547. }
  548. if ( isempty )
  549. return empty_icon;
  550. }
  551. }
  552. if ( icon.isEmpty() )
  553. return KMimeType::icon( _url, _is_local );
  554. if ( icon.startsWith( "./" ) ) {
  555. // path is relative with respect to the location
  556. // of the .directory file (#73463)
  557. KURL v( _url );
  558. v.addPath( icon.mid( 2 ) );
  559. icon = v.path();
  560. }
  561. return icon;
  562. }
  563. TQString KFolderType::comment( const TQString& _url, bool _is_local ) const
  564. {
  565. if ( !_is_local || _url.isEmpty() )
  566. return KMimeType::comment( _url, _is_local );
  567. return KFolderType::comment( KURL(_url), _is_local );
  568. }
  569. TQString KFolderType::comment( const KURL& _url, bool _is_local ) const
  570. {
  571. if ( !_is_local )
  572. return KMimeType::comment( _url, _is_local );
  573. KURL u( _url );
  574. u.addPath( ".directory" );
  575. KDesktopFile cfg( u.path(), true );
  576. TQString comment = cfg.readComment();
  577. if ( comment.isEmpty() )
  578. return KMimeType::comment( _url, _is_local );
  579. return comment;
  580. }
  581. /*******************************************************
  582. *
  583. * KDEDesktopMimeType
  584. *
  585. ******************************************************/
  586. TQString KDEDesktopMimeType::icon( const TQString& _url, bool _is_local ) const
  587. {
  588. if ( !_is_local || _url.isEmpty() )
  589. return KMimeType::icon( _url, _is_local );
  590. KURL u( _url );
  591. return icon( u, _is_local );
  592. }
  593. TQString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const
  594. {
  595. if ( !_is_local )
  596. return KMimeType::icon( _url, _is_local );
  597. KSimpleConfig cfg( _url.path(), true );
  598. cfg.setDesktopGroup();
  599. TQString icon = cfg.readEntry( "Icon" );
  600. TQString type = cfg.readEntry( "Type" );
  601. if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for
  602. // backwards compatibility
  603. {
  604. TQString unmount_icon = cfg.readEntry( "UnmountIcon" );
  605. TQString dev = cfg.readEntry( "Dev" );
  606. if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() )
  607. {
  608. TQString mp = TDEIO::findDeviceMountPoint( dev );
  609. // Is the device not mounted ?
  610. if ( mp.isNull() )
  611. return unmount_icon;
  612. }
  613. } else if ( type == "Link" ) {
  614. const TQString emptyIcon = cfg.readEntry( "EmptyIcon" );
  615. if ( !emptyIcon.isEmpty() ) {
  616. const TQString u = cfg.readPathEntry( "URL" );
  617. const KURL url( u );
  618. if ( url.protocol() == "trash" ) {
  619. // We need to find if the trash is empty, preferrably without using a KIO job.
  620. // So instead tdeio_trash leaves an entry in its config file for us.
  621. KSimpleConfig trashConfig( "trashrc", true );
  622. trashConfig.setGroup( "Status" );
  623. if ( trashConfig.readBoolEntry( "Empty", true ) ) {
  624. return emptyIcon;
  625. }
  626. }
  627. }
  628. }
  629. if ( icon.isEmpty() )
  630. return KMimeType::icon( _url, _is_local );
  631. return icon;
  632. }
  633. TQPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
  634. int _state, TQString * _path ) const
  635. {
  636. TQString _icon = icon( _url, _url.isLocalFile() );
  637. TQPixmap pix = TDEGlobal::iconLoader()->loadIcon( _icon, _group,
  638. _force_size, _state, _path, false );
  639. if ( pix.isNull() )
  640. pix = TDEGlobal::iconLoader()->loadIcon( "unknown", _group,
  641. _force_size, _state, _path, false );
  642. return pix;
  643. }
  644. TQString KDEDesktopMimeType::comment( const TQString& _url, bool _is_local ) const
  645. {
  646. if ( !_is_local || _url.isEmpty() )
  647. return KMimeType::comment( _url, _is_local );
  648. KURL u( _url );
  649. return comment( u, _is_local );
  650. }
  651. TQString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const
  652. {
  653. if ( !_is_local )
  654. return KMimeType::comment( _url, _is_local );
  655. KDesktopFile cfg( _url.path(), true );
  656. TQString comment = cfg.readComment();
  657. if ( comment.isEmpty() )
  658. return KMimeType::comment( _url, _is_local );
  659. return comment;
  660. }
  661. pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local )
  662. {
  663. // It might be a security problem to run external untrusted desktop
  664. // entry files
  665. if ( !_is_local )
  666. return 0;
  667. KSimpleConfig cfg( u.path(), true );
  668. cfg.setDesktopGroup();
  669. TQString type = cfg.readEntry( "Type" );
  670. if ( type.isEmpty() )
  671. {
  672. TQString tmp = i18n("The desktop entry file %1 "
  673. "has no Type=... entry.").arg(u.path() );
  674. KMessageBoxWrapper::error( 0, tmp);
  675. return 0;
  676. }
  677. //kdDebug(7009) << "TYPE = " << type.data() << endl;
  678. if ( type == "FSDevice" )
  679. return runFSDevice( u, cfg );
  680. else if ( type == "Application" )
  681. return runApplication( u, u.path() );
  682. else if ( type == "Link" )
  683. {
  684. cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon)
  685. return runLink( u, cfg );
  686. }
  687. else if ( type == "MimeType" )
  688. return runMimeType( u, cfg );
  689. TQString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type );
  690. KMessageBoxWrapper::error( 0, tmp);
  691. return 0;
  692. }
  693. pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg )
  694. {
  695. pid_t retval = 0;
  696. TQString dev = cfg.readEntry( "Dev" );
  697. if ( dev.isEmpty() )
  698. {
  699. TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
  700. KMessageBoxWrapper::error( 0, tmp);
  701. return retval;
  702. }
  703. TQString mp = TDEIO::findDeviceMountPoint( dev );
  704. // Is the device already mounted ?
  705. if ( !mp.isNull() )
  706. {
  707. KURL mpURL;
  708. mpURL.setPath( mp );
  709. // Open a new window
  710. retval = KRun::runURL( mpURL, TQString::fromLatin1("inode/directory") );
  711. }
  712. else
  713. {
  714. bool ro = cfg.readBoolEntry( "ReadOnly", false );
  715. TQString fstype = cfg.readEntry( "FSType" );
  716. if ( fstype == "Default" ) // KDE-1 thing
  717. fstype = TQString::null;
  718. TQString point = cfg.readEntry( "MountPoint" );
  719. #ifndef Q_WS_WIN
  720. (void) new KAutoMount( ro, fstype, dev, point, _url.path() );
  721. #endif
  722. retval = -1; // we don't want to return 0, but we don't want to return a pid
  723. }
  724. return retval;
  725. }
  726. pid_t KDEDesktopMimeType::runApplication( const KURL& , const TQString & _serviceFile )
  727. {
  728. KService s( _serviceFile );
  729. if ( !s.isValid() )
  730. // The error message was already displayed, so we can just quit here
  731. return 0;
  732. KURL::List lst;
  733. return KRun::run( s, lst );
  734. }
  735. pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg )
  736. {
  737. TQString u = cfg.readPathEntry( "URL" );
  738. if ( u.isEmpty() )
  739. {
  740. TQString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() );
  741. KMessageBoxWrapper::error( 0, tmp );
  742. return 0;
  743. }
  744. KURL url ( u );
  745. KRun* run = new KRun(url);
  746. // X-TDE-LastOpenedWith holds the service desktop entry name that
  747. // was should be preferred for opening this URL if possible.
  748. // This is used by the Recent Documents menu for instance.
  749. TQString lastOpenedWidth = cfg.readEntry( "X-TDE-LastOpenedWith" );
  750. if ( !lastOpenedWidth.isEmpty() )
  751. run->setPreferredService( lastOpenedWidth );
  752. return -1; // we don't want to return 0, but we don't want to return a pid
  753. }
  754. pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & )
  755. {
  756. // Hmm, can't really use keditfiletype since we might be looking
  757. // at the global file, or at a file not in share/mimelnk...
  758. TQStringList args;
  759. args << "openProperties";
  760. args << url.path();
  761. int pid;
  762. if ( !TDEApplication::tdeinitExec("kfmclient", args, 0, &pid) )
  763. return pid;
  764. TDEProcess p;
  765. p << "kfmclient" << args;
  766. p.start(TDEProcess::DontCare);
  767. return p.pid();
  768. }
  769. TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url )
  770. {
  771. TQValueList<Service> result;
  772. if ( !_url.isLocalFile() )
  773. return result;
  774. KSimpleConfig cfg( _url.path(), true );
  775. cfg.setDesktopGroup();
  776. TQString type = cfg.readEntry( "Type" );
  777. if ( type.isEmpty() )
  778. return result;
  779. if ( type == "FSDevice" )
  780. {
  781. TQString dev = cfg.readEntry( "Dev" );
  782. if ( dev.isEmpty() )
  783. {
  784. TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
  785. KMessageBoxWrapper::error( 0, tmp);
  786. }
  787. else
  788. {
  789. TQString mp = TDEIO::findDeviceMountPoint( dev );
  790. // not mounted ?
  791. if ( mp.isEmpty() )
  792. {
  793. Service mount;
  794. mount.m_strName = i18n("Mount");
  795. mount.m_type = ST_MOUNT;
  796. result.append( mount );
  797. }
  798. else
  799. {
  800. Service unmount;
  801. #ifdef HAVE_VOLMGT
  802. /*
  803. * Solaris' volume management can only umount+eject
  804. */
  805. unmount.m_strName = i18n("Eject");
  806. #else
  807. unmount.m_strName = i18n("Unmount");
  808. #endif
  809. unmount.m_type = ST_UNMOUNT;
  810. result.append( unmount );
  811. }
  812. }
  813. }
  814. return result;
  815. }
  816. TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, bool bLocalFiles )
  817. {
  818. KSimpleConfig cfg( path, true );
  819. return userDefinedServices( path, cfg, bLocalFiles );
  820. }
  821. TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, TDEConfig& cfg, bool bLocalFiles )
  822. {
  823. return userDefinedServices( path, cfg, bLocalFiles, KURL::List() );
  824. }
  825. TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, TDEConfig& cfg, bool bLocalFiles, const KURL::List & file_list )
  826. {
  827. TQValueList<Service> result;
  828. cfg.setDesktopGroup();
  829. if ( !cfg.hasKey( "Actions" ) && !cfg.hasKey( "X-TDE-GetActionMenu") )
  830. return result;
  831. if ( cfg.hasKey( "TryExec" ) )
  832. {
  833. TQString tryexec = cfg.readPathEntry( "TryExec" );
  834. TQString exe = KStandardDirs::findExe( tryexec );
  835. if (exe.isEmpty()) {
  836. return result;
  837. }
  838. }
  839. TQStringList keys;
  840. if( cfg.hasKey( "X-TDE-GetActionMenu" )) {
  841. TQString dcopcall = cfg.readEntry( "X-TDE-GetActionMenu" );
  842. const TQCString app = TQString(dcopcall.section(' ', 0,0)).utf8();
  843. TQByteArray dataToSend;
  844. TQDataStream dataStream(dataToSend, IO_WriteOnly);
  845. dataStream << file_list;
  846. TQCString replyType;
  847. TQByteArray replyData;
  848. TQCString object = TQString(dcopcall.section(' ', 1,-2)).utf8();
  849. TQString function = dcopcall.section(' ', -1);
  850. if(!function.endsWith("(KURL::List)")) {
  851. kdWarning() << "Desktop file " << path << " contains an invalid X-TDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
  852. } else {
  853. if(kapp->dcopClient()->call( app, object,
  854. function.utf8(),
  855. dataToSend, replyType, replyData, true, -1)
  856. && replyType == "TQStringList" ) {
  857. TQDataStream dataStreamIn(replyData, IO_ReadOnly);
  858. dataStreamIn >> keys;
  859. }
  860. }
  861. }
  862. keys += cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator!
  863. if ( keys.count() == 0 )
  864. return result;
  865. TQStringList::ConstIterator it = keys.begin();
  866. TQStringList::ConstIterator end = keys.end();
  867. for ( ; it != end; ++it )
  868. {
  869. //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl;
  870. TQString group = *it;
  871. if (group == "_SEPARATOR_")
  872. {
  873. Service s;
  874. result.append(s);
  875. continue;
  876. }
  877. group.prepend( "Desktop Action " );
  878. bool bInvalidMenu = false;
  879. if ( cfg.hasGroup( group ) )
  880. {
  881. cfg.setGroup( group );
  882. if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) )
  883. bInvalidMenu = true;
  884. else
  885. {
  886. TQString exec = cfg.readPathEntry( "Exec" );
  887. if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") )
  888. {
  889. Service s;
  890. s.m_strName = cfg.readEntry( "Name" );
  891. s.m_strIcon = cfg.readEntry( "Icon" );
  892. s.m_strExec = exec;
  893. s.m_type = ST_USER_DEFINED;
  894. s.m_display = !cfg.readBoolEntry( "NoDisplay" );
  895. result.append( s );
  896. }
  897. }
  898. }
  899. else
  900. bInvalidMenu = true;
  901. if ( bInvalidMenu )
  902. {
  903. TQString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it );
  904. KMessageBoxWrapper::error( 0, tmp );
  905. }
  906. }
  907. return result;
  908. }
  909. void KDEDesktopMimeType::executeService( const TQString& _url, KDEDesktopMimeType::Service& _service )
  910. {
  911. KURL u;
  912. u.setPath(_url);
  913. KURL::List lst;
  914. lst.append( u );
  915. executeService( lst, _service );
  916. }
  917. void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service )
  918. {
  919. //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl;
  920. if ( _service.m_type == ST_USER_DEFINED )
  921. {
  922. kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName
  923. << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl;
  924. KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon );
  925. // The action may update the desktop file. Example: eject unmounts (#5129).
  926. KDirNotify_stub allDirNotify("*", "KDirNotify*");
  927. allDirNotify.FilesChanged( urls );
  928. return;
  929. }
  930. else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT )
  931. {
  932. Q_ASSERT( urls.count() == 1 );
  933. TQString path = urls.first().path();
  934. //kdDebug(7009) << "MOUNT&UNMOUNT" << endl;
  935. KSimpleConfig cfg( path, true );
  936. cfg.setDesktopGroup();
  937. TQString dev = cfg.readEntry( "Dev" );
  938. if ( dev.isEmpty() )
  939. {
  940. TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path );
  941. KMessageBoxWrapper::error( 0, tmp );
  942. return;
  943. }
  944. TQString mp = TDEIO::findDeviceMountPoint( dev );
  945. if ( _service.m_type == ST_MOUNT )
  946. {
  947. // Already mounted? Strange, but who knows ...
  948. if ( !mp.isEmpty() )
  949. {
  950. kdDebug(7009) << "ALREADY Mounted" << endl;
  951. return;
  952. }
  953. bool ro = cfg.readBoolEntry( "ReadOnly", false );
  954. TQString fstype = cfg.readEntry( "FSType" );
  955. if ( fstype == "Default" ) // KDE-1 thing
  956. fstype = TQString::null;
  957. TQString point = cfg.readEntry( "MountPoint" );
  958. #ifndef Q_WS_WIN
  959. (void)new KAutoMount( ro, fstype, dev, point, path, false );
  960. #endif
  961. }
  962. else if ( _service.m_type == ST_UNMOUNT )
  963. {
  964. // Not mounted? Strange, but who knows ...
  965. if ( mp.isEmpty() )
  966. return;
  967. #ifndef Q_WS_WIN
  968. (void)new KAutoUnmount( mp, path );
  969. #endif
  970. }
  971. }
  972. else
  973. assert( 0 );
  974. }
  975. const TQString & KMimeType::defaultMimeType()
  976. {
  977. static const TQString & s_strDefaultMimeType =
  978. TDEGlobal::staticQString( "application/octet-stream" );
  979. return s_strDefaultMimeType;
  980. }
  981. void KMimeType::virtual_hook( int id, void* data )
  982. { KServiceType::virtual_hook( id, data ); }
  983. void KFolderType::virtual_hook( int id, void* data )
  984. { KMimeType::virtual_hook( id, data ); }
  985. void KDEDesktopMimeType::virtual_hook( int id, void* data )
  986. { KMimeType::virtual_hook( id, data ); }
  987. void KExecMimeType::virtual_hook( int id, void* data )
  988. { KMimeType::virtual_hook( id, data ); }
  989. #include "kmimetyperesolver.moc"