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