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