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