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