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