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