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(kRegistrarSignature, BPrivate::get_roster_port_name(), false, 61 _error), 62 fRoster(NULL), 63 fClipboardHandler(NULL), 64 fMIMEManager(NULL), 65 fEventQueue(NULL), 66 fMessageRunnerManager(NULL), 67 fSanityEvent(NULL), 68 fShutdownProcess(NULL), 69 fAuthenticationManager(NULL), 70 fPackageWatchingManager(NULL) 71 { 72 FUNCTION_START(); 73 74 set_thread_priority(find_thread(NULL), B_NORMAL_PRIORITY + 1); 75 } 76 77 78 /*! \brief Frees all resources associated with the registrar. 79 80 All registrar services, that haven't been shut down earlier, are 81 terminated. 82 */ 83 Registrar::~Registrar() 84 { 85 FUNCTION_START(); 86 Lock(); 87 fEventQueue->Die(); 88 delete fAuthenticationManager; 89 delete fPackageWatchingManager; 90 delete fMessageRunnerManager; 91 delete fEventQueue; 92 delete fSanityEvent; 93 fMIMEManager->Lock(); 94 fMIMEManager->Quit(); 95 RemoveHandler(fClipboardHandler); 96 delete fClipboardHandler; 97 delete fRoster; 98 // Invalidate the global be_roster, so that the BApplication destructor 99 // won't dead-lock when sending a message to itself. 100 BRoster::Private().SetTo(BMessenger(), BMessenger()); 101 FUNCTION_END(); 102 } 103 104 105 /*! \brief Overrides the super class version to dispatch roster specific 106 messages. 107 \param message The message to be handled 108 */ 109 void 110 Registrar::MessageReceived(BMessage *message) 111 { 112 try { 113 _MessageReceived(message); 114 } catch (std::exception& exception) { 115 char buffer[1024]; 116 snprintf(buffer, sizeof(buffer), 117 "Registrar::MessageReceived() caught exception: %s", 118 exception.what()); 119 debugger(buffer); 120 } catch (...) { 121 debugger("Registrar::MessageReceived() caught unknown exception"); 122 } 123 } 124 125 126 /*! \brief Overrides the super class version to initialize the registrar 127 services. 128 */ 129 void 130 Registrar::ReadyToRun() 131 { 132 FUNCTION_START(); 133 134 // create message deliverer 135 status_t error = MessageDeliverer::CreateDefault(); 136 if (error != B_OK) { 137 FATAL("Registrar::ReadyToRun(): Failed to create the message " 138 "deliverer: %s\n", strerror(error)); 139 } 140 141 // create event queue 142 fEventQueue = new EventQueue(kEventQueueName); 143 144 // create authentication manager 145 fAuthenticationManager = new AuthenticationManager; 146 fAuthenticationManager->Init(); 147 148 // create roster 149 fRoster = new TRoster; 150 fRoster->Init(); 151 152 // create clipboard handler 153 fClipboardHandler = new ClipboardHandler; 154 AddHandler(fClipboardHandler); 155 156 // create MIME manager 157 fMIMEManager = new MIMEManager; 158 fMIMEManager->Run(); 159 160 // create message runner manager 161 fMessageRunnerManager = new MessageRunnerManager(fEventQueue); 162 163 // init the global be_roster 164 BRoster::Private().SetTo(be_app_messenger, BMessenger(NULL, fMIMEManager)); 165 166 // create the messaging service 167 error = MessagingService::CreateDefault(); 168 if (error != B_OK) { 169 ERROR("Registrar::ReadyToRun(): Failed to init messaging service " 170 "(that's by design when running under R5): %s\n", strerror(error)); 171 } 172 173 // create the package watching manager 174 fPackageWatchingManager = new PackageWatchingManager; 175 176 // create and schedule the sanity message event 177 fSanityEvent = new MessageEvent(system_time() + kRosterSanityEventInterval, 178 this, B_REG_ROSTER_SANITY_EVENT); 179 fSanityEvent->SetAutoDelete(false); 180 fEventQueue->AddEvent(fSanityEvent); 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_REG_ROSTER_SANITY_EVENT: 357 fRoster->CheckSanity(); 358 fSanityEvent->SetTime(system_time() + kRosterSanityEventInterval); 359 fEventQueue->AddEvent(fSanityEvent); 360 break; 361 case B_REG_SHUTDOWN_FINISHED: 362 if (fShutdownProcess) { 363 fShutdownProcess->PostMessage(B_QUIT_REQUESTED, 364 fShutdownProcess); 365 fShutdownProcess = NULL; 366 } 367 break; 368 369 case kMsgRestartAppServer: 370 { 371 fRoster->HandleRestartAppServer(message); 372 break; 373 } 374 375 default: 376 BApplication::MessageReceived(message); 377 break; 378 } 379 } 380 381 382 /*! \brief Handle a shut down request message. 383 \param request The request to be handled. 384 */ 385 void 386 Registrar::_HandleShutDown(BMessage *request) 387 { 388 status_t error = B_OK; 389 390 // check, whether we're already shutting down 391 if (fShutdownProcess) 392 error = B_SHUTTING_DOWN; 393 394 bool needsReply = true; 395 if (error == B_OK) { 396 // create a ShutdownProcess 397 fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue); 398 if (fShutdownProcess) { 399 error = fShutdownProcess->Init(request); 400 if (error == B_OK) { 401 DetachCurrentMessage(); 402 fShutdownProcess->Run(); 403 needsReply = false; 404 } else { 405 delete fShutdownProcess; 406 fShutdownProcess = NULL; 407 } 408 } else 409 error = B_NO_MEMORY; 410 } 411 412 if (needsReply) 413 ShutdownProcess::SendReply(request, error); 414 } 415 416 417 // #pragma mark - 418 419 420 /*! \brief Creates and runs the registrar application. 421 422 The main thread is renamed. 423 424 \return 0. 425 */ 426 int 427 main() 428 { 429 FUNCTION_START(); 430 431 // Create the global be_clipboard manually -- it will not work, since it 432 // wants to talk to the registrar in its constructor, but it doesn't have 433 // to and we would otherwise deadlock when initializing our GUI in the 434 // app thread. 435 be_clipboard = new BClipboard(NULL); 436 437 438 // create and run the registrar application 439 status_t error; 440 Registrar *app = new Registrar(&error); 441 if (error != B_OK) { 442 fprintf(stderr, "REG: Failed to create the BApplication: %s\n", 443 strerror(error)); 444 return 1; 445 } 446 447 // rename the main thread 448 rename_thread(find_thread(NULL), kRosterThreadName); 449 450 PRINT("app->Run()...\n"); 451 452 try { 453 app->Run(); 454 } catch (std::exception& exception) { 455 char buffer[1024]; 456 snprintf(buffer, sizeof(buffer), 457 "registrar main() caught exception: %s", exception.what()); 458 debugger(buffer); 459 } catch (...) { 460 debugger("registrar main() caught unknown exception"); 461 } 462 463 PRINT("delete app...\n"); 464 delete app; 465 466 FUNCTION_END(); 467 return 0; 468 } 469 470