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