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