2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
20 #include <AppFileInfo.h>
21 #include <Application.h>
23 #include <Directory.h>
25 #include <FindDirectory.h>
36 #include <RegistrarDefs.h>
39 #include <VolumeRoster.h>
44 #include <DesktopLink.h>
45 #include <LaunchRoster.h>
46 #include <MessengerPrivate.h>
48 #include <RosterPrivate.h>
49 #include <ServerProtocol.h>
53 using namespace BPrivate
;
60 # define OUT DEBUG_PRINTF
67 NOT_IMPLEMENTED
= B_ERROR
,
71 const BRoster
* be_roster
;
74 // #pragma mark - Helper functions
77 /*! Extracts an app_info from a BMessage.
79 The function searchs for a field "app_info" typed B_REG_APP_INFO_TYPE
80 and initializes \a info with the found data.
82 \param message The message
83 \param info A pointer to a pre-allocated app_info to be filled in with the
84 info found in the message.
86 \return A status code.
87 \retval B_OK Everything went fine.
88 \retval B_BAD_VALUE \c NULL \a message or \a info.
91 find_message_app_info(BMessage
* message
, app_info
* info
)
93 status_t error
= (message
&& info
? B_OK
: B_BAD_VALUE
);
94 const flat_app_info
* flatInfo
= NULL
;
96 // find the flat app info in the message
98 error
= message
->FindData("app_info", B_REG_APP_INFO_TYPE
,
99 (const void**)&flatInfo
, &size
);
101 // unflatten the flat info
103 if (size
== sizeof(flat_app_info
)) {
104 memcpy(info
, &flatInfo
->info
, sizeof(app_info
));
105 info
->ref
.name
= NULL
;
106 if (strlen(flatInfo
->ref_name
) > 0)
107 info
->ref
.set_name(flatInfo
->ref_name
);
116 /*! Checks whether or not an application can be used.
118 Currently it is only checked whether the application is in the trash.
120 \param ref An entry_ref referring to the application executable.
122 \return A status code, \c B_OK on success oir other error codes specifying
123 why the application cannot be used.
124 \retval B_OK The application can be used.
125 \retval B_ENTRY_NOT_FOUND \a ref doesn't refer to and existing entry.
126 \retval B_IS_A_DIRECTORY \a ref refers to a directory.
127 \retval B_LAUNCH_FAILED_APP_IN_TRASH The application executable is in the
131 can_app_be_used(const entry_ref
* ref
)
133 status_t error
= (ref
? B_OK
: B_BAD_VALUE
);
134 // check whether the file exists and is a file.
137 error
= entry
.SetTo(ref
, true);
139 if (error
== B_OK
&& !entry
.Exists())
140 error
= B_ENTRY_NOT_FOUND
;
142 if (error
== B_OK
&& !entry
.IsFile())
143 error
= B_IS_A_DIRECTORY
;
145 // check whether the file is in trash
147 BDirectory directory
;
150 && volume
.SetTo(ref
->device
) == B_OK
151 && find_directory(B_TRASH_DIRECTORY
, &trashPath
, false, &volume
)
153 && directory
.SetTo(trashPath
.Path()) == B_OK
154 && directory
.Contains(&entry
)) {
155 error
= B_LAUNCH_FAILED_APP_IN_TRASH
;
162 /*! Compares the supplied version infos.
164 \param info1 The first info.
165 \param info2 The second info.
167 \return \c -1, if the first info is less than the second one, \c 1, if
168 the first one is greater than the second one, and \c 0, if both
172 compare_version_infos(const version_info
& info1
, const version_info
& info2
)
175 if (info1
.major
< info2
.major
)
177 else if (info1
.major
> info2
.major
)
179 else if (info1
.middle
< info2
.middle
)
181 else if (info1
.middle
> info2
.middle
)
183 else if (info1
.minor
< info2
.minor
)
185 else if (info1
.minor
> info2
.minor
)
187 else if (info1
.variety
< info2
.variety
)
189 else if (info1
.variety
> info2
.variety
)
191 else if (info1
.internal
< info2
.internal
)
193 else if (info1
.internal
> info2
.internal
)
200 /*! Compares two applications to decide which one should be rather
201 returned as a query result.
203 First, it checks if both apps are in the path, and prefers the app that
206 If both files have a version info, then those are compared.
207 If one file has a version info, it is said to be greater. If both
208 files have no version info, their modification times are compared.
210 \param app1 An entry_ref referring to the first application.
211 \param app2 An entry_ref referring to the second application.
212 \return \c -1, if the first application version is less than the second
213 one, \c 1, if the first one is greater than the second one, and
214 \c 0, if both are equal.
217 compare_queried_apps(const entry_ref
* app1
, const entry_ref
* app2
)
224 const char* searchPathes
= getenv("PATH");
225 if (searchPathes
!= NULL
) {
226 char* searchBuffer
= strdup(searchPathes
);
227 if (searchBuffer
!= NULL
) {
229 const char* path
= strtok_r(searchBuffer
, ":", &last
);
230 while (path
!= NULL
) {
231 // Check if any app path matches
232 size_t length
= strlen(path
);
233 bool found1
= !strncmp(path
, path1
.Path(), length
)
234 && path1
.Path()[length
] == '/';
235 bool found2
= !strncmp(path
, path2
.Path(), length
)
236 && path2
.Path()[length
] == '/';;
238 if (found1
!= found2
) {
240 return found1
? 1 : -1;
243 path
= strtok_r(NULL
, ":", &last
);
250 // Check system servers folder
252 find_directory(B_SYSTEM_SERVERS_DIRECTORY
, &path
);
253 BString
serverPath(path
.Path());
255 size_t length
= serverPath
.Length();
257 bool inSystem1
= !strncmp(serverPath
.String(), path1
.Path(), length
);
258 bool inSystem2
= !strncmp(serverPath
.String(), path2
.Path(), length
);
259 if (inSystem1
!= inSystem2
)
260 return inSystem1
? 1 : -1;
262 // Check version info
265 file1
.SetTo(app1
, B_READ_ONLY
);
267 file2
.SetTo(app2
, B_READ_ONLY
);
269 BAppFileInfo appFileInfo1
;
270 appFileInfo1
.SetTo(&file1
);
271 BAppFileInfo appFileInfo2
;
272 appFileInfo2
.SetTo(&file2
);
274 time_t modificationTime1
= 0;
275 time_t modificationTime2
= 0;
277 file1
.GetModificationTime(&modificationTime1
);
278 file2
.GetModificationTime(&modificationTime2
);
282 version_info versionInfo1
;
283 version_info versionInfo2
;
284 bool hasVersionInfo1
= (appFileInfo1
.GetVersionInfo(
285 &versionInfo1
, B_APP_VERSION_KIND
) == B_OK
);
286 bool hasVersionInfo2
= (appFileInfo2
.GetVersionInfo(
287 &versionInfo2
, B_APP_VERSION_KIND
) == B_OK
);
289 if (hasVersionInfo1
) {
291 result
= compare_version_infos(versionInfo1
, versionInfo2
);
297 else if (modificationTime1
< modificationTime2
)
299 else if (modificationTime1
> modificationTime2
)
307 /*! Finds an app by signature on any mounted volume.
309 \param signature The app's signature.
310 \param appRef A pointer to a pre-allocated entry_ref to be filled with
311 a reference to the found application's executable.
313 \return A status code.
314 \retval B_OK Everything went fine.
315 \retval B_BAD_VALUE: \c NULL \a signature or \a appRef.
316 \retval B_LAUNCH_FAILED_APP_NOT_FOUND: An application with this signature
320 query_for_app(const char* signature
, entry_ref
* appRef
)
322 if (signature
== NULL
|| appRef
== NULL
)
325 status_t error
= B_LAUNCH_FAILED_APP_NOT_FOUND
;
326 bool caseInsensitive
= false;
329 // search on all volumes
330 BVolumeRoster volumeRoster
;
332 while (volumeRoster
.GetNextVolume(&volume
) == B_OK
) {
333 if (!volume
.KnowsQuery())
337 if (fs_stat_index(volume
.Device(), "BEOS:APP_SIG", &info
) != 0) {
338 // This volume doesn't seem to have the index we're looking for;
339 // querying it might need a long time, and we don't care *that*
345 query
.SetVolume(&volume
);
346 query
.PushAttr("BEOS:APP_SIG");
347 if (!caseInsensitive
)
348 query
.PushString(signature
);
350 // second pass, create a case insensitive query string
351 char string
[B_MIME_TYPE_LENGTH
* 4];
352 strlcpy(string
, "application/", sizeof(string
));
354 int32 length
= strlen(string
);
355 const char* from
= signature
+ length
;
356 char* to
= string
+ length
;
358 for (; from
[0]; from
++) {
359 if (isalpha(from
[0])) {
361 *to
++ = tolower(from
[0]);
362 *to
++ = toupper(from
[0]);
369 query
.PushString(string
);
375 // walk through the query
376 bool appFound
= false;
377 status_t foundAppError
= B_OK
;
379 while (query
.GetNextRef(&ref
) == B_OK
) {
380 if ((!appFound
|| compare_queried_apps(appRef
, &ref
) < 0)
381 && (foundAppError
= can_app_be_used(&ref
)) == B_OK
) {
387 // If the query didn't return any hits, the error is
388 // B_LAUNCH_FAILED_APP_NOT_FOUND, otherwise we return the
389 // result of the last can_app_be_used().
390 error
= foundAppError
!= B_OK
391 ? foundAppError
: B_LAUNCH_FAILED_APP_NOT_FOUND
;
396 if (!caseInsensitive
)
397 caseInsensitive
= true;
406 // #pragma mark - app_info
414 flags(B_REG_DEFAULT_APP_FLAGS
),
421 app_info::~app_info()
426 // #pragma mark - BRoster::ArgVector
429 class BRoster::ArgVector
{
434 status_t
Init(int argc
, const char* const* args
,
435 const entry_ref
* appRef
,
436 const entry_ref
* docRef
);
438 inline int Count() const { return fArgc
; }
439 inline const char* const* Args() const { return fArgs
; }
449 //! Creates an uninitialized ArgVector.
450 BRoster::ArgVector::ArgVector()
460 //! Frees all resources associated with the ArgVector.
461 BRoster::ArgVector::~ArgVector()
467 /*! Initilizes the object according to the supplied parameters.
469 If the initialization succeeds, the methods Count() and Args() grant
470 access to the argument count and vector created by this methods.
471 \note The returned vector is valid only as long as the elements of the
472 supplied \a args (if any) are valid and this object is not destroyed.
473 This object retains ownership of the vector returned by Args().
474 In case of error, the value returned by Args() is invalid (or \c NULL).
476 The argument vector is created as follows: First element is the path
477 of the entry \a appRef refers to, then follow all elements of \a args
478 and then, if \a args has at least one element and \a docRef can be
479 resolved to a path, the path of the entry \a docRef refers to. That is,
480 if no or an empty \a args vector is supplied, the resulting argument
481 vector contains only one element, the path associated with \a appRef.
483 \param argc Specifies the number of elements \a args contains.
484 \param args Argument vector. May be \c NULL.
485 \param appRef entry_ref referring to the entry whose path shall be the
486 first element of the resulting argument vector.
487 \param docRef entry_ref referring to the entry whose path shall be the
488 last element of the resulting argument vector. May be \c NULL.
490 - \c B_OK: Everything went fine.
491 - \c B_BAD_VALUE: \c NULL \a appRef.
492 - \c B_ENTRY_NOT_FOUND or other file system error codes: \a appRef could
493 not be resolved to a path.
494 - \c B_NO_MEMORY: Not enough memory to allocate for this operation.
497 BRoster::ArgVector::Init(int argc
, const char* const* args
,
498 const entry_ref
* appRef
, const entry_ref
* docRef
)
502 status_t error
= appRef
? B_OK
: B_BAD_VALUE
;
505 error
= fAppPath
.SetTo(appRef
);
506 // determine number of arguments
507 bool hasDocArg
= false;
510 if (argc
> 0 && args
) {
512 if (docRef
!= NULL
&& fDocPath
.SetTo(docRef
) == B_OK
) {
517 fArgs
= new(nothrow
) const char*[fArgc
+ 1];
518 // + 1 for the terminating NULL
524 fArgs
[0] = fAppPath
.Path();
525 if (argc
> 0 && args
!= NULL
) {
526 for (int i
= 0; i
< argc
; i
++)
527 fArgs
[i
+ 1] = args
[i
];
529 fArgs
[fArgc
- 1] = fDocPath
.Path();
531 // NULL terminate (e.g. required by load_image())
538 //! Uninitializes the object.
540 BRoster::ArgVector::Unset()
550 // #pragma mark - BRoster
557 fMimeMessengerInitOnce(INIT_ONCE_UNINITIALIZED
),
569 // #pragma mark - Querying for apps
573 BRoster::IsRunning(const char* signature
) const
575 return (TeamFor(signature
) >= 0);
580 BRoster::IsRunning(entry_ref
* ref
) const
582 return (TeamFor(ref
) >= 0);
587 BRoster::TeamFor(const char* signature
) const
591 status_t error
= GetAppInfo(signature
, &info
);
602 BRoster::TeamFor(entry_ref
* ref
) const
606 status_t error
= GetAppInfo(ref
, &info
);
616 BRoster::GetAppList(BList
* teamIDList
) const
618 status_t error
= (teamIDList
? B_OK
: B_BAD_VALUE
);
619 // compose the request message
620 BMessage
request(B_REG_GET_APP_LIST
);
625 error
= fMessenger
.SendMessage(&request
, &reply
);
627 // evaluate the reply
629 if (reply
.what
== B_REG_SUCCESS
) {
631 for (int32 i
= 0; reply
.FindInt32("teams", i
, &team
) == B_OK
; i
++)
632 teamIDList
->AddItem((void*)(addr_t
)team
);
634 if (reply
.FindInt32("error", &error
) != B_OK
)
636 DBG(OUT("Roster request unsuccessful: %s\n", strerror(error
)));
637 DBG(reply
.PrintToStream());
640 DBG(OUT("Sending message to roster failed: %s\n", strerror(error
)));
646 BRoster::GetAppList(const char* signature
, BList
* teamIDList
) const
648 status_t error
= B_OK
;
649 if (signature
== NULL
|| teamIDList
== NULL
)
652 // compose the request message
653 BMessage
request(B_REG_GET_APP_LIST
);
655 error
= request
.AddString("signature", signature
);
660 error
= fMessenger
.SendMessage(&request
, &reply
);
662 // evaluate the reply
664 if (reply
.what
== B_REG_SUCCESS
) {
666 for (int32 i
= 0; reply
.FindInt32("teams", i
, &team
) == B_OK
; i
++)
667 teamIDList
->AddItem((void*)(addr_t
)team
);
668 } else if (reply
.FindInt32("error", &error
) != B_OK
)
675 BRoster::GetAppInfo(const char* signature
, app_info
* info
) const
677 status_t error
= B_OK
;
678 if (signature
== NULL
|| info
== NULL
)
681 // compose the request message
682 BMessage
request(B_REG_GET_APP_INFO
);
684 error
= request
.AddString("signature", signature
);
689 error
= fMessenger
.SendMessage(&request
, &reply
);
691 // evaluate the reply
693 if (reply
.what
== B_REG_SUCCESS
)
694 error
= find_message_app_info(&reply
, info
);
695 else if (reply
.FindInt32("error", &error
) != B_OK
)
704 BRoster::GetAppInfo(entry_ref
* ref
, app_info
* info
) const
706 status_t error
= (ref
&& info
? B_OK
: B_BAD_VALUE
);
707 // compose the request message
708 BMessage
request(B_REG_GET_APP_INFO
);
710 error
= request
.AddRef("ref", ref
);
715 error
= fMessenger
.SendMessage(&request
, &reply
);
717 // evaluate the reply
719 if (reply
.what
== B_REG_SUCCESS
)
720 error
= find_message_app_info(&reply
, info
);
721 else if (reply
.FindInt32("error", &error
) != B_OK
)
729 BRoster::GetRunningAppInfo(team_id team
, app_info
* info
) const
731 status_t error
= (info
? B_OK
: B_BAD_VALUE
);
732 if (error
== B_OK
&& team
< 0)
733 error
= B_BAD_TEAM_ID
;
734 // compose the request message
735 BMessage
request(B_REG_GET_APP_INFO
);
737 error
= request
.AddInt32("team", team
);
741 error
= fMessenger
.SendMessage(&request
, &reply
);
743 // evaluate the reply
745 if (reply
.what
== B_REG_SUCCESS
)
746 error
= find_message_app_info(&reply
, info
);
747 else if (reply
.FindInt32("error", &error
) != B_OK
)
755 BRoster::GetActiveAppInfo(app_info
* info
) const
760 // compose the request message
761 BMessage
request(B_REG_GET_APP_INFO
);
764 status_t error
= fMessenger
.SendMessage(&request
, &reply
);
765 // evaluate the reply
767 if (reply
.what
== B_REG_SUCCESS
)
768 error
= find_message_app_info(&reply
, info
);
769 else if (reply
.FindInt32("error", &error
) != B_OK
)
777 BRoster::FindApp(const char* mimeType
, entry_ref
* app
) const
779 if (mimeType
== NULL
|| app
== NULL
)
782 return _ResolveApp(mimeType
, NULL
, app
, NULL
, NULL
, NULL
);
787 BRoster::FindApp(entry_ref
* ref
, entry_ref
* app
) const
789 if (ref
== NULL
|| app
== NULL
)
792 entry_ref
_ref(*ref
);
793 return _ResolveApp(NULL
, &_ref
, app
, NULL
, NULL
, NULL
);
797 // #pragma mark - Launching, activating, and broadcasting to apps
801 BRoster::Broadcast(BMessage
* message
) const
803 return Broadcast(message
, be_app_messenger
);
808 BRoster::Broadcast(BMessage
* message
, BMessenger replyTo
) const
810 status_t error
= (message
? B_OK
: B_BAD_VALUE
);
811 // compose the request message
812 BMessage
request(B_REG_BROADCAST
);
814 error
= request
.AddInt32("team", BPrivate::current_team());
816 error
= request
.AddMessage("message", message
);
818 error
= request
.AddMessenger("reply_target", replyTo
);
823 error
= fMessenger
.SendMessage(&request
, &reply
);
825 // evaluate the reply
826 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
827 && reply
.FindInt32("error", &error
) != B_OK
)
835 BRoster::StartWatching(BMessenger target
, uint32 eventMask
) const
837 status_t error
= B_OK
;
838 // compose the request message
839 BMessage
request(B_REG_START_WATCHING
);
841 error
= request
.AddMessenger("target", target
);
843 error
= request
.AddInt32("events", (int32
)eventMask
);
848 error
= fMessenger
.SendMessage(&request
, &reply
);
850 // evaluate the reply
851 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
852 && reply
.FindInt32("error", &error
) != B_OK
)
860 BRoster::StopWatching(BMessenger target
) const
862 status_t error
= B_OK
;
863 // compose the request message
864 BMessage
request(B_REG_STOP_WATCHING
);
866 error
= request
.AddMessenger("target", target
);
871 error
= fMessenger
.SendMessage(&request
, &reply
);
873 // evaluate the reply
874 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
875 && reply
.FindInt32("error", &error
) != B_OK
)
883 BRoster::ActivateApp(team_id team
) const
885 BPrivate::DesktopLink link
;
887 status_t status
= link
.InitCheck();
891 // prepare the message
892 status_t error
= link
.StartMessage(AS_ACTIVATE_APP
);
896 error
= link
.Attach(link
.ReceiverPort());
900 error
= link
.Attach(team
);
906 error
= link
.FlushWithReply(code
);
915 BRoster::Launch(const char* mimeType
, BMessage
* initialMessage
,
916 team_id
* _appTeam
) const
918 if (mimeType
== NULL
)
922 if (initialMessage
!= NULL
)
923 messageList
.AddItem(initialMessage
);
925 return _LaunchApp(mimeType
, NULL
, &messageList
, 0, NULL
,
926 (const char**)environ
, _appTeam
, NULL
, false);
931 BRoster::Launch(const char* mimeType
, BList
* messageList
,
932 team_id
* _appTeam
) const
934 if (mimeType
== NULL
)
937 return _LaunchApp(mimeType
, NULL
, messageList
, 0, NULL
,
938 (const char**)environ
, _appTeam
, NULL
, false);
943 BRoster::Launch(const char* mimeType
, int argc
, const char* const* args
,
944 team_id
* _appTeam
) const
946 if (mimeType
== NULL
)
949 return _LaunchApp(mimeType
, NULL
, NULL
, argc
, args
, (const char**)environ
,
950 _appTeam
, NULL
, false);
955 BRoster::Launch(const entry_ref
* ref
, const BMessage
* initialMessage
,
956 team_id
* _appTeam
) const
962 if (initialMessage
!= NULL
)
963 messageList
.AddItem(const_cast<BMessage
*>(initialMessage
));
965 return _LaunchApp(NULL
, ref
, &messageList
, 0, NULL
, (const char**)environ
,
966 _appTeam
, NULL
, false);
971 BRoster::Launch(const entry_ref
* ref
, const BList
* messageList
,
972 team_id
* appTeam
) const
977 return _LaunchApp(NULL
, ref
, messageList
, 0, NULL
, (const char**)environ
,
978 appTeam
, NULL
, false);
983 BRoster::Launch(const entry_ref
* ref
, int argc
, const char* const* args
,
984 team_id
* appTeam
) const
989 return _LaunchApp(NULL
, ref
, NULL
, argc
, args
, (const char**)environ
,
990 appTeam
, NULL
, false);
995 // #pragma mark - Binary compatibility
999 Launch__C7BRosterP9entry_refP8BMessagePl(BRoster
* roster
, entry_ref
* ref
,
1000 BMessage
* initialMessage
)
1002 return roster
->BRoster::Launch(ref
, initialMessage
, NULL
);
1007 Launch__C7BRosterPCciPPcPl(BRoster
* roster
, const char* mimeType
,
1008 int argc
, char** args
, team_id
* _appTeam
)
1010 return roster
->BRoster::Launch(mimeType
, argc
, args
, _appTeam
);
1015 Launch__C7BRosterP9entry_refiPPcPl(BRoster
* roster
, entry_ref
* ref
,
1016 int argc
, char* const* args
, team_id
* _appTeam
)
1018 return roster
->BRoster::Launch(ref
, argc
, args
, _appTeam
);
1020 #endif // __GNUC__ == 2
1023 // #pragma mark - Recent document and app support
1027 BRoster::GetRecentDocuments(BMessage
* refList
, int32 maxCount
,
1028 const char* fileType
, const char* signature
) const
1030 if (refList
== NULL
)
1033 status_t error
= maxCount
> 0 ? B_OK
: B_BAD_VALUE
;
1035 // Use the message we've been given for both request and reply
1036 BMessage
& message
= *refList
;
1037 BMessage
& reply
= *refList
;
1040 // Build and send the message, read the reply
1041 if (error
== B_OK
) {
1042 message
.what
= B_REG_GET_RECENT_DOCUMENTS
;
1043 error
= message
.AddInt32("max count", maxCount
);
1045 if (error
== B_OK
&& fileType
)
1046 error
= message
.AddString("file type", fileType
);
1048 if (error
== B_OK
&& signature
)
1049 error
= message
.AddString("app sig", signature
);
1051 fMessenger
.SendMessage(&message
, &reply
);
1052 if (error
== B_OK
) {
1053 error
= reply
.what
== B_REG_RESULT
1054 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
1058 error
= reply
.FindInt32("result", &result
);
1063 // Clear the result if an error occured
1064 if (error
!= B_OK
&& refList
!= NULL
)
1065 refList
->MakeEmpty();
1067 // No return value, how sad :-(
1073 BRoster::GetRecentDocuments(BMessage
* refList
, int32 maxCount
,
1074 const char* fileTypes
[], int32 fileTypesCount
,
1075 const char* signature
) const
1077 if (refList
== NULL
)
1080 status_t error
= maxCount
> 0 ? B_OK
: B_BAD_VALUE
;
1082 // Use the message we've been given for both request and reply
1083 BMessage
& message
= *refList
;
1084 BMessage
& reply
= *refList
;
1087 // Build and send the message, read the reply
1088 if (error
== B_OK
) {
1089 message
.what
= B_REG_GET_RECENT_DOCUMENTS
;
1090 error
= message
.AddInt32("max count", maxCount
);
1092 if (error
== B_OK
&& fileTypes
) {
1093 for (int i
= 0; i
< fileTypesCount
&& error
== B_OK
; i
++)
1094 error
= message
.AddString("file type", fileTypes
[i
]);
1096 if (error
== B_OK
&& signature
)
1097 error
= message
.AddString("app sig", signature
);
1099 fMessenger
.SendMessage(&message
, &reply
);
1100 if (error
== B_OK
) {
1101 error
= reply
.what
== B_REG_RESULT
1102 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
1105 error
= reply
.FindInt32("result", &result
);
1110 // Clear the result if an error occured
1111 if (error
!= B_OK
&& refList
!= NULL
)
1112 refList
->MakeEmpty();
1114 // No return value, how sad :-(
1120 BRoster::GetRecentFolders(BMessage
* refList
, int32 maxCount
,
1121 const char* signature
) const
1123 if (refList
== NULL
)
1126 status_t error
= maxCount
> 0 ? B_OK
: B_BAD_VALUE
;
1128 // Use the message we've been given for both request and reply
1129 BMessage
& message
= *refList
;
1130 BMessage
& reply
= *refList
;
1133 // Build and send the message, read the reply
1134 if (error
== B_OK
) {
1135 message
.what
= B_REG_GET_RECENT_FOLDERS
;
1136 error
= message
.AddInt32("max count", maxCount
);
1138 if (error
== B_OK
&& signature
)
1139 error
= message
.AddString("app sig", signature
);
1141 fMessenger
.SendMessage(&message
, &reply
);
1142 if (error
== B_OK
) {
1143 error
= reply
.what
== B_REG_RESULT
1144 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
1148 error
= reply
.FindInt32("result", &result
);
1153 // Clear the result if an error occured
1154 if (error
!= B_OK
&& refList
!= NULL
)
1155 refList
->MakeEmpty();
1157 // No return value, how sad :-(
1163 BRoster::GetRecentApps(BMessage
* refList
, int32 maxCount
) const
1165 if (refList
== NULL
)
1168 status_t err
= maxCount
> 0 ? B_OK
: B_BAD_VALUE
;
1170 // Use the message we've been given for both request and reply
1171 BMessage
& message
= *refList
;
1172 BMessage
& reply
= *refList
;
1175 // Build and send the message, read the reply
1177 message
.what
= B_REG_GET_RECENT_APPS
;
1178 err
= message
.AddInt32("max count", maxCount
);
1180 fMessenger
.SendMessage(&message
, &reply
);
1182 err
= reply
.what
== B_REG_RESULT
1183 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
1186 err
= reply
.FindInt32("result", &result
);
1191 // Clear the result if an error occured
1193 refList
->MakeEmpty();
1195 // No return value, how sad :-(
1201 BRoster::AddToRecentDocuments(const entry_ref
* document
,
1202 const char* signature
) const
1204 status_t error
= document
? B_OK
: B_BAD_VALUE
;
1206 // Use the message we've been given for both request and reply
1207 BMessage
message(B_REG_ADD_TO_RECENT_DOCUMENTS
);
1210 char* callingApplicationSignature
= NULL
;
1212 // If no signature is supplied, look up the signature of
1214 if (error
== B_OK
&& signature
== NULL
) {
1216 error
= GetRunningAppInfo(be_app
->Team(), &info
);
1218 callingApplicationSignature
= info
.signature
;
1221 // Build and send the message, read the reply
1223 error
= message
.AddRef("ref", document
);
1225 if (error
== B_OK
) {
1226 error
= message
.AddString("app sig", signature
!= NULL
1227 ? signature
: callingApplicationSignature
);
1229 fMessenger
.SendMessage(&message
, &reply
);
1230 if (error
== B_OK
) {
1231 error
= reply
.what
== B_REG_RESULT
1232 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
1235 error
= reply
.FindInt32("result", &result
);
1240 if (error
!= B_OK
) {
1241 DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error "
1248 BRoster::AddToRecentFolders(const entry_ref
* folder
,
1249 const char* signature
) const
1251 status_t error
= folder
? B_OK
: B_BAD_VALUE
;
1253 // Use the message we've been given for both request and reply
1254 BMessage
message(B_REG_ADD_TO_RECENT_FOLDERS
);
1257 char* callingApplicationSignature
= NULL
;
1259 // If no signature is supplied, look up the signature of
1261 if (error
== B_OK
&& signature
== NULL
) {
1263 error
= GetRunningAppInfo(be_app
->Team(), &info
);
1265 callingApplicationSignature
= info
.signature
;
1268 // Build and send the message, read the reply
1270 error
= message
.AddRef("ref", folder
);
1272 if (error
== B_OK
) {
1273 error
= message
.AddString("app sig",
1274 signature
!= NULL
? signature
: callingApplicationSignature
);
1276 fMessenger
.SendMessage(&message
, &reply
);
1277 if (error
== B_OK
) {
1278 error
= reply
.what
== B_REG_RESULT
1279 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
1282 error
= reply
.FindInt32("result", &result
);
1287 if (error
!= B_OK
) {
1288 DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error "
1293 // #pragma mark - Private or reserved
1296 /*! Shuts down the system.
1298 When \c synchronous is \c true and the method succeeds, it doesn't return.
1300 \param reboot If \c true, the system will be rebooted instead of being
1302 \param confirm If \c true, the user will be asked to confirm to shut down
1304 \param synchronous If \c false, the method will return as soon as the
1305 shutdown process has been initiated successfully (or an error
1306 occurred). Otherwise the method doesn't return, if successfully.
1308 \return A status code, \c B_OK on success or another error code in case
1309 something went wrong.
1310 \retval B_SHUTTING_DOWN, when there's already a shutdown process in
1312 \retval B_SHUTDOWN_CANCELLED, when the user cancelled the shutdown process,
1315 BRoster::_ShutDown(bool reboot
, bool confirm
, bool synchronous
)
1317 status_t error
= B_OK
;
1319 // compose the request message
1320 BMessage
request(B_REG_SHUT_DOWN
);
1322 error
= request
.AddBool("reboot", reboot
);
1325 error
= request
.AddBool("confirm", confirm
);
1328 error
= request
.AddBool("synchronous", synchronous
);
1333 error
= fMessenger
.SendMessage(&request
, &reply
);
1335 // evaluate the reply
1336 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
1337 && reply
.FindInt32("error", &error
) != B_OK
) {
1345 /*! (Pre-)Registers an application with the registrar.
1347 This methods is invoked either to register or to pre-register an
1348 application. Full registration is requested by supplying \c true via
1349 \a fullRegistration.
1351 A full registration requires \a signature, \a ref, \a flags, \a team,
1352 \a thread and \a port to contain valid values. No token will be return
1355 For a pre-registration \a signature, \a ref, \a flags must be valid.
1356 \a team and \a thread are optional and should be set to -1, if they are
1357 unknown. If no team ID is supplied, \a pToken should be valid and, if the
1358 the pre-registration succeeds, will be filled with a unique token assigned
1361 In both cases the registration may fail, if single/exclusive launch is
1362 requested and an instance of the application is already running. Then
1363 \c B_ALREADY_RUNNING is returned and the team ID of the running instance
1364 is passed back via \a otherTeam, if supplied.
1366 \param signature The application's signature
1367 \param ref An entry_ref referring to the app's executable
1368 \param flags The application's flags
1369 \param team The application's team ID
1370 \param thread The application's main thread
1371 \param port The application's looper port
1372 \param fullRegistration \c true for full, \c false for pre-registration
1373 \param pToken A pointer to a pre-allocated uint32 into which the token
1374 assigned by the registrar is written (may be \c NULL)
1375 \param otherTeam A pointer to a pre-allocated team_id into which the
1376 team ID of the already running instance of a single/exclusive
1377 launch application is written (may be \c NULL)
1379 \return A status code
1380 \retval B_OK Everything went fine.
1381 \retval B_ENTRY_NOT_FOUND \a ref didn't refer to a file.
1382 \retval B_ALREADY_RUNNING The application requested a single/exclusive
1383 launch and an instance was already running.
1384 \retval B_REG_ALREADY_REGISTERED An application with the team ID \a team
1385 was already registered.
1388 BRoster::_AddApplication(const char* signature
, const entry_ref
* ref
,
1389 uint32 flags
, team_id team
, thread_id thread
, port_id port
,
1390 bool fullRegistration
, uint32
* pToken
, team_id
* otherTeam
) const
1392 status_t error
= B_OK
;
1394 // compose the request message
1395 BMessage
request(B_REG_ADD_APP
);
1396 if (error
== B_OK
&& signature
!= NULL
)
1397 error
= request
.AddString("signature", signature
);
1399 if (error
== B_OK
&& ref
!= NULL
)
1400 error
= request
.AddRef("ref", ref
);
1403 error
= request
.AddInt32("flags", (int32
)flags
);
1405 if (error
== B_OK
&& team
>= 0)
1406 error
= request
.AddInt32("team", team
);
1408 if (error
== B_OK
&& thread
>= 0)
1409 error
= request
.AddInt32("thread", thread
);
1411 if (error
== B_OK
&& port
>= 0)
1412 error
= request
.AddInt32("port", port
);
1415 error
= request
.AddBool("full_registration", fullRegistration
);
1420 error
= fMessenger
.SendMessage(&request
, &reply
);
1422 // evaluate the reply
1423 if (error
== B_OK
) {
1424 if (reply
.what
== B_REG_SUCCESS
) {
1425 if (!fullRegistration
&& team
< 0) {
1427 if (reply
.FindInt32("token", (int32
*)&token
) == B_OK
) {
1434 if (reply
.FindInt32("error", &error
) != B_OK
)
1437 // get team and token from the reply
1438 if (otherTeam
!= NULL
1439 && reply
.FindInt32("other_team", otherTeam
) != B_OK
) {
1443 && reply
.FindInt32("token", (int32
*)pToken
) != B_OK
) {
1453 /*! Sets an application's signature.
1455 The application must be registered or at pre-registered with a valid
1458 \param team The app's team ID.
1459 \param signature The app's new signature.
1461 \return A status code.
1462 \retval B_OK Everything went fine.
1463 \retval B_REG_APP_NOT_REGISTERED The supplied team ID did not identify a
1464 registered application.
1467 BRoster::_SetSignature(team_id team
, const char* signature
) const
1469 status_t error
= B_OK
;
1471 // compose the request message
1472 BMessage
request(B_REG_SET_SIGNATURE
);
1473 if (error
== B_OK
&& team
>= 0)
1474 error
= request
.AddInt32("team", team
);
1476 if (error
== B_OK
&& signature
)
1477 error
= request
.AddString("signature", signature
);
1482 error
= fMessenger
.SendMessage(&request
, &reply
);
1484 // evaluate the reply
1485 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
1486 && reply
.FindInt32("error", &error
) != B_OK
) {
1494 //! \todo Really needed?
1496 BRoster::_SetThread(team_id team
, thread_id thread
) const
1501 /*! Sets the team and thread IDs of a pre-registered application.
1503 After an application has been pre-registered via AddApplication(), without
1504 supplying a team ID, the team and thread IDs have to be set using this
1507 \param entryToken The token identifying the application (returned by
1509 \param thread The app's thread ID
1510 \param team The app's team ID
1512 \return A status code.
1513 \retval B_OK Everything went fine.
1514 \retval B_REG_APP_NOT_PRE_REGISTERED The supplied token did not identify a
1515 pre-registered application.
1518 BRoster::_SetThreadAndTeam(uint32 entryToken
, thread_id thread
,
1521 status_t error
= B_OK
;
1523 // compose the request message
1524 BMessage
request(B_REG_SET_THREAD_AND_TEAM
);
1526 error
= request
.AddInt32("token", (int32
)entryToken
);
1528 if (error
== B_OK
&& team
>= 0)
1529 error
= request
.AddInt32("team", team
);
1531 if (error
== B_OK
&& thread
>= 0)
1532 error
= request
.AddInt32("thread", thread
);
1537 error
= fMessenger
.SendMessage(&request
, &reply
);
1539 // evaluate the reply
1540 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
1541 && reply
.FindInt32("error", &error
) != B_OK
)
1548 /*! Completes the registration process for a pre-registered application.
1550 After an application has been pre-registered via AddApplication() and
1551 after assigning it a team ID (via SetThreadAndTeam()) the application is
1552 still pre-registered and must complete the registration.
1554 \param team The app's team ID
1555 \param thread The app's thread ID
1556 \param thread The app looper port
1558 \return A status code.
1559 \retval B_OK Everything went fine.
1560 \retval B_REG_APP_NOT_PRE_REGISTERED \a team did not identify an existing
1561 application or the identified application was already fully
1565 BRoster::_CompleteRegistration(team_id team
, thread_id thread
,
1568 status_t error
= B_OK
;
1570 // compose the request message
1571 BMessage
request(B_REG_COMPLETE_REGISTRATION
);
1572 if (error
== B_OK
&& team
>= 0)
1573 error
= request
.AddInt32("team", team
);
1575 if (error
== B_OK
&& thread
>= 0)
1576 error
= request
.AddInt32("thread", thread
);
1578 if (error
== B_OK
&& port
>= 0)
1579 error
= request
.AddInt32("port", port
);
1584 error
= fMessenger
.SendMessage(&request
, &reply
);
1586 // evaluate the reply
1587 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
1588 && reply
.FindInt32("error", &error
) != B_OK
) {
1596 /*! Returns whether an application is registered.
1598 If the application is indeed pre-registered and \a info is not \c NULL,
1599 the methods fills in the app_info structure pointed to by \a info.
1601 \param ref An entry_ref referring to the app's executable
1602 \param team The app's team ID. May be -1, if \a token is given.
1603 \param token The app's pre-registration token. May be 0, if \a team is
1605 \param preRegistered: Pointer to a pre-allocated bool to be filled in
1606 by this method, indicating whether or not the app was
1608 \param info A pointer to a pre-allocated app_info structure to be filled
1609 in by this method (may be \c NULL)
1611 \return \c B_OK, if the application is registered and all requested
1612 information could be retrieved, or another error code, if the app
1613 is not registered or an error occurred.
1616 BRoster::_IsAppRegistered(const entry_ref
* ref
, team_id team
,
1617 uint32 token
, bool* preRegistered
, app_info
* info
) const
1619 status_t error
= B_OK
;
1621 // compose the request message
1622 BMessage
request(B_REG_IS_APP_REGISTERED
);
1623 if (error
== B_OK
&& ref
)
1624 error
= request
.AddRef("ref", ref
);
1625 if (error
== B_OK
&& team
>= 0)
1626 error
= request
.AddInt32("team", team
);
1627 if (error
== B_OK
&& token
> 0)
1628 error
= request
.AddInt32("token", (int32
)token
);
1633 error
= fMessenger
.SendMessage(&request
, &reply
);
1635 // evaluate the reply
1636 bool isRegistered
= false;
1637 bool isPreRegistered
= false;
1638 if (error
== B_OK
) {
1639 if (reply
.what
== B_REG_SUCCESS
) {
1640 if (reply
.FindBool("registered", &isRegistered
) != B_OK
1642 || reply
.FindBool("pre-registered", &isPreRegistered
) != B_OK
) {
1646 if (error
== B_OK
&& preRegistered
)
1647 *preRegistered
= isPreRegistered
;
1648 if (error
== B_OK
&& info
)
1649 error
= find_message_app_info(&reply
, info
);
1650 } else if (reply
.FindInt32("error", &error
) != B_OK
)
1658 /*! Completely unregisters a pre-registered application.
1660 This method can only be used to unregister applications that don't have
1661 a team ID assigned yet. All other applications must be unregistered via
1664 \param entryToken The token identifying the application (returned by
1667 \return A status code.
1668 \retval B_OK Everything went fine.
1669 \retval B_REG_APP_NOT_PRE_REGISTERED The supplied token did not identify
1670 a pre-registered application.
1673 BRoster::_RemovePreRegApp(uint32 entryToken
) const
1675 status_t error
= B_OK
;
1677 // compose the request message
1678 BMessage
request(B_REG_REMOVE_PRE_REGISTERED_APP
);
1680 error
= request
.AddInt32("token", (int32
)entryToken
);
1685 error
= fMessenger
.SendMessage(&request
, &reply
);
1687 // evaluate the reply
1688 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
1689 && reply
.FindInt32("error", &error
) != B_OK
) {
1697 /*! Unregisters a (pre-)registered application.
1699 This method must be used to unregister applications that already have
1700 a team ID assigned, i.e. also for pre-registered application for which
1701 SetThreadAndTeam() has already been invoked.
1703 \param team The app's team ID
1705 \return A status code.
1706 \retval B_OK Everything went fine.
1707 \retval B_REG_APP_NOT_REGISTERED The supplied team ID does not identify a
1708 (pre-)registered application.
1711 BRoster::_RemoveApp(team_id team
) const
1713 status_t error
= B_OK
;
1715 // compose the request message
1716 BMessage
request(B_REG_REMOVE_APP
);
1717 if (error
== B_OK
&& team
>= 0)
1718 error
= request
.AddInt32("team", team
);
1723 error
= fMessenger
.SendMessage(&request
, &reply
);
1725 // evaluate the reply
1726 if (error
== B_OK
&& reply
.what
!= B_REG_SUCCESS
1727 && reply
.FindInt32("error", &error
) != B_OK
) {
1736 BRoster::_ApplicationCrashed(team_id team
)
1738 BPrivate::DesktopLink link
;
1739 if (link
.InitCheck() != B_OK
)
1742 if (link
.StartMessage(AS_APP_CRASHED
) == B_OK
1743 && link
.Attach(team
) == B_OK
) {
1749 /*! Tells the registrar which application is currently active.
1751 It's called from within the app_server when the active application is
1754 As it's called in the event loop, it must run asynchronously and cannot
1758 BRoster::_UpdateActiveApp(team_id team
) const
1761 return B_BAD_TEAM_ID
;
1763 // compose the request message
1764 BMessage
request(B_REG_UPDATE_ACTIVE_APP
);
1765 status_t status
= request
.AddInt32("team", team
);
1770 return fMessenger
.SendMessage(&request
);
1774 /*! Launches the application associated with the supplied MIME type or
1775 the entry referred to by the supplied entry_ref.
1777 The application to be started is searched the same way FindApp() does it.
1779 At least one of \a mimeType or \a ref must not be \c NULL. If \a mimeType
1780 is supplied, \a ref is ignored for finding the application.
1782 If \a ref does refer to an application executable, that application is
1783 launched. Otherwise the respective application is searched and launched,
1784 and \a ref is sent to it in a \c B_REFS_RECEIVED message, unless other
1785 arguments are passed via \a argc and \a args -- then the entry_ref is
1786 converted into a path (C-string) and added to the argument vector.
1788 \a messageList contains messages to be sent to the application
1789 "on launch", i.e. before ReadyToRun() is invoked on the BApplication
1790 object. The caller retains ownership of the supplied BList and the
1791 contained BMessages. In case the method fails with \c B_ALREADY_RUNNING
1792 the messages are delivered to the already running instance. The same
1793 applies to the \c B_REFS_RECEIVED message.
1795 The supplied \a argc and \a args are (if containing at least one argument)
1796 put into a \c B_ARGV_RECEIVED message and sent to the launched application
1797 "on launch". The caller retains ownership of the supplied \a args.
1798 In case the method fails with \c B_ALREADY_RUNNING the message is
1799 delivered to the already running instance. The same applies to the
1800 \c B_REFS_RECEIVED message, if no arguments are supplied via \a argc and
1803 If \a launchSuspended is set to true, the main thread of the loaded app
1804 (returned in \a appThread) is kept in the suspended state and not
1805 automatically resumed.
1807 \param mimeType MIME type for which the application shall be launched.
1809 \param ref entry_ref referring to the file for which an application shall
1810 be launched. May be \c NULL.
1811 \param messageList Optional list of messages to be sent to the application
1812 "on launch". May be \c NULL.
1813 \param argc Specifies the number of elements in \a args.
1814 \param args An array of C-strings to be sent as B_ARGV_RECEIVED messaged
1815 to the launched application.
1816 \param appTeam Pointer to a pre-allocated team_id variable to be set to
1817 the team ID of the launched application.
1818 \param appThread Pointer to a pre-allocated thread_id variable to
1819 be set to the thread ID of the launched main thread.
1820 \param launchSuspended Indicates whether to keep the app thread in the
1821 suspended state or resume it.
1823 \return A status code.
1824 \retval B_OK Everything went fine.
1825 \retval B_BAD_VALUE \c NULL \a mimeType
1826 \retval B_LAUNCH_FAILED_NO_PREFERRED_APP Neither with the supplied type
1827 nor with its supertype (if the supplied isn't a supertype itself)
1828 a preferred application is associated.
1829 \retval B_LAUNCH_FAILED_APP_NOT_FOUND The supplied type is not installed
1830 or its preferred application could not be found.
1831 \retval B_LAUNCH_FAILED_APP_IN_TRASH The supplied type's preferred
1832 application was in the trash.
1833 \retval B_LAUNCH_FAILED_EXECUTABLE The found application was not
1837 BRoster::_LaunchApp(const char* mimeType
, const entry_ref
* ref
,
1838 const BList
* messageList
, int argc
, const char* const* args
,
1839 const char** environment
, team_id
* _appTeam
,
1840 thread_id
* _appThread
, bool launchSuspended
) const
1842 DBG(OUT("BRoster::_LaunchApp()"));
1844 if (_appTeam
!= NULL
) {
1845 // we're supposed to set _appTeam to -1 on error; we'll
1846 // reset it later if everything goes well
1850 if (mimeType
== NULL
&& ref
== NULL
)
1853 // use a mutable copy of the document entry_ref
1855 entry_ref
* docRef
= NULL
;
1861 uint32 otherAppFlags
= B_REG_DEFAULT_APP_FLAGS
;
1862 uint32 appFlags
= B_REG_DEFAULT_APP_FLAGS
;
1863 bool alreadyRunning
= false;
1864 bool wasDocument
= true;
1865 status_t error
= B_OK
;
1866 ArgVector argVector
;
1868 thread_id appThread
= -1;
1873 char signature
[B_MIME_TYPE_LENGTH
];
1874 error
= _ResolveApp(mimeType
, docRef
, &appRef
, signature
,
1875 &appFlags
, &wasDocument
);
1876 DBG(OUT(" find app: %s (%lx)\n", strerror(error
), error
));
1880 // build an argument vector
1881 error
= argVector
.Init(argc
, args
, &appRef
,
1882 wasDocument
? docRef
: NULL
);
1883 DBG(OUT(" build argv: %s (%lx)\n", strerror(error
), error
));
1887 // pre-register the app (but ignore scipts)
1888 uint32 appToken
= 0;
1890 bool isScript
= wasDocument
&& docRef
!= NULL
&& *docRef
== appRef
;
1891 if (!isScript
&& !fNoRegistrar
) {
1892 error
= _AddApplication(signature
, &appRef
, appFlags
, -1, -1, -1,
1893 false, &appToken
, &team
);
1894 if (error
== B_ALREADY_RUNNING
) {
1895 DBG(OUT(" already running\n"));
1896 alreadyRunning
= true;
1898 // get the app flags for the running application
1899 error
= _IsAppRegistered(&appRef
, team
, appToken
, NULL
,
1901 if (error
== B_OK
) {
1902 otherAppFlags
= appInfo
.flags
;
1903 team
= appInfo
.team
;
1906 DBG(OUT(" pre-register: %s (%lx)\n", strerror(error
), error
));
1910 if (error
== B_OK
&& !alreadyRunning
) {
1911 DBG(OUT(" token: %lu\n", appToken
));
1912 // load the app image
1913 appThread
= load_image(argVector
.Count(),
1914 const_cast<const char**>(argVector
.Args()), environment
);
1917 if (appThread
>= 0) {
1918 thread_info threadInfo
;
1919 error
= get_thread_info(appThread
, &threadInfo
);
1921 team
= threadInfo
.team
;
1922 } else if (wasDocument
&& appThread
== B_NOT_AN_EXECUTABLE
)
1923 error
= B_LAUNCH_FAILED_EXECUTABLE
;
1927 DBG(OUT(" load image: %s (%lx)\n", strerror(error
), error
));
1928 // finish the registration
1929 if (error
== B_OK
&& !isScript
&& !fNoRegistrar
)
1930 error
= _SetThreadAndTeam(appToken
, appThread
, team
);
1932 DBG(OUT(" set thread and team: %s (%lx)\n", strerror(error
),
1934 // resume the launched team
1935 if (error
== B_OK
&& !launchSuspended
)
1936 error
= resume_thread(appThread
);
1938 DBG(OUT(" resume thread: %s (%lx)\n", strerror(error
), error
));
1939 // on error: kill the launched team and unregister the app
1940 if (error
!= B_OK
) {
1942 kill_thread(appThread
);
1946 _RemovePreRegApp(appToken
);
1949 // Remove app hint if it's this one
1950 BMimeType
appType(signature
);
1953 if (appType
.InitCheck() == B_OK
1954 && appType
.GetAppHint(&hintRef
) == B_OK
1955 && appRef
== hintRef
) {
1956 appType
.SetAppHint(NULL
);
1966 if (alreadyRunning
&& current_team() == team
) {
1967 // The target team is calling us, so we don't send it the message
1968 // to prevent an endless loop
1969 error
= B_BAD_VALUE
;
1972 // send "on launch" messages
1973 if (error
== B_OK
&& !fNoRegistrar
) {
1974 // If the target app is B_ARGV_ONLY, only if it is newly launched
1975 // messages are sent to it (namely B_ARGV_RECEIVED and B_READY_TO_RUN).
1976 // An already running B_ARGV_ONLY app won't get any messages.
1977 bool argvOnly
= (appFlags
& B_ARGV_ONLY
) != 0
1978 || (alreadyRunning
&& (otherAppFlags
& B_ARGV_ONLY
) != 0);
1979 const BList
* _messageList
= (argvOnly
? NULL
: messageList
);
1980 // don't send ref, if it refers to the app or is included in the
1982 const entry_ref
* _ref
= argvOnly
|| !wasDocument
1983 || argVector
.Count() > 1 ? NULL
: docRef
;
1984 if (!(argvOnly
&& alreadyRunning
)) {
1985 _SendToRunning(team
, argVector
.Count(), argVector
.Args(),
1986 _messageList
, _ref
, alreadyRunning
);
1990 // set return values
1991 if (error
== B_OK
) {
1993 error
= B_ALREADY_RUNNING
;
1997 if (_appThread
!= NULL
)
1998 *_appThread
= appThread
;
2001 DBG(OUT("BRoster::_LaunchApp() done: %s (%lx)\n",
2002 strerror(error
), error
));
2009 BRoster::_SetAppFlags(team_id team
, uint32 flags
) const
2015 BRoster::_DumpRoster() const
2020 /*! Finds an application associated with a MIME type or a file.
2022 It does also supply the caller with some more information about the
2023 application, like signature, app flags and whether the supplied
2024 MIME type/entry_ref already identified an application.
2026 At least one of \a inType or \a ref must not be \c NULL. If \a inType is
2027 supplied, \a ref is ignored.
2029 If \a ref refers to a link, it is updated with the entry_ref for the
2032 \see FindApp() for how the application is searched.
2034 \a signature is set to a string with length 0, if the found
2035 application has no signature.
2037 \param inType The MIME type for which an application shall be found.
2039 \param ref The file for which an application shall be found.
2041 \param appRef A pointer to a pre-allocated entry_ref to be filled with
2042 a reference to the found application's executable. May be \c NULL.
2043 \param signature A pointer to a pre-allocated char buffer of at
2044 least size \c B_MIME_TYPE_LENGTH to be filled with the signature of
2045 the found application. May be \c NULL.
2046 \param appFlags A pointer to a pre-allocated uint32 variable to be filled
2047 with the app flags of the found application. May be \c NULL.
2048 \param wasDocument A pointer to a pre-allocated bool variable to be set to
2049 \c true, if the supplied file was not identifying an application,
2050 to \c false otherwise. Has no meaning, if a \a inType is supplied.
2053 \return A status code.
2054 \retval B_OK Everything went fine.
2055 \retval B_BAD_VALUE \c NULL \a inType and \a ref.
2057 \see FindApp() for other error codes.
2060 BRoster::_ResolveApp(const char* inType
, entry_ref
* ref
,
2061 entry_ref
* _appRef
, char* _signature
, uint32
* _appFlags
,
2062 bool* _wasDocument
) const
2064 if ((inType
== NULL
&& ref
== NULL
)
2065 || (inType
!= NULL
&& strlen(inType
) >= B_MIME_TYPE_LENGTH
))
2074 if (inType
!= NULL
) {
2075 error
= _TranslateType(inType
, &appMeta
, &appRef
, &appFile
);
2076 if (_wasDocument
!= NULL
)
2077 *_wasDocument
= !(appMeta
== inType
);
2079 error
= _TranslateRef(ref
, &appMeta
, &appRef
, &appFile
,
2084 if (!fNoRegistrar
&& error
== B_OK
) {
2086 if (path
.SetTo(&appRef
) == B_OK
)
2087 create_app_meta_mime(path
.Path(), false, true, false);
2090 // set the app hint on the type -- but only if the file has the
2091 // respective signature, otherwise unset the app hint
2092 BAppFileInfo appFileInfo
;
2093 if (!fNoRegistrar
&& error
== B_OK
) {
2094 char signature
[B_MIME_TYPE_LENGTH
];
2095 if (appFileInfo
.SetTo(&appFile
) == B_OK
2096 && appFileInfo
.GetSignature(signature
) == B_OK
) {
2097 if (!strcasecmp(appMeta
.Type(), signature
)) {
2098 // Only set the app hint if there is none yet
2100 if (appMeta
.GetAppHint(&dummyRef
) != B_OK
)
2101 appMeta
.SetAppHint(&appRef
);
2103 appMeta
.SetAppHint(NULL
);
2104 appMeta
.SetTo(signature
);
2107 appMeta
.SetAppHint(NULL
);
2110 // set the return values
2111 if (error
== B_OK
) {
2115 if (_signature
!= NULL
) {
2116 // there's no warranty, that appMeta is valid
2117 if (appMeta
.IsValid()) {
2118 strlcpy(_signature
, appMeta
.Type(),
2119 B_MIME_TYPE_LENGTH
);
2121 _signature
[0] = '\0';
2124 if (_appFlags
!= NULL
) {
2125 // if an error occurs here, we don't care and just set a default
2127 if (appFileInfo
.InitCheck() != B_OK
2128 || appFileInfo
.GetAppFlags(_appFlags
) != B_OK
) {
2129 *_appFlags
= B_REG_DEFAULT_APP_FLAGS
;
2133 // unset the ref on error
2134 if (_appRef
!= NULL
)
2142 /*! \brief Finds an application associated with a file.
2144 \a appMeta is left unmodified, if the file is executable, but has no
2147 \see FindApp() for how the application is searched.
2149 If \a ref refers to a link, it is updated with the entry_ref for the
2152 \param ref The file for which an application shall be found.
2153 \param appMeta A pointer to a pre-allocated BMimeType to be set to the
2154 signature of the found application.
2155 \param appRef A pointer to a pre-allocated entry_ref to be filled with
2156 a reference to the found application's executable.
2157 \param appFile A pointer to a pre-allocated BFile to be set to the
2158 executable of the found application.
2159 \param wasDocument A pointer to a pre-allocated bool variable to be set to
2160 \c true, if the supplied file was not identifying an application,
2161 to \c false otherwise. May be \c NULL.
2163 \return A status code.
2164 \retval B_OK: Everything went fine.
2165 \retval B_BAD_VALUE: \c NULL \a ref, \a appMeta, \a appRef or \a appFile.
2167 \see FindApp() for other error codes.
2170 BRoster::_TranslateRef(entry_ref
* ref
, BMimeType
* appMeta
,
2171 entry_ref
* appRef
, BFile
* appFile
, bool* _wasDocument
) const
2173 if (ref
== NULL
|| appMeta
== NULL
|| appRef
== NULL
|| appFile
== NULL
)
2176 // resolve ref, if necessary
2178 status_t error
= entry
.SetTo(ref
, false);
2182 if (entry
.IsSymLink()) {
2183 // ref refers to a link
2184 if (entry
.SetTo(ref
, true) != B_OK
|| entry
.GetRef(ref
) != B_OK
)
2185 return B_LAUNCH_FAILED_NO_RESOLVE_LINK
;
2190 error
= node
.SetTo(ref
);
2196 error
= node
.GetPermissions(&permissions
);
2200 if ((permissions
& S_IXUSR
) != 0 && node
.IsFile()) {
2201 // node is executable and a file
2202 error
= appFile
->SetTo(ref
, B_READ_ONLY
);
2206 // get the app's signature via a BAppFileInfo
2207 BAppFileInfo appFileInfo
;
2208 error
= appFileInfo
.SetTo(appFile
);
2212 // don't worry, if the file doesn't have a signature, just
2213 // unset the supplied object
2214 char type
[B_MIME_TYPE_LENGTH
];
2215 if (appFileInfo
.GetSignature(type
) == B_OK
) {
2216 error
= appMeta
->SetTo(type
);
2222 // If the file type indicates that the file is an application, we've
2223 // definitely got what we're looking for.
2224 bool isDocument
= true;
2225 if (_GetFileType(ref
, &appFileInfo
, type
) == B_OK
2226 && strcasecmp(type
, B_APP_MIME_TYPE
) == 0) {
2230 // If our file is not an application executable, we probably have a
2231 // script. Check whether the file has a preferred application set. If
2232 // so, we fall through and use the preferred app instead. Otherwise
2234 char preferredApp
[B_MIME_TYPE_LENGTH
];
2235 if (!isDocument
|| appFileInfo
.GetPreferredApp(preferredApp
) != B_OK
) {
2237 if (_wasDocument
!= NULL
)
2238 *_wasDocument
= isDocument
;
2243 // Executable file, but not an application, and it has a preferred
2244 // application set. Fall through...
2247 // the node is not exectuable or not a file
2250 error
= nodeInfo
.SetTo(&node
);
2254 // if the file has a preferred app, let _TranslateType() find
2256 char preferredApp
[B_MIME_TYPE_LENGTH
];
2257 if (nodeInfo
.GetPreferredApp(preferredApp
) == B_OK
2258 && _TranslateType(preferredApp
, appMeta
, appRef
, appFile
) == B_OK
) {
2259 if (_wasDocument
!= NULL
)
2260 *_wasDocument
= true;
2265 // no preferred app or existing one was not found -- we
2266 // need to get the file's type
2268 // get the type from the file
2269 char fileType
[B_MIME_TYPE_LENGTH
];
2270 error
= _GetFileType(ref
, &nodeInfo
, fileType
);
2274 // now let _TranslateType() do the actual work
2275 error
= _TranslateType(fileType
, appMeta
, appRef
, appFile
);
2279 if (_wasDocument
!= NULL
)
2280 *_wasDocument
= true;
2286 /*! Finds an application associated with a MIME type.
2288 \see FindApp() for how the application is searched.
2290 \param mimeType The MIME type for which an application shall be found.
2291 \param appMeta A pointer to a pre-allocated BMimeType to be set to the
2292 signature of the found application.
2293 \param appRef A pointer to a pre-allocated entry_ref to be filled with
2294 a reference to the found application's executable.
2295 \param appFile A pointer to a pre-allocated BFile to be set to the
2296 executable of the found application.
2298 \return A status code.
2299 \retval B_OK Everything went fine.
2300 \retval B_BAD_VALUE \c NULL \a mimeType, \a appMeta, \a appRef or
2303 \see FindApp() for other error codes.
2306 BRoster::_TranslateType(const char* mimeType
, BMimeType
* appMeta
,
2307 entry_ref
* appRef
, BFile
* appFile
) const
2309 if (mimeType
== NULL
|| appMeta
== NULL
|| appRef
== NULL
2310 || appFile
== NULL
|| strlen(mimeType
) >= B_MIME_TYPE_LENGTH
) {
2314 // Create a BMimeType and check, if the type is installed.
2316 status_t error
= type
.SetTo(mimeType
);
2318 // Get the preferred apps from the sub and super type.
2319 char primarySignature
[B_MIME_TYPE_LENGTH
];
2320 char secondarySignature
[B_MIME_TYPE_LENGTH
];
2321 primarySignature
[0] = '\0';
2322 secondarySignature
[0] = '\0';
2324 if (error
== B_OK
) {
2325 BMimeType superType
;
2326 if (type
.GetSupertype(&superType
) == B_OK
)
2327 superType
.GetPreferredApp(secondarySignature
);
2328 if (type
.IsInstalled()) {
2329 if (type
.GetPreferredApp(primarySignature
) != B_OK
) {
2330 // The type is installed, but has no preferred app.
2331 primarySignature
[0] = '\0';
2332 } else if (!strcmp(primarySignature
, secondarySignature
)) {
2333 // Both types have the same preferred app, there is
2334 // no point in testing it twice.
2335 secondarySignature
[0] = '\0';
2338 // The type is not installed. We assume it is an app signature.
2339 strlcpy(primarySignature
, mimeType
, sizeof(primarySignature
));
2343 // We will use this BMessage "signatures" to hold all supporting apps
2344 // so we can iterator over them in the preferred order. We include
2345 // the supporting apps in such a way that the configured preferred
2346 // applications for the MIME type are in front of other supporting
2347 // applications for the sub and the super type respectively.
2348 const char* kSigField
= "applications";
2349 BMessage signatures
;
2350 bool addedSecondarySignature
= false;
2351 if (error
== B_OK
) {
2352 if (primarySignature
[0] != '\0')
2353 error
= signatures
.AddString(kSigField
, primarySignature
);
2355 // If there is a preferred app configured for the super type,
2356 // but no preferred type for the sub-type, add the preferred
2357 // super type handler in front of any other handlers. This way
2358 // we fall-back to non-preferred but supporting apps only in the
2359 // case when there is a preferred handler for the sub-type but
2360 // it cannot be resolved (misconfiguration).
2361 if (secondarySignature
[0] != '\0') {
2362 error
= signatures
.AddString(kSigField
, secondarySignature
);
2363 addedSecondarySignature
= true;
2368 BMessage supportingSignatures
;
2370 && type
.GetSupportingApps(&supportingSignatures
) == B_OK
) {
2372 if (supportingSignatures
.FindInt32("be:sub", &subCount
) != B_OK
)
2374 // Add all signatures with direct support for the sub-type.
2375 const char* supportingType
;
2376 if (!addedSecondarySignature
) {
2377 // Try to add the secondarySignature in front of all other
2378 // supporting apps, if we find it among those.
2379 for (int32 i
= 0; error
== B_OK
&& i
< subCount
2380 && supportingSignatures
.FindString(kSigField
, i
,
2381 &supportingType
) == B_OK
; i
++) {
2382 if (strcmp(primarySignature
, supportingType
) != 0
2383 && strcmp(secondarySignature
, supportingType
) == 0) {
2384 error
= signatures
.AddString(kSigField
, supportingType
);
2385 addedSecondarySignature
= true;
2391 for (int32 i
= 0; error
== B_OK
&& i
< subCount
2392 && supportingSignatures
.FindString(kSigField
, i
,
2393 &supportingType
) == B_OK
; i
++) {
2394 if (strcmp(primarySignature
, supportingType
) != 0
2395 && strcmp(secondarySignature
, supportingType
) != 0) {
2396 error
= signatures
.AddString(kSigField
, supportingType
);
2400 // Add the preferred type of the super type here before adding
2401 // the other types supporting the super type, but only if we have
2402 // not already added it in case there was no preferred app for the
2403 // sub-type configured.
2404 if (error
== B_OK
&& !addedSecondarySignature
2405 && secondarySignature
[0] != '\0') {
2406 error
= signatures
.AddString(kSigField
, secondarySignature
);
2409 // Add all signatures with support for the super-type.
2410 for (int32 i
= subCount
; error
== B_OK
2411 && supportingSignatures
.FindString(kSigField
, i
,
2412 &supportingType
) == B_OK
; i
++) {
2413 // Don't add the signature if it's one of the preferred apps
2415 if (strcmp(primarySignature
, supportingType
) != 0
2416 && strcmp(secondarySignature
, supportingType
) != 0) {
2417 error
= signatures
.AddString(kSigField
, supportingType
);
2421 // Failed to get supporting apps, just add the preferred apps.
2422 if (error
== B_OK
&& secondarySignature
[0] != '\0')
2423 error
= signatures
.AddString(kSigField
, secondarySignature
);
2429 // Set an error in case we can't resolve a single supporting app.
2430 error
= B_LAUNCH_FAILED_NO_PREFERRED_APP
;
2432 // See if we can find a good application that is valid from the messege.
2433 const char* signature
;
2435 signatures
.FindString(kSigField
, i
, &signature
) == B_OK
; i
++) {
2436 if (signature
[0] == '\0')
2439 error
= appMeta
->SetTo(signature
);
2441 // Check, whether the signature is installed and has an app hint
2442 bool appFound
= false;
2443 if (error
== B_OK
&& appMeta
->GetAppHint(appRef
) == B_OK
) {
2444 // Resolve symbolic links, if necessary
2446 if (entry
.SetTo(appRef
, true) == B_OK
&& entry
.IsFile()
2447 && entry
.GetRef(appRef
) == B_OK
) {
2450 // Bad app hint -- remove it
2451 appMeta
->SetAppHint(NULL
);
2455 // In case there is no app hint or it is invalid, we need to query for
2457 if (error
== B_OK
&& !appFound
)
2458 error
= query_for_app(appMeta
->Type(), appRef
);
2461 error
= appFile
->SetTo(appRef
, B_READ_ONLY
);
2463 // check, whether the app can be used
2465 error
= can_app_be_used(appRef
);
2475 /*! Gets the type of a file either from the node info or by sniffing.
2477 The method first tries to get the file type from the supplied node info. If
2478 that didn't work, the given entry ref is sniffed.
2480 \param file An entry_ref referring to the file in question.
2481 \param nodeInfo A BNodeInfo initialized to the file.
2482 \param mimeType A pointer to a pre-allocated char buffer of at least size
2483 \c B_MIME_TYPE_LENGTH to be filled with the MIME type sniffed for
2486 \return A status code.
2487 \retval B_OK Everything went fine.
2488 \retval B_BAD_VALUE \c NULL \a file, \a nodeInfo or \a mimeType.
2491 BRoster::_GetFileType(const entry_ref
* file
, BNodeInfo
* nodeInfo
,
2492 char* mimeType
) const
2494 // first try the node info
2495 if (nodeInfo
->GetType(mimeType
) == B_OK
)
2501 // Try to update the file's MIME info and just read the updated type.
2502 // If that fails, sniff manually.
2504 if (path
.SetTo(file
) != B_OK
2505 || update_mime_info(path
.Path(), false, true, false) != B_OK
2506 || nodeInfo
->GetType(mimeType
) != B_OK
) {
2508 status_t error
= BMimeType::GuessMimeType(file
, &type
);
2512 if (!type
.IsValid())
2515 strlcpy(mimeType
, type
.Type(), B_MIME_TYPE_LENGTH
);
2522 /*! Sends messages to a running team.
2524 In particular those messages are \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED,
2525 \c B_READY_TO_RUN and other, arbitrary, ones.
2527 If \a messageList is not \c NULL or empty, those messages are sent first,
2528 then follow \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED and finally
2531 \c B_ARGV_RECEIVED is sent only, if \a args is not \c NULL and contains
2532 more than one element. \c B_REFS_RECEIVED is sent only, if \a ref is not
2535 The ownership of all supplied objects retains to the caller.
2537 \param team The team ID of the target application.
2538 \param argc Number of elements in \a args.
2539 \param args Argument vector to be sent to the target. May be \c NULL.
2540 \param messageList List of BMessages to be sent to the target. May be
2542 \param ref entry_ref to be sent to the target. May be \c NULL.
2543 \param alreadyRunning \c true, if the target app is not newly launched,
2544 but was already running, \c false otherwise (a \c B_READY_TO_RUN
2545 message will be sent in this case).
2547 \return \c B_OK if everything went fine, or an error code otherwise.
2550 BRoster::_SendToRunning(team_id team
, int argc
, const char* const* args
,
2551 const BList
* messageList
, const entry_ref
* ref
,
2552 bool alreadyRunning
) const
2554 status_t error
= B_OK
;
2556 // Construct a messenger to the app: We can't use the public constructor,
2557 // since the target application may be B_ARGV_ONLY.
2559 error
= GetRunningAppInfo(team
, &info
);
2560 if (error
== B_OK
) {
2561 BMessenger messenger
;
2562 BMessenger::Private(messenger
).SetTo(team
, info
.port
,
2565 // send messages from the list
2566 if (messageList
!= NULL
) {
2568 BMessage
* message
= (BMessage
*)messageList
->ItemAt(i
);
2570 messenger
.SendMessage(message
);
2574 // send B_ARGV_RECEIVED or B_REFS_RECEIVED or B_SILENT_RELAUNCH
2575 // (if already running)
2576 if (args
!= NULL
&& argc
> 1) {
2577 BMessage
message(B_ARGV_RECEIVED
);
2578 message
.AddInt32("argc", argc
);
2579 for (int32 i
= 0; i
< argc
; i
++)
2580 message
.AddString("argv", args
[i
]);
2582 // also add current working directory
2583 char cwd
[B_PATH_NAME_LENGTH
];
2584 if (getcwd(cwd
, B_PATH_NAME_LENGTH
) != NULL
)
2585 message
.AddString("cwd", cwd
);
2587 messenger
.SendMessage(&message
);
2588 } else if (ref
!= NULL
) {
2589 DBG(OUT("_SendToRunning : B_REFS_RECEIVED\n"));
2590 BMessage
message(B_REFS_RECEIVED
);
2591 message
.AddRef("refs", ref
);
2592 messenger
.SendMessage(&message
);
2593 } else if (alreadyRunning
&& (!messageList
|| messageList
->IsEmpty()))
2594 messenger
.SendMessage(B_SILENT_RELAUNCH
);
2596 if (!alreadyRunning
) {
2597 // send B_READY_TO_RUN
2598 DBG(OUT("_SendToRunning : B_READY_TO_RUN\n"));
2599 messenger
.SendMessage(B_READY_TO_RUN
);
2607 /*! Allows to use certain functionality of the BRoster class without
2608 accessing the registrar.
2611 BRoster::_SetWithoutRegistrar(bool noRegistrar
)
2613 fNoRegistrar
= noRegistrar
;
2618 BRoster::_InitMessenger()
2620 DBG(OUT("BRoster::InitMessengers()\n"));
2622 // find the registrar port
2624 if (BLaunchRoster().GetData("application/x-vnd.Haiku-registrar", data
)
2627 port_id port
= data
.GetInt32("port", -1);
2628 team_id team
= data
.GetInt32("team", -1);
2630 if (port
>= 0 && team
!= current_team()) {
2631 // Make sure we aren't the registrar ourselves.
2633 DBG(OUT(" found roster port\n"));
2635 BMessenger::Private(fMessenger
).SetTo(team
, port
,
2640 DBG(OUT("BRoster::InitMessengers() done\n"));
2645 BRoster::_InitMimeMessenger(void* data
)
2647 BRoster
* roster
= (BRoster
*)data
;
2649 // ask for the MIME messenger
2650 // Generous 1s + 5s timeouts. It could actually be synchronous, but
2651 // timeouts allow us to debug the registrar main thread.
2652 BMessage
request(B_REG_GET_MIME_MESSENGER
);
2654 status_t error
= roster
->fMessenger
.SendMessage(&request
, &reply
,
2655 1000000LL, 5000000LL);
2656 if (error
== B_OK
&& reply
.what
== B_REG_SUCCESS
) {
2657 DBG(OUT(" got reply from roster\n"));
2658 reply
.FindMessenger("messenger", &roster
->fMimeMessenger
);
2660 DBG(OUT(" no (useful) reply from roster: error: %lx: %s\n", error
,
2663 DBG(reply
.PrintToStream());
2671 BRoster::_MimeMessenger()
2673 __init_once(&fMimeMessengerInitOnce
, &_InitMimeMessenger
, this);
2674 return fMimeMessenger
;
2678 /*! Sends a request to the roster to add the application with the
2679 given signature to the front of the recent apps list.
2682 BRoster::_AddToRecentApps(const char* signature
) const
2684 status_t error
= B_OK
;
2685 // compose the request message
2686 BMessage
request(B_REG_ADD_TO_RECENT_APPS
);
2688 error
= request
.AddString("app sig", signature
);
2693 error
= fMessenger
.SendMessage(&request
, &reply
);
2695 // evaluate the reply
2697 if (error
== B_OK
) {
2698 error
= reply
.what
== B_REG_RESULT
2699 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
2703 error
= reply
.FindInt32("result", &result
);
2708 // Nothing to return... how sad :-(
2713 //! Sends a request to the roster to clear the recent documents list.
2715 BRoster::_ClearRecentDocuments() const
2717 BMessage
request(B_REG_CLEAR_RECENT_DOCUMENTS
);
2719 fMessenger
.SendMessage(&request
, &reply
);
2723 //! Sends a request to the roster to clear the recent documents list.
2725 BRoster::_ClearRecentFolders() const
2727 BMessage
request(B_REG_CLEAR_RECENT_FOLDERS
);
2729 fMessenger
.SendMessage(&request
, &reply
);
2733 //! \brief Sends a request to the roster to clear the recent documents list.
2735 BRoster::_ClearRecentApps() const
2737 BMessage
request(B_REG_CLEAR_RECENT_APPS
);
2739 fMessenger
.SendMessage(&request
, &reply
);
2743 /*! Loads the system's recently used document, folder, and
2744 application lists from the specified file.
2746 \note The current lists are cleared before loading the new lists
2748 \param filename The name of the file to load from
2751 BRoster::_LoadRecentLists(const char* filename
) const
2753 status_t error
= B_OK
;
2755 // compose the request message
2756 BMessage
request(B_REG_LOAD_RECENT_LISTS
);
2758 error
= request
.AddString("filename", filename
);
2763 error
= fMessenger
.SendMessage(&request
, &reply
);
2765 // evaluate the reply
2767 if (error
== B_OK
) {
2768 error
= reply
.what
== B_REG_RESULT
2769 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
2772 error
= reply
.FindInt32("result", &result
);
2777 // Nothing to return... how sad :-(
2782 /*! Saves the system's recently used document, folder, and
2783 application lists to the specified file.
2785 \param filename The name of the file to save to
2788 BRoster::_SaveRecentLists(const char* filename
) const
2790 status_t error
= B_OK
;
2792 // compose the request message
2793 BMessage
request(B_REG_SAVE_RECENT_LISTS
);
2795 error
= request
.AddString("filename", filename
);
2800 error
= fMessenger
.SendMessage(&request
, &reply
);
2802 // evaluate the reply
2804 if (error
== B_OK
) {
2805 error
= reply
.what
== B_REG_RESULT
2806 ? (status_t
)B_OK
: (status_t
)B_BAD_REPLY
;
2809 error
= reply
.FindInt32("result", &result
);
2814 // Nothing to return... how sad :-(