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