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