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