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