1 /*
2 * Copyright 2001-2008, Ingo Weinhold, bonefish@users.sf.net.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 /*! TRoster is the incarnation of The Roster. It manages the running
8 applications.
9 */
10
11
12 #include "TRoster.h"
13
14 #include <new>
15
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <strings.h>
20
21 #include <Application.h>
22 #include <AutoDeleter.h>
23 #include <Autolock.h>
24 #include <Directory.h>
25 #include <File.h>
26 #include <FindDirectory.h>
27 #include <Path.h>
28
29 #include <AppMisc.h>
30 #include <MessagePrivate.h>
31 #include <MessengerPrivate.h>
32 #include <RosterPrivate.h>
33 #include <ServerProtocol.h>
34 #include <storage_support.h>
35
36 #include "AppInfoListMessagingTargetSet.h"
37 #include "Debug.h"
38 #include "EventMaskWatcher.h"
39 #include "MessageDeliverer.h"
40 #include "RegistrarDefs.h"
41 #include "RosterAppInfo.h"
42 #include "RosterSettingsCharStream.h"
43
44 using std::nothrow;
45 using namespace BPrivate;
46
47
48 /*! \class TRoster
49 \brief Implements the application roster.
50
51 This class handles the BRoster requests. For each kind a hook method is
52 implemented to which the registrar looper dispatches the request messages.
53
54 Registered and pre-registered are managed via AppInfoLists.
55 \a fEarlyPreRegisteredApps contains the infos for those application that
56 are pre-registered and currently have no team ID assigned to them yet,
57 whereas the infos of registered and pre-registered applications with a
58 team ID are to be found in \a fRegisteredApps.
59
60 When an application asks whether it is pre-registered or not and there
61 are one or more instances of the application that are pre-registered, but
62 have no team ID assigned yet, the reply to the request has to be
63 postponed until the status of the requesting team is clear. The request
64 message is dequeued from the registrar's message queue and added to
65 \a fIARRequestsByID for a later reply.
66
67 The field \a fActiveApp identifies the currently active application
68 and \a fLastToken is a counter used to generate unique tokens for
69 pre-registered applications.
70 */
71
72 //! The maximal period of time an app may be early pre-registered (60 s).
73 const bigtime_t kMaximalEarlyPreRegistrationPeriod = 60000000LL;
74
75
76 // #pragma mark - Private local functions
77
78
79 /*! \brief Returns the path to the default roster settings.
80
81 \param path BPath to be set to the roster settings path.
82 \param createDirectory makes sure the target directory exists if \c true.
83
84 \return the settings path as C string (\code path.Path() \endcode).
85 */
86 static const char*
get_default_roster_settings_path(BPath & path,bool createDirectory)87 get_default_roster_settings_path(BPath& path, bool createDirectory)
88 {
89 // get the path of the settings dir and append the subpath of our file
90 status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
91 if (error == B_OK)
92 error = path.Append("system/registrar");
93 if (error == B_OK && createDirectory)
94 error = create_directory(path.Path(), 0777);
95 if (error == B_OK)
96 error = path.Append("RosterSettings");
97
98 return path.Path();
99 }
100
101
102 /*! \brief Returns true if entry1's index is larger than entry2's index.
103
104 Also returns true if either entry is \c NULL.
105
106 Used for sorting the recent entry lists loaded from disk into the
107 proper order.
108 */
109 bool
larger_index(const recent_entry * entry1,const recent_entry * entry2)110 larger_index(const recent_entry* entry1, const recent_entry* entry2)
111 {
112 if (entry1 && entry2)
113 return entry1->index > entry2->index;
114
115 return true;
116 }
117
118
119 // #pragma mark -
120
121
122 /*! \brief Creates a new roster.
123
124 The object is completely initialized and ready to handle requests.
125 */
TRoster()126 TRoster::TRoster()
127 :
128 fLock("roster"),
129 fRegisteredApps(),
130 fEarlyPreRegisteredApps(),
131 fIARRequestsByID(),
132 fIARRequestsByToken(),
133 fActiveApp(NULL),
134 fWatchingService(),
135 fRecentApps(),
136 fRecentDocuments(),
137 fRecentFolders(),
138 fLastToken(0),
139 fShuttingDown(false)
140 {
141 find_directory(B_SYSTEM_DIRECTORY, &fSystemAppPath);
142 find_directory(B_SYSTEM_SERVERS_DIRECTORY, &fSystemServerPath);
143 }
144
145
146 /*! \brief Frees all resources associated with this object.
147 */
~TRoster()148 TRoster::~TRoster()
149 {
150 }
151
152
153 /*! \brief Handles an AddApplication() request.
154 \param request The request message
155 */
156 void
HandleAddApplication(BMessage * request)157 TRoster::HandleAddApplication(BMessage* request)
158 {
159 FUNCTION_START();
160
161 BAutolock _(fLock);
162
163 status_t error = B_OK;
164 // get the parameters
165 const char* signature;
166 entry_ref ref;
167 uint32 flags;
168 team_id team;
169 thread_id thread;
170 port_id port;
171 bool fullReg;
172 if (request->FindString("signature", &signature) != B_OK)
173 signature = NULL;
174 if (request->FindRef("ref", &ref) != B_OK)
175 SET_ERROR(error, B_BAD_VALUE);
176 if (request->FindInt32("flags", (int32*)&flags) != B_OK)
177 flags = B_REG_DEFAULT_APP_FLAGS;
178 if (request->FindInt32("team", &team) != B_OK)
179 team = -1;
180 if (request->FindInt32("thread", &thread) != B_OK)
181 thread = -1;
182 if (request->FindInt32("port", &port) != B_OK)
183 port = -1;
184 if (request->FindBool("full_registration", &fullReg) != B_OK)
185 fullReg = false;
186
187 PRINT("team: %" B_PRId32 ", signature: %s\n", team, signature);
188 PRINT("full registration: %d\n", fullReg);
189
190 if (fShuttingDown)
191 error = B_SHUTTING_DOWN;
192
193 // check the parameters
194 team_id otherTeam = -1;
195 uint32 token = 0;
196
197 uint32 launchFlags = flags & B_LAUNCH_MASK;
198 BEntry entry(&ref);
199 if (!entry.Exists())
200 SET_ERROR(error, B_ENTRY_NOT_FOUND);
201
202 if (error == B_OK)
203 _ValidateRunning(ref, signature);
204
205 // entry_ref
206 if (error == B_OK) {
207 PRINT("flags: %" B_PRIx32 "\n", flags);
208 PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device,
209 ref.directory, ref.name);
210 // check single/exclusive launchers
211 RosterAppInfo* info = NULL;
212 if ((launchFlags == B_SINGLE_LAUNCH
213 || launchFlags == B_EXCLUSIVE_LAUNCH)
214 && ((info = fRegisteredApps.InfoFor(&ref)) != NULL
215 || (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL)) {
216 SET_ERROR(error, B_ALREADY_RUNNING);
217 otherTeam = info->team;
218 token = info->token;
219 }
220 }
221
222 // signature
223 if (error == B_OK && signature) {
224 // check exclusive launchers
225 RosterAppInfo* info = NULL;
226 if (launchFlags == B_EXCLUSIVE_LAUNCH
227 && (((info = fRegisteredApps.InfoFor(signature)))
228 || ((info = fEarlyPreRegisteredApps.InfoFor(signature))))) {
229 SET_ERROR(error, B_ALREADY_RUNNING);
230 otherTeam = info->team;
231 token = info->token;
232 }
233 }
234
235 // If no team ID is given, full registration isn't possible.
236 if (error == B_OK) {
237 if (team < 0) {
238 if (fullReg)
239 SET_ERROR(error, B_BAD_VALUE);
240 } else if (fRegisteredApps.InfoFor(team))
241 SET_ERROR(error, B_REG_ALREADY_REGISTERED);
242 }
243
244 // Add the application info.
245 if (error == B_OK) {
246 // alloc and init the info
247 RosterAppInfo* info = new(nothrow) RosterAppInfo;
248 if (info) {
249 info->Init(thread, team, port, flags, &ref, signature);
250 if (fullReg)
251 info->state = APP_STATE_REGISTERED;
252 else
253 info->state = APP_STATE_PRE_REGISTERED;
254 info->registration_time = system_time();
255 // add it to the right list
256 bool addingSuccess = false;
257 if (team >= 0) {
258 PRINT("added ref: %" B_PRId32 ", %" B_PRId64 ", %s\n",
259 info->ref.device, info->ref.directory, info->ref.name);
260 addingSuccess = (AddApp(info) == B_OK);
261 if (addingSuccess && fullReg)
262 _AppAdded(info);
263 } else {
264 token = info->token = _NextToken();
265 addingSuccess = fEarlyPreRegisteredApps.AddInfo(info);
266 PRINT("added to early pre-regs, token: %" B_PRIu32 "\n", token);
267 }
268 if (!addingSuccess)
269 SET_ERROR(error, B_NO_MEMORY);
270 } else
271 SET_ERROR(error, B_NO_MEMORY);
272 // delete the info on failure
273 if (error != B_OK && info)
274 delete info;
275 }
276
277 // reply to the request
278 if (error == B_OK) {
279 // add to recent apps if successful
280 if (signature && signature[0] != '\0')
281 fRecentApps.Add(signature, flags);
282 else
283 fRecentApps.Add(&ref, flags);
284
285 BMessage reply(B_REG_SUCCESS);
286 // The token is valid only when no team ID has been supplied.
287 if (team < 0)
288 reply.AddInt32("token", (int32)token);
289 request->SendReply(&reply);
290 } else {
291 BMessage reply(B_REG_ERROR);
292 reply.AddInt32("error", error);
293 if (otherTeam >= 0)
294 reply.AddInt32("other_team", otherTeam);
295 if (token > 0)
296 reply.AddInt32("token", (int32)token);
297 request->SendReply(&reply);
298 }
299
300 FUNCTION_END();
301 }
302
303
304 /*! \brief Handles a CompleteRegistration() request.
305 \param request The request message
306 */
307 void
HandleCompleteRegistration(BMessage * request)308 TRoster::HandleCompleteRegistration(BMessage* request)
309 {
310 FUNCTION_START();
311
312 BAutolock _(fLock);
313
314 status_t error = B_OK;
315 // get the parameters
316 team_id team;
317 thread_id thread;
318 port_id port;
319 if (request->FindInt32("team", &team) != B_OK)
320 team = -1;
321 if (request->FindInt32("thread", &thread) != B_OK)
322 thread = -1;
323 if (request->FindInt32("port", &port) != B_OK)
324 port = -1;
325
326 if (fShuttingDown)
327 error = B_SHUTTING_DOWN;
328
329 // check the parameters
330 // port
331 if (error == B_OK && port < 0)
332 SET_ERROR(error, B_BAD_VALUE);
333
334 // thread
335 if (error == B_OK && thread < 0)
336 SET_ERROR(error, B_BAD_VALUE);
337
338 // team
339 if (error == B_OK) {
340 if (team >= 0) {
341 // everything is fine -- set the values
342 RosterAppInfo* info = fRegisteredApps.InfoFor(team);
343 if (info && info->state == APP_STATE_PRE_REGISTERED) {
344 info->thread = thread;
345 info->port = port;
346 info->state = APP_STATE_REGISTERED;
347 _AppAdded(info);
348 } else
349 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
350 } else
351 SET_ERROR(error, B_BAD_VALUE);
352 }
353
354 // reply to the request
355 if (error == B_OK) {
356 BMessage reply(B_REG_SUCCESS);
357 request->SendReply(&reply);
358 } else {
359 BMessage reply(B_REG_ERROR);
360 reply.AddInt32("error", error);
361 request->SendReply(&reply);
362 }
363
364 FUNCTION_END();
365 }
366
367
368 /*! \brief Handles an IsAppRegistered() request.
369 \param request The request message
370 */
371 void
HandleIsAppRegistered(BMessage * request)372 TRoster::HandleIsAppRegistered(BMessage* request)
373 {
374 FUNCTION_START();
375
376 BAutolock _(fLock);
377
378 status_t error = B_OK;
379 // get the parameters
380 entry_ref ref;
381 team_id team;
382 uint32 token;
383 if (request->FindRef("ref", &ref) != B_OK)
384 SET_ERROR(error, B_BAD_VALUE);
385 if (request->FindInt32("team", &team) != B_OK)
386 team = -1;
387 if (request->FindInt32("token", (int32*)&token) != B_OK)
388 token = 0;
389
390 PRINT("team: %" B_PRId32 ", token: %" B_PRIu32 "\n", team, token);
391 PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device, ref.directory,
392 ref.name);
393
394 // check the parameters
395 // entry_ref
396 if (error == B_OK && !BEntry(&ref).Exists())
397 SET_ERROR(error, B_ENTRY_NOT_FOUND);
398 // team/token
399 if (error == B_OK && team < 0 && token == 0)
400 SET_ERROR(error, B_BAD_VALUE);
401
402 // look up the information
403 RosterAppInfo* info = NULL;
404 if (error == B_OK) {
405 if ((info = fRegisteredApps.InfoFor(team)) != NULL) {
406 PRINT("found team in fRegisteredApps\n");
407 _ReplyToIARRequest(request, info);
408 } else if (token > 0
409 && (info = fEarlyPreRegisteredApps.InfoForToken(token)) != NULL) {
410 PRINT("found ref in fEarlyRegisteredApps (by token)\n");
411 // pre-registered and has no team ID assigned yet -- queue the
412 // request
413 be_app->DetachCurrentMessage();
414 _AddIARRequest(fIARRequestsByToken, token, request);
415 } else if (team >= 0
416 && (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL) {
417 PRINT("found ref in fEarlyRegisteredApps (by ref)\n");
418 // pre-registered and has no team ID assigned yet -- queue the
419 // request
420 be_app->DetachCurrentMessage();
421 _AddIARRequest(fIARRequestsByID, team, request);
422 } else {
423 PRINT("didn't find team or ref\n");
424 // team not registered, ref/token not early pre-registered
425 _ReplyToIARRequest(request, NULL);
426 }
427 } else {
428 // reply to the request on error
429 BMessage reply(B_REG_ERROR);
430 reply.AddInt32("error", error);
431 request->SendReply(&reply);
432 }
433
434 FUNCTION_END();
435 }
436
437
438 /*! \brief Handles a RemovePreRegApp() request.
439 \param request The request message
440 */
441 void
HandleRemovePreRegApp(BMessage * request)442 TRoster::HandleRemovePreRegApp(BMessage* request)
443 {
444 FUNCTION_START();
445
446 BAutolock _(fLock);
447
448 status_t error = B_OK;
449 // get the parameters
450 uint32 token;
451 if (request->FindInt32("token", (int32*)&token) != B_OK)
452 SET_ERROR(error, B_BAD_VALUE);
453 // remove the app
454 if (error == B_OK) {
455 RosterAppInfo* info = fEarlyPreRegisteredApps.InfoForToken(token);
456 if (info) {
457 fEarlyPreRegisteredApps.RemoveInfo(info);
458 delete info;
459 } else
460 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
461 }
462 // reply to the request
463 if (error == B_OK) {
464 BMessage reply(B_REG_SUCCESS);
465 request->SendReply(&reply);
466 } else {
467 BMessage reply(B_REG_ERROR);
468 reply.AddInt32("error", error);
469 request->SendReply(&reply);
470 }
471
472 FUNCTION_END();
473 }
474
475
476 /*! \brief Handles a RemoveApp() request.
477 \param request The request message
478 */
479 void
HandleRemoveApp(BMessage * request)480 TRoster::HandleRemoveApp(BMessage* request)
481 {
482 FUNCTION_START();
483
484 BAutolock _(fLock);
485
486 status_t error = B_OK;
487 // get the parameters
488 team_id team;
489 error = request->FindInt32("team", &team);
490 PRINT("team: %" B_PRId32 "\n", team);
491
492 // remove the app
493 if (error == B_OK) {
494 if (RosterAppInfo* info = fRegisteredApps.InfoFor(team)) {
495 RemoveApp(info);
496 delete info;
497 } else
498 SET_ERROR(error, B_REG_APP_NOT_REGISTERED);
499 }
500 // reply to the request
501 if (error == B_OK) {
502 BMessage reply(B_REG_SUCCESS);
503 request->SendReply(&reply);
504 } else {
505 BMessage reply(B_REG_ERROR);
506 reply.AddInt32("error", error);
507 request->SendReply(&reply);
508 }
509
510 FUNCTION_END();
511 }
512
513
514 /*! \brief Handles a SetThreadAndTeam() request.
515 \param request The request message
516 */
517 void
HandleSetThreadAndTeam(BMessage * request)518 TRoster::HandleSetThreadAndTeam(BMessage* request)
519 {
520 FUNCTION_START();
521
522 BAutolock _(fLock);
523
524 status_t error = B_OK;
525
526 // get the parameters
527 team_id team;
528 thread_id thread;
529 uint32 token;
530 if (request->FindInt32("team", &team) != B_OK)
531 team = -1;
532 if (request->FindInt32("thread", &thread) != B_OK)
533 thread = -1;
534 if (request->FindInt32("token", (int32*)&token) != B_OK)
535 SET_ERROR(error, B_BAD_VALUE);
536
537 // check the parameters
538 // team
539 if (error == B_OK && team < 0)
540 SET_ERROR(error, B_BAD_VALUE);
541
542 PRINT("team: %" B_PRId32 ", thread: %" B_PRId32 ", token: %" B_PRIu32 "\n",
543 team, thread, token);
544
545 port_id port = -1;
546
547 // update the app_info
548 if (error == B_OK) {
549 RosterAppInfo* info = fEarlyPreRegisteredApps.InfoForToken(token);
550 if (info != NULL) {
551 // Set thread and team, create a port for the application and
552 // move the app_info from the list of the early pre-registered
553 // apps to the list of the (pre-)registered apps.
554 fEarlyPreRegisteredApps.RemoveInfo(info);
555 info->team = team;
556 info->thread = thread;
557 // create and transfer the port
558 info->port = port = create_port(B_REG_APP_LOOPER_PORT_CAPACITY,
559 kRAppLooperPortName);
560 if (info->port < 0)
561 SET_ERROR(error, info->port);
562 if (error == B_OK)
563 SET_ERROR(error, set_port_owner(info->port, team));
564 // add the info to the registered apps list
565 if (error == B_OK)
566 SET_ERROR(error, AddApp(info));
567 // cleanup on failure
568 if (error != B_OK) {
569 if (info->port >= 0)
570 delete_port(info->port);
571 delete info;
572 info = NULL;
573 }
574 // handle pending IsAppRegistered() requests
575 IARRequestMap::iterator it = fIARRequestsByID.find(team);
576 if (it != fIARRequestsByID.end()) {
577 BMessageQueue* requests = it->second;
578 if (error == B_OK)
579 _ReplyToIARRequests(requests, info);
580 delete requests;
581 fIARRequestsByID.erase(it);
582 }
583
584 it = fIARRequestsByToken.find((int32)token);
585 if (it != fIARRequestsByToken.end()) {
586 BMessageQueue* requests = it->second;
587 if (error == B_OK)
588 _ReplyToIARRequests(requests, info);
589 delete requests;
590 fIARRequestsByToken.erase(it);
591 }
592 } else
593 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
594 }
595 // reply to the request
596 if (error == B_OK) {
597 BMessage reply(B_REG_SUCCESS);
598 reply.AddInt32("port", port);
599 request->SendReply(&reply);
600 } else {
601 BMessage reply(B_REG_ERROR);
602 reply.AddInt32("error", error);
603 request->SendReply(&reply);
604 }
605
606 FUNCTION_END();
607 }
608
609
610 /*! \brief Handles a SetSignature() request.
611 \param request The request message
612 */
613 void
HandleSetSignature(BMessage * request)614 TRoster::HandleSetSignature(BMessage* request)
615 {
616 FUNCTION_START();
617
618 BAutolock _(fLock);
619
620 status_t error = B_OK;
621 // get the parameters
622 team_id team;
623 const char* signature;
624 if (request->FindInt32("team", &team) != B_OK)
625 error = B_BAD_VALUE;
626 if (request->FindString("signature", &signature) != B_OK)
627 error = B_BAD_VALUE;
628 // find the app and set the signature
629 if (error == B_OK) {
630 if (RosterAppInfo* info = fRegisteredApps.InfoFor(team))
631 strcpy(info->signature, signature);
632 else
633 SET_ERROR(error, B_REG_APP_NOT_REGISTERED);
634 }
635 // reply to the request
636 if (error == B_OK) {
637 BMessage reply(B_REG_SUCCESS);
638 request->SendReply(&reply);
639 } else {
640 BMessage reply(B_REG_ERROR);
641 reply.AddInt32("error", error);
642 request->SendReply(&reply);
643 }
644
645 FUNCTION_END();
646 }
647
648
649 /*! \brief Handles a Get{Running,Active,}AppInfo() request.
650 \param request The request message
651 */
652 void
HandleGetAppInfo(BMessage * request)653 TRoster::HandleGetAppInfo(BMessage* request)
654 {
655 FUNCTION_START();
656
657 BAutolock _(fLock);
658
659 // get the parameters
660 team_id team;
661 entry_ref ref;
662 const char* signature;
663 bool hasTeam = true;
664 bool hasRef = true;
665 bool hasSignature = true;
666 if (request->FindInt32("team", &team) != B_OK)
667 hasTeam = false;
668 if (request->FindRef("ref", &ref) != B_OK)
669 hasRef = false;
670 if (request->FindString("signature", &signature) != B_OK)
671 hasSignature = false;
672
673 if (hasTeam)
674 PRINT("team: %" B_PRId32 "\n", team);
675 if (hasRef) {
676 PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device,
677 ref.directory, ref.name);
678 }
679 if (hasSignature)
680 PRINT("signature: %s\n", signature);
681
682 // get the info
683 RosterAppInfo* info = NULL;
684 status_t error = B_OK;
685 if (hasTeam) {
686 info = fRegisteredApps.InfoFor(team);
687 if (info == NULL)
688 SET_ERROR(error, B_BAD_TEAM_ID);
689 } else if (hasRef) {
690 info = fRegisteredApps.InfoFor(&ref);
691 if (info == NULL)
692 SET_ERROR(error, B_ERROR);
693 } else if (hasSignature) {
694 info = fRegisteredApps.InfoFor(signature);
695 if (info == NULL)
696 SET_ERROR(error, B_ERROR);
697 } else {
698 // If neither of those has been supplied, the active application
699 // info is requested.
700 if (fActiveApp)
701 info = fActiveApp;
702 else
703 SET_ERROR(error, B_ERROR);
704 }
705
706 // reply to the request
707 if (error == B_OK) {
708 BMessage reply(B_REG_SUCCESS);
709 _AddMessageAppInfo(&reply, info);
710 request->SendReply(&reply);
711 } else {
712 BMessage reply(B_REG_ERROR);
713 reply.AddInt32("error", error);
714 request->SendReply(&reply);
715 }
716
717 FUNCTION_END();
718 }
719
720
721 /*! \brief Handles a GetAppList() request.
722 \param request The request message
723 */
724 void
HandleGetAppList(BMessage * request)725 TRoster::HandleGetAppList(BMessage* request)
726 {
727 FUNCTION_START();
728
729 BAutolock _(fLock);
730
731 // get the parameters
732 const char* signature;
733 if (request->FindString("signature", &signature) != B_OK)
734 signature = NULL;
735
736 // reply to the request
737 BMessage reply(B_REG_SUCCESS);
738 // get the list
739 for (AppInfoList::Iterator it(fRegisteredApps.It());
740 RosterAppInfo* info = *it;
741 ++it) {
742 if (info->state != APP_STATE_REGISTERED)
743 continue;
744 if (signature == NULL || strcasecmp(signature, info->signature) == 0)
745 reply.AddInt32("teams", info->team);
746 }
747 request->SendReply(&reply);
748
749 FUNCTION_END();
750 }
751
752
753 /*! \brief Handles a _UpdateActiveApp() request.
754
755 This is sent from the app_server when the current active application
756 is changed.
757
758 \param request The request message
759 */
760 void
HandleUpdateActiveApp(BMessage * request)761 TRoster::HandleUpdateActiveApp(BMessage* request)
762 {
763 FUNCTION_START();
764
765 BAutolock _(fLock);
766
767 // get the parameters
768 status_t error = B_OK;
769 team_id team;
770 if (request->FindInt32("team", &team) != B_OK)
771 error = B_BAD_VALUE;
772
773 // activate the app
774 if (error == B_OK) {
775 if (RosterAppInfo* info = fRegisteredApps.InfoFor(team))
776 UpdateActiveApp(info);
777 else
778 error = B_BAD_TEAM_ID;
779 }
780
781 // reply to the request
782 if (request->IsSourceWaiting()) {
783 if (error == B_OK) {
784 BMessage reply(B_REG_SUCCESS);
785 request->SendReply(&reply);
786 } else {
787 BMessage reply(B_REG_ERROR);
788 reply.AddInt32("error", error);
789 request->SendReply(&reply);
790 }
791 }
792
793 FUNCTION_END();
794 }
795
796
797 /*! \brief Handles a Broadcast() request.
798 \param request The request message
799 */
800 void
HandleBroadcast(BMessage * request)801 TRoster::HandleBroadcast(BMessage* request)
802 {
803 FUNCTION_START();
804
805 BAutolock _(fLock);
806
807 status_t error = B_OK;
808 // get the parameters
809 team_id team;
810 BMessage message;
811 BMessenger replyTarget;
812 if (request->FindInt32("team", &team) != B_OK)
813 team = -1;
814 if (error == B_OK && request->FindMessage("message", &message) != B_OK)
815 error = B_BAD_VALUE;
816 if (error == B_OK
817 && request->FindMessenger("reply_target", &replyTarget) != B_OK) {
818 error = B_BAD_VALUE;
819 }
820
821 // reply to the request -- do this first, don't let the inquirer wait
822 if (error == B_OK) {
823 BMessage reply(B_REG_SUCCESS);
824 request->SendReply(&reply);
825 } else {
826 BMessage reply(B_REG_ERROR);
827 reply.AddInt32("error", error);
828 request->SendReply(&reply);
829 }
830
831 // broadcast the message
832 if (error == B_OK) {
833 // the target set (excludes the registrar and the requesting team)
834 class BroadcastMessagingTargetSet
835 : public AppInfoListMessagingTargetSet {
836 public:
837 BroadcastMessagingTargetSet(AppInfoList& list, team_id team)
838 : AppInfoListMessagingTargetSet(list, true),
839 fTeam(team)
840 {
841 }
842
843 virtual bool Filter(const RosterAppInfo* info)
844 {
845 return AppInfoListMessagingTargetSet::Filter(info)
846 && (info->team != fTeam);
847 }
848
849 private:
850 team_id fTeam;
851 } targetSet(fRegisteredApps, team);
852
853 if (targetSet.HasNext()) {
854 // set the reply target
855 BMessage::Private(message).SetReply(replyTarget);
856
857 // send the messages
858 MessageDeliverer::Default()->DeliverMessage(&message, targetSet);
859 }
860 }
861
862 FUNCTION_END();
863 }
864
865
866 /*! \brief Handles a StartWatching() request.
867 \param request The request message
868 */
869 void
HandleStartWatching(BMessage * request)870 TRoster::HandleStartWatching(BMessage* request)
871 {
872 FUNCTION_START();
873
874 BAutolock _(fLock);
875
876 status_t error = B_OK;
877 // get the parameters
878 BMessenger target;
879 uint32 events;
880 if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
881 error = B_BAD_VALUE;
882 if (request->FindInt32("events", (int32*)&events) != B_OK)
883 error = B_BAD_VALUE;
884 // add the new watcher
885 if (error == B_OK) {
886 Watcher* watcher = new(nothrow) EventMaskWatcher(target, events);
887 if (watcher) {
888 if (!fWatchingService.AddWatcher(watcher)) {
889 error = B_NO_MEMORY;
890 delete watcher;
891 }
892 } else
893 error = B_NO_MEMORY;
894 }
895 // reply to the request
896 if (error == B_OK) {
897 BMessage reply(B_REG_SUCCESS);
898 request->SendReply(&reply);
899 } else {
900 BMessage reply(B_REG_ERROR);
901 reply.AddInt32("error", error);
902 request->SendReply(&reply);
903 }
904
905 FUNCTION_END();
906 }
907
908
909 /*! \brief Handles a StopWatching() request.
910 \param request The request message
911 */
912 void
HandleStopWatching(BMessage * request)913 TRoster::HandleStopWatching(BMessage* request)
914 {
915 FUNCTION_START();
916
917 BAutolock _(fLock);
918
919 status_t error = B_OK;
920 // get the parameters
921 BMessenger target;
922 if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
923 error = B_BAD_VALUE;
924 // remove the watcher
925 if (error == B_OK) {
926 if (!fWatchingService.RemoveWatcher(target))
927 error = B_BAD_VALUE;
928 }
929 // reply to the request
930 if (error == B_OK) {
931 BMessage reply(B_REG_SUCCESS);
932 request->SendReply(&reply);
933 } else {
934 BMessage reply(B_REG_ERROR);
935 reply.AddInt32("error", error);
936 request->SendReply(&reply);
937 }
938
939 FUNCTION_END();
940 }
941
942
943 /*! \brief Handles a GetRecentDocuments() request.
944 \param request The request message
945 */
946 void
HandleGetRecentDocuments(BMessage * request)947 TRoster::HandleGetRecentDocuments(BMessage* request)
948 {
949 FUNCTION_START();
950
951 BAutolock _(fLock);
952
953 _HandleGetRecentEntries(request);
954
955 FUNCTION_END();
956 }
957
958
959 /*! \brief Handles a GetRecentFolders() request.
960 \param request The request message
961 */
962 void
HandleGetRecentFolders(BMessage * request)963 TRoster::HandleGetRecentFolders(BMessage* request)
964 {
965 FUNCTION_START();
966
967 BAutolock _(fLock);
968
969 _HandleGetRecentEntries(request);
970
971 FUNCTION_END();
972 }
973
974
975 /*! \brief Handles a GetRecentApps() request.
976 \param request The request message
977 */
978 void
HandleGetRecentApps(BMessage * request)979 TRoster::HandleGetRecentApps(BMessage* request)
980 {
981 FUNCTION_START();
982
983 BAutolock _(fLock);
984
985 if (!request) {
986 D(PRINT("WARNING: TRoster::HandleGetRecentApps(NULL) called\n"));
987 return;
988 }
989
990 int32 maxCount;
991 BMessage reply(B_REG_RESULT);
992
993 status_t error = request->FindInt32("max count", &maxCount);
994 if (!error)
995 error = fRecentApps.Get(maxCount, &reply);
996 reply.AddInt32("result", error);
997 request->SendReply(&reply);
998
999 FUNCTION_END();
1000 }
1001
1002
1003 /*! \brief Handles an AddToRecentDocuments() request.
1004 \param request The request message
1005 */
1006 void
HandleAddToRecentDocuments(BMessage * request)1007 TRoster::HandleAddToRecentDocuments(BMessage* request)
1008 {
1009 FUNCTION_START();
1010
1011 BAutolock _(fLock);
1012
1013 if (!request) {
1014 D(PRINT("WARNING: TRoster::HandleAddToRecentDocuments(NULL) called\n"));
1015 return;
1016 }
1017
1018 entry_ref ref;
1019 const char* appSig;
1020 BMessage reply(B_REG_RESULT);
1021
1022 status_t error = request->FindRef("ref", &ref);
1023 if (!error)
1024 error = request->FindString("app sig", &appSig);
1025 if (!error)
1026 error = fRecentDocuments.Add(&ref, appSig);
1027 reply.AddInt32("result", error);
1028 request->SendReply(&reply);
1029
1030 FUNCTION_END();
1031 }
1032
1033
1034 /*! \brief Handles an AddToRecentFolders() request.
1035 \param request The request message
1036 */
1037 void
HandleAddToRecentFolders(BMessage * request)1038 TRoster::HandleAddToRecentFolders(BMessage* request)
1039 {
1040 FUNCTION_START();
1041
1042 BAutolock _(fLock);
1043
1044 if (!request) {
1045 D(PRINT("WARNING: TRoster::HandleAddToRecentFolders(NULL) called\n"));
1046 return;
1047 }
1048
1049 entry_ref ref;
1050 const char* appSig;
1051 BMessage reply(B_REG_RESULT);
1052
1053 status_t error = request->FindRef("ref", &ref);
1054 if (!error)
1055 error = request->FindString("app sig", &appSig);
1056 if (!error)
1057 error = fRecentFolders.Add(&ref, appSig);
1058 reply.AddInt32("result", error);
1059 request->SendReply(&reply);
1060
1061 FUNCTION_END();
1062 }
1063
1064
1065 /*! \brief Handles an AddToRecentApps() request.
1066 \param request The request message
1067 */
1068 void
HandleAddToRecentApps(BMessage * request)1069 TRoster::HandleAddToRecentApps(BMessage* request)
1070 {
1071 FUNCTION_START();
1072
1073 BAutolock _(fLock);
1074
1075 if (!request) {
1076 D(PRINT("WARNING: TRoster::HandleAddToRecentApps(NULL) called\n"));
1077 return;
1078 }
1079
1080 const char* appSig;
1081 BMessage reply(B_REG_RESULT);
1082
1083 status_t error = request->FindString("app sig", &appSig);
1084 if (!error)
1085 error = fRecentApps.Add(appSig);
1086 reply.AddInt32("result", error);
1087 request->SendReply(&reply);
1088
1089 FUNCTION_END();
1090 }
1091
1092
1093 void
HandleLoadRecentLists(BMessage * request)1094 TRoster::HandleLoadRecentLists(BMessage* request)
1095 {
1096 FUNCTION_START();
1097
1098 BAutolock _(fLock);
1099
1100 if (!request) {
1101 D(PRINT("WARNING: TRoster::HandleLoadRecentLists(NULL) called\n"));
1102 return;
1103 }
1104
1105 const char* filename;
1106 BMessage reply(B_REG_RESULT);
1107
1108 status_t error = request->FindString("filename", &filename);
1109 if (!error)
1110 error = _LoadRosterSettings(filename);
1111 reply.AddInt32("result", error);
1112 request->SendReply(&reply);
1113
1114 FUNCTION_END();
1115 }
1116
1117
1118 void
HandleSaveRecentLists(BMessage * request)1119 TRoster::HandleSaveRecentLists(BMessage* request)
1120 {
1121 FUNCTION_START();
1122
1123 BAutolock _(fLock);
1124
1125 if (!request) {
1126 D(PRINT("WARNING: TRoster::HandleSaveRecentLists(NULL) called\n"));
1127 return;
1128 }
1129
1130 const char* filename;
1131 BMessage reply(B_REG_RESULT);
1132
1133 status_t error = request->FindString("filename", &filename);
1134 if (!error)
1135 error = _SaveRosterSettings(filename);
1136 reply.AddInt32("result", error);
1137 request->SendReply(&reply);
1138
1139 FUNCTION_END();
1140 }
1141
1142
1143 void
HandleRestartAppServer(BMessage * request)1144 TRoster::HandleRestartAppServer(BMessage* request)
1145 {
1146 BAutolock _(fLock);
1147
1148 // TODO: if an app_server is still running, stop it first
1149
1150 const char* pathString;
1151 if (request->FindString("path", &pathString) != B_OK)
1152 pathString = "/boot/system/servers";
1153 BPath path(pathString);
1154 path.Append("app_server");
1155 // NOTE: its required at some point that the binary name is "app_server"
1156
1157 const char **argv = new const char * [2];
1158 argv[0] = strdup(path.Path());
1159 argv[1] = NULL;
1160
1161 thread_id threadId = load_image(1, argv, (const char**)environ);
1162 int i;
1163 for (i = 0; i < 1; i++)
1164 delete argv[i];
1165 delete [] argv;
1166
1167 resume_thread(threadId);
1168 // give the server some time to create the server port
1169 snooze(100000);
1170
1171 // notify all apps
1172 // TODO: whats about ourself?
1173 AppInfoListMessagingTargetSet targetSet(fRegisteredApps);
1174 if (targetSet.HasNext()) {
1175 // send the messages
1176 BMessage message(kMsgAppServerRestarted);
1177 MessageDeliverer::Default()->DeliverMessage(&message, targetSet);
1178 }
1179 }
1180
1181
1182 /*! \brief Clears the current list of recent documents
1183 */
1184 void
ClearRecentDocuments()1185 TRoster::ClearRecentDocuments()
1186 {
1187 BAutolock _(fLock);
1188
1189 fRecentDocuments.Clear();
1190 }
1191
1192
1193 /*! \brief Clears the current list of recent folders
1194 */
1195 void
ClearRecentFolders()1196 TRoster::ClearRecentFolders()
1197 {
1198 BAutolock _(fLock);
1199
1200 fRecentFolders.Clear();
1201 }
1202
1203
1204 /*! \brief Clears the current list of recent apps
1205 */
1206 void
ClearRecentApps()1207 TRoster::ClearRecentApps()
1208 {
1209 BAutolock _(fLock);
1210
1211 fRecentApps.Clear();
1212 }
1213
1214
1215 /*! \brief Initializes the roster.
1216
1217 Currently only adds the registrar to the roster.
1218 The application must already be running, more precisly Run() must have
1219 been called.
1220
1221 \return
1222 - \c B_OK: Everything went fine.
1223 - an error code
1224 */
1225 status_t
Init()1226 TRoster::Init()
1227 {
1228 // check lock initialization
1229 if (fLock.InitCheck() < 0)
1230 return fLock.InitCheck();
1231
1232 // create the info
1233 RosterAppInfo* info = new(nothrow) RosterAppInfo;
1234 if (info == NULL)
1235 return B_NO_MEMORY;
1236
1237 // get the app's ref
1238 entry_ref ref;
1239 status_t error = get_app_ref(&ref);
1240
1241 // init and add the info
1242 if (error == B_OK) {
1243 info->Init(be_app->Thread(), be_app->Team(),
1244 BMessenger::Private(be_app_messenger).Port(),
1245 B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP, &ref, B_REGISTRAR_SIGNATURE);
1246 info->state = APP_STATE_REGISTERED;
1247 info->registration_time = system_time();
1248 error = AddApp(info);
1249 }
1250
1251 if (error == B_OK)
1252 _LoadRosterSettings();
1253
1254 // cleanup on error
1255 if (error != B_OK)
1256 delete info;
1257
1258 return error;
1259 }
1260
1261
1262 /*! \brief Add the supplied app info to the list of (pre-)registered apps.
1263
1264 \param info The app info to be added
1265 */
1266 status_t
AddApp(RosterAppInfo * info)1267 TRoster::AddApp(RosterAppInfo* info)
1268 {
1269 BAutolock _(fLock);
1270
1271 status_t error = (info ? B_OK : B_BAD_VALUE);
1272 if (info) {
1273 if (!fRegisteredApps.AddInfo(info))
1274 error = B_NO_MEMORY;
1275 }
1276 return error;
1277 }
1278
1279
1280 /*! \brief Removes the supplied app info from the list of (pre-)registered
1281 apps.
1282
1283 \param info The app info to be removed
1284 */
1285 void
RemoveApp(RosterAppInfo * info)1286 TRoster::RemoveApp(RosterAppInfo* info)
1287 {
1288 BAutolock _(fLock);
1289
1290 if (info) {
1291 if (fRegisteredApps.RemoveInfo(info)) {
1292 if (info->state == APP_STATE_REGISTERED) {
1293 info->state = APP_STATE_UNREGISTERED;
1294 _AppRemoved(info);
1295 }
1296 }
1297 }
1298 }
1299
1300
1301 /*! \brief Activates the application identified by \a info.
1302
1303 The currently active application is deactivated and the one whose
1304 info is supplied is activated. \a info may be \c NULL, which only
1305 deactivates the currently active application.
1306
1307 \param info The info of the app to be activated
1308 */
1309 void
UpdateActiveApp(RosterAppInfo * info)1310 TRoster::UpdateActiveApp(RosterAppInfo* info)
1311 {
1312 BAutolock _(fLock);
1313
1314 if (info != fActiveApp) {
1315 // deactivate the currently active app
1316 RosterAppInfo* oldActiveApp = fActiveApp;
1317 fActiveApp = NULL;
1318 if (oldActiveApp)
1319 _AppDeactivated(oldActiveApp);
1320
1321 // activate the new app
1322 if (info) {
1323 fActiveApp = info;
1324 _AppActivated(info);
1325 }
1326 }
1327 }
1328
1329
1330 /*! \brief Checks whether the (pre-)registered applications are still running.
1331
1332 This is necessary, since killed applications don't unregister properly.
1333 */
1334 void
CheckSanity()1335 TRoster::CheckSanity()
1336 {
1337 BAutolock _(fLock);
1338
1339 // not early (pre-)registered applications
1340 AppInfoList obsoleteApps;
1341 for (AppInfoList::Iterator it = fRegisteredApps.It(); it.IsValid(); ++it) {
1342 if (!(*it)->IsRunning())
1343 obsoleteApps.AddInfo(*it);
1344 }
1345
1346 // remove the apps
1347 for (AppInfoList::Iterator it = obsoleteApps.It(); it.IsValid(); ++it) {
1348 RemoveApp(*it);
1349 delete *it;
1350 }
1351 obsoleteApps.MakeEmpty(false);
1352 // don't delete infos a second time
1353
1354 // early pre-registered applications
1355 bigtime_t timeLimit = system_time() - kMaximalEarlyPreRegistrationPeriod;
1356 for (AppInfoList::Iterator it = fEarlyPreRegisteredApps.It();
1357 it.IsValid();
1358 ++it) {
1359 if ((*it)->registration_time < timeLimit)
1360 obsoleteApps.AddInfo(*it);
1361 }
1362
1363 // remove the apps
1364 for (AppInfoList::Iterator it = obsoleteApps.It(); it.IsValid(); ++it) {
1365 fEarlyPreRegisteredApps.RemoveInfo(*it);
1366 delete *it;
1367 }
1368 obsoleteApps.MakeEmpty(false);
1369 // don't delete infos a second time
1370 }
1371
1372
1373 /*! \brief Tells the roster whether a shutdown process is in progess at the
1374 moment.
1375
1376 After this method is called with \a shuttingDown == \c true, no more
1377 applications can be created.
1378
1379 \param shuttingDown \c true, to indicate the start of the shutdown process,
1380 \c false to signalling its end.
1381 */
1382 void
SetShuttingDown(bool shuttingDown)1383 TRoster::SetShuttingDown(bool shuttingDown)
1384 {
1385 BAutolock _(fLock);
1386
1387 fShuttingDown = shuttingDown;
1388
1389 if (shuttingDown)
1390 _SaveRosterSettings();
1391 }
1392
1393
1394 /*! \brief Returns lists of applications to be asked to quit on shutdown.
1395
1396 \param userApps List of RosterAppInfos identifying the user applications.
1397 Those will be ask to quit first.
1398 \param systemApps List of RosterAppInfos identifying the system applications
1399 (like Tracker and Deskbar), which will be asked to quit after the
1400 user applications are gone.
1401 \param vitalSystemApps A set of team_ids identifying teams that must not
1402 be terminated (app server and registrar).
1403 \return \c B_OK, if everything went fine, another error code otherwise.
1404 */
1405 status_t
GetShutdownApps(AppInfoList & userApps,AppInfoList & systemApps,AppInfoList & backgroundApps,HashSet<HashKey32<team_id>> & vitalSystemApps)1406 TRoster::GetShutdownApps(AppInfoList& userApps, AppInfoList& systemApps,
1407 AppInfoList& backgroundApps, HashSet<HashKey32<team_id> >& vitalSystemApps)
1408 {
1409 BAutolock _(fLock);
1410
1411 status_t error = B_OK;
1412
1413 // get the vital system apps:
1414 // * ourself
1415 // * kernel team
1416 // * app server
1417 // * debug server
1418
1419 // ourself
1420 vitalSystemApps.Add(be_app->Team());
1421
1422 // kernel team
1423 team_info teamInfo;
1424 if (get_team_info(B_SYSTEM_TEAM, &teamInfo) == B_OK)
1425 vitalSystemApps.Add(teamInfo.team);
1426
1427 // app server
1428 RosterAppInfo* info
1429 = fRegisteredApps.InfoFor("application/x-vnd.haiku-app_server");
1430 if (info != NULL)
1431 vitalSystemApps.Add(info->team);
1432
1433 // debug server
1434 info = fRegisteredApps.InfoFor("application/x-vnd.haiku-debug_server");
1435 if (info != NULL)
1436 vitalSystemApps.Add(info->team);
1437
1438 // populate the other groups
1439 for (AppInfoList::Iterator it(fRegisteredApps.It());
1440 RosterAppInfo* info = *it; ++it) {
1441 if (!vitalSystemApps.Contains(info->team)) {
1442 RosterAppInfo* clonedInfo = info->Clone();
1443 if (clonedInfo) {
1444 if (_IsSystemApp(info)) {
1445 if (!systemApps.AddInfo(clonedInfo))
1446 error = B_NO_MEMORY;
1447 } else if (info->flags & B_BACKGROUND_APP) {
1448 if (!backgroundApps.AddInfo(clonedInfo))
1449 error = B_NO_MEMORY;
1450 } else {
1451 if (!userApps.AddInfo(clonedInfo))
1452 error = B_NO_MEMORY;
1453 }
1454
1455 if (error != B_OK)
1456 delete clonedInfo;
1457 } else
1458 error = B_NO_MEMORY;
1459 }
1460
1461 if (error != B_OK)
1462 break;
1463 }
1464
1465 // Special case, we add the input server to vital apps here so it is
1466 // not excluded in the lists above
1467 info = fRegisteredApps.InfoFor("application/x-vnd.Be-input_server");
1468 if (info != NULL)
1469 vitalSystemApps.Add(info->team);
1470
1471 // clean up on error
1472 if (error != B_OK) {
1473 userApps.MakeEmpty(true);
1474 systemApps.MakeEmpty(true);
1475 }
1476
1477 return error;
1478 }
1479
1480
1481 status_t
AddAppInfo(AppInfoList & apps,team_id team)1482 TRoster::AddAppInfo(AppInfoList& apps, team_id team)
1483 {
1484 BAutolock _(fLock);
1485
1486 for (AppInfoList::Iterator it(fRegisteredApps.It());
1487 RosterAppInfo* info = *it; ++it) {
1488 if (info->team == team) {
1489 RosterAppInfo* clonedInfo = info->Clone();
1490 status_t error = B_NO_MEMORY;
1491 if (clonedInfo != NULL) {
1492 if (!apps.AddInfo(clonedInfo))
1493 delete clonedInfo;
1494 else
1495 error = B_OK;
1496 }
1497 return error;
1498 }
1499 }
1500
1501 return B_BAD_TEAM_ID;
1502 }
1503
1504
1505 status_t
AddWatcher(Watcher * watcher)1506 TRoster::AddWatcher(Watcher* watcher)
1507 {
1508 BAutolock _(fLock);
1509
1510 if (!watcher)
1511 return B_BAD_VALUE;
1512
1513 if (!fWatchingService.AddWatcher(watcher))
1514 return B_NO_MEMORY;
1515
1516 return B_OK;
1517 }
1518
1519
1520 void
RemoveWatcher(Watcher * watcher)1521 TRoster::RemoveWatcher(Watcher* watcher)
1522 {
1523 BAutolock _(fLock);
1524
1525 if (watcher)
1526 fWatchingService.RemoveWatcher(watcher, false);
1527 }
1528
1529
1530 /*! \brief Hook method invoked, when an application has been fully registered.
1531 \param info The RosterAppInfo of the added application.
1532 */
1533 void
_AppAdded(RosterAppInfo * info)1534 TRoster::_AppAdded(RosterAppInfo* info)
1535 {
1536 // notify the watchers
1537 BMessage message(B_SOME_APP_LAUNCHED);
1538 _AddMessageWatchingInfo(&message, info);
1539 EventMaskWatcherFilter filter(B_REQUEST_LAUNCHED);
1540 fWatchingService.NotifyWatchers(&message, &filter);
1541 }
1542
1543
1544 /*! \brief Hook method invoked, when a fully registered application has been
1545 removed.
1546 \param info The RosterAppInfo of the removed application.
1547 */
1548 void
_AppRemoved(RosterAppInfo * info)1549 TRoster::_AppRemoved(RosterAppInfo* info)
1550 {
1551 if (info) {
1552 // deactivate the app, if it was the active one
1553 if (info == fActiveApp)
1554 UpdateActiveApp(NULL);
1555
1556 // notify the watchers
1557 BMessage message(B_SOME_APP_QUIT);
1558 _AddMessageWatchingInfo(&message, info);
1559 EventMaskWatcherFilter filter(B_REQUEST_QUIT);
1560 fWatchingService.NotifyWatchers(&message, &filter);
1561 }
1562 }
1563
1564
1565 /*! \brief Hook method invoked, when an application has been activated.
1566 \param info The RosterAppInfo of the activated application.
1567 */
1568 void
_AppActivated(RosterAppInfo * info)1569 TRoster::_AppActivated(RosterAppInfo* info)
1570 {
1571 if (info != NULL && info->state == APP_STATE_REGISTERED) {
1572 // send B_APP_ACTIVATED to the app
1573 BMessenger messenger;
1574 BMessenger::Private messengerPrivate(messenger);
1575 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN);
1576 BMessage message(B_APP_ACTIVATED);
1577 message.AddBool("active", true);
1578 // not sure, if it makes sense to use the MessageDeliverer here
1579 MessageDeliverer::Default()->DeliverMessage(&message, messenger);
1580
1581 // notify the watchers
1582 BMessage watcherMessage(B_SOME_APP_ACTIVATED);
1583 _AddMessageWatchingInfo(&watcherMessage, info);
1584 EventMaskWatcherFilter filter(B_REQUEST_ACTIVATED);
1585 fWatchingService.NotifyWatchers(&watcherMessage, &filter);
1586 }
1587 }
1588
1589
1590 /*! \brief Hook method invoked, when an application has been deactivated.
1591 \param info The RosterAppInfo of the deactivated application.
1592 */
1593 void
_AppDeactivated(RosterAppInfo * info)1594 TRoster::_AppDeactivated(RosterAppInfo* info)
1595 {
1596 if (info != NULL && info->state == APP_STATE_REGISTERED) {
1597 // send B_APP_ACTIVATED to the app
1598 BMessenger messenger;
1599 BMessenger::Private messengerPrivate(messenger);
1600 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN);
1601 BMessage message(B_APP_ACTIVATED);
1602 message.AddBool("active", false);
1603 // not sure, if it makes sense to use the MessageDeliverer here
1604 MessageDeliverer::Default()->DeliverMessage(&message, messenger);
1605 }
1606 }
1607
1608
1609 /*! \brief Adds an app_info to a message.
1610
1611 The info is added as a flat_app_info to a field "app_info" with the type
1612 \c B_REG_APP_INFO_TYPE.
1613
1614 \param message The message
1615 \param info The app_info.
1616 \return \c B_OK if everything went fine, an error code otherwise.
1617 */
1618 status_t
_AddMessageAppInfo(BMessage * message,const app_info * info)1619 TRoster::_AddMessageAppInfo(BMessage* message, const app_info* info)
1620 {
1621 // An app_info is not completely flat. The entry_ref contains a string
1622 // pointer. Therefore we flatten the info.
1623 flat_app_info flatInfo;
1624 flatInfo.thread = info->thread;
1625 flatInfo.team = info->team;
1626 flatInfo.port = info->port;
1627 flatInfo.flags = info->flags;
1628 flatInfo.ref_device = info->ref.device;
1629 flatInfo.ref_directory = info->ref.directory;
1630 memcpy(flatInfo.signature, info->signature, B_MIME_TYPE_LENGTH);
1631
1632 // set the ref name to NULL and copy it into the flat structure
1633 flatInfo.ref_name[0] = '\0';
1634 if (info->ref.name)
1635 strcpy(flatInfo.ref_name, info->ref.name);
1636
1637 // add the flat info
1638 return message->AddData("app_info", B_REG_APP_INFO_TYPE, &flatInfo,
1639 sizeof(flat_app_info));
1640 }
1641
1642
1643 /*! \brief Adds application monitoring related fields to a message.
1644 \param message The message.
1645 \param info The app_info of the concerned application.
1646 \return \c B_OK if everything went fine, an error code otherwise.
1647 */
1648 status_t
_AddMessageWatchingInfo(BMessage * message,const app_info * info)1649 TRoster::_AddMessageWatchingInfo(BMessage* message, const app_info* info)
1650 {
1651 status_t error = B_OK;
1652 if (error == B_OK)
1653 error = message->AddString("be:signature", info->signature);
1654 if (error == B_OK)
1655 error = message->AddInt32("be:team", info->team);
1656 if (error == B_OK)
1657 error = message->AddInt32("be:thread", info->thread);
1658 if (error == B_OK)
1659 error = message->AddInt32("be:flags", (int32)info->flags);
1660 if (error == B_OK)
1661 error = message->AddRef("be:ref", &info->ref);
1662 return error;
1663 }
1664
1665
1666 /*! \brief Returns the next available token.
1667 \return The token.
1668 */
1669 uint32
_NextToken()1670 TRoster::_NextToken()
1671 {
1672 return ++fLastToken;
1673 }
1674
1675
1676 /*! \brief Adds an IsAppRegistered() request to the given map.
1677
1678 If something goes wrong, the method deletes the request.
1679
1680 \param map The map the request shall be added to.
1681 \param key The key under which to add the request.
1682 \param request The request message to be added.
1683 */
1684 void
_AddIARRequest(IARRequestMap & map,int32 key,BMessage * request)1685 TRoster::_AddIARRequest(IARRequestMap& map, int32 key, BMessage* request)
1686 {
1687 IARRequestMap::iterator it = map.find(key);
1688 BMessageQueue* requests = NULL;
1689 if (it == map.end()) {
1690 requests = new(nothrow) BMessageQueue();
1691 if (!requests) {
1692 delete request;
1693 return;
1694 }
1695
1696 map[key] = requests;
1697 } else
1698 requests = it->second;
1699
1700 requests->AddMessage(request);
1701 }
1702
1703
1704 /*! \brief Invokes _ReplyToIARRequest() for all messages in the given
1705 message queue.
1706
1707 \param requests The request messages to be replied to
1708 \param info The RosterAppInfo of the application in question
1709 (may be \c NULL)
1710 */
1711 void
_ReplyToIARRequests(BMessageQueue * requests,const RosterAppInfo * info)1712 TRoster::_ReplyToIARRequests(BMessageQueue* requests, const RosterAppInfo* info)
1713 {
1714 while (BMessage* request = requests->NextMessage()) {
1715 _ReplyToIARRequest(request, info);
1716 delete request;
1717 }
1718 }
1719
1720
1721 /*! \brief Sends a reply message to an IsAppRegistered() request.
1722
1723 The message to be sent is a simple \c B_REG_SUCCESS message containing
1724 a "pre-registered" field, that says whether or not the application is
1725 pre-registered. It will be set to \c false, unless an \a info is supplied
1726 and the application this info refers to is pre-registered.
1727
1728 \param request The request message to be replied to
1729 \param info The RosterAppInfo of the application in question
1730 (may be \c NULL)
1731 */
1732 void
_ReplyToIARRequest(BMessage * request,const RosterAppInfo * info)1733 TRoster::_ReplyToIARRequest(BMessage* request, const RosterAppInfo* info)
1734 {
1735 // pre-registered or registered?
1736 bool preRegistered = false;
1737 if (info) {
1738 switch (info->state) {
1739 case APP_STATE_PRE_REGISTERED:
1740 preRegistered = true;
1741 break;
1742 case APP_STATE_UNREGISTERED:
1743 case APP_STATE_REGISTERED:
1744 preRegistered = false;
1745 break;
1746 }
1747 }
1748 // send reply
1749 BMessage reply(B_REG_SUCCESS);
1750 reply.AddBool("registered", (bool)info);
1751 reply.AddBool("pre-registered", preRegistered);
1752 PRINT("_ReplyToIARRequest(): pre-registered: %d\n", preRegistered);
1753 if (info)
1754 _AddMessageAppInfo(&reply, info);
1755 request->SendReply(&reply);
1756 }
1757
1758
1759 /*! \brief Handles requests for both GetRecentDocuments() and
1760 GetRecentFolders().
1761 */
1762 void
_HandleGetRecentEntries(BMessage * request)1763 TRoster::_HandleGetRecentEntries(BMessage* request)
1764 {
1765 FUNCTION_START();
1766 if (!request) {
1767 D(PRINT("WARNING: TRoster::HandleGetRecentFolders(NULL) called\n"));
1768 return;
1769 }
1770
1771 int32 maxCount;
1772 BMessage reply(B_REG_RESULT);
1773 char** fileTypes = NULL;
1774 int32 fileTypesCount = 0;
1775 char* appSig = NULL;
1776
1777 status_t error = request->FindInt32("max count", &maxCount);
1778 // Look for optional file type(s)
1779 if (!error) {
1780 type_code typeFound;
1781 status_t typeError = request->GetInfo("file type", &typeFound,
1782 &fileTypesCount);
1783 if (!typeError)
1784 typeError = typeFound == B_STRING_TYPE ? B_OK : B_BAD_TYPE;
1785 if (!typeError) {
1786 fileTypes = new(nothrow) char*[fileTypesCount];
1787 typeError = fileTypes ? B_OK : B_NO_MEMORY;
1788 }
1789 if (!typeError) {
1790 for (int i = 0; !error && i < fileTypesCount; i++) {
1791 const char* type;
1792 if (request->FindString("file type", i, &type) == B_OK) {
1793 fileTypes[i] = new(nothrow) char[B_MIME_TYPE_LENGTH];
1794 error = fileTypes[i] ? B_OK : B_NO_MEMORY;
1795 // Yes, I do mean to use "error" here, not "typeError"
1796 BPrivate::Storage::to_lower(type, fileTypes[i]);
1797 // Types are expected to be lowercase
1798 }
1799 }
1800 }
1801 }
1802 // Look for optional app sig
1803 if (!error) {
1804 const char* sig;
1805 error = request->FindString("app sig", &sig);
1806 if (!error) {
1807 appSig = new(nothrow) char[B_MIME_TYPE_LENGTH];
1808 error = appSig ? B_OK : B_NO_MEMORY;
1809 BPrivate::Storage::to_lower(sig, appSig);
1810 } else if (error == B_NAME_NOT_FOUND)
1811 error = B_OK;
1812 }
1813 if (!error) {
1814 switch (request->what) {
1815 case B_REG_GET_RECENT_DOCUMENTS:
1816 error = fRecentDocuments.Get(maxCount, (const char**)fileTypes,
1817 fileTypesCount, appSig, &reply);
1818 D(fRecentDocuments.Print());
1819 break;
1820
1821 case B_REG_GET_RECENT_FOLDERS:
1822 error = fRecentFolders.Get(maxCount, (const char**)fileTypes,
1823 fileTypesCount, appSig, &reply);
1824 D(fRecentFolders.Print());
1825 break;
1826
1827 default:
1828 D(PRINT("WARNING: TRoster::_HandleGetRecentEntries(): "
1829 "unexpected request->what value of 0x%" B_PRIx32 "\n",
1830 request->what));
1831 error = B_BAD_VALUE;
1832 break;
1833 }
1834 }
1835 reply.AddInt32("result", error);
1836 // Clean up before sending a reply
1837 delete [] appSig;
1838 if (fileTypes) {
1839 for (int i = 0; i < fileTypesCount; i++)
1840 delete [] fileTypes[i];
1841 delete[] fileTypes;
1842 fileTypes = NULL;
1843 }
1844 request->SendReply(&reply);
1845
1846 FUNCTION_END();
1847 }
1848
1849
1850 /*!
1851 \brief Checks all registered apps for \a ref and \a signature if
1852 they are still alive, and removes those that aren't.
1853 */
1854 void
_ValidateRunning(const entry_ref & ref,const char * signature)1855 TRoster::_ValidateRunning(const entry_ref& ref, const char* signature)
1856 {
1857 while (true) {
1858 // get info via ref or signature
1859 RosterAppInfo* info = fRegisteredApps.InfoFor(&ref);
1860 if (info == NULL && signature != NULL)
1861 info = fRegisteredApps.InfoFor(signature);
1862
1863 // if app is alive or does not exist, we can exit
1864 if (info == NULL || info->IsRunning())
1865 return;
1866
1867 RemoveApp(info);
1868 delete info;
1869 }
1870 }
1871
1872
1873 bool
_IsSystemApp(RosterAppInfo * info) const1874 TRoster::_IsSystemApp(RosterAppInfo* info) const
1875 {
1876 BPath path;
1877 if (path.SetTo(&info->ref) != B_OK || path.GetParent(&path) != B_OK)
1878 return false;
1879
1880 return !strcmp(path.Path(), fSystemAppPath.Path())
1881 || !strcmp(path.Path(), fSystemServerPath.Path());
1882 }
1883
1884
1885 status_t
_LoadRosterSettings(const char * path)1886 TRoster::_LoadRosterSettings(const char* path)
1887 {
1888 BPath _path;
1889 const char* settingsPath
1890 = path ? path : get_default_roster_settings_path(_path, false);
1891
1892 RosterSettingsCharStream stream;
1893 status_t error;
1894 BFile file;
1895
1896 error = file.SetTo(settingsPath, B_READ_ONLY);
1897 off_t size;
1898 if (!error)
1899 error = file.GetSize(&size);
1900
1901 char* data = NULL;
1902
1903 if (!error) {
1904 data = new(nothrow) char[size + 1];
1905 error = data ? B_OK : B_NO_MEMORY;
1906 }
1907 if (!error) {
1908 ssize_t bytes = file.Read(data, size);
1909 error = bytes < 0 ? bytes : (bytes == size ? B_OK : B_FILE_ERROR);
1910 }
1911 if (!error) {
1912 data[size] = 0;
1913 error = stream.SetTo(std::string(data));
1914 }
1915
1916 delete[] data;
1917
1918 if (!error) {
1919 // Clear the current lists as
1920 // we'll be manually building them up
1921 fRecentDocuments.Clear();
1922 fRecentFolders.Clear();
1923 fRecentApps.Clear();
1924
1925 // Now we just walk through the file and read in the info
1926 while (true) {
1927 status_t streamError;
1928 char str[B_PATH_NAME_LENGTH];
1929
1930 // (RecentDoc | RecentFolder | RecentApp)
1931 streamError = stream.GetString(str);
1932 if (!streamError) {
1933 enum EntryType {
1934 etDoc,
1935 etFolder,
1936 etApp,
1937 etSomethingIsAmiss,
1938 } type;
1939
1940 if (strcmp(str, "RecentDoc") == 0)
1941 type = etDoc;
1942 else if (strcmp(str, "RecentFolder") == 0)
1943 type = etFolder;
1944 else if (strcmp(str, "RecentApp") == 0)
1945 type = etApp;
1946 else
1947 type = etSomethingIsAmiss;
1948
1949 switch (type) {
1950 case etDoc:
1951 case etFolder:
1952 {
1953 // For curing laziness
1954 std::list<recent_entry*>* list = type == etDoc
1955 ? &fRecentDocuments.fEntryList
1956 : &fRecentFolders.fEntryList;
1957
1958 char path[B_PATH_NAME_LENGTH];
1959 char app[B_PATH_NAME_LENGTH];
1960 char rank[B_PATH_NAME_LENGTH];
1961 entry_ref ref;
1962 ulong index = 0;
1963
1964 // Convert the given path to an entry ref
1965 streamError = stream.GetString(path);
1966 if (!streamError)
1967 streamError = get_ref_for_path(path, &ref);
1968
1969 // Add a new entry to the list for each application
1970 // signature and rank we find
1971 while (!streamError) {
1972 if (!streamError)
1973 streamError = stream.GetString(app);
1974 if (!streamError) {
1975 BPrivate::Storage::to_lower(app);
1976 streamError = stream.GetString(rank);
1977 }
1978 if (!streamError) {
1979 index = strtoul(rank, NULL, 10);
1980 if (index == ULONG_MAX)
1981 streamError = errno;
1982 }
1983 recent_entry* entry = NULL;
1984 if (!streamError) {
1985 entry = new(nothrow) recent_entry(&ref, app,
1986 index);
1987 streamError = entry ? B_OK : B_NO_MEMORY;
1988 }
1989 if (!streamError) {
1990 D(printf("pushing entry, leaf == '%s', app == "
1991 "'%s', index == %" B_PRId32 "\n",
1992 entry->ref.name, entry->sig.c_str(),
1993 entry->index));
1994
1995 list->push_back(entry);
1996 }
1997 }
1998
1999 if (streamError) {
2000 D(printf("entry error 0x%" B_PRIx32 "\n",
2001 streamError));
2002 if (streamError
2003 != RosterSettingsCharStream::kEndOfLine
2004 && streamError
2005 != RosterSettingsCharStream::kEndOfStream)
2006 stream.SkipLine();
2007 }
2008
2009 break;
2010 }
2011
2012
2013 case etApp:
2014 {
2015 char app[B_PATH_NAME_LENGTH];
2016 streamError = stream.GetString(app);
2017 if (!streamError) {
2018 BPrivate::Storage::to_lower(app);
2019 fRecentApps.fAppList.push_back(app);
2020 } else
2021 stream.SkipLine();
2022 break;
2023 }
2024
2025 default:
2026 // Something was amiss; skip to the next line
2027 stream.SkipLine();
2028 break;
2029 }
2030
2031 }
2032
2033 if (streamError == RosterSettingsCharStream::kEndOfStream)
2034 break;
2035 }
2036
2037 // Now we must sort our lists of documents and folders by the
2038 // indicies we read for each entry (largest index first)
2039 fRecentDocuments.fEntryList.sort(larger_index);
2040 fRecentFolders.fEntryList.sort(larger_index);
2041
2042 D(
2043 printf("----------------------------------------------------------------------\n");
2044 fRecentDocuments.Print();
2045 printf("----------------------------------------------------------------------\n");
2046 fRecentFolders.Print();
2047 printf("----------------------------------------------------------------------\n");
2048 fRecentApps.Print();
2049 printf("----------------------------------------------------------------------\n");
2050 );
2051 }
2052 if (error) {
2053 D(PRINT("WARNING: TRoster::_LoadRosterSettings(): error loading roster "
2054 "settings from '%s', 0x%" B_PRIx32 "\n", settingsPath, error));
2055 }
2056 return error;
2057 }
2058
2059
2060 status_t
_SaveRosterSettings(const char * path)2061 TRoster::_SaveRosterSettings(const char* path)
2062 {
2063 BPath _path;
2064 const char* settingsPath
2065 = path != NULL ? path : get_default_roster_settings_path(_path, true);
2066
2067 status_t error;
2068 FILE* file;
2069
2070 file = fopen(settingsPath, "w+");
2071 error = file ? B_OK : errno;
2072 if (!error) {
2073 status_t saveError;
2074 saveError = fRecentDocuments.Save(file, "Recent documents", "RecentDoc");
2075 if (saveError) {
2076 D(PRINT("TRoster::_SaveRosterSettings(): recent documents save "
2077 "failed with error 0x%" B_PRIx32 "\n", saveError));
2078 }
2079 saveError = fRecentFolders.Save(file, "Recent folders", "RecentFolder");
2080 if (saveError) {
2081 D(PRINT("TRoster::_SaveRosterSettings(): recent folders save "
2082 "failed with error 0x%" B_PRIx32 "\n", saveError));
2083 }
2084 saveError = fRecentApps.Save(file);
2085 if (saveError) {
2086 D(PRINT("TRoster::_SaveRosterSettings(): recent folders save "
2087 "failed with error 0x%" B_PRIx32 "\n", saveError));
2088 }
2089 fclose(file);
2090 }
2091
2092 return error;
2093 }
2094