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