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