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