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