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