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