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