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