1/*
2 * Copyright 2002-2006 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 *		Tyler Dauwalder
8 *		Ingo Weinhold, bonefish@users.sf.net
9 */
10
11
12#include "MimeType.h"
13
14#include <Bitmap.h>
15#include <mime/database_support.h>
16#include <mime/DatabaseLocation.h>
17#include <sniffer/Rule.h>
18#include <sniffer/Parser.h>
19
20#include <RegistrarDefs.h>
21#include <RosterPrivate.h>
22
23#include <ctype.h>
24#include <new>
25#include <stdio.h>
26#include <strings.h>
27
28
29using namespace BPrivate;
30
31// Private helper functions
32static bool isValidMimeChar(const char ch);
33
34using namespace BPrivate::Storage::Mime;
35using namespace std;
36
37const char* B_PEF_APP_MIME_TYPE		= "application/x-be-executable";
38const char* B_PE_APP_MIME_TYPE		= "application/x-vnd.Be-peexecutable";
39const char* B_ELF_APP_MIME_TYPE		= "application/x-vnd.Be-elfexecutable";
40const char* B_RESOURCE_MIME_TYPE	= "application/x-be-resource";
41const char* B_FILE_MIME_TYPE		= "application/octet-stream";
42// Might be defined platform depended, but ELF will certainly be the common
43// format for all platforms anyway.
44const char* B_APP_MIME_TYPE			= B_ELF_APP_MIME_TYPE;
45
46
47static bool
48isValidMimeChar(const char ch)
49{
50	// Handles white space and most CTLs
51	return ch > 32
52		&& ch != '/'
53		&& ch != '<'
54		&& ch != '>'
55		&& ch != '@'
56		&& ch != ','
57		&& ch != ';'
58		&& ch != ':'
59		&& ch != '"'
60		&& ch != '('
61		&& ch != ')'
62		&& ch != '['
63		&& ch != ']'
64		&& ch != '?'
65		&& ch != '='
66		&& ch != '\\'
67		&& ch != 127;	// DEL
68}
69
70
71//	#pragma mark -
72
73
74// Creates an uninitialized BMimeType object.
75BMimeType::BMimeType()
76	:
77	fType(NULL),
78	fCStatus(B_NO_INIT)
79{
80}
81
82
83// Creates a BMimeType object and initializes it to the supplied
84// MIME type.
85BMimeType::BMimeType(const char* mimeType)
86	:
87	fType(NULL),
88	fCStatus(B_NO_INIT)
89{
90	SetTo(mimeType);
91}
92
93
94// Frees all resources associated with this object.
95BMimeType::~BMimeType()
96{
97	Unset();
98}
99
100
101// Initializes this object to the supplied MIME type.
102status_t
103BMimeType::SetTo(const char* mimeType)
104{
105	if (mimeType == NULL) {
106		Unset();
107	} else if (!BMimeType::IsValid(mimeType)) {
108		fCStatus = B_BAD_VALUE;
109	} else {
110		Unset();
111		fType = new(std::nothrow) char[strlen(mimeType) + 1];
112		if (fType) {
113			strlcpy(fType, mimeType, B_MIME_TYPE_LENGTH);
114			fCStatus = B_OK;
115		} else {
116			fCStatus = B_NO_MEMORY;
117		}
118	}
119	return fCStatus;
120}
121
122
123// Returns the object to an uninitialized state
124void
125BMimeType::Unset()
126{
127	delete [] fType;
128	fType = NULL;
129	fCStatus = B_NO_INIT;
130}
131
132
133// Returns the result of the most recent constructor or SetTo() call
134status_t
135BMimeType::InitCheck() const
136{
137	return fCStatus;
138}
139
140
141// Returns the MIME string represented by this object
142const char*
143BMimeType::Type() const
144{
145	return fType;
146}
147
148
149// Returns whether the object represents a valid MIME type
150bool
151BMimeType::IsValid() const
152{
153	return InitCheck() == B_OK && BMimeType::IsValid(Type());
154}
155
156
157// Returns whether this objects represents a supertype
158bool
159BMimeType::IsSupertypeOnly() const
160{
161	if (fCStatus == B_OK) {
162		// We assume here fCStatus will be B_OK *only* if
163		// the MIME string is valid
164		size_t len = strlen(fType);
165		for (size_t i = 0; i < len; i++) {
166			if (fType[i] == '/')
167				return false;
168		}
169		return true;
170	} else
171		return false;
172}
173
174
175// Returns whether or not this type is currently installed in the
176// MIME database
177bool
178BMimeType::IsInstalled() const
179{
180	return InitCheck() == B_OK
181		&& default_database_location()->IsInstalled(Type());
182}
183
184
185// Gets the supertype of the MIME type represented by this object
186status_t
187BMimeType::GetSupertype(BMimeType* supertype) const
188{
189	if (supertype == NULL)
190		return B_BAD_VALUE;
191
192	supertype->Unset();
193	status_t status = fCStatus == B_OK ? B_OK : B_BAD_VALUE;
194	if (status == B_OK) {
195		size_t len = strlen(fType);
196		size_t i = 0;
197		for (; i < len; i++) {
198			if (fType[i] == '/')
199				break;
200		}
201		if (i == len) {
202			// object is a supertype only
203			status = B_BAD_VALUE;
204		} else {
205			char superMime[B_MIME_TYPE_LENGTH];
206			strncpy(superMime, fType, i);
207			superMime[i] = 0;
208			status = supertype->SetTo(superMime) == B_OK ? B_OK : B_BAD_VALUE;
209		}
210	}
211
212	return status;
213}
214
215
216// Returns whether this and the supplied MIME type are equal
217bool
218BMimeType::operator==(const BMimeType &type) const
219{
220	if (InitCheck() == B_NO_INIT && type.InitCheck() == B_NO_INIT)
221		return true;
222	else if (InitCheck() == B_OK && type.InitCheck() == B_OK)
223		return strcasecmp(Type(), type.Type()) == 0;
224
225	return false;
226}
227
228
229// Returns whether this and the supplied MIME type are equal
230bool
231BMimeType::operator==(const char* type) const
232{
233	BMimeType mime;
234	if (type)
235		mime.SetTo(type);
236
237	return (*this) == mime;
238}
239
240
241// Returns whether this MIME type is a supertype of or equals the
242// supplied one
243bool
244BMimeType::Contains(const BMimeType* type) const
245{
246	if (type == NULL)
247		return false;
248
249	if (*this == *type)
250		return true;
251
252	BMimeType super;
253	if (type->GetSupertype(&super) == B_OK && *this == super)
254		return true;
255	return false;
256}
257
258
259// Adds the MIME type to the MIME database
260status_t
261BMimeType::Install()
262{
263	status_t err = InitCheck();
264
265	BMessage message(B_REG_MIME_INSTALL);
266	BMessage reply;
267	status_t result;
268
269	// Build and send the message, read the reply
270	if (err == B_OK)
271		err = message.AddString("type", Type());
272
273	if (err == B_OK)
274		err = BRoster::Private().SendTo(&message, &reply, true);
275
276	if (err == B_OK)
277		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
278
279	if (err == B_OK)
280		err = reply.FindInt32("result", &result);
281
282	if (err == B_OK)
283		err = result;
284
285	return err;
286}
287
288
289// Removes the MIME type from the MIME database
290status_t
291BMimeType::Delete()
292{
293	status_t err = InitCheck();
294
295	BMessage message(B_REG_MIME_DELETE);
296	BMessage reply;
297	status_t result;
298
299	// Build and send the message, read the reply
300	if (err == B_OK)
301		err = message.AddString("type", Type());
302
303	if (err == B_OK)
304		err = BRoster::Private().SendTo(&message, &reply, true);
305
306	if (err == B_OK)
307		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
308
309	if (err == B_OK)
310		err = reply.FindInt32("result", &result);
311
312	if (err == B_OK)
313		err = result;
314
315	return err;
316}
317
318
319// Fetches the large or mini icon associated with the MIME type
320status_t
321BMimeType::GetIcon(BBitmap* icon, icon_size size) const
322{
323	if (icon == NULL)
324		return B_BAD_VALUE;
325
326	status_t err = InitCheck();
327	if (err == B_OK)
328		err = default_database_location()->GetIcon(Type(), *icon, size);
329
330	return err;
331}
332
333
334//	Fetches the vector icon associated with the MIME type
335status_t
336BMimeType::GetIcon(uint8** data, size_t* size) const
337{
338	if (data == NULL || size == NULL)
339		return B_BAD_VALUE;
340
341	status_t err = InitCheck();
342	if (err == B_OK)
343		err = default_database_location()->GetIcon(Type(), *data, *size);
344
345	return err;
346}
347
348
349// Fetches the signature of the MIME type's preferred application from the
350// MIME database
351status_t
352BMimeType::GetPreferredApp(char* signature, app_verb verb) const
353{
354	status_t err = InitCheck();
355	if (err == B_OK) {
356		err = default_database_location()->GetPreferredApp(Type(), signature,
357			verb);
358	}
359
360	return err;
361}
362
363
364// Fetches from the MIME database a BMessage describing the attributes
365// typically associated with files of the given MIME type
366status_t
367BMimeType::GetAttrInfo(BMessage* info) const
368{
369	if (info == NULL)
370		return B_BAD_VALUE;
371
372	status_t err = InitCheck();
373	if (err == B_OK)
374		err = default_database_location()->GetAttributesInfo(Type(), *info);
375
376	return err;
377}
378
379
380// Fetches the MIME type's associated filename extensions from the MIME
381// database
382status_t
383BMimeType::GetFileExtensions(BMessage* extensions) const
384{
385	if (extensions == NULL)
386		return B_BAD_VALUE;
387
388	status_t err = InitCheck();
389	if (err == B_OK) {
390		err = default_database_location()->GetFileExtensions(Type(),
391			*extensions);
392	}
393
394	return err;
395}
396
397
398// Fetches the MIME type's short description from the MIME database
399status_t
400BMimeType::GetShortDescription(char* description) const
401{
402	status_t err = InitCheck();
403	if (err == B_OK) {
404		err = default_database_location()->GetShortDescription(Type(),
405			description);
406	}
407
408	return err;
409}
410
411
412// Fetches the MIME type's long description from the MIME database
413status_t
414BMimeType::GetLongDescription(char* description) const
415{
416	status_t err = InitCheck();
417	if (err == B_OK) {
418		err = default_database_location()->GetLongDescription(Type(),
419			description);
420	}
421
422	return err;
423}
424
425
426// Fetches a \c BMessage containing a list of MIME signatures of
427// applications that are able to handle files of this MIME type.
428status_t
429BMimeType::GetSupportingApps(BMessage* signatures) const
430{
431	if (signatures == NULL)
432		return B_BAD_VALUE;
433
434	BMessage message(B_REG_MIME_GET_SUPPORTING_APPS);
435	status_t result;
436
437	status_t err = InitCheck();
438	if (err == B_OK)
439		err = message.AddString("type", Type());
440	if (err == B_OK)
441		err = BRoster::Private().SendTo(&message, signatures, true);
442	if (err == B_OK) {
443		err = (status_t)(signatures->what == B_REG_RESULT ? B_OK
444			: B_BAD_REPLY);
445	}
446	if (err == B_OK)
447		err = signatures->FindInt32("result", &result);
448	if (err == B_OK)
449		err = result;
450
451	return err;
452}
453
454
455// Sets the large or mini icon for the MIME type
456status_t
457BMimeType::SetIcon(const BBitmap* icon, icon_size which)
458{
459	return SetIconForType(NULL, icon, which);
460}
461
462
463// Sets the vector icon for the MIME type
464status_t
465BMimeType::SetIcon(const uint8* data, size_t size)
466{
467	return SetIconForType(NULL, data, size);
468}
469
470
471// Sets the preferred application for the MIME type
472status_t
473BMimeType::SetPreferredApp(const char* signature, app_verb verb)
474{
475	status_t err = InitCheck();
476
477	BMessage message(signature && signature[0]
478		? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
479	BMessage reply;
480	status_t result;
481
482	// Build and send the message, read the reply
483	if (err == B_OK)
484		err = message.AddString("type", Type());
485
486	if (err == B_OK)
487		err = message.AddInt32("which", B_REG_MIME_PREFERRED_APP);
488
489	if (err == B_OK && signature != NULL)
490		err = message.AddString("signature", signature);
491
492	if (err == B_OK)
493		err = message.AddInt32("app verb", verb);
494
495	if (err == B_OK)
496		err = BRoster::Private().SendTo(&message, &reply, true);
497
498	if (err == B_OK)
499		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
500
501	if (err == B_OK)
502		err = reply.FindInt32("result", &result);
503
504	if (err == B_OK)
505		err = result;
506
507	return err;
508}
509
510
511// Sets the description of the attributes typically associated with files
512// of the given MIME type
513status_t
514BMimeType::SetAttrInfo(const BMessage* info)
515{
516	status_t err = InitCheck();
517
518	BMessage message(info ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
519	BMessage reply;
520	status_t result;
521
522	// Build and send the message, read the reply
523	if (err == B_OK)
524		err = message.AddString("type", Type());
525	if (err == B_OK)
526		err = message.AddInt32("which", B_REG_MIME_ATTR_INFO);
527	if (err == B_OK && info != NULL)
528		err = message.AddMessage("attr info", info);
529	if (err == B_OK)
530		err = BRoster::Private().SendTo(&message, &reply, true);
531	if (err == B_OK)
532		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
533	if (err == B_OK)
534		err = reply.FindInt32("result", &result);
535	if (err == B_OK)
536		err = result;
537
538	return err;
539}
540
541
542// Sets the list of filename extensions associated with the MIME type
543status_t
544BMimeType::SetFileExtensions(const BMessage* extensions)
545{
546	status_t err = InitCheck();
547
548	BMessage message(extensions ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
549	BMessage reply;
550	status_t result;
551
552	// Build and send the message, read the reply
553	if (err == B_OK)
554		err = message.AddString("type", Type());
555
556	if (err == B_OK)
557		err = message.AddInt32("which", B_REG_MIME_FILE_EXTENSIONS);
558
559	if (err == B_OK && extensions != NULL)
560		err = message.AddMessage("extensions", extensions);
561
562	if (err == B_OK)
563		err = BRoster::Private().SendTo(&message, &reply, true);
564
565	if (err == B_OK)
566		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
567
568	if (err == B_OK)
569		err = reply.FindInt32("result", &result);
570
571	if (err == B_OK)
572		err = result;
573
574	return err;
575}
576
577
578// Sets the short description field for the MIME type
579status_t
580BMimeType::SetShortDescription(const char* description)
581{
582	status_t err = InitCheck();
583
584	BMessage message(description && description [0]
585		? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
586	BMessage reply;
587	status_t result;
588
589	// Build and send the message, read the reply
590	if (err == B_OK)
591		err = message.AddString("type", Type());
592
593	if (err == B_OK)
594		err = message.AddInt32("which", B_REG_MIME_DESCRIPTION);
595
596	if (err == B_OK && description)
597		err = message.AddString("description", description);
598
599	if (err == B_OK)
600		err = message.AddBool("long", false);
601
602	if (err == B_OK)
603		err = BRoster::Private().SendTo(&message, &reply, true);
604
605	if (err == B_OK)
606		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
607
608	if (err == B_OK)
609		err = reply.FindInt32("result", &result);
610
611	if (err == B_OK)
612		err = result;
613
614	return err;
615}
616
617
618// Sets the long description field for the MIME type
619status_t
620BMimeType::SetLongDescription(const char* description)
621{
622	status_t err = InitCheck();
623
624	BMessage message(description && description[0]
625		? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
626	BMessage reply;
627	status_t result;
628
629	// Build and send the message, read the reply
630	if (err == B_OK)
631		err = message.AddString("type", Type());
632
633	if (err == B_OK)
634		err = message.AddInt32("which", B_REG_MIME_DESCRIPTION);
635
636	if (err == B_OK && description)
637		err = message.AddString("description", description);
638
639	if (err == B_OK)
640		err = message.AddBool("long", true);
641
642	if (err == B_OK)
643		err = BRoster::Private().SendTo(&message, &reply, true);
644
645	if (err == B_OK)
646		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
647
648	if (err == B_OK)
649		err = reply.FindInt32("result", &result);
650
651	if (err == B_OK)
652		err = result;
653
654	return err;
655}
656
657
658// Fetches a BMessage listing all the MIME supertypes currently
659// installed in the MIME database.
660/*static*/ status_t
661BMimeType::GetInstalledSupertypes(BMessage* supertypes)
662{
663	if (supertypes == NULL)
664		return B_BAD_VALUE;
665
666	BMessage message(B_REG_MIME_GET_INSTALLED_SUPERTYPES);
667	status_t result;
668
669	status_t err = BRoster::Private().SendTo(&message, supertypes, true);
670	if (err == B_OK) {
671		err = (status_t)(supertypes->what == B_REG_RESULT ? B_OK
672			: B_BAD_REPLY);
673	}
674	if (err == B_OK)
675		err = supertypes->FindInt32("result", &result);
676	if (err == B_OK)
677		err = result;
678
679	return err;
680}
681
682
683// Fetches a BMessage listing all the MIME types currently installed
684// in the MIME database.
685status_t
686BMimeType::GetInstalledTypes(BMessage* types)
687{
688	return GetInstalledTypes(NULL, types);
689}
690
691
692// Fetches a BMessage listing all the MIME subtypes of the given
693// supertype currently installed in the MIME database.
694/*static*/ status_t
695BMimeType::GetInstalledTypes(const char* supertype, BMessage* types)
696{
697	if (types == NULL)
698		return B_BAD_VALUE;
699
700	status_t result;
701
702	// Build and send the message, read the reply
703	BMessage message(B_REG_MIME_GET_INSTALLED_TYPES);
704	status_t err = B_OK;
705
706	if (supertype != NULL)
707		err = message.AddString("supertype", supertype);
708	if (err == B_OK)
709		err = BRoster::Private().SendTo(&message, types, true);
710	if (err == B_OK)
711		err = (status_t)(types->what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
712	if (err == B_OK)
713		err = types->FindInt32("result", &result);
714	if (err == B_OK)
715		err = result;
716
717	return err;
718}
719
720
721// Fetches a \c BMessage containing a list of MIME signatures of
722// applications that are able to handle files of any type.
723status_t
724BMimeType::GetWildcardApps(BMessage* wild_ones)
725{
726	BMimeType mime;
727	status_t err = mime.SetTo("application/octet-stream");
728	if (err == B_OK)
729		err = mime.GetSupportingApps(wild_ones);
730	return err;
731}
732
733
734// Returns whether the given string represents a valid MIME type.
735bool
736BMimeType::IsValid(const char* string)
737{
738	if (string == NULL)
739		return false;
740
741	bool foundSlash = false;
742	size_t len = strlen(string);
743	if (len >= B_MIME_TYPE_LENGTH || len == 0)
744		return false;
745
746	for (size_t i = 0; i < len; i++) {
747		char ch = string[i];
748		if (ch == '/') {
749			if (foundSlash || i == 0 || i == len - 1)
750				return false;
751			else
752				foundSlash = true;
753		} else if (!isValidMimeChar(ch)) {
754			return false;
755		}
756	}
757	return true;
758}
759
760
761// Fetches an \c entry_ref that serves as a hint as to where the MIME type's
762// preferred application might live
763status_t
764BMimeType::GetAppHint(entry_ref* ref) const
765{
766	if (ref == NULL)
767		return B_BAD_VALUE;
768
769	status_t err = InitCheck();
770	if (err == B_OK)
771		err = default_database_location()->GetAppHint(Type(), *ref);
772	return err;
773}
774
775
776// Sets the app hint field for the MIME type
777status_t
778BMimeType::SetAppHint(const entry_ref* ref)
779{
780	status_t err = InitCheck();
781
782	BMessage message(ref ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
783	BMessage reply;
784	status_t result;
785
786	// Build and send the message, read the reply
787	if (err == B_OK)
788		err = message.AddString("type", Type());
789
790	if (err == B_OK)
791		err = message.AddInt32("which", B_REG_MIME_APP_HINT);
792
793	if (err == B_OK && ref != NULL)
794		err = message.AddRef("app hint", ref);
795
796	if (err == B_OK)
797		err = BRoster::Private().SendTo(&message, &reply, true);
798
799	if (err == B_OK)
800		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
801
802	if (err == B_OK)
803		err = reply.FindInt32("result", &result);
804
805	if (err == B_OK)
806		err = result;
807
808	return err;
809}
810
811
812// Fetches the large or mini icon used by an application of this type for
813// files of the given type.
814status_t
815BMimeType::GetIconForType(const char* type, BBitmap* icon, icon_size which) const
816{
817	if (icon == NULL)
818		return B_BAD_VALUE;
819
820	// If type is NULL, this function works just like GetIcon(), othewise,
821	// we need to make sure the give type is valid.
822	status_t err;
823	if (type) {
824		err = BMimeType::IsValid(type) ? B_OK : B_BAD_VALUE;
825		if (err == B_OK) {
826			err = default_database_location()->GetIconForType(Type(), type,
827				*icon, which);
828		}
829	} else
830		err = GetIcon(icon, which);
831
832	return err;
833}
834
835
836// Fetches the vector icon used by an application of this type for files of
837// the given type.
838status_t
839BMimeType::GetIconForType(const char* type, uint8** _data, size_t* _size) const
840{
841	if (_data == NULL || _size == NULL)
842		return B_BAD_VALUE;
843
844	// If type is NULL, this function works just like GetIcon(), otherwise,
845	// we need to make sure the give type is valid.
846	if (type == NULL)
847		return GetIcon(_data, _size);
848
849	if (!BMimeType::IsValid(type))
850		return B_BAD_VALUE;
851
852	return default_database_location()->GetIconForType(Type(), type, *_data,
853		*_size);
854}
855
856
857// Sets the large or mini icon used by an application of this type for
858// files of the given type.
859status_t
860BMimeType::SetIconForType(const char* type, const BBitmap* icon, icon_size which)
861{
862	status_t err = InitCheck();
863
864	BMessage message(icon ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
865	BMessage reply;
866	status_t result;
867
868	void* data = NULL;
869	int32 dataSize;
870
871	// Build and send the message, read the reply
872	if (err == B_OK)
873		err = message.AddString("type", Type());
874
875	if (err == B_OK) {
876		err = message.AddInt32("which",
877			type ? B_REG_MIME_ICON_FOR_TYPE : B_REG_MIME_ICON);
878	}
879
880	if (icon != NULL) {
881		if (err == B_OK)
882			err = get_icon_data(icon, which, &data, &dataSize);
883
884		if (err == B_OK)
885			err = message.AddData("icon data", B_RAW_TYPE, data, dataSize);
886	}
887
888	if (err == B_OK)
889		err = message.AddInt32("icon size", which);
890
891	if (type != NULL) {
892		if (err == B_OK)
893			err = BMimeType::IsValid(type) ? B_OK : B_BAD_VALUE;
894
895		if (err == B_OK)
896			err = message.AddString("file type", type);
897	}
898
899	if (err == B_OK)
900		err = BRoster::Private().SendTo(&message, &reply, true);
901
902	if (err == B_OK)
903		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
904
905	if (err == B_OK)
906		err = reply.FindInt32("result", &result);
907
908	if (err == B_OK)
909		err = result;
910
911	delete[] (int8*)data;
912
913	return err;
914}
915
916
917// Sets the large or mini icon used by an application of this type for
918// files of the given type.
919status_t
920BMimeType::SetIconForType(const char* type, const uint8* data, size_t dataSize)
921{
922	status_t err = InitCheck();
923
924	BMessage message(data ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
925	BMessage reply;
926	status_t result;
927
928	// Build and send the message, read the reply
929	if (err == B_OK)
930		err = message.AddString("type", Type());
931	if (err == B_OK)
932		err = message.AddInt32("which", (type ? B_REG_MIME_ICON_FOR_TYPE : B_REG_MIME_ICON));
933	if (data) {
934		if (err == B_OK)
935			err = message.AddData("icon data", B_RAW_TYPE, data, dataSize);
936	}
937	if (err == B_OK)
938		err = message.AddInt32("icon size", -1);
939		// -1 indicates size should be ignored (vector icon data)
940	if (type) {
941		if (err == B_OK)
942			err = BMimeType::IsValid(type) ? B_OK : B_BAD_VALUE;
943		if (err == B_OK)
944			err = message.AddString("file type", type);
945	}
946	if (err == B_OK)
947		err = BRoster::Private().SendTo(&message, &reply, true);
948	if (err == B_OK)
949		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
950	if (err == B_OK)
951		err = reply.FindInt32("result", &result);
952	if (err == B_OK)
953		err = result;
954
955	return err;
956}
957
958
959// Retrieves the MIME type's sniffer rule
960status_t
961BMimeType::GetSnifferRule(BString* result) const
962{
963	if (result == NULL)
964		return B_BAD_VALUE;
965
966	status_t err = InitCheck();
967	if (err == B_OK)
968		err = default_database_location()->GetSnifferRule(Type(), *result);
969
970	return err;
971}
972
973
974// Sets the MIME type's sniffer rule
975status_t
976BMimeType::SetSnifferRule(const char* rule)
977{
978	status_t err = InitCheck();
979	if (err == B_OK && rule != NULL && rule[0] != '\0')
980		err = CheckSnifferRule(rule, NULL);
981
982	if (err != B_OK)
983		return err;
984
985	BMessage message(rule && rule[0] ? B_REG_MIME_SET_PARAM
986		: B_REG_MIME_DELETE_PARAM);
987	BMessage reply;
988	status_t result;
989
990	// Build and send the message, read the reply
991	err = message.AddString("type", Type());
992	if (err == B_OK)
993		err = message.AddInt32("which", B_REG_MIME_SNIFFER_RULE);
994
995	if (err == B_OK && rule)
996		err = message.AddString("sniffer rule", rule);
997
998	if (err == B_OK)
999		err = BRoster::Private().SendTo(&message, &reply, true);
1000
1001	if (err == B_OK)
1002		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1003
1004	if (err == B_OK)
1005		err = reply.FindInt32("result", &result);
1006
1007	if (err == B_OK)
1008		err = result;
1009
1010	return err;
1011}
1012
1013
1014// Checks whether a MIME sniffer rule is valid or not.
1015status_t
1016BMimeType::CheckSnifferRule(const char* rule, BString* parseError)
1017{
1018	BPrivate::Storage::Sniffer::Rule snifferRule;
1019
1020	return BPrivate::Storage::Sniffer::parse(rule, &snifferRule, parseError);
1021}
1022
1023
1024// Guesses a MIME type for the entry referred to by the given
1025// entry_ref.
1026status_t
1027BMimeType::GuessMimeType(const entry_ref* file, BMimeType* type)
1028{
1029	status_t err = file && type ? B_OK : B_BAD_VALUE;
1030
1031	BMessage message(B_REG_MIME_SNIFF);
1032	BMessage reply;
1033	status_t result;
1034	const char* str;
1035
1036	// Build and send the message, read the reply
1037	if (err == B_OK)
1038		err = message.AddRef("file ref", file);
1039
1040	if (err == B_OK)
1041		err = BRoster::Private().SendTo(&message, &reply, true);
1042
1043	if (err == B_OK)
1044		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1045
1046	if (err == B_OK)
1047		err = reply.FindInt32("result", &result);
1048
1049	if (err == B_OK)
1050		err = result;
1051
1052	if (err == B_OK)
1053		err = reply.FindString("mime type", &str);
1054
1055	if (err == B_OK)
1056		err = type->SetTo(str);
1057
1058	return err;
1059}
1060
1061
1062// Guesses a MIME type for the supplied chunk of data.
1063status_t
1064BMimeType::GuessMimeType(const void* buffer, int32 length, BMimeType* type)
1065{
1066	status_t err = buffer && type ? B_OK : B_BAD_VALUE;
1067
1068	BMessage message(B_REG_MIME_SNIFF);
1069	BMessage reply;
1070	status_t result;
1071	const char* str;
1072
1073	// Build and send the message, read the reply
1074	if (err == B_OK)
1075		err = message.AddData("data", B_RAW_TYPE, buffer, length);
1076
1077	if (err == B_OK)
1078		err = BRoster::Private().SendTo(&message, &reply, true);
1079
1080	if (err == B_OK)
1081		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1082
1083	if (err == B_OK)
1084		err = reply.FindInt32("result", &result);
1085
1086	if (err == B_OK)
1087		err = result;
1088
1089	if (err == B_OK)
1090		err = reply.FindString("mime type", &str);
1091
1092	if (err == B_OK)
1093		err = type->SetTo(str);
1094
1095	return err;
1096}
1097
1098
1099// Guesses a MIME type for the given filename.
1100status_t
1101BMimeType::GuessMimeType(const char* filename, BMimeType* type)
1102{
1103	status_t err = filename && type ? B_OK : B_BAD_VALUE;
1104
1105	BMessage message(B_REG_MIME_SNIFF);
1106	BMessage reply;
1107	status_t result;
1108	const char* str;
1109
1110	// Build and send the message, read the reply
1111	if (err == B_OK)
1112		err = message.AddString("filename", filename);
1113
1114	if (err == B_OK)
1115		err = BRoster::Private().SendTo(&message, &reply, true);
1116
1117	if (err == B_OK)
1118		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1119
1120	if (err == B_OK)
1121		err = reply.FindInt32("result", &result);
1122
1123	if (err == B_OK)
1124		err = result;
1125
1126	if (err == B_OK)
1127		err = reply.FindString("mime type", &str);
1128
1129	if (err == B_OK)
1130		err = type->SetTo(str);
1131
1132	return err;
1133}
1134
1135
1136// Starts monitoring the MIME database for a given target.
1137status_t
1138BMimeType::StartWatching(BMessenger target)
1139{
1140	BMessage message(B_REG_MIME_START_WATCHING);
1141	BMessage reply;
1142	status_t result;
1143	status_t err;
1144
1145	// Build and send the message, read the reply
1146	err = message.AddMessenger("target", target);
1147	if (err == B_OK)
1148		err = BRoster::Private().SendTo(&message, &reply, true);
1149
1150	if (err == B_OK)
1151		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1152
1153	if (err == B_OK)
1154		err = reply.FindInt32("result", &result);
1155
1156	if (err == B_OK)
1157		err = result;
1158
1159	return err;
1160}
1161
1162
1163// Stops monitoring the MIME database for a given target
1164status_t
1165BMimeType::StopWatching(BMessenger target)
1166{
1167	BMessage message(B_REG_MIME_STOP_WATCHING);
1168	BMessage reply;
1169	status_t result;
1170	status_t err;
1171
1172	// Build and send the message, read the reply
1173	err = message.AddMessenger("target", target);
1174	if (err == B_OK)
1175		err = BRoster::Private().SendTo(&message, &reply, true);
1176
1177	if (err == B_OK)
1178		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1179
1180	if (err == B_OK)
1181		err = reply.FindInt32("result", &result);
1182
1183	if (err == B_OK)
1184		err = result;
1185
1186	return err;
1187}
1188
1189
1190// Initializes this object to the supplied MIME type
1191status_t
1192BMimeType::SetType(const char* mimeType)
1193{
1194	return SetTo(mimeType);
1195}
1196
1197
1198void BMimeType::_ReservedMimeType1() {}
1199void BMimeType::_ReservedMimeType2() {}
1200void BMimeType::_ReservedMimeType3() {}
1201
1202
1203#ifdef _BEOS_R5_COMPATIBLE_
1204// assignment operator.
1205// Unimplemented
1206BMimeType&
1207BMimeType::operator=(const BMimeType &)
1208{
1209	return *this;
1210		// not implemented
1211}
1212
1213
1214// copy constructor
1215// Unimplemented
1216BMimeType::BMimeType(const BMimeType &)
1217{
1218}
1219#endif
1220
1221
1222status_t
1223BMimeType::GetSupportedTypes(BMessage* types)
1224{
1225	if (types == NULL)
1226		return B_BAD_VALUE;
1227
1228	status_t err = InitCheck();
1229	if (err == B_OK)
1230		err = default_database_location()->GetSupportedTypes(Type(), *types);
1231
1232	return err;
1233}
1234
1235
1236/*!	Sets the list of MIME types supported by the MIME type (which is
1237	assumed to be an application signature).
1238
1239	If \a types is \c NULL the application's supported types are unset.
1240
1241	The supported MIME types must be stored in a field "types" of type
1242	\c B_STRING_TYPE in \a types.
1243
1244	For each supported type the result of BMimeType::GetSupportingApps() will
1245	afterwards include the signature of this application.
1246
1247	\a fullSync specifies whether or not any types that are no longer
1248	listed as supported types as of this call to SetSupportedTypes() shall be
1249	updated as well, i.e. whether this application shall be removed from their
1250	lists of supporting applications.
1251
1252	If \a fullSync is \c false, this application will not be removed from the
1253	previously supported types' supporting apps lists until the next call
1254	to BMimeType::SetSupportedTypes() or BMimeType::DeleteSupportedTypes()
1255	with a \c true \a fullSync parameter, the next call to BMimeType::Delete(),
1256	or the next reboot.
1257
1258	\param types The supported types to be assigned to the file.
1259	       May be \c NULL.
1260	\param fullSync \c true to also synchronize the previously supported
1261	       types, \c false otherwise.
1262
1263	\returns \c B_OK on success or another error code on failure.
1264*/
1265status_t
1266BMimeType::SetSupportedTypes(const BMessage* types, bool fullSync)
1267{
1268	status_t err = InitCheck();
1269
1270	// Build and send the message, read the reply
1271	BMessage message(types ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM);
1272	BMessage reply;
1273	status_t result;
1274
1275	if (err == B_OK)
1276		err = message.AddString("type", Type());
1277
1278	if (err == B_OK)
1279		err = message.AddInt32("which", B_REG_MIME_SUPPORTED_TYPES);
1280
1281	if (err != B_OK && types != NULL)
1282		err = message.AddMessage("types", types);
1283
1284	if (err == B_OK)
1285		err = message.AddBool("full sync", fullSync);
1286
1287	if (err == B_OK)
1288		err = BRoster::Private().SendTo(&message, &reply, true);
1289
1290	if (err == B_OK)
1291		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1292
1293	if (err == B_OK)
1294		err = reply.FindInt32("result", &result);
1295
1296	if (err == B_OK)
1297		err = result;
1298
1299	return err;
1300}
1301
1302
1303/*!	Returns a list of mime types associated with the given file extension
1304
1305	The list of types is returned in the pre-allocated \c BMessage pointed to
1306	by \a types. The types are stored in the message's "types" field, which
1307	is an array of \c B_STRING_TYPE values.
1308
1309	\param extension The file extension of interest
1310	\param types Pointer to a pre-allocated BMessage into which the result will
1311	       be stored.
1312
1313	\returns \c B_OK on success or another error code on failure.
1314*/
1315status_t
1316BMimeType::GetAssociatedTypes(const char* extension, BMessage* types)
1317{
1318	status_t err = extension && types ? B_OK : B_BAD_VALUE;
1319
1320	BMessage message(B_REG_MIME_GET_ASSOCIATED_TYPES);
1321	BMessage &reply = *types;
1322	status_t result;
1323
1324	// Build and send the message, read the reply
1325	if (err == B_OK)
1326		err = message.AddString("extension", extension);
1327
1328	if (err == B_OK)
1329		err = BRoster::Private().SendTo(&message, &reply, true);
1330
1331	if (err == B_OK)
1332		err = (status_t)(reply.what == B_REG_RESULT ? B_OK : B_BAD_REPLY);
1333
1334	if (err == B_OK)
1335		err = reply.FindInt32("result", &result);
1336
1337	if (err == B_OK)
1338		err = result;
1339
1340	return err;
1341}
1342