xref: /haiku/src/kits/app/Roster.cpp (revision 5629675a326ecf2ff3fd23f154beb525c171048d)
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 	do {
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 	} while (false);
1975 
1976 	if (alreadyRunning && current_team() == team) {
1977 		// The target team is calling us, so we don't send it the message
1978 		// to prevent an endless loop
1979 		error = B_BAD_VALUE;
1980 	}
1981 
1982 	// send "on launch" messages
1983 	if (error == B_OK && !fNoRegistrar) {
1984 		// If the target app is B_ARGV_ONLY, only if it is newly launched
1985 		// messages are sent to it (namely B_ARGV_RECEIVED and B_READY_TO_RUN).
1986 		// An already running B_ARGV_ONLY app won't get any messages.
1987 		bool argvOnly = (appFlags & B_ARGV_ONLY) != 0
1988 			|| (alreadyRunning && (otherAppFlags & B_ARGV_ONLY) != 0);
1989 		const BList* _messageList = (argvOnly ? NULL : messageList);
1990 		// don't send ref, if it refers to the app or is included in the
1991 		// argument vector
1992 		const entry_ref* _ref = argvOnly || !wasDocument
1993 			|| argVector.Count() > 1 ? NULL : docRef;
1994 		if (!(argvOnly && alreadyRunning)) {
1995 			_SendToRunning(team, argVector.Count(), argVector.Args(),
1996 				_messageList, _ref, alreadyRunning);
1997 		}
1998 	}
1999 
2000 	// set return values
2001 	if (error == B_OK) {
2002 		if (alreadyRunning)
2003 			error = B_ALREADY_RUNNING;
2004 		else if (_appTeam)
2005 			*_appTeam = team;
2006 
2007 		if (_appThread != NULL)
2008 			*_appThread = appThread;
2009 		if (_appPort != NULL)
2010 			*_appPort = appPort;
2011 		if (_appToken != NULL)
2012 			*_appToken = appToken;
2013 	}
2014 
2015 	DBG(OUT("BRoster::_LaunchApp() done: %s (%" B_PRIx32 ")\n",
2016 		strerror(error), error));
2017 
2018 	return error;
2019 }
2020 
2021 
2022 void
2023 BRoster::_SetAppFlags(team_id team, uint32 flags) const
2024 {
2025 }
2026 
2027 
2028 void
2029 BRoster::_DumpRoster() const
2030 {
2031 }
2032 
2033 
2034 /*!	Finds an application associated with a MIME type or a file.
2035 
2036 	It does also supply the caller with some more information about the
2037 	application, like signature, app flags and whether the supplied
2038 	MIME type/entry_ref already identified an application.
2039 
2040 	At least one of \a inType or \a ref must not be \c NULL. If \a inType is
2041 	supplied, \a ref is ignored.
2042 
2043 	If \a ref refers to a link, it is updated with the entry_ref for the
2044 	resolved entry.
2045 
2046 	\see FindApp() for how the application is searched.
2047 
2048 	\a signature is set to a string with length 0, if the found
2049 	application has no signature.
2050 
2051 	\param inType The MIME type for which an application shall be found.
2052 	       May be \c NULL.
2053 	\param ref The file for which an application shall be found.
2054 	       May be \c NULL.
2055 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2056 	       a reference to the found application's executable. May be \c NULL.
2057 	\param signature A pointer to a pre-allocated char buffer of at
2058 	       least size \c B_MIME_TYPE_LENGTH to be filled with the signature of
2059 	       the found application. May be \c NULL.
2060 	\param appFlags A pointer to a pre-allocated uint32 variable to be filled
2061 	       with the app flags of the found application. May be \c NULL.
2062 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2063 	       \c true, if the supplied file was not identifying an application,
2064 	       to \c false otherwise. Has no meaning, if a \a inType is supplied.
2065 	       May be \c NULL.
2066 
2067 	\return A status code.
2068 	\retval B_OK Everything went fine.
2069 	\retval B_BAD_VALUE \c NULL \a inType and \a ref.
2070 
2071 	\see FindApp() for other error codes.
2072 */
2073 status_t
2074 BRoster::_ResolveApp(const char* inType, entry_ref* ref,
2075 	entry_ref* _appRef, char* _signature, uint32* _appFlags,
2076 	bool* _wasDocument) const
2077 {
2078 	if ((inType == NULL && ref == NULL)
2079 		|| (inType != NULL && strlen(inType) >= B_MIME_TYPE_LENGTH))
2080 		return B_BAD_VALUE;
2081 
2082 	// find the app
2083 	BMimeType appMeta;
2084 	BFile appFile;
2085 	entry_ref appRef;
2086 	status_t error;
2087 
2088 	if (inType != NULL) {
2089 		error = _TranslateType(inType, &appMeta, &appRef, &appFile);
2090 		if (_wasDocument != NULL)
2091 			*_wasDocument = !(appMeta == inType);
2092 	} else {
2093 		error = _TranslateRef(ref, &appMeta, &appRef, &appFile,
2094 			_wasDocument);
2095 	}
2096 
2097 	// create meta mime
2098 	if (!fNoRegistrar && error == B_OK) {
2099 		BPath path;
2100 		if (path.SetTo(&appRef) == B_OK)
2101 			create_app_meta_mime(path.Path(), false, true, false);
2102 	}
2103 
2104 	// set the app hint on the type -- but only if the file has the
2105 	// respective signature, otherwise unset the app hint
2106 	BAppFileInfo appFileInfo;
2107 	if (!fNoRegistrar && error == B_OK) {
2108 		char signature[B_MIME_TYPE_LENGTH];
2109 		if (appFileInfo.SetTo(&appFile) == B_OK
2110 			&& appFileInfo.GetSignature(signature) == B_OK) {
2111 			if (!strcasecmp(appMeta.Type(), signature)) {
2112 				// Only set the app hint if there is none yet
2113 				entry_ref dummyRef;
2114 				if (appMeta.GetAppHint(&dummyRef) != B_OK)
2115 					appMeta.SetAppHint(&appRef);
2116 			} else {
2117 				appMeta.SetAppHint(NULL);
2118 				appMeta.SetTo(signature);
2119 			}
2120 		} else
2121 			appMeta.SetAppHint(NULL);
2122 	}
2123 
2124 	// set the return values
2125 	if (error == B_OK) {
2126 		if (_appRef)
2127 			*_appRef = appRef;
2128 
2129 		if (_signature != NULL) {
2130 			// there's no warranty, that appMeta is valid
2131 			if (appMeta.IsValid()) {
2132 				strlcpy(_signature, appMeta.Type(),
2133 					B_MIME_TYPE_LENGTH);
2134 			} else
2135 				_signature[0] = '\0';
2136 		}
2137 
2138 		if (_appFlags != NULL) {
2139 			// if an error occurs here, we don't care and just set a default
2140 			// value
2141 			if (appFileInfo.InitCheck() != B_OK
2142 				|| appFileInfo.GetAppFlags(_appFlags) != B_OK) {
2143 				*_appFlags = B_REG_DEFAULT_APP_FLAGS;
2144 			}
2145 		}
2146 	} else {
2147 		// unset the ref on error
2148 		if (_appRef != NULL)
2149 			*_appRef = appRef;
2150 	}
2151 
2152 	return error;
2153 }
2154 
2155 
2156 /*!	\brief Finds an application associated with a file.
2157 
2158 	\a appMeta is left unmodified, if the file is executable, but has no
2159 	signature.
2160 
2161 	\see FindApp() for how the application is searched.
2162 
2163 	If \a ref refers to a link, it is updated with the entry_ref for the
2164 	resolved entry.
2165 
2166 	\param ref The file for which an application shall be found.
2167 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2168 	       signature of the found application.
2169 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2170 	       a reference to the found application's executable.
2171 	\param appFile A pointer to a pre-allocated BFile to be set to the
2172 	       executable of the found application.
2173 	\param wasDocument A pointer to a pre-allocated bool variable to be set to
2174 	       \c true, if the supplied file was not identifying an application,
2175 	       to \c false otherwise. May be \c NULL.
2176 
2177 	\return A status code.
2178 	\retval B_OK: Everything went fine.
2179 	\retval B_BAD_VALUE: \c NULL \a ref, \a appMeta, \a appRef or \a appFile.
2180 
2181 	\see FindApp() for other error codes.
2182 */
2183 status_t
2184 BRoster::_TranslateRef(entry_ref* ref, BMimeType* appMeta,
2185 	entry_ref* appRef, BFile* appFile, bool* _wasDocument) const
2186 {
2187 	if (ref == NULL || appMeta == NULL || appRef == NULL || appFile == NULL)
2188 		return B_BAD_VALUE;
2189 
2190 	// resolve ref, if necessary
2191 	BEntry entry;
2192 	status_t error = entry.SetTo(ref, false);
2193 	if (error != B_OK)
2194 		return error;
2195 
2196 	if (entry.IsSymLink()) {
2197 		// ref refers to a link
2198 		if (entry.SetTo(ref, true) != B_OK || entry.GetRef(ref) != B_OK)
2199 			return B_LAUNCH_FAILED_NO_RESOLVE_LINK;
2200 	}
2201 
2202 	// init node
2203 	BNode node;
2204 	error = node.SetTo(ref);
2205 	if (error != B_OK)
2206 		return error;
2207 
2208 	// get permissions
2209 	mode_t permissions;
2210 	error = node.GetPermissions(&permissions);
2211 	if (error != B_OK)
2212 		return error;
2213 
2214 	if ((permissions & S_IXUSR) != 0 && node.IsFile()) {
2215 		// node is executable and a file
2216 		error = appFile->SetTo(ref, B_READ_ONLY);
2217 		if (error != B_OK)
2218 			return error;
2219 
2220 		// get the app's signature via a BAppFileInfo
2221 		BAppFileInfo appFileInfo;
2222 		error = appFileInfo.SetTo(appFile);
2223 		if (error != B_OK)
2224 			return error;
2225 
2226 		// don't worry, if the file doesn't have a signature, just
2227 		// unset the supplied object
2228 		char type[B_MIME_TYPE_LENGTH];
2229 		if (appFileInfo.GetSignature(type) == B_OK) {
2230 			error = appMeta->SetTo(type);
2231 			if (error != B_OK)
2232 				return error;
2233 		} else
2234 			appMeta->Unset();
2235 
2236 		// If the file type indicates that the file is an application, we've
2237 		// definitely got what we're looking for.
2238 		bool isDocument = true;
2239 		if (_GetFileType(ref, &appFileInfo, type) == B_OK
2240 			&& strcasecmp(type, B_APP_MIME_TYPE) == 0) {
2241 			isDocument = false;
2242 		}
2243 
2244 		// If our file is not an application executable, we probably have a
2245 		// script. Check whether the file has a preferred application set. If
2246 		// so, we fall through and use the preferred app instead. Otherwise
2247 		// we're done.
2248 		char preferredApp[B_MIME_TYPE_LENGTH];
2249 		if (!isDocument || appFileInfo.GetPreferredApp(preferredApp) != B_OK) {
2250 			*appRef = *ref;
2251 			if (_wasDocument != NULL)
2252 				*_wasDocument = isDocument;
2253 
2254 			return B_OK;
2255 		}
2256 
2257 		// Executable file, but not an application, and it has a preferred
2258 		// application set. Fall through...
2259 	}
2260 
2261 	// the node is not exectuable or not a file
2262 	// init a node info
2263 	BNodeInfo nodeInfo;
2264 	error = nodeInfo.SetTo(&node);
2265 	if (error != B_OK)
2266 		return error;
2267 
2268 	// if the file has a preferred app, let _TranslateType() find
2269 	// it for us
2270 	char preferredApp[B_MIME_TYPE_LENGTH];
2271 	if (nodeInfo.GetPreferredApp(preferredApp) == B_OK
2272 		&& _TranslateType(preferredApp, appMeta, appRef, appFile) == B_OK) {
2273 		if (_wasDocument != NULL)
2274 			*_wasDocument = true;
2275 
2276 		return B_OK;
2277 	}
2278 
2279 	// no preferred app or existing one was not found -- we
2280 	// need to get the file's type
2281 
2282 	// get the type from the file
2283 	char fileType[B_MIME_TYPE_LENGTH];
2284 	error = _GetFileType(ref, &nodeInfo, fileType);
2285 	if (error != B_OK)
2286 		return error;
2287 
2288 	// now let _TranslateType() do the actual work
2289 	error = _TranslateType(fileType, appMeta, appRef, appFile);
2290 	if (error != B_OK)
2291 		return error;
2292 
2293 	if (_wasDocument != NULL)
2294 		*_wasDocument = true;
2295 
2296 	return B_OK;
2297 }
2298 
2299 
2300 /*!	Finds an application associated with a MIME type.
2301 
2302 	\see FindApp() for how the application is searched.
2303 
2304 	\param mimeType The MIME type for which an application shall be found.
2305 	\param appMeta A pointer to a pre-allocated BMimeType to be set to the
2306 	       signature of the found application.
2307 	\param appRef A pointer to a pre-allocated entry_ref to be filled with
2308 	       a reference to the found application's executable.
2309 	\param appFile A pointer to a pre-allocated BFile to be set to the
2310 	       executable of the found application.
2311 
2312 	\return A status code.
2313 	\retval B_OK Everything went fine.
2314 	\retval B_BAD_VALUE \c NULL \a mimeType, \a appMeta, \a appRef or
2315 	        \a appFile.
2316 
2317 	\see FindApp() for other error codes.
2318 */
2319 status_t
2320 BRoster::_TranslateType(const char* mimeType, BMimeType* appMeta,
2321 	entry_ref* appRef, BFile* appFile) const
2322 {
2323 	if (mimeType == NULL || appMeta == NULL || appRef == NULL
2324 		|| appFile == NULL || strlen(mimeType) >= B_MIME_TYPE_LENGTH) {
2325 		return B_BAD_VALUE;
2326 	}
2327 
2328 	// Create a BMimeType and check, if the type is installed.
2329 	BMimeType type;
2330 	status_t error = type.SetTo(mimeType);
2331 
2332 	// Get the preferred apps from the sub and super type.
2333 	char primarySignature[B_MIME_TYPE_LENGTH];
2334 	char secondarySignature[B_MIME_TYPE_LENGTH];
2335 	primarySignature[0] = '\0';
2336 	secondarySignature[0] = '\0';
2337 
2338 	if (error == B_OK) {
2339 		BMimeType superType;
2340 		if (type.GetSupertype(&superType) == B_OK)
2341 			superType.GetPreferredApp(secondarySignature);
2342 		if (type.IsInstalled()) {
2343 			if (type.GetPreferredApp(primarySignature) != B_OK) {
2344 				// The type is installed, but has no preferred app.
2345 				primarySignature[0] = '\0';
2346 			} else if (!strcmp(primarySignature, secondarySignature)) {
2347 				// Both types have the same preferred app, there is
2348 				// no point in testing it twice.
2349 				secondarySignature[0] = '\0';
2350 			}
2351 		} else {
2352 			// The type is not installed. We assume it is an app signature.
2353 			strlcpy(primarySignature, mimeType, sizeof(primarySignature));
2354 		}
2355 	}
2356 
2357 	// We will use this BMessage "signatures" to hold all supporting apps
2358 	// so we can iterator over them in the preferred order. We include
2359 	// the supporting apps in such a way that the configured preferred
2360 	// applications for the MIME type are in front of other supporting
2361 	// applications for the sub and the super type respectively.
2362 	const char* kSigField = "applications";
2363 	BMessage signatures;
2364 	bool addedSecondarySignature = false;
2365 	if (error == B_OK) {
2366 		if (primarySignature[0] != '\0')
2367 			error = signatures.AddString(kSigField, primarySignature);
2368 		else {
2369 			// If there is a preferred app configured for the super type,
2370 			// but no preferred type for the sub-type, add the preferred
2371 			// super type handler in front of any other handlers. This way
2372 			// we fall-back to non-preferred but supporting apps only in the
2373 			// case when there is a preferred handler for the sub-type but
2374 			// it cannot be resolved (misconfiguration).
2375 			if (secondarySignature[0] != '\0') {
2376 				error = signatures.AddString(kSigField, secondarySignature);
2377 				addedSecondarySignature = true;
2378 			}
2379 		}
2380 	}
2381 
2382 	BMessage supportingSignatures;
2383 	if (error == B_OK
2384 		&& type.GetSupportingApps(&supportingSignatures) == B_OK) {
2385 		int32 subCount;
2386 		if (supportingSignatures.FindInt32("be:sub", &subCount) != B_OK)
2387 			subCount = 0;
2388 		// Add all signatures with direct support for the sub-type.
2389 		const char* supportingType;
2390 		if (!addedSecondarySignature) {
2391 			// Try to add the secondarySignature in front of all other
2392 			// supporting apps, if we find it among those.
2393 			for (int32 i = 0; error == B_OK && i < subCount
2394 					&& supportingSignatures.FindString(kSigField, i,
2395 						&supportingType) == B_OK; i++) {
2396 				if (strcmp(primarySignature, supportingType) != 0
2397 					&& strcmp(secondarySignature, supportingType) == 0) {
2398 					error = signatures.AddString(kSigField, supportingType);
2399 					addedSecondarySignature = true;
2400 					break;
2401 				}
2402 			}
2403 		}
2404 
2405 		for (int32 i = 0; error == B_OK && i < subCount
2406 				&& supportingSignatures.FindString(kSigField, i,
2407 					&supportingType) == B_OK; i++) {
2408 			if (strcmp(primarySignature, supportingType) != 0
2409 				&& strcmp(secondarySignature, supportingType) != 0) {
2410 				error = signatures.AddString(kSigField, supportingType);
2411 			}
2412 		}
2413 
2414 		// Add the preferred type of the super type here before adding
2415 		// the other types supporting the super type, but only if we have
2416 		// not already added it in case there was no preferred app for the
2417 		// sub-type configured.
2418 		if (error == B_OK && !addedSecondarySignature
2419 			&& secondarySignature[0] != '\0') {
2420 			error = signatures.AddString(kSigField, secondarySignature);
2421 		}
2422 
2423 		// Add all signatures with support for the super-type.
2424 		for (int32 i = subCount; error == B_OK
2425 				&& supportingSignatures.FindString(kSigField, i,
2426 					&supportingType) == B_OK; i++) {
2427 			// Don't add the signature if it's one of the preferred apps
2428 			// already.
2429 			if (strcmp(primarySignature, supportingType) != 0
2430 				&& strcmp(secondarySignature, supportingType) != 0) {
2431 				error = signatures.AddString(kSigField, supportingType);
2432 			}
2433 		}
2434 	} else {
2435 		// Failed to get supporting apps, just add the preferred apps.
2436 		if (error == B_OK && secondarySignature[0] != '\0')
2437 			error = signatures.AddString(kSigField, secondarySignature);
2438 	}
2439 
2440 	if (error != B_OK)
2441 		return error;
2442 
2443 	// Set an error in case we can't resolve a single supporting app.
2444 	error = B_LAUNCH_FAILED_NO_PREFERRED_APP;
2445 
2446 	// See if we can find a good application that is valid from the messege.
2447 	const char* signature;
2448 	for (int32 i = 0;
2449 		signatures.FindString(kSigField, i, &signature) == B_OK; i++) {
2450 		if (signature[0] == '\0')
2451 			continue;
2452 
2453 		error = appMeta->SetTo(signature);
2454 
2455 		// Check, whether the signature is installed and has an app hint
2456 		bool appFound = false;
2457 		if (error == B_OK && appMeta->GetAppHint(appRef) == B_OK) {
2458 			// Resolve symbolic links, if necessary
2459 			BEntry entry;
2460 			if (entry.SetTo(appRef, true) == B_OK && entry.IsFile()
2461 				&& entry.GetRef(appRef) == B_OK) {
2462 				appFound = true;
2463 			} else {
2464 				// Bad app hint -- remove it
2465 				appMeta->SetAppHint(NULL);
2466 			}
2467 		}
2468 
2469 		// In case there is no app hint or it is invalid, we need to query for
2470 		// the app.
2471 		if (error == B_OK && !appFound)
2472 			error = query_for_app(appMeta->Type(), appRef);
2473 
2474 		if (error == B_OK)
2475 			error = appFile->SetTo(appRef, B_READ_ONLY);
2476 
2477 		// check, whether the app can be used
2478 		if (error == B_OK)
2479 			error = can_app_be_used(appRef);
2480 
2481 		if (error == B_OK)
2482 			break;
2483 	}
2484 
2485 	return error;
2486 }
2487 
2488 
2489 /*!	Gets the type of a file either from the node info or by sniffing.
2490 
2491 	The method first tries to get the file type from the supplied node info. If
2492 	that didn't work, the given entry ref is sniffed.
2493 
2494 	\param file An entry_ref referring to the file in question.
2495 	\param nodeInfo A BNodeInfo initialized to the file.
2496 	\param mimeType A pointer to a pre-allocated char buffer of at least size
2497 	       \c B_MIME_TYPE_LENGTH to be filled with the MIME type sniffed for
2498 	       the file.
2499 
2500 	\return A status code.
2501 	\retval B_OK Everything went fine.
2502 	\retval B_BAD_VALUE \c NULL \a file, \a nodeInfo or \a mimeType.
2503 */
2504 status_t
2505 BRoster::_GetFileType(const entry_ref* file, BNodeInfo* nodeInfo,
2506 	char* mimeType) const
2507 {
2508 	// first try the node info
2509 	if (nodeInfo->GetType(mimeType) == B_OK)
2510 		return B_OK;
2511 
2512 	if (fNoRegistrar)
2513 		return B_NO_INIT;
2514 
2515 	// Try to update the file's MIME info and just read the updated type.
2516 	// If that fails, sniff manually.
2517 	BPath path;
2518 	if (path.SetTo(file) != B_OK
2519 		|| update_mime_info(path.Path(), false, true, false) != B_OK
2520 		|| nodeInfo->GetType(mimeType) != B_OK) {
2521 		BMimeType type;
2522 		status_t error = BMimeType::GuessMimeType(file, &type);
2523 		if (error != B_OK)
2524 			return error;
2525 
2526 		if (!type.IsValid())
2527 			return B_BAD_VALUE;
2528 
2529 		strlcpy(mimeType, type.Type(), B_MIME_TYPE_LENGTH);
2530 	}
2531 
2532 	return B_OK;
2533 }
2534 
2535 
2536 /*!	Sends messages to a running team.
2537 
2538 	In particular those messages are \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED,
2539 	\c B_READY_TO_RUN and other, arbitrary, ones.
2540 
2541 	If \a messageList is not \c NULL or empty, those messages are sent first,
2542 	then follow \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED and finally
2543 	\c B_READ_TO_RUN.
2544 
2545 	\c B_ARGV_RECEIVED is sent only, if \a args is not \c NULL and contains
2546 	more than one element. \c B_REFS_RECEIVED is sent only, if \a ref is not
2547 	\c NULL.
2548 
2549 	The ownership of all supplied objects retains to the caller.
2550 
2551 	\param team The team ID of the target application.
2552 	\param argc Number of elements in \a args.
2553 	\param args Argument vector to be sent to the target. May be \c NULL.
2554 	\param messageList List of BMessages to be sent to the target. May be
2555 	       \c NULL or empty.
2556 	\param ref entry_ref to be sent to the target. May be \c NULL.
2557 	\param alreadyRunning \c true, if the target app is not newly launched,
2558 	       but was already running, \c false otherwise (a \c B_READY_TO_RUN
2559 	       message will be sent in this case).
2560 
2561 	\return \c B_OK if everything went fine, or an error code otherwise.
2562 */
2563 status_t
2564 BRoster::_SendToRunning(team_id team, int argc, const char* const* args,
2565 	const BList* messageList, const entry_ref* ref,
2566 	bool alreadyRunning) const
2567 {
2568 	status_t error = B_OK;
2569 
2570 	// Construct a messenger to the app: We can't use the public constructor,
2571 	// since the target application may be B_ARGV_ONLY.
2572 	app_info info;
2573 	error = GetRunningAppInfo(team, &info);
2574 	if (error == B_OK) {
2575 		BMessenger messenger;
2576 		BMessenger::Private(messenger).SetTo(team, info.port,
2577 			B_PREFERRED_TOKEN);
2578 
2579 		// send messages from the list
2580 		if (messageList != NULL) {
2581 			for (int32 i = 0;
2582 					BMessage* message = (BMessage*)messageList->ItemAt(i);
2583 					i++) {
2584 				messenger.SendMessage(message);
2585 			}
2586 		}
2587 
2588 		// send B_ARGV_RECEIVED or B_REFS_RECEIVED or B_SILENT_RELAUNCH
2589 		// (if already running)
2590 		if (args != NULL && argc > 1) {
2591 			BMessage message(B_ARGV_RECEIVED);
2592 			message.AddInt32("argc", argc);
2593 			for (int32 i = 0; i < argc; i++)
2594 				message.AddString("argv", args[i]);
2595 
2596 			// also add current working directory
2597 			char cwd[B_PATH_NAME_LENGTH];
2598 			if (getcwd(cwd, B_PATH_NAME_LENGTH) != NULL)
2599 				message.AddString("cwd", cwd);
2600 
2601 			messenger.SendMessage(&message);
2602 		} else if (ref != NULL) {
2603 			DBG(OUT("_SendToRunning : B_REFS_RECEIVED\n"));
2604 			BMessage message(B_REFS_RECEIVED);
2605 			message.AddRef("refs", ref);
2606 			messenger.SendMessage(&message);
2607 		} else if (alreadyRunning && (!messageList || messageList->IsEmpty()))
2608 			messenger.SendMessage(B_SILENT_RELAUNCH);
2609 
2610 		if (!alreadyRunning) {
2611 			// send B_READY_TO_RUN
2612 			DBG(OUT("_SendToRunning : B_READY_TO_RUN\n"));
2613 			messenger.SendMessage(B_READY_TO_RUN);
2614 		}
2615 	}
2616 
2617 	return error;
2618 }
2619 
2620 
2621 /*!	Allows to use certain functionality of the BRoster class without
2622 	accessing the registrar.
2623 */
2624 void
2625 BRoster::_SetWithoutRegistrar(bool noRegistrar)
2626 {
2627 	fNoRegistrar = noRegistrar;
2628 }
2629 
2630 
2631 void
2632 BRoster::_InitMessenger()
2633 {
2634 	DBG(OUT("BRoster::InitMessengers()\n"));
2635 
2636 	// find the registrar port
2637 
2638 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2639 	BMessage data;
2640 	if (BLaunchRoster().GetData(B_REGISTRAR_SIGNATURE, data) == B_OK) {
2641 		port_id port = data.GetInt32("port", -1);
2642 		team_id team = data.GetInt32("team", -1);
2643 
2644 		if (port >= 0 && team != current_team()) {
2645 			// Make sure we aren't the registrar ourselves.
2646 
2647 			DBG(OUT("  found roster port\n"));
2648 
2649 			BMessenger::Private(fMessenger).SetTo(team, port,
2650 				B_PREFERRED_TOKEN);
2651 		}
2652 	}
2653 #else
2654 	port_id rosterPort = find_port(B_REGISTRAR_PORT_NAME);
2655 	port_info info;
2656 	if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) {
2657 		DBG(OUT("  found roster port\n"));
2658 
2659 		BMessenger::Private(fMessenger).SetTo(info.team, rosterPort,
2660 			B_PREFERRED_TOKEN);
2661 	}
2662 #endif
2663 
2664 	DBG(OUT("BRoster::InitMessengers() done\n"));
2665 }
2666 
2667 
2668 /*static*/ status_t
2669 BRoster::_InitMimeMessenger(void* data)
2670 {
2671 	BRoster* roster = (BRoster*)data;
2672 
2673 	// ask for the MIME messenger
2674 	// Generous 1s + 5s timeouts. It could actually be synchronous, but
2675 	// timeouts allow us to debug the registrar main thread.
2676 	BMessage request(B_REG_GET_MIME_MESSENGER);
2677 	BMessage reply;
2678 	status_t error = roster->fMessenger.SendMessage(&request, &reply,
2679 		1000000LL, 5000000LL);
2680 	if (error == B_OK && reply.what == B_REG_SUCCESS) {
2681 		DBG(OUT("  got reply from roster\n"));
2682 			reply.FindMessenger("messenger", &roster->fMimeMessenger);
2683 	} else {
2684 		DBG(OUT("  no (useful) reply from roster: error: %" B_PRIx32 ": %s\n",
2685 			error, strerror(error)));
2686 		if (error == B_OK)
2687 			DBG(reply.PrintToStream());
2688 	}
2689 
2690 	return error;
2691 }
2692 
2693 
2694 BMessenger&
2695 BRoster::_MimeMessenger()
2696 {
2697 	__init_once(&fMimeMessengerInitOnce, &_InitMimeMessenger, this);
2698 	return fMimeMessenger;
2699 }
2700 
2701 
2702 /*!	Sends a request to the roster to add the application with the
2703 	given signature to the front of the recent apps list.
2704 */
2705 void
2706 BRoster::_AddToRecentApps(const char* signature) const
2707 {
2708 	status_t error = B_OK;
2709 	// compose the request message
2710 	BMessage request(B_REG_ADD_TO_RECENT_APPS);
2711 	if (error == B_OK)
2712 		error = request.AddString("app sig", signature);
2713 
2714 	// send the request
2715 	BMessage reply;
2716 	if (error == B_OK)
2717 		error = fMessenger.SendMessage(&request, &reply);
2718 
2719 	// evaluate the reply
2720 	status_t result;
2721 	if (error == B_OK) {
2722 		error = reply.what == B_REG_RESULT
2723 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
2724 	}
2725 
2726 	if (error == B_OK)
2727 		error = reply.FindInt32("result", &result);
2728 
2729 	if (error == B_OK)
2730 		error = result;
2731 
2732 	// Nothing to return... how sad :-(
2733 	//return error;
2734 }
2735 
2736 
2737 //!	Sends a request to the roster to clear the recent documents list.
2738 void
2739 BRoster::_ClearRecentDocuments() const
2740 {
2741 	BMessage request(B_REG_CLEAR_RECENT_DOCUMENTS);
2742 	BMessage reply;
2743 	fMessenger.SendMessage(&request, &reply);
2744 }
2745 
2746 
2747 //!	Sends a request to the roster to clear the recent documents list.
2748 void
2749 BRoster::_ClearRecentFolders() const
2750 {
2751 	BMessage request(B_REG_CLEAR_RECENT_FOLDERS);
2752 	BMessage reply;
2753 	fMessenger.SendMessage(&request, &reply);
2754 }
2755 
2756 
2757 //! \brief Sends a request to the roster to clear the recent documents list.
2758 void
2759 BRoster::_ClearRecentApps() const
2760 {
2761 	BMessage request(B_REG_CLEAR_RECENT_APPS);
2762 	BMessage reply;
2763 	fMessenger.SendMessage(&request, &reply);
2764 }
2765 
2766 
2767 /*!	Loads the system's recently used document, folder, and
2768 	application lists from the specified file.
2769 
2770 	\note The current lists are cleared before loading the new lists
2771 
2772 	\param filename The name of the file to load from
2773 */
2774 void
2775 BRoster::_LoadRecentLists(const char* filename) const
2776 {
2777 	status_t error = B_OK;
2778 
2779 	// compose the request message
2780 	BMessage request(B_REG_LOAD_RECENT_LISTS);
2781 	if (error == B_OK)
2782 		error = request.AddString("filename", filename);
2783 
2784 	// send the request
2785 	BMessage reply;
2786 	if (error == B_OK)
2787 		error = fMessenger.SendMessage(&request, &reply);
2788 
2789 	// evaluate the reply
2790 	status_t result;
2791 	if (error == B_OK) {
2792 		error = reply.what == B_REG_RESULT
2793 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
2794 	}
2795 	if (error == B_OK)
2796 		error = reply.FindInt32("result", &result);
2797 
2798 	if (error == B_OK)
2799 		error = result;
2800 
2801 	// Nothing to return... how sad :-(
2802 	//return error;
2803 }
2804 
2805 
2806 /*!	Saves the system's recently used document, folder, and
2807 	application lists to the specified file.
2808 
2809 	\param filename The name of the file to save to
2810 */
2811 void
2812 BRoster::_SaveRecentLists(const char* filename) const
2813 {
2814 	status_t error = B_OK;
2815 
2816 	// compose the request message
2817 	BMessage request(B_REG_SAVE_RECENT_LISTS);
2818 	if (error == B_OK)
2819 		error = request.AddString("filename", filename);
2820 
2821 	// send the request
2822 	BMessage reply;
2823 	if (error == B_OK)
2824 		error = fMessenger.SendMessage(&request, &reply);
2825 
2826 	// evaluate the reply
2827 	status_t result;
2828 	if (error == B_OK) {
2829 		error = reply.what == B_REG_RESULT
2830 			? (status_t)B_OK : (status_t)B_BAD_REPLY;
2831 	}
2832 	if (error == B_OK)
2833 		error = reply.FindInt32("result", &result);
2834 
2835 	if (error == B_OK)
2836 		error = result;
2837 
2838 	// Nothing to return... how sad :-(
2839 	//return error;
2840 }
2841