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