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