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