2 * Copyright 2002-2013, Haiku Inc.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold (bonefish@users.sf.net)
11 #include "MIMEManager.h"
18 #include <Messenger.h>
20 #include <RegistrarDefs.h>
22 #include <TypeConstants.h>
24 #include <mime/AppMetaMimeCreator.h>
25 #include <mime/database_support.h>
26 #include <mime/MimeSnifferAddonManager.h>
27 #include <mime/TextSnifferAddon.h>
29 #include "CreateAppMetaMimeThread.h"
30 #include "MessageDeliverer.h"
31 #include "UpdateMimeInfoThread.h"
35 using namespace BPrivate
;
36 using BPrivate::Storage::Mime::MimeSnifferAddonManager
;
37 using BPrivate::Storage::Mime::TextSnifferAddon
;
40 /*! \class MIMEManager
41 \brief MIMEManager handles communication between BMimeType and the system-wide
42 MimeDatabase object for BMimeType's write and non-atomic read functions.
47 static MimeSnifferAddonManager
*
48 init_mime_sniffer_add_on_manager()
50 if (MimeSnifferAddonManager::CreateDefault() != B_OK
)
53 MimeSnifferAddonManager
* manager
= MimeSnifferAddonManager::Default();
54 manager
->AddMimeSnifferAddon(new(nothrow
) TextSnifferAddon(
55 BPrivate::Storage::Mime::default_database_location()));
60 class MIMEManager::DatabaseLocker
61 : public BPrivate::Storage::Mime::MimeEntryProcessor::DatabaseLocker
{
63 DatabaseLocker(MIMEManager
* manager
)
71 return fManager
->Lock();
80 MIMEManager
* fManager
;
84 /*! \brief Creates and initializes a MIMEManager.
86 MIMEManager::MIMEManager()
89 fDatabase(BPrivate::Storage::Mime::default_database_location(),
90 init_mime_sniffer_add_on_manager(), this),
91 fDatabaseLocker(new(std::nothrow
) DatabaseLocker(this)),
94 AddHandler(&fThreadManager
);
98 /*! \brief Frees all resources associate with this object.
100 MIMEManager::~MIMEManager()
105 /*! \brief Overrides the super class version to handle the MIME specific
107 \param message The message to be handled
110 MIMEManager::MessageReceived(BMessage
*message
)
115 switch (message
->what
) {
116 case B_REG_MIME_SET_PARAM
:
117 HandleSetParam(message
);
120 case B_REG_MIME_DELETE_PARAM
:
121 HandleDeleteParam(message
);
124 case B_REG_MIME_START_WATCHING
:
125 case B_REG_MIME_STOP_WATCHING
:
127 BMessenger messenger
;
128 err
= message
->FindMessenger("target", &messenger
);
130 err
= message
->what
== B_REG_MIME_START_WATCHING
131 ? fDatabase
.StartWatching(messenger
)
132 : fDatabase
.StopWatching(messenger
);
135 reply
.what
= B_REG_RESULT
;
136 reply
.AddInt32("result", err
);
137 message
->SendReply(&reply
, this);
141 case B_REG_MIME_INSTALL
:
142 case B_REG_MIME_DELETE
:
145 err
= message
->FindString("type", &type
);
147 err
= message
->what
== B_REG_MIME_INSTALL
148 ? fDatabase
.Install(type
) : fDatabase
.Delete(type
);
150 reply
.what
= B_REG_RESULT
;
151 reply
.AddInt32("result", err
);
152 message
->SendReply(&reply
, this);
156 case B_REG_MIME_GET_INSTALLED_TYPES
:
158 const char *supertype
;
159 err
= message
->FindString("supertype", &supertype
);
160 if (err
== B_NAME_NOT_FOUND
)
161 err
= fDatabase
.GetInstalledTypes(&reply
);
163 err
= fDatabase
.GetInstalledTypes(supertype
, &reply
);
165 reply
.what
= B_REG_RESULT
;
166 reply
.AddInt32("result", err
);
167 message
->SendReply(&reply
, this);
171 case B_REG_MIME_GET_INSTALLED_SUPERTYPES
:
173 err
= fDatabase
.GetInstalledSupertypes(&reply
);
175 reply
.what
= B_REG_RESULT
;
176 reply
.AddInt32("result", err
);
177 message
->SendReply(&reply
, this);
181 case B_REG_MIME_GET_SUPPORTING_APPS
:
184 err
= message
->FindString("type", &type
);
186 err
= fDatabase
.GetSupportingApps(type
, &reply
);
188 reply
.what
= B_REG_RESULT
;
189 reply
.AddInt32("result", err
);
190 message
->SendReply(&reply
, this);
194 case B_REG_MIME_GET_ASSOCIATED_TYPES
:
196 const char *extension
;
197 err
= message
->FindString("extension", &extension
);
199 err
= fDatabase
.GetAssociatedTypes(extension
, &reply
);
201 reply
.what
= B_REG_RESULT
;
202 reply
.AddInt32("result", err
);
203 message
->SendReply(&reply
, this);
207 case B_REG_MIME_SNIFF
:
211 const char *filename
;
212 err
= message
->FindString("filename", &filename
);
214 err
= fDatabase
.GuessMimeType(filename
, &str
);
215 else if (err
== B_NAME_NOT_FOUND
) {
216 err
= message
->FindRef("file ref", &ref
);
218 err
= fDatabase
.GuessMimeType(&ref
, &str
);
219 else if (err
== B_NAME_NOT_FOUND
) {
222 err
= message
->FindData("data", B_RAW_TYPE
, &data
,
225 err
= fDatabase
.GuessMimeType(data
, dataSize
, &str
);
229 err
= reply
.AddString("mime type", str
);
231 reply
.what
= B_REG_RESULT
;
232 reply
.AddInt32("result", err
);
233 message
->SendReply(&reply
, this);
237 case B_REG_MIME_CREATE_APP_META_MIME
:
238 case B_REG_MIME_UPDATE_MIME_INFO
:
240 using BPrivate::Storage::Mime::MimeUpdateThread
;
241 using BPrivate::Storage::Mime::CreateAppMetaMimeThread
;
242 using BPrivate::Storage::Mime::UpdateMimeInfoThread
;
246 bool synchronous
= false;
249 MimeUpdateThread
*thread
= NULL
;
251 status_t threadStatus
= B_NO_INIT
;
252 bool messageIsDetached
= false;
253 bool stillOwnsThread
= true;
255 // Gather our arguments
256 err
= message
->FindRef("entry", &root
);
258 err
= message
->FindBool("recursive", &recursive
);
260 err
= message
->FindBool("synchronous", &synchronous
);
262 err
= message
->FindInt32("force", &force
);
264 // Detach the message for synchronous calls
265 if (!err
&& synchronous
) {
266 DetachCurrentMessage();
267 messageIsDetached
= true;
270 // Create the appropriate flavor of mime update thread
272 switch (message
->what
) {
273 case B_REG_MIME_CREATE_APP_META_MIME
:
274 thread
= new(nothrow
) CreateAppMetaMimeThread(
275 synchronous
? "create_app_meta_mime (s)"
276 : "create_app_meta_mime (a)",
277 B_NORMAL_PRIORITY
+ 1, &fDatabase
, fDatabaseLocker
,
278 BMessenger(&fThreadManager
), &root
, recursive
,
279 force
, synchronous
? message
: NULL
);
282 case B_REG_MIME_UPDATE_MIME_INFO
:
283 thread
= new(nothrow
) UpdateMimeInfoThread(synchronous
284 ? "update_mime_info (s)"
285 : "update_mime_info (a)",
286 B_NORMAL_PRIORITY
+ 1, &fDatabase
, fDatabaseLocker
,
287 BMessenger(&fThreadManager
), &root
, recursive
,
288 force
, synchronous
? message
: NULL
);
297 err
= thread
? B_OK
: B_NO_MEMORY
;
299 err
= threadStatus
= thread
->InitCheck();
303 err
= fThreadManager
.LaunchThread(thread
);
305 stillOwnsThread
= false;
309 // If something went wrong, we need to notify the sender regardless. However,
310 // if this is a synchronous call, we've already detached the message, and must
311 // be careful that it gets deleted once and only once. Thus, if the MimeUpdateThread
312 // object was created successfully, we don't need to delete the message, as that
313 // object has assumed control of it. Otherwise, we are still responsible.
314 if (err
|| !synchronous
) {
316 reply
.what
= B_REG_RESULT
;
317 reply
.AddInt32("result", err
);
318 message
->SendReply(&reply
, this);
320 // Delete the message if necessary
321 if (messageIsDetached
&& threadStatus
!= B_OK
)
323 // Delete the thread if necessary
330 printf("MIMEMan: msg->what == %" B_PRIx32
" (%.4s)\n",
331 message
->what
, (char*)&(message
->what
));
332 BLooper::MessageReceived(message
);
339 MIMEManager::Notify(BMessage
* message
, const BMessenger
& target
)
341 return MessageDeliverer::Default()->DeliverMessage(message
, target
);
345 //! Handles all B_REG_MIME_SET_PARAM messages
347 MIMEManager::HandleSetParam(BMessage
*message
)
353 err
= message
->FindString("type", &type
);
355 err
= message
->FindInt32("which", &which
);
358 case B_REG_MIME_APP_HINT
:
361 err
= message
->FindRef("app hint", &ref
);
363 err
= fDatabase
.SetAppHint(type
, &ref
);
367 case B_REG_MIME_ATTR_INFO
:
370 err
= message
->FindMessage("attr info", &info
);
372 err
= fDatabase
.SetAttrInfo(type
, &info
);
376 case B_REG_MIME_DESCRIPTION
:
379 const char *description
;
380 err
= message
->FindBool("long", &isLong
);
382 err
= message
->FindString("description", &description
);
385 ? fDatabase
.SetLongDescription(type
, description
)
386 : fDatabase
.SetShortDescription(type
, description
);
391 case B_REG_MIME_FILE_EXTENSIONS
:
394 err
= message
->FindMessage("extensions", &extensions
);
396 err
= fDatabase
.SetFileExtensions(type
, &extensions
);
400 case B_REG_MIME_ICON
:
401 case B_REG_MIME_ICON_FOR_TYPE
:
406 err
= message
->FindData("icon data", B_RAW_TYPE
, &data
,
409 err
= message
->FindInt32("icon size", &size
);
410 if (which
== B_REG_MIME_ICON_FOR_TYPE
) {
411 const char *fileType
;
413 err
= message
->FindString("file type", &fileType
);
416 ? fDatabase
.SetIconForType(type
, fileType
, data
,
418 : fDatabase
.SetIconForType(type
, fileType
, data
,
419 dataSize
, (icon_size
)size
);
424 ? fDatabase
.SetIcon(type
, data
, dataSize
)
425 : fDatabase
.SetIcon(type
, data
, dataSize
,
430 // End temporary fix code
433 case B_REG_MIME_PREFERRED_APP
:
435 const char *signature
;
437 err
= message
->FindString("signature", &signature
);
439 err
= message
->FindInt32("app verb", &verb
);
441 err
= fDatabase
.SetPreferredApp(type
, signature
,
447 case B_REG_MIME_SNIFFER_RULE
:
450 err
= message
->FindString("sniffer rule", &rule
);
452 err
= fDatabase
.SetSnifferRule(type
, rule
);
456 case B_REG_MIME_SUPPORTED_TYPES
:
459 bool fullSync
= true;
460 err
= message
->FindMessage("types", &types
);
462 err
= message
->FindBool("full sync", &fullSync
);
464 err
= fDatabase
.SetSupportedTypes(type
, &types
, fullSync
);
474 BMessage
reply(B_REG_RESULT
);
475 reply
.AddInt32("result", err
);
476 message
->SendReply(&reply
, this);
480 //! Handles all B_REG_MIME_SET_PARAM messages
482 MIMEManager::HandleDeleteParam(BMessage
*message
)
488 err
= message
->FindString("type", &type
);
490 err
= message
->FindInt32("which", &which
);
493 case B_REG_MIME_APP_HINT
:
494 err
= fDatabase
.DeleteAppHint(type
);
497 case B_REG_MIME_ATTR_INFO
:
498 err
= fDatabase
.DeleteAttrInfo(type
);
501 case B_REG_MIME_DESCRIPTION
:
504 err
= message
->FindBool("long", &isLong
);
507 ? fDatabase
.DeleteLongDescription(type
)
508 : fDatabase
.DeleteShortDescription(type
);
513 case B_REG_MIME_FILE_EXTENSIONS
:
514 err
= fDatabase
.DeleteFileExtensions(type
);
517 case B_REG_MIME_ICON
:
518 case B_REG_MIME_ICON_FOR_TYPE
:
521 err
= message
->FindInt32("icon size", &size
);
522 if (which
== B_REG_MIME_ICON_FOR_TYPE
) {
523 const char *fileType
;
525 err
= message
->FindString("file type", &fileType
);
528 ? fDatabase
.DeleteIconForType(type
, fileType
)
529 : fDatabase
.DeleteIconForType(type
, fileType
,
535 ? fDatabase
.DeleteIcon(type
)
536 : fDatabase
.DeleteIcon(type
, (icon_size
)size
);
542 case B_REG_MIME_PREFERRED_APP
:
545 err
= message
->FindInt32("app verb", &verb
);
547 err
= fDatabase
.DeletePreferredApp(type
, (app_verb
)verb
);
551 case B_REG_MIME_SNIFFER_RULE
:
552 err
= fDatabase
.DeleteSnifferRule(type
);
555 case B_REG_MIME_SUPPORTED_TYPES
:
558 err
= message
->FindBool("full sync", &fullSync
);
560 err
= fDatabase
.DeleteSupportedTypes(type
, fullSync
);
570 BMessage
reply(B_REG_RESULT
);
571 reply
.AddInt32("result", err
);
572 message
->SendReply(&reply
, this);