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