xref: /haiku/src/servers/registrar/MIMEManager.cpp (revision a4f6a81235ca2522c01f532de13cad9b729d4029)
1 // MIMEManager.cpp
2 
3 #include <Bitmap.h>
4 #include <ClassInfo.h>
5 #include <Message.h>
6 #include <Messenger.h>
7 #include <mime/UpdateMimeInfoThread.h>
8 #include <mime/CreateAppMetaMimeThread.h>
9 #include <Path.h>
10 #include <RegistrarDefs.h>
11 #include <String.h>
12 #include <TypeConstants.h>
13 
14 #include <stdio.h>
15 #include <string>
16 
17 using namespace std;
18 using namespace BPrivate;
19 
20 #include "MIMEManager.h"
21 
22 /*!
23 	\class MIMEManager
24 	\brief MIMEManager handles communication between BMimeType and the system-wide
25 	MimeDatabase object for BMimeType's write and non-atomic read functions.
26 
27 */
28 
29 // constructor
30 /*!	\brief Creates and initializes a MIMEManager.
31 */
32 MIMEManager::MIMEManager()
33 		   : BLooper("main_mime")
34 		   , fDatabase()
35 		   , fThreadManager()
36 {
37 	AddHandler(&fThreadManager);
38 }
39 
40 // destructor
41 /*!	\brief Frees all resources associate with this object.
42 */
43 MIMEManager::~MIMEManager()
44 {
45 }
46 
47 // MessageReceived
48 /*!	\brief Overrides the super class version to handle the MIME specific
49 		   messages.
50 	\param message The message to be handled
51 */
52 void
53 MIMEManager::MessageReceived(BMessage *message)
54 {
55 	BMessage reply;
56 	status_t err;
57 
58 	switch (message->what) {
59 		case B_REG_MIME_SET_PARAM:
60 			HandleSetParam(message);
61 			break;
62 
63 		case B_REG_MIME_DELETE_PARAM:
64 			HandleDeleteParam(message);
65 			break;
66 
67 		case B_REG_MIME_START_WATCHING:
68 		case B_REG_MIME_STOP_WATCHING:
69 		{
70 			BMessenger messenger;
71 			err = message->FindMessenger("target", &messenger);
72 			if (!err) {
73 				err = message->what == B_REG_MIME_START_WATCHING
74 					    ? fDatabase.StartWatching(messenger)
75 					      : fDatabase.StopWatching(messenger);
76 			}
77 
78 			reply.what = B_REG_RESULT;
79 			reply.AddInt32("result", err);
80 			message->SendReply(&reply, this);
81 			break;
82 		}
83 
84 		case B_REG_MIME_INSTALL:
85 		case B_REG_MIME_DELETE:
86 		{
87 			const char *type;
88 			err = message->FindString("type", &type);
89 			if (!err)
90 				err = message->what == B_REG_MIME_INSTALL
91 					    ? fDatabase.Install(type)
92 					      : fDatabase.Delete(type);
93 
94 			reply.what = B_REG_RESULT;
95 			reply.AddInt32("result", err);
96 			message->SendReply(&reply, this);
97 			break;
98 		}
99 
100 		case B_REG_MIME_GET_INSTALLED_TYPES:
101 		{
102 			const char *supertype;
103 			err = message->FindString("supertype", &supertype);
104 			if (err == B_NAME_NOT_FOUND)
105 				err = fDatabase.GetInstalledTypes(&reply);
106 			else if (!err)
107 				err = fDatabase.GetInstalledTypes(supertype, &reply);
108 
109 			reply.what = B_REG_RESULT;
110 			reply.AddInt32("result", err);
111 			message->SendReply(&reply, this);
112 			break;
113 		}
114 
115 		case B_REG_MIME_GET_INSTALLED_SUPERTYPES:
116 		{
117 			err = fDatabase.GetInstalledSupertypes(&reply);
118 
119 			reply.what = B_REG_RESULT;
120 			reply.AddInt32("result", err);
121 			message->SendReply(&reply, this);
122 			break;
123 		}
124 
125 		case B_REG_MIME_GET_SUPPORTING_APPS:
126 		{
127 			const char *type;
128 			err = message->FindString("type", &type);
129 			if (!err)
130 				err = fDatabase.GetSupportingApps(type, &reply);
131 
132 			reply.what = B_REG_RESULT;
133 			reply.AddInt32("result", err);
134 			message->SendReply(&reply, this);
135 			break;
136 		}
137 
138 		case B_REG_MIME_GET_ASSOCIATED_TYPES:
139 		{
140 			const char *extension;
141 			err = message->FindString("extension", &extension);
142 			if (!err)
143 				err = fDatabase.GetAssociatedTypes(extension, &reply);
144 
145 			reply.what = B_REG_RESULT;
146 			reply.AddInt32("result", err);
147 			message->SendReply(&reply, this);
148 			break;
149 		}
150 
151 		case B_REG_MIME_SNIFF:
152 		{
153 			BString str;
154 			entry_ref ref;
155 			const char *filename;
156 			err = message->FindString("filename", &filename);
157 			if (!err)
158 				err = fDatabase.GuessMimeType(filename, &str);
159 			else if (err == B_NAME_NOT_FOUND) {
160 				err = message->FindRef("file ref", &ref);
161 				if (!err)
162 					err = fDatabase.GuessMimeType(&ref, &str);
163 				else if (err == B_NAME_NOT_FOUND) {
164 					const void *data;
165 					int32 dataSize;
166 					err = message->FindData("data", B_RAW_TYPE, &data,
167 						&dataSize);
168 					if (!err)
169 						err = fDatabase.GuessMimeType(data, dataSize, &str);
170 				}
171 			}
172 			if (!err)
173 				err = reply.AddString("mime type", str);
174 
175 			reply.what = B_REG_RESULT;
176 			reply.AddInt32("result", err);
177 			message->SendReply(&reply, this);
178 			break;
179 		}
180 
181 		case B_REG_MIME_CREATE_APP_META_MIME:
182 		case B_REG_MIME_UPDATE_MIME_INFO:
183 		{
184 			using BPrivate::Storage::Mime::MimeUpdateThread;
185 			using BPrivate::Storage::Mime::CreateAppMetaMimeThread;
186 			using BPrivate::Storage::Mime::UpdateMimeInfoThread;
187 
188 			entry_ref root;
189 			bool recursive;
190 			bool synchronous = false;
191 			int32 force;
192 
193 			MimeUpdateThread *thread = NULL;
194 
195 			status_t threadStatus = B_NO_INIT;
196 			bool messageIsDetached = false;
197 			bool stillOwnThread = true;
198 
199 			// Gather our arguments
200 			err = message->FindRef("entry", &root);
201 			if (!err)
202 				err = message->FindBool("recursive", &recursive);
203 			if (!err)
204 				err = message->FindBool("synchronous", &synchronous);
205 			if (!err)
206 				err = message->FindInt32("force", &force);
207 
208 			// Detach the message for synchronous calls
209 			if (!err && synchronous) {
210 				DetachCurrentMessage();
211 				messageIsDetached = true;
212 			}
213 
214 			// Create the appropriate flavor of mime update thread
215 			if (!err) {
216 				switch (message->what) {
217 					case B_REG_MIME_CREATE_APP_META_MIME:
218 						thread = new(nothrow) CreateAppMetaMimeThread((synchronous ?
219 							"create_app_meta_mime (s)" : "create_app_meta_mime (a)"),
220 							B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive,
221 							force, synchronous ? message : NULL);
222 						break;
223 
224 					case B_REG_MIME_UPDATE_MIME_INFO:
225 						thread = new(nothrow) UpdateMimeInfoThread((synchronous ?
226 							"update_mime_info (s)" : "update_mime_info (a)"),
227 							B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive,
228 							force, synchronous ? message : NULL);
229 						break;
230 
231 					default:
232 						err = B_BAD_VALUE;
233 						break;
234 				}
235 			}
236 			if (!err)
237 				err = thread ? B_OK : B_NO_MEMORY;
238 			if (!err)
239 				err = threadStatus = thread->InitCheck();
240 
241 			// Launch the thread
242 			if (!err) {
243 				err = fThreadManager.LaunchThread(thread);
244 				if (!err) {
245 					stillOwnThread = false;
246 				}
247 			}
248 
249 			// If something went wrong, we need to notify the sender regardless. However,
250 			// if this is a synchronous call, we've already detached the message, and must
251 			// be careful that it gets deleted once and only once. Thus, if the MimeUpdateThread
252 			// object was created successfully, we don't need to delete the message, as that
253 			// object has assumed control of it. Otherwise, we are still responsible.
254 			if (err || !synchronous) {
255 				// Send the reply
256 				reply.what = B_REG_RESULT;
257 				reply.AddInt32("result", err);
258 				message->SendReply(&reply, this);
259 			}
260 			// Delete the message if necessary
261 			if (messageIsDetached && threadStatus != B_OK)
262 				delete message;
263 			// Delete the thread if necessary
264 			if (stillOwnThread)
265 				delete thread;
266 			break;
267 		}
268 
269 		default:
270 			printf("MIMEMan: msg->what == %lx (%.4s)\n", message->what,
271 				(char*)&(message->what));
272 			BLooper::MessageReceived(message);
273 			break;
274 	}
275 }
276 
277 // HandleSetParam
278 //! Handles all B_REG_MIME_SET_PARAM messages
279 void
280 MIMEManager::HandleSetParam(BMessage *message)
281 {
282 	status_t err;
283 	int32 which;
284 	const char *type;
285 
286 	err = message->FindString("type", &type);
287 	if (!err)
288 		err = message->FindInt32("which", &which);
289 	if (!err) {
290 		switch (which) {
291 			case B_REG_MIME_APP_HINT:
292 			{
293 				entry_ref ref;
294 				err = message->FindRef("app hint", &ref);
295 				if (!err)
296 					err = fDatabase.SetAppHint(type, &ref);
297 				break;
298 			}
299 
300 			case B_REG_MIME_ATTR_INFO:
301 			{
302 				BMessage info;
303 				err = message->FindMessage("attr info", &info);
304 				if (!err)
305 					err = fDatabase.SetAttrInfo(type, &info);
306 				break;
307 			}
308 
309 			case B_REG_MIME_DESCRIPTION:
310 			{
311 				bool isLong;
312 				const char *description;
313 				err = message->FindBool("long", &isLong);
314 				if (!err)
315 					err = message->FindString("description", &description);
316 				if (!err)
317 					err = (isLong
318 						     ? fDatabase.SetLongDescription(type, description)
319 						       : fDatabase.SetShortDescription(type, description));
320 				break;
321 			}
322 
323 			case B_REG_MIME_FILE_EXTENSIONS:
324 			{
325 				BMessage extensions;
326 				err = message->FindMessage("extensions", &extensions);
327 				if (!err)
328 					err = fDatabase.SetFileExtensions(type, &extensions);
329 				break;
330 			}
331 
332 			case B_REG_MIME_ICON:
333 			case B_REG_MIME_ICON_FOR_TYPE:
334 			{
335 				const void *data;
336 				ssize_t dataSize;
337 				int32 size;
338 				err = message->FindData("icon data", B_RAW_TYPE, &data, &dataSize);
339 				if (!err)
340 					err = message->FindInt32("icon size", &size);
341 				if (which == B_REG_MIME_ICON_FOR_TYPE) {
342 					const char *fileType;
343 					if (!err)
344 						err = message->FindString("file type", &fileType);
345 					if (!err)
346 						err = fDatabase.SetIconForType(type, fileType, data,
347 								dataSize, (icon_size)size);
348 				} else {
349 					if (!err)
350 						err = fDatabase.SetIcon(type, data, dataSize,
351 								(icon_size)size);
352 				}
353 				break;
354 				// End temporary fix code
355 			}
356 
357 			case B_REG_MIME_PREFERRED_APP:
358 			{
359 				const char *signature;
360 				int32 verb;
361 				err = message->FindString("signature", &signature);
362 				if (!err)
363 					err = message->FindInt32("app verb", &verb);
364 				if (!err)
365 					err = fDatabase.SetPreferredApp(type, signature, (app_verb)verb);
366 				break;
367 			}
368 
369 			case B_REG_MIME_SNIFFER_RULE:
370 			{
371 				const char *rule;
372 				err = message->FindString("sniffer rule", &rule);
373 				if (!err)
374 					err = fDatabase.SetSnifferRule(type, rule);
375 				break;
376 			}
377 
378 			case B_REG_MIME_SUPPORTED_TYPES:
379 			{
380 				BMessage types;
381 				bool fullSync = true;
382 				err = message->FindMessage("types", &types);
383 				if (!err)
384 					err = message->FindBool("full sync", &fullSync);
385 				if (!err)
386 					err = fDatabase.SetSupportedTypes(type, &types, fullSync);
387 				break;
388 			}
389 
390 			default:
391 				err = B_BAD_VALUE;
392 				break;
393 		}
394 	}
395 
396 	BMessage reply(B_REG_RESULT);
397 	reply.AddInt32("result", err);
398 	message->SendReply(&reply, this);
399 }
400 
401 // HandleSetParam
402 //! Handles all B_REG_MIME_SET_PARAM messages
403 void
404 MIMEManager::HandleDeleteParam(BMessage *message)
405 {
406 //	using BPrivate::MimeDatabase;
407 
408 	status_t err;
409 	int32 which;
410 	const char *type;
411 
412 	err = message->FindString("type", &type);
413 	if (!err)
414 		err = message->FindInt32("which", &which);
415 	if (!err) {
416 		switch (which) {
417 			case B_REG_MIME_APP_HINT:
418 				err = fDatabase.DeleteAppHint(type);
419 				break;
420 
421 			case B_REG_MIME_ATTR_INFO:
422 				err = fDatabase.DeleteAttrInfo(type);
423 				break;
424 
425 			case B_REG_MIME_DESCRIPTION:
426 			{
427 				bool isLong;
428 				err = message->FindBool("long", &isLong);
429 				if (!err)
430 					err = isLong
431 						    ? fDatabase.DeleteLongDescription(type)
432 						      : fDatabase.DeleteShortDescription(type);
433 				break;
434 			}
435 
436 			case B_REG_MIME_FILE_EXTENSIONS:
437 				err = fDatabase.DeleteFileExtensions(type);
438 				break;
439 
440 			case B_REG_MIME_ICON:
441 			case B_REG_MIME_ICON_FOR_TYPE:
442 			{
443 				int32 size;
444 				err = message->FindInt32("icon size", &size);
445 				if (which == B_REG_MIME_ICON_FOR_TYPE) {
446 					const char *fileType;
447 					if (!err)
448 						err = message->FindString("file type", &fileType);
449 					if (!err)
450 						err = fDatabase.DeleteIconForType(type, fileType, (icon_size)size);
451 				} else {
452 					if (!err)
453 						err = fDatabase.DeleteIcon(type, (icon_size)size);
454 				}
455 				break;
456 			}
457 
458 			case B_REG_MIME_PREFERRED_APP:
459 			{
460 				int32 verb;
461 				err = message->FindInt32("app verb", &verb);
462 				if (!err)
463 					err = fDatabase.DeletePreferredApp(type, (app_verb)verb);
464 				break;
465 			}
466 
467 			case B_REG_MIME_SNIFFER_RULE:
468 				err = fDatabase.DeleteSnifferRule(type);
469 				break;
470 
471 			case B_REG_MIME_SUPPORTED_TYPES:
472 			{
473 				bool fullSync;
474 				err = message->FindBool("full sync", &fullSync);
475 				if (!err)
476 					err = fDatabase.DeleteSupportedTypes(type, fullSync);
477 				break;
478 			}
479 
480 			default:
481 				err = B_BAD_VALUE;
482 				break;
483 		}
484 	}
485 
486 	BMessage reply(B_REG_RESULT);
487 	reply.AddInt32("result", err);
488 	message->SendReply(&reply, this);
489 }
490 
491