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