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