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