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