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