

MIME types are used to describe the content type of files or data chunks. Originally they were introduced in order to allow sending around image or sound files etc. by e-mail (MIME stands for "Multipurpose Internet Mail Extensions"). Later this system was also used by web browsers to determine how to present data sent by a web server to the user. For example, an HTML page has a MIME type "text/html", a postscript file "application/postscript". In KDE, this concept is used at a variety of places:
In Konqueror's icon view, files are represented by icons. Each MIME type has a certain associated icon shown here.
When you click onto a file icon or a file name in Konqueror, either the file is shown in an embedded view, or an application associated with the file type is opened.
When you drag and drop some data from one application to another (or within the same application), the drop target may choose to accept only certain data types. Furthermore, it will handle image data different from textual data.
Clipboard data has a MIME type. Traditionally, X programs only handle pixmaps or texts, but with Qt, there are no restrictions on the data type.
From the above examples, it is clear that MIME handling is a complex issue. First, it is necessary to establish a mapping from file names to MIME types. KDE goes one step further in allowing even file contents to be mapped to MIME types, for cases in which the file name is not available. Second, it is necessary to map MIME types to applications or libraries which can view or edit a file with a certain type, or create a thumbnail picture for it.
There is a variety of APIs to figure out the MIME type of data or files. In
general, there is a certain speed/reliability trade-off you have to make. You
can find out the type of a file by examining only its file name (i.e. in most
cases the file name extension). For example, a file
foo.jpg is normally "image/jpeg". In cases where the
extension is stripped off this is not safe, and you actually have to look at
the contents of the file. This is of course slower, in particular for files
that have to be downloaded via HTTP first. The content-based method is based
on the file KDEDIR/share/mimelnk/magic and therefore
difficult to extend. But in general, MIME type information can easily be made
available to the system by installing a .desktop file, and
it is efficiently and conveniently available through the KDE libraries.
Let us define a type "application/x-foo" for our new
foobar program. To this end, you have to write a
file foo.desktop and install it into
KDEDIR/share/mimelnk/application. (This is the usual
location, which may differ between distributions). This can be done by adding
this to the Makefile.am:
mimedir = $(kde_mimedir)/application mime_DATA = foo.desktop EXTRA_DIST = $(mime_DATA)
The file foo.desktop should look as follows:
[Desktop Entry] Type=MimeType MimeType=application/x-foo Icon=fooicon Patterns=*.foo; DefaultApp=foobar Comment=Foo Data File Comment[de]=Foo Datei
The "Comment" entry is supposed to be translated. Since the
.desktop file specifies an icon, you should also install
an icon fooicon.png, which represents the file e.g. in
Konqueror.
In the KDE libraries, such a type definition is mapped to an instance of the class KMimeType. Use this like in the following example:
KMimeType::Ptr type = KMimeType::mimeType("application/x-foo");
cout << "Type: " << type->name() < endl;
cout << "Icon: " << type->icon() < endl;
cout << "Comment: " << type->icon() < endl;
QStringList patterns = type->patterns();
QStringList::ConstIterator it;
for (it = patterns.begin(); it != patterns.end(); ++it)
cout << "Pattern: " << (*it) << endl;
The fast method for determining the type of a file is
KMimeType::findByURL(). This looks for the URL string and
in most cases determines the type from the extension. For certain protocols
(e.g. http, man, info), this mechanism is not used. For example, CGI scripts
on web servers written in Perl often have the extension
.pl, which would indicate a
"text/x-perl" type. However, we file delivered by the
server is the output of this script, which is normally HTML. For such a case,
KMimeType::findByURL() returns the MIME type
"application/octet-stream" (available through
KMimeType::defaultMimeType()), which indicates a failure
to find out the type.
KMimeType::Ptr type = KMimeType::findByURL("/home/bernd/foobar.jpg");
if (type->name() == KMimeType::defaultMimeType())
cout << "Could not find out type" << endl;
else
cout << "Type: " << type->name() << endl;
(this method has some more arguments, but these are undocumented, so simply forget about them.)
You may want to find out a MIME from the contents of file instead of the file name. This is more reliable, but also slower, as it requires reading a part of the file. This is done with the KMimeMagic class, which has different error handling:
KMimeMagicResult *result = KMimeMagic::self()->findFileType("/home/bernd/foobar.jpg");
if (!result || !result->isValid())
cout << "Could not find out type" << endl;
else
cout << "Type: " << result->mimeType() << endl;
As a variant of this function, you can also determine the type of a memory chunk. This is e.g. used in Kate in order to find out the highlighting mode:
QByteArray array;
...
KMimeMagicResult *result = KMimeMagic::self()->findBufferType(array);
if (!result || !result->isValid())
cout << "Could not find out type" << endl;
else
cout << "Type: " << result->mimeType() << endl;
Of course, even KMimeMagic is only able to determine a file type from the contents of a local file. For remote files, there is a further possibility:
KURL url("http://developer.kde.org/favicon.ico");
QString type = KIO::NetAccess::mimetype(url);
if (type == KMimeType::defaultMimeType())
cout << "Could not find out type" << endl;
else
cout << "Type: " << type << endl;
This starts a KIO job to download a part of the file and check this.
Note that this function is perhaps quite slow and blocks the program. Normally
you will only want to use this if KMimeType::findByURL()
has returned "application/octet-stream".
On the other hand, if you do not want to block your application, you can also explicitly start the KIO job and connect to some of its signals:
void FooClass::findType()
{
KURL url("http://developer.kde.org/favicon.ico");
KIO::MimetypeJob *job = KIO::mimetype(url);
connect( job, SIGNAL(result(KIO::Job*)),
this, SLOT(mimeResult(KIO::Job*)) );
}
void FooClass::mimeResult(KIO::Job *job)
{
if (job->error())
job->showErrorDialog();
else
cout << "MIME type: " << ((KIO::MimetypeJob *)job)->mimetype() << endl;
}
When an application is installed, it installs a .desktop
file which contains a list of MIME types this application can load. Similarly,
components like KParts make this information available by their service
.desktop files. So in general, there are several programs
and components which can process a given MIME type. You can obtain such a list
from the class KServiceTypeProfile:
KService::OfferList offers = KServiceTypeProfile::offers("text/html", "Application");
KService::OfferList::ConstIterator it;
for (it = offers.begin(); it != offers.end(); ++it) {
KService::Ptr service = (*it);
cout << "Name: " << service->name() << endl;
}
The return value of this function is a list of service offers. A
KServiceOffer object packages a KService::Ptr together
with a preference number. The list returned by
KServiceTypeProfile::offers() is ordered by the user's
preference. The user can change this by calling "keditfiletype
text/html" or choosing on
Konqueror's context menu on a HTML file.
In the above example, an offer list of the applications supporting
text/html was requested. This will - among others - contain
HTML editors like Quanta Plus. You can also replace
the second argument "Application" by
"KParts::ReadOnlyPart". In that case, you get a list of
embedable components for presenting HTML content, for example KHTML.
In most cases, you are not interested in the list of all service offers for a combination of MIME type and service type. There is a convenience function which gives you only the service offer with the highest preference:
KService::Ptr offer = KServiceTypeProfile::preferredService("text/html", "Application");
if (offer)
cout << "Name: " << service->name() << endl;
else
cout << "No appropriate service found" << endl;
For even more complex queries, there is a full-blown CORBA-like trader.
In order to run an application service with some URLs, use KRun:
KURL::List urlList; urlList << "http://www.ietf.org/rfc/rfc1341.txt?number=1341"; urlList << "http://www.ietf.org/rfc/rfc2046.txt?number=2046"; KRun::run(offer.service(), urlList);
In this section, we want to list some APIs which are loosely related to the previous discussion.
Getting an icon for a URL. This looks for the type of the URL and returns the associated icon.
KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
QString icon = KMimeType::iconForURL(url);
Running a URL. This looks for the type of the URL and starts the user's preferred program associated with this type.
KURL url("http://dot.kde.org");
new KRun(url);