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