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 strcpy(string, "application/"); 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 // find the app 2253 entry_ref appRef; 2254 char signature[B_MIME_TYPE_LENGTH]; 2255 uint32 appFlags = B_REG_DEFAULT_APP_FLAGS; 2256 bool wasDocument = true; 2257 status_t error = _ResolveApp(mimeType, docRef, &appRef, signature, 2258 &appFlags, &wasDocument); 2259 DBG(OUT(" find app: %s (%lx)\n", strerror(error), error)); 2260 2261 // build an argument vector 2262 ArgVector argVector; 2263 if (error == B_OK) { 2264 error = argVector.Init(argc, args, &appRef, 2265 (wasDocument ? docRef : NULL)); 2266 } 2267 DBG(OUT(" build argv: %s (%lx)\n", strerror(error), error)); 2268 2269 // pre-register the app (but ignore scipts) 2270 app_info appInfo; 2271 bool isScript = wasDocument && docRef != NULL && *docRef == appRef; 2272 bool alreadyRunning = false; 2273 uint32 appToken = 0; 2274 team_id team = -1; 2275 uint32 otherAppFlags = B_REG_DEFAULT_APP_FLAGS; 2276 if (error == B_OK && !isScript) { 2277 error = _AddApplication(signature, &appRef, appFlags, -1, -1, -1, false, 2278 &appToken, &team); 2279 if (error == B_ALREADY_RUNNING) { 2280 DBG(OUT(" already running\n")); 2281 alreadyRunning = true; 2282 2283 // get the app flags for the running application 2284 error = _IsAppRegistered(&appRef, team, appToken, NULL, &appInfo); 2285 if (error == B_OK) { 2286 otherAppFlags = appInfo.flags; 2287 team = appInfo.team; 2288 } 2289 } 2290 DBG(OUT(" pre-register: %s (%lx)\n", strerror(error), error)); 2291 } 2292 2293 // launch the app 2294 if (error == B_OK && !alreadyRunning) { 2295 DBG(OUT(" token: %lu\n", appToken)); 2296 // load the app image 2297 thread_id appThread = load_image(argVector.Count(), 2298 const_cast<const char**>(argVector.Args()), 2299 const_cast<const char**>(environ)); 2300 2301 // get the app team 2302 if (appThread >= 0) { 2303 thread_info threadInfo; 2304 error = get_thread_info(appThread, &threadInfo); 2305 if (error == B_OK) 2306 team = threadInfo.team; 2307 } else if (wasDocument && appThread == B_NOT_AN_EXECUTABLE) 2308 error = B_LAUNCH_FAILED_EXECUTABLE; 2309 else 2310 error = appThread; 2311 2312 DBG(OUT(" load image: %s (%lx)\n", strerror(error), error)); 2313 // finish the registration 2314 if (error == B_OK && !isScript) 2315 error = _SetThreadAndTeam(appToken, appThread, team); 2316 2317 DBG(OUT(" set thread and team: %s (%lx)\n", strerror(error), error)); 2318 // resume the launched team 2319 if (error == B_OK) 2320 error = resume_thread(appThread); 2321 2322 DBG(OUT(" resume thread: %s (%lx)\n", strerror(error), error)); 2323 // on error: kill the launched team and unregister the app 2324 if (error != B_OK) { 2325 if (appThread >= 0) 2326 kill_thread(appThread); 2327 if (!isScript) { 2328 _RemovePreRegApp(appToken); 2329 2330 if (!wasDocument) { 2331 // Remove app hint if it's this one 2332 BMimeType appType(signature); 2333 entry_ref hintRef; 2334 2335 if (appType.InitCheck() == B_OK 2336 && appType.GetAppHint(&hintRef) == B_OK 2337 && appRef == hintRef) 2338 appType.SetAppHint(NULL); 2339 } 2340 } 2341 } 2342 } 2343 2344 if (alreadyRunning && current_team() == team) { 2345 // The target team is calling us, so we don't send it the message 2346 // to prevent an endless loop 2347 error = B_BAD_VALUE; 2348 } 2349 2350 // send "on launch" messages 2351 if (error == B_OK) { 2352 // If the target app is B_ARGV_ONLY, only if it is newly launched 2353 // messages are sent to it (namely B_ARGV_RECEIVED and B_READY_TO_RUN). 2354 // An already running B_ARGV_ONLY app won't get any messages. 2355 bool argvOnly = (appFlags & B_ARGV_ONLY) 2356 || (alreadyRunning && (otherAppFlags & B_ARGV_ONLY)); 2357 const BList* _messageList = (argvOnly ? NULL : messageList); 2358 // don't send ref, if it refers to the app or is included in the 2359 // argument vector 2360 const entry_ref* _ref = argvOnly || !wasDocument 2361 || argVector.Count() > 1 ? NULL : docRef; 2362 if (!(argvOnly && alreadyRunning)) { 2363 _SendToRunning(team, argVector.Count(), argVector.Args(), 2364 _messageList, _ref, alreadyRunning); 2365 } 2366 } 2367 2368 // set return values 2369 if (error == B_OK) { 2370 if (alreadyRunning) 2371 error = B_ALREADY_RUNNING; 2372 else if (_appTeam) 2373 *_appTeam = team; 2374 } 2375 2376 DBG(OUT("BRoster::_LaunchApp() done: %s (%lx)\n", 2377 strerror(error), error)); 2378 return error; 2379 } 2380 2381 2382 void 2383 BRoster::_SetAppFlags(team_id team, uint32 flags) const 2384 { 2385 } 2386 2387 2388 void 2389 BRoster::_DumpRoster() const 2390 { 2391 } 2392 2393 2394 /*! \brief Finds an application associated with a MIME type or a file. 2395 2396 It does also supply the caller with some more information about the 2397 application, like signature, app flags and whether the supplied 2398 MIME type/entry_ref already identified an application. 2399 2400 At least one of \a inType or \a ref must not be \c NULL. If \a inType is 2401 supplied, \a ref is ignored. 2402 2403 If \a ref refers to a link, it is updated with the entry_ref for the 2404 resolved entry. 2405 2406 \see FindApp() for how the application is searched. 2407 2408 \a appSig is set to a string with length 0, if the found application 2409 has no signature. 2410 2411 \param inType The MIME type for which an application shall be found. 2412 May be \c NULL. 2413 \param ref The file for which an application shall be found. 2414 May be \c NULL. 2415 \param appRef A pointer to a pre-allocated entry_ref to be filled with 2416 a reference to the found application's executable. May be \c NULL. 2417 \param appSig A pointer to a pre-allocated char buffer of at least size 2418 \c B_MIME_TYPE_LENGTH to be filled with the signature of the found 2419 application. May be \c NULL. 2420 \param appFlags A pointer to a pre-allocated uint32 variable to be filled 2421 with the app flags of the found application. May be \c NULL. 2422 \param wasDocument A pointer to a pre-allocated bool variable to be set to 2423 \c true, if the supplied file was not identifying an application, 2424 to \c false otherwise. Has no meaning, if a \a inType is supplied. 2425 May be \c NULL. 2426 \return 2427 - \c B_OK: Everything went fine. 2428 - \c B_BAD_VALUE: \c NULL \a inType and \a ref. 2429 - \see FindApp() for other error codes. 2430 */ 2431 status_t 2432 BRoster::_ResolveApp(const char* inType, entry_ref* ref, 2433 entry_ref* _appRef, char* _appSig, uint32* _appFlags, 2434 bool* _wasDocument) const 2435 { 2436 if ((inType == NULL && ref == NULL) 2437 || (inType != NULL && strlen(inType) >= B_MIME_TYPE_LENGTH)) 2438 return B_BAD_VALUE; 2439 2440 // find the app 2441 BMimeType appMeta; 2442 BFile appFile; 2443 entry_ref appRef; 2444 status_t error; 2445 2446 if (inType) 2447 error = _TranslateType(inType, &appMeta, &appRef, &appFile); 2448 else { 2449 error = _TranslateRef(ref, &appMeta, &appRef, &appFile, 2450 _wasDocument); 2451 } 2452 2453 // create meta mime 2454 if (error == B_OK) { 2455 BPath path; 2456 if (path.SetTo(&appRef) == B_OK) 2457 create_app_meta_mime(path.Path(), false, true, false); 2458 } 2459 2460 // set the app hint on the type -- but only if the file has the 2461 // respective signature, otherwise unset the app hint 2462 BAppFileInfo appFileInfo; 2463 if (error == B_OK) { 2464 char signature[B_MIME_TYPE_LENGTH]; 2465 if (appFileInfo.SetTo(&appFile) == B_OK 2466 && appFileInfo.GetSignature(signature) == B_OK) { 2467 if (!strcasecmp(appMeta.Type(), signature)) { 2468 // Only set the app hint if there is none yet 2469 entry_ref dummyRef; 2470 if (appMeta.GetAppHint(&dummyRef) != B_OK) 2471 appMeta.SetAppHint(&appRef); 2472 } else { 2473 appMeta.SetAppHint(NULL); 2474 appMeta.SetTo(signature); 2475 } 2476 } else 2477 appMeta.SetAppHint(NULL); 2478 } 2479 2480 // set the return values 2481 if (error == B_OK) { 2482 if (_appRef) 2483 *_appRef = appRef; 2484 2485 if (_appSig) { 2486 // there's no warranty, that appMeta is valid 2487 if (appMeta.IsValid()) 2488 strcpy(_appSig, appMeta.Type()); 2489 else 2490 _appSig[0] = '\0'; 2491 } 2492 2493 if (_appFlags) { 2494 // if an error occurs here, we don't care and just set a default 2495 // value 2496 if (appFileInfo.InitCheck() != B_OK 2497 || appFileInfo.GetAppFlags(_appFlags) != B_OK) { 2498 *_appFlags = B_REG_DEFAULT_APP_FLAGS; 2499 } 2500 } 2501 } else { 2502 // unset the ref on error 2503 if (_appRef) 2504 *_appRef = appRef; 2505 } 2506 2507 return error; 2508 } 2509 2510 2511 /*! \brief Finds an application associated with a file. 2512 2513 \a appMeta is left unmodified, if the file is executable, but has no 2514 signature. 2515 2516 \see FindApp() for how the application is searched. 2517 2518 If \a ref refers to a link, it is updated with the entry_ref for the 2519 resolved entry. 2520 2521 \param ref The file for which an application shall be found. 2522 \param appMeta A pointer to a pre-allocated BMimeType to be set to the 2523 signature of the found application. 2524 \param appRef A pointer to a pre-allocated entry_ref to be filled with 2525 a reference to the found application's executable. 2526 \param appFile A pointer to a pre-allocated BFile to be set to the 2527 executable of the found application. 2528 \param wasDocument A pointer to a pre-allocated bool variable to be set to 2529 \c true, if the supplied file was not identifying an application, 2530 to \c false otherwise. May be \c NULL. 2531 \return 2532 - \c B_OK: Everything went fine. 2533 - \c B_BAD_VALUE: \c NULL \a ref, \a appMeta, \a appRef or \a appFile. 2534 - \see FindApp() for other error codes. 2535 */ 2536 status_t 2537 BRoster::_TranslateRef(entry_ref* ref, BMimeType* appMeta, 2538 entry_ref* appRef, BFile* appFile, bool* _wasDocument) const 2539 { 2540 if (ref == NULL || appMeta == NULL || appRef == NULL || appFile == NULL) 2541 return B_BAD_VALUE; 2542 2543 // resolve ref, if necessary 2544 BEntry entry; 2545 status_t error = entry.SetTo(ref, false); 2546 if (error != B_OK) 2547 return error; 2548 2549 if (entry.IsSymLink()) { 2550 // ref refers to a link 2551 if (entry.SetTo(ref, true) != B_OK || entry.GetRef(ref) != B_OK) 2552 return B_LAUNCH_FAILED_NO_RESOLVE_LINK; 2553 } 2554 2555 // init node 2556 BNode node; 2557 error = node.SetTo(ref); 2558 if (error != B_OK) 2559 return error; 2560 2561 // get permissions 2562 mode_t permissions; 2563 error = node.GetPermissions(&permissions); 2564 if (error != B_OK) 2565 return error; 2566 2567 if ((permissions & S_IXUSR) && node.IsFile()) { 2568 // node is executable and a file 2569 error = appFile->SetTo(ref, B_READ_ONLY); 2570 if (error != B_OK) 2571 return error; 2572 2573 // get the app's signature via a BAppFileInfo 2574 BAppFileInfo appFileInfo; 2575 error = appFileInfo.SetTo(appFile); 2576 if (error != B_OK) 2577 return error; 2578 2579 // don't worry, if the file doesn't have a signature, just 2580 // unset the supplied object 2581 char type[B_MIME_TYPE_LENGTH]; 2582 if (appFileInfo.GetSignature(type) == B_OK) { 2583 error = appMeta->SetTo(type); 2584 if (error != B_OK) 2585 return error; 2586 } else 2587 appMeta->Unset(); 2588 2589 // If the file type indicates that the file is an application, we've 2590 // definitely got what we're looking for. 2591 bool isDocument = true; 2592 if (_GetFileType(ref, &appFileInfo, type) == B_OK 2593 && strcasecmp(type, B_APP_MIME_TYPE) == 0) { 2594 isDocument = false; 2595 } 2596 2597 // If our file is not an application executable, we probably have a 2598 // script. Check whether the file has a preferred application set. If 2599 // so, we fall through and use the preferred app instead. Otherwise 2600 // we're done. 2601 char preferredApp[B_MIME_TYPE_LENGTH]; 2602 if (!isDocument || appFileInfo.GetPreferredApp(preferredApp) != B_OK) { 2603 *appRef = *ref; 2604 if (_wasDocument) 2605 *_wasDocument = isDocument; 2606 return B_OK; 2607 } 2608 2609 // Executable file, but not an application, and it has a preferred 2610 // application set. Fall through... 2611 } 2612 2613 // the node is not exectuable or not a file 2614 // init a node info 2615 BNodeInfo nodeInfo; 2616 error = nodeInfo.SetTo(&node); 2617 if (error != B_OK) 2618 return error; 2619 2620 // if the file has a preferred app, let _TranslateType() find 2621 // it for us 2622 char preferredApp[B_MIME_TYPE_LENGTH]; 2623 if (nodeInfo.GetPreferredApp(preferredApp) == B_OK 2624 && _TranslateType(preferredApp, appMeta, appRef, appFile) == B_OK) { 2625 if (_wasDocument) 2626 *_wasDocument = true; 2627 return B_OK; 2628 } 2629 2630 // no preferred app or existing one was not found -- we 2631 // need to get the file's type 2632 2633 // get the type from the file 2634 char fileType[B_MIME_TYPE_LENGTH]; 2635 error = _GetFileType(ref, &nodeInfo, fileType); 2636 if (error != B_OK) 2637 return error; 2638 2639 // now let _TranslateType() do the actual work 2640 error = _TranslateType(fileType, appMeta, appRef, appFile); 2641 if (error != B_OK) 2642 return error; 2643 2644 if (_wasDocument) 2645 *_wasDocument = true; 2646 2647 return B_OK; 2648 } 2649 2650 2651 /*! \brief Finds an application associated with a MIME type. 2652 2653 \see FindApp() for how the application is searched. 2654 2655 \param mimeType The MIME type for which an application shall be found. 2656 \param appMeta A pointer to a pre-allocated BMimeType to be set to the 2657 signature of the found application. 2658 \param appRef A pointer to a pre-allocated entry_ref to be filled with 2659 a reference to the found application's executable. 2660 \param appFile A pointer to a pre-allocated BFile to be set to the 2661 executable of the found application. 2662 \return 2663 - \c B_OK: Everything went fine. 2664 - \c B_BAD_VALUE: \c NULL \a mimeType, \a appMeta, \a appRef or \a appFile. 2665 - \see FindApp() for other error codes. 2666 */ 2667 status_t 2668 BRoster::_TranslateType(const char* mimeType, BMimeType* appMeta, 2669 entry_ref* appRef, BFile* appFile) const 2670 { 2671 if (mimeType == NULL || appMeta == NULL || appRef == NULL 2672 || appFile == NULL || strlen(mimeType) >= B_MIME_TYPE_LENGTH) 2673 return B_BAD_VALUE; 2674 2675 // Create a BMimeType and check, if the type is installed. 2676 BMimeType type; 2677 status_t error = type.SetTo(mimeType); 2678 2679 // Get the preferred apps from the sub and super type. 2680 char primarySignature[B_MIME_TYPE_LENGTH]; 2681 char secondarySignature[B_MIME_TYPE_LENGTH]; 2682 primarySignature[0] = '\0'; 2683 secondarySignature[0] = '\0'; 2684 2685 if (error == B_OK) { 2686 BMimeType superType; 2687 if (type.GetSupertype(&superType) == B_OK) 2688 superType.GetPreferredApp(secondarySignature); 2689 if (type.IsInstalled()) { 2690 if (type.GetPreferredApp(primarySignature) != B_OK) { 2691 // The type is installed, but has no preferred app. 2692 primarySignature[0] = '\0'; 2693 } else if (!strcmp(primarySignature, secondarySignature)) { 2694 // Both types have the same preferred app, there is 2695 // no point in testing it twice. 2696 secondarySignature[0] = '\0'; 2697 } 2698 } else { 2699 // The type is not installed. We assume it is an app signature. 2700 strcpy(primarySignature, mimeType); 2701 } 2702 } 2703 2704 // We will use this BMessage "signatures" to hold all supporting apps 2705 // so we can iterator over them in the preferred order. We include 2706 // the supporting apps in such a way that the configured preferred 2707 // applications for the MIME type are in front of other supporting 2708 // applications for the sub and the super type respectively. 2709 const char* kSigField = "applications"; 2710 BMessage signatures; 2711 bool addedSecondarySignature = false; 2712 if (error == B_OK) { 2713 if (primarySignature[0] != '\0') 2714 error = signatures.AddString(kSigField, primarySignature); 2715 else { 2716 // If there is a preferred app configured for the super type, 2717 // but no preferred type for the sub-type, add the preferred 2718 // super type handler in front of any other handlers. This way 2719 // we fall-back to non-preferred but supporting apps only in the 2720 // case when there is a preferred handler for the sub-type but 2721 // it cannot be resolved (misconfiguration). 2722 if (secondarySignature[0] != '\0') { 2723 error = signatures.AddString(kSigField, secondarySignature); 2724 addedSecondarySignature = true; 2725 } 2726 } 2727 } 2728 2729 BMessage supportingSignatures; 2730 if (error == B_OK 2731 && type.GetSupportingApps(&supportingSignatures) == B_OK) { 2732 int32 subCount; 2733 if (supportingSignatures.FindInt32("be:sub", &subCount) != B_OK) 2734 subCount = 0; 2735 // Add all signatures with direct support for the sub-type. 2736 const char* supportingType; 2737 if (!addedSecondarySignature) { 2738 // Try to add the secondarySignature in front of all other 2739 // supporting apps, if we find it among those. 2740 for (int32 i = 0; error == B_OK && i < subCount 2741 && supportingSignatures.FindString(kSigField, i, 2742 &supportingType) == B_OK; i++) { 2743 if (strcmp(primarySignature, supportingType) != 0 2744 && strcmp(secondarySignature, supportingType) == 0) { 2745 error = signatures.AddString(kSigField, supportingType); 2746 addedSecondarySignature = true; 2747 break; 2748 } 2749 } 2750 } 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 } 2758 } 2759 // Add the preferred type of the super type here before adding 2760 // the other types supporting the super type, but only if we have 2761 // not already added it in case there was no preferred app for the 2762 // sub-type configured. 2763 if (error == B_OK && !addedSecondarySignature 2764 && secondarySignature[0] != '\0') { 2765 error = signatures.AddString(kSigField, secondarySignature); 2766 } 2767 // Add all signatures with support for the super-type. 2768 for (int32 i = subCount; error == B_OK 2769 && supportingSignatures.FindString(kSigField, i, 2770 &supportingType) == B_OK; i++) { 2771 // Don't add the signature if it's one of the preferred apps 2772 // already. 2773 if (strcmp(primarySignature, supportingType) != 0 2774 && strcmp(secondarySignature, supportingType) != 0) { 2775 error = signatures.AddString(kSigField, supportingType); 2776 } 2777 } 2778 } else { 2779 // Failed to get supporting apps, just add the preferred apps. 2780 if (error == B_OK && secondarySignature[0] != '\0') 2781 error = signatures.AddString(kSigField, secondarySignature); 2782 } 2783 2784 if (error != B_OK) 2785 return error; 2786 2787 // Set an error in case we can't resolve a single supporting app. 2788 error = B_LAUNCH_FAILED_NO_PREFERRED_APP; 2789 2790 // See if we can find a good application that is valid from the messege. 2791 const char* signature; 2792 for (int32 i = 0; 2793 signatures.FindString(kSigField, i, &signature) == B_OK; i++) { 2794 if (signature[0] == '\0') 2795 continue; 2796 2797 error = appMeta->SetTo(signature); 2798 2799 // Check, whether the signature is installed and has an app hint 2800 bool appFound = false; 2801 if (error == B_OK && appMeta->GetAppHint(appRef) == B_OK) { 2802 // Resolve symbolic links, if necessary 2803 BEntry entry; 2804 if (entry.SetTo(appRef, true) == B_OK && entry.IsFile() 2805 && entry.GetRef(appRef) == B_OK) { 2806 appFound = true; 2807 } else { 2808 // Bad app hint -- remove it 2809 appMeta->SetAppHint(NULL); 2810 } 2811 } 2812 2813 // In case there is no app hint or it is invalid, we need to query for 2814 // the app. 2815 if (error == B_OK && !appFound) 2816 error = query_for_app(appMeta->Type(), appRef); 2817 if (error == B_OK) 2818 error = appFile->SetTo(appRef, B_READ_ONLY); 2819 // check, whether the app can be used 2820 if (error == B_OK) 2821 error = can_app_be_used(appRef); 2822 2823 if (error == B_OK) 2824 break; 2825 } 2826 2827 return error; 2828 } 2829 2830 2831 /*! \brief Gets the type of a file either from the node info or by sniffing. 2832 2833 The method first tries to get the file type from the supplied node info. If 2834 that didn't work, the given entry ref is sniffed. 2835 2836 \param file An entry_ref referring to the file in question. 2837 \param nodeInfo A BNodeInfo initialized to the file. 2838 \param mimeType A pointer to a pre-allocated char buffer of at least size 2839 \c B_MIME_TYPE_LENGTH to be filled with the MIME type sniffed for 2840 the file. 2841 \return 2842 - \c B_OK: Everything went fine. 2843 - \c B_BAD_VALUE: \c NULL \a file, \a nodeInfo or \a mimeType. 2844 - other errors 2845 */ 2846 status_t 2847 BRoster::_GetFileType(const entry_ref* file, BNodeInfo* nodeInfo, 2848 char* mimeType) const 2849 { 2850 // first try the node info 2851 if (nodeInfo->GetType(mimeType) == B_OK) 2852 return B_OK; 2853 2854 // Try to update the file's MIME info and just read the updated type. 2855 // If that fails, sniff manually. 2856 BPath path; 2857 if (path.SetTo(file) != B_OK 2858 || update_mime_info(path.Path(), false, true, false) != B_OK 2859 || nodeInfo->GetType(mimeType) != B_OK) { 2860 BMimeType type; 2861 status_t error = BMimeType::GuessMimeType(file, &type); 2862 if (error != B_OK) 2863 return error; 2864 2865 if (!type.IsValid()) 2866 return B_BAD_VALUE; 2867 2868 strcpy(mimeType, type.Type()); 2869 } 2870 2871 return B_OK; 2872 } 2873 2874 2875 /*! \brief Sends messages to a running team. 2876 2877 In particular those messages are \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED, 2878 \c B_READY_TO_RUN and other, arbitrary, ones. 2879 2880 If \a messageList is not \c NULL or empty, those messages are sent first, 2881 then follow \c B_ARGV_RECEIVED, \c B_REFS_RECEIVED and finally 2882 \c B_READ_TO_RUN. 2883 2884 \c B_ARGV_RECEIVED is sent only, if \a args is not \c NULL and contains 2885 more than one element. \c B_REFS_RECEIVED is sent only, if \a ref is not 2886 \c NULL. 2887 2888 The ownership of all supplied objects retains to the caller. 2889 2890 \param team The team ID of the target application. 2891 \param argc Number of elements in \a args. 2892 \param args Argument vector to be sent to the target. May be \c NULL. 2893 \param messageList List of BMessages to be sent to the target. May be 2894 \c NULL or empty. 2895 \param ref entry_ref to be sent to the target. May be \c NULL. 2896 \param alreadyRunning \c true, if the target app is not newly launched, 2897 but was already running, \c false otherwise (a \c B_READY_TO_RUN 2898 message will be sent in this case). 2899 \return 2900 - \c B_OK: Everything went fine. 2901 - an error code otherwise 2902 */ 2903 status_t 2904 BRoster::_SendToRunning(team_id team, int argc, const char* const* args, 2905 const BList* messageList, const entry_ref* ref, 2906 bool alreadyRunning) const 2907 { 2908 status_t error = B_OK; 2909 // Construct a messenger to the app: We can't use the public constructor, 2910 // since the target application may be B_ARGV_ONLY. 2911 app_info info; 2912 error = GetRunningAppInfo(team, &info); 2913 if (error == B_OK) { 2914 BMessenger messenger; 2915 BMessenger::Private(messenger).SetTo(team, info.port, 2916 B_PREFERRED_TOKEN); 2917 2918 // send messages from the list 2919 if (messageList) { 2920 for (int32 i = 0; 2921 BMessage* message = (BMessage*)messageList->ItemAt(i); 2922 i++) { 2923 messenger.SendMessage(message); 2924 } 2925 } 2926 2927 // send B_ARGV_RECEIVED or B_REFS_RECEIVED or B_SILENT_RELAUNCH (if 2928 // already running) 2929 if (args && argc > 1) { 2930 BMessage message(B_ARGV_RECEIVED); 2931 message.AddInt32("argc", argc); 2932 for (int32 i = 0; i < argc; i++) 2933 message.AddString("argv", args[i]); 2934 2935 // also add current working directory 2936 char cwd[B_PATH_NAME_LENGTH]; 2937 if (getcwd(cwd, B_PATH_NAME_LENGTH) != NULL) 2938 message.AddString("cwd", cwd); 2939 2940 messenger.SendMessage(&message); 2941 } else if (ref) { 2942 printf("_SendToRunning : B_REFS_RECEIVED\n"); 2943 BMessage message(B_REFS_RECEIVED); 2944 message.AddRef("refs", ref); 2945 messenger.SendMessage(&message); 2946 } else if (alreadyRunning && (!messageList || messageList->IsEmpty())) 2947 messenger.SendMessage(B_SILENT_RELAUNCH); 2948 2949 // send B_READY_TO_RUN 2950 if (!alreadyRunning) 2951 messenger.SendMessage(B_READY_TO_RUN); 2952 } 2953 return error; 2954 } 2955 2956 2957 void 2958 BRoster::_InitMessenger() 2959 { 2960 DBG(OUT("BRoster::InitMessengers()\n")); 2961 2962 // find the registrar port 2963 port_id rosterPort = find_port(BPrivate::get_roster_port_name()); 2964 port_info info; 2965 if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) { 2966 DBG(OUT(" found roster port\n")); 2967 2968 BMessenger::Private(fMessenger).SetTo(info.team, rosterPort, 2969 B_PREFERRED_TOKEN); 2970 } 2971 2972 DBG(OUT("BRoster::InitMessengers() done\n")); 2973 } 2974 2975 2976 /*static*/ status_t 2977 BRoster::_InitMimeMessenger(void* data) 2978 { 2979 BRoster* roster = (BRoster*)data; 2980 2981 // ask for the MIME messenger 2982 // Generous 1s + 5s timeouts. It could actually be synchronous, but 2983 // timeouts allow us to debug the registrar main thread. 2984 BMessage request(B_REG_GET_MIME_MESSENGER); 2985 BMessage reply; 2986 status_t error = roster->fMessenger.SendMessage(&request, &reply, 1000000LL, 2987 5000000LL); 2988 if (error == B_OK && reply.what == B_REG_SUCCESS) { 2989 DBG(OUT(" got reply from roster\n")); 2990 reply.FindMessenger("messenger", &roster->fMimeMessenger); 2991 } else { 2992 DBG(OUT(" no (useful) reply from roster: error: %lx: %s\n", error, 2993 strerror(error))); 2994 if (error == B_OK) 2995 DBG(reply.PrintToStream()); 2996 } 2997 2998 return error; 2999 } 3000 3001 3002 BMessenger& 3003 BRoster::_MimeMessenger() 3004 { 3005 __init_once(&fMimeMessengerInitOnce, &_InitMimeMessenger, this); 3006 return fMimeMessenger; 3007 } 3008 3009 3010 /*! \brief Sends a request to the roster to add the application with the 3011 given signature to the front of the recent apps list. 3012 */ 3013 void 3014 BRoster::_AddToRecentApps(const char* appSig) const 3015 { 3016 status_t error = B_OK; 3017 // compose the request message 3018 BMessage request(B_REG_ADD_TO_RECENT_APPS); 3019 if (error == B_OK) 3020 error = request.AddString("app sig", appSig); 3021 // send the request 3022 BMessage reply; 3023 if (error == B_OK) 3024 error = fMessenger.SendMessage(&request, &reply); 3025 // evaluate the reply 3026 status_t result; 3027 if (error == B_OK) { 3028 error = reply.what == B_REG_RESULT 3029 ? (status_t)B_OK : (status_t)B_BAD_REPLY; 3030 } 3031 if (error == B_OK) 3032 error = reply.FindInt32("result", &result); 3033 if (error == B_OK) 3034 error = result; 3035 // Nothing to return... how sad :-( 3036 // return error; 3037 } 3038 3039 3040 /*! \brief Sends a request to the roster to clear the recent 3041 documents list. 3042 */ 3043 void 3044 BRoster::_ClearRecentDocuments() const 3045 { 3046 BMessage request(B_REG_CLEAR_RECENT_DOCUMENTS); 3047 BMessage reply; 3048 fMessenger.SendMessage(&request, &reply); 3049 } 3050 3051 3052 /*! \brief Sends a request to the roster to clear the recent 3053 documents list. 3054 */ 3055 void 3056 BRoster::_ClearRecentFolders() const 3057 { 3058 BMessage request(B_REG_CLEAR_RECENT_FOLDERS); 3059 BMessage reply; 3060 fMessenger.SendMessage(&request, &reply); 3061 } 3062 3063 3064 /*! \brief Sends a request to the roster to clear the recent 3065 documents list. 3066 */ 3067 void 3068 BRoster::_ClearRecentApps() const 3069 { 3070 BMessage request(B_REG_CLEAR_RECENT_APPS); 3071 BMessage reply; 3072 fMessenger.SendMessage(&request, &reply); 3073 } 3074 3075 3076 /*! \brief Loads the system's recently used document, folder, and 3077 application lists from the specified file. 3078 3079 \note The current lists are cleared before loading the new lists 3080 3081 \param filename The name of the file to load from 3082 */ 3083 void 3084 BRoster::_LoadRecentLists(const char* filename) const 3085 { 3086 status_t error = B_OK; 3087 // compose the request message 3088 BMessage request(B_REG_LOAD_RECENT_LISTS); 3089 if (error == B_OK) 3090 error = request.AddString("filename", filename); 3091 // send the request 3092 BMessage reply; 3093 if (error == B_OK) 3094 error = fMessenger.SendMessage(&request, &reply); 3095 // evaluate the reply 3096 status_t result; 3097 if (error == B_OK) { 3098 error = reply.what == B_REG_RESULT 3099 ? (status_t)B_OK : (status_t)B_BAD_REPLY; 3100 } 3101 if (error == B_OK) 3102 error = reply.FindInt32("result", &result); 3103 if (error == B_OK) 3104 error = result; 3105 // Nothing to return... how sad :-( 3106 // return error; 3107 } 3108 3109 3110 /*! \brief Saves the system's recently used document, folder, and 3111 application lists to the specified file. 3112 3113 \param filename The name of the file to save to 3114 */ 3115 void 3116 BRoster::_SaveRecentLists(const char* filename) const 3117 { 3118 status_t error = B_OK; 3119 // compose the request message 3120 BMessage request(B_REG_SAVE_RECENT_LISTS); 3121 if (error == B_OK) 3122 error = request.AddString("filename", filename); 3123 // send the request 3124 BMessage reply; 3125 if (error == B_OK) 3126 error = fMessenger.SendMessage(&request, &reply); 3127 // evaluate the reply 3128 status_t result; 3129 if (error == B_OK) { 3130 error = reply.what == B_REG_RESULT 3131 ? (status_t)B_OK : (status_t)B_BAD_REPLY; 3132 } 3133 if (error == B_OK) 3134 error = reply.FindInt32("result", &result); 3135 if (error == B_OK) 3136 error = result; 3137 // Nothing to return... how sad :-( 3138 // return error; 3139 } 3140