]> git.saurik.com Git - wxWidgets.git/blame - src/unix/mimetype.cpp
TRUE/FALSE source cleaning.
[wxWidgets.git] / src / unix / mimetype.cpp
CommitLineData
b13d92d1 1/////////////////////////////////////////////////////////////////////////////
7dc3cc31 2// Name: unix/mimetype.cpp
b13d92d1
VZ
3// Purpose: classes and functions to manage MIME types
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 23.09.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence (part of wxExtra library)
b13d92d1
VZ
10/////////////////////////////////////////////////////////////////////////////
11
2b813b73
VZ
12// known bugs; there may be others!! chris elliott, biol75@york.ac.uk 27 Mar 01
13
14// 1) .mailcap and .mimetypes can be either in a netscape or metamail format
15// and entries may get confused during writing (I've tried to fix this; please let me know
16// any files that fail)
17// 2) KDE and Gnome do not yet fully support international read/write
18// 3) Gnome key lines like open.latex."LaTeX this file"=latex %f will have odd results
19// 4) writing to files comments out the existing data; I hope this avoids losing
20// any data which we could not read, and data which we did not store like test=
21// 5) results from reading files with multiple entries (especially matches with type/* )
22// may (or may not) work for getXXX commands
23// 6) Loading the png icons in Gnome doesn't work for me...
24// 7) In Gnome, if keys.mime exists but keys.users does not, there is
25// an error message in debug mode, but the file is still written OK
26// 8) Deleting entries is only allowed from the user file; sytem wide entries
27// will be preserved during unassociate
678ebfcd
VZ
28// 9) KDE does not yet handle multiple actions; Netscape mode never will
29
7c2e5dec 30// TODO: this file is a mess, we need to split it and review everything (VZ)
f6bcfd97 31
b13d92d1
VZ
32// for compilers that support precompilation, includes "wx.h".
33#include "wx/wxprec.h"
34
35#ifdef __BORLANDC__
ce4169a4 36 #pragma hdrstop
b13d92d1
VZ
37#endif
38
b13d92d1 39#ifndef WX_PRECOMP
ce4169a4
RR
40 #include "wx/defs.h"
41#endif
42
b79e32cc 43#if wxUSE_MIMETYPE && wxUSE_FILE && wxUSE_TEXTFILE
ce4169a4
RR
44
45#ifndef WX_PRECOMP
46 #include "wx/string.h"
7c2e5dec 47#endif
3d05544e 48
b13d92d1 49#include "wx/log.h"
ce4169a4 50#include "wx/file.h"
b13d92d1
VZ
51#include "wx/intl.h"
52#include "wx/dynarray.h"
2432b92d 53#include "wx/confbase.h"
b13d92d1 54
7dc3cc31
VS
55#include "wx/ffile.h"
56#include "wx/textfile.h"
57#include "wx/dir.h"
58#include "wx/utils.h"
59#include "wx/tokenzr.h"
c41dbc20 60#include "wx/iconloc.h"
1d529ef7 61#include "wx/filename.h"
b13d92d1 62
7dc3cc31 63#include "wx/unix/mimetype.h"
b13d92d1
VZ
64
65// other standard headers
66#include <ctype.h>
67
2900bd1c
JJ
68#ifdef __VMS
69/* silence warnings for comparing unsigned int's <0 */
70# pragma message disable unscomzer
71#endif
72
678ebfcd
VZ
73// wxMimeTypeCommands stores the verbs defined for the given MIME type with
74// their values
75class wxMimeTypeCommands
2b813b73
VZ
76{
77public:
dfea7acc 78 wxMimeTypeCommands() {}
678ebfcd
VZ
79
80 wxMimeTypeCommands(const wxArrayString& verbs,
81 const wxArrayString& commands)
82 : m_verbs(verbs),
83 m_commands(commands)
2b813b73 84 {
2b813b73
VZ
85 }
86
678ebfcd
VZ
87 // add a new verb with the command or replace the old value
88 void AddOrReplaceVerb(const wxString& verb, const wxString& cmd)
2b813b73 89 {
d0ee33f5 90 int n = m_verbs.Index(verb, false /* ignore case */);
678ebfcd 91 if ( n == wxNOT_FOUND )
2b813b73 92 {
678ebfcd
VZ
93 m_verbs.Add(verb);
94 m_commands.Add(cmd);
95 }
96 else
97 {
98 m_commands[n] = cmd;
2b813b73 99 }
2b813b73
VZ
100 }
101
678ebfcd 102 void Add(const wxString& s)
2b813b73 103 {
dfea7acc
DS
104 m_verbs.Add(s.BeforeFirst(wxT('=')));
105 m_commands.Add(s.AfterFirst(wxT('=')));
2b813b73
VZ
106 }
107
678ebfcd
VZ
108 // access the commands
109 size_t GetCount() const { return m_verbs.GetCount(); }
110 const wxString& GetVerb(size_t n) const { return m_verbs[n]; }
111 const wxString& GetCmd(size_t n) const { return m_commands[n]; }
112
113 bool HasVerb(const wxString& verb) const
114 { return m_verbs.Index(verb) != wxNOT_FOUND; }
115
116 wxString GetCommandForVerb(const wxString& verb, size_t *idx = NULL) const
2b813b73 117 {
678ebfcd
VZ
118 wxString s;
119
120 int n = m_verbs.Index(verb);
121 if ( n != wxNOT_FOUND )
122 {
123 s = m_commands[(size_t)n];
124 if ( idx )
125 *idx = n;
126 }
8a7fc9b5
VZ
127 else if ( idx )
128 {
129 // different from any valid index
130 *idx = (size_t)-1;
131 }
678ebfcd
VZ
132
133 return s;
2b813b73
VZ
134 }
135
678ebfcd
VZ
136 // get a "verb=command" string
137 wxString GetVerbCmd(size_t n) const
2b813b73 138 {
dfea7acc 139 return m_verbs[n] + wxT('=') + m_commands[n];
2b813b73 140 }
678ebfcd
VZ
141
142private:
dfea7acc
DS
143 wxArrayString m_verbs;
144 wxArrayString m_commands;
2b813b73
VZ
145};
146
678ebfcd
VZ
147// this class extends wxTextFile
148//
149// VZ: ???
2b813b73
VZ
150class wxMimeTextFile : public wxTextFile
151{
152public:
153 // constructors
154 wxMimeTextFile () : wxTextFile () {};
7c2e5dec 155 wxMimeTextFile(const wxString& strFile) : wxTextFile(strFile) {};
2b813b73 156
d0ee33f5 157 int pIndexOf(const wxString & sSearch, bool bIncludeComments = false, int iStart = 0)
2b813b73
VZ
158 {
159 size_t i = iStart;
160 int nResult = wxNOT_FOUND;
dfea7acc
DS
161 if (i >= GetLineCount())
162 return wxNOT_FOUND;
2b813b73
VZ
163
164 wxString sTest = sSearch;
165 sTest.MakeLower();
166 wxString sLine;
167
168 if (bIncludeComments)
169 {
dfea7acc 170 while ( i < GetLineCount() )
2b813b73 171 {
dfea7acc 172 sLine = GetLine(i);
2b813b73 173 sLine.MakeLower();
dfea7acc
DS
174 if (sLine.Contains(sTest))
175 nResult = (int) i;
7c2e5dec 176
2b813b73
VZ
177 i++;
178 }
179 }
180 else
181 {
182 while ( (i < GetLineCount()) )
183 {
dfea7acc 184 sLine = GetLine(i);
2b813b73
VZ
185 sLine.MakeLower();
186 if ( ! sLine.StartsWith(wxT("#")))
187 {
dfea7acc
DS
188 if (sLine.Contains(sTest))
189 nResult = (int) i;
2b813b73 190 }
dfea7acc 191
2b813b73
VZ
192 i++;
193 }
194 }
dfea7acc 195
2b813b73
VZ
196 return nResult;
197 }
198
199 bool CommentLine(int nIndex)
200 {
dfea7acc
DS
201 if (nIndex < 0)
202 return false;
203 if (nIndex >= (int)GetLineCount() )
204 return false;
7c2e5dec 205
2b813b73 206 GetLine(nIndex) = GetLine(nIndex).Prepend(wxT("#"));
d0ee33f5 207 return true;
2b813b73
VZ
208 }
209
210 bool CommentLine(const wxString & sTest)
211 {
212 int nIndex = pIndexOf(sTest);
dfea7acc
DS
213 if (nIndex < 0)
214 return false;
215 if (nIndex >= (int)GetLineCount() )
216 return false;
217
2b813b73 218 GetLine(nIndex) = GetLine(nIndex).Prepend(wxT("#"));
d0ee33f5 219 return true;
2b813b73
VZ
220 }
221
dfea7acc 222 wxString GetVerb(size_t i)
2b813b73 223 {
dfea7acc
DS
224 if (i > GetLineCount() )
225 return wxEmptyString;
226
2b813b73
VZ
227 wxString sTmp = GetLine(i).BeforeFirst(wxT('='));
228 return sTmp;
229 }
230
dfea7acc 231 wxString GetCmd(size_t i)
2b813b73 232 {
dfea7acc
DS
233 if (i > GetLineCount() )
234 return wxEmptyString;
235
2b813b73
VZ
236 wxString sTmp = GetLine(i).AfterFirst(wxT('='));
237 return sTmp;
238 }
239};
240
b12915c1
VZ
241// in case we're compiling in non-GUI mode
242class WXDLLEXPORT wxIcon;
243
f6bcfd97
BP
244// ----------------------------------------------------------------------------
245// constants
246// ----------------------------------------------------------------------------
247
248// MIME code tracing mask
dfea7acc 249#define TRACE_MIME wxT("mime")
f6bcfd97 250
678ebfcd 251// give trace messages about the results of mailcap tests
dfea7acc 252#define TRACE_MIME_TEST wxT("mimetest")
678ebfcd 253
f6bcfd97
BP
254// ----------------------------------------------------------------------------
255// private functions
256// ----------------------------------------------------------------------------
257
258// there are some fields which we don't understand but for which we don't give
259// warnings as we know that they're not important - this function is used to
260// test for them
261static bool IsKnownUnimportantField(const wxString& field);
262
b13d92d1
VZ
263// ----------------------------------------------------------------------------
264// private classes
265// ----------------------------------------------------------------------------
266
2b813b73 267
a6c65e88 268// This class uses both mailcap and mime.types to gather information about file
b13d92d1
VZ
269// types.
270//
a6c65e88
VZ
271// The information about mailcap file was extracted from metamail(1) sources
272// and documentation and subsequently revised when I found the RFC 1524
273// describing it.
b13d92d1
VZ
274//
275// Format of mailcap file: spaces are ignored, each line is either a comment
276// (starts with '#') or a line of the form <field1>;<field2>;...;<fieldN>.
277// A backslash can be used to quote semicolons and newlines (and, in fact,
278// anything else including itself).
279//
280// The first field is always the MIME type in the form of type/subtype (see RFC
281// 822) where subtype may be '*' meaning "any". Following metamail, we accept
282// "type" which means the same as "type/*", although I'm not sure whether this
283// is standard.
284//
285// The second field is always the command to run. It is subject to
286// parameter/filename expansion described below.
287//
288// All the following fields are optional and may not be present at all. If
289// they're present they may appear in any order, although each of them should
290// appear only once. The optional fields are the following:
291// * notes=xxx is an uninterpreted string which is silently ignored
292// * test=xxx is the command to be used to determine whether this mailcap line
293// applies to our data or not. The RHS of this field goes through the
294// parameter/filename expansion (as the 2nd field) and the resulting string
295// is executed. The line applies only if the command succeeds, i.e. returns 0
296// exit code.
297// * print=xxx is the command to be used to print (and not view) the data of
298// this type (parameter/filename expansion is done here too)
299// * edit=xxx is the command to open/edit the data of this type
a6c65e88
VZ
300// * needsterminal means that a new interactive console must be created for
301// the viewer
b13d92d1
VZ
302// * copiousoutput means that the viewer doesn't interact with the user but
303// produces (possibly) a lof of lines of output on stdout (i.e. "cat" is a
304// good example), thus it might be a good idea to use some kind of paging
305// mechanism.
306// * textualnewlines means not to perform CR/LF translation (not honored)
307// * compose and composetyped fields are used to determine the program to be
308// called to create a new message pert in the specified format (unused).
309//
a6c65e88 310// Parameter/filename expansion:
b13d92d1
VZ
311// * %s is replaced with the (full) file name
312// * %t is replaced with MIME type/subtype of the entry
313// * for multipart type only %n is replaced with the nnumber of parts and %F is
314// replaced by an array of (content-type, temporary file name) pairs for all
315// message parts (TODO)
316// * %{parameter} is replaced with the value of parameter taken from
317// Content-type header line of the message.
318//
b13d92d1
VZ
319//
320// There are 2 possible formats for mime.types file, one entry per line (used
a6c65e88
VZ
321// for global mime.types and called Mosaic format) and "expanded" format where
322// an entry takes multiple lines (used for users mime.types and called
323// Netscape format).
b13d92d1
VZ
324//
325// For both formats spaces are ignored and lines starting with a '#' are
326// comments. Each record has one of two following forms:
327// a) for "brief" format:
328// <mime type> <space separated list of extensions>
ec4768ef 329// b) for "expanded" format:
1457c903
VZ
330// type=<mime type> BACKSLASH
331// desc="<description>" BACKSLASH
a6c65e88 332// exts="<comma separated list of extensions>"
b13d92d1 333//
1457c903
VZ
334// (where BACKSLASH is a literal '\\' which we can't put here because cpp
335// misinterprets it)
336//
b13d92d1
VZ
337// We try to autodetect the format of mime.types: if a non-comment line starts
338// with "type=" we assume the second format, otherwise the first one.
339
340// there may be more than one entry for one and the same mime type, to
341// choose the right one we have to run the command specified in the test
342// field on our data.
b9517a0a
VZ
343
344// ----------------------------------------------------------------------------
2b813b73 345// wxGNOME
b9517a0a
VZ
346// ----------------------------------------------------------------------------
347
348// GNOME stores the info we're interested in in several locations:
349// 1. xxx.keys files under /usr/share/mime-info
350// 2. xxx.keys files under ~/.gnome/mime-info
351//
352// The format of xxx.keys file is the following:
353//
354// mimetype/subtype:
355// field=value
356//
357// with blank lines separating the entries and indented lines starting with
358// TABs. We're interested in the field icon-filename whose value is the path
359// containing the icon.
afaee315
VZ
360//
361// Update (Chris Elliott): apparently there may be an optional "[lang]" prefix
362// just before the field name.
b9517a0a 363
b9517a0a 364
7c2e5dec 365bool wxMimeTypesManagerImpl::CheckGnomeDirsExist()
678ebfcd 366{
2b813b73
VZ
367 wxString gnomedir;
368 wxGetHomeDir( &gnomedir );
369 wxString sTmp = gnomedir;
2b5f62a0 370 sTmp = sTmp + wxT("/.gnome");
7c2e5dec 371 if (! wxDir::Exists( sTmp ) )
678ebfcd 372 {
7c2e5dec 373 if (!wxMkdir( sTmp ))
678ebfcd 374 {
dfea7acc 375 wxLogError(wxT("Failed to create directory %s/.gnome."), sTmp.c_str());
d0ee33f5 376 return false;
b9517a0a 377 }
678ebfcd 378 }
7c2e5dec 379
2b5f62a0 380 sTmp = sTmp + wxT("/mime-info");
7c2e5dec 381 if (! wxDir::Exists( sTmp ) )
678ebfcd 382 {
7c2e5dec 383 if (!wxMkdir( sTmp ))
2b813b73 384 {
dfea7acc 385 wxLogError(wxT("Failed to create directory %s/mime-info."), sTmp.c_str());
d0ee33f5 386 return false;
b9517a0a 387 }
2b813b73 388 }
b9517a0a 389
dfea7acc 390 return true;
2b813b73
VZ
391}
392
2b813b73 393bool wxMimeTypesManagerImpl::WriteGnomeKeyFile(int index, bool delete_index)
678ebfcd 394{
2b813b73
VZ
395 wxString gnomedir;
396 wxGetHomeDir( &gnomedir );
397
dfea7acc 398 wxMimeTextFile outfile( gnomedir + wxT("/.gnome/mime-info/user.keys"));
2b813b73
VZ
399 // if this fails probably Gnome is not installed ??
400 // create it anyway as a private mime store
401
2b5f62a0 402#if defined(__WXGTK20__) && wxUSE_UNICODE
7c2e5dec 403 if (! outfile.Open( wxConvUTF8) )
2b5f62a0 404#else
7c2e5dec 405 if (! outfile.Open() )
2b5f62a0 406#endif
2b813b73 407 {
dfea7acc
DS
408 if (delete_index)
409 return false;
410 if (!CheckGnomeDirsExist() )
411 return false;
412
413 outfile.Create();
2b813b73
VZ
414 }
415
416 wxString sTmp, strType = m_aTypes[index];
417 int nIndex = outfile.pIndexOf(strType);
418 if ( nIndex == wxNOT_FOUND )
678ebfcd 419 {
7c2e5dec 420 outfile.AddLine( strType + wxT(':') );
2b813b73
VZ
421 // see file:/usr/doc/gnome-libs-devel-1.0.40/devel-docs/mime-type-handling.txt
422 // as this does not deal with internationalisation
423 // wxT( "\t[en_US]") + verb + wxT ('=') + cmd + wxT(" %f");
678ebfcd
VZ
424 wxMimeTypeCommands * entries = m_aEntries[index];
425 size_t count = entries->GetCount();
426 for ( size_t i = 0; i < count; i++ )
427 {
7c2e5dec 428 sTmp = entries->GetVerbCmd( i );
2b813b73 429 sTmp.Replace( wxT("%s"), wxT("%f") );
dfea7acc
DS
430 sTmp = wxT( "\t") + sTmp;
431 outfile.AddLine( sTmp );
678ebfcd 432 }
7c2e5dec 433
2b813b73 434 //for international use do something like this
7c2e5dec 435 //outfile.AddLine( wxString( "\t[en_US]icon-filename=") + cmd );
dfea7acc 436 outfile.AddLine( wxT( "\ticon-filename=") + m_aIcons[index] );
678ebfcd
VZ
437 }
438 else
439 {
440 if (delete_index)
441 outfile.CommentLine(nIndex);
442
443 wxMimeTypeCommands sOld;
2b813b73 444 size_t nOld = nIndex + 1;
d0ee33f5 445 bool oldEntryEnd = false;
7c2e5dec 446 while ( (nOld < outfile.GetLineCount() ) && !oldEntryEnd)
678ebfcd 447 {
2b813b73
VZ
448 sTmp = outfile.GetLine(nOld);
449 if ( (sTmp[0u] == wxT('\t')) || (sTmp[0u] == wxT('#')) )
678ebfcd 450 {
2b813b73
VZ
451 // we have another line to deal with
452 outfile.CommentLine(nOld);
7c2e5dec 453 nOld++;
dfea7acc 454
2b813b73 455 // add the line to our store
678ebfcd
VZ
456 if ((!delete_index) && (sTmp[0u] == wxT('\t')))
457 sOld.Add(sTmp);
b9517a0a 458 }
dfea7acc 459 // next mimetpye ?? or blank line
678ebfcd 460 else
d0ee33f5 461 oldEntryEnd = true;
678ebfcd 462 }
dfea7acc 463
2b813b73
VZ
464 // list of entries in our data; these should all be in sOld,
465 // though sOld may also contain other entries , eg flags
466 if (!delete_index)
678ebfcd
VZ
467 {
468 wxMimeTypeCommands * entries = m_aEntries[index];
2b813b73
VZ
469 size_t i;
470 for (i=0; i < entries->GetCount(); i++)
678ebfcd 471 {
2b813b73 472 // replace any entries in sold that match verbs we know
dfea7acc 473 sOld.AddOrReplaceVerb( entries->GetVerb(i), entries->GetCmd(i) );
b9517a0a 474 }
dfea7acc 475
2b813b73 476 //sOld should also contain the icon
678ebfcd 477 if ( !m_aIcons[index].empty() )
dfea7acc 478 sOld.AddOrReplaceVerb( wxT("icon-filename"), m_aIcons[index] );
b9517a0a 479
2b813b73 480 for (i=0; i < sOld.GetCount(); i++)
678ebfcd 481 {
7c2e5dec 482 sTmp = sOld.GetVerbCmd( i );
2b813b73 483 sTmp.Replace( wxT("%s"), wxT("%f") );
2b5f62a0 484 sTmp = wxT("\t") + sTmp;
7c2e5dec 485 nIndex++;
dfea7acc 486 outfile.InsertLine( sTmp, nIndex );
2b813b73
VZ
487 }
488 }
678ebfcd 489 }
dfea7acc
DS
490
491 bool bTmp = outfile.Write();
2b813b73 492 return bTmp;
678ebfcd 493}
b9517a0a 494
2b813b73 495bool wxMimeTypesManagerImpl::WriteGnomeMimeFile(int index, bool delete_index)
678ebfcd 496{
2b813b73
VZ
497 wxString gnomedir;
498 wxGetHomeDir( &gnomedir );
afaee315 499
7c2e5dec 500 wxMimeTextFile outfile( gnomedir + wxT("/.gnome/mime-info/user.mime") );
2b813b73
VZ
501 // if this fails probably Gnome is not installed ??
502 // create it anyway as a private mime store
dfea7acc 503 if (! outfile.Open() )
2b813b73 504 {
dfea7acc
DS
505 if (delete_index)
506 return false;
507 if (!CheckGnomeDirsExist() )
508 return false;
509
510 outfile.Create();
2b813b73 511 }
dfea7acc 512
2b813b73
VZ
513 wxString strType = m_aTypes[index];
514 int nIndex = outfile.pIndexOf(strType);
515 if ( nIndex == wxNOT_FOUND )
678ebfcd 516 {
dfea7acc
DS
517 outfile.AddLine( strType );
518 outfile.AddLine( wxT("\text:") + m_aExtensions.Item(index) );
678ebfcd 519 }
2b813b73 520 else
678ebfcd 521 {
2b813b73 522 if (delete_index)
678ebfcd 523 {
2b813b73 524 outfile.CommentLine(nIndex);
7c2e5dec 525 outfile.CommentLine(nIndex + 1);
b9517a0a
VZ
526 }
527 else
dfea7acc
DS
528 {
529 // check for next line being the right one to replace ??
7c2e5dec
DS
530 wxString sOld = outfile.GetLine(nIndex + 1);
531 if (sOld.Contains( wxT("\text: ") ))
678ebfcd 532 {
7c2e5dec 533 outfile.GetLine(nIndex + 1) = wxT("\text: ") + m_aExtensions.Item(index);
678ebfcd 534 }
2b813b73 535 else
b9517a0a 536 {
2b5f62a0 537 outfile.InsertLine( wxT("\text: ") + m_aExtensions.Item(index), nIndex + 1 );
b9517a0a 538 }
4d2976ad
VS
539 }
540 }
dfea7acc
DS
541
542 bool bTmp = outfile.Write();
2b813b73 543 return bTmp;
4d2976ad
VS
544}
545
25d599ae
VS
546void wxMimeTypesManagerImpl::LoadGnomeDataFromKeyFile(const wxString& filename,
547 const wxArrayString& dirs)
4d2976ad 548{
2b813b73 549 wxTextFile textfile(filename);
2b5f62a0 550#if defined(__WXGTK20__) && wxUSE_UNICODE
dfea7acc 551 if ( !textfile.Open(wxConvUTF8) )
2b5f62a0 552#else
2b813b73 553 if ( !textfile.Open() )
2b5f62a0 554#endif
2b813b73 555 return;
dfea7acc 556
2b813b73 557 wxLogTrace(TRACE_MIME, wxT("--- Opened Gnome file %s ---"),
678ebfcd 558 filename.c_str());
4d2976ad 559
2b813b73
VZ
560 // values for the entry being parsed
561 wxString curMimeType, curIconFile;
678ebfcd 562 wxMimeTypeCommands * entry = new wxMimeTypeCommands;
4d2976ad 563
2b813b73
VZ
564 // these are always empty in this file
565 wxArrayString strExtensions;
566 wxString strDesc;
4d2976ad 567
2b813b73
VZ
568 const wxChar *pc;
569 size_t nLineCount = textfile.GetLineCount();
570 size_t nLine = 0;
7c2e5dec 571 while ( nLine < nLineCount )
678ebfcd 572 {
2b813b73 573 pc = textfile[nLine].c_str();
dfea7acc 574 if ( *pc != wxT('#') )
678ebfcd 575 {
4d2976ad 576
2b813b73 577 wxLogTrace(TRACE_MIME, wxT("--- Reading from Gnome file %s '%s' ---"),
7c2e5dec 578 filename.c_str(), pc);
4d2976ad 579
2b813b73
VZ
580 wxString sTmp(pc);
581 if (sTmp.Contains(wxT("=")) )
582 {
678ebfcd 583 if (sTmp.Contains( wxT("icon-filename=") ) )
2b813b73 584 {
dfea7acc 585 // GNOME 1:
678ebfcd 586 curIconFile = sTmp.AfterFirst(wxT('='));
2b813b73 587 }
25d599ae
VS
588 else if (sTmp.Contains( wxT("icon_filename=") ) )
589 {
dfea7acc 590 // GNOME 2:
25d599ae 591 curIconFile = sTmp.AfterFirst(wxT('='));
d0ee33f5 592
25d599ae
VS
593 if (!wxFileExists(curIconFile))
594 {
595 size_t nDirs = dirs.GetCount();
596 for (size_t nDir = 0; nDir < nDirs; nDir++)
597 {
1d529ef7 598 wxFileName newFile( curIconFile );
10274336
RR
599 newFile.SetPath( dirs[nDir] );
600 newFile.AppendDir( wxT("pixmaps") );
601 newFile.AppendDir( wxT("document-icons") );
602 newFile.SetExt( wxT("png") );
1d529ef7
RR
603 if (newFile.FileExists())
604 curIconFile = newFile.GetFullPath();
25d599ae
VS
605 }
606 }
607 }
678ebfcd
VZ
608 else //: some other field,
609 {
610 //may contain lines like this (RH7)
611 // \t[lang]open.tex."TeX this file"=tex %f
612 // \tflags.tex.flags=needsterminal
613 // \topen.latex."LaTeX this file"=latex %f
614 // \tflags.latex.flags=needsterminal
615
616 // \topen=xdvi %f
617 // \tview=xdvi %f
618 // \topen.convert.Convert file to Postscript=dvips %f -o `basename %f .dvi`.ps
619
620 // for now ignore lines with flags in...FIX
621 sTmp = sTmp.AfterLast(wxT(']'));
622 sTmp = sTmp.AfterLast(wxT('\t'));
d0ee33f5 623 sTmp.Trim(false).Trim();
dfea7acc
DS
624 if (0 == sTmp.Replace( wxT("%f"), wxT("%s") ))
625 sTmp = sTmp + wxT(" %s");
678ebfcd 626 entry->Add(sTmp);
2b813b73
VZ
627 }
628
629 } // emd of has an equals sign
630 else
678ebfcd 631 {
2b813b73
VZ
632 // not a comment and not an equals sign
633 if (sTmp.Contains(wxT('/')))
678ebfcd 634 {
2b813b73
VZ
635 // this is the start of the new mimetype
636 // overwrite any existing data
678ebfcd
VZ
637 if (! curMimeType.empty())
638 {
7c2e5dec 639 AddToMimeData( curMimeType, curIconFile, entry, strExtensions, strDesc );
2b813b73
VZ
640
641 // now get ready for next bit
678ebfcd 642 entry = new wxMimeTypeCommands;
2b813b73 643 }
dfea7acc 644
678ebfcd
VZ
645 curMimeType = sTmp.BeforeFirst(wxT(':'));
646 }
647 }
2b813b73 648 } // end of not a comment
dfea7acc 649
678ebfcd 650 // ignore blank lines
7c2e5dec 651 nLine++;
2b813b73 652 } // end of while, save any data
d0ee33f5 653
32592f4a
VZ
654 if ( curMimeType.empty() )
655 delete entry;
656 else
dfea7acc 657 AddToMimeData( curMimeType, curIconFile, entry, strExtensions, strDesc);
4d2976ad
VS
658}
659
2b813b73 660void wxMimeTypesManagerImpl::LoadGnomeMimeTypesFromMimeFile(const wxString& filename)
4d2976ad
VS
661{
662 wxTextFile textfile(filename);
663 if ( !textfile.Open() )
664 return;
2b6d8c00
VZ
665
666 wxLogTrace(TRACE_MIME,
667 wxT("--- Opened Gnome file %s ---"),
668 filename.c_str());
4d2976ad
VS
669
670 // values for the entry being parsed
671 wxString curMimeType, curExtList;
672
673 const wxChar *pc;
674 size_t nLineCount = textfile.GetLineCount();
1c4cd9e0 675 for ( size_t nLine = 0; /* nothing */; nLine++ )
4d2976ad
VS
676 {
677 if ( nLine < nLineCount )
678 {
679 pc = textfile[nLine].c_str();
2b5f62a0 680 if ( *pc == wxT('#') )
4d2976ad
VS
681 {
682 // skip comments
683 continue;
684 }
685 }
686 else
687 {
688 // so that we will fall into the "if" below
689 pc = NULL;
690 }
b9517a0a 691
4d2976ad
VS
692 if ( !pc || !*pc )
693 {
694 // end of the entry
d0ee33f5 695 if ( !curMimeType.empty() && !curExtList.empty() )
b9517a0a 696 {
2b6d8c00
VZ
697 wxLogTrace(TRACE_MIME,
698 wxT("--- At end of Gnome file finding mimetype %s ---"),
699 curMimeType.c_str());
d0ee33f5 700
2b813b73 701 AddMimeTypeInfo(curMimeType, curExtList, wxEmptyString);
4d2976ad 702 }
b9517a0a 703
4d2976ad
VS
704 if ( !pc )
705 {
7c2e5dec 706 // the end: this can only happen if nLine == nLineCount
b9517a0a
VZ
707 break;
708 }
4d2976ad
VS
709
710 curExtList.Empty();
711
712 continue;
713 }
714
715 // what do we have here?
2b5f62a0 716 if ( *pc == wxT('\t') )
4d2976ad
VS
717 {
718 // this is a field=value ling
719 pc++; // skip leading TAB
720
2b6d8c00
VZ
721 static const int lenField = 5; // strlen("ext: ")
722 if ( wxStrncmp(pc, wxT("ext: "), lenField) == 0 )
4d2976ad 723 {
2b6d8c00
VZ
724 // skip it and take everything left until the end of line
725 curExtList = pc + lenField;
4d2976ad
VS
726 }
727 //else: some other field, we don't care
728 }
729 else
730 {
731 // this is the start of the new section
2b6d8c00
VZ
732 wxLogTrace(TRACE_MIME,
733 wxT("--- In Gnome file finding mimetype %s ---"),
734 curMimeType.c_str());
2b813b73 735
678ebfcd
VZ
736 if (! curMimeType.empty())
737 AddMimeTypeInfo(curMimeType, curExtList, wxEmptyString);
2b813b73 738
4d2976ad
VS
739 curMimeType.Empty();
740
2b5f62a0 741 while ( *pc != wxT(':') && *pc != wxT('\0') )
4d2976ad
VS
742 {
743 curMimeType += *pc++;
744 }
b9517a0a
VZ
745 }
746 }
747}
748
4d2976ad 749
25d599ae
VS
750void wxMimeTypesManagerImpl::LoadGnomeMimeFilesFromDir(
751 const wxString& dirbase, const wxArrayString& dirs)
b9517a0a 752{
d0ee33f5 753 wxASSERT_MSG( !dirbase.empty() && !wxEndsWithPathSeparator(dirbase),
dfea7acc 754 wxT("base directory shouldn't end with a slash") );
b9517a0a
VZ
755
756 wxString dirname = dirbase;
2b5f62a0 757 dirname << wxT("/mime-info");
d0ee33f5 758
b9517a0a
VZ
759 if ( !wxDir::Exists(dirname) )
760 return;
761
762 wxDir dir(dirname);
763 if ( !dir.IsOpened() )
764 return;
765
766 // we will concatenate it with filename to get the full path below
2b5f62a0 767 dirname += wxT('/');
b9517a0a
VZ
768
769 wxString filename;
1d529ef7 770 bool cont;
dfea7acc
DS
771
772 cont = dir.GetFirst(&filename, wxT("*.mime"), wxDIR_FILES);
b9517a0a
VZ
773 while ( cont )
774 {
2b813b73 775 LoadGnomeMimeTypesFromMimeFile(dirname + filename);
b9517a0a
VZ
776
777 cont = dir.GetNext(&filename);
778 }
fb5ddb4c 779
dfea7acc 780 cont = dir.GetFirst(&filename, wxT("*.keys"), wxDIR_FILES);
2b813b73 781 while ( cont )
b9517a0a 782 {
25d599ae 783 LoadGnomeDataFromKeyFile(dirname + filename, dirs);
b9517a0a 784
2b813b73
VZ
785 cont = dir.GetNext(&filename);
786 }
b9517a0a 787
7c2e5dec 788 // FIXME: Hack alert: We scan all icons and deduce the
1d529ef7
RR
789 // mime-type from the file name.
790 dirname = dirbase;
791 dirname << wxT("/pixmaps/document-icons");
d0ee33f5 792
1d529ef7
RR
793 // these are always empty in this file
794 wxArrayString strExtensions;
795 wxString strDesc;
d0ee33f5 796
1d529ef7 797 if ( !wxDir::Exists(dirname) )
ca06ee0d 798 {
7c2e5dec 799 // Just test for default GPE dir also
ca06ee0d 800 dirname = wxT("/usr/share/gpe/pixmaps/default/filemanager/document-icons");
d0ee33f5 801
ca06ee0d
RR
802 if ( !wxDir::Exists(dirname) )
803 return;
804 }
4d2976ad 805
1d529ef7 806 wxDir dir2( dirname );
2b813b73 807
1d529ef7
RR
808 cont = dir2.GetFirst(&filename, wxT("gnome-*.png"), wxDIR_FILES);
809 while ( cont )
810 {
10274336
RR
811 wxString mimeType = filename;
812 mimeType.Remove( 0, 6 ); // remove "gnome-"
7c2e5dec 813 mimeType.Remove( mimeType.Len() - 4, 4 ); // remove ".png"
10274336
RR
814 int pos = mimeType.Find( wxT("-") );
815 if (pos != wxNOT_FOUND)
816 {
817 mimeType.SetChar( pos, wxT('/') );
818 wxString iconFile = dirname;
819 iconFile << wxT("/");
820 iconFile << filename;
dfea7acc 821 AddToMimeData( mimeType, iconFile, NULL, strExtensions, strDesc, true );
10274336 822 }
1d529ef7
RR
823
824 cont = dir2.GetNext(&filename);
825 }
826}
2b813b73
VZ
827
828void wxMimeTypesManagerImpl::GetGnomeMimeInfo(const wxString& sExtraDir)
4d2976ad 829{
4d2976ad 830 wxArrayString dirs;
d0ee33f5 831
1c4cd9e0 832 wxString gnomedir = wxGetenv( wxT("GNOMEDIR") );
10274336
RR
833 if (!gnomedir.empty())
834 {
835 gnomedir << wxT("/share");
836 dirs.Add( gnomedir );
837 }
838
2b5f62a0
VZ
839 dirs.Add(wxT("/usr/share"));
840 dirs.Add(wxT("/usr/local/share"));
d0ee33f5 841
10274336
RR
842 gnomedir = wxGetHomeDir();
843 gnomedir << wxT("/.gnome");
4d2976ad 844 dirs.Add( gnomedir );
d0ee33f5 845
dfea7acc
DS
846 if (!sExtraDir.empty())
847 dirs.Add( sExtraDir );
4d2976ad
VS
848
849 size_t nDirs = dirs.GetCount();
850 for ( size_t nDir = 0; nDir < nDirs; nDir++ )
851 {
25d599ae 852 LoadGnomeMimeFilesFromDir(dirs[nDir], dirs);
4d2976ad
VS
853 }
854}
855
b9517a0a 856// ----------------------------------------------------------------------------
678ebfcd 857// KDE
b9517a0a
VZ
858// ----------------------------------------------------------------------------
859
678ebfcd 860
b9517a0a
VZ
861// KDE stores the icon info in its .kdelnk files. The file for mimetype/subtype
862// may be found in either of the following locations
863//
509a6196 864// 1. $KDEDIR/share/mimelnk/mimetype/subtype.kdelnk
b9517a0a
VZ
865// 2. ~/.kde/share/mimelnk/mimetype/subtype.kdelnk
866//
867// The format of a .kdelnk file is almost the same as the one used by
868// wxFileConfig, i.e. there are groups, comments and entries. The icon is the
869// value for the entry "Type"
870
2b813b73
VZ
871// kde writing; see http://webcvs.kde.org/cgi-bin/cvsweb.cgi/~checkout~/kdelibs/kio/DESKTOP_ENTRY_STANDARD
872// for now write to .kdelnk but should eventually do .desktop instead (in preference??)
873
dfea7acc 874bool wxMimeTypesManagerImpl::CheckKDEDirsExist( const wxString &sOK, const wxString &sTest )
10274336 875{
678ebfcd 876 if (sTest.empty())
10274336 877 {
dfea7acc 878 return wxDir::Exists(sOK);
10274336 879 }
2b813b73 880 else
10274336
RR
881 {
882 wxString sStart = sOK + wxT("/") + sTest.BeforeFirst(wxT('/'));
dfea7acc
DS
883 if (!wxDir::Exists(sStart))
884 wxMkdir(sStart);
10274336
RR
885 wxString sEnd = sTest.AfterFirst(wxT('/'));
886 return CheckKDEDirsExist(sStart, sEnd);
2b813b73
VZ
887 }
888}
889
890bool wxMimeTypesManagerImpl::WriteKDEMimeFile(int index, bool delete_index)
891{
892 wxMimeTextFile appoutfile, mimeoutfile;
893 wxString sHome = wxGetHomeDir();
894 wxString sTmp = wxT(".kde/share/mimelnk/");
678ebfcd 895 wxString sMime = m_aTypes[index];
dfea7acc 896 CheckKDEDirsExist(sHome, sTmp + sMime.BeforeFirst(wxT('/')) );
2b813b73
VZ
897 sTmp = sHome + wxT('/') + sTmp + sMime + wxT(".kdelnk");
898
899 bool bTemp;
dfea7acc 900 bool bMimeExists = mimeoutfile.Open(sTmp);
2b813b73
VZ
901 if (!bMimeExists)
902 {
dfea7acc 903 bTemp = mimeoutfile.Create(sTmp);
678ebfcd 904 // some unknown error eg out of disk space
dfea7acc
DS
905 if (!bTemp)
906 return false;
2b813b73
VZ
907 }
908
909 sTmp = wxT(".kde/share/applnk/");
dfea7acc 910 CheckKDEDirsExist(sHome, sTmp + sMime.AfterFirst(wxT('/')) );
2b813b73
VZ
911 sTmp = sHome + wxT('/') + sTmp + sMime.AfterFirst(wxT('/')) + wxT(".kdelnk");
912
913 bool bAppExists;
dfea7acc 914 bAppExists = appoutfile.Open(sTmp);
2b813b73
VZ
915 if (!bAppExists)
916 {
dfea7acc 917 bTemp = appoutfile.Create(sTmp);
2b813b73 918 // some unknown error eg out of disk space
dfea7acc
DS
919 if (!bTemp)
920 return false;
2b813b73
VZ
921 }
922
923 // fixed data; write if new file
924 if (!bMimeExists)
925 {
926 mimeoutfile.AddLine(wxT("#KDE Config File"));
927 mimeoutfile.AddLine(wxT("[KDE Desktop Entry]"));
928 mimeoutfile.AddLine(wxT("Version=1.0"));
929 mimeoutfile.AddLine(wxT("Type=MimeType"));
930 mimeoutfile.AddLine(wxT("MimeType=") + sMime);
931 }
932
933 if (!bAppExists)
934 {
935 mimeoutfile.AddLine(wxT("#KDE Config File"));
936 mimeoutfile.AddLine(wxT("[KDE Desktop Entry]"));
937 appoutfile.AddLine(wxT("Version=1.0"));
938 appoutfile.AddLine(wxT("Type=Application"));
939 appoutfile.AddLine(wxT("MimeType=") + sMime + wxT(';'));
940 }
941
942 // variable data
943 // ignore locale
944 mimeoutfile.CommentLine(wxT("Comment="));
945 if (!delete_index)
946 mimeoutfile.AddLine(wxT("Comment=") + m_aDescriptions[index]);
947 appoutfile.CommentLine(wxT("Name="));
948 if (!delete_index)
949 appoutfile.AddLine(wxT("Comment=") + m_aDescriptions[index]);
950
951 sTmp = m_aIcons[index];
952 // we can either give the full path, or the shortfilename if its in
953 // one of the directories we search
954 mimeoutfile.CommentLine(wxT("Icon=") );
dfea7acc
DS
955 if (!delete_index)
956 mimeoutfile.AddLine(wxT("Icon=") + sTmp );
7c2e5dec 957 appoutfile.CommentLine(wxT("Icon=") );
dfea7acc
DS
958 if (!delete_index)
959 appoutfile.AddLine(wxT("Icon=") + sTmp );
2b813b73
VZ
960
961 sTmp = wxT(" ") + m_aExtensions[index];
962
dfea7acc 963 wxStringTokenizer tokenizer(sTmp, wxT(" "));
2b813b73
VZ
964 sTmp = wxT("Patterns=");
965 mimeoutfile.CommentLine(sTmp);
966 while ( tokenizer.HasMoreTokens() )
967 {
968 // holds an extension; need to change it to *.ext;
969 wxString e = wxT("*.") + tokenizer.GetNextToken() + wxT(";");
970 sTmp = sTmp + e;
678ebfcd 971 }
dfea7acc
DS
972
973 if (!delete_index)
974 mimeoutfile.AddLine(sTmp);
2b813b73 975
678ebfcd 976 wxMimeTypeCommands * entries = m_aEntries[index];
2b813b73 977 // if we don't find open just have an empty string ... FIX this
dfea7acc 978 sTmp = entries->GetCommandForVerb(wxT("open"));
2b813b73
VZ
979 sTmp.Replace( wxT("%s"), wxT("%f") );
980
981 mimeoutfile.CommentLine(wxT("DefaultApp=") );
dfea7acc
DS
982 if (!delete_index)
983 mimeoutfile.AddLine(wxT("DefaultApp=") + sTmp);
2b813b73
VZ
984
985 sTmp.Replace( wxT("%f"), wxT("") );
986 appoutfile.CommentLine(wxT("Exec="));
dfea7acc
DS
987 if (!delete_index)
988 appoutfile.AddLine(wxT("Exec=") + sTmp);
2b813b73
VZ
989
990 if (entries->GetCount() > 1)
678ebfcd
VZ
991 {
992 //other actions as well as open
678ebfcd 993 }
dfea7acc 994
d0ee33f5 995 bTemp = false;
dfea7acc
DS
996 if (mimeoutfile.Write())
997 bTemp = true;
998 mimeoutfile.Close();
999 if (appoutfile.Write())
1000 bTemp = true;
1001 appoutfile.Close();
2b813b73
VZ
1002
1003 return bTemp;
2b813b73
VZ
1004}
1005
1006void wxMimeTypesManagerImpl::LoadKDELinksForMimeSubtype(const wxString& dirbase,
b9517a0a 1007 const wxString& subdir,
cdf339c9
VS
1008 const wxString& filename,
1009 const wxArrayString& icondirs)
b9517a0a 1010{
2b813b73 1011 wxMimeTextFile file;
dfea7acc
DS
1012 if ( !file.Open(dirbase + filename) )
1013 return;
b9517a0a 1014
25d599ae 1015 wxLogTrace(TRACE_MIME, wxT("loading KDE file %s"),
7c2e5dec 1016 (dirbase + filename).c_str());
d0ee33f5 1017
678ebfcd 1018 wxMimeTypeCommands * entry = new wxMimeTypeCommands;
2b813b73
VZ
1019 wxArrayString sExts;
1020 wxString mimetype, mime_desc, strIcon;
1021
2b5f62a0 1022 int nIndex = file.pIndexOf( wxT("MimeType=") );
2b813b73 1023 if (nIndex == wxNOT_FOUND)
678ebfcd
VZ
1024 {
1025 // construct mimetype from the directory name and the basename of the
1026 // file (it always has .kdelnk extension)
2b5f62a0 1027 mimetype << subdir << wxT('/') << filename.BeforeLast( wxT('.') );
678ebfcd 1028 }
dfea7acc
DS
1029 else
1030 mimetype = file.GetCmd(nIndex);
b9517a0a 1031
276c7463
VZ
1032 // first find the description string: it is the value in either "Comment="
1033 // line or "Comment[<locale_name>]=" one
2b813b73 1034 nIndex = wxNOT_FOUND;
276c7463
VZ
1035
1036 wxString comment;
7c2e5dec 1037
276c7463
VZ
1038#if wxUSE_INTL
1039 wxLocale *locale = wxGetLocale();
1040 if ( locale )
1041 {
1042 // try "Comment[locale name]" first
dfea7acc 1043 comment << wxT("Comment[") + locale->GetName() + wxT("]=");
2b813b73 1044 nIndex = file.pIndexOf(comment);
276c7463 1045 }
7c2e5dec 1046#endif
cdf339c9 1047
2b813b73 1048 if ( nIndex == wxNOT_FOUND )
276c7463 1049 {
dfea7acc 1050 comment = wxT("Comment=");
2b813b73 1051 nIndex = file.pIndexOf(comment);
276c7463
VZ
1052 }
1053
dfea7acc
DS
1054 if ( nIndex != wxNOT_FOUND )
1055 mime_desc = file.GetCmd(nIndex);
276c7463 1056 //else: no description
cdf339c9 1057
276c7463
VZ
1058 // next find the extensions
1059 wxString mime_extension;
1060
dfea7acc 1061 nIndex = file.pIndexOf(wxT("Patterns="));
2b813b73 1062 if ( nIndex != wxNOT_FOUND )
678ebfcd 1063 {
dfea7acc 1064 wxString exts = file.GetCmd(nIndex);
5bd3a2da 1065
dfea7acc 1066 wxStringTokenizer tokenizer(exts, wxT(";"));
276c7463 1067 while ( tokenizer.HasMoreTokens() )
cdf339c9 1068 {
276c7463 1069 wxString e = tokenizer.GetNextToken();
7c2e5dec
DS
1070
1071 // don't support too difficult patterns
dfea7acc 1072 if ( e.Left(2) != wxT("*.") )
7c2e5dec 1073 continue;
276c7463
VZ
1074
1075 if ( !mime_extension.empty() )
1076 {
1077 // separate from the previous ext
dfea7acc 1078 mime_extension << wxT(' ');
276c7463
VZ
1079 }
1080
cdf339c9 1081 mime_extension << e.Mid(2);
cdf339c9 1082 }
cdf339c9 1083 }
dfea7acc 1084
2b813b73 1085 sExts.Add(mime_extension);
5bd3a2da 1086
cdf339c9
VS
1087 // ok, now we can take care of icon:
1088
dfea7acc 1089 nIndex = file.pIndexOf(wxT("Icon="));
2b813b73 1090 if ( nIndex != wxNOT_FOUND )
b9517a0a 1091 {
2b813b73 1092 strIcon = file.GetCmd(nIndex);
7c2e5dec 1093
25d599ae 1094 wxLogTrace(TRACE_MIME, wxT(" icon %s"), strIcon.c_str());
d0ee33f5 1095
7c2e5dec 1096 // it could be the real path, but more often a short name
2b813b73 1097 if (!wxFileExists(strIcon))
678ebfcd 1098 {
2b813b73 1099 // icon is just the short name
678ebfcd 1100 if ( !strIcon.empty() )
cdf339c9 1101 {
678ebfcd
VZ
1102 // we must check if the file exists because it may be stored
1103 // in many locations, at least ~/.kde and $KDEDIR
1104 size_t nDir, nDirs = icondirs.GetCount();
1105 for ( nDir = 0; nDir < nDirs; nDir++ )
10274336 1106 {
3d780434
RR
1107 wxFileName fnameIcon( strIcon );
1108 wxFileName fname( icondirs[nDir], fnameIcon.GetName() );
10274336 1109 fname.SetExt( wxT("png") );
1d529ef7 1110 if (fname.FileExists())
678ebfcd 1111 {
1d529ef7 1112 strIcon = fname.GetFullPath();
25d599ae 1113 wxLogTrace(TRACE_MIME, wxT(" iconfile %s"), strIcon.c_str());
678ebfcd
VZ
1114 break;
1115 }
10274336 1116 }
2b813b73 1117 }
678ebfcd
VZ
1118 }
1119 }
dfea7acc 1120
2b813b73
VZ
1121 // now look for lines which know about the application
1122 // exec= or DefaultApp=
1123
1124 nIndex = file.pIndexOf(wxT("DefaultApp"));
b9517a0a 1125
2b813b73 1126 if ( nIndex == wxNOT_FOUND )
678ebfcd 1127 {
2b813b73
VZ
1128 // no entry try exec
1129 nIndex = file.pIndexOf(wxT("Exec"));
678ebfcd 1130 }
2b813b73
VZ
1131
1132 if ( nIndex != wxNOT_FOUND )
678ebfcd 1133 {
2b813b73 1134 // we expect %f; others including %F and %U and %u are possible
7c2e5dec 1135 wxString sTmp = file.GetCmd(nIndex);
dfea7acc 1136 if (0 == sTmp.Replace( wxT("%f"), wxT("%s") ))
678ebfcd 1137 sTmp = sTmp + wxT(" %s");
dfea7acc 1138 entry->AddOrReplaceVerb(wxString(wxT("open")), sTmp );
b9517a0a 1139 }
2b813b73 1140
dfea7acc 1141 AddToMimeData(mimetype, strIcon, entry, sExts, mime_desc);
b9517a0a
VZ
1142}
1143
2b813b73 1144void wxMimeTypesManagerImpl::LoadKDELinksForMimeType(const wxString& dirbase,
cdf339c9
VS
1145 const wxString& subdir,
1146 const wxArrayString& icondirs)
b9517a0a
VZ
1147{
1148 wxString dirname = dirbase;
1149 dirname += subdir;
1150 wxDir dir(dirname);
1151 if ( !dir.IsOpened() )
1152 return;
1153
25d599ae
VS
1154 wxLogTrace(TRACE_MIME, wxT("--- Loading from KDE directory %s ---"),
1155 dirname.c_str());
d0ee33f5 1156
dfea7acc 1157 dirname += wxT('/');
b9517a0a
VZ
1158
1159 wxString filename;
dfea7acc 1160 bool cont = dir.GetFirst(&filename, wxT("*.kdelnk"), wxDIR_FILES);
b9517a0a
VZ
1161 while ( cont )
1162 {
2b813b73
VZ
1163 LoadKDELinksForMimeSubtype(dirname, subdir, filename, icondirs);
1164
1165 cont = dir.GetNext(&filename);
1166 }
dfea7acc 1167
2b813b73 1168 // new standard for Gnome and KDE
dfea7acc 1169 cont = dir.GetFirst(&filename, wxT("*.desktop"), wxDIR_FILES);
2b813b73
VZ
1170 while ( cont )
1171 {
1172 LoadKDELinksForMimeSubtype(dirname, subdir, filename, icondirs);
b9517a0a
VZ
1173
1174 cont = dir.GetNext(&filename);
1175 }
1176}
1177
2b813b73 1178void wxMimeTypesManagerImpl::LoadKDELinkFilesFromDir(const wxString& dirbase,
cdf339c9 1179 const wxArrayString& icondirs)
b9517a0a 1180{
d0ee33f5 1181 wxASSERT_MSG( !dirbase.empty() && !wxEndsWithPathSeparator(dirbase),
dfea7acc 1182 wxT("base directory shouldn't end with a slash") );
b9517a0a
VZ
1183
1184 wxString dirname = dirbase;
dfea7acc 1185 dirname << wxT("/mimelnk");
b9517a0a
VZ
1186
1187 if ( !wxDir::Exists(dirname) )
1188 return;
1189
1190 wxDir dir(dirname);
1191 if ( !dir.IsOpened() )
1192 return;
1193
1194 // we will concatenate it with dir name to get the full path below
dfea7acc 1195 dirname += wxT('/');
b9517a0a
VZ
1196
1197 wxString subdir;
1198 bool cont = dir.GetFirst(&subdir, wxEmptyString, wxDIR_DIRS);
1199 while ( cont )
1200 {
2b813b73 1201 LoadKDELinksForMimeType(dirname, subdir, icondirs);
b9517a0a
VZ
1202
1203 cont = dir.GetNext(&subdir);
1204 }
1205}
1206
2b813b73 1207void wxMimeTypesManagerImpl::GetKDEMimeInfo(const wxString& sExtraDir)
b9517a0a
VZ
1208{
1209 wxArrayString dirs;
cdf339c9 1210 wxArrayString icondirs;
320c341a
VS
1211
1212 // FIXME: This code is heavily broken. There are three bugs in it:
1213 // 1) it uses only KDEDIR, which is deprecated, instead of using
1214 // list of paths from KDEDIRS and using KDEDIR only if KDEDIRS
1215 // is not set
1216 // 2) it doesn't look into ~/.kde/share/config/kdeglobals where
1217 // user's settings are stored and thus *ignores* user's settings
1218 // instead of respecting them
1219 // 3) it "tries to guess KDEDIR" and "tries a few likely theme
1220 // names", both of which is completely arbitrary; instead, the
1221 // code should give up if KDEDIR(S) is not set and/or the icon
1222 // theme cannot be determined, because it means that the user is
1223 // not using KDE (and thus is not interested in KDE icons anyway)
d0ee33f5 1224
10274336
RR
1225 // the variable $KDEDIR is set when KDE is running
1226 wxString kdedir = wxGetenv( wxT("KDEDIR") );
d0ee33f5 1227
10274336 1228 if (!kdedir.empty())
1d529ef7 1229 {
10274336
RR
1230 // $(KDEDIR)/share/config/kdeglobals holds info
1231 // the current icons theme
1232 wxFileName configFile( kdedir, wxEmptyString );
1233 configFile.AppendDir( wxT("share") );
1234 configFile.AppendDir( wxT("config") );
1235 configFile.SetName( wxT("kdeglobals") );
d0ee33f5 1236
320c341a
VS
1237 wxTextFile config;
1238 if (configFile.FileExists() && config.Open(configFile.GetFullPath()))
10274336 1239 {
10274336 1240 // $(KDEDIR)/share/config -> $(KDEDIR)/share
7c2e5dec 1241 configFile.RemoveDir( configFile.GetDirCount() - 1 );
10274336
RR
1242 // $(KDEDIR)/share/ -> $(KDEDIR)/share/icons
1243 configFile.AppendDir( wxT("icons") );
1244
1245 // Check for entry
320c341a
VS
1246 wxString theme(wxT("default.kde"));
1247 size_t cnt = config.GetLineCount();
1248 for (size_t i = 0; i < cnt; i++)
1249 {
1250 if (config[i].StartsWith(wxT("Theme="), &theme/*rest*/))
1251 break;
1252 }
dfea7acc 1253
320c341a 1254 configFile.AppendDir(theme);
10274336
RR
1255 }
1256 else
1257 {
1258 // $(KDEDIR)/share/config -> $(KDEDIR)/share
dfea7acc
DS
1259 configFile.RemoveDir( configFile.GetDirCount() - 1 );
1260
10274336
RR
1261 // $(KDEDIR)/share/ -> $(KDEDIR)/share/icons
1262 configFile.AppendDir( wxT("icons") );
dfea7acc 1263
10274336
RR
1264 // $(KDEDIR)/share/icons -> $(KDEDIR)/share/icons/default.kde
1265 configFile.AppendDir( wxT("default.kde") );
1266 }
d0ee33f5 1267
10274336 1268 configFile.SetName( wxEmptyString );
16c587ca
RR
1269 configFile.AppendDir( wxT("32x32") );
1270 configFile.AppendDir( wxT("mimetypes") );
d0ee33f5 1271
10274336 1272 // Just try a few likely icons theme names
d0ee33f5 1273
7c2e5dec 1274 int pos = configFile.GetDirCount() - 3;
d0ee33f5 1275
10274336
RR
1276 if (!wxDir::Exists(configFile.GetPath()))
1277 {
16c587ca
RR
1278 configFile.RemoveDir( pos );
1279 configFile.InsertDir( pos, wxT("default.kde") );
10274336 1280 }
d0ee33f5 1281
10274336
RR
1282 if (!wxDir::Exists(configFile.GetPath()))
1283 {
16c587ca
RR
1284 configFile.RemoveDir( pos );
1285 configFile.InsertDir( pos, wxT("default") );
10274336 1286 }
d0ee33f5 1287
10274336
RR
1288 if (!wxDir::Exists(configFile.GetPath()))
1289 {
16c587ca
RR
1290 configFile.RemoveDir( pos );
1291 configFile.InsertDir( pos, wxT("crystalsvg") );
10274336 1292 }
d0ee33f5 1293
10274336
RR
1294 if (!wxDir::Exists(configFile.GetPath()))
1295 {
16c587ca
RR
1296 configFile.RemoveDir( pos );
1297 configFile.InsertDir( pos, wxT("crystal") );
10274336 1298 }
d0ee33f5 1299
10274336 1300 if (wxDir::Exists(configFile.GetPath()))
10274336 1301 icondirs.Add( configFile.GetFullPath() );
1d529ef7 1302 }
cdf339c9
VS
1303
1304 // settings in ~/.kde have maximal priority
2b5f62a0
VZ
1305 dirs.Add(wxGetHomeDir() + wxT("/.kde/share"));
1306 icondirs.Add(wxGetHomeDir() + wxT("/.kde/share/icons/"));
509a6196 1307
10274336 1308 if (kdedir)
509a6196 1309 {
2b5f62a0
VZ
1310 dirs.Add( wxString(kdedir) + wxT("/share") );
1311 icondirs.Add( wxString(kdedir) + wxT("/share/icons/") );
509a6196
VZ
1312 }
1313 else
1314 {
1315 // try to guess KDEDIR
dfea7acc
DS
1316 dirs.Add(wxT("/usr/share"));
1317 dirs.Add(wxT("/opt/kde/share"));
1318 icondirs.Add(wxT("/usr/share/icons/"));
1319 icondirs.Add(wxT("/usr/X11R6/share/icons/")); // Debian/Corel linux
1320 icondirs.Add(wxT("/opt/kde/share/icons/"));
509a6196
VZ
1321 }
1322
dfea7acc
DS
1323 if (!sExtraDir.empty())
1324 dirs.Add(sExtraDir);
2b813b73
VZ
1325 icondirs.Add(sExtraDir + wxT("/icons"));
1326
b9517a0a
VZ
1327 size_t nDirs = dirs.GetCount();
1328 for ( size_t nDir = 0; nDir < nDirs; nDir++ )
1329 {
2b813b73 1330 LoadKDELinkFilesFromDir(dirs[nDir], icondirs);
b9517a0a 1331 }
b9517a0a
VZ
1332}
1333
2b813b73
VZ
1334// ----------------------------------------------------------------------------
1335// wxFileTypeImpl (Unix)
1336// ----------------------------------------------------------------------------
1337
2b813b73 1338wxString wxFileTypeImpl::GetExpandedCommand(const wxString & verb, const wxFileType::MessageParameters& params) const
b9517a0a 1339{
2b813b73
VZ
1340 wxString sTmp;
1341 size_t i = 0;
678ebfcd 1342 while ( (i < m_index.GetCount() ) && sTmp.empty() )
b9517a0a 1343 {
dfea7acc
DS
1344 sTmp = m_manager->GetCommand( verb, m_index[i] );
1345 i++;
b9517a0a
VZ
1346 }
1347
2b813b73
VZ
1348 return wxFileType::ExpandCommand(sTmp, params);
1349}
b9517a0a 1350
da0766ab 1351bool wxFileTypeImpl::GetIcon(wxIconLocation *iconLoc) const
2b813b73
VZ
1352{
1353 wxString sTmp;
1354 size_t i = 0;
678ebfcd 1355 while ( (i < m_index.GetCount() ) && sTmp.empty() )
c786f763
VZ
1356 {
1357 sTmp = m_manager->m_aIcons[m_index[i]];
dfea7acc 1358 i++;
c786f763 1359 }
dfea7acc
DS
1360
1361 if ( sTmp.empty() )
d0ee33f5 1362 return false;
b9517a0a 1363
da0766ab 1364 if ( iconLoc )
c786f763 1365 {
a49686b4 1366 iconLoc->SetFileName(sTmp);
2b813b73 1367 }
c786f763 1368
d0ee33f5 1369 return true;
c786f763 1370}
2b813b73 1371
dfea7acc 1372bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const
2b813b73
VZ
1373{
1374 mimeTypes.Clear();
1375 for (size_t i = 0; i < m_index.GetCount(); i++)
1376 mimeTypes.Add(m_manager->m_aTypes[m_index[i]]);
dfea7acc 1377
d0ee33f5 1378 return true;
2b813b73
VZ
1379}
1380
2b813b73
VZ
1381size_t wxFileTypeImpl::GetAllCommands(wxArrayString *verbs,
1382 wxArrayString *commands,
1383 const wxFileType::MessageParameters& params) const
1384{
2b813b73
VZ
1385 wxString vrb, cmd, sTmp;
1386 size_t count = 0;
678ebfcd 1387 wxMimeTypeCommands * sPairs;
2b813b73
VZ
1388
1389 // verbs and commands have been cleared already in mimecmn.cpp...
1390 // if we find no entries in the exact match, try the inexact match
7c2e5dec 1391 for (size_t n = 0; ((count == 0) && (n < m_index.GetCount())); n++)
2b813b73
VZ
1392 {
1393 // list of verb = command pairs for this mimetype
1394 sPairs = m_manager->m_aEntries [m_index[n]];
1395 size_t i;
dfea7acc
DS
1396 for ( i = 0; i < sPairs->GetCount(); i++ )
1397 {
1398 vrb = sPairs->GetVerb(i);
7c2e5dec 1399 // some gnome entries have "." inside
dfea7acc
DS
1400 vrb = vrb.AfterLast(wxT('.'));
1401 cmd = sPairs->GetCmd(i);
1402 if (! cmd.empty() )
2b813b73 1403 {
dfea7acc 1404 cmd = wxFileType::ExpandCommand(cmd, params);
7c2e5dec 1405 count++;
dfea7acc
DS
1406 if ( vrb.IsSameAs(wxT("open")))
1407 {
d6a7ca31
VZ
1408 if ( verbs )
1409 verbs->Insert(vrb, 0u);
1410 if ( commands )
1411 commands ->Insert(cmd, 0u);
dfea7acc
DS
1412 }
1413 else
1414 {
d6a7ca31
VZ
1415 if ( verbs )
1416 verbs->Add(vrb);
1417 if ( commands )
1418 commands->Add(cmd);
dfea7acc
DS
1419 }
1420 }
2b813b73 1421 }
2b813b73 1422 }
2b813b73 1423
dfea7acc 1424 return count;
2b813b73
VZ
1425}
1426
1427bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
1428{
1429 wxString strExtensions = m_manager->GetExtension(m_index[0]);
1430 extensions.Empty();
1431
1c4cd9e0 1432 // one extension in the space or comma-delimited list
2b813b73 1433 wxString strExt;
dfea7acc
DS
1434 for ( const wxChar *p = strExtensions; /* nothing */; p++ )
1435 {
1436 if ( *p == wxT(' ') || *p == wxT(',') || *p == wxT('\0') )
1437 {
1438 if ( !strExt.empty() )
1439 {
2b813b73
VZ
1440 extensions.Add(strExt);
1441 strExt.Empty();
1442 }
7c2e5dec
DS
1443 //else: repeated spaces
1444 // (shouldn't happen, but it's not that important if it does happen)
2b813b73
VZ
1445
1446 if ( *p == wxT('\0') )
1447 break;
1448 }
dfea7acc
DS
1449 else if ( *p == wxT('.') )
1450 {
2b813b73 1451 // remove the dot from extension (but only if it's the first char)
dfea7acc
DS
1452 if ( !strExt.empty() )
1453 {
2b813b73
VZ
1454 strExt += wxT('.');
1455 }
1456 //else: no, don't append it
1457 }
dfea7acc
DS
1458 else
1459 {
2b813b73
VZ
1460 strExt += *p;
1461 }
1462 }
1463
d0ee33f5 1464 return true;
2b813b73
VZ
1465}
1466
7c2e5dec 1467// set an arbitrary command:
2b813b73 1468// could adjust the code to ask confirmation if it already exists and
d0ee33f5 1469// overwriteprompt is true, but this is currently ignored as *Associate* has
2b813b73 1470// no overwrite prompt
17a1ebd1
VZ
1471bool
1472wxFileTypeImpl::SetCommand(const wxString& cmd,
1473 const wxString& verb,
1474 bool WXUNUSED(overwriteprompt))
d84afea9 1475{
2b813b73 1476 wxArrayString strExtensions;
678ebfcd 1477 wxString strDesc, strIcon;
2b813b73 1478
2b813b73 1479 wxArrayString strTypes;
dfea7acc 1480 GetMimeTypes(strTypes);
926ce9e3 1481 if ( strTypes.IsEmpty() )
dfea7acc 1482 return false;
2b813b73 1483
926ce9e3
VZ
1484 wxMimeTypeCommands *entry = new wxMimeTypeCommands();
1485 entry->Add(verb + wxT("=") + cmd + wxT(" %s "));
1486
dfea7acc 1487 bool ok = true;
926ce9e3 1488 for ( size_t i = 0; i < strTypes.GetCount(); i++ )
d84afea9 1489 {
dfea7acc
DS
1490 if (!m_manager->DoAssociation(strTypes[i], strIcon, entry, strExtensions, strDesc))
1491 ok = false;
d84afea9 1492 }
2b813b73 1493
dfea7acc 1494 return ok;
d84afea9 1495}
2b813b73
VZ
1496
1497// ignore index on the grouds that we only have one icon in a Unix file
17a1ebd1 1498bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int WXUNUSED(index))
d84afea9 1499{
dfea7acc
DS
1500 if (strIcon.empty())
1501 return false;
1502
2b813b73
VZ
1503 wxArrayString strExtensions;
1504 wxString strDesc;
1505
2b813b73 1506 wxArrayString strTypes;
dfea7acc 1507 GetMimeTypes(strTypes);
cb0b7b7d 1508 if ( strTypes.IsEmpty() )
dfea7acc 1509 return false;
2b813b73 1510
cb0b7b7d 1511 wxMimeTypeCommands *entry = new wxMimeTypeCommands();
dfea7acc 1512 bool ok = true;
cb0b7b7d 1513 for ( size_t i = 0; i < strTypes.GetCount(); i++ )
d84afea9 1514 {
cb0b7b7d
VZ
1515 if ( !m_manager->DoAssociation
1516 (
1517 strTypes[i],
1518 strIcon,
1519 entry,
1520 strExtensions,
1521 strDesc
1522 ) )
1523 {
dfea7acc 1524 ok = false;
cb0b7b7d 1525 }
d84afea9 1526 }
2b813b73 1527
dfea7acc 1528 return ok;
d84afea9
GD
1529}
1530
2b813b73
VZ
1531// ----------------------------------------------------------------------------
1532// wxMimeTypesManagerImpl (Unix)
1533// ----------------------------------------------------------------------------
1534
2b813b73
VZ
1535wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
1536{
d0ee33f5 1537 m_initialized = false;
2b813b73
VZ
1538 m_mailcapStylesInited = 0;
1539}
1540
1d529ef7
RR
1541void wxMimeTypesManagerImpl::InitIfNeeded()
1542{
1543 if ( !m_initialized )
1544 {
1545 // set the flag first to prevent recursion
d0ee33f5
WS
1546 m_initialized = true;
1547
dfea7acc
DS
1548#if 1
1549 Initialize();
1550#else
10274336 1551 wxString wm = wxGetenv( wxT("WINDOWMANAGER") );
d0ee33f5 1552
10274336 1553 if (wm.Find( wxT("kde") ) != wxNOT_FOUND)
dfea7acc 1554 Initialize( wxMAILCAP_KDE | wxMAILCAP_STANDARD );
10274336 1555 else if (wm.Find( wxT("gnome") ) != wxNOT_FOUND)
dfea7acc 1556 Initialize( wxMAILCAP_GNOME | wxMAILCAP_STANDARD );
10274336 1557 else
dfea7acc 1558 Initialize();
1d529ef7 1559#endif
1d529ef7
RR
1560 }
1561}
1562
2b813b73
VZ
1563// read system and user mailcaps and other files
1564void wxMimeTypesManagerImpl::Initialize(int mailcapStyles,
1565 const wxString& sExtraDir)
1566{
1567 // read mimecap amd mime.types
a06c1b9b
VZ
1568 if ( (mailcapStyles & wxMAILCAP_NETSCAPE) ||
1569 (mailcapStyles & wxMAILCAP_STANDARD) )
2b813b73
VZ
1570 GetMimeInfo(sExtraDir);
1571
1572 // read GNOME tables
1d529ef7 1573 if (mailcapStyles & wxMAILCAP_GNOME)
2b813b73
VZ
1574 GetGnomeMimeInfo(sExtraDir);
1575
1576 // read KDE tables
1d529ef7 1577 if (mailcapStyles & wxMAILCAP_KDE)
2b813b73
VZ
1578 GetKDEMimeInfo(sExtraDir);
1579
1580 m_mailcapStylesInited |= mailcapStyles;
1581}
1582
1583// clear data so you can read another group of WM files
1584void wxMimeTypesManagerImpl::ClearData()
1585{
dfea7acc
DS
1586 m_aTypes.Clear();
1587 m_aIcons.Clear();
1588 m_aExtensions.Clear();
1589 m_aDescriptions.Clear();
2b813b73 1590
2b5f62a0 1591 WX_CLEAR_ARRAY(m_aEntries);
678ebfcd
VZ
1592 m_aEntries.Empty();
1593
2b813b73
VZ
1594 m_mailcapStylesInited = 0;
1595}
1596
1597wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
1598{
678ebfcd 1599 ClearData();
2b813b73
VZ
1600}
1601
dfea7acc 1602void wxMimeTypesManagerImpl::GetMimeInfo(const wxString& sExtraDir)
2b813b73
VZ
1603{
1604 // read this for netscape or Metamail formats
1605
1606 // directories where we look for mailcap and mime.types by default
1607 // used by netscape and pine and other mailers, using 2 different formats!
1608
1609 // (taken from metamail(1) sources)
1610 //
1611 // although RFC 1524 specifies the search path of
1612 // /etc/:/usr/etc:/usr/local/etc only, it doesn't hurt to search in more
1613 // places - OTOH, the RFC also says that this path can be changed with
1614 // MAILCAPS environment variable (containing the colon separated full
1615 // filenames to try) which is not done yet (TODO?)
1616
1617 wxString strHome = wxGetenv(wxT("HOME"));
1618
1619 wxArrayString dirs;
dfea7acc
DS
1620 dirs.Add( strHome + wxT("/.") );
1621 dirs.Add( wxT("/etc/") );
1622 dirs.Add( wxT("/usr/etc/") );
1623 dirs.Add( wxT("/usr/local/etc/") );
1624 dirs.Add( wxT("/etc/mail/") );
1625 dirs.Add( wxT("/usr/public/lib/") );
1626 if (!sExtraDir.empty())
1627 dirs.Add( sExtraDir + wxT("/") );
2b813b73
VZ
1628
1629 size_t nDirs = dirs.GetCount();
1630 for ( size_t nDir = 0; nDir < nDirs; nDir++ )
1631 {
1632 wxString file = dirs[nDir] + wxT("mailcap");
dfea7acc
DS
1633 if ( wxFile::Exists(file) )
1634 {
2b813b73
VZ
1635 ReadMailcap(file);
1636 }
1637
1638 file = dirs[nDir] + wxT("mime.types");
dfea7acc
DS
1639 if ( wxFile::Exists(file) )
1640 {
2b813b73
VZ
1641 ReadMimeTypes(file);
1642 }
1643 }
2b813b73
VZ
1644}
1645
dfea7acc 1646bool wxMimeTypesManagerImpl::WriteToMimeTypes(int index, bool delete_index)
2b813b73
VZ
1647{
1648 // check we have the right manager
a06c1b9b 1649 if (! ( m_mailcapStylesInited & wxMAILCAP_STANDARD) )
d0ee33f5 1650 return false;
2b813b73
VZ
1651
1652 bool bTemp;
1653 wxString strHome = wxGetenv(wxT("HOME"));
1654
1655 // and now the users mailcap
1656 wxString strUserMailcap = strHome + wxT("/.mime.types");
1657
1658 wxMimeTextFile file;
1659 if ( wxFile::Exists(strUserMailcap) )
1660 {
7c2e5dec 1661 bTemp = file.Open(strUserMailcap);
2b813b73
VZ
1662 }
1663 else
1664 {
dfea7acc
DS
1665 if (delete_index)
1666 return false;
1667
2b813b73
VZ
1668 bTemp = file.Create(strUserMailcap);
1669 }
dfea7acc 1670
2b813b73
VZ
1671 if (bTemp)
1672 {
1673 int nIndex;
d0ee33f5 1674 // test for netscape's header and return false if its found
dfea7acc 1675 nIndex = file.pIndexOf(wxT("#--Netscape"));
2b813b73
VZ
1676 if (nIndex != wxNOT_FOUND)
1677 {
d0ee33f5
WS
1678 wxASSERT_MSG(false,wxT("Error in .mime.types \nTrying to mix Netscape and Metamail formats\nFile not modiifed"));
1679 return false;
2b813b73 1680 }
dfea7acc 1681
2b813b73
VZ
1682 // write it in alternative format
1683 // get rid of unwanted entries
1684 wxString strType = m_aTypes[index];
dfea7acc
DS
1685 nIndex = file.pIndexOf(strType);
1686
2b813b73 1687 // get rid of all the unwanted entries...
dfea7acc
DS
1688 if (nIndex != wxNOT_FOUND)
1689 file.CommentLine(nIndex);
2b813b73
VZ
1690
1691 if (!delete_index)
1692 {
1693 // add the new entries in
7c2e5dec 1694 wxString sTmp = strType.Append( wxT(' '), 40 - strType.Len() );
2b813b73 1695 sTmp = sTmp + m_aExtensions[index];
dfea7acc 1696 file.AddLine(sTmp);
2b813b73
VZ
1697 }
1698
dfea7acc
DS
1699 bTemp = file.Write();
1700 file.Close();
2b813b73 1701 }
dfea7acc 1702
2b813b73
VZ
1703 return bTemp;
1704}
1705
dfea7acc 1706bool wxMimeTypesManagerImpl::WriteToNSMimeTypes(int index, bool delete_index)
2b813b73
VZ
1707{
1708 //check we have the right managers
1709 if (! ( m_mailcapStylesInited & wxMAILCAP_NETSCAPE) )
d0ee33f5 1710 return false;
2b813b73
VZ
1711
1712 bool bTemp;
1713 wxString strHome = wxGetenv(wxT("HOME"));
1714
1715 // and now the users mailcap
1716 wxString strUserMailcap = strHome + wxT("/.mime.types");
1717
1718 wxMimeTextFile file;
1719 if ( wxFile::Exists(strUserMailcap) )
1720 {
7c2e5dec 1721 bTemp = file.Open(strUserMailcap);
2b813b73
VZ
1722 }
1723 else
1724 {
dfea7acc
DS
1725 if (delete_index)
1726 return false;
1727
2b813b73
VZ
1728 bTemp = file.Create(strUserMailcap);
1729 }
dfea7acc 1730
2b813b73
VZ
1731 if (bTemp)
1732 {
2b813b73
VZ
1733 // write it in the format that Netscape uses
1734 int nIndex;
1735 // test for netscape's header and insert if required...
d0ee33f5 1736 // this is a comment so use true
dfea7acc 1737 nIndex = file.pIndexOf(wxT("#--Netscape"), true);
2b813b73
VZ
1738 if (nIndex == wxNOT_FOUND)
1739 {
1740 // either empty file or metamail format
1741 // at present we can't cope with mixed formats, so exit to preseve
1742 // metamail entreies
dfea7acc 1743 if (file.GetLineCount() > 0)
2b813b73 1744 {
d0ee33f5
WS
1745 wxASSERT_MSG(false, wxT(".mime.types File not in Netscape format\nNo entries written to\n.mime.types or to .mailcap"));
1746 return false;
2b813b73 1747 }
dfea7acc
DS
1748
1749 file.InsertLine(wxT( "#--Netscape Communications Corporation MIME Information" ), 0);
2b813b73
VZ
1750 nIndex = 0;
1751 }
1752
1753 wxString strType = wxT("type=") + m_aTypes[index];
dfea7acc
DS
1754 nIndex = file.pIndexOf(strType);
1755
2b813b73
VZ
1756 // get rid of all the unwanted entries...
1757 if (nIndex != wxNOT_FOUND)
1758 {
1759 wxString sOld = file[nIndex];
1760 while ( (sOld.Contains(wxT("\\"))) && (nIndex < (int) file.GetLineCount()) )
1761 {
1762 file.CommentLine(nIndex);
1763 sOld = file[nIndex];
dfea7acc 1764
2b813b73 1765 wxLogTrace(TRACE_MIME, wxT("--- Deleting from mime.types line '%d %s' ---"), nIndex, sOld.c_str());
dfea7acc
DS
1766
1767 nIndex++;
2b813b73 1768 }
dfea7acc
DS
1769
1770 if (nIndex < (int) file.GetLineCount())
1771 file.CommentLine(nIndex);
2b813b73 1772 }
dfea7acc
DS
1773 else
1774 nIndex = (int) file.GetLineCount();
2b813b73
VZ
1775
1776 wxString sTmp = strType + wxT(" \\");
dfea7acc
DS
1777 if (!delete_index)
1778 file.InsertLine(sTmp, nIndex);
1779
678ebfcd 1780 if ( ! m_aDescriptions.Item(index).empty() )
2b813b73 1781 {
dfea7acc 1782 sTmp = wxT("desc=\"") + m_aDescriptions[index]+ wxT("\" \\"); //.trim ??
2b813b73
VZ
1783 if (!delete_index)
1784 {
7c2e5dec 1785 nIndex++;
dfea7acc 1786 file.InsertLine(sTmp, nIndex);
2b813b73
VZ
1787 }
1788 }
dfea7acc 1789
7c2e5dec 1790 wxString sExts = m_aExtensions.Item(index);
dfea7acc 1791 sTmp = wxT("exts=\"") + sExts.Trim(false).Trim() + wxT("\"");
2b813b73
VZ
1792 if (!delete_index)
1793 {
7c2e5dec 1794 nIndex++;
dfea7acc 1795 file.InsertLine(sTmp, nIndex);
2b813b73
VZ
1796 }
1797
dfea7acc
DS
1798 bTemp = file.Write();
1799 file.Close();
2b813b73 1800 }
dfea7acc 1801
2b813b73
VZ
1802 return bTemp;
1803}
1804
dfea7acc 1805bool wxMimeTypesManagerImpl::WriteToMailCap(int index, bool delete_index)
2b813b73
VZ
1806{
1807 //check we have the right managers
1808 if ( !( ( m_mailcapStylesInited & wxMAILCAP_NETSCAPE) ||
a06c1b9b 1809 ( m_mailcapStylesInited & wxMAILCAP_STANDARD) ) )
d0ee33f5 1810 return false;
2b813b73 1811
7c2e5dec 1812 bool bTemp = false;
2b813b73
VZ
1813 wxString strHome = wxGetenv(wxT("HOME"));
1814
1815 // and now the users mailcap
1816 wxString strUserMailcap = strHome + wxT("/.mailcap");
1817
1818 wxMimeTextFile file;
1819 if ( wxFile::Exists(strUserMailcap) )
1820 {
7c2e5dec 1821 bTemp = file.Open(strUserMailcap);
2b813b73 1822 }
be0a33fb 1823 else
2b813b73 1824 {
dfea7acc
DS
1825 if (delete_index)
1826 return false;
1827
2b813b73
VZ
1828 bTemp = file.Create(strUserMailcap);
1829 }
dfea7acc 1830
2b813b73
VZ
1831 if (bTemp)
1832 {
1833 // now got a file we can write to ....
678ebfcd
VZ
1834 wxMimeTypeCommands * entries = m_aEntries[index];
1835 size_t iOpen;
dfea7acc 1836 wxString sCmd = entries->GetCommandForVerb(wxT("open"), &iOpen);
2b813b73
VZ
1837 wxString sTmp;
1838
1839 sTmp = m_aTypes[index];
1840 wxString sOld;
1841 int nIndex = file.pIndexOf(sTmp);
7c2e5dec 1842
2b813b73
VZ
1843 // get rid of all the unwanted entries...
1844 if (nIndex == wxNOT_FOUND)
1845 {
1846 nIndex = (int) file.GetLineCount();
1847 }
1848 else
1849 {
1850 sOld = file[nIndex];
1851 wxLogTrace(TRACE_MIME, wxT("--- Deleting from mailcap line '%d' ---"), nIndex);
6dc6fda6 1852
2b813b73
VZ
1853 while ( (sOld.Contains(wxT("\\"))) && (nIndex < (int) file.GetLineCount()) )
1854 {
1855 file.CommentLine(nIndex);
dfea7acc
DS
1856 if (nIndex < (int) file.GetLineCount())
1857 sOld = sOld + file[nIndex];
2b813b73 1858 }
7c2e5dec 1859
dfea7acc
DS
1860 if (nIndex < (int)
1861 file.GetLineCount()) file.CommentLine(nIndex);
2b813b73 1862 }
6dc6fda6 1863
678ebfcd 1864 sTmp = sTmp + wxT(";") + sCmd; //includes wxT(" %s ");
b9517a0a 1865
2b813b73 1866 // write it in the format that Netscape uses (default)
7c2e5dec 1867 if (! ( m_mailcapStylesInited & wxMAILCAP_STANDARD ) )
2b813b73 1868 {
dfea7acc
DS
1869 if (! delete_index)
1870 file.InsertLine(sTmp, nIndex);
1871 nIndex++;
2b813b73 1872 }
2b813b73
VZ
1873 else
1874 {
dfea7acc
DS
1875 // write extended format
1876
1877 // TODO - FIX this code:
2b813b73
VZ
1878 // ii) lost entries
1879 // sOld holds all the entries, but our data store only has some
1880 // eg test= is not stored
1881
1882 // so far we have written the mimetype and command out
dfea7acc
DS
1883 wxStringTokenizer sT(sOld, wxT(";\\"));
1884 if (sT.CountTokens() > 2)
2b813b73
VZ
1885 {
1886 // first one mimetype; second one command, rest unknown...
1887 wxString s;
1888 s = sT.GetNextToken();
1889 s = sT.GetNextToken();
1890
1891 // first unknown
1892 s = sT.GetNextToken();
678ebfcd 1893 while ( ! s.empty() )
2b813b73 1894 {
d0ee33f5 1895 bool bKnownToken = false;
dfea7acc
DS
1896 if (s.Contains(wxT("description=")))
1897 bKnownToken = true;
1898 if (s.Contains(wxT("x11-bitmap=")))
1899 bKnownToken = true;
7c2e5dec 1900
2b813b73
VZ
1901 size_t i;
1902 for (i=0; i < entries->GetCount(); i++)
1903 {
dfea7acc
DS
1904 if (s.Contains(entries->GetVerb(i)))
1905 bKnownToken = true;
2b813b73 1906 }
dfea7acc 1907
2b813b73
VZ
1908 if (!bKnownToken)
1909 {
1910 sTmp = sTmp + wxT("; \\");
dfea7acc 1911 file.InsertLine(sTmp, nIndex);
2b813b73
VZ
1912 sTmp = s;
1913 }
cdf339c9 1914
dfea7acc
DS
1915 s = sT.GetNextToken();
1916 }
2b813b73 1917 }
5bd3a2da 1918
678ebfcd 1919 if (! m_aDescriptions[index].empty() )
2b813b73
VZ
1920 {
1921 sTmp = sTmp + wxT("; \\");
dfea7acc 1922 file.InsertLine(sTmp, nIndex);
7c2e5dec 1923 nIndex++;
2b813b73
VZ
1924 sTmp = wxT(" description=\"") + m_aDescriptions[index] + wxT("\"");
1925 }
cdf339c9 1926
678ebfcd 1927 if (! m_aIcons[index].empty() )
2b813b73
VZ
1928 {
1929 sTmp = sTmp + wxT("; \\");
dfea7acc 1930 file.InsertLine(sTmp, nIndex);
7c2e5dec 1931 nIndex++;
2b813b73
VZ
1932 sTmp = wxT(" x11-bitmap=\"") + m_aIcons[index] + wxT("\"");
1933 }
cdf339c9 1934
dfea7acc 1935 if ( entries->GetCount() > 1 )
2b813b73
VZ
1936 {
1937 size_t i;
1938 for (i=0; i < entries->GetCount(); i++)
1939 if ( i != iOpen )
1940 {
1941 sTmp = sTmp + wxT("; \\");
dfea7acc 1942 file.InsertLine(sTmp, nIndex);
7c2e5dec 1943 nIndex++;
678ebfcd 1944 sTmp = wxT(" ") + entries->GetVerbCmd(i);
2b813b73
VZ
1945 }
1946 }
b9517a0a 1947
dfea7acc
DS
1948 file.InsertLine(sTmp, nIndex);
1949 nIndex++;
b13d92d1 1950 }
dfea7acc
DS
1951
1952 bTemp = file.Write();
1953 file.Close();
b13d92d1 1954 }
dfea7acc 1955
2b813b73 1956 return bTemp;
b13d92d1
VZ
1957}
1958
dfea7acc 1959wxFileType * wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
b9517a0a 1960{
2b813b73 1961 InitIfNeeded();
b9517a0a 1962
dfea7acc
DS
1963 wxString strType = ftInfo.GetMimeType();
1964 wxString strDesc = ftInfo.GetDescription();
1965 wxString strIcon = ftInfo.GetIconFile();
2b813b73 1966
dfea7acc 1967 wxMimeTypeCommands *entry = new wxMimeTypeCommands();
2b813b73 1968
678ebfcd 1969 if ( ! ftInfo.GetOpenCommand().empty())
dfea7acc
DS
1970 entry->Add(wxT("open=") + ftInfo.GetOpenCommand() + wxT(" %s "));
1971 if ( ! ftInfo.GetPrintCommand().empty())
1972 entry->Add(wxT("print=") + ftInfo.GetPrintCommand() + wxT(" %s "));
2b813b73
VZ
1973
1974 // now find where these extensions are in the data store and remove them
dfea7acc 1975 wxArrayString sA_Exts = ftInfo.GetExtensions();
2b813b73
VZ
1976 wxString sExt, sExtStore;
1977 size_t i, nIndex;
1978 for (i=0; i < sA_Exts.GetCount(); i++)
dfea7acc 1979 {
2b813b73 1980 sExt = sA_Exts.Item(i);
dfea7acc
DS
1981
1982 // clean up to just a space before and after
d0ee33f5 1983 sExt.Trim().Trim(false);
2b813b73 1984 sExt = wxT(' ') + sExt + wxT(' ');
7c2e5dec 1985 for (nIndex = 0; nIndex < m_aExtensions.GetCount(); nIndex++)
dfea7acc 1986 {
2b813b73 1987 sExtStore = m_aExtensions.Item(nIndex);
dfea7acc
DS
1988 if (sExtStore.Replace(sExt, wxT(" ") ) > 0)
1989 m_aExtensions.Item(nIndex) = sExtStore;
1990 }
2b813b73 1991 }
b9517a0a 1992
dfea7acc 1993 if ( !DoAssociation(strType, strIcon, entry, sA_Exts, strDesc) )
2b813b73 1994 return NULL;
4d2976ad 1995
2b813b73 1996 return GetFileTypeFromMimeType(strType);
4d2976ad
VS
1997}
1998
2b813b73
VZ
1999bool wxMimeTypesManagerImpl::DoAssociation(const wxString& strType,
2000 const wxString& strIcon,
678ebfcd 2001 wxMimeTypeCommands *entry,
2b813b73
VZ
2002 const wxArrayString& strExtensions,
2003 const wxString& strDesc)
b13d92d1 2004{
d0ee33f5 2005 int nIndex = AddToMimeData(strType, strIcon, entry, strExtensions, strDesc, true);
b13d92d1 2006
2b813b73 2007 if ( nIndex == wxNOT_FOUND )
d0ee33f5 2008 return false;
b13d92d1 2009
dfea7acc 2010 return WriteMimeInfo(nIndex, false);
b13d92d1
VZ
2011}
2012
2b813b73 2013bool wxMimeTypesManagerImpl::WriteMimeInfo(int nIndex, bool delete_mime )
b13d92d1 2014{
d0ee33f5 2015 bool ok = true;
b13d92d1 2016
a06c1b9b 2017 if ( m_mailcapStylesInited & wxMAILCAP_STANDARD )
2b813b73
VZ
2018 {
2019 // write in metamail format;
dfea7acc
DS
2020 if (WriteToMimeTypes(nIndex, delete_mime) )
2021 if ( WriteToMailCap(nIndex, delete_mime) )
d0ee33f5 2022 ok = false;
b13d92d1 2023 }
dfea7acc 2024
2b813b73 2025 if ( m_mailcapStylesInited & wxMAILCAP_NETSCAPE )
b9517a0a 2026 {
2b813b73 2027 // write in netsacpe format;
dfea7acc
DS
2028 if (WriteToNSMimeTypes(nIndex, delete_mime) )
2029 if ( WriteToMailCap(nIndex, delete_mime) )
d0ee33f5 2030 ok = false;
2b813b73 2031 }
dfea7acc 2032
2b813b73
VZ
2033 if (m_mailcapStylesInited & wxMAILCAP_GNOME)
2034 {
2035 // write in Gnome format;
dfea7acc
DS
2036 if (WriteGnomeMimeFile(nIndex, delete_mime) )
2037 if (WriteGnomeKeyFile(nIndex, delete_mime) )
d0ee33f5 2038 ok = false;
2b813b73 2039 }
dfea7acc 2040
2b813b73
VZ
2041 if (m_mailcapStylesInited & wxMAILCAP_KDE)
2042 {
2043 // write in KDE format;
dfea7acc 2044 if (WriteKDEMimeFile(nIndex, delete_mime) )
d0ee33f5 2045 ok = false;
b9517a0a
VZ
2046 }
2047
2b813b73 2048 return ok;
a6c65e88
VZ
2049}
2050
2b813b73
VZ
2051int wxMimeTypesManagerImpl::AddToMimeData(const wxString& strType,
2052 const wxString& strIcon,
678ebfcd 2053 wxMimeTypeCommands *entry,
2b813b73
VZ
2054 const wxArrayString& strExtensions,
2055 const wxString& strDesc,
678ebfcd 2056 bool replaceExisting)
b13d92d1 2057{
2b813b73 2058 InitIfNeeded();
b13d92d1 2059
2b813b73 2060 // ensure mimetype is always lower case
678ebfcd
VZ
2061 wxString mimeType = strType.Lower();
2062
2063 // is this a known MIME type?
2b813b73
VZ
2064 int nIndex = m_aTypes.Index(mimeType);
2065 if ( nIndex == wxNOT_FOUND )
2066 {
2067 // new file type
2068 m_aTypes.Add(mimeType);
2069 m_aIcons.Add(strIcon);
678ebfcd 2070 m_aEntries.Add(entry ? entry : new wxMimeTypeCommands);
b13d92d1 2071
678ebfcd 2072 // change nIndex so we can use it below to add the extensions
df5168c4 2073 m_aExtensions.Add(wxEmptyString);
b8d61021 2074 nIndex = m_aExtensions.size() - 1;
678ebfcd
VZ
2075
2076 m_aDescriptions.Add(strDesc);
b13d92d1 2077 }
678ebfcd 2078 else // yes, we already have it
2b813b73 2079 {
678ebfcd 2080 if ( replaceExisting )
2b813b73
VZ
2081 {
2082 // if new description change it
678ebfcd 2083 if ( !strDesc.empty())
2b813b73
VZ
2084 m_aDescriptions[nIndex] = strDesc;
2085
2086 // if new icon change it
678ebfcd 2087 if ( !strIcon.empty())
2b813b73
VZ
2088 m_aIcons[nIndex] = strIcon;
2089
678ebfcd
VZ
2090 if ( entry )
2091 {
2092 delete m_aEntries[nIndex];
2093 m_aEntries[nIndex] = entry;
2094 }
2b813b73 2095 }
678ebfcd 2096 else // add data we don't already have ...
2b813b73 2097 {
2b813b73 2098 // if new description add only if none
678ebfcd 2099 if ( m_aDescriptions[nIndex].empty() )
2b813b73
VZ
2100 m_aDescriptions[nIndex] = strDesc;
2101
2102 // if new icon and no existing icon
dfea7acc 2103 if ( m_aIcons[nIndex].empty() )
2b813b73
VZ
2104 m_aIcons[nIndex] = strIcon;
2105
2b813b73 2106 // add any new entries...
678ebfcd 2107 if ( entry )
2b813b73 2108 {
7c2e5dec 2109 wxMimeTypeCommands *entryOld = m_aEntries[nIndex];
678ebfcd
VZ
2110
2111 size_t count = entry->GetCount();
2112 for ( size_t i = 0; i < count; i++ )
2113 {
2114 const wxString& verb = entry->GetVerb(i);
2115 if ( !entryOld->HasVerb(verb) )
2116 {
2117 entryOld->AddOrReplaceVerb(verb, entry->GetCmd(i));
2118 }
2119 }
2b293fc7
VZ
2120
2121 // as we don't store it anywhere, it won't be deleted later as
2122 // usual -- do it immediately instead
2123 delete entry;
2b813b73
VZ
2124 }
2125 }
b13d92d1 2126 }
4d2976ad 2127
678ebfcd
VZ
2128 // always add the extensions to this mimetype
2129 wxString& exts = m_aExtensions[nIndex];
2130
2131 // add all extensions we don't have yet
2132 size_t count = strExtensions.GetCount();
2133 for ( size_t i = 0; i < count; i++ )
2134 {
dfea7acc 2135 wxString ext = strExtensions[i] + wxT(' ');
678ebfcd
VZ
2136
2137 if ( exts.Find(ext) == wxNOT_FOUND )
2138 {
2139 exts += ext;
2140 }
2141 }
2142
2b813b73
VZ
2143 // check data integrity
2144 wxASSERT( m_aTypes.Count() == m_aEntries.Count() &&
678ebfcd
VZ
2145 m_aTypes.Count() == m_aExtensions.Count() &&
2146 m_aTypes.Count() == m_aIcons.Count() &&
2147 m_aTypes.Count() == m_aDescriptions.Count() );
cf471cab 2148
2b813b73 2149 return nIndex;
cf471cab
VS
2150}
2151
dfea7acc 2152wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
b13d92d1 2153{
678ebfcd 2154 if (ext.empty() )
2b813b73
VZ
2155 return NULL;
2156
a6c65e88
VZ
2157 InitIfNeeded();
2158
1ee17e1c 2159 size_t count = m_aExtensions.GetCount();
2b813b73 2160 for ( size_t n = 0; n < count; n++ )
678ebfcd 2161 {
dfea7acc 2162 wxStringTokenizer tk(m_aExtensions[n], wxT(' '));
1ee17e1c 2163
678ebfcd
VZ
2164 while ( tk.HasMoreTokens() )
2165 {
1ee17e1c 2166 // consider extensions as not being case-sensitive
d0ee33f5 2167 if ( tk.GetNextToken().IsSameAs(ext, false /* no case */) )
678ebfcd 2168 {
1ee17e1c 2169 // found
678ebfcd 2170 wxFileType *fileType = new wxFileType;
1ee17e1c 2171 fileType->m_impl->Init(this, n);
678ebfcd
VZ
2172
2173 return fileType;
1ee17e1c
VZ
2174 }
2175 }
2176 }
b13d92d1 2177
678ebfcd 2178 return NULL;
b13d92d1
VZ
2179}
2180
7c2e5dec 2181wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
b13d92d1 2182{
a6c65e88
VZ
2183 InitIfNeeded();
2184
2b813b73 2185 wxFileType * fileType = NULL;
b13d92d1
VZ
2186 // mime types are not case-sensitive
2187 wxString mimetype(mimeType);
2188 mimetype.MakeLower();
2189
2190 // first look for an exact match
2191 int index = m_aTypes.Index(mimetype);
2b813b73
VZ
2192 if ( index != wxNOT_FOUND )
2193 {
2194 fileType = new wxFileType;
2195 fileType->m_impl->Init(this, index);
2196 }
2197
2198 // then try to find "text/*" as match for "text/plain" (for example)
2199 // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return
2200 // the whole string - ok.
2201
2202 index = wxNOT_FOUND;
2203 wxString strCategory = mimetype.BeforeFirst(wxT('/'));
2204
2205 size_t nCount = m_aTypes.Count();
dfea7acc
DS
2206 for ( size_t n = 0; n < nCount; n++ )
2207 {
2b813b73 2208 if ( (m_aTypes[n].BeforeFirst(wxT('/')) == strCategory ) &&
dfea7acc
DS
2209 m_aTypes[n].AfterFirst(wxT('/')) == wxT("*") )
2210 {
2b813b73
VZ
2211 index = n;
2212 break;
b13d92d1
VZ
2213 }
2214 }
2215
2b813b73 2216 if ( index != wxNOT_FOUND )
dfea7acc
DS
2217 {
2218 // don't throw away fileType that was already found
2219 if (!fileType)
7bc5ddc6 2220 fileType = new wxFileType;
b13d92d1 2221 fileType->m_impl->Init(this, index);
b13d92d1 2222 }
dfea7acc 2223
2b813b73
VZ
2224 return fileType;
2225}
2226
2b813b73
VZ
2227wxString wxMimeTypesManagerImpl::GetCommand(const wxString & verb, size_t nIndex) const
2228{
2229 wxString command, testcmd, sV, sTmp;
2230 sV = verb + wxT("=");
dfea7acc 2231
2b813b73 2232 // list of verb = command pairs for this mimetype
678ebfcd 2233 wxMimeTypeCommands * sPairs = m_aEntries [nIndex];
2b813b73
VZ
2234
2235 size_t i;
678ebfcd 2236 for ( i = 0; i < sPairs->GetCount (); i++ )
2b813b73 2237 {
678ebfcd
VZ
2238 sTmp = sPairs->GetVerbCmd (i);
2239 if ( sTmp.Contains(sV) )
2240 command = sTmp.AfterFirst(wxT('='));
b13d92d1 2241 }
dfea7acc 2242
2b813b73 2243 return command;
b13d92d1
VZ
2244}
2245
8e124873
VZ
2246void wxMimeTypesManagerImpl::AddFallback(const wxFileTypeInfo& filetype)
2247{
a6c65e88
VZ
2248 InitIfNeeded();
2249
3f1aaa16 2250 wxString extensions;
8e124873
VZ
2251 const wxArrayString& exts = filetype.GetExtensions();
2252 size_t nExts = exts.GetCount();
dfea7acc
DS
2253 for ( size_t nExt = 0; nExt < nExts; nExt++ )
2254 {
2255 if ( nExt > 0 )
223d09f6 2256 extensions += wxT(' ');
dfea7acc 2257
8e124873
VZ
2258 extensions += exts[nExt];
2259 }
2260
2261 AddMimeTypeInfo(filetype.GetMimeType(),
2262 extensions,
2263 filetype.GetDescription());
2264
2265 AddMailcapInfo(filetype.GetMimeType(),
2266 filetype.GetOpenCommand(),
2267 filetype.GetPrintCommand(),
223d09f6 2268 wxT(""),
8e124873
VZ
2269 filetype.GetDescription());
2270}
2271
2272void wxMimeTypesManagerImpl::AddMimeTypeInfo(const wxString& strMimeType,
2273 const wxString& strExtensions,
2274 const wxString& strDesc)
2275{
2b813b73
VZ
2276 // reading mailcap may find image/* , while
2277 // reading mime.types finds image/gif and no match is made
2278 // this means all the get functions don't work fix this
2279 wxString strIcon;
2280 wxString sTmp = strExtensions;
a6c65e88 2281
2b813b73 2282 wxArrayString sExts;
d0ee33f5 2283 sTmp.Trim().Trim(false);
2b813b73 2284
678ebfcd 2285 while (!sTmp.empty())
2b813b73 2286 {
dfea7acc 2287 sExts.Add(sTmp.AfterLast(wxT(' ')));
2b813b73 2288 sTmp = sTmp.BeforeLast(wxT(' '));
8e124873 2289 }
2b813b73 2290
dfea7acc 2291 AddToMimeData(strMimeType, strIcon, NULL, sExts, strDesc, true);
8e124873
VZ
2292}
2293
2294void wxMimeTypesManagerImpl::AddMailcapInfo(const wxString& strType,
2295 const wxString& strOpenCmd,
2296 const wxString& strPrintCmd,
2297 const wxString& strTest,
2298 const wxString& strDesc)
2299{
a6c65e88
VZ
2300 InitIfNeeded();
2301
678ebfcd 2302 wxMimeTypeCommands *entry = new wxMimeTypeCommands;
2b813b73
VZ
2303 entry->Add(wxT("open=") + strOpenCmd);
2304 entry->Add(wxT("print=") + strPrintCmd);
2305 entry->Add(wxT("test=") + strTest);
8e124873 2306
2b813b73
VZ
2307 wxString strIcon;
2308 wxArrayString strExtensions;
2309
dfea7acc 2310 AddToMimeData(strType, strIcon, entry, strExtensions, strDesc, true);
8e124873
VZ
2311}
2312
cc385968 2313bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName)
b13d92d1 2314{
f6bcfd97
BP
2315 wxLogTrace(TRACE_MIME, wxT("--- Parsing mime.types file '%s' ---"),
2316 strFileName.c_str());
b13d92d1
VZ
2317
2318 wxTextFile file(strFileName);
2b5f62a0 2319#if defined(__WXGTK20__) && wxUSE_UNICODE
7c2e5dec 2320 if ( !file.Open(wxConvUTF8) )
2b5f62a0 2321#else
b13d92d1 2322 if ( !file.Open() )
2b5f62a0 2323#endif
d0ee33f5 2324 return false;
b13d92d1
VZ
2325
2326 // the information we extract
2327 wxString strMimeType, strDesc, strExtensions;
2328
2329 size_t nLineCount = file.GetLineCount();
50920146 2330 const wxChar *pc = NULL;
2b5f62a0
VZ
2331 for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
2332 {
dfea7acc
DS
2333 if ( pc == NULL )
2334 {
22b4634c
VZ
2335 // now we're at the start of the line
2336 pc = file[nLine].c_str();
2337 }
dfea7acc
DS
2338 else
2339 {
22b4634c
VZ
2340 // we didn't finish with the previous line yet
2341 nLine--;
2342 }
b13d92d1
VZ
2343
2344 // skip whitespace
50920146 2345 while ( wxIsspace(*pc) )
b13d92d1
VZ
2346 pc++;
2347
54acce90 2348 // comment or blank line?
dfea7acc
DS
2349 if ( *pc == wxT('#') || !*pc )
2350 {
22b4634c
VZ
2351 // skip the whole line
2352 pc = NULL;
b13d92d1 2353 continue;
22b4634c 2354 }
b13d92d1
VZ
2355
2356 // detect file format
223d09f6 2357 const wxChar *pEqualSign = wxStrchr(pc, wxT('='));
dfea7acc
DS
2358 if ( pEqualSign == NULL )
2359 {
b13d92d1
VZ
2360 // brief format
2361 // ------------
2362
2363 // first field is mime type
dfea7acc
DS
2364 for ( strMimeType.Empty(); !wxIsspace(*pc) && *pc != wxT('\0'); pc++ )
2365 {
b13d92d1
VZ
2366 strMimeType += *pc;
2367 }
2368
2369 // skip whitespace
50920146 2370 while ( wxIsspace(*pc) )
b13d92d1
VZ
2371 pc++;
2372
2373 // take all the rest of the string
2374 strExtensions = pc;
2375
2376 // no description...
2377 strDesc.Empty();
2378 }
dfea7acc
DS
2379 else
2380 {
b13d92d1
VZ
2381 // expanded format
2382 // ---------------
2383
2384 // the string on the left of '=' is the field name
2385 wxString strLHS(pc, pEqualSign - pc);
2386
2387 // eat whitespace
50920146 2388 for ( pc = pEqualSign + 1; wxIsspace(*pc); pc++ )
678ebfcd 2389 ;
b13d92d1 2390
50920146 2391 const wxChar *pEnd;
dfea7acc
DS
2392 if ( *pc == wxT('"') )
2393 {
b13d92d1 2394 // the string is quoted and ends at the matching quote
223d09f6 2395 pEnd = wxStrchr(++pc, wxT('"'));
dfea7acc
DS
2396 if ( pEnd == NULL )
2397 {
5d0d3e6d 2398 wxLogWarning(wxT("Mime.types file %s, line %lu: unterminated quoted string."),
985f824c 2399 strFileName.c_str(), nLine + 1L);
b13d92d1
VZ
2400 }
2401 }
dfea7acc
DS
2402 else
2403 {
8862e11b
VZ
2404 // unquoted string ends at the first space or at the end of
2405 // line
2406 for ( pEnd = pc; *pEnd && !wxIsspace(*pEnd); pEnd++ )
678ebfcd 2407 ;
b13d92d1
VZ
2408 }
2409
2410 // now we have the RHS (field value)
2411 wxString strRHS(pc, pEnd - pc);
2412
22b4634c 2413 // check what follows this entry
dfea7acc
DS
2414 if ( *pEnd == wxT('"') )
2415 {
b13d92d1
VZ
2416 // skip this quote
2417 pEnd++;
2418 }
2419
50920146 2420 for ( pc = pEnd; wxIsspace(*pc); pc++ )
678ebfcd 2421 ;
b13d92d1 2422
22b4634c
VZ
2423 // if there is something left, it may be either a '\\' to continue
2424 // the line or the next field of the same entry
dfea7acc
DS
2425 bool entryEnded = *pc == wxT('\0');
2426 bool nextFieldOnSameLine = false;
2427 if ( !entryEnded )
2428 {
223d09f6 2429 nextFieldOnSameLine = ((*pc != wxT('\\')) || (pc[1] != wxT('\0')));
b13d92d1 2430 }
b13d92d1
VZ
2431
2432 // now see what we got
dfea7acc
DS
2433 if ( strLHS == wxT("type") )
2434 {
b13d92d1
VZ
2435 strMimeType = strRHS;
2436 }
dfea7acc
DS
2437 else if ( strLHS.StartsWith(wxT("desc")) )
2438 {
b13d92d1
VZ
2439 strDesc = strRHS;
2440 }
dfea7acc
DS
2441 else if ( strLHS == wxT("exts") )
2442 {
b13d92d1
VZ
2443 strExtensions = strRHS;
2444 }
dfea7acc 2445 else if ( strLHS == wxT("icon") )
70687b63 2446 {
a2717c3d
VZ
2447 // this one is simply ignored: it usually refers to Netscape
2448 // built in icons which are useless for us anyhow
70687b63 2449 }
dfea7acc 2450 else if ( !strLHS.StartsWith(wxT("x-")) )
70687b63
VZ
2451 {
2452 // we suppose that all fields starting with "X-" are
2453 // unregistered extensions according to the standard practice,
2454 // but it may be worth telling the user about other junk in
2455 // his mime.types file
5d0d3e6d 2456 wxLogWarning(wxT("Unknown field in file %s, line %lu: '%s'."),
985f824c 2457 strFileName.c_str(), nLine + 1L, strLHS.c_str());
b13d92d1
VZ
2458 }
2459
dfea7acc
DS
2460 if ( !entryEnded )
2461 {
22b4634c
VZ
2462 if ( !nextFieldOnSameLine )
2463 pc = NULL;
2464 //else: don't reset it
2465
2466 // as we don't reset strMimeType, the next field in this entry
b13d92d1 2467 // will be interpreted correctly.
22b4634c 2468
b13d92d1
VZ
2469 continue;
2470 }
2471 }
2472
a6c65e88
VZ
2473 // depending on the format (Mosaic or Netscape) either space or comma
2474 // is used to separate the extensions
223d09f6 2475 strExtensions.Replace(wxT(","), wxT(" "));
a1d8eaf7
VZ
2476
2477 // also deal with the leading dot
678ebfcd 2478 if ( !strExtensions.empty() && strExtensions[0u] == wxT('.') )
1b986aef 2479 {
a1d8eaf7
VZ
2480 strExtensions.erase(0, 1);
2481 }
2482
678ebfcd
VZ
2483 wxLogTrace(TRACE_MIME, wxT("mime.types: '%s' => '%s' (%s)"),
2484 strExtensions.c_str(),
2485 strMimeType.c_str(),
2486 strDesc.c_str());
2b813b73 2487
8e124873 2488 AddMimeTypeInfo(strMimeType, strExtensions, strDesc);
22b4634c
VZ
2489
2490 // finished with this line
2491 pc = NULL;
b13d92d1
VZ
2492 }
2493
d0ee33f5 2494 return true;
b13d92d1
VZ
2495}
2496
678ebfcd
VZ
2497// ----------------------------------------------------------------------------
2498// UNIX mailcap files parsing
2499// ----------------------------------------------------------------------------
2500
2501// the data for a single MIME type
2502struct MailcapLineData
2503{
2504 // field values
2505 wxString type,
2506 cmdOpen,
2507 test,
2508 icon,
2509 desc;
2510
2511 wxArrayString verbs,
2512 commands;
2513
2514 // flags
2515 bool testfailed,
2516 needsterminal,
2517 copiousoutput;
2518
d0ee33f5 2519 MailcapLineData() { testfailed = needsterminal = copiousoutput = false; }
678ebfcd
VZ
2520};
2521
2522// process a non-standard (i.e. not the first or second one) mailcap field
2523bool
2524wxMimeTypesManagerImpl::ProcessOtherMailcapField(MailcapLineData& data,
2525 const wxString& curField)
2526{
2527 if ( curField.empty() )
2528 {
2529 // we don't care
d0ee33f5 2530 return true;
678ebfcd
VZ
2531 }
2532
2533 // is this something of the form foo=bar?
2534 const wxChar *pEq = wxStrchr(curField, wxT('='));
2535 if ( pEq != NULL )
2536 {
2537 // split "LHS = RHS" in 2
2538 wxString lhs = curField.BeforeFirst(wxT('=')),
2539 rhs = curField.AfterFirst(wxT('='));
2540
d0ee33f5
WS
2541 lhs.Trim(true); // from right
2542 rhs.Trim(false); // from left
678ebfcd
VZ
2543
2544 // it might be quoted
2545 if ( !rhs.empty() && rhs[0u] == wxT('"') && rhs.Last() == wxT('"') )
2546 {
2547 rhs = rhs.Mid(1, rhs.length() - 2);
2548 }
2549
2550 // is it a command verb or something else?
2551 if ( lhs == wxT("test") )
2552 {
2553 if ( wxSystem(rhs) == 0 )
2554 {
2555 // ok, test passed
2556 wxLogTrace(TRACE_MIME_TEST,
2557 wxT("Test '%s' for mime type '%s' succeeded."),
2558 rhs.c_str(), data.type.c_str());
678ebfcd
VZ
2559 }
2560 else
2561 {
2562 wxLogTrace(TRACE_MIME_TEST,
2563 wxT("Test '%s' for mime type '%s' failed, skipping."),
2564 rhs.c_str(), data.type.c_str());
2565
d0ee33f5 2566 data.testfailed = true;
678ebfcd
VZ
2567 }
2568 }
2569 else if ( lhs == wxT("desc") )
2570 {
2571 data.desc = rhs;
2572 }
2573 else if ( lhs == wxT("x11-bitmap") )
2574 {
2575 data.icon = rhs;
2576 }
2577 else if ( lhs == wxT("notes") )
2578 {
2579 // ignore
2580 }
2581 else // not a (recognized) special case, must be a verb (e.g. "print")
2582 {
2583 data.verbs.Add(lhs);
2584 data.commands.Add(rhs);
2585 }
2586 }
2587 else // '=' not found
2588 {
2589 // so it must be a simple flag
2590 if ( curField == wxT("needsterminal") )
2591 {
d0ee33f5 2592 data.needsterminal = true;
678ebfcd
VZ
2593 }
2594 else if ( curField == wxT("copiousoutput"))
2595 {
2596 // copiousoutput impies that the viewer is a console program
2597 data.needsterminal =
d0ee33f5 2598 data.copiousoutput = true;
678ebfcd
VZ
2599 }
2600 else if ( !IsKnownUnimportantField(curField) )
2601 {
d0ee33f5 2602 return false;
678ebfcd
VZ
2603 }
2604 }
2605
d0ee33f5 2606 return true;
678ebfcd
VZ
2607}
2608
cc385968
VZ
2609bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName,
2610 bool fallback)
b13d92d1 2611{
f6bcfd97
BP
2612 wxLogTrace(TRACE_MIME, wxT("--- Parsing mailcap file '%s' ---"),
2613 strFileName.c_str());
b13d92d1
VZ
2614
2615 wxTextFile file(strFileName);
2b5f62a0 2616#if defined(__WXGTK20__) && wxUSE_UNICODE
7c2e5dec 2617 if ( !file.Open(wxConvUTF8) )
2b5f62a0 2618#else
b13d92d1 2619 if ( !file.Open() )
2b5f62a0 2620#endif
d0ee33f5 2621 return false;
b13d92d1 2622
678ebfcd
VZ
2623 // indices of MIME types (in m_aTypes) we already found in this file
2624 //
2625 // (see the comments near the end of function for the reason we need this)
2626 wxArrayInt aIndicesSeenHere;
2627
2628 // accumulator for the current field
2629 wxString curField;
2630 curField.reserve(1024);
b13d92d1
VZ
2631
2632 size_t nLineCount = file.GetLineCount();
678ebfcd
VZ
2633 for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
2634 {
b13d92d1 2635 // now we're at the start of the line
50920146 2636 const wxChar *pc = file[nLine].c_str();
b13d92d1
VZ
2637
2638 // skip whitespace
50920146 2639 while ( wxIsspace(*pc) )
b13d92d1
VZ
2640 pc++;
2641
2642 // comment or empty string?
223d09f6 2643 if ( *pc == wxT('#') || *pc == wxT('\0') )
b13d92d1
VZ
2644 continue;
2645
2646 // no, do parse
678ebfcd 2647 // ------------
b13d92d1
VZ
2648
2649 // what field are we currently in? The first 2 are fixed and there may
678ebfcd
VZ
2650 // be an arbitrary number of other fields parsed by
2651 // ProcessOtherMailcapField()
2652 //
2653 // the first field is the MIME type
b13d92d1
VZ
2654 enum
2655 {
2656 Field_Type,
2657 Field_OpenCmd,
2658 Field_Other
dfea7acc
DS
2659 }
2660 currentToken = Field_Type;
b13d92d1
VZ
2661
2662 // the flags and field values on the current line
678ebfcd
VZ
2663 MailcapLineData data;
2664
d0ee33f5 2665 bool cont = true;
678ebfcd
VZ
2666 while ( cont )
2667 {
2668 switch ( *pc )
2669 {
223d09f6 2670 case wxT('\\'):
b13d92d1
VZ
2671 // interpret the next character literally (notice that
2672 // backslash can be used for line continuation)
678ebfcd
VZ
2673 if ( *++pc == wxT('\0') )
2674 {
6e358ae7 2675 // fetch the next line if there is one
678ebfcd
VZ
2676 if ( nLine == nLineCount - 1 )
2677 {
6e358ae7 2678 // something is wrong, bail out
d0ee33f5 2679 cont = false;
6e358ae7 2680
76a6e803 2681 wxLogDebug(wxT("Mailcap file %s, line %lu: '\\' on the end of the last line ignored."),
6e358ae7 2682 strFileName.c_str(),
985f824c 2683 nLine + 1L);
6e358ae7 2684 }
678ebfcd
VZ
2685 else
2686 {
6e358ae7
VZ
2687 // pass to the beginning of the next line
2688 pc = file[++nLine].c_str();
2689
2690 // skip pc++ at the end of the loop
2691 continue;
2692 }
b13d92d1 2693 }
678ebfcd
VZ
2694 else
2695 {
b13d92d1
VZ
2696 // just a normal character
2697 curField += *pc;
2698 }
2699 break;
2700
223d09f6 2701 case wxT('\0'):
d0ee33f5 2702 cont = false; // end of line reached, exit the loop
b13d92d1 2703
678ebfcd 2704 // fall through to still process this field
b13d92d1 2705
223d09f6 2706 case wxT(';'):
b13d92d1 2707 // trim whitespaces from both sides
d0ee33f5 2708 curField.Trim(true).Trim(false);
b13d92d1 2709
678ebfcd
VZ
2710 switch ( currentToken )
2711 {
b13d92d1 2712 case Field_Type:
678ebfcd
VZ
2713 data.type = curField.Lower();
2714 if ( data.type.empty() )
2715 {
6e358ae7
VZ
2716 // I don't think that this is a valid mailcap
2717 // entry, but try to interpret it somehow
dfea7acc 2718 data.type = wxT('*');
6e358ae7
VZ
2719 }
2720
678ebfcd
VZ
2721 if ( data.type.Find(wxT('/')) == wxNOT_FOUND )
2722 {
b13d92d1 2723 // we interpret "type" as "type/*"
678ebfcd 2724 data.type += wxT("/*");
b13d92d1
VZ
2725 }
2726
2727 currentToken = Field_OpenCmd;
2728 break;
2729
2730 case Field_OpenCmd:
678ebfcd 2731 data.cmdOpen = curField;
b13d92d1
VZ
2732
2733 currentToken = Field_Other;
2734 break;
2735
2736 case Field_Other:
678ebfcd
VZ
2737 if ( !ProcessOtherMailcapField(data, curField) )
2738 {
2739 // don't flood the user with error messages if
2740 // we don't understand something in his
2741 // mailcap, but give them in debug mode because
2742 // this might be useful for the programmer
2743 wxLogDebug
2744 (
76a6e803 2745 wxT("Mailcap file %s, line %lu: unknown field '%s' for the MIME type '%s' ignored."),
678ebfcd 2746 strFileName.c_str(),
985f824c 2747 nLine + 1L,
678ebfcd
VZ
2748 curField.c_str(),
2749 data.type.c_str()
2750 );
2751 }
2752 else if ( data.testfailed )
2753 {
2754 // skip this entry entirely
d0ee33f5 2755 cont = false;
b13d92d1
VZ
2756 }
2757
2758 // it already has this value
2759 //currentToken = Field_Other;
2760 break;
2761
2762 default:
223d09f6 2763 wxFAIL_MSG(wxT("unknown field type in mailcap"));
b13d92d1
VZ
2764 }
2765
2766 // next token starts immediately after ';'
2767 curField.Empty();
2768 break;
2769
2770 default:
2771 curField += *pc;
2772 }
6e358ae7
VZ
2773
2774 // continue in the same line
2775 pc++;
b13d92d1
VZ
2776 }
2777
678ebfcd
VZ
2778 // we read the entire entry, check what have we got
2779 // ------------------------------------------------
2780
b13d92d1 2781 // check that we really read something reasonable
678ebfcd
VZ
2782 if ( currentToken < Field_Other )
2783 {
5d0d3e6d 2784 wxLogWarning(wxT("Mailcap file %s, line %lu: incomplete entry ignored."),
985f824c 2785 strFileName.c_str(), nLine + 1L);
678ebfcd
VZ
2786
2787 continue;
b13d92d1 2788 }
e1e9ea40 2789
7c2e5dec 2790 // if the test command failed, it's as if the entry were not there at all
678ebfcd
VZ
2791 if ( data.testfailed )
2792 {
2793 continue;
2794 }
2b813b73 2795
678ebfcd
VZ
2796 // support for flags:
2797 // 1. create an xterm for 'needsterminal'
2798 // 2. append "| $PAGER" for 'copiousoutput'
2799 //
2800 // Note that the RFC says that having both needsterminal and
2801 // copiousoutput is probably a mistake, so it seems that running
2802 // programs with copiousoutput inside an xterm as it is done now
2803 // is a bad idea (FIXME)
2804 if ( data.copiousoutput )
2805 {
dfea7acc
DS
2806 const wxChar *p = wxGetenv(wxT("PAGER"));
2807 data.cmdOpen << wxT(" | ") << (p ? p : wxT("more"));
678ebfcd 2808 }
b13d92d1 2809
678ebfcd
VZ
2810 if ( data.needsterminal )
2811 {
dfea7acc 2812 data.cmdOpen = wxString::Format(wxT("xterm -e sh -c '%s'"),
2b5f62a0 2813 data.cmdOpen.c_str());
678ebfcd 2814 }
b13d92d1 2815
678ebfcd
VZ
2816 if ( !data.cmdOpen.empty() )
2817 {
dfea7acc 2818 data.verbs.Insert(wxT("open"), 0);
678ebfcd
VZ
2819 data.commands.Insert(data.cmdOpen, 0);
2820 }
2b813b73 2821
678ebfcd
VZ
2822 // we have to decide whether the new entry should replace any entries
2823 // for the same MIME type we had previously found or not
2824 bool overwrite;
2825
2826 // the fall back entries have the lowest priority, by definition
2827 if ( fallback )
2828 {
d0ee33f5 2829 overwrite = false;
678ebfcd
VZ
2830 }
2831 else
2832 {
2833 // have we seen this one before?
2834 int nIndex = m_aTypes.Index(data.type);
2835
a9a76b2f
VZ
2836 // and if we have, was it in this file? if not, we should
2837 // overwrite the previously seen one
678ebfcd 2838 overwrite = nIndex == wxNOT_FOUND ||
a9a76b2f 2839 aIndicesSeenHere.Index(nIndex) == wxNOT_FOUND;
b13d92d1
VZ
2840 }
2841
dfea7acc 2842 wxLogTrace(TRACE_MIME, wxT("mailcap %s: %s [%s]"),
678ebfcd 2843 data.type.c_str(), data.cmdOpen.c_str(),
dfea7acc 2844 overwrite ? wxT("replace") : wxT("add"));
678ebfcd
VZ
2845
2846 int n = AddToMimeData
2847 (
2848 data.type,
2849 data.icon,
2850 new wxMimeTypeCommands(data.verbs, data.commands),
2851 wxArrayString() /* extensions */,
2852 data.desc,
2853 overwrite
2854 );
2855
2856 if ( overwrite )
2857 {
2858 aIndicesSeenHere.Add(n);
2859 }
b13d92d1 2860 }
cc385968 2861
d0ee33f5 2862 return true;
b13d92d1
VZ
2863}
2864
696e1ea0 2865size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
1b986aef 2866{
a6c65e88
VZ
2867 InitIfNeeded();
2868
54acce90
VZ
2869 mimetypes.Empty();
2870
2871 wxString type;
2872 size_t count = m_aTypes.GetCount();
2873 for ( size_t n = 0; n < count; n++ )
2874 {
2875 // don't return template types from here (i.e. anything containg '*')
2876 type = m_aTypes[n];
dfea7acc 2877 if ( type.Find(wxT('*')) == wxNOT_FOUND )
54acce90
VZ
2878 {
2879 mimetypes.Add(type);
2880 }
2881 }
1b986aef 2882
54acce90 2883 return mimetypes.GetCount();
1b986aef
VZ
2884}
2885
a6c65e88
VZ
2886// ----------------------------------------------------------------------------
2887// writing to MIME type files
2888// ----------------------------------------------------------------------------
2889
2b813b73 2890bool wxMimeTypesManagerImpl::Unassociate(wxFileType *ft)
a6c65e88 2891{
2b813b73 2892 wxArrayString sMimeTypes;
dfea7acc 2893 ft->GetMimeTypes(sMimeTypes);
a6c65e88 2894
2b813b73
VZ
2895 wxString sMime;
2896 size_t i;
2897 for (i = 0; i < sMimeTypes.GetCount(); i ++)
2898 {
2899 sMime = sMimeTypes.Item(i);
dfea7acc 2900 int nIndex = m_aTypes.Index(sMime);
2b813b73
VZ
2901 if ( nIndex == wxNOT_FOUND)
2902 {
2903 // error if we get here ??
d0ee33f5 2904 return false;
2b813b73
VZ
2905 }
2906 else
2907 {
dfea7acc 2908 WriteMimeInfo(nIndex, true);
e9d9f136
VZ
2909 m_aTypes.RemoveAt(nIndex);
2910 m_aEntries.RemoveAt(nIndex);
2911 m_aExtensions.RemoveAt(nIndex);
2912 m_aDescriptions.RemoveAt(nIndex);
2913 m_aIcons.RemoveAt(nIndex);
2b813b73
VZ
2914 }
2915 }
2916 // check data integrity
2917 wxASSERT( m_aTypes.Count() == m_aEntries.Count() &&
2918 m_aTypes.Count() == m_aExtensions.Count() &&
2919 m_aTypes.Count() == m_aIcons.Count() &&
2920 m_aTypes.Count() == m_aDescriptions.Count() );
2921
d0ee33f5 2922 return true;
a6c65e88
VZ
2923}
2924
f6bcfd97
BP
2925// ----------------------------------------------------------------------------
2926// private functions
2927// ----------------------------------------------------------------------------
2928
2929static bool IsKnownUnimportantField(const wxString& fieldAll)
2930{
2931 static const wxChar *knownFields[] =
2932 {
dfea7acc
DS
2933 wxT("x-mozilla-flags"),
2934 wxT("nametemplate"),
2935 wxT("textualnewlines"),
f6bcfd97
BP
2936 };
2937
dfea7acc 2938 wxString field = fieldAll.BeforeFirst(wxT('='));
f6bcfd97
BP
2939 for ( size_t n = 0; n < WXSIZEOF(knownFields); n++ )
2940 {
2941 if ( field.CmpNoCase(knownFields[n]) == 0 )
d0ee33f5 2942 return true;
f6bcfd97
BP
2943 }
2944
d0ee33f5 2945 return false;
f6bcfd97
BP
2946}
2947
8e124873 2948#endif
b79e32cc 2949 // wxUSE_MIMETYPE && wxUSE_FILE && wxUSE_TEXTFILE
b13d92d1 2950