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