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