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