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