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