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