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