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