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