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