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