1// LaunchTesterHelper.cpp 2 3#include <stdio.h> 4#include <string.h> 5 6#include <Autolock.h> 7#include <Entry.h> 8#include <List.h> 9#include <Message.h> 10#include <Messenger.h> 11#include <Path.h> 12 13#include "LaunchTesterHelper.h" 14#include "RosterTestAppDefs.h" 15 16///////////////// 17// LaunchContext 18 19const char *LaunchContext::kStandardArgv[] = { 20 "Some", "nice", "arguments" 21}; 22const int32 LaunchContext::kStandardArgc 23 = sizeof(kStandardArgv) / sizeof(const char*); 24 25// Message 26class LaunchContext::Message { 27public: 28 BMessage message; 29 bigtime_t when; 30}; 31 32// Sleeper 33class LaunchContext::Sleeper { 34public: 35 Sleeper() : fMessageCode(0), fSemaphore(-1) {} 36 37 ~Sleeper() 38 { 39 delete_sem(fSemaphore); 40 } 41 42 status_t Init(uint32 messageCode) 43 { 44 fMessageCode = messageCode; 45 fSemaphore = create_sem(0, "sleeper sem"); 46 return (fSemaphore >= 0 ? B_OK : fSemaphore); 47 } 48 49 uint32 MessageCode() const { return fMessageCode; } 50 51 status_t Sleep(bigtime_t timeout = B_INFINITE_TIMEOUT) 52 { 53 return acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, timeout); 54 } 55 56 status_t WakeUp() 57 { 58 return release_sem(fSemaphore); 59 } 60 61private: 62 uint32 fMessageCode; 63 sem_id fSemaphore; 64}; 65 66// AppInfo 67class LaunchContext::AppInfo { 68public: 69 AppInfo(team_id team) 70 : fTeam(team), 71 fMessenger(), 72 fMessages(), 73 fTerminating(false) 74 { 75 } 76 77 ~AppInfo() 78 { 79 for (int32 i = 0; LaunchContext::Message *message = MessageAt(i); i++) 80 delete message; 81 } 82 83 team_id Team() const 84 { 85 return fTeam; 86 } 87 88 void SetMessenger(BMessenger messenger) 89 { 90 fMessenger = messenger; 91 } 92 93 BMessenger Messenger() const 94 { 95 return fMessenger; 96 } 97 98 void Terminate() 99 { 100 if (!fTerminating && fMessenger.IsValid()) 101 { 102 fTerminating = true; 103 fMessenger.SendMessage(B_QUIT_REQUESTED); 104 } 105 } 106 107 void AddMessage(const BMessage &_message) 108 { 109 LaunchContext::Message *message = new LaunchContext::Message; 110 message->message = _message; 111 message->when = system_time(); 112 fMessages.AddItem(message); 113 NotifySleepers(_message.what); 114 } 115 116 LaunchContext::Message *RemoveMessage(int32 index) 117 { 118 return (LaunchContext::Message*)fMessages.RemoveItem(index); 119 } 120 121 LaunchContext::Message *MessageAt(int32 index) const 122 { 123 return (LaunchContext::Message*)fMessages.ItemAt(index); 124 } 125 126 LaunchContext::Message *FindMessage(uint32 messageCode, 127 int32 startIndex = 0) const 128 { 129 LaunchContext::Message *message = NULL; 130 for (int32 i = startIndex; (message = MessageAt(i)) != NULL; i++) { 131 if (message->message.what == messageCode) 132 break; 133 } 134 return message; 135 } 136 137 void AddSleeper(Sleeper *sleeper) 138 { 139 fSleepers.AddItem(sleeper); 140 } 141 142 void RemoveSleeper(Sleeper *sleeper) 143 { 144 fSleepers.RemoveItem(sleeper); 145 } 146 147 void NotifySleepers(uint32 messageCode) 148 { 149 for (int32 i = 0; 150 Sleeper *sleeper = (Sleeper*)fSleepers.ItemAt(i); 151 i++) { 152 if (sleeper->MessageCode() == messageCode) 153 sleeper->WakeUp(); 154 } 155 } 156 157private: 158 team_id fTeam; 159 BMessenger fMessenger; 160 BList fMessages; 161 bool fTerminating; 162 BList fSleepers; 163}; 164 165// constructor 166LaunchContext::LaunchContext() 167 : fAppInfos(), 168 fSleepers(), 169 fLock(), 170 fAppThread(B_ERROR), 171 fTerminator(B_ERROR), 172 fTerminating(false) 173{ 174 RosterLaunchApp *app = dynamic_cast<RosterLaunchApp*>(be_app); 175 app->SetLaunchContext(this); 176 app->Unlock(); 177 fAppThread = spawn_thread(AppThreadEntry, "app thread", B_NORMAL_PRIORITY, 178 this); 179 if (fAppThread >= 0) { 180 status_t error = resume_thread(fAppThread); 181 if (error != B_OK) 182 printf("ERROR: Couldn't resume app thread: %s\n", strerror(error)); 183 } else 184 printf("ERROR: Couldn't spawn app thread: %s\n", strerror(fAppThread)); 185} 186 187// destructor 188LaunchContext::~LaunchContext() 189{ 190 Terminate(); 191 // cleanup 192 for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++) 193 delete info; 194 for (int32 i = 0; 195 BMessage *message = (BMessage*)fStandardMessages.ItemAt(i); 196 i++) { 197 delete message; 198 } 199} 200 201// () 202status_t 203LaunchContext::operator()(LaunchCaller &caller, const char *type, 204 team_id *team) 205{ 206 BMessage message1(MSG_1); 207 BMessage message2(MSG_2); 208 BMessage message3(MSG_3); 209 BList messages; 210 messages.AddItem(&message1); 211 messages.AddItem(&message2); 212 messages.AddItem(&message3); 213 return (*this)(caller, type, &messages, kStandardArgc, kStandardArgv, 214 team); 215} 216 217// () 218status_t 219LaunchContext::operator()(LaunchCaller &caller, const char *type, 220 BList *messages, int32 argc, const char **argv, 221 team_id *team) 222{ 223 BAutolock _lock(fLock); 224 status_t result = caller(type, messages, argc, argv, team); 225 if (result == B_OK && team) 226 CreateAppInfo(*team); 227 return result; 228} 229 230// HandleMessage 231void 232LaunchContext::HandleMessage(BMessage *message) 233{ 234//printf("LaunchContext::HandleMessage(%6ld: %.4s)\n", 235//message->ReturnAddress().Team(), (char*)&message->what); 236//if (message->what == MSG_MESSAGE_RECEIVED) { 237// BMessage sentMessage; 238// message->FindMessage("message", &sentMessage); 239// team_id sender = -1; 240// message->FindInt32("sender", &sender); 241// printf(" <- %6ld: %.4s\n", sender, (char*)&sentMessage.what); 242//} 243 244 BAutolock _lock(fLock); 245 switch (message->what) { 246 case MSG_STARTED: 247 case MSG_TERMINATED: 248 case MSG_MAIN_ARGS: 249 case MSG_ARGV_RECEIVED: 250 case MSG_REFS_RECEIVED: 251 case MSG_MESSAGE_RECEIVED: 252 case MSG_QUIT_REQUESTED: 253 case MSG_READY_TO_RUN: 254 case MSG_1: 255 case MSG_2: 256 case MSG_3: 257 case MSG_REPLY: 258 { 259 BMessenger messenger = message->ReturnAddress(); 260 // add the message to the respective team's message list 261 // Note: catch messages that have not been sent by us or the 262 // remote team. The R5 registrar seems to send a B_REPLY message 263 // sometimes. 264 team_id sender = -1; 265 bool dontIgnore = false; 266 if (message->FindInt32("sender", &sender) != B_OK 267 || sender == be_app->Team() 268 || sender == messenger.Team() 269 || (message->FindBool("don't ignore", &dontIgnore) == B_OK) 270 && dontIgnore) { 271 AppInfo *info = CreateAppInfo(messenger); 272 info->AddMessage(*message); 273 if (fTerminating) 274 TerminateApp(info); 275 } 276 NotifySleepers(message->what); 277 break; 278 } 279 default: 280 break; 281 } 282} 283 284// Terminate 285void 286LaunchContext::Terminate() 287{ 288 fLock.Lock(); 289 if (!fTerminating) { 290 fTerminating = true; 291 // tell all test apps to quit 292 for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++) 293 TerminateApp(info); 294 // start terminator 295 fTerminator = spawn_thread(TerminatorEntry, "terminator", 296 B_NORMAL_PRIORITY, this); 297 if (fTerminator >= 0) { 298 status_t error = resume_thread(fTerminator); 299 if (error != B_OK) { 300 printf("ERROR: Couldn't resume terminator thread: %s\n", 301 strerror(error)); 302 } 303 } else { 304 printf("ERROR: Couldn't spawn terminator thread: %s\n", 305 strerror(fTerminator)); 306 } 307 } 308 fLock.Unlock(); 309 // wait for the app to terminate 310 int32 dummy; 311 wait_for_thread(fAppThread, &dummy); 312 wait_for_thread(fTerminator, &dummy); 313} 314 315// TerminateApp 316void 317LaunchContext::TerminateApp(team_id team, bool wait) 318{ 319 fLock.Lock(); 320 if (AppInfo *info = AppInfoFor(team)) 321 TerminateApp(info); 322 fLock.Unlock(); 323 if (wait) 324 WaitForMessage(team, MSG_TERMINATED); 325} 326 327// TeamAt 328team_id 329LaunchContext::TeamAt(int32 index) const 330{ 331 BAutolock _lock(fLock); 332 team_id team = B_ERROR; 333 if (AppInfo *info = AppInfoAt(index)) 334 team = info->Team(); 335 return team; 336} 337 338// AppMessengerFor 339BMessenger 340LaunchContext::AppMessengerFor(team_id team) const 341{ 342 BAutolock _lock(fLock); 343 BMessenger result; 344 if (AppInfoFor(team)) { 345 // We need to do some hacking. 346 BMessenger messenger; 347 struct fake_messenger { 348 port_id fPort; 349 int32 fHandlerToken; 350 team_id fTeam; 351 int32 extra0; 352 int32 extra1; 353 bool fPreferredTarget; 354 bool extra2; 355 bool extra3; 356 bool extra4; 357 } &fake = *(fake_messenger*)&messenger; 358 status_t error = B_OK; 359 fake.fTeam = team; 360 // find app looper port 361 bool found = false; 362 int32 cookie = 0; 363 port_info info; 364 while (error == B_OK && !found) { 365 error = get_next_port_info(fake.fTeam, &cookie, &info); 366 found = (error == B_OK 367 && (!strcmp("AppLooperPort", info.name) 368 || !strcmp("rAppLooperPort", info.name))); 369 } 370 // init messenger 371 if (error == B_OK) { 372 fake.fPort = info.port; 373 fake.fHandlerToken = 0; 374 fake.fPreferredTarget = true; 375 } 376 if (error == B_OK) 377 result = messenger; 378 } 379 return result; 380} 381 382// NextMessageFrom 383BMessage* 384LaunchContext::NextMessageFrom(team_id team, int32 &cookie, bigtime_t *time) 385{ 386 BAutolock _lock(fLock); 387 BMessage *message = NULL; 388 if (AppInfo *info = AppInfoFor(team)) { 389 if (Message *contextMessage = info->MessageAt(cookie++)) 390 message = &contextMessage->message; 391 } 392 return message; 393} 394 395// CheckNextMessage 396bool 397LaunchContext::CheckNextMessage(LaunchCaller &caller, team_id team, 398 int32 &cookie, uint32 what) 399{ 400 BMessage *message = NextMessageFrom(team, cookie); 401 return (message && message->what == what); 402} 403 404// CheckMainArgsMessage 405bool 406LaunchContext::CheckMainArgsMessage(LaunchCaller &caller, team_id team, 407 int32 &cookie, const entry_ref *appRef, 408 bool useRef) 409{ 410 int32 argc = 0; 411 const char **argv = NULL; 412 if (caller.SupportsArgv()) { 413 argc = kStandardArgc; 414 argv = kStandardArgv; 415 } 416 return CheckMainArgsMessage(caller, team, cookie, appRef, argc, argv, 417 useRef); 418} 419 420// CheckMainArgsMessage 421bool 422LaunchContext::CheckMainArgsMessage(LaunchCaller &caller, team_id team, 423 int32 &cookie, const entry_ref *appRef, 424 int32 argc, const char **argv, bool useRef) 425{ 426 useRef &= caller.SupportsArgv() && argv && argc > 0; 427 const entry_ref *ref = (useRef ? caller.Ref() : NULL); 428 return CheckArgsMessage(caller, team, cookie, appRef, ref, argc, argv, 429 MSG_MAIN_ARGS); 430} 431 432// CheckArgvMessage 433bool 434LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team, 435 int32 &cookie, const entry_ref *appRef, 436 bool useRef) 437{ 438 bool result = true; 439 if (caller.SupportsArgv()) { 440 result = CheckArgvMessage(caller, team, cookie, appRef, kStandardArgc, 441 kStandardArgv, useRef); 442 } 443 return result; 444} 445 446// CheckArgvMessage 447bool 448LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team, 449 int32 &cookie, const entry_ref *appRef, 450 int32 argc, const char **argv, bool useRef) 451{ 452 const entry_ref *ref = (useRef ? caller.Ref() : NULL); 453 return CheckArgvMessage(caller, team, cookie, appRef, ref , argc, argv); 454} 455 456// CheckArgvMessage 457bool 458LaunchContext::CheckArgvMessage(LaunchCaller &caller, team_id team, 459 int32 &cookie, const entry_ref *appRef, 460 const entry_ref *ref , int32 argc, 461 const char **argv) 462{ 463 return CheckArgsMessage(caller, team, cookie, appRef, ref, argc, argv, 464 MSG_ARGV_RECEIVED); 465} 466 467// CheckArgsMessage 468bool 469LaunchContext::CheckArgsMessage(LaunchCaller &caller, team_id team, 470 int32 &cookie, const entry_ref *appRef, 471 const entry_ref *ref , int32 argc, 472 const char **argv, uint32 messageCode) 473{ 474 BMessage *message = NextMessageFrom(team, cookie); 475 bool result = (message && message->what == messageCode); 476 int32 additionalRef = (ref ? 1 : 0); 477 // check argc 478 int32 foundArgc = -1; 479 if (result) { 480 result = (message->FindInt32("argc", &foundArgc) == B_OK 481 && foundArgc == argc + 1 + additionalRef); 482if (!result) 483printf("argc differ: %ld vs %ld + 1 + %ld\n", foundArgc, argc, additionalRef); 484 } 485 // check argv[0] (the app file name) 486 if (result) { 487 BPath path; 488 const char *arg = NULL; 489 result = (path.SetTo(appRef) == B_OK 490 && message->FindString("argv", 0, &arg) == B_OK 491 && path == arg); 492if (!result) 493printf("app paths differ: `%s' vs `%s'\n", arg, path.Path()); 494 } 495 // check remaining argv 496 for (int32 i = 1; result && i < argc; i++) { 497 const char *arg = NULL; 498 result = (message->FindString("argv", i, &arg) == B_OK 499 && !strcmp(arg, argv[i - 1])); 500if (!result) 501printf("arg[%ld] differ: `%s' vs `%s'\n", i, arg, argv[i - 1]); 502 } 503 // check additional ref 504 if (result && additionalRef) { 505 BPath path; 506 const char *arg = NULL; 507 result = (path.SetTo(ref) == B_OK 508 && message->FindString("argv", argc + 1, &arg) == B_OK 509 && path == arg); 510if (!result) 511printf("document paths differ: `%s' vs `%s'\n", arg, path.Path()); 512 } 513 return result; 514} 515 516// CheckMessageMessages 517bool 518LaunchContext::CheckMessageMessages(LaunchCaller &caller, team_id team, 519 int32 &cookie) 520{ 521 BAutolock _lock(fLock); 522 bool result = true; 523 for (int32 i = 0; i < 3; i++) 524 result &= CheckMessageMessage(caller, team, cookie, i); 525 return result; 526} 527 528// CheckMessageMessage 529bool 530LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team, 531 int32 &cookie, int32 index) 532{ 533 bool result = true; 534 if (caller.SupportsMessages() > index && index < 3) { 535 uint32 commands[] = { MSG_1, MSG_2, MSG_3 }; 536 BMessage message(commands[index]); 537 result = CheckMessageMessage(caller, team, cookie, &message); 538 } 539 return result; 540} 541 542// CheckMessageMessage 543bool 544LaunchContext::CheckMessageMessage(LaunchCaller &caller, team_id team, 545 int32 &cookie, 546 const BMessage *expectedMessage) 547{ 548 BMessage *message = NextMessageFrom(team, cookie); 549 bool result = (message && message->what == MSG_MESSAGE_RECEIVED); 550 if (result) { 551 BMessage sentMessage; 552 result = (message->FindMessage("message", &sentMessage) == B_OK 553 && sentMessage.what == expectedMessage->what); 554 } 555 return result; 556} 557 558// CheckRefsMessage 559bool 560LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team, 561 int32 &cookie) 562{ 563 bool result = true; 564 if (caller.SupportsRefs()) 565 result = CheckRefsMessage(caller, team, cookie, caller.Ref()); 566 return result; 567} 568 569// CheckRefsMessage 570bool 571LaunchContext::CheckRefsMessage(LaunchCaller &caller, team_id team, 572 int32 &cookie, const entry_ref *refs, 573 int32 count) 574{ 575 BMessage *message = NextMessageFrom(team, cookie); 576 bool result = (message && message->what == MSG_REFS_RECEIVED); 577 if (result) { 578 entry_ref ref; 579 for (int32 i = 0; result && i < count; i++) { 580 result = (message->FindRef("refs", i, &ref) == B_OK 581 && ref == refs[i]); 582 } 583 } 584 return result; 585} 586 587// WaitForMessage 588bool 589LaunchContext::WaitForMessage(uint32 messageCode, bool fromNow, 590 bigtime_t timeout) 591{ 592 status_t error = B_ERROR; 593 fLock.Lock(); 594 error = B_OK; 595 if (fromNow || !FindMessage(messageCode)) { 596 // add sleeper 597 Sleeper *sleeper = new Sleeper; 598 error = sleeper->Init(messageCode); 599 if (error == B_OK) { 600 AddSleeper(sleeper); 601 fLock.Unlock(); 602 // sleep 603 error = sleeper->Sleep(timeout); 604 fLock.Lock(); 605 // remove sleeper 606 RemoveSleeper(sleeper); 607 delete sleeper; 608 } 609 } 610 fLock.Unlock(); 611 return (error == B_OK); 612} 613 614// WaitForMessage 615bool 616LaunchContext::WaitForMessage(team_id team, uint32 messageCode, bool fromNow, 617 bigtime_t timeout, int32 startIndex) 618{ 619 status_t error = B_ERROR; 620 fLock.Lock(); 621 if (AppInfo *info = AppInfoFor(team)) { 622 error = B_OK; 623 if (fromNow || !info->FindMessage(messageCode, startIndex)) { 624 // add sleeper 625 Sleeper *sleeper = new Sleeper; 626 error = sleeper->Init(messageCode); 627 if (error == B_OK) { 628 info->AddSleeper(sleeper); 629 fLock.Unlock(); 630 // sleep 631 error = sleeper->Sleep(timeout); 632 fLock.Lock(); 633 // remove sleeper 634 info->RemoveSleeper(sleeper); 635 delete sleeper; 636 } 637 } 638 } 639 fLock.Unlock(); 640 return (error == B_OK); 641} 642 643// StandardMessages 644BList* 645LaunchContext::StandardMessages() 646{ 647 if (fStandardMessages.IsEmpty()) { 648 fStandardMessages.AddItem(new BMessage(MSG_1)); 649 fStandardMessages.AddItem(new BMessage(MSG_2)); 650 fStandardMessages.AddItem(new BMessage(MSG_3)); 651 } 652 return &fStandardMessages; 653} 654 655// AppInfoAt 656LaunchContext::AppInfo* 657LaunchContext::AppInfoAt(int32 index) const 658{ 659 return (AppInfo*)fAppInfos.ItemAt(index); 660} 661 662// AppInfoFor 663LaunchContext::AppInfo* 664LaunchContext::AppInfoFor(team_id team) const 665{ 666 for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++) { 667 if (info->Team() == team) 668 return info; 669 } 670 return NULL; 671} 672 673// CreateAppInfo 674LaunchContext::AppInfo* 675LaunchContext::CreateAppInfo(BMessenger messenger) 676{ 677 return CreateAppInfo(messenger.Team(), &messenger); 678} 679 680// CreateAppInfo 681LaunchContext::AppInfo* 682LaunchContext::CreateAppInfo(team_id team, const BMessenger *messenger) 683{ 684 AppInfo *info = AppInfoFor(team); 685 if (!info) { 686 info = new AppInfo(team); 687 fAppInfos.AddItem(info); 688 } 689 if (messenger && !info->Messenger().IsValid()) 690 info->SetMessenger(*messenger); 691 return info; 692} 693 694// TerminateApp 695void 696LaunchContext::TerminateApp(AppInfo *info) 697{ 698 if (info) 699 info->Terminate(); 700} 701 702// Terminator 703int32 704LaunchContext::Terminator() 705{ 706 bool allGone = false; 707 while (!allGone) { 708 allGone = true; 709 fLock.Lock(); 710 for (int32 i = 0; AppInfo *info = AppInfoAt(i); i++) { 711 team_info teamInfo; 712 allGone &= (get_team_info(info->Team(), &teamInfo) != B_OK); 713 } 714 fLock.Unlock(); 715 if (!allGone) 716 snooze(10000); 717 } 718 be_app->PostMessage(B_QUIT_REQUESTED, be_app); 719 return 0; 720} 721 722// AppThreadEntry 723int32 724LaunchContext::AppThreadEntry(void *) 725{ 726 be_app->Lock(); 727 be_app->Run(); 728 return 0; 729} 730 731// TerminatorEntry 732int32 733LaunchContext::TerminatorEntry(void *data) 734{ 735 return ((LaunchContext*)data)->Terminator(); 736} 737 738// FindMessage 739LaunchContext::Message* 740LaunchContext::FindMessage(uint32 messageCode) 741{ 742 BAutolock _lock(fLock); 743 Message *message = NULL; 744 AppInfo *info = NULL; 745 for (int32 i = 0; !message && (info = AppInfoAt(i)) != NULL; i++) 746 message = info->FindMessage(messageCode); 747 return message; 748} 749 750// AddSleeper 751void 752LaunchContext::AddSleeper(Sleeper *sleeper) 753{ 754 fSleepers.AddItem(sleeper); 755} 756 757// RemoveSleeper 758void 759LaunchContext::RemoveSleeper(Sleeper *sleeper) 760{ 761 fSleepers.RemoveItem(sleeper); 762} 763 764// NotifySleepers 765void 766LaunchContext::NotifySleepers(uint32 messageCode) 767{ 768 for (int32 i = 0; Sleeper *sleeper = (Sleeper*)fSleepers.ItemAt(i); i++) { 769 if (sleeper->MessageCode() == messageCode) 770 sleeper->WakeUp(); 771 } 772} 773 774 775/////////////////// 776// RosterLaunchApp 777 778// constructor 779RosterLaunchApp::RosterLaunchApp(const char *signature) 780 : BApplication(signature), 781 fLaunchContext(NULL), 782 fHandler(NULL) 783{ 784} 785 786// destructor 787RosterLaunchApp::~RosterLaunchApp() 788{ 789 SetHandler(NULL); 790} 791 792// MessageReceived 793void 794RosterLaunchApp::MessageReceived(BMessage *message) 795{ 796 if (fLaunchContext) 797 fLaunchContext->HandleMessage(message); 798} 799 800// SetLaunchContext 801void 802RosterLaunchApp::SetLaunchContext(LaunchContext *context) 803{ 804 fLaunchContext = context; 805} 806 807// GetLaunchContext 808LaunchContext * 809RosterLaunchApp::GetLaunchContext() const 810{ 811 return fLaunchContext; 812} 813 814// SetHandler 815void 816RosterLaunchApp::SetHandler(BHandler *handler) 817{ 818 Lock(); 819 if (fHandler) { 820 RemoveHandler(fHandler); 821 delete fHandler; 822 fHandler = NULL; 823 } 824 if (handler) { 825 fHandler = handler; 826 AddHandler(handler); 827 } 828 Unlock(); 829} 830 831 832////////////////////////// 833// RosterBroadcastHandler 834 835// constructor 836RosterBroadcastHandler::RosterBroadcastHandler() 837{ 838} 839 840// MessageReceived 841void 842RosterBroadcastHandler::MessageReceived(BMessage *message) 843{ 844 RosterLaunchApp *app = dynamic_cast<RosterLaunchApp*>(be_app); 845 if (LaunchContext *launchContext = app->GetLaunchContext()) { 846 message->AddInt32("original what", (int32)message->what); 847 message->what = MSG_REPLY; 848 launchContext->HandleMessage(message); 849 } 850} 851 852