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