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