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