/* * Copyright 2001-2015, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Ingo Weinhold, ingo_weinhold@gmx.de */ #include "Registrar.h" #include #include #include #include #include #include #include #include #include #include #include #include "AuthenticationManager.h" #include "ClipboardHandler.h" #include "Debug.h" #include "EventQueue.h" #include "MessageDeliverer.h" #include "MessageEvent.h" #include "MessageRunnerManager.h" #include "MessagingService.h" #include "MIMEManager.h" #include "PackageWatchingManager.h" #include "ShutdownProcess.h" #include "TRoster.h" /*! \class Registrar \brief The application class of the registrar. Glues the registrar services together and dispatches the roster messages. */ using std::nothrow; using namespace BPrivate; //! Name of the event queue. static const char *kEventQueueName = "timer_thread"; /*! \brief Creates the registrar application class. \param error Passed to the BApplication constructor for returning an error code. */ Registrar::Registrar(status_t* _error) : BServer(B_REGISTRAR_SIGNATURE, B_REGISTRAR_PORT_NAME, -1, false, _error), fRoster(NULL), fClipboardHandler(NULL), fMIMEManager(NULL), fEventQueue(NULL), fMessageRunnerManager(NULL), fShutdownProcess(NULL), fAuthenticationManager(NULL), fPackageWatchingManager(NULL) { FUNCTION_START(); set_thread_priority(find_thread(NULL), B_NORMAL_PRIORITY + 1); } /*! \brief Frees all resources associated with the registrar. All registrar services, that haven't been shut down earlier, are terminated. */ Registrar::~Registrar() { FUNCTION_START(); Lock(); fEventQueue->Die(); delete fAuthenticationManager; delete fPackageWatchingManager; delete fMessageRunnerManager; delete fEventQueue; fMIMEManager->Lock(); fMIMEManager->Quit(); RemoveHandler(fClipboardHandler); delete fClipboardHandler; delete fRoster; // Invalidate the global be_roster, so that the BApplication destructor // won't dead-lock when sending a message to itself. BRoster::Private().SetTo(BMessenger(), BMessenger()); FUNCTION_END(); } /*! \brief Overrides the super class version to dispatch roster specific messages. \param message The message to be handled */ void Registrar::MessageReceived(BMessage *message) { try { _MessageReceived(message); } catch (std::exception& exception) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "Registrar::MessageReceived() caught exception: %s", exception.what()); debugger(buffer); } catch (...) { debugger("Registrar::MessageReceived() caught unknown exception"); } } /*! \brief Overrides the super class version to initialize the registrar services. */ void Registrar::ReadyToRun() { FUNCTION_START(); // create message deliverer status_t error = MessageDeliverer::CreateDefault(); if (error != B_OK) { FATAL("Registrar::ReadyToRun(): Failed to create the message " "deliverer: %s\n", strerror(error)); } // create event queue fEventQueue = new EventQueue(kEventQueueName); // create authentication manager fAuthenticationManager = new AuthenticationManager; fAuthenticationManager->Init(); // create roster fRoster = new TRoster; fRoster->Init(); // create clipboard handler fClipboardHandler = new ClipboardHandler; AddHandler(fClipboardHandler); // create MIME manager fMIMEManager = new MIMEManager; fMIMEManager->Run(); // create message runner manager fMessageRunnerManager = new MessageRunnerManager(fEventQueue); // init the global be_roster BRoster::Private().SetTo(be_app_messenger, BMessenger(NULL, fMIMEManager)); // create the messaging service error = MessagingService::CreateDefault(); if (error != B_OK) { ERROR("Registrar::ReadyToRun(): Failed to init messaging service " "(that's by design when running under R5): %s\n", strerror(error)); } // create the package watching manager fPackageWatchingManager = new PackageWatchingManager; // Sanity check roster after team deletion BMessenger target(this); BMessenger::Private messengerPrivate(target); port_id port = messengerPrivate.Port(); int32 token = messengerPrivate.Token(); __start_watching_system(-1, B_WATCH_SYSTEM_TEAM_DELETION, port, token); fRoster->CheckSanity(); // Clean up any teams that exited before we started watching FUNCTION_END(); } /*! \brief Overrides the super class version to avoid termination of the registrar until the system shutdown. */ bool Registrar::QuitRequested() { FUNCTION_START(); // The final registrar must not quit. At least not that easily. ;-) return BApplication::QuitRequested(); } /*! \brief Returns the registrar's event queue. \return The registrar's event queue. */ EventQueue* Registrar::GetEventQueue() const { return fEventQueue; } /*! \brief Returns the Registrar application object. \return The Registrar application object. */ Registrar* Registrar::App() { return dynamic_cast(be_app); } void Registrar::_MessageReceived(BMessage *message) { switch (message->what) { // general requests case B_REG_GET_MIME_MESSENGER: { PRINT("B_REG_GET_MIME_MESSENGER\n"); BMessenger messenger(NULL, fMIMEManager); BMessage reply(B_REG_SUCCESS); reply.AddMessenger("messenger", messenger); message->SendReply(&reply); break; } case B_REG_GET_CLIPBOARD_MESSENGER: { PRINT("B_REG_GET_CLIPBOARD_MESSENGER\n"); BMessenger messenger(fClipboardHandler); BMessage reply(B_REG_SUCCESS); reply.AddMessenger("messenger", messenger); message->SendReply(&reply); break; } // shutdown process case B_REG_SHUT_DOWN: { PRINT("B_REG_SHUT_DOWN\n"); _HandleShutDown(message); break; } case B_REG_IS_SHUT_DOWN_IN_PROGRESS: { PRINT("B_REG_IS_SHUT_DOWN_IN_PROGRESS\n"); _HandleIsShutDownInProgress(message); break; } case B_REG_TEAM_DEBUGGER_ALERT: { if (fShutdownProcess != NULL) fShutdownProcess->PostMessage(message); break; } // roster requests case B_REG_ADD_APP: fRoster->HandleAddApplication(message); break; case B_REG_COMPLETE_REGISTRATION: fRoster->HandleCompleteRegistration(message); break; case B_REG_IS_APP_REGISTERED: fRoster->HandleIsAppRegistered(message); break; case B_REG_REMOVE_PRE_REGISTERED_APP: fRoster->HandleRemovePreRegApp(message); break; case B_REG_REMOVE_APP: fRoster->HandleRemoveApp(message); break; case B_REG_SET_THREAD_AND_TEAM: fRoster->HandleSetThreadAndTeam(message); break; case B_REG_SET_SIGNATURE: fRoster->HandleSetSignature(message); break; case B_REG_GET_APP_INFO: fRoster->HandleGetAppInfo(message); break; case B_REG_GET_APP_LIST: fRoster->HandleGetAppList(message); break; case B_REG_UPDATE_ACTIVE_APP: fRoster->HandleUpdateActiveApp(message); break; case B_REG_BROADCAST: fRoster->HandleBroadcast(message); break; case B_REG_START_WATCHING: fRoster->HandleStartWatching(message); break; case B_REG_STOP_WATCHING: fRoster->HandleStopWatching(message); break; case B_REG_GET_RECENT_DOCUMENTS: fRoster->HandleGetRecentDocuments(message); break; case B_REG_GET_RECENT_FOLDERS: fRoster->HandleGetRecentFolders(message); break; case B_REG_GET_RECENT_APPS: fRoster->HandleGetRecentApps(message); break; case B_REG_ADD_TO_RECENT_DOCUMENTS: fRoster->HandleAddToRecentDocuments(message); break; case B_REG_ADD_TO_RECENT_FOLDERS: fRoster->HandleAddToRecentFolders(message); break; case B_REG_ADD_TO_RECENT_APPS: fRoster->HandleAddToRecentApps(message); break; case B_REG_CLEAR_RECENT_DOCUMENTS: fRoster->ClearRecentDocuments(); break; case B_REG_CLEAR_RECENT_FOLDERS: fRoster->ClearRecentFolders(); break; case B_REG_CLEAR_RECENT_APPS: fRoster->ClearRecentApps(); break; case B_REG_LOAD_RECENT_LISTS: fRoster->HandleLoadRecentLists(message); break; case B_REG_SAVE_RECENT_LISTS: fRoster->HandleSaveRecentLists(message); break; // message runner requests case B_REG_REGISTER_MESSAGE_RUNNER: fMessageRunnerManager->HandleRegisterRunner(message); break; case B_REG_UNREGISTER_MESSAGE_RUNNER: fMessageRunnerManager->HandleUnregisterRunner(message); break; case B_REG_SET_MESSAGE_RUNNER_PARAMS: fMessageRunnerManager->HandleSetRunnerParams(message); break; case B_REG_GET_MESSAGE_RUNNER_INFO: fMessageRunnerManager->HandleGetRunnerInfo(message); break; // package watching requests case B_REG_PACKAGE_START_WATCHING: case B_REG_PACKAGE_STOP_WATCHING: fPackageWatchingManager->HandleStartStopWatching(message); break; case B_PACKAGE_UPDATE: fPackageWatchingManager->NotifyWatchers(message); break; // internal messages case B_SYSTEM_OBJECT_UPDATE: { team_id team = (team_id)message->GetInt32("team", -1); if (team >= 0 && message->GetInt32("opcode", 0) == B_TEAM_DELETED) fRoster->HandleRemoveApp(message); break; } case B_REG_SHUTDOWN_FINISHED: if (fShutdownProcess) { fShutdownProcess->PostMessage(B_QUIT_REQUESTED, fShutdownProcess); fShutdownProcess = NULL; } break; case kMsgRestartAppServer: { fRoster->HandleRestartAppServer(message); break; } default: BApplication::MessageReceived(message); break; } } /*! \brief Handle a shut down request message. \param request The request to be handled. */ void Registrar::_HandleShutDown(BMessage *request) { status_t error = B_OK; // check, whether we're already shutting down if (fShutdownProcess) error = B_SHUTTING_DOWN; bool needsReply = true; if (error == B_OK) { // create a ShutdownProcess fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue); if (fShutdownProcess) { error = fShutdownProcess->Init(request); if (error == B_OK) { DetachCurrentMessage(); fShutdownProcess->Run(); needsReply = false; } else { delete fShutdownProcess; fShutdownProcess = NULL; } } else error = B_NO_MEMORY; } if (needsReply) ShutdownProcess::SendReply(request, error); } /*! \brief Handle a is shut down in progress request message. \param request The request to be handled. */ void Registrar::_HandleIsShutDownInProgress(BMessage *request) { BMessage reply(B_REG_SUCCESS); reply.AddBool("in-progress", fShutdownProcess != NULL); request->SendReply(&reply); } // #pragma mark - /*! \brief Creates and runs the registrar application. The main thread is renamed. \return 0. */ int main() { FUNCTION_START(); // Create the global be_clipboard manually -- it will not work, since it // wants to talk to the registrar in its constructor, but it doesn't have // to and we would otherwise deadlock when initializing our GUI in the // app thread. be_clipboard = new BClipboard(NULL); // create and run the registrar application status_t error; Registrar *app = new Registrar(&error); if (error != B_OK) { fprintf(stderr, "REG: Failed to create the BApplication: %s\n", strerror(error)); return 1; } // rename the main thread rename_thread(find_thread(NULL), "roster"); PRINT("app->Run()...\n"); try { app->Run(); } catch (std::exception& exception) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "registrar main() caught exception: %s", exception.what()); debugger(buffer); } catch (...) { debugger("registrar main() caught unknown exception"); } PRINT("delete app...\n"); delete app; FUNCTION_END(); return 0; }