From: Vadim Zeitlin Date: Tue, 5 Jan 1999 22:40:50 +0000 (+0000) Subject: MIME classes with docs (not yet added to the makefiles) X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/b13d92d1c8840feca54b00e15ad558d77bda78df MIME classes with docs (not yet added to the makefiles) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1321 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index 19ecd75429..e7eded49ff 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -81,6 +81,7 @@ $$\image{14cm;0cm}{wxclass.ps}$$ \input file.tex \input filedlg.tex \input filehist.tex +\input filetype.tex \input focusevt.tex \input font.tex \input fontdlg.tex @@ -113,13 +114,14 @@ $$\image{14cm;0cm}{wxclass.ps}$$ \input menuitem.tex \input menuevt.tex \input memorydc.tex -\input msgdlg.tex \input metafile.tex +\input mimetype.tex \input minifram.tex \input module.tex \input mouseevt.tex \input moveevt.tex \input mltchdlg.tex +\input msgdlg.tex \input mutex.tex \input mutexlck.tex \input node.tex diff --git a/docs/latex/wx/filetype.tex b/docs/latex/wx/filetype.tex new file mode 100644 index 0000000000..3b56bcdb6b --- /dev/null +++ b/docs/latex/wx/filetype.tex @@ -0,0 +1,194 @@ +\section{\class{wxFileType}}\label{wxfiletype} + +This class holds information about a given "file type". File type is the same as +MIME type under Unix, but under Windows it corresponds more to an extension than +to MIME type (in fact, several extensions may correspond to a file type). This +object may be created in several different ways: the program might know the file +extension and wish to find out the corresponding MIME type or, conversely, it +might want to find the right extension for the file to which it writes the +contents of given MIME type. Depending on how it was created some fields may be +unknown so the return value of all the accessors {\bf must} be checked: FALSE +will be returned if the corresponding information couldn't be found. + +The objects of this class are never created by the application code but are +returned by \helpref{wxMimeTypesManager::GetFileTypeFromMimeType}{wxmimetypesmanagergetfiletypefrommimetype} and +\helpref{wxMimeTypesManager::GetFileTypeFromExtension}{wxmimetypesmanagergetfiletypefromextension} methods. +But it's your responsability to delete the returned pointer when you're done +with it! + +% TODO describe MIME types better than this... +A brief remainder about what the MIME types are (see the RFC 1341 for more +information): basicly, it is just a pair category/type (for example, +"text/plain") where the category is a basic indication of what a file is +(examples of categories are "application", "image", "text", "binary"...) and +type is a precise definition of the document format: "plain" in the example +above means just ASCII text without any formatting, while "text/html" is the +HTML document source. + +A MIME type may have one or more associated extensions: "text/plain" will +typically correspond to the extension ".txt", but may as well be associated with +".ini" or ".conf". + +\wxheading{Required headers} + +#include + +\wxheading{Derived from} + +No base class. + +\wxheading{See also} + +\helpref{wxMimeTypesManager}{wxmimetypesmanager} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{MessageParameters class}{wxfiletypemessageparameters} + +One of the most common usages of MIME is to encode an e-mail message. The MIME +type of the encoded message is an example of a {\it message parameter}. These +parameters are found in the message headers ("Content-XXX"). At the very least, +they must specify the MIME type and the version of MIME used, but almost always +they provide additional information about the message such as the original file +name or the charset (for the text documents). + +These parameters may be useful to the program used to open, edit, view or print +the message, so, for example, an e-mail client program will have to pass them to +this program. Because wxFileType itself can not know about these parameters, +it uses MessageParameters class to query them. The default implementation only +requiers the caller to provide the file name (always used by the program to be +called - it must know which file to open) and the MIME type and supposes that +there are no other parameters. If you wish to supply additional parameters, you +must derive your own class from MessageParameters and override GetParamValue() +function, for example: + +\begin{verbatim} +// provide the message parameters for the MIME type manager +class MailMessageParamaters : public wxFileType::MessageParameters +{ +public: + MailMessageParamaters(const wxString& filename, + const wxString& mimetype) + : wxFileType::MessageParameters(filename, mimetype) + { + } + + virtual wxString GetParamValue(const wxString& name) const + { + // parameter names are not case-sensitive + if ( name.CmpNoCase("charset") == 0 ) + return "US-ASCII"; + else + return wxFileType::MessageParameters::GetParamValue(name); + } +}; +\end{verbatim} + +Now you only need to create an object of this class and pass it to, for example, +\helpref{GetOpenCommand}{wxfiletypegetopencommand} like this: + +\begin{verbatim} +wxString command; +if ( filetype->GetOpenCommand(&command, + MailMessageParamaters("foo.txt", "text/plain")) ) +{ + // the full command for opening the text documents is in 'command' + // (it might be "notepad foo.txt" under Windows or "cat foo.txt" under Unix) +} +else +{ + // we don't know how to handle such files... +} + +\end{verbatim} + +{\bf Windows:} As only the file name is used by the program associated with the +given extension anyhow (but no other message parameters), there is no need to +ever derive from MessageParameters class for a Windows-only program. + +\membersection{wxFileType::wxFileType}\label{wxfiletypewxfiletype} +\func{}{wxFileType}{\void} + +The default constructor is private because you should never create objects of +this type: they are only returned by +\helpref{wxMimeTypesManager}{wxmimetypesmanager} methods. + +\membersection{wxFileType::\destruct{wxFileType}}\label{wxfiletypedtor} +\func{}{\destruct{wxFileType}{\void} + +The destructor of this class is not virtual, so it should not be derived from. + +\membersection{wxFileType::GetMimeType}\label{wxfiletypegetmimetype} +\func{bool}{GetMimeType}{\param{wxString *}{mimeType}} + +If the function returns TRUE, the string pointed to by {\it mimeType} is filled +with full MIME type specification for this file type: for example, "text/plain". + +\membersection{wxFileType::GetExtensions}\label{wxfiletypegetextensions} +\func{bool}{GetExtensions}{\param{wxArrayString \&}{extensions}} + +If the function returns TRUE, the array {\it extensions} is filled +with all extensions associated with this file type: for example, it may +contain the following two elements for the MIME type "text/html" (notice the +absence of the leading dot): "html" and "htm". + +{\bf Windows:} This function is currently not implemented: there is no +(efficient) way to retrieve associated extensions from the given MIME type on +this platform, so it will only return TRUE if the wxFileType object was created +by \helpref{GetFileTypeFromExtension}{wxmimetypesmanagergetfiletypefromextension} +function in the first place. + +\membersection{wxFileType::GetIcon}\label{wxfiletypegeticon} +\func{bool}{GetIcon}{\param{wxIcon *}{icon}} + +If the function returns TRUE, the icon associated with this file type will be +created and assigned to the {\it icon} parameter. + +{\bf Unix:} This function always returns FALSE under Unix. + +\membersection{wxFileType::GetDescription}\label{wxfiletypegetdescription} +\func{bool}{GetDescription}{\param{wxString *}{desc}} + +If the function returns TRUE, the string pointed to by {\it desc} is filled +with a brief description for this file type: for example, "text document" for +the "text/plain" MIME type. + +\membersection{wxFileType::GetOpenCommand}\label{wxfiletypegetopencommand} +\func{bool}{GetOpenCommand}{\param{wxString *}{command},\param{MessageParameters \&}{params}} + +If the function returns TRUE, the string pointed to by {\it command} is filled +with the command which must be executed (see \helpref{wxExecute}{wxexecute}) in +order to open the file of the given type. The name of the file is +retrieved from \helpref{MessageParameters}{wxfiletypemessageparameters} class. + +\membersection{wxFileType::GetPrintCommand}\label{wxfiletypegetprintcommand} +\func{bool}{GetPrintCommand}{\param{wxString *}{command},\param{MessageParameters \&}{params}} + +If the function returns TRUE, the string pointed to by {\it command} is filled +with the command which must be executed (see \helpref{wxExecute}{wxexecute}) in +order to print the file of the given type. The name of the file is +retrieved from \helpref{MessageParameters}{wxfiletypemessageparameters} class. + +\membersection{wxFileType::ExpandCommand}\label{wxfiletypeexpandcommand} +\func{static wxString}{ExpandCommand}{\param{const wxString \&}{command},\param{MessageParameters \&}{params}} + +This function is primarly intended for GetOpenCommand and GetPrintCommand +usage but may be also used by the application directly if, for example, you want +to use some non default command to open the file. + +The function replaces all occurences of +\twocolwidtha{7cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{format specificator}{with} +\twocolitem{\%s}{the full file name} +\twocolitem{\%t}{the MIME type} +\twocolitem{\%\{param\}}{the value of the parameter {\it param}} +\end{twocollist} +using the MessageParameters object you pass to it. + +If there is no '\%s' in the command string (and the string is not empty), it is +assumed that the command reads the data on stdin and so the effect is the same +as "< \%s" were appended to the string. + +Unlike all other functions of this class, there is no error return for this +function. diff --git a/docs/latex/wx/mimetype.tex b/docs/latex/wx/mimetype.tex new file mode 100644 index 0000000000..263e124619 --- /dev/null +++ b/docs/latex/wx/mimetype.tex @@ -0,0 +1,111 @@ +\section{\class{wxMimeTypesManager}}\label{wxmimetypesmanager} + +This class allows the application to retrieve the information about all known +MIME types from a system-specific location and the filename extensions to the +MIME types and vice versa. After initialization the functions +\helpref{wxMimeTypesManager::GetFileTypeFromMimeType}{wxmimetypesmanagergetfiletypefrommimetype} +and \helpref{wxMimeTypesManager::GetFileTypeFromExtension}{wxmimetypesmanagergetfiletypefromextension} +may be called: they will return a \helpref{wxFileType}{wxfiletype} object which +may be further queried for file description, icon and other attributes. + +{\bf Windows:} MIME type information is stored in the registry and no additional +initialization is needed. + +{\bf Unix:} MIME type information is stored in the files mailcap and mime.types +(system-wide) and .mailcap and .mime.types in the current user's home directory: +all of these files are searched for and loaded if found by default. However, +additional functions +\helpref{wxMimeTypesManager::ReadMailcap}{wxmimetypesmanagerreadmailcap} and +\helpref{wxMimeTypesManager::ReadMimeTypes}{wxmimetypesmanagerreadmimetypes} are +provided to load additional files. + +NB: Currently, wxMimeTypesManager is limited to reading MIME type information +but it will support modifying it as well in the future versions. + +\wxheading{Required headers} + +#include + +\wxheading{Derived from} + +No base class. + +\wxheading{See also} + +\helpref{wxFileType}{wxfiletype} + +\latexignore{\rtfignore{\wxheading{Function groups}}} + +\membersection{Constructor and destructor} + +NB: You won't normally need to use more than one wxMimeTypesManager object in a +program. + +\helpref{wxMimeTypesManager}{wxmimetypesmanagerctor}\\ +\helpref{\destruct{wxMimeTypesManager}}{wxmimetypesmanagerdtor} + +\membersection{Query database} + +These functions are the heart of this class: they allow to find a +\helpref{file type}{wxfiletype} object from either file extension or MIME type. +If the function is successful, it returns a pointer to the wxFileType object +which {\bf must be deleted by the caller}, otherwise NULL will be returned. + +\helpref{GetFileTypeFromMimeType}{wxmimetypesmanagergetfiletypefrommimetype}\\ +\helpref{GetFileTypeFromExtension}{wxmimetypesmanagergetfiletypefromextension} + +\membersection{Initialization functions} + +{\bf Unix:} These functions may be used to load additional (except for the +default ones which are loaded automatically) files containing MIME +information in either mailcap(5) or mime.types(5) format. + +\helpref{ReadMailcap}{wxmimetypesmanagerreadmailcap}\\ +\helpref{ReadMimeTypes}{wxmimetypesmanagerreadmimetypes} + +%%%%% MEMBERS HERE %%%%% +\helponly{\insertatlevel{2}{ + +\wxheading{Members} + +}} + +\membersection{wxMimeTypesManager::wxMimeTypesManager}\label{wxmimetypesmanagerctor} +\func{}{wxMimeTypesManager}{\void} + +Constructor puts the object in the "working" state, no additional initialization +are needed - but \helpref{ReadXXX}{wxmimetypesmanagerinit} may be used to load +additional mailcap/mime.types files. + +\membersection{wxMimeTypesManager::\destruct{wxMimeTypesManager}}\label{wxmimetypesmanagerdtor} +\func{}{\destruct{wxMimeTypesManager}{\void} + +Destructor is not virtual, so this class should not be derived from. + +\membersection{wxMimeTypesManager::GetFileTypeFromExtension}\label{wxmimetypesmanagergetfiletypefromextension} +\func{wxFileType *}{GetFileTypeFromExtension}{\param{const wxString \&}{extension}} + +Gather information about the files with given extension and return the +corresponding \helpref{wxFileType}{wxfiletype} object or NULL if the extension +is unknown. + +\membersection{wxMimeTypesManager::GetFileTypeFromMimeType}\label{wxmimetypesmanagergetfiletypefrommimetype} +\func{wxFileType *}{GetFileTypeFromMimeType}{\param{const wxString \&}{mimeType}} + +Gather information about the files with given MIME type and return the +corresponding \helpref{wxFileType}{wxfiletype} object or NULL if the MIME type +is unknown. + +\membersection{wxMimeTypesManager::ReadMailcap}\label{wxmimetypesmanagerreadmailcap} +\func{\void}{ReadMailcap}{\param{const wxString \&}{filename}} + +Load additional file containing information about MIME types and associated +information in mailcap format. See metamail(1) and mailcap(5) for more +information. + +\membersection{wxMimeTypesManager::ReadMimeTypes}\label{wxmimetypesmanagerreadmimetypes} +\func{\void}{ReadMimeTypes}{\param{const wxString \&}{filename}} + +Load additional file containing information about MIME types and associated +information in mime.types file format. See metamail(1) and mailcap(5) for more +information. diff --git a/include/wx/mimetype.h b/include/wx/mimetype.h new file mode 100644 index 0000000000..d79caf78af --- /dev/null +++ b/include/wx/mimetype.h @@ -0,0 +1,145 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/mimetype.h +// Purpose: classes and functions to manage MIME types +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.09.98 +// RCS-ID: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows license (part of wxExtra library) +///////////////////////////////////////////////////////////////////////////// + +#ifndef _MIMETYPE_H +#define _MIMETYPE_H + +// fwd decls +class wxIcon; +class wxFileTypeImpl; +class wxMimeTypesManagerImpl; + +// the things we really need +#include "wx/string.h" + +// This class holds information about a given "file type". File type is the +// same as MIME type under Unix, but under Windows it corresponds more to an +// extension than to MIME type (in fact, several extensions may correspond to a +// file type). This object may be created in many different ways and depending +// on how it was created some fields may be unknown so the return value of all +// the accessors *must* be checked! +class wxFileType +{ +friend wxMimeTypesManagerImpl; // it has access to m_impl + +public: + // An object of this class must be passed to Get{Open|Print}Command. The + // default implementation is trivial and doesn't know anything at all about + // parameters, only filename and MIME type are used (so it's probably ok for + // Windows where %{param} is not used anyhow) + class MessageParameters + { + public: + // ctors + MessageParameters() { } + MessageParameters(const wxString& filename, const wxString& mimetype) + : m_filename(filename), m_mimetype(mimetype) { } + + // accessors (called by GetOpenCommand) + // filename + const wxString& GetFileName() const { return m_filename; } + // mime type + const wxString& GetMimeType() const { return m_mimetype; } + + // override this function in derived class + virtual wxString GetParamValue(const wxString& paramName) const + { return ""; } + + // virtual dtor as in any base class + virtual ~MessageParameters() { } + + protected: + wxString m_filename, m_mimetype; + }; + + // accessors: all of them return true if the corresponding information + // could be retrieved/found, false otherwise (and in this case all [out] + // parameters are unchanged) + // return the MIME type for this file type + bool GetMimeType(wxString *mimeType) const; + // fill passed in array with all extensions associated with this file + // type + bool GetExtensions(wxArrayString& extensions); + // get the icon corresponding to this file type + bool GetIcon(wxIcon *icon) const; + // get a brief file type description ("*.txt" => "text document") + bool GetDescription(wxString *desc) const; + + // get the command to be used to open/print the given file. + // get the command to execute the file of given type + bool GetOpenCommand(wxString *openCmd, + const MessageParameters& params) const; + // get the command to print the file of given type + bool GetPrintCommand(wxString *printCmd, + const MessageParameters& params) const; + + // operations + // expand a string in the format of GetOpenCommand (which may contain + // '%s' and '%t' format specificators for the file name and mime type + // and %{param} constructions). + static wxString ExpandCommand(const wxString& command, + const MessageParameters& params); + + // dtor (not virtual, shouldn't be derived from) + ~wxFileType(); + +private: + // default ctor is private because the user code never creates us + wxFileType(); + + // no copy ctor/assignment operator + wxFileType(const wxFileType&); + wxFileType& operator=(const wxFileType&); + + wxFileTypeImpl *m_impl; +}; + +// This class accesses the information about all known MIME types and allows +// the application to retrieve information (including how to handle data of +// given type) about them. +// +// NB: currently it doesn't support modifying MIME database (read-only access). +class wxMimeTypesManager +{ +public: + // ctor + wxMimeTypesManager(); + + // Database lookup: all functions return a pointer to wxFileType object + // whose methods may be used to query it for the information you're + // interested in. If the return value is !NULL, caller is responsible for + // deleting it. + // get file type from file extension + wxFileType *GetFileTypeFromExtension(const wxString& ext); + // get file type from MIME type (in format /) + wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); + + // other operations + // read in additional file (the standard ones are read automatically) + // in mailcap format (see mimetype.cpp for description) + void ReadMailcap(const wxString& filename); + // read in additional file in mime.types format + void ReadMimeTypes(const wxString& filename); + + // dtor (not virtual, shouldn't be derived from) + ~wxMimeTypesManager(); + +private: + // no copy ctor/assignment operator + wxMimeTypesManager(const wxMimeTypesManager&); + wxMimeTypesManager& operator=(const wxMimeTypesManager&); + + wxMimeTypesManagerImpl *m_impl; +}; + +#endif //_MIMETYPE_H + +/* vi: set cin tw=80 ts=4 sw=4: */ diff --git a/src/common/mimetype.cpp b/src/common/mimetype.cpp new file mode 100644 index 0000000000..61310e14de --- /dev/null +++ b/src/common/mimetype.cpp @@ -0,0 +1,1211 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: common/mimetype.cpp +// Purpose: classes and functions to manage MIME types +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.09.98 +// RCS-ID: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows license (part of wxExtra library) +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "mimetype.h" +#endif + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// wxWindows +#ifndef WX_PRECOMP + #include "wx/string.h" +#endif //WX_PRECOMP + +#include "wx/log.h" +#include "wx/intl.h" +#include "wx/dynarray.h" + +#ifdef __WXMSW__ + #include "wx/msw/registry.h" +#else // Unix + #include "wx/textfile.h" +#endif // OS + +#include "wx/mimetype.h" + +// other standard headers +#include + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// implementation classes, platform dependent +#ifdef __WXMSW__ + +// These classes use Windows registry to retrieve the required information. +// +// Keys used (not all of them are documented, so it might actually stop working +// in futur versions of Windows...): +// 1. "HKCR\MIME\Database\Content Type" contains subkeys for all known MIME +// types, each key has a string value "Extension" which gives (dot preceded) +// extension for the files of this MIME type. +// +// 2. "HKCR\.ext" contains +// a) unnamed value containing the "filetype" +// b) value "Content Type" containing the MIME type +// +// 3. "HKCR\filetype" contains +// a) unnamed value containing the description +// b) subkey "DefaultIcon" with single unnamed value giving the icon index in +// an icon file +// c) shell\open\command and shell\open\print subkeys containing the commands +// to open/print the file (the positional parameters are introduced by %1, +// %2, ... in these strings, we change them to %s ourselves) + +class wxFileTypeImpl +{ +public: + // ctor + wxFileTypeImpl() { } + + // initialize us with our file type name + void SetFileType(const wxString& strFileType) + { m_strFileType = strFileType; } + void SetExt(const wxString& ext) + { m_ext = ext; } + + // implement accessor functions + bool GetExtensions(wxArrayString& extensions); + bool GetMimeType(wxString *mimeType) const; + bool GetIcon(wxIcon *icon) const; + bool GetDescription(wxString *desc) const; + bool GetOpenCommand(wxString *openCmd, + const wxFileType::MessageParameters&) const + { return GetCommand(openCmd, "open"); } + bool GetPrintCommand(wxString *printCmd, + const wxFileType::MessageParameters&) const + { return GetCommand(printCmd, "print"); } + +private: + // helper function + bool GetCommand(wxString *command, const char *verb) const; + + wxString m_strFileType, m_ext; +}; + +class wxMimeTypesManagerImpl +{ +public: + // nothing to do here, we don't load any data but just go and fetch it from + // the registry when asked for + wxMimeTypesManagerImpl() { } + + // implement containing class functions + wxFileType *GetFileTypeFromExtension(const wxString& ext); + wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); + + // this are NOPs under Windows + void ReadMailcap(const wxString& filename) { } + void ReadMimeTypes(const wxString& filename) { } +}; + +#else // Unix + +// this class uses both mailcap and mime.types to gather information about file +// types. +// +// The information about mailcap file was extracted from metamail(1) sources and +// documentation. +// +// Format of mailcap file: spaces are ignored, each line is either a comment +// (starts with '#') or a line of the form ;;...;. +// A backslash can be used to quote semicolons and newlines (and, in fact, +// anything else including itself). +// +// The first field is always the MIME type in the form of type/subtype (see RFC +// 822) where subtype may be '*' meaning "any". Following metamail, we accept +// "type" which means the same as "type/*", although I'm not sure whether this +// is standard. +// +// The second field is always the command to run. It is subject to +// parameter/filename expansion described below. +// +// All the following fields are optional and may not be present at all. If +// they're present they may appear in any order, although each of them should +// appear only once. The optional fields are the following: +// * notes=xxx is an uninterpreted string which is silently ignored +// * test=xxx is the command to be used to determine whether this mailcap line +// applies to our data or not. The RHS of this field goes through the +// parameter/filename expansion (as the 2nd field) and the resulting string +// is executed. The line applies only if the command succeeds, i.e. returns 0 +// exit code. +// * print=xxx is the command to be used to print (and not view) the data of +// this type (parameter/filename expansion is done here too) +// * edit=xxx is the command to open/edit the data of this type +// * needsterminal means that a new console must be created for the viewer +// * copiousoutput means that the viewer doesn't interact with the user but +// produces (possibly) a lof of lines of output on stdout (i.e. "cat" is a +// good example), thus it might be a good idea to use some kind of paging +// mechanism. +// * textualnewlines means not to perform CR/LF translation (not honored) +// * compose and composetyped fields are used to determine the program to be +// called to create a new message pert in the specified format (unused). +// +// Parameter/filename xpansion: +// * %s is replaced with the (full) file name +// * %t is replaced with MIME type/subtype of the entry +// * for multipart type only %n is replaced with the nnumber of parts and %F is +// replaced by an array of (content-type, temporary file name) pairs for all +// message parts (TODO) +// * %{parameter} is replaced with the value of parameter taken from +// Content-type header line of the message. +// +// FIXME any docs with real descriptions of these files?? +// +// There are 2 possible formats for mime.types file, one entry per line (used +// for global mime.types) and "expanded" format where an entry takes multiple +// lines (used for users mime.types). +// +// For both formats spaces are ignored and lines starting with a '#' are +// comments. Each record has one of two following forms: +// a) for "brief" format: +// +// b) for "expanded" format: +// type= \ desc="" \ exts="ext" +// +// We try to autodetect the format of mime.types: if a non-comment line starts +// with "type=" we assume the second format, otherwise the first one. + +// there may be more than one entry for one and the same mime type, to +// choose the right one we have to run the command specified in the test +// field on our data. +class MailCapEntry +{ +public: + // ctor + MailCapEntry(const wxString& openCmd, + const wxString& printCmd, + const wxString& testCmd) + : m_openCmd(openCmd), m_printCmd(printCmd), m_testCmd(testCmd) + { + m_next = NULL; + } + + // accessors + const wxString& GetOpenCmd() const { return m_openCmd; } + const wxString& GetPrintCmd() const { return m_printCmd; } + const wxString& GetTestCmd() const { return m_testCmd; } + + MailCapEntry *GetNext() const { return m_next; } + + // operations + // prepend this element to the list + void Prepend(MailCapEntry *next) { m_next = next; } + // append to the list + void Append(MailCapEntry *next) + { + // FIXME slooow... + MailCapEntry *cur; + for ( cur = next; cur->m_next != NULL; cur = cur->m_next ) + ; + + cur->m_next = this; + + // we initialize it in the ctor and there is no reason to both Prepend() + // and Append() one and the same entry + wxASSERT( m_next == NULL ); + } + +private: + wxString m_openCmd, // command to use to open/view the file + m_printCmd, // print + m_testCmd; // only apply this entry if test yields + // true (i.e. the command returns 0) + + MailCapEntry *m_next; // in the linked list +}; + +WX_DEFINE_ARRAY(MailCapEntry *, ArrayTypeEntries); + +class wxMimeTypesManagerImpl +{ +friend class wxFileTypeImpl; // give it access to m_aXXX variables + +public: + // ctor loads all info into memory for quicker access later on + // @@ it would be nice to load them all, but parse on demand only... + wxMimeTypesManagerImpl(); + + // implement containing class functions + wxFileType *GetFileTypeFromExtension(const wxString& ext); + wxFileType *GetFileTypeFromMimeType(const wxString& mimeType); + + void ReadMailcap(const wxString& filename); + void ReadMimeTypes(const wxString& filename); + + // accessors + // get the string containing space separated extensions for the given + // file type + wxString GetExtension(size_t index) { return m_aExtensions[index]; } + +private: + wxArrayString m_aTypes, // MIME types + m_aDescriptions, // descriptions (just some text) + m_aExtensions; // space separated list of extensions + ArrayTypeEntries m_aEntries; // commands and tests for this file type +}; + +class wxFileTypeImpl +{ +public: + // initialization functions + void Init(wxMimeTypesManagerImpl *manager, size_t index) + { m_manager = manager; m_index = index; } + + // accessors + bool GetExtensions(wxArrayString& extensions); + bool GetMimeType(wxString *mimeType) const + { *mimeType = m_manager->m_aTypes[m_index]; return TRUE; } + bool GetIcon(wxIcon *icon) const + { return FALSE; } // @@ maybe with Gnome/KDE integration... + bool GetDescription(wxString *desc) const + { *desc = m_manager->m_aDescriptions[m_index]; return TRUE; } + + bool GetOpenCommand(wxString *openCmd, + const wxFileType::MessageParameters& params) const + { + return GetExpandedCommand(openCmd, params, TRUE); + } + + bool GetPrintCommand(wxString *printCmd, + const wxFileType::MessageParameters& params) const + { + return GetExpandedCommand(printCmd, params, FALSE); + } + +private: + // get the entry which passes the test (may return NULL) + MailCapEntry *GetEntry(const wxFileType::MessageParameters& params) const; + + // choose the correct entry to use and expand the command + bool GetExpandedCommand(wxString *expandedCmd, + const wxFileType::MessageParameters& params, + bool open) const; + + wxMimeTypesManagerImpl *m_manager; + size_t m_index; // in the wxMimeTypesManagerImpl arrays +}; + +#endif // OS type + +// ============================================================================ +// implementation of the wrapper classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFileType +// ---------------------------------------------------------------------------- + +wxString wxFileType::ExpandCommand(const wxString& command, + const wxFileType::MessageParameters& params) +{ + bool hasFilename = FALSE; + + wxString str; + for ( const char *pc = command.c_str(); *pc != '\0'; pc++ ) { + if ( *pc == '%' ) { + switch ( *++pc ) { + case 's': + // '%s' expands into file name (quoted because it might + // contain spaces) - except if there are already quotes + // there because otherwise some programs may get confused by + // double double quotes +#if 0 + if ( *(pc - 2) == '"' ) + str << params.GetFileName(); + else + str << '"' << params.GetFileName() << '"'; +#endif + str << params.GetFileName(); + hasFilename = TRUE; + break; + + case 't': + // '%t' expands into MIME type (quote it too just to be + // consistent) + str << '\'' << params.GetMimeType() << '\''; + break; + + case '{': + { + const char *pEnd = strchr(pc, '}'); + if ( pEnd == NULL ) { + wxString mimetype; + wxLogWarning(_("Unmatched '{' in an entry for " + "mime type %s."), + params.GetMimeType().c_str()); + str << "%{"; + } + else { + wxString param(pc + 1, pEnd - pc - 1); + str << '\'' << params.GetParamValue(param) << '\''; + pc = pEnd; + } + } + break; + + case 'n': + case 'F': + // TODO %n is the number of parts, %F is an array containing + // the names of temp files these parts were written to + // and their mime types. + break; + + default: + wxLogDebug("Unknown field %%%c in command '%s'.", + *pc, command.c_str()); + str << *pc; + } + } + else { + str << *pc; + } + } + + // metamail(1) man page states that if the mailcap entry doesn't have '%s' + // the program will accept the data on stdin: so give it to it! + if ( !hasFilename && !str.IsEmpty() ) { + str << " < '" << params.GetFileName() << '\''; + } + + return str; +} + +wxFileType::wxFileType() +{ + m_impl = new wxFileTypeImpl; +} + +wxFileType::~wxFileType() +{ + delete m_impl; +} + +bool wxFileType::GetExtensions(wxArrayString& extensions) +{ + return m_impl->GetExtensions(extensions); +} + +bool wxFileType::GetMimeType(wxString *mimeType) const +{ + return m_impl->GetMimeType(mimeType); +} + +bool wxFileType::GetIcon(wxIcon *icon) const +{ + return m_impl->GetIcon(icon); +} + +bool wxFileType::GetDescription(wxString *desc) const +{ + return m_impl->GetDescription(desc); +} + +bool +wxFileType::GetOpenCommand(wxString *openCmd, + const wxFileType::MessageParameters& params) const +{ + return m_impl->GetOpenCommand(openCmd, params); +} + +bool +wxFileType::GetPrintCommand(wxString *printCmd, + const wxFileType::MessageParameters& params) const +{ + return m_impl->GetPrintCommand(printCmd, params); +} + +// ---------------------------------------------------------------------------- +// wxMimeTypesManager +// ---------------------------------------------------------------------------- + +wxMimeTypesManager::wxMimeTypesManager() +{ + m_impl = new wxMimeTypesManagerImpl; +} + +wxMimeTypesManager::~wxMimeTypesManager() +{ + delete m_impl; +} + +wxFileType * +wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext) +{ + return m_impl->GetFileTypeFromExtension(ext); +} + +wxFileType * +wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) +{ + return m_impl->GetFileTypeFromMimeType(mimeType); +} + +// ============================================================================ +// real (OS specific) implementation +// ============================================================================ + +#ifdef __WXMSW__ + +bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const +{ + // suppress possible error messages + wxLogNull nolog; + wxString strKey; + strKey << m_strFileType << "\\shell\\" << verb << "\\command"; + wxRegKey key(wxRegKey::HKCR, strKey); + + if ( key.Open() ) { + // it's the default value of the key + if ( key.QueryValue("", *command) ) { + // transform it from '%1' to '%s' style format string + // @@ we don't make any attempt to verify that the string is valid, + // i.e. doesn't contain %2, or second %1 or .... But we do make + // sure that we return a string with _exactly_ one '%s'! + size_t len = command->Len(); + for ( size_t n = 0; n < len; n++ ) { + if ( command->GetChar(n) == '%' && + (n + 1 < len) && command->GetChar(n + 1) == '1' ) { + // replace it with '%s' + command->SetChar(n + 1, 's'); + + return TRUE; + } + } + + // we didn't find any '%1'! + // @@@ hack: append the filename at the end, hope that it will do + *command << " %s"; + + return TRUE; + } + } + + // no such file type or no value + return FALSE; +} + +// @@ this function is half implemented +bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) +{ + if ( m_ext.IsEmpty() ) { + // the only way to get the list of extensions from the file type is to + // scan through all extensions in the registry - too slow... + return FALSE; + } + else { + extensions.Empty(); + extensions.Add(m_ext); + + // it's a lie too, we don't return _all_ extensions... + return TRUE; + } +} + +bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const +{ + // suppress possible error messages + wxLogNull nolog; + wxRegKey key(wxRegKey::HKCR, m_strFileType); + if ( key.Open() && key.QueryValue("Content Type", *mimeType) ) { + return TRUE; + } + else { + return FALSE; + } +} + +bool wxFileTypeImpl::GetIcon(wxIcon *icon) const +{ + wxString strIconKey; + strIconKey << m_strFileType << "\\DefaultIcon"; + + // suppress possible error messages + wxLogNull nolog; + wxRegKey key(wxRegKey::HKCR, strIconKey); + + if ( key.Open() ) { + wxString strIcon; + // it's the default value of the key + if ( key.QueryValue("", strIcon) ) { + // the format is the following: , + // NB: icon index may be negative as well as positive and the full + // path may contain the environment variables inside '%' + wxString strFullPath = strIcon.Before(','), + strIndex = strIcon.Right(','); + + // index may be omitted, in which case Before(',') is empty and + // Right(',') is the whole string + if ( strFullPath.IsEmpty() ) { + strFullPath = strIndex; + strIndex = "0"; + } + + wxString strExpPath = wxExpandEnvVars(strFullPath); + int nIndex = atoi(strIndex); + + HICON hIcon = ExtractIcon(GetModuleHandle(NULL), strExpPath, nIndex); + switch ( (int)hIcon ) { + case 0: // means no icons were found + case 1: // means no such file or it wasn't a DLL/EXE/OCX/ICO/... + wxLogDebug("incorrect registry entry '%s': no such icon.", + key.GetName().c_str()); + break; + + default: + icon->SetHICON((WXHICON)hIcon); + return TRUE; + } + } + } + + // no such file type or no value or incorrect icon entry + return FALSE; +} + +bool wxFileTypeImpl::GetDescription(wxString *desc) const +{ + // suppress possible error messages + wxLogNull nolog; + wxRegKey key(wxRegKey::HKCR, m_strFileType); + + if ( key.Open() ) { + // it's the default value of the key + if ( key.QueryValue("", *desc) ) { + return TRUE; + } + } + + return FALSE; +} + +// extension -> file type +wxFileType * +wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) +{ + // add the leading point if necessary + wxString str; + if ( ext[0u] != '.' ) { + str = '.'; + } + str << ext; + + // suppress possible error messages + wxLogNull nolog; + + wxString strFileType; + wxRegKey key(wxRegKey::HKCR, str); + if ( key.Open() ) { + // it's the default value of the key + if ( key.QueryValue("", strFileType) ) { + // create the new wxFileType object + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(strFileType); + fileType->m_impl->SetExt(ext); + + return fileType; + } + } + + // unknown extension + return NULL; +} + +// MIME type -> extension -> file type +wxFileType * +wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) +{ + // @@@ I don't know of any official documentation which mentions this + // location, but as a matter of fact IE uses it, so why not we? + static const char *szMimeDbase = "MIME\\Database\\Content Type\\"; + + wxString strKey = szMimeDbase; + strKey << mimeType; + + // suppress possible error messages + wxLogNull nolog; + + wxString ext; + wxRegKey key(wxRegKey::HKCR, strKey); + if ( key.Open() ) { + if ( key.QueryValue("Extension", ext) ) { + return GetFileTypeFromExtension(ext); + } + } + + // unknown MIME type + return NULL; +} + +#else // Unix + +MailCapEntry * +wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const +{ + wxString command; + MailCapEntry *entry = m_manager->m_aEntries[m_index]; + while ( entry != NULL ) { + // notice that an empty command would always succeed (@@ is it ok?) + command = wxFileType::ExpandCommand(entry->GetTestCmd(), params); + + if ( command.IsEmpty() || (system(command) == 0) ) { + // ok, passed + wxLogTrace("Test '%s' for mime type '%s' succeeded.", + command.c_str(), params.GetMimeType().c_str()); + break; + } + else { + wxLogTrace("Test '%s' for mime type '%s' failed.", + command.c_str(), params.GetMimeType().c_str()); + } + + entry = entry->GetNext(); + } + + return entry; +} + +bool +wxFileTypeImpl::GetExpandedCommand(wxString *expandedCmd, + const wxFileType::MessageParameters& params, + bool open) const +{ + MailCapEntry *entry = GetEntry(params); + if ( entry == NULL ) { + // all tests failed... + return FALSE; + } + + wxString cmd = open ? entry->GetOpenCmd() : entry->GetPrintCmd(); + if ( cmd.IsEmpty() ) { + // may happen, especially for "print" + return FALSE; + } + + *expandedCmd = wxFileType::ExpandCommand(cmd, params); + return TRUE; +} + +bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) +{ + wxString strExtensions = m_manager->GetExtension(m_index); + extensions.Empty(); + + // one extension in the space or comma delimitid list + wxString strExt; + for ( const char *p = strExtensions; ; p++ ) { + if ( *p == ' ' || *p == ',' || *p == '\0' ) { + if ( !strExt.IsEmpty() ) { + extensions.Add(strExt); + strExt.Empty(); + } + //else: repeated spaces (shouldn't happen, but it's not that + // important if it does happen) + + if ( *p == '\0' ) + break; + } + else if ( *p == '.' ) { + // remove the dot from extension (but only if it's the first char) + if ( !strExt.IsEmpty() ) { + strExt += '.'; + } + //else: no, don't append it + } + else { + strExt += *p; + } + } + + return TRUE; +} + +// read system and user mailcaps (TODO implement mime.types support) +wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() +{ + // directories where we look for mailcap and mime.types by default + // (taken from metamail(1) sources) + static const char *aStandardLocations[] = + { + "/etc", + "/usr/etc", + "/usr/local/etc", + "/etc/mail", + "/usr/public/lib" + }; + + // first read the system wide file(s) + for ( size_t n = 0; n < WXSIZEOF(aStandardLocations); n++ ) { + wxString dir = aStandardLocations[n]; + + wxString file = dir + "/mailcap"; + if ( wxFile::Exists(file) ) { + ReadMailcap(file); + } + + file = dir + "/mime.types"; + if ( wxFile::Exists(file) ) { + ReadMimeTypes(file); + } + } + + wxString strHome = getenv("HOME"); + + // and now the users mailcap + wxString strUserMailcap = strHome + "/.mailcap"; + if ( wxFile::Exists(strUserMailcap) ) { + ReadMailcap(strUserMailcap); + } + + // read the users mime.types + wxString strUserMimeTypes = strHome + "/.mime.types"; + if ( wxFile::Exists(strUserMimeTypes) ) { + ReadMimeTypes(strUserMimeTypes); + } +} + +wxFileType * +wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext) +{ + wxFAIL_MSG("not implemented (must parse mime.types)"); + + return NULL; +} + +wxFileType * +wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) +{ + // mime types are not case-sensitive + wxString mimetype(mimeType); + mimetype.MakeLower(); + + // first look for an exact match + int index = m_aTypes.Index(mimetype); + if ( index == NOT_FOUND ) { + // then try to find "text/*" as match for "text/plain" (for example) + // NB: if mimeType doesn't contain '/' at all, Left() will return the + // whole string - ok. + wxString strCategory = mimetype.Left('/'); + + size_t nCount = m_aTypes.Count(); + for ( size_t n = 0; n < nCount; n++ ) { + if ( (m_aTypes[n].Before('/') == strCategory ) && + m_aTypes[n].Right('/') == "*" ) { + index = n; + break; + } + } + } + + if ( index != NOT_FOUND ) { + wxFileType *fileType = new wxFileType; + fileType->m_impl->Init(this, index); + + return fileType; + } + else { + // not found... + return NULL; + } +} + +void wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName) +{ + wxLogTrace("--- Parsing mime.types file '%s' ---", strFileName.c_str()); + + wxTextFile file(strFileName); + if ( !file.Open() ) + return; + + // the information we extract + wxString strMimeType, strDesc, strExtensions; + + size_t nLineCount = file.GetLineCount(); + for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) { + // now we're at the start of the line + const char *pc = file[nLine].c_str(); + + // skip whitespace + while ( isspace(*pc) ) + pc++; + + // comment? + if ( *pc == '#' ) + continue; + + // detect file format + const char *pEqualSign = strchr(pc, '='); + if ( pEqualSign == NULL ) { + // brief format + // ------------ + + // first field is mime type + for ( strMimeType.Empty(); !isspace(*pc) && *pc != '\0'; pc++ ) { + strMimeType += *pc; + } + + // skip whitespace + while ( isspace(*pc) ) + pc++; + + // take all the rest of the string + strExtensions = pc; + + // no description... + strDesc.Empty(); + } + else { + // expanded format + // --------------- + + // the string on the left of '=' is the field name + wxString strLHS(pc, pEqualSign - pc); + + // eat whitespace + for ( pc = pEqualSign + 1; isspace(*pc); pc++ ) + ; + + const char *pEnd; + if ( *pc == '"' ) { + // the string is quoted and ends at the matching quote + pEnd = strchr(++pc, '"'); + if ( pEnd == NULL ) { + wxLogWarning(_("Mime.types file %s, line %d: unterminated " + "quoted string."), + strFileName.c_str(), nLine + 1); + } + } + else { + // unquoted stringends at the first space + for ( pEnd = pc; !isspace(*pEnd); pEnd++ ) + ; + } + + // now we have the RHS (field value) + wxString strRHS(pc, pEnd - pc); + + // check that it's more or less what we're waiting for, i.e. that + // only '\' is left on the line + if ( *pEnd == '"' ) { + // skip this quote + pEnd++; + } + + for ( pc = pEnd; isspace(*pc); pc++ ) + ; + + // only '\\' may be left on the line normally + bool entryEnded = *pc == '\0'; + if ( !entryEnded && ((*pc != '\\') || (*++pc != '\0')) ) { + wxLogWarning(_("Mime.types file %s, line %d: extra characters " + "after the field value ignored."), + strFileName.c_str(), nLine + 1); + } + // if there is a trailing backslash entryEnded = FALSE + + // now see what we got + if ( strLHS == "type" ) { + strMimeType = strRHS; + } + else if ( strLHS == "desc" ) { + strDesc = strRHS; + } + else if ( strLHS == "exts" ) { + strExtensions = strRHS; + } + else { + wxLogWarning(_("Unknown field in file %s, line %d: '%s'."), + strFileName.c_str(), nLine + 1, strLHS.c_str()); + } + + if ( !entryEnded ) { + // as we don't reset strMimeType, the next line in this entry + // will be interpreted correctly. + continue; + } + } + + int index = m_aTypes.Index(strMimeType); + if ( index == NOT_FOUND ) { + // add a new entry + m_aTypes.Add(strMimeType); + m_aEntries.Add(NULL); + m_aExtensions.Add(strExtensions); + m_aDescriptions.Add(strDesc); + } + else { + // modify an existing one + if ( !strDesc.IsEmpty() ) { + m_aDescriptions[index] = strDesc; // replace old value + } + m_aExtensions[index] += strExtensions; + } + } + + // check our data integriry + wxASSERT( m_aTypes.Count() == m_aEntries.Count() && + m_aTypes.Count() == m_aExtensions.Count() && + m_aTypes.Count() == m_aDescriptions.Count() ); +} + +void wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName) +{ + wxLogTrace("--- Parsing mailcap file '%s' ---", strFileName.c_str()); + + wxTextFile file(strFileName); + if ( !file.Open() ) + return; + + // see the comments near the end of function for the reason we need this + wxArrayInt aEntryIndices; + + size_t nLineCount = file.GetLineCount(); + for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) { + // now we're at the start of the line + const char *pc = file[nLine].c_str(); + + // skip whitespace + while ( isspace(*pc) ) + pc++; + + // comment or empty string? + if ( *pc == '#' || *pc == '\0' ) + continue; + + // no, do parse + + // what field are we currently in? The first 2 are fixed and there may + // be an arbitrary number of other fields -- currently, we are not + // interested in any of them, but we should parse them as well... + enum + { + Field_Type, + Field_OpenCmd, + Field_Other + } currentToken = Field_Type; + + // the flags and field values on the current line + bool needsterminal = false, + copiousoutput = false; + wxString strType, + strOpenCmd, + strPrintCmd, + strTest, + strDesc, + curField; // accumulator + for ( bool cont = TRUE; cont; pc++ ) { + switch ( *pc ) { + case '\\': + // interpret the next character literally (notice that + // backslash can be used for line continuation) + if ( *++pc == '\0' ) { + // fetch the next line. + + // pc currently points to nowhere, but after the next + // pc++ in the for line it will point to the beginning + // of the next line in the file + pc = file[++nLine].c_str() - 1; + } + else { + // just a normal character + curField += *pc; + } + break; + + case '\0': + cont = FALSE; // end of line reached, exit the loop + + // fall through + + case ';': + // store this field and start looking for the next one + + // trim whitespaces from both sides + curField.Trim(TRUE).Trim(FALSE); + + switch ( currentToken ) { + case Field_Type: + strType = curField; + if ( strType.Find('/') == NOT_FOUND ) { + // we interpret "type" as "type/*" + strType += "/*"; + } + + currentToken = Field_OpenCmd; + break; + + case Field_OpenCmd: + strOpenCmd = curField; + + currentToken = Field_Other; + break; + + case Field_Other: + { + // "good" mailcap entry? + bool ok = TRUE; + + // is this something of the form foo=bar? + const char *pEq = strchr(curField, '='); + if ( pEq != NULL ) { + wxString lhs = curField.Left('='), + rhs = curField.After('='); + + lhs.Trim(TRUE); // from right + rhs.Trim(FALSE); // from left + + if ( lhs == "print" ) + strPrintCmd = rhs; + else if ( lhs == "test" ) + strTest = rhs; + else if ( lhs == "description" ) { + // it might be quoted + if ( rhs[0u] == '"' && + rhs.Last() == '"' ) { + strDesc = wxString(rhs.c_str() + 1, + rhs.Len() - 2); + } + else { + strDesc = rhs; + } + } + else if ( lhs == "compose" || + lhs == "composetyped" || + lhs == "notes" || + lhs == "edit" ) + ; // ignore + else + ok = FALSE; + + } + else { + // no, it's a simple flag + // TODO support the flags: + // 1. create an xterm for 'needsterminal' + // 2. append "| $PAGER" for 'copiousoutput' + if ( curField == "needsterminal" ) + needsterminal = TRUE; + else if ( curField == "copiousoutput" ) + copiousoutput = TRUE; + else if ( curField == "textualnewlines" ) + ; // ignore + else + ok = FALSE; + } + + if ( !ok ) + { + // don't flood the user with error messages + // if we don't understand something in his + // mailcap + wxLogDebug + ( + _("Mailcap file %s, line %d: unknown " + "field '%s' for the MIME type " + "'%s' ignored."), + strFileName.c_str(), + nLine + 1, + curField.c_str(), + strType.c_str() + ); + } + } + + // it already has this value + //currentToken = Field_Other; + break; + + default: + wxFAIL_MSG("unknown field type in mailcap"); + } + + // next token starts immediately after ';' + curField.Empty(); + break; + + default: + curField += *pc; + } + } + + // check that we really read something reasonable + if ( currentToken == Field_Type || currentToken == Field_OpenCmd ) { + wxLogWarning(_("Mailcap file %s, line %d: incomplete entry " + "ignored."), + strFileName.c_str(), nLine + 1); + } + else { + MailCapEntry *entry = new MailCapEntry(strOpenCmd, + strPrintCmd, + strTest); + + strType.MakeLower(); + int nIndex = m_aTypes.Index(strType); + if ( nIndex == NOT_FOUND ) { + // new file type + m_aTypes.Add(strType); + + m_aEntries.Add(entry); + m_aExtensions.Add(""); + m_aDescriptions.Add(strDesc); + } + else { + // modify the existing entry: the entry in one and the same file + // are read in top-to-bottom order, i.e. the entries read first + // should be tried before the entries below. However, the files + // read later should override the settings in the files read + // before, thus we Append() the new entry to the list if it has + // already occured in _this_ file, but Prepend() it if it + // occured in some of the previous ones. + if ( aEntryIndices.Index(nIndex) == NOT_FOUND ) { + // first time in this file + aEntryIndices.Add(nIndex); + entry->Prepend(m_aEntries[nIndex]); + m_aEntries[nIndex] = entry; + } + else { + // not the first time in _this_ file + entry->Append(m_aEntries[nIndex]); + } + + if ( !strDesc.IsEmpty() ) { + // @@ replace the old one - what else can we do?? + m_aDescriptions[nIndex] = strDesc; + } + } + } + + // check our data integriry + wxASSERT( m_aTypes.Count() == m_aEntries.Count() && + m_aTypes.Count() == m_aExtensions.Count() && + m_aTypes.Count() == m_aDescriptions.Count() ); + } +} + +#endif // OS type + +/* vi: set cin tw=80 ts=4 sw=4: */ +