vfs: check userland buffers before reading them.
[haiku.git] / src / servers / registrar / MIMEManager.cpp
blob7be789ba3c4e933a3aee46c1ebace4781aff48fa
1 /*
2 * Copyright 2002-2013, Haiku Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold (bonefish@users.sf.net)
7 * Tyler Dauwalder
8 */
11 #include "MIMEManager.h"
13 #include <stdio.h>
14 #include <string>
16 #include <Bitmap.h>
17 #include <Message.h>
18 #include <Messenger.h>
19 #include <Path.h>
20 #include <RegistrarDefs.h>
21 #include <String.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"
34 using namespace std;
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)
51 return NULL;
53 MimeSnifferAddonManager* manager = MimeSnifferAddonManager::Default();
54 manager->AddMimeSnifferAddon(new(nothrow) TextSnifferAddon(
55 BPrivate::Storage::Mime::default_database_location()));
56 return manager;
60 class MIMEManager::DatabaseLocker
61 : public BPrivate::Storage::Mime::MimeEntryProcessor::DatabaseLocker {
62 public:
63 DatabaseLocker(MIMEManager* manager)
65 fManager(manager)
69 virtual bool Lock()
71 return fManager->Lock();
74 virtual void Unlock()
76 fManager->Unlock();
79 private:
80 MIMEManager* fManager;
84 /*! \brief Creates and initializes a MIMEManager.
86 MIMEManager::MIMEManager()
88 BLooper("main_mime"),
89 fDatabase(BPrivate::Storage::Mime::default_database_location(),
90 init_mime_sniffer_add_on_manager(), this),
91 fDatabaseLocker(new(std::nothrow) DatabaseLocker(this)),
92 fThreadManager()
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
106 messages.
107 \param message The message to be handled
109 void
110 MIMEManager::MessageReceived(BMessage *message)
112 BMessage reply;
113 status_t err;
115 switch (message->what) {
116 case B_REG_MIME_SET_PARAM:
117 HandleSetParam(message);
118 break;
120 case B_REG_MIME_DELETE_PARAM:
121 HandleDeleteParam(message);
122 break;
124 case B_REG_MIME_START_WATCHING:
125 case B_REG_MIME_STOP_WATCHING:
127 BMessenger messenger;
128 err = message->FindMessenger("target", &messenger);
129 if (!err) {
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);
138 break;
141 case B_REG_MIME_INSTALL:
142 case B_REG_MIME_DELETE:
144 const char *type;
145 err = message->FindString("type", &type);
146 if (!err)
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);
153 break;
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);
162 else if (!err)
163 err = fDatabase.GetInstalledTypes(supertype, &reply);
165 reply.what = B_REG_RESULT;
166 reply.AddInt32("result", err);
167 message->SendReply(&reply, this);
168 break;
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);
178 break;
181 case B_REG_MIME_GET_SUPPORTING_APPS:
183 const char *type;
184 err = message->FindString("type", &type);
185 if (!err)
186 err = fDatabase.GetSupportingApps(type, &reply);
188 reply.what = B_REG_RESULT;
189 reply.AddInt32("result", err);
190 message->SendReply(&reply, this);
191 break;
194 case B_REG_MIME_GET_ASSOCIATED_TYPES:
196 const char *extension;
197 err = message->FindString("extension", &extension);
198 if (!err)
199 err = fDatabase.GetAssociatedTypes(extension, &reply);
201 reply.what = B_REG_RESULT;
202 reply.AddInt32("result", err);
203 message->SendReply(&reply, this);
204 break;
207 case B_REG_MIME_SNIFF:
209 BString str;
210 entry_ref ref;
211 const char *filename;
212 err = message->FindString("filename", &filename);
213 if (!err)
214 err = fDatabase.GuessMimeType(filename, &str);
215 else if (err == B_NAME_NOT_FOUND) {
216 err = message->FindRef("file ref", &ref);
217 if (!err)
218 err = fDatabase.GuessMimeType(&ref, &str);
219 else if (err == B_NAME_NOT_FOUND) {
220 const void *data;
221 ssize_t dataSize;
222 err = message->FindData("data", B_RAW_TYPE, &data,
223 &dataSize);
224 if (!err)
225 err = fDatabase.GuessMimeType(data, dataSize, &str);
228 if (!err)
229 err = reply.AddString("mime type", str);
231 reply.what = B_REG_RESULT;
232 reply.AddInt32("result", err);
233 message->SendReply(&reply, this);
234 break;
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;
244 entry_ref root;
245 bool recursive;
246 bool synchronous = false;
247 int32 force;
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);
257 if (!err)
258 err = message->FindBool("recursive", &recursive);
259 if (!err)
260 err = message->FindBool("synchronous", &synchronous);
261 if (!err)
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
271 if (!err) {
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);
280 break;
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);
289 break;
291 default:
292 err = B_BAD_VALUE;
293 break;
296 if (!err)
297 err = thread ? B_OK : B_NO_MEMORY;
298 if (!err)
299 err = threadStatus = thread->InitCheck();
301 // Launch the thread
302 if (!err) {
303 err = fThreadManager.LaunchThread(thread);
304 if (!err) {
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) {
315 // Send the reply
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)
322 delete message;
323 // Delete the thread if necessary
324 if (stillOwnsThread)
325 delete thread;
326 break;
329 default:
330 printf("MIMEMan: msg->what == %" B_PRIx32 " (%.4s)\n",
331 message->what, (char*)&(message->what));
332 BLooper::MessageReceived(message);
333 break;
338 status_t
339 MIMEManager::Notify(BMessage* message, const BMessenger& target)
341 return MessageDeliverer::Default()->DeliverMessage(message, target);
345 //! Handles all B_REG_MIME_SET_PARAM messages
346 void
347 MIMEManager::HandleSetParam(BMessage *message)
349 status_t err;
350 int32 which;
351 const char *type;
353 err = message->FindString("type", &type);
354 if (!err)
355 err = message->FindInt32("which", &which);
356 if (!err) {
357 switch (which) {
358 case B_REG_MIME_APP_HINT:
360 entry_ref ref;
361 err = message->FindRef("app hint", &ref);
362 if (!err)
363 err = fDatabase.SetAppHint(type, &ref);
364 break;
367 case B_REG_MIME_ATTR_INFO:
369 BMessage info;
370 err = message->FindMessage("attr info", &info);
371 if (!err)
372 err = fDatabase.SetAttrInfo(type, &info);
373 break;
376 case B_REG_MIME_DESCRIPTION:
378 bool isLong;
379 const char *description;
380 err = message->FindBool("long", &isLong);
381 if (!err)
382 err = message->FindString("description", &description);
383 if (!err) {
384 err = isLong
385 ? fDatabase.SetLongDescription(type, description)
386 : fDatabase.SetShortDescription(type, description);
388 break;
391 case B_REG_MIME_FILE_EXTENSIONS:
393 BMessage extensions;
394 err = message->FindMessage("extensions", &extensions);
395 if (!err)
396 err = fDatabase.SetFileExtensions(type, &extensions);
397 break;
400 case B_REG_MIME_ICON:
401 case B_REG_MIME_ICON_FOR_TYPE:
403 const void *data;
404 ssize_t dataSize;
405 int32 size;
406 err = message->FindData("icon data", B_RAW_TYPE, &data,
407 &dataSize);
408 if (!err)
409 err = message->FindInt32("icon size", &size);
410 if (which == B_REG_MIME_ICON_FOR_TYPE) {
411 const char *fileType;
412 if (!err)
413 err = message->FindString("file type", &fileType);
414 if (!err) {
415 err = size == -1
416 ? fDatabase.SetIconForType(type, fileType, data,
417 dataSize)
418 : fDatabase.SetIconForType(type, fileType, data,
419 dataSize, (icon_size)size);
421 } else {
422 if (!err) {
423 err = size == -1
424 ? fDatabase.SetIcon(type, data, dataSize)
425 : fDatabase.SetIcon(type, data, dataSize,
426 (icon_size)size);
429 break;
430 // End temporary fix code
433 case B_REG_MIME_PREFERRED_APP:
435 const char *signature;
436 int32 verb;
437 err = message->FindString("signature", &signature);
438 if (!err)
439 err = message->FindInt32("app verb", &verb);
440 if (!err) {
441 err = fDatabase.SetPreferredApp(type, signature,
442 (app_verb)verb);
444 break;
447 case B_REG_MIME_SNIFFER_RULE:
449 const char *rule;
450 err = message->FindString("sniffer rule", &rule);
451 if (!err)
452 err = fDatabase.SetSnifferRule(type, rule);
453 break;
456 case B_REG_MIME_SUPPORTED_TYPES:
458 BMessage types;
459 bool fullSync = true;
460 err = message->FindMessage("types", &types);
461 if (!err)
462 err = message->FindBool("full sync", &fullSync);
463 if (!err)
464 err = fDatabase.SetSupportedTypes(type, &types, fullSync);
465 break;
468 default:
469 err = B_BAD_VALUE;
470 break;
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
481 void
482 MIMEManager::HandleDeleteParam(BMessage *message)
484 status_t err;
485 int32 which;
486 const char *type;
488 err = message->FindString("type", &type);
489 if (!err)
490 err = message->FindInt32("which", &which);
491 if (!err) {
492 switch (which) {
493 case B_REG_MIME_APP_HINT:
494 err = fDatabase.DeleteAppHint(type);
495 break;
497 case B_REG_MIME_ATTR_INFO:
498 err = fDatabase.DeleteAttrInfo(type);
499 break;
501 case B_REG_MIME_DESCRIPTION:
503 bool isLong;
504 err = message->FindBool("long", &isLong);
505 if (!err) {
506 err = isLong
507 ? fDatabase.DeleteLongDescription(type)
508 : fDatabase.DeleteShortDescription(type);
510 break;
513 case B_REG_MIME_FILE_EXTENSIONS:
514 err = fDatabase.DeleteFileExtensions(type);
515 break;
517 case B_REG_MIME_ICON:
518 case B_REG_MIME_ICON_FOR_TYPE:
520 int32 size;
521 err = message->FindInt32("icon size", &size);
522 if (which == B_REG_MIME_ICON_FOR_TYPE) {
523 const char *fileType;
524 if (!err)
525 err = message->FindString("file type", &fileType);
526 if (!err) {
527 err = size == -1
528 ? fDatabase.DeleteIconForType(type, fileType)
529 : fDatabase.DeleteIconForType(type, fileType,
530 (icon_size)size);
532 } else {
533 if (!err) {
534 err = size == -1
535 ? fDatabase.DeleteIcon(type)
536 : fDatabase.DeleteIcon(type, (icon_size)size);
539 break;
542 case B_REG_MIME_PREFERRED_APP:
544 int32 verb;
545 err = message->FindInt32("app verb", &verb);
546 if (!err)
547 err = fDatabase.DeletePreferredApp(type, (app_verb)verb);
548 break;
551 case B_REG_MIME_SNIFFER_RULE:
552 err = fDatabase.DeleteSnifferRule(type);
553 break;
555 case B_REG_MIME_SUPPORTED_TYPES:
557 bool fullSync;
558 err = message->FindBool("full sync", &fullSync);
559 if (!err)
560 err = fDatabase.DeleteSupportedTypes(type, fullSync);
561 break;
564 default:
565 err = B_BAD_VALUE;
566 break;
570 BMessage reply(B_REG_RESULT);
571 reply.AddInt32("result", err);
572 message->SendReply(&reply, this);