From 15424f3d37665c19370cc5af241f1a37ece82e85 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 28 Jan 2006 19:41:07 +0000 Subject: [PATCH] Finally fixed update_mime_info(). As Be's version it understands two different "force" levels now and updates the app file info attributes for shared object files. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16123 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- docs/develop/servers/registrar/Protocols | 11 +- headers/os/storage/Mime.h | 20 +- .../storage/mime/CreateAppMetaMimeThread.h | 5 +- .../private/storage/mime/MimeUpdateThread.h | 7 +- .../storage/mime/UpdateMimeInfoThread.h | 5 +- src/kits/storage/Mime.cpp | 14 +- .../storage/mime/CreateAppMetaMimeThread.cpp | 8 +- src/kits/storage/mime/MimeUpdateThread.cpp | 5 +- .../storage/mime/UpdateMimeInfoThread.cpp | 185 +++++++++++++++--- src/servers/registrar/MIMEManager.cpp | 5 +- 10 files changed, 211 insertions(+), 54 deletions(-) diff --git a/docs/develop/servers/registrar/Protocols b/docs/develop/servers/registrar/Protocols index 2e2403d8bf..08c7fbea15 100644 --- a/docs/develop/servers/registrar/Protocols +++ b/docs/develop/servers/registrar/Protocols @@ -579,7 +579,7 @@ message: B_REG_MIME_UPDATE_MIME_INFO "entry": B_REF_TYPE "recursive": B_BOOLEAN_TYPE "synchronous": B_BOOLEAN_TYPE - "force": B_BOOLEAN_TYPE + "force": B_INT32_TYPE reply: standard general result message fields: @@ -589,8 +589,9 @@ message fields: - "synchronous": If true, the call will block until the operation is completed. If false, the call will return immediately and the operation will run asynchronously in another thread. -- "force": If true, also update entries for which a BEOS:TYPE attribute - already exists. +- "force": Specifies how to handle entries for which a BEOS:TYPE attribute + already exists. Valid values are + B_UPDATE_MIME_INFO_{NO_FORCE, FORCE_KEEP_TYPE, FORCE_UPDATE_ALL}. reply fields: - "result": @@ -607,7 +608,7 @@ message: B_REG_MIME_CREATE_APP_META_MIME "entry": B_REF_TYPE "recursive": B_BOOLEAN_TYPE "synchronous": B_BOOLEAN_TYPE - "force": B_BOOLEAN_TYPE + "force": B_INT32_TYPE reply: standard general result message fields: @@ -617,7 +618,7 @@ message fields: - "synchronous": If true, the call will block until the operation is completed. If false, the call will return immediately and the operation will run asynchronously in another thread. -- "force": If true, also update entries for which meta app information +- "force": If != 0, also update entries for which meta app information already exists. reply fields: diff --git a/headers/os/storage/Mime.h b/headers/os/storage/Mime.h index 314e95d7bb..e79f33acff 100644 --- a/headers/os/storage/Mime.h +++ b/headers/os/storage/Mime.h @@ -1,7 +1,8 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -//--------------------------------------------------------------------- +/* + * Copyright 2004-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + /*! \file Mime.h Mime type C functions interface declarations. @@ -37,11 +38,18 @@ enum icon_size { B_MINI_ICON = 16 }; +// values for the "force" parameter of update_mime_info() (Haiku only) +enum { + B_UPDATE_MIME_INFO_NO_FORCE = 0, + B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE = 1, + B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL = 2, +}; + #ifdef __cplusplus } #endif -// OpenBeOS only! +// Haiku only! #ifdef __cplusplus class BBitmap; @@ -56,5 +64,3 @@ status_t get_device_icon(const char *dev, BBitmap *icon, icon_size which); #endif #endif // _MIME_H - - diff --git a/headers/private/storage/mime/CreateAppMetaMimeThread.h b/headers/private/storage/mime/CreateAppMetaMimeThread.h index 02be36ba8f..acab27d886 100644 --- a/headers/private/storage/mime/CreateAppMetaMimeThread.h +++ b/headers/private/storage/mime/CreateAppMetaMimeThread.h @@ -18,8 +18,9 @@ namespace Mime { class CreateAppMetaMimeThread : public MimeUpdateThread { public: - CreateAppMetaMimeThread(const char *name, int32 priority, BMessenger managerMessenger, - const entry_ref *root, bool recursive, bool force, BMessage *replyee); + CreateAppMetaMimeThread(const char *name, int32 priority, + BMessenger managerMessenger, const entry_ref *root, bool recursive, + int32 force, BMessage *replyee); status_t DoMimeUpdate(const entry_ref *entry, bool *entryIsDir); }; diff --git a/headers/private/storage/mime/MimeUpdateThread.h b/headers/private/storage/mime/MimeUpdateThread.h index 3adad5c3c3..924d2b9e0a 100644 --- a/headers/private/storage/mime/MimeUpdateThread.h +++ b/headers/private/storage/mime/MimeUpdateThread.h @@ -26,8 +26,9 @@ namespace Mime { class MimeUpdateThread : public RegistrarThread { public: - MimeUpdateThread(const char *name, int32 priority, BMessenger managerMessenger, - const entry_ref *root, bool recursive, bool force, BMessage *replyee); + MimeUpdateThread(const char *name, int32 priority, + BMessenger managerMessenger, const entry_ref *root, bool recursive, + int32 force, BMessage *replyee); virtual ~MimeUpdateThread(); virtual status_t InitCheck(); @@ -38,7 +39,7 @@ protected: const entry_ref fRoot; const bool fRecursive; - const bool fForce; + const int32 fForce; BMessage *fReplyee; bool DeviceSupportsAttributes(dev_t device); diff --git a/headers/private/storage/mime/UpdateMimeInfoThread.h b/headers/private/storage/mime/UpdateMimeInfoThread.h index 6bae0b2624..9dd8183a85 100644 --- a/headers/private/storage/mime/UpdateMimeInfoThread.h +++ b/headers/private/storage/mime/UpdateMimeInfoThread.h @@ -18,8 +18,9 @@ namespace Mime { class UpdateMimeInfoThread : public MimeUpdateThread { public: - UpdateMimeInfoThread(const char *name, int32 priority, BMessenger managerMessenger, - const entry_ref *root, bool recursive, bool force, BMessage *replyee); + UpdateMimeInfoThread(const char *name, int32 priority, + BMessenger managerMessenger, const entry_ref *root, bool recursive, + int32 force, BMessage *replyee); status_t DoMimeUpdate(const entry_ref *entry, bool *entryIsDir); }; diff --git a/src/kits/storage/Mime.cpp b/src/kits/storage/Mime.cpp index b3d2bc6f8f..f8e8f93078 100644 --- a/src/kits/storage/Mime.cpp +++ b/src/kits/storage/Mime.cpp @@ -53,7 +53,7 @@ status_t do_mime_update(int32 what, const char *path, int recursive, if (!err) err = msg.AddBool("synchronous", synchronous); if (!err) - err = msg.AddBool("force", force); + err = msg.AddInt32("force", force); if (!err) err = BRoster::Private().SendTo(&msg, &reply, true); if (!err) @@ -78,8 +78,16 @@ status_t do_mime_update(int32 what, const char *path, int recursive, \param synchronous If non-null update_mime_info() waits until the operation is finished, otherwise it returns immediately and the update is done asynchronously. - \param force If non-null, also the information for files are updated that - have already been updated. + \param force Specifies how to handle files that already have MIME + information: + - \c B_UPDATE_MIME_INFO_NO_FORCE: Files that already have a + \c BEOS:TYPE attribute won't be updated. + - \c B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE: Files that already have a + \c BEOS:TYPE attribute will be updated too, but \c BEOS:TYPE + itself will remain untouched. + - \c B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL: Similar to + \c B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE, but the \c BEOS:TYPE + attribute will be updated too. \return - \c B_OK: Everything went fine. - An error code otherwise. diff --git a/src/kits/storage/mime/CreateAppMetaMimeThread.cpp b/src/kits/storage/mime/CreateAppMetaMimeThread.cpp index 894c14b323..4fc33ba712 100644 --- a/src/kits/storage/mime/CreateAppMetaMimeThread.cpp +++ b/src/kits/storage/mime/CreateAppMetaMimeThread.cpp @@ -23,9 +23,11 @@ namespace BPrivate { namespace Storage { namespace Mime { -CreateAppMetaMimeThread::CreateAppMetaMimeThread(const char *name, int32 priority, - BMessenger managerMessenger, const entry_ref *root, bool recursive, bool force, BMessage *replyee) - : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, replyee) +CreateAppMetaMimeThread::CreateAppMetaMimeThread(const char *name, + int32 priority, BMessenger managerMessenger, const entry_ref *root, + bool recursive, int32 force, BMessage *replyee) + : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, + replyee) { } diff --git a/src/kits/storage/mime/MimeUpdateThread.cpp b/src/kits/storage/mime/MimeUpdateThread.cpp index 2a63b3e539..6c7a296c3a 100644 --- a/src/kits/storage/mime/MimeUpdateThread.cpp +++ b/src/kits/storage/mime/MimeUpdateThread.cpp @@ -42,8 +42,9 @@ namespace Mime { field detached from the registrar's mime manager looper (though this is not verified). The message will be replied to at the end of the thread's execution. */ -MimeUpdateThread::MimeUpdateThread(const char *name, int32 priority, BMessenger managerMessenger, - const entry_ref *root, bool recursive, bool force, BMessage *replyee) +MimeUpdateThread::MimeUpdateThread(const char *name, int32 priority, + BMessenger managerMessenger, const entry_ref *root, bool recursive, + int32 force, BMessage *replyee) : RegistrarThread(name, priority, managerMessenger) , fRoot(root ? *root : entry_ref()) , fRecursive(recursive) diff --git a/src/kits/storage/mime/UpdateMimeInfoThread.cpp b/src/kits/storage/mime/UpdateMimeInfoThread.cpp index 1e5bc13605..e3576dcc1d 100644 --- a/src/kits/storage/mime/UpdateMimeInfoThread.cpp +++ b/src/kits/storage/mime/UpdateMimeInfoThread.cpp @@ -9,7 +9,10 @@ #include "mime/UpdateMimeInfoThread.h" +#include +#include #include +#include #include #include #include @@ -18,11 +21,36 @@ namespace BPrivate { namespace Storage { namespace Mime { +static const char *kAppFlagsAttribute = "BEOS:APP_FLAGS"; + +// update_icon +static status_t +update_icon(BAppFileInfo &appFileInfoRead, BAppFileInfo &appFileInfoWrite, + const char *type, BBitmap &icon, icon_size iconSize) +{ + status_t err = appFileInfoRead.GetIconForType(type, &icon, iconSize); + if (err == B_OK) + err = appFileInfoWrite.SetIconForType(type, &icon, iconSize); + else if (err == B_ENTRY_NOT_FOUND) + err = appFileInfoWrite.SetIconForType(type, NULL, iconSize); + return err; +} + +// is_shared_object_mime_type +static bool +is_shared_object_mime_type(BMimeType &type) +{ + return (type == "application/x-vnd.Be-elfexecutable"); +} + + // constructor //! Creates a new UpdateMimeInfoThread object UpdateMimeInfoThread::UpdateMimeInfoThread(const char *name, int32 priority, - BMessenger managerMessenger, const entry_ref *root, bool recursive, bool force, BMessage *replyee) - : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, replyee) + BMessenger managerMessenger, const entry_ref *root, bool recursive, + int32 force, BMessage *replyee) + : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, + replyee) { } @@ -35,43 +63,150 @@ UpdateMimeInfoThread::UpdateMimeInfoThread(const char *name, int32 priority, status_t UpdateMimeInfoThread::DoMimeUpdate(const entry_ref *entry, bool *entryIsDir) { -// TODO: This implementation is incomplete. -// For application executables we also need to copy several things from the -// resources into attributes (basically that is supported by BAppFileInfo, -// which we can use here, BTW). -// Furthermore fForce shouldn't be a boolean. The do_mime_update() API -// functions takes an "int force", which can have three valid values, 0, 1, -// and 2. 0 is no-force, 1 and 2 correspond to the mimeset flags -f and -F, -// respectively. status_t err = entry ? B_OK : B_BAD_VALUE; - bool doUpdate = true; + bool updateType = false; + bool updateAppInfo = false; BNode node; if (!err) err = node.SetTo(entry); if (!err && entryIsDir) *entryIsDir = node.IsDirectory(); - if (!err && !fForce) { + if (!err) { // If not forced, only update if the entry has no file type attribute attr_info info; - if (!err) - doUpdate = node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND; + if (fForce == B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL + || node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND) { + updateType = true; + } + updateAppInfo = (updateType + || fForce == B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE); } - if (!err && doUpdate) { - BMimeType type; + + // guess the MIME type + BMimeType type; + if (!err && (updateType || updateAppInfo)) { err = BMimeType::GuessMimeType(entry, &type); if (!err) err = type.InitCheck(); - if (!err) { - 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 ? (status_t)B_FILE_ERROR : (status_t)B_OK); - } } + + // update the MIME type + if (!err && updateType) { + 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 ? (status_t)B_FILE_ERROR : (status_t)B_OK); + } + + // update the app file info attributes, if this is a shared object + BFile file; + BAppFileInfo appFileInfoRead; + BAppFileInfo appFileInfoWrite; + if (!err && updateAppInfo && node.IsFile() + && is_shared_object_mime_type(type) + && file.SetTo(entry, B_READ_WRITE) == B_OK + && appFileInfoRead.SetTo(&file) == B_OK + && appFileInfoWrite.SetTo(&file) == B_OK) { + + // we read from resources and write to attributes + appFileInfoRead.SetInfoLocation(B_USE_RESOURCES); + appFileInfoWrite.SetInfoLocation(B_USE_ATTRIBUTES); + + // signature + char signature[B_MIME_TYPE_LENGTH]; + err = appFileInfoRead.GetSignature(signature); + if (err == B_OK) + err = appFileInfoWrite.SetSignature(signature); + else if (err == B_ENTRY_NOT_FOUND) + err = appFileInfoWrite.SetSignature(NULL); + if (err != B_OK) + return err; + + // app flags + uint32 appFlags; + err = appFileInfoRead.GetAppFlags(&appFlags); + if (err == B_OK) { + err = appFileInfoWrite.SetAppFlags(appFlags); + } else if (err == B_ENTRY_NOT_FOUND) { + file.RemoveAttr(kAppFlagsAttribute); + err = B_OK; + } + if (err != B_OK) + return err; + + // supported types + BMessage supportedTypes; + bool hasSupportedTypes = false; + err = appFileInfoRead.GetSupportedTypes(&supportedTypes); + if (err == B_OK) { + err = appFileInfoWrite.SetSupportedTypes(&supportedTypes); + hasSupportedTypes = true; + } else if (err == B_ENTRY_NOT_FOUND) + err = appFileInfoWrite.SetSignature(NULL); + if (err != B_OK) + return err; + + // small icon + BBitmap smallIcon(BRect(0, 0, 15, 15), B_BITMAP_NO_SERVER_LINK, + B_CMAP8); + if (smallIcon.InitCheck() != B_OK) + return smallIcon.InitCheck(); + err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, smallIcon, + B_MINI_ICON); + if (err != B_OK) + return err; + + // large icon + BBitmap largeIcon(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK, + B_CMAP8); + if (largeIcon.InitCheck() != B_OK) + return largeIcon.InitCheck(); + err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, largeIcon, + B_LARGE_ICON); + if (err != B_OK) + return err; + + // version infos + const version_kind versionKinds[] + = {B_APP_VERSION_KIND, B_SYSTEM_VERSION_KIND}; + for (int i = 0; i < 2; i++) { + version_kind kind = versionKinds[i]; + version_info versionInfo; + err = appFileInfoRead.GetVersionInfo(&versionInfo, kind); + if (err == B_OK) + err = appFileInfoWrite.SetVersionInfo(&versionInfo, kind); + else if (err == B_ENTRY_NOT_FOUND) + err = appFileInfoWrite.SetVersionInfo(NULL, kind); + if (err != B_OK) + return err; + } + + // icons for supported types + if (hasSupportedTypes) { + const char *supportedType; + for (int32 i = 0; + supportedTypes.FindString("types", i, &supportedType) == B_OK; + i++) { + // small icon + err = update_icon(appFileInfoRead, appFileInfoWrite, + supportedType, smallIcon, B_MINI_ICON); + if (err != B_OK) + return err; + + // large icon + err = update_icon(appFileInfoRead, appFileInfoWrite, + supportedType, largeIcon, B_LARGE_ICON); + if (err != B_OK) + return err; + } + } + } + return err; } diff --git a/src/servers/registrar/MIMEManager.cpp b/src/servers/registrar/MIMEManager.cpp index d6da187852..a9dc23991b 100644 --- a/src/servers/registrar/MIMEManager.cpp +++ b/src/servers/registrar/MIMEManager.cpp @@ -186,8 +186,9 @@ MIMEManager::MessageReceived(BMessage *message) using BPrivate::Storage::Mime::UpdateMimeInfoThread; entry_ref root; - bool recursive, force; + bool recursive; bool synchronous = false; + int32 force; MimeUpdateThread *thread = NULL; @@ -202,7 +203,7 @@ MIMEManager::MessageReceived(BMessage *message) if (!err) err = message->FindBool("synchronous", &synchronous); if (!err) - err = message->FindBool("force", &force); + err = message->FindInt32("force", &force); // Detach the message for synchronous calls if (!err && synchronous) {