1/*
2 * Copyright 2001-2015, 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 <MessengerPrivate.h>
20#include <OS.h>
21#include <RegistrarDefs.h>
22#include <RosterPrivate.h>
23#include <system_info.h>
24
25#include "AuthenticationManager.h"
26#include "ClipboardHandler.h"
27#include "Debug.h"
28#include "EventQueue.h"
29#include "MessageDeliverer.h"
30#include "MessageEvent.h"
31#include "MessageRunnerManager.h"
32#include "MessagingService.h"
33#include "MIMEManager.h"
34#include "PackageWatchingManager.h"
35#include "ShutdownProcess.h"
36#include "TRoster.h"
37
38
39/*!
40	\class Registrar
41	\brief The application class of the registrar.
42
43	Glues the registrar services together and dispatches the roster messages.
44*/
45
46using std::nothrow;
47using namespace BPrivate;
48
49//! Name of the event queue.
50static const char *kEventQueueName = "timer_thread";
51
52
53/*!	\brief Creates the registrar application class.
54	\param error Passed to the BApplication constructor for returning an
55		   error code.
56*/
57Registrar::Registrar(status_t* _error)
58	:
59	BServer(B_REGISTRAR_SIGNATURE, B_REGISTRAR_PORT_NAME, -1, false, _error),
60	fRoster(NULL),
61	fClipboardHandler(NULL),
62	fMIMEManager(NULL),
63	fEventQueue(NULL),
64	fMessageRunnerManager(NULL),
65	fShutdownProcess(NULL),
66	fAuthenticationManager(NULL),
67	fPackageWatchingManager(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*/
80Registrar::~Registrar()
81{
82	FUNCTION_START();
83	Lock();
84	fEventQueue->Die();
85	delete fAuthenticationManager;
86	delete fPackageWatchingManager;
87	delete fMessageRunnerManager;
88	delete fEventQueue;
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*/
105void
106Registrar::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*/
125void
126Registrar::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 the package watching manager
170	fPackageWatchingManager = new PackageWatchingManager;
171
172	// Sanity check roster after team deletion
173	BMessenger target(this);
174	BMessenger::Private messengerPrivate(target);
175
176	port_id port = messengerPrivate.Port();
177	int32 token = messengerPrivate.Token();
178	__start_watching_system(-1, B_WATCH_SYSTEM_TEAM_DELETION, port, token);
179	fRoster->CheckSanity();
180		// Clean up any teams that exited before we started watching
181
182	FUNCTION_END();
183}
184
185
186/*!	\brief Overrides the super class version to avoid termination of the
187		   registrar until the system shutdown.
188*/
189bool
190Registrar::QuitRequested()
191{
192	FUNCTION_START();
193	// The final registrar must not quit. At least not that easily. ;-)
194	return BApplication::QuitRequested();
195}
196
197
198/*!	\brief Returns the registrar's event queue.
199	\return The registrar's event queue.
200*/
201EventQueue*
202Registrar::GetEventQueue() const
203{
204	return fEventQueue;
205}
206
207
208/*!	\brief Returns the Registrar application object.
209	\return The Registrar application object.
210*/
211Registrar*
212Registrar::App()
213{
214	return dynamic_cast<Registrar*>(be_app);
215}
216
217
218void
219Registrar::_MessageReceived(BMessage *message)
220{
221	switch (message->what) {
222		// general requests
223		case B_REG_GET_MIME_MESSENGER:
224		{
225			PRINT("B_REG_GET_MIME_MESSENGER\n");
226			BMessenger messenger(NULL, fMIMEManager);
227			BMessage reply(B_REG_SUCCESS);
228			reply.AddMessenger("messenger", messenger);
229			message->SendReply(&reply);
230			break;
231		}
232
233		case B_REG_GET_CLIPBOARD_MESSENGER:
234		{
235			PRINT("B_REG_GET_CLIPBOARD_MESSENGER\n");
236			BMessenger messenger(fClipboardHandler);
237			BMessage reply(B_REG_SUCCESS);
238			reply.AddMessenger("messenger", messenger);
239			message->SendReply(&reply);
240			break;
241		}
242
243		// shutdown process
244		case B_REG_SHUT_DOWN:
245		{
246			PRINT("B_REG_SHUT_DOWN\n");
247
248			_HandleShutDown(message);
249			break;
250		}
251		case B_REG_IS_SHUT_DOWN_IN_PROGRESS:
252		{
253			PRINT("B_REG_IS_SHUT_DOWN_IN_PROGRESS\n");
254
255			_HandleIsShutDownInProgress(message);
256			break;
257		}
258		case B_REG_TEAM_DEBUGGER_ALERT:
259		{
260			if (fShutdownProcess != NULL)
261				fShutdownProcess->PostMessage(message);
262			break;
263		}
264
265		// roster requests
266		case B_REG_ADD_APP:
267			fRoster->HandleAddApplication(message);
268			break;
269		case B_REG_COMPLETE_REGISTRATION:
270			fRoster->HandleCompleteRegistration(message);
271			break;
272		case B_REG_IS_APP_REGISTERED:
273			fRoster->HandleIsAppRegistered(message);
274			break;
275		case B_REG_REMOVE_PRE_REGISTERED_APP:
276			fRoster->HandleRemovePreRegApp(message);
277			break;
278		case B_REG_REMOVE_APP:
279			fRoster->HandleRemoveApp(message);
280			break;
281		case B_REG_SET_THREAD_AND_TEAM:
282			fRoster->HandleSetThreadAndTeam(message);
283			break;
284		case B_REG_SET_SIGNATURE:
285			fRoster->HandleSetSignature(message);
286			break;
287		case B_REG_GET_APP_INFO:
288			fRoster->HandleGetAppInfo(message);
289			break;
290		case B_REG_GET_APP_LIST:
291			fRoster->HandleGetAppList(message);
292			break;
293		case B_REG_UPDATE_ACTIVE_APP:
294			fRoster->HandleUpdateActiveApp(message);
295			break;
296		case B_REG_BROADCAST:
297			fRoster->HandleBroadcast(message);
298			break;
299		case B_REG_START_WATCHING:
300			fRoster->HandleStartWatching(message);
301			break;
302		case B_REG_STOP_WATCHING:
303			fRoster->HandleStopWatching(message);
304			break;
305		case B_REG_GET_RECENT_DOCUMENTS:
306			fRoster->HandleGetRecentDocuments(message);
307			break;
308		case B_REG_GET_RECENT_FOLDERS:
309			fRoster->HandleGetRecentFolders(message);
310			break;
311		case B_REG_GET_RECENT_APPS:
312			fRoster->HandleGetRecentApps(message);
313			break;
314		case B_REG_ADD_TO_RECENT_DOCUMENTS:
315			fRoster->HandleAddToRecentDocuments(message);
316			break;
317		case B_REG_ADD_TO_RECENT_FOLDERS:
318			fRoster->HandleAddToRecentFolders(message);
319			break;
320		case B_REG_ADD_TO_RECENT_APPS:
321			fRoster->HandleAddToRecentApps(message);
322			break;
323		case B_REG_CLEAR_RECENT_DOCUMENTS:
324			fRoster->ClearRecentDocuments();
325			break;
326		case B_REG_CLEAR_RECENT_FOLDERS:
327			fRoster->ClearRecentFolders();
328			break;
329		case B_REG_CLEAR_RECENT_APPS:
330			fRoster->ClearRecentApps();
331			break;
332		case B_REG_LOAD_RECENT_LISTS:
333			fRoster->HandleLoadRecentLists(message);
334			break;
335		case B_REG_SAVE_RECENT_LISTS:
336			fRoster->HandleSaveRecentLists(message);
337			break;
338
339		// message runner requests
340		case B_REG_REGISTER_MESSAGE_RUNNER:
341			fMessageRunnerManager->HandleRegisterRunner(message);
342			break;
343		case B_REG_UNREGISTER_MESSAGE_RUNNER:
344			fMessageRunnerManager->HandleUnregisterRunner(message);
345			break;
346		case B_REG_SET_MESSAGE_RUNNER_PARAMS:
347			fMessageRunnerManager->HandleSetRunnerParams(message);
348			break;
349		case B_REG_GET_MESSAGE_RUNNER_INFO:
350			fMessageRunnerManager->HandleGetRunnerInfo(message);
351			break;
352
353		// package watching requests
354		case B_REG_PACKAGE_START_WATCHING:
355		case B_REG_PACKAGE_STOP_WATCHING:
356			fPackageWatchingManager->HandleStartStopWatching(message);
357			break;
358		case B_PACKAGE_UPDATE:
359			fPackageWatchingManager->NotifyWatchers(message);
360			break;
361
362		// internal messages
363		case B_SYSTEM_OBJECT_UPDATE:
364		{
365			team_id team = (team_id)message->GetInt32("team", -1);
366			if (team >= 0 && message->GetInt32("opcode", 0) == B_TEAM_DELETED)
367				fRoster->HandleRemoveApp(message);
368			break;
369		}
370		case B_REG_SHUTDOWN_FINISHED:
371			if (fShutdownProcess) {
372				fShutdownProcess->PostMessage(B_QUIT_REQUESTED,
373					fShutdownProcess);
374				fShutdownProcess = NULL;
375			}
376			break;
377
378		case kMsgRestartAppServer:
379		{
380			fRoster->HandleRestartAppServer(message);
381			break;
382		}
383
384		default:
385			BApplication::MessageReceived(message);
386			break;
387	}
388}
389
390
391/*!	\brief Handle a shut down request message.
392	\param request The request to be handled.
393*/
394void
395Registrar::_HandleShutDown(BMessage *request)
396{
397	status_t error = B_OK;
398
399	// check, whether we're already shutting down
400	if (fShutdownProcess)
401		error = B_SHUTTING_DOWN;
402
403	bool needsReply = true;
404	if (error == B_OK) {
405		// create a ShutdownProcess
406		fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue);
407		if (fShutdownProcess) {
408			error = fShutdownProcess->Init(request);
409			if (error == B_OK) {
410				DetachCurrentMessage();
411				fShutdownProcess->Run();
412				needsReply = false;
413			} else {
414				delete fShutdownProcess;
415				fShutdownProcess = NULL;
416			}
417		} else
418			error = B_NO_MEMORY;
419	}
420
421	if (needsReply)
422		ShutdownProcess::SendReply(request, error);
423}
424
425
426/*!	\brief Handle a is shut down in progress request message.
427	\param request The request to be handled.
428*/
429void
430Registrar::_HandleIsShutDownInProgress(BMessage *request)
431{
432	BMessage reply(B_REG_SUCCESS);
433	reply.AddBool("in-progress", fShutdownProcess != NULL);
434	request->SendReply(&reply);
435}
436
437
438//	#pragma mark -
439
440
441/*!	\brief Creates and runs the registrar application.
442
443	The main thread is renamed.
444
445	\return 0.
446*/
447int
448main()
449{
450	FUNCTION_START();
451
452	// Create the global be_clipboard manually -- it will not work, since it
453	// wants to talk to the registrar in its constructor, but it doesn't have
454	// to and we would otherwise deadlock when initializing our GUI in the
455	// app thread.
456	be_clipboard = new BClipboard(NULL);
457
458	// create and run the registrar application
459	status_t error;
460	Registrar *app = new Registrar(&error);
461	if (error != B_OK) {
462		fprintf(stderr, "REG: Failed to create the BApplication: %s\n",
463			strerror(error));
464		return 1;
465	}
466
467	// rename the main thread
468	rename_thread(find_thread(NULL), "roster");
469
470	PRINT("app->Run()...\n");
471
472	try {
473		app->Run();
474	} catch (std::exception& exception) {
475		char buffer[1024];
476		snprintf(buffer, sizeof(buffer),
477			"registrar main() caught exception: %s", exception.what());
478		debugger(buffer);
479	} catch (...) {
480		debugger("registrar��main() caught unknown exception");
481	}
482
483	PRINT("delete app...\n");
484	delete app;
485
486	FUNCTION_END();
487	return 0;
488}
489
490