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/RepositoryInfo.h>
12
13#include <stdlib.h>
14
15#include <new>
16
17#include <driver_settings.h>
18#include <File.h>
19#include <Message.h>
20
21#include <AutoDeleter.h>
22#include <AutoDeleterDrivers.h>
23#include <package/PackageInfo.h>
24
25
26namespace BPackageKit {
27
28
29const uint8 BRepositoryInfo::kDefaultPriority	= 50;
30
31const char* const BRepositoryInfo::kNameField			= "name";
32const char* const BRepositoryInfo::kURLField			= "url";
33const char* const BRepositoryInfo::kIdentifierField		= "identifier";
34const char* const BRepositoryInfo::kBaseURLField		= "baseUrl";
35const char* const BRepositoryInfo::kVendorField			= "vendor";
36const char* const BRepositoryInfo::kSummaryField		= "summary";
37const char* const BRepositoryInfo::kPriorityField		= "priority";
38const char* const BRepositoryInfo::kArchitectureField	= "architecture";
39const char* const BRepositoryInfo::kLicenseNameField	= "licenseName";
40const char* const BRepositoryInfo::kLicenseTextField	= "licenseText";
41
42
43BRepositoryInfo::BRepositoryInfo()
44	:
45	fInitStatus(B_NO_INIT),
46	fPriority(kDefaultPriority),
47	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
48{
49}
50
51
52BRepositoryInfo::BRepositoryInfo(BMessage* data)
53	:
54	inherited(data),
55	fLicenseTexts(5)
56{
57	fInitStatus = _SetTo(data);
58}
59
60
61BRepositoryInfo::BRepositoryInfo(const BEntry& entry)
62{
63	fInitStatus = _SetTo(entry);
64}
65
66
67BRepositoryInfo::~BRepositoryInfo()
68{
69}
70
71
72/*static*/ BRepositoryInfo*
73BRepositoryInfo::Instantiate(BMessage* data)
74{
75	if (validate_instantiation(data, "BPackageKit::BRepositoryInfo"))
76		return new (std::nothrow) BRepositoryInfo(data);
77
78	return NULL;
79}
80
81
82status_t
83BRepositoryInfo::Archive(BMessage* data, bool deep) const
84{
85	status_t result = inherited::Archive(data, deep);
86	if (result != B_OK)
87		return result;
88
89	if (!fBaseURL.IsEmpty()) {
90		if ((result = data->AddString(kBaseURLField, fBaseURL)) != B_OK)
91			return result;
92	}
93
94	if ((result = data->AddString(kNameField, fName)) != B_OK)
95		return result;
96	if ((result = data->AddString(kIdentifierField, fIdentifier)) != B_OK)
97		return result;
98	// "url" is an older, deprecated key for "identifier"
99	if ((result = data->AddString(kURLField, fIdentifier)) != B_OK)
100		return result;
101	if ((result = data->AddString(kVendorField, fVendor)) != B_OK)
102		return result;
103	if ((result = data->AddString(kSummaryField, fSummary)) != B_OK)
104		return result;
105	if ((result = data->AddUInt8(kPriorityField, fPriority)) != B_OK)
106		return result;
107	if ((result = data->AddUInt8(kArchitectureField, fArchitecture)) != B_OK)
108		return result;
109	for (int i = 0; i < fLicenseNames.CountStrings(); ++i) {
110		result = data->AddString(kLicenseNameField, fLicenseNames.StringAt(i));
111		if (result != B_OK)
112			return result;
113	}
114	for (int i = 0; i < fLicenseTexts.CountStrings(); ++i) {
115		result = data->AddString(kLicenseTextField, fLicenseTexts.StringAt(i));
116		if (result != B_OK)
117			return result;
118	}
119
120	return B_OK;
121}
122
123
124status_t
125BRepositoryInfo::InitCheck() const
126{
127	return fInitStatus;
128}
129
130
131status_t
132BRepositoryInfo::SetTo(const BMessage* data)
133{
134	return fInitStatus = _SetTo(data);
135}
136
137
138status_t
139BRepositoryInfo::SetTo(const BEntry& entry)
140{
141	return fInitStatus = _SetTo(entry);
142}
143
144
145const BString&
146BRepositoryInfo::Name() const
147{
148	return fName;
149}
150
151
152const BString&
153BRepositoryInfo::BaseURL() const
154{
155	return fBaseURL;
156}
157
158
159const BString&
160BRepositoryInfo::Identifier() const
161{
162	return fIdentifier;
163}
164
165
166const BString&
167BRepositoryInfo::Vendor() const
168{
169	return fVendor;
170}
171
172
173const BString&
174BRepositoryInfo::Summary() const
175{
176	return fSummary;
177}
178
179
180uint8
181BRepositoryInfo::Priority() const
182{
183	return fPriority;
184}
185
186
187BPackageArchitecture
188BRepositoryInfo::Architecture() const
189{
190	return fArchitecture;
191}
192
193
194const BStringList&
195BRepositoryInfo::LicenseNames() const
196{
197	return fLicenseNames;
198}
199
200
201const BStringList&
202BRepositoryInfo::LicenseTexts() const
203{
204	return fLicenseTexts;
205}
206
207
208void
209BRepositoryInfo::SetName(const BString& name)
210{
211	fName = name;
212}
213
214
215void
216BRepositoryInfo::SetIdentifier(const BString& identifier)
217{
218	fIdentifier = identifier;
219}
220
221
222void
223BRepositoryInfo::SetBaseURL(const BString& url)
224{
225	fBaseURL = url;
226}
227
228
229void
230BRepositoryInfo::SetVendor(const BString& vendor)
231{
232	fVendor = vendor;
233}
234
235
236void
237BRepositoryInfo::SetSummary(const BString& summary)
238{
239	fSummary = summary;
240}
241
242
243void
244BRepositoryInfo::SetPriority(uint8 priority)
245{
246	fPriority = priority;
247}
248
249
250void
251BRepositoryInfo::SetArchitecture(BPackageArchitecture architecture)
252{
253	fArchitecture = architecture;
254}
255
256
257status_t
258BRepositoryInfo::AddLicense(const BString& licenseName,
259	const BString& licenseText)
260{
261	if (!fLicenseNames.Add(licenseName) || !fLicenseTexts.Add(licenseText))
262		return B_NO_MEMORY;
263
264	return B_OK;
265}
266
267
268void
269BRepositoryInfo::ClearLicenses()
270{
271	fLicenseNames.MakeEmpty();
272	fLicenseTexts.MakeEmpty();
273}
274
275
276status_t
277BRepositoryInfo::_SetTo(const BMessage* data)
278{
279	if (data == NULL)
280		return B_BAD_VALUE;
281
282	status_t result;
283	if ((result = data->FindString(kNameField, &fName)) != B_OK)
284		return result;
285	result = data->FindString(kIdentifierField, &fIdentifier);
286	if (result == B_NAME_NOT_FOUND) {
287		result = data->FindString(kURLField, &fIdentifier);
288			// this is a legacy key for the identifier.
289	}
290	if (result != B_OK)
291		return result;
292	if ((result = data->FindString(kVendorField, &fVendor)) != B_OK)
293		return result;
294	if ((result = data->FindString(kSummaryField, &fSummary)) != B_OK)
295		return result;
296	if ((result = data->FindUInt8(kPriorityField, &fPriority)) != B_OK)
297		return result;
298	if ((result = data->FindUInt8(
299			kArchitectureField, (uint8*)&fArchitecture)) != B_OK) {
300		return result;
301	}
302	if (fArchitecture == B_PACKAGE_ARCHITECTURE_ANY)
303		return B_BAD_DATA;
304
305	// this field is optional because earlier versions did not support this
306	// field.
307	status_t baseUrlResult = data->FindString(kBaseURLField, &fBaseURL);
308	switch (baseUrlResult) {
309		case B_NAME_NOT_FOUND:
310			// This is a temporary measure because older versions of the file
311			// format would take the "url" (identifier) field for the "base-url"
312			// Once this transitional period is over this can be removed.
313			if (fIdentifier.StartsWith("http"))
314				fBaseURL = fIdentifier;
315			break;
316		case B_OK:
317			break;
318		default:
319			return baseUrlResult;
320	}
321
322	const char* licenseName;
323	const char* licenseText;
324	for (int i = 0;
325		data->FindString(kLicenseNameField, i, &licenseName) == B_OK
326			&& data->FindString(kLicenseTextField, i, &licenseText) == B_OK;
327		++i) {
328		if (!fLicenseNames.Add(licenseName) || !fLicenseTexts.Add(licenseText))
329			return B_NO_MEMORY;
330	}
331
332	return B_OK;
333}
334
335
336status_t
337BRepositoryInfo::_SetTo(const BEntry& entry)
338{
339	BFile file(&entry, B_READ_ONLY);
340	status_t result = file.InitCheck();
341	if (result != B_OK)
342		return result;
343
344	off_t size;
345	if ((result = file.GetSize(&size)) != B_OK)
346		return result;
347
348	BString configString;
349	char* buffer = configString.LockBuffer(size);
350	if (buffer == NULL)
351		return B_NO_MEMORY;
352
353	if ((result = file.Read(buffer, size)) < size) {
354		configString.UnlockBuffer(0);
355		return (result >= 0) ? B_IO_ERROR : result;
356	}
357
358	buffer[size] = '\0';
359	configString.UnlockBuffer(size);
360
361	DriverSettingsUnloader settingsHandle(
362		parse_driver_settings_string(configString.String()));
363	if (!settingsHandle.IsSet())
364		return B_BAD_DATA;
365
366	const char* name = get_driver_parameter(settingsHandle.Get(), "name", NULL,
367		NULL);
368	const char* identifier = get_driver_parameter(settingsHandle.Get(),
369		"identifier", NULL, NULL);
370	// Also handle the old name if the new one isn't found
371	if (identifier == NULL || *identifier == '\0')
372		identifier = get_driver_parameter(settingsHandle.Get(),
373			"url", NULL, NULL);
374	const char* baseUrl = get_driver_parameter(settingsHandle.Get(),
375		"baseurl", NULL, NULL);
376	const char* vendor = get_driver_parameter(settingsHandle.Get(),
377		"vendor", NULL, NULL);
378	const char* summary = get_driver_parameter(settingsHandle.Get(),
379		"summary", NULL, NULL);
380	const char* priorityString = get_driver_parameter(settingsHandle.Get(),
381		"priority", NULL, NULL);
382	const char* architectureString = get_driver_parameter(settingsHandle.Get(),
383		"architecture", NULL, NULL);
384
385	if (name == NULL || *name == '\0'
386		|| identifier == NULL || *identifier == '\0'
387		|| vendor == NULL || *vendor == '\0'
388		|| summary == NULL || *summary == '\0'
389		|| priorityString == NULL || *priorityString == '\0'
390		|| architectureString == NULL || *architectureString == '\0') {
391		return B_BAD_DATA;
392	}
393
394	BPackageArchitecture architecture;
395	if (BPackageInfo::GetArchitectureByName(architectureString, architecture)
396			!= B_OK || architecture == B_PACKAGE_ARCHITECTURE_ANY) {
397		return B_BAD_DATA;
398	}
399
400	fName = name;
401	fBaseURL = baseUrl;
402	fIdentifier = identifier;
403	fVendor = vendor;
404	fSummary = summary;
405	fPriority = atoi(priorityString);
406	fArchitecture = architecture;
407
408	return B_OK;
409}
410
411
412}	// namespace BPackageKit
413