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