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