1 /* 2 * Copyright 2001-2015, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, ingo_weinhold@gmx.de 7 */ 8 9 #include "Registrar.h" 10 11 #include <stdio.h> 12 #include <string.h> 13 14 #include <exception> 15 16 #include <Application.h> 17 #include <Clipboard.h> 18 #include <Message.h> 19 #include <MessengerPrivate.h> 20 #include <OS.h> 21 #include <RegistrarDefs.h> 22 #include <RosterPrivate.h> 23 #include <system_info.h> 24 25 #include "AuthenticationManager.h" 26 #include "ClipboardHandler.h" 27 #include "Debug.h" 28 #include "EventQueue.h" 29 #include "MessageDeliverer.h" 30 #include "MessageEvent.h" 31 #include "MessageRunnerManager.h" 32 #include "MessagingService.h" 33 #include "MIMEManager.h" 34 #include "PackageWatchingManager.h" 35 #include "ShutdownProcess.h" 36 #include "TRoster.h" 37 38 39 /*! 40 \class Registrar 41 \brief The application class of the registrar. 42 43 Glues the registrar services together and dispatches the roster messages. 44 */ 45 46 using std::nothrow; 47 using namespace BPrivate; 48 49 //! Name of the event queue. 50 static const char *kEventQueueName = "timer_thread"; 51 52 53 /*! \brief Creates the registrar application class. 54 \param error Passed to the BApplication constructor for returning an 55 error code. 56 */ 57 Registrar::Registrar(status_t* _error) 58 : 59 BServer(B_REGISTRAR_SIGNATURE, B_REGISTRAR_PORT_NAME, -1, false, _error), 60 fRoster(NULL), 61 fClipboardHandler(NULL), 62 fMIMEManager(NULL), 63 fEventQueue(NULL), 64 fMessageRunnerManager(NULL), 65 fShutdownProcess(NULL), 66 fAuthenticationManager(NULL), 67 fPackageWatchingManager(NULL) 68 { 69 FUNCTION_START(); 70 71 set_thread_priority(find_thread(NULL), B_NORMAL_PRIORITY + 1); 72 } 73 74 75 /*! \brief Frees all resources associated with the registrar. 76 77 All registrar services, that haven't been shut down earlier, are 78 terminated. 79 */ 80 Registrar::~Registrar() 81 { 82 FUNCTION_START(); 83 Lock(); 84 fEventQueue->Die(); 85 delete fAuthenticationManager; 86 delete fPackageWatchingManager; 87 delete fMessageRunnerManager; 88 delete fEventQueue; 89 fMIMEManager->Lock(); 90 fMIMEManager->Quit(); 91 RemoveHandler(fClipboardHandler); 92 delete fClipboardHandler; 93 delete fRoster; 94 // Invalidate the global be_roster, so that the BApplication destructor 95 // won't dead-lock when sending a message to itself. 96 BRoster::Private().SetTo(BMessenger(), BMessenger()); 97 FUNCTION_END(); 98 } 99 100 101 /*! \brief Overrides the super class version to dispatch roster specific 102 messages. 103 \param message The message to be handled 104 */ 105 void 106 Registrar::MessageReceived(BMessage *message) 107 { 108 try { 109 _MessageReceived(message); 110 } catch (std::exception& exception) { 111 char buffer[1024]; 112 snprintf(buffer, sizeof(buffer), 113 "Registrar::MessageReceived() caught exception: %s", 114 exception.what()); 115 debugger(buffer); 116 } catch (...) { 117 debugger("Registrar::MessageReceived() caught unknown exception"); 118 } 119 } 120 121 122 /*! \brief Overrides the super class version to initialize the registrar 123 services. 124 */ 125 void 126 Registrar::ReadyToRun() 127 { 128 FUNCTION_START(); 129 130 // create message deliverer 131 status_t error = MessageDeliverer::CreateDefault(); 132 if (error != B_OK) { 133 FATAL("Registrar::ReadyToRun(): Failed to create the message " 134 "deliverer: %s\n", strerror(error)); 135 } 136 137 // create event queue 138 fEventQueue = new EventQueue(kEventQueueName); 139 140 // create authentication manager 141 fAuthenticationManager = new AuthenticationManager; 142 fAuthenticationManager->Init(); 143 144 // create roster 145 fRoster = new TRoster; 146 fRoster->Init(); 147 148 // create clipboard handler 149 fClipboardHandler = new ClipboardHandler; 150 AddHandler(fClipboardHandler); 151 152 // create MIME manager 153 fMIMEManager = new MIMEManager; 154 fMIMEManager->Run(); 155 156 // create message runner manager 157 fMessageRunnerManager = new MessageRunnerManager(fEventQueue); 158 159 // init the global be_roster 160 BRoster::Private().SetTo(be_app_messenger, BMessenger(NULL, fMIMEManager)); 161 162 // create the messaging service 163 error = MessagingService::CreateDefault(); 164 if (error != B_OK) { 165 ERROR("Registrar::ReadyToRun(): Failed to init messaging service " 166 "(that's by design when running under R5): %s\n", strerror(error)); 167 } 168 169 // create the package watching manager 170 fPackageWatchingManager = new PackageWatchingManager; 171 172 // Sanity check roster after team deletion 173 BMessenger target(this); 174 BMessenger::Private messengerPrivate(target); 175 176 port_id port = messengerPrivate.Port(); 177 int32 token = messengerPrivate.Token(); 178 __start_watching_system(-1, B_WATCH_SYSTEM_TEAM_DELETION, port, token); 179 fRoster->CheckSanity(); 180 // Clean up any teams that exited before we started watching 181 182 FUNCTION_END(); 183 } 184 185 186 /*! \brief Overrides the super class version to avoid termination of the 187 registrar until the system shutdown. 188 */ 189 bool 190 Registrar::QuitRequested() 191 { 192 FUNCTION_START(); 193 // The final registrar must not quit. At least not that easily. ;-) 194 return BApplication::QuitRequested(); 195 } 196 197 198 /*! \brief Returns the registrar's event queue. 199 \return The registrar's event queue. 200 */ 201 EventQueue* 202 Registrar::GetEventQueue() const 203 { 204 return fEventQueue; 205 } 206 207 208 /*! \brief Returns the Registrar application object. 209 \return The Registrar application object. 210 */ 211 Registrar* 212 Registrar::App() 213 { 214 return dynamic_cast<Registrar*>(be_app); 215 } 216 217 218 void 219 Registrar::_MessageReceived(BMessage *message) 220 { 221 switch (message->what) { 222 // general requests 223 case B_REG_GET_MIME_MESSENGER: 224 { 225 PRINT("B_REG_GET_MIME_MESSENGER\n"); 226 BMessenger messenger(NULL, fMIMEManager); 227 BMessage reply(B_REG_SUCCESS); 228 reply.AddMessenger("messenger", messenger); 229 message->SendReply(&reply); 230 break; 231 } 232 233 case B_REG_GET_CLIPBOARD_MESSENGER: 234 { 235 PRINT("B_REG_GET_CLIPBOARD_MESSENGER\n"); 236 BMessenger messenger(fClipboardHandler); 237 BMessage reply(B_REG_SUCCESS); 238 reply.AddMessenger("messenger", messenger); 239 message->SendReply(&reply); 240 break; 241 } 242 243 // shutdown process 244 case B_REG_SHUT_DOWN: 245 { 246 PRINT("B_REG_SHUT_DOWN\n"); 247 248 _HandleShutDown(message); 249 break; 250 } 251 case B_REG_TEAM_DEBUGGER_ALERT: 252 { 253 if (fShutdownProcess != NULL) 254 fShutdownProcess->PostMessage(message); 255 break; 256 } 257 258 // roster requests 259 case B_REG_ADD_APP: 260 fRoster->HandleAddApplication(message); 261 break; 262 case B_REG_COMPLETE_REGISTRATION: 263 fRoster->HandleCompleteRegistration(message); 264 break; 265 case B_REG_IS_APP_REGISTERED: 266 fRoster->HandleIsAppRegistered(message); 267 break; 268 case B_REG_REMOVE_PRE_REGISTERED_APP: 269 fRoster->HandleRemovePreRegApp(message); 270 break; 271 case B_REG_REMOVE_APP: 272 fRoster->HandleRemoveApp(message); 273 break; 274 case B_REG_SET_THREAD_AND_TEAM: 275 fRoster->HandleSetThreadAndTeam(message); 276 break; 277 case B_REG_SET_SIGNATURE: 278 fRoster->HandleSetSignature(message); 279 break; 280 case B_REG_GET_APP_INFO: 281 fRoster->HandleGetAppInfo(message); 282 break; 283 case B_REG_GET_APP_LIST: 284 fRoster->HandleGetAppList(message); 285 break; 286 case B_REG_UPDATE_ACTIVE_APP: 287 fRoster->HandleUpdateActiveApp(message); 288 break; 289 case B_REG_BROADCAST: 290 fRoster->HandleBroadcast(message); 291 break; 292 case B_REG_START_WATCHING: 293 fRoster->HandleStartWatching(message); 294 break; 295 case B_REG_STOP_WATCHING: 296 fRoster->HandleStopWatching(message); 297 break; 298 case B_REG_GET_RECENT_DOCUMENTS: 299 fRoster->HandleGetRecentDocuments(message); 300 break; 301 case B_REG_GET_RECENT_FOLDERS: 302 fRoster->HandleGetRecentFolders(message); 303 break; 304 case B_REG_GET_RECENT_APPS: 305 fRoster->HandleGetRecentApps(message); 306 break; 307 case B_REG_ADD_TO_RECENT_DOCUMENTS: 308 fRoster->HandleAddToRecentDocuments(message); 309 break; 310 case B_REG_ADD_TO_RECENT_FOLDERS: 311 fRoster->HandleAddToRecentFolders(message); 312 break; 313 case B_REG_ADD_TO_RECENT_APPS: 314 fRoster->HandleAddToRecentApps(message); 315 break; 316 case B_REG_CLEAR_RECENT_DOCUMENTS: 317 fRoster->ClearRecentDocuments(); 318 break; 319 case B_REG_CLEAR_RECENT_FOLDERS: 320 fRoster->ClearRecentFolders(); 321 break; 322 case B_REG_CLEAR_RECENT_APPS: 323 fRoster->ClearRecentApps(); 324 break; 325 case B_REG_LOAD_RECENT_LISTS: 326 fRoster->HandleLoadRecentLists(message); 327 break; 328 case B_REG_SAVE_RECENT_LISTS: 329 fRoster->HandleSaveRecentLists(message); 330 break; 331 332 // message runner requests 333 case B_REG_REGISTER_MESSAGE_RUNNER: 334 fMessageRunnerManager->HandleRegisterRunner(message); 335 break; 336 case B_REG_UNREGISTER_MESSAGE_RUNNER: 337 fMessageRunnerManager->HandleUnregisterRunner(message); 338 break; 339 case B_REG_SET_MESSAGE_RUNNER_PARAMS: 340 fMessageRunnerManager->HandleSetRunnerParams(message); 341 break; 342 case B_REG_GET_MESSAGE_RUNNER_INFO: 343 fMessageRunnerManager->HandleGetRunnerInfo(message); 344 break; 345 346 // package watching requests 347 case B_REG_PACKAGE_START_WATCHING: 348 case B_REG_PACKAGE_STOP_WATCHING: 349 fPackageWatchingManager->HandleStartStopWatching(message); 350 break; 351 case B_PACKAGE_UPDATE: 352 fPackageWatchingManager->NotifyWatchers(message); 353 break; 354 355 // internal messages 356 case B_SYSTEM_OBJECT_UPDATE: 357 { 358 team_id team = (team_id)message->GetInt32("team", -1); 359 if (team >= 0 && message->GetInt32("opcode", 0) == B_TEAM_DELETED) 360 fRoster->HandleRemoveApp(message); 361 break; 362 } 363 case B_REG_SHUTDOWN_FINISHED: 364 if (fShutdownProcess) { 365 fShutdownProcess->PostMessage(B_QUIT_REQUESTED, 366 fShutdownProcess); 367 fShutdownProcess = NULL; 368 } 369 break; 370 371 case kMsgRestartAppServer: 372 { 373 fRoster->HandleRestartAppServer(message); 374 break; 375 } 376 377 default: 378 BApplication::MessageReceived(message); 379 break; 380 } 381 } 382 383 384 /*! \brief Handle a shut down request message. 385 \param request The request to be handled. 386 */ 387 void 388 Registrar::_HandleShutDown(BMessage *request) 389 { 390 status_t error = B_OK; 391 392 // check, whether we're already shutting down 393 if (fShutdownProcess) 394 error = B_SHUTTING_DOWN; 395 396 bool needsReply = true; 397 if (error == B_OK) { 398 // create a ShutdownProcess 399 fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue); 400 if (fShutdownProcess) { 401 error = fShutdownProcess->Init(request); 402 if (error == B_OK) { 403 DetachCurrentMessage(); 404 fShutdownProcess->Run(); 405 needsReply = false; 406 } else { 407 delete fShutdownProcess; 408 fShutdownProcess = NULL; 409 } 410 } else 411 error = B_NO_MEMORY; 412 } 413 414 if (needsReply) 415 ShutdownProcess::SendReply(request, error); 416 } 417 418 419 // #pragma mark - 420 421 422 /*! \brief Creates and runs the registrar application. 423 424 The main thread is renamed. 425 426 \return 0. 427 */ 428 int 429 main() 430 { 431 FUNCTION_START(); 432 433 // Create the global be_clipboard manually -- it will not work, since it 434 // wants to talk to the registrar in its constructor, but it doesn't have 435 // to and we would otherwise deadlock when initializing our GUI in the 436 // app thread. 437 be_clipboard = new BClipboard(NULL); 438 439 // create and run the registrar application 440 status_t error; 441 Registrar *app = new Registrar(&error); 442 if (error != B_OK) { 443 fprintf(stderr, "REG: Failed to create the BApplication: %s\n", 444 strerror(error)); 445 return 1; 446 } 447 448 // rename the main thread 449 rename_thread(find_thread(NULL), "roster"); 450 451 PRINT("app->Run()...\n"); 452 453 try { 454 app->Run(); 455 } catch (std::exception& exception) { 456 char buffer[1024]; 457 snprintf(buffer, sizeof(buffer), 458 "registrar main() caught exception: %s", exception.what()); 459 debugger(buffer); 460 } catch (...) { 461 debugger("registrar main() caught unknown exception"); 462 } 463 464 PRINT("delete app...\n"); 465 delete app; 466 467 FUNCTION_END(); 468 return 0; 469 } 470 471