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