xref: /haiku/src/servers/registrar/MIMEManager.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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, force;
190 			bool synchronous = false;
191 
192 			MimeUpdateThread *thread = NULL;
193 
194 			status_t threadStatus = B_NO_INIT;
195 			bool messageIsDetached = false;
196 			bool stillOwnThread = true;
197 
198 			// Gather our arguments
199 			err = message->FindRef("entry", &root);
200 			if (!err)
201 				err = message->FindBool("recursive", &recursive);
202 			if (!err)
203 				err = message->FindBool("synchronous", &synchronous);
204 			if (!err)
205 				err = message->FindBool("force", &force);
206 
207 			// Detach the message for synchronous calls
208 			if (!err && synchronous) {
209 				DetachCurrentMessage();
210 				messageIsDetached = true;
211 			}
212 
213 			// Create the appropriate flavor of mime update thread
214 			if (!err) {
215 				switch (message->what) {
216 					case B_REG_MIME_CREATE_APP_META_MIME:
217 						thread = new(nothrow) CreateAppMetaMimeThread((synchronous ?
218 							"create_app_meta_mime (s)" : "create_app_meta_mime (a)"),
219 							B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive,
220 							force, synchronous ? message : NULL);
221 						break;
222 
223 					case B_REG_MIME_UPDATE_MIME_INFO:
224 						thread = new(nothrow) UpdateMimeInfoThread((synchronous ?
225 							"update_mime_info (s)" : "update_mime_info (a)"),
226 							B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive,
227 							force, synchronous ? message : NULL);
228 						break;
229 
230 					default:
231 						err = B_BAD_VALUE;
232 						break;
233 				}
234 			}
235 			if (!err)
236 				err = thread ? B_OK : B_NO_MEMORY;
237 			if (!err)
238 				err = threadStatus = thread->InitCheck();
239 
240 			// Launch the thread
241 			if (!err) {
242 				err = fThreadManager.LaunchThread(thread);
243 				if (!err) {
244 					stillOwnThread = false;
245 				}
246 			}
247 
248 			// If something went wrong, we need to notify the sender regardless. However,
249 			// if this is a synchronous call, we've already detached the message, and must
250 			// be careful that it gets deleted once and only once. Thus, if the MimeUpdateThread
251 			// object was created successfully, we don't need to delete the message, as that
252 			// object has assumed control of it. Otherwise, we are still responsible.
253 			if (err || !synchronous) {
254 				// Send the reply
255 				reply.what = B_REG_RESULT;
256 				reply.AddInt32("result", err);
257 				message->SendReply(&reply, this);
258 			}
259 			// Delete the message if necessary
260 			if (messageIsDetached && threadStatus != B_OK)
261 				delete message;
262 			// Delete the thread if necessary
263 			if (stillOwnThread)
264 				delete thread;
265 			break;
266 		}
267 
268 		default:
269 			printf("MIMEMan: msg->what == %lx (%.4s)\n", message->what,
270 				(char*)&(message->what));
271 			BLooper::MessageReceived(message);
272 			break;
273 	}
274 }
275 
276 // HandleSetParam
277 //! Handles all B_REG_MIME_SET_PARAM messages
278 void
279 MIMEManager::HandleSetParam(BMessage *message)
280 {
281 	status_t err;
282 	int32 which;
283 	const char *type;
284 
285 	err = message->FindString("type", &type);
286 	if (!err)
287 		err = message->FindInt32("which", &which);
288 	if (!err) {
289 		switch (which) {
290 			case B_REG_MIME_APP_HINT:
291 			{
292 				entry_ref ref;
293 				err = message->FindRef("app hint", &ref);
294 				if (!err)
295 					err = fDatabase.SetAppHint(type, &ref);
296 				break;
297 			}
298 
299 			case B_REG_MIME_ATTR_INFO:
300 			{
301 				BMessage info;
302 				err = message->FindMessage("attr info", &info);
303 				if (!err)
304 					err = fDatabase.SetAttrInfo(type, &info);
305 				break;
306 			}
307 
308 			case B_REG_MIME_DESCRIPTION:
309 			{
310 				bool isLong;
311 				const char *description;
312 				err = message->FindBool("long", &isLong);
313 				if (!err)
314 					err = message->FindString("description", &description);
315 				if (!err)
316 					err = (isLong
317 						     ? fDatabase.SetLongDescription(type, description)
318 						       : fDatabase.SetShortDescription(type, description));
319 				break;
320 			}
321 
322 			case B_REG_MIME_FILE_EXTENSIONS:
323 			{
324 				BMessage extensions;
325 				err = message->FindMessage("extensions", &extensions);
326 				if (!err)
327 					err = fDatabase.SetFileExtensions(type, &extensions);
328 				break;
329 			}
330 
331 			case B_REG_MIME_ICON:
332 			case B_REG_MIME_ICON_FOR_TYPE:
333 			{
334 				const void *data;
335 				ssize_t dataSize;
336 				int32 size;
337 				err = message->FindData("icon data", B_RAW_TYPE, &data, &dataSize);
338 				if (!err)
339 					err = message->FindInt32("icon size", &size);
340 				if (which == B_REG_MIME_ICON_FOR_TYPE) {
341 					const char *fileType;
342 					if (!err)
343 						err = message->FindString("file type", &fileType);
344 					if (!err)
345 						err = fDatabase.SetIconForType(type, fileType, data,
346 								dataSize, (icon_size)size);
347 				} else {
348 					if (!err)
349 						err = fDatabase.SetIcon(type, data, dataSize,
350 								(icon_size)size);
351 				}
352 				break;
353 				// End temporary fix code
354 			}
355 
356 			case B_REG_MIME_PREFERRED_APP:
357 			{
358 				const char *signature;
359 				int32 verb;
360 				err = message->FindString("signature", &signature);
361 				if (!err)
362 					err = message->FindInt32("app verb", &verb);
363 				if (!err)
364 					err = fDatabase.SetPreferredApp(type, signature, (app_verb)verb);
365 				break;
366 			}
367 
368 			case B_REG_MIME_SNIFFER_RULE:
369 			{
370 				const char *rule;
371 				err = message->FindString("sniffer rule", &rule);
372 				if (!err)
373 					err = fDatabase.SetSnifferRule(type, rule);
374 				break;
375 			}
376 
377 			case B_REG_MIME_SUPPORTED_TYPES:
378 			{
379 				BMessage types;
380 				bool fullSync = true;
381 				err = message->FindMessage("types", &types);
382 				if (!err)
383 					err = message->FindBool("full sync", &fullSync);
384 				if (!err)
385 					err = fDatabase.SetSupportedTypes(type, &types, fullSync);
386 				break;
387 			}
388 
389 			default:
390 				err = B_BAD_VALUE;
391 				break;
392 		}
393 	}
394 
395 	BMessage reply(B_REG_RESULT);
396 	reply.AddInt32("result", err);
397 	message->SendReply(&reply, this);
398 }
399 
400 // HandleSetParam
401 //! Handles all B_REG_MIME_SET_PARAM messages
402 void
403 MIMEManager::HandleDeleteParam(BMessage *message)
404 {
405 //	using BPrivate::MimeDatabase;
406 
407 	status_t err;
408 	int32 which;
409 	const char *type;
410 
411 	err = message->FindString("type", &type);
412 	if (!err)
413 		err = message->FindInt32("which", &which);
414 	if (!err) {
415 		switch (which) {
416 			case B_REG_MIME_APP_HINT:
417 				err = fDatabase.DeleteAppHint(type);
418 				break;
419 
420 			case B_REG_MIME_ATTR_INFO:
421 				err = fDatabase.DeleteAttrInfo(type);
422 				break;
423 
424 			case B_REG_MIME_DESCRIPTION:
425 			{
426 				bool isLong;
427 				err = message->FindBool("long", &isLong);
428 				if (!err)
429 					err = isLong
430 						    ? fDatabase.DeleteLongDescription(type)
431 						      : fDatabase.DeleteShortDescription(type);
432 				break;
433 			}
434 
435 			case B_REG_MIME_FILE_EXTENSIONS:
436 				err = fDatabase.DeleteFileExtensions(type);
437 				break;
438 
439 			case B_REG_MIME_ICON:
440 			case B_REG_MIME_ICON_FOR_TYPE:
441 			{
442 				int32 size;
443 				err = message->FindInt32("icon size", &size);
444 				if (which == B_REG_MIME_ICON_FOR_TYPE) {
445 					const char *fileType;
446 					if (!err)
447 						err = message->FindString("file type", &fileType);
448 					if (!err)
449 						err = fDatabase.DeleteIconForType(type, fileType, (icon_size)size);
450 				} else {
451 					if (!err)
452 						err = fDatabase.DeleteIcon(type, (icon_size)size);
453 				}
454 				break;
455 			}
456 
457 			case B_REG_MIME_PREFERRED_APP:
458 			{
459 				int32 verb;
460 				err = message->FindInt32("app verb", &verb);
461 				if (!err)
462 					err = fDatabase.DeletePreferredApp(type, (app_verb)verb);
463 				break;
464 			}
465 
466 			case B_REG_MIME_SNIFFER_RULE:
467 				err = fDatabase.DeleteSnifferRule(type);
468 				break;
469 
470 			case B_REG_MIME_SUPPORTED_TYPES:
471 			{
472 				bool fullSync;
473 				err = message->FindBool("full sync", &fullSync);
474 				if (!err)
475 					err = fDatabase.DeleteSupportedTypes(type, fullSync);
476 				break;
477 			}
478 
479 			default:
480 				err = B_BAD_VALUE;
481 				break;
482 		}
483 	}
484 
485 	BMessage reply(B_REG_RESULT);
486 	reply.AddInt32("result", err);
487 	message->SendReply(&reply, this);
488 }
489 
490