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