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