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