1/*
2 * Copyright 2011-2020, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Oliver Tappe <zooey@hirschkaefer.de>
7 *		Andrew Lindesay <apl@lindesay.co.nz>
8 */
9
10
11#include <package/RepositoryConfig.h>
12
13#include <stdlib.h>
14
15#include <new>
16
17#include <Directory.h>
18#include <driver_settings.h>
19#include <File.h>
20#include <FindDirectory.h>
21#include <Path.h>
22
23#include <DriverSettings.h>
24
25
26#define STORAGE_VERSION 2
27
28#define KEY_BASE_URL_V1 "url"
29#define KEY_IDENTIFIER_V1 "url"
30
31#define KEY_BASE_URL_V2 "baseurl"
32#define KEY_IDENTIFIER_V2 "identifier"
33#define KEY_IDENTIFIER_V2_ALT "url"
34	// should not be used any more in favour of 'identifier'
35
36#define KEY_PRIORITY "priority"
37#define KEY_CONFIG_VERSION "cfgversion"
38
39namespace BPackageKit {
40
41
42// these are mappings of known legacy identifier URLs that are possibly
43// still present in some installations.  These are in pairs; the first
44// being the legacy URL and the next being the replacement.  This can
45// be phased out over time.
46
47static const char* kLegacyUrlMappings[] = {
48	"https://eu.hpkg.haiku-os.org/haikuports/master/x86_gcc2/current",
49	"https://hpkg.haiku-os.org/haikuports/master/x86_gcc2/current",
50	"https://eu.hpkg.haiku-os.org/haikuports/master/x86_64/current",
51	"https://hpkg.haiku-os.org/haikuports/master/x86_64/current",
52	NULL,
53	NULL
54};
55
56
57BRepositoryConfig::BRepositoryConfig()
58	:
59	fInitStatus(B_NO_INIT),
60	fPriority(kUnsetPriority),
61	fIsUserSpecific(false)
62{
63}
64
65
66BRepositoryConfig::BRepositoryConfig(const BEntry& entry)
67{
68	SetTo(entry);
69}
70
71
72BRepositoryConfig::BRepositoryConfig(const BString& name,
73	const BString& baseURL, uint8 priority)
74	:
75	fInitStatus(B_OK),
76	fName(name),
77	fBaseURL(baseURL),
78	fPriority(priority),
79	fIsUserSpecific(false)
80{
81}
82
83
84BRepositoryConfig::~BRepositoryConfig()
85{
86}
87
88
89status_t
90BRepositoryConfig::Store(const BEntry& entry) const
91{
92	BFile file(&entry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
93	status_t result = file.InitCheck();
94	if (result != B_OK)
95		return result;
96
97	BString configString;
98	configString << KEY_CONFIG_VERSION << "=" << STORAGE_VERSION << "\n";
99	configString << "\n";
100	configString << "# the url where the repository data can be "
101		"accessed.\n";
102	configString << KEY_BASE_URL_V2 << "=" << fBaseURL << "\n";
103	configString << "\n";
104
105	configString << "# an identifier for the repository that is "
106		"consistent across mirrors\n";
107	if (fIdentifier.IsEmpty())
108		configString << "# " << KEY_IDENTIFIER_V2 << "=???\n";
109	else
110		configString << KEY_IDENTIFIER_V2 << "=" << fIdentifier << "\n";
111	configString << "\n";
112
113	configString << "# a deprecated copy of the ["
114		<< KEY_IDENTIFIER_V2 << "] key above for older os versions\n";
115	if (fIdentifier.IsEmpty())
116		configString << "# " << KEY_IDENTIFIER_V2_ALT << "=???\n";
117	else
118		configString << KEY_IDENTIFIER_V2_ALT << "=" << fIdentifier << "\n";
119	configString << "\n";
120
121	configString << KEY_PRIORITY << "=" << fPriority << "\n";
122
123	int32 size = configString.Length();
124	if ((result = file.Write(configString.String(), size)) < size)
125		return (result >= 0) ? B_ERROR : result;
126
127	return B_OK;
128}
129
130
131status_t
132BRepositoryConfig::InitCheck() const
133{
134	return fInitStatus;
135}
136
137
138static const char*
139repository_config_swap_legacy_identifier_v1(const char* identifier)
140{
141	for (int32 i = 0; kLegacyUrlMappings[i] != NULL; i += 2) {
142		if (strcmp(identifier, kLegacyUrlMappings[i]) == 0)
143			return kLegacyUrlMappings[i + 1];
144	}
145	return identifier;
146}
147
148
149status_t
150BRepositoryConfig::SetTo(const BEntry& entry)
151{
152	fEntry = entry;
153	fInitStatus = B_NO_INIT;
154
155	entry_ref ref;
156	status_t result = entry.GetRef(&ref);
157	if (result != B_OK)
158		return result;
159
160	BDriverSettings driverSettings;
161	result = driverSettings.Load(ref);
162	if (result != B_OK)
163		return result;
164
165	const char* version = driverSettings.GetParameterValue(KEY_CONFIG_VERSION);
166	int versionNumber = version == NULL ? 1 : atoi(version);
167	const char *baseUrlKey;
168	const char *identifierKeys[3] = { NULL, NULL, NULL };
169
170	switch (versionNumber) {
171		case 1:
172			baseUrlKey = KEY_BASE_URL_V1;
173			identifierKeys[0] = KEY_IDENTIFIER_V1;
174			break;
175		case 2:
176			baseUrlKey = KEY_BASE_URL_V2;
177			identifierKeys[0] = KEY_IDENTIFIER_V2;
178			identifierKeys[1] = KEY_IDENTIFIER_V2_ALT;
179			break;
180		default:
181			return B_BAD_DATA;
182	}
183
184	const char* baseUrl = driverSettings.GetParameterValue(baseUrlKey);
185	const char* priorityString = driverSettings.GetParameterValue(KEY_PRIORITY);
186	const char* identifier = NULL;
187
188	for (int32 i = 0; identifier == NULL && identifierKeys[i] != NULL; i++)
189		identifier = driverSettings.GetParameterValue(identifierKeys[i]);
190
191	if (baseUrl == NULL || *baseUrl == '\0')
192		return B_BAD_DATA;
193	if (identifier == NULL || *identifier == '\0')
194		return B_BAD_DATA;
195
196	if (versionNumber == 1)
197		identifier = repository_config_swap_legacy_identifier_v1(identifier);
198
199	fName = entry.Name();
200	fBaseURL = baseUrl;
201	fPriority = priorityString == NULL
202		? kUnsetPriority : atoi(priorityString);
203	fIdentifier = identifier;
204
205	BPath userSettingsPath;
206	if (find_directory(B_USER_SETTINGS_DIRECTORY, &userSettingsPath) == B_OK) {
207		BDirectory userSettingsDir(userSettingsPath.Path());
208		fIsUserSpecific = userSettingsDir.Contains(&entry);
209	} else
210		fIsUserSpecific = false;
211
212	fInitStatus = B_OK;
213
214	return B_OK;
215}
216
217
218const BString&
219BRepositoryConfig::Name() const
220{
221	return fName;
222}
223
224
225const BString&
226BRepositoryConfig::BaseURL() const
227{
228	return fBaseURL;
229}
230
231
232const BString&
233BRepositoryConfig::Identifier() const
234{
235	return fIdentifier;
236}
237
238
239uint8
240BRepositoryConfig::Priority() const
241{
242	return fPriority;
243}
244
245
246bool
247BRepositoryConfig::IsUserSpecific() const
248{
249	return fIsUserSpecific;
250}
251
252
253const BEntry&
254BRepositoryConfig::Entry() const
255{
256	return fEntry;
257}
258
259
260BString
261BRepositoryConfig::PackagesURL() const
262{
263	if (fBaseURL.IsEmpty())
264		return BString();
265	return BString().SetToFormat("%s/packages", fBaseURL.String());
266}
267
268
269void
270BRepositoryConfig::SetName(const BString& name)
271{
272	fName = name;
273}
274
275
276void
277BRepositoryConfig::SetBaseURL(const BString& baseURL)
278{
279	fBaseURL = baseURL;
280}
281
282
283void
284BRepositoryConfig::SetIdentifier(const BString& identifier)
285{
286	fIdentifier = identifier;
287}
288
289
290void
291BRepositoryConfig::SetPriority(uint8 priority)
292{
293	fPriority = priority;
294}
295
296
297void
298BRepositoryConfig::SetIsUserSpecific(bool isUserSpecific)
299{
300	fIsUserSpecific = isUserSpecific;
301}
302
303
304}	// namespace BPackageKit
305