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