#include <mime/Database.h>
#include <stdio.h>
#include <string>
#include <new>
#include <Application.h>
#include <Bitmap.h>
#include <DataIO.h>
#include <Directory.h>
#include <Entry.h>
#include <fs_attr.h>
#include <Message.h>
#include <MimeType.h>
#include <Node.h>
#include <Path.h>
#include <String.h>
#include <TypeConstants.h>
#include <AutoLocker.h>
#include <mime/database_support.h>
#include <mime/DatabaseLocation.h>
#include <storage_support.h>
#define DBG(x)
#define OUT printf
namespace BPrivate {
namespace Storage {
namespace Mime {
Database::NotificationListener::~NotificationListener()
{
}
Database::Database(DatabaseLocation* databaseLocation, MimeSniffer* mimeSniffer,
NotificationListener* notificationListener)
:
fStatus(B_NO_INIT),
fLocation(databaseLocation),
fNotificationListener(notificationListener),
fAssociatedTypes(databaseLocation, mimeSniffer),
fInstalledTypes(databaseLocation),
fSnifferRules(databaseLocation, mimeSniffer),
fSupportingApps(databaseLocation),
fDeferredInstallNotificationsLocker("deferred install notifications"),
fDeferredInstallNotifications()
{
fStatus = create_directory(fLocation->WritableDirectory(),
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
}
Database::~Database()
{
}
status_t
Database::InitCheck() const
{
return fStatus;
}
status_t
Database::Install(const char *type)
{
if (type == NULL)
return B_BAD_VALUE;
BEntry entry;
status_t err = entry.SetTo(fLocation->WritablePathForType(type));
if (err == B_OK || err == B_ENTRY_NOT_FOUND) {
if (entry.Exists())
err = B_FILE_EXISTS;
else {
bool didCreate = false;
BNode node;
err = fLocation->OpenWritableType(type, node, true, &didCreate);
if (!err && didCreate) {
fInstalledTypes.AddType(type);
_SendInstallNotification(type);
}
}
}
return err;
}
status_t
Database::Delete(const char *type)
{
if (type == NULL)
return B_BAD_VALUE;
BEntry entry;
status_t status = entry.SetTo(fLocation->WritablePathForType(type));
if (status != B_OK)
return status;
if (entry.IsDirectory()) {
BDirectory directory(&entry);
if (directory.InitCheck() == B_OK) {
size_t length = strlen(type);
char subType[B_PATH_NAME_LENGTH];
memcpy(subType, type, length);
subType[length++] = '/';
BEntry subEntry;
while (directory.GetNextEntry(&subEntry) == B_OK) {
if (subEntry.GetName(subType + length) == B_OK) {
status = Delete(subType);
if (status != B_OK)
return status;
}
}
}
}
status = entry.Remove();
if (status == B_OK) {
fInstalledTypes.RemoveType(type);
fSupportingApps.DeleteSupportedTypes(type, true);
_SendDeleteNotification(type);
}
return status;
}
status_t
Database::_SetStringValue(const char *type, int32 what, const char* attribute,
type_code attributeType, size_t maxLength, const char *value)
{
size_t length = value != NULL ? strlen(value) : 0;
if (type == NULL || value == NULL || length >= maxLength)
return B_BAD_VALUE;
char oldValue[maxLength];
status_t status = fLocation->ReadAttribute(type, attribute, oldValue,
maxLength, attributeType);
if (status >= B_OK && !strcmp(value, oldValue)) {
return B_OK;
}
bool didCreate = false;
status = fLocation->WriteAttribute(type, attribute, value, length + 1,
attributeType, &didCreate);
if (status == B_OK) {
if (didCreate)
_SendInstallNotification(type);
else
_SendMonitorUpdate(what, type, B_META_MIME_MODIFIED);
}
return status;
}
status_t
Database::SetAppHint(const char *type, const entry_ref *ref)
{
DBG(OUT("Database::SetAppHint()\n"));
if (type == NULL || ref == NULL)
return B_BAD_VALUE;
BPath path;
status_t status = path.SetTo(ref);
if (status < B_OK)
return status;
return _SetStringValue(type, B_APP_HINT_CHANGED, kAppHintAttr,
kAppHintType, B_PATH_NAME_LENGTH, path.Path());
}
status_t
Database::SetAttrInfo(const char *type, const BMessage *info)
{
DBG(OUT("Database::SetAttrInfo()\n"));
if (type == NULL || info == NULL)
return B_BAD_VALUE;
bool didCreate = false;
status_t status = fLocation->WriteMessageAttribute(type, kAttrInfoAttr,
*info, &didCreate);
if (status == B_OK) {
if (didCreate)
_SendInstallNotification(type);
else
_SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED);
}
return status;
}
status_t
Database::SetShortDescription(const char *type, const char *description)
{
DBG(OUT("Database::SetShortDescription()\n"));
return _SetStringValue(type, B_SHORT_DESCRIPTION_CHANGED, kShortDescriptionAttr,
kShortDescriptionType, B_MIME_TYPE_LENGTH, description);
}
status_t
Database::SetLongDescription(const char *type, const char *description)
{
DBG(OUT("Database::SetLongDescription()\n"));
size_t length = description != NULL ? strlen(description) : 0;
if (type == NULL || description == NULL || length >= B_MIME_TYPE_LENGTH)
return B_BAD_VALUE;
return _SetStringValue(type, B_LONG_DESCRIPTION_CHANGED, kLongDescriptionAttr,
kLongDescriptionType, B_MIME_TYPE_LENGTH, description);
}
status_t
Database::SetFileExtensions(const char *type, const BMessage *extensions)
{
DBG(OUT("Database::SetFileExtensions()\n"));
if (type == NULL || extensions == NULL)
return B_BAD_VALUE;
bool didCreate = false;
status_t status = fLocation->WriteMessageAttribute(type,
kFileExtensionsAttr, *extensions, &didCreate);
if (status == B_OK) {
if (didCreate) {
_SendInstallNotification(type);
} else {
_SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type,
B_META_MIME_MODIFIED);
}
}
return status;
}
status_t
Database::SetIcon(const char* type, const BBitmap* icon, icon_size which)
{
if (icon != NULL)
return SetIcon(type, icon->Bits(), icon->BitsLength(), which);
return SetIcon(type, NULL, 0, which);
}
status_t
Database::SetIcon(const char *type, const void *data, size_t dataSize,
icon_size which)
{
return SetIconForType(type, NULL, data, dataSize, which);
}
status_t
Database::SetIcon(const char *type, const void *data, size_t dataSize)
{
return SetIconForType(type, NULL, data, dataSize);
}
status_t
Database::SetIconForType(const char* type, const char* fileType,
const BBitmap* icon, icon_size which)
{
if (icon != NULL) {
return SetIconForType(type, fileType, icon->Bits(),
(size_t)icon->BitsLength(), which);
}
return SetIconForType(type, fileType, NULL, 0, which);
}
status_t
Database::SetIconForType(const char *type, const char *fileType,
const void *data, size_t dataSize, icon_size which)
{
DBG(OUT("Database::SetIconForType()\n"));
if (type == NULL || data == NULL)
return B_BAD_VALUE;
int32 attrType = 0;
switch (which) {
case B_MINI_ICON:
attrType = kMiniIconType;
break;
case B_LARGE_ICON:
attrType = kLargeIconType;
break;
default:
return B_BAD_VALUE;
}
size_t attrSize = (size_t)which * (size_t)which;
if (dataSize != attrSize)
return B_BAD_VALUE;
std::string attr;
if (fileType) {
attr = (which == B_MINI_ICON
? kMiniIconAttrPrefix : kLargeIconAttrPrefix)
+ BPrivate::Storage::to_lower(fileType);
} else
attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr;
BNode node;
bool didCreate = false;
status_t err = fLocation->OpenWritableType(type, node, true, &didCreate);
if (err != B_OK)
return err;
if (!err)
err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize);
if (err >= 0)
err = err == (ssize_t)attrSize ? (status_t)B_OK : (status_t)B_FILE_ERROR;
if (didCreate) {
_SendInstallNotification(type);
} else if (!err) {
if (fileType) {
_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
which == B_LARGE_ICON, B_META_MIME_MODIFIED);
} else {
_SendMonitorUpdate(B_ICON_CHANGED, type,
which == B_LARGE_ICON, B_META_MIME_MODIFIED);
}
}
return err;
}
status_t
Database::SetIconForType(const char *type, const char *fileType,
const void *data, size_t dataSize)
{
DBG(OUT("Database::SetIconForType()\n"));
if (type == NULL || data == NULL)
return B_BAD_VALUE;
int32 attrType = B_VECTOR_ICON_TYPE;
std::string attr;
if (fileType) {
attr = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType);
} else
attr = kIconAttr;
BNode node;
bool didCreate = false;
status_t err = fLocation->OpenWritableType(type, node, true, &didCreate);
if (err != B_OK)
return err;
if (!err)
err = node.WriteAttr(attr.c_str(), attrType, 0, data, dataSize);
if (err >= 0)
err = err == (ssize_t)dataSize ? (status_t)B_OK : (status_t)B_FILE_ERROR;
if (didCreate) {
_SendInstallNotification(type);
} else if (!err) {
if (fileType) {
_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
true, B_META_MIME_MODIFIED);
} else {
_SendMonitorUpdate(B_ICON_CHANGED, type, true,
B_META_MIME_MODIFIED);
}
}
return err;
}
status_t
Database::SetPreferredApp(const char *type, const char *signature, app_verb verb)
{
DBG(OUT("Database::SetPreferredApp()\n"));
return _SetStringValue(type, B_PREFERRED_APP_CHANGED, kPreferredAppAttr,
kPreferredAppType, B_MIME_TYPE_LENGTH, signature);
}
status_t
Database::SetSnifferRule(const char *type, const char *rule)
{
DBG(OUT("Database::SetSnifferRule()\n"));
if (type == NULL || rule == NULL)
return B_BAD_VALUE;
bool didCreate = false;
status_t status = fLocation->WriteAttribute(type, kSnifferRuleAttr, rule,
strlen(rule) + 1, kSnifferRuleType, &didCreate);
if (status == B_OK)
status = fSnifferRules.SetSnifferRule(type, rule);
if (didCreate) {
_SendInstallNotification(type);
} else if (status == B_OK) {
_SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type,
B_META_MIME_MODIFIED);
}
return status;
}
status_t
Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSync)
{
DBG(OUT("Database::SetSupportedTypes()\n"));
if (type == NULL || types == NULL)
return B_BAD_VALUE;
const char *supportedType;
for (int32 i = 0; types->FindString("types", i, &supportedType) == B_OK; i++) {
if (!fLocation->IsInstalled(supportedType)) {
if (Install(supportedType) != B_OK)
break;
SetPreferredApp(supportedType, type, B_OPEN);
}
}
bool didCreate = false;
status_t status = fLocation->WriteMessageAttribute(type,
kSupportedTypesAttr, *types, &didCreate);
if (status != B_OK)
return status;
if (status == B_OK)
status = fSupportingApps.SetSupportedTypes(type, types, fullSync);
if (didCreate) {
_SendInstallNotification(type);
} else if (status == B_OK) {
_SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type,
B_META_MIME_MODIFIED);
}
return status;
}
status_t
Database::GetInstalledSupertypes(BMessage *supertypes)
{
return fInstalledTypes.GetInstalledSupertypes(supertypes);
}
status_t
Database::GetInstalledTypes(BMessage *types)
{
return fInstalledTypes.GetInstalledTypes(types);
}
status_t
Database::GetInstalledTypes(const char *supertype, BMessage *subtypes)
{
return fInstalledTypes.GetInstalledTypes(supertype, subtypes);
}
status_t
Database::GetSupportingApps(const char *type, BMessage *signatures)
{
return fSupportingApps.GetSupportingApps(type, signatures);
}
status_t
Database::GetAssociatedTypes(const char *extension, BMessage *types)
{
return B_ERROR;
}
status_t
Database::GuessMimeType(const entry_ref *ref, BString *result)
{
if (ref == NULL || result == NULL)
return B_BAD_VALUE;
BNode node;
struct stat statData;
status_t status = node.SetTo(ref);
if (status < B_OK)
return status;
attr_info info;
if (node.GetAttrInfo(kTypeAttr, &info) == B_OK) {
result->SetTo(kMetaMimeType);
return B_OK;
}
status = node.GetStat(&statData);
if (status < B_OK)
return status;
if (S_ISDIR(statData.st_mode)) {
result->SetTo(kDirectoryType);
} else if (S_ISLNK(statData.st_mode)) {
result->SetTo(kSymlinkType);
} else if (S_ISREG(statData.st_mode)) {
status = fSnifferRules.GuessMimeType(ref, result);
if (status == kMimeGuessFailureError)
status = fAssociatedTypes.GuessMimeType(ref, result);
if (status == kMimeGuessFailureError) {
result->SetTo(kGenericFileType);
status = B_OK;
}
} else {
return B_BAD_TYPE;
}
return status;
}
status_t
Database::GuessMimeType(const void *buffer, int32 length, BString *result)
{
if (buffer == NULL || result == NULL)
return B_BAD_VALUE;
status_t status = fSnifferRules.GuessMimeType(buffer, length, result);
if (status == kMimeGuessFailureError) {
result->SetTo(kGenericFileType);
return B_OK;
}
return status;
}
status_t
Database::GuessMimeType(const char *filename, BString *result)
{
if (filename == NULL || result == NULL)
return B_BAD_VALUE;
status_t status = fAssociatedTypes.GuessMimeType(filename, result);
if (status == kMimeGuessFailureError) {
result->SetTo(kGenericFileType);
return B_OK;
}
return status;
}
status_t
Database::StartWatching(BMessenger target)
{
DBG(OUT("Database::StartWatching()\n"));
if (!target.IsValid())
return B_BAD_VALUE;
fMonitorMessengers.insert(target);
return B_OK;
}
status_t
Database::StopWatching(BMessenger target)
{
DBG(OUT("Database::StopWatching()\n"));
if (!target.IsValid())
return B_BAD_VALUE;
status_t status = fMonitorMessengers.find(target) != fMonitorMessengers.end()
? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
if (status == B_OK)
fMonitorMessengers.erase(target);
return status;
}
status_t
Database::DeleteAppHint(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kAppHintAttr);
if (status == B_OK)
_SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED);
else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteAttrInfo(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kAttrInfoAttr);
if (status == B_OK)
_SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED);
else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteShortDescription(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kShortDescriptionAttr);
if (status == B_OK)
_SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED);
else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteLongDescription(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kLongDescriptionAttr);
if (status == B_OK)
_SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED);
else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteFileExtensions(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kFileExtensionsAttr);
if (status == B_OK)
_SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED);
else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteIcon(const char *type, icon_size which)
{
const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr;
status_t status = fLocation->DeleteAttribute(type, attr);
if (status == B_OK) {
_SendMonitorUpdate(B_ICON_CHANGED, type, which == B_LARGE_ICON,
B_META_MIME_DELETED);
} else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteIcon(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kIconAttr);
if (status == B_OK) {
_SendMonitorUpdate(B_ICON_CHANGED, type, true,
B_META_MIME_DELETED);
} else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteIconForType(const char *type, const char *fileType, icon_size which)
{
if (fileType == NULL)
return B_BAD_VALUE;
std::string attr = (which == B_MINI_ICON
? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType);
status_t status = fLocation->DeleteAttribute(type, attr.c_str());
if (status == B_OK) {
_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
which == B_LARGE_ICON, B_META_MIME_DELETED);
} else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteIconForType(const char *type, const char *fileType)
{
if (fileType == NULL)
return B_BAD_VALUE;
std::string attr = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType);
status_t status = fLocation->DeleteAttribute(type, attr.c_str());
if (status == B_OK) {
_SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType,
true, B_META_MIME_DELETED);
} else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeletePreferredApp(const char *type, app_verb verb)
{
status_t status;
switch (verb) {
case B_OPEN:
status = fLocation->DeleteAttribute(type, kPreferredAppAttr);
break;
default:
return B_BAD_VALUE;
}
if (status == B_OK)
_SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_DELETED);
else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteSnifferRule(const char *type)
{
status_t status = fLocation->DeleteAttribute(type, kSnifferRuleAttr);
if (status == B_OK) {
status = fSnifferRules.DeleteSnifferRule(type);
if (status == B_OK) {
_SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type,
B_META_MIME_DELETED);
}
} else if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
return status;
}
status_t
Database::DeleteSupportedTypes(const char *type, bool fullSync)
{
status_t status = fLocation->DeleteAttribute(type, kSupportedTypesAttr);
bool sendUpdate = true;
if (status == B_OK)
status = fSupportingApps.DeleteSupportedTypes(type, fullSync);
else if (status == B_ENTRY_NOT_FOUND) {
status = B_OK;
if (fullSync)
fSupportingApps.DeleteSupportedTypes(type, fullSync);
else
sendUpdate = false;
}
if (status == B_OK && sendUpdate)
_SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED);
return status;
}
void
Database::DeferInstallNotification(const char* type)
{
AutoLocker<BLocker> _(fDeferredInstallNotificationsLocker);
if (_FindDeferredInstallNotification(type))
return;
DeferredInstallNotification* notification
= new(std::nothrow) DeferredInstallNotification;
if (notification == NULL)
return;
strlcpy(notification->type, type, sizeof(notification->type));
notification->notify = false;
if (!fDeferredInstallNotifications.AddItem(notification))
delete notification;
}
void
Database::UndeferInstallNotification(const char* type)
{
AutoLocker<BLocker> locker(fDeferredInstallNotificationsLocker);
DeferredInstallNotification* notification
= _FindDeferredInstallNotification(type, true);
locker.Unlock();
if (notification == NULL)
return;
if (notification->notify)
_SendInstallNotification(notification->type);
delete notification;
}
status_t
Database::_SendInstallNotification(const char *type)
{
return _SendMonitorUpdate(B_MIME_TYPE_CREATED, type, B_META_MIME_MODIFIED);
}
status_t
Database::_SendDeleteNotification(const char *type)
{
return _SendMonitorUpdate(B_MIME_TYPE_DELETED, type, B_META_MIME_MODIFIED);
}
status_t
Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType,
bool largeIcon, int32 action)
{
BMessage msg(B_META_MIME_CHANGED);
status_t err;
if (_CheckDeferredInstallNotification(which, type))
return B_OK;
err = msg.AddInt32("be:which", which);
if (!err)
err = msg.AddString("be:type", type);
if (!err)
err = msg.AddString("be:extra_type", extraType);
if (!err)
err = msg.AddBool("be:large_icon", largeIcon);
if (!err)
err = msg.AddInt32("be:action", action);
if (!err)
err = _SendMonitorUpdate(msg);
return err;
}
status_t
Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType,
int32 action)
{
if (_CheckDeferredInstallNotification(which, type))
return B_OK;
BMessage msg(B_META_MIME_CHANGED);
status_t err = msg.AddInt32("be:which", which);
if (!err)
err = msg.AddString("be:type", type);
if (!err)
err = msg.AddString("be:extra_type", extraType);
if (!err)
err = msg.AddInt32("be:action", action);
if (!err)
err = _SendMonitorUpdate(msg);
return err;
}
status_t
Database::_SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action)
{
if (_CheckDeferredInstallNotification(which, type))
return B_OK;
BMessage msg(B_META_MIME_CHANGED);
status_t err = msg.AddInt32("be:which", which);
if (!err)
err = msg.AddString("be:type", type);
if (!err)
err = msg.AddBool("be:large_icon", largeIcon);
if (!err)
err = msg.AddInt32("be:action", action);
if (!err)
err = _SendMonitorUpdate(msg);
return err;
}
status_t
Database::_SendMonitorUpdate(int32 which, const char *type, int32 action)
{
if (_CheckDeferredInstallNotification(which, type))
return B_OK;
BMessage msg(B_META_MIME_CHANGED);
status_t err = msg.AddInt32("be:which", which);
if (!err)
err = msg.AddString("be:type", type);
if (!err)
err = msg.AddInt32("be:action", action);
if (!err)
err = _SendMonitorUpdate(msg);
return err;
}
status_t
Database::_SendMonitorUpdate(BMessage &msg)
{
if (fNotificationListener == NULL)
return B_OK;
status_t err;
std::set<BMessenger>::const_iterator i;
for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) {
status_t err = fNotificationListener->Notify(&msg, *i);
if (err) {
DBG(OUT("Database::_SendMonitorUpdate(BMessage&): DeliverMessage failed, 0x%lx\n", err));
}
}
err = B_OK;
return err;
}
Database::DeferredInstallNotification*
Database::_FindDeferredInstallNotification(const char* type, bool remove)
{
for (int32 i = 0;
DeferredInstallNotification* notification
= (DeferredInstallNotification*)fDeferredInstallNotifications
.ItemAt(i); i++) {
if (strcmp(type, notification->type) == 0) {
if (remove)
fDeferredInstallNotifications.RemoveItem(i);
return notification;
}
}
return NULL;
}
bool
Database::_CheckDeferredInstallNotification(int32 which, const char* type)
{
AutoLocker<BLocker> locker(fDeferredInstallNotificationsLocker);
DeferredInstallNotification* notification
= _FindDeferredInstallNotification(type);
if (notification == NULL)
return false;
if (which == B_MIME_TYPE_DELETED) {
if (notification->notify) {
fDeferredInstallNotifications.RemoveItem(notification);
delete notification;
return true;
}
} else if (which == B_MIME_TYPE_CREATED) {
notification->notify = true;
return true;
} else {
if (notification->notify)
return true;
}
return false;
}
}
}
}