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