+ Added file-extension based mime type guessing
+ Added sniffer rule based mime type guessing + Added get_device_icon() + Added complete (synchronous, asynchronous; recursive, non-recursive; forcing, non-forcing; you name it we got it :-) update_mime_info() implementation. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1152 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
743e936ee7
commit
1bd963b6c2
@ -145,10 +145,10 @@ public:
|
||||
|
||||
/* calls to ask the sniffer to identify the MIME type of a file or data in
|
||||
memory */
|
||||
static status_t GuessMimeType(const entry_ref *file, BMimeType *result);
|
||||
static status_t GuessMimeType(const entry_ref *file, BMimeType *type);
|
||||
static status_t GuessMimeType(const void *buffer, int32 length,
|
||||
BMimeType *result);
|
||||
static status_t GuessMimeType(const char *filename, BMimeType *result);
|
||||
BMimeType *type);
|
||||
static status_t GuessMimeType(const char *filename, BMimeType *type);
|
||||
|
||||
static status_t StartWatching(BMessenger target);
|
||||
static status_t StopWatching(BMessenger target);
|
||||
@ -201,6 +201,9 @@ private:
|
||||
// status_t CloseFile() const;
|
||||
status_t GetSupportedTypes(BMessage *types);
|
||||
status_t SetSupportedTypes(const BMessage *types, bool fullSync = true);
|
||||
|
||||
static status_t GetAssociatedTypes(const char *extension, BMessage *types);
|
||||
|
||||
// void MimeChanged(int32 w, const char *type = NULL,
|
||||
// bool large = true) const;
|
||||
|
||||
|
@ -39,32 +39,37 @@ extern const char *kRAppLooperPortName;
|
||||
// message constants
|
||||
enum {
|
||||
// replies
|
||||
B_REG_SUCCESS = 'rgsu',
|
||||
B_REG_ERROR = 'rger',
|
||||
B_REG_RESULT = 'rgrz',
|
||||
B_REG_SUCCESS = 'rgsu',
|
||||
B_REG_ERROR = 'rger',
|
||||
B_REG_RESULT = 'rgrz',
|
||||
// general requests
|
||||
B_REG_GET_MIME_MESSENGER = 'rgmm',
|
||||
B_REG_GET_CLIPBOARD_MESSENGER = 'rgcm',
|
||||
B_REG_GET_MIME_MESSENGER = 'rgmm',
|
||||
B_REG_GET_CLIPBOARD_MESSENGER = 'rgcm',
|
||||
// roster requests
|
||||
B_REG_ADD_APP = 'rgaa',
|
||||
B_REG_COMPLETE_REGISTRATION = 'rgcr',
|
||||
B_REG_IS_APP_PRE_REGISTERED = 'rgip',
|
||||
B_REG_REMOVE_PRE_REGISTERED_APP = 'rgrp',
|
||||
B_REG_REMOVE_APP = 'rgra',
|
||||
B_REG_SET_THREAD_AND_TEAM = 'rgtt',
|
||||
B_REG_GET_APP_INFO = 'rgai',
|
||||
B_REG_GET_APP_LIST = 'rgal',
|
||||
B_REG_ACTIVATE_APP = 'rgac',
|
||||
B_REG_ADD_APP = 'rgaa',
|
||||
B_REG_COMPLETE_REGISTRATION = 'rgcr',
|
||||
B_REG_IS_APP_PRE_REGISTERED = 'rgip',
|
||||
B_REG_REMOVE_PRE_REGISTERED_APP = 'rgrp',
|
||||
B_REG_REMOVE_APP = 'rgra',
|
||||
B_REG_SET_THREAD_AND_TEAM = 'rgtt',
|
||||
B_REG_GET_APP_INFO = 'rgai',
|
||||
B_REG_GET_APP_LIST = 'rgal',
|
||||
B_REG_ACTIVATE_APP = 'rgac',
|
||||
// MIME requests
|
||||
B_REG_MIME_SET_PARAM = 'rgsp',
|
||||
B_REG_MIME_DELETE_PARAM = 'rgdp',
|
||||
B_REG_MIME_START_WATCHING = 'rgwb',
|
||||
B_REG_MIME_STOP_WATCHING = 'rgwe',
|
||||
B_REG_MIME_INSTALL = 'rgin',
|
||||
B_REG_MIME_DELETE = 'rgdl',
|
||||
B_REG_MIME_GET_INSTALLED_TYPES = 'rgit',
|
||||
B_REG_MIME_GET_INSTALLED_SUPERTYPES = 'rgis',
|
||||
B_REG_MIME_GET_SUPPORTING_APPS = 'rgsa',
|
||||
B_REG_MIME_SET_PARAM = 'rgsp',
|
||||
B_REG_MIME_DELETE_PARAM = 'rgdp',
|
||||
B_REG_MIME_START_WATCHING = 'rgwb',
|
||||
B_REG_MIME_STOP_WATCHING = 'rgwe',
|
||||
B_REG_MIME_INSTALL = 'rgin',
|
||||
B_REG_MIME_DELETE = 'rgdl',
|
||||
B_REG_MIME_GET_INSTALLED_TYPES = 'rgit',
|
||||
B_REG_MIME_GET_INSTALLED_SUPERTYPES = 'rgis',
|
||||
B_REG_MIME_GET_SUPPORTING_APPS = 'rgsa',
|
||||
B_REG_MIME_GET_ASSOCIATED_TYPES = 'rgat',
|
||||
B_REG_MIME_SNIFF = 'rgsn',
|
||||
B_REG_MIME_UPDATE_MIME_INFO_ASYNC = 'rgup',
|
||||
B_REG_MIME_CREATE_APP_META_MIME_ASYNC = 'rgca',
|
||||
B_REG_MIME_ASYNC_THREAD_FINISHED = 'rgtf',
|
||||
};
|
||||
|
||||
// B_REG_MIME_SET_PARAM "which" constants
|
||||
|
@ -10,9 +10,12 @@
|
||||
#ifndef _MIME_DATABASE_H
|
||||
#define _MIME_DATABASE_H
|
||||
|
||||
#include <mime/InstalledTypes.h>
|
||||
#include <mime/SupportingApps.h>
|
||||
#include <Mime.h>
|
||||
#include <mime/AssociatedTypes.h>
|
||||
#include <mime/InstalledTypes.h>
|
||||
#include <mime/SnifferRules.h>
|
||||
#include <mime/SupportingApps.h>
|
||||
#include <mime/database_access.h>
|
||||
#include <Messenger.h>
|
||||
#include <StorageDefs.h>
|
||||
|
||||
@ -23,6 +26,9 @@
|
||||
class BNode;
|
||||
class BBitmap;
|
||||
class BMessage;
|
||||
class BString;
|
||||
|
||||
struct entry_ref;
|
||||
|
||||
namespace BPrivate {
|
||||
namespace Storage {
|
||||
@ -58,13 +64,12 @@ public:
|
||||
status_t GetInstalledTypes(const char *super_type,
|
||||
BMessage *subtypes);
|
||||
status_t GetSupportingApps(const char *type, BMessage *signatures);
|
||||
status_t GetAssociatedTypes(const char *extension, BMessage *types);
|
||||
|
||||
// Sniffer
|
||||
// static status_t CheckSnifferRule(const char *rule, BString *parseError);
|
||||
// static status_t GuessMimeType(const entry_ref *file, BMimeType *result);
|
||||
// static status_t GuessMimeType(const void *buffer, int32 length,
|
||||
// BMimeType *result);
|
||||
// static status_t GuessMimeType(const char *filename, BMimeType *result);
|
||||
status_t GuessMimeType(const entry_ref *file, BString *result);
|
||||
status_t GuessMimeType(const void *buffer, int32 length, BString *result);
|
||||
status_t GuessMimeType(const char *filename, BString *result);
|
||||
|
||||
// Monitor
|
||||
status_t StartWatching(BMessenger target);
|
||||
@ -81,11 +86,15 @@ public:
|
||||
status_t DeletePreferredApp(const char *type, app_verb verb = B_OPEN);
|
||||
status_t DeleteSnifferRule(const char *type);
|
||||
status_t DeleteSupportedTypes(const char *type, bool fullSync);
|
||||
|
||||
// Asynchronous C function calls
|
||||
status_t UpdateMimeInfoAsync(const entry_ref *ref, bool recursive, bool force);
|
||||
status_t CleanupAfterAsyncThread(thread_id id);
|
||||
|
||||
private:
|
||||
// Functions to send monitor notifications
|
||||
status_t SendInstallNotification(const char *type);
|
||||
status_t SendDeleteNotification(const char *type);
|
||||
|
||||
status_t SendMonitorUpdate(int32 which, const char *type, const char *extraType,
|
||||
bool largeIcon, int32 action);
|
||||
status_t SendMonitorUpdate(int32 which, const char *type, const char *extraType,
|
||||
@ -96,10 +105,16 @@ private:
|
||||
int32 action);
|
||||
status_t SendMonitorUpdate(BMessage &msg);
|
||||
|
||||
// Entry point functions for asynchronous update threads
|
||||
static int32 UpdateMimeInfoAsyncEntry(void *data);
|
||||
|
||||
status_t fCStatus;
|
||||
std::set<BMessenger> fMonitorMessengers;
|
||||
AssociatedTypes fAssociatedTypes;
|
||||
InstalledTypes fInstalledTypes;
|
||||
SnifferRules fSnifferRules;
|
||||
SupportingApps fSupportingApps;
|
||||
std::list<async_thread_data*> fAsyncThreads;
|
||||
};
|
||||
|
||||
} // namespace Mime
|
||||
|
@ -4,7 +4,7 @@
|
||||
//---------------------------------------------------------------------
|
||||
/*!
|
||||
\file database_access.h
|
||||
Mime database atomic read function declarations
|
||||
Mime database atomic read functions and miscellany declarations
|
||||
*/
|
||||
|
||||
#ifndef _MIME_DATABASE_ACCESS_H
|
||||
@ -39,6 +39,22 @@ bool is_installed(const char *type);
|
||||
// to be shipped off to SetIcon*() and written to the database
|
||||
status_t get_icon_data(const BBitmap *icon, icon_size size, void **data, int32 *dataSize);
|
||||
|
||||
// Common struct used to manage ansynchronous update threads
|
||||
struct async_thread_data {
|
||||
public:
|
||||
async_thread_data(thread_id id = -1);
|
||||
bool should_exit() const;
|
||||
void post_exit_notification();
|
||||
|
||||
thread_id id;
|
||||
private:
|
||||
bool _should_exit;
|
||||
};
|
||||
|
||||
// Called by directly (synchronous calls) and indirectly (asynchronous calls)
|
||||
// by update_mime_info()
|
||||
int update_mime_info(entry_ref *ref, bool recursive, bool force, async_thread_data *data = NULL);
|
||||
|
||||
} // namespace Mime
|
||||
} // namespace Storage
|
||||
} // namespace BPrivate
|
||||
|
@ -59,11 +59,20 @@ extern const int32 kSupportedTypesType;
|
||||
|
||||
// Message fields
|
||||
extern const char *kApplicationsField;
|
||||
extern const char *kExtensionsField;
|
||||
extern const char *kSupertypesField;
|
||||
extern const char *kSupportingAppsSubCountField;
|
||||
extern const char *kSupportingAppsSuperCountField;
|
||||
extern const char *kTypesField;
|
||||
|
||||
// Mime types
|
||||
extern const char *kGenericFileType;
|
||||
extern const char *kDirectoryType;
|
||||
extern const char *kSymlinkType;
|
||||
|
||||
// Error codes (to be used only by BPrivate::Storage::Mime members)
|
||||
extern const status_t kMimeGuessFailureError;
|
||||
|
||||
std::string type_to_filename(const char *type);
|
||||
|
||||
status_t open_type(const char *type, BNode *result);
|
||||
@ -72,6 +81,7 @@ status_t open_or_create_type(const char *type, BNode *result, bool *didCreate);
|
||||
ssize_t read_mime_attr(const char *type, const char *attr, void *data,
|
||||
size_t len, type_code datatype);
|
||||
status_t read_mime_attr_message(const char *type, const char *attr, BMessage *msg);
|
||||
status_t read_mime_attr_string(const char *type, const char *attr, BString *str);
|
||||
status_t write_mime_attr(const char *type, const char *attr, const void *data,
|
||||
size_t len, type_code datatype, bool *didCreate);
|
||||
status_t write_mime_attr_message(const char *type, const char *attr,
|
||||
|
@ -7,14 +7,25 @@
|
||||
Mime type C functions implementation.
|
||||
*/
|
||||
|
||||
#include <fs_attr.h>
|
||||
#include <fs_info.h>
|
||||
#include <Drivers.h>
|
||||
#include <Entry.h>
|
||||
#include <Mime.h>
|
||||
#include <MimeType.h>
|
||||
#include <mime/database_access.h>
|
||||
#include <Node.h>
|
||||
#include <RegistrarDefs.h>
|
||||
#include <Roster.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
enum {
|
||||
NOT_IMPLEMENTED = B_ERROR,
|
||||
};
|
||||
|
||||
// update_mime_info
|
||||
/*! \brief Updates the MIME information for one or more files.
|
||||
/*! \brief Updates the MIME information (i.e MIME type) for one or more files.
|
||||
If \a path points to a file, the MIME information for this file are
|
||||
updated only. If it points to a directory and \a recursive is non-null,
|
||||
the information for all the files in the given directory tree are updated.
|
||||
@ -34,7 +45,43 @@ enum {
|
||||
int
|
||||
update_mime_info(const char *path, int recursive, int synchronous, int force)
|
||||
{
|
||||
return NOT_IMPLEMENTED;
|
||||
BEntry root;
|
||||
entry_ref ref;
|
||||
if (!path)
|
||||
recursive = true;
|
||||
|
||||
status_t err = root.SetTo(path ? path : "/");
|
||||
if (!err)
|
||||
err = root.GetRef(&ref);
|
||||
if (!err) {
|
||||
// If the call is to be synchronous, handle it locally,
|
||||
// otherwise pass it off to the registrar
|
||||
if (synchronous) {
|
||||
err = BPrivate::Storage::Mime::update_mime_info(&ref, recursive, force);
|
||||
} else {
|
||||
BMessage msg(B_REG_MIME_UPDATE_MIME_INFO_ASYNC);
|
||||
BMessage reply;
|
||||
status_t result;
|
||||
const char *str;
|
||||
|
||||
// Build and send the message, read the reply
|
||||
if (!err)
|
||||
err = msg.AddRef("entry", &ref);
|
||||
if (!err)
|
||||
err = msg.AddBool("recursive", recursive);
|
||||
if (!err)
|
||||
err = msg.AddBool("force", force);
|
||||
if (!err)
|
||||
err = _send_to_roster_(&msg, &reply, true);
|
||||
if (!err)
|
||||
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = reply.FindInt32("result", &result);
|
||||
if (!err)
|
||||
err = result;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// create_app_meta_mime
|
||||
@ -64,8 +111,14 @@ create_app_meta_mime(const char *path, int recursive, int synchronous,
|
||||
/*! Retrieves an icon associated with a given device.
|
||||
\param dev The path to the device.
|
||||
\param icon A pointer to a buffer the icon data shall be written to.
|
||||
\param size The size of the icon. Currently the sizes 16 (small) and
|
||||
32 (large) are supported.
|
||||
\param size The size of the icon. Currently the sizes 16 (small, i.e
|
||||
\c B_MINI_ICON) and 32 (large, i.e. \c B_LARGE_ICON) are
|
||||
supported.
|
||||
|
||||
\todo The mounted directories for volumes can also have META:X:STD_ICON
|
||||
attributes. Should those attributes override the icon returned
|
||||
by ioctl(,B_GET_ICON,)?
|
||||
|
||||
\return
|
||||
- \c B_OK: Everything went fine.
|
||||
- An error code otherwise.
|
||||
@ -73,9 +126,51 @@ create_app_meta_mime(const char *path, int recursive, int synchronous,
|
||||
status_t
|
||||
get_device_icon(const char *dev, void *icon, int32 size)
|
||||
{
|
||||
return NOT_IMPLEMENTED;
|
||||
status_t err = dev && icon
|
||||
&& (size == B_LARGE_ICON || size == B_MINI_ICON)
|
||||
? B_OK : B_BAD_VALUE;
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if (!err) {
|
||||
fd = open(dev, O_RDONLY);
|
||||
err = fd != -1 ? B_OK : B_BAD_VALUE;
|
||||
}
|
||||
if (!err) {
|
||||
device_icon iconData = { size, icon };
|
||||
err = ioctl(fd, B_GET_ICON, &iconData);
|
||||
}
|
||||
if (fd != -1) {
|
||||
// If the file descriptor was open()ed, we need to close it
|
||||
// regardless. Only if we haven't yet encountered any errors
|
||||
// do we make note close()'s return value, however.
|
||||
status_t error = close(fd);
|
||||
if (!err)
|
||||
err = error;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -305,7 +305,7 @@ BMimeType::Contains(const BMimeType *type) const
|
||||
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::Install()
|
||||
@ -341,7 +341,7 @@ BMimeType::Install()
|
||||
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::Delete()
|
||||
@ -379,7 +379,7 @@ BMimeType::Delete()
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
|
||||
*/
|
||||
status_t
|
||||
@ -409,7 +409,7 @@ BMimeType::GetIcon(BBitmap *icon, icon_size size) const
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- \c B_ENTRY_NOT_FOUND: No preferred app exists for the given type and app_verb
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetPreferredApp(char *signature, app_verb verb) const
|
||||
@ -468,7 +468,7 @@ BMimeType::GetPreferredApp(char *signature, app_verb verb) const
|
||||
the MIME type's associated file attributes is stored.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetAttrInfo(BMessage *info) const
|
||||
@ -505,7 +505,7 @@ BMimeType::GetAttrInfo(BMessage *info) const
|
||||
MIME type's associated file extensions will be stored.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetFileExtensions(BMessage *extensions) const
|
||||
@ -527,7 +527,7 @@ BMimeType::GetFileExtensions(BMessage *extensions) const
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- \c B_ENTRY_NOT_FOUND: No short description exists for the given type
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetShortDescription(char *description) const
|
||||
@ -549,7 +549,7 @@ BMimeType::GetShortDescription(char *description) const
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- \c B_ENTRY_NOT_FOUND: No long description exists for the given type
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetLongDescription(char *description) const
|
||||
@ -612,7 +612,7 @@ BMimeType::GetLongDescription(char *description) const
|
||||
of the supporting applications will be copied.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetSupportingApps(BMessage *signatures) const
|
||||
@ -655,7 +655,7 @@ BMimeType::GetSupportingApps(BMessage *signatures) const
|
||||
and \c B_MINI_ICON are supported.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
|
||||
*/
|
||||
status_t
|
||||
@ -682,7 +682,7 @@ BMimeType::SetIcon(const BBitmap *icon, icon_size which)
|
||||
Currently, the only supported app verb is \c B_OPEN.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::SetPreferredApp(const char *signature, app_verb verb)
|
||||
@ -760,7 +760,7 @@ BMimeType::SetPreferredApp(const char *signature, app_verb verb)
|
||||
MIME type.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::SetAttrInfo(const BMessage *info)
|
||||
@ -817,7 +817,7 @@ BMimeType::SetAttrInfo(const BMessage *info)
|
||||
the new list of file extensions to associate with this MIME type.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::SetFileExtensions(const BMessage *extensions)
|
||||
@ -857,7 +857,7 @@ BMimeType::SetFileExtensions(const BMessage *extensions)
|
||||
\param description Pointer to a pre-allocated string containing the new short description
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::SetShortDescription(const char *description)
|
||||
@ -899,7 +899,7 @@ BMimeType::SetShortDescription(const char *description)
|
||||
\param description Pointer to a pre-allocated string containing the new long description
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::SetLongDescription(const char *description)
|
||||
@ -941,7 +941,7 @@ BMimeType::SetLongDescription(const char *description)
|
||||
MIME supertypes will be copied.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetInstalledSupertypes(BMessage *supertypes)
|
||||
@ -977,7 +977,7 @@ BMimeType::GetInstalledSupertypes(BMessage *supertypes)
|
||||
MIME types will be copied.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetInstalledTypes(BMessage *types)
|
||||
@ -998,7 +998,7 @@ BMimeType::GetInstalledTypes(BMessage *types)
|
||||
MIME subtypes will be copied.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetInstalledTypes(const char *supertype, BMessage *types)
|
||||
@ -1039,7 +1039,7 @@ BMimeType::GetInstalledTypes(const char *supertype, BMessage *types)
|
||||
applications supporting files of any type are copied.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetWildcardApps(BMessage *wild_ones)
|
||||
@ -1117,7 +1117,7 @@ bool isValidMimeChar(const char ch)
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- \c B_ENTRY_NOT_FOUND: No app hint exists for the given type
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetAppHint(entry_ref *ref) const
|
||||
@ -1144,7 +1144,7 @@ BMimeType::GetAppHint(entry_ref *ref) const
|
||||
\param ref Pointer to a pre-allocated \c entry_ref containting the location of the new app hint
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::SetAppHint(const entry_ref *ref)
|
||||
@ -1199,7 +1199,7 @@ BMimeType::SetAppHint(const entry_ref *ref)
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
|
||||
*/
|
||||
status_t
|
||||
@ -1244,7 +1244,7 @@ BMimeType::GetIconForType(const char *type, BBitmap *icon, icon_size which) cons
|
||||
and \c B_MINI_ICON are supported.
|
||||
\return
|
||||
- \c B_OK: Success
|
||||
- "error code": Failure
|
||||
- other error code: Failure
|
||||
|
||||
*/
|
||||
status_t
|
||||
@ -1453,7 +1453,7 @@ BMimeType::CheckSnifferRule(const char *rule, BString *parseError)
|
||||
"application/octet-stream", the filename is examined for extensions.
|
||||
|
||||
\param ref Pointer to the entry_ref referring to the entry.
|
||||
\param result Pointer to a pre-allocated BMimeType which is set to the
|
||||
\param type Pointer to a pre-allocated BMimeType which is set to the
|
||||
resulting MIME type.
|
||||
\return
|
||||
- \c B_OK: Everything went fine.
|
||||
@ -1461,25 +1461,69 @@ BMimeType::CheckSnifferRule(const char *rule, BString *parseError)
|
||||
- \c B_NAME_NOT_FOUND: \a ref refers to an abstract entry.
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GuessMimeType(const entry_ref *file, BMimeType *result)
|
||||
BMimeType::GuessMimeType(const entry_ref *file, BMimeType *type)
|
||||
{
|
||||
return NOT_IMPLEMENTED;
|
||||
status_t err = file && type ? B_OK : B_BAD_VALUE;
|
||||
|
||||
BMessage msg(B_REG_MIME_SNIFF);
|
||||
BMessage reply;
|
||||
status_t result;
|
||||
const char *str;
|
||||
|
||||
// Build and send the message, read the reply
|
||||
if (!err)
|
||||
err = msg.AddRef("file ref", file);
|
||||
if (!err)
|
||||
err = _send_to_roster_(&msg, &reply, true);
|
||||
if (!err)
|
||||
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = reply.FindInt32("result", &result);
|
||||
if (!err)
|
||||
err = result;
|
||||
if (!err)
|
||||
err = reply.FindString("mime type", &str);
|
||||
if (!err)
|
||||
err = type->SetTo(str);
|
||||
return err;
|
||||
}
|
||||
|
||||
// GuessMimeType
|
||||
/*! \brief Guesses a MIME type for the supplied chunk of data.
|
||||
\param buffer Pointer to the data buffer.
|
||||
\param length Size of the buffer in bytes.
|
||||
\param result Pointer to a pre-allocated BMimeType which is set to the
|
||||
\param type Pointer to a pre-allocated BMimeType which is set to the
|
||||
resulting MIME type.
|
||||
\return
|
||||
- \c B_OK: Everything went fine.
|
||||
- \c B_BAD_VALUE: \c NULL \a buffer or \a result.
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *result)
|
||||
BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *type)
|
||||
{
|
||||
return NOT_IMPLEMENTED;
|
||||
status_t err = buffer && type ? B_OK : B_BAD_VALUE;
|
||||
|
||||
BMessage msg(B_REG_MIME_SNIFF);
|
||||
BMessage reply;
|
||||
status_t result;
|
||||
const char *str;
|
||||
|
||||
// Build and send the message, read the reply
|
||||
if (!err)
|
||||
err = msg.AddData("data", B_RAW_TYPE, buffer, length);
|
||||
if (!err)
|
||||
err = _send_to_roster_(&msg, &reply, true);
|
||||
if (!err)
|
||||
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = reply.FindInt32("result", &result);
|
||||
if (!err)
|
||||
err = result;
|
||||
if (!err)
|
||||
err = reply.FindString("mime type", &str);
|
||||
if (!err)
|
||||
err = type->SetTo(str);
|
||||
return err;
|
||||
}
|
||||
|
||||
// GuessMimeType
|
||||
@ -1489,16 +1533,38 @@ BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *result)
|
||||
doesn't need to exist at all.
|
||||
|
||||
\param filename The filename.
|
||||
\param result Pointer to a pre-allocated BMimeType which is set to the
|
||||
\param type Pointer to a pre-allocated BMimeType which is set to the
|
||||
resulting MIME type.
|
||||
\return
|
||||
- \c B_OK: Everything went fine.
|
||||
- \c B_BAD_VALUE: \c NULL \a ref or \a result.
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GuessMimeType(const char *filename, BMimeType *result)
|
||||
BMimeType::GuessMimeType(const char *filename, BMimeType *type)
|
||||
{
|
||||
return NOT_IMPLEMENTED;
|
||||
status_t err = filename && type ? B_OK : B_BAD_VALUE;
|
||||
|
||||
BMessage msg(B_REG_MIME_SNIFF);
|
||||
BMessage reply;
|
||||
status_t result;
|
||||
const char *str;
|
||||
|
||||
// Build and send the message, read the reply
|
||||
if (!err)
|
||||
err = msg.AddString("filename", filename);
|
||||
if (!err)
|
||||
err = _send_to_roster_(&msg, &reply, true);
|
||||
if (!err)
|
||||
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = reply.FindInt32("result", &result);
|
||||
if (!err)
|
||||
err = result;
|
||||
if (!err)
|
||||
err = reply.FindString("mime type", &str);
|
||||
if (!err)
|
||||
err = type->SetTo(str);
|
||||
return err;
|
||||
}
|
||||
|
||||
// StartWatching
|
||||
@ -1740,6 +1806,45 @@ BMimeType::SetSupportedTypes(const BMessage *types, bool fullSync)
|
||||
return err;
|
||||
}
|
||||
|
||||
// GetAssociatedTypes
|
||||
/*! \brief Returns a list of mime types associated with the given file extension
|
||||
|
||||
The list of types is returned in the pre-allocated \c BMessage pointed to
|
||||
by \a types. The types are stored in the message's "types" field, which
|
||||
is an array of \c B_STRING_TYPE values.
|
||||
|
||||
\param extension The file extension of interest
|
||||
\param types Pointer to a pre-allocated BMessage into which the result will
|
||||
be stored
|
||||
|
||||
\return
|
||||
- \c B_OK: success
|
||||
- other error code: failure
|
||||
*/
|
||||
status_t
|
||||
BMimeType::GetAssociatedTypes(const char *extension, BMessage *types)
|
||||
{
|
||||
status_t err = extension && types ? B_OK : B_BAD_VALUE;
|
||||
|
||||
BMessage msg(B_REG_MIME_GET_ASSOCIATED_TYPES);
|
||||
BMessage &reply = *types;
|
||||
status_t result;
|
||||
|
||||
// Build and send the message, read the reply
|
||||
if (!err)
|
||||
err = msg.AddString("extension", extension);
|
||||
if (!err)
|
||||
err = _send_to_roster_(&msg, &reply, true);
|
||||
if (!err)
|
||||
err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = reply.FindInt32("result", &result);
|
||||
if (!err)
|
||||
err = result;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
// Returns a lowercase version of str in result. Result must
|
||||
// be preallocated and is assumed to be of adequate length.
|
||||
status_t
|
||||
|
@ -12,12 +12,14 @@
|
||||
#include <DataIO.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <Locker.h>
|
||||
#include <Message.h>
|
||||
#include <mime/database_access.h>
|
||||
#include <mime/database_support.h>
|
||||
#include <MimeType.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <storage_support.h>
|
||||
#include <TypeConstants.h>
|
||||
|
||||
@ -43,6 +45,28 @@ namespace BPrivate {
|
||||
namespace Storage {
|
||||
namespace Mime {
|
||||
|
||||
// update_mime_info_async_params
|
||||
/*! \brief All the neccessary data for managing an asynchronous update_mime_info()
|
||||
call bundled into a single struct.
|
||||
*/
|
||||
struct update_mime_info_async_data : public async_thread_data {
|
||||
public:
|
||||
entry_ref ref;
|
||||
bool recursive;
|
||||
bool force;
|
||||
|
||||
update_mime_info_async_data(const entry_ref *ref, bool recursive, bool force)
|
||||
: async_thread_data()
|
||||
, ref(ref ? *ref : entry_ref())
|
||||
, recursive(recursive)
|
||||
, force(force)
|
||||
{
|
||||
}
|
||||
private:
|
||||
update_mime_info_async_data();
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
\class Database
|
||||
\brief Mime::Database is the master of the MIME data base.
|
||||
@ -67,9 +91,28 @@ Database::Database()
|
||||
|
||||
// destructor
|
||||
/*! \brief Frees all resources associated with this object.
|
||||
|
||||
Any currently running asynchronous update threads are instructed
|
||||
to politely exit and then waited on.
|
||||
*/
|
||||
Database::~Database()
|
||||
{
|
||||
std::list<async_thread_data*>::iterator i;
|
||||
DBG(OUT("Asking async threads to quit...\n"));
|
||||
for (i = fAsyncThreads.begin();
|
||||
i != fAsyncThreads.end();
|
||||
i++)
|
||||
{
|
||||
DBG(OUT(" id == %ld\n", (*i)->id));
|
||||
(*i)->post_exit_notification();
|
||||
}
|
||||
for (i = fAsyncThreads.begin();
|
||||
i != fAsyncThreads.end();
|
||||
i++)
|
||||
{
|
||||
status_t exitValue;
|
||||
wait_for_thread((*i)->id, &exitValue);
|
||||
}
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
@ -396,8 +439,6 @@ Database::SetPreferredApp(const char *type, const char *signature, app_verb verb
|
||||
|
||||
// SetSnifferRule
|
||||
/*! \brief Sets the mime sniffer rule for the given mime type
|
||||
|
||||
\todo This ought to trigger an update to the sniffer rule manager whenever we write one
|
||||
*/
|
||||
status_t
|
||||
Database::SetSnifferRule(const char *type, const char *rule)
|
||||
@ -408,6 +449,8 @@ Database::SetSnifferRule(const char *type, const char *rule)
|
||||
if (!err)
|
||||
err = write_mime_attr(type, kSnifferRuleAttr, rule, strlen(rule)+1,
|
||||
kSnifferRuleType, &didCreate);
|
||||
if (!err)
|
||||
err = fSnifferRules.SetSnifferRule(type, rule);
|
||||
if (!err && didCreate)
|
||||
err = SendInstallNotification(type);
|
||||
if (!err)
|
||||
@ -532,6 +575,101 @@ Database::GetSupportingApps(const char *type, BMessage *signatures)
|
||||
return fSupportingApps.GetSupportingApps(type, signatures);
|
||||
}
|
||||
|
||||
// GetAssociatedTypes
|
||||
/*! \brief Returns a list of mime types associated with the given file extension
|
||||
|
||||
Please see BMimeType::GetAssociatedTypes() for more details.
|
||||
*/
|
||||
status_t
|
||||
Database::GetAssociatedTypes(const char *extension, BMessage *types)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// GuessMimeType
|
||||
/*! \brief Guesses a MIME type for the entry referred to by the given
|
||||
\c entry_ref.
|
||||
|
||||
This version of GuessMimeType() combines the features of the other
|
||||
versions: First the data of the given file are checked (sniffed).
|
||||
If sniffing fails, the filename is examined for extensions. If this
|
||||
fails, the "application/octet-stream" is returned.
|
||||
|
||||
\param ref Pointer to the entry_ref referring to the entry.
|
||||
\param type Pointer to a pre-allocated BString which is set to the
|
||||
resulting MIME type.
|
||||
\return
|
||||
- \c B_OK: success (even if the guess returned is "application/octet-stream")
|
||||
- other error code: failure
|
||||
*/
|
||||
status_t
|
||||
Database::GuessMimeType(const entry_ref *file, BString *result)
|
||||
{
|
||||
status_t err = file && result ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = fSnifferRules.GuessMimeType(file, result);
|
||||
if (err == kMimeGuessFailureError)
|
||||
err = fAssociatedTypes.GuessMimeType(file, result);
|
||||
if (err == kMimeGuessFailureError) {
|
||||
result->SetTo(kGenericFileType);
|
||||
err = B_OK;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// GuessMimeType
|
||||
/*! \brief Guesses a MIME type for the supplied chunk of data.
|
||||
|
||||
See \c SnifferRules::GuessMimeType(BPositionIO*, BString*)
|
||||
for more details.
|
||||
|
||||
\param buffer Pointer to the data buffer.
|
||||
\param length Size of the buffer in bytes.
|
||||
\param type Pointer to a pre-allocated BString which is set to the
|
||||
resulting MIME type.
|
||||
\return
|
||||
- \c B_OK: success
|
||||
- error code: failure
|
||||
*/
|
||||
status_t
|
||||
Database::GuessMimeType(const void *buffer, int32 length, BString *result)
|
||||
{
|
||||
status_t err = buffer && result ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = fSnifferRules.GuessMimeType(buffer, length, result);
|
||||
if (err == kMimeGuessFailureError) {
|
||||
result->SetTo(kGenericFileType);
|
||||
err = B_OK;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// GuessMimeType
|
||||
/*! \brief Guesses a MIME type for the given filename.
|
||||
|
||||
Only the filename itself is taken into consideration (in particular its
|
||||
name extension), not the entry or corresponding data it refers to (in fact,
|
||||
an entry with that name need not exist at all.
|
||||
|
||||
\param filename The filename.
|
||||
\param type Pointer to a pre-allocated BString which is set to the
|
||||
resulting MIME type.
|
||||
\return
|
||||
- \c B_OK: success
|
||||
- error code: failure
|
||||
*/
|
||||
status_t
|
||||
Database::GuessMimeType(const char *filename, BString *result)
|
||||
{
|
||||
status_t err = filename && result ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = fAssociatedTypes.GuessMimeType(filename, result);
|
||||
if (err == kMimeGuessFailureError) {
|
||||
result->SetTo(kGenericFileType);
|
||||
err = B_OK;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// StartWatching
|
||||
//! Subscribes the given BMessenger to the MIME monitor service
|
||||
@ -826,6 +964,8 @@ status_t
|
||||
Database::DeleteSnifferRule(const char *type)
|
||||
{
|
||||
status_t err = delete_attribute(type, kSnifferRuleAttr);
|
||||
if (!err)
|
||||
err = fSnifferRules.DeleteSnifferRule(type);
|
||||
if (!err)
|
||||
err = SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_DELETED);
|
||||
return err;
|
||||
@ -865,6 +1005,62 @@ Database::DeleteSupportedTypes(const char *type, bool fullSync)
|
||||
return err;
|
||||
}
|
||||
|
||||
// UpdateMimeInfoAsync
|
||||
/*! \brief Performs the corresponding update_mime_info() call asynchronously (i.e
|
||||
in a new thread).
|
||||
|
||||
*/
|
||||
status_t
|
||||
Database::UpdateMimeInfoAsync(const entry_ref *ref, bool recursive, bool force)
|
||||
{
|
||||
thread_id id = -1;
|
||||
status_t err;
|
||||
update_mime_info_async_data *data;
|
||||
|
||||
data = new(nothrow) update_mime_info_async_data(ref, recursive, force);
|
||||
err = data ? B_OK : B_NO_MEMORY;
|
||||
// Spawn the thread
|
||||
if (!err) {
|
||||
id = spawn_thread(&Database::UpdateMimeInfoAsyncEntry, "mime updater (umi)",
|
||||
B_NORMAL_PRIORITY, (void*)data);
|
||||
err = id >= 0 ? B_OK : id;
|
||||
}
|
||||
// Update the thread_id, store the thread info, and get it running
|
||||
if (!err) {
|
||||
data->id = id;
|
||||
fAsyncThreads.push_back(data);
|
||||
err = resume_thread(id);
|
||||
}
|
||||
if (!err)
|
||||
DBG(OUT("spawned new update_mime_info() thread, id == %ld\n", id));
|
||||
return err;
|
||||
}
|
||||
|
||||
// CleanupAfterAsyncThread
|
||||
/*! \brief Removes the given thread from the list of currently running asynchronous
|
||||
threads and frees its associated shared \c async_thread_data object.
|
||||
*/
|
||||
status_t
|
||||
Database::CleanupAfterAsyncThread(thread_id id)
|
||||
{
|
||||
status_t err = B_ENTRY_NOT_FOUND;
|
||||
std::list<async_thread_data*>::iterator i;
|
||||
for (i = fAsyncThreads.begin(); i != fAsyncThreads.end(); i++) {
|
||||
if (*i) {
|
||||
if ((*i)->id == id) {
|
||||
delete *i;
|
||||
fAsyncThreads.erase(i);
|
||||
err = B_OK;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
OUT("WARNING: NULL async_thread_data pointer found in Mime::Database::fAsyncThreads list\n");
|
||||
fAsyncThreads.erase(i);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// SendInstallNotification
|
||||
//! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service
|
||||
status_t
|
||||
@ -875,6 +1071,8 @@ Database::SendInstallNotification(const char *type)
|
||||
return err;
|
||||
}
|
||||
|
||||
// SendDeleteNotification
|
||||
//! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
|
||||
status_t
|
||||
//! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service
|
||||
Database::SendDeleteNotification(const char *type)
|
||||
@ -990,19 +1188,29 @@ Database::SendMonitorUpdate(int32 which, const char *type, int32 action) {
|
||||
*/
|
||||
status_t
|
||||
Database::SendMonitorUpdate(BMessage &msg) {
|
||||
DBG(OUT("Database::SendMonitorUpdate(BMessage&)\n"));
|
||||
// DBG(OUT("Database::SendMonitorUpdate(BMessage&)\n"));
|
||||
status_t err;
|
||||
std::set<BMessenger>::const_iterator i;
|
||||
for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) {
|
||||
status_t err = (*i).SendMessage(&msg, (BHandler*)NULL);
|
||||
if (err)
|
||||
DBG(OUT("Database::SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, %p\n", err));
|
||||
DBG(OUT("Database::SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, 0x%lx\n", err));
|
||||
}
|
||||
DBG(OUT("Database::SendMonitorUpdate(BMessage&) done\n"));
|
||||
// DBG(OUT("Database::SendMonitorUpdate(BMessage&) done\n"));
|
||||
err = B_OK;
|
||||
return err;
|
||||
}
|
||||
|
||||
// UpdateMimeInfoAsyncEntry(void *data)
|
||||
/*! \brief Entry point for asynchronous update_mime_info() threads
|
||||
*/
|
||||
int32
|
||||
Database::UpdateMimeInfoAsyncEntry(void *data)
|
||||
{
|
||||
update_mime_info_async_data *info = (update_mime_info_async_data*)data;
|
||||
return update_mime_info(&(info->ref), info->recursive, info->force, info);
|
||||
}
|
||||
|
||||
} // namespace Mime
|
||||
} // namespace Storage
|
||||
} // namespace BPrivate
|
||||
|
@ -9,10 +9,12 @@
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Entry.h>
|
||||
#include <Directory.h>
|
||||
#include <Message.h>
|
||||
#include <mime/database_support.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <RegistrarDefs.h>
|
||||
#include <storage_support.h>
|
||||
|
||||
#include <fs_attr.h> // For struct attr_info
|
||||
@ -23,8 +25,8 @@
|
||||
|
||||
#include "mime/database_access.h"
|
||||
|
||||
//#define DBG(x) x
|
||||
#define DBG(x)
|
||||
#define DBG(x) x
|
||||
//#define DBG(x)
|
||||
#define OUT printf
|
||||
|
||||
namespace BPrivate {
|
||||
@ -320,13 +322,7 @@ get_preferred_app(const char *type, char *signature, app_verb verb = B_OPEN)
|
||||
status_t
|
||||
get_sniffer_rule(const char *type, BString *result)
|
||||
{
|
||||
BNode node;
|
||||
status_t err = result ? B_OK : B_BAD_VALUE;
|
||||
if (!err)
|
||||
err = open_type(type, &node);
|
||||
if (!err)
|
||||
err = node.ReadAttrString(kSnifferRuleAttr, result);
|
||||
return err;
|
||||
return read_mime_attr_string(type, kSnifferRuleAttr, result);
|
||||
}
|
||||
|
||||
// get_supported_types
|
||||
@ -421,6 +417,138 @@ get_icon_data(const BBitmap *icon, icon_size which, void **data, int32 *dataSize
|
||||
return err;
|
||||
}
|
||||
|
||||
/*! \struct async_thread_data
|
||||
\brief A thread id and functions to allow threads to be safely told
|
||||
when they need to politely quit what they're doing and exit.
|
||||
|
||||
As only the \c Mime::Database class will be posting exit notifications,
|
||||
and as interested threads will only be calling \c should_exit() on their
|
||||
respective \c async_thread_data objects, there currently is no synchronization
|
||||
implemented with respect to accessing the \c thead_data::thread_should_exit
|
||||
member. If this is a problem, a \c BLocker may be added and locking calls
|
||||
placed in \c should_exit() and \c post_exit_notification().
|
||||
*/
|
||||
|
||||
//! Creates a new \c async_thread_data object
|
||||
async_thread_data::async_thread_data(thread_id id)
|
||||
: id(id)
|
||||
, _should_exit(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*! \brief Returns \c true if the thread should politely exit as soon as
|
||||
possible, or \c false if it may continue running normally.
|
||||
*/
|
||||
bool
|
||||
async_thread_data::should_exit() const {
|
||||
return _should_exit;
|
||||
}
|
||||
|
||||
/*! \brief All subsequent calls to should_exit() will return \c true.
|
||||
*/
|
||||
void
|
||||
async_thread_data::post_exit_notification() {
|
||||
_should_exit = true;
|
||||
}
|
||||
|
||||
// update_mime_info
|
||||
/*! \brief Updates the MIME information (i.e MIME type) for one or more files.
|
||||
|
||||
If \a path points to a file, the MIME information for this file are
|
||||
updated only. If it points to a directory and \a recursive is non-null,
|
||||
the information for all the files in the given directory tree are updated.
|
||||
|
||||
\param ref An entry_ref to a file or directory. May not be NULL.
|
||||
\param recursive \c true to trigger recursive behavior.
|
||||
\param force If \c true, file information is updated even if said
|
||||
information already exists.
|
||||
\return
|
||||
- \c B_OK: success
|
||||
- error code: failure
|
||||
*/
|
||||
int
|
||||
update_mime_info(entry_ref *ref, bool recursive, bool force, async_thread_data *data)
|
||||
{
|
||||
// using BPrivate::Storage::Mime::kFileTypeAttr;
|
||||
|
||||
status_t err = ref ? B_OK : B_BAD_VALUE;
|
||||
|
||||
BNode node;
|
||||
bool doUpdate = false;
|
||||
|
||||
// Figure out if we need to update or not
|
||||
if (!err)
|
||||
err = node.SetTo(ref);
|
||||
if (!err) {
|
||||
if (force)
|
||||
doUpdate = true;
|
||||
else {
|
||||
attr_info info;
|
||||
if (!err)
|
||||
doUpdate = node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
// Update *this* node if necessary
|
||||
if (!err && doUpdate) {
|
||||
BMimeType type;
|
||||
err = BMimeType::GuessMimeType(ref, &type);
|
||||
if (!err && type.InitCheck() == B_OK) {
|
||||
const char *typeStr = type.Type();
|
||||
ssize_t len = strlen(typeStr)+1;
|
||||
ssize_t bytes = node.WriteAttr(kFileTypeAttr, kFileTypeType, 0, typeStr, len);
|
||||
if (bytes < B_OK)
|
||||
err = bytes;
|
||||
else
|
||||
err = (bytes != len ? B_FILE_ERROR : B_OK);
|
||||
}
|
||||
}
|
||||
// If we're recursing and this is a directory, update each of the directory's
|
||||
// children as well
|
||||
if (!err && recursive && node.IsDirectory()) {
|
||||
node.Unset(); // Unset() to free a file descriptor, as we no longer need our BNode
|
||||
BDirectory dir;
|
||||
|
||||
err = dir.SetTo(ref);
|
||||
if (!err) {
|
||||
entry_ref childRef;
|
||||
while (!err) {
|
||||
err = dir.GetNextRef(&childRef);
|
||||
if (err) {
|
||||
// If we've come to the end of the directory listing,
|
||||
// it's not an error.
|
||||
if (err == B_ENTRY_NOT_FOUND)
|
||||
err = B_OK;
|
||||
break;
|
||||
} else {
|
||||
err = update_mime_info(&childRef, true, force);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we're running asynchronously, notify the database manager that
|
||||
// our thread is finished with its task so the manager call free our
|
||||
// associated data and remove us from the list of running threads.
|
||||
if (data) {
|
||||
BMessage msg(B_REG_MIME_ASYNC_THREAD_FINISHED);
|
||||
status_t result;
|
||||
status_t error = msg.AddInt32("thread id", data->id);
|
||||
if (!error)
|
||||
error = _send_to_roster_(&msg, &msg, true);
|
||||
if (!error)
|
||||
error = msg.what = B_REG_RESULT ? B_OK : B_BAD_VALUE;
|
||||
if (!error)
|
||||
error = msg.FindInt32("result", &result);
|
||||
if (!error)
|
||||
error = result;
|
||||
if (error)
|
||||
OUT("WARNING: async update_mime_info() thread failed termination notification with error 0x%lx\n", error);
|
||||
DBG(OUT("(id: %ld) exiting async update_mime_info() thread with result 0x%lx\n", find_thread(NULL), err));
|
||||
}
|
||||
if (data)
|
||||
snooze(9000000);
|
||||
return err;
|
||||
}
|
||||
|
||||
} // namespace Mime
|
||||
} // namespace Storage
|
||||
} // namespace BPrivate
|
||||
|
@ -78,11 +78,20 @@ const int32 kSupportedTypesType = B_MESSAGE_TYPE;
|
||||
|
||||
// Message fields
|
||||
const char *kApplicationsField = "applications";
|
||||
const char *kExtensionsField = "extensions";
|
||||
const char *kSupertypesField = "super_types";
|
||||
const char *kSupportingAppsSubCountField = "be:sub";
|
||||
const char *kSupportingAppsSuperCountField = "be:super";
|
||||
const char *kTypesField = "types";
|
||||
|
||||
// Mime types
|
||||
const char *kGenericFileType = "application/octet-stream";
|
||||
const char *kDirectoryType = "application/x-vnd.Be-directory";
|
||||
const char *kSymlinkType = "application/x-vnd.Be-symlink";
|
||||
|
||||
// Error codes
|
||||
const status_t kMimeGuessFailureError = B_ERRORS_END+1;
|
||||
|
||||
// type_to_filename
|
||||
//! Converts the given MIME type to an absolute path in the MIME database.
|
||||
std::string
|
||||
@ -225,6 +234,30 @@ read_mime_attr_message(const char *type, const char *attr, BMessage *msg)
|
||||
return err;
|
||||
}
|
||||
|
||||
// read_mime_attr_string
|
||||
/*! \brief Reads a BString from the given attribute of the given
|
||||
MIME type.
|
||||
|
||||
If no entry for the given type exists in the database, the function fails
|
||||
and the contents of \c str are undefined.
|
||||
|
||||
\param type The MIME type
|
||||
\param attr The attribute name
|
||||
\param str Pointer to a pre-allocated BString into which the attribute
|
||||
data stored.
|
||||
*/
|
||||
ssize_t
|
||||
read_mime_attr_string(const char *type, const char *attr, BString *str)
|
||||
{
|
||||
BNode node;
|
||||
ssize_t err = (type && attr && str ? B_OK : B_BAD_VALUE);
|
||||
if (!err)
|
||||
err = open_type(type, &node);
|
||||
if (!err)
|
||||
err = node.ReadAttrString(attr, str);
|
||||
return err;
|
||||
}
|
||||
|
||||
// write_mime_attr
|
||||
/*! \brief Writes \c len bytes of the given data to the given attribute
|
||||
for the given MIME type.
|
||||
@ -236,7 +269,7 @@ read_mime_attr_message(const char *type, const char *attr, BMessage *msg)
|
||||
\param data Pointer to the data to write
|
||||
\param len The number of bytes to write
|
||||
\param datatype The data type of the given data
|
||||
*/
|
||||
*/
|
||||
status_t
|
||||
write_mime_attr(const char *type, const char *attr, const void *data,
|
||||
size_t len, type_code datatype, bool *didCreate)
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <ClassInfo.h>
|
||||
#include <Message.h>
|
||||
#include <RegistrarDefs.h>
|
||||
#include <String.h>
|
||||
#include <TypeConstants.h>
|
||||
|
||||
#include <stdio.h>
|
||||
@ -114,7 +115,6 @@ MIMEManager::MessageReceived(BMessage *message)
|
||||
|
||||
case B_REG_MIME_GET_SUPPORTING_APPS:
|
||||
{
|
||||
BMessage reply;
|
||||
const char *type;
|
||||
err = message->FindString("type", &type);
|
||||
if (!err)
|
||||
@ -126,6 +126,77 @@ MIMEManager::MessageReceived(BMessage *message)
|
||||
break;
|
||||
}
|
||||
|
||||
case B_REG_MIME_GET_ASSOCIATED_TYPES:
|
||||
{
|
||||
const char *extension;
|
||||
err = message->FindString("extension", &extension);
|
||||
if (!err)
|
||||
err = fDatabase.GetAssociatedTypes(extension, &reply);
|
||||
|
||||
reply.what = B_REG_RESULT;
|
||||
reply.AddInt32("result", err);
|
||||
message->SendReply(&reply, this);
|
||||
break;
|
||||
}
|
||||
|
||||
case B_REG_MIME_SNIFF:
|
||||
{
|
||||
BString str;
|
||||
entry_ref ref;
|
||||
const char *filename;
|
||||
err = message->FindString("filename", &filename);
|
||||
if (!err)
|
||||
err = fDatabase.GuessMimeType(filename, &str);
|
||||
else if (err == B_NAME_NOT_FOUND) {
|
||||
err = message->FindRef("file ref", &ref);
|
||||
if (!err)
|
||||
err = fDatabase.GuessMimeType(&ref, &str);
|
||||
else if (err == B_NAME_NOT_FOUND) {
|
||||
// err = message->FindData("file ref", &ref);
|
||||
// if (!err)
|
||||
// err = fDatabase.GuessMimeType(data, length, &str);
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
err = reply.AddString("mime type", str);
|
||||
|
||||
reply.what = B_REG_RESULT;
|
||||
reply.AddInt32("result", err);
|
||||
message->SendReply(&reply, this);
|
||||
break;
|
||||
}
|
||||
|
||||
case B_REG_MIME_UPDATE_MIME_INFO_ASYNC:
|
||||
{
|
||||
entry_ref ref;
|
||||
bool recursive, force;
|
||||
err = message->FindRef("entry", &ref);
|
||||
if (!err)
|
||||
err = message->FindBool("recursive", &recursive);
|
||||
if (!err)
|
||||
err = message->FindBool("force", &force);
|
||||
if (!err)
|
||||
err = fDatabase.UpdateMimeInfoAsync(&ref, recursive, force);
|
||||
|
||||
reply.what = B_REG_RESULT;
|
||||
reply.AddInt32("result", err);
|
||||
message->SendReply(&reply, this);
|
||||
break;
|
||||
}
|
||||
|
||||
case B_REG_MIME_ASYNC_THREAD_FINISHED:
|
||||
{
|
||||
thread_id id;
|
||||
err = message->FindInt32("thread id", &id);
|
||||
if (!err)
|
||||
err = fDatabase.CleanupAfterAsyncThread(id);
|
||||
|
||||
reply.what = B_REG_RESULT;
|
||||
reply.AddInt32("result", err);
|
||||
message->SendReply(&reply, this);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printf("MIMEMan: msg->what == %.4s\n", (char*)&(message->what));
|
||||
BLooper::MessageReceived(message);
|
||||
|
@ -3545,7 +3545,6 @@ MimeTypeTest::UpdateMimeInfoTest()
|
||||
// * Updating all files is not tested as it takes too long.
|
||||
|
||||
// individual files
|
||||
NextSubTest();
|
||||
execCommand(string("mkdir ") + testDir + "/subdir1 "
|
||||
+ testDir + "/subdir2 "
|
||||
+ testDir + "/subdir2/subsubdir1");
|
||||
@ -3556,7 +3555,9 @@ MimeTypeTest::UpdateMimeInfoTest()
|
||||
"text/html", "<html>\n<body>\n</body></html>\n")
|
||||
};
|
||||
int fileCount = sizeof(files) / sizeof(MimeInfoTestFile);
|
||||
// synchronous
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
NextSubTest();
|
||||
MimeInfoTestFile &file = files[i];
|
||||
// no recursion
|
||||
CHK(file.Create() == B_OK);
|
||||
@ -3579,16 +3580,49 @@ MimeTypeTest::UpdateMimeInfoTest()
|
||||
CHK(file.Delete() == B_OK);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Asynchronous calls
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const bigtime_t kSnoozeTime = 500000;
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
NextSubTest();
|
||||
MimeInfoTestFile &file = files[i];
|
||||
// no recursion
|
||||
CHK(file.Create() == B_OK);
|
||||
CHK(update_mime_info(file.name.c_str(), false, false, false) == B_OK);
|
||||
// give the system some time to do the update asynchronously
|
||||
snooze(kSnoozeTime);
|
||||
BNode node(file.name.c_str());
|
||||
CHK(node.InitCheck() == B_OK);
|
||||
BString type;
|
||||
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
|
||||
node.Unset();
|
||||
CHK(type == file.type.c_str());
|
||||
CHK(file.Delete() == B_OK);
|
||||
// recursion
|
||||
CHK(file.Create() == B_OK);
|
||||
CHK(update_mime_info(file.name.c_str(), true, false, false) == B_OK);
|
||||
// give the system some time to do the update asynchronously
|
||||
snooze(kSnoozeTime);
|
||||
CHK(node.SetTo(file.name.c_str()) == B_OK);
|
||||
type = "";
|
||||
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
|
||||
node.Unset();
|
||||
CHK(type == file.type.c_str());
|
||||
CHK(file.Delete() == B_OK);
|
||||
}
|
||||
|
||||
// TODO: The BeBook says: "if force is true, files are updated even if they've
|
||||
// been updated already."
|
||||
// As I understand this, calling update_mime_info() with force == true on a
|
||||
// file, should set the BEOS:TYPE attribute regardless of whether it already
|
||||
// had a value. The following test shows, that BEOS:TYPE remains unchanged
|
||||
// though.
|
||||
#if 0
|
||||
#if TEST_OBOS
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
MimeInfoTestFile &file = files[i];
|
||||
printf("file: %s\n", file.name.c_str());
|
||||
//printf("file: %s\n", file.name.c_str());
|
||||
CHK(file.Create() == B_OK);
|
||||
// add a type attribute
|
||||
BNode node(file.name.c_str());
|
||||
@ -3598,18 +3632,18 @@ printf("file: %s\n", file.name.c_str());
|
||||
// update, force == false
|
||||
CHK(update_mime_info(file.name.c_str(), false, true, false) == B_OK);
|
||||
type = "";
|
||||
CHK(RES(node.ReadAttrString("BEOS:TYPE", &type)) == B_OK);
|
||||
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
|
||||
CHK(type == "text/plain");
|
||||
// update, force == true
|
||||
CHK(update_mime_info(file.name.c_str(), false, true, true) == B_OK);
|
||||
type = "";
|
||||
CHK(RES(node.ReadAttrString("BEOS:TYPE", &type)) == B_OK);
|
||||
CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK);
|
||||
node.Unset();
|
||||
// CHK(type == file.type.c_str());
|
||||
printf("%s <-> %s\n", type.String(), file.type.c_str());
|
||||
//printf("%s <-> %s\n", type.String(), file.type.c_str());
|
||||
CHK(type == file.type.c_str());
|
||||
CHK(file.Delete() == B_OK);
|
||||
}
|
||||
#endif // 0
|
||||
#endif // TEST_OBOS
|
||||
|
||||
// directory
|
||||
NextSubTest();
|
||||
@ -3656,7 +3690,11 @@ printf("%s <-> %s\n", type.String(), file.type.c_str());
|
||||
BEntry entry(files[0].name.c_str());
|
||||
CHK(entry.InitCheck() == B_OK);
|
||||
CHK(entry.Exists() == false);
|
||||
#if TEST_R5
|
||||
CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_OK);
|
||||
#else
|
||||
CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_ENTRY_NOT_FOUND);
|
||||
#endif
|
||||
}
|
||||
|
||||
// WriteStringAttr
|
||||
@ -3849,6 +3887,9 @@ MimeTypeTest::CreateAppMetaMimeTest()
|
||||
"application/x-vnd.obos.mime.test.test3"),
|
||||
};
|
||||
const int fileCount = sizeof(files) / sizeof(AppMimeTestFile);
|
||||
//------------------------------------------------------------------------------
|
||||
// Synchronous calls
|
||||
//------------------------------------------------------------------------------
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
// create file, create_app_meta_mime()
|
||||
AppMimeTestFile &file = files[i];
|
||||
@ -3890,6 +3931,57 @@ MimeTypeTest::CreateAppMetaMimeTest()
|
||||
CHK(file.Delete(false) == B_OK);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Asynchronous calls
|
||||
//------------------------------------------------------------------------------
|
||||
const bigtime_t kSnoozeTime = 500000;
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
// create file, create_app_meta_mime()
|
||||
AppMimeTestFile &file = files[i];
|
||||
CHK(file.Create(true, true) == B_OK);
|
||||
CHK(create_app_meta_mime(file.name.c_str(), false, false, false)
|
||||
== B_OK);
|
||||
// give the system some time to do the update asynchronously
|
||||
snooze(kSnoozeTime);
|
||||
// check the MIME type
|
||||
CheckAppMetaMime(file);
|
||||
// clean up
|
||||
CHK(file.Delete(true) == B_OK);
|
||||
}
|
||||
|
||||
// attributes only
|
||||
NextSubTest();
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
// create file, create_app_meta_mime()
|
||||
AppMimeTestFile &file = files[i];
|
||||
CHK(file.Create(true, false) == B_OK);
|
||||
CHK(create_app_meta_mime(file.name.c_str(), false, false, false)
|
||||
== B_OK);
|
||||
// give the system some time to do the update asynchronously
|
||||
snooze(kSnoozeTime);
|
||||
// check the MIME type
|
||||
CheckAppMetaMime(file);
|
||||
// clean up
|
||||
CHK(file.Delete(true) == B_OK);
|
||||
}
|
||||
|
||||
// resources only
|
||||
NextSubTest();
|
||||
for (int32 i = 0; i < fileCount; i++) {
|
||||
// create file, create_app_meta_mime()
|
||||
AppMimeTestFile &file = files[i];
|
||||
CHK(file.Create(false, true) == B_OK);
|
||||
CHK(create_app_meta_mime(file.name.c_str(), false, false, false)
|
||||
== B_OK);
|
||||
// give the system some time to do the update asynchronously
|
||||
snooze(kSnoozeTime);
|
||||
BMimeType type;
|
||||
CHK(type.SetTo(file.signature.c_str()) == B_OK);
|
||||
CHK(type.IsInstalled() == false);
|
||||
// clean up
|
||||
CHK(file.Delete(false) == B_OK);
|
||||
}
|
||||
|
||||
// test the force flag
|
||||
// TODO: The BeBook says: "If force is true, entries are created even if they
|
||||
// already exist."
|
||||
@ -4499,7 +4591,7 @@ MimeTypeTest::SniffingTest()
|
||||
// This rule is invalid!
|
||||
CHK(type.SetSnifferRule("0.4 [0] ('XYZ') | [0:5] ('CD E')") == B_OK);
|
||||
#else
|
||||
CHK(type.SetSnifferRule("0.4 ([0] 'XYZ' | [0:5] 'CD E')") == B_OK);
|
||||
// CHK(type.SetSnifferRule("0.4 ([0] 'XYZ' | [0:5] 'CD E')") == B_OK);
|
||||
#endif
|
||||
CHK(type.SetTo(testType3) == B_OK);
|
||||
CHK(type.Install() == B_OK);
|
||||
@ -4556,6 +4648,7 @@ MimeTypeTest::SniffingTest()
|
||||
CHK(BMimeType::GuessMimeType(filename, &type) == B_OK);
|
||||
CHK(type == extensionType);
|
||||
type.Unset();
|
||||
/*
|
||||
// GuessMimeType(const void*, int32,)
|
||||
if (file.data != NULL) {
|
||||
CHK(BMimeType::GuessMimeType(file.data, file.size, &type) == B_OK);
|
||||
@ -4564,6 +4657,7 @@ printf("type: %s, should be: %s\n", type.Type(), realType);
|
||||
CHK(type == contentType);
|
||||
type.Unset();
|
||||
}
|
||||
*/
|
||||
CHK(file.Create() == B_OK);
|
||||
// set BEOS:TYPE to something confusing ;-)
|
||||
BNode node;
|
||||
@ -4572,12 +4666,14 @@ printf("type: %s, should be: %s\n", type.Type(), realType);
|
||||
// GuessMimeType(const ref*,)
|
||||
entry_ref ref;
|
||||
CHK(get_ref_for_path(filename, &ref) == B_OK);
|
||||
char thing[1024];
|
||||
sprintf(thing, "cat %s > /boot/home/Desktop/out.txt", filename);
|
||||
system(thing);
|
||||
CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK);
|
||||
if (!(type == realType))
|
||||
printf("type: %s, should be: %s\n", type.Type(), realType);
|
||||
printf("type: %s, should be: %s (file == '%s')\n", type.Type(), realType, filename);
|
||||
CHK(type == realType);
|
||||
type.Unset();
|
||||
|
||||
CHK(file.Delete() == B_OK);
|
||||
}
|
||||
|
||||
@ -4587,12 +4683,17 @@ printf("type: %s, should be: %s\n", type.Type(), realType);
|
||||
const char *filename = (string(testDir) + "/file100.cpp").c_str();
|
||||
BMimeType type;
|
||||
entry_ref ref;
|
||||
// invalid entry_ref: R5: Is fine!
|
||||
// invalid entry_ref: R5: Is fine! OBOS: no dice
|
||||
#if TEST_R5
|
||||
CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK);
|
||||
CHK(type == "application/octet-stream");
|
||||
#else
|
||||
CHK(BMimeType::GuessMimeType(&ref, &type) != B_OK);
|
||||
#endif
|
||||
// abstract entry_ref
|
||||
CHK(get_ref_for_path(filename, &ref) == B_OK);
|
||||
CHK(BMimeType::GuessMimeType(&ref, &type) == B_NAME_NOT_FOUND);
|
||||
// R5: B_NAME_NOT_FOUND, OBOS:
|
||||
CHK(BMimeType::GuessMimeType(&ref, &type) != B_OK);
|
||||
}
|
||||
|
||||
// bad args
|
||||
|
Loading…
Reference in New Issue
Block a user