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