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