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