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