+    return true;
+}
+
+// set an arbitrary command:
+// could adjust the code to ask confirmation if it already exists and
+// overwriteprompt is true, but this is currently ignored as *Associate* has
+// no overwrite prompt
+bool
+wxFileTypeImpl::SetCommand(const wxString& cmd,
+                           const wxString& verb,
+                           bool WXUNUSED(overwriteprompt))
+{
+    wxArrayString strExtensions;
+    wxString strDesc, strIcon;
+
+    wxArrayString strTypes;
+    GetMimeTypes(strTypes);
+    if ( strTypes.IsEmpty() )
+        return false;
+
+    wxMimeTypeCommands *entry = new wxMimeTypeCommands();
+    entry->Add(verb + wxT("=")  + cmd + wxT(" %s "));
+
+    bool ok = true;
+    size_t nCount = strTypes.GetCount();
+    for ( size_t i = 0; i < nCount; i++ )
+    {
+        if (!m_manager->DoAssociation(strTypes[i], strIcon, entry, strExtensions, strDesc))
+            ok = false;
+    }
+
+    return ok;
+}
+
+// ignore index on the grounds that we only have one icon in a Unix file
+bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int WXUNUSED(index))
+{
+    if (strIcon.empty())
+        return false;
+
+    wxArrayString strExtensions;
+    wxString strDesc;
+
+    wxArrayString strTypes;
+    GetMimeTypes(strTypes);
+    if ( strTypes.IsEmpty() )
+        return false;
+
+    wxMimeTypeCommands *entry = new wxMimeTypeCommands();
+    bool ok = true;
+    size_t nCount = strTypes.GetCount();
+    for ( size_t i = 0; i < nCount; i++ )
+    {
+        if ( !m_manager->DoAssociation
+                         (
+                            strTypes[i],
+                            strIcon,
+                            entry,
+                            strExtensions,
+                            strDesc
+                         ) )
+        {
+            ok = false;
+        }
+    }
+
+    return ok;
+}
+
+// ----------------------------------------------------------------------------
+// wxMimeTypesManagerImpl (Unix)
+// ----------------------------------------------------------------------------
+
+wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
+{
+    m_initialized = false;
+    m_mailcapStylesInited = 0;
+}
+
+void wxMimeTypesManagerImpl::InitIfNeeded()
+{
+    if ( !m_initialized )
+    {
+        // set the flag first to prevent recursion
+        m_initialized = true;
+        
+        wxString wm = wxTheApp->GetTraits()->GetDesktopEnvironment();
+        
+        if (wm == wxT("KDE"))
+            Initialize( wxMAILCAP_KDE  );
+        else if (wm == wxT("GNOME"))
+            Initialize( wxMAILCAP_GNOME );
+        else
+            Initialize();
+    }
+}
+
+// read system and user mailcaps and other files
+void wxMimeTypesManagerImpl::Initialize(int mailcapStyles,
+                                        const wxString& sExtraDir)
+{
+    // read mimecap amd mime.types
+    if ( (mailcapStyles & wxMAILCAP_NETSCAPE) ||
+         (mailcapStyles & wxMAILCAP_STANDARD) )
+        GetMimeInfo(sExtraDir);
+
+    // read GNOME tables
+    if (mailcapStyles & wxMAILCAP_GNOME)
+        GetGnomeMimeInfo(sExtraDir);
+
+    // read KDE tables which are never installed on OpenVMS
+#ifndef __VMS
+    if (mailcapStyles & wxMAILCAP_KDE)
+        GetKDEMimeInfo(sExtraDir);
+#endif
+
+    m_mailcapStylesInited |= mailcapStyles;
+}
+
+// clear data so you can read another group of WM files
+void wxMimeTypesManagerImpl::ClearData()
+{
+    m_aTypes.Clear();
+    m_aIcons.Clear();
+    m_aExtensions.Clear();
+    m_aDescriptions.Clear();
+
+    WX_CLEAR_ARRAY(m_aEntries);
+    m_aEntries.Empty();
+
+    m_mailcapStylesInited = 0;
+}
+
+wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
+{
+    ClearData();
+}
+
+void wxMimeTypesManagerImpl::GetMimeInfo(const wxString& sExtraDir)
+{
+    // read this for netscape or Metamail formats
+
+    // directories where we look for mailcap and mime.types by default
+    // used by netscape and pine and other mailers, using 2 different formats!
+
+    // (taken from metamail(1) sources)
+    //
+    // although RFC 1524 specifies the search path of
+    // /etc/:/usr/etc:/usr/local/etc only, it doesn't hurt to search in more
+    // places - OTOH, the RFC also says that this path can be changed with
+    // MAILCAPS environment variable (containing the colon separated full
+    // filenames to try) which is not done yet (TODO?)
+
+    wxString strHome = wxGetenv(wxT("HOME"));
+
+    wxArrayString dirs;
+    dirs.Add( strHome + wxT("/.") );
+    dirs.Add( wxT("/etc/") );
+    dirs.Add( wxT("/usr/etc/") );
+    dirs.Add( wxT("/usr/local/etc/") );
+    dirs.Add( wxT("/etc/mail/") );
+    dirs.Add( wxT("/usr/public/lib/") );
+    if (!sExtraDir.empty())
+        dirs.Add( sExtraDir + wxT("/") );
+
+    wxString file;
+    size_t nDirs = dirs.GetCount();
+    for ( size_t nDir = 0; nDir < nDirs; nDir++ )
+    {
+        file = dirs[nDir];
+        file += wxT("mailcap");
+        if ( wxFile::Exists(file) )
+        {
+            ReadMailcap(file);
+        }
+
+        file = dirs[nDir];
+        file += wxT("mime.types");
+        if ( wxFile::Exists(file) )
+            ReadMimeTypes(file);
+    }
+}
+
+bool wxMimeTypesManagerImpl::WriteToMimeTypes(int index, bool delete_index)
+{
+    // check we have the right manager
+    if (! ( m_mailcapStylesInited & wxMAILCAP_STANDARD) )
+        return false;
+
+    bool bTemp;
+    wxString strHome = wxGetenv(wxT("HOME"));
+
+    // and now the users mailcap
+    wxString strUserMailcap = strHome + wxT("/.mime.types");
+
+    wxMimeTextFile file;
+    if ( wxFile::Exists(strUserMailcap) )
+    {
+        bTemp = file.Open(strUserMailcap);
+    }
+    else
+    {
+        if (delete_index)
+            return false;
+
+        bTemp = file.Create(strUserMailcap);
+    }
+
+    if (bTemp)
+    {
+        int nIndex;
+        // test for netscape's header and return false if its found
+        nIndex = file.pIndexOf(wxT("#--Netscape"));
+        if (nIndex != wxNOT_FOUND)
+        {
+            wxFAIL_MSG(wxT("Error in .mime.types\nTrying to mix Netscape and Metamail formats\nFile not modified"));
+            return false;
+        }
+
+        // write it in alternative format
+        // get rid of unwanted entries
+        wxString strType = m_aTypes[index];
+        nIndex = file.pIndexOf(strType);
+
+        // get rid of all the unwanted entries...
+        if (nIndex != wxNOT_FOUND)
+            file.CommentLine(nIndex);
+
+        if (!delete_index)
+        {
+            // add the new entries in
+            wxString sTmp = strType.Append( wxT(' '), 40 - strType.Len() );
+            sTmp += m_aExtensions[index];
+            file.AddLine(sTmp);
+        }
+
+        bTemp = file.Write();
+        file.Close();
+    }
+
+    return bTemp;
+}
+
+bool wxMimeTypesManagerImpl::WriteToNSMimeTypes(int index, bool delete_index)
+{
+    //check we have the right managers
+    if (! ( m_mailcapStylesInited & wxMAILCAP_NETSCAPE) )
+        return false;
+
+    bool bTemp;
+    wxString strHome = wxGetenv(wxT("HOME"));
+
+    // and now the users mailcap
+    wxString strUserMailcap = strHome + wxT("/.mime.types");
+
+    wxMimeTextFile file;
+    if ( wxFile::Exists(strUserMailcap) )
+    {
+        bTemp = file.Open(strUserMailcap);
+    }
+    else
+    {
+        if (delete_index)
+            return false;
+
+        bTemp = file.Create(strUserMailcap);
+    }
+
+    if (bTemp)
+    {
+        // write it in the format that Netscape uses
+        int nIndex;
+        // test for netscape's header and insert if required...
+        // this is a comment so use true
+        nIndex = file.pIndexOf(wxT("#--Netscape"), true);
+        if (nIndex == wxNOT_FOUND)
+        {
+            // either empty file or metamail format
+            // at present we can't cope with mixed formats, so exit to preseve
+            // metamail entreies
+            if (file.GetLineCount() > 0)
+            {
+                wxFAIL_MSG(wxT(".mime.types File not in Netscape format\nNo entries written to\n.mime.types or to .mailcap"));
+                return false;
+            }
+
+            file.InsertLine(wxT( "#--Netscape Communications Corporation MIME Information" ), 0);
+            nIndex = 0;
+        }
+
+        wxString strType = wxT("type=") + m_aTypes[index];
+        nIndex = file.pIndexOf(strType);
+
+        // get rid of all the unwanted entries...
+        if (nIndex != wxNOT_FOUND)
+        {
+            wxString sOld = file[nIndex];
+            while ( (sOld.Contains(wxT("\\"))) && (nIndex < (int) file.GetLineCount()) )
+            {
+                file.CommentLine(nIndex);
+                sOld = file[nIndex];
+
+                wxLogTrace(TRACE_MIME, wxT("--- Deleting from mime.types line '%d %s' ---"), nIndex, sOld.c_str());
+
+                nIndex++;
+            }
+
+            if (nIndex < (int) file.GetLineCount())
+                file.CommentLine(nIndex);
+        }
+        else
+            nIndex = (int) file.GetLineCount();
+
+        wxString sTmp = strType + wxT(" \\");
+        if (!delete_index)
+            file.InsertLine(sTmp, nIndex);
+
+        if ( ! m_aDescriptions.Item(index).empty() )
+        {
+            sTmp = wxT("desc=\"") + m_aDescriptions[index]+ wxT("\" \\"); //.trim ??
+            if (!delete_index)
+            {
+                nIndex++;
+                file.InsertLine(sTmp, nIndex);
+            }
+        }
+
+        wxString sExts = m_aExtensions.Item(index);
+        sTmp = wxT("exts=\"") + sExts.Trim(false).Trim() + wxT("\"");
+        if (!delete_index)
+        {
+            nIndex++;
+            file.InsertLine(sTmp, nIndex);
+        }
+
+        bTemp = file.Write();
+        file.Close();
+    }
+
+    return bTemp;
+}
+
+bool wxMimeTypesManagerImpl::WriteToMailCap(int index, bool delete_index)
+{
+    //check we have the right managers
+    if ( !( ( m_mailcapStylesInited & wxMAILCAP_NETSCAPE) ||
+            ( m_mailcapStylesInited & wxMAILCAP_STANDARD) ) )
+        return false;
+
+    bool bTemp = false;
+    wxString strHome = wxGetenv(wxT("HOME"));
+
+    // and now the users mailcap
+    wxString strUserMailcap = strHome + wxT("/.mailcap");
+
+    wxMimeTextFile file;
+    if ( wxFile::Exists(strUserMailcap) )
+    {
+        bTemp = file.Open(strUserMailcap);
+    }
+    else
+    {
+        if (delete_index)
+            return false;
+
+        bTemp = file.Create(strUserMailcap);
+    }
+
+    if (bTemp)
+    {
+        // now got a file we can write to ....
+        wxMimeTypeCommands * entries = m_aEntries[index];
+        size_t iOpen;
+        wxString sCmd = entries->GetCommandForVerb(wxT("open"), &iOpen);
+        wxString sTmp;
+
+        sTmp = m_aTypes[index];
+        wxString sOld;
+        int nIndex = file.pIndexOf(sTmp);
+
+        // get rid of all the unwanted entries...
+        if (nIndex == wxNOT_FOUND)
+        {
+            nIndex = (int) file.GetLineCount();
+        }
+        else
+        {
+            sOld = file[nIndex];
+            wxLogTrace(TRACE_MIME, wxT("--- Deleting from mailcap line '%d' ---"), nIndex);
+
+            while ( (sOld.Contains(wxT("\\"))) && (nIndex < (int) file.GetLineCount()) )
+            {
+                file.CommentLine(nIndex);
+                if (nIndex < (int) file.GetLineCount())
+                    sOld = sOld + file[nIndex];
+            }
+
+            if (nIndex < (int)
+                file.GetLineCount()) file.CommentLine(nIndex);
+        }
+
+        sTmp += wxT(";") + sCmd; //includes wxT(" %s ");
+
+        // write it in the format that Netscape uses (default)
+        if (! ( m_mailcapStylesInited & wxMAILCAP_STANDARD ) )
+        {
+            if (! delete_index)
+                file.InsertLine(sTmp, nIndex);
+            nIndex++;
+        }
+        else
+        {
+            // write extended format
+
+            // TODO - FIX this code:
+            // ii) lost entries
+            // sOld holds all the entries, but our data store only has some
+            // eg test= is not stored
+
+            // so far we have written the mimetype and command out
+            wxStringTokenizer sT(sOld, wxT(";\\"));
+            if (sT.CountTokens() > 2)
+            {
+                // first one mimetype; second one command, rest unknown...
+                wxString s;
+                s = sT.GetNextToken();
+                s = sT.GetNextToken();
+
+                // first unknown
+                s = sT.GetNextToken();
+                while ( ! s.empty() )
+                {
+                    bool bKnownToken = false;
+                    if (s.Contains(wxT("description=")))
+                        bKnownToken = true;
+                    if (s.Contains(wxT("x11-bitmap=")))
+                        bKnownToken = true;
+
+                    size_t i;
+                    size_t nCount = entries->GetCount();
+                    for (i=0; i < nCount; i++)
+                    {
+                        if (s.Contains(entries->GetVerb(i)))
+                            bKnownToken = true;
+                    }
+
+                    if (!bKnownToken)
+                    {
+                        sTmp += wxT("; \\");
+                        file.InsertLine(sTmp, nIndex);
+                        sTmp = s;
+                    }
+
+                    s = sT.GetNextToken();
+                }
+            }
+
+            if (! m_aDescriptions[index].empty() )
+            {
+                sTmp += wxT("; \\");
+                file.InsertLine(sTmp, nIndex);
+                nIndex++;
+                sTmp = wxT("       description=\"") + m_aDescriptions[index] + wxT("\"");
+            }
+
+            if (! m_aIcons[index].empty() )
+            {
+                sTmp += wxT("; \\");
+                file.InsertLine(sTmp, nIndex);
+                nIndex++;
+                sTmp = wxT("       x11-bitmap=\"") + m_aIcons[index] + wxT("\"");
+            }
+
+            if ( entries->GetCount() > 1 )
+            {
+                size_t i;
+                for (i=0; i < entries->GetCount(); i++)
+                    if ( i != iOpen )
+                    {
+                        sTmp += wxT("; \\");
+                        file.InsertLine(sTmp, nIndex);
+                        nIndex++;
+                        sTmp = wxT("       ") + entries->GetVerbCmd(i);
+                    }
+            }
+
+            file.InsertLine(sTmp, nIndex);
+            nIndex++;
+        }
+
+        bTemp = file.Write();
+        file.Close();
+    }
+
+    return bTemp;
+}
+
+wxFileType * wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
+{
+    InitIfNeeded();
+
+    wxString strType = ftInfo.GetMimeType();
+    wxString strDesc = ftInfo.GetDescription();
+    wxString strIcon = ftInfo.GetIconFile();
+
+    wxMimeTypeCommands *entry = new wxMimeTypeCommands();
+
+    if ( ! ftInfo.GetOpenCommand().empty())
+        entry->Add(wxT("open=")  + ftInfo.GetOpenCommand() + wxT(" %s "));
+    if ( ! ftInfo.GetPrintCommand().empty())
+        entry->Add(wxT("print=") + ftInfo.GetPrintCommand() + wxT(" %s "));
+
+    // now find where these extensions are in the data store and remove them
+    wxArrayString sA_Exts = ftInfo.GetExtensions();
+    wxString sExt, sExtStore;
+    size_t i, nIndex;
+    size_t nExtCount = sA_Exts.GetCount();
+    for (i=0; i < nExtCount; i++)
+    {
+        sExt = sA_Exts.Item(i);
+
+        // clean up to just a space before and after
+        sExt.Trim().Trim(false);
+        sExt = wxT(' ') + sExt + wxT(' ');
+        size_t nCount = m_aExtensions.GetCount();
+        for (nIndex = 0; nIndex < nCount; nIndex++)
+        {
+            sExtStore = m_aExtensions.Item(nIndex);
+            if (sExtStore.Replace(sExt, wxT(" ") ) > 0)
+                m_aExtensions.Item(nIndex) = sExtStore;
+        }
+    }
+
+    if ( !DoAssociation(strType, strIcon, entry, sA_Exts, strDesc) )
+        return NULL;
+
+    return GetFileTypeFromMimeType(strType);
+}
+
+bool wxMimeTypesManagerImpl::DoAssociation(const wxString& strType,
+                                           const wxString& strIcon,
+                                           wxMimeTypeCommands *entry,
+                                           const wxArrayString& strExtensions,
+                                           const wxString& strDesc)
+{
+    int nIndex = AddToMimeData(strType, strIcon, entry, strExtensions, strDesc, true);
+
+    if ( nIndex == wxNOT_FOUND )
+        return false;
+
+    return WriteMimeInfo(nIndex, false);
+}
+
+bool wxMimeTypesManagerImpl::WriteMimeInfo(int nIndex, bool delete_mime )
+{
+    bool ok = true;
+
+    if ( m_mailcapStylesInited & wxMAILCAP_STANDARD )
+    {
+        // write in metamail  format;
+        if (WriteToMimeTypes(nIndex, delete_mime) )
+            if ( WriteToMailCap(nIndex, delete_mime) )
+                ok = false;
+    }
+
+    if ( m_mailcapStylesInited & wxMAILCAP_NETSCAPE )
+    {
+        // write in netsacpe format;
+        if (WriteToNSMimeTypes(nIndex, delete_mime) )
+            if ( WriteToMailCap(nIndex, delete_mime) )
+                ok = false;
+    }