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