BPicture: Fix archive constructor.
[haiku.git] / src / kits / app / Roster.cpp
blobdf8ec689d117b7e1d5b550bc383482e9f84af957
1 /*
2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
8 */
11 #include <Roster.h>
13 #include <ctype.h>
14 #include <new>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <strings.h>
18 #include <unistd.h>
20 #include <AppFileInfo.h>
21 #include <Application.h>
22 #include <Bitmap.h>
23 #include <Directory.h>
24 #include <File.h>
25 #include <FindDirectory.h>
26 #include <fs_index.h>
27 #include <fs_info.h>
28 #include <image.h>
29 #include <List.h>
30 #include <Mime.h>
31 #include <Node.h>
32 #include <NodeInfo.h>
33 #include <OS.h>
34 #include <Path.h>
35 #include <Query.h>
36 #include <RegistrarDefs.h>
37 #include <String.h>
38 #include <Volume.h>
39 #include <VolumeRoster.h>
41 #include <locks.h>
43 #include <AppMisc.h>
44 #include <DesktopLink.h>
45 #include <LaunchRoster.h>
46 #include <MessengerPrivate.h>
47 #include <PortLink.h>
48 #include <RosterPrivate.h>
49 #include <ServerProtocol.h>
52 using namespace std;
53 using namespace BPrivate;
56 // debugging
57 //#define DBG(x) x
58 #define DBG(x)
59 #ifdef DEBUG_PRINTF
60 # define OUT DEBUG_PRINTF
61 #else
62 # define OUT printf
63 #endif
66 enum {
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.
90 static status_t
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;
95 ssize_t size = 0;
96 // find the flat app info in the message
97 if (error == B_OK) {
98 error = message->FindData("app_info", B_REG_APP_INFO_TYPE,
99 (const void**)&flatInfo, &size);
101 // unflatten the flat info
102 if (error == B_OK) {
103 if (size == sizeof(flat_app_info)) {
104 memcpy(info, &flatInfo->info, sizeof(app_info));
105 info->ref.name = NULL;
106 if (strlen(flatInfo->ref_name) > 0)
107 info->ref.set_name(flatInfo->ref_name);
108 } else
109 error = B_ERROR;
112 return error;
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
128 trash.
130 static status_t
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.
135 BEntry entry;
136 if (error == B_OK)
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
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;
158 return error;
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
169 are equal.
171 static int32
172 compare_version_infos(const version_info& info1, const version_info& info2)
174 int32 result = 0;
175 if (info1.major < info2.major)
176 result = -1;
177 else if (info1.major > info2.major)
178 result = 1;
179 else if (info1.middle < info2.middle)
180 result = -1;
181 else if (info1.middle > info2.middle)
182 result = 1;
183 else if (info1.minor < info2.minor)
184 result = -1;
185 else if (info1.minor > info2.minor)
186 result = 1;
187 else if (info1.variety < info2.variety)
188 result = -1;
189 else if (info1.variety > info2.variety)
190 result = 1;
191 else if (info1.internal < info2.internal)
192 result = -1;
193 else if (info1.internal > info2.internal)
194 result = 1;
196 return result;
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
204 appears earlier.
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.
216 static int32
217 compare_queried_apps(const entry_ref* app1, const entry_ref* app2)
219 BPath path1(app1);
220 BPath path2(app2);
222 // Check search path
224 const char* searchPathes = getenv("PATH");
225 if (searchPathes != NULL) {
226 char* searchBuffer = strdup(searchPathes);
227 if (searchBuffer != NULL) {
228 char* last;
229 const char* path = strtok_r(searchBuffer, ":", &last);
230 while (path != NULL) {
231 // Check if any app path matches
232 size_t length = strlen(path);
233 bool found1 = !strncmp(path, path1.Path(), length)
234 && path1.Path()[length] == '/';
235 bool found2 = !strncmp(path, path2.Path(), length)
236 && path2.Path()[length] == '/';;
238 if (found1 != found2) {
239 free(searchBuffer);
240 return found1 ? 1 : -1;
243 path = strtok_r(NULL, ":", &last);
246 free(searchBuffer);
250 // Check system servers folder
251 BPath path;
252 find_directory(B_SYSTEM_SERVERS_DIRECTORY, &path);
253 BString serverPath(path.Path());
254 serverPath << '/';
255 size_t length = serverPath.Length();
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
264 BFile file1;
265 file1.SetTo(app1, B_READ_ONLY);
266 BFile file2;
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);
280 int32 result = 0;
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) {
290 if (hasVersionInfo2)
291 result = compare_version_infos(versionInfo1, versionInfo2);
292 else
293 result = 1;
294 } else {
295 if (hasVersionInfo2)
296 result = -1;
297 else if (modificationTime1 < modificationTime2)
298 result = -1;
299 else if (modificationTime1 > modificationTime2)
300 result = 1;
303 return result;
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
317 could not be found.
319 static status_t
320 query_for_app(const char* signature, entry_ref* appRef)
322 if (signature == NULL || appRef == NULL)
323 return B_BAD_VALUE;
325 status_t error = B_LAUNCH_FAILED_APP_NOT_FOUND;
326 bool caseInsensitive = false;
328 while (true) {
329 // search on all volumes
330 BVolumeRoster volumeRoster;
331 BVolume volume;
332 while (volumeRoster.GetNextVolume(&volume) == B_OK) {
333 if (!volume.KnowsQuery())
334 continue;
336 index_info info;
337 if (fs_stat_index(volume.Device(), "BEOS:APP_SIG", &info) != 0) {
338 // This volume doesn't seem to have the index we're looking for;
339 // querying it might need a long time, and we don't care *that*
340 // much...
341 continue;
344 BQuery query;
345 query.SetVolume(&volume);
346 query.PushAttr("BEOS:APP_SIG");
347 if (!caseInsensitive)
348 query.PushString(signature);
349 else {
350 // second pass, create a case insensitive query string
351 char string[B_MIME_TYPE_LENGTH * 4];
352 strlcpy(string, "application/", sizeof(string));
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])) {
360 *to++ = '[';
361 *to++ = tolower(from[0]);
362 *to++ = toupper(from[0]);
363 *to++ = ']';
364 } else
365 *to++ = from[0];
368 to[0] = '\0';
369 query.PushString(string);
371 query.PushOp(B_EQ);
373 query.Fetch();
375 // walk through the query
376 bool appFound = false;
377 status_t foundAppError = B_OK;
378 entry_ref ref;
379 while (query.GetNextRef(&ref) == B_OK) {
380 if ((!appFound || compare_queried_apps(appRef, &ref) < 0)
381 && (foundAppError = can_app_be_used(&ref)) == B_OK) {
382 *appRef = ref;
383 appFound = true;
386 if (!appFound) {
387 // If the query didn't return any hits, the error is
388 // B_LAUNCH_FAILED_APP_NOT_FOUND, otherwise we return the
389 // result of the last can_app_be_used().
390 error = foundAppError != B_OK
391 ? foundAppError : B_LAUNCH_FAILED_APP_NOT_FOUND;
392 } else
393 return B_OK;
396 if (!caseInsensitive)
397 caseInsensitive = true;
398 else
399 break;
402 return error;
406 // #pragma mark - app_info
409 app_info::app_info()
411 thread(-1),
412 team(-1),
413 port(-1),
414 flags(B_REG_DEFAULT_APP_FLAGS),
415 ref()
417 signature[0] = '\0';
421 app_info::~app_info()
426 // #pragma mark - BRoster::ArgVector
429 class BRoster::ArgVector {
430 public:
431 ArgVector();
432 ~ArgVector();
434 status_t Init(int argc, const char* const* args,
435 const entry_ref* appRef,
436 const entry_ref* docRef);
437 void Unset();
438 inline int Count() const { return fArgc; }
439 inline const char* const* Args() const { return fArgs; }
441 private:
442 int fArgc;
443 const char** fArgs;
444 BPath fAppPath;
445 BPath fDocPath;
449 //! Creates an uninitialized ArgVector.
450 BRoster::ArgVector::ArgVector()
452 fArgc(0),
453 fArgs(NULL),
454 fAppPath(),
455 fDocPath()
460 //! Frees all resources associated with the ArgVector.
461 BRoster::ArgVector::~ArgVector()
463 Unset();
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.
489 \return
490 - \c B_OK: Everything went fine.
491 - \c B_BAD_VALUE: \c NULL \a appRef.
492 - \c B_ENTRY_NOT_FOUND or other file system error codes: \a appRef could
493 not be resolved to a path.
494 - \c B_NO_MEMORY: Not enough memory to allocate for this operation.
496 status_t
497 BRoster::ArgVector::Init(int argc, const char* const* args,
498 const entry_ref* appRef, const entry_ref* docRef)
500 // unset old values
501 Unset();
502 status_t error = appRef ? B_OK : B_BAD_VALUE;
503 // get app path
504 if (error == B_OK)
505 error = fAppPath.SetTo(appRef);
506 // determine number of arguments
507 bool hasDocArg = false;
508 if (error == B_OK) {
509 fArgc = 1;
510 if (argc > 0 && args) {
511 fArgc += argc;
512 if (docRef != NULL && fDocPath.SetTo(docRef) == B_OK) {
513 fArgc++;
514 hasDocArg = true;
517 fArgs = new(nothrow) const char*[fArgc + 1];
518 // + 1 for the terminating NULL
519 if (!fArgs)
520 error = B_NO_MEMORY;
522 // init vector
523 if (error == B_OK) {
524 fArgs[0] = fAppPath.Path();
525 if (argc > 0 && args != NULL) {
526 for (int i = 0; i < argc; i++)
527 fArgs[i + 1] = args[i];
528 if (hasDocArg)
529 fArgs[fArgc - 1] = fDocPath.Path();
531 // NULL terminate (e.g. required by load_image())
532 fArgs[fArgc] = NULL;
534 return error;
538 //! Uninitializes the object.
539 void
540 BRoster::ArgVector::Unset()
542 fArgc = 0;
543 delete[] fArgs;
544 fArgs = NULL;
545 fAppPath.Unset();
546 fDocPath.Unset();
550 // #pragma mark - BRoster
553 BRoster::BRoster()
555 fMessenger(),
556 fMimeMessenger(),
557 fMimeMessengerInitOnce(INIT_ONCE_UNINITIALIZED),
558 fNoRegistrar(false)
560 _InitMessenger();
564 BRoster::~BRoster()
569 // #pragma mark - Querying for apps
572 bool
573 BRoster::IsRunning(const char* signature) const
575 return (TeamFor(signature) >= 0);
579 bool
580 BRoster::IsRunning(entry_ref* ref) const
582 return (TeamFor(ref) >= 0);
586 team_id
587 BRoster::TeamFor(const char* signature) const
589 team_id team;
590 app_info info;
591 status_t error = GetAppInfo(signature, &info);
592 if (error == B_OK)
593 team = info.team;
594 else
595 team = error;
597 return team;
601 team_id
602 BRoster::TeamFor(entry_ref* ref) const
604 team_id team;
605 app_info info;
606 status_t error = GetAppInfo(ref, &info);
607 if (error == B_OK)
608 team = info.team;
609 else
610 team = error;
611 return team;
615 void
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);
622 // send the request
623 BMessage reply;
624 if (error == B_OK)
625 error = fMessenger.SendMessage(&request, &reply);
627 // evaluate the reply
628 if (error == B_OK) {
629 if (reply.what == B_REG_SUCCESS) {
630 team_id team;
631 for (int32 i = 0; reply.FindInt32("teams", i, &team) == B_OK; i++)
632 teamIDList->AddItem((void*)(addr_t)team);
633 } else {
634 if (reply.FindInt32("error", &error) != B_OK)
635 error = B_ERROR;
636 DBG(OUT("Roster request unsuccessful: %s\n", strerror(error)));
637 DBG(reply.PrintToStream());
639 } else {
640 DBG(OUT("Sending message to roster failed: %s\n", strerror(error)));
645 void
646 BRoster::GetAppList(const char* signature, BList* teamIDList) const
648 status_t error = B_OK;
649 if (signature == NULL || teamIDList == NULL)
650 error = B_BAD_VALUE;
652 // compose the request message
653 BMessage request(B_REG_GET_APP_LIST);
654 if (error == B_OK)
655 error = request.AddString("signature", signature);
657 // send the request
658 BMessage reply;
659 if (error == B_OK)
660 error = fMessenger.SendMessage(&request, &reply);
662 // evaluate the reply
663 if (error == B_OK) {
664 if (reply.what == B_REG_SUCCESS) {
665 team_id team;
666 for (int32 i = 0; reply.FindInt32("teams", i, &team) == B_OK; i++)
667 teamIDList->AddItem((void*)(addr_t)team);
668 } else if (reply.FindInt32("error", &error) != B_OK)
669 error = B_ERROR;
674 status_t
675 BRoster::GetAppInfo(const char* signature, app_info* info) const
677 status_t error = B_OK;
678 if (signature == NULL || info == NULL)
679 error = B_BAD_VALUE;
681 // compose the request message
682 BMessage request(B_REG_GET_APP_INFO);
683 if (error == B_OK)
684 error = request.AddString("signature", signature);
686 // send the request
687 BMessage reply;
688 if (error == B_OK)
689 error = fMessenger.SendMessage(&request, &reply);
691 // evaluate the reply
692 if (error == B_OK) {
693 if (reply.what == B_REG_SUCCESS)
694 error = find_message_app_info(&reply, info);
695 else if (reply.FindInt32("error", &error) != B_OK)
696 error = B_ERROR;
699 return error;
703 status_t
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);
709 if (error == B_OK)
710 error = request.AddRef("ref", ref);
712 // send the request
713 BMessage reply;
714 if (error == B_OK)
715 error = fMessenger.SendMessage(&request, &reply);
717 // evaluate the reply
718 if (error == B_OK) {
719 if (reply.what == B_REG_SUCCESS)
720 error = find_message_app_info(&reply, info);
721 else if (reply.FindInt32("error", &error) != B_OK)
722 error = B_ERROR;
724 return error;
728 status_t
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);
736 if (error == B_OK)
737 error = request.AddInt32("team", team);
738 // send the request
739 BMessage reply;
740 if (error == B_OK)
741 error = fMessenger.SendMessage(&request, &reply);
743 // evaluate the reply
744 if (error == B_OK) {
745 if (reply.what == B_REG_SUCCESS)
746 error = find_message_app_info(&reply, info);
747 else if (reply.FindInt32("error", &error) != B_OK)
748 error = B_ERROR;
750 return error;
754 status_t
755 BRoster::GetActiveAppInfo(app_info* info) const
757 if (info == NULL)
758 return B_BAD_VALUE;
760 // compose the request message
761 BMessage request(B_REG_GET_APP_INFO);
762 // send the request
763 BMessage reply;
764 status_t error = fMessenger.SendMessage(&request, &reply);
765 // evaluate the reply
766 if (error == B_OK) {
767 if (reply.what == B_REG_SUCCESS)
768 error = find_message_app_info(&reply, info);
769 else if (reply.FindInt32("error", &error) != B_OK)
770 error = B_ERROR;
772 return error;
776 status_t
777 BRoster::FindApp(const char* mimeType, entry_ref* app) const
779 if (mimeType == NULL || app == NULL)
780 return B_BAD_VALUE;
782 return _ResolveApp(mimeType, NULL, app, NULL, NULL, NULL);
786 status_t
787 BRoster::FindApp(entry_ref* ref, entry_ref* app) const
789 if (ref == NULL || app == NULL)
790 return B_BAD_VALUE;
792 entry_ref _ref(*ref);
793 return _ResolveApp(NULL, &_ref, app, NULL, NULL, NULL);
797 // #pragma mark - Launching, activating, and broadcasting to apps
800 status_t
801 BRoster::Broadcast(BMessage* message) const
803 return Broadcast(message, be_app_messenger);
807 status_t
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);
813 if (error == B_OK)
814 error = request.AddInt32("team", BPrivate::current_team());
815 if (error == B_OK)
816 error = request.AddMessage("message", message);
817 if (error == B_OK)
818 error = request.AddMessenger("reply_target", replyTo);
820 // send the request
821 BMessage reply;
822 if (error == B_OK)
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)
828 error = B_ERROR;
830 return error;
834 status_t
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);
840 if (error == B_OK)
841 error = request.AddMessenger("target", target);
842 if (error == B_OK)
843 error = request.AddInt32("events", (int32)eventMask);
845 // send the request
846 BMessage reply;
847 if (error == B_OK)
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)
853 error = B_ERROR;
855 return error;
859 status_t
860 BRoster::StopWatching(BMessenger target) const
862 status_t error = B_OK;
863 // compose the request message
864 BMessage request(B_REG_STOP_WATCHING);
865 if (error == B_OK)
866 error = request.AddMessenger("target", target);
868 // send the request
869 BMessage reply;
870 if (error == B_OK)
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)
876 error = B_ERROR;
878 return error;
882 status_t
883 BRoster::ActivateApp(team_id team) const
885 BPrivate::DesktopLink link;
887 status_t status = link.InitCheck();
888 if (status < B_OK)
889 return status;
891 // prepare the message
892 status_t error = link.StartMessage(AS_ACTIVATE_APP);
893 if (error != B_OK)
894 return error;
896 error = link.Attach(link.ReceiverPort());
897 if (error != B_OK)
898 return error;
900 error = link.Attach(team);
901 if (error != B_OK)
902 return error;
904 // send it
905 status_t code;
906 error = link.FlushWithReply(code);
907 if (error != B_OK)
908 return error;
910 return code;
914 status_t
915 BRoster::Launch(const char* mimeType, BMessage* initialMessage,
916 team_id* _appTeam) const
918 if (mimeType == NULL)
919 return B_BAD_VALUE;
921 BList messageList;
922 if (initialMessage != NULL)
923 messageList.AddItem(initialMessage);
925 return _LaunchApp(mimeType, NULL, &messageList, 0, NULL,
926 (const char**)environ, _appTeam, NULL, false);
930 status_t
931 BRoster::Launch(const char* mimeType, BList* messageList,
932 team_id* _appTeam) const
934 if (mimeType == NULL)
935 return B_BAD_VALUE;
937 return _LaunchApp(mimeType, NULL, messageList, 0, NULL,
938 (const char**)environ, _appTeam, NULL, false);
942 status_t
943 BRoster::Launch(const char* mimeType, int argc, const char* const* args,
944 team_id* _appTeam) const
946 if (mimeType == NULL)
947 return B_BAD_VALUE;
949 return _LaunchApp(mimeType, NULL, NULL, argc, args, (const char**)environ,
950 _appTeam, NULL, false);
954 status_t
955 BRoster::Launch(const entry_ref* ref, const BMessage* initialMessage,
956 team_id* _appTeam) const
958 if (ref == NULL)
959 return B_BAD_VALUE;
961 BList messageList;
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);
970 status_t
971 BRoster::Launch(const entry_ref* ref, const BList* messageList,
972 team_id* appTeam) const
974 if (ref == NULL)
975 return B_BAD_VALUE;
977 return _LaunchApp(NULL, ref, messageList, 0, NULL, (const char**)environ,
978 appTeam, NULL, false);
982 status_t
983 BRoster::Launch(const entry_ref* ref, int argc, const char* const* args,
984 team_id* appTeam) const
986 if (ref == NULL)
987 return B_BAD_VALUE;
989 return _LaunchApp(NULL, ref, NULL, argc, args, (const char**)environ,
990 appTeam, NULL, false);
994 #if __GNUC__ == 2
995 // #pragma mark - Binary compatibility
998 extern "C" status_t
999 Launch__C7BRosterP9entry_refP8BMessagePl(BRoster* roster, entry_ref* ref,
1000 BMessage* initialMessage)
1002 return roster->BRoster::Launch(ref, initialMessage, NULL);
1006 extern "C" status_t
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);
1014 extern "C" status_t
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
1026 void
1027 BRoster::GetRecentDocuments(BMessage* refList, int32 maxCount,
1028 const char* fileType, const char* signature) const
1030 if (refList == NULL)
1031 return;
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;
1038 status_t result;
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;
1057 if (error == B_OK)
1058 error = reply.FindInt32("result", &result);
1060 if (error == B_OK)
1061 error = 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 :-(
1068 //return error;
1072 void
1073 BRoster::GetRecentDocuments(BMessage* refList, int32 maxCount,
1074 const char* fileTypes[], int32 fileTypesCount,
1075 const char* signature) const
1077 if (refList == NULL)
1078 return;
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;
1085 status_t result;
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;
1104 if (error == B_OK)
1105 error = reply.FindInt32("result", &result);
1107 if (error == B_OK)
1108 error = 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 :-(
1115 //return error;
1119 void
1120 BRoster::GetRecentFolders(BMessage* refList, int32 maxCount,
1121 const char* signature) const
1123 if (refList == NULL)
1124 return;
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;
1131 status_t result;
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;
1147 if (error == B_OK)
1148 error = reply.FindInt32("result", &result);
1150 if (error == B_OK)
1151 error = 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 :-(
1158 //return error;
1162 void
1163 BRoster::GetRecentApps(BMessage* refList, int32 maxCount) const
1165 if (refList == NULL)
1166 return;
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;
1173 status_t result;
1175 // Build and send the message, read the reply
1176 if (!err) {
1177 message.what = B_REG_GET_RECENT_APPS;
1178 err = message.AddInt32("max count", maxCount);
1180 fMessenger.SendMessage(&message, &reply);
1181 if (!err) {
1182 err = reply.what == B_REG_RESULT
1183 ? (status_t)B_OK : (status_t)B_BAD_REPLY;
1185 if (!err)
1186 err = reply.FindInt32("result", &result);
1188 if (!err)
1189 err = result;
1191 // Clear the result if an error occured
1192 if (err && refList)
1193 refList->MakeEmpty();
1195 // No return value, how sad :-(
1196 //return err;
1200 void
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);
1208 BMessage reply;
1209 status_t result;
1210 char* callingApplicationSignature = NULL;
1212 // If no signature is supplied, look up the signature of
1213 // the calling app
1214 if (error == B_OK && signature == NULL) {
1215 app_info info;
1216 error = GetRunningAppInfo(be_app->Team(), &info);
1217 if (error == B_OK)
1218 callingApplicationSignature = info.signature;
1221 // Build and send the message, read the reply
1222 if (error == B_OK)
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;
1234 if (error == B_OK)
1235 error = reply.FindInt32("result", &result);
1237 if (error == B_OK)
1238 error = result;
1240 if (error != B_OK) {
1241 DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error "
1242 "0x%lx\n", error));
1247 void
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);
1255 BMessage reply;
1256 status_t result;
1257 char* callingApplicationSignature = NULL;
1259 // If no signature is supplied, look up the signature of
1260 // the calling app
1261 if (error == B_OK && signature == NULL) {
1262 app_info info;
1263 error = GetRunningAppInfo(be_app->Team(), &info);
1264 if (error == B_OK)
1265 callingApplicationSignature = info.signature;
1268 // Build and send the message, read the reply
1269 if (error == B_OK)
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;
1281 if (error == B_OK)
1282 error = reply.FindInt32("result", &result);
1284 if (error == B_OK)
1285 error = result;
1287 if (error != B_OK) {
1288 DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error "
1289 "0x%lx\n", 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
1301 powered off.
1302 \param confirm If \c true, the user will be asked to confirm to shut down
1303 the system.
1304 \param synchronous If \c false, the method will return as soon as the
1305 shutdown process has been initiated successfully (or an error
1306 occurred). Otherwise the method doesn't return, if successfully.
1308 \return A status code, \c B_OK on success or another error code in case
1309 something went wrong.
1310 \retval B_SHUTTING_DOWN, when there's already a shutdown process in
1311 progress,
1312 \retval B_SHUTDOWN_CANCELLED, when the user cancelled the shutdown process,
1314 status_t
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);
1321 if (error == B_OK)
1322 error = request.AddBool("reboot", reboot);
1324 if (error == B_OK)
1325 error = request.AddBool("confirm", confirm);
1327 if (error == B_OK)
1328 error = request.AddBool("synchronous", synchronous);
1330 // send the request
1331 BMessage reply;
1332 if (error == B_OK)
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) {
1338 error = B_ERROR;
1341 return error;
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
1353 via \a pToken.
1355 For a pre-registration \a signature, \a ref, \a flags must be valid.
1356 \a team and \a thread are optional and should be set to -1, if they are
1357 unknown. If no team ID is supplied, \a pToken should be valid and, if the
1358 the pre-registration succeeds, will be filled with a unique token assigned
1359 by the roster.
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.
1387 status_t
1388 BRoster::_AddApplication(const char* signature, const entry_ref* ref,
1389 uint32 flags, team_id team, thread_id thread, port_id port,
1390 bool fullRegistration, uint32* pToken, team_id* otherTeam) const
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);
1402 if (error == B_OK)
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);
1414 if (error == B_OK)
1415 error = request.AddBool("full_registration", fullRegistration);
1417 // send the request
1418 BMessage reply;
1419 if (error == B_OK)
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) {
1426 uint32 token;
1427 if (reply.FindInt32("token", (int32*)&token) == B_OK) {
1428 if (pToken != NULL)
1429 *pToken = token;
1430 } else
1431 error = B_ERROR;
1433 } else {
1434 if (reply.FindInt32("error", &error) != B_OK)
1435 error = B_ERROR;
1437 // get team and token from the reply
1438 if (otherTeam != NULL
1439 && reply.FindInt32("other_team", otherTeam) != B_OK) {
1440 *otherTeam = -1;
1442 if (pToken != NULL
1443 && reply.FindInt32("token", (int32*)pToken) != B_OK) {
1444 *pToken = 0;
1449 return error;
1453 /*! Sets an application's signature.
1455 The application must be registered or at pre-registered with a valid
1456 team ID.
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.
1466 status_t
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);
1479 // send the request
1480 BMessage reply;
1481 if (error == B_OK)
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) {
1487 error = B_ERROR;
1490 return error;
1494 //! \todo Really needed?
1495 void
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
1505 method.
1507 \param entryToken The token identifying the application (returned by
1508 AddApplication())
1509 \param thread The app's thread ID
1510 \param team The app's team ID
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.
1517 status_t
1518 BRoster::_SetThreadAndTeam(uint32 entryToken, thread_id thread,
1519 team_id team) const
1521 status_t error = B_OK;
1523 // compose the request message
1524 BMessage request(B_REG_SET_THREAD_AND_TEAM);
1525 if (error == B_OK)
1526 error = request.AddInt32("token", (int32)entryToken);
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);
1534 // send the request
1535 BMessage reply;
1536 if (error == B_OK)
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)
1542 error = B_ERROR;
1544 return error;
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
1562 registered.
1564 status_t
1565 BRoster::_CompleteRegistration(team_id team, thread_id thread,
1566 port_id port) const
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);
1581 // send the request
1582 BMessage reply;
1583 if (error == B_OK)
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) {
1589 error = B_ERROR;
1592 return error;
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
1604 given.
1605 \param preRegistered: Pointer to a pre-allocated bool to be filled in
1606 by this method, indicating whether or not the app was
1607 pre-registered.
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.
1615 status_t
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);
1630 // send the request
1631 BMessage reply;
1632 if (error == B_OK)
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
1641 || !isRegistered
1642 || reply.FindBool("pre-registered", &isPreRegistered) != B_OK) {
1643 error = B_ERROR;
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)
1651 error = B_ERROR;
1654 return error;
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
1662 RemoveApp().
1664 \param entryToken The token identifying the application (returned by
1665 AddApplication())
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.
1672 status_t
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);
1679 if (error == B_OK)
1680 error = request.AddInt32("token", (int32)entryToken);
1682 // send the request
1683 BMessage reply;
1684 if (error == B_OK)
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) {
1690 error = B_ERROR;
1693 return error;
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.
1710 status_t
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);
1720 // send the request
1721 BMessage reply;
1722 if (error == B_OK)
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) {
1728 error = B_ERROR;
1731 return error;
1735 void
1736 BRoster::_ApplicationCrashed(team_id team)
1738 BPrivate::DesktopLink link;
1739 if (link.InitCheck() != B_OK)
1740 return;
1742 if (link.StartMessage(AS_APP_CRASHED) == B_OK
1743 && link.Attach(team) == B_OK) {
1744 link.Flush();
1749 /*! Tells the registrar which application is currently active.
1751 It's called from within the app_server when the active application is
1752 changed.
1754 As it's called in the event loop, it must run asynchronously and cannot
1755 wait for a reply.
1757 status_t
1758 BRoster::_UpdateActiveApp(team_id team) const
1760 if (team < B_OK)
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);
1766 if (status < B_OK)
1767 return status;
1769 // send the request
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
1801 \args.
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.
1808 May be \c NULL.
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
1834 executable.
1836 status_t
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
1847 *_appTeam = -1;
1850 if (mimeType == NULL && ref == NULL)
1851 return B_BAD_VALUE;
1853 // use a mutable copy of the document entry_ref
1854 entry_ref _docRef;
1855 entry_ref* docRef = NULL;
1856 if (ref != NULL) {
1857 _docRef = *ref;
1858 docRef = &_docRef;
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;
1867 team_id team = -1;
1868 thread_id appThread = -1;
1870 do {
1871 // find the app
1872 entry_ref appRef;
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));
1877 if (error != B_OK)
1878 return 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));
1884 if (error != B_OK)
1885 return error;
1887 // pre-register the app (but ignore scipts)
1888 uint32 appToken = 0;
1889 app_info appInfo;
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,
1900 &appInfo);
1901 if (error == B_OK) {
1902 otherAppFlags = appInfo.flags;
1903 team = appInfo.team;
1906 DBG(OUT(" pre-register: %s (%lx)\n", strerror(error), error));
1909 // launch the app
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);
1916 // get the app team
1917 if (appThread >= 0) {
1918 thread_info threadInfo;
1919 error = get_thread_info(appThread, &threadInfo);
1920 if (error == B_OK)
1921 team = threadInfo.team;
1922 } else if (wasDocument && appThread == B_NOT_AN_EXECUTABLE)
1923 error = B_LAUNCH_FAILED_EXECUTABLE;
1924 else
1925 error = appThread;
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),
1933 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) {
1941 if (appThread >= 0)
1942 kill_thread(appThread);
1944 if (!isScript) {
1945 if (!fNoRegistrar)
1946 _RemovePreRegApp(appToken);
1948 if (!wasDocument) {
1949 // Remove app hint if it's this one
1950 BMimeType appType(signature);
1951 entry_ref hintRef;
1953 if (appType.InitCheck() == B_OK
1954 && appType.GetAppHint(&hintRef) == B_OK
1955 && appRef == hintRef) {
1956 appType.SetAppHint(NULL);
1957 // try again
1958 continue;
1964 } while (false);
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
1981 // argument vector
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) {
1992 if (alreadyRunning)
1993 error = B_ALREADY_RUNNING;
1994 else if (_appTeam)
1995 *_appTeam = team;
1997 if (_appThread != NULL)
1998 *_appThread = appThread;
2001 DBG(OUT("BRoster::_LaunchApp() done: %s (%lx)\n",
2002 strerror(error), error));
2004 return error;
2008 void
2009 BRoster::_SetAppFlags(team_id team, uint32 flags) const
2014 void
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
2030 resolved entry.
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.
2038 May be \c NULL.
2039 \param ref The file for which an application shall be found.
2040 May be \c NULL.
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.
2051 May be \c NULL.
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.
2059 status_t
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))
2066 return B_BAD_VALUE;
2068 // find the app
2069 BMimeType appMeta;
2070 BFile appFile;
2071 entry_ref appRef;
2072 status_t error;
2074 if (inType != NULL) {
2075 error = _TranslateType(inType, &appMeta, &appRef, &appFile);
2076 if (_wasDocument != NULL)
2077 *_wasDocument = !(appMeta == inType);
2078 } else {
2079 error = _TranslateRef(ref, &appMeta, &appRef, &appFile,
2080 _wasDocument);
2083 // create meta mime
2084 if (!fNoRegistrar && error == B_OK) {
2085 BPath path;
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
2099 entry_ref dummyRef;
2100 if (appMeta.GetAppHint(&dummyRef) != B_OK)
2101 appMeta.SetAppHint(&appRef);
2102 } else {
2103 appMeta.SetAppHint(NULL);
2104 appMeta.SetTo(signature);
2106 } else
2107 appMeta.SetAppHint(NULL);
2110 // set the return values
2111 if (error == B_OK) {
2112 if (_appRef)
2113 *_appRef = appRef;
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);
2120 } else
2121 _signature[0] = '\0';
2124 if (_appFlags != NULL) {
2125 // if an error occurs here, we don't care and just set a default
2126 // value
2127 if (appFileInfo.InitCheck() != B_OK
2128 || appFileInfo.GetAppFlags(_appFlags) != B_OK) {
2129 *_appFlags = B_REG_DEFAULT_APP_FLAGS;
2132 } else {
2133 // unset the ref on error
2134 if (_appRef != NULL)
2135 *_appRef = appRef;
2138 return error;
2142 /*! \brief Finds an application associated with a file.
2144 \a appMeta is left unmodified, if the file is executable, but has no
2145 signature.
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
2150 resolved entry.
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.
2169 status_t
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)
2174 return B_BAD_VALUE;
2176 // resolve ref, if necessary
2177 BEntry entry;
2178 status_t error = entry.SetTo(ref, false);
2179 if (error != B_OK)
2180 return error;
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;
2188 // init node
2189 BNode node;
2190 error = node.SetTo(ref);
2191 if (error != B_OK)
2192 return error;
2194 // get permissions
2195 mode_t permissions;
2196 error = node.GetPermissions(&permissions);
2197 if (error != B_OK)
2198 return error;
2200 if ((permissions & S_IXUSR) != 0 && node.IsFile()) {
2201 // node is executable and a file
2202 error = appFile->SetTo(ref, B_READ_ONLY);
2203 if (error != B_OK)
2204 return error;
2206 // get the app's signature via a BAppFileInfo
2207 BAppFileInfo appFileInfo;
2208 error = appFileInfo.SetTo(appFile);
2209 if (error != B_OK)
2210 return error;
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);
2217 if (error != B_OK)
2218 return error;
2219 } else
2220 appMeta->Unset();
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) {
2227 isDocument = false;
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
2233 // we're done.
2234 char preferredApp[B_MIME_TYPE_LENGTH];
2235 if (!isDocument || appFileInfo.GetPreferredApp(preferredApp) != B_OK) {
2236 *appRef = *ref;
2237 if (_wasDocument != NULL)
2238 *_wasDocument = isDocument;
2240 return B_OK;
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
2248 // init a node info
2249 BNodeInfo nodeInfo;
2250 error = nodeInfo.SetTo(&node);
2251 if (error != B_OK)
2252 return error;
2254 // if the file has a preferred app, let _TranslateType() find
2255 // it for us
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;
2262 return B_OK;
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);
2271 if (error != B_OK)
2272 return error;
2274 // now let _TranslateType() do the actual work
2275 error = _TranslateType(fileType, appMeta, appRef, appFile);
2276 if (error != B_OK)
2277 return error;
2279 if (_wasDocument != NULL)
2280 *_wasDocument = true;
2282 return B_OK;
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
2301 \a appFile.
2303 \see FindApp() for other error codes.
2305 status_t
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) {
2311 return B_BAD_VALUE;
2314 // Create a BMimeType and check, if the type is installed.
2315 BMimeType type;
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';
2337 } else {
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);
2354 else {
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;
2369 if (error == B_OK
2370 && type.GetSupportingApps(&supportingSignatures) == B_OK) {
2371 int32 subCount;
2372 if (supportingSignatures.FindInt32("be:sub", &subCount) != B_OK)
2373 subCount = 0;
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;
2386 break;
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
2414 // already.
2415 if (strcmp(primarySignature, supportingType) != 0
2416 && strcmp(secondarySignature, supportingType) != 0) {
2417 error = signatures.AddString(kSigField, supportingType);
2420 } else {
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);
2426 if (error != B_OK)
2427 return error;
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;
2434 for (int32 i = 0;
2435 signatures.FindString(kSigField, i, &signature) == B_OK; i++) {
2436 if (signature[0] == '\0')
2437 continue;
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
2445 BEntry entry;
2446 if (entry.SetTo(appRef, true) == B_OK && entry.IsFile()
2447 && entry.GetRef(appRef) == B_OK) {
2448 appFound = true;
2449 } else {
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
2456 // the app.
2457 if (error == B_OK && !appFound)
2458 error = query_for_app(appMeta->Type(), appRef);
2460 if (error == B_OK)
2461 error = appFile->SetTo(appRef, B_READ_ONLY);
2463 // check, whether the app can be used
2464 if (error == B_OK)
2465 error = can_app_be_used(appRef);
2467 if (error == B_OK)
2468 break;
2471 return error;
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
2484 the file.
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.
2490 status_t
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)
2496 return B_OK;
2498 if (fNoRegistrar)
2499 return B_NO_INIT;
2501 // Try to update the file's MIME info and just read the updated type.
2502 // If that fails, sniff manually.
2503 BPath path;
2504 if (path.SetTo(file) != B_OK
2505 || update_mime_info(path.Path(), false, true, false) != B_OK
2506 || nodeInfo->GetType(mimeType) != B_OK) {
2507 BMimeType type;
2508 status_t error = BMimeType::GuessMimeType(file, &type);
2509 if (error != B_OK)
2510 return error;
2512 if (!type.IsValid())
2513 return B_BAD_VALUE;
2515 strlcpy(mimeType, type.Type(), B_MIME_TYPE_LENGTH);
2518 return B_OK;
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
2529 \c B_READ_TO_RUN.
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
2533 \c NULL.
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
2541 \c NULL or empty.
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.
2549 status_t
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.
2558 app_info info;
2559 error = GetRunningAppInfo(team, &info);
2560 if (error == B_OK) {
2561 BMessenger messenger;
2562 BMessenger::Private(messenger).SetTo(team, info.port,
2563 B_PREFERRED_TOKEN);
2565 // send messages from the list
2566 if (messageList != NULL) {
2567 for (int32 i = 0;
2568 BMessage* message = (BMessage*)messageList->ItemAt(i);
2569 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);
2603 return error;
2607 /*! Allows to use certain functionality of the BRoster class without
2608 accessing the registrar.
2610 void
2611 BRoster::_SetWithoutRegistrar(bool noRegistrar)
2613 fNoRegistrar = noRegistrar;
2617 void
2618 BRoster::_InitMessenger()
2620 DBG(OUT("BRoster::InitMessengers()\n"));
2622 // find the registrar port
2623 BMessage data;
2624 if (BLaunchRoster().GetData("application/x-vnd.Haiku-registrar", data)
2625 == B_OK) {
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,
2636 B_PREFERRED_TOKEN);
2640 DBG(OUT("BRoster::InitMessengers() done\n"));
2644 /*static*/ status_t
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);
2653 BMessage reply;
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);
2659 } else {
2660 DBG(OUT(" no (useful) reply from roster: error: %lx: %s\n", error,
2661 strerror(error)));
2662 if (error == B_OK)
2663 DBG(reply.PrintToStream());
2666 return error;
2670 BMessenger&
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.
2681 void
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);
2687 if (error == B_OK)
2688 error = request.AddString("app sig", signature);
2690 // send the request
2691 BMessage reply;
2692 if (error == B_OK)
2693 error = fMessenger.SendMessage(&request, &reply);
2695 // evaluate the reply
2696 status_t result;
2697 if (error == B_OK) {
2698 error = reply.what == B_REG_RESULT
2699 ? (status_t)B_OK : (status_t)B_BAD_REPLY;
2702 if (error == B_OK)
2703 error = reply.FindInt32("result", &result);
2705 if (error == B_OK)
2706 error = result;
2708 // Nothing to return... how sad :-(
2709 //return error;
2713 //! Sends a request to the roster to clear the recent documents list.
2714 void
2715 BRoster::_ClearRecentDocuments() const
2717 BMessage request(B_REG_CLEAR_RECENT_DOCUMENTS);
2718 BMessage reply;
2719 fMessenger.SendMessage(&request, &reply);
2723 //! Sends a request to the roster to clear the recent documents list.
2724 void
2725 BRoster::_ClearRecentFolders() const
2727 BMessage request(B_REG_CLEAR_RECENT_FOLDERS);
2728 BMessage reply;
2729 fMessenger.SendMessage(&request, &reply);
2733 //! \brief Sends a request to the roster to clear the recent documents list.
2734 void
2735 BRoster::_ClearRecentApps() const
2737 BMessage request(B_REG_CLEAR_RECENT_APPS);
2738 BMessage reply;
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
2750 void
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);
2757 if (error == B_OK)
2758 error = request.AddString("filename", filename);
2760 // send the request
2761 BMessage reply;
2762 if (error == B_OK)
2763 error = fMessenger.SendMessage(&request, &reply);
2765 // evaluate the reply
2766 status_t result;
2767 if (error == B_OK) {
2768 error = reply.what == B_REG_RESULT
2769 ? (status_t)B_OK : (status_t)B_BAD_REPLY;
2771 if (error == B_OK)
2772 error = reply.FindInt32("result", &result);
2774 if (error == B_OK)
2775 error = result;
2777 // Nothing to return... how sad :-(
2778 //return error;
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
2787 void
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);
2794 if (error == B_OK)
2795 error = request.AddString("filename", filename);
2797 // send the request
2798 BMessage reply;
2799 if (error == B_OK)
2800 error = fMessenger.SendMessage(&request, &reply);
2802 // evaluate the reply
2803 status_t result;
2804 if (error == B_OK) {
2805 error = reply.what == B_REG_RESULT
2806 ? (status_t)B_OK : (status_t)B_BAD_REPLY;
2808 if (error == B_OK)
2809 error = reply.FindInt32("result", &result);
2811 if (error == B_OK)
2812 error = result;
2814 // Nothing to return... how sad :-(
2815 //return error;