xref: /haiku/src/kits/app/Roster.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * Copyright 2001-2010, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold (ingo_weinhold@gmx.de)
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 
11 /*!	BRoster class lets you launch apps and keeps track of apps
12 	that are running.
13 	Global be_roster represents the default BRoster.
14 	app_info structure provides info for a running app.
15 */
16 
17 
18 #include <Roster.h>
19 
20 #include <ctype.h>
21 #include <new>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include <AppFileInfo.h>
28 #include <Application.h>
29 #include <Bitmap.h>
30 #include <Directory.h>
31 #include <File.h>
32 #include <FindDirectory.h>
33 #include <fs_index.h>
34 #include <fs_info.h>
35 #include <image.h>
36 #include <List.h>
37 #include <Mime.h>
38 #include <Node.h>
39 #include <NodeInfo.h>
40 #include <OS.h>
41 #include <Path.h>
42 #include <Query.h>
43 #include <RegistrarDefs.h>
44 #include <String.h>
45 #include <Volume.h>
46 #include <VolumeRoster.h>
47 
48 #include <locks.h>
49 
50 #include <AppMisc.h>
51 #include <DesktopLink.h>
52 #include <MessengerPrivate.h>
53 #include <PortLink.h>
54 #include <RosterPrivate.h>
55 #include <ServerProtocol.h>
56 
57 
58 using namespace std;
59 using namespace BPrivate;
60 
61 
62 // debugging
63 //#define DBG(x) x
64 #define DBG(x)
65 #ifdef DEBUG_PRINTF
66 	#define OUT DEBUG_PRINTF
67 #else
68 	#define OUT	printf
69 #endif
70 
71 enum {
72 	NOT_IMPLEMENTED	= B_ERROR,
73 };
74 
75 
76 const BRoster* be_roster;
77 
78 
79 //	#pragma mark - Helper functions
80 
81 
82 /*!	\brief Extracts an app_info from a BMessage.
83 
84 	The function searchs for a field "app_info" typed B_REG_APP_INFO_TYPE
85 	and initializes \a info with the found data.
86 
87 	\param message The message
88 	\param info A pointer to a pre-allocated app_info to be filled in with the
89 		   info found in the message.
90 	\return
91 	- \c B_OK: Everything went fine.
92 	- \c B_BAD_VALUE: \c NULL \a message or \a info.
93 	- other error codes
94 */
95 static status_t
96 find_message_app_info(BMessage* message, app_info* info)
97 {
98 	status_t error = (message && info ? B_OK : B_BAD_VALUE);
99 	const flat_app_info* flatInfo = NULL;
100 	ssize_t size = 0;
101 	// find the flat app info in the message
102 	if (error == B_OK) {
103 		error = message->FindData("app_info", B_REG_APP_INFO_TYPE,
104 			(const void**)&flatInfo, &size);
105 	}
106 	// unflatten the flat info
107 	if (error == B_OK) {
108 		if (size == sizeof(flat_app_info)) {
109 			memcpy(info, &flatInfo->info, sizeof(app_info));
110 			info->ref.name = NULL;
111 			if (strlen(flatInfo->ref_name) > 0)
112 				info->ref.set_name(flatInfo->ref_name);
113 		} else
114 			error = B_ERROR;
115 	}
116 	return error;
117 }
118 
119 
120 /*!	\brief Checks whether or not an application can be used.
121 
122 	Currently it is only checked whether the application is in the trash.
123 
124 	\param ref An entry_ref referring to the application executable.
125 	\return
126 	- \c B_OK: The application can be used.
127 	- \c B_ENTRY_NOT_FOUND: \a ref doesn't refer to and existing entry.
128 	- \c B_IS_A_DIRECTORY: \a ref refers to a directory.
129 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The application executable is in the
130 	  trash.
131 	- other error codes specifying why the application cannot be used.
132 */
133 static status_t
134 can_app_be_used(const entry_ref* ref)
135 {
136 	status_t error = (ref ? B_OK : B_BAD_VALUE);
137 	// check whether the file exists and is a file.
138 	BEntry entry;
139 	if (error == B_OK)
140 		error = entry.SetTo(ref, true);
141 	if (error == B_OK && !entry.Exists())
142 		error = B_ENTRY_NOT_FOUND;
143 	if (error == B_OK && !entry.IsFile())
144 		error = B_IS_A_DIRECTORY;
145 	// check whether the file is in trash
146 	BPath trashPath;
147 	BDirectory directory;
148 	BVolume volume;
149 	if (error == B_OK
150 		&& volume.SetTo(ref->device) == B_OK
151 		&& find_directory(B_TRASH_DIRECTORY, &trashPath, false, &volume)
152 			== B_OK
153 		&& directory.SetTo(trashPath.Path()) == B_OK
154 		&& directory.Contains(&entry)) {
155 		error = B_LAUNCH_FAILED_APP_IN_TRASH;
156 	}
157 	return error;
158 }
159 
160 
161 /*!	\brief Compares the supplied version infos.
162 	\param info1 The first info.
163 	\param info2 The second info.
164 	\return \c -1, if the first info is less than the second one, \c 1, if
165 			the first one is greater than the second one, and \c 0, if both
166 			are equal.
167 */
168 static int32
169 compare_version_infos(const version_info& info1, const version_info& info2)
170 {
171 	int32 result = 0;
172 	if (info1.major < info2.major)
173 		result = -1;
174 	else if (info1.major > info2.major)
175 		result = 1;
176 	else if (info1.middle < info2.middle)
177 		result = -1;
178 	else if (info1.middle > info2.middle)
179 		result = 1;
180 	else if (info1.minor < info2.minor)
181 		result = -1;
182 	else if (info1.minor > info2.minor)
183 		result = 1;
184 	else if (info1.variety < info2.variety)
185 		result = -1;
186 	else if (info1.variety > info2.variety)
187 		result = 1;
188 	else if (info1.internal < info2.internal)
189 		result = -1;
190 	else if (info1.internal > info2.internal)
191 		result = 1;
192 	return result;
193 }
194 
195 
196 /*!	\brief Compares two applications to decide which one should be rather
197 		returned as a query result.
198 
199 	First, it checks if both apps are in the path, and prefers the app that
200 	appears earlier.
201 
202 	If both files have a version info, then those are compared.
203 	If one file has a version info, it is said to be greater. If both
204 	files have no version info, their modification times are compared.
205 
206 	\param app1 An entry_ref referring to the first application.
207 	\param app2 An entry_ref referring to the second application.
208 	\return \c -1, if the first application version is less than the second
209 			one, \c 1, if the first one is greater than the second one, and
210 			\c 0, if both are equal.
211 */
212 static int32
213 compare_queried_apps(const entry_ref* app1, const entry_ref* app2)
214 {
215 	BPath path1(app1);
216 	BPath path2(app2);
217 
218 	// Check search path
219 
220 	const char* searchPathes = getenv("PATH");
221 	if (searchPathes != NULL) {
222 		char* searchBuffer = strdup(searchPathes);
223 		if (searchBuffer != NULL) {
224 			char* last;
225 			const char* path = strtok_r(searchBuffer, ":", &last);
226 			while (path != NULL) {
227 				// Check if any app path matches
228 				size_t length = strlen(path);
229 				bool found1 = !strncmp(path, path1.Path(), length)
230 					&& path1.Path()[length] == '/';
231 				bool found2 = !strncmp(path, path2.Path(), length)
232 					&& path2.Path()[length] == '/';;
233 
234 				if (found1 != found2) {
235 					free(searchBuffer);
236 					return found1 ? 1 : -1;
237 				}
238 
239 				path = strtok_r(NULL, ":", &last);
240 			}
241 
242 			free(searchBuffer);
243 		}
244 	}
245 
246 	// Check system servers folder
247 	BPath path;
248 	find_directory(B_SYSTEM_SERVERS_DIRECTORY, &path);
249 	BString serverPath(path.Path());
250 	serverPath << '/';
251 	size_t length = serverPath.Length();
252 
253 	bool inSystem1 = !strncmp(serverPath.String(), path1.Path(), length);
254 	bool inSystem2 = !strncmp(serverPath.String(), path2.Path(), length);
255 	if (inSystem1 != inSystem2)
256 		return inSystem1 ? 1 : -1;
257 
258 	// Check version info
259 
260 	BFile file1, file2;
261 	BAppFileInfo appFileInfo1, appFileInfo2;
262 	file1.SetTo(app1, B_READ_ONLY);
263 	file2.SetTo(app2, B_READ_ONLY);
264 	appFileInfo1.SetTo(&file1);
265 	appFileInfo2.SetTo(&file2);
266 	time_t modificationTime1 = 0;
267 	time_t modificationTime2 = 0;
268 	file1.GetModificationTime(&modificationTime1);
269 	file2.GetModificationTime(&modificationTime2);
270 	int32 result = 0;
271 	version_info versionInfo1, versionInfo2;
272 	bool hasVersionInfo1 = (appFileInfo1.GetVersionInfo(
273 		&versionInfo1, B_APP_VERSION_KIND) == B_OK);
274 	bool hasVersionInfo2 = (appFileInfo2.GetVersionInfo(
275 		&versionInfo2, B_APP_VERSION_KIND) == B_OK);
276 	if (hasVersionInfo1) {
277 		if (hasVersionInfo2)
278 			result = compare_version_infos(versionInfo1, versionInfo2);
279 		else
280 			result = 1;
281 	} else {
282 		if (hasVersionInfo2)
283 			result = -1;
284 		else if (modificationTime1 < modificationTime2)
285 			result = -1;
286 		else if (modificationTime1 > modificationTime2)
287 			result = 1;
288 	}
289 	return result;
290 }
291 
292 
293 /*!	\brief Finds an app by signature on any mounted volume.
294 	\param signature The app's signature.
295 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
296 		   a reference to the found application's executable.
297 	\return
298 	- \c B_OK: Everything went fine.
299 	- \c B_BAD_VALUE: \c NULL \a signature or \a appRef.
300 	- B_LAUNCH_FAILED_APP_NOT_FOUND: An application with this signature
301 	  could not be found.
302 	- other error codes
303 */
304 static status_t
305 query_for_app(const char* signature, entry_ref* appRef)
306 {
307 	if (signature == NULL || appRef == NULL)
308 		return B_BAD_VALUE;
309 
310 	status_t error = B_LAUNCH_FAILED_APP_NOT_FOUND;
311 	bool caseInsensitive = false;
312 
313 	while (true) {
314 		// search on all volumes
315 		BVolumeRoster volumeRoster;
316 		BVolume volume;
317 		while (volumeRoster.GetNextVolume(&volume) == B_OK) {
318 			if (!volume.KnowsQuery())
319 				continue;
320 
321 			index_info info;
322 			if (fs_stat_index(volume.Device(), "BEOS:APP_SIG", &info) != 0) {
323 				// This volume doesn't seem to have the index we're looking for;
324 				// querying it might need a long time, and we don't care *that*
325 				// much...
326 				continue;
327 			}
328 
329 			BQuery query;
330 			query.SetVolume(&volume);
331 			query.PushAttr("BEOS:APP_SIG");
332 			if (!caseInsensitive)
333 				query.PushString(signature);
334 			else {
335 				// second pass, create a case insensitive query string
336 				char string[B_MIME_TYPE_LENGTH * 4];
337 				strlcpy(string, "application/", sizeof(string));
338 
339 				int32 length = strlen(string);
340 				const char* from = signature + length;
341 				char* to = string + length;
342 
343 				for (; from[0]; from++) {
344 					if (isalpha(from[0])) {
345 						*to++ = '[';
346 						*to++ = tolower(from[0]);
347 						*to++ = toupper(from[0]);
348 						*to++ = ']';
349 					} else
350 						*to++ = from[0];
351 				}
352 
353 				to[0] = '\0';
354 				query.PushString(string);
355 			}
356 			query.PushOp(B_EQ);
357 
358 			query.Fetch();
359 
360 			// walk through the query
361 			bool appFound = false;
362 			status_t foundAppError = B_OK;
363 			entry_ref ref;
364 			while (query.GetNextRef(&ref) == B_OK) {
365 				if ((!appFound || compare_queried_apps(appRef, &ref) < 0)
366 					&& (foundAppError = can_app_be_used(&ref)) == B_OK) {
367 					*appRef = ref;
368 					appFound = true;
369 				}
370 			}
371 			if (!appFound) {
372 				// If the query didn't return any hits, the error is
373 				// B_LAUNCH_FAILED_APP_NOT_FOUND, otherwise we return the
374 				// result of the last can_app_be_used().
375 				error = foundAppError != B_OK
376 					? foundAppError : B_LAUNCH_FAILED_APP_NOT_FOUND;
377 			} else
378 				return B_OK;
379 		}
380 
381 		if (!caseInsensitive)
382 			caseInsensitive = true;
383 		else
384 			break;
385 	}
386 
387 	return error;
388 }
389 
390 
391 //	#pragma mark - app_info
392 
393 
394 /*!	\brief Creates an uninitialized app_info.
395 */
396 app_info::app_info()
397 	:
398 	thread(-1),
399 	team(-1),
400 	port(-1),
401 	flags(B_REG_DEFAULT_APP_FLAGS),
402 	ref()
403 {
404 	signature[0] = '\0';
405 }
406 
407 
408 /*!	\brief Does nothing.
409 */
410 app_info::~app_info()
411 {
412 }
413 
414 
415 //	#pragma mark - BRoster::ArgVector
416 
417 
418 class BRoster::ArgVector {
419 public:
420 								ArgVector();
421 								~ArgVector();
422 
423 			status_t			Init(int argc, const char* const* args,
424 									const entry_ref* appRef,
425 									const entry_ref* docRef);
426 			void				Unset();
427 	inline	int					Count() const { return fArgc; }
428 	inline	const char* const*	Args() const { return fArgs; }
429 
430 private:
431 			int					fArgc;
432 			const char**		fArgs;
433 			BPath				fAppPath;
434 			BPath				fDocPath;
435 };
436 
437 
438 /*!	\brief Creates an uninitialized ArgVector.
439 */
440 BRoster::ArgVector::ArgVector()
441 	:
442 	fArgc(0),
443 	fArgs(NULL),
444 	fAppPath(),
445 	fDocPath()
446 {
447 }
448 
449 
450 /*!	\brief Frees all resources associated with the ArgVector.
451 */
452 BRoster::ArgVector::~ArgVector()
453 {
454 	Unset();
455 }
456 
457 
458 /*!	\brief Initilizes the object according to the supplied parameters.
459 
460 	If the initialization succeeds, the methods Count() and Args() grant
461 	access to the argument count and vector created by this methods.
462 	\note The returned vector is valid only as long as the elements of the
463 	supplied \a args (if any) are valid and this object is not destroyed.
464 	This object retains ownership of the vector returned by Args().
465 	In case of error, the value returned by Args() is invalid (or \c NULL).
466 
467 	The argument vector is created as follows: First element is the path
468 	of the entry \a appRef refers to, then follow all elements of \a args
469 	and then, if \a args has at least one element and \a docRef can be
470 	resolved to a path, the path of the entry \a docRef refers to. That is,
471 	if no or an empty \a args vector is supplied, the resulting argument
472 	vector contains only one element, the path associated with \a appRef.
473 
474 	\param argc Specifies the number of elements \a args contains.
475 	\param args Argument vector. May be \c NULL.
476 	\param appRef entry_ref referring to the entry whose path shall be the
477 		   first element of the resulting argument vector.
478 	\param docRef entry_ref referring to the entry whose path shall be the
479 		   last element of the resulting argument vector. May be \c NULL.
480 	\return
481 	- \c B_OK: Everything went fine.
482 	- \c B_BAD_VALUE: \c NULL \a appRef.
483 	- \c B_ENTRY_NOT_FOUND or other file system error codes: \a appRef could
484 	  not be resolved to a path.
485 	- \c B_NO_MEMORY: Not enough memory to allocate for this operation.
486 */
487 status_t
488 BRoster::ArgVector::Init(int argc, const char* const* args,
489 	const entry_ref* appRef, const entry_ref* docRef)
490 {
491 	// unset old values
492 	Unset();
493 	status_t error = (appRef ? B_OK : B_BAD_VALUE);
494 	// get app path
495 	if (error == B_OK)
496 		error = fAppPath.SetTo(appRef);
497 	// determine number of arguments
498 	bool hasDocArg = false;
499 	if (error == B_OK) {
500 		fArgc = 1;
501 		if (argc > 0 && args) {
502 			fArgc += argc;
503 			if (docRef && fDocPath.SetTo(docRef) == B_OK) {
504 				fArgc++;
505 				hasDocArg = true;
506 			}
507 		}
508 		fArgs = new(nothrow) const char*[fArgc + 1];	// + 1 for term. NULL
509 		if (!fArgs)
510 			error = B_NO_MEMORY;
511 	}
512 	// init vector
513 	if (error == B_OK) {
514 		fArgs[0] = fAppPath.Path();
515 		if (argc > 0 && args) {
516 			for (int i = 0; i < argc; i++)
517 				fArgs[i + 1] = args[i];
518 			if (hasDocArg)
519 				fArgs[fArgc - 1] = fDocPath.Path();
520 		}
521 		// NULL terminate (e.g. required by load_image())
522 		fArgs[fArgc] = NULL;
523 	}
524 	return error;
525 }
526 
527 
528 /*!	\brief Uninitializes the object.
529 */
530 void
531 BRoster::ArgVector::Unset()
532 {
533 	fArgc = 0;
534 	delete[] fArgs;
535 	fArgs = NULL;
536 	fAppPath.Unset();
537 	fDocPath.Unset();
538 }
539 
540 
541 //	#pragma mark - BRoster
542 
543 
544 BRoster::BRoster()
545 	:
546 	fMessenger(),
547 	fMimeMessenger(),
548 	fMimeMessengerInitOnce(INIT_ONCE_UNINITIALIZED)
549 {
550 	_InitMessenger();
551 }
552 
553 
554 BRoster::~BRoster()
555 {
556 }
557 
558 
559 //	#pragma mark - Querying for apps
560 
561 
562 /*!	\brief Returns whether or not an application with the supplied signature
563 		   is currently running.
564 	\param mimeSig The app signature
565 	\return \c true, if the supplied signature is not \c NULL and an
566 			application with this signature is running, \c false otherwise.
567 */
568 bool
569 BRoster::IsRunning(const char* mimeSig) const
570 {
571 	return (TeamFor(mimeSig) >= 0);
572 }
573 
574 
575 /*!	\brief Returns whether or not an application ran from an executable
576 		   referred to by the supplied entry_ref is currently running.
577 	\param ref The app's entry_ref
578 	\return \c true, if the supplied entry_ref is not \c NULL and an
579 			application executing this file is running, \c false otherwise.
580 */
581 bool
582 BRoster::IsRunning(entry_ref* ref) const
583 {
584 	return (TeamFor(ref) >= 0);
585 }
586 
587 
588 /*!	\brief Returns the team ID of a currently running application with the
589 		   supplied signature.
590 	\param mimeSig The app signature
591 	\return
592 	- The team ID of a running application with the supplied signature.
593 	- \c B_BAD_VALUE: \a mimeSig is \c NULL.
594 	- \c B_ERROR: No application with the supplied signature is currently
595 	  running.
596 */
597 team_id
598 BRoster::TeamFor(const char* mimeSig) const
599 {
600 	team_id team;
601 	app_info info;
602 	status_t error = GetAppInfo(mimeSig, &info);
603 	if (error == B_OK)
604 		team = info.team;
605 	else
606 		team = error;
607 	return team;
608 }
609 
610 
611 /*!	\brief Returns the team ID of a currently running application executing
612 		   the executable referred to by the supplied entry_ref.
613 	\param ref The app's entry_ref
614 	\return
615 	- The team ID of a running application executing the file referred to by
616 	  \a ref.
617 	- \c B_BAD_VALUE: \a ref is \c NULL.
618 	- \c B_ERROR: No application executing the file referred to by \a ref is
619 	  currently running.
620 */
621 team_id
622 BRoster::TeamFor(entry_ref* ref) const
623 {
624 	team_id team;
625 	app_info info;
626 	status_t error = GetAppInfo(ref, &info);
627 	if (error == B_OK)
628 		team = info.team;
629 	else
630 		team = error;
631 	return team;
632 }
633 
634 
635 /*!	\brief Returns a list of all currently running applications.
636 
637 	The supplied list is not emptied before adding the team IDs of the
638 	running applications. The list elements are team_id's, not pointers.
639 
640 	\param teamIDList A pointer to a pre-allocated BList to be filled with
641 		   the team IDs.
642 */
643 void
644 BRoster::GetAppList(BList* teamIDList) const
645 {
646 	status_t error = (teamIDList ? B_OK : B_BAD_VALUE);
647 	// compose the request message
648 	BMessage request(B_REG_GET_APP_LIST);
649 
650 	// send the request
651 	BMessage reply;
652 	if (error == B_OK)
653 		error = fMessenger.SendMessage(&request, &reply);
654 
655 	// evaluate the reply
656 	if (error == B_OK) {
657 		if (reply.what == B_REG_SUCCESS) {
658 			team_id team;
659 			for (int32 i = 0; reply.FindInt32("teams", i, &team) == B_OK; i++)
660 				teamIDList->AddItem((void*)team);
661 		} else {
662 			if (reply.FindInt32("error", &error) != B_OK)
663 				error = B_ERROR;
664 			DBG(OUT("Roster request unsuccessful: %s\n", strerror(error)));
665 			DBG(reply.PrintToStream());
666 		}
667 	} else {
668 		DBG(OUT("Sending message to roster failed: %s\n", strerror(error)));
669 	}
670 }
671 
672 
673 /*!	\brief Returns a list of all currently running applications with the
674 		   specified signature.
675 
676 	The supplied list is not emptied before adding the team IDs of the
677 	running applications. The list elements are team_id's, not pointers.
678 	If \a sig is \c NULL or invalid, no team IDs are added to the list.
679 
680 	\param sig The app signature
681 	\param teamIDList A pointer to a pre-allocated BList to be filled with
682 		   the team IDs.
683 */
684 void
685 BRoster::GetAppList(const char* sig, BList* teamIDList) const
686 {
687 	status_t error = (sig && teamIDList ? B_OK : B_BAD_VALUE);
688 	// compose the request message
689 	BMessage request(B_REG_GET_APP_LIST);
690 	if (error == B_OK)
691 		error = request.AddString("signature", sig);
692 
693 	// send the request
694 	BMessage reply;
695 	if (error == B_OK)
696 		error = fMessenger.SendMessage(&request, &reply);
697 
698 	// evaluate the reply
699 	if (error == B_OK) {
700 		if (reply.what == B_REG_SUCCESS) {
701 			team_id team;
702 			for (int32 i = 0; reply.FindInt32("teams", i, &team) == B_OK; i++)
703 				teamIDList->AddItem((void*)team);
704 		} else if (reply.FindInt32("error", &error) != B_OK)
705 			error = B_ERROR;
706 	}
707 }
708 
709 
710 /*!	\brief Returns the app_info of a currently running application with the
711 		   supplied signature.
712 	\param sig The app signature
713 	\param info A pointer to a pre-allocated app_info structure to be filled
714 		   in by this method.
715 	\return
716 	- \c B_OK: Everything went fine.
717 	- \c B_BAD_VALUE: \a sig is \c NULL.
718 	- \c B_ERROR: No application with the supplied signature is currently
719 	  running.
720 */
721 status_t
722 BRoster::GetAppInfo(const char* sig, app_info* info) const
723 {
724 	status_t error = (sig && info ? B_OK : B_BAD_VALUE);
725 	// compose the request message
726 	BMessage request(B_REG_GET_APP_INFO);
727 	if (error == B_OK)
728 		error = request.AddString("signature", sig);
729 
730 	// send the request
731 	BMessage reply;
732 	if (error == B_OK)
733 		error = fMessenger.SendMessage(&request, &reply);
734 
735 	// evaluate the reply
736 	if (error == B_OK) {
737 		if (reply.what == B_REG_SUCCESS)
738 			error = find_message_app_info(&reply, info);
739 		else if (reply.FindInt32("error", &error) != B_OK)
740 			error = B_ERROR;
741 	}
742 	return error;
743 }
744 
745 
746 /*!	\brief Returns the app_info of a currently running application executing
747 		   the executable referred to by the supplied entry_ref.
748 	\param ref The app's entry_ref
749 	\param info A pointer to a pre-allocated app_info structure to be filled
750 		   in by this method.
751 	\return
752 	- \c B_OK: Everything went fine.
753 	- \c B_BAD_VALUE: \a ref is \c NULL.
754 	- \c B_ERROR: No application executing the file referred to by \a ref is
755 	  currently running.
756 */
757 status_t
758 BRoster::GetAppInfo(entry_ref* ref, app_info* info) const
759 {
760 	status_t error = (ref && info ? B_OK : B_BAD_VALUE);
761 	// compose the request message
762 	BMessage request(B_REG_GET_APP_INFO);
763 	if (error == B_OK)
764 		error = request.AddRef("ref", ref);
765 
766 	// send the request
767 	BMessage reply;
768 	if (error == B_OK)
769 		error = fMessenger.SendMessage(&request, &reply);
770 
771 	// evaluate the reply
772 	if (error == B_OK) {
773 		if (reply.what == B_REG_SUCCESS)
774 			error = find_message_app_info(&reply, info);
775 		else if (reply.FindInt32("error", &error) != B_OK)
776 			error = B_ERROR;
777 	}
778 	return error;
779 }
780 
781 
782 /*!	\brief Returns the app_info of a currently running application identified
783 		   by the supplied team ID.
784 	\param team The app's team ID
785 	\param info A pointer to a pre-allocated app_info structure to be filled
786 		   in by this method.
787 	\return
788 	- \c B_OK: Everything went fine.
789 	- \c B_BAD_VALUE: \a info is \c NULL.
790 	- \c B_BAD_TEAM_ID: \a team does not identify a running application.
791 */
792 status_t
793 BRoster::GetRunningAppInfo(team_id team, app_info* info) const
794 {
795 	status_t error = (info ? B_OK : B_BAD_VALUE);
796 	if (error == B_OK && team < 0)
797 		error = B_BAD_TEAM_ID;
798 	// compose the request message
799 	BMessage request(B_REG_GET_APP_INFO);
800 	if (error == B_OK)
801 		error = request.AddInt32("team", team);
802 	// send the request
803 	BMessage reply;
804 	if (error == B_OK)
805 		error = fMessenger.SendMessage(&request, &reply);
806 
807 	// evaluate the reply
808 	if (error == B_OK) {
809 		if (reply.what == B_REG_SUCCESS)
810 			error = find_message_app_info(&reply, info);
811 		else if (reply.FindInt32("error", &error) != B_OK)
812 			error = B_ERROR;
813 	}
814 	return error;
815 }
816 
817 
818 /*!	\brief Returns the app_info of a currently active application.
819 	\param info A pointer to a pre-allocated app_info structure to be filled
820 		   in by this method.
821 	\return
822 	- \c B_OK: Everything went fine.
823 	- \c B_BAD_VALUE: \a info is \c NULL.
824 	- \c B_ERROR: Currently no application is active.
825 */
826 status_t
827 BRoster::GetActiveAppInfo(app_info* info) const
828 {
829 	if (info == NULL)
830 		return B_BAD_VALUE;
831 
832 	// compose the request message
833 	BMessage request(B_REG_GET_APP_INFO);
834 	// send the request
835 	BMessage reply;
836 	status_t error = fMessenger.SendMessage(&request, &reply);
837 	// evaluate the reply
838 	if (error == B_OK) {
839 		if (reply.what == B_REG_SUCCESS)
840 			error = find_message_app_info(&reply, info);
841 		else if (reply.FindInt32("error", &error) != B_OK)
842 			error = B_ERROR;
843 	}
844 	return error;
845 }
846 
847 
848 /*!	\brief Finds an application associated with a MIME type.
849 
850 	The method gets the signature of the supplied type's preferred application
851 	and the signature of the super type's preferred application. It will also
852 	get all supporting applications for the type and super type and build a
853 	list of candiate handlers. In the case that a preferred handler is
854 	configured for the sub-type, other supporting apps will be inserted in the
855 	candidate list before the super-type preferred and supporting handlers,
856 	since it is assumed that the super type handlers are not well suited for
857 	the sub-type. The following resolving algorithm is performed on each
858 	signature of the resulting list:
859 	The MIME database is asked which executable is associated with the
860 	signature. If the database doesn't have a reference to an exectuable, the
861 	boot volume is queried for a file with the signature. If more than one file
862 	has been found, the one with the greatest version is picked, or if no file
863 	has a version info, the one with the most recent modification date. The
864 	first application from the signature list which can be successfully
865 	resolved by this algorithm is returned. Contrary to BeOS behavior, this
866 	means that if the preferred application of the provided MIME type cannot
867 	be resolved, or if it does not have a preferred application associated,
868 	the method will return other applications with direct support for the MIME
869 	type before it resorts to the preferred application or supporting
870 	applications of the super type.
871 
872 	\param mimeType The MIME type for which an application shall be found.
873 	\param app A pointer to a pre-allocated entry_ref to be filled with
874 		   a reference to the found application's executable.
875 	\return
876 	- \c B_OK: Everything went fine.
877 	- \c B_BAD_VALUE: \c NULL \a mimeType or \a app.
878 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
879 	  with its supertype (if the supplied isn't a supertype itself) a
880 	  preferred application is associated and no other supporting
881 	  applications could be identified.
882 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
883 	  its preferred application could not be found.
884 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's only supporting
885 	  application is in trash.
886 	- other error codes
887 */
888 status_t
889 BRoster::FindApp(const char* mimeType, entry_ref* app) const
890 {
891 	if (mimeType == NULL || app == NULL)
892 		return B_BAD_VALUE;
893 
894 	return _ResolveApp(mimeType, NULL, app, NULL, NULL, NULL);
895 }
896 
897 
898 /*!	\brief Finds an application associated with a file.
899 
900 	The method first checks, if the file has a preferred application
901 	associated with it (see BNodeInfo::GetPreferredApp()) and if so,
902 	tries to find the executable the same way FindApp(const char*, entry_ref*)
903 	does. If not, it gets the MIME type of the file and searches an
904 	application for it exactly like the first FindApp() method.
905 
906 	The type of the file is defined in a file attribute (BNodeInfo::GetType()),
907 	but if it is not set yet, the method tries to guess it via
908 	BMimeType::GuessMimeType().
909 
910 	As a special case the file may have execute permission. Then preferred
911 	application and type are ignored and an entry_ref to the file itself is
912 	returned.
913 
914 	\param ref An entry_ref referring to the file for which an application
915 		   shall be found.
916 	\param app A pointer to a pre-allocated entry_ref to be filled with
917 		   a reference to the found application's executable.
918 	\return
919 	- \c B_OK: Everything went fine.
920 	- \c B_BAD_VALUE: \c NULL \a mimeType or \a app.
921 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
922 	  with its supertype (if the supplied isn't a supertype itself) a
923 	  preferred application is associated.
924 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
925 	  its preferred application could not be found.
926 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
927 	  application is in trash.
928 	- other error codes
929 */
930 status_t
931 BRoster::FindApp(entry_ref* ref, entry_ref* app) const
932 {
933 	if (ref == NULL || app == NULL)
934 		return B_BAD_VALUE;
935 
936 	entry_ref _ref(*ref);
937 	return _ResolveApp(NULL, &_ref, app, NULL, NULL, NULL);
938 }
939 
940 
941 //	#pragma mark - Launching, activating, and broadcasting to apps
942 
943 
944 /*!	\brief Sends a message to all running applications.
945 
946 	The methods doesn't broadcast the message itself, but it asks the roster
947 	to do so. It immediatly returns after sending the request. The return
948 	value only tells about whether the request has successfully been sent.
949 
950 	The message is sent asynchronously. Replies to it go to the application.
951 	(\c be_app_messenger).
952 
953 	\param message The message to be broadcast.
954 	\return
955 	- \c B_OK: Everything went fine.
956 	- \c B_BAD_VALUE: \c NULL \a message.
957 	- other error codes
958 */
959 status_t
960 BRoster::Broadcast(BMessage* message) const
961 {
962 	return Broadcast(message, be_app_messenger);
963 }
964 
965 
966 /*!	\brief Sends a message to all running applications.
967 
968 	The methods doesn't broadcast the message itself, but it asks the roster
969 	to do so. It immediatly returns after sending the request. The return
970 	value only tells about whether the request has successfully been sent.
971 
972 	The message is sent asynchronously. Replies to it go to the specified
973 	target (\a replyTo).
974 
975 	\param message The message to be broadcast.
976 	\param replyTo Reply target for the message.
977 	\return
978 	- \c B_OK: Everything went fine.
979 	- \c B_BAD_VALUE: \c NULL \a message.
980 	- other error codes
981 */
982 status_t
983 BRoster::Broadcast(BMessage* message, BMessenger replyTo) const
984 {
985 	status_t error = (message ? B_OK : B_BAD_VALUE);
986 	// compose the request message
987 	BMessage request(B_REG_BROADCAST);
988 	if (error == B_OK)
989 		error = request.AddInt32("team", BPrivate::current_team());
990 	if (error == B_OK)
991 		error = request.AddMessage("message", message);
992 	if (error == B_OK)
993 		error = request.AddMessenger("reply_target", replyTo);
994 
995 	// send the request
996 	BMessage reply;
997 	if (error == B_OK)
998 		error = fMessenger.SendMessage(&request, &reply);
999 
1000 	// evaluate the reply
1001 	if (error == B_OK && reply.what != B_REG_SUCCESS
1002 		&& reply.FindInt32("error", &error) != B_OK)
1003 		error = B_ERROR;
1004 
1005 	return error;
1006 }
1007 
1008 
1009 /*!	\brief Adds a new roster application monitor.
1010 
1011 	After StartWatching() event messages will be sent to the supplied target
1012 	according to the specified flags until a respective StopWatching() call.
1013 
1014 	\a eventMask must be a bitwise OR of one or more of the following flags:
1015 	- \c B_REQUEST_LAUNCHED: A \c B_SOME_APP_LAUNCHED is sent, whenever an
1016 	  application has been launched.
1017 	- \c B_REQUEST_QUIT: A \c B_SOME_APP_QUIT is sent, whenever an
1018 	  application has quit.
1019 	- \c B_REQUEST_ACTIVATED: A \c B_SOME_APP_ACTIVATED is sent, whenever an
1020 	  application has been activated.
1021 
1022 	All event messages contain the following fields supplying more information
1023 	about the concerned application:
1024 	- \c "be:signature", \c B_STRING_TYPE: The signature of the application.
1025 	- \c "be:team", \c B_INT32_TYPE: The team ID of the application
1026 	  (\c team_id).
1027 	- \c "be:thread", \c B_INT32_TYPE: The ID of the application's main thread
1028 	  (\c thread_id).
1029 	- \c "be:flags", \c B_INT32_TYPE: The application flags (\c uint32).
1030 	- \c "be:ref", \c B_REF_TYPE: An entry_ref referring to the application's
1031 	  executable.
1032 
1033 	A second call to StartWatching() with the same \a target simply sets
1034 	the new \a eventMask. The messages won't be sent twice to the target.
1035 
1036 	\param target The target the event messages shall be sent to.
1037 	\param eventMask Specifies the events the caller is interested in.
1038 	\return
1039 	- \c B_OK: Everything went fine.
1040 	- an error code, if some error occured.
1041 */
1042 status_t
1043 BRoster::StartWatching(BMessenger target, uint32 eventMask) const
1044 {
1045 	status_t error = B_OK;
1046 	// compose the request message
1047 	BMessage request(B_REG_START_WATCHING);
1048 	if (error == B_OK)
1049 		error = request.AddMessenger("target", target);
1050 	if (error == B_OK)
1051 		error = request.AddInt32("events", (int32)eventMask);
1052 
1053 	// send the request
1054 	BMessage reply;
1055 	if (error == B_OK)
1056 		error = fMessenger.SendMessage(&request, &reply);
1057 
1058 	// evaluate the reply
1059 	if (error == B_OK && reply.what != B_REG_SUCCESS
1060 		&& reply.FindInt32("error", &error) != B_OK)
1061 		error = B_ERROR;
1062 
1063 	return error;
1064 }
1065 
1066 
1067 /*!	\brief Removes a roster application monitor added with StartWatching().
1068 	\param target The target that shall not longer receive any event messages.
1069 	\return
1070 	- \c B_OK: Everything went fine.
1071 	- \c B_BAD_VALUE: No application monitor has been associated with the
1072 	  specified \a target before.
1073 */
1074 status_t
1075 BRoster::StopWatching(BMessenger target) const
1076 {
1077 	status_t error = B_OK;
1078 	// compose the request message
1079 	BMessage request(B_REG_STOP_WATCHING);
1080 	if (error == B_OK)
1081 		error = request.AddMessenger("target", target);
1082 
1083 	// send the request
1084 	BMessage reply;
1085 	if (error == B_OK)
1086 		error = fMessenger.SendMessage(&request, &reply);
1087 
1088 	// evaluate the reply
1089 	if (error == B_OK && reply.what != B_REG_SUCCESS
1090 		&& reply.FindInt32("error", &error) != B_OK)
1091 		error = B_ERROR;
1092 
1093 	return error;
1094 }
1095 
1096 
1097 /*!	\brief Activates the application identified by the supplied team ID.
1098 	\param team The app's team ID
1099 	\return
1100 	- \c B_OK: Everything went fine.
1101 	- \c B_BAD_TEAM_ID: \a team does not identify a running application.
1102 */
1103 status_t
1104 BRoster::ActivateApp(team_id team) const
1105 {
1106 	BPrivate::DesktopLink link;
1107 
1108 	status_t status = link.InitCheck();
1109 	if (status < B_OK)
1110 		return status;
1111 
1112 	// prepare the message
1113 	status_t error = link.StartMessage(AS_ACTIVATE_APP);
1114 	if (error != B_OK)
1115 		return error;
1116 
1117 	error = link.Attach(link.ReceiverPort());
1118 	if (error != B_OK)
1119 		return error;
1120 
1121 	error = link.Attach(team);
1122 	if (error != B_OK)
1123 		return error;
1124 
1125 	// send it
1126 	status_t code;
1127 	error = link.FlushWithReply(code);
1128 	if (error != B_OK)
1129 		return error;
1130 
1131 	return code;
1132 }
1133 
1134 
1135 /*!	\brief Launches the application associated with the supplied MIME type.
1136 
1137 	The application to be started is searched the same way FindApp() does it.
1138 
1139 	\a initialMessage is a message to be sent to the application "on launch",
1140 	i.e. before ReadyToRun() is invoked on the BApplication object. The
1141 	caller retains ownership of the supplied BMessage. In case the method
1142 	fails with \c B_ALREADY_RUNNING the message is delivered to the already
1143 	running instance.
1144 
1145 	\param mimeType MIME type for which the application shall be launched.
1146 	\param initialMessage Optional message to be sent to the application
1147 		   "on launch". May be \c NULL.
1148 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1149 		   the team ID of the launched application.
1150 	\return
1151 	- \c B_OK: Everything went fine.
1152 	- \c B_BAD_VALUE: \c NULL \a mimeType
1153 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1154 	  with its supertype (if the supplied isn't a supertype itself) a
1155 	  preferred application is associated.
1156 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1157 	  its preferred application could not be found.
1158 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1159 	  application is in trash.
1160 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1161 	- \c B_ALREADY_RUNNING: The application's app flags specify
1162 	  \c B_SINGLE_LAUNCH or B_EXCLUSIVE_LAUNCH and the application (the very
1163 	  same (single) or at least one with the same signature (exclusive)) is
1164 	  already running.
1165 	- other error codes
1166 */
1167 status_t
1168 BRoster::Launch(const char* mimeType, BMessage* initialMessage,
1169 	team_id* appTeam) const
1170 {
1171 	if (mimeType == NULL)
1172 		return B_BAD_VALUE;
1173 
1174 	BList messageList;
1175 	if (initialMessage)
1176 		messageList.AddItem(initialMessage);
1177 
1178 	return _LaunchApp(mimeType, NULL, &messageList, 0, NULL, appTeam);
1179 }
1180 
1181 
1182 /*!	\brief Launches the application associated with the supplied MIME type.
1183 
1184 	The application to be started is searched the same way FindApp() does it.
1185 
1186 	\a messageList contains messages to be sent to the application
1187 	"on launch", i.e. before ReadyToRun() is invoked on the BApplication
1188 	object. The caller retains ownership of the supplied BList and the
1189 	contained BMessages. In case the method fails with \c B_ALREADY_RUNNING
1190 	the messages are delivered to the already running instance.
1191 
1192 	\param mimeType MIME type for which the application shall be launched.
1193 	\param messageList Optional list of messages to be sent to the application
1194 		   "on launch". May be \c NULL.
1195 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1196 		   the team ID of the launched application.
1197 	\return
1198 	- \c B_OK: Everything went fine.
1199 	- \c B_BAD_VALUE: \c NULL \a mimeType
1200 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1201 	  with its supertype (if the supplied isn't a supertype itself) a
1202 	  preferred application is associated.
1203 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1204 	  its preferred application could not be found.
1205 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1206 	  application is in trash.
1207 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1208 	- other error codes
1209 */
1210 status_t
1211 BRoster::Launch(const char* mimeType, BList* messageList,
1212 	team_id* appTeam) const
1213 {
1214 	if (mimeType == NULL)
1215 		return B_BAD_VALUE;
1216 
1217 	return _LaunchApp(mimeType, NULL, messageList, 0, NULL, appTeam);
1218 }
1219 
1220 
1221 /*!	\brief Launches the application associated with the supplied MIME type.
1222 
1223 	The application to be started is searched the same way FindApp() does it.
1224 
1225 	The supplied \a argc and \a args are (if containing at least one argument)
1226 	put into a \c B_ARGV_RECEIVED message and sent to the launched application
1227 	"on launch". The caller retains ownership of the supplied \a args.
1228 	In case the method fails with \c B_ALREADY_RUNNING the message is
1229 	delivered to the already running instance.
1230 
1231 	\param mimeType MIME type for which the application shall be launched.
1232 	\param argc Specifies the number of elements in \a args.
1233 	\param args An array of C-strings to be sent as B_ARGV_RECEIVED messaged
1234 		   to the launched application.
1235 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1236 		   the team ID of the launched application.
1237 	\return
1238 	- \c B_OK: Everything went fine.
1239 	- \c B_BAD_VALUE: \c NULL \a mimeType
1240 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1241 	  with its supertype (if the supplied isn't a supertype itself) a
1242 	  preferred application is associated.
1243 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1244 	  its preferred application could not be found.
1245 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1246 	  application is in trash.
1247 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1248 	- other error codes
1249 */
1250 status_t
1251 BRoster::Launch(const char* mimeType, int argc, char** args,
1252 	team_id* appTeam) const
1253 {
1254 	if (mimeType == NULL)
1255 		return B_BAD_VALUE;
1256 
1257 	return _LaunchApp(mimeType, NULL, NULL, argc, args, appTeam);
1258 }
1259 
1260 
1261 /*!	\brief Launches the application associated with the entry referred to by
1262 		   the supplied entry_ref.
1263 
1264 	The application to be started is searched the same way FindApp() does it.
1265 
1266 	If \a ref does refer to an application executable, that application is
1267 	launched. Otherwise the respective application is searched and launched,
1268 	and \a ref is sent to it in a \c B_REFS_RECEIVED message.
1269 
1270 	\a initialMessage is a message to be sent to the application "on launch",
1271 	i.e. before ReadyToRun() is invoked on the BApplication object. The
1272 	caller retains ownership of the supplied BMessage. In case the method
1273 	fails with \c B_ALREADY_RUNNING the message is delivered to the already
1274 	running instance. The same applies to the \c B_REFS_RECEIVED message.
1275 
1276 	\param ref entry_ref referring to the file for which an application shall
1277 		   be launched.
1278 	\param initialMessage Optional message to be sent to the application
1279 		   "on launch". May be \c NULL.
1280 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1281 		   the team ID of the launched application.
1282 	\return
1283 	- \c B_OK: Everything went fine.
1284 	- \c B_BAD_VALUE: \c NULL \a ref
1285 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1286 	  with its supertype (if the supplied isn't a supertype itself) a
1287 	  preferred application is associated.
1288 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1289 	  its preferred application could not be found.
1290 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1291 	  application is in trash.
1292 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1293 	- \c B_ALREADY_RUNNING: The application's app flags specify
1294 	  \c B_SINGLE_LAUNCH or B_EXCLUSIVE_LAUNCH and the application (the very
1295 	  same (single) or at least one with the same signature (exclusive)) is
1296 	  already running.
1297 	- other error codes
1298 */
1299 status_t
1300 BRoster::Launch(const entry_ref* ref, const BMessage* initialMessage,
1301 	team_id* appTeam) const
1302 {
1303 	if (ref == NULL)
1304 		return B_BAD_VALUE;
1305 
1306 	BList messageList;
1307 	if (initialMessage)
1308 		messageList.AddItem(const_cast<BMessage*>(initialMessage));
1309 
1310 	return _LaunchApp(NULL, ref, &messageList, 0, NULL, appTeam);
1311 }
1312 
1313 
1314 /*!	\brief Launches the application associated with the entry referred to by
1315 		   the supplied entry_ref.
1316 
1317 	The application to be started is searched the same way FindApp() does it.
1318 
1319 	If \a ref does refer to an application executable, that application is
1320 	launched. Otherwise the respective application is searched and launched,
1321 	and \a ref is sent to it in a \c B_REFS_RECEIVED message.
1322 
1323 	\a messageList contains messages to be sent to the application
1324 	"on launch", i.e. before ReadyToRun() is invoked on the BApplication
1325 	object. The caller retains ownership of the supplied BList and the
1326 	contained BMessages. In case the method fails with \c B_ALREADY_RUNNING
1327 	the messages are delivered to the already running instance. The same
1328 	applies to the \c B_REFS_RECEIVED message.
1329 
1330 	\param ref entry_ref referring to the file for which an application shall
1331 		   be launched.
1332 	\param messageList Optional list of messages to be sent to the application
1333 		   "on launch". May be \c NULL.
1334 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1335 		   the team ID of the launched application.
1336 	\return
1337 	- \c B_OK: Everything went fine.
1338 	- \c B_BAD_VALUE: \c NULL \a ref
1339 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1340 	  with its supertype (if the supplied isn't a supertype itself) a
1341 	  preferred application is associated.
1342 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1343 	  its preferred application could not be found.
1344 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1345 	  application is in trash.
1346 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1347 	- other error codes
1348 */
1349 status_t
1350 BRoster::Launch(const entry_ref* ref, const BList* messageList,
1351 	team_id* appTeam) const
1352 {
1353 	if (ref == NULL)
1354 		return B_BAD_VALUE;
1355 
1356 	return _LaunchApp(NULL, ref, messageList, 0, NULL, appTeam);
1357 }
1358 
1359 
1360 /*!	\brief Launches the application associated with the entry referred to by
1361 		   the supplied entry_ref.
1362 
1363 	The application to be started is searched the same way FindApp() does it.
1364 
1365 	If \a ref does refer to an application executable, that application is
1366 	launched. Otherwise the respective application is searched and launched,
1367 	and \a ref is sent to it in a \c B_REFS_RECEIVED message, unless other
1368 	arguments are passed via \a argc and \a args -- then the entry_ref is
1369 	converted into a path (C-string) and added to the argument vector.
1370 
1371 	The supplied \a argc and \a args are (if containing at least one argument)
1372 	put into a \c B_ARGV_RECEIVED message and sent to the launched application
1373 	"on launch". The caller retains ownership of the supplied \a args.
1374 	In case the method fails with \c B_ALREADY_RUNNING the message is
1375 	delivered to the already running instance. The same applies to the
1376 	\c B_REFS_RECEIVED message, if no arguments are supplied via \a argc and
1377 	\args.
1378 
1379 	\param ref entry_ref referring to the file for which an application shall
1380 		   be launched.
1381 	\param argc Specifies the number of elements in \a args.
1382 	\param args An array of C-strings to be sent as B_ARGV_RECEIVED messaged
1383 		   to the launched application.
1384 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1385 		   the team ID of the launched application.
1386 	\return
1387 	- \c B_OK: Everything went fine.
1388 	- \c B_BAD_VALUE: \c NULL \a ref
1389 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1390 	  with its supertype (if the supplied isn't a supertype itself) a
1391 	  preferred application is associated.
1392 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1393 	  its preferred application could not be found.
1394 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1395 	  application is in trash.
1396 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1397 	- other error codes
1398 */
1399 status_t
1400 BRoster::Launch(const entry_ref* ref, int argc, const char* const* args,
1401 	team_id* appTeam) const
1402 {
1403 	if (ref == NULL)
1404 		return B_BAD_VALUE;
1405 
1406 	return _LaunchApp(NULL, ref, NULL, argc, args, appTeam);
1407 }
1408 
1409 
1410 #if __GNUC__ == 2
1411 /*!	Just here for providing binary compatibility
1412 	(for example "Guido" needs this)
1413 */
1414 extern "C" status_t
1415 Launch__C7BRosterP9entry_refP8BMessagePl(BRoster* roster, entry_ref* ref,
1416 	BMessage* initialMessage)
1417 {
1418 	return roster->BRoster::Launch(ref, initialMessage, NULL);
1419 }
1420 #endif	// __GNUC__ == 2
1421 
1422 
1423 //	#pragma mark - Recent document and app support
1424 
1425 
1426 void
1427 BRoster::GetRecentDocuments(BMessage* refList, int32 maxCount,
1428 	const char* fileType, const char* appSig) const
1429 {
1430 	if (!refList)
1431 		return;
1432 
1433 	status_t err = maxCount > 0 ? B_OK : B_BAD_VALUE;
1434 
1435 	// Use the message we've been given for both request and reply
1436 	BMessage& msg = *refList;
1437 	BMessage& reply = *refList;
1438 	status_t result;
1439 
1440 	// Build and send the message, read the reply
1441 	if (!err) {
1442 		msg.what = B_REG_GET_RECENT_DOCUMENTS;
1443 		err = msg.AddInt32("max count", maxCount);
1444 	}
1445 	if (!err && fileType)
1446 		err = msg.AddString("file type", fileType);
1447 	if (!err && appSig)
1448 		err = msg.AddString("app sig", appSig);
1449 	fMessenger.SendMessage(&msg, &reply);
1450 	if (!err) {
1451 		err = reply.what == B_REG_RESULT
1452 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
1453 	}
1454 	if (!err)
1455 		err = reply.FindInt32("result", &result);
1456 	if (!err)
1457 		err = result;
1458 	// Clear the result if an error occured
1459 	if (err && refList)
1460 		refList->MakeEmpty();
1461 	// No return value, how sad :-(
1462 //	return err;
1463 }
1464 
1465 
1466 void
1467 BRoster::GetRecentDocuments(BMessage* refList, int32 maxCount,
1468 	const char* fileTypes[], int32 fileTypesCount, const char* appSig) const
1469 {
1470 	if (!refList)
1471 		return;
1472 
1473 	status_t err = maxCount > 0 ? B_OK : B_BAD_VALUE;
1474 
1475 	// Use the message we've been given for both request and reply
1476 	BMessage& msg = *refList;
1477 	BMessage& reply = *refList;
1478 	status_t result;
1479 
1480 	// Build and send the message, read the reply
1481 	if (!err) {
1482 		msg.what = B_REG_GET_RECENT_DOCUMENTS;
1483 		err = msg.AddInt32("max count", maxCount);
1484 	}
1485 	if (!err && fileTypes) {
1486 		for (int i = 0; i < fileTypesCount && !err; i++)
1487 			err = msg.AddString("file type", fileTypes[i]);
1488 	}
1489 	if (!err && appSig)
1490 		err = msg.AddString("app sig", appSig);
1491 	fMessenger.SendMessage(&msg, &reply);
1492 	if (!err) {
1493 		err = reply.what == B_REG_RESULT
1494 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
1495 	}
1496 	if (!err)
1497 		err = reply.FindInt32("result", &result);
1498 	if (!err)
1499 		err = result;
1500 	// Clear the result if an error occured
1501 	if (err && refList)
1502 		refList->MakeEmpty();
1503 	// No return value, how sad :-(
1504 //	return err;
1505 }
1506 
1507 
1508 void
1509 BRoster::GetRecentFolders(BMessage* refList, int32 maxCount,
1510 	const char* appSig) const
1511 {
1512 	if (!refList)
1513 		return;
1514 
1515 	status_t err = maxCount > 0 ? B_OK : B_BAD_VALUE;
1516 
1517 	// Use the message we've been given for both request and reply
1518 	BMessage& msg = *refList;
1519 	BMessage& reply = *refList;
1520 	status_t result;
1521 
1522 	// Build and send the message, read the reply
1523 	if (!err) {
1524 		msg.what = B_REG_GET_RECENT_FOLDERS;
1525 		err = msg.AddInt32("max count", maxCount);
1526 	}
1527 	if (!err && appSig)
1528 		err = msg.AddString("app sig", appSig);
1529 	fMessenger.SendMessage(&msg, &reply);
1530 	if (!err) {
1531 		err = reply.what == B_REG_RESULT
1532 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
1533 	}
1534 	if (!err)
1535 		err = reply.FindInt32("result", &result);
1536 	if (!err)
1537 		err = result;
1538 	// Clear the result if an error occured
1539 	if (err && refList)
1540 		refList->MakeEmpty();
1541 	// No return value, how sad :-(
1542 //	return err;
1543 }
1544 
1545 
1546 void
1547 BRoster::GetRecentApps(BMessage* refList, int32 maxCount) const
1548 {
1549 	if (!refList)
1550 		return;
1551 
1552 	status_t err = maxCount > 0 ? B_OK : B_BAD_VALUE;
1553 
1554 	// Use the message we've been given for both request and reply
1555 	BMessage& msg = *refList;
1556 	BMessage& reply = *refList;
1557 	status_t result;
1558 
1559 	// Build and send the message, read the reply
1560 	if (!err) {
1561 		msg.what = B_REG_GET_RECENT_APPS;
1562 		err = msg.AddInt32("max count", maxCount);
1563 	}
1564 	fMessenger.SendMessage(&msg, &reply);
1565 	if (!err) {
1566 		err = reply.what == B_REG_RESULT
1567 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
1568 	}
1569 	if (!err)
1570 		err = reply.FindInt32("result", &result);
1571 	if (!err)
1572 		err = result;
1573 	// Clear the result if an error occured
1574 	if (err && refList)
1575 		refList->MakeEmpty();
1576 	// No return value, how sad :-(
1577 //	return err;
1578 }
1579 
1580 
1581 void
1582 BRoster::AddToRecentDocuments(const entry_ref* doc, const char* appSig) const
1583 {
1584 	status_t err = doc ? B_OK : B_BAD_VALUE;
1585 
1586 	// Use the message we've been given for both request and reply
1587 	BMessage msg(B_REG_ADD_TO_RECENT_DOCUMENTS);
1588 	BMessage reply;
1589 	status_t result;
1590 	char* callingAppSig = NULL;
1591 
1592 	// If no signature is supplied, look up the signature of
1593 	// the calling app
1594 	if (!err && !appSig) {
1595 		app_info info;
1596 		err = GetRunningAppInfo(be_app->Team(), &info);
1597 		if (!err)
1598 			callingAppSig = info.signature;
1599 	}
1600 
1601 	// Build and send the message, read the reply
1602 	if (!err)
1603 		err = msg.AddRef("ref", doc);
1604 	if (!err)
1605 		err = msg.AddString("app sig", (appSig ? appSig : callingAppSig));
1606 	fMessenger.SendMessage(&msg, &reply);
1607 	if (!err) {
1608 		err = reply.what == B_REG_RESULT
1609 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
1610 	}
1611 	if (!err)
1612 		err = reply.FindInt32("result", &result);
1613 	if (!err)
1614 		err = result;
1615 	if (err)
1616 		DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error 0x%lx\n", err));
1617 }
1618 
1619 
1620 void
1621 BRoster::AddToRecentFolders(const entry_ref* folder, const char* appSig) const
1622 {
1623 	status_t err = folder ? B_OK : B_BAD_VALUE;
1624 
1625 	// Use the message we've been given for both request and reply
1626 	BMessage msg(B_REG_ADD_TO_RECENT_FOLDERS);
1627 	BMessage reply;
1628 	status_t result;
1629 	char* callingAppSig = NULL;
1630 
1631 	// If no signature is supplied, look up the signature of
1632 	// the calling app
1633 	if (!err && !appSig) {
1634 		app_info info;
1635 		err = GetRunningAppInfo(be_app->Team(), &info);
1636 		if (!err)
1637 			callingAppSig = info.signature;
1638 	}
1639 
1640 	// Build and send the message, read the reply
1641 	if (!err)
1642 		err = msg.AddRef("ref", folder);
1643 	if (!err)
1644 		err = msg.AddString("app sig", (appSig ? appSig : callingAppSig));
1645 	fMessenger.SendMessage(&msg, &reply);
1646 	if (!err) {
1647 		err = reply.what == B_REG_RESULT
1648 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
1649 	}
1650 	if (!err)
1651 		err = reply.FindInt32("result", &result);
1652 	if (!err)
1653 		err = result;
1654 	if (err)
1655 		DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error 0x%lx\n", err));
1656 }
1657 
1658 //	#pragma mark - Private or reserved
1659 
1660 
1661 /*!	\brief Shuts down the system.
1662 
1663 	When \c synchronous is \c true and the method succeeds, it doesn't return.
1664 
1665 	\param reboot If \c true, the system will be rebooted instead of being
1666 		   powered off.
1667 	\param confirm If \c true, the user will be asked to confirm to shut down
1668 		   the system.
1669 	\param synchronous If \c false, the method will return as soon as the
1670 		   shutdown process has been initiated successfully (or an error
1671 		   occurred). Otherwise the method doesn't return, if successfully.
1672 	\return
1673 	- \c B_SHUTTING_DOWN, when there's already a shutdown process in
1674 	  progress,
1675 	- \c B_SHUTDOWN_CANCELLED, when the user cancelled the shutdown process,
1676 	- another error code in case something went wrong.
1677 */
1678 status_t
1679 BRoster::_ShutDown(bool reboot, bool confirm, bool synchronous)
1680 {
1681 	status_t error = B_OK;
1682 
1683 	// compose the request message
1684 	BMessage request(B_REG_SHUT_DOWN);
1685 	if (error == B_OK)
1686 		error = request.AddBool("reboot", reboot);
1687 	if (error == B_OK)
1688 		error = request.AddBool("confirm", confirm);
1689 	if (error == B_OK)
1690 		error = request.AddBool("synchronous", synchronous);
1691 
1692 	// send the request
1693 	BMessage reply;
1694 	if (error == B_OK)
1695 		error = fMessenger.SendMessage(&request, &reply);
1696 
1697 	// evaluate the reply
1698 	if (error == B_OK && reply.what != B_REG_SUCCESS
1699 		&& reply.FindInt32("error", &error) != B_OK)
1700 		error = B_ERROR;
1701 
1702 	return error;
1703 }
1704 
1705 
1706 /*!	\brief (Pre-)Registers an application with the registrar.
1707 
1708 	This methods is invoked either to register or to pre-register an
1709 	application. Full registration is requested by supplying \c true via
1710 	\a fullReg.
1711 
1712 	A full registration requires \a mimeSig, \a ref, \a flags, \a team,
1713 	\a thread and \a port to contain valid values. No token will be return
1714 	via \a pToken.
1715 
1716 	For a pre-registration \a mimeSig, \a ref, \a flags must be valid.
1717 	\a team and \a thread are optional and should be set to -1, if they are
1718 	unknown. If no team ID is supplied, \a pToken should be valid and, if the
1719 	the pre-registration succeeds, will be filled with a unique token assigned
1720 	by the roster.
1721 
1722 	In both cases the registration may fail, if single/exclusive launch is
1723 	requested and an instance of the application is already running. Then
1724 	\c B_ALREADY_RUNNING is returned and the team ID of the running instance
1725 	is passed back via \a otherTeam, if supplied.
1726 
1727 	\param mimeSig The app's signature
1728 	\param ref An entry_ref referring to the app's executable
1729 	\param flags The app flags
1730 	\param team The app's team ID
1731 	\param thread The app's main thread
1732 	\param port The app looper port
1733 	\param fullReg \c true for full, \c false for pre-registration
1734 	\param pToken A pointer to a pre-allocated uint32 into which the token
1735 		   assigned by the registrar is written (may be \c NULL)
1736 	\param otherTeam A pointer to a pre-allocated team_id into which the
1737 		   team ID of the already running instance of a single/exclusive
1738 		   launch application is written (may be \c NULL)
1739 	\return
1740 	- \c B_OK: Everything went fine.
1741 	- \c B_ENTRY_NOT_FOUND: \a ref doesn't refer to a file.
1742 	- \c B_ALREADY_RUNNING: The application requests single/exclusive launch
1743 	  and an instance is already running.
1744 	- \c B_REG_ALREADY_REGISTERED: An application with the team ID \a team
1745 	  is already registered.
1746 */
1747 status_t
1748 BRoster::_AddApplication(const char* mimeSig, const entry_ref* ref,
1749 	uint32 flags, team_id team, thread_id thread, port_id port, bool fullReg,
1750 	uint32* pToken, team_id* otherTeam) const
1751 {
1752 	status_t error = B_OK;
1753 	// compose the request message
1754 	BMessage request(B_REG_ADD_APP);
1755 	if (error == B_OK && mimeSig)
1756 		error = request.AddString("signature", mimeSig);
1757 	if (error == B_OK && ref)
1758 		error = request.AddRef("ref", ref);
1759 	if (error == B_OK)
1760 		error = request.AddInt32("flags", (int32)flags);
1761 	if (error == B_OK && team >= 0)
1762 		error = request.AddInt32("team", team);
1763 	if (error == B_OK && thread >= 0)
1764 		error = request.AddInt32("thread", thread);
1765 	if (error == B_OK && port >= 0)
1766 		error = request.AddInt32("port", port);
1767 	if (error == B_OK)
1768 		error = request.AddBool("full_registration", fullReg);
1769 
1770 	// send the request
1771 	BMessage reply;
1772 	if (error == B_OK)
1773 		error = fMessenger.SendMessage(&request, &reply);
1774 
1775 	// evaluate the reply
1776 	if (error == B_OK) {
1777 		if (reply.what == B_REG_SUCCESS) {
1778 			if (!fullReg && team < 0) {
1779 				uint32 token;
1780 				if (reply.FindInt32("token", (int32*)&token) == B_OK) {
1781 					if (pToken)
1782 						*pToken = token;
1783 				} else
1784 					error = B_ERROR;
1785 			}
1786 		} else {
1787 			if (reply.FindInt32("error", &error) != B_OK)
1788 				error = B_ERROR;
1789 			// get team and token from the reply
1790 			if (otherTeam && reply.FindInt32("other_team", otherTeam) != B_OK)
1791 				*otherTeam = -1;
1792 			if (pToken && reply.FindInt32("token", (int32*)pToken) != B_OK)
1793 				*pToken = 0;
1794 		}
1795 	}
1796 	return error;
1797 }
1798 
1799 
1800 /*!	\brief Sets an application's signature.
1801 
1802 	The application must be registered or at pre-registered with a valid
1803 	team ID.
1804 
1805 	\param team The app's team ID.
1806 	\param mimeSig The app's new signature.
1807 	\return
1808 	- \c B_OK: Everything went fine.
1809 	- \c B_REG_APP_NOT_REGISTERED: The supplied team ID does not identify a
1810 	  registered application.
1811 */
1812 status_t
1813 BRoster::_SetSignature(team_id team, const char* mimeSig) const
1814 {
1815 	status_t error = B_OK;
1816 	// compose the request message
1817 	BMessage request(B_REG_SET_SIGNATURE);
1818 	if (error == B_OK && team >= 0)
1819 		error = request.AddInt32("team", team);
1820 	if (error == B_OK && mimeSig)
1821 		error = request.AddString("signature", mimeSig);
1822 
1823 	// send the request
1824 	BMessage reply;
1825 	if (error == B_OK)
1826 		error = fMessenger.SendMessage(&request, &reply);
1827 
1828 	// evaluate the reply
1829 	if (error == B_OK && reply.what != B_REG_SUCCESS
1830 		&& reply.FindInt32("error", &error) != B_OK)
1831 		error = B_ERROR;
1832 
1833 	return error;
1834 }
1835 
1836 
1837 /*!	\todo Really needed?
1838 */
1839 void
1840 BRoster::_SetThread(team_id team, thread_id thread) const
1841 {
1842 }
1843 
1844 
1845 /*!	\brief Sets the team and thread IDs of a pre-registered application.
1846 
1847 	After an application has been pre-registered via AddApplication(), without
1848 	supplying a team ID, the team and thread IDs have to be set using this
1849 	method.
1850 
1851 	\param entryToken The token identifying the application (returned by
1852 		   AddApplication())
1853 	\param thread The app's thread ID
1854 	\param team The app's team ID
1855 	\return
1856 	- \c B_OK: Everything went fine.
1857 	- \c B_REG_APP_NOT_PRE_REGISTERED: The supplied token does not identify a
1858 	  pre-registered application.
1859 */
1860 status_t
1861 BRoster::_SetThreadAndTeam(uint32 entryToken, thread_id thread,
1862 	team_id team) const
1863 {
1864 	status_t error = B_OK;
1865 	// compose the request message
1866 	BMessage request(B_REG_SET_THREAD_AND_TEAM);
1867 	if (error == B_OK)
1868 		error = request.AddInt32("token", (int32)entryToken);
1869 	if (error == B_OK && team >= 0)
1870 		error = request.AddInt32("team", team);
1871 	if (error == B_OK && thread >= 0)
1872 		error = request.AddInt32("thread", thread);
1873 
1874 	// send the request
1875 	BMessage reply;
1876 	if (error == B_OK)
1877 		error = fMessenger.SendMessage(&request, &reply);
1878 
1879 	// evaluate the reply
1880 	if (error == B_OK && reply.what != B_REG_SUCCESS
1881 		&& reply.FindInt32("error", &error) != B_OK)
1882 		error = B_ERROR;
1883 
1884 	return error;
1885 }
1886 
1887 
1888 /*!	\brief Completes the registration process for a pre-registered application.
1889 
1890 	After an application has been pre-registered via AddApplication() and
1891 	after assigning it a team ID (via SetThreadAndTeam()) the application is
1892 	still pre-registered and must complete the registration.
1893 
1894 	\param team The app's team ID
1895 	\param thread The app's thread ID
1896 	\param thread The app looper port
1897 	\return
1898 	- \c B_OK: Everything went fine.
1899 	- \c B_REG_APP_NOT_PRE_REGISTERED: \a team does not identify an existing
1900 	  application or the identified application is already fully registered.
1901 */
1902 status_t
1903 BRoster::_CompleteRegistration(team_id team, thread_id thread,
1904 	port_id port) const
1905 {
1906 	status_t error = B_OK;
1907 	// compose the request message
1908 	BMessage request(B_REG_COMPLETE_REGISTRATION);
1909 	if (error == B_OK && team >= 0)
1910 		error = request.AddInt32("team", team);
1911 	if (error == B_OK && thread >= 0)
1912 		error = request.AddInt32("thread", thread);
1913 	if (error == B_OK && port >= 0)
1914 		error = request.AddInt32("port", port);
1915 
1916 	// send the request
1917 	BMessage reply;
1918 	if (error == B_OK)
1919 		error = fMessenger.SendMessage(&request, &reply);
1920 
1921 	// evaluate the reply
1922 	if (error == B_OK && reply.what != B_REG_SUCCESS
1923 		&& reply.FindInt32("error", &error) != B_OK)
1924 		error = B_ERROR;
1925 
1926 	return error;
1927 }
1928 
1929 
1930 /*!	\brief Returns whether an application is registered.
1931 
1932 	If the application is indeed pre-registered and \a info is not \c NULL,
1933 	the methods fills in the app_info structure pointed to by \a info.
1934 
1935 	\param ref An entry_ref referring to the app's executable
1936 	\param team The app's team ID. May be -1, if \a token is given.
1937 	\param token The app's pre-registration token. May be 0, if \a team is
1938 				 given.
1939 	\param preRegistered: Pointer to a pre-allocated bool to be filled in
1940 		   by this method, indicating whether or not the app was
1941 		   pre-registered.
1942 	\param info A pointer to a pre-allocated app_info structure to be filled
1943 		   in by this method (may be \c NULL)
1944 	\return
1945 		- \c B_OK, if the application is registered and all requested
1946 		  information could be retrieved,
1947 		- another error code, if the app is not registered or an error occurred.
1948 */
1949 status_t
1950 BRoster::_IsAppRegistered(const entry_ref* ref, team_id team,
1951 	uint32 token, bool* preRegistered, app_info* info) const
1952 {
1953 	status_t error = B_OK;
1954 
1955 	// compose the request message
1956 	BMessage request(B_REG_IS_APP_REGISTERED);
1957 	if (error == B_OK && ref)
1958 		error = request.AddRef("ref", ref);
1959 	if (error == B_OK && team >= 0)
1960 		error = request.AddInt32("team", team);
1961 	if (error == B_OK && token > 0)
1962 		error = request.AddInt32("token", (int32)token);
1963 
1964 	// send the request
1965 	BMessage reply;
1966 	if (error == B_OK)
1967 		error = fMessenger.SendMessage(&request, &reply);
1968 
1969 	// evaluate the reply
1970 	bool isRegistered = false;
1971 	bool isPreRegistered = false;
1972 	if (error == B_OK) {
1973 		if (reply.what == B_REG_SUCCESS) {
1974 			if (reply.FindBool("registered", &isRegistered) != B_OK
1975 				|| !isRegistered
1976 				|| reply.FindBool("pre-registered", &isPreRegistered) != B_OK) {
1977 				error = B_ERROR;
1978 			}
1979 
1980 			if (error == B_OK && preRegistered)
1981 				*preRegistered = isPreRegistered;
1982 			if (error == B_OK && info)
1983 				error = find_message_app_info(&reply, info);
1984 		} else if (reply.FindInt32("error", &error) != B_OK)
1985 			error = B_ERROR;
1986 	}
1987 
1988 	return error;
1989 }
1990 
1991 
1992 /*!	\brief Completely unregisters a pre-registered application.
1993 
1994 	This method can only be used to unregister applications that don't have
1995 	a team ID assigned yet. All other applications must be unregistered via
1996 	RemoveApp().
1997 
1998 	\param entryToken The token identifying the application (returned by
1999 		   AddApplication())
2000 	\return
2001 	- \c B_OK: Everything went fine.
2002 	- \c B_REG_APP_NOT_PRE_REGISTERED: The supplied token does not identify a
2003 	  pre-registered application.
2004 */
2005 status_t
2006 BRoster::_RemovePreRegApp(uint32 entryToken) const
2007 {
2008 	status_t error = B_OK;
2009 	// compose the request message
2010 	BMessage request(B_REG_REMOVE_PRE_REGISTERED_APP);
2011 	if (error == B_OK)
2012 		error = request.AddInt32("token", (int32)entryToken);
2013 
2014 	// send the request
2015 	BMessage reply;
2016 	if (error == B_OK)
2017 		error = fMessenger.SendMessage(&request, &reply);
2018 
2019 	// evaluate the reply
2020 	if (error == B_OK && reply.what != B_REG_SUCCESS
2021 		&& reply.FindInt32("error", &error) != B_OK)
2022 		error = B_ERROR;
2023 
2024 	return error;
2025 }
2026 
2027 
2028 /*!	\brief Unregisters a (pre-)registered application.
2029 
2030 	This method must be used to unregister applications that already have
2031 	a team ID assigned, i.e. also for pre-registered application for which
2032 	SetThreadAndTeam() has already been invoked.
2033 
2034 	\param team The app's team ID
2035 	\return
2036 	- \c B_OK: Everything went fine.
2037 	- \c B_REG_APP_NOT_REGISTERED: The supplied team ID does not identify a
2038 	  (pre-)registered application.
2039 */
2040 status_t
2041 BRoster::_RemoveApp(team_id team) const
2042 {
2043 	status_t error = B_OK;
2044 	// compose the request message
2045 	BMessage request(B_REG_REMOVE_APP);
2046 	if (error == B_OK && team >= 0)
2047 		error = request.AddInt32("team", team);
2048 
2049 	// send the request
2050 	BMessage reply;
2051 	if (error == B_OK)
2052 		error = fMessenger.SendMessage(&request, &reply);
2053 
2054 	// evaluate the reply
2055 	if (error == B_OK && reply.what != B_REG_SUCCESS
2056 		&& reply.FindInt32("error", &error) != B_OK)
2057 		error = B_ERROR;
2058 
2059 	return error;
2060 }
2061 
2062 
2063 void
2064 BRoster::_ApplicationCrashed(team_id team)
2065 {
2066 	BPrivate::DesktopLink link;
2067 	if (link.InitCheck() != B_OK)
2068 		return;
2069 
2070 	if (link.StartMessage(AS_APP_CRASHED) == B_OK
2071 		&& link.Attach(team) == B_OK)
2072 		link.Flush();
2073 }
2074 
2075 
2076 /*!	Tells the registrar which application is currently active.
2077 	It's called from within the app_server when the active application is
2078 	changed.
2079 	As it's called in the event loop, it must run asynchronously and cannot
2080 	wait for a reply.
2081 */
2082 status_t
2083 BRoster::_UpdateActiveApp(team_id team) const
2084 {
2085 	if (team < B_OK)
2086 		return B_BAD_TEAM_ID;
2087 
2088 	// compose the request message
2089 	BMessage request(B_REG_UPDATE_ACTIVE_APP);
2090 	status_t status = request.AddInt32("team", team);
2091 	if (status < B_OK)
2092 		return status;
2093 
2094 	// send the request
2095 	return fMessenger.SendMessage(&request);
2096 }
2097 
2098 
2099 /*!	\brief Launches the application associated with the supplied MIME type or
2100 		   the entry referred to by the supplied entry_ref.
2101 
2102 	The application to be started is searched the same way FindApp() does it.
2103 
2104 	At least one of \a mimeType or \a ref must not be \c NULL. If \a mimeType
2105 	is supplied, \a ref is ignored for finding the application.
2106 
2107 	If \a ref does refer to an application executable, that application is
2108 	launched. Otherwise the respective application is searched and launched,
2109 	and \a ref is sent to it in a \c B_REFS_RECEIVED message, unless other
2110 	arguments are passed via \a argc and \a args -- then the entry_ref is
2111 	converted into a path (C-string) and added to the argument vector.
2112 
2113 	\a messageList contains messages to be sent to the application
2114 	"on launch", i.e. before ReadyToRun() is invoked on the BApplication
2115 	object. The caller retains ownership of the supplied BList and the
2116 	contained BMessages. In case the method fails with \c B_ALREADY_RUNNING
2117 	the messages are delivered to the already running instance. The same
2118 	applies to the \c B_REFS_RECEIVED message.
2119 
2120 	The supplied \a argc and \a args are (if containing at least one argument)
2121 	put into a \c B_ARGV_RECEIVED message and sent to the launched application
2122 	"on launch". The caller retains ownership of the supplied \a args.
2123 	In case the method fails with \c B_ALREADY_RUNNING the message is
2124 	delivered to the already running instance. The same applies to the
2125 	\c B_REFS_RECEIVED message, if no arguments are supplied via \a argc and
2126 	\args.
2127 
2128 	\param mimeType MIME type for which the application shall be launched.
2129 		   May be \c NULL.
2130 	\param ref entry_ref referring to the file for which an application shall
2131 		   be launched. May be \c NULL.
2132 	\param messageList Optional list of messages to be sent to the application
2133 		   "on launch". May be \c NULL.
2134 	\param argc Specifies the number of elements in \a args.
2135 	\param args An array of C-strings to be sent as B_ARGV_RECEIVED messaged
2136 		   to the launched application.
2137 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
2138 		   the team ID of the launched application.
2139 	\return
2140 	- \c B_OK: Everything went fine.
2141 	- \c B_BAD_VALUE: \c NULL \a mimeType and \a ref.
2142 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
2143 	  with its supertype (if the supplied isn't a supertype itself) a
2144 	  preferred application is associated.
2145 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
2146 	  its preferred application could not be found.
2147 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
2148 	  application is in trash.
2149 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
2150 	- other error codes
2151 */
2152 status_t
2153 BRoster::_LaunchApp(const char* mimeType, const entry_ref* ref,
2154 	const BList* messageList, int argc,
2155 	const char* const* args, team_id* _appTeam) const
2156 {
2157 	DBG(OUT("BRoster::_LaunchApp()"));
2158 
2159 	if (_appTeam != NULL) {
2160 		// we're supposed to set _appTeam to -1 on error; we'll
2161 		// reset it later if everything goes well
2162 		*_appTeam = -1;
2163 	}
2164 
2165 	if (mimeType == NULL && ref == NULL)
2166 		return B_BAD_VALUE;
2167 
2168 	// use a mutable copy of the document entry_ref
2169 	entry_ref _docRef;
2170 	entry_ref* docRef = NULL;
2171 	if (ref != NULL) {
2172 		_docRef = *ref;
2173 		docRef = &_docRef;
2174 	}
2175 
2176 	uint32 otherAppFlags = B_REG_DEFAULT_APP_FLAGS;
2177 	uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
2178 	bool alreadyRunning = false;
2179 	bool wasDocument = true;
2180 	status_t error = B_OK;
2181 	ArgVector argVector;
2182 	team_id team = -1;
2183 
2184 	do {
2185 		// find the app
2186 		entry_ref appRef;
2187 		char signature[B_MIME_TYPE_LENGTH];
2188 		error = _ResolveApp(mimeType, docRef, &appRef, signature,
2189 			&appFlags, &wasDocument);
2190 		DBG(OUT("  find app: %s (%lx)\n", strerror(error), error));
2191 		if (error != B_OK)
2192 			return error;
2193 
2194 		// build an argument vector
2195 		error = argVector.Init(argc, args, &appRef,
2196 			wasDocument ? docRef : NULL);
2197 		DBG(OUT("  build argv: %s (%lx)\n", strerror(error), error));
2198 		if (error != B_OK)
2199 			return error;
2200 
2201 		// pre-register the app (but ignore scipts)
2202 		uint32 appToken = 0;
2203 		app_info appInfo;
2204 		bool isScript = wasDocument && docRef != NULL && *docRef == appRef;
2205 		if (!isScript) {
2206 			error = _AddApplication(signature, &appRef, appFlags, -1, -1, -1, false,
2207 				&appToken, &team);
2208 			if (error == B_ALREADY_RUNNING) {
2209 				DBG(OUT("  already running\n"));
2210 				alreadyRunning = true;
2211 
2212 				// get the app flags for the running application
2213 				error = _IsAppRegistered(&appRef, team, appToken, NULL, &appInfo);
2214 				if (error == B_OK) {
2215 					otherAppFlags = appInfo.flags;
2216 					team = appInfo.team;
2217 				}
2218 			}
2219 			DBG(OUT("  pre-register: %s (%lx)\n", strerror(error), error));
2220 		}
2221 
2222 		// launch the app
2223 		if (error == B_OK && !alreadyRunning) {
2224 			DBG(OUT("  token: %lu\n", appToken));
2225 			// load the app image
2226 			thread_id appThread = load_image(argVector.Count(),
2227 				const_cast<const char**>(argVector.Args()),
2228 				const_cast<const char**>(environ));
2229 
2230 			// get the app team
2231 			if (appThread >= 0) {
2232 				thread_info threadInfo;
2233 				error = get_thread_info(appThread, &threadInfo);
2234 				if (error == B_OK)
2235 					team = threadInfo.team;
2236 			} else if (wasDocument && appThread == B_NOT_AN_EXECUTABLE)
2237 				error = B_LAUNCH_FAILED_EXECUTABLE;
2238 			else
2239 				error = appThread;
2240 
2241 			DBG(OUT("  load image: %s (%lx)\n", strerror(error), error));
2242 			// finish the registration
2243 			if (error == B_OK && !isScript)
2244 				error = _SetThreadAndTeam(appToken, appThread, team);
2245 
2246 			DBG(OUT("  set thread and team: %s (%lx)\n", strerror(error), error));
2247 			// resume the launched team
2248 			if (error == B_OK)
2249 				error = resume_thread(appThread);
2250 
2251 			DBG(OUT("  resume thread: %s (%lx)\n", strerror(error), error));
2252 			// on error: kill the launched team and unregister the app
2253 			if (error != B_OK) {
2254 				if (appThread >= 0)
2255 					kill_thread(appThread);
2256 				if (!isScript) {
2257 					_RemovePreRegApp(appToken);
2258 
2259 					if (!wasDocument) {
2260 						// Remove app hint if it's this one
2261 						BMimeType appType(signature);
2262 						entry_ref hintRef;
2263 
2264 						if (appType.InitCheck() == B_OK
2265 							&& appType.GetAppHint(&hintRef) == B_OK
2266 							&& appRef == hintRef) {
2267 							appType.SetAppHint(NULL);
2268 							// try again
2269 							continue;
2270 						}
2271 					}
2272 				}
2273 			}
2274 		}
2275 	} while (false);
2276 
2277 	if (alreadyRunning && current_team() == team) {
2278 		// The target team is calling us, so we don't send it the message
2279 		// to prevent an endless loop
2280 		error = B_BAD_VALUE;
2281 	}
2282 
2283 	// send "on launch" messages
2284 	if (error == B_OK) {
2285 		// If the target app is B_ARGV_ONLY, only if it is newly launched
2286 		// messages are sent to it (namely B_ARGV_RECEIVED and B_READY_TO_RUN).
2287 		// An already running B_ARGV_ONLY app won't get any messages.
2288 		bool argvOnly = (appFlags & B_ARGV_ONLY)
2289 			|| (alreadyRunning && (otherAppFlags & B_ARGV_ONLY));
2290 		const BList* _messageList = (argvOnly ? NULL : messageList);
2291 		// don't send ref, if it refers to the app or is included in the
2292 		// argument vector
2293 		const entry_ref* _ref = argvOnly || !wasDocument
2294 			|| argVector.Count() > 1 ? NULL : docRef;
2295 		if (!(argvOnly && alreadyRunning)) {
2296 			_SendToRunning(team, argVector.Count(), argVector.Args(),
2297 				_messageList, _ref, alreadyRunning);
2298 		}
2299 	}
2300 
2301 	// set return values
2302 	if (error == B_OK) {
2303 		if (alreadyRunning)
2304 			error = B_ALREADY_RUNNING;
2305 		else if (_appTeam)
2306 			*_appTeam = team;
2307 	}
2308 
2309 	DBG(OUT("BRoster::_LaunchApp() done: %s (%lx)\n",
2310 		strerror(error), error));
2311 	return error;
2312 }
2313 
2314 
2315 void
2316 BRoster::_SetAppFlags(team_id team, uint32 flags) const
2317 {
2318 }
2319 
2320 
2321 void
2322 BRoster::_DumpRoster() const
2323 {
2324 }
2325 
2326 
2327 /*!	\brief Finds an application associated with a MIME type or a file.
2328 
2329 	It does also supply the caller with some more information about the
2330 	application, like signature, app flags and whether the supplied
2331 	MIME type/entry_ref already identified an application.
2332 
2333 	At least one of \a inType or \a ref must not be \c NULL. If \a inType is
2334 	supplied, \a ref is ignored.
2335 
2336 	If \a ref refers to a link, it is updated with the entry_ref for the
2337 	resolved entry.
2338 
2339 	\see FindApp() for how the application is searched.
2340 
2341 	\a appSig is set to a string with length 0, if the found application
2342 	has no signature.
2343 
2344 	\param inType The MIME type for which an application shall be found.
2345 		   May be \c NULL.
2346 	\param ref The file for which an application shall be found.
2347 		   May be \c NULL.
2348 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2349 		   a reference to the found application's executable. May be \c NULL.
2350 	\param appSig A pointer to a pre-allocated char buffer of at least size
2351 		   \c B_MIME_TYPE_LENGTH to be filled with the signature of the found
2352 		   application. May be \c NULL.
2353 	\param appFlags A pointer to a pre-allocated uint32 variable to be filled
2354 		   with the app flags of the found application. May be \c NULL.
2355 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2356 		   \c true, if the supplied file was not identifying an application,
2357 		   to \c false otherwise. Has no meaning, if a \a inType is supplied.
2358 		   May be \c NULL.
2359 	\return
2360 	- \c B_OK: Everything went fine.
2361 	- \c B_BAD_VALUE: \c NULL \a inType and \a ref.
2362 	- \see FindApp() for other error codes.
2363 */
2364 status_t
2365 BRoster::_ResolveApp(const char* inType, entry_ref* ref,
2366 	entry_ref* _appRef, char* _appSig, uint32* _appFlags,
2367 	bool* _wasDocument) const
2368 {
2369 	if ((inType == NULL && ref == NULL)
2370 		|| (inType != NULL && strlen(inType) >= B_MIME_TYPE_LENGTH))
2371 		return B_BAD_VALUE;
2372 
2373 	// find the app
2374 	BMimeType appMeta;
2375 	BFile appFile;
2376 	entry_ref appRef;
2377 	status_t error;
2378 
2379 	if (inType != NULL) {
2380 		error = _TranslateType(inType, &appMeta, &appRef, &appFile);
2381 		if (_wasDocument != NULL)
2382 			*_wasDocument = !(appMeta == inType);
2383 	} else {
2384 		error = _TranslateRef(ref, &appMeta, &appRef, &appFile,
2385 			_wasDocument);
2386 	}
2387 
2388 	// create meta mime
2389 	if (error == B_OK) {
2390 		BPath path;
2391 		if (path.SetTo(&appRef) == B_OK)
2392 			create_app_meta_mime(path.Path(), false, true, false);
2393 	}
2394 
2395 	// set the app hint on the type -- but only if the file has the
2396 	// respective signature, otherwise unset the app hint
2397 	BAppFileInfo appFileInfo;
2398 	if (error == B_OK) {
2399 		char signature[B_MIME_TYPE_LENGTH];
2400 		if (appFileInfo.SetTo(&appFile) == B_OK
2401 			&& appFileInfo.GetSignature(signature) == B_OK) {
2402 			if (!strcasecmp(appMeta.Type(), signature)) {
2403 				// Only set the app hint if there is none yet
2404 				entry_ref dummyRef;
2405 				if (appMeta.GetAppHint(&dummyRef) != B_OK)
2406 					appMeta.SetAppHint(&appRef);
2407 			} else {
2408 				appMeta.SetAppHint(NULL);
2409 				appMeta.SetTo(signature);
2410 			}
2411 		} else
2412 			appMeta.SetAppHint(NULL);
2413 	}
2414 
2415 	// set the return values
2416 	if (error == B_OK) {
2417 		if (_appRef)
2418 			*_appRef = appRef;
2419 
2420 		if (_appSig) {
2421 			// there's no warranty, that appMeta is valid
2422 			if (appMeta.IsValid())
2423 				strlcpy(_appSig, appMeta.Type(), B_MIME_TYPE_LENGTH);
2424 			else
2425 				_appSig[0] = '\0';
2426 		}
2427 
2428 		if (_appFlags) {
2429 			// if an error occurs here, we don't care and just set a default
2430 			// value
2431 			if (appFileInfo.InitCheck() != B_OK
2432 				|| appFileInfo.GetAppFlags(_appFlags) != B_OK) {
2433 				*_appFlags = B_REG_DEFAULT_APP_FLAGS;
2434 			}
2435 		}
2436 	} else {
2437 		// unset the ref on error
2438 		if (_appRef)
2439 			*_appRef = appRef;
2440 	}
2441 
2442 	return error;
2443 }
2444 
2445 
2446 /*!	\brief Finds an application associated with a file.
2447 
2448 	\a appMeta is left unmodified, if the file is executable, but has no
2449 	signature.
2450 
2451 	\see FindApp() for how the application is searched.
2452 
2453 	If \a ref refers to a link, it is updated with the entry_ref for the
2454 	resolved entry.
2455 
2456 	\param ref The file for which an application shall be found.
2457 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2458 		   signature of the found application.
2459 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2460 		   a reference to the found application's executable.
2461 	\param appFile A pointer to a pre-allocated BFile to be set to the
2462 		   executable of the found application.
2463 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2464 		   \c true, if the supplied file was not identifying an application,
2465 		   to \c false otherwise. May be \c NULL.
2466 	\return
2467 	- \c B_OK: Everything went fine.
2468 	- \c B_BAD_VALUE: \c NULL \a ref, \a appMeta, \a appRef or \a appFile.
2469 	- \see FindApp() for other error codes.
2470 */
2471 status_t
2472 BRoster::_TranslateRef(entry_ref* ref, BMimeType* appMeta,
2473 	entry_ref* appRef, BFile* appFile, bool* _wasDocument) const
2474 {
2475 	if (ref == NULL || appMeta == NULL || appRef == NULL || appFile == NULL)
2476 		return B_BAD_VALUE;
2477 
2478 	// resolve ref, if necessary
2479 	BEntry entry;
2480 	status_t error = entry.SetTo(ref, false);
2481 	if (error != B_OK)
2482 		return error;
2483 
2484 	if (entry.IsSymLink()) {
2485 		// ref refers to a link
2486 		if (entry.SetTo(ref, true) != B_OK || entry.GetRef(ref) != B_OK)
2487 			return B_LAUNCH_FAILED_NO_RESOLVE_LINK;
2488 	}
2489 
2490 	// init node
2491 	BNode node;
2492 	error = node.SetTo(ref);
2493 	if (error != B_OK)
2494 		return error;
2495 
2496 	// get permissions
2497 	mode_t permissions;
2498 	error = node.GetPermissions(&permissions);
2499 	if (error != B_OK)
2500 		return error;
2501 
2502 	if ((permissions & S_IXUSR) && node.IsFile()) {
2503 		// node is executable and a file
2504 		error = appFile->SetTo(ref, B_READ_ONLY);
2505 		if (error != B_OK)
2506 			return error;
2507 
2508 		// get the app's signature via a BAppFileInfo
2509 		BAppFileInfo appFileInfo;
2510 		error = appFileInfo.SetTo(appFile);
2511 		if (error != B_OK)
2512 			return error;
2513 
2514 		// don't worry, if the file doesn't have a signature, just
2515 		// unset the supplied object
2516 		char type[B_MIME_TYPE_LENGTH];
2517 		if (appFileInfo.GetSignature(type) == B_OK) {
2518 			error = appMeta->SetTo(type);
2519 			if (error != B_OK)
2520 				return error;
2521 		} else
2522 			appMeta->Unset();
2523 
2524 		// If the file type indicates that the file is an application, we've
2525 		// definitely got what we're looking for.
2526 		bool isDocument = true;
2527 		if (_GetFileType(ref, &appFileInfo, type) == B_OK
2528 			&& strcasecmp(type, B_APP_MIME_TYPE) == 0) {
2529 			isDocument = false;
2530 		}
2531 
2532 		// If our file is not an application executable, we probably have a
2533 		// script. Check whether the file has a preferred application set. If
2534 		// so, we fall through and use the preferred app instead. Otherwise
2535 		// we're done.
2536 		char preferredApp[B_MIME_TYPE_LENGTH];
2537 		if (!isDocument || appFileInfo.GetPreferredApp(preferredApp) != B_OK) {
2538 			*appRef = *ref;
2539 			if (_wasDocument)
2540 				*_wasDocument = isDocument;
2541 			return B_OK;
2542 		}
2543 
2544 		// Executable file, but not an application, and it has a preferred
2545 		// application set. Fall through...
2546 	}
2547 
2548 	// the node is not exectuable or not a file
2549 	// init a node info
2550 	BNodeInfo nodeInfo;
2551 	error = nodeInfo.SetTo(&node);
2552 	if (error != B_OK)
2553 		return error;
2554 
2555 	// if the file has a preferred app, let _TranslateType() find
2556 	// it for us
2557 	char preferredApp[B_MIME_TYPE_LENGTH];
2558 	if (nodeInfo.GetPreferredApp(preferredApp) == B_OK
2559 		&& _TranslateType(preferredApp, appMeta, appRef, appFile) == B_OK) {
2560 		if (_wasDocument)
2561 			*_wasDocument = true;
2562 		return B_OK;
2563 	}
2564 
2565 	// no preferred app or existing one was not found -- we
2566 	// need to get the file's type
2567 
2568 	// get the type from the file
2569 	char fileType[B_MIME_TYPE_LENGTH];
2570 	error = _GetFileType(ref, &nodeInfo, fileType);
2571 	if (error != B_OK)
2572 		return error;
2573 
2574 	// now let _TranslateType() do the actual work
2575 	error = _TranslateType(fileType, appMeta, appRef, appFile);
2576 	if (error != B_OK)
2577 		return error;
2578 
2579 	if (_wasDocument)
2580 		*_wasDocument = true;
2581 
2582 	return B_OK;
2583 }
2584 
2585 
2586 /*!	\brief Finds an application associated with a MIME type.
2587 
2588 	\see FindApp() for how the application is searched.
2589 
2590 	\param mimeType The MIME type for which an application shall be found.
2591 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2592 		   signature of the found application.
2593 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2594 		   a reference to the found application's executable.
2595 	\param appFile A pointer to a pre-allocated BFile to be set to the
2596 		   executable of the found application.
2597 	\return
2598 	- \c B_OK: Everything went fine.
2599 	- \c B_BAD_VALUE: \c NULL \a mimeType, \a appMeta, \a appRef or \a appFile.
2600 	- \see FindApp() for other error codes.
2601 */
2602 status_t
2603 BRoster::_TranslateType(const char* mimeType, BMimeType* appMeta,
2604 	entry_ref* appRef, BFile* appFile) const
2605 {
2606 	if (mimeType == NULL || appMeta == NULL || appRef == NULL
2607 		|| appFile == NULL || strlen(mimeType) >= B_MIME_TYPE_LENGTH)
2608 		return B_BAD_VALUE;
2609 
2610 	// Create a BMimeType and check, if the type is installed.
2611 	BMimeType type;
2612 	status_t error = type.SetTo(mimeType);
2613 
2614 	// Get the preferred apps from the sub and super type.
2615 	char primarySignature[B_MIME_TYPE_LENGTH];
2616 	char secondarySignature[B_MIME_TYPE_LENGTH];
2617 	primarySignature[0] = '\0';
2618 	secondarySignature[0] = '\0';
2619 
2620 	if (error == B_OK) {
2621 		BMimeType superType;
2622 		if (type.GetSupertype(&superType) == B_OK)
2623 			superType.GetPreferredApp(secondarySignature);
2624 		if (type.IsInstalled()) {
2625 			if (type.GetPreferredApp(primarySignature) != B_OK) {
2626 				// The type is installed, but has no preferred app.
2627 				primarySignature[0] = '\0';
2628 			} else if (!strcmp(primarySignature, secondarySignature)) {
2629 				// Both types have the same preferred app, there is
2630 				// no point in testing it twice.
2631 				secondarySignature[0] = '\0';
2632 			}
2633 		} else {
2634 			// The type is not installed. We assume it is an app signature.
2635 			strlcpy(primarySignature, mimeType, sizeof(primarySignature));
2636 		}
2637 	}
2638 
2639 	// We will use this BMessage "signatures" to hold all supporting apps
2640 	// so we can iterator over them in the preferred order. We include
2641 	// the supporting apps in such a way that the configured preferred
2642 	// applications for the MIME type are in front of other supporting
2643 	// applications for the sub and the super type respectively.
2644 	const char* kSigField = "applications";
2645 	BMessage signatures;
2646 	bool addedSecondarySignature = false;
2647 	if (error == B_OK) {
2648 		if (primarySignature[0] != '\0')
2649 			error = signatures.AddString(kSigField, primarySignature);
2650 		else {
2651 			// If there is a preferred app configured for the super type,
2652 			// but no preferred type for the sub-type, add the preferred
2653 			// super type handler in front of any other handlers. This way
2654 			// we fall-back to non-preferred but supporting apps only in the
2655 			// case when there is a preferred handler for the sub-type but
2656 			// it cannot be resolved (misconfiguration).
2657 			if (secondarySignature[0] != '\0') {
2658 				error = signatures.AddString(kSigField, secondarySignature);
2659 				addedSecondarySignature = true;
2660 			}
2661 		}
2662 	}
2663 
2664 	BMessage supportingSignatures;
2665 	if (error == B_OK
2666 		&& type.GetSupportingApps(&supportingSignatures) == B_OK) {
2667 		int32 subCount;
2668 		if (supportingSignatures.FindInt32("be:sub", &subCount) != B_OK)
2669 			subCount = 0;
2670 		// Add all signatures with direct support for the sub-type.
2671 		const char* supportingType;
2672 		if (!addedSecondarySignature) {
2673 			// Try to add the secondarySignature in front of all other
2674 			// supporting apps, if we find it among those.
2675 			for (int32 i = 0; error == B_OK && i < subCount
2676 					&& supportingSignatures.FindString(kSigField, i,
2677 						&supportingType) == B_OK; i++) {
2678 				if (strcmp(primarySignature, supportingType) != 0
2679 					&& strcmp(secondarySignature, supportingType) == 0) {
2680 					error = signatures.AddString(kSigField, supportingType);
2681 					addedSecondarySignature = true;
2682 					break;
2683 				}
2684 			}
2685 		}
2686 		for (int32 i = 0; error == B_OK && i < subCount
2687 				&& supportingSignatures.FindString(kSigField, i,
2688 					&supportingType) == B_OK; i++) {
2689 			if (strcmp(primarySignature, supportingType) != 0
2690 				&& strcmp(secondarySignature, supportingType) != 0) {
2691 				error = signatures.AddString(kSigField, supportingType);
2692 			}
2693 		}
2694 		// Add the preferred type of the super type here before adding
2695 		// the other types supporting the super type, but only if we have
2696 		// not already added it in case there was no preferred app for the
2697 		// sub-type configured.
2698 		if (error == B_OK && !addedSecondarySignature
2699 			&& secondarySignature[0] != '\0') {
2700 			error = signatures.AddString(kSigField, secondarySignature);
2701 		}
2702 		// Add all signatures with support for the super-type.
2703 		for (int32 i = subCount; error == B_OK
2704 				&& supportingSignatures.FindString(kSigField, i,
2705 					&supportingType) == B_OK; i++) {
2706 			// Don't add the signature if it's one of the preferred apps
2707 			// already.
2708 			if (strcmp(primarySignature, supportingType) != 0
2709 				&& strcmp(secondarySignature, supportingType) != 0) {
2710 				error = signatures.AddString(kSigField, supportingType);
2711 			}
2712 		}
2713 	} else {
2714 		// Failed to get supporting apps, just add the preferred apps.
2715 		if (error == B_OK && secondarySignature[0] != '\0')
2716 			error = signatures.AddString(kSigField, secondarySignature);
2717 	}
2718 
2719 	if (error != B_OK)
2720 		return error;
2721 
2722 	// Set an error in case we can't resolve a single supporting app.
2723 	error = B_LAUNCH_FAILED_NO_PREFERRED_APP;
2724 
2725 	// See if we can find a good application that is valid from the messege.
2726 	const char* signature;
2727 	for (int32 i = 0;
2728 		signatures.FindString(kSigField, i, &signature) == B_OK; i++) {
2729 		if (signature[0] == '\0')
2730 			continue;
2731 
2732 		error = appMeta->SetTo(signature);
2733 
2734 		// Check, whether the signature is installed and has an app hint
2735 		bool appFound = false;
2736 		if (error == B_OK && appMeta->GetAppHint(appRef) == B_OK) {
2737 			// Resolve symbolic links, if necessary
2738 			BEntry entry;
2739 			if (entry.SetTo(appRef, true) == B_OK && entry.IsFile()
2740 				&& entry.GetRef(appRef) == B_OK) {
2741 				appFound = true;
2742 			} else {
2743 				// Bad app hint -- remove it
2744 				appMeta->SetAppHint(NULL);
2745 			}
2746 		}
2747 
2748 		// In case there is no app hint or it is invalid, we need to query for
2749 		// the app.
2750 		if (error == B_OK && !appFound)
2751 			error = query_for_app(appMeta->Type(), appRef);
2752 		if (error == B_OK)
2753 			error = appFile->SetTo(appRef, B_READ_ONLY);
2754 		// check, whether the app can be used
2755 		if (error == B_OK)
2756 			error = can_app_be_used(appRef);
2757 
2758 		if (error == B_OK)
2759 			break;
2760 	}
2761 
2762 	return error;
2763 }
2764 
2765 
2766 /*!	\brief Gets the type of a file either from the node info or by sniffing.
2767 
2768 	The method first tries to get the file type from the supplied node info. If
2769 	that didn't work, the given entry ref is sniffed.
2770 
2771 	\param file An entry_ref referring to the file in question.
2772 	\param nodeInfo A BNodeInfo initialized to the file.
2773 	\param mimeType A pointer to a pre-allocated char buffer of at least size
2774 		   \c B_MIME_TYPE_LENGTH to be filled with the MIME type sniffed for
2775 		   the file.
2776 	\return
2777 	- \c B_OK: Everything went fine.
2778 	- \c B_BAD_VALUE: \c NULL \a file, \a nodeInfo or \a mimeType.
2779 	- other errors
2780 */
2781 status_t
2782 BRoster::_GetFileType(const entry_ref* file, BNodeInfo* nodeInfo,
2783 	char* mimeType) const
2784 {
2785 	// first try the node info
2786 	if (nodeInfo->GetType(mimeType) == B_OK)
2787 		return B_OK;
2788 
2789 	// Try to update the file's MIME info and just read the updated type.
2790 	// If that fails, sniff manually.
2791 	BPath path;
2792 	if (path.SetTo(file) != B_OK
2793 		|| update_mime_info(path.Path(), false, true, false) != B_OK
2794 		|| nodeInfo->GetType(mimeType) != B_OK) {
2795 		BMimeType type;
2796 		status_t error = BMimeType::GuessMimeType(file, &type);
2797 		if (error != B_OK)
2798 			return error;
2799 
2800 		if (!type.IsValid())
2801 			return B_BAD_VALUE;
2802 
2803 		strlcpy(mimeType, type.Type(), B_MIME_TYPE_LENGTH);
2804 	}
2805 
2806 	return B_OK;
2807 }
2808 
2809 
2810 /*!	\brief Sends messages to a running team.
2811 
2812 	In particular those messages are \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED,
2813 	\c B_READY_TO_RUN and other, arbitrary, ones.
2814 
2815 	If \a messageList is not \c NULL or empty, those messages are sent first,
2816 	then follow \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED and finally
2817 	\c B_READ_TO_RUN.
2818 
2819 	\c B_ARGV_RECEIVED is sent only, if \a args is not \c NULL and contains
2820 	more than one element. \c B_REFS_RECEIVED is sent only, if \a ref is not
2821 	\c NULL.
2822 
2823 	The ownership of all supplied objects retains to the caller.
2824 
2825 	\param team The team ID of the target application.
2826 	\param argc Number of elements in \a args.
2827 	\param args Argument vector to be sent to the target. May be \c NULL.
2828 	\param messageList List of BMessages to be sent to the target. May be
2829 		   \c NULL or empty.
2830 	\param ref entry_ref to be sent to the target. May be \c NULL.
2831 	\param alreadyRunning \c true, if the target app is not newly launched,
2832 		   but was already running, \c false otherwise (a \c B_READY_TO_RUN
2833 		   message will be sent in this case).
2834 	\return
2835 	- \c B_OK: Everything went fine.
2836 	- an error code otherwise
2837 */
2838 status_t
2839 BRoster::_SendToRunning(team_id team, int argc, const char* const* args,
2840 	const BList* messageList, const entry_ref* ref,
2841 	bool alreadyRunning) const
2842 {
2843 	status_t error = B_OK;
2844 	// Construct a messenger to the app: We can't use the public constructor,
2845 	// since the target application may be B_ARGV_ONLY.
2846 	app_info info;
2847 	error = GetRunningAppInfo(team, &info);
2848 	if (error == B_OK) {
2849 		BMessenger messenger;
2850 		BMessenger::Private(messenger).SetTo(team, info.port,
2851 			B_PREFERRED_TOKEN);
2852 
2853 		// send messages from the list
2854 		if (messageList) {
2855 			for (int32 i = 0;
2856 				 BMessage* message = (BMessage*)messageList->ItemAt(i);
2857 				 i++) {
2858 				messenger.SendMessage(message);
2859 			}
2860 		}
2861 
2862 		// send B_ARGV_RECEIVED or B_REFS_RECEIVED or B_SILENT_RELAUNCH (if
2863 		// already running)
2864 		if (args && argc > 1) {
2865 			BMessage message(B_ARGV_RECEIVED);
2866 			message.AddInt32("argc", argc);
2867 			for (int32 i = 0; i < argc; i++)
2868 				message.AddString("argv", args[i]);
2869 
2870 			// also add current working directory
2871 			char cwd[B_PATH_NAME_LENGTH];
2872 			if (getcwd(cwd, B_PATH_NAME_LENGTH) != NULL)
2873 				message.AddString("cwd", cwd);
2874 
2875 			messenger.SendMessage(&message);
2876 		} else if (ref) {
2877 			printf("_SendToRunning : B_REFS_RECEIVED\n");
2878 			BMessage message(B_REFS_RECEIVED);
2879 			message.AddRef("refs", ref);
2880 			messenger.SendMessage(&message);
2881 		} else if (alreadyRunning && (!messageList || messageList->IsEmpty()))
2882 			messenger.SendMessage(B_SILENT_RELAUNCH);
2883 
2884 		// send B_READY_TO_RUN
2885 		if (!alreadyRunning)
2886 			messenger.SendMessage(B_READY_TO_RUN);
2887 	}
2888 	return error;
2889 }
2890 
2891 
2892 void
2893 BRoster::_InitMessenger()
2894 {
2895 	DBG(OUT("BRoster::InitMessengers()\n"));
2896 
2897 	// find the registrar port
2898 	port_id rosterPort = find_port(BPrivate::get_roster_port_name());
2899 	port_info info;
2900 	if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) {
2901 		DBG(OUT("  found roster port\n"));
2902 
2903 		BMessenger::Private(fMessenger).SetTo(info.team, rosterPort,
2904 			B_PREFERRED_TOKEN);
2905 	}
2906 
2907 	DBG(OUT("BRoster::InitMessengers() done\n"));
2908 }
2909 
2910 
2911 /*static*/ status_t
2912 BRoster::_InitMimeMessenger(void* data)
2913 {
2914 	BRoster* roster = (BRoster*)data;
2915 
2916 	// ask for the MIME messenger
2917 	// Generous 1s + 5s timeouts. It could actually be synchronous, but
2918 	// timeouts allow us to debug the registrar main thread.
2919 	BMessage request(B_REG_GET_MIME_MESSENGER);
2920 	BMessage reply;
2921 	status_t error = roster->fMessenger.SendMessage(&request, &reply, 1000000LL,
2922 		5000000LL);
2923 	if (error == B_OK && reply.what == B_REG_SUCCESS) {
2924 		DBG(OUT("  got reply from roster\n"));
2925 			reply.FindMessenger("messenger", &roster->fMimeMessenger);
2926 	} else {
2927 		DBG(OUT("  no (useful) reply from roster: error: %lx: %s\n", error,
2928 			strerror(error)));
2929 		if (error == B_OK)
2930 			DBG(reply.PrintToStream());
2931 	}
2932 
2933 	return error;
2934 }
2935 
2936 
2937 BMessenger&
2938 BRoster::_MimeMessenger()
2939 {
2940 	__init_once(&fMimeMessengerInitOnce, &_InitMimeMessenger, this);
2941 	return fMimeMessenger;
2942 }
2943 
2944 
2945 /*! \brief Sends a request to the roster to add the application with the
2946 	given signature to the front of the recent apps list.
2947 */
2948 void
2949 BRoster::_AddToRecentApps(const char* appSig) const
2950 {
2951 	status_t error = B_OK;
2952 	// compose the request message
2953 	BMessage request(B_REG_ADD_TO_RECENT_APPS);
2954 	if (error == B_OK)
2955 		error = request.AddString("app sig", appSig);
2956 	// send the request
2957 	BMessage reply;
2958 	if (error == B_OK)
2959 		error = fMessenger.SendMessage(&request, &reply);
2960 	// evaluate the reply
2961 	status_t result;
2962 	if (error == B_OK) {
2963 		error = reply.what == B_REG_RESULT
2964 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
2965 	}
2966 	if (error == B_OK)
2967 		error = reply.FindInt32("result", &result);
2968 	if (error == B_OK)
2969 		error = result;
2970 	// Nothing to return... how sad :-(
2971 	// return error;
2972 }
2973 
2974 
2975 /*! \brief Sends a request to the roster to clear the recent
2976 	documents list.
2977 */
2978 void
2979 BRoster::_ClearRecentDocuments() const
2980 {
2981 	BMessage request(B_REG_CLEAR_RECENT_DOCUMENTS);
2982 	BMessage reply;
2983 	fMessenger.SendMessage(&request, &reply);
2984 }
2985 
2986 
2987 /*! \brief Sends a request to the roster to clear the recent
2988 	documents list.
2989 */
2990 void
2991 BRoster::_ClearRecentFolders() const
2992 {
2993 	BMessage request(B_REG_CLEAR_RECENT_FOLDERS);
2994 	BMessage reply;
2995 	fMessenger.SendMessage(&request, &reply);
2996 }
2997 
2998 
2999 /*! \brief Sends a request to the roster to clear the recent
3000 	documents list.
3001 */
3002 void
3003 BRoster::_ClearRecentApps() const
3004 {
3005 	BMessage request(B_REG_CLEAR_RECENT_APPS);
3006 	BMessage reply;
3007 	fMessenger.SendMessage(&request, &reply);
3008 }
3009 
3010 
3011 /*! \brief Loads the system's recently used document, folder, and
3012 	application lists from the specified file.
3013 
3014 	\note The current lists are cleared before loading the new lists
3015 
3016 	\param filename The name of the file to load from
3017 */
3018 void
3019 BRoster::_LoadRecentLists(const char* filename) const
3020 {
3021 	status_t error = B_OK;
3022 	// compose the request message
3023 	BMessage request(B_REG_LOAD_RECENT_LISTS);
3024 	if (error == B_OK)
3025 		error = request.AddString("filename", filename);
3026 	// send the request
3027 	BMessage reply;
3028 	if (error == B_OK)
3029 		error = fMessenger.SendMessage(&request, &reply);
3030 	// evaluate the reply
3031 	status_t result;
3032 	if (error == B_OK) {
3033 		error = reply.what == B_REG_RESULT
3034 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
3035 	}
3036 	if (error == B_OK)
3037 		error = reply.FindInt32("result", &result);
3038 	if (error == B_OK)
3039 		error = result;
3040 	// Nothing to return... how sad :-(
3041 	// return error;
3042 }
3043 
3044 
3045 /*! \brief Saves the system's recently used document, folder, and
3046 	application lists to the specified file.
3047 
3048 	\param filename The name of the file to save to
3049 */
3050 void
3051 BRoster::_SaveRecentLists(const char* filename) const
3052 {
3053 	status_t error = B_OK;
3054 	// compose the request message
3055 	BMessage request(B_REG_SAVE_RECENT_LISTS);
3056 	if (error == B_OK)
3057 		error = request.AddString("filename", filename);
3058 	// send the request
3059 	BMessage reply;
3060 	if (error == B_OK)
3061 		error = fMessenger.SendMessage(&request, &reply);
3062 	// evaluate the reply
3063 	status_t result;
3064 	if (error == B_OK) {
3065 		error = reply.what == B_REG_RESULT
3066 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
3067 	}
3068 	if (error == B_OK)
3069 		error = reply.FindInt32("result", &result);
3070 	if (error == B_OK)
3071 		error = result;
3072 	// Nothing to return... how sad :-(
3073 	// return error;
3074 }
3075