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