1 /* 2 * Copyright 2001-2009, 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 "ShutdownProcess.h" 33 #include "TRoster.h" 34 35 36 /*! 37 \class Registrar 38 \brief The application class of the registrar. 39 40 Glues the registrar services together and dispatches the roster messages. 41 */ 42 43 using std::nothrow; 44 using namespace BPrivate; 45 46 //! Name of the event queue. 47 static const char *kEventQueueName = "timer_thread"; 48 49 //! Time interval between two roster sanity checks (1 s). 50 static const bigtime_t kRosterSanityEventInterval = 1000000LL; 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(kRegistrarSignature, false, error), 60 fRoster(NULL), 61 fClipboardHandler(NULL), 62 fMIMEManager(NULL), 63 fEventQueue(NULL), 64 fMessageRunnerManager(NULL), 65 fSanityEvent(NULL), 66 fShutdownProcess(NULL), 67 fAuthenticationManager(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 fMessageRunnerManager; 87 delete fEventQueue; 88 delete fSanityEvent; 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 and schedule the sanity message event 170 fSanityEvent = new MessageEvent(system_time() + kRosterSanityEventInterval, 171 this, B_REG_ROSTER_SANITY_EVENT); 172 fSanityEvent->SetAutoDelete(false); 173 fEventQueue->AddEvent(fSanityEvent); 174 175 FUNCTION_END(); 176 } 177 178 179 /*! \brief Overrides the super class version to avoid termination of the 180 registrar until the system shutdown. 181 */ 182 bool 183 Registrar::QuitRequested() 184 { 185 FUNCTION_START(); 186 // The final registrar must not quit. At least not that easily. ;-) 187 return BApplication::QuitRequested(); 188 } 189 190 191 /*! \brief Returns the registrar's event queue. 192 \return The registrar's event queue. 193 */ 194 EventQueue* 195 Registrar::GetEventQueue() const 196 { 197 return fEventQueue; 198 } 199 200 201 /*! \brief Returns the Registrar application object. 202 \return The Registrar application object. 203 */ 204 Registrar* 205 Registrar::App() 206 { 207 return dynamic_cast<Registrar*>(be_app); 208 } 209 210 211 void 212 Registrar::_MessageReceived(BMessage *message) 213 { 214 switch (message->what) { 215 // general requests 216 case B_REG_GET_MIME_MESSENGER: 217 { 218 PRINT(("B_REG_GET_MIME_MESSENGER\n")); 219 BMessenger messenger(NULL, fMIMEManager); 220 BMessage reply(B_REG_SUCCESS); 221 reply.AddMessenger("messenger", messenger); 222 message->SendReply(&reply); 223 break; 224 } 225 226 case B_REG_GET_CLIPBOARD_MESSENGER: 227 { 228 PRINT(("B_REG_GET_CLIPBOARD_MESSENGER\n")); 229 BMessenger messenger(fClipboardHandler); 230 BMessage reply(B_REG_SUCCESS); 231 reply.AddMessenger("messenger", messenger); 232 message->SendReply(&reply); 233 break; 234 } 235 236 // shutdown process 237 case B_REG_SHUT_DOWN: 238 { 239 PRINT(("B_REG_SHUT_DOWN\n")); 240 241 _HandleShutDown(message); 242 break; 243 } 244 case B_REG_TEAM_DEBUGGER_ALERT: 245 { 246 if (fShutdownProcess != NULL) 247 fShutdownProcess->PostMessage(message); 248 break; 249 } 250 251 // roster requests 252 case B_REG_ADD_APP: 253 fRoster->HandleAddApplication(message); 254 break; 255 case B_REG_COMPLETE_REGISTRATION: 256 fRoster->HandleCompleteRegistration(message); 257 break; 258 case B_REG_IS_APP_REGISTERED: 259 fRoster->HandleIsAppRegistered(message); 260 break; 261 case B_REG_REMOVE_PRE_REGISTERED_APP: 262 fRoster->HandleRemovePreRegApp(message); 263 break; 264 case B_REG_REMOVE_APP: 265 fRoster->HandleRemoveApp(message); 266 break; 267 case B_REG_SET_THREAD_AND_TEAM: 268 fRoster->HandleSetThreadAndTeam(message); 269 break; 270 case B_REG_SET_SIGNATURE: 271 fRoster->HandleSetSignature(message); 272 break; 273 case B_REG_GET_APP_INFO: 274 fRoster->HandleGetAppInfo(message); 275 break; 276 case B_REG_GET_APP_LIST: 277 fRoster->HandleGetAppList(message); 278 break; 279 case B_REG_UPDATE_ACTIVE_APP: 280 fRoster->HandleUpdateActiveApp(message); 281 break; 282 case B_REG_BROADCAST: 283 fRoster->HandleBroadcast(message); 284 break; 285 case B_REG_START_WATCHING: 286 fRoster->HandleStartWatching(message); 287 break; 288 case B_REG_STOP_WATCHING: 289 fRoster->HandleStopWatching(message); 290 break; 291 case B_REG_GET_RECENT_DOCUMENTS: 292 fRoster->HandleGetRecentDocuments(message); 293 break; 294 case B_REG_GET_RECENT_FOLDERS: 295 fRoster->HandleGetRecentFolders(message); 296 break; 297 case B_REG_GET_RECENT_APPS: 298 fRoster->HandleGetRecentApps(message); 299 break; 300 case B_REG_ADD_TO_RECENT_DOCUMENTS: 301 fRoster->HandleAddToRecentDocuments(message); 302 break; 303 case B_REG_ADD_TO_RECENT_FOLDERS: 304 fRoster->HandleAddToRecentFolders(message); 305 break; 306 case B_REG_ADD_TO_RECENT_APPS: 307 fRoster->HandleAddToRecentApps(message); 308 break; 309 case B_REG_CLEAR_RECENT_DOCUMENTS: 310 fRoster->ClearRecentDocuments(); 311 break; 312 case B_REG_CLEAR_RECENT_FOLDERS: 313 fRoster->ClearRecentFolders(); 314 break; 315 case B_REG_CLEAR_RECENT_APPS: 316 fRoster->ClearRecentApps(); 317 break; 318 case B_REG_LOAD_RECENT_LISTS: 319 fRoster->HandleLoadRecentLists(message); 320 break; 321 case B_REG_SAVE_RECENT_LISTS: 322 fRoster->HandleSaveRecentLists(message); 323 break; 324 325 // message runner requests 326 case B_REG_REGISTER_MESSAGE_RUNNER: 327 fMessageRunnerManager->HandleRegisterRunner(message); 328 break; 329 case B_REG_UNREGISTER_MESSAGE_RUNNER: 330 fMessageRunnerManager->HandleUnregisterRunner(message); 331 break; 332 case B_REG_SET_MESSAGE_RUNNER_PARAMS: 333 fMessageRunnerManager->HandleSetRunnerParams(message); 334 break; 335 case B_REG_GET_MESSAGE_RUNNER_INFO: 336 fMessageRunnerManager->HandleGetRunnerInfo(message); 337 break; 338 339 // internal messages 340 case B_REG_ROSTER_SANITY_EVENT: 341 fRoster->CheckSanity(); 342 fSanityEvent->SetTime(system_time() + kRosterSanityEventInterval); 343 fEventQueue->AddEvent(fSanityEvent); 344 break; 345 case B_REG_SHUTDOWN_FINISHED: 346 if (fShutdownProcess) { 347 fShutdownProcess->PostMessage(B_QUIT_REQUESTED, 348 fShutdownProcess); 349 fShutdownProcess = NULL; 350 } 351 break; 352 353 default: 354 BApplication::MessageReceived(message); 355 break; 356 } 357 } 358 359 360 /*! \brief Handle a shut down request message. 361 \param request The request to be handled. 362 */ 363 void 364 Registrar::_HandleShutDown(BMessage *request) 365 { 366 status_t error = B_OK; 367 368 // check, whether we're already shutting down 369 if (fShutdownProcess) 370 error = B_SHUTTING_DOWN; 371 372 bool needsReply = true; 373 if (error == B_OK) { 374 // create a ShutdownProcess 375 fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue); 376 if (fShutdownProcess) { 377 error = fShutdownProcess->Init(request); 378 if (error == B_OK) { 379 DetachCurrentMessage(); 380 fShutdownProcess->Run(); 381 needsReply = false; 382 } else { 383 delete fShutdownProcess; 384 fShutdownProcess = NULL; 385 } 386 } else 387 error = B_NO_MEMORY; 388 } 389 390 if (needsReply) 391 ShutdownProcess::SendReply(request, error); 392 } 393 394 395 // #pragma mark - 396 397 398 /*! \brief Creates and runs the registrar application. 399 400 The main thread is renamed. 401 402 \return 0. 403 */ 404 int 405 main() 406 { 407 FUNCTION_START(); 408 409 // Create the global be_clipboard manually -- it will not work, since it 410 // wants to talk to the registrar in its constructor, but it doesn't have 411 // to and we would otherwise deadlock when initializing our GUI in the 412 // app thread. 413 be_clipboard = new BClipboard(NULL); 414 415 416 // create and run the registrar application 417 status_t error; 418 Registrar *app = new Registrar(&error); 419 if (error != B_OK) { 420 fprintf(stderr, "REG: Failed to create the BApplication: %s\n", 421 strerror(error)); 422 return 1; 423 } 424 425 // rename the main thread 426 rename_thread(find_thread(NULL), kRosterThreadName); 427 428 PRINT(("app->Run()...\n")); 429 430 try { 431 app->Run(); 432 } catch (std::exception& exception) { 433 char buffer[1024]; 434 snprintf(buffer, sizeof(buffer), 435 "registrar main() caught exception: %s", exception.what()); 436 debugger(buffer); 437 } catch (...) { 438 debugger("registrar main() caught unknown exception"); 439 } 440 441 PRINT(("delete app...\n")); 442 delete app; 443 444 FUNCTION_END(); 445 return 0; 446 } 447 448