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