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