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