btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / registrar / TRoster.cpp
blobe8cd9a87651f8cf772eab8df2d8ca2d1af591cf4
1 /*
2 * Copyright 2001-2008, Ingo Weinhold, bonefish@users.sf.net.
3 * Distributed under the terms of the MIT License.
4 */
7 /*! TRoster is the incarnation of The Roster. It manages the running
8 applications.
9 */
12 #include "TRoster.h"
14 #include <new>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <strings.h>
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>
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>
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"
44 using std::nothrow;
45 using namespace BPrivate;
48 /*! \class TRoster
49 \brief Implements the application roster.
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.
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.
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.
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.
72 //! The maximal period of time an app may be early pre-registered (60 s).
73 const bigtime_t kMaximalEarlyPreRegistrationPeriod = 60000000LL;
76 // #pragma mark - Private local functions
79 /*! \brief Returns the path to the default roster settings.
81 \param path BPath to be set to the roster settings path.
82 \param createDirectory makes sure the target directory exists if \c true.
84 \return the settings path as C string (\code path.Path() \endcode).
86 static const char*
87 get_default_roster_settings_path(BPath& path, bool createDirectory)
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");
98 return path.Path();
102 /*! \brief Returns true if entry1's index is larger than entry2's index.
104 Also returns true if either entry is \c NULL.
106 Used for sorting the recent entry lists loaded from disk into the
107 proper order.
109 bool
110 larger_index(const recent_entry* entry1, const recent_entry* entry2)
112 if (entry1 && entry2)
113 return entry1->index > entry2->index;
115 return true;
119 // #pragma mark -
122 /*! \brief Creates a new roster.
124 The object is completely initialized and ready to handle requests.
126 TRoster::TRoster()
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)
141 find_directory(B_SYSTEM_DIRECTORY, &fSystemAppPath);
142 find_directory(B_SYSTEM_SERVERS_DIRECTORY, &fSystemServerPath);
146 /*! \brief Frees all resources associated with this object.
148 TRoster::~TRoster()
153 /*! \brief Handles an AddApplication() request.
154 \param request The request message
156 void
157 TRoster::HandleAddApplication(BMessage* request)
159 FUNCTION_START();
161 BAutolock _(fLock);
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;
187 PRINT("team: %" B_PRId32 ", signature: %s\n", team, signature);
188 PRINT("full registration: %d\n", fullReg);
190 if (fShuttingDown)
191 error = B_SHUTTING_DOWN;
193 // check the parameters
194 team_id otherTeam = -1;
195 uint32 token = 0;
197 uint32 launchFlags = flags & B_LAUNCH_MASK;
198 BEntry entry(&ref);
199 if (!entry.Exists())
200 SET_ERROR(error, B_ENTRY_NOT_FOUND);
202 if (error == B_OK)
203 _ValidateRunning(ref, signature);
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;
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;
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);
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);
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;
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);
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);
300 FUNCTION_END();
304 /*! \brief Handles a CompleteRegistration() request.
305 \param request The request message
307 void
308 TRoster::HandleCompleteRegistration(BMessage* request)
310 FUNCTION_START();
312 BAutolock _(fLock);
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;
326 if (fShuttingDown)
327 error = B_SHUTTING_DOWN;
329 // check the parameters
330 // port
331 if (error == B_OK && port < 0)
332 SET_ERROR(error, B_BAD_VALUE);
334 // thread
335 if (error == B_OK && thread < 0)
336 SET_ERROR(error, B_BAD_VALUE);
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);
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);
364 FUNCTION_END();
368 /*! \brief Handles an IsAppRegistered() request.
369 \param request The request message
371 void
372 TRoster::HandleIsAppRegistered(BMessage* request)
374 FUNCTION_START();
376 BAutolock _(fLock);
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;
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);
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);
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);
427 } else {
428 // reply to the request on error
429 BMessage reply(B_REG_ERROR);
430 reply.AddInt32("error", error);
431 request->SendReply(&reply);
434 FUNCTION_END();
438 /*! \brief Handles a RemovePreRegApp() request.
439 \param request The request message
441 void
442 TRoster::HandleRemovePreRegApp(BMessage* request)
444 FUNCTION_START();
446 BAutolock _(fLock);
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);
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);
472 FUNCTION_END();
476 /*! \brief Handles a RemoveApp() request.
477 \param request The request message
479 void
480 TRoster::HandleRemoveApp(BMessage* request)
482 FUNCTION_START();
484 BAutolock _(fLock);
486 status_t error = B_OK;
487 // get the parameters
488 team_id team;
489 if (request->FindInt32("team", &team) != B_OK)
490 team = -1;
492 PRINT("team: %" B_PRId32 "\n", team);
494 // remove the app
495 if (error == B_OK) {
496 if (RosterAppInfo* info = fRegisteredApps.InfoFor(team)) {
497 RemoveApp(info);
498 delete info;
499 } else
500 SET_ERROR(error, B_REG_APP_NOT_REGISTERED);
502 // reply to the request
503 if (error == B_OK) {
504 BMessage reply(B_REG_SUCCESS);
505 request->SendReply(&reply);
506 } else {
507 BMessage reply(B_REG_ERROR);
508 reply.AddInt32("error", error);
509 request->SendReply(&reply);
512 FUNCTION_END();
516 /*! \brief Handles a SetThreadAndTeam() request.
517 \param request The request message
519 void
520 TRoster::HandleSetThreadAndTeam(BMessage* request)
522 FUNCTION_START();
524 BAutolock _(fLock);
526 status_t error = B_OK;
528 // get the parameters
529 team_id team;
530 thread_id thread;
531 uint32 token;
532 if (request->FindInt32("team", &team) != B_OK)
533 team = -1;
534 if (request->FindInt32("thread", &thread) != B_OK)
535 thread = -1;
536 if (request->FindInt32("token", (int32*)&token) != B_OK)
537 SET_ERROR(error, B_BAD_VALUE);
539 // check the parameters
540 // team
541 if (error == B_OK && team < 0)
542 SET_ERROR(error, B_BAD_VALUE);
544 PRINT("team: %" B_PRId32 ", thread: %" B_PRId32 ", token: %" B_PRIu32 "\n",
545 team, thread, token);
547 port_id port = -1;
549 // update the app_info
550 if (error == B_OK) {
551 RosterAppInfo* info = fEarlyPreRegisteredApps.InfoForToken(token);
552 if (info != NULL) {
553 // Set thread and team, create a port for the application and
554 // move the app_info from the list of the early pre-registered
555 // apps to the list of the (pre-)registered apps.
556 fEarlyPreRegisteredApps.RemoveInfo(info);
557 info->team = team;
558 info->thread = thread;
559 // create and transfer the port
560 info->port = port = create_port(B_REG_APP_LOOPER_PORT_CAPACITY,
561 kRAppLooperPortName);
562 if (info->port < 0)
563 SET_ERROR(error, info->port);
564 if (error == B_OK)
565 SET_ERROR(error, set_port_owner(info->port, team));
566 // add the info to the registered apps list
567 if (error == B_OK)
568 SET_ERROR(error, AddApp(info));
569 // cleanup on failure
570 if (error != B_OK) {
571 if (info->port >= 0)
572 delete_port(info->port);
573 delete info;
574 info = NULL;
576 // handle pending IsAppRegistered() requests
577 IARRequestMap::iterator it = fIARRequestsByID.find(team);
578 if (it != fIARRequestsByID.end()) {
579 BMessageQueue* requests = it->second;
580 if (error == B_OK)
581 _ReplyToIARRequests(requests, info);
582 delete requests;
583 fIARRequestsByID.erase(it);
586 it = fIARRequestsByToken.find((int32)token);
587 if (it != fIARRequestsByToken.end()) {
588 BMessageQueue* requests = it->second;
589 if (error == B_OK)
590 _ReplyToIARRequests(requests, info);
591 delete requests;
592 fIARRequestsByToken.erase(it);
594 } else
595 SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
597 // reply to the request
598 if (error == B_OK) {
599 BMessage reply(B_REG_SUCCESS);
600 reply.AddInt32("port", port);
601 request->SendReply(&reply);
602 } else {
603 BMessage reply(B_REG_ERROR);
604 reply.AddInt32("error", error);
605 request->SendReply(&reply);
608 FUNCTION_END();
612 /*! \brief Handles a SetSignature() request.
613 \param request The request message
615 void
616 TRoster::HandleSetSignature(BMessage* request)
618 FUNCTION_START();
620 BAutolock _(fLock);
622 status_t error = B_OK;
623 // get the parameters
624 team_id team;
625 const char* signature;
626 if (request->FindInt32("team", &team) != B_OK)
627 error = B_BAD_VALUE;
628 if (request->FindString("signature", &signature) != B_OK)
629 error = B_BAD_VALUE;
630 // find the app and set the signature
631 if (error == B_OK) {
632 if (RosterAppInfo* info = fRegisteredApps.InfoFor(team))
633 strcpy(info->signature, signature);
634 else
635 SET_ERROR(error, B_REG_APP_NOT_REGISTERED);
637 // reply to the request
638 if (error == B_OK) {
639 BMessage reply(B_REG_SUCCESS);
640 request->SendReply(&reply);
641 } else {
642 BMessage reply(B_REG_ERROR);
643 reply.AddInt32("error", error);
644 request->SendReply(&reply);
647 FUNCTION_END();
651 /*! \brief Handles a Get{Running,Active,}AppInfo() request.
652 \param request The request message
654 void
655 TRoster::HandleGetAppInfo(BMessage* request)
657 FUNCTION_START();
659 BAutolock _(fLock);
661 status_t error = B_OK;
662 // get the parameters
663 team_id team;
664 entry_ref ref;
665 const char* signature;
666 bool hasTeam = true;
667 bool hasRef = true;
668 bool hasSignature = true;
669 if (request->FindInt32("team", &team) != B_OK)
670 hasTeam = false;
671 if (request->FindRef("ref", &ref) != B_OK)
672 hasRef = false;
673 if (request->FindString("signature", &signature) != B_OK)
674 hasSignature = false;
676 if (hasTeam)
677 PRINT("team: %" B_PRId32 "\n", team);
678 if (hasRef)
679 PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device, ref.directory,
680 ref.name);
681 if (hasSignature)
682 PRINT("signature: %s\n", signature);
684 // get the info
685 RosterAppInfo* info = NULL;
686 if (error == B_OK) {
687 if (hasTeam) {
688 info = fRegisteredApps.InfoFor(team);
689 if (info == NULL)
690 SET_ERROR(error, B_BAD_TEAM_ID);
691 } else if (hasRef) {
692 info = fRegisteredApps.InfoFor(&ref);
693 if (info == NULL)
694 SET_ERROR(error, B_ERROR);
695 } else if (hasSignature) {
696 info = fRegisteredApps.InfoFor(signature);
697 if (info == NULL)
698 SET_ERROR(error, B_ERROR);
699 } else {
700 // If neither of those has been supplied, the active application
701 // info is requested.
702 if (fActiveApp)
703 info = fActiveApp;
704 else
705 SET_ERROR(error, B_ERROR);
708 // reply to the request
709 if (error == B_OK) {
710 BMessage reply(B_REG_SUCCESS);
711 _AddMessageAppInfo(&reply, info);
712 request->SendReply(&reply);
713 } else {
714 BMessage reply(B_REG_ERROR);
715 reply.AddInt32("error", error);
716 request->SendReply(&reply);
719 FUNCTION_END();
723 /*! \brief Handles a GetAppList() request.
724 \param request The request message
726 void
727 TRoster::HandleGetAppList(BMessage* request)
729 FUNCTION_START();
731 BAutolock _(fLock);
733 status_t error = B_OK;
734 // get the parameters
735 const char* signature;
736 if (request->FindString("signature", &signature) != B_OK)
737 signature = NULL;
738 // reply to the request
739 if (error == B_OK) {
740 BMessage reply(B_REG_SUCCESS);
741 // get the list
742 for (AppInfoList::Iterator it(fRegisteredApps.It());
743 RosterAppInfo* info = *it;
744 ++it) {
745 if (info->state != APP_STATE_REGISTERED)
746 continue;
747 if (!signature || !strcasecmp(signature, info->signature))
748 reply.AddInt32("teams", info->team);
750 request->SendReply(&reply);
751 } else {
752 BMessage reply(B_REG_ERROR);
753 reply.AddInt32("error", error);
754 request->SendReply(&reply);
757 FUNCTION_END();
761 /*! \brief Handles a _UpdateActiveApp() request.
763 This is sent from the app_server when the current active application
764 is changed.
766 \param request The request message
768 void
769 TRoster::HandleUpdateActiveApp(BMessage* request)
771 FUNCTION_START();
773 BAutolock _(fLock);
775 // get the parameters
776 status_t error = B_OK;
777 team_id team;
778 if (request->FindInt32("team", &team) != B_OK)
779 error = B_BAD_VALUE;
781 // activate the app
782 if (error == B_OK) {
783 if (RosterAppInfo* info = fRegisteredApps.InfoFor(team))
784 UpdateActiveApp(info);
785 else
786 error = B_BAD_TEAM_ID;
789 // reply to the request
790 if (request->IsSourceWaiting()) {
791 if (error == B_OK) {
792 BMessage reply(B_REG_SUCCESS);
793 request->SendReply(&reply);
794 } else {
795 BMessage reply(B_REG_ERROR);
796 reply.AddInt32("error", error);
797 request->SendReply(&reply);
801 FUNCTION_END();
805 /*! \brief Handles a Broadcast() request.
806 \param request The request message
808 void
809 TRoster::HandleBroadcast(BMessage* request)
811 FUNCTION_START();
813 BAutolock _(fLock);
815 status_t error = B_OK;
816 // get the parameters
817 team_id team;
818 BMessage message;
819 BMessenger replyTarget;
820 if (request->FindInt32("team", &team) != B_OK)
821 team = -1;
822 if (error == B_OK && request->FindMessage("message", &message) != B_OK)
823 error = B_BAD_VALUE;
824 if (error == B_OK
825 && request->FindMessenger("reply_target", &replyTarget) != B_OK) {
826 error = B_BAD_VALUE;
829 // reply to the request -- do this first, don't let the inquirer wait
830 if (error == B_OK) {
831 BMessage reply(B_REG_SUCCESS);
832 request->SendReply(&reply);
833 } else {
834 BMessage reply(B_REG_ERROR);
835 reply.AddInt32("error", error);
836 request->SendReply(&reply);
839 // broadcast the message
840 if (error == B_OK) {
841 // the target set (excludes the registrar and the requesting team)
842 class BroadcastMessagingTargetSet
843 : public AppInfoListMessagingTargetSet {
844 public:
845 BroadcastMessagingTargetSet(AppInfoList& list, team_id team)
846 : AppInfoListMessagingTargetSet(list, true),
847 fTeam(team)
851 virtual bool Filter(const RosterAppInfo* info)
853 return AppInfoListMessagingTargetSet::Filter(info)
854 && (info->team != fTeam);
857 private:
858 team_id fTeam;
859 } targetSet(fRegisteredApps, team);
861 if (targetSet.HasNext()) {
862 // set the reply target
863 BMessage::Private(message).SetReply(replyTarget);
865 // send the messages
866 MessageDeliverer::Default()->DeliverMessage(&message, targetSet);
870 FUNCTION_END();
874 /*! \brief Handles a StartWatching() request.
875 \param request The request message
877 void
878 TRoster::HandleStartWatching(BMessage* request)
880 FUNCTION_START();
882 BAutolock _(fLock);
884 status_t error = B_OK;
885 // get the parameters
886 BMessenger target;
887 uint32 events;
888 if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
889 error = B_BAD_VALUE;
890 if (request->FindInt32("events", (int32*)&events) != B_OK)
891 error = B_BAD_VALUE;
892 // add the new watcher
893 if (error == B_OK) {
894 Watcher* watcher = new(nothrow) EventMaskWatcher(target, events);
895 if (watcher) {
896 if (!fWatchingService.AddWatcher(watcher)) {
897 error = B_NO_MEMORY;
898 delete watcher;
900 } else
901 error = B_NO_MEMORY;
903 // reply to the request
904 if (error == B_OK) {
905 BMessage reply(B_REG_SUCCESS);
906 request->SendReply(&reply);
907 } else {
908 BMessage reply(B_REG_ERROR);
909 reply.AddInt32("error", error);
910 request->SendReply(&reply);
913 FUNCTION_END();
917 /*! \brief Handles a StopWatching() request.
918 \param request The request message
920 void
921 TRoster::HandleStopWatching(BMessage* request)
923 FUNCTION_START();
925 BAutolock _(fLock);
927 status_t error = B_OK;
928 // get the parameters
929 BMessenger target;
930 if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
931 error = B_BAD_VALUE;
932 // remove the watcher
933 if (error == B_OK) {
934 if (!fWatchingService.RemoveWatcher(target))
935 error = B_BAD_VALUE;
937 // reply to the request
938 if (error == B_OK) {
939 BMessage reply(B_REG_SUCCESS);
940 request->SendReply(&reply);
941 } else {
942 BMessage reply(B_REG_ERROR);
943 reply.AddInt32("error", error);
944 request->SendReply(&reply);
947 FUNCTION_END();
951 /*! \brief Handles a GetRecentDocuments() request.
952 \param request The request message
954 void
955 TRoster::HandleGetRecentDocuments(BMessage* request)
957 FUNCTION_START();
959 BAutolock _(fLock);
961 _HandleGetRecentEntries(request);
963 FUNCTION_END();
967 /*! \brief Handles a GetRecentFolders() request.
968 \param request The request message
970 void
971 TRoster::HandleGetRecentFolders(BMessage* request)
973 FUNCTION_START();
975 BAutolock _(fLock);
977 _HandleGetRecentEntries(request);
979 FUNCTION_END();
983 /*! \brief Handles a GetRecentApps() request.
984 \param request The request message
986 void
987 TRoster::HandleGetRecentApps(BMessage* request)
989 FUNCTION_START();
991 BAutolock _(fLock);
993 if (!request) {
994 D(PRINT("WARNING: TRoster::HandleGetRecentApps(NULL) called\n"));
995 return;
998 int32 maxCount;
999 BMessage reply(B_REG_RESULT);
1001 status_t error = request->FindInt32("max count", &maxCount);
1002 if (!error)
1003 error = fRecentApps.Get(maxCount, &reply);
1004 reply.AddInt32("result", error);
1005 request->SendReply(&reply);
1007 FUNCTION_END();
1011 /*! \brief Handles an AddToRecentDocuments() request.
1012 \param request The request message
1014 void
1015 TRoster::HandleAddToRecentDocuments(BMessage* request)
1017 FUNCTION_START();
1019 BAutolock _(fLock);
1021 if (!request) {
1022 D(PRINT("WARNING: TRoster::HandleAddToRecentDocuments(NULL) called\n"));
1023 return;
1026 entry_ref ref;
1027 const char* appSig;
1028 BMessage reply(B_REG_RESULT);
1030 status_t error = request->FindRef("ref", &ref);
1031 if (!error)
1032 error = request->FindString("app sig", &appSig);
1033 if (!error)
1034 error = fRecentDocuments.Add(&ref, appSig);
1035 reply.AddInt32("result", error);
1036 request->SendReply(&reply);
1038 FUNCTION_END();
1042 /*! \brief Handles an AddToRecentFolders() request.
1043 \param request The request message
1045 void
1046 TRoster::HandleAddToRecentFolders(BMessage* request)
1048 FUNCTION_START();
1050 BAutolock _(fLock);
1052 if (!request) {
1053 D(PRINT("WARNING: TRoster::HandleAddToRecentFolders(NULL) called\n"));
1054 return;
1057 entry_ref ref;
1058 const char* appSig;
1059 BMessage reply(B_REG_RESULT);
1061 status_t error = request->FindRef("ref", &ref);
1062 if (!error)
1063 error = request->FindString("app sig", &appSig);
1064 if (!error)
1065 error = fRecentFolders.Add(&ref, appSig);
1066 reply.AddInt32("result", error);
1067 request->SendReply(&reply);
1069 FUNCTION_END();
1073 /*! \brief Handles an AddToRecentApps() request.
1074 \param request The request message
1076 void
1077 TRoster::HandleAddToRecentApps(BMessage* request)
1079 FUNCTION_START();
1081 BAutolock _(fLock);
1083 if (!request) {
1084 D(PRINT("WARNING: TRoster::HandleAddToRecentApps(NULL) called\n"));
1085 return;
1088 const char* appSig;
1089 BMessage reply(B_REG_RESULT);
1091 status_t error = request->FindString("app sig", &appSig);
1092 if (!error)
1093 error = fRecentApps.Add(appSig);
1094 reply.AddInt32("result", error);
1095 request->SendReply(&reply);
1097 FUNCTION_END();
1101 void
1102 TRoster::HandleLoadRecentLists(BMessage* request)
1104 FUNCTION_START();
1106 BAutolock _(fLock);
1108 if (!request) {
1109 D(PRINT("WARNING: TRoster::HandleLoadRecentLists(NULL) called\n"));
1110 return;
1113 const char* filename;
1114 BMessage reply(B_REG_RESULT);
1116 status_t error = request->FindString("filename", &filename);
1117 if (!error)
1118 error = _LoadRosterSettings(filename);
1119 reply.AddInt32("result", error);
1120 request->SendReply(&reply);
1122 FUNCTION_END();
1126 void
1127 TRoster::HandleSaveRecentLists(BMessage* request)
1129 FUNCTION_START();
1131 BAutolock _(fLock);
1133 if (!request) {
1134 D(PRINT("WARNING: TRoster::HandleSaveRecentLists(NULL) called\n"));
1135 return;
1138 const char* filename;
1139 BMessage reply(B_REG_RESULT);
1141 status_t error = request->FindString("filename", &filename);
1142 if (!error)
1143 error = _SaveRosterSettings(filename);
1144 reply.AddInt32("result", error);
1145 request->SendReply(&reply);
1147 FUNCTION_END();
1151 void
1152 TRoster::HandleRestartAppServer(BMessage* request)
1154 BAutolock _(fLock);
1156 // TODO: if an app_server is still running, stop it first
1158 const char* pathString;
1159 if (request->FindString("path", &pathString) != B_OK)
1160 pathString = "/boot/system/servers";
1161 BPath path(pathString);
1162 path.Append("app_server");
1163 // NOTE: its required at some point that the binary name is "app_server"
1165 const char **argv = new const char * [2];
1166 argv[0] = strdup(path.Path());
1167 argv[1] = NULL;
1169 thread_id threadId = load_image(1, argv, (const char**)environ);
1170 int i;
1171 for (i = 0; i < 1; i++)
1172 delete argv[i];
1173 delete [] argv;
1175 resume_thread(threadId);
1176 // give the server some time to create the server port
1177 snooze(100000);
1179 // notify all apps
1180 // TODO: whats about ourself?
1181 AppInfoListMessagingTargetSet targetSet(fRegisteredApps);
1182 if (targetSet.HasNext()) {
1183 // send the messages
1184 BMessage message(kMsgAppServerRestarted);
1185 MessageDeliverer::Default()->DeliverMessage(&message, targetSet);
1190 /*! \brief Clears the current list of recent documents
1192 void
1193 TRoster::ClearRecentDocuments()
1195 BAutolock _(fLock);
1197 fRecentDocuments.Clear();
1201 /*! \brief Clears the current list of recent folders
1203 void
1204 TRoster::ClearRecentFolders()
1206 BAutolock _(fLock);
1208 fRecentFolders.Clear();
1212 /*! \brief Clears the current list of recent apps
1214 void
1215 TRoster::ClearRecentApps()
1217 BAutolock _(fLock);
1219 fRecentApps.Clear();
1223 /*! \brief Initializes the roster.
1225 Currently only adds the registrar to the roster.
1226 The application must already be running, more precisly Run() must have
1227 been called.
1229 \return
1230 - \c B_OK: Everything went fine.
1231 - an error code
1233 status_t
1234 TRoster::Init()
1236 // check lock initialization
1237 if (fLock.Sem() < 0)
1238 return fLock.Sem();
1240 // create the info
1241 RosterAppInfo* info = new(nothrow) RosterAppInfo;
1242 if (info == NULL)
1243 return B_NO_MEMORY;
1245 // get the app's ref
1246 entry_ref ref;
1247 status_t error = get_app_ref(&ref);
1249 // init and add the info
1250 if (error == B_OK) {
1251 info->Init(be_app->Thread(), be_app->Team(),
1252 BMessenger::Private(be_app_messenger).Port(),
1253 B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP, &ref, B_REGISTRAR_SIGNATURE);
1254 info->state = APP_STATE_REGISTERED;
1255 info->registration_time = system_time();
1256 error = AddApp(info);
1259 if (error == B_OK)
1260 _LoadRosterSettings();
1262 // cleanup on error
1263 if (error != B_OK)
1264 delete info;
1266 return error;
1270 /*! \brief Add the supplied app info to the list of (pre-)registered apps.
1272 \param info The app info to be added
1274 status_t
1275 TRoster::AddApp(RosterAppInfo* info)
1277 BAutolock _(fLock);
1279 status_t error = (info ? B_OK : B_BAD_VALUE);
1280 if (info) {
1281 if (!fRegisteredApps.AddInfo(info))
1282 error = B_NO_MEMORY;
1284 return error;
1288 /*! \brief Removes the supplied app info from the list of (pre-)registered
1289 apps.
1291 \param info The app info to be removed
1293 void
1294 TRoster::RemoveApp(RosterAppInfo* info)
1296 BAutolock _(fLock);
1298 if (info) {
1299 if (fRegisteredApps.RemoveInfo(info)) {
1300 if (info->state == APP_STATE_REGISTERED) {
1301 info->state = APP_STATE_UNREGISTERED;
1302 _AppRemoved(info);
1309 /*! \brief Activates the application identified by \a info.
1311 The currently active application is deactivated and the one whose
1312 info is supplied is activated. \a info may be \c NULL, which only
1313 deactivates the currently active application.
1315 \param info The info of the app to be activated
1317 void
1318 TRoster::UpdateActiveApp(RosterAppInfo* info)
1320 BAutolock _(fLock);
1322 if (info != fActiveApp) {
1323 // deactivate the currently active app
1324 RosterAppInfo* oldActiveApp = fActiveApp;
1325 fActiveApp = NULL;
1326 if (oldActiveApp)
1327 _AppDeactivated(oldActiveApp);
1329 // activate the new app
1330 if (info) {
1331 fActiveApp = info;
1332 _AppActivated(info);
1338 /*! \brief Checks whether the (pre-)registered applications are still running.
1340 This is necessary, since killed applications don't unregister properly.
1342 void
1343 TRoster::CheckSanity()
1345 BAutolock _(fLock);
1347 // not early (pre-)registered applications
1348 AppInfoList obsoleteApps;
1349 for (AppInfoList::Iterator it = fRegisteredApps.It(); it.IsValid(); ++it) {
1350 if (!(*it)->IsRunning())
1351 obsoleteApps.AddInfo(*it);
1354 // remove the apps
1355 for (AppInfoList::Iterator it = obsoleteApps.It(); it.IsValid(); ++it) {
1356 RemoveApp(*it);
1357 delete *it;
1359 obsoleteApps.MakeEmpty(false);
1360 // don't delete infos a second time
1362 // early pre-registered applications
1363 bigtime_t timeLimit = system_time() - kMaximalEarlyPreRegistrationPeriod;
1364 for (AppInfoList::Iterator it = fEarlyPreRegisteredApps.It();
1365 it.IsValid();
1366 ++it) {
1367 if ((*it)->registration_time < timeLimit)
1368 obsoleteApps.AddInfo(*it);
1371 // remove the apps
1372 for (AppInfoList::Iterator it = obsoleteApps.It(); it.IsValid(); ++it) {
1373 fEarlyPreRegisteredApps.RemoveInfo(*it);
1374 delete *it;
1376 obsoleteApps.MakeEmpty(false);
1377 // don't delete infos a second time
1381 /*! \brief Tells the roster whether a shutdown process is in progess at the
1382 moment.
1384 After this method is called with \a shuttingDown == \c true, no more
1385 applications can be created.
1387 \param shuttingDown \c true, to indicate the start of the shutdown process,
1388 \c false to signalling its end.
1390 void
1391 TRoster::SetShuttingDown(bool shuttingDown)
1393 BAutolock _(fLock);
1395 fShuttingDown = shuttingDown;
1397 if (shuttingDown)
1398 _SaveRosterSettings();
1402 /*! \brief Returns lists of applications to be asked to quit on shutdown.
1404 \param userApps List of RosterAppInfos identifying the user applications.
1405 Those will be ask to quit first.
1406 \param systemApps List of RosterAppInfos identifying the system applications
1407 (like Tracker and Deskbar), which will be asked to quit after the
1408 user applications are gone.
1409 \param vitalSystemApps A set of team_ids identifying teams that must not
1410 be terminated (app server and registrar).
1411 \return \c B_OK, if everything went fine, another error code otherwise.
1413 status_t
1414 TRoster::GetShutdownApps(AppInfoList& userApps, AppInfoList& systemApps,
1415 AppInfoList& backgroundApps, hash_set<team_id>& vitalSystemApps)
1417 BAutolock _(fLock);
1419 status_t error = B_OK;
1421 // get the vital system apps:
1422 // * ourself
1423 // * kernel team
1424 // * app server
1425 // * debug server
1427 // ourself
1428 vitalSystemApps.insert(be_app->Team());
1430 // kernel team
1431 team_info teamInfo;
1432 if (get_team_info(B_SYSTEM_TEAM, &teamInfo) == B_OK)
1433 vitalSystemApps.insert(teamInfo.team);
1435 // app server
1436 RosterAppInfo* info
1437 = fRegisteredApps.InfoFor("application/x-vnd.haiku-app_server");
1438 if (info != NULL)
1439 vitalSystemApps.insert(info->team);
1441 // debug server
1442 info = fRegisteredApps.InfoFor("application/x-vnd.haiku-debug_server");
1443 if (info != NULL)
1444 vitalSystemApps.insert(info->team);
1446 // populate the other groups
1447 for (AppInfoList::Iterator it(fRegisteredApps.It());
1448 RosterAppInfo* info = *it; ++it) {
1449 if (vitalSystemApps.find(info->team) == vitalSystemApps.end()) {
1450 RosterAppInfo* clonedInfo = info->Clone();
1451 if (clonedInfo) {
1452 if (_IsSystemApp(info)) {
1453 if (!systemApps.AddInfo(clonedInfo))
1454 error = B_NO_MEMORY;
1455 } else if (info->flags & B_BACKGROUND_APP) {
1456 if (!backgroundApps.AddInfo(clonedInfo))
1457 error = B_NO_MEMORY;
1458 } else {
1459 if (!userApps.AddInfo(clonedInfo))
1460 error = B_NO_MEMORY;
1463 if (error != B_OK)
1464 delete clonedInfo;
1465 } else
1466 error = B_NO_MEMORY;
1469 if (error != B_OK)
1470 break;
1473 // Special case, we add the input server to vital apps here so it is
1474 // not excluded in the lists above
1475 info = fRegisteredApps.InfoFor("application/x-vnd.Be-input_server");
1476 if (info != NULL)
1477 vitalSystemApps.insert(info->team);
1479 // clean up on error
1480 if (error != B_OK) {
1481 userApps.MakeEmpty(true);
1482 systemApps.MakeEmpty(true);
1485 return error;
1489 status_t
1490 TRoster::AddWatcher(Watcher* watcher)
1492 BAutolock _(fLock);
1494 if (!watcher)
1495 return B_BAD_VALUE;
1497 if (!fWatchingService.AddWatcher(watcher))
1498 return B_NO_MEMORY;
1500 return B_OK;
1504 void
1505 TRoster::RemoveWatcher(Watcher* watcher)
1507 BAutolock _(fLock);
1509 if (watcher)
1510 fWatchingService.RemoveWatcher(watcher, false);
1514 /*! \brief Hook method invoked, when an application has been fully registered.
1515 \param info The RosterAppInfo of the added application.
1517 void
1518 TRoster::_AppAdded(RosterAppInfo* info)
1520 // notify the watchers
1521 BMessage message(B_SOME_APP_LAUNCHED);
1522 _AddMessageWatchingInfo(&message, info);
1523 EventMaskWatcherFilter filter(B_REQUEST_LAUNCHED);
1524 fWatchingService.NotifyWatchers(&message, &filter);
1528 /*! \brief Hook method invoked, when a fully registered application has been
1529 removed.
1530 \param info The RosterAppInfo of the removed application.
1532 void
1533 TRoster::_AppRemoved(RosterAppInfo* info)
1535 if (info) {
1536 // deactivate the app, if it was the active one
1537 if (info == fActiveApp)
1538 UpdateActiveApp(NULL);
1540 // notify the watchers
1541 BMessage message(B_SOME_APP_QUIT);
1542 _AddMessageWatchingInfo(&message, info);
1543 EventMaskWatcherFilter filter(B_REQUEST_QUIT);
1544 fWatchingService.NotifyWatchers(&message, &filter);
1549 /*! \brief Hook method invoked, when an application has been activated.
1550 \param info The RosterAppInfo of the activated application.
1552 void
1553 TRoster::_AppActivated(RosterAppInfo* info)
1555 if (info != NULL && info->state == APP_STATE_REGISTERED) {
1556 // send B_APP_ACTIVATED to the app
1557 BMessenger messenger;
1558 BMessenger::Private messengerPrivate(messenger);
1559 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN);
1560 BMessage message(B_APP_ACTIVATED);
1561 message.AddBool("active", true);
1562 // not sure, if it makes sense to use the MessageDeliverer here
1563 MessageDeliverer::Default()->DeliverMessage(&message, messenger);
1565 // notify the watchers
1566 BMessage watcherMessage(B_SOME_APP_ACTIVATED);
1567 _AddMessageWatchingInfo(&watcherMessage, info);
1568 EventMaskWatcherFilter filter(B_REQUEST_ACTIVATED);
1569 fWatchingService.NotifyWatchers(&watcherMessage, &filter);
1574 /*! \brief Hook method invoked, when an application has been deactivated.
1575 \param info The RosterAppInfo of the deactivated application.
1577 void
1578 TRoster::_AppDeactivated(RosterAppInfo* info)
1580 if (info != NULL && info->state == APP_STATE_REGISTERED) {
1581 // send B_APP_ACTIVATED to the app
1582 BMessenger messenger;
1583 BMessenger::Private messengerPrivate(messenger);
1584 messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN);
1585 BMessage message(B_APP_ACTIVATED);
1586 message.AddBool("active", false);
1587 // not sure, if it makes sense to use the MessageDeliverer here
1588 MessageDeliverer::Default()->DeliverMessage(&message, messenger);
1593 /*! \brief Adds an app_info to a message.
1595 The info is added as a flat_app_info to a field "app_info" with the type
1596 \c B_REG_APP_INFO_TYPE.
1598 \param message The message
1599 \param info The app_info.
1600 \return \c B_OK if everything went fine, an error code otherwise.
1602 status_t
1603 TRoster::_AddMessageAppInfo(BMessage* message, const app_info* info)
1605 // An app_info is not completely flat. The entry_ref contains a string
1606 // pointer. Therefore we flatten the info.
1607 flat_app_info flatInfo;
1608 flatInfo.info = *info;
1610 // set the ref name to NULL and copy it into the flat structure
1611 flatInfo.info.ref.name = NULL;
1612 flatInfo.ref_name[0] = '\0';
1613 if (info->ref.name)
1614 strcpy(flatInfo.ref_name, info->ref.name);
1616 // add the flat info
1617 return message->AddData("app_info", B_REG_APP_INFO_TYPE, &flatInfo,
1618 sizeof(flat_app_info));
1622 /*! \brief Adds application monitoring related fields to a message.
1623 \param message The message.
1624 \param info The app_info of the concerned application.
1625 \return \c B_OK if everything went fine, an error code otherwise.
1627 status_t
1628 TRoster::_AddMessageWatchingInfo(BMessage* message, const app_info* info)
1630 status_t error = B_OK;
1631 if (error == B_OK)
1632 error = message->AddString("be:signature", info->signature);
1633 if (error == B_OK)
1634 error = message->AddInt32("be:team", info->team);
1635 if (error == B_OK)
1636 error = message->AddInt32("be:thread", info->thread);
1637 if (error == B_OK)
1638 error = message->AddInt32("be:flags", (int32)info->flags);
1639 if (error == B_OK)
1640 error = message->AddRef("be:ref", &info->ref);
1641 return error;
1645 /*! \brief Returns the next available token.
1646 \return The token.
1648 uint32
1649 TRoster::_NextToken()
1651 return ++fLastToken;
1655 /*! \brief Adds an IsAppRegistered() request to the given map.
1657 If something goes wrong, the method deletes the request.
1659 \param map The map the request shall be added to.
1660 \param key The key under which to add the request.
1661 \param request The request message to be added.
1663 void
1664 TRoster::_AddIARRequest(IARRequestMap& map, int32 key, BMessage* request)
1666 IARRequestMap::iterator it = map.find(key);
1667 BMessageQueue* requests = NULL;
1668 if (it == map.end()) {
1669 requests = new(nothrow) BMessageQueue();
1670 if (!requests) {
1671 delete request;
1672 return;
1675 map[key] = requests;
1676 } else
1677 requests = it->second;
1679 requests->AddMessage(request);
1683 /*! \brief Invokes _ReplyToIARRequest() for all messages in the given
1684 message queue.
1686 \param requests The request messages to be replied to
1687 \param info The RosterAppInfo of the application in question
1688 (may be \c NULL)
1690 void
1691 TRoster::_ReplyToIARRequests(BMessageQueue* requests, const RosterAppInfo* info)
1693 while (BMessage* request = requests->NextMessage()) {
1694 _ReplyToIARRequest(request, info);
1695 delete request;
1700 /*! \brief Sends a reply message to an IsAppRegistered() request.
1702 The message to be sent is a simple \c B_REG_SUCCESS message containing
1703 a "pre-registered" field, that says whether or not the application is
1704 pre-registered. It will be set to \c false, unless an \a info is supplied
1705 and the application this info refers to is pre-registered.
1707 \param request The request message to be replied to
1708 \param info The RosterAppInfo of the application in question
1709 (may be \c NULL)
1711 void
1712 TRoster::_ReplyToIARRequest(BMessage* request, const RosterAppInfo* info)
1714 // pre-registered or registered?
1715 bool preRegistered = false;
1716 if (info) {
1717 switch (info->state) {
1718 case APP_STATE_PRE_REGISTERED:
1719 preRegistered = true;
1720 break;
1721 case APP_STATE_UNREGISTERED:
1722 case APP_STATE_REGISTERED:
1723 preRegistered = false;
1724 break;
1727 // send reply
1728 BMessage reply(B_REG_SUCCESS);
1729 reply.AddBool("registered", (bool)info);
1730 reply.AddBool("pre-registered", preRegistered);
1731 PRINT("_ReplyToIARRequest(): pre-registered: %d\n", preRegistered);
1732 if (info)
1733 _AddMessageAppInfo(&reply, info);
1734 request->SendReply(&reply);
1738 /*! \brief Handles requests for both GetRecentDocuments() and
1739 GetRecentFolders().
1741 void
1742 TRoster::_HandleGetRecentEntries(BMessage* request)
1744 FUNCTION_START();
1745 if (!request) {
1746 D(PRINT("WARNING: TRoster::HandleGetRecentFolders(NULL) called\n"));
1747 return;
1750 int32 maxCount;
1751 BMessage reply(B_REG_RESULT);
1752 char** fileTypes = NULL;
1753 int32 fileTypesCount = 0;
1754 char* appSig = NULL;
1756 status_t error = request->FindInt32("max count", &maxCount);
1757 // Look for optional file type(s)
1758 if (!error) {
1759 type_code typeFound;
1760 status_t typeError = request->GetInfo("file type", &typeFound,
1761 &fileTypesCount);
1762 if (!typeError)
1763 typeError = typeFound == B_STRING_TYPE ? B_OK : B_BAD_TYPE;
1764 if (!typeError) {
1765 fileTypes = new(nothrow) char*[fileTypesCount];
1766 typeError = fileTypes ? B_OK : B_NO_MEMORY;
1768 if (!typeError) {
1769 for (int i = 0; !error && i < fileTypesCount; i++) {
1770 const char* type;
1771 if (request->FindString("file type", i, &type) == B_OK) {
1772 fileTypes[i] = new(nothrow) char[B_MIME_TYPE_LENGTH];
1773 error = fileTypes[i] ? B_OK : B_NO_MEMORY;
1774 // Yes, I do mean to use "error" here, not "typeError"
1775 BPrivate::Storage::to_lower(type, fileTypes[i]);
1776 // Types are expected to be lowercase
1781 // Look for optional app sig
1782 if (!error) {
1783 const char* sig;
1784 error = request->FindString("app sig", &sig);
1785 if (!error) {
1786 appSig = new(nothrow) char[B_MIME_TYPE_LENGTH];
1787 error = appSig ? B_OK : B_NO_MEMORY;
1788 BPrivate::Storage::to_lower(sig, appSig);
1789 } else if (error == B_NAME_NOT_FOUND)
1790 error = B_OK;
1792 if (!error) {
1793 switch (request->what) {
1794 case B_REG_GET_RECENT_DOCUMENTS:
1795 error = fRecentDocuments.Get(maxCount, (const char**)fileTypes,
1796 fileTypesCount, appSig, &reply);
1797 D(fRecentDocuments.Print());
1798 break;
1800 case B_REG_GET_RECENT_FOLDERS:
1801 error = fRecentFolders.Get(maxCount, (const char**)fileTypes,
1802 fileTypesCount, appSig, &reply);
1803 D(fRecentFolders.Print());
1804 break;
1806 default:
1807 D(PRINT("WARNING: TRoster::_HandleGetRecentEntries(): "
1808 "unexpected request->what value of 0x%" B_PRIx32 "\n",
1809 request->what));
1810 error = B_BAD_VALUE;
1811 break;
1814 reply.AddInt32("result", error);
1815 // Clean up before sending a reply
1816 delete [] appSig;
1817 if (fileTypes) {
1818 for (int i = 0; i < fileTypesCount; i++)
1819 delete [] fileTypes[i];
1820 delete[] fileTypes;
1821 fileTypes = NULL;
1823 request->SendReply(&reply);
1825 FUNCTION_END();
1830 \brief Checks all registered apps for \a ref and \a signature if
1831 they are still alive, and removes those that aren't.
1833 void
1834 TRoster::_ValidateRunning(const entry_ref& ref, const char* signature)
1836 while (true) {
1837 // get info via ref or signature
1838 RosterAppInfo* info = fRegisteredApps.InfoFor(&ref);
1839 if (info == NULL && signature != NULL)
1840 info = fRegisteredApps.InfoFor(signature);
1842 // if app is alive or does not exist, we can exit
1843 if (info == NULL || info->IsRunning())
1844 return;
1846 RemoveApp(info);
1847 delete info;
1852 bool
1853 TRoster::_IsSystemApp(RosterAppInfo* info) const
1855 BPath path;
1856 if (path.SetTo(&info->ref) != B_OK || path.GetParent(&path) != B_OK)
1857 return false;
1859 return !strcmp(path.Path(), fSystemAppPath.Path())
1860 || !strcmp(path.Path(), fSystemServerPath.Path());
1864 status_t
1865 TRoster::_LoadRosterSettings(const char* path)
1867 BPath _path;
1868 const char* settingsPath
1869 = path ? path : get_default_roster_settings_path(_path, false);
1871 RosterSettingsCharStream stream;
1872 status_t error;
1873 BFile file;
1875 error = file.SetTo(settingsPath, B_READ_ONLY);
1876 off_t size;
1877 if (!error)
1878 error = file.GetSize(&size);
1880 char* data = NULL;
1882 if (!error) {
1883 data = new(nothrow) char[size + 1];
1884 error = data ? B_OK : B_NO_MEMORY;
1886 if (!error) {
1887 ssize_t bytes = file.Read(data, size);
1888 error = bytes < 0 ? bytes : (bytes == size ? B_OK : B_FILE_ERROR);
1890 if (!error) {
1891 data[size] = 0;
1892 error = stream.SetTo(std::string(data));
1895 delete[] data;
1897 if (!error) {
1898 // Clear the current lists as
1899 // we'll be manually building them up
1900 fRecentDocuments.Clear();
1901 fRecentFolders.Clear();
1902 fRecentApps.Clear();
1904 // Now we just walk through the file and read in the info
1905 while (true) {
1906 status_t streamError;
1907 char str[B_PATH_NAME_LENGTH];
1909 // (RecentDoc | RecentFolder | RecentApp)
1910 streamError = stream.GetString(str);
1911 if (!streamError) {
1912 enum EntryType {
1913 etDoc,
1914 etFolder,
1915 etApp,
1916 etSomethingIsAmiss,
1917 } type;
1919 if (strcmp(str, "RecentDoc") == 0)
1920 type = etDoc;
1921 else if (strcmp(str, "RecentFolder") == 0)
1922 type = etFolder;
1923 else if (strcmp(str, "RecentApp") == 0)
1924 type = etApp;
1925 else
1926 type = etSomethingIsAmiss;
1928 switch (type) {
1929 case etDoc:
1930 case etFolder:
1932 // For curing laziness
1933 std::list<recent_entry*>* list = type == etDoc
1934 ? &fRecentDocuments.fEntryList
1935 : &fRecentFolders.fEntryList;
1937 char path[B_PATH_NAME_LENGTH];
1938 char app[B_PATH_NAME_LENGTH];
1939 char rank[B_PATH_NAME_LENGTH];
1940 entry_ref ref;
1941 ulong index = 0;
1943 // Convert the given path to an entry ref
1944 streamError = stream.GetString(path);
1945 if (!streamError)
1946 streamError = get_ref_for_path(path, &ref);
1948 // Add a new entry to the list for each application
1949 // signature and rank we find
1950 while (!streamError) {
1951 if (!streamError)
1952 streamError = stream.GetString(app);
1953 if (!streamError) {
1954 BPrivate::Storage::to_lower(app);
1955 streamError = stream.GetString(rank);
1957 if (!streamError) {
1958 index = strtoul(rank, NULL, 10);
1959 if (index == ULONG_MAX)
1960 streamError = errno;
1962 recent_entry* entry = NULL;
1963 if (!streamError) {
1964 entry = new(nothrow) recent_entry(&ref, app,
1965 index);
1966 streamError = entry ? B_OK : B_NO_MEMORY;
1968 if (!streamError) {
1969 D(printf("pushing entry, leaf == '%s', app == "
1970 "'%s', index == %" B_PRId32 "\n",
1971 entry->ref.name, entry->sig.c_str(),
1972 entry->index));
1974 list->push_back(entry);
1978 if (streamError) {
1979 D(printf("entry error 0x%" B_PRIx32 "\n",
1980 streamError));
1981 if (streamError
1982 != RosterSettingsCharStream::kEndOfLine
1983 && streamError
1984 != RosterSettingsCharStream::kEndOfStream)
1985 stream.SkipLine();
1988 break;
1992 case etApp:
1994 char app[B_PATH_NAME_LENGTH];
1995 streamError = stream.GetString(app);
1996 if (!streamError) {
1997 BPrivate::Storage::to_lower(app);
1998 fRecentApps.fAppList.push_back(app);
1999 } else
2000 stream.SkipLine();
2001 break;
2004 default:
2005 // Something was amiss; skip to the next line
2006 stream.SkipLine();
2007 break;
2012 if (streamError == RosterSettingsCharStream::kEndOfStream)
2013 break;
2016 // Now we must sort our lists of documents and folders by the
2017 // indicies we read for each entry (largest index first)
2018 fRecentDocuments.fEntryList.sort(larger_index);
2019 fRecentFolders.fEntryList.sort(larger_index);
2022 printf("----------------------------------------------------------------------\n");
2023 fRecentDocuments.Print();
2024 printf("----------------------------------------------------------------------\n");
2025 fRecentFolders.Print();
2026 printf("----------------------------------------------------------------------\n");
2027 fRecentApps.Print();
2028 printf("----------------------------------------------------------------------\n");
2031 if (error) {
2032 D(PRINT("WARNING: TRoster::_LoadRosterSettings(): error loading roster "
2033 "settings from '%s', 0x%" B_PRIx32 "\n", settingsPath, error));
2035 return error;
2039 status_t
2040 TRoster::_SaveRosterSettings(const char* path)
2042 BPath _path;
2043 const char* settingsPath
2044 = path != NULL ? path : get_default_roster_settings_path(_path, true);
2046 status_t error;
2047 FILE* file;
2049 file = fopen(settingsPath, "w+");
2050 error = file ? B_OK : errno;
2051 if (!error) {
2052 status_t saveError;
2053 saveError = fRecentDocuments.Save(file, "Recent documents", "RecentDoc");
2054 if (saveError) {
2055 D(PRINT("TRoster::_SaveRosterSettings(): recent documents save "
2056 "failed with error 0x%" B_PRIx32 "\n", saveError));
2058 saveError = fRecentFolders.Save(file, "Recent folders", "RecentFolder");
2059 if (saveError) {
2060 D(PRINT("TRoster::_SaveRosterSettings(): recent folders save "
2061 "failed with error 0x%" B_PRIx32 "\n", saveError));
2063 saveError = fRecentApps.Save(file);
2064 if (saveError) {
2065 D(PRINT("TRoster::_SaveRosterSettings(): recent folders save "
2066 "failed with error 0x%" B_PRIx32 "\n", saveError));
2068 fclose(file);
2071 return error;