xref: /haiku/src/kits/app/Roster.cpp (revision 55b40aa53a835472ec7952b138ae4256203d02e4)
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 
1428 	// send the request
1429 	BMessage reply;
1430 	if (error == B_OK)
1431 		error = fMessenger.SendMessage(&request, &reply);
1432 
1433 	// evaluate the reply
1434 	if (error == B_OK) {
1435 		if (reply.what == B_REG_SUCCESS) {
1436 			if (!fullReg && team < 0) {
1437 				uint32 token;
1438 				if (reply.FindInt32("token", (int32*)&token) == B_OK) {
1439 					if (pToken)
1440 						*pToken = token;
1441 				} else
1442 					error = B_ERROR;
1443 			}
1444 		} else {
1445 			if (reply.FindInt32("error", &error) != B_OK)
1446 				error = B_ERROR;
1447 			// get team and token from the reply
1448 			if (otherTeam && reply.FindInt32("other_team", otherTeam) != B_OK)
1449 				*otherTeam = -1;
1450 			if (pToken && reply.FindInt32("token", (int32*)pToken) != B_OK)
1451 				*pToken = 0;
1452 		}
1453 	}
1454 	return error;
1455 }
1456 
1457 // SetSignature
1458 /*!	\brief Sets an application's signature.
1459 
1460 	The application must be registered or at pre-registered with a valid
1461 	team ID.
1462 
1463 	\param team The app's team ID.
1464 	\param mimeSig The app's new signature.
1465 	\return
1466 	- \c B_OK: Everything went fine.
1467 	- \c B_REG_APP_NOT_REGISTERED: The supplied team ID does not identify a
1468 	  registered application.
1469 */
1470 status_t
1471 BRoster::_SetSignature(team_id team, const char *mimeSig) const
1472 {
1473 	status_t error = B_OK;
1474 	// compose the request message
1475 	BMessage request(B_REG_SET_SIGNATURE);
1476 	if (error == B_OK && team >= 0)
1477 		error = request.AddInt32("team", team);
1478 	if (error == B_OK && mimeSig)
1479 		error = request.AddString("signature", mimeSig);
1480 
1481 	// send the request
1482 	BMessage reply;
1483 	if (error == B_OK)
1484 		error = fMessenger.SendMessage(&request, &reply);
1485 
1486 	// evaluate the reply
1487 	if (error == B_OK && reply.what != B_REG_SUCCESS
1488 		&& reply.FindInt32("error", &error) != B_OK)
1489 		error = B_ERROR;
1490 
1491 	return error;
1492 }
1493 
1494 // SetThread
1495 /*!
1496 	\todo Really needed?
1497 */
1498 void
1499 BRoster::_SetThread(team_id team, thread_id thread) const
1500 {
1501 }
1502 
1503 // SetThreadAndTeam
1504 /*!	\brief Sets the team and thread IDs of a pre-registered application.
1505 
1506 	After an application has been pre-registered via AddApplication(), without
1507 	supplying a team ID, the team and thread IDs have to be set using this
1508 	method.
1509 
1510 	\param entryToken The token identifying the application (returned by
1511 		   AddApplication())
1512 	\param thread The app's thread ID
1513 	\param team The app's team ID
1514 	\return
1515 	- \c B_OK: Everything went fine.
1516 	- \c B_REG_APP_NOT_PRE_REGISTERED: The supplied token does not identify a
1517 	  pre-registered application.
1518 */
1519 status_t
1520 BRoster::_SetThreadAndTeam(uint32 entryToken, thread_id thread,
1521 	team_id team) const
1522 {
1523 	status_t error = B_OK;
1524 	// compose the request message
1525 	BMessage request(B_REG_SET_THREAD_AND_TEAM);
1526 	if (error == B_OK)
1527 		error = request.AddInt32("token", (int32)entryToken);
1528 	if (error == B_OK && team >= 0)
1529 		error = request.AddInt32("team", team);
1530 	if (error == B_OK && thread >= 0)
1531 		error = request.AddInt32("thread", thread);
1532 
1533 	// send the request
1534 	BMessage reply;
1535 	if (error == B_OK)
1536 		error = fMessenger.SendMessage(&request, &reply);
1537 
1538 	// evaluate the reply
1539 	if (error == B_OK && reply.what != B_REG_SUCCESS
1540 		&& reply.FindInt32("error", &error) != B_OK)
1541 		error = B_ERROR;
1542 
1543 	return error;
1544 }
1545 
1546 // CompleteRegistration
1547 /*!	\brief Completes the registration process for a pre-registered application.
1548 
1549 	After an application has been pre-registered via AddApplication() and
1550 	after assigning it a team ID (via SetThreadAndTeam()) the application is
1551 	still pre-registered and must complete the registration.
1552 
1553 	\param team The app's team ID
1554 	\param thread The app's thread ID
1555 	\param thread The app looper port
1556 	\return
1557 	- \c B_OK: Everything went fine.
1558 	- \c B_REG_APP_NOT_PRE_REGISTERED: \a team does not identify an existing
1559 	  application or the identified application is already fully registered.
1560 */
1561 status_t
1562 BRoster::_CompleteRegistration(team_id team, thread_id thread,
1563 	port_id port) const
1564 {
1565 	status_t error = B_OK;
1566 	// compose the request message
1567 	BMessage request(B_REG_COMPLETE_REGISTRATION);
1568 	if (error == B_OK && team >= 0)
1569 		error = request.AddInt32("team", team);
1570 	if (error == B_OK && thread >= 0)
1571 		error = request.AddInt32("thread", thread);
1572 	if (error == B_OK && port >= 0)
1573 		error = request.AddInt32("port", port);
1574 
1575 	// send the request
1576 	BMessage reply;
1577 	if (error == B_OK)
1578 		error = fMessenger.SendMessage(&request, &reply);
1579 
1580 	// evaluate the reply
1581 	if (error == B_OK && reply.what != B_REG_SUCCESS
1582 		&& reply.FindInt32("error", &error) != B_OK)
1583 		error = B_ERROR;
1584 
1585 	return error;
1586 }
1587 
1588 // _IsAppRegistered
1589 /*!	\brief Returns whether an application is registered.
1590 
1591 	If the application is indeed pre-registered and \a info is not \c NULL,
1592 	the methods fills in the app_info structure pointed to by \a info.
1593 
1594 	\param ref An entry_ref referring to the app's executable
1595 	\param team The app's team ID. May be -1, if \a token is given.
1596 	\param token The app's pre-registration token. May be 0, if \a team is
1597 				 given.
1598 	\param preRegistered: Pointer to a pre-allocated bool to be filled in
1599 		   by this method, indicating whether or not the app was
1600 		   pre-registered.
1601 	\param info A pointer to a pre-allocated app_info structure to be filled
1602 		   in by this method (may be \c NULL)
1603 	\return
1604 		- \c B_OK, if the application is registered and all requested
1605 		  information could be retrieved,
1606 		- another error code, if the app is not registered or an error occurred.
1607 */
1608 status_t
1609 BRoster::_IsAppRegistered(const entry_ref *ref, team_id team,
1610 	uint32 token, bool *preRegistered, app_info *info) const
1611 {
1612 	status_t error = B_OK;
1613 
1614 	// compose the request message
1615 	BMessage request(B_REG_IS_APP_REGISTERED);
1616 	if (error == B_OK && ref)
1617 		error = request.AddRef("ref", ref);
1618 	if (error == B_OK && team >= 0)
1619 		error = request.AddInt32("team", team);
1620 	if (error == B_OK && token > 0)
1621 		error = request.AddInt32("token", (int32)token);
1622 
1623 	// send the request
1624 	BMessage reply;
1625 	if (error == B_OK)
1626 		error = fMessenger.SendMessage(&request, &reply);
1627 
1628 	// evaluate the reply
1629 	bool isRegistered = false;
1630 	bool isPreRegistered = false;
1631 	if (error == B_OK) {
1632 		if (reply.what == B_REG_SUCCESS) {
1633 			if (reply.FindBool("registered", &isRegistered) != B_OK
1634 				|| !isRegistered
1635 				|| reply.FindBool("pre-registered", &isPreRegistered) != B_OK) {
1636 				error = B_ERROR;
1637 			}
1638 
1639 			if (error == B_OK && preRegistered)
1640 				*preRegistered = isPreRegistered;
1641 			if (error == B_OK && info)
1642 				error = find_message_app_info(&reply, info);
1643 		} else if (reply.FindInt32("error", &error) != B_OK)
1644 			error = B_ERROR;
1645 	}
1646 
1647 	return error;
1648 }
1649 
1650 // RemovePreRegApp
1651 /*!	\brief Completely unregisters a pre-registered application.
1652 
1653 	This method can only be used to unregister applications that don't have
1654 	a team ID assigned yet. All other applications must be unregistered via
1655 	RemoveApp().
1656 
1657 	\param entryToken The token identifying the application (returned by
1658 		   AddApplication())
1659 	\return
1660 	- \c B_OK: Everything went fine.
1661 	- \c B_REG_APP_NOT_PRE_REGISTERED: The supplied token does not identify a
1662 	  pre-registered application.
1663 */
1664 status_t
1665 BRoster::_RemovePreRegApp(uint32 entryToken) const
1666 {
1667 	status_t error = B_OK;
1668 	// compose the request message
1669 	BMessage request(B_REG_REMOVE_PRE_REGISTERED_APP);
1670 	if (error == B_OK)
1671 		error = request.AddInt32("token", (int32)entryToken);
1672 
1673 	// send the request
1674 	BMessage reply;
1675 	if (error == B_OK)
1676 		error = fMessenger.SendMessage(&request, &reply);
1677 
1678 	// evaluate the reply
1679 	if (error == B_OK && reply.what != B_REG_SUCCESS
1680 		&& reply.FindInt32("error", &error) != B_OK)
1681 		error = B_ERROR;
1682 
1683 	return error;
1684 }
1685 
1686 // RemoveApp
1687 /*!	\brief Unregisters a (pre-)registered application.
1688 
1689 	This method must be used to unregister applications that already have
1690 	a team ID assigned, i.e. also for pre-registered application for which
1691 	SetThreadAndTeam() has already been invoked.
1692 
1693 	\param team The app's team ID
1694 	\return
1695 	- \c B_OK: Everything went fine.
1696 	- \c B_REG_APP_NOT_REGISTERED: The supplied team ID does not identify a
1697 	  (pre-)registered application.
1698 */
1699 status_t
1700 BRoster::_RemoveApp(team_id team) const
1701 {
1702 	status_t error = B_OK;
1703 	// compose the request message
1704 	BMessage request(B_REG_REMOVE_APP);
1705 	if (error == B_OK && team >= 0)
1706 		error = request.AddInt32("team", team);
1707 
1708 	// send the request
1709 	BMessage reply;
1710 	if (error == B_OK)
1711 		error = fMessenger.SendMessage(&request, &reply);
1712 
1713 	// evaluate the reply
1714 	if (error == B_OK && reply.what != B_REG_SUCCESS
1715 		&& reply.FindInt32("error", &error) != B_OK)
1716 		error = B_ERROR;
1717 
1718 	return error;
1719 }
1720 
1721 
1722 void
1723 BRoster::_ApplicationCrashed(team_id team)
1724 {
1725 	BPrivate::DesktopLink link;
1726 	if (link.InitCheck() != B_OK)
1727 		return;
1728 
1729 	if (link.StartMessage(AS_APP_CRASHED) == B_OK
1730 		&& link.Attach(team) == B_OK)
1731 		link.Flush();
1732 }
1733 
1734 
1735 // _LaunchApp
1736 /*!	\brief Launches the application associated with the supplied MIME type or
1737 		   the entry referred to by the supplied entry_ref.
1738 
1739 	The application to be started is searched the same way FindApp() does it.
1740 
1741 	At least one of \a mimeType or \a ref must not be \c NULL. If \a mimeType
1742 	is supplied, \a ref is ignored for finding the application.
1743 
1744 	If \a ref does refer to an application executable, that application is
1745 	launched. Otherwise the respective application is searched and launched,
1746 	and \a ref is sent to it in a \c B_REFS_RECEIVED message, unless other
1747 	arguments are passed via \a argc and \a args -- then the entry_ref is
1748 	converted into a path (C-string) and added to the argument vector.
1749 
1750 	\a messageList contains messages to be sent to the application
1751 	"on launch", i.e. before ReadyToRun() is invoked on the BApplication
1752 	object. The caller retains ownership of the supplied BList and the
1753 	contained BMessages. In case the method fails with \c B_ALREADY_RUNNING
1754 	the messages are delivered to the already running instance. The same
1755 	applies to the \c B_REFS_RECEIVED message.
1756 
1757 	The supplied \a argc and \a args are (if containing at least one argument)
1758 	put into a \c B_ARGV_RECEIVED message and sent to the launched application
1759 	"on launch". The caller retains ownership of the supplied \a args.
1760 	In case the method fails with \c B_ALREADY_RUNNING the message is
1761 	delivered to the already running instance. The same applies to the
1762 	\c B_REFS_RECEIVED message, if no arguments are supplied via \a argc and
1763 	\args.
1764 
1765 	\param mimeType MIME type for which the application shall be launched.
1766 		   May be \c NULL.
1767 	\param ref entry_ref referring to the file for which an application shall
1768 		   be launched. May be \c NULL.
1769 	\param messageList Optional list of messages to be sent to the application
1770 		   "on launch". May be \c NULL.
1771 	\param argc Specifies the number of elements in \a args.
1772 	\param args An array of C-strings to be sent as B_ARGV_RECEIVED messaged
1773 		   to the launched application.
1774 	\param appTeam Pointer to a pre-allocated team_id variable to be set to
1775 		   the team ID of the launched application.
1776 	\return
1777 	- \c B_OK: Everything went fine.
1778 	- \c B_BAD_VALUE: \c NULL \a mimeType and \a ref.
1779 	- \c B_LAUNCH_FAILED_NO_PREFERRED_APP: Neither with the supplied type nor
1780 	  with its supertype (if the supplied isn't a supertype itself) a
1781 	  preferred application is associated.
1782 	- \c B_LAUNCH_FAILED_APP_NOT_FOUND: The supplied type is not installed or
1783 	  its preferred application could not be found.
1784 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The supplied type's preferred
1785 	  application is in trash.
1786 	- \c B_LAUNCH_FAILED_EXECUTABLE: The found application is not executable.
1787 	- other error codes
1788 */
1789 status_t
1790 BRoster::_LaunchApp(const char *mimeType, const entry_ref *ref,
1791 	const BList *messageList, int argc,
1792 	const char *const *args, team_id *_appTeam) const
1793 {
1794 	DBG(OUT("BRoster::_LaunchApp()"));
1795 
1796 	if (_appTeam != NULL) {
1797 		// we're supposed to set _appTeam to -1 on error; we'll
1798 		// reset it later if everything goes well
1799 		*_appTeam = -1;
1800 	}
1801 
1802 	if (mimeType == NULL && ref == NULL)
1803 		return B_BAD_VALUE;
1804 
1805 	// use a mutable copy of the document entry_ref
1806 	entry_ref _docRef;
1807 	entry_ref *docRef = NULL;
1808 	if (ref != NULL) {
1809 		_docRef = *ref;
1810 		docRef = &_docRef;
1811 	}
1812 
1813 	// find the app
1814 	entry_ref appRef;
1815 	char signature[B_MIME_TYPE_LENGTH];
1816 	uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
1817 	bool wasDocument = true;
1818 	status_t error = _ResolveApp(mimeType, docRef, &appRef, signature, &appFlags,
1819 			&wasDocument);
1820 	DBG(OUT("  find app: %s (%lx)\n", strerror(error), error));
1821 
1822 	// build an argument vector
1823 	ArgVector argVector;
1824 	if (error == B_OK) {
1825 		error = argVector.Init(argc, args, &appRef,
1826 			(wasDocument ? docRef : NULL));
1827 	}
1828 	DBG(OUT("  build argv: %s (%lx)\n", strerror(error), error));
1829 
1830 	// pre-register the app (but ignore scipts)
1831 	app_info appInfo;
1832 	bool isScript = wasDocument && docRef != NULL && *docRef == appRef;
1833 	bool alreadyRunning = false;
1834 	uint32 appToken = 0;
1835 	team_id team = -1;
1836 	uint32 otherAppFlags = B_REG_DEFAULT_APP_FLAGS;
1837 	if (error == B_OK && !isScript) {
1838 		error = _AddApplication(signature, &appRef, appFlags, -1, -1, -1, false,
1839 			&appToken, &team);
1840 		if (error == B_ALREADY_RUNNING) {
1841 			DBG(OUT("  already running\n"));
1842 			alreadyRunning = true;
1843 
1844 			// get the app flags for the running application
1845 			error = _IsAppRegistered(&appRef, team, appToken, NULL, &appInfo);
1846 			if (error == B_OK) {
1847 				otherAppFlags = appInfo.flags;
1848 				team = appInfo.team;
1849 			}
1850 		}
1851 		DBG(OUT("  pre-register: %s (%lx)\n", strerror(error), error));
1852 	}
1853 
1854 	// launch the app
1855 	if (error == B_OK && !alreadyRunning) {
1856 		DBG(OUT("  token: %lu\n", appToken));
1857 		// load the app image
1858 		thread_id appThread = load_image(argVector.Count(),
1859 			const_cast<const char**>(argVector.Args()),
1860 			const_cast<const char**>(environ));
1861 
1862 		// get the app team
1863 		if (appThread >= 0) {
1864 			thread_info threadInfo;
1865 			error = get_thread_info(appThread, &threadInfo);
1866 			if (error == B_OK)
1867 				team = threadInfo.team;
1868 		} else if (wasDocument && appThread == B_NOT_AN_EXECUTABLE)
1869 			error = B_LAUNCH_FAILED_EXECUTABLE;
1870 		else
1871 			error = appThread;
1872 
1873 		DBG(OUT("  load image: %s (%lx)\n", strerror(error), error));
1874 		// finish the registration
1875 		if (error == B_OK && !isScript)
1876 			error = _SetThreadAndTeam(appToken, appThread, team);
1877 
1878 		DBG(OUT("  set thread and team: %s (%lx)\n", strerror(error), error));
1879 		// resume the launched team
1880 		if (error == B_OK)
1881 			error = resume_thread(appThread);
1882 
1883 		DBG(OUT("  resume thread: %s (%lx)\n", strerror(error), error));
1884 		// on error: kill the launched team and unregister the app
1885 		if (error != B_OK) {
1886 			if (appThread >= 0)
1887 				kill_thread(appThread);
1888 			if (!isScript)
1889 				_RemovePreRegApp(appToken);
1890 		}
1891 	}
1892 
1893 	if (alreadyRunning && current_team() == team) {
1894 		// The target team is calling us, so we don't send it the message
1895 		// to prevent an endless loop
1896 		error = B_BAD_VALUE;
1897 	}
1898 
1899 	// send "on launch" messages
1900 	if (error == B_OK) {
1901 		// If the target app is B_ARGV_ONLY almost no messages are sent to it.
1902 		// More precisely, the launched app gets at least B_ARGV_RECEIVED and
1903 		// B_READY_TO_RUN, an already running app gets nothing.
1904 		bool argvOnly = (appFlags & B_ARGV_ONLY)
1905 			|| (alreadyRunning && (otherAppFlags & B_ARGV_ONLY));
1906 		const BList *_messageList = (argvOnly ? NULL : messageList);
1907 		// don't send ref, if it refers to the app or is included in the
1908 		// argument vector
1909 		const entry_ref *_ref = argvOnly || !wasDocument
1910 			|| argVector.Count() > 1 ? NULL : docRef;
1911 		if (!(argvOnly && alreadyRunning)) {
1912 			_SendToRunning(team, argVector.Count(), argVector.Args(),
1913 				_messageList, _ref, !alreadyRunning);
1914 		}
1915 	}
1916 
1917 	// set return values
1918 	if (error == B_OK) {
1919 		if (alreadyRunning)
1920 			error = B_ALREADY_RUNNING;
1921 		else if (_appTeam)
1922 			*_appTeam = team;
1923 	}
1924 
1925 	DBG(OUT("BRoster::_LaunchApp() done: %s (%lx)\n",
1926 		strerror(error), error));
1927 	return error;
1928 }
1929 
1930 // SetAppFlags
1931 void
1932 BRoster::_SetAppFlags(team_id team, uint32 flags) const
1933 {
1934 }
1935 
1936 // DumpRoster
1937 void
1938 BRoster::_DumpRoster() const
1939 {
1940 }
1941 
1942 // _ResolveApp
1943 /*!	\brief Finds an application associated with a MIME type or a file.
1944 
1945 	It does also supply the caller with some more information about the
1946 	application, like signature, app flags and whether the supplied
1947 	MIME type/entry_ref already identified an application.
1948 
1949 	At least one of \a inType or \a ref must not be \c NULL. If \a inType is
1950 	supplied, \a ref is ignored.
1951 
1952 	If \a ref refers to a link, it is updated with the entry_ref for the
1953 	resolved entry.
1954 
1955 	\see FindApp() for how the application is searched.
1956 
1957 	\a appSig is set to a string with length 0, if the found application
1958 	has no signature.
1959 
1960 	\param inType The MIME type for which an application shall be found.
1961 		   May be \c NULL.
1962 	\param ref The file for which an application shall be found.
1963 		   May be \c NULL.
1964 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
1965 		   a reference to the found application's executable. May be \c NULL.
1966 	\param appSig A pointer to a pre-allocated char buffer of at least size
1967 		   \c B_MIME_TYPE_LENGTH to be filled with the signature of the found
1968 		   application. May be \c NULL.
1969 	\param appFlags A pointer to a pre-allocated uint32 variable to be filled
1970 		   with the app flags of the found application. May be \c NULL.
1971 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
1972 		   \c true, if the supplied file was not identifying an application,
1973 		   to \c false otherwise. Has no meaning, if a \a inType is supplied.
1974 		   May be \c NULL.
1975 	\return
1976 	- \c B_OK: Everything went fine.
1977 	- \c B_BAD_VALUE: \c NULL \a inType and \a ref.
1978 	- \see FindApp() for other error codes.
1979 */
1980 status_t
1981 BRoster::_ResolveApp(const char *inType, entry_ref *ref,
1982 	entry_ref* _appRef, char* _appSig, uint32* _appFlags,
1983 	bool* _wasDocument) const
1984 {
1985 	if ((inType == NULL && ref == NULL)
1986 		|| (inType != NULL && strlen(inType) >= B_MIME_TYPE_LENGTH))
1987 		return B_BAD_VALUE;
1988 
1989 	// find the app
1990 	BMimeType appMeta;
1991 	BFile appFile;
1992 	entry_ref appRef;
1993 	status_t error;
1994 
1995 	if (inType)
1996 		error = _TranslateType(inType, &appMeta, &appRef, &appFile);
1997 	else {
1998 		error = _TranslateRef(ref, &appMeta, &appRef, &appFile,
1999 			_wasDocument);
2000 	}
2001 
2002 	// create meta mime
2003 	if (error == B_OK) {
2004 		BPath path;
2005 		if (path.SetTo(&appRef) == B_OK)
2006 			create_app_meta_mime(path.Path(), false, true, false);
2007 	}
2008 
2009 	// set the app hint on the type -- but only if the file has the
2010 	// respective signature, otherwise unset the app hint
2011 	BAppFileInfo appFileInfo;
2012 	if (error == B_OK) {
2013 		char signature[B_MIME_TYPE_LENGTH];
2014 		if (appFileInfo.SetTo(&appFile) == B_OK
2015 			&& appFileInfo.GetSignature(signature) == B_OK) {
2016 			if (!strcasecmp(appMeta.Type(), signature))
2017 				appMeta.SetAppHint(&appRef);
2018 			else {
2019 				appMeta.SetAppHint(NULL);
2020 				appMeta.SetTo(signature);
2021 			}
2022 		} else
2023 			appMeta.SetAppHint(NULL);
2024 	}
2025 
2026 	// set the return values
2027 	if (error == B_OK) {
2028 		if (_appRef)
2029 			*_appRef = appRef;
2030 
2031 		if (_appSig) {
2032 			// there's no warranty, that appMeta is valid
2033 			if (appMeta.IsValid())
2034 				strcpy(_appSig, appMeta.Type());
2035 			else
2036 				_appSig[0] = '\0';
2037 		}
2038 
2039 		if (_appFlags) {
2040 			// if an error occurs here, we don't care and just set a default
2041 			// value
2042 			if (appFileInfo.InitCheck() != B_OK
2043 				|| appFileInfo.GetAppFlags(_appFlags) != B_OK) {
2044 				*_appFlags = B_REG_DEFAULT_APP_FLAGS;
2045 			}
2046 		}
2047 	} else {
2048 		// unset the ref on error
2049 		if (_appRef)
2050 			*_appRef = appRef;
2051 	}
2052 
2053 	return error;
2054 }
2055 
2056 // _TranslateRef
2057 /*!	\brief Finds an application associated with a file.
2058 
2059 	\a appMeta is left unmodified, if the file is executable, but has no
2060 	signature.
2061 
2062 	\see FindApp() for how the application is searched.
2063 
2064 	If \a ref refers to a link, it is updated with the entry_ref for the
2065 	resolved entry.
2066 
2067 	\param ref The file for which an application shall be found.
2068 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2069 		   signature of the found application.
2070 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2071 		   a reference to the found application's executable.
2072 	\param appFile A pointer to a pre-allocated BFile to be set to the
2073 		   executable of the found application.
2074 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2075 		   \c true, if the supplied file was not identifying an application,
2076 		   to \c false otherwise. May be \c NULL.
2077 	\return
2078 	- \c B_OK: Everything went fine.
2079 	- \c B_BAD_VALUE: \c NULL \a ref, \a appMeta, \a appRef or \a appFile.
2080 	- \see FindApp() for other error codes.
2081 */
2082 status_t
2083 BRoster::_TranslateRef(entry_ref *ref, BMimeType *appMeta,
2084 	entry_ref *appRef, BFile *appFile, bool *_wasDocument) const
2085 {
2086 	if (ref == NULL || appMeta == NULL || appRef == NULL || appFile == NULL)
2087 		return B_BAD_VALUE;
2088 
2089 	// resolve ref, if necessary
2090 	BEntry entry;
2091 	status_t error = entry.SetTo(ref, false);
2092 	if (error == B_OK && entry.IsSymLink()) {
2093 		// ref refers to a link
2094 		error = entry.SetTo(ref, true);
2095 		if (error == B_OK)
2096 			error = entry.GetRef(ref);
2097 		if (error != B_OK)
2098 			error = B_LAUNCH_FAILED_NO_RESOLVE_LINK;
2099 	}
2100 
2101 	// init node
2102 	BNode node;
2103 	if (error == B_OK)
2104 		error = node.SetTo(ref);
2105 	// get permissions
2106 	mode_t permissions;
2107 	if (error == B_OK)
2108 		error = node.GetPermissions(&permissions);
2109 	if (error == B_OK) {
2110 		if ((permissions & S_IXUSR) && node.IsFile()) {
2111 			// node is executable and a file -- we're done
2112 			*appRef = *ref;
2113 			error = appFile->SetTo(appRef, B_READ_ONLY);
2114 
2115 			// get the app's signature via a BAppFileInfo
2116 			BAppFileInfo appFileInfo;
2117 			if (error == B_OK)
2118 				error = appFileInfo.SetTo(appFile);
2119 
2120 			char type[B_MIME_TYPE_LENGTH];
2121 			bool isDocument = true;
2122 
2123 			if (error == B_OK) {
2124 				// don't worry, if the file doesn't have a signature, just
2125 				// unset the supplied object
2126 				if (appFileInfo.GetSignature(type) == B_OK)
2127 					error = appMeta->SetTo(type);
2128 				else
2129 					appMeta->Unset();
2130 				if (appFileInfo.GetType(type) == B_OK
2131 					&& !strcasecmp(type, B_APP_MIME_TYPE))
2132 					isDocument = false;
2133 			}
2134 			if (_wasDocument)
2135 				*_wasDocument = isDocument;
2136 		} else {
2137 			// the node is not exectuable or not a file
2138 			// init a node info
2139 			BNodeInfo nodeInfo;
2140 			if (error == B_OK)
2141 				error = nodeInfo.SetTo(&node);
2142 			char preferredApp[B_MIME_TYPE_LENGTH];
2143 			if (error == B_OK) {
2144 				// if the file has a preferred app, let _TranslateType() find
2145 				// it for us
2146 				if (nodeInfo.GetPreferredApp(preferredApp) == B_OK) {
2147 					error = _TranslateType(preferredApp, appMeta, appRef,
2148 										   appFile);
2149 				} else {
2150 					// no preferred app -- we need to get the file's type
2151 					char fileType[B_MIME_TYPE_LENGTH];
2152 					// get the type from the file, or guess a type
2153 					if (nodeInfo.GetType(fileType) != B_OK)
2154 						error = _SniffFile(ref, &nodeInfo, fileType);
2155 					// now let _TranslateType() do the actual work
2156 					if (error == B_OK) {
2157 						error = _TranslateType(fileType, appMeta, appRef,
2158 											   appFile);
2159 					}
2160 				}
2161 			}
2162 			if (_wasDocument)
2163 				*_wasDocument = true;
2164 		}
2165 	}
2166 	return error;
2167 }
2168 
2169 // _TranslateType
2170 /*!	\brief Finds an application associated with a MIME type.
2171 
2172 	\see FindApp() for how the application is searched.
2173 
2174 	\param mimeType The MIME type for which an application shall be found.
2175 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2176 		   signature of the found application.
2177 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2178 		   a reference to the found application's executable.
2179 	\param appFile A pointer to a pre-allocated BFile to be set to the
2180 		   executable of the found application.
2181 	\return
2182 	- \c B_OK: Everything went fine.
2183 	- \c B_BAD_VALUE: \c NULL \a mimeType, \a appMeta, \a appRef or \a appFile.
2184 	- \see FindApp() for other error codes.
2185 */
2186 status_t
2187 BRoster::_TranslateType(const char *mimeType, BMimeType *appMeta,
2188 	entry_ref *appRef, BFile *appFile) const
2189 {
2190 	if (mimeType == NULL || appMeta == NULL || appRef == NULL
2191 		|| appFile == NULL || strlen(mimeType) >= B_MIME_TYPE_LENGTH)
2192 		return B_BAD_VALUE;
2193 
2194 	// create a BMimeType and check, if the type is installed
2195 	BMimeType type;
2196 	status_t error = type.SetTo(mimeType);
2197 
2198 	// get the preferred app
2199 	char primarySignature[B_MIME_TYPE_LENGTH];
2200 	char secondarySignature[B_MIME_TYPE_LENGTH];
2201 	primarySignature[0] = '\0';
2202 	secondarySignature[0] = '\0';
2203 
2204 	if (error == B_OK) {
2205 		if (type.IsInstalled()) {
2206 			BMimeType superType;
2207 			if (type.GetSupertype(&superType) == B_OK)
2208 				superType.GetPreferredApp(secondarySignature);
2209 
2210 			if (type.GetPreferredApp(primarySignature) != B_OK
2211 				&& !secondarySignature[0]) {
2212 				// The type is installed, but has no preferred app.
2213 				// In fact it might be an app signature and even having a
2214 				// valid app hint. Nevertheless we fail.
2215 				error = B_LAUNCH_FAILED_NO_PREFERRED_APP;
2216 			} else if (!strcmp(primarySignature, secondarySignature)) {
2217 				// Both types have the same preferred app, there is
2218 				// no point in testing it twice.
2219 				secondarySignature[0] = '\0';
2220 			}
2221 		} else {
2222 			// The type is not installed. We assume it is an app signature.
2223 			strcpy(primarySignature, mimeType);
2224 		}
2225 	}
2226 
2227 	if (error != B_OK)
2228 		return error;
2229 
2230 	// see if we can find the application and if it's valid, try
2231 	// both preferred app signatures, if available (from type and
2232 	// super type)
2233 
2234 	status_t primaryError = B_OK;
2235 
2236 	for (int32 tries = 0; tries < 2; tries++) {
2237 		const char* signature = tries == 0 ? primarySignature : secondarySignature;
2238 		if (signature[0] == '\0')
2239 			continue;
2240 
2241 		error = appMeta->SetTo(signature);
2242 
2243 		// check, whether the signature is installed and has an app hint
2244 		bool appFound = false;
2245 		if (error == B_OK && appMeta->GetAppHint(appRef) == B_OK) {
2246 			// resolve symbolic links, if necessary
2247 			BEntry entry;
2248 			if (entry.SetTo(appRef, true) == B_OK && entry.IsFile()
2249 				&& entry.GetRef(appRef) == B_OK) {
2250 				appFound = true;
2251 			} else
2252 				appMeta->SetAppHint(NULL);	// bad app hint -- remove it
2253 		}
2254 
2255 		// in case there is no app hint or it is invalid, we need to query for the
2256 		// app
2257 		if (error == B_OK && !appFound)
2258 			error = query_for_app(appMeta->Type(), appRef);
2259 		if (error == B_OK)
2260 			error = appFile->SetTo(appRef, B_READ_ONLY);
2261 		// check, whether the app can be used
2262 		if (error == B_OK)
2263 			error = can_app_be_used(appRef);
2264 
2265 		if (error != B_OK) {
2266 			if (tries == 0)
2267 				primaryError = error;
2268 			else if (primarySignature[0])
2269 				error = primaryError;
2270 		} else
2271 			break;
2272 	}
2273 
2274 	return error;
2275 }
2276 
2277 // _SniffFile
2278 /*!	\brief Sniffs the MIME type for a file.
2279 
2280 	Also updates the file's MIME info, if possible.
2281 
2282 	\param file An entry_ref referring to the file in question.
2283 	\param nodeInfo A BNodeInfo initialized to the file.
2284 	\param mimeType A pointer to a pre-allocated char buffer of at least size
2285 		   \c B_MIME_TYPE_LENGTH to be filled with the MIME type sniffed for
2286 		   the file.
2287 	\return
2288 	- \c B_OK: Everything went fine.
2289 	- \c B_BAD_VALUE: \c NULL \a file, \a nodeInfo or \a mimeType.
2290 	- other errors
2291 */
2292 status_t
2293 BRoster::_SniffFile(const entry_ref *file, BNodeInfo *nodeInfo,
2294 	char *mimeType) const
2295 {
2296 	status_t error = (file && nodeInfo && mimeType ? B_OK : B_BAD_VALUE);
2297 	if (error == B_OK) {
2298 		// Try to update the file's MIME info and just read the updated type.
2299 		// If that fails, sniff manually.
2300 		BPath path;
2301 		if (path.SetTo(file) != B_OK
2302 			|| update_mime_info(path.Path(), false, true, false) != B_OK
2303 			|| nodeInfo->GetType(mimeType) != B_OK) {
2304 			BMimeType type;
2305 			error = BMimeType::GuessMimeType(file, &type);
2306 			if (error == B_OK && type.IsValid())
2307 				strcpy(mimeType, type.Type());
2308 		}
2309 	}
2310 	return error;
2311 }
2312 
2313 // _SendToRunning
2314 /*!	\brief Sends messages to a running team.
2315 
2316 	In particular those messages are \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED,
2317 	\c B_READY_TO_RUN and other, arbitrary, ones.
2318 
2319 	If \a messageList is not \c NULL or empty, those messages are sent first,
2320 	then follow \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED and finally
2321 	\c B_READ_TO_RUN.
2322 
2323 	\c B_ARGV_RECEIVED is sent only, if \a args is not \c NULL and contains
2324 	more than one element. \c B_REFS_RECEIVED is sent only, if \a ref is not
2325 	\c NULL.
2326 
2327 	The ownership of all supplied objects retains to the caller.
2328 
2329 	\param team The team ID of the target application.
2330 	\param argc Number of elements in \a args.
2331 	\param args Argument vector to be sent to the target. May be \c NULL.
2332 	\param messageList List of BMessages to be sent to the target. May be
2333 		   \c NULL or empty.
2334 	\param ref entry_ref to be sent to the target. May be \c NULL.
2335 	\param readyToRun \c true, if a \c B_READY_TO_RUN message shall be sent,
2336 		   \c false otherwise.
2337 	\return
2338 	- \c B_OK: Everything went fine.
2339 	- an error code otherwise
2340 */
2341 status_t
2342 BRoster::_SendToRunning(team_id team, int argc, const char *const *args,
2343 	const BList *messageList, const entry_ref *ref,
2344 	bool readyToRun) const
2345 {
2346 	status_t error = B_OK;
2347 	// Construct a messenger to the app: We can't use the public constructor,
2348 	// since the target application may be B_ARGV_ONLY.
2349 	app_info info;
2350 	error = GetRunningAppInfo(team, &info);
2351 	if (error == B_OK) {
2352 		BMessenger messenger;
2353 		BMessenger::Private(messenger).SetTo(team, info.port, B_PREFERRED_TOKEN);
2354 		// send messages from the list
2355 		if (messageList) {
2356 			for (int32 i = 0;
2357 				 BMessage *message = (BMessage*)messageList->ItemAt(i);
2358 				 i++) {
2359 				messenger.SendMessage(message);
2360 			}
2361 		}
2362 		// send B_ARGV_RECEIVED
2363 		if (args && argc > 1) {
2364 			BMessage message(B_ARGV_RECEIVED);
2365 			message.AddInt32("argc", argc);
2366 			for (int32 i = 0; i < argc; i++)
2367 				message.AddString("argv", args[i]);
2368 			messenger.SendMessage(&message);
2369 		}
2370 		// send B_REFS_RECEIVED
2371 		if (ref) {
2372 			BMessage message(B_REFS_RECEIVED);
2373 			message.AddRef("refs", ref);
2374 			messenger.SendMessage(&message);
2375 		}
2376 		// send B_READY_TO_RUN
2377 		if (readyToRun)
2378 			messenger.SendMessage(B_READY_TO_RUN);
2379 	}
2380 	return error;
2381 }
2382 
2383 
2384 void
2385 BRoster::_InitMessengers()
2386 {
2387 	DBG(OUT("BRoster::InitMessengers()\n"));
2388 
2389 	// find the registrar port
2390 	port_id rosterPort = find_port(BPrivate::get_roster_port_name());
2391 	port_info info;
2392 	if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) {
2393 		DBG(OUT("  found roster port\n"));
2394 		// ask for the MIME messenger
2395 		BMessenger::Private(fMessenger).SetTo(info.team, rosterPort,
2396 			B_PREFERRED_TOKEN);
2397 		BMessage reply;
2398 		status_t error = fMessenger.SendMessage(B_REG_GET_MIME_MESSENGER, &reply);
2399 		if (error == B_OK && reply.what == B_REG_SUCCESS) {
2400 			DBG(OUT("  got reply from roster\n"));
2401 				reply.FindMessenger("messenger", &fMimeMessenger);
2402 		} else {
2403 			DBG(OUT("  no (useful) reply from roster: error: %lx: %s\n", error,
2404 				strerror(error)));
2405 			if (error == B_OK)
2406 				DBG(reply.PrintToStream());
2407 		}
2408 	}
2409 	DBG(OUT("BRoster::InitMessengers() done\n"));
2410 }
2411 
2412 
2413 /*! \brief Sends a request to the roster to add the application with the
2414 	given signature to the front of the recent apps list.
2415 */
2416 void
2417 BRoster::_AddToRecentApps(const char *appSig) const
2418 {
2419 	status_t error = B_OK;
2420 	// compose the request message
2421 	BMessage request(B_REG_ADD_TO_RECENT_APPS);
2422 	if (error == B_OK)
2423 		error = request.AddString("app sig", appSig);
2424 	// send the request
2425 	BMessage reply;
2426 	if (error == B_OK)
2427 		error = fMessenger.SendMessage(&request, &reply);
2428 	// evaluate the reply
2429 	status_t result;
2430 	if (error == B_OK)
2431 		error = reply.what == B_REG_RESULT ? (status_t)B_OK : (status_t)B_BAD_REPLY;
2432 	if (error == B_OK)
2433 		error = reply.FindInt32("result", &result);
2434 	if (error == B_OK)
2435 		error = result;
2436 	// Nothing to return... how sad :-(
2437 	// return error;
2438 }
2439 
2440 /*! \brief Sends a request to the roster to clear the recent
2441 	documents list.
2442 */
2443 void
2444 BRoster::_ClearRecentDocuments() const
2445 {
2446 	BMessage request(B_REG_CLEAR_RECENT_DOCUMENTS);
2447 	BMessage reply;
2448 	fMessenger.SendMessage(&request, &reply);
2449 }
2450 
2451 /*! \brief Sends a request to the roster to clear the recent
2452 	documents list.
2453 */
2454 void
2455 BRoster::_ClearRecentFolders() const
2456 {
2457 	BMessage request(B_REG_CLEAR_RECENT_FOLDERS);
2458 	BMessage reply;
2459 	fMessenger.SendMessage(&request, &reply);
2460 }
2461 
2462 /*! \brief Sends a request to the roster to clear the recent
2463 	documents list.
2464 */
2465 void
2466 BRoster::_ClearRecentApps() const
2467 {
2468 	BMessage request(B_REG_CLEAR_RECENT_APPS);
2469 	BMessage reply;
2470 	fMessenger.SendMessage(&request, &reply);
2471 }
2472 
2473 // LoadRecentLists
2474 /*! \brief Loads the system's recently used document, folder, and
2475 	application lists from the specified file.
2476 
2477 	\note The current lists are cleared before loading the new lists
2478 
2479 	\param filename The name of the file to load from
2480 */
2481 void
2482 BRoster::_LoadRecentLists(const char *filename) const
2483 {
2484 	status_t error = B_OK;
2485 	// compose the request message
2486 	BMessage request(B_REG_LOAD_RECENT_LISTS);
2487 	if (error == B_OK)
2488 		error = request.AddString("filename", filename);
2489 	// send the request
2490 	BMessage reply;
2491 	if (error == B_OK)
2492 		error = fMessenger.SendMessage(&request, &reply);
2493 	// evaluate the reply
2494 	status_t result;
2495 	if (error == B_OK)
2496 		error = reply.what == B_REG_RESULT ? (status_t)B_OK : (status_t)B_BAD_REPLY;
2497 	if (error == B_OK)
2498 		error = reply.FindInt32("result", &result);
2499 	if (error == B_OK)
2500 		error = result;
2501 	// Nothing to return... how sad :-(
2502 	// return error;
2503 }
2504 
2505 // SaveRecentLists
2506 /*! \brief Saves the system's recently used document, folder, and
2507 	application lists to the specified file.
2508 
2509 	\param filename The name of the file to save to
2510 */
2511 void
2512 BRoster::_SaveRecentLists(const char *filename) const
2513 {
2514 	status_t error = B_OK;
2515 	// compose the request message
2516 	BMessage request(B_REG_SAVE_RECENT_LISTS);
2517 	if (error == B_OK)
2518 		error = request.AddString("filename", filename);
2519 	// send the request
2520 	BMessage reply;
2521 	if (error == B_OK)
2522 		error = fMessenger.SendMessage(&request, &reply);
2523 	// evaluate the reply
2524 	status_t result;
2525 	if (error == B_OK)
2526 		error = reply.what == B_REG_RESULT ? (status_t)B_OK : (status_t)B_BAD_REPLY;
2527 	if (error == B_OK)
2528 		error = reply.FindInt32("result", &result);
2529 	if (error == B_OK)
2530 		error = result;
2531 	// Nothing to return... how sad :-(
2532 	// return error;
2533 }
2534 
2535 
2536 //	#pragma mark - Helper functions
2537 
2538 
2539 /*!	\brief Extracts an app_info from a BMessage.
2540 
2541 	The function searchs for a field "app_info" typed B_REG_APP_INFO_TYPE
2542 	and initializes \a info with the found data.
2543 
2544 	\param message The message
2545 	\param info A pointer to a pre-allocated app_info to be filled in with the
2546 		   info found in the message.
2547 	\return
2548 	- \c B_OK: Everything went fine.
2549 	- \c B_BAD_VALUE: \c NULL \a message or \a info.
2550 	- other error codes
2551 */
2552 static
2553 status_t
2554 find_message_app_info(BMessage *message, app_info *info)
2555 {
2556 	status_t error = (message && info ? B_OK : B_BAD_VALUE);
2557 	const flat_app_info *flatInfo = NULL;
2558 	ssize_t size = 0;
2559 	// find the flat app info in the message
2560 	if (error == B_OK) {
2561 		error = message->FindData("app_info", B_REG_APP_INFO_TYPE,
2562 								  (const void**)&flatInfo, &size);
2563 	}
2564 	// unflatten the flat info
2565 	if (error == B_OK) {
2566 		if (size == sizeof(flat_app_info)) {
2567 			memcpy(info, &flatInfo->info, sizeof(app_info));
2568 			info->ref.name = NULL;
2569 			if (strlen(flatInfo->ref_name) > 0)
2570 				info->ref.set_name(flatInfo->ref_name);
2571 		} else
2572 			error = B_ERROR;
2573 	}
2574 	return error;
2575  }
2576 
2577 // query_for_app
2578 /*!	\brief Finds an app by signature on any mounted volume.
2579 	\param signature The app's signature.
2580 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2581 		   a reference to the found application's executable.
2582 	\return
2583 	- \c B_OK: Everything went fine.
2584 	- \c B_BAD_VALUE: \c NULL \a signature or \a appRef.
2585 	- B_LAUNCH_FAILED_APP_NOT_FOUND: An application with this signature
2586 	  could not be found.
2587 	- other error codes
2588 */
2589 static
2590 status_t
2591 query_for_app(const char *signature, entry_ref *appRef)
2592 {
2593 	if (signature == NULL || appRef == NULL)
2594 		return B_BAD_VALUE;
2595 
2596 	status_t error = B_LAUNCH_FAILED_APP_NOT_FOUND;
2597 	bool caseInsensitive = false;
2598 
2599 	while (true) {
2600 		// search on all volumes
2601 		BVolumeRoster volumeRoster;
2602 		BVolume volume;
2603 		while (volumeRoster.GetNextVolume(&volume) == B_OK) {
2604 			if (!volume.KnowsQuery())
2605 				continue;
2606 
2607 			index_info info;
2608 			if (fs_stat_index(volume.Device(), "BEOS:APP_SIG", &info) != 0) {
2609 				// This volume doesn't seem to have the index we're looking for;
2610 				// querying it might need a long time, and we don't care *that*
2611 				// much...
2612 				continue;
2613 			}
2614 
2615 			BQuery query;
2616 			query.SetVolume(&volume);
2617 			query.PushAttr("BEOS:APP_SIG");
2618 			if (!caseInsensitive)
2619 				query.PushString(signature);
2620 			else {
2621 				// second pass, create a case insensitive query string
2622 				char string[B_MIME_TYPE_LENGTH * 4];
2623 				strcpy(string, "application/");
2624 
2625 				int32 length = strlen(string);
2626 				const char *from = signature + length;
2627 				char *to = string + length;
2628 
2629 				for (; from[0]; from++) {
2630 					if (isalpha(from[0])) {
2631 						*to++ = '[';
2632 						*to++ = tolower(from[0]);
2633 						*to++ = toupper(from[0]);
2634 						*to++ = ']';
2635 					} else
2636 						*to++ = from[0];
2637 				}
2638 
2639 				to[0] = '\0';
2640 				query.PushString(string);
2641 			}
2642 			query.PushOp(B_EQ);
2643 
2644 			query.Fetch();
2645 
2646 			// walk through the query
2647 			bool appFound = false;
2648 			status_t foundAppError = B_OK;
2649 			entry_ref ref;
2650 			while (query.GetNextRef(&ref) == B_OK) {
2651 				if ((!appFound || compare_app_versions(appRef, &ref) < 0)
2652 					&& (foundAppError = can_app_be_used(&ref)) == B_OK) {
2653 					*appRef = ref;
2654 					appFound = true;
2655 				}
2656 			}
2657 			if (!appFound) {
2658 				// If the query didn't return any hits, the error is
2659 				// B_LAUNCH_FAILED_APP_NOT_FOUND, otherwise we return the
2660 				// result of the last can_app_be_used().
2661 				error = foundAppError != B_OK
2662 					? foundAppError : B_LAUNCH_FAILED_APP_NOT_FOUND;
2663 			} else
2664 				return B_OK;
2665 		}
2666 
2667 		if (!caseInsensitive)
2668 			caseInsensitive = true;
2669 		else
2670 			break;
2671 	}
2672 
2673 	return error;
2674 }
2675 
2676 
2677 // can_app_be_used
2678 /*!	\brief Checks whether or not an application can be used.
2679 
2680 	Currently it is only checked whether the application is in the trash.
2681 
2682 	\param ref An entry_ref referring to the application executable.
2683 	\return
2684 	- \c B_OK: The application can be used.
2685 	- \c B_ENTRY_NOT_FOUND: \a ref doesn't refer to and existing entry.
2686 	- \c B_IS_A_DIRECTORY: \a ref refers to a directory.
2687 	- \c B_LAUNCH_FAILED_APP_IN_TRASH: The application executable is in the
2688 	  trash.
2689 	- other error codes specifying why the application cannot be used.
2690 */
2691 static
2692 status_t
2693 can_app_be_used(const entry_ref *ref)
2694 {
2695 	status_t error = (ref ? B_OK : B_BAD_VALUE);
2696 	// check whether the file exists and is a file.
2697 	BEntry entry;
2698 	if (error == B_OK)
2699 		error = entry.SetTo(ref, true);
2700 	if (error == B_OK && !entry.Exists())
2701 		error = B_ENTRY_NOT_FOUND;
2702 	if (error == B_OK && !entry.IsFile())
2703 		error = B_IS_A_DIRECTORY;
2704 	// check whether the file is in trash
2705 	BPath trashPath;
2706 	BDirectory directory;
2707 	if (error == B_OK
2708 		&& find_directory(B_TRASH_DIRECTORY, &trashPath) == B_OK
2709 		&& directory.SetTo(trashPath.Path()) == B_OK
2710 		&& directory.Contains(&entry)) {
2711 		error = B_LAUNCH_FAILED_APP_IN_TRASH;
2712 	}
2713 	return error;
2714 }
2715 
2716 // compare_version_infos
2717 /*!	\brief Compares the supplied version infos.
2718 	\param info1 The first info.
2719 	\param info2 The second info.
2720 	\return \c -1, if the first info is less than the second one, \c 1, if
2721 			the first one is greater than the second one, and \c 0, if both
2722 			are equal.
2723 */
2724 static
2725 int32
2726 compare_version_infos(const version_info &info1, const version_info &info2)
2727 {
2728 	int32 result = 0;
2729 	if (info1.major < info2.major)
2730 		result = -1;
2731 	else if (info1.major > info2.major)
2732 		result = 1;
2733 	else if (info1.middle < info2.middle)
2734 		result = -1;
2735 	else if (info1.middle > info2.middle)
2736 		result = 1;
2737 	else if (info1.minor < info2.minor)
2738 		result = -1;
2739 	else if (info1.minor > info2.minor)
2740 		result = 1;
2741 	else if (info1.variety < info2.variety)
2742 		result = -1;
2743 	else if (info1.variety > info2.variety)
2744 		result = 1;
2745 	else if (info1.internal < info2.internal)
2746 		result = -1;
2747 	else if (info1.internal > info2.internal)
2748 		result = 1;
2749 	return result;
2750 }
2751 
2752 // compare_app_versions
2753 /*!	\brief Compares the version of two applications.
2754 
2755 	If both files have a version info, then those are compared.
2756 	If one file has a version info, it is said to be greater. If both
2757 	files have no version info, their modification times are compared.
2758 
2759 	\param app1 An entry_ref referring to the first application.
2760 	\param app2 An entry_ref referring to the second application.
2761 	\return \c -1, if the first application version is less than the second
2762 			one, \c 1, if the first one is greater than the second one, and
2763 			\c 0, if both are equal.
2764 */
2765 static
2766 int32
2767 compare_app_versions(const entry_ref *app1, const entry_ref *app2)
2768 {
2769 	BFile file1, file2;
2770 	BAppFileInfo appFileInfo1, appFileInfo2;
2771 	file1.SetTo(app1, B_READ_ONLY);
2772 	file2.SetTo(app2, B_READ_ONLY);
2773 	appFileInfo1.SetTo(&file1);
2774 	appFileInfo2.SetTo(&file2);
2775 	time_t modificationTime1 = 0;
2776 	time_t modificationTime2 = 0;
2777 	file1.GetModificationTime(&modificationTime1);
2778 	file2.GetModificationTime(&modificationTime2);
2779 	int32 result = 0;
2780 	version_info versionInfo1, versionInfo2;
2781 	bool hasVersionInfo1 = (appFileInfo1.GetVersionInfo(
2782 		&versionInfo1, B_APP_VERSION_KIND) == B_OK);
2783 	bool hasVersionInfo2 = (appFileInfo2.GetVersionInfo(
2784 		&versionInfo2, B_APP_VERSION_KIND) == B_OK);
2785 	if (hasVersionInfo1) {
2786 		if (hasVersionInfo2)
2787 			result = compare_version_infos(versionInfo1, versionInfo2);
2788 		else
2789 			result = 1;
2790 	} else {
2791 		if (hasVersionInfo2)
2792 			result = -1;
2793 		else if (modificationTime1 < modificationTime2)
2794 			result = -1;
2795 		else if (modificationTime1 > modificationTime2)
2796 			result = 1;
2797 	}
2798 	return result;
2799 }
2800 
2801