xref: /haiku/src/kits/storage/mime/Database.cpp (revision 6aff37d1c79e20748c683ae224bd629f88a5b0be)
1 /*
2  * Copyright 2002-2014, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Tyler Dauwalder
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Rene Gollent, rene@gollent.com.
9  */
10 
11 
12 #include <mime/Database.h>
13 
14 #include <stdio.h>
15 #include <string>
16 
17 #include <iostream>
18 #include <new>
19 
20 #include <Application.h>
21 #include <Bitmap.h>
22 #include <DataIO.h>
23 #include <Directory.h>
24 #include <Entry.h>
25 #include <fs_attr.h>
26 #include <Message.h>
27 #include <MimeType.h>
28 #include <Node.h>
29 #include <Path.h>
30 #include <String.h>
31 #include <TypeConstants.h>
32 
33 #include <AutoLocker.h>
34 #include <mime/database_support.h>
35 #include <mime/DatabaseLocation.h>
36 #include <storage_support.h>
37 
38 
39 //#define DBG(x) x
40 #define DBG(x)
41 #define OUT printf
42 
43 
44 namespace BPrivate {
45 namespace Storage {
46 namespace Mime {
47 
48 
49 Database::NotificationListener::~NotificationListener()
50 {
51 }
52 
53 
54 /*!
55 	\class Database
56 	\brief Mime::Database is the master of the MIME data base.
57 
58 	All write and non-atomic read accesses are carried out by this class.
59 
60 	\note No error checking (other than checks for NULL pointers) is performed
61 	      by this class on the mime type strings passed to it. It's assumed
62 	      that this sort of checking has been done beforehand.
63 */
64 
65 // constructor
66 /*!	\brief Creates and initializes a Mime::Database object.
67 */
68 Database::Database(DatabaseLocation* databaseLocation, MimeSniffer* mimeSniffer,
69 	NotificationListener* notificationListener)
70 	:
71 	fStatus(B_NO_INIT),
72 	fLocation(databaseLocation),
73 	fNotificationListener(notificationListener),
74 	fAssociatedTypes(databaseLocation, mimeSniffer),
75 	fInstalledTypes(databaseLocation),
76 	fSnifferRules(databaseLocation, mimeSniffer),
77 	fSupportingApps(databaseLocation),
78 	fDeferredInstallNotificationsLocker("deferred install notifications"),
79 	fDeferredInstallNotifications()
80 {
81 	// make sure the user's MIME DB directory exists
82 	fStatus = create_directory(fLocation->WritableDirectory(),
83 		S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
84 }
85 
86 // destructor
87 /*!	\brief Frees all resources associated with this object.
88 */
89 Database::~Database()
90 {
91 }
92 
93 // InitCheck
94 /*! \brief Returns the initialization status of the object.
95 	\return
96 	- B_OK: success
97 	- "error code": failure
98 */
99 status_t
100 Database::InitCheck() const
101 {
102 	return fStatus;
103 }
104 
105 // Install
106 /*!	\brief Installs the given type in the database
107 	\note The R5 version of this call returned an unreliable result if the
108 	      MIME type was already installed. Ours simply returns B_OK.
109 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
110 	\param decsription Pointer to a NULL-terminated string containing the new long description
111 	\return
112 	- B_OK: success
113 	- B_FILE_EXISTS: the type is already installed
114 	- "error code": failure
115 */
116 status_t
117 Database::Install(const char *type)
118 {
119 	if (type == NULL)
120 		return B_BAD_VALUE;
121 
122 	BEntry entry;
123 	status_t err = entry.SetTo(fLocation->WritablePathForType(type));
124 	if (err == B_OK || err == B_ENTRY_NOT_FOUND) {
125 		if (entry.Exists())
126 			err = B_FILE_EXISTS;
127 		else {
128 			bool didCreate = false;
129 			BNode node;
130 			err = fLocation->OpenWritableType(type, node, true, &didCreate);
131 			if (!err && didCreate) {
132 				fInstalledTypes.AddType(type);
133 				_SendInstallNotification(type);
134 			}
135 		}
136 	}
137 	return err;
138 }
139 
140 // Delete
141 /*!	\brief Removes the given type from the database
142 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
143 	\return
144 	- B_OK: success
145 	- "error code": failure
146 */
147 status_t
148 Database::Delete(const char *type)
149 {
150 	if (type == NULL)
151 		return B_BAD_VALUE;
152 
153 	// Open the type
154 	BEntry entry;
155 	status_t status = entry.SetTo(fLocation->WritablePathForType(type));
156 	if (status != B_OK)
157 		return status;
158 
159 	// Remove it
160 	if (entry.IsDirectory()) {
161 		// We need to remove all files in this directory
162 		BDirectory directory(&entry);
163 		if (directory.InitCheck() == B_OK) {
164 			size_t length = strlen(type);
165 			char subType[B_PATH_NAME_LENGTH];
166 			memcpy(subType, type, length);
167 			subType[length++] = '/';
168 
169 			BEntry subEntry;
170 			while (directory.GetNextEntry(&subEntry) == B_OK) {
171 				// Construct MIME type and remove it
172 				if (subEntry.GetName(subType + length) == B_OK) {
173 					status = Delete(subType);
174 					if (status != B_OK)
175 						return status;
176 				}
177 			}
178 		}
179 	}
180 
181 	status = entry.Remove();
182 
183 	if (status == B_OK) {
184 		// Notify the installed types database
185 		fInstalledTypes.RemoveType(type);
186 		// Notify the supporting apps database
187 		fSupportingApps.DeleteSupportedTypes(type, true);
188 		// Notify the monitor service
189 		_SendDeleteNotification(type);
190 	}
191 
192 	return status;
193 }
194 
195 
196 status_t
197 Database::_SetStringValue(const char *type, int32 what, const char* attribute,
198 	type_code attributeType, size_t maxLength, const char *value)
199 {
200 	size_t length = value != NULL ? strlen(value) : 0;
201 	if (type == NULL || value == NULL || length >= maxLength)
202 		return B_BAD_VALUE;
203 
204 	char oldValue[maxLength];
205 	status_t status = fLocation->ReadAttribute(type, attribute, oldValue,
206 		maxLength, attributeType);
207 	if (status >= B_OK && !strcmp(value, oldValue)) {
208 		// nothing has changed, no need to write back the data
209 		return B_OK;
210 	}
211 
212 	bool didCreate = false;
213 	status = fLocation->WriteAttribute(type, attribute, value, length + 1,
214 		attributeType, &didCreate);
215 
216 	if (status == B_OK) {
217 		if (didCreate)
218 			_SendInstallNotification(type);
219 		else
220 			_SendMonitorUpdate(what, type, B_META_MIME_MODIFIED);
221 	}
222 
223 	return status;
224 }
225 
226 
227 // SetAppHint
228 /*!	\brief Sets the application hint 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 an entry_ref containing the location of an application
231 	       that should be used when launching an application with this signature.
232 */
233 status_t
234 Database::SetAppHint(const char *type, const entry_ref *ref)
235 {
236 	DBG(OUT("Database::SetAppHint()\n"));
237 
238 	if (type == NULL || ref == NULL)
239 		return B_BAD_VALUE;
240 
241 	BPath path;
242 	status_t status = path.SetTo(ref);
243 	if (status < B_OK)
244 		return status;
245 
246 	return _SetStringValue(type, B_APP_HINT_CHANGED, kAppHintAttr,
247 		kAppHintType, B_PATH_NAME_LENGTH, path.Path());
248 }
249 
250 // SetAttrInfo
251 /*! \brief Stores a BMessage describing the format of attributes typically associated with
252 	files of the given MIME type
253 
254 	See BMimeType::SetAttrInfo() for description of the expected message format.
255 
256 	The \c BMessage::what value is ignored.
257 
258 	\param info Pointer to a pre-allocated and properly formatted BMessage containing
259 	            information about the file attributes typically associated with the
260 	            MIME type.
261 	\return
262 	- \c B_OK: Success
263 	- "error code": Failure
264 */
265 status_t
266 Database::SetAttrInfo(const char *type, const BMessage *info)
267 {
268 	DBG(OUT("Database::SetAttrInfo()\n"));
269 
270 	if (type == NULL || info == NULL)
271 		return B_BAD_VALUE;
272 
273 	bool didCreate = false;
274 	status_t status = fLocation->WriteMessageAttribute(type, kAttrInfoAttr,
275 		*info, &didCreate);
276 	if (status == B_OK) {
277 		if (didCreate)
278 			_SendInstallNotification(type);
279 		else
280 			_SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED);
281 	}
282 
283 	return status;
284 }
285 
286 
287 // SetShortDescription
288 /*!	\brief Sets the short description for the given MIME type
289 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
290 	\param decsription Pointer to a NULL-terminated string containing the new short description
291 */
292 status_t
293 Database::SetShortDescription(const char *type, const char *description)
294 {
295 	DBG(OUT("Database::SetShortDescription()\n"));
296 
297 	return _SetStringValue(type, B_SHORT_DESCRIPTION_CHANGED, kShortDescriptionAttr,
298 		kShortDescriptionType, B_MIME_TYPE_LENGTH, description);
299 }
300 
301 // SetLongDescription
302 /*!	\brief Sets the long description for the given MIME type
303 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
304 	\param decsription Pointer to a NULL-terminated string containing the new long description
305 */
306 status_t
307 Database::SetLongDescription(const char *type, const char *description)
308 {
309 	DBG(OUT("Database::SetLongDescription()\n"));
310 
311 	size_t length = description != NULL ? strlen(description) : 0;
312 	if (type == NULL || description == NULL || length >= B_MIME_TYPE_LENGTH)
313 		return B_BAD_VALUE;
314 
315 	return _SetStringValue(type, B_LONG_DESCRIPTION_CHANGED, kLongDescriptionAttr,
316 		kLongDescriptionType, B_MIME_TYPE_LENGTH, description);
317 }
318 
319 
320 /*!
321 	\brief Sets the list of filename extensions associated with the MIME type
322 
323 	The list of extensions is given in a pre-allocated BMessage pointed to by
324 	the \c extensions parameter. Please see BMimeType::SetFileExtensions()
325 	for a description of the expected message format.
326 
327 	\param extensions Pointer to a pre-allocated, properly formatted BMessage containing
328 	                  the new list of file extensions to associate with this MIME type.
329 	\return
330 	- \c B_OK: Success
331 	- "error code": Failure
332 */
333 status_t
334 Database::SetFileExtensions(const char *type, const BMessage *extensions)
335 {
336 	DBG(OUT("Database::SetFileExtensions()\n"));
337 
338 	if (type == NULL || extensions == NULL)
339 		return B_BAD_VALUE;
340 
341 	bool didCreate = false;
342 	status_t status = fLocation->WriteMessageAttribute(type,
343 		kFileExtensionsAttr, *extensions, &didCreate);
344 
345 	if (status == B_OK) {
346 		if (didCreate) {
347 			_SendInstallNotification(type);
348 		} else {
349 			_SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type,
350 				B_META_MIME_MODIFIED);
351 		}
352 	}
353 
354 	return status;
355 }
356 
357 
358 /*!
359 	\brief Sets a bitmap icon for the given mime type
360 */
361 status_t
362 Database::SetIcon(const char* type, const BBitmap* icon, icon_size which)
363 {
364 	if (icon != NULL)
365 		return SetIcon(type, icon->Bits(), icon->BitsLength(), which);
366 	return SetIcon(type, NULL, 0, which);
367 }
368 
369 
370 /*!
371 	\brief Sets a bitmap icon for the given mime type
372 */
373 status_t
374 Database::SetIcon(const char *type, const void *data, size_t dataSize,
375 	icon_size which)
376 {
377 	return SetIconForType(type, NULL, data, dataSize, which);
378 }
379 
380 
381 /*!
382 	\brief Sets the vector icon for the given mime type
383 */
384 status_t
385 Database::SetIcon(const char *type, const void *data, size_t dataSize)
386 {
387 	return SetIconForType(type, NULL, data, dataSize);
388 }
389 
390 
391 status_t
392 Database::SetIconForType(const char* type, const char* fileType,
393 	const BBitmap* icon, icon_size which)
394 {
395 	if (icon != NULL) {
396 		return SetIconForType(type, fileType, icon->Bits(),
397 			(size_t)icon->BitsLength(), which);
398 	}
399 	return SetIconForType(type, fileType, NULL, 0, which);
400 }
401 
402 
403 // SetIconForType
404 /*! \brief Sets the large or mini icon used by an application of this type for
405 	files of the given type.
406 
407 	The type of the \c BMimeType object is not required to actually be a subtype of
408 	\c "application/"; that is the intended use however, and application-specific
409 	icons are not expected to be present for non-application types.
410 
411 	The bitmap data pointed to by \c data must be of the proper size (\c 32x32
412 	for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and the proper color
413 	space (B_CMAP8).
414 
415 	\param type The MIME type
416 	\param fileType The MIME type whose custom icon you wish to set.
417 	\param data Pointer to an array of bitmap data of proper dimensions and color depth
418 	\param dataSize The length of the array pointed to by \c data
419 	\param size The size icon you're expecting (\c B_LARGE_ICON or \c B_MINI_ICON)
420 	\return
421 	- \c B_OK: Success
422 	- "error code": Failure
423 
424 */
425 status_t
426 Database::SetIconForType(const char *type, const char *fileType,
427 	const void *data, size_t dataSize, icon_size which)
428 {
429 	DBG(OUT("Database::SetIconForType()\n"));
430 
431 	if (type == NULL || data == NULL)
432 		return B_BAD_VALUE;
433 
434 	int32 attrType = 0;
435 
436 	// Figure out what kind of data we *should* have
437 	switch (which) {
438 		case B_MINI_ICON:
439 			attrType = kMiniIconType;
440 			break;
441 		case B_LARGE_ICON:
442 			attrType = kLargeIconType;
443 			break;
444 
445 		default:
446 			return B_BAD_VALUE;
447 	}
448 
449 	size_t attrSize = (size_t)which * (size_t)which;
450 	// Double check the data we've been given
451 	if (dataSize != attrSize)
452 		return B_BAD_VALUE;
453 
454 	// Construct our attribute name
455 	std::string attr;
456 	if (fileType) {
457 		attr = (which == B_MINI_ICON
458 			? kMiniIconAttrPrefix : kLargeIconAttrPrefix)
459 			+ BPrivate::Storage::to_lower(fileType);
460 	} else
461 		attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr;
462 
463 	// Write the icon data
464 	BNode node;
465 	bool didCreate = false;
466 
467 	status_t err = fLocation->OpenWritableType(type, node, true, &didCreate);
468 	if (err != B_OK)
469 		return err;
470 
471 	if (!err)
472 		err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize);
473 	if (err >= 0)
474 		err = err == (ssize_t)attrSize ? (status_t)B_OK : (status_t)B_FILE_ERROR;
475 	if (didCreate) {
476 		_SendInstallNotification(type);
477 	} else if (!err) {
478 		if (fileType) {
479 			_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
480 				which == B_LARGE_ICON, B_META_MIME_MODIFIED);
481 		} else {
482 			_SendMonitorUpdate(B_ICON_CHANGED, type,
483 				which == B_LARGE_ICON, B_META_MIME_MODIFIED);
484 		}
485 	}
486 	return err;
487 }
488 
489 // SetIconForType
490 /*! \brief Sets the vector icon used by an application of this type for
491 	files of the given type.
492 
493 	The type of the \c BMimeType object is not required to actually be a subtype of
494 	\c "application/"; that is the intended use however, and application-specific
495 	icons are not expected to be present for non-application types.
496 
497 	\param type The MIME type
498 	\param fileType The MIME type whose custom icon you wish to set.
499 	\param data Pointer to an array of vector data
500 	\param dataSize The length of the array pointed to by \c data
501 	\return
502 	- \c B_OK: Success
503 	- "error code": Failure
504 
505 */
506 status_t
507 Database::SetIconForType(const char *type, const char *fileType,
508 	const void *data, size_t dataSize)
509 {
510 	DBG(OUT("Database::SetIconForType()\n"));
511 
512 	if (type == NULL || data == NULL)
513 		return B_BAD_VALUE;
514 
515 	int32 attrType = B_VECTOR_ICON_TYPE;
516 
517 	// Construct our attribute name
518 	std::string attr;
519 	if (fileType) {
520 		attr = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType);
521 	} else
522 		attr = kIconAttr;
523 
524 	// Write the icon data
525 	BNode node;
526 	bool didCreate = false;
527 
528 	status_t err = fLocation->OpenWritableType(type, node, true, &didCreate);
529 	if (err != B_OK)
530 		return err;
531 
532 	if (!err)
533 		err = node.WriteAttr(attr.c_str(), attrType, 0, data, dataSize);
534 	if (err >= 0)
535 		err = err == (ssize_t)dataSize ? (status_t)B_OK : (status_t)B_FILE_ERROR;
536 	if (didCreate) {
537 		_SendInstallNotification(type);
538 	} else if (!err) {
539 		// TODO: extra notification for vector icons (currently
540 		// passing "true" for B_LARGE_ICON)?
541 		if (fileType) {
542 			_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
543 				true, B_META_MIME_MODIFIED);
544 		} else {
545 			_SendMonitorUpdate(B_ICON_CHANGED, type, true,
546 				B_META_MIME_MODIFIED);
547 		}
548 	}
549 	return err;
550 }
551 
552 // SetPreferredApp
553 /*!	\brief Sets the signature of the preferred application for the given app verb
554 
555 	Currently, the only supported app verb is \c B_OPEN
556 	\param type Pointer to a NULL-terminated string containing the MIME type of interest
557 	\param signature Pointer to a NULL-terminated string containing the MIME signature
558 	                 of the new preferred application
559 	\param verb \c app_verb action for which the new preferred application is applicable
560 */
561 status_t
562 Database::SetPreferredApp(const char *type, const char *signature, app_verb verb)
563 {
564 	DBG(OUT("Database::SetPreferredApp()\n"));
565 
566 	// TODO: use "verb" some day!
567 
568 	return _SetStringValue(type, B_PREFERRED_APP_CHANGED, kPreferredAppAttr,
569 		kPreferredAppType, B_MIME_TYPE_LENGTH, signature);
570 }
571 
572 // SetSnifferRule
573 /*! \brief Sets the mime sniffer rule for the given mime type
574 */
575 status_t
576 Database::SetSnifferRule(const char *type, const char *rule)
577 {
578 	DBG(OUT("Database::SetSnifferRule()\n"));
579 
580 	if (type == NULL || rule == NULL)
581 		return B_BAD_VALUE;
582 
583 	bool didCreate = false;
584 	status_t status = fLocation->WriteAttribute(type, kSnifferRuleAttr, rule,
585 		strlen(rule) + 1, kSnifferRuleType, &didCreate);
586 
587 	if (status == B_OK)
588 		status = fSnifferRules.SetSnifferRule(type, rule);
589 
590 	if (didCreate) {
591 		_SendInstallNotification(type);
592 	} else if (status == B_OK) {
593 		_SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type,
594 			B_META_MIME_MODIFIED);
595 	}
596 
597 	return status;
598 }
599 
600 // SetSupportedTypes
601 /*!	\brief Sets the list of MIME types supported by the MIME type and
602 	syncs the internal supporting apps database either partially or
603 	completely.
604 
605 	Please see BMimeType::SetSupportedTypes() for details.
606 	\param type The mime type of interest
607 	\param types The supported types to be assigned to the file.
608 	\param syncAll \c true to also synchronize the previously supported
609 		   types, \c false otherwise.
610 	\return
611 	- \c B_OK: success
612 	- other error codes: failure
613 */
614 status_t
615 Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSync)
616 {
617 	DBG(OUT("Database::SetSupportedTypes()\n"));
618 
619 	if (type == NULL || types == NULL)
620 		return B_BAD_VALUE;
621 
622 	// Install the types
623 	const char *supportedType;
624 	for (int32 i = 0; types->FindString("types", i, &supportedType) == B_OK; i++) {
625 		if (!fLocation->IsInstalled(supportedType)) {
626 			if (Install(supportedType) != B_OK)
627 				break;
628 
629 			// Since the type has been introduced by this application
630 			// we take the liberty and make it the preferred handler
631 			// for them, too.
632 			SetPreferredApp(supportedType, type, B_OPEN);
633 		}
634 	}
635 
636 	// Write the attr
637 	bool didCreate = false;
638 	status_t status = fLocation->WriteMessageAttribute(type,
639 		kSupportedTypesAttr, *types, &didCreate);
640 
641 	// Notify the monitor if we created the type when we opened it
642 	if (status != B_OK)
643 		return status;
644 
645 	// Update the supporting apps map
646 	if (status == B_OK)
647 		status = fSupportingApps.SetSupportedTypes(type, types, fullSync);
648 
649 	// Notify the monitor
650 	if (didCreate) {
651 		_SendInstallNotification(type);
652 	} else if (status == B_OK) {
653 		_SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type,
654 			B_META_MIME_MODIFIED);
655 	}
656 
657 	return status;
658 }
659 
660 
661 // GetInstalledSupertypes
662 /*! \brief Fetches a BMessage listing all the MIME supertypes currently
663 	installed in the MIME database.
664 
665 	The types are copied into the \c "super_types" field of the passed-in \c BMessage.
666 	The \c BMessage must be pre-allocated.
667 
668 	\param super_types Pointer to a pre-allocated \c BMessage into which the
669 	                   MIME supertypes will be copied.
670 	\return
671 	- \c B_OK: Success
672 	- "error code": Failure
673 */
674 status_t
675 Database::GetInstalledSupertypes(BMessage *supertypes)
676 {
677 	return fInstalledTypes.GetInstalledSupertypes(supertypes);
678 }
679 
680 // GetInstalledTypes
681 /*! \brief Fetches a BMessage listing all the MIME types currently installed
682 	in the MIME database.
683 
684 	The types are copied into the \c "types" field of the passed-in \c BMessage.
685 	The \c BMessage must be pre-allocated.
686 
687 	\param types Pointer to a pre-allocated \c BMessage into which the
688 	             MIME types will be copied.
689 	\return
690 	- \c B_OK: Success
691 	- "error code": Failure
692 */
693 status_t
694 Database::GetInstalledTypes(BMessage *types)
695 {
696 	return fInstalledTypes.GetInstalledTypes(types);
697 }
698 
699 // GetInstalledTypes
700 /*! \brief Fetches a BMessage listing all the MIME subtypes of the given
701 	supertype currently installed in the MIME database.
702 
703 	The types are copied into the \c "types" field of the passed-in \c BMessage.
704 	The \c BMessage must be pre-allocated.
705 
706 	\param super_type Pointer to a string containing the MIME supertype whose
707 	                  subtypes you wish to retrieve.
708 	\param subtypes Pointer to a pre-allocated \c BMessage into which the appropriate
709 	                MIME subtypes will be copied.
710 	\return
711 	- \c B_OK: Success
712 	- "error code": Failure
713 */
714 status_t
715 Database::GetInstalledTypes(const char *supertype, BMessage *subtypes)
716 {
717 	return fInstalledTypes.GetInstalledTypes(supertype, subtypes);
718 }
719 
720 // GetSupportingApps
721 /*! \brief Fetches a \c BMessage containing a list of MIME signatures of
722 	applications that are able to handle files of this MIME type.
723 
724 	Please see BMimeType::GetSupportingApps() for more details.
725 */
726 status_t
727 Database::GetSupportingApps(const char *type, BMessage *signatures)
728 {
729 	return fSupportingApps.GetSupportingApps(type, signatures);
730 }
731 
732 // GetAssociatedTypes
733 /*! \brief Returns a list of mime types associated with the given file extension
734 
735 	Please see BMimeType::GetAssociatedTypes() for more details.
736 */
737 status_t
738 Database::GetAssociatedTypes(const char *extension, BMessage *types)
739 {
740 	return B_ERROR;
741 }
742 
743 // GuessMimeType
744 /*!	\brief Guesses a MIME type for the entry referred to by the given
745 	\c entry_ref.
746 
747 	This version of GuessMimeType() combines the features of the other
748 	versions, plus adds a few tricks of its own:
749 	- If the entry is a meta mime entry (i.e. has a \c "META:TYPE" attribute),
750 	  the type returned is \c "application/x-vnd.be-meta-mime".
751 	- If the entry is a directory, the type returned is
752 	  \c "application/x-vnd.be-directory".
753 	- If the entry is a symlink, the type returned is
754 	  \c "application/x-vnd.be-symlink".
755 	- If the entry is a regular file, the file data is sniffed and, the
756 	  type returned is the mime type with the matching rule of highest
757 	  priority.
758 	- If sniffing fails, the filename is checked for known extensions.
759 	- If the extension check fails, the type returned is
760 	  \c "application/octet-stream".
761 
762 	\param ref Pointer to the entry_ref referring to the entry.
763 	\param type Pointer to a pre-allocated BString which is set to the
764 		   resulting MIME type.
765 	\return
766 	- \c B_OK: success (even if the guess returned is "application/octet-stream")
767 	- other error code: failure
768 */
769 status_t
770 Database::GuessMimeType(const entry_ref *ref, BString *result)
771 {
772 	if (ref == NULL || result == NULL)
773 		return B_BAD_VALUE;
774 
775 	BNode node;
776 	struct stat statData;
777 	status_t status = node.SetTo(ref);
778 	if (status < B_OK)
779 		return status;
780 
781 	attr_info info;
782 	if (node.GetAttrInfo(kTypeAttr, &info) == B_OK) {
783 		// Check for a META:TYPE attribute
784 		result->SetTo(kMetaMimeType);
785 		return B_OK;
786 	}
787 
788 	// See if we have a directory, a symlink, or a vanilla file
789 	status = node.GetStat(&statData);
790 	if (status < B_OK)
791 		return status;
792 
793 	if (S_ISDIR(statData.st_mode)) {
794 		// Directory
795 		result->SetTo(kDirectoryType);
796 	} else if (S_ISLNK(statData.st_mode)) {
797 		// Symlink
798 		result->SetTo(kSymlinkType);
799 	} else if (S_ISREG(statData.st_mode)) {
800 		// Vanilla file: sniff first
801 		status = fSnifferRules.GuessMimeType(ref, result);
802 
803 		// If that fails, check extensions
804 		if (status == kMimeGuessFailureError)
805 			status = fAssociatedTypes.GuessMimeType(ref, result);
806 
807 		// If that fails, return the generic file type
808 		if (status == kMimeGuessFailureError) {
809 			result->SetTo(kGenericFileType);
810 			status = B_OK;
811 		}
812 	} else {
813 		// TODO: we could filter out devices, ...
814 		return B_BAD_TYPE;
815 	}
816 
817 	return status;
818 }
819 
820 // GuessMimeType
821 /*!	\brief Guesses a MIME type for the supplied chunk of data.
822 
823 	See \c SnifferRules::GuessMimeType(BPositionIO*, BString*)
824 	for more details.
825 
826 	\param buffer Pointer to the data buffer.
827 	\param length Size of the buffer in bytes.
828 	\param type Pointer to a pre-allocated BString which is set to the
829 		   resulting MIME type.
830 	\return
831 	- \c B_OK: success
832 	- error code: failure
833 */
834 status_t
835 Database::GuessMimeType(const void *buffer, int32 length, BString *result)
836 {
837 	if (buffer == NULL || result == NULL)
838 		return B_BAD_VALUE;
839 
840 	status_t status = fSnifferRules.GuessMimeType(buffer, length, result);
841 	if (status == kMimeGuessFailureError) {
842 		result->SetTo(kGenericFileType);
843 		return B_OK;
844 	}
845 
846 	return status;
847 }
848 
849 // GuessMimeType
850 /*!	\brief Guesses a MIME type for the given filename.
851 
852 	Only the filename itself is taken into consideration (in particular its
853 	name extension), not the entry or corresponding data it refers to (in fact,
854 	an entry with that name need not exist at all.
855 
856 	\param filename The filename.
857 	\param type Pointer to a pre-allocated BString which is set to the
858 		   resulting MIME type.
859 	\return
860 	- \c B_OK: success
861 	- error code: failure
862 */
863 status_t
864 Database::GuessMimeType(const char *filename, BString *result)
865 {
866 	if (filename == NULL || result == NULL)
867 		return B_BAD_VALUE;
868 
869 	status_t status = fAssociatedTypes.GuessMimeType(filename, result);
870 	if (status == kMimeGuessFailureError) {
871 		result->SetTo(kGenericFileType);
872 		return B_OK;
873 	}
874 
875 	return status;
876 }
877 
878 
879 /*!	\brief Subscribes the given BMessenger to the MIME monitor service
880 
881 	Notification messages will be sent with a \c BMessage::what value
882 	of \c B_META_MIME_CHANGED. Notification messages have the following
883 	fields:
884 
885 	<table>
886 		<tr>
887 			<td> Name </td>
888 			<td> Type </td>
889 			<td> Description </td>
890 		</tr>
891 		<tr>
892 			<td> \c be:type </td>
893 			<td> \c B_STRING_TYPE </td>
894 			<td> The MIME type that was changed </td>
895 		</tr>
896 		<tr>
897 			<td> \c be:which </td>
898 			<td> \c B_INT32_TYPE </td>
899 			<td> Bitmask describing which attributes were changed (see below) </td>
900 		</tr>
901 		<tr>
902 			<td> \c be:extra_type </td>
903 			<td> \c B_STRING_TYPE </td>
904 			<td> Additional MIME type string (applicable to B_ICON_FOR_TYPE_CHANGED notifications only)</td>
905 		</tr>
906 		<tr>
907 			<td> \c be:large_icon </td>
908 			<td> \c B_BOOL_TYPE </td>
909 			<td> \c true if the large icon was changed, \c false if the small icon
910 			     was changed (applicable to B_ICON_[FOR_TYPE_]CHANGED updates only) </td>
911 		</tr>
912 	</table>
913 
914 	The \c be:which field of the message describes which attributes were updated, and
915 	may be the bitwise \c OR of any of the following values:
916 
917 	<table>
918 		<tr>
919 			<td> Value </td>
920 			<td> Triggered By </td>
921 		</tr>
922 		<tr>
923 			<td> \c B_ICON_CHANGED </td>
924 			<td> \c BMimeType::SetIcon() </td>
925 		</tr>
926 		<tr>
927 			<td> \c B_PREFERRED_APP_CHANGED </td>
928 			<td> \c BMimeType::SetPreferredApp() </td>
929 		</tr>
930 		<tr>
931 			<td> \c B_ATTR_INFO_CHANGED </td>
932 			<td> \c BMimeType::SetAttrInfo() </td>
933 		</tr>
934 		<tr>
935 			<td> \c B_FILE_EXTENSIONS_CHANGED </td>
936 			<td> \c BMimeType::SetFileExtensions() </td>
937 		</tr>
938 		<tr>
939 			<td> \c B_SHORT_DESCRIPTION_CHANGED </td>
940 			<td> \c BMimeType::SetShortDescription() </td>
941 		</tr>
942 		<tr>
943 			<td> \c B_LONG_DESCRIPTION_CHANGED </td>
944 			<td> \c BMimeType::SetLongDescription() </td>
945 		</tr>
946 		<tr>
947 			<td> \c B_ICON_FOR_TYPE_CHANGED </td>
948 			<td> \c BMimeType::SetIconForType() </td>
949 		</tr>
950 		<tr>
951 			<td> \c B_APP_HINT_CHANGED </td>
952 			<td> \c BMimeType::SetAppHint() </td>
953 		</tr>
954 	</table>
955 
956 	\param target The \c BMessenger to subscribe to the MIME monitor service
957 */
958 status_t
959 Database::StartWatching(BMessenger target)
960 {
961 	DBG(OUT("Database::StartWatching()\n"));
962 
963 	if (!target.IsValid())
964 		return B_BAD_VALUE;
965 
966 	fMonitorMessengers.insert(target);
967 	return B_OK;
968 }
969 
970 
971 /*!
972 	Unsubscribes the given BMessenger from the MIME monitor service
973 	\param target The \c BMessenger to unsubscribe
974 */
975 status_t
976 Database::StopWatching(BMessenger target)
977 {
978 	DBG(OUT("Database::StopWatching()\n"));
979 
980 	if (!target.IsValid())
981 		return B_BAD_VALUE;
982 
983 	status_t status = fMonitorMessengers.find(target) != fMonitorMessengers.end()
984 		? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
985 	if (status == B_OK)
986 		fMonitorMessengers.erase(target);
987 
988 	return status;
989 }
990 
991 
992 /*!	\brief Deletes the app hint attribute for the given type
993 
994 	A \c B_APP_HINT_CHANGED notification is sent to the mime monitor service.
995 	\param type The mime type of interest
996 	\return
997 	- B_OK: success
998 	- B_ENTRY_NOT_FOUND: no such attribute existed
999 	- "error code": failure
1000 */
1001 status_t
1002 Database::DeleteAppHint(const char *type)
1003 {
1004 	status_t status = fLocation->DeleteAttribute(type, kAppHintAttr);
1005 	if (status == B_OK)
1006 		_SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED);
1007 	else if (status == B_ENTRY_NOT_FOUND)
1008 		status = B_OK;
1009 
1010 	return status;
1011 }
1012 
1013 
1014 /*!	\brief Deletes the attribute info attribute for the given type
1015 
1016 	A \c B_ATTR_INFO_CHANGED notification is sent to the mime monitor service.
1017 	\param type The mime type of interest
1018 	\return
1019 	- B_OK: success
1020 	- B_ENTRY_NOT_FOUND: no such attribute existed
1021 	- "error code": failure
1022 */
1023 status_t
1024 Database::DeleteAttrInfo(const char *type)
1025 {
1026 	status_t status = fLocation->DeleteAttribute(type, kAttrInfoAttr);
1027 	if (status == B_OK)
1028 		_SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED);
1029 	else if (status == B_ENTRY_NOT_FOUND)
1030 		status = B_OK;
1031 
1032 	return status;
1033 }
1034 
1035 
1036 /*!	\brief Deletes the short description attribute for the given type
1037 
1038 	A \c B_SHORT_DESCRIPTION_CHANGED notification is sent to the mime monitor service.
1039 	\param type The mime type of interest
1040 	\return
1041 	- B_OK: success
1042 	- B_ENTRY_NOT_FOUND: no such attribute existed
1043 	- "error code": failure
1044 */
1045 status_t
1046 Database::DeleteShortDescription(const char *type)
1047 {
1048 	status_t status = fLocation->DeleteAttribute(type, kShortDescriptionAttr);
1049 	if (status == B_OK)
1050 		_SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED);
1051 	else if (status == B_ENTRY_NOT_FOUND)
1052 		status = B_OK;
1053 
1054 	return status;
1055 }
1056 
1057 
1058 /*!	\brief Deletes the long description attribute for the given type
1059 
1060 	A \c B_LONG_DESCRIPTION_CHANGED notification is sent to the mime monitor service.
1061 	\param type The mime type of interest
1062 	\return
1063 	- B_OK: success
1064 	- B_ENTRY_NOT_FOUND: no such attribute existed
1065 	- "error code": failure
1066 */
1067 status_t
1068 Database::DeleteLongDescription(const char *type)
1069 {
1070 	status_t status = fLocation->DeleteAttribute(type, kLongDescriptionAttr);
1071 	if (status == B_OK)
1072 		_SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED);
1073 	else if (status == B_ENTRY_NOT_FOUND)
1074 		status = B_OK;
1075 
1076 	return status;
1077 }
1078 
1079 
1080 /*!	\brief Deletes the associated file extensions attribute for the given type
1081 
1082 	A \c B_FILE_EXTENSIONS_CHANGED notification is sent to the mime monitor service.
1083 	\param type The mime type of interest
1084 	\return
1085 	- B_OK: success
1086 	- B_ENTRY_NOT_FOUND: no such attribute existed
1087 	- "error code": failure
1088 */
1089 status_t
1090 Database::DeleteFileExtensions(const char *type)
1091 {
1092 	status_t status = fLocation->DeleteAttribute(type, kFileExtensionsAttr);
1093 	if (status == B_OK)
1094 		_SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED);
1095 	else if (status == B_ENTRY_NOT_FOUND)
1096 		status = B_OK;
1097 
1098 	return status;
1099 }
1100 
1101 
1102 /*!	\brief Deletes the icon of the given size for the given type
1103 
1104 	A \c B_ICON_CHANGED notification is sent to the mime monitor service.
1105 	\param type The mime type of interest
1106 	\param which The icon size of interest
1107 	\return
1108 	- B_OK: success
1109 	- B_ENTRY_NOT_FOUND: no such attribute existed
1110 	- "error code": failure
1111 */
1112 status_t
1113 Database::DeleteIcon(const char *type, icon_size which)
1114 {
1115 	const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr;
1116 	status_t status = fLocation->DeleteAttribute(type, attr);
1117 	if (status == B_OK) {
1118 		_SendMonitorUpdate(B_ICON_CHANGED, type, which == B_LARGE_ICON,
1119 			B_META_MIME_DELETED);
1120 	} else if (status == B_ENTRY_NOT_FOUND)
1121 		status = B_OK;
1122 
1123 	return status;
1124 }
1125 
1126 
1127 /*!	\brief Deletes the vector icon for the given type
1128 
1129 	A \c B_ICON_CHANGED notification is sent to the mime monitor service.
1130 	\param type The mime type of interest
1131 	\return
1132 	- B_OK: success
1133 	- B_ENTRY_NOT_FOUND: no such attribute existed
1134 	- "error code": failure
1135 */
1136 status_t
1137 Database::DeleteIcon(const char *type)
1138 {
1139 	// TODO: extra notification for vector icon (for now we notify a "large"
1140 	// icon)
1141 	status_t status = fLocation->DeleteAttribute(type, kIconAttr);
1142 	if (status == B_OK) {
1143 		_SendMonitorUpdate(B_ICON_CHANGED, type, true,
1144 						   B_META_MIME_DELETED);
1145 	} else if (status == B_ENTRY_NOT_FOUND)
1146 		status = B_OK;
1147 
1148 	return status;
1149 }
1150 
1151 
1152 /*!	\brief Deletes the icon of the given size associated with the given file
1153 		type for the given application signature.
1154 
1155     (If this function seems confusing, please see BMimeType::GetIconForType() for a
1156     better description of what the *IconForType() functions are used for.)
1157 
1158 	A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service.
1159 	\param type The mime type of the application whose custom icon you are deleting.
1160 	\param fileType The mime type for which you no longer wish \c type to have a custom icon.
1161 	\param which The icon size of interest
1162 	\return
1163 	- B_OK: success
1164 	- B_ENTRY_NOT_FOUND: no such attribute existed
1165 	- "error code": failure
1166 */
1167 status_t
1168 Database::DeleteIconForType(const char *type, const char *fileType, icon_size which)
1169 {
1170 	if (fileType == NULL)
1171 		return B_BAD_VALUE;
1172 
1173 	std::string attr = (which == B_MINI_ICON
1174 		? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType);
1175 
1176 	status_t status = fLocation->DeleteAttribute(type, attr.c_str());
1177 	if (status == B_OK) {
1178 		_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
1179 			which == B_LARGE_ICON, B_META_MIME_DELETED);
1180 	} else if (status == B_ENTRY_NOT_FOUND)
1181 		status = B_OK;
1182 
1183 	return status;
1184 }
1185 
1186 
1187 /*!	\brief Deletes the vector icon associated with the given file
1188 		type for the given application signature.
1189 
1190     (If this function seems confusing, please see BMimeType::GetIconForType() for a
1191     better description of what the *IconForType() functions are used for.)
1192 
1193 	A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service.
1194 	\param type The mime type of the application whose custom icon you are deleting.
1195 	\param fileType The mime type for which you no longer wish \c type to have a custom icon.
1196 	\return
1197 	- B_OK: success
1198 	- B_ENTRY_NOT_FOUND: no such attribute existed
1199 	- "error code": failure
1200 */
1201 status_t
1202 Database::DeleteIconForType(const char *type, const char *fileType)
1203 {
1204 	if (fileType == NULL)
1205 		return B_BAD_VALUE;
1206 
1207 	std::string attr = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType);
1208 
1209 	// TODO: introduce extra notification for vector icons?
1210 	// (uses B_LARGE_ICON now)
1211 	status_t status = fLocation->DeleteAttribute(type, attr.c_str());
1212 	if (status == B_OK) {
1213 		_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
1214 			true, B_META_MIME_DELETED);
1215 	} else if (status == B_ENTRY_NOT_FOUND)
1216 		status = B_OK;
1217 
1218 	return status;
1219 }
1220 
1221 
1222 // DeletePreferredApp
1223 //! Deletes the preferred app for the given app verb for the given type
1224 /*! A \c B_PREFERRED_APP_CHANGED notification is sent to the mime monitor service.
1225 	\param type The mime type of interest
1226 	\param which The app verb of interest
1227 	\return
1228 	- B_OK: success
1229 	- B_ENTRY_NOT_FOUND: no such attribute existed
1230 	- "error code": failure
1231 */
1232 status_t
1233 Database::DeletePreferredApp(const char *type, app_verb verb)
1234 {
1235 	status_t status;
1236 
1237 	switch (verb) {
1238 		case B_OPEN:
1239 			status = fLocation->DeleteAttribute(type, kPreferredAppAttr);
1240 			break;
1241 
1242 		default:
1243 			return B_BAD_VALUE;
1244 	}
1245 
1246 	/*! \todo The R5 monitor makes no note of which app_verb value was updated. If
1247 		additional app_verb values besides \c B_OPEN are someday added, the format
1248 		of the MIME monitor messages will need to be augmented.
1249 	*/
1250 	if (status == B_OK)
1251 		_SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_DELETED);
1252 	else if (status == B_ENTRY_NOT_FOUND)
1253 		status = B_OK;
1254 
1255 	return status;
1256 }
1257 
1258 // DeleteSnifferRule
1259 //! Deletes the sniffer rule for the given type
1260 /*! A \c B_SNIFFER_RULE_CHANGED notification is sent to the mime monitor service,
1261 	and the corresponding rule is removed from the internal database of sniffer
1262 	rules.
1263 	\param type The mime type of interest
1264 	\return
1265 	- B_OK: success
1266 	- B_ENTRY_NOT_FOUND: no such attribute existed
1267 	- "error code": failure
1268 */
1269 status_t
1270 Database::DeleteSnifferRule(const char *type)
1271 {
1272 	status_t status = fLocation->DeleteAttribute(type, kSnifferRuleAttr);
1273 	if (status == B_OK) {
1274 		status = fSnifferRules.DeleteSnifferRule(type);
1275 		if (status == B_OK) {
1276 			_SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type,
1277 				B_META_MIME_DELETED);
1278 		}
1279 	} else if (status == B_ENTRY_NOT_FOUND)
1280 		status = B_OK;
1281 
1282 	return status;
1283 }
1284 
1285 // DeleteSupportedTypes
1286 //! Deletes the supported types list for the given type
1287 /*! A \c B_SUPPORTED_TYPES_CHANGED notification is sent to the mime monitor service.
1288 	If \c fullSync is \c true, the given type is removed from the internal list
1289 	of supporting applictions for each previously supported type. If \c fullSync
1290 	is \c false, the said removal will occur the next time SetSupportedTypes() or
1291 	DeleteSupportedTypes() is called with a \c true \c fullSync paramter, or
1292 	\c Delete() is called for the given type.
1293 	\param type The mime type of interest
1294 	\param fullSync Whether or not to remove the type as a supporting app for
1295 	                all previously supported types
1296 	\return
1297 	- B_OK: success
1298 	- B_ENTRY_NOT_FOUND: no such attribute existed
1299 	- "error code": failure
1300 */
1301 status_t
1302 Database::DeleteSupportedTypes(const char *type, bool fullSync)
1303 {
1304 	status_t status = fLocation->DeleteAttribute(type, kSupportedTypesAttr);
1305 
1306 	// Update the supporting apps database. If fullSync is specified,
1307 	// do so even if the supported types attribute didn't exist, as
1308 	// stranded types *may* exist in the database due to previous
1309 	// calls to {Set,Delete}SupportedTypes() with fullSync == false.
1310 	bool sendUpdate = true;
1311 	if (status == B_OK)
1312 		status = fSupportingApps.DeleteSupportedTypes(type, fullSync);
1313 	else if (status == B_ENTRY_NOT_FOUND) {
1314 		status = B_OK;
1315 		if (fullSync)
1316 			fSupportingApps.DeleteSupportedTypes(type, fullSync);
1317 		else
1318 			sendUpdate = false;
1319 	}
1320 
1321 	// Send a monitor notification
1322 	if (status == B_OK && sendUpdate)
1323 		_SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED);
1324 
1325 	return status;
1326 }
1327 
1328 
1329 void
1330 Database::DeferInstallNotification(const char* type)
1331 {
1332 	AutoLocker<BLocker> _(fDeferredInstallNotificationsLocker);
1333 
1334 	// check, if already deferred
1335 	if (_FindDeferredInstallNotification(type))
1336 		return;
1337 
1338 	// add new
1339 	DeferredInstallNotification* notification
1340 		= new(std::nothrow) DeferredInstallNotification;
1341 	if (notification == NULL)
1342 		return;
1343 
1344 	strlcpy(notification->type, type, sizeof(notification->type));
1345 	notification->notify = false;
1346 
1347 	if (!fDeferredInstallNotifications.AddItem(notification))
1348 		delete notification;
1349 }
1350 
1351 
1352 void
1353 Database::UndeferInstallNotification(const char* type)
1354 {
1355 	AutoLocker<BLocker> locker(fDeferredInstallNotificationsLocker);
1356 
1357 	// check, if deferred at all
1358 	DeferredInstallNotification* notification
1359 		= _FindDeferredInstallNotification(type, true);
1360 
1361 	locker.Unlock();
1362 
1363 	if (notification == NULL)
1364 		return;
1365 
1366 	// notify, if requested
1367 	if (notification->notify)
1368 		_SendInstallNotification(notification->type);
1369 
1370 	delete notification;
1371 }
1372 
1373 
1374 //! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service
1375 status_t
1376 Database::_SendInstallNotification(const char *type)
1377 {
1378 	return _SendMonitorUpdate(B_MIME_TYPE_CREATED, type, B_META_MIME_MODIFIED);
1379 }
1380 
1381 
1382 //! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
1383 status_t
1384 Database::_SendDeleteNotification(const char *type)
1385 {
1386 	// Tell the backend first
1387 	return _SendMonitorUpdate(B_MIME_TYPE_DELETED, type, B_META_MIME_MODIFIED);
1388 }
1389 
1390 // _SendMonitorUpdate
1391 /*! \brief Sends an update notification to all BMessengers that have
1392 	subscribed to the MIME Monitor service
1393 	\param type The MIME type that was updated
1394 	\param which Bitmask describing which attribute was updated
1395 	\param extraType The MIME type to which the change is applies
1396 	\param largeIcon \true if the the large icon was updated, \false if the
1397 		   small icon was updated
1398 */
1399 status_t
1400 Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType,
1401 	bool largeIcon, int32 action)
1402 {
1403 	BMessage msg(B_META_MIME_CHANGED);
1404 	status_t err;
1405 
1406 	if (_CheckDeferredInstallNotification(which, type))
1407 		return B_OK;
1408 
1409 	err = msg.AddInt32("be:which", which);
1410 	if (!err)
1411 		err = msg.AddString("be:type", type);
1412 	if (!err)
1413 		err = msg.AddString("be:extra_type", extraType);
1414 	if (!err)
1415 		err = msg.AddBool("be:large_icon", largeIcon);
1416 	if (!err)
1417 		err = msg.AddInt32("be:action", action);
1418 	if (!err)
1419 		err = _SendMonitorUpdate(msg);
1420 	return err;
1421 }
1422 
1423 // _SendMonitorUpdate
1424 /*! \brief Sends an update notification to all BMessengers that have
1425 	subscribed to the MIME Monitor service
1426 	\param type The MIME type that was updated
1427 	\param which Bitmask describing which attribute was updated
1428 	\param extraType The MIME type to which the change is applies
1429 */
1430 status_t
1431 Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType,
1432 	int32 action)
1433 {
1434 	if (_CheckDeferredInstallNotification(which, type))
1435 		return B_OK;
1436 
1437 	BMessage msg(B_META_MIME_CHANGED);
1438 
1439 	status_t err = msg.AddInt32("be:which", which);
1440 	if (!err)
1441 		err = msg.AddString("be:type", type);
1442 	if (!err)
1443 		err = msg.AddString("be:extra_type", extraType);
1444 	if (!err)
1445 		err = msg.AddInt32("be:action", action);
1446 	if (!err)
1447 		err = _SendMonitorUpdate(msg);
1448 	return err;
1449 }
1450 
1451 // _SendMonitorUpdate
1452 /*! \brief Sends an update notification to all BMessengers that have
1453 	subscribed to the MIME Monitor service
1454 	\param type The MIME type that was updated
1455 	\param which Bitmask describing which attribute was updated
1456 	\param largeIcon \true if the the large icon was updated, \false if the
1457 		   small icon was updated
1458 */
1459 status_t
1460 Database::_SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action)
1461 {
1462 	if (_CheckDeferredInstallNotification(which, type))
1463 		return B_OK;
1464 
1465 	BMessage msg(B_META_MIME_CHANGED);
1466 
1467 	status_t err = msg.AddInt32("be:which", which);
1468 	if (!err)
1469 		err = msg.AddString("be:type", type);
1470 	if (!err)
1471 		err = msg.AddBool("be:large_icon", largeIcon);
1472 	if (!err)
1473 		err = msg.AddInt32("be:action", action);
1474 	if (!err)
1475 		err = _SendMonitorUpdate(msg);
1476 	return err;
1477 }
1478 
1479 // _SendMonitorUpdate
1480 /*! \brief Sends an update notification to all BMessengers that have
1481 	subscribed to the MIME Monitor service
1482 	\param type The MIME type that was updated
1483 	\param which Bitmask describing which attribute was updated
1484 */
1485 status_t
1486 Database::_SendMonitorUpdate(int32 which, const char *type, int32 action)
1487 {
1488 	if (_CheckDeferredInstallNotification(which, type))
1489 		return B_OK;
1490 
1491 	BMessage msg(B_META_MIME_CHANGED);
1492 
1493 	status_t err = msg.AddInt32("be:which", which);
1494 	if (!err)
1495 		err = msg.AddString("be:type", type);
1496 	if (!err)
1497 		err = msg.AddInt32("be:action", action);
1498 	if (!err)
1499 		err = _SendMonitorUpdate(msg);
1500 	return err;
1501 }
1502 
1503 // _SendMonitorUpdate
1504 /*! \brief Sends an update notification to all BMessengers that have subscribed to
1505 	the MIME Monitor service
1506 	\param BMessage A preformatted MIME monitor message to be sent to all subscribers
1507 */
1508 status_t
1509 Database::_SendMonitorUpdate(BMessage &msg)
1510 {
1511 	if (fNotificationListener == NULL)
1512 		return B_OK;
1513 
1514 	status_t err;
1515 	std::set<BMessenger>::const_iterator i;
1516 	for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) {
1517 		status_t err = fNotificationListener->Notify(&msg, *i);
1518 		if (err) {
1519 			DBG(OUT("Database::_SendMonitorUpdate(BMessage&): DeliverMessage failed, 0x%lx\n", err));
1520 		}
1521 	}
1522 	err = B_OK;
1523 	return err;
1524 }
1525 
1526 
1527 Database::DeferredInstallNotification*
1528 Database::_FindDeferredInstallNotification(const char* type, bool remove)
1529 {
1530 	for (int32 i = 0;
1531 		DeferredInstallNotification* notification
1532 			= (DeferredInstallNotification*)fDeferredInstallNotifications
1533 				.ItemAt(i); i++) {
1534 		if (strcmp(type, notification->type) == 0) {
1535 			if (remove)
1536 				fDeferredInstallNotifications.RemoveItem(i);
1537 			return notification;
1538 		}
1539 	}
1540 
1541 	return NULL;
1542 }
1543 
1544 
1545 bool
1546 Database::_CheckDeferredInstallNotification(int32 which, const char* type)
1547 {
1548 	AutoLocker<BLocker> locker(fDeferredInstallNotificationsLocker);
1549 
1550 	// check, if deferred at all
1551 	DeferredInstallNotification* notification
1552 		= _FindDeferredInstallNotification(type);
1553 	if (notification == NULL)
1554 		return false;
1555 
1556 	if (which == B_MIME_TYPE_DELETED) {
1557 		// MIME type deleted -- if the install notification had been
1558 		// deferred, we don't send anything
1559 		if (notification->notify) {
1560 			fDeferredInstallNotifications.RemoveItem(notification);
1561 			delete notification;
1562 			return true;
1563 		}
1564 	} else if (which == B_MIME_TYPE_CREATED) {
1565 		// MIME type created -- defer notification
1566 		notification->notify = true;
1567 		return true;
1568 	} else {
1569 		// MIME type update -- don't send update, if deferred
1570 		if (notification->notify)
1571 			return true;
1572 	}
1573 
1574 	return false;
1575 }
1576 
1577 
1578 } // namespace Mime
1579 } // namespace Storage
1580 } // namespace BPrivate
1581