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