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