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 <MessengerPrivate.h>
20 #include <OS.h>
21 #include <RegistrarDefs.h>
22 #include <RosterPrivate.h>
23 #include <system_info.h>
24
25 #include "AuthenticationManager.h"
26 #include "ClipboardHandler.h"
27 #include "Debug.h"
28 #include "EventQueue.h"
29 #include "MessageDeliverer.h"
30 #include "MessageEvent.h"
31 #include "MessageRunnerManager.h"
32 #include "MessagingService.h"
33 #include "MIMEManager.h"
34 #include "PackageWatchingManager.h"
35 #include "ShutdownProcess.h"
36 #include "TRoster.h"
37
38
39 /*!
40 \class Registrar
41 \brief The application class of the registrar.
42
43 Glues the registrar services together and dispatches the roster messages.
44 */
45
46 using std::nothrow;
47 using namespace BPrivate;
48
49 //! Name of the event queue.
50 static const char *kEventQueueName = "timer_thread";
51
52
53 /*! \brief Creates the registrar application class.
54 \param error Passed to the BApplication constructor for returning an
55 error code.
56 */
Registrar(status_t * _error)57 Registrar::Registrar(status_t* _error)
58 :
59 BServer(B_REGISTRAR_SIGNATURE, B_REGISTRAR_PORT_NAME, -1, false, _error),
60 fRoster(NULL),
61 fClipboardHandler(NULL),
62 fMIMEManager(NULL),
63 fEventQueue(NULL),
64 fMessageRunnerManager(NULL),
65 fShutdownProcess(NULL),
66 fAuthenticationManager(NULL),
67 fPackageWatchingManager(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 */
~Registrar()80 Registrar::~Registrar()
81 {
82 FUNCTION_START();
83 Lock();
84 fEventQueue->Die();
85 delete fAuthenticationManager;
86 delete fPackageWatchingManager;
87 delete fMessageRunnerManager;
88 delete fEventQueue;
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
MessageReceived(BMessage * message)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
ReadyToRun()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 the package watching manager
170 fPackageWatchingManager = new PackageWatchingManager;
171
172 // Sanity check roster after team deletion
173 BMessenger target(this);
174 BMessenger::Private messengerPrivate(target);
175
176 port_id port = messengerPrivate.Port();
177 int32 token = messengerPrivate.Token();
178 __start_watching_system(-1, B_WATCH_SYSTEM_TEAM_DELETION, port, token);
179 fRoster->CheckSanity();
180 // Clean up any teams that exited before we started watching
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
QuitRequested()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*
GetEventQueue() const202 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*
App()212 Registrar::App()
213 {
214 return dynamic_cast<Registrar*>(be_app);
215 }
216
217
218 void
_MessageReceived(BMessage * message)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_IS_SHUT_DOWN_IN_PROGRESS:
252 {
253 PRINT("B_REG_IS_SHUT_DOWN_IN_PROGRESS\n");
254
255 _HandleIsShutDownInProgress(message);
256 break;
257 }
258 case B_REG_TEAM_DEBUGGER_ALERT:
259 {
260 if (fShutdownProcess != NULL)
261 fShutdownProcess->PostMessage(message);
262 break;
263 }
264
265 // roster requests
266 case B_REG_ADD_APP:
267 fRoster->HandleAddApplication(message);
268 break;
269 case B_REG_COMPLETE_REGISTRATION:
270 fRoster->HandleCompleteRegistration(message);
271 break;
272 case B_REG_IS_APP_REGISTERED:
273 fRoster->HandleIsAppRegistered(message);
274 break;
275 case B_REG_REMOVE_PRE_REGISTERED_APP:
276 fRoster->HandleRemovePreRegApp(message);
277 break;
278 case B_REG_REMOVE_APP:
279 fRoster->HandleRemoveApp(message);
280 break;
281 case B_REG_SET_THREAD_AND_TEAM:
282 fRoster->HandleSetThreadAndTeam(message);
283 break;
284 case B_REG_SET_SIGNATURE:
285 fRoster->HandleSetSignature(message);
286 break;
287 case B_REG_GET_APP_INFO:
288 fRoster->HandleGetAppInfo(message);
289 break;
290 case B_REG_GET_APP_LIST:
291 fRoster->HandleGetAppList(message);
292 break;
293 case B_REG_UPDATE_ACTIVE_APP:
294 fRoster->HandleUpdateActiveApp(message);
295 break;
296 case B_REG_BROADCAST:
297 fRoster->HandleBroadcast(message);
298 break;
299 case B_REG_START_WATCHING:
300 fRoster->HandleStartWatching(message);
301 break;
302 case B_REG_STOP_WATCHING:
303 fRoster->HandleStopWatching(message);
304 break;
305 case B_REG_GET_RECENT_DOCUMENTS:
306 fRoster->HandleGetRecentDocuments(message);
307 break;
308 case B_REG_GET_RECENT_FOLDERS:
309 fRoster->HandleGetRecentFolders(message);
310 break;
311 case B_REG_GET_RECENT_APPS:
312 fRoster->HandleGetRecentApps(message);
313 break;
314 case B_REG_ADD_TO_RECENT_DOCUMENTS:
315 fRoster->HandleAddToRecentDocuments(message);
316 break;
317 case B_REG_ADD_TO_RECENT_FOLDERS:
318 fRoster->HandleAddToRecentFolders(message);
319 break;
320 case B_REG_ADD_TO_RECENT_APPS:
321 fRoster->HandleAddToRecentApps(message);
322 break;
323 case B_REG_CLEAR_RECENT_DOCUMENTS:
324 fRoster->ClearRecentDocuments();
325 break;
326 case B_REG_CLEAR_RECENT_FOLDERS:
327 fRoster->ClearRecentFolders();
328 break;
329 case B_REG_CLEAR_RECENT_APPS:
330 fRoster->ClearRecentApps();
331 break;
332 case B_REG_LOAD_RECENT_LISTS:
333 fRoster->HandleLoadRecentLists(message);
334 break;
335 case B_REG_SAVE_RECENT_LISTS:
336 fRoster->HandleSaveRecentLists(message);
337 break;
338
339 // message runner requests
340 case B_REG_REGISTER_MESSAGE_RUNNER:
341 fMessageRunnerManager->HandleRegisterRunner(message);
342 break;
343 case B_REG_UNREGISTER_MESSAGE_RUNNER:
344 fMessageRunnerManager->HandleUnregisterRunner(message);
345 break;
346 case B_REG_SET_MESSAGE_RUNNER_PARAMS:
347 fMessageRunnerManager->HandleSetRunnerParams(message);
348 break;
349 case B_REG_GET_MESSAGE_RUNNER_INFO:
350 fMessageRunnerManager->HandleGetRunnerInfo(message);
351 break;
352
353 // package watching requests
354 case B_REG_PACKAGE_START_WATCHING:
355 case B_REG_PACKAGE_STOP_WATCHING:
356 fPackageWatchingManager->HandleStartStopWatching(message);
357 break;
358 case B_PACKAGE_UPDATE:
359 fPackageWatchingManager->NotifyWatchers(message);
360 break;
361
362 // internal messages
363 case B_SYSTEM_OBJECT_UPDATE:
364 {
365 team_id team = (team_id)message->GetInt32("team", -1);
366 if (team >= 0 && message->GetInt32("opcode", 0) == B_TEAM_DELETED)
367 fRoster->HandleRemoveApp(message);
368 break;
369 }
370 case B_REG_SHUTDOWN_FINISHED:
371 if (fShutdownProcess) {
372 fShutdownProcess->PostMessage(B_QUIT_REQUESTED,
373 fShutdownProcess);
374 fShutdownProcess = NULL;
375 }
376 break;
377
378 case kMsgRestartAppServer:
379 {
380 fRoster->HandleRestartAppServer(message);
381 break;
382 }
383
384 default:
385 BApplication::MessageReceived(message);
386 break;
387 }
388 }
389
390
391 /*! \brief Handle a shut down request message.
392 \param request The request to be handled.
393 */
394 void
_HandleShutDown(BMessage * request)395 Registrar::_HandleShutDown(BMessage *request)
396 {
397 status_t error = B_OK;
398
399 // check, whether we're already shutting down
400 if (fShutdownProcess)
401 error = B_SHUTTING_DOWN;
402
403 bool needsReply = true;
404 if (error == B_OK) {
405 // create a ShutdownProcess
406 fShutdownProcess = new(nothrow) ShutdownProcess(fRoster, fEventQueue);
407 if (fShutdownProcess) {
408 error = fShutdownProcess->Init(request);
409 if (error == B_OK) {
410 DetachCurrentMessage();
411 fShutdownProcess->Run();
412 needsReply = false;
413 } else {
414 delete fShutdownProcess;
415 fShutdownProcess = NULL;
416 }
417 } else
418 error = B_NO_MEMORY;
419 }
420
421 if (needsReply)
422 ShutdownProcess::SendReply(request, error);
423 }
424
425
426 /*! \brief Handle a is shut down in progress request message.
427 \param request The request to be handled.
428 */
429 void
_HandleIsShutDownInProgress(BMessage * request)430 Registrar::_HandleIsShutDownInProgress(BMessage *request)
431 {
432 BMessage reply(B_REG_SUCCESS);
433 reply.AddBool("in-progress", fShutdownProcess != NULL);
434 request->SendReply(&reply);
435 }
436
437
438 // #pragma mark -
439
440
441 /*! \brief Creates and runs the registrar application.
442
443 The main thread is renamed.
444
445 \return 0.
446 */
447 int
main()448 main()
449 {
450 FUNCTION_START();
451
452 // Create the global be_clipboard manually -- it will not work, since it
453 // wants to talk to the registrar in its constructor, but it doesn't have
454 // to and we would otherwise deadlock when initializing our GUI in the
455 // app thread.
456 be_clipboard = new BClipboard(NULL);
457
458 // create and run the registrar application
459 status_t error;
460 Registrar *app = new Registrar(&error);
461 if (error != B_OK) {
462 fprintf(stderr, "REG: Failed to create the BApplication: %s\n",
463 strerror(error));
464 return 1;
465 }
466
467 // rename the main thread
468 rename_thread(find_thread(NULL), "roster");
469
470 PRINT("app->Run()...\n");
471
472 try {
473 app->Run();
474 } catch (std::exception& exception) {
475 char buffer[1024];
476 snprintf(buffer, sizeof(buffer),
477 "registrar main() caught exception: %s", exception.what());
478 debugger(buffer);
479 } catch (...) {
480 debugger("registrar main() caught unknown exception");
481 }
482
483 PRINT("delete app...\n");
484 delete app;
485
486 FUNCTION_END();
487 return 0;
488 }
489
490