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