xref: /haiku/src/servers/registrar/Registrar.cpp (revision 19ae20e67e91fc09cc9fc5c0e60e21e24e7a53eb)
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 
43 using std::nothrow;
44 using namespace BPrivate;
45 
46 //! Name of the event queue.
47 static const char *kEventQueueName = "timer_thread";
48 
49 //! Time interval between two roster sanity checks (1 s).
50 static 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 */
57 Registrar::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 */
80 Registrar::~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 */
105 void
106 Registrar::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 */
125 void
126 Registrar::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 */
182 bool
183 Registrar::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 */
194 EventQueue*
195 Registrar::GetEventQueue() const
196 {
197 	return fEventQueue;
198 }
199 
200 
201 /*!	\brief Returns the Registrar application object.
202 	\return The Registrar application object.
203 */
204 Registrar*
205 Registrar::App()
206 {
207 	return dynamic_cast<Registrar*>(be_app);
208 }
209 
210 
211 void
212 Registrar::_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 		default:
354 			BApplication::MessageReceived(message);
355 			break;
356 	}
357 }
358 
359 
360 /*!	\brief Handle a shut down request message.
361 	\param request The request to be handled.
362 */
363 void
364 Registrar::_HandleShutDown(BMessage *request)
365 {
366 	status_t error = B_OK;
367 
368 	// check, whether we're already shutting down
369 	if (fShutdownProcess)
370 		error = B_SHUTTING_DOWN;
371 
372 	bool needsReply = true;
373 	if (error == B_OK) {
374 		// create a ShutdownProcess
375 		fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue);
376 		if (fShutdownProcess) {
377 			error = fShutdownProcess->Init(request);
378 			if (error == B_OK) {
379 				DetachCurrentMessage();
380 				fShutdownProcess->Run();
381 				needsReply = false;
382 			} else {
383 				delete fShutdownProcess;
384 				fShutdownProcess = NULL;
385 			}
386 		} else
387 			error = B_NO_MEMORY;
388 	}
389 
390 	if (needsReply)
391 		ShutdownProcess::SendReply(request, error);
392 }
393 
394 
395 //	#pragma mark -
396 
397 
398 /*!	\brief Creates and runs the registrar application.
399 
400 	The main thread is renamed.
401 
402 	\return 0.
403 */
404 int
405 main()
406 {
407 	FUNCTION_START();
408 
409 	// Create the global be_clipboard manually -- it will not work, since it
410 	// wants to talk to the registrar in its constructor, but it doesn't have
411 	// to and we would otherwise deadlock when initializing our GUI in the
412 	// app thread.
413 	be_clipboard = new BClipboard(NULL);
414 
415 
416 	// create and run the registrar application
417 	status_t error;
418 	Registrar *app = new Registrar(&error);
419 	if (error != B_OK) {
420 		fprintf(stderr, "REG: Failed to create the BApplication: %s\n",
421 			strerror(error));
422 		return 1;
423 	}
424 
425 	// rename the main thread
426 	rename_thread(find_thread(NULL), kRosterThreadName);
427 
428 	PRINT("app->Run()...\n");
429 
430 	try {
431 		app->Run();
432 	} catch (std::exception& exception) {
433 		char buffer[1024];
434 		snprintf(buffer, sizeof(buffer),
435 			"registrar main() caught exception: %s", exception.what());
436 		debugger(buffer);
437 	} catch (...) {
438 		debugger("registrar main() caught unknown exception");
439 	}
440 
441 	PRINT("delete app...\n");
442 	delete app;
443 
444 	FUNCTION_END();
445 	return 0;
446 }
447 
448