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