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::AddWatcher(Watcher* watcher) 1491 { 1492 BAutolock _(fLock); 1493 1494 if (!watcher) 1495 return B_BAD_VALUE; 1496 1497 if (!fWatchingService.AddWatcher(watcher)) 1498 return B_NO_MEMORY; 1499 1500 return B_OK; 1501 } 1502 1503 1504 void 1505 TRoster::RemoveWatcher(Watcher* watcher) 1506 { 1507 BAutolock _(fLock); 1508 1509 if (watcher) 1510 fWatchingService.RemoveWatcher(watcher, false); 1511 } 1512 1513 1514 /*! \brief Hook method invoked, when an application has been fully registered. 1515 \param info The RosterAppInfo of the added application. 1516 */ 1517 void 1518 TRoster::_AppAdded(RosterAppInfo* info) 1519 { 1520 // notify the watchers 1521 BMessage message(B_SOME_APP_LAUNCHED); 1522 _AddMessageWatchingInfo(&message, info); 1523 EventMaskWatcherFilter filter(B_REQUEST_LAUNCHED); 1524 fWatchingService.NotifyWatchers(&message, &filter); 1525 } 1526 1527 1528 /*! \brief Hook method invoked, when a fully registered application has been 1529 removed. 1530 \param info The RosterAppInfo of the removed application. 1531 */ 1532 void 1533 TRoster::_AppRemoved(RosterAppInfo* info) 1534 { 1535 if (info) { 1536 // deactivate the app, if it was the active one 1537 if (info == fActiveApp) 1538 UpdateActiveApp(NULL); 1539 1540 // notify the watchers 1541 BMessage message(B_SOME_APP_QUIT); 1542 _AddMessageWatchingInfo(&message, info); 1543 EventMaskWatcherFilter filter(B_REQUEST_QUIT); 1544 fWatchingService.NotifyWatchers(&message, &filter); 1545 } 1546 } 1547 1548 1549 /*! \brief Hook method invoked, when an application has been activated. 1550 \param info The RosterAppInfo of the activated application. 1551 */ 1552 void 1553 TRoster::_AppActivated(RosterAppInfo* info) 1554 { 1555 if (info != NULL && info->state == APP_STATE_REGISTERED) { 1556 // send B_APP_ACTIVATED to the app 1557 BMessenger messenger; 1558 BMessenger::Private messengerPrivate(messenger); 1559 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN); 1560 BMessage message(B_APP_ACTIVATED); 1561 message.AddBool("active", true); 1562 // not sure, if it makes sense to use the MessageDeliverer here 1563 MessageDeliverer::Default()->DeliverMessage(&message, messenger); 1564 1565 // notify the watchers 1566 BMessage watcherMessage(B_SOME_APP_ACTIVATED); 1567 _AddMessageWatchingInfo(&watcherMessage, info); 1568 EventMaskWatcherFilter filter(B_REQUEST_ACTIVATED); 1569 fWatchingService.NotifyWatchers(&watcherMessage, &filter); 1570 } 1571 } 1572 1573 1574 /*! \brief Hook method invoked, when an application has been deactivated. 1575 \param info The RosterAppInfo of the deactivated application. 1576 */ 1577 void 1578 TRoster::_AppDeactivated(RosterAppInfo* info) 1579 { 1580 if (info != NULL && info->state == APP_STATE_REGISTERED) { 1581 // send B_APP_ACTIVATED to the app 1582 BMessenger messenger; 1583 BMessenger::Private messengerPrivate(messenger); 1584 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN); 1585 BMessage message(B_APP_ACTIVATED); 1586 message.AddBool("active", false); 1587 // not sure, if it makes sense to use the MessageDeliverer here 1588 MessageDeliverer::Default()->DeliverMessage(&message, messenger); 1589 } 1590 } 1591 1592 1593 /*! \brief Adds an app_info to a message. 1594 1595 The info is added as a flat_app_info to a field "app_info" with the type 1596 \c B_REG_APP_INFO_TYPE. 1597 1598 \param message The message 1599 \param info The app_info. 1600 \return \c B_OK if everything went fine, an error code otherwise. 1601 */ 1602 status_t 1603 TRoster::_AddMessageAppInfo(BMessage* message, const app_info* info) 1604 { 1605 // An app_info is not completely flat. The entry_ref contains a string 1606 // pointer. Therefore we flatten the info. 1607 flat_app_info flatInfo; 1608 flatInfo.info = *info; 1609 1610 // set the ref name to NULL and copy it into the flat structure 1611 flatInfo.info.ref.name = NULL; 1612 flatInfo.ref_name[0] = '\0'; 1613 if (info->ref.name) 1614 strcpy(flatInfo.ref_name, info->ref.name); 1615 1616 // add the flat info 1617 return message->AddData("app_info", B_REG_APP_INFO_TYPE, &flatInfo, 1618 sizeof(flat_app_info)); 1619 } 1620 1621 1622 /*! \brief Adds application monitoring related fields to a message. 1623 \param message The message. 1624 \param info The app_info of the concerned application. 1625 \return \c B_OK if everything went fine, an error code otherwise. 1626 */ 1627 status_t 1628 TRoster::_AddMessageWatchingInfo(BMessage* message, const app_info* info) 1629 { 1630 status_t error = B_OK; 1631 if (error == B_OK) 1632 error = message->AddString("be:signature", info->signature); 1633 if (error == B_OK) 1634 error = message->AddInt32("be:team", info->team); 1635 if (error == B_OK) 1636 error = message->AddInt32("be:thread", info->thread); 1637 if (error == B_OK) 1638 error = message->AddInt32("be:flags", (int32)info->flags); 1639 if (error == B_OK) 1640 error = message->AddRef("be:ref", &info->ref); 1641 return error; 1642 } 1643 1644 1645 /*! \brief Returns the next available token. 1646 \return The token. 1647 */ 1648 uint32 1649 TRoster::_NextToken() 1650 { 1651 return ++fLastToken; 1652 } 1653 1654 1655 /*! \brief Adds an IsAppRegistered() request to the given map. 1656 1657 If something goes wrong, the method deletes the request. 1658 1659 \param map The map the request shall be added to. 1660 \param key The key under which to add the request. 1661 \param request The request message to be added. 1662 */ 1663 void 1664 TRoster::_AddIARRequest(IARRequestMap& map, int32 key, BMessage* request) 1665 { 1666 IARRequestMap::iterator it = map.find(key); 1667 BMessageQueue* requests = NULL; 1668 if (it == map.end()) { 1669 requests = new(nothrow) BMessageQueue(); 1670 if (!requests) { 1671 delete request; 1672 return; 1673 } 1674 1675 map[key] = requests; 1676 } else 1677 requests = it->second; 1678 1679 requests->AddMessage(request); 1680 } 1681 1682 1683 /*! \brief Invokes _ReplyToIARRequest() for all messages in the given 1684 message queue. 1685 1686 \param requests The request messages to be replied to 1687 \param info The RosterAppInfo of the application in question 1688 (may be \c NULL) 1689 */ 1690 void 1691 TRoster::_ReplyToIARRequests(BMessageQueue* requests, const RosterAppInfo* info) 1692 { 1693 while (BMessage* request = requests->NextMessage()) { 1694 _ReplyToIARRequest(request, info); 1695 delete request; 1696 } 1697 } 1698 1699 1700 /*! \brief Sends a reply message to an IsAppRegistered() request. 1701 1702 The message to be sent is a simple \c B_REG_SUCCESS message containing 1703 a "pre-registered" field, that says whether or not the application is 1704 pre-registered. It will be set to \c false, unless an \a info is supplied 1705 and the application this info refers to is pre-registered. 1706 1707 \param request The request message to be replied to 1708 \param info The RosterAppInfo of the application in question 1709 (may be \c NULL) 1710 */ 1711 void 1712 TRoster::_ReplyToIARRequest(BMessage* request, const RosterAppInfo* info) 1713 { 1714 // pre-registered or registered? 1715 bool preRegistered = false; 1716 if (info) { 1717 switch (info->state) { 1718 case APP_STATE_PRE_REGISTERED: 1719 preRegistered = true; 1720 break; 1721 case APP_STATE_UNREGISTERED: 1722 case APP_STATE_REGISTERED: 1723 preRegistered = false; 1724 break; 1725 } 1726 } 1727 // send reply 1728 BMessage reply(B_REG_SUCCESS); 1729 reply.AddBool("registered", (bool)info); 1730 reply.AddBool("pre-registered", preRegistered); 1731 PRINT("_ReplyToIARRequest(): pre-registered: %d\n", preRegistered); 1732 if (info) 1733 _AddMessageAppInfo(&reply, info); 1734 request->SendReply(&reply); 1735 } 1736 1737 1738 /*! \brief Handles requests for both GetRecentDocuments() and 1739 GetRecentFolders(). 1740 */ 1741 void 1742 TRoster::_HandleGetRecentEntries(BMessage* request) 1743 { 1744 FUNCTION_START(); 1745 if (!request) { 1746 D(PRINT("WARNING: TRoster::HandleGetRecentFolders(NULL) called\n")); 1747 return; 1748 } 1749 1750 int32 maxCount; 1751 BMessage reply(B_REG_RESULT); 1752 char** fileTypes = NULL; 1753 int32 fileTypesCount = 0; 1754 char* appSig = NULL; 1755 1756 status_t error = request->FindInt32("max count", &maxCount); 1757 // Look for optional file type(s) 1758 if (!error) { 1759 type_code typeFound; 1760 status_t typeError = request->GetInfo("file type", &typeFound, 1761 &fileTypesCount); 1762 if (!typeError) 1763 typeError = typeFound == B_STRING_TYPE ? B_OK : B_BAD_TYPE; 1764 if (!typeError) { 1765 fileTypes = new(nothrow) char*[fileTypesCount]; 1766 typeError = fileTypes ? B_OK : B_NO_MEMORY; 1767 } 1768 if (!typeError) { 1769 for (int i = 0; !error && i < fileTypesCount; i++) { 1770 const char* type; 1771 if (request->FindString("file type", i, &type) == B_OK) { 1772 fileTypes[i] = new(nothrow) char[B_MIME_TYPE_LENGTH]; 1773 error = fileTypes[i] ? B_OK : B_NO_MEMORY; 1774 // Yes, I do mean to use "error" here, not "typeError" 1775 BPrivate::Storage::to_lower(type, fileTypes[i]); 1776 // Types are expected to be lowercase 1777 } 1778 } 1779 } 1780 } 1781 // Look for optional app sig 1782 if (!error) { 1783 const char* sig; 1784 error = request->FindString("app sig", &sig); 1785 if (!error) { 1786 appSig = new(nothrow) char[B_MIME_TYPE_LENGTH]; 1787 error = appSig ? B_OK : B_NO_MEMORY; 1788 BPrivate::Storage::to_lower(sig, appSig); 1789 } else if (error == B_NAME_NOT_FOUND) 1790 error = B_OK; 1791 } 1792 if (!error) { 1793 switch (request->what) { 1794 case B_REG_GET_RECENT_DOCUMENTS: 1795 error = fRecentDocuments.Get(maxCount, (const char**)fileTypes, 1796 fileTypesCount, appSig, &reply); 1797 D(fRecentDocuments.Print()); 1798 break; 1799 1800 case B_REG_GET_RECENT_FOLDERS: 1801 error = fRecentFolders.Get(maxCount, (const char**)fileTypes, 1802 fileTypesCount, appSig, &reply); 1803 D(fRecentFolders.Print()); 1804 break; 1805 1806 default: 1807 D(PRINT("WARNING: TRoster::_HandleGetRecentEntries(): " 1808 "unexpected request->what value of 0x%" B_PRIx32 "\n", 1809 request->what)); 1810 error = B_BAD_VALUE; 1811 break; 1812 } 1813 } 1814 reply.AddInt32("result", error); 1815 // Clean up before sending a reply 1816 delete [] appSig; 1817 if (fileTypes) { 1818 for (int i = 0; i < fileTypesCount; i++) 1819 delete [] fileTypes[i]; 1820 delete[] fileTypes; 1821 fileTypes = NULL; 1822 } 1823 request->SendReply(&reply); 1824 1825 FUNCTION_END(); 1826 } 1827 1828 1829 /*! 1830 \brief Checks all registered apps for \a ref and \a signature if 1831 they are still alive, and removes those that aren't. 1832 */ 1833 void 1834 TRoster::_ValidateRunning(const entry_ref& ref, const char* signature) 1835 { 1836 while (true) { 1837 // get info via ref or signature 1838 RosterAppInfo* info = fRegisteredApps.InfoFor(&ref); 1839 if (info == NULL && signature != NULL) 1840 info = fRegisteredApps.InfoFor(signature); 1841 1842 // if app is alive or does not exist, we can exit 1843 if (info == NULL || info->IsRunning()) 1844 return; 1845 1846 RemoveApp(info); 1847 delete info; 1848 } 1849 } 1850 1851 1852 bool 1853 TRoster::_IsSystemApp(RosterAppInfo* info) const 1854 { 1855 BPath path; 1856 if (path.SetTo(&info->ref) != B_OK || path.GetParent(&path) != B_OK) 1857 return false; 1858 1859 return !strcmp(path.Path(), fSystemAppPath.Path()) 1860 || !strcmp(path.Path(), fSystemServerPath.Path()); 1861 } 1862 1863 1864 status_t 1865 TRoster::_LoadRosterSettings(const char* path) 1866 { 1867 BPath _path; 1868 const char* settingsPath 1869 = path ? path : get_default_roster_settings_path(_path, false); 1870 1871 RosterSettingsCharStream stream; 1872 status_t error; 1873 BFile file; 1874 1875 error = file.SetTo(settingsPath, B_READ_ONLY); 1876 off_t size; 1877 if (!error) 1878 error = file.GetSize(&size); 1879 1880 char* data = NULL; 1881 1882 if (!error) { 1883 data = new(nothrow) char[size + 1]; 1884 error = data ? B_OK : B_NO_MEMORY; 1885 } 1886 if (!error) { 1887 ssize_t bytes = file.Read(data, size); 1888 error = bytes < 0 ? bytes : (bytes == size ? B_OK : B_FILE_ERROR); 1889 } 1890 if (!error) { 1891 data[size] = 0; 1892 error = stream.SetTo(std::string(data)); 1893 } 1894 1895 delete[] data; 1896 1897 if (!error) { 1898 // Clear the current lists as 1899 // we'll be manually building them up 1900 fRecentDocuments.Clear(); 1901 fRecentFolders.Clear(); 1902 fRecentApps.Clear(); 1903 1904 // Now we just walk through the file and read in the info 1905 while (true) { 1906 status_t streamError; 1907 char str[B_PATH_NAME_LENGTH]; 1908 1909 // (RecentDoc | RecentFolder | RecentApp) 1910 streamError = stream.GetString(str); 1911 if (!streamError) { 1912 enum EntryType { 1913 etDoc, 1914 etFolder, 1915 etApp, 1916 etSomethingIsAmiss, 1917 } type; 1918 1919 if (strcmp(str, "RecentDoc") == 0) 1920 type = etDoc; 1921 else if (strcmp(str, "RecentFolder") == 0) 1922 type = etFolder; 1923 else if (strcmp(str, "RecentApp") == 0) 1924 type = etApp; 1925 else 1926 type = etSomethingIsAmiss; 1927 1928 switch (type) { 1929 case etDoc: 1930 case etFolder: 1931 { 1932 // For curing laziness 1933 std::list<recent_entry*>* list = type == etDoc 1934 ? &fRecentDocuments.fEntryList 1935 : &fRecentFolders.fEntryList; 1936 1937 char path[B_PATH_NAME_LENGTH]; 1938 char app[B_PATH_NAME_LENGTH]; 1939 char rank[B_PATH_NAME_LENGTH]; 1940 entry_ref ref; 1941 ulong index = 0; 1942 1943 // Convert the given path to an entry ref 1944 streamError = stream.GetString(path); 1945 if (!streamError) 1946 streamError = get_ref_for_path(path, &ref); 1947 1948 // Add a new entry to the list for each application 1949 // signature and rank we find 1950 while (!streamError) { 1951 if (!streamError) 1952 streamError = stream.GetString(app); 1953 if (!streamError) { 1954 BPrivate::Storage::to_lower(app); 1955 streamError = stream.GetString(rank); 1956 } 1957 if (!streamError) { 1958 index = strtoul(rank, NULL, 10); 1959 if (index == ULONG_MAX) 1960 streamError = errno; 1961 } 1962 recent_entry* entry = NULL; 1963 if (!streamError) { 1964 entry = new(nothrow) recent_entry(&ref, app, 1965 index); 1966 streamError = entry ? B_OK : B_NO_MEMORY; 1967 } 1968 if (!streamError) { 1969 D(printf("pushing entry, leaf == '%s', app == " 1970 "'%s', index == %" B_PRId32 "\n", 1971 entry->ref.name, entry->sig.c_str(), 1972 entry->index)); 1973 1974 list->push_back(entry); 1975 } 1976 } 1977 1978 if (streamError) { 1979 D(printf("entry error 0x%" B_PRIx32 "\n", 1980 streamError)); 1981 if (streamError 1982 != RosterSettingsCharStream::kEndOfLine 1983 && streamError 1984 != RosterSettingsCharStream::kEndOfStream) 1985 stream.SkipLine(); 1986 } 1987 1988 break; 1989 } 1990 1991 1992 case etApp: 1993 { 1994 char app[B_PATH_NAME_LENGTH]; 1995 streamError = stream.GetString(app); 1996 if (!streamError) { 1997 BPrivate::Storage::to_lower(app); 1998 fRecentApps.fAppList.push_back(app); 1999 } else 2000 stream.SkipLine(); 2001 break; 2002 } 2003 2004 default: 2005 // Something was amiss; skip to the next line 2006 stream.SkipLine(); 2007 break; 2008 } 2009 2010 } 2011 2012 if (streamError == RosterSettingsCharStream::kEndOfStream) 2013 break; 2014 } 2015 2016 // Now we must sort our lists of documents and folders by the 2017 // indicies we read for each entry (largest index first) 2018 fRecentDocuments.fEntryList.sort(larger_index); 2019 fRecentFolders.fEntryList.sort(larger_index); 2020 2021 D( 2022 printf("----------------------------------------------------------------------\n"); 2023 fRecentDocuments.Print(); 2024 printf("----------------------------------------------------------------------\n"); 2025 fRecentFolders.Print(); 2026 printf("----------------------------------------------------------------------\n"); 2027 fRecentApps.Print(); 2028 printf("----------------------------------------------------------------------\n"); 2029 ); 2030 } 2031 if (error) { 2032 D(PRINT("WARNING: TRoster::_LoadRosterSettings(): error loading roster " 2033 "settings from '%s', 0x%" B_PRIx32 "\n", settingsPath, error)); 2034 } 2035 return error; 2036 } 2037 2038 2039 status_t 2040 TRoster::_SaveRosterSettings(const char* path) 2041 { 2042 BPath _path; 2043 const char* settingsPath 2044 = path != NULL ? path : get_default_roster_settings_path(_path, true); 2045 2046 status_t error; 2047 FILE* file; 2048 2049 file = fopen(settingsPath, "w+"); 2050 error = file ? B_OK : errno; 2051 if (!error) { 2052 status_t saveError; 2053 saveError = fRecentDocuments.Save(file, "Recent documents", "RecentDoc"); 2054 if (saveError) { 2055 D(PRINT("TRoster::_SaveRosterSettings(): recent documents save " 2056 "failed with error 0x%" B_PRIx32 "\n", saveError)); 2057 } 2058 saveError = fRecentFolders.Save(file, "Recent folders", "RecentFolder"); 2059 if (saveError) { 2060 D(PRINT("TRoster::_SaveRosterSettings(): recent folders save " 2061 "failed with error 0x%" B_PRIx32 "\n", saveError)); 2062 } 2063 saveError = fRecentApps.Save(file); 2064 if (saveError) { 2065 D(PRINT("TRoster::_SaveRosterSettings(): recent folders save " 2066 "failed with error 0x%" B_PRIx32 "\n", saveError)); 2067 } 2068 fclose(file); 2069 } 2070 2071 return error; 2072 } 2073