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