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