xref: /haiku/src/servers/registrar/TRoster.cpp (revision c207330527b13270b07bb307dbe66e0f096e3baa)
1 /*
2  * Copyright 2001-2008, Ingo Weinhold, bonefish@users.sf.net.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 /*!	TRoster is the incarnation of The Roster. It manages the running
8 	applications.
9 */
10 
11 
12 #include "TRoster.h"
13 
14 #include <new>
15 
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <strings.h>
20 
21 #include <Application.h>
22 #include <AutoDeleter.h>
23 #include <Autolock.h>
24 #include <Directory.h>
25 #include <File.h>
26 #include <FindDirectory.h>
27 #include <Path.h>
28 
29 #include <AppMisc.h>
30 #include <MessagePrivate.h>
31 #include <MessengerPrivate.h>
32 #include <RosterPrivate.h>
33 #include <ServerProtocol.h>
34 #include <storage_support.h>
35 
36 #include "AppInfoListMessagingTargetSet.h"
37 #include "Debug.h"
38 #include "EventMaskWatcher.h"
39 #include "MessageDeliverer.h"
40 #include "RegistrarDefs.h"
41 #include "RosterAppInfo.h"
42 #include "RosterSettingsCharStream.h"
43 
44 using std::nothrow;
45 using namespace BPrivate;
46 
47 
48 /*!	\class TRoster
49 	\brief Implements the application roster.
50 
51 	This class handles the BRoster requests. For each kind a hook method is
52 	implemented to which the registrar looper dispatches the request messages.
53 
54 	Registered and pre-registered are managed via AppInfoLists.
55 	\a fEarlyPreRegisteredApps contains the infos for those application that
56 	are pre-registered and currently have no team ID assigned to them yet,
57 	whereas the infos of registered and pre-registered applications with a
58 	team ID are to be found in \a fRegisteredApps.
59 
60 	When an application asks whether it is pre-registered or not and there
61 	are one or more instances of the application that are pre-registered, but
62 	have no team ID assigned yet, the reply to the request has to be
63 	postponed until the status of the requesting team is clear. The request
64 	message is dequeued from the registrar's message queue and added to
65 	\a fIARRequestsByID for a later reply.
66 
67 	The field \a fActiveApp identifies the currently active application
68 	and \a fLastToken is a counter used to generate unique tokens for
69 	pre-registered applications.
70 */
71 
72 //! The maximal period of time an app may be early pre-registered (60 s).
73 const bigtime_t kMaximalEarlyPreRegistrationPeriod = 60000000LL;
74 
75 
76 //	#pragma mark - Private local functions
77 
78 
79 /*!	\brief Returns the path to the default roster settings.
80 
81 	\param path BPath to be set to the roster settings path.
82 	\param createDirectory makes sure the target directory exists if \c true.
83 
84 	\return the settings path as C string (\code path.Path() \endcode).
85 */
86 static const char*
get_default_roster_settings_path(BPath & path,bool createDirectory)87 get_default_roster_settings_path(BPath& path, bool createDirectory)
88 {
89 	// get the path of the settings dir and append the subpath of our file
90 	status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
91 	if (error == B_OK)
92 		error = path.Append("system/registrar");
93 	if (error == B_OK && createDirectory)
94 		error = create_directory(path.Path(), 0777);
95 	if (error == B_OK)
96 		error = path.Append("RosterSettings");
97 
98 	return path.Path();
99 }
100 
101 
102 /*! \brief Returns true if entry1's index is larger than entry2's index.
103 
104 	Also returns true if either entry is \c NULL.
105 
106 	Used for sorting the recent entry lists loaded from disk into the
107 	proper order.
108 */
109 bool
larger_index(const recent_entry * entry1,const recent_entry * entry2)110 larger_index(const recent_entry* entry1, const recent_entry* entry2)
111 {
112 	if (entry1 && entry2)
113 		return entry1->index > entry2->index;
114 
115 	return true;
116 }
117 
118 
119 //	#pragma mark -
120 
121 
122 /*!	\brief Creates a new roster.
123 
124 	The object is completely initialized and ready to handle requests.
125 */
TRoster()126 TRoster::TRoster()
127 	:
128 	fLock("roster"),
129 	fRegisteredApps(),
130 	fEarlyPreRegisteredApps(),
131 	fIARRequestsByID(),
132 	fIARRequestsByToken(),
133 	fActiveApp(NULL),
134 	fWatchingService(),
135 	fRecentApps(),
136 	fRecentDocuments(),
137 	fRecentFolders(),
138 	fLastToken(0),
139 	fShuttingDown(false)
140 {
141 	find_directory(B_SYSTEM_DIRECTORY, &fSystemAppPath);
142 	find_directory(B_SYSTEM_SERVERS_DIRECTORY, &fSystemServerPath);
143 }
144 
145 
146 /*!	\brief Frees all resources associated with this object.
147 */
~TRoster()148 TRoster::~TRoster()
149 {
150 }
151 
152 
153 /*!	\brief Handles an AddApplication() request.
154 	\param request The request message
155 */
156 void
HandleAddApplication(BMessage * request)157 TRoster::HandleAddApplication(BMessage* request)
158 {
159 	FUNCTION_START();
160 
161 	BAutolock _(fLock);
162 
163 	status_t error = B_OK;
164 	// get the parameters
165 	const char* signature;
166 	entry_ref ref;
167 	uint32 flags;
168 	team_id team;
169 	thread_id thread;
170 	port_id port;
171 	bool fullReg;
172 	if (request->FindString("signature", &signature) != B_OK)
173 		signature = NULL;
174 	if (request->FindRef("ref", &ref) != B_OK)
175 		SET_ERROR(error, B_BAD_VALUE);
176 	if (request->FindInt32("flags", (int32*)&flags) != B_OK)
177 		flags = B_REG_DEFAULT_APP_FLAGS;
178 	if (request->FindInt32("team", &team) != B_OK)
179 		team = -1;
180 	if (request->FindInt32("thread", &thread) != B_OK)
181 		thread = -1;
182 	if (request->FindInt32("port", &port) != B_OK)
183 		port = -1;
184 	if (request->FindBool("full_registration", &fullReg) != B_OK)
185 		fullReg = false;
186 
187 	PRINT("team: %" B_PRId32 ", signature: %s\n", team, signature);
188 	PRINT("full registration: %d\n", fullReg);
189 
190 	if (fShuttingDown)
191 		error = B_SHUTTING_DOWN;
192 
193 	// check the parameters
194 	team_id otherTeam = -1;
195 	uint32 token = 0;
196 
197 	uint32 launchFlags = flags & B_LAUNCH_MASK;
198 	BEntry entry(&ref);
199 	if (!entry.Exists())
200 		SET_ERROR(error, B_ENTRY_NOT_FOUND);
201 
202 	if (error == B_OK)
203 		_ValidateRunning(ref, signature);
204 
205 	// entry_ref
206 	if (error == B_OK) {
207 		PRINT("flags: %" B_PRIx32 "\n", flags);
208 		PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device,
209 			ref.directory, ref.name);
210 		// check single/exclusive launchers
211 		RosterAppInfo* info = NULL;
212 		if ((launchFlags == B_SINGLE_LAUNCH
213 			 || launchFlags ==  B_EXCLUSIVE_LAUNCH)
214 			&& ((info = fRegisteredApps.InfoFor(&ref)) != NULL
215 				|| (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL)) {
216 			SET_ERROR(error, B_ALREADY_RUNNING);
217 			otherTeam = info->team;
218 			token = info->token;
219 		}
220 	}
221 
222 	// signature
223 	if (error == B_OK && signature) {
224 		// check exclusive launchers
225 		RosterAppInfo* info = NULL;
226 		if (launchFlags == B_EXCLUSIVE_LAUNCH
227 			&& (((info = fRegisteredApps.InfoFor(signature)))
228 				|| ((info = fEarlyPreRegisteredApps.InfoFor(signature))))) {
229 			SET_ERROR(error, B_ALREADY_RUNNING);
230 			otherTeam = info->team;
231 			token = info->token;
232 		}
233 	}
234 
235 	// If no team ID is given, full registration isn't possible.
236 	if (error == B_OK) {
237 		if (team < 0) {
238 			if (fullReg)
239 				SET_ERROR(error, B_BAD_VALUE);
240 		} else if (fRegisteredApps.InfoFor(team))
241 			SET_ERROR(error, B_REG_ALREADY_REGISTERED);
242 	}
243 
244 	// Add the application info.
245 	if (error == B_OK) {
246 		// alloc and init the info
247 		RosterAppInfo* info = new(nothrow) RosterAppInfo;
248 		if (info) {
249 			info->Init(thread, team, port, flags, &ref, signature);
250 			if (fullReg)
251 				info->state = APP_STATE_REGISTERED;
252 			else
253 				info->state = APP_STATE_PRE_REGISTERED;
254 			info->registration_time = system_time();
255 			// add it to the right list
256 			bool addingSuccess = false;
257 			if (team >= 0) {
258 				PRINT("added ref: %" B_PRId32 ", %" B_PRId64 ", %s\n",
259 					info->ref.device, info->ref.directory, info->ref.name);
260 				addingSuccess = (AddApp(info) == B_OK);
261 				if (addingSuccess && fullReg)
262 					_AppAdded(info);
263 			} else {
264 				token = info->token = _NextToken();
265 				addingSuccess = fEarlyPreRegisteredApps.AddInfo(info);
266 				PRINT("added to early pre-regs, token: %" B_PRIu32 "\n", token);
267 			}
268 			if (!addingSuccess)
269 				SET_ERROR(error, B_NO_MEMORY);
270 		} else
271 			SET_ERROR(error, B_NO_MEMORY);
272 		// delete the info on failure
273 		if (error != B_OK && info)
274 			delete info;
275 	}
276 
277 	// reply to the request
278 	if (error == B_OK) {
279 		// add to recent apps if successful
280 		if (signature && signature[0] != '\0')
281 			fRecentApps.Add(signature, flags);
282 		else
283 			fRecentApps.Add(&ref, flags);
284 
285 		BMessage reply(B_REG_SUCCESS);
286 		// The token is valid only when no team ID has been supplied.
287 		if (team < 0)
288 			reply.AddInt32("token", (int32)token);
289 		request->SendReply(&reply);
290 	} else {
291 		BMessage reply(B_REG_ERROR);
292 		reply.AddInt32("error", error);
293 		if (otherTeam >= 0)
294 			reply.AddInt32("other_team", otherTeam);
295 		if (token > 0)
296 			reply.AddInt32("token", (int32)token);
297 		request->SendReply(&reply);
298 	}
299 
300 	FUNCTION_END();
301 }
302 
303 
304 /*!	\brief Handles a CompleteRegistration() request.
305 	\param request The request message
306 */
307 void
HandleCompleteRegistration(BMessage * request)308 TRoster::HandleCompleteRegistration(BMessage* request)
309 {
310 	FUNCTION_START();
311 
312 	BAutolock _(fLock);
313 
314 	status_t error = B_OK;
315 	// get the parameters
316 	team_id team;
317 	thread_id thread;
318 	port_id port;
319 	if (request->FindInt32("team", &team) != B_OK)
320 		team = -1;
321 	if (request->FindInt32("thread", &thread) != B_OK)
322 		thread = -1;
323 	if (request->FindInt32("port", &port) != B_OK)
324 		port = -1;
325 
326 	if (fShuttingDown)
327 		error = B_SHUTTING_DOWN;
328 
329 	// check the parameters
330 	// port
331 	if (error == B_OK && port < 0)
332 		SET_ERROR(error, B_BAD_VALUE);
333 
334 	// thread
335 	if (error == B_OK && thread < 0)
336 		SET_ERROR(error, B_BAD_VALUE);
337 
338 	// team
339 	if (error == B_OK) {
340 		if (team >= 0) {
341 			// everything is fine -- set the values
342 			RosterAppInfo* info = fRegisteredApps.InfoFor(team);
343 			if (info && info->state == APP_STATE_PRE_REGISTERED) {
344 				info->thread = thread;
345 				info->port = port;
346 				info->state = APP_STATE_REGISTERED;
347 				_AppAdded(info);
348 			} else
349 				SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
350 		} else
351 			SET_ERROR(error, B_BAD_VALUE);
352 	}
353 
354 	// reply to the request
355 	if (error == B_OK) {
356 		BMessage reply(B_REG_SUCCESS);
357 		request->SendReply(&reply);
358 	} else {
359 		BMessage reply(B_REG_ERROR);
360 		reply.AddInt32("error", error);
361 		request->SendReply(&reply);
362 	}
363 
364 	FUNCTION_END();
365 }
366 
367 
368 /*!	\brief Handles an IsAppRegistered() request.
369 	\param request The request message
370 */
371 void
HandleIsAppRegistered(BMessage * request)372 TRoster::HandleIsAppRegistered(BMessage* request)
373 {
374 	FUNCTION_START();
375 
376 	BAutolock _(fLock);
377 
378 	status_t error = B_OK;
379 	// get the parameters
380 	entry_ref ref;
381 	team_id team;
382 	uint32 token;
383 	if (request->FindRef("ref", &ref) != B_OK)
384 		SET_ERROR(error, B_BAD_VALUE);
385 	if (request->FindInt32("team", &team) != B_OK)
386 		team = -1;
387 	if (request->FindInt32("token", (int32*)&token) != B_OK)
388 		token = 0;
389 
390 	PRINT("team: %" B_PRId32 ", token: %" B_PRIu32 "\n", team, token);
391 	PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device, ref.directory,
392 		ref.name);
393 
394 	// check the parameters
395 	// entry_ref
396 	if (error == B_OK && !BEntry(&ref).Exists())
397 		SET_ERROR(error, B_ENTRY_NOT_FOUND);
398 	// team/token
399 	if (error == B_OK && team < 0 && token == 0)
400 		SET_ERROR(error, B_BAD_VALUE);
401 
402 	// look up the information
403 	RosterAppInfo* info = NULL;
404 	if (error == B_OK) {
405 		if ((info = fRegisteredApps.InfoFor(team)) != NULL) {
406 			PRINT("found team in fRegisteredApps\n");
407 			_ReplyToIARRequest(request, info);
408 		} else if (token > 0
409 			&& (info = fEarlyPreRegisteredApps.InfoForToken(token)) != NULL) {
410 			PRINT("found ref in fEarlyRegisteredApps (by token)\n");
411 			// pre-registered and has no team ID assigned yet -- queue the
412 			// request
413 			be_app->DetachCurrentMessage();
414 			_AddIARRequest(fIARRequestsByToken, token, request);
415 		} else if (team >= 0
416 			&& (info = fEarlyPreRegisteredApps.InfoFor(&ref)) != NULL) {
417 			PRINT("found ref in fEarlyRegisteredApps (by ref)\n");
418 			// pre-registered and has no team ID assigned yet -- queue the
419 			// request
420 			be_app->DetachCurrentMessage();
421 			_AddIARRequest(fIARRequestsByID, team, request);
422 		} else {
423 			PRINT("didn't find team or ref\n");
424 			// team not registered, ref/token not early pre-registered
425 			_ReplyToIARRequest(request, NULL);
426 		}
427 	} else {
428 		// reply to the request on error
429 		BMessage reply(B_REG_ERROR);
430 		reply.AddInt32("error", error);
431 		request->SendReply(&reply);
432 	}
433 
434 	FUNCTION_END();
435 }
436 
437 
438 /*!	\brief Handles a RemovePreRegApp() request.
439 	\param request The request message
440 */
441 void
HandleRemovePreRegApp(BMessage * request)442 TRoster::HandleRemovePreRegApp(BMessage* request)
443 {
444 	FUNCTION_START();
445 
446 	BAutolock _(fLock);
447 
448 	status_t error = B_OK;
449 	// get the parameters
450 	uint32 token;
451 	if (request->FindInt32("token", (int32*)&token) != B_OK)
452 		SET_ERROR(error, B_BAD_VALUE);
453 	// remove the app
454 	if (error == B_OK) {
455 		RosterAppInfo* info = fEarlyPreRegisteredApps.InfoForToken(token);
456 		if (info) {
457 			fEarlyPreRegisteredApps.RemoveInfo(info);
458 			delete info;
459 		} else
460 			SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
461 	}
462 	// reply to the request
463 	if (error == B_OK) {
464 		BMessage reply(B_REG_SUCCESS);
465 		request->SendReply(&reply);
466 	} else {
467 		BMessage reply(B_REG_ERROR);
468 		reply.AddInt32("error", error);
469 		request->SendReply(&reply);
470 	}
471 
472 	FUNCTION_END();
473 }
474 
475 
476 /*!	\brief Handles a RemoveApp() request.
477 	\param request The request message
478 */
479 void
HandleRemoveApp(BMessage * request)480 TRoster::HandleRemoveApp(BMessage* request)
481 {
482 	FUNCTION_START();
483 
484 	BAutolock _(fLock);
485 
486 	status_t error = B_OK;
487 	// get the parameters
488 	team_id team;
489 	error = request->FindInt32("team", &team);
490 	PRINT("team: %" B_PRId32 "\n", team);
491 
492 	// remove the app
493 	if (error == B_OK) {
494 		if (RosterAppInfo* info = fRegisteredApps.InfoFor(team)) {
495 			RemoveApp(info);
496 			delete info;
497 		} else
498 			SET_ERROR(error, B_REG_APP_NOT_REGISTERED);
499 	}
500 	// reply to the request
501 	if (error == B_OK) {
502 		BMessage reply(B_REG_SUCCESS);
503 		request->SendReply(&reply);
504 	} else {
505 		BMessage reply(B_REG_ERROR);
506 		reply.AddInt32("error", error);
507 		request->SendReply(&reply);
508 	}
509 
510 	FUNCTION_END();
511 }
512 
513 
514 /*!	\brief Handles a SetThreadAndTeam() request.
515 	\param request The request message
516 */
517 void
HandleSetThreadAndTeam(BMessage * request)518 TRoster::HandleSetThreadAndTeam(BMessage* request)
519 {
520 	FUNCTION_START();
521 
522 	BAutolock _(fLock);
523 
524 	status_t error = B_OK;
525 
526 	// get the parameters
527 	team_id team;
528 	thread_id thread;
529 	uint32 token;
530 	if (request->FindInt32("team", &team) != B_OK)
531 		team = -1;
532 	if (request->FindInt32("thread", &thread) != B_OK)
533 		thread = -1;
534 	if (request->FindInt32("token", (int32*)&token) != B_OK)
535 		SET_ERROR(error, B_BAD_VALUE);
536 
537 	// check the parameters
538 	// team
539 	if (error == B_OK && team < 0)
540 		SET_ERROR(error, B_BAD_VALUE);
541 
542 	PRINT("team: %" B_PRId32 ", thread: %" B_PRId32 ", token: %" B_PRIu32 "\n",
543 		team, thread, token);
544 
545 	port_id port = -1;
546 
547 	// update the app_info
548 	if (error == B_OK) {
549 		RosterAppInfo* info = fEarlyPreRegisteredApps.InfoForToken(token);
550 		if (info != NULL) {
551 			// Set thread and team, create a port for the application and
552 			// move the app_info from the list of the early pre-registered
553 			// apps to the list of the (pre-)registered apps.
554 			fEarlyPreRegisteredApps.RemoveInfo(info);
555 			info->team = team;
556 			info->thread = thread;
557 			// create and transfer the port
558 			info->port = port = create_port(B_REG_APP_LOOPER_PORT_CAPACITY,
559 				kRAppLooperPortName);
560 			if (info->port < 0)
561 				SET_ERROR(error, info->port);
562 			if (error == B_OK)
563 				SET_ERROR(error, set_port_owner(info->port, team));
564 			// add the info to the registered apps list
565 			if (error == B_OK)
566 				SET_ERROR(error, AddApp(info));
567 			// cleanup on failure
568 			if (error != B_OK) {
569 				if (info->port >= 0)
570 					delete_port(info->port);
571 				delete info;
572 				info = NULL;
573 			}
574 			// handle pending IsAppRegistered() requests
575 			IARRequestMap::iterator it = fIARRequestsByID.find(team);
576 			if (it != fIARRequestsByID.end()) {
577 				BMessageQueue* requests = it->second;
578 				if (error == B_OK)
579 					_ReplyToIARRequests(requests, info);
580 				delete requests;
581 				fIARRequestsByID.erase(it);
582 			}
583 
584 			it = fIARRequestsByToken.find((int32)token);
585 			if (it != fIARRequestsByToken.end()) {
586 				BMessageQueue* requests = it->second;
587 				if (error == B_OK)
588 					_ReplyToIARRequests(requests, info);
589 				delete requests;
590 				fIARRequestsByToken.erase(it);
591 			}
592 		} else
593 			SET_ERROR(error, B_REG_APP_NOT_PRE_REGISTERED);
594 	}
595 	// reply to the request
596 	if (error == B_OK) {
597 		BMessage reply(B_REG_SUCCESS);
598 		reply.AddInt32("port", port);
599 		request->SendReply(&reply);
600 	} else {
601 		BMessage reply(B_REG_ERROR);
602 		reply.AddInt32("error", error);
603 		request->SendReply(&reply);
604 	}
605 
606 	FUNCTION_END();
607 }
608 
609 
610 /*!	\brief Handles a SetSignature() request.
611 	\param request The request message
612 */
613 void
HandleSetSignature(BMessage * request)614 TRoster::HandleSetSignature(BMessage* request)
615 {
616 	FUNCTION_START();
617 
618 	BAutolock _(fLock);
619 
620 	status_t error = B_OK;
621 	// get the parameters
622 	team_id team;
623 	const char* signature;
624 	if (request->FindInt32("team", &team) != B_OK)
625 		error = B_BAD_VALUE;
626 	if (request->FindString("signature", &signature) != B_OK)
627 		error = B_BAD_VALUE;
628 	// find the app and set the signature
629 	if (error == B_OK) {
630 		if (RosterAppInfo* info = fRegisteredApps.InfoFor(team))
631 			strcpy(info->signature, signature);
632 		else
633 			SET_ERROR(error, B_REG_APP_NOT_REGISTERED);
634 	}
635 	// reply to the request
636 	if (error == B_OK) {
637 		BMessage reply(B_REG_SUCCESS);
638 		request->SendReply(&reply);
639 	} else {
640 		BMessage reply(B_REG_ERROR);
641 		reply.AddInt32("error", error);
642 		request->SendReply(&reply);
643 	}
644 
645 	FUNCTION_END();
646 }
647 
648 
649 /*!	\brief Handles a Get{Running,Active,}AppInfo() request.
650 	\param request The request message
651 */
652 void
HandleGetAppInfo(BMessage * request)653 TRoster::HandleGetAppInfo(BMessage* request)
654 {
655 	FUNCTION_START();
656 
657 	BAutolock _(fLock);
658 
659 	// get the parameters
660 	team_id team;
661 	entry_ref ref;
662 	const char* signature;
663 	bool hasTeam = true;
664 	bool hasRef = true;
665 	bool hasSignature = true;
666 	if (request->FindInt32("team", &team) != B_OK)
667 		hasTeam = false;
668 	if (request->FindRef("ref", &ref) != B_OK)
669 		hasRef = false;
670 	if (request->FindString("signature", &signature) != B_OK)
671 		hasSignature = false;
672 
673 	if (hasTeam)
674 		PRINT("team: %" B_PRId32 "\n", team);
675 	if (hasRef) {
676 		PRINT("ref: %" B_PRId32 ", %" B_PRId64 ", %s\n", ref.device,
677 			ref.directory, ref.name);
678 	}
679 	if (hasSignature)
680 		PRINT("signature: %s\n", signature);
681 
682 	// get the info
683 	RosterAppInfo* info = NULL;
684 	status_t error = B_OK;
685 	if (hasTeam) {
686 		info = fRegisteredApps.InfoFor(team);
687 		if (info == NULL)
688 			SET_ERROR(error, B_BAD_TEAM_ID);
689 	} else if (hasRef) {
690 		info = fRegisteredApps.InfoFor(&ref);
691 		if (info == NULL)
692 			SET_ERROR(error, B_ERROR);
693 	} else if (hasSignature) {
694 		info = fRegisteredApps.InfoFor(signature);
695 		if (info == NULL)
696 			SET_ERROR(error, B_ERROR);
697 	} else {
698 		// If neither of those has been supplied, the active application
699 		// info is requested.
700 		if (fActiveApp)
701 			info = fActiveApp;
702 		else
703 			SET_ERROR(error, B_ERROR);
704 	}
705 
706 	// reply to the request
707 	if (error == B_OK) {
708 		BMessage reply(B_REG_SUCCESS);
709 		_AddMessageAppInfo(&reply, info);
710 		request->SendReply(&reply);
711 	} else {
712 		BMessage reply(B_REG_ERROR);
713 		reply.AddInt32("error", error);
714 		request->SendReply(&reply);
715 	}
716 
717 	FUNCTION_END();
718 }
719 
720 
721 /*!	\brief Handles a GetAppList() request.
722 	\param request The request message
723 */
724 void
HandleGetAppList(BMessage * request)725 TRoster::HandleGetAppList(BMessage* request)
726 {
727 	FUNCTION_START();
728 
729 	BAutolock _(fLock);
730 
731 	// get the parameters
732 	const char* signature;
733 	if (request->FindString("signature", &signature) != B_OK)
734 		signature = NULL;
735 
736 	// reply to the request
737 	BMessage reply(B_REG_SUCCESS);
738 	// get the list
739 	for (AppInfoList::Iterator it(fRegisteredApps.It());
740 		 RosterAppInfo* info = *it;
741 		 ++it) {
742 		if (info->state != APP_STATE_REGISTERED)
743 			continue;
744 		if (signature == NULL || strcasecmp(signature, info->signature) == 0)
745 			reply.AddInt32("teams", info->team);
746 	}
747 	request->SendReply(&reply);
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
HandleUpdateActiveApp(BMessage * request)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
HandleBroadcast(BMessage * request)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
HandleStartWatching(BMessage * request)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
HandleStopWatching(BMessage * request)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
HandleGetRecentDocuments(BMessage * request)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
HandleGetRecentFolders(BMessage * request)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
HandleGetRecentApps(BMessage * request)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
HandleAddToRecentDocuments(BMessage * request)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
HandleAddToRecentFolders(BMessage * request)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
HandleAddToRecentApps(BMessage * request)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
HandleLoadRecentLists(BMessage * request)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
HandleSaveRecentLists(BMessage * request)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
HandleRestartAppServer(BMessage * request)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
ClearRecentDocuments()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
ClearRecentFolders()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
ClearRecentApps()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
Init()1226 TRoster::Init()
1227 {
1228 	// check lock initialization
1229 	if (fLock.InitCheck() < 0)
1230 		return fLock.InitCheck();
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, B_REGISTRAR_SIGNATURE);
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
AddApp(RosterAppInfo * info)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
RemoveApp(RosterAppInfo * info)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
UpdateActiveApp(RosterAppInfo * info)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
CheckSanity()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
SetShuttingDown(bool shuttingDown)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
GetShutdownApps(AppInfoList & userApps,AppInfoList & systemApps,AppInfoList & backgroundApps,HashSet<HashKey32<team_id>> & vitalSystemApps)1406 TRoster::GetShutdownApps(AppInfoList& userApps, AppInfoList& systemApps,
1407 	AppInfoList& backgroundApps, HashSet<HashKey32<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.Add(be_app->Team());
1421 
1422 	// kernel team
1423 	team_info teamInfo;
1424 	if (get_team_info(B_SYSTEM_TEAM, &teamInfo) == B_OK)
1425 		vitalSystemApps.Add(teamInfo.team);
1426 
1427 	// app server
1428 	RosterAppInfo* info
1429 		= fRegisteredApps.InfoFor("application/x-vnd.haiku-app_server");
1430 	if (info != NULL)
1431 		vitalSystemApps.Add(info->team);
1432 
1433 	// debug server
1434 	info = fRegisteredApps.InfoFor("application/x-vnd.haiku-debug_server");
1435 	if (info != NULL)
1436 		vitalSystemApps.Add(info->team);
1437 
1438 	// populate the other groups
1439 	for (AppInfoList::Iterator it(fRegisteredApps.It());
1440 			RosterAppInfo* info = *it; ++it) {
1441 		if (!vitalSystemApps.Contains(info->team)) {
1442 			RosterAppInfo* clonedInfo = info->Clone();
1443 			if (clonedInfo) {
1444 				if (_IsSystemApp(info)) {
1445 					if (!systemApps.AddInfo(clonedInfo))
1446 						error = B_NO_MEMORY;
1447 				} else if (info->flags & B_BACKGROUND_APP) {
1448 					if (!backgroundApps.AddInfo(clonedInfo))
1449 						error = B_NO_MEMORY;
1450 				} else {
1451 					if (!userApps.AddInfo(clonedInfo))
1452 						error = B_NO_MEMORY;
1453 				}
1454 
1455 				if (error != B_OK)
1456 					delete clonedInfo;
1457 			} else
1458 				error = B_NO_MEMORY;
1459 		}
1460 
1461 		if (error != B_OK)
1462 			break;
1463 	}
1464 
1465 	// Special case, we add the input server to vital apps here so it is
1466 	// not excluded in the lists above
1467 	info = fRegisteredApps.InfoFor("application/x-vnd.Be-input_server");
1468 	if (info != NULL)
1469 		vitalSystemApps.Add(info->team);
1470 
1471 	// clean up on error
1472 	if (error != B_OK) {
1473 		userApps.MakeEmpty(true);
1474 		systemApps.MakeEmpty(true);
1475 	}
1476 
1477 	return error;
1478 }
1479 
1480 
1481 status_t
AddAppInfo(AppInfoList & apps,team_id team)1482 TRoster::AddAppInfo(AppInfoList& apps, team_id team)
1483 {
1484 	BAutolock _(fLock);
1485 
1486 	for (AppInfoList::Iterator it(fRegisteredApps.It());
1487 			RosterAppInfo* info = *it; ++it) {
1488 		if (info->team == team) {
1489 			RosterAppInfo* clonedInfo = info->Clone();
1490 			status_t error = B_NO_MEMORY;
1491 			if (clonedInfo != NULL) {
1492 				if (!apps.AddInfo(clonedInfo))
1493 					delete clonedInfo;
1494 				else
1495 					error = B_OK;
1496 			}
1497 			return error;
1498 		}
1499 	}
1500 
1501 	return B_BAD_TEAM_ID;
1502 }
1503 
1504 
1505 status_t
AddWatcher(Watcher * watcher)1506 TRoster::AddWatcher(Watcher* watcher)
1507 {
1508 	BAutolock _(fLock);
1509 
1510 	if (!watcher)
1511 		return B_BAD_VALUE;
1512 
1513 	if (!fWatchingService.AddWatcher(watcher))
1514 		return B_NO_MEMORY;
1515 
1516 	return B_OK;
1517 }
1518 
1519 
1520 void
RemoveWatcher(Watcher * watcher)1521 TRoster::RemoveWatcher(Watcher* watcher)
1522 {
1523 	BAutolock _(fLock);
1524 
1525 	if (watcher)
1526 		fWatchingService.RemoveWatcher(watcher, false);
1527 }
1528 
1529 
1530 /*!	\brief Hook method invoked, when an application has been fully registered.
1531 	\param info The RosterAppInfo of the added application.
1532 */
1533 void
_AppAdded(RosterAppInfo * info)1534 TRoster::_AppAdded(RosterAppInfo* info)
1535 {
1536 	// notify the watchers
1537 	BMessage message(B_SOME_APP_LAUNCHED);
1538 	_AddMessageWatchingInfo(&message, info);
1539 	EventMaskWatcherFilter filter(B_REQUEST_LAUNCHED);
1540 	fWatchingService.NotifyWatchers(&message, &filter);
1541 }
1542 
1543 
1544 /*!	\brief Hook method invoked, when a fully registered application has been
1545 		removed.
1546 	\param info The RosterAppInfo of the removed application.
1547 */
1548 void
_AppRemoved(RosterAppInfo * info)1549 TRoster::_AppRemoved(RosterAppInfo* info)
1550 {
1551 	if (info) {
1552 		// deactivate the app, if it was the active one
1553 		if (info == fActiveApp)
1554 			UpdateActiveApp(NULL);
1555 
1556 		// notify the watchers
1557 		BMessage message(B_SOME_APP_QUIT);
1558 		_AddMessageWatchingInfo(&message, info);
1559 		EventMaskWatcherFilter filter(B_REQUEST_QUIT);
1560 		fWatchingService.NotifyWatchers(&message, &filter);
1561 	}
1562 }
1563 
1564 
1565 /*!	\brief Hook method invoked, when an application has been activated.
1566 	\param info The RosterAppInfo of the activated application.
1567 */
1568 void
_AppActivated(RosterAppInfo * info)1569 TRoster::_AppActivated(RosterAppInfo* info)
1570 {
1571 	if (info != NULL && info->state == APP_STATE_REGISTERED) {
1572 		// send B_APP_ACTIVATED to the app
1573 		BMessenger messenger;
1574 		BMessenger::Private messengerPrivate(messenger);
1575 		messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN);
1576 		BMessage message(B_APP_ACTIVATED);
1577 		message.AddBool("active", true);
1578 		// not sure, if it makes sense to use the MessageDeliverer here
1579 		MessageDeliverer::Default()->DeliverMessage(&message, messenger);
1580 
1581 		// notify the watchers
1582 		BMessage watcherMessage(B_SOME_APP_ACTIVATED);
1583 		_AddMessageWatchingInfo(&watcherMessage, info);
1584 		EventMaskWatcherFilter filter(B_REQUEST_ACTIVATED);
1585 		fWatchingService.NotifyWatchers(&watcherMessage, &filter);
1586 	}
1587 }
1588 
1589 
1590 /*!	\brief Hook method invoked, when an application has been deactivated.
1591 	\param info The RosterAppInfo of the deactivated application.
1592 */
1593 void
_AppDeactivated(RosterAppInfo * info)1594 TRoster::_AppDeactivated(RosterAppInfo* info)
1595 {
1596 	if (info != NULL && info->state == APP_STATE_REGISTERED) {
1597 		// send B_APP_ACTIVATED to the app
1598 		BMessenger messenger;
1599 		BMessenger::Private messengerPrivate(messenger);
1600 		messengerPrivate.SetTo(info->team, info->port, B_NULL_TOKEN);
1601 		BMessage message(B_APP_ACTIVATED);
1602 		message.AddBool("active", false);
1603 		// not sure, if it makes sense to use the MessageDeliverer here
1604 		MessageDeliverer::Default()->DeliverMessage(&message, messenger);
1605 	}
1606 }
1607 
1608 
1609 /*!	\brief Adds an app_info to a message.
1610 
1611 	The info is added as a flat_app_info to a field "app_info" with the type
1612 	\c B_REG_APP_INFO_TYPE.
1613 
1614 	\param message The message
1615 	\param info The app_info.
1616 	\return \c B_OK if everything went fine, an error code otherwise.
1617 */
1618 status_t
_AddMessageAppInfo(BMessage * message,const app_info * info)1619 TRoster::_AddMessageAppInfo(BMessage* message, const app_info* info)
1620 {
1621 	// An app_info is not completely flat. The entry_ref contains a string
1622 	// pointer. Therefore we flatten the info.
1623 	flat_app_info flatInfo;
1624 	flatInfo.thread = info->thread;
1625 	flatInfo.team = info->team;
1626 	flatInfo.port = info->port;
1627 	flatInfo.flags = info->flags;
1628 	flatInfo.ref_device = info->ref.device;
1629 	flatInfo.ref_directory = info->ref.directory;
1630 	memcpy(flatInfo.signature, info->signature, B_MIME_TYPE_LENGTH);
1631 
1632 	// set the ref name to NULL and copy it into the flat structure
1633 	flatInfo.ref_name[0] = '\0';
1634 	if (info->ref.name)
1635 		strcpy(flatInfo.ref_name, info->ref.name);
1636 
1637 	// add the flat info
1638 	return message->AddData("app_info", B_REG_APP_INFO_TYPE, &flatInfo,
1639 		sizeof(flat_app_info));
1640 }
1641 
1642 
1643 /*!	\brief Adds application monitoring related fields to a message.
1644 	\param message The message.
1645 	\param info The app_info of the concerned application.
1646 	\return \c B_OK if everything went fine, an error code otherwise.
1647 */
1648 status_t
_AddMessageWatchingInfo(BMessage * message,const app_info * info)1649 TRoster::_AddMessageWatchingInfo(BMessage* message, const app_info* info)
1650 {
1651 	status_t error = B_OK;
1652 	if (error == B_OK)
1653 		error = message->AddString("be:signature", info->signature);
1654 	if (error == B_OK)
1655 		error = message->AddInt32("be:team", info->team);
1656 	if (error == B_OK)
1657 		error = message->AddInt32("be:thread", info->thread);
1658 	if (error == B_OK)
1659 		error = message->AddInt32("be:flags", (int32)info->flags);
1660 	if (error == B_OK)
1661 		error = message->AddRef("be:ref", &info->ref);
1662 	return error;
1663 }
1664 
1665 
1666 /*!	\brief Returns the next available token.
1667 	\return The token.
1668 */
1669 uint32
_NextToken()1670 TRoster::_NextToken()
1671 {
1672 	return ++fLastToken;
1673 }
1674 
1675 
1676 /*!	\brief Adds an IsAppRegistered() request to the given map.
1677 
1678 	If something goes wrong, the method deletes the request.
1679 
1680 	\param map The map the request shall be added to.
1681 	\param key The key under which to add the request.
1682 	\param request The request message to be added.
1683 */
1684 void
_AddIARRequest(IARRequestMap & map,int32 key,BMessage * request)1685 TRoster::_AddIARRequest(IARRequestMap& map, int32 key, BMessage* request)
1686 {
1687 	IARRequestMap::iterator it = map.find(key);
1688 	BMessageQueue* requests = NULL;
1689 	if (it == map.end()) {
1690 		requests = new(nothrow) BMessageQueue();
1691 		if (!requests) {
1692 			delete request;
1693 			return;
1694 		}
1695 
1696 		map[key] = requests;
1697 	} else
1698 		requests = it->second;
1699 
1700 	requests->AddMessage(request);
1701 }
1702 
1703 
1704 /*!	\brief Invokes _ReplyToIARRequest() for all messages in the given
1705 		   message queue.
1706 
1707 	\param requests The request messages to be replied to
1708 	\param info The RosterAppInfo of the application in question
1709 		   (may be \c NULL)
1710 */
1711 void
_ReplyToIARRequests(BMessageQueue * requests,const RosterAppInfo * info)1712 TRoster::_ReplyToIARRequests(BMessageQueue* requests, const RosterAppInfo* info)
1713 {
1714 	while (BMessage* request = requests->NextMessage()) {
1715 		_ReplyToIARRequest(request, info);
1716 		delete request;
1717 	}
1718 }
1719 
1720 
1721 /*!	\brief Sends a reply message to an IsAppRegistered() request.
1722 
1723 	The message to be sent is a simple \c B_REG_SUCCESS message containing
1724 	a "pre-registered" field, that says whether or not the application is
1725 	pre-registered. It will be set to \c false, unless an \a info is supplied
1726 	and the application this info refers to is pre-registered.
1727 
1728 	\param request The request message to be replied to
1729 	\param info The RosterAppInfo of the application in question
1730 		   (may be \c NULL)
1731 */
1732 void
_ReplyToIARRequest(BMessage * request,const RosterAppInfo * info)1733 TRoster::_ReplyToIARRequest(BMessage* request, const RosterAppInfo* info)
1734 {
1735 	// pre-registered or registered?
1736 	bool preRegistered = false;
1737 	if (info) {
1738 		switch (info->state) {
1739 			case APP_STATE_PRE_REGISTERED:
1740 				preRegistered = true;
1741 				break;
1742 			case APP_STATE_UNREGISTERED:
1743 			case APP_STATE_REGISTERED:
1744 				preRegistered = false;
1745 				break;
1746 		}
1747 	}
1748 	// send reply
1749 	BMessage reply(B_REG_SUCCESS);
1750 	reply.AddBool("registered", (bool)info);
1751 	reply.AddBool("pre-registered", preRegistered);
1752 	PRINT("_ReplyToIARRequest(): pre-registered: %d\n", preRegistered);
1753 	if (info)
1754 		_AddMessageAppInfo(&reply, info);
1755 	request->SendReply(&reply);
1756 }
1757 
1758 
1759 /*! \brief Handles requests for both GetRecentDocuments() and
1760 	GetRecentFolders().
1761 */
1762 void
_HandleGetRecentEntries(BMessage * request)1763 TRoster::_HandleGetRecentEntries(BMessage* request)
1764 {
1765 	FUNCTION_START();
1766 	if (!request) {
1767 		D(PRINT("WARNING: TRoster::HandleGetRecentFolders(NULL) called\n"));
1768 		return;
1769 	}
1770 
1771 	int32 maxCount;
1772 	BMessage reply(B_REG_RESULT);
1773 	char** fileTypes = NULL;
1774 	int32 fileTypesCount = 0;
1775 	char* appSig = NULL;
1776 
1777 	status_t error = request->FindInt32("max count", &maxCount);
1778 	// Look for optional file type(s)
1779 	if (!error) {
1780 		type_code typeFound;
1781 		status_t typeError = request->GetInfo("file type", &typeFound,
1782 			&fileTypesCount);
1783 		if (!typeError)
1784 			typeError = typeFound == B_STRING_TYPE ? B_OK : B_BAD_TYPE;
1785 		if (!typeError) {
1786 			fileTypes = new(nothrow) char*[fileTypesCount];
1787 			typeError = fileTypes ? B_OK : B_NO_MEMORY;
1788 		}
1789 		if (!typeError) {
1790 			for (int i = 0; !error && i < fileTypesCount; i++) {
1791 				const char* type;
1792 				if (request->FindString("file type", i, &type) == B_OK) {
1793 					fileTypes[i] = new(nothrow) char[B_MIME_TYPE_LENGTH];
1794 					error = fileTypes[i] ? B_OK : B_NO_MEMORY;
1795 						// Yes, I do mean to use "error" here, not "typeError"
1796 					BPrivate::Storage::to_lower(type, fileTypes[i]);
1797 						// Types are expected to be lowercase
1798 				}
1799 			}
1800 		}
1801 	}
1802 	// Look for optional app sig
1803 	if (!error) {
1804 		const char* sig;
1805 		error = request->FindString("app sig", &sig);
1806 		if (!error) {
1807 			appSig = new(nothrow) char[B_MIME_TYPE_LENGTH];
1808 			error = appSig ? B_OK : B_NO_MEMORY;
1809 			BPrivate::Storage::to_lower(sig, appSig);
1810 		} else if (error == B_NAME_NOT_FOUND)
1811 			error = B_OK;
1812 	}
1813 	if (!error) {
1814 		switch (request->what) {
1815 			case B_REG_GET_RECENT_DOCUMENTS:
1816 				error = fRecentDocuments.Get(maxCount, (const char**)fileTypes,
1817 					fileTypesCount, appSig, &reply);
1818 				D(fRecentDocuments.Print());
1819 		   	    break;
1820 
1821 			case B_REG_GET_RECENT_FOLDERS:
1822 				error = fRecentFolders.Get(maxCount, (const char**)fileTypes,
1823 					fileTypesCount, appSig, &reply);
1824 				D(fRecentFolders.Print());
1825 			    break;
1826 
1827 			default:
1828 				D(PRINT("WARNING: TRoster::_HandleGetRecentEntries(): "
1829 					"unexpected request->what value of 0x%" B_PRIx32 "\n",
1830 					request->what));
1831 				error = B_BAD_VALUE;
1832 				break;
1833 		}
1834 	}
1835 	reply.AddInt32("result", error);
1836 	// Clean up before sending a reply
1837 	delete [] appSig;
1838 	if (fileTypes) {
1839 		for (int i = 0; i < fileTypesCount; i++)
1840 			delete [] fileTypes[i];
1841 		delete[] fileTypes;
1842 		fileTypes = NULL;
1843 	}
1844 	request->SendReply(&reply);
1845 
1846 	FUNCTION_END();
1847 }
1848 
1849 
1850 /*!
1851 	\brief Checks all registered apps for \a ref and \a signature if
1852 		they are still alive, and removes those that aren't.
1853 */
1854 void
_ValidateRunning(const entry_ref & ref,const char * signature)1855 TRoster::_ValidateRunning(const entry_ref& ref, const char* signature)
1856 {
1857 	while (true) {
1858 		// get info via ref or signature
1859 		RosterAppInfo* info = fRegisteredApps.InfoFor(&ref);
1860 		if (info == NULL && signature != NULL)
1861 			info = fRegisteredApps.InfoFor(signature);
1862 
1863 		// if app is alive or does not exist, we can exit
1864 		if (info == NULL || info->IsRunning())
1865 			return;
1866 
1867 		RemoveApp(info);
1868 		delete info;
1869 	}
1870 }
1871 
1872 
1873 bool
_IsSystemApp(RosterAppInfo * info) const1874 TRoster::_IsSystemApp(RosterAppInfo* info) const
1875 {
1876 	BPath path;
1877 	if (path.SetTo(&info->ref) != B_OK || path.GetParent(&path) != B_OK)
1878 		return false;
1879 
1880 	return !strcmp(path.Path(), fSystemAppPath.Path())
1881 		|| !strcmp(path.Path(), fSystemServerPath.Path());
1882 }
1883 
1884 
1885 status_t
_LoadRosterSettings(const char * path)1886 TRoster::_LoadRosterSettings(const char* path)
1887 {
1888 	BPath _path;
1889 	const char* settingsPath
1890 		= path ? path : get_default_roster_settings_path(_path, false);
1891 
1892 	RosterSettingsCharStream stream;
1893 	status_t error;
1894 	BFile file;
1895 
1896 	error = file.SetTo(settingsPath, B_READ_ONLY);
1897 	off_t size;
1898 	if (!error)
1899 		error = file.GetSize(&size);
1900 
1901 	char* data = NULL;
1902 
1903 	if (!error) {
1904 		data = new(nothrow) char[size + 1];
1905 		error = data ? B_OK : B_NO_MEMORY;
1906 	}
1907 	if (!error) {
1908 		ssize_t bytes = file.Read(data, size);
1909 		error = bytes < 0 ? bytes : (bytes == size ? B_OK : B_FILE_ERROR);
1910 	}
1911 	if (!error) {
1912 		data[size] = 0;
1913 		error = stream.SetTo(std::string(data));
1914 	}
1915 
1916 	delete[] data;
1917 
1918 	if (!error) {
1919 		// Clear the current lists as
1920 		// we'll be manually building them up
1921 		fRecentDocuments.Clear();
1922 		fRecentFolders.Clear();
1923 		fRecentApps.Clear();
1924 
1925 		// Now we just walk through the file and read in the info
1926 		while (true) {
1927 			status_t streamError;
1928 			char str[B_PATH_NAME_LENGTH];
1929 
1930 			// (RecentDoc | RecentFolder | RecentApp)
1931 			streamError = stream.GetString(str);
1932 			if (!streamError) {
1933 				enum EntryType {
1934 					etDoc,
1935 					etFolder,
1936 					etApp,
1937 					etSomethingIsAmiss,
1938 				} type;
1939 
1940 				if (strcmp(str, "RecentDoc") == 0)
1941 					type = etDoc;
1942 				else if (strcmp(str, "RecentFolder") == 0)
1943 					type = etFolder;
1944 				else if (strcmp(str, "RecentApp") == 0)
1945 					type = etApp;
1946 				else
1947 					type = etSomethingIsAmiss;
1948 
1949 				switch (type) {
1950 					case etDoc:
1951 					case etFolder:
1952 					{
1953 						// For curing laziness
1954 						std::list<recent_entry*>* list = type == etDoc
1955 							? &fRecentDocuments.fEntryList
1956 							: &fRecentFolders.fEntryList;
1957 
1958 						char path[B_PATH_NAME_LENGTH];
1959 						char app[B_PATH_NAME_LENGTH];
1960 						char rank[B_PATH_NAME_LENGTH];
1961 						entry_ref ref;
1962 						ulong index = 0;
1963 
1964 						// Convert the given path to an entry ref
1965 						streamError = stream.GetString(path);
1966 						if (!streamError)
1967 							streamError = get_ref_for_path(path, &ref);
1968 
1969 						// Add a new entry to the list for each application
1970 						// signature and rank we find
1971 						while (!streamError) {
1972 							if (!streamError)
1973 								streamError = stream.GetString(app);
1974 							if (!streamError) {
1975 								BPrivate::Storage::to_lower(app);
1976 								streamError = stream.GetString(rank);
1977 							}
1978 							if (!streamError) {
1979 								index = strtoul(rank, NULL, 10);
1980 								if (index == ULONG_MAX)
1981 									streamError = errno;
1982 							}
1983 							recent_entry* entry = NULL;
1984 							if (!streamError) {
1985 								entry = new(nothrow) recent_entry(&ref, app,
1986 									index);
1987 								streamError = entry ? B_OK : B_NO_MEMORY;
1988 							}
1989 							if (!streamError) {
1990 								D(printf("pushing entry, leaf == '%s', app == "
1991 									"'%s', index == %" B_PRId32 "\n",
1992 									entry->ref.name, entry->sig.c_str(),
1993 									entry->index));
1994 
1995 								list->push_back(entry);
1996 							}
1997 						}
1998 
1999 						if (streamError) {
2000 							D(printf("entry error 0x%" B_PRIx32 "\n",
2001 								streamError));
2002 							if (streamError
2003 									!= RosterSettingsCharStream::kEndOfLine
2004 							    && streamError
2005 							    	!= RosterSettingsCharStream::kEndOfStream)
2006 							stream.SkipLine();
2007 						}
2008 
2009 						break;
2010 					}
2011 
2012 
2013 					case etApp:
2014 					{
2015 						char app[B_PATH_NAME_LENGTH];
2016 						streamError = stream.GetString(app);
2017 						if (!streamError) {
2018 							BPrivate::Storage::to_lower(app);
2019 							fRecentApps.fAppList.push_back(app);
2020 						} else
2021 							stream.SkipLine();
2022 						break;
2023 					}
2024 
2025 					default:
2026 						// Something was amiss; skip to the next line
2027 						stream.SkipLine();
2028 						break;
2029 				}
2030 
2031 			}
2032 
2033 			if (streamError == RosterSettingsCharStream::kEndOfStream)
2034 				break;
2035 		}
2036 
2037 		// Now we must sort our lists of documents and folders by the
2038 		// indicies we read for each entry (largest index first)
2039 		fRecentDocuments.fEntryList.sort(larger_index);
2040 		fRecentFolders.fEntryList.sort(larger_index);
2041 
2042 		D(
2043 			printf("----------------------------------------------------------------------\n");
2044 			fRecentDocuments.Print();
2045 			printf("----------------------------------------------------------------------\n");
2046 			fRecentFolders.Print();
2047 			printf("----------------------------------------------------------------------\n");
2048 			fRecentApps.Print();
2049 			printf("----------------------------------------------------------------------\n");
2050 		);
2051 	}
2052 	if (error) {
2053 		D(PRINT("WARNING: TRoster::_LoadRosterSettings(): error loading roster "
2054 			"settings from '%s', 0x%" B_PRIx32 "\n", settingsPath, error));
2055 	}
2056 	return error;
2057 }
2058 
2059 
2060 status_t
_SaveRosterSettings(const char * path)2061 TRoster::_SaveRosterSettings(const char* path)
2062 {
2063 	BPath _path;
2064 	const char* settingsPath
2065 		= path != NULL ? path : get_default_roster_settings_path(_path, true);
2066 
2067 	status_t error;
2068 	FILE* file;
2069 
2070 	file = fopen(settingsPath, "w+");
2071 	error = file ? B_OK : errno;
2072 	if (!error) {
2073 		status_t saveError;
2074 		saveError = fRecentDocuments.Save(file, "Recent documents", "RecentDoc");
2075 		if (saveError) {
2076 			D(PRINT("TRoster::_SaveRosterSettings(): recent documents save "
2077 				"failed with error 0x%" B_PRIx32 "\n", saveError));
2078 		}
2079 		saveError = fRecentFolders.Save(file, "Recent folders", "RecentFolder");
2080 		if (saveError) {
2081 			D(PRINT("TRoster::_SaveRosterSettings(): recent folders save "
2082 				"failed with error 0x%" B_PRIx32 "\n", saveError));
2083 		}
2084 		saveError = fRecentApps.Save(file);
2085 		if (saveError) {
2086 			D(PRINT("TRoster::_SaveRosterSettings(): recent folders save "
2087 				"failed with error 0x%" B_PRIx32 "\n", saveError));
2088 		}
2089 		fclose(file);
2090 	}
2091 
2092 	return error;
2093 }
2094