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