1/*
2 * Copyright 2011-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Oliver Tappe <zooey@hirschkaefer.de>
7 */
8
9
10#include <package/PackageRoster.h>
11
12#include <errno.h>
13#include <sys/stat.h>
14
15#include <Directory.h>
16#include <Entry.h>
17#include <Messenger.h>
18#include <Path.h>
19#include <String.h>
20#include <StringList.h>
21
22#include <package/InstallationLocationInfo.h>
23#include <package/PackageInfo.h>
24#include <package/PackageInfoContentHandler.h>
25#include <package/PackageInfoSet.h>
26#include <package/RepositoryCache.h>
27#include <package/RepositoryConfig.h>
28
29#include <package/hpkg/PackageReader.h>
30
31
32#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
33#	include <package/DaemonClient.h>
34#	include <RegistrarDefs.h>
35#	include <RosterPrivate.h>
36#endif
37
38
39namespace BPackageKit {
40
41
42using namespace BHPKG;
43
44
45BPackageRoster::BPackageRoster()
46{
47}
48
49
50BPackageRoster::~BPackageRoster()
51{
52}
53
54
55bool
56BPackageRoster::IsRebootNeeded()
57{
58	BInstallationLocationInfo info;
59
60	// We get information on the system package installation location.
61	// If we fail, we just have to assume a reboot is not needed.
62	if (GetInstallationLocationInfo(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM,
63		info) != B_OK)
64		return false;
65
66	// CurrentlyActivePackageInfos() will return 0 if no packages need to be
67	// activated with a reboot. Otherwise, the method will return the total
68	// number of packages in the system package directory.
69	if (info.CurrentlyActivePackageInfos().CountInfos() != 0)
70		return true;
71
72	return false;
73}
74
75
76status_t
77BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const
78{
79	return _GetRepositoryPath(path, create, B_SYSTEM_SETTINGS_DIRECTORY);
80}
81
82
83status_t
84BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const
85{
86	return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY);
87}
88
89
90status_t
91BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const
92{
93	return _GetRepositoryPath(path, create, B_SYSTEM_CACHE_DIRECTORY);
94}
95
96
97status_t
98BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const
99{
100	return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY);
101}
102
103
104status_t
105BPackageRoster::VisitCommonRepositoryConfigs(BRepositoryConfigVisitor& visitor)
106{
107	BPath commonRepositoryConfigPath;
108	status_t result
109		= GetCommonRepositoryConfigPath(&commonRepositoryConfigPath);
110	if (result != B_OK)
111		return result;
112
113	return _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor);
114}
115
116
117status_t
118BPackageRoster::VisitUserRepositoryConfigs(BRepositoryConfigVisitor& visitor)
119{
120	BPath userRepositoryConfigPath;
121	status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath);
122	if (result != B_OK)
123		return result;
124
125	return _VisitRepositoryConfigs(userRepositoryConfigPath, visitor);
126}
127
128
129status_t
130BPackageRoster::GetRepositoryNames(BStringList& names)
131{
132	struct RepositoryNameCollector : public BRepositoryConfigVisitor {
133		RepositoryNameCollector(BStringList& _names)
134			: names(_names)
135		{
136		}
137		status_t operator()(const BEntry& entry)
138		{
139			char name[B_FILE_NAME_LENGTH];
140			status_t result = entry.GetName(name);
141			if (result != B_OK)
142				return result;
143			int32 count = names.CountStrings();
144			for (int i = 0; i < count; ++i) {
145				if (names.StringAt(i).Compare(name) == 0)
146					return B_OK;
147			}
148			names.Add(name);
149			return B_OK;
150		}
151		BStringList& names;
152	};
153	RepositoryNameCollector repositoryNameCollector(names);
154	status_t result = VisitUserRepositoryConfigs(repositoryNameCollector);
155	if (result != B_OK)
156		return result;
157
158	return VisitCommonRepositoryConfigs(repositoryNameCollector);
159}
160
161
162status_t
163BPackageRoster::GetRepositoryCache(const BString& name,
164	BRepositoryCache* repositoryCache)
165{
166	if (repositoryCache == NULL)
167		return B_BAD_VALUE;
168
169	// user path has higher precedence than common path
170	BPath path;
171	status_t result = GetUserRepositoryCachePath(&path);
172	if (result != B_OK)
173		return result;
174	path.Append(name.String());
175
176	BEntry repoCacheEntry(path.Path());
177	if (repoCacheEntry.Exists())
178		return repositoryCache->SetTo(repoCacheEntry);
179
180	if ((result = GetCommonRepositoryCachePath(&path, true)) != B_OK)
181		return result;
182	path.Append(name.String());
183
184	repoCacheEntry.SetTo(path.Path());
185	return repositoryCache->SetTo(repoCacheEntry);
186}
187
188
189status_t
190BPackageRoster::GetRepositoryConfig(const BString& name,
191	BRepositoryConfig* repositoryConfig)
192{
193	if (repositoryConfig == NULL)
194		return B_BAD_VALUE;
195
196	// user path has higher precedence than common path
197	BPath path;
198	status_t result = GetUserRepositoryConfigPath(&path);
199	if (result != B_OK)
200		return result;
201	path.Append(name.String());
202
203	BEntry repoConfigEntry(path.Path());
204	if (repoConfigEntry.Exists())
205		return repositoryConfig->SetTo(repoConfigEntry);
206
207	if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK)
208		return result;
209	path.Append(name.String());
210
211	repoConfigEntry.SetTo(path.Path());
212	return repositoryConfig->SetTo(repoConfigEntry);
213}
214
215
216status_t
217BPackageRoster::GetInstallationLocationInfo(
218	BPackageInstallationLocation location, BInstallationLocationInfo& _info)
219{
220// This method makes sense only on an installed Haiku, but not for the build
221// tools.
222#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
223	return BPackageKit::BPrivate::BDaemonClient().GetInstallationLocationInfo(
224		location, _info);
225#else
226	return B_NOT_SUPPORTED;
227#endif
228}
229
230
231status_t
232BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
233	BPackageInfoSet& packageInfos)
234{
235// This method makes sense only on an installed Haiku, but not for the build
236// tools.
237#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
238	BInstallationLocationInfo info;
239	status_t error = GetInstallationLocationInfo(location, info);
240	if (error != B_OK)
241		return error;
242
243	packageInfos = info.LatestActivePackageInfos();
244	return B_OK;
245#else
246	return B_NOT_SUPPORTED;
247#endif
248}
249
250
251status_t
252BPackageRoster::StartWatching(const BMessenger& target, uint32 eventMask)
253{
254// This method makes sense only on an installed Haiku, but not for the build
255// tools.
256#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
257	// compose the registrar request
258	BMessage request(::BPrivate::B_REG_PACKAGE_START_WATCHING);
259	status_t error;
260	if ((error = request.AddMessenger("target", target)) != B_OK
261		|| (error = request.AddUInt32("events", eventMask)) != B_OK) {
262		return error;
263	}
264
265	// send it
266	BMessage reply;
267	error = BRoster::Private().SendTo(&request, &reply, false);
268	if (error != B_OK)
269		return error;
270
271	// get result
272	if (reply.what != ::BPrivate::B_REG_SUCCESS) {
273		int32 result;
274		if (reply.FindInt32("error", &result) != B_OK)
275			result = B_ERROR;
276		return (status_t)error;
277	}
278
279	return B_OK;
280#else
281	return B_NOT_SUPPORTED;
282#endif
283}
284
285
286status_t
287BPackageRoster::StopWatching(const BMessenger& target)
288{
289// This method makes sense only on an installed Haiku, but not for the build
290// tools.
291#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
292	// compose the registrar request
293	BMessage request(::BPrivate::B_REG_PACKAGE_STOP_WATCHING);
294	status_t error = request.AddMessenger("target", target);
295	if (error  != B_OK)
296		return error;
297
298	// send it
299	BMessage reply;
300	error = BRoster::Private().SendTo(&request, &reply, false);
301	if (error != B_OK)
302		return error;
303
304	// get result
305	if (reply.what != ::BPrivate::B_REG_SUCCESS) {
306		int32 result;
307		if (reply.FindInt32("error", &result) != B_OK)
308			result = B_ERROR;
309		return (status_t)error;
310	}
311
312	return B_OK;
313#else
314	return B_NOT_SUPPORTED;
315#endif
316}
317
318
319status_t
320BPackageRoster::_GetRepositoryPath(BPath* path, bool create,
321	directory_which whichDir) const
322{
323	if (path == NULL)
324		return B_BAD_VALUE;
325
326	status_t result = find_directory(whichDir, path);
327	if (result != B_OK)
328		return result;
329	if ((result = path->Append("package-repositories")) != B_OK)
330		return result;
331
332	if (create) {
333		BEntry entry(path->Path(), true);
334		if (!entry.Exists()) {
335			if (mkdir(path->Path(), 0755) != 0)
336				return errno;
337		}
338	}
339
340	return B_OK;
341}
342
343
344status_t
345BPackageRoster::_VisitRepositoryConfigs(const BPath& path,
346	BRepositoryConfigVisitor& visitor)
347{
348	BDirectory directory(path.Path());
349	status_t result = directory.InitCheck();
350	if (result == B_ENTRY_NOT_FOUND)
351		return B_OK;
352	if (result != B_OK)
353		return result;
354
355	BEntry entry;
356	while (directory.GetNextEntry(&entry, true) == B_OK) {
357		if ((result = visitor(entry)) != B_OK)
358			return result;
359	}
360
361	return B_OK;
362}
363
364
365}	// namespace BPackageKit
366