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