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