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