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