xref: /haiku/src/kits/app/Roster.cpp (revision 5b6fca06392320a9c32d542b519d8f4fe876aef2)
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 				strcpy(string, "application/");
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 	// find the app
2253 	entry_ref appRef;
2254 	char signature[B_MIME_TYPE_LENGTH];
2255 	uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
2256 	bool wasDocument = true;
2257 	status_t error = _ResolveApp(mimeType, docRef, &appRef, signature,
2258 		&appFlags, &wasDocument);
2259 	DBG(OUT("  find app: %s (%lx)\n", strerror(error), error));
2260 
2261 	// build an argument vector
2262 	ArgVector argVector;
2263 	if (error == B_OK) {
2264 		error = argVector.Init(argc, args, &appRef,
2265 			(wasDocument ? docRef : NULL));
2266 	}
2267 	DBG(OUT("  build argv: %s (%lx)\n", strerror(error), error));
2268 
2269 	// pre-register the app (but ignore scipts)
2270 	app_info appInfo;
2271 	bool isScript = wasDocument && docRef != NULL && *docRef == appRef;
2272 	bool alreadyRunning = false;
2273 	uint32 appToken = 0;
2274 	team_id team = -1;
2275 	uint32 otherAppFlags = B_REG_DEFAULT_APP_FLAGS;
2276 	if (error == B_OK && !isScript) {
2277 		error = _AddApplication(signature, &appRef, appFlags, -1, -1, -1, false,
2278 			&appToken, &team);
2279 		if (error == B_ALREADY_RUNNING) {
2280 			DBG(OUT("  already running\n"));
2281 			alreadyRunning = true;
2282 
2283 			// get the app flags for the running application
2284 			error = _IsAppRegistered(&appRef, team, appToken, NULL, &appInfo);
2285 			if (error == B_OK) {
2286 				otherAppFlags = appInfo.flags;
2287 				team = appInfo.team;
2288 			}
2289 		}
2290 		DBG(OUT("  pre-register: %s (%lx)\n", strerror(error), error));
2291 	}
2292 
2293 	// launch the app
2294 	if (error == B_OK && !alreadyRunning) {
2295 		DBG(OUT("  token: %lu\n", appToken));
2296 		// load the app image
2297 		thread_id appThread = load_image(argVector.Count(),
2298 			const_cast<const char**>(argVector.Args()),
2299 			const_cast<const char**>(environ));
2300 
2301 		// get the app team
2302 		if (appThread >= 0) {
2303 			thread_info threadInfo;
2304 			error = get_thread_info(appThread, &threadInfo);
2305 			if (error == B_OK)
2306 				team = threadInfo.team;
2307 		} else if (wasDocument && appThread == B_NOT_AN_EXECUTABLE)
2308 			error = B_LAUNCH_FAILED_EXECUTABLE;
2309 		else
2310 			error = appThread;
2311 
2312 		DBG(OUT("  load image: %s (%lx)\n", strerror(error), error));
2313 		// finish the registration
2314 		if (error == B_OK && !isScript)
2315 			error = _SetThreadAndTeam(appToken, appThread, team);
2316 
2317 		DBG(OUT("  set thread and team: %s (%lx)\n", strerror(error), error));
2318 		// resume the launched team
2319 		if (error == B_OK)
2320 			error = resume_thread(appThread);
2321 
2322 		DBG(OUT("  resume thread: %s (%lx)\n", strerror(error), error));
2323 		// on error: kill the launched team and unregister the app
2324 		if (error != B_OK) {
2325 			if (appThread >= 0)
2326 				kill_thread(appThread);
2327 			if (!isScript) {
2328 				_RemovePreRegApp(appToken);
2329 
2330 				if (!wasDocument) {
2331 					// Remove app hint if it's this one
2332 					BMimeType appType(signature);
2333 					entry_ref hintRef;
2334 
2335 					if (appType.InitCheck() == B_OK
2336 						&& appType.GetAppHint(&hintRef) == B_OK
2337 						&& appRef == hintRef)
2338 						appType.SetAppHint(NULL);
2339 				}
2340 			}
2341 		}
2342 	}
2343 
2344 	if (alreadyRunning && current_team() == team) {
2345 		// The target team is calling us, so we don't send it the message
2346 		// to prevent an endless loop
2347 		error = B_BAD_VALUE;
2348 	}
2349 
2350 	// send "on launch" messages
2351 	if (error == B_OK) {
2352 		// If the target app is B_ARGV_ONLY, only if it is newly launched
2353 		// messages are sent to it (namely B_ARGV_RECEIVED and B_READY_TO_RUN).
2354 		// An already running B_ARGV_ONLY app won't get any messages.
2355 		bool argvOnly = (appFlags & B_ARGV_ONLY)
2356 			|| (alreadyRunning && (otherAppFlags & B_ARGV_ONLY));
2357 		const BList* _messageList = (argvOnly ? NULL : messageList);
2358 		// don't send ref, if it refers to the app or is included in the
2359 		// argument vector
2360 		const entry_ref* _ref = argvOnly || !wasDocument
2361 			|| argVector.Count() > 1 ? NULL : docRef;
2362 		if (!(argvOnly && alreadyRunning)) {
2363 			_SendToRunning(team, argVector.Count(), argVector.Args(),
2364 				_messageList, _ref, alreadyRunning);
2365 		}
2366 	}
2367 
2368 	// set return values
2369 	if (error == B_OK) {
2370 		if (alreadyRunning)
2371 			error = B_ALREADY_RUNNING;
2372 		else if (_appTeam)
2373 			*_appTeam = team;
2374 	}
2375 
2376 	DBG(OUT("BRoster::_LaunchApp() done: %s (%lx)\n",
2377 		strerror(error), error));
2378 	return error;
2379 }
2380 
2381 
2382 void
2383 BRoster::_SetAppFlags(team_id team, uint32 flags) const
2384 {
2385 }
2386 
2387 
2388 void
2389 BRoster::_DumpRoster() const
2390 {
2391 }
2392 
2393 
2394 /*!	\brief Finds an application associated with a MIME type or a file.
2395 
2396 	It does also supply the caller with some more information about the
2397 	application, like signature, app flags and whether the supplied
2398 	MIME type/entry_ref already identified an application.
2399 
2400 	At least one of \a inType or \a ref must not be \c NULL. If \a inType is
2401 	supplied, \a ref is ignored.
2402 
2403 	If \a ref refers to a link, it is updated with the entry_ref for the
2404 	resolved entry.
2405 
2406 	\see FindApp() for how the application is searched.
2407 
2408 	\a appSig is set to a string with length 0, if the found application
2409 	has no signature.
2410 
2411 	\param inType The MIME type for which an application shall be found.
2412 		   May be \c NULL.
2413 	\param ref The file for which an application shall be found.
2414 		   May be \c NULL.
2415 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2416 		   a reference to the found application's executable. May be \c NULL.
2417 	\param appSig A pointer to a pre-allocated char buffer of at least size
2418 		   \c B_MIME_TYPE_LENGTH to be filled with the signature of the found
2419 		   application. May be \c NULL.
2420 	\param appFlags A pointer to a pre-allocated uint32 variable to be filled
2421 		   with the app flags of the found application. May be \c NULL.
2422 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2423 		   \c true, if the supplied file was not identifying an application,
2424 		   to \c false otherwise. Has no meaning, if a \a inType is supplied.
2425 		   May be \c NULL.
2426 	\return
2427 	- \c B_OK: Everything went fine.
2428 	- \c B_BAD_VALUE: \c NULL \a inType and \a ref.
2429 	- \see FindApp() for other error codes.
2430 */
2431 status_t
2432 BRoster::_ResolveApp(const char* inType, entry_ref* ref,
2433 	entry_ref* _appRef, char* _appSig, uint32* _appFlags,
2434 	bool* _wasDocument) const
2435 {
2436 	if ((inType == NULL && ref == NULL)
2437 		|| (inType != NULL && strlen(inType) >= B_MIME_TYPE_LENGTH))
2438 		return B_BAD_VALUE;
2439 
2440 	// find the app
2441 	BMimeType appMeta;
2442 	BFile appFile;
2443 	entry_ref appRef;
2444 	status_t error;
2445 
2446 	if (inType)
2447 		error = _TranslateType(inType, &appMeta, &appRef, &appFile);
2448 	else {
2449 		error = _TranslateRef(ref, &appMeta, &appRef, &appFile,
2450 			_wasDocument);
2451 	}
2452 
2453 	// create meta mime
2454 	if (error == B_OK) {
2455 		BPath path;
2456 		if (path.SetTo(&appRef) == B_OK)
2457 			create_app_meta_mime(path.Path(), false, true, false);
2458 	}
2459 
2460 	// set the app hint on the type -- but only if the file has the
2461 	// respective signature, otherwise unset the app hint
2462 	BAppFileInfo appFileInfo;
2463 	if (error == B_OK) {
2464 		char signature[B_MIME_TYPE_LENGTH];
2465 		if (appFileInfo.SetTo(&appFile) == B_OK
2466 			&& appFileInfo.GetSignature(signature) == B_OK) {
2467 			if (!strcasecmp(appMeta.Type(), signature)) {
2468 				// Only set the app hint if there is none yet
2469 				entry_ref dummyRef;
2470 				if (appMeta.GetAppHint(&dummyRef) != B_OK)
2471 					appMeta.SetAppHint(&appRef);
2472 			} else {
2473 				appMeta.SetAppHint(NULL);
2474 				appMeta.SetTo(signature);
2475 			}
2476 		} else
2477 			appMeta.SetAppHint(NULL);
2478 	}
2479 
2480 	// set the return values
2481 	if (error == B_OK) {
2482 		if (_appRef)
2483 			*_appRef = appRef;
2484 
2485 		if (_appSig) {
2486 			// there's no warranty, that appMeta is valid
2487 			if (appMeta.IsValid())
2488 				strcpy(_appSig, appMeta.Type());
2489 			else
2490 				_appSig[0] = '\0';
2491 		}
2492 
2493 		if (_appFlags) {
2494 			// if an error occurs here, we don't care and just set a default
2495 			// value
2496 			if (appFileInfo.InitCheck() != B_OK
2497 				|| appFileInfo.GetAppFlags(_appFlags) != B_OK) {
2498 				*_appFlags = B_REG_DEFAULT_APP_FLAGS;
2499 			}
2500 		}
2501 	} else {
2502 		// unset the ref on error
2503 		if (_appRef)
2504 			*_appRef = appRef;
2505 	}
2506 
2507 	return error;
2508 }
2509 
2510 
2511 /*!	\brief Finds an application associated with a file.
2512 
2513 	\a appMeta is left unmodified, if the file is executable, but has no
2514 	signature.
2515 
2516 	\see FindApp() for how the application is searched.
2517 
2518 	If \a ref refers to a link, it is updated with the entry_ref for the
2519 	resolved entry.
2520 
2521 	\param ref The file for which an application shall be found.
2522 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2523 		   signature of the found application.
2524 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2525 		   a reference to the found application's executable.
2526 	\param appFile A pointer to a pre-allocated BFile to be set to the
2527 		   executable of the found application.
2528 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2529 		   \c true, if the supplied file was not identifying an application,
2530 		   to \c false otherwise. May be \c NULL.
2531 	\return
2532 	- \c B_OK: Everything went fine.
2533 	- \c B_BAD_VALUE: \c NULL \a ref, \a appMeta, \a appRef or \a appFile.
2534 	- \see FindApp() for other error codes.
2535 */
2536 status_t
2537 BRoster::_TranslateRef(entry_ref* ref, BMimeType* appMeta,
2538 	entry_ref* appRef, BFile* appFile, bool* _wasDocument) const
2539 {
2540 	if (ref == NULL || appMeta == NULL || appRef == NULL || appFile == NULL)
2541 		return B_BAD_VALUE;
2542 
2543 	// resolve ref, if necessary
2544 	BEntry entry;
2545 	status_t error = entry.SetTo(ref, false);
2546 	if (error != B_OK)
2547 		return error;
2548 
2549 	if (entry.IsSymLink()) {
2550 		// ref refers to a link
2551 		if (entry.SetTo(ref, true) != B_OK || entry.GetRef(ref) != B_OK)
2552 			return B_LAUNCH_FAILED_NO_RESOLVE_LINK;
2553 	}
2554 
2555 	// init node
2556 	BNode node;
2557 	error = node.SetTo(ref);
2558 	if (error != B_OK)
2559 		return error;
2560 
2561 	// get permissions
2562 	mode_t permissions;
2563 	error = node.GetPermissions(&permissions);
2564 	if (error != B_OK)
2565 		return error;
2566 
2567 	if ((permissions & S_IXUSR) && node.IsFile()) {
2568 		// node is executable and a file
2569 		error = appFile->SetTo(ref, B_READ_ONLY);
2570 		if (error != B_OK)
2571 			return error;
2572 
2573 		// get the app's signature via a BAppFileInfo
2574 		BAppFileInfo appFileInfo;
2575 		error = appFileInfo.SetTo(appFile);
2576 		if (error != B_OK)
2577 			return error;
2578 
2579 		// don't worry, if the file doesn't have a signature, just
2580 		// unset the supplied object
2581 		char type[B_MIME_TYPE_LENGTH];
2582 		if (appFileInfo.GetSignature(type) == B_OK) {
2583 			error = appMeta->SetTo(type);
2584 			if (error != B_OK)
2585 				return error;
2586 		} else
2587 			appMeta->Unset();
2588 
2589 		// If the file type indicates that the file is an application, we've
2590 		// definitely got what we're looking for.
2591 		bool isDocument = true;
2592 		if (_GetFileType(ref, &appFileInfo, type) == B_OK
2593 			&& strcasecmp(type, B_APP_MIME_TYPE) == 0) {
2594 			isDocument = false;
2595 		}
2596 
2597 		// If our file is not an application executable, we probably have a
2598 		// script. Check whether the file has a preferred application set. If
2599 		// so, we fall through and use the preferred app instead. Otherwise
2600 		// we're done.
2601 		char preferredApp[B_MIME_TYPE_LENGTH];
2602 		if (!isDocument || appFileInfo.GetPreferredApp(preferredApp) != B_OK) {
2603 			*appRef = *ref;
2604 			if (_wasDocument)
2605 				*_wasDocument = isDocument;
2606 			return B_OK;
2607 		}
2608 
2609 		// Executable file, but not an application, and it has a preferred
2610 		// application set. Fall through...
2611 	}
2612 
2613 	// the node is not exectuable or not a file
2614 	// init a node info
2615 	BNodeInfo nodeInfo;
2616 	error = nodeInfo.SetTo(&node);
2617 	if (error != B_OK)
2618 		return error;
2619 
2620 	// if the file has a preferred app, let _TranslateType() find
2621 	// it for us
2622 	char preferredApp[B_MIME_TYPE_LENGTH];
2623 	if (nodeInfo.GetPreferredApp(preferredApp) == B_OK
2624 		&& _TranslateType(preferredApp, appMeta, appRef, appFile) == B_OK) {
2625 		if (_wasDocument)
2626 			*_wasDocument = true;
2627 		return B_OK;
2628 	}
2629 
2630 	// no preferred app or existing one was not found -- we
2631 	// need to get the file's type
2632 
2633 	// get the type from the file
2634 	char fileType[B_MIME_TYPE_LENGTH];
2635 	error = _GetFileType(ref, &nodeInfo, fileType);
2636 	if (error != B_OK)
2637 		return error;
2638 
2639 	// now let _TranslateType() do the actual work
2640 	error = _TranslateType(fileType, appMeta, appRef, appFile);
2641 	if (error != B_OK)
2642 		return error;
2643 
2644 	if (_wasDocument)
2645 		*_wasDocument = true;
2646 
2647 	return B_OK;
2648 }
2649 
2650 
2651 /*!	\brief Finds an application associated with a MIME type.
2652 
2653 	\see FindApp() for how the application is searched.
2654 
2655 	\param mimeType The MIME type for which an application shall be found.
2656 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2657 		   signature of the found application.
2658 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2659 		   a reference to the found application's executable.
2660 	\param appFile A pointer to a pre-allocated BFile to be set to the
2661 		   executable of the found application.
2662 	\return
2663 	- \c B_OK: Everything went fine.
2664 	- \c B_BAD_VALUE: \c NULL \a mimeType, \a appMeta, \a appRef or \a appFile.
2665 	- \see FindApp() for other error codes.
2666 */
2667 status_t
2668 BRoster::_TranslateType(const char* mimeType, BMimeType* appMeta,
2669 	entry_ref* appRef, BFile* appFile) const
2670 {
2671 	if (mimeType == NULL || appMeta == NULL || appRef == NULL
2672 		|| appFile == NULL || strlen(mimeType) >= B_MIME_TYPE_LENGTH)
2673 		return B_BAD_VALUE;
2674 
2675 	// Create a BMimeType and check, if the type is installed.
2676 	BMimeType type;
2677 	status_t error = type.SetTo(mimeType);
2678 
2679 	// Get the preferred apps from the sub and super type.
2680 	char primarySignature[B_MIME_TYPE_LENGTH];
2681 	char secondarySignature[B_MIME_TYPE_LENGTH];
2682 	primarySignature[0] = '\0';
2683 	secondarySignature[0] = '\0';
2684 
2685 	if (error == B_OK) {
2686 		BMimeType superType;
2687 		if (type.GetSupertype(&superType) == B_OK)
2688 			superType.GetPreferredApp(secondarySignature);
2689 		if (type.IsInstalled()) {
2690 			if (type.GetPreferredApp(primarySignature) != B_OK) {
2691 				// The type is installed, but has no preferred app.
2692 				primarySignature[0] = '\0';
2693 			} else if (!strcmp(primarySignature, secondarySignature)) {
2694 				// Both types have the same preferred app, there is
2695 				// no point in testing it twice.
2696 				secondarySignature[0] = '\0';
2697 			}
2698 		} else {
2699 			// The type is not installed. We assume it is an app signature.
2700 			strcpy(primarySignature, mimeType);
2701 		}
2702 	}
2703 
2704 	// We will use this BMessage "signatures" to hold all supporting apps
2705 	// so we can iterator over them in the preferred order. We include
2706 	// the supporting apps in such a way that the configured preferred
2707 	// applications for the MIME type are in front of other supporting
2708 	// applications for the sub and the super type respectively.
2709 	const char* kSigField = "applications";
2710 	BMessage signatures;
2711 	bool addedSecondarySignature = false;
2712 	if (error == B_OK) {
2713 		if (primarySignature[0] != '\0')
2714 			error = signatures.AddString(kSigField, primarySignature);
2715 		else {
2716 			// If there is a preferred app configured for the super type,
2717 			// but no preferred type for the sub-type, add the preferred
2718 			// super type handler in front of any other handlers. This way
2719 			// we fall-back to non-preferred but supporting apps only in the
2720 			// case when there is a preferred handler for the sub-type but
2721 			// it cannot be resolved (misconfiguration).
2722 			if (secondarySignature[0] != '\0') {
2723 				error = signatures.AddString(kSigField, secondarySignature);
2724 				addedSecondarySignature = true;
2725 			}
2726 		}
2727 	}
2728 
2729 	BMessage supportingSignatures;
2730 	if (error == B_OK
2731 		&& type.GetSupportingApps(&supportingSignatures) == B_OK) {
2732 		int32 subCount;
2733 		if (supportingSignatures.FindInt32("be:sub", &subCount) != B_OK)
2734 			subCount = 0;
2735 		// Add all signatures with direct support for the sub-type.
2736 		const char* supportingType;
2737 		if (!addedSecondarySignature) {
2738 			// Try to add the secondarySignature in front of all other
2739 			// supporting apps, if we find it among those.
2740 			for (int32 i = 0; error == B_OK && i < subCount
2741 					&& supportingSignatures.FindString(kSigField, i,
2742 						&supportingType) == B_OK; i++) {
2743 				if (strcmp(primarySignature, supportingType) != 0
2744 					&& strcmp(secondarySignature, supportingType) == 0) {
2745 					error = signatures.AddString(kSigField, supportingType);
2746 					addedSecondarySignature = true;
2747 					break;
2748 				}
2749 			}
2750 		}
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 			}
2758 		}
2759 		// Add the preferred type of the super type here before adding
2760 		// the other types supporting the super type, but only if we have
2761 		// not already added it in case there was no preferred app for the
2762 		// sub-type configured.
2763 		if (error == B_OK && !addedSecondarySignature
2764 			&& secondarySignature[0] != '\0') {
2765 			error = signatures.AddString(kSigField, secondarySignature);
2766 		}
2767 		// Add all signatures with support for the super-type.
2768 		for (int32 i = subCount; error == B_OK
2769 				&& supportingSignatures.FindString(kSigField, i,
2770 					&supportingType) == B_OK; i++) {
2771 			// Don't add the signature if it's one of the preferred apps
2772 			// already.
2773 			if (strcmp(primarySignature, supportingType) != 0
2774 				&& strcmp(secondarySignature, supportingType) != 0) {
2775 				error = signatures.AddString(kSigField, supportingType);
2776 			}
2777 		}
2778 	} else {
2779 		// Failed to get supporting apps, just add the preferred apps.
2780 		if (error == B_OK && secondarySignature[0] != '\0')
2781 			error = signatures.AddString(kSigField, secondarySignature);
2782 	}
2783 
2784 	if (error != B_OK)
2785 		return error;
2786 
2787 	// Set an error in case we can't resolve a single supporting app.
2788 	error = B_LAUNCH_FAILED_NO_PREFERRED_APP;
2789 
2790 	// See if we can find a good application that is valid from the messege.
2791 	const char* signature;
2792 	for (int32 i = 0;
2793 		signatures.FindString(kSigField, i, &signature) == B_OK; i++) {
2794 		if (signature[0] == '\0')
2795 			continue;
2796 
2797 		error = appMeta->SetTo(signature);
2798 
2799 		// Check, whether the signature is installed and has an app hint
2800 		bool appFound = false;
2801 		if (error == B_OK && appMeta->GetAppHint(appRef) == B_OK) {
2802 			// Resolve symbolic links, if necessary
2803 			BEntry entry;
2804 			if (entry.SetTo(appRef, true) == B_OK && entry.IsFile()
2805 				&& entry.GetRef(appRef) == B_OK) {
2806 				appFound = true;
2807 			} else {
2808 				// Bad app hint -- remove it
2809 				appMeta->SetAppHint(NULL);
2810 			}
2811 		}
2812 
2813 		// In case there is no app hint or it is invalid, we need to query for
2814 		// the app.
2815 		if (error == B_OK && !appFound)
2816 			error = query_for_app(appMeta->Type(), appRef);
2817 		if (error == B_OK)
2818 			error = appFile->SetTo(appRef, B_READ_ONLY);
2819 		// check, whether the app can be used
2820 		if (error == B_OK)
2821 			error = can_app_be_used(appRef);
2822 
2823 		if (error == B_OK)
2824 			break;
2825 	}
2826 
2827 	return error;
2828 }
2829 
2830 
2831 /*!	\brief Gets the type of a file either from the node info or by sniffing.
2832 
2833 	The method first tries to get the file type from the supplied node info. If
2834 	that didn't work, the given entry ref is sniffed.
2835 
2836 	\param file An entry_ref referring to the file in question.
2837 	\param nodeInfo A BNodeInfo initialized to the file.
2838 	\param mimeType A pointer to a pre-allocated char buffer of at least size
2839 		   \c B_MIME_TYPE_LENGTH to be filled with the MIME type sniffed for
2840 		   the file.
2841 	\return
2842 	- \c B_OK: Everything went fine.
2843 	- \c B_BAD_VALUE: \c NULL \a file, \a nodeInfo or \a mimeType.
2844 	- other errors
2845 */
2846 status_t
2847 BRoster::_GetFileType(const entry_ref* file, BNodeInfo* nodeInfo,
2848 	char* mimeType) const
2849 {
2850 	// first try the node info
2851 	if (nodeInfo->GetType(mimeType) == B_OK)
2852 		return B_OK;
2853 
2854 	// Try to update the file's MIME info and just read the updated type.
2855 	// If that fails, sniff manually.
2856 	BPath path;
2857 	if (path.SetTo(file) != B_OK
2858 		|| update_mime_info(path.Path(), false, true, false) != B_OK
2859 		|| nodeInfo->GetType(mimeType) != B_OK) {
2860 		BMimeType type;
2861 		status_t error = BMimeType::GuessMimeType(file, &type);
2862 		if (error != B_OK)
2863 			return error;
2864 
2865 		if (!type.IsValid())
2866 			return B_BAD_VALUE;
2867 
2868 		strcpy(mimeType, type.Type());
2869 	}
2870 
2871 	return B_OK;
2872 }
2873 
2874 
2875 /*!	\brief Sends messages to a running team.
2876 
2877 	In particular those messages are \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED,
2878 	\c B_READY_TO_RUN and other, arbitrary, ones.
2879 
2880 	If \a messageList is not \c NULL or empty, those messages are sent first,
2881 	then follow \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED and finally
2882 	\c B_READ_TO_RUN.
2883 
2884 	\c B_ARGV_RECEIVED is sent only, if \a args is not \c NULL and contains
2885 	more than one element. \c B_REFS_RECEIVED is sent only, if \a ref is not
2886 	\c NULL.
2887 
2888 	The ownership of all supplied objects retains to the caller.
2889 
2890 	\param team The team ID of the target application.
2891 	\param argc Number of elements in \a args.
2892 	\param args Argument vector to be sent to the target. May be \c NULL.
2893 	\param messageList List of BMessages to be sent to the target. May be
2894 		   \c NULL or empty.
2895 	\param ref entry_ref to be sent to the target. May be \c NULL.
2896 	\param alreadyRunning \c true, if the target app is not newly launched,
2897 		   but was already running, \c false otherwise (a \c B_READY_TO_RUN
2898 		   message will be sent in this case).
2899 	\return
2900 	- \c B_OK: Everything went fine.
2901 	- an error code otherwise
2902 */
2903 status_t
2904 BRoster::_SendToRunning(team_id team, int argc, const char* const* args,
2905 	const BList* messageList, const entry_ref* ref,
2906 	bool alreadyRunning) const
2907 {
2908 	status_t error = B_OK;
2909 	// Construct a messenger to the app: We can't use the public constructor,
2910 	// since the target application may be B_ARGV_ONLY.
2911 	app_info info;
2912 	error = GetRunningAppInfo(team, &info);
2913 	if (error == B_OK) {
2914 		BMessenger messenger;
2915 		BMessenger::Private(messenger).SetTo(team, info.port,
2916 			B_PREFERRED_TOKEN);
2917 
2918 		// send messages from the list
2919 		if (messageList) {
2920 			for (int32 i = 0;
2921 				 BMessage* message = (BMessage*)messageList->ItemAt(i);
2922 				 i++) {
2923 				messenger.SendMessage(message);
2924 			}
2925 		}
2926 
2927 		// send B_ARGV_RECEIVED or B_REFS_RECEIVED or B_SILENT_RELAUNCH (if
2928 		// already running)
2929 		if (args && argc > 1) {
2930 			BMessage message(B_ARGV_RECEIVED);
2931 			message.AddInt32("argc", argc);
2932 			for (int32 i = 0; i < argc; i++)
2933 				message.AddString("argv", args[i]);
2934 
2935 			// also add current working directory
2936 			char cwd[B_PATH_NAME_LENGTH];
2937 			if (getcwd(cwd, B_PATH_NAME_LENGTH) != NULL)
2938 				message.AddString("cwd", cwd);
2939 
2940 			messenger.SendMessage(&message);
2941 		} else if (ref) {
2942 			printf("_SendToRunning : B_REFS_RECEIVED\n");
2943 			BMessage message(B_REFS_RECEIVED);
2944 			message.AddRef("refs", ref);
2945 			messenger.SendMessage(&message);
2946 		} else if (alreadyRunning && (!messageList || messageList->IsEmpty()))
2947 			messenger.SendMessage(B_SILENT_RELAUNCH);
2948 
2949 		// send B_READY_TO_RUN
2950 		if (!alreadyRunning)
2951 			messenger.SendMessage(B_READY_TO_RUN);
2952 	}
2953 	return error;
2954 }
2955 
2956 
2957 void
2958 BRoster::_InitMessenger()
2959 {
2960 	DBG(OUT("BRoster::InitMessengers()\n"));
2961 
2962 	// find the registrar port
2963 	port_id rosterPort = find_port(BPrivate::get_roster_port_name());
2964 	port_info info;
2965 	if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) {
2966 		DBG(OUT("  found roster port\n"));
2967 
2968 		BMessenger::Private(fMessenger).SetTo(info.team, rosterPort,
2969 			B_PREFERRED_TOKEN);
2970 	}
2971 
2972 	DBG(OUT("BRoster::InitMessengers() done\n"));
2973 }
2974 
2975 
2976 /*static*/ status_t
2977 BRoster::_InitMimeMessenger(void* data)
2978 {
2979 	BRoster* roster = (BRoster*)data;
2980 
2981 	// ask for the MIME messenger
2982 	// Generous 1s + 5s timeouts. It could actually be synchronous, but
2983 	// timeouts allow us to debug the registrar main thread.
2984 	BMessage request(B_REG_GET_MIME_MESSENGER);
2985 	BMessage reply;
2986 	status_t error = roster->fMessenger.SendMessage(&request, &reply, 1000000LL,
2987 		5000000LL);
2988 	if (error == B_OK && reply.what == B_REG_SUCCESS) {
2989 		DBG(OUT("  got reply from roster\n"));
2990 			reply.FindMessenger("messenger", &roster->fMimeMessenger);
2991 	} else {
2992 		DBG(OUT("  no (useful) reply from roster: error: %lx: %s\n", error,
2993 			strerror(error)));
2994 		if (error == B_OK)
2995 			DBG(reply.PrintToStream());
2996 	}
2997 
2998 	return error;
2999 }
3000 
3001 
3002 BMessenger&
3003 BRoster::_MimeMessenger()
3004 {
3005 	__init_once(&fMimeMessengerInitOnce, &_InitMimeMessenger, this);
3006 	return fMimeMessenger;
3007 }
3008 
3009 
3010 /*! \brief Sends a request to the roster to add the application with the
3011 	given signature to the front of the recent apps list.
3012 */
3013 void
3014 BRoster::_AddToRecentApps(const char* appSig) const
3015 {
3016 	status_t error = B_OK;
3017 	// compose the request message
3018 	BMessage request(B_REG_ADD_TO_RECENT_APPS);
3019 	if (error == B_OK)
3020 		error = request.AddString("app sig", appSig);
3021 	// send the request
3022 	BMessage reply;
3023 	if (error == B_OK)
3024 		error = fMessenger.SendMessage(&request, &reply);
3025 	// evaluate the reply
3026 	status_t result;
3027 	if (error == B_OK) {
3028 		error = reply.what == B_REG_RESULT
3029 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
3030 	}
3031 	if (error == B_OK)
3032 		error = reply.FindInt32("result", &result);
3033 	if (error == B_OK)
3034 		error = result;
3035 	// Nothing to return... how sad :-(
3036 	// return error;
3037 }
3038 
3039 
3040 /*! \brief Sends a request to the roster to clear the recent
3041 	documents list.
3042 */
3043 void
3044 BRoster::_ClearRecentDocuments() const
3045 {
3046 	BMessage request(B_REG_CLEAR_RECENT_DOCUMENTS);
3047 	BMessage reply;
3048 	fMessenger.SendMessage(&request, &reply);
3049 }
3050 
3051 
3052 /*! \brief Sends a request to the roster to clear the recent
3053 	documents list.
3054 */
3055 void
3056 BRoster::_ClearRecentFolders() const
3057 {
3058 	BMessage request(B_REG_CLEAR_RECENT_FOLDERS);
3059 	BMessage reply;
3060 	fMessenger.SendMessage(&request, &reply);
3061 }
3062 
3063 
3064 /*! \brief Sends a request to the roster to clear the recent
3065 	documents list.
3066 */
3067 void
3068 BRoster::_ClearRecentApps() const
3069 {
3070 	BMessage request(B_REG_CLEAR_RECENT_APPS);
3071 	BMessage reply;
3072 	fMessenger.SendMessage(&request, &reply);
3073 }
3074 
3075 
3076 /*! \brief Loads the system's recently used document, folder, and
3077 	application lists from the specified file.
3078 
3079 	\note The current lists are cleared before loading the new lists
3080 
3081 	\param filename The name of the file to load from
3082 */
3083 void
3084 BRoster::_LoadRecentLists(const char* filename) const
3085 {
3086 	status_t error = B_OK;
3087 	// compose the request message
3088 	BMessage request(B_REG_LOAD_RECENT_LISTS);
3089 	if (error == B_OK)
3090 		error = request.AddString("filename", filename);
3091 	// send the request
3092 	BMessage reply;
3093 	if (error == B_OK)
3094 		error = fMessenger.SendMessage(&request, &reply);
3095 	// evaluate the reply
3096 	status_t result;
3097 	if (error == B_OK) {
3098 		error = reply.what == B_REG_RESULT
3099 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
3100 	}
3101 	if (error == B_OK)
3102 		error = reply.FindInt32("result", &result);
3103 	if (error == B_OK)
3104 		error = result;
3105 	// Nothing to return... how sad :-(
3106 	// return error;
3107 }
3108 
3109 
3110 /*! \brief Saves the system's recently used document, folder, and
3111 	application lists to the specified file.
3112 
3113 	\param filename The name of the file to save to
3114 */
3115 void
3116 BRoster::_SaveRecentLists(const char* filename) const
3117 {
3118 	status_t error = B_OK;
3119 	// compose the request message
3120 	BMessage request(B_REG_SAVE_RECENT_LISTS);
3121 	if (error == B_OK)
3122 		error = request.AddString("filename", filename);
3123 	// send the request
3124 	BMessage reply;
3125 	if (error == B_OK)
3126 		error = fMessenger.SendMessage(&request, &reply);
3127 	// evaluate the reply
3128 	status_t result;
3129 	if (error == B_OK) {
3130 		error = reply.what == B_REG_RESULT
3131 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
3132 	}
3133 	if (error == B_OK)
3134 		error = reply.FindInt32("result", &result);
3135 	if (error == B_OK)
3136 		error = result;
3137 	// Nothing to return... how sad :-(
3138 	// return error;
3139 }
3140