1 /* 2 * Copyright 2001-2007, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! TRoster is the incarnation of The Roster. It manages the running 7 applications. 8 */ 9 10 #include <new> 11 12 #include <Application.h> 13 #include <AppMisc.h> 14 #include <AutoDeleter.h> 15 #include <Autolock.h> 16 #include <File.h> 17 #include <FindDirectory.h> 18 #include <MessagePrivate.h> 19 #include <MessengerPrivate.h> 20 #include <Path.h> 21 #include <Roster.h> // for B_BACKGROUND_APP 22 #include <ServerProtocol.h> 23 #include <storage_support.h> 24 25 #include <errno.h> 26 #include <stdio.h> 27 28 #include "AppInfoListMessagingTargetSet.h" 29 #include "Debug.h" 30 #include "EventMaskWatcher.h" 31 #include "MessageDeliverer.h" 32 #include "RegistrarDefs.h" 33 #include "RosterAppInfo.h" 34 #include "RosterSettingsCharStream.h" 35 #include "TRoster.h" 36 37 using std::nothrow; 38 using namespace BPrivate; 39 40 //------------------------------------------------------------------------------ 41 // Private local function declarations 42 //------------------------------------------------------------------------------ 43 44 static bool larger_index(const recent_entry *entry1, const recent_entry *entry2); 45 46 47 //------------------------------------------------------------------------------ 48 // TRoster 49 //------------------------------------------------------------------------------ 50 51 /*! 52 \class TRoster 53 \brief Implements the application roster. 54 55 This class handles the BRoster requests. For each kind a hook method is 56 implemented to which the registrar looper dispatches the request messages. 57 58 Registered and pre-registered are managed via AppInfoLists. 59 \a fEarlyPreRegisteredApps contains the infos for those application that 60 are pre-registered and currently have no team ID assigned to them yet, 61 whereas the infos of registered and pre-registered applications with a 62 team ID are to be found in \a fRegisteredApps. 63 64 When an application asks whether it is pre-registered or not and there 65 are one or more instances of the application that are pre-registered, but 66 have no team ID assigned yet, the reply to the request has to be 67 postponed until the status of the requesting team is clear. The request 68 message is dequeued from the registrar's message queue and added to 69 \a fIARRequestsByID for a later reply. 70 71 The field \a fActiveApp identifies the currently active application 72 and \a fLastToken is a counter used to generate unique tokens for 73 pre-registered applications. 74 */ 75 76 //! The maximal period of time an app may be early pre-registered (60 s). 77 const bigtime_t kMaximalEarlyPreRegistrationPeriod = 60000000LL; 78 79 //! Applications living in this tree are considered "vital system apps". 80 static const char *const kVitalSystemAppPathPrefix 81 = "/boot/beos/system/servers"; 82 83 //! Applications living in this tree are considered "system apps". 84 static const char *const kSystemAppPathPrefix = "/boot/beos/system"; 85 86 // get_default_roster_settings_file 87 /*! \brief Returns the path to the default roster settings. 88 \param path BPath to be set to the roster settings path. 89 \return the settings path as C string (\code path.Path() \endcode). 90 */ 91 static 92 const char * 93 get_default_roster_settings_file(BPath &path) 94 { 95 // get the path of the settings dir and append the subpath of our file 96 status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 97 if (error == B_OK) 98 error = path.Append("Roster/HaikuRosterSettings"); 99 100 // If some error occurred, set the standard path (can only fail, if there's 101 // insufficient memory, which can't be helped anyway). 102 if (error != B_OK) 103 path.SetTo("/boot/home/config/settings/Roster/HaikuRosterSettings"); 104 105 return path.Path(); 106 } 107 108 // constructor 109 /*! \brief Creates a new roster. 110 111 The object is completely initialized and ready to handle requests. 112 */ 113 TRoster::TRoster() 114 : fLock("roster"), 115 fRegisteredApps(), 116 fEarlyPreRegisteredApps(), 117 fIARRequestsByID(), 118 fIARRequestsByToken(), 119 fActiveApp(NULL), 120 fWatchingService(), 121 fRecentApps(), 122 fRecentDocuments(), 123 fRecentFolders(), 124 fLastToken(0), 125 fShuttingDown(false) 126 { 127 _LoadRosterSettings(); 128 } 129 130 // destructor 131 /*! \brief Frees all resources associated with this object. 132 */ 133 TRoster::~TRoster() 134 { 135 } 136 137 // HandleAddApplication 138 /*! \brief Handles an AddApplication() request. 139 \param request The request message 140 */ 141 void 142 TRoster::HandleAddApplication(BMessage *request) 143 { 144 FUNCTION_START(); 145 146 BAutolock _(fLock); 147 148 status_t error = B_OK; 149 // get the parameters 150 const char *signature; 151 entry_ref ref; 152 uint32 flags; 153 team_id team; 154 thread_id thread; 155 port_id port; 156 bool fullReg; 157 if (request->FindString("signature", &signature) != B_OK) 158 signature = NULL; 159 if (request->FindRef("ref", &ref) != B_OK) 160 SET_ERROR(error, B_BAD_VALUE); 161 if (request->FindInt32("flags", (int32*)&flags) != B_OK) 162 flags = B_REG_DEFAULT_APP_FLAGS; 163 if (request->FindInt32("team", &team) != B_OK) 164 team = -1; 165 if (request->FindInt32("thread", &thread) != B_OK) 166 thread = -1; 167 if (request->FindInt32("port", &port) != B_OK) 168 port = -1; 169 if (request->FindBool("full_registration", &fullReg) != B_OK) 170 fullReg = false; 171 PRINT(("team: %ld, signature: %s\n", team, signature)); 172 PRINT(("full registration: %d\n", fullReg)); 173 174 if (fShuttingDown) 175 error = B_SHUTTING_DOWN; 176 177 // check the parameters 178 team_id otherTeam = -1; 179 uint32 token = 0; 180 181 uint32 launchFlags = flags & B_LAUNCH_MASK; 182 BEntry entry(&ref); 183 if (!entry.Exists()) 184 SET_ERROR(error, B_ENTRY_NOT_FOUND); 185 186 if (error == B_OK) 187 _ValidateRunning(ref, signature); 188 189 // entry_ref 190 if (error == B_OK) { 191 PRINT(("flags: %lx\n", flags)); 192 PRINT(("ref: %ld, %lld, %s\n", ref.device, ref.directory, ref.name)); 193 // check single/exclusive launchers 194 RosterAppInfo *info = NULL; 195 if ((launchFlags == B_SINGLE_LAUNCH 196 || launchFlags == B_EXCLUSIVE_LAUNCH) 197 && ((info = info = fRegisteredApps.InfoFor(&ref)) != NULL 198 || (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL)) { 199 SET_ERROR(error, B_ALREADY_RUNNING); 200 otherTeam = info->team; 201 token = info->token; 202 } 203 } 204 205 // signature 206 if (error == B_OK && signature) { 207 // check exclusive launchers 208 RosterAppInfo *info = NULL; 209 if (launchFlags == B_EXCLUSIVE_LAUNCH 210 && (((info = fRegisteredApps.InfoFor(signature))) 211 || ((info = fEarlyPreRegisteredApps.InfoFor(signature))))) { 212 SET_ERROR(error, B_ALREADY_RUNNING); 213 otherTeam = info->team; 214 token = info->token; 215 } 216 } 217 218 // If no team ID is given, full registration isn't possible. 219 if (error == B_OK) { 220 if (team < 0) { 221 if (fullReg) 222 SET_ERROR(error, B_BAD_VALUE); 223 } else if (fRegisteredApps.InfoFor(team)) 224 SET_ERROR(error, B_REG_ALREADY_REGISTERED); 225 } 226 227 // Add the application info. 228 if (error == B_OK) { 229 // alloc and init the info 230 RosterAppInfo *info = new(nothrow) RosterAppInfo; 231 if (info) { 232 info->Init(thread, team, port, flags, &ref, signature); 233 if (fullReg) 234 info->state = APP_STATE_REGISTERED; 235 else 236 info->state = APP_STATE_PRE_REGISTERED; 237 info->registration_time = system_time(); 238 // add it to the right list 239 bool addingSuccess = false; 240 if (team >= 0) { 241 PRINT(("added ref: %ld, %lld, %s\n", info->ref.device, info->ref.directory, info->ref.name)); 242 addingSuccess = (AddApp(info) == B_OK); 243 if (addingSuccess && fullReg) 244 _AppAdded(info); 245 } else { 246 token = info->token = _NextToken(); 247 addingSuccess = fEarlyPreRegisteredApps.AddInfo(info); 248 PRINT(("added to early pre-regs, token: %lu\n", token)); 249 } 250 if (!addingSuccess) 251 SET_ERROR(error, B_NO_MEMORY); 252 } else 253 SET_ERROR(error, B_NO_MEMORY); 254 // delete the info on failure 255 if (error != B_OK && info) 256 delete info; 257 } 258 259 // reply to the request 260 if (error == B_OK) { 261 // add to recent apps if successful 262 if (signature && signature[0] != '\0') 263 fRecentApps.Add(signature, flags); 264 else 265 fRecentApps.Add(&ref, flags); 266 // fRecentApps.Print(); 267 268 BMessage reply(B_REG_SUCCESS); 269 // The token is valid only when no team ID has been supplied. 270 if (team < 0) 271 reply.AddInt32("token", (int32)token); 272 request->SendReply(&reply); 273 } else { 274 BMessage reply(B_REG_ERROR); 275 reply.AddInt32("error", error); 276 if (otherTeam >= 0) 277 reply.AddInt32("other_team", otherTeam); 278 if (token > 0) 279 reply.AddInt32("token", (int32)token); 280 request->SendReply(&reply); 281 } 282 283 FUNCTION_END(); 284 } 285 286 // HandleCompleteRegistration 287 /*! \brief Handles a CompleteRegistration() request. 288 \param request The request message 289 */ 290 void 291 TRoster::HandleCompleteRegistration(BMessage *request) 292 { 293 FUNCTION_START(); 294 295 BAutolock _(fLock); 296 297 status_t error = B_OK; 298 // get the parameters 299 team_id team; 300 thread_id thread; 301 port_id port; 302 if (request->FindInt32("team", &team) != B_OK) 303 team = -1; 304 if (request->FindInt32("thread", &thread) != B_OK) 305 thread = -1; 306 if (request->FindInt32("port", &port) != B_OK) 307 port = -1; 308 309 if (fShuttingDown) 310 error = B_SHUTTING_DOWN; 311 312 // check the parameters 313 // port 314 if (error == B_OK && port < 0) 315 SET_ERROR(error, B_BAD_VALUE); 316 317 // thread 318 if (error == B_OK && thread < 0) 319 SET_ERROR(error, B_BAD_VALUE); 320 321 // team 322 if (error == B_OK) { 323 if (team >= 0) { 324 // everything is fine -- set the values 325 RosterAppInfo *info = fRegisteredApps.InfoFor(team); 326 if (info && info->state == APP_STATE_PRE_REGISTERED) { 327 info->thread = thread; 328 info->port = port; 329 info->state = APP_STATE_REGISTERED; 330 _AppAdded(info); 331 } else 332 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED); 333 } else 334 SET_ERROR(error, B_BAD_VALUE); 335 } 336 337 // reply to the request 338 if (error == B_OK) { 339 BMessage reply(B_REG_SUCCESS); 340 request->SendReply(&reply); 341 } else { 342 BMessage reply(B_REG_ERROR); 343 reply.AddInt32("error", error); 344 request->SendReply(&reply); 345 } 346 347 FUNCTION_END(); 348 } 349 350 // HandleIsAppRegistered 351 /*! \brief Handles an IsAppRegistered() request. 352 \param request The request message 353 */ 354 void 355 TRoster::HandleIsAppRegistered(BMessage *request) 356 { 357 FUNCTION_START(); 358 359 BAutolock _(fLock); 360 361 status_t error = B_OK; 362 // get the parameters 363 entry_ref ref; 364 team_id team; 365 uint32 token; 366 if (request->FindRef("ref", &ref) != B_OK) 367 SET_ERROR(error, B_BAD_VALUE); 368 if (request->FindInt32("team", &team) != B_OK) 369 team = -1; 370 if (request->FindInt32("token", (int32*)&token) != B_OK) 371 token = 0; 372 373 PRINT(("team: %ld, token: %lu\n", team, token)); 374 PRINT(("ref: %ld, %lld, %s\n", ref.device, ref.directory, ref.name)); 375 376 // check the parameters 377 // entry_ref 378 if (error == B_OK & !BEntry(&ref).Exists()) 379 SET_ERROR(error, B_ENTRY_NOT_FOUND); 380 // team/token 381 if (error == B_OK && team < 0 && token == 0) 382 SET_ERROR(error, B_BAD_VALUE); 383 384 // look up the information 385 RosterAppInfo *info = NULL; 386 if (error == B_OK) { 387 if ((info = fRegisteredApps.InfoFor(team)) != NULL) { 388 PRINT(("found team in fRegisteredApps\n")); 389 _ReplyToIARRequest(request, info); 390 } else if (token > 0 391 && (info = fEarlyPreRegisteredApps.InfoForToken(token)) != NULL) { 392 PRINT(("found ref in fEarlyRegisteredApps (by token)\n")); 393 // pre-registered and has no team ID assigned yet -- queue the 394 // request 395 be_app->DetachCurrentMessage(); 396 _AddIARRequest(fIARRequestsByToken, token, request); 397 } else if (team >= 0 398 && (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL) { 399 PRINT(("found ref in fEarlyRegisteredApps (by ref)\n")); 400 // pre-registered and has no team ID assigned yet -- queue the 401 // request 402 be_app->DetachCurrentMessage(); 403 _AddIARRequest(fIARRequestsByID, team, request); 404 } else { 405 PRINT(("didn't find team or ref\n")); 406 // team not registered, ref/token not early pre-registered 407 _ReplyToIARRequest(request, NULL); 408 } 409 } else { 410 // reply to the request on error 411 BMessage reply(B_REG_ERROR); 412 reply.AddInt32("error", error); 413 request->SendReply(&reply); 414 } 415 416 FUNCTION_END(); 417 } 418 419 // HandleRemovePreRegApp 420 /*! \brief Handles a RemovePreRegApp() request. 421 \param request The request message 422 */ 423 void 424 TRoster::HandleRemovePreRegApp(BMessage *request) 425 { 426 FUNCTION_START(); 427 428 BAutolock _(fLock); 429 430 status_t error = B_OK; 431 // get the parameters 432 uint32 token; 433 if (request->FindInt32("token", (int32*)&token) != B_OK) 434 SET_ERROR(error, B_BAD_VALUE); 435 // remove the app 436 if (error == B_OK) { 437 RosterAppInfo *info = fEarlyPreRegisteredApps.InfoForToken(token); 438 if (info) { 439 fEarlyPreRegisteredApps.RemoveInfo(info); 440 delete info; 441 } else 442 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED); 443 } 444 // reply to the request 445 if (error == B_OK) { 446 BMessage reply(B_REG_SUCCESS); 447 request->SendReply(&reply); 448 } else { 449 BMessage reply(B_REG_ERROR); 450 reply.AddInt32("error", error); 451 request->SendReply(&reply); 452 } 453 454 FUNCTION_END(); 455 } 456 457 // HandleRemoveApp 458 /*! \brief Handles a RemoveApp() request. 459 \param request The request message 460 */ 461 void 462 TRoster::HandleRemoveApp(BMessage *request) 463 { 464 FUNCTION_START(); 465 466 BAutolock _(fLock); 467 468 status_t error = B_OK; 469 // get the parameters 470 team_id team; 471 if (request->FindInt32("team", &team) != B_OK) 472 team = -1; 473 PRINT(("team: %ld\n", team)); 474 // remove the app 475 if (error == B_OK) { 476 if (RosterAppInfo *info = fRegisteredApps.InfoFor(team)) { 477 RemoveApp(info); 478 delete info; 479 } else 480 SET_ERROR(error, B_REG_APP_NOT_REGISTERED); 481 } 482 // reply to the request 483 if (error == B_OK) { 484 BMessage reply(B_REG_SUCCESS); 485 request->SendReply(&reply); 486 } else { 487 BMessage reply(B_REG_ERROR); 488 reply.AddInt32("error", error); 489 request->SendReply(&reply); 490 } 491 492 FUNCTION_END(); 493 } 494 495 // HandleSetThreadAndTeam 496 /*! \brief Handles a SetThreadAndTeam() request. 497 \param request The request message 498 */ 499 void 500 TRoster::HandleSetThreadAndTeam(BMessage *request) 501 { 502 FUNCTION_START(); 503 504 BAutolock _(fLock); 505 506 status_t error = B_OK; 507 // get the parameters 508 team_id team; 509 thread_id thread; 510 uint32 token; 511 if (request->FindInt32("team", &team) != B_OK) 512 team = -1; 513 if (request->FindInt32("thread", &thread) != B_OK) 514 thread = -1; 515 if (request->FindInt32("token", (int32*)&token) != B_OK) 516 SET_ERROR(error, B_BAD_VALUE); 517 // check the parameters 518 // team 519 if (error == B_OK && team < 0) 520 SET_ERROR(error, B_BAD_VALUE); 521 PRINT(("team: %ld, thread: %ld, token: %lu\n", team, thread, token)); 522 // update the app_info 523 if (error == B_OK) { 524 RosterAppInfo *info = fEarlyPreRegisteredApps.InfoForToken(token); 525 if (info) { 526 // Set thread and team, create a port for the application and 527 // move the app_info from the list of the early pre-registered 528 // apps to the list of the (pre-)registered apps. 529 fEarlyPreRegisteredApps.RemoveInfo(info); 530 info->team = team; 531 info->thread = thread; 532 // create and transfer the port 533 info->port = create_port(B_REG_APP_LOOPER_PORT_CAPACITY, 534 kRAppLooperPortName); 535 if (info->port < 0) 536 SET_ERROR(error, info->port); 537 if (error == B_OK) 538 SET_ERROR(error, set_port_owner(info->port, team)); 539 // add the info to the registered apps list 540 if (error == B_OK) 541 SET_ERROR(error, AddApp(info)); 542 // cleanup on failure 543 if (error != B_OK) { 544 if (info->port >= 0) 545 delete_port(info->port); 546 delete info; 547 info = NULL; 548 } 549 // handle pending IsAppRegistered() requests 550 IARRequestMap::iterator it = fIARRequestsByID.find(team); 551 if (it != fIARRequestsByID.end()) { 552 BMessageQueue *requests = it->second; 553 if (error == B_OK) 554 _ReplyToIARRequests(requests, info); 555 delete requests; 556 fIARRequestsByID.erase(it); 557 } 558 559 it = fIARRequestsByToken.find((int32)token); 560 if (it != fIARRequestsByToken.end()) { 561 BMessageQueue *requests = it->second; 562 if (error == B_OK) 563 _ReplyToIARRequests(requests, info); 564 delete requests; 565 fIARRequestsByToken.erase(it); 566 } 567 } else 568 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED); 569 } 570 // reply to the request 571 if (error == B_OK) { 572 BMessage reply(B_REG_SUCCESS); 573 request->SendReply(&reply); 574 } else { 575 BMessage reply(B_REG_ERROR); 576 reply.AddInt32("error", error); 577 request->SendReply(&reply); 578 } 579 580 FUNCTION_END(); 581 } 582 583 // HandleSetSignature 584 /*! \brief Handles a SetSignature() request. 585 \param request The request message 586 */ 587 void 588 TRoster::HandleSetSignature(BMessage *request) 589 { 590 FUNCTION_START(); 591 592 BAutolock _(fLock); 593 594 status_t error = B_OK; 595 // get the parameters 596 team_id team; 597 const char *signature; 598 if (request->FindInt32("team", &team) != B_OK) 599 error = B_BAD_VALUE; 600 if (request->FindString("signature", &signature) != B_OK) 601 error = B_BAD_VALUE; 602 // find the app and set the signature 603 if (error == B_OK) { 604 if (RosterAppInfo *info = fRegisteredApps.InfoFor(team)) 605 strcpy(info->signature, signature); 606 else 607 SET_ERROR(error, B_REG_APP_NOT_REGISTERED); 608 } 609 // reply to the request 610 if (error == B_OK) { 611 BMessage reply(B_REG_SUCCESS); 612 request->SendReply(&reply); 613 } else { 614 BMessage reply(B_REG_ERROR); 615 reply.AddInt32("error", error); 616 request->SendReply(&reply); 617 } 618 619 FUNCTION_END(); 620 } 621 622 // HandleGetAppInfo 623 /*! \brief Handles a Get{Running,Active,}AppInfo() request. 624 \param request The request message 625 */ 626 void 627 TRoster::HandleGetAppInfo(BMessage *request) 628 { 629 FUNCTION_START(); 630 631 BAutolock _(fLock); 632 633 status_t error = B_OK; 634 // get the parameters 635 team_id team; 636 entry_ref ref; 637 const char *signature; 638 bool hasTeam = true; 639 bool hasRef = true; 640 bool hasSignature = true; 641 if (request->FindInt32("team", &team) != B_OK) 642 hasTeam = false; 643 if (request->FindRef("ref", &ref) != B_OK) 644 hasRef = false; 645 if (request->FindString("signature", &signature) != B_OK) 646 hasSignature = false; 647 if (hasTeam) 648 PRINT(("team: %ld\n", team)); 649 if (hasRef) 650 PRINT(("ref: %ld, %lld, %s\n", ref.device, ref.directory, ref.name)); 651 if (hasSignature) 652 PRINT(("signature: %s\n", signature)); 653 // get the info 654 RosterAppInfo *info = NULL; 655 if (error == B_OK) { 656 if (hasTeam) { 657 info = fRegisteredApps.InfoFor(team); 658 if (info == NULL) 659 SET_ERROR(error, B_BAD_TEAM_ID); 660 } else if (hasRef) { 661 info = fRegisteredApps.InfoFor(&ref); 662 if (info == NULL) 663 SET_ERROR(error, B_ERROR); 664 } else if (hasSignature) { 665 info = fRegisteredApps.InfoFor(signature); 666 if (info == NULL) 667 SET_ERROR(error, B_ERROR); 668 } else { 669 // If neither of those has been supplied, the active application 670 // info is requested. 671 if (fActiveApp) 672 info = fActiveApp; 673 else 674 SET_ERROR(error, B_ERROR); 675 } 676 } 677 // reply to the request 678 if (error == B_OK) { 679 BMessage reply(B_REG_SUCCESS); 680 _AddMessageAppInfo(&reply, info); 681 request->SendReply(&reply); 682 } else { 683 BMessage reply(B_REG_ERROR); 684 reply.AddInt32("error", error); 685 request->SendReply(&reply); 686 } 687 688 FUNCTION_END(); 689 } 690 691 // HandleGetAppList 692 /*! \brief Handles a GetAppList() request. 693 \param request The request message 694 */ 695 void 696 TRoster::HandleGetAppList(BMessage *request) 697 { 698 FUNCTION_START(); 699 700 BAutolock _(fLock); 701 702 status_t error = B_OK; 703 // get the parameters 704 const char *signature; 705 if (request->FindString("signature", &signature) != B_OK) 706 signature = NULL; 707 // reply to the request 708 if (error == B_OK) { 709 BMessage reply(B_REG_SUCCESS); 710 // get the list 711 for (AppInfoList::Iterator it(fRegisteredApps.It()); 712 RosterAppInfo *info = *it; 713 ++it) { 714 if (info->state != APP_STATE_REGISTERED) 715 continue; 716 if (!signature || !strcasecmp(signature, info->signature)) 717 reply.AddInt32("teams", info->team); 718 } 719 request->SendReply(&reply); 720 } else { 721 BMessage reply(B_REG_ERROR); 722 reply.AddInt32("error", error); 723 request->SendReply(&reply); 724 } 725 726 FUNCTION_END(); 727 } 728 729 730 /*! \brief Handles a _UpdateActiveApp() request. 731 732 This is sent from the app_server when the current active application 733 is changed. 734 735 \param request The request message 736 */ 737 void 738 TRoster::HandleUpdateActiveApp(BMessage *request) 739 { 740 FUNCTION_START(); 741 742 BAutolock _(fLock); 743 744 // get the parameters 745 status_t error = B_OK; 746 team_id team; 747 if (request->FindInt32("team", &team) != B_OK) 748 error = B_BAD_VALUE; 749 750 // activate the app 751 if (error == B_OK) { 752 if (RosterAppInfo *info = fRegisteredApps.InfoFor(team)) 753 UpdateActiveApp(info); 754 else 755 error = B_BAD_TEAM_ID; 756 } 757 758 // reply to the request 759 if (request->IsSourceWaiting()) { 760 if (error == B_OK) { 761 BMessage reply(B_REG_SUCCESS); 762 request->SendReply(&reply); 763 } else { 764 BMessage reply(B_REG_ERROR); 765 reply.AddInt32("error", error); 766 request->SendReply(&reply); 767 } 768 } 769 770 FUNCTION_END(); 771 } 772 773 // HandleBroadcast 774 /*! \brief Handles a Broadcast() request. 775 \param request The request message 776 */ 777 void 778 TRoster::HandleBroadcast(BMessage *request) 779 { 780 FUNCTION_START(); 781 782 BAutolock _(fLock); 783 784 status_t error = B_OK; 785 // get the parameters 786 team_id team; 787 BMessage message; 788 BMessenger replyTarget; 789 if (request->FindInt32("team", &team) != B_OK) 790 team = -1; 791 if (error == B_OK && request->FindMessage("message", &message) != B_OK) 792 error = B_BAD_VALUE; 793 if (error == B_OK 794 && request->FindMessenger("reply_target", &replyTarget) != B_OK) { 795 error = B_BAD_VALUE; 796 } 797 798 // reply to the request -- do this first, don't let the inquirer wait 799 if (error == B_OK) { 800 BMessage reply(B_REG_SUCCESS); 801 request->SendReply(&reply); 802 } else { 803 BMessage reply(B_REG_ERROR); 804 reply.AddInt32("error", error); 805 request->SendReply(&reply); 806 } 807 808 // broadcast the message 809 if (error == B_OK) { 810 // the target set (excludes the registrar and the requesting team) 811 class BroadcastMessagingTargetSet 812 : public AppInfoListMessagingTargetSet { 813 public: 814 BroadcastMessagingTargetSet(AppInfoList &list, team_id team) 815 : AppInfoListMessagingTargetSet(list, true), 816 fTeam(team) 817 { 818 } 819 820 virtual bool Filter(const RosterAppInfo *info) 821 { 822 return AppInfoListMessagingTargetSet::Filter(info) 823 && (info->team != fTeam); 824 } 825 826 private: 827 team_id fTeam; 828 } targetSet(fRegisteredApps, team); 829 830 if (targetSet.HasNext()) { 831 // set the reply target 832 BMessage::Private(message).SetReply(replyTarget); 833 834 // send the messages 835 MessageDeliverer::Default()->DeliverMessage(&message, targetSet); 836 } 837 } 838 839 FUNCTION_END(); 840 } 841 842 // HandleStartWatching 843 /*! \brief Handles a StartWatching() request. 844 \param request The request message 845 */ 846 void 847 TRoster::HandleStartWatching(BMessage *request) 848 { 849 FUNCTION_START(); 850 851 BAutolock _(fLock); 852 853 status_t error = B_OK; 854 // get the parameters 855 BMessenger target; 856 uint32 events; 857 if (error == B_OK && request->FindMessenger("target", &target) != B_OK) 858 error = B_BAD_VALUE; 859 if (request->FindInt32("events", (int32*)&events) != B_OK) 860 error = B_BAD_VALUE; 861 // add the new watcher 862 if (error == B_OK) { 863 Watcher *watcher = new(nothrow) EventMaskWatcher(target, events); 864 if (watcher) { 865 if (!fWatchingService.AddWatcher(watcher)) { 866 error = B_NO_MEMORY; 867 delete watcher; 868 } 869 } else 870 error = B_NO_MEMORY; 871 } 872 // reply to the request 873 if (error == B_OK) { 874 BMessage reply(B_REG_SUCCESS); 875 request->SendReply(&reply); 876 } else { 877 BMessage reply(B_REG_ERROR); 878 reply.AddInt32("error", error); 879 request->SendReply(&reply); 880 } 881 882 FUNCTION_END(); 883 } 884 885 // HandleStopWatching 886 /*! \brief Handles a StopWatching() request. 887 \param request The request message 888 */ 889 void 890 TRoster::HandleStopWatching(BMessage *request) 891 { 892 FUNCTION_START(); 893 894 BAutolock _(fLock); 895 896 status_t error = B_OK; 897 // get the parameters 898 BMessenger target; 899 if (error == B_OK && request->FindMessenger("target", &target) != B_OK) 900 error = B_BAD_VALUE; 901 // remove the watcher 902 if (error == B_OK) { 903 if (!fWatchingService.RemoveWatcher(target)) 904 error = B_BAD_VALUE; 905 } 906 // reply to the request 907 if (error == B_OK) { 908 BMessage reply(B_REG_SUCCESS); 909 request->SendReply(&reply); 910 } else { 911 BMessage reply(B_REG_ERROR); 912 reply.AddInt32("error", error); 913 request->SendReply(&reply); 914 } 915 916 FUNCTION_END(); 917 } 918 919 // HandleGetRecentDocuments 920 /*! \brief Handles a GetRecentDocuments() request. 921 \param request The request message 922 */ 923 void 924 TRoster::HandleGetRecentDocuments(BMessage *request) 925 { 926 FUNCTION_START(); 927 928 BAutolock _(fLock); 929 930 _HandleGetRecentEntries(request); 931 932 FUNCTION_END(); 933 } 934 935 // HandleGetRecentFolders 936 /*! \brief Handles a GetRecentFolders() request. 937 \param request The request message 938 */ 939 void 940 TRoster::HandleGetRecentFolders(BMessage *request) 941 { 942 FUNCTION_START(); 943 944 BAutolock _(fLock); 945 946 _HandleGetRecentEntries(request); 947 948 FUNCTION_END(); 949 } 950 951 // HandleGetRecentApps 952 /*! \brief Handles a GetRecentApps() request. 953 \param request The request message 954 */ 955 void 956 TRoster::HandleGetRecentApps(BMessage *request) 957 { 958 FUNCTION_START(); 959 960 BAutolock _(fLock); 961 962 if (!request) { 963 D(PRINT(("WARNING: TRoster::HandleGetRecentApps(NULL) called\n"))); 964 return; 965 } 966 967 int32 maxCount; 968 BMessage reply(B_REG_RESULT); 969 970 status_t error = request->FindInt32("max count", &maxCount); 971 if (!error) 972 error = fRecentApps.Get(maxCount, &reply); 973 reply.AddInt32("result", error); 974 request->SendReply(&reply); 975 976 FUNCTION_END(); 977 } 978 979 // HandleAddToRecentDocuments 980 /*! \brief Handles an AddToRecentDocuments() request. 981 \param request The request message 982 */ 983 void 984 TRoster::HandleAddToRecentDocuments(BMessage *request) 985 { 986 FUNCTION_START(); 987 988 BAutolock _(fLock); 989 990 if (!request) { 991 D(PRINT(("WARNING: TRoster::HandleAddToRecentDocuments(NULL) called\n"))); 992 return; 993 } 994 995 entry_ref ref; 996 const char *appSig; 997 BMessage reply(B_REG_RESULT); 998 999 status_t error = request->FindRef("ref", &ref); 1000 if (!error) 1001 error = request->FindString("app sig", &appSig); 1002 if (!error) 1003 error = fRecentDocuments.Add(&ref, appSig); 1004 reply.AddInt32("result", error); 1005 request->SendReply(&reply); 1006 1007 FUNCTION_END(); 1008 } 1009 1010 // HandleAddToRecentFolders 1011 /*! \brief Handles an AddToRecentFolders() request. 1012 \param request The request message 1013 */ 1014 void 1015 TRoster::HandleAddToRecentFolders(BMessage *request) 1016 { 1017 FUNCTION_START(); 1018 1019 BAutolock _(fLock); 1020 1021 if (!request) { 1022 D(PRINT(("WARNING: TRoster::HandleAddToRecentFolders(NULL) called\n"))); 1023 return; 1024 } 1025 1026 entry_ref ref; 1027 const char *appSig; 1028 BMessage reply(B_REG_RESULT); 1029 1030 status_t error = request->FindRef("ref", &ref); 1031 if (!error) 1032 error = request->FindString("app sig", &appSig); 1033 if (!error) 1034 error = fRecentFolders.Add(&ref, appSig); 1035 reply.AddInt32("result", error); 1036 request->SendReply(&reply); 1037 1038 FUNCTION_END(); 1039 } 1040 1041 // HandleAddToRecentApps 1042 /*! \brief Handles an AddToRecentApps() request. 1043 \param request The request message 1044 */ 1045 void 1046 TRoster::HandleAddToRecentApps(BMessage *request) 1047 { 1048 FUNCTION_START(); 1049 1050 BAutolock _(fLock); 1051 1052 if (!request) { 1053 D(PRINT(("WARNING: TRoster::HandleAddToRecentApps(NULL) called\n"))); 1054 return; 1055 } 1056 1057 const char *appSig; 1058 BMessage reply(B_REG_RESULT); 1059 1060 status_t error = request->FindString("app sig", &appSig); 1061 if (!error) 1062 error = fRecentApps.Add(appSig); 1063 reply.AddInt32("result", error); 1064 request->SendReply(&reply); 1065 1066 FUNCTION_END(); 1067 } 1068 1069 void 1070 TRoster::HandleLoadRecentLists(BMessage *request) 1071 { 1072 FUNCTION_START(); 1073 1074 BAutolock _(fLock); 1075 1076 if (!request) { 1077 D(PRINT(("WARNING: TRoster::HandleLoadRecentLists(NULL) called\n"))); 1078 return; 1079 } 1080 1081 const char *filename; 1082 BMessage reply(B_REG_RESULT); 1083 1084 status_t error = request->FindString("filename", &filename); 1085 if (!error) 1086 error = _LoadRosterSettings(filename); 1087 reply.AddInt32("result", error); 1088 request->SendReply(&reply); 1089 1090 FUNCTION_END(); 1091 } 1092 1093 void 1094 TRoster::HandleSaveRecentLists(BMessage *request) 1095 { 1096 FUNCTION_START(); 1097 1098 BAutolock _(fLock); 1099 1100 if (!request) { 1101 D(PRINT(("WARNING: TRoster::HandleSaveRecentLists(NULL) called\n"))); 1102 return; 1103 } 1104 1105 const char *filename; 1106 BMessage reply(B_REG_RESULT); 1107 1108 status_t error = request->FindString("filename", &filename); 1109 if (!error) 1110 error = _SaveRosterSettings(filename); 1111 reply.AddInt32("result", error); 1112 request->SendReply(&reply); 1113 1114 FUNCTION_END(); 1115 } 1116 1117 // ClearRecentDocuments 1118 /*! \brief Clears the current list of recent documents 1119 */ 1120 void 1121 TRoster::ClearRecentDocuments() 1122 { 1123 BAutolock _(fLock); 1124 1125 fRecentDocuments.Clear(); 1126 } 1127 1128 // ClearRecentFolders 1129 /*! \brief Clears the current list of recent folders 1130 */ 1131 void 1132 TRoster::ClearRecentFolders() 1133 { 1134 BAutolock _(fLock); 1135 1136 fRecentFolders.Clear(); 1137 } 1138 1139 // ClearRecentApps 1140 /*! \brief Clears the current list of recent apps 1141 */ 1142 void 1143 TRoster::ClearRecentApps() 1144 { 1145 BAutolock _(fLock); 1146 1147 fRecentApps.Clear(); 1148 } 1149 1150 // Init 1151 /*! \brief Initializes the roster. 1152 1153 Currently only adds the registrar to the roster. 1154 The application must already be running, more precisly Run() must have 1155 been called. 1156 1157 \return 1158 - \c B_OK: Everything went fine. 1159 - an error code 1160 */ 1161 status_t 1162 TRoster::Init() 1163 { 1164 status_t error = B_OK; 1165 1166 // check lock initialization 1167 if (fLock.Sem() < 0) 1168 return fLock.Sem(); 1169 1170 // create the info 1171 RosterAppInfo *info = new(nothrow) RosterAppInfo; 1172 if (!info) 1173 error = B_NO_MEMORY; 1174 1175 // get the app's ref 1176 entry_ref ref; 1177 if (error == B_OK) 1178 error = get_app_ref(&ref); 1179 1180 // init and add the info 1181 if (error == B_OK) { 1182 info->Init(be_app->Thread(), be_app->Team(), 1183 BMessenger::Private(be_app_messenger).Port(), 1184 B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP, &ref, 1185 kRegistrarSignature); 1186 info->state = APP_STATE_REGISTERED; 1187 info->registration_time = system_time(); 1188 error = AddApp(info); 1189 } 1190 1191 // cleanup on error 1192 if (error != B_OK && info) 1193 delete info; 1194 1195 return error; 1196 } 1197 1198 // AddApp 1199 /*! \brief Add the supplied app info to the list of (pre-)registered apps. 1200 1201 \param info The app info to be added 1202 */ 1203 status_t 1204 TRoster::AddApp(RosterAppInfo *info) 1205 { 1206 BAutolock _(fLock); 1207 1208 status_t error = (info ? B_OK : B_BAD_VALUE); 1209 if (info) { 1210 if (!fRegisteredApps.AddInfo(info)) 1211 error = B_NO_MEMORY; 1212 } 1213 return error; 1214 } 1215 1216 // RemoveApp 1217 /*! \brief Removes the supplied app info from the list of (pre-)registered 1218 apps. 1219 1220 \param info The app info to be removed 1221 */ 1222 void 1223 TRoster::RemoveApp(RosterAppInfo *info) 1224 { 1225 BAutolock _(fLock); 1226 1227 if (info) { 1228 if (fRegisteredApps.RemoveInfo(info)) { 1229 if (info->state == APP_STATE_REGISTERED) { 1230 info->state = APP_STATE_UNREGISTERED; 1231 _AppRemoved(info); 1232 } 1233 } 1234 } 1235 } 1236 1237 1238 /*! \brief Activates the application identified by \a info. 1239 1240 The currently active application is deactivated and the one whose 1241 info is supplied is activated. \a info may be \c NULL, which only 1242 deactivates the currently active application. 1243 1244 \param info The info of the app to be activated 1245 */ 1246 void 1247 TRoster::UpdateActiveApp(RosterAppInfo *info) 1248 { 1249 BAutolock _(fLock); 1250 1251 if (info != fActiveApp) { 1252 // deactivate the currently active app 1253 RosterAppInfo *oldActiveApp = fActiveApp; 1254 fActiveApp = NULL; 1255 if (oldActiveApp) 1256 _AppDeactivated(oldActiveApp); 1257 1258 // activate the new app 1259 if (info) { 1260 fActiveApp = info; 1261 _AppActivated(info); 1262 } 1263 } 1264 } 1265 1266 // CheckSanity 1267 /*! \brief Checks whether the (pre-)registered applications are still running. 1268 1269 This is necessary, since killed applications don't unregister properly. 1270 */ 1271 void 1272 TRoster::CheckSanity() 1273 { 1274 BAutolock _(fLock); 1275 1276 // not early (pre-)registered applications 1277 AppInfoList obsoleteApps; 1278 for (AppInfoList::Iterator it = fRegisteredApps.It(); it.IsValid(); ++it) { 1279 if (!(*it)->IsRunning()) 1280 obsoleteApps.AddInfo(*it); 1281 } 1282 1283 // remove the apps 1284 for (AppInfoList::Iterator it = obsoleteApps.It(); it.IsValid(); ++it) { 1285 RemoveApp(*it); 1286 delete *it; 1287 } 1288 obsoleteApps.MakeEmpty(false); 1289 // don't delete infos a second time 1290 1291 // early pre-registered applications 1292 bigtime_t timeLimit = system_time() - kMaximalEarlyPreRegistrationPeriod; 1293 for (AppInfoList::Iterator it = fEarlyPreRegisteredApps.It(); 1294 it.IsValid(); 1295 ++it) { 1296 if ((*it)->registration_time < timeLimit) 1297 obsoleteApps.AddInfo(*it); 1298 } 1299 1300 // remove the apps 1301 for (AppInfoList::Iterator it = obsoleteApps.It(); it.IsValid(); ++it) { 1302 fEarlyPreRegisteredApps.RemoveInfo(*it); 1303 delete *it; 1304 } 1305 obsoleteApps.MakeEmpty(false); 1306 // don't delete infos a second time 1307 } 1308 1309 // SetShuttingDown 1310 /*! \brief Tells the roster whether a shutdown process is in progess at the 1311 moment. 1312 1313 After this method is called with \a shuttingDown == \c true, no more 1314 applications can be created. 1315 1316 \param shuttingDown \c true, to indicate the start of the shutdown process, 1317 \c false to signalling its end. 1318 */ 1319 void 1320 TRoster::SetShuttingDown(bool shuttingDown) 1321 { 1322 BAutolock _(fLock); 1323 1324 fShuttingDown = shuttingDown; 1325 } 1326 1327 // GetShutdownApps 1328 /*! \brief Returns lists of applications to be asked to quit on shutdown. 1329 1330 \param userApps List of RosterAppInfos identifying the user applications. 1331 Those will be ask to quit first. 1332 \param systemApps List of RosterAppInfos identifying the system applications 1333 (like Tracker and Deskbar), which will be asked to quit after the 1334 user applications are gone. 1335 \param vitalSystemApps A set of team_ids identifying teams that must not 1336 be terminated (app server and registrar). 1337 \return \c B_OK, if everything went fine, another error code otherwise. 1338 */ 1339 status_t 1340 TRoster::GetShutdownApps(AppInfoList &userApps, AppInfoList &systemApps, 1341 AppInfoList &backgroundApps, hash_set<team_id> &vitalSystemApps) 1342 { 1343 BAutolock _(fLock); 1344 1345 status_t error = B_OK; 1346 1347 // get the vital system apps: 1348 // * ourself 1349 // * kernel team 1350 // * app server 1351 // * debug server 1352 1353 // ourself 1354 vitalSystemApps.insert(be_app->Team()); 1355 1356 // kernel team 1357 team_info teamInfo; 1358 if (get_team_info(B_SYSTEM_TEAM, &teamInfo) == B_OK) 1359 vitalSystemApps.insert(teamInfo.team); 1360 1361 // app server 1362 port_id appServerPort = find_port(SERVER_PORT_NAME); 1363 port_info portInfo; 1364 if (appServerPort >= 0 1365 && get_port_info(appServerPort, &portInfo) == B_OK) { 1366 vitalSystemApps.insert(portInfo.team); 1367 } 1368 1369 // debug server 1370 RosterAppInfo *info = 1371 fRegisteredApps.InfoFor("application/x-vnd.haiku-debug_server"); 1372 if (info) 1373 vitalSystemApps.insert(info->team); 1374 1375 // populate the other groups 1376 for (AppInfoList::Iterator it(fRegisteredApps.It()); 1377 RosterAppInfo *info = *it; 1378 ++it) { 1379 if (vitalSystemApps.find(info->team) == vitalSystemApps.end()) { 1380 RosterAppInfo *clonedInfo = info->Clone(); 1381 if (clonedInfo) { 1382 if (_IsSystemApp(info)) { 1383 if (!systemApps.AddInfo(clonedInfo)) 1384 error = B_NO_MEMORY; 1385 } else if (info->flags & B_BACKGROUND_APP) { 1386 if (!backgroundApps.AddInfo(clonedInfo)) 1387 error = B_NO_MEMORY; 1388 } else { 1389 if (!userApps.AddInfo(clonedInfo)) 1390 error = B_NO_MEMORY; 1391 } 1392 1393 if (error != B_OK) 1394 delete clonedInfo; 1395 } else 1396 error = B_NO_MEMORY; 1397 } 1398 1399 if (error != B_OK) 1400 break; 1401 } 1402 1403 // Special case, we add the input server to vital apps here so it is 1404 // not excluded in the lists above 1405 info = fRegisteredApps.InfoFor("application/x-vnd.Be-input_server"); 1406 if (info) 1407 vitalSystemApps.insert(info->team); 1408 1409 // clean up on error 1410 if (error != B_OK) { 1411 userApps.MakeEmpty(true); 1412 systemApps.MakeEmpty(true); 1413 } 1414 1415 return error; 1416 } 1417 1418 // AddWatcher 1419 status_t 1420 TRoster::AddWatcher(Watcher *watcher) 1421 { 1422 BAutolock _(fLock); 1423 1424 if (!watcher) 1425 return B_BAD_VALUE; 1426 1427 if (!fWatchingService.AddWatcher(watcher)) 1428 return B_NO_MEMORY; 1429 1430 return B_OK; 1431 } 1432 1433 1434 // RemoveWatcher 1435 void 1436 TRoster::RemoveWatcher(Watcher *watcher) 1437 { 1438 BAutolock _(fLock); 1439 1440 if (watcher) 1441 fWatchingService.RemoveWatcher(watcher, false); 1442 } 1443 1444 1445 // _AppAdded 1446 /*! \brief Hook method invoked, when an application has been fully registered. 1447 \param info The RosterAppInfo of the added application. 1448 */ 1449 void 1450 TRoster::_AppAdded(RosterAppInfo *info) 1451 { 1452 // notify the watchers 1453 BMessage message(B_SOME_APP_LAUNCHED); 1454 _AddMessageWatchingInfo(&message, info); 1455 EventMaskWatcherFilter filter(B_REQUEST_LAUNCHED); 1456 fWatchingService.NotifyWatchers(&message, &filter); 1457 } 1458 1459 // _AppRemoved 1460 /*! \brief Hook method invoked, when a fully registered application has been removed. 1461 \param info The RosterAppInfo of the removed application. 1462 */ 1463 void 1464 TRoster::_AppRemoved(RosterAppInfo *info) 1465 { 1466 if (info) { 1467 // deactivate the app, if it was the active one 1468 if (info == fActiveApp) 1469 UpdateActiveApp(NULL); 1470 1471 // notify the watchers 1472 BMessage message(B_SOME_APP_QUIT); 1473 _AddMessageWatchingInfo(&message, info); 1474 EventMaskWatcherFilter filter(B_REQUEST_QUIT); 1475 fWatchingService.NotifyWatchers(&message, &filter); 1476 } 1477 } 1478 1479 // _AppActivated 1480 /*! \brief Hook method invoked, when an application has been activated. 1481 \param info The RosterAppInfo of the activated application. 1482 */ 1483 void 1484 TRoster::_AppActivated(RosterAppInfo *info) 1485 { 1486 if (info) { 1487 if (info->state == APP_STATE_REGISTERED) { 1488 // send B_APP_ACTIVATED to the app 1489 BMessenger messenger; 1490 BMessenger::Private messengerPrivate(messenger); 1491 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN); 1492 BMessage message(B_APP_ACTIVATED); 1493 message.AddBool("active", true); 1494 // not sure, if it makes sense to use the MessageDeliverer here 1495 MessageDeliverer::Default()->DeliverMessage(&message, messenger); 1496 1497 // notify the watchers 1498 BMessage watcherMessage(B_SOME_APP_ACTIVATED); 1499 _AddMessageWatchingInfo(&watcherMessage, info); 1500 EventMaskWatcherFilter filter(B_REQUEST_ACTIVATED); 1501 fWatchingService.NotifyWatchers(&watcherMessage, &filter); 1502 } 1503 } 1504 } 1505 1506 // _AppDeactivated 1507 /*! \brief Hook method invoked, when an application has been deactivated. 1508 \param info The RosterAppInfo of the deactivated application. 1509 */ 1510 void 1511 TRoster::_AppDeactivated(RosterAppInfo *info) 1512 { 1513 if (info) { 1514 if (info->state == APP_STATE_REGISTERED) { 1515 // send B_APP_ACTIVATED to the app 1516 BMessenger messenger; 1517 BMessenger::Private messengerPrivate(messenger); 1518 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN); 1519 BMessage message(B_APP_ACTIVATED); 1520 message.AddBool("active", false); 1521 // not sure, if it makes sense to use the MessageDeliverer here 1522 MessageDeliverer::Default()->DeliverMessage(&message, messenger); 1523 } 1524 } 1525 } 1526 1527 // _AddMessageAppInfo 1528 /*! \brief Adds an app_info to a message. 1529 1530 The info is added as a flat_app_info to a field "app_info" with the type 1531 \c B_REG_APP_INFO_TYPE. 1532 1533 \param message The message 1534 \param info The app_info. 1535 \return \c B_OK if everything went fine, an error code otherwise. 1536 */ 1537 status_t 1538 TRoster::_AddMessageAppInfo(BMessage *message, const app_info *info) 1539 { 1540 // An app_info is not completely flat. The entry_ref contains a string 1541 // pointer. Therefore we flatten the info. 1542 flat_app_info flatInfo; 1543 flatInfo.info = *info; 1544 // set the ref name to NULL and copy it into the flat structure 1545 flatInfo.info.ref.name = NULL; 1546 flatInfo.ref_name[0] = '\0'; 1547 if (info->ref.name) 1548 strcpy(flatInfo.ref_name, info->ref.name); 1549 // add the flat info 1550 return message->AddData("app_info", B_REG_APP_INFO_TYPE, &flatInfo, 1551 sizeof(flat_app_info)); 1552 } 1553 1554 // _AddMessageWatchingInfo 1555 /*! \brief Adds application monitoring related fields to a message. 1556 \param message The message. 1557 \param info The app_info of the concerned application. 1558 \return \c B_OK if everything went fine, an error code otherwise. 1559 */ 1560 status_t 1561 TRoster::_AddMessageWatchingInfo(BMessage *message, const app_info *info) 1562 { 1563 status_t error = B_OK; 1564 if (error == B_OK) 1565 error = message->AddString("be:signature", info->signature); 1566 if (error == B_OK) 1567 error = message->AddInt32("be:team", info->team); 1568 if (error == B_OK) 1569 error = message->AddInt32("be:thread", info->thread); 1570 if (error == B_OK) 1571 error = message->AddInt32("be:flags", (int32)info->flags); 1572 if (error == B_OK) 1573 error = message->AddRef("be:ref", &info->ref); 1574 return error; 1575 } 1576 1577 // _NextToken 1578 /*! \brief Returns the next available token. 1579 \return The token. 1580 */ 1581 uint32 1582 TRoster::_NextToken() 1583 { 1584 return ++fLastToken; 1585 } 1586 1587 // _AddIARRequest 1588 /*! \brief Adds an IsAppRegistered() request to the given map. 1589 1590 If something goes wrong, the method deletes the request. 1591 1592 \param map The map the request shall be added to. 1593 \param key The key under which to add the request. 1594 \param request The request message to be added. 1595 */ 1596 void 1597 TRoster::_AddIARRequest(IARRequestMap& map, int32 key, BMessage* request) 1598 { 1599 IARRequestMap::iterator it = map.find(key); 1600 BMessageQueue* requests = NULL; 1601 if (it == map.end()) { 1602 requests = new(nothrow) BMessageQueue(); 1603 if (!requests) { 1604 delete request; 1605 return; 1606 } 1607 1608 map[key] = requests; 1609 } else 1610 requests = it->second; 1611 1612 requests->AddMessage(request); 1613 } 1614 1615 // _ReplyToIARRequests 1616 /*! \brief Invokes _ReplyToIARRequest() for all messages in the given 1617 message queue. 1618 1619 \param requests The request messages to be replied to 1620 \param info The RosterAppInfo of the application in question 1621 (may be \c NULL) 1622 */ 1623 void 1624 TRoster::_ReplyToIARRequests(BMessageQueue *requests, 1625 const RosterAppInfo *info) 1626 { 1627 while (BMessage* request = requests->NextMessage()) { 1628 _ReplyToIARRequest(request, info); 1629 delete request; 1630 } 1631 } 1632 1633 // _ReplyToIARRequest 1634 /*! \brief Sends a reply message to an IsAppRegistered() request. 1635 1636 The message to be sent is a simple \c B_REG_SUCCESS message containing 1637 a "pre-registered" field, that says whether or not the application is 1638 pre-registered. It will be set to \c false, unless an \a info is supplied 1639 and the application this info refers to is pre-registered. 1640 1641 \param request The request message to be replied to 1642 \param info The RosterAppInfo of the application in question 1643 (may be \c NULL) 1644 */ 1645 void 1646 TRoster::_ReplyToIARRequest(BMessage *request, const RosterAppInfo *info) 1647 { 1648 // pre-registered or registered? 1649 bool preRegistered = false; 1650 if (info) { 1651 switch (info->state) { 1652 case APP_STATE_PRE_REGISTERED: 1653 preRegistered = true; 1654 break; 1655 case APP_STATE_UNREGISTERED: 1656 case APP_STATE_REGISTERED: 1657 preRegistered = false; 1658 break; 1659 } 1660 } 1661 // send reply 1662 BMessage reply(B_REG_SUCCESS); 1663 reply.AddBool("registered", (bool)info); 1664 reply.AddBool("pre-registered", preRegistered); 1665 PRINT(("_ReplyToIARRequest(): pre-registered: %d\n", preRegistered)); 1666 if (info) 1667 _AddMessageAppInfo(&reply, info); 1668 request->SendReply(&reply); 1669 } 1670 1671 // _HandleGetRecentEntries 1672 /*! \brief Handles requests for both GetRecentDocuments() and 1673 GetRecentFolders(). 1674 */ 1675 void 1676 TRoster::_HandleGetRecentEntries(BMessage *request) 1677 { 1678 FUNCTION_START(); 1679 if (!request) { 1680 D(PRINT(("WARNING: TRoster::HandleGetRecentFolders(NULL) called\n"))); 1681 return; 1682 } 1683 1684 int32 maxCount; 1685 BMessage reply(B_REG_RESULT); 1686 char **fileTypes = NULL; 1687 int32 fileTypesCount = 0; 1688 char *appSig = NULL; 1689 1690 status_t error = request->FindInt32("max count", &maxCount); 1691 // Look for optional file type(s) 1692 if (!error) { 1693 type_code typeFound; 1694 status_t typeError = request->GetInfo("file type", &typeFound, &fileTypesCount); 1695 if (!typeError) 1696 typeError = typeFound == B_STRING_TYPE ? B_OK : B_BAD_TYPE; 1697 if (!typeError) { 1698 fileTypes = new(nothrow) char*[fileTypesCount]; 1699 typeError = fileTypes ? B_OK : B_NO_MEMORY; 1700 } 1701 if (!typeError) { 1702 for (int i = 0; !error && i < fileTypesCount; i++) { 1703 const char *type; 1704 if (request->FindString("file type", i, &type) == B_OK) { 1705 fileTypes[i] = new(nothrow) char[B_MIME_TYPE_LENGTH]; 1706 error = fileTypes[i] ? B_OK : B_NO_MEMORY; 1707 // Yes, I do mean to use "error" here, not "typeError" 1708 BPrivate::Storage::to_lower(type, fileTypes[i]); 1709 // Types are expected to be lowercase 1710 } 1711 } 1712 } 1713 } 1714 // Look for optional app sig 1715 if (!error) { 1716 const char *sig; 1717 error = request->FindString("app sig", &sig); 1718 if (!error) { 1719 appSig = new(nothrow) char[B_MIME_TYPE_LENGTH]; 1720 error = appSig ? B_OK : B_NO_MEMORY; 1721 BPrivate::Storage::to_lower(sig, appSig); 1722 } else if (error == B_NAME_NOT_FOUND) 1723 error = B_OK; 1724 } 1725 if (!error) { 1726 switch (request->what) { 1727 case B_REG_GET_RECENT_DOCUMENTS: 1728 error = fRecentDocuments.Get(maxCount, (const char**)fileTypes, 1729 fileTypesCount, appSig, &reply); 1730 D(fRecentDocuments.Print()); 1731 break; 1732 1733 case B_REG_GET_RECENT_FOLDERS: 1734 error = fRecentFolders.Get(maxCount, (const char**)fileTypes, 1735 fileTypesCount, appSig, &reply); 1736 D(fRecentFolders.Print()); 1737 break; 1738 1739 default: 1740 D(PRINT(("WARNING: TRoster::_HandleGetRecentEntries(): unexpected " 1741 "request->what value of 0x%lx\n", request->what))); 1742 error = B_BAD_VALUE; 1743 break; 1744 } 1745 } 1746 reply.AddInt32("result", error); 1747 // Clean up before sending a reply 1748 delete [] appSig; 1749 if (fileTypes) { 1750 for (int i = 0; i < fileTypesCount; i++) 1751 delete [] fileTypes[i]; 1752 delete fileTypes; 1753 fileTypes = NULL; 1754 } 1755 request->SendReply(&reply); 1756 1757 FUNCTION_END(); 1758 } 1759 1760 1761 /*! 1762 \brief Checks all registered apps for \a ref and \a signature if 1763 they are still alive, and removes those that aren't. 1764 */ 1765 void 1766 TRoster::_ValidateRunning(const entry_ref& ref, const char* signature) 1767 { 1768 while (true) { 1769 // get info via ref or signature 1770 RosterAppInfo* info = fRegisteredApps.InfoFor(&ref); 1771 if (info == NULL && signature != NULL) 1772 info = fRegisteredApps.InfoFor(signature); 1773 1774 // if app is alive or does not exist, we can exit 1775 if (info == NULL || info->IsRunning()) 1776 return; 1777 1778 RemoveApp(info); 1779 delete info; 1780 } 1781 } 1782 1783 1784 bool 1785 TRoster::_IsSystemApp(RosterAppInfo *info) const 1786 { 1787 BPath path; 1788 status_t error = path.SetTo(&info->ref); 1789 if (error != B_OK) 1790 return false; 1791 1792 int len = strlen(path.Path()); 1793 int prefixLen = strlen(kSystemAppPathPrefix); 1794 return (len > prefixLen 1795 && strncmp(path.Path(), kSystemAppPathPrefix, prefixLen) == 0); 1796 } 1797 1798 status_t 1799 TRoster::_LoadRosterSettings(const char *path) 1800 { 1801 BPath _path; 1802 const char *settingsPath 1803 = path ? path : get_default_roster_settings_file(_path); 1804 1805 RosterSettingsCharStream stream; 1806 status_t error; 1807 BFile file; 1808 1809 error = file.SetTo(settingsPath, B_READ_ONLY); 1810 off_t size; 1811 if (!error) 1812 error = file.GetSize(&size); 1813 char *data; 1814 if (!error) { 1815 data = new(nothrow) char[size]; 1816 error = data ? B_OK : B_NO_MEMORY; 1817 } 1818 if (!error) { 1819 ssize_t bytes = file.Read(data, size); 1820 error = bytes < 0 ? bytes : (bytes == size ? B_OK : B_FILE_ERROR); 1821 } 1822 if (!error) 1823 error = stream.SetTo(std::string(data)); 1824 if (!error) { 1825 // Clear the current lists as 1826 // we'll be manually building them up 1827 fRecentDocuments.Clear(); 1828 fRecentFolders.Clear(); 1829 fRecentApps.Clear(); 1830 1831 // Now we just walk through the file and read in the info 1832 while (true) { 1833 status_t streamError; 1834 char str[B_PATH_NAME_LENGTH]; 1835 1836 1837 // (RecentDoc | RecentFolder | RecentApp) 1838 streamError = stream.GetString(str); 1839 if (!streamError) { 1840 enum EntryType { 1841 etDoc, 1842 etFolder, 1843 etApp, 1844 etSomethingIsAmiss, 1845 } type; 1846 1847 if (strcmp(str, "RecentDoc") == 0) { 1848 type = etDoc; 1849 } else if (strcmp(str, "RecentFolder") == 0) { 1850 type = etFolder; 1851 } else if (strcmp(str, "RecentApp") == 0) { 1852 type = etApp; 1853 } else { 1854 type = etSomethingIsAmiss; 1855 } 1856 1857 switch (type) { 1858 case etDoc: 1859 case etFolder: 1860 { 1861 // For curing laziness 1862 std::list<recent_entry*> *list = (type == etDoc) 1863 ? &fRecentDocuments.fEntryList 1864 : &fRecentFolders.fEntryList; 1865 1866 char path[B_PATH_NAME_LENGTH]; 1867 char app[B_PATH_NAME_LENGTH]; 1868 char rank[B_PATH_NAME_LENGTH]; 1869 entry_ref ref; 1870 uint32 index = 0; 1871 1872 // Convert the given path to an entry ref 1873 streamError = stream.GetString(path); 1874 if (!streamError) 1875 streamError = get_ref_for_path(path, &ref); 1876 1877 // Add a new entry to the list for each application 1878 // signature and rank we find 1879 while (!streamError) { 1880 if (!streamError) 1881 streamError = stream.GetString(app); 1882 if (!streamError) { 1883 BPrivate::Storage::to_lower(app); 1884 streamError = stream.GetString(rank); 1885 } 1886 if (!streamError) { 1887 index = strtoul(rank, NULL, 10); 1888 if (index == ULONG_MAX) 1889 streamError = errno; 1890 } 1891 recent_entry *entry = NULL; 1892 if (!streamError) { 1893 entry = new(nothrow) recent_entry(&ref, app, index); 1894 streamError = entry ? B_OK : B_NO_MEMORY; 1895 } 1896 if (!streamError) { 1897 printf("pushing entry, leaf == '%s', app == '%s', index == %ld\n", 1898 entry->ref.name, entry->sig.c_str(), entry->index); 1899 1900 list->push_back(entry); 1901 } 1902 } 1903 1904 if (streamError) { 1905 printf("entry error 0x%lx\n", streamError); 1906 if (streamError != RosterSettingsCharStream::kEndOfLine 1907 && streamError != RosterSettingsCharStream::kEndOfStream) 1908 stream.SkipLine(); 1909 } 1910 1911 break; 1912 } 1913 1914 1915 case etApp: 1916 { 1917 char app[B_PATH_NAME_LENGTH]; 1918 streamError = stream.GetString(app); 1919 if (!streamError) { 1920 BPrivate::Storage::to_lower(app); 1921 fRecentApps.fAppList.push_back(app); 1922 } else 1923 stream.SkipLine(); 1924 break; 1925 } 1926 1927 default: 1928 // Something was amiss; skip to the next line 1929 stream.SkipLine(); 1930 break; 1931 } 1932 1933 } 1934 1935 if (streamError == RosterSettingsCharStream::kEndOfStream) 1936 break; 1937 } 1938 1939 // Now we must sort our lists of documents and folders by the 1940 // indicies we read for each entry (largest index first) 1941 fRecentDocuments.fEntryList.sort(larger_index); 1942 fRecentFolders.fEntryList.sort(larger_index); 1943 1944 printf("----------------------------------------------------------------------\n"); 1945 fRecentDocuments.Print(); 1946 printf("----------------------------------------------------------------------\n"); 1947 fRecentFolders.Print(); 1948 printf("----------------------------------------------------------------------\n"); 1949 fRecentApps.Print(); 1950 printf("----------------------------------------------------------------------\n"); 1951 } 1952 if (error) 1953 D(PRINT(("WARNING: TRoster::_LoadRosterSettings(): error loading roster settings " 1954 "from '%s', 0x%lx\n", settingsPath, error))); 1955 return error; 1956 } 1957 1958 status_t 1959 TRoster::_SaveRosterSettings(const char *path) 1960 { 1961 BPath _path; 1962 const char *settingsPath 1963 = path ? path : get_default_roster_settings_file(_path); 1964 1965 status_t error; 1966 FILE* file; 1967 1968 file = fopen(settingsPath, "w+"); 1969 error = file ? B_OK : errno; 1970 if (!error) { 1971 status_t saveError; 1972 saveError = fRecentDocuments.Save(file, "Recent documents", "RecentDoc"); 1973 if (saveError) 1974 D(PRINT(("TRoster::_SaveRosterSettings(): recent documents save failed " 1975 "with error 0x%lx\n", saveError))); 1976 saveError = fRecentFolders.Save(file, "Recent folders", "RecentFolder"); 1977 if (saveError) 1978 D(PRINT(("TRoster::_SaveRosterSettings(): recent folders save failed " 1979 "with error 0x%lx\n", saveError))); 1980 saveError = fRecentApps.Save(file); 1981 if (saveError) 1982 D(PRINT(("TRoster::_SaveRosterSettings(): recent folders save failed " 1983 "with error 0x%lx\n", saveError))); 1984 fclose(file); 1985 } 1986 1987 return error; 1988 } 1989 1990 1991 //------------------------------------------------------------------------------ 1992 // Private local functions 1993 //------------------------------------------------------------------------------ 1994 1995 /*! \brief Returns true if entry1's index is larger than entry2's index. 1996 1997 Also returns true if either entry is \c NULL. 1998 1999 Used for sorting the recent entry lists loaded from disk into the 2000 proper order. 2001 */ 2002 bool 2003 larger_index(const recent_entry *entry1, const recent_entry *entry2) 2004 { 2005 if (entry1 && entry2) 2006 return entry1->index > entry2->index; 2007 else 2008 return true; 2009 } 2010 2011