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