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