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