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