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 case B_REG_SHUT_DOWN: 226 { 227 PRINT(("B_REG_SHUT_DOWN\n")); 228 229 _HandleShutDown(message); 230 break; 231 } 232 233 // roster requests 234 case B_REG_ADD_APP: 235 fRoster->HandleAddApplication(message); 236 break; 237 case B_REG_COMPLETE_REGISTRATION: 238 fRoster->HandleCompleteRegistration(message); 239 break; 240 case B_REG_IS_APP_REGISTERED: 241 fRoster->HandleIsAppRegistered(message); 242 break; 243 case B_REG_REMOVE_PRE_REGISTERED_APP: 244 fRoster->HandleRemovePreRegApp(message); 245 break; 246 case B_REG_REMOVE_APP: 247 fRoster->HandleRemoveApp(message); 248 break; 249 case B_REG_SET_THREAD_AND_TEAM: 250 fRoster->HandleSetThreadAndTeam(message); 251 break; 252 case B_REG_SET_SIGNATURE: 253 fRoster->HandleSetSignature(message); 254 break; 255 case B_REG_GET_APP_INFO: 256 fRoster->HandleGetAppInfo(message); 257 break; 258 case B_REG_GET_APP_LIST: 259 fRoster->HandleGetAppList(message); 260 break; 261 case B_REG_UPDATE_ACTIVE_APP: 262 fRoster->HandleUpdateActiveApp(message); 263 break; 264 case B_REG_BROADCAST: 265 fRoster->HandleBroadcast(message); 266 break; 267 case B_REG_START_WATCHING: 268 fRoster->HandleStartWatching(message); 269 break; 270 case B_REG_STOP_WATCHING: 271 fRoster->HandleStopWatching(message); 272 break; 273 case B_REG_GET_RECENT_DOCUMENTS: 274 fRoster->HandleGetRecentDocuments(message); 275 break; 276 case B_REG_GET_RECENT_FOLDERS: 277 fRoster->HandleGetRecentFolders(message); 278 break; 279 case B_REG_GET_RECENT_APPS: 280 fRoster->HandleGetRecentApps(message); 281 break; 282 case B_REG_ADD_TO_RECENT_DOCUMENTS: 283 fRoster->HandleAddToRecentDocuments(message); 284 break; 285 case B_REG_ADD_TO_RECENT_FOLDERS: 286 fRoster->HandleAddToRecentFolders(message); 287 break; 288 case B_REG_ADD_TO_RECENT_APPS: 289 fRoster->HandleAddToRecentApps(message); 290 break; 291 case B_REG_CLEAR_RECENT_DOCUMENTS: 292 fRoster->ClearRecentDocuments(); 293 break; 294 case B_REG_CLEAR_RECENT_FOLDERS: 295 fRoster->ClearRecentFolders(); 296 break; 297 case B_REG_CLEAR_RECENT_APPS: 298 fRoster->ClearRecentApps(); 299 break; 300 case B_REG_LOAD_RECENT_LISTS: 301 fRoster->HandleLoadRecentLists(message); 302 break; 303 case B_REG_SAVE_RECENT_LISTS: 304 fRoster->HandleSaveRecentLists(message); 305 break; 306 307 // message runner requests 308 case B_REG_REGISTER_MESSAGE_RUNNER: 309 fMessageRunnerManager->HandleRegisterRunner(message); 310 break; 311 case B_REG_UNREGISTER_MESSAGE_RUNNER: 312 fMessageRunnerManager->HandleUnregisterRunner(message); 313 break; 314 case B_REG_SET_MESSAGE_RUNNER_PARAMS: 315 fMessageRunnerManager->HandleSetRunnerParams(message); 316 break; 317 case B_REG_GET_MESSAGE_RUNNER_INFO: 318 fMessageRunnerManager->HandleGetRunnerInfo(message); 319 break; 320 321 // internal messages 322 case B_REG_ROSTER_SANITY_EVENT: 323 fRoster->CheckSanity(); 324 fSanityEvent->SetTime(system_time() + kRosterSanityEventInterval); 325 fEventQueue->AddEvent(fSanityEvent); 326 break; 327 case B_REG_SHUTDOWN_FINISHED: 328 if (fShutdownProcess) { 329 fShutdownProcess->PostMessage(B_QUIT_REQUESTED, 330 fShutdownProcess); 331 fShutdownProcess = NULL; 332 } 333 break; 334 335 default: 336 BApplication::MessageReceived(message); 337 break; 338 } 339 } 340 341 // _HandleShutDown 342 /*! \brief Handle a shut down request message. 343 \param request The request to be handled. 344 */ 345 void 346 Registrar::_HandleShutDown(BMessage *request) 347 { 348 status_t error = B_OK; 349 350 // check, whether we're already shutting down 351 if (fShutdownProcess) 352 error = B_SHUTTING_DOWN; 353 354 bool needsReply = true; 355 if (error == B_OK) { 356 // create a ShutdownProcess 357 fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue); 358 if (fShutdownProcess) { 359 error = fShutdownProcess->Init(request); 360 if (error == B_OK) { 361 DetachCurrentMessage(); 362 fShutdownProcess->Run(); 363 needsReply = false; 364 } else { 365 delete fShutdownProcess; 366 fShutdownProcess = NULL; 367 } 368 } else 369 error = B_NO_MEMORY; 370 } 371 372 if (needsReply) 373 ShutdownProcess::SendReply(request, error); 374 } 375 376 377 // #pragma mark - 378 379 380 /*! \brief Creates and runs the registrar application. 381 382 The main thread is renamed. 383 384 \return 0. 385 */ 386 int 387 main() 388 { 389 FUNCTION_START(); 390 391 // create and run the registrar application 392 status_t error; 393 Registrar *app = new Registrar(&error); 394 if (error != B_OK) { 395 fprintf(stderr, "REG: Failed to create the BApplication: %s\n", 396 strerror(error)); 397 return 1; 398 } 399 400 // rename the main thread 401 rename_thread(find_thread(NULL), kRosterThreadName); 402 403 PRINT(("app->Run()...\n")); 404 405 try { 406 app->Run(); 407 } catch (std::exception& exception) { 408 char buffer[1024]; 409 snprintf(buffer, sizeof(buffer), 410 "registrar main() caught exception: %s", exception.what()); 411 debugger(buffer); 412 } catch (...) { 413 debugger("registrar main() caught unknown exception"); 414 } 415 416 PRINT(("delete app...\n")); 417 delete app; 418 419 FUNCTION_END(); 420 return 0; 421 } 422 423