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