xref: /haiku/src/kits/storage/mime/Database.cpp (revision 7120e97489acbf17d86d3f33e3b2e68974fd4b23)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 /*!
6 	\file Database.cpp
7 	Database class implementation
8 */
9 
10 #include <Application.h>
11 #include <Bitmap.h>
12 #include <DataIO.h>
13 #include <Directory.h>
14 #include <Entry.h>
15 #include <Locker.h>
16 #include <Message.h>
17 #include <mime/database_access.h>
18 #include <mime/database_support.h>
19 #include <MimeType.h>
20 #include <Node.h>
21 #include <Path.h>
22 #include <String.h>
23 #include <storage_support.h>
24 #include <TypeConstants.h>
25 
26 #include <fs_attr.h>	// For struct attr_info
27 #include <iostream>
28 #include <new>			// For new(nothrow)
29 #include <stdio.h>
30 #include <string>
31 
32 #include "mime/Database.h"
33 
34 //#define DBG(x) x
35 #define DBG(x)
36 #define OUT printf
37 
38 // icon types
39 enum {
40 	B_MINI_ICON_TYPE	= 'MICN',
41 	B_LARGE_ICON_TYPE	= 'ICON',
42 };
43 
44 namespace BPrivate {
45 namespace Storage {
46 namespace Mime {
47 
48 /*!
49 	\class Database
50 	\brief Mime::Database is the master of the MIME data base.
51 
52 	All write and non-atomic read accesses are carried out by this class.
53 
54 	\note No error checking (other than checks for NULL pointers) is performed
55 	      by this class on the mime type strings passed to it. It's assumed
56 	      that this sort of checking has been done beforehand.
57 */
58 
59 // constructor
60 /*!	\brief Creates and initializes a Mime::Database object.
61 */
62 Database::Database()
63 	: fStatus(B_NO_INIT)
64 {
65 	// Do some really minor error checking
66 	BEntry entry(kDatabaseDir.c_str());
67 	fStatus = entry.Exists() ? B_OK : B_BAD_VALUE;
68 }
69 
70 // destructor
71 /*!	\brief Frees all resources associated with this object.
72 */
73 Database::~Database()
74 {
75 }
76 
77 // InitCheck
78 /*! \brief Returns the initialization status of the object.
79 	\return
80 	- B_OK: success
81 	- "error code": failure
82 */
83 status_t
84 Database::InitCheck() const
85 {
86 	return fStatus;
87 }
88 
89 // Install
90 /*!	\brief Installs the given type in the database
91 	\note The R5 version of this call returned an unreliable result if the
92 	      MIME type was already installed. Ours simply returns B_OK.
93 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
94 	\param decsription Pointer to a NULL-terminated string containing the new long description
95 	\return
96 	- B_OK: success
97 	- B_FILE_EXISTS: the type is already installed
98 	- "error code": failure
99 */
100 status_t
101 Database::Install(const char *type)
102 {
103 	BEntry entry;
104 	status_t err = (type ? B_OK : B_BAD_VALUE);
105 	if (!err)
106 		err = entry.SetTo(type_to_filename(type).c_str());
107 	if (!err) {
108 		if (entry.Exists())
109 			err = B_FILE_EXISTS;
110 		else {
111 			bool didCreate = false;
112 			BNode node;
113 			err = open_or_create_type(type, &node, &didCreate);
114 			if (!err && didCreate) {
115 				fInstalledTypes.AddType(type);
116 				err = SendInstallNotification(type);
117 			}
118 		}
119 	}
120 	return err;
121 }
122 
123 // Delete
124 /*!	\brief Removes the given type from the database
125 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
126 	\return
127 	- B_OK: success
128 	- "error code": failure
129 */
130 status_t
131 Database::Delete(const char *type)
132 {
133 	BEntry entry;
134 	status_t err = (type ? B_OK : B_BAD_VALUE);
135 	// Open the type
136 	if (!err)
137 		err = entry.SetTo(type_to_filename(type).c_str());
138 	// Remove it
139 	if (!err)
140 		err = entry.Remove();
141 	// Notify the installed types database
142 	if (!err)
143 		fInstalledTypes.RemoveType(type);
144 	// Notify the supporting apps database
145 	if (!err)
146 		err = fSupportingApps.DeleteSupportedTypes(type, true);
147 	// Notify the monitor service
148 	if (!err)
149 		err = SendDeleteNotification(type);
150 	return err;
151 }
152 
153 // SetAppHint
154 /*!	\brief Sets the application hint for the given MIME type
155 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
156 	\param decsription Pointer to an entry_ref containing the location of an application
157 	       that should be used when launching an application with this signature.
158 */
159 status_t
160 Database::SetAppHint(const char *type, const entry_ref *ref)
161 {
162 	DBG(OUT("Database::SetAppHint()\n"));
163 	BPath path;
164 	bool didCreate = false;
165 	status_t err = (type && ref) ? B_OK : B_BAD_VALUE;
166 	if (!err)
167 		err = path.SetTo(ref);
168 	if (!err)
169 		err = write_mime_attr(type, kAppHintAttr, path.Path(), strlen(path.Path())+1,
170 							    kAppHintType, &didCreate);
171 	if (!err && didCreate)
172 		err = SendInstallNotification(type);
173 	if (!err)
174 		err = SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_MODIFIED);
175 	return err;
176 }
177 
178 // SetAttrInfo
179 /*! \brief Stores a BMessage describing the format of attributes typically associated with
180 	files of the given MIME type
181 
182 	See BMimeType::SetAttrInfo() for description of the expected message format.
183 
184 	The \c BMessage::what value is ignored.
185 
186 	\param info Pointer to a pre-allocated and properly formatted BMessage containing
187 	            information about the file attributes typically associated with the
188 	            MIME type.
189 	\return
190 	- \c B_OK: Success
191 	- "error code": Failure
192 */
193 status_t
194 Database::SetAttrInfo(const char *type, const BMessage *info)
195 {
196 	DBG(OUT("Database::SetAttrInfo()\n"));
197 	bool didCreate = false;
198 	status_t err = (type && info) ? B_OK : B_BAD_VALUE;
199 	if (!err)
200 		err = write_mime_attr_message(type, kAttrInfoAttr, info, &didCreate);
201 	if (!err && didCreate)
202 		err = SendInstallNotification(type);
203 	if (!err)
204 		err = SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED);
205 	return err;
206 }
207 
208 // SetShortDescription
209 /*!	\brief Sets the short description for the given MIME type
210 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
211 	\param decsription Pointer to a NULL-terminated string containing the new short description
212 */
213 status_t
214 Database::SetShortDescription(const char *type, const char *description)
215 {
216 	DBG(OUT("Database::SetShortDescription()\n"));
217 	bool didCreate = false;
218 	status_t err = (type && description && strlen(description) < B_MIME_TYPE_LENGTH) ? B_OK : B_BAD_VALUE;
219 	if (!err)
220 		err = write_mime_attr(type, kShortDescriptionAttr, description, strlen(description)+1,
221 							    kShortDescriptionType, &didCreate);
222 	if (!err)
223 		err = SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_MODIFIED);
224 	return err;
225 }
226 
227 // SetLongDescription
228 /*!	\brief Sets the long description for the given MIME type
229 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
230 	\param decsription Pointer to a NULL-terminated string containing the new long description
231 */
232 status_t
233 Database::SetLongDescription(const char *type, const char *description)
234 {
235 	DBG(OUT("Database::SetLongDescription()\n"));
236 	bool didCreate = false;
237 	status_t err = (type && description && strlen(description) < B_MIME_TYPE_LENGTH) ? B_OK : B_BAD_VALUE;
238 	if (!err)
239 		err = write_mime_attr(type, kLongDescriptionAttr, description, strlen(description)+1,
240 							    kLongDescriptionType, &didCreate);
241 	if (!err && didCreate)
242 		err = SendInstallNotification(type);
243 	if (!err)
244 		err = SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_MODIFIED);
245 	return err;
246 }
247 
248 // SetFileExtensions
249 //! Sets the list of filename extensions associated with the MIME type
250 /*! The list of extensions is given in a pre-allocated BMessage pointed to by
251 	the \c extensions parameter. Please see BMimeType::SetFileExtensions()
252 	for a description of the expected message format.
253 
254 	\param extensions Pointer to a pre-allocated, properly formatted BMessage containing
255 	                  the new list of file extensions to associate with this MIME type.
256 	\return
257 	- \c B_OK: Success
258 	- "error code": Failure
259 */
260 status_t
261 Database::SetFileExtensions(const char *type, const BMessage *extensions)
262 {
263 	DBG(OUT("Database::SetFileExtensions()\n"));
264 	bool didCreate = false;
265 	status_t err = (type && extensions) ? B_OK : B_BAD_VALUE;
266 	if (!err)
267 		err = write_mime_attr_message(type, kFileExtensionsAttr, extensions, &didCreate);
268 	if (!err && didCreate)
269 		err = SendInstallNotification(type);
270 	if (!err)
271 		err = SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_MODIFIED);
272 	return err;
273 }
274 
275 //! Sets the icon for the given mime type
276 /*! This is the version I would have used if I could have gotten a BBitmap
277 	to the registrar somehow. Since R5::BBitmap::Instantiate is causing a
278 	violent crash, I've copied most of the icon	color conversion code into
279 	Mime::get_icon_data() so BMimeType::SetIcon() can get at it.
280 
281 	Once we have a sufficiently complete OBOS::BBitmap implementation, we
282 	ought to be able to use this version of SetIcon() again. At that point,
283 	I'll add some real documentation.
284 */
285 status_t
286 Database::SetIcon(const char *type, const void *data, size_t dataSize, icon_size which)
287 {
288 	return SetIconForType(type, NULL, data, dataSize, which);
289 }
290 
291 // SetIconForType
292 /*! \brief Sets the large or mini icon used by an application of this type for
293 	files of the given type.
294 
295 	The type of the \c BMimeType object is not required to actually be a subtype of
296 	\c "application/"; that is the intended use however, and application-specific
297 	icons are not expected to be present for non-application types.
298 
299 	The bitmap data pointed to by \c data must be of the proper size (\c 32x32
300 	for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and the proper color
301 	space (B_CMAP8).
302 
303 	\param type The MIME type
304 	\param fileType The MIME type whose custom icon you wish to set.
305 	\param data Pointer to an array of bitmap data of proper dimensions and color depth
306 	\param dataSize The length of the array pointed to by \c data
307 	\param size The size icon you're expecting (\c B_LARGE_ICON or \c B_MINI_ICON)
308 	\return
309 	- \c B_OK: Success
310 	- "error code": Failure
311 
312 */
313 status_t
314 Database::SetIconForType(const char *type, const char *fileType, const void *data,
315 							   size_t dataSize, icon_size which)
316 {
317 	ssize_t err = (type && data) ? B_OK : B_BAD_VALUE;
318 
319 	std::string attr;
320 	int32 attrType = 0;
321 	size_t attrSize = 0;
322 
323 	// Figure out what kind of data we *should* have
324 	if (!err) {
325 		switch (which) {
326 			case B_MINI_ICON:
327 				attrType = kMiniIconType;
328 				attrSize = 16 * 16;
329 				break;
330 			case B_LARGE_ICON:
331 				attrType = kLargeIconType;
332 				attrSize = 32 * 32;
333 				break;
334 			default:
335 				err = B_BAD_VALUE;
336 				break;
337 		}
338 	}
339 
340 	// Construct our attribute name
341 	if (fileType) {
342 		attr = (which == B_MINI_ICON
343 	              ? kMiniIconAttrPrefix
344 	                : kLargeIconAttrPrefix)
345 	                  + BPrivate::Storage::to_lower(fileType);
346 	} else
347 		attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr;
348 
349 	// Double check the data we've been given
350 	if (!err)
351 		err = dataSize == attrSize ? B_OK : B_BAD_VALUE;
352 
353 	// Write the icon data
354 	BNode node;
355 	bool didCreate = false;
356 	if (!err)
357 		err = open_or_create_type(type, &node, &didCreate);
358 	if (!err && didCreate)
359 		err = SendInstallNotification(type);
360 	if (!err)
361 		err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize);
362 	if (err >= 0)
363 		err = err == (ssize_t)attrSize ? B_OK : B_FILE_ERROR;
364 	if (!err) {
365 		if (fileType)
366 			err = SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, (which == B_LARGE_ICON), B_META_MIME_MODIFIED);
367 		else
368 			err = SendMonitorUpdate(B_ICON_CHANGED, type, (which == B_LARGE_ICON), B_META_MIME_MODIFIED);
369 	}
370 	return err;
371 
372 }
373 
374 // SetPreferredApp
375 /*!	\brief Sets the signature of the preferred application for the given app verb
376 
377 	Currently, the only supported app verb is \c B_OPEN
378 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
379 	\param signature Pointer to a NULL-terminated string containing the MIME signature
380 	                 of the new preferred application
381 	\param verb \c app_verb action for which the new preferred application is applicable
382 */
383 status_t
384 Database::SetPreferredApp(const char *type, const char *signature, app_verb verb = B_OPEN)
385 {
386 	DBG(OUT("Database::SetPreferredApp()\n"));
387 	bool didCreate = false;
388 	status_t err = (type && signature && strlen(signature) < B_MIME_TYPE_LENGTH) ? B_OK : B_BAD_VALUE;
389 	if (!err)
390 		err = write_mime_attr(type, kPreferredAppAttr, signature, strlen(signature)+1,
391 		                        kPreferredAppType, &didCreate);
392 	if (!err && didCreate)
393 		err = SendInstallNotification(type);
394 	if (!err)
395 		err = SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_MODIFIED);
396 	return err;
397 }
398 
399 // SetSnifferRule
400 /*! \brief Sets the mime sniffer rule for the given mime type
401 */
402 status_t
403 Database::SetSnifferRule(const char *type, const char *rule)
404 {
405 	DBG(OUT("Database::SetSnifferRule()\n"));
406 	bool didCreate = false;
407 	status_t err = (type && rule) ? B_OK : B_BAD_VALUE;
408 	if (!err)
409 		err = write_mime_attr(type, kSnifferRuleAttr, rule, strlen(rule)+1,
410 		                        kSnifferRuleType, &didCreate);
411 	if (!err)
412 		err = fSnifferRules.SetSnifferRule(type, rule);
413 	if (!err && didCreate)
414 		err = SendInstallNotification(type);
415 	if (!err)
416 		err = SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_MODIFIED);
417 	return err;
418 }
419 
420 // SetSupportedTypes
421 /*!	\brief Sets the list of MIME types supported by the MIME type and
422 	syncs the internal supporting apps database either partially or
423 	completely.
424 
425 	Please see BMimeType::SetSupportedTypes() for details.
426 	\param type The mime type of interest
427 	\param types The supported types to be assigned to the file.
428 	\param syncAll \c true to also synchronize the previously supported
429 		   types, \c false otherwise.
430 	\return
431 	- \c B_OK: success
432 	- other error codes: failure
433 */
434 status_t
435 Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSync)
436 {
437 	DBG(OUT("Database::SetSupportedTypes()\n"));
438 	bool didCreate = false;
439 	status_t err = (type && types) ? B_OK : B_BAD_VALUE;
440 	// Install the types
441 	if (!err) {
442 		const char *supportedType;
443 		for (int32 i = 0;
444 			 err == B_OK
445 			 && types->FindString("types", i, &supportedType) == B_OK;
446 			 i++) {
447 			if (!is_installed(supportedType))
448 				err = Install(supportedType);
449 		}
450 	}
451 	// Write the attr
452 	if (!err)
453 		err = write_mime_attr_message(type, kSupportedTypesAttr, types, &didCreate);
454 	// Notify the monitor if we created the type when we opened it
455 	if (!err && didCreate)
456 		err = SendInstallNotification(type);
457 	// Update the supporting apps map
458 	if (!err)
459 		err = fSupportingApps.SetSupportedTypes(type, types, fullSync);
460 	// Notify the monitor
461 	if (!err)
462 		err = SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_MODIFIED);
463 	return err;
464 }
465 
466 // GetInstalledSupertypes
467 /*! \brief Fetches a BMessage listing all the MIME supertypes currently
468 	installed in the MIME database.
469 
470 	The types are copied into the \c "super_types" field of the passed-in \c BMessage.
471 	The \c BMessage must be pre-allocated.
472 
473 	\param super_types Pointer to a pre-allocated \c BMessage into which the
474 	                   MIME supertypes will be copied.
475 	\return
476 	- \c B_OK: Success
477 	- "error code": Failure
478 */
479 status_t
480 Database::GetInstalledSupertypes(BMessage *supertypes)
481 {
482 	return fInstalledTypes.GetInstalledSupertypes(supertypes);
483 }
484 
485 // GetInstalledTypes
486 /*! \brief Fetches a BMessage listing all the MIME types currently installed
487 	in the MIME database.
488 
489 	The types are copied into the \c "types" field of the passed-in \c BMessage.
490 	The \c BMessage must be pre-allocated.
491 
492 	\param types Pointer to a pre-allocated \c BMessage into which the
493 	             MIME types will be copied.
494 	\return
495 	- \c B_OK: Success
496 	- "error code": Failure
497 */
498 status_t
499 Database::GetInstalledTypes(BMessage *types)
500 {
501 	return fInstalledTypes.GetInstalledTypes(types);
502 }
503 
504 // GetInstalledTypes
505 /*! \brief Fetches a BMessage listing all the MIME subtypes of the given
506 	supertype currently installed in the MIME database.
507 
508 	The types are copied into the \c "types" field of the passed-in \c BMessage.
509 	The \c BMessage must be pre-allocated.
510 
511 	\param super_type Pointer to a string containing the MIME supertype whose
512 	                  subtypes you wish to retrieve.
513 	\param subtypes Pointer to a pre-allocated \c BMessage into which the appropriate
514 	                MIME subtypes will be copied.
515 	\return
516 	- \c B_OK: Success
517 	- "error code": Failure
518 */
519 status_t
520 Database::GetInstalledTypes(const char *supertype, BMessage *subtypes)
521 {
522 	return fInstalledTypes.GetInstalledTypes(supertype, subtypes);
523 }
524 
525 // GetSupportingApps
526 /*! \brief Fetches a \c BMessage containing a list of MIME signatures of
527 	applications that are able to handle files of this MIME type.
528 
529 	Please see BMimeType::GetSupportingApps() for more details.
530 */
531 status_t
532 Database::GetSupportingApps(const char *type, BMessage *signatures)
533 {
534 	return fSupportingApps.GetSupportingApps(type, signatures);
535 }
536 
537 // GetAssociatedTypes
538 /*! \brief Returns a list of mime types associated with the given file extension
539 
540 	Please see BMimeType::GetAssociatedTypes() for more details.
541 */
542 status_t
543 Database::GetAssociatedTypes(const char *extension, BMessage *types)
544 {
545 	return B_ERROR;
546 }
547 
548 // GuessMimeType
549 /*!	\brief Guesses a MIME type for the entry referred to by the given
550 	\c entry_ref.
551 
552 	This version of GuessMimeType() combines the features of the other
553 	versions, plus adds a few tricks of its own:
554 	- If the entry is a meta mime entry (i.e. has a \c "META:TYPE" attribute),
555 	  the type returned is \c "application/x-vnd.be-meta-mime".
556 	- If the entry is a directory, the type returned is
557 	  \c "application/x-vnd.be-directory".
558 	- If the entry is a symlink, the type returned is
559 	  \c "application/x-vnd.be-symlink".
560 	- If the entry is a regular file, the file data is sniffed and, the
561 	  type returned is the mime type with the matching rule of highest
562 	  priority.
563 	- If sniffing fails, the filename is checked for known extensions.
564 	- If the extension check fails, the type returned is
565 	  \c "application/octet-stream".
566 
567 	\param ref Pointer to the entry_ref referring to the entry.
568 	\param type Pointer to a pre-allocated BString which is set to the
569 		   resulting MIME type.
570 	\return
571 	- \c B_OK: success (even if the guess returned is "application/octet-stream")
572 	- other error code: failure
573 */
574 status_t
575 Database::GuessMimeType(const entry_ref *file, BString *result)
576 {
577 	status_t err = file && result ? B_OK : B_BAD_VALUE;
578 
579 	BNode node;
580 	struct stat statData;
581 	if (!err)
582 		err = node.SetTo(file);
583 	if (!err) {
584 		attr_info info;
585 		if (node.GetAttrInfo(kTypeAttr, &info) == B_OK) {
586 			// Check for a META:TYPE attribute
587 			result->SetTo(kMetaMimeType);
588 			BPath path(file);
589 		} else {
590 			// See if we have a directory, a symlink, or a vanilla file
591 			err = node.GetStat(&statData);
592 			if (!err) {
593 				if (S_ISDIR(statData.st_mode)) {
594 					// Directory
595 					result->SetTo(kDirectoryType);
596 				} else if (S_ISLNK(statData.st_mode)) {
597 					// Symlink
598 					result->SetTo(kSymlinkType);
599 				} else if (S_ISREG(statData.st_mode)) {
600 					// Vanilla file: sniff first
601 					err = fSnifferRules.GuessMimeType(file, result);
602 					// If that fails, check extensions
603 					if (err == kMimeGuessFailureError)
604 						err = fAssociatedTypes.GuessMimeType(file, result);
605 					// If that fails, return the generic file type
606 					if (err == kMimeGuessFailureError) {
607 						result->SetTo(kGenericFileType);
608 						err = B_OK;
609 					}
610 				}
611 			}
612 		}
613 	}
614 	return err;
615 }
616 
617 // GuessMimeType
618 /*!	\brief Guesses a MIME type for the supplied chunk of data.
619 
620 	See \c SnifferRules::GuessMimeType(BPositionIO*, BString*)
621 	for more details.
622 
623 	\param buffer Pointer to the data buffer.
624 	\param length Size of the buffer in bytes.
625 	\param type Pointer to a pre-allocated BString which is set to the
626 		   resulting MIME type.
627 	\return
628 	- \c B_OK: success
629 	- error code: failure
630 */
631 status_t
632 Database::GuessMimeType(const void *buffer, int32 length, BString *result)
633 {
634 	status_t err = buffer && result ? B_OK : B_BAD_VALUE;
635 	if (!err)
636 		err = fSnifferRules.GuessMimeType(buffer, length, result);
637 	if (err == kMimeGuessFailureError) {
638 		result->SetTo(kGenericFileType);
639 		err = B_OK;
640 	}
641 	return err;
642 }
643 
644 // GuessMimeType
645 /*!	\brief Guesses a MIME type for the given filename.
646 
647 	Only the filename itself is taken into consideration (in particular its
648 	name extension), not the entry or corresponding data it refers to (in fact,
649 	an entry with that name need not exist at all.
650 
651 	\param filename The filename.
652 	\param type Pointer to a pre-allocated BString which is set to the
653 		   resulting MIME type.
654 	\return
655 	- \c B_OK: success
656 	- error code: failure
657 */
658 status_t
659 Database::GuessMimeType(const char *filename, BString *result)
660 {
661 	status_t err = filename && result ? B_OK : B_BAD_VALUE;
662 	if (!err)
663 		err = fAssociatedTypes.GuessMimeType(filename, result);
664 	if (err == kMimeGuessFailureError) {
665 		result->SetTo(kGenericFileType);
666 		err = B_OK;
667 	}
668 	return err;
669 }
670 
671 // StartWatching
672 //!	Subscribes the given BMessenger to the MIME monitor service
673 /*!	Notification messages will be sent with a \c BMessage::what value
674 	of \c B_META_MIME_CHANGED. Notification messages have the following
675 	fields:
676 
677 	<table>
678 		<tr>
679 			<td> Name </td>
680 			<td> Type </td>
681 			<td> Description </td>
682 		</tr>
683 		<tr>
684 			<td> \c be:type </td>
685 			<td> \c B_STRING_TYPE </td>
686 			<td> The MIME type that was changed </td>
687 		</tr>
688 		<tr>
689 			<td> \c be:which </td>
690 			<td> \c B_INT32_TYPE </td>
691 			<td> Bitmask describing which attributes were changed (see below) </td>
692 		</tr>
693 		<tr>
694 			<td> \c be:extra_type </td>
695 			<td> \c B_STRING_TYPE </td>
696 			<td> Additional MIME type string (applicable to B_ICON_FOR_TYPE_CHANGED notifications only)</td>
697 		</tr>
698 		<tr>
699 			<td> \c be:large_icon </td>
700 			<td> \c B_BOOL_TYPE </td>
701 			<td> \c true if the large icon was changed, \c false if the small icon
702 			     was changed (applicable to B_ICON_[FOR_TYPE_]CHANGED updates only) </td>
703 		</tr>
704 	</table>
705 
706 	The \c be:which field of the message describes which attributes were updated, and
707 	may be the bitwise \c OR of any of the following values:
708 
709 	<table>
710 		<tr>
711 			<td> Value </td>
712 			<td> Triggered By </td>
713 		</tr>
714 		<tr>
715 			<td> \c B_ICON_CHANGED </td>
716 			<td> \c BMimeType::SetIcon() </td>
717 		</tr>
718 		<tr>
719 			<td> \c B_PREFERRED_APP_CHANGED </td>
720 			<td> \c BMimeType::SetPreferredApp() </td>
721 		</tr>
722 		<tr>
723 			<td> \c B_ATTR_INFO_CHANGED </td>
724 			<td> \c BMimeType::SetAttrInfo() </td>
725 		</tr>
726 		<tr>
727 			<td> \c B_FILE_EXTENSIONS_CHANGED </td>
728 			<td> \c BMimeType::SetFileExtensions() </td>
729 		</tr>
730 		<tr>
731 			<td> \c B_SHORT_DESCRIPTION_CHANGED </td>
732 			<td> \c BMimeType::SetShortDescription() </td>
733 		</tr>
734 		<tr>
735 			<td> \c B_LONG_DESCRIPTION_CHANGED </td>
736 			<td> \c BMimeType::SetLongDescription() </td>
737 		</tr>
738 		<tr>
739 			<td> \c B_ICON_FOR_TYPE_CHANGED </td>
740 			<td> \c BMimeType::SetIconForType() </td>
741 		</tr>
742 		<tr>
743 			<td> \c B_APP_HINT_CHANGED </td>
744 			<td> \c BMimeType::SetAppHint() </td>
745 		</tr>
746 	</table>
747 
748 	\param target The \c BMessenger to subscribe to the MIME monitor service
749 */
750 status_t
751 Database::StartWatching(BMessenger target)
752 {
753 	DBG(OUT("Database::StartWatching()\n"));
754 	status_t err = target.IsValid() ? B_OK : B_BAD_VALUE;
755 	if (!err)
756 		fMonitorMessengers.insert(target);
757 	return err;
758 }
759 
760 // StartWatching
761 //!	Unsubscribes the given BMessenger from the MIME monitor service
762 /*! \param target The \c BMessenger to unsubscribe
763 */
764 status_t
765 Database::StopWatching(BMessenger target)
766 {
767 	DBG(OUT("Database::StopWatching()\n"));
768 	status_t err = target.IsValid() ? B_OK : B_BAD_VALUE;
769 	if (!err)
770 		err = fMonitorMessengers.find(target) != fMonitorMessengers.end() ? B_OK : B_ENTRY_NOT_FOUND;
771 	if (!err)
772 		fMonitorMessengers.erase(target);
773 	return err;
774 }
775 
776 // DeleteAppHint
777 //! Deletes the app hint attribute for the given type
778 /*! A \c B_APP_HINT_CHANGED notification is sent to the mime monitor service.
779 	\param type The mime type of interest
780 	\return
781 	- B_OK: success
782 	- B_ENTRY_NOT_FOUND: no such attribute existed
783 	- "error code": failure
784 */
785 status_t
786 Database::DeleteAppHint(const char *type)
787 {
788 	status_t err = delete_attribute(type, kAppHintAttr);
789 	if (!err)
790 		err = SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED);
791 	return err;
792 }
793 
794 // DeleteAttrInfo
795 //! Deletes the attribute info attribute for the given type
796 /*! A \c B_ATTR_INFO_CHANGED notification is sent to the mime monitor service.
797 	\param type The mime type of interest
798 	\return
799 	- B_OK: success
800 	- B_ENTRY_NOT_FOUND: no such attribute existed
801 	- "error code": failure
802 */
803 status_t
804 Database::DeleteAttrInfo(const char *type)
805 {
806 	status_t err = delete_attribute(type, kAttrInfoAttr);
807 	if (!err)
808 		err = SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED);
809 	return err;
810 }
811 
812 // DeleteShortDescription
813 //! Deletes the short description attribute for the given type
814 /*! A \c B_SHORT_DESCRIPTION_CHANGED notification is sent to the mime monitor service.
815 	\param type The mime type of interest
816 	\return
817 	- B_OK: success
818 	- B_ENTRY_NOT_FOUND: no such attribute existed
819 	- "error code": failure
820 */
821 status_t
822 Database::DeleteShortDescription(const char *type)
823 {
824 	status_t err = delete_attribute(type, kShortDescriptionAttr);
825 	if (!err)
826 		err = SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED);
827 	return err;
828 }
829 
830 // DeleteLongDescription
831 //! Deletes the long description attribute for the given type
832 /*! A \c B_LONG_DESCRIPTION_CHANGED notification is sent to the mime monitor service.
833 	\param type The mime type of interest
834 	\return
835 	- B_OK: success
836 	- B_ENTRY_NOT_FOUND: no such attribute existed
837 	- "error code": failure
838 */
839 status_t
840 Database::DeleteLongDescription(const char *type)
841 {
842 	status_t err = delete_attribute(type, kLongDescriptionAttr);
843 	if (!err)
844 		err = SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED);
845 	return err;
846 }
847 
848 // DeleteFileExtensions
849 //! Deletes the associated file extensions attribute for the given type
850 /*! A \c B_FILE_EXTENSIONS_CHANGED notification is sent to the mime monitor service.
851 	\param type The mime type of interest
852 	\return
853 	- B_OK: success
854 	- B_ENTRY_NOT_FOUND: no such attribute existed
855 	- "error code": failure
856 */
857 status_t
858 Database::DeleteFileExtensions(const char *type)
859 {
860 	status_t err = delete_attribute(type, kFileExtensionsAttr);
861 	if (!err)
862 		err = SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED);
863 	return err;
864 }
865 
866 // DeleteIcon
867 //! Deletes the icon of the given size for the given type
868 /*! A \c B_ICON_CHANGED notification is sent to the mime monitor service.
869 	\param type The mime type of interest
870 	\param which The icon size of interest
871 	\return
872 	- B_OK: success
873 	- B_ENTRY_NOT_FOUND: no such attribute existed
874 	- "error code": failure
875 */
876 status_t
877 Database::DeleteIcon(const char *type, icon_size which)
878 {
879 	const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr;
880 	status_t err = delete_attribute(type, attr);
881 	if (!err)
882 		err = SendMonitorUpdate(B_ICON_CHANGED, type, which, B_META_MIME_DELETED);
883 	return err;
884 }
885 
886 // DeleteIconForType
887 /*! \brief Deletes the icon of the given size associated with the given file type for the given
888     application signature.
889 
890     (If this function seems confusing, please see BMimeType::GetIconForType() for a
891     better description of what the *IconForType() functions are used for.)
892 
893 	A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service.
894 	\param type The mime type of the application whose custom icon you are deleting.
895 	\param which The mime type for which you no longer wish \c type to have a custom icon.
896 	\param which The icon size of interest
897 	\return
898 	- B_OK: success
899 	- B_ENTRY_NOT_FOUND: no such attribute existed
900 	- "error code": failure
901 */
902 status_t
903 Database::DeleteIconForType(const char *type, const char *fileType, icon_size which)
904 {
905 	std::string attr;
906 	status_t err = fileType ? B_OK : B_BAD_VALUE;
907 	if (!err) {
908 		attr = (which == B_MINI_ICON ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType);
909 		err = delete_attribute(type, attr.c_str());
910 	}
911 	if (!err)
912 		err = SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
913 		                          which == B_LARGE_ICON, B_META_MIME_DELETED);
914 	return err;
915 }
916 
917 // DeletePreferredApp
918 //! Deletes the preferred app for the given app verb for the given type
919 /*! A \c B_PREFERRED_APP_CHANGED notification is sent to the mime monitor service.
920 	\param type The mime type of interest
921 	\param which The app verb of interest
922 	\return
923 	- B_OK: success
924 	- B_ENTRY_NOT_FOUND: no such attribute existed
925 	- "error code": failure
926 */
927 status_t
928 Database::DeletePreferredApp(const char *type, app_verb verb = B_OPEN)
929 {
930 	status_t err;
931 	switch (verb) {
932 		case B_OPEN:
933 			err = delete_attribute(type, kPreferredAppAttr);
934 			break;
935 
936 		default:
937 			err = B_BAD_VALUE;
938 			break;
939 	}
940 	/*! \todo The R5 monitor makes no note of which app_verb value was updated. If
941 		additional app_verb values besides \c B_OPEN are someday added, the format
942 		of the MIME monitor messages will need to be augmented.
943 	*/
944 	if (!err)
945 		err = SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_DELETED);
946 	return err;
947 }
948 
949 // DeleteSnifferRule
950 //! Deletes the sniffer rule for the given type
951 /*! A \c B_SNIFFER_RULE_CHANGED notification is sent to the mime monitor service,
952 	and the corresponding rule is removed from the internal database of sniffer
953 	rules.
954 	\param type The mime type of interest
955 	\return
956 	- B_OK: success
957 	- B_ENTRY_NOT_FOUND: no such attribute existed
958 	- "error code": failure
959 */
960 status_t
961 Database::DeleteSnifferRule(const char *type)
962 {
963 	status_t err = delete_attribute(type, kSnifferRuleAttr);
964 	if (!err)
965 		err = fSnifferRules.DeleteSnifferRule(type);
966 	if (!err)
967 		err = SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_DELETED);
968 	return err;
969 }
970 
971 // DeleteSupportedTypes
972 //! Deletes the supported types list for the given type
973 /*! A \c B_SUPPORTED_TYPES_CHANGED notification is sent to the mime monitor service.
974 	If \c fullSync is \c true, the given type is removed from the internal list
975 	of supporting applictions for each previously supported type. If \c fullSync
976 	is \c false, the said removal will occur the next time SetSupportedTypes() or
977 	DeleteSupportedTypes() is called with a \c true \c fullSync paramter, or
978 	\c Delete() is called for the given type.
979 	\param type The mime type of interest
980 	\param fullSync Whether or not to remove the type as a supporting app for
981 	                all previously supported types
982 	\return
983 	- B_OK: success
984 	- B_ENTRY_NOT_FOUND: no such attribute existed
985 	- "error code": failure
986 */
987 status_t
988 Database::DeleteSupportedTypes(const char *type, bool fullSync)
989 {
990 	status_t err = delete_attribute(type, kSupportedTypesAttr);
991 	// Update the supporting apps database. If fullSync is specified,
992 	// do so even if the supported types attribute didn't exist, as
993 	// stranded types *may* exist in the database due to previous
994 	// calls to {Set,Delete}SupportedTypes() with fullSync == false.
995 	if (!err)
996 		err = fSupportingApps.DeleteSupportedTypes(type, fullSync);
997 	else if (fullSync && err == B_ENTRY_NOT_FOUND)
998 		fSupportingApps.DeleteSupportedTypes(type, fullSync);
999 	// Send a monitor notification
1000 	if (!err)
1001 		err = SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED);
1002 	return err;
1003 }
1004 
1005 // SendInstallNotification
1006 //! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service
1007 status_t
1008 Database::SendInstallNotification(const char *type)
1009 {
1010 //	fInstalledTypes.AddType(type);
1011 	status_t err = SendMonitorUpdate(B_MIME_TYPE_CREATED, type, B_META_MIME_MODIFIED);
1012 	return err;
1013 }
1014 
1015 // SendDeleteNotification
1016 //! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
1017 status_t
1018 //! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
1019 Database::SendDeleteNotification(const char *type)
1020 {
1021 	// Tell the backend first
1022 //	fInstalledTypes.RemoveType(type);
1023 	status_t err = SendMonitorUpdate(B_MIME_TYPE_DELETED, type, B_META_MIME_MODIFIED);
1024 	return err;
1025 }
1026 
1027 // SendMonitorUpdate
1028 /*! \brief Sends an update notification to all BMessengers that have
1029 	subscribed to the MIME Monitor service
1030 	\param type The MIME type that was updated
1031 	\param which Bitmask describing which attribute was updated
1032 	\param extraType The MIME type to which the change is applies
1033 	\param largeIcon \true if the the large icon was updated, \false if the
1034 		   small icon was updated
1035 */
1036 status_t
1037 Database::SendMonitorUpdate(int32 which, const char *type, const char *extraType, bool largeIcon, int32 action) {
1038 	BMessage msg(B_META_MIME_CHANGED);
1039 	status_t err;
1040 
1041 	err = msg.AddInt32("be:which", which);
1042 	if (!err)
1043 		err = msg.AddString("be:type", type);
1044 	if (!err)
1045 		err = msg.AddString("be:extra_type", extraType);
1046 	if (!err)
1047 		err = msg.AddBool("be:large_icon", largeIcon);
1048 	if (!err)
1049 		err = msg.AddInt32("be:action", action);
1050 	if (!err)
1051 		err = SendMonitorUpdate(msg);
1052 	return err;
1053 }
1054 
1055 // SendMonitorUpdate
1056 /*! \brief Sends an update notification to all BMessengers that have
1057 	subscribed to the MIME Monitor service
1058 	\param type The MIME type that was updated
1059 	\param which Bitmask describing which attribute was updated
1060 	\param extraType The MIME type to which the change is applies
1061 */
1062 status_t
1063 Database::SendMonitorUpdate(int32 which, const char *type, const char *extraType, int32 action) {
1064 	BMessage msg(B_META_MIME_CHANGED);
1065 	status_t err;
1066 
1067 	err = msg.AddInt32("be:which", which);
1068 	if (!err)
1069 		err = msg.AddString("be:type", type);
1070 	if (!err)
1071 		err = msg.AddString("be:extra_type", extraType);
1072 	if (!err)
1073 		err = msg.AddInt32("be:action", action);
1074 	if (!err)
1075 		err = SendMonitorUpdate(msg);
1076 	return err;
1077 }
1078 
1079 // SendMonitorUpdate
1080 /*! \brief Sends an update notification to all BMessengers that have
1081 	subscribed to the MIME Monitor service
1082 	\param type The MIME type that was updated
1083 	\param which Bitmask describing which attribute was updated
1084 	\param largeIcon \true if the the large icon was updated, \false if the
1085 		   small icon was updated
1086 */
1087 status_t
1088 Database::SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action) {
1089 	BMessage msg(B_META_MIME_CHANGED);
1090 	status_t err;
1091 
1092 	err = msg.AddInt32("be:which", which);
1093 	if (!err)
1094 		err = msg.AddString("be:type", type);
1095 	if (!err)
1096 		err = msg.AddBool("be:large_icon", largeIcon);
1097 	if (!err)
1098 		err = msg.AddInt32("be:action", action);
1099 	if (!err)
1100 		err = SendMonitorUpdate(msg);
1101 	return err;
1102 }
1103 
1104 // SendMonitorUpdate
1105 /*! \brief Sends an update notification to all BMessengers that have
1106 	subscribed to the MIME Monitor service
1107 	\param type The MIME type that was updated
1108 	\param which Bitmask describing which attribute was updated
1109 */
1110 status_t
1111 Database::SendMonitorUpdate(int32 which, const char *type, int32 action) {
1112 	BMessage msg(B_META_MIME_CHANGED);
1113 	status_t err;
1114 
1115 	err = msg.AddInt32("be:which", which);
1116 	if (!err)
1117 		err = msg.AddString("be:type", type);
1118 	if (!err)
1119 		err = msg.AddInt32("be:action", action);
1120 	if (!err)
1121 		err = SendMonitorUpdate(msg);
1122 	return err;
1123 }
1124 
1125 // SendMonitorUpdate
1126 /*! \brief Sends an update notification to all BMessengers that have subscribed to
1127 	the MIME Monitor service
1128 	\param BMessage A preformatted MIME monitor message to be sent to all subscribers
1129 */
1130 status_t
1131 Database::SendMonitorUpdate(BMessage &msg) {
1132 //	DBG(OUT("Database::SendMonitorUpdate(BMessage&)\n"));
1133 	status_t err;
1134 	std::set<BMessenger>::const_iterator i;
1135 	for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) {
1136 		status_t err = (*i).SendMessage(&msg, (BHandler*)NULL);
1137 		if (err)
1138 			DBG(OUT("Database::SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, 0x%lx\n", err));
1139 	}
1140 //	DBG(OUT("Database::SendMonitorUpdate(BMessage&) done\n"));
1141 	err = B_OK;
1142 	return err;
1143 }
1144 
1145 } // namespace Mime
1146 } // namespace Storage
1147 } // namespace BPrivate
1148 
1149