1 /* 2 * Copyright 2011-2018, 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 <package/PackageInfo.h> 23 24 25 namespace BPackageKit { 26 27 28 const uint8 BRepositoryInfo::kDefaultPriority = 50; 29 30 const char* const BRepositoryInfo::kNameField = "name"; 31 const char* const BRepositoryInfo::kURLField = "url"; 32 const char* const BRepositoryInfo::kIdentifierField = "identifier"; 33 const char* const BRepositoryInfo::kBaseURLField = "baseUrl"; 34 const char* const BRepositoryInfo::kVendorField = "vendor"; 35 const char* const BRepositoryInfo::kSummaryField = "summary"; 36 const char* const BRepositoryInfo::kPriorityField = "priority"; 37 const char* const BRepositoryInfo::kArchitectureField = "architecture"; 38 const char* const BRepositoryInfo::kLicenseNameField = "licenseName"; 39 const char* const BRepositoryInfo::kLicenseTextField = "licenseText"; 40 41 42 BRepositoryInfo::BRepositoryInfo() 43 : 44 fInitStatus(B_NO_INIT), 45 fPriority(kDefaultPriority), 46 fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT) 47 { 48 } 49 50 51 BRepositoryInfo::BRepositoryInfo(BMessage* data) 52 : 53 inherited(data), 54 fLicenseTexts(5) 55 { 56 fInitStatus = _SetTo(data); 57 } 58 59 60 BRepositoryInfo::BRepositoryInfo(const BEntry& entry) 61 { 62 fInitStatus = _SetTo(entry); 63 } 64 65 66 BRepositoryInfo::~BRepositoryInfo() 67 { 68 } 69 70 71 /*static*/ BRepositoryInfo* 72 BRepositoryInfo::Instantiate(BMessage* data) 73 { 74 if (validate_instantiation(data, "BPackageKit::BRepositoryInfo")) 75 return new (std::nothrow) BRepositoryInfo(data); 76 77 return NULL; 78 } 79 80 81 status_t 82 BRepositoryInfo::Archive(BMessage* data, bool deep) const 83 { 84 status_t result = inherited::Archive(data, deep); 85 if (result != B_OK) 86 return result; 87 88 if (!fBaseURL.IsEmpty()) { 89 if ((result = data->AddString(kBaseURLField, fBaseURL)) != B_OK) 90 return result; 91 } 92 93 if ((result = data->AddString(kNameField, fName)) != B_OK) 94 return result; 95 // Field in the archive is named "url" for backward compatility reasons. 96 // We can change this when everyone has updated to a version of Haiku 97 // with support for reading the "identifier" field. 98 if ((result = data->AddString(kURLField, fIdentifier)) != B_OK) 99 return result; 100 if ((result = data->AddString(kVendorField, fVendor)) != B_OK) 101 return result; 102 result = data->AddString(kSummaryField, fSummary); 103 if (result != 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 124 status_t 125 BRepositoryInfo::InitCheck() const 126 { 127 return fInitStatus; 128 } 129 130 131 status_t 132 BRepositoryInfo::SetTo(const BMessage* data) 133 { 134 return fInitStatus = _SetTo(data); 135 } 136 137 138 status_t 139 BRepositoryInfo::SetTo(const BEntry& entry) 140 { 141 return fInitStatus = _SetTo(entry); 142 } 143 144 145 const BString& 146 BRepositoryInfo::Name() const 147 { 148 return fName; 149 } 150 151 152 const BString& 153 BRepositoryInfo::BaseURL() const 154 { 155 return fBaseURL; 156 } 157 158 159 const BString& 160 BRepositoryInfo::Identifier() const 161 { 162 return fIdentifier; 163 } 164 165 166 const BString& 167 BRepositoryInfo::Vendor() const 168 { 169 return fVendor; 170 } 171 172 173 const BString& 174 BRepositoryInfo::Summary() const 175 { 176 return fSummary; 177 } 178 179 180 uint8 181 BRepositoryInfo::Priority() const 182 { 183 return fPriority; 184 } 185 186 187 BPackageArchitecture 188 BRepositoryInfo::Architecture() const 189 { 190 return fArchitecture; 191 } 192 193 194 const BStringList& 195 BRepositoryInfo::LicenseNames() const 196 { 197 return fLicenseNames; 198 } 199 200 201 const BStringList& 202 BRepositoryInfo::LicenseTexts() const 203 { 204 return fLicenseTexts; 205 } 206 207 208 void 209 BRepositoryInfo::SetName(const BString& name) 210 { 211 fName = name; 212 } 213 214 215 void 216 BRepositoryInfo::SetIdentifier(const BString& identifier) 217 { 218 fIdentifier = identifier; 219 } 220 221 222 void 223 BRepositoryInfo::SetBaseURL(const BString& url) 224 { 225 fBaseURL = url; 226 } 227 228 229 void 230 BRepositoryInfo::SetVendor(const BString& vendor) 231 { 232 fVendor = vendor; 233 } 234 235 236 void 237 BRepositoryInfo::SetSummary(const BString& summary) 238 { 239 fSummary = summary; 240 } 241 242 243 void 244 BRepositoryInfo::SetPriority(uint8 priority) 245 { 246 fPriority = priority; 247 } 248 249 250 void 251 BRepositoryInfo::SetArchitecture(BPackageArchitecture architecture) 252 { 253 fArchitecture = architecture; 254 } 255 256 257 status_t 258 BRepositoryInfo::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 268 void 269 BRepositoryInfo::ClearLicenses() 270 { 271 fLicenseNames.MakeEmpty(); 272 fLicenseTexts.MakeEmpty(); 273 } 274 275 276 status_t 277 BRepositoryInfo::_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 if ((result = data->FindString(kIdentifierField, &fIdentifier)) != B_OK) { 286 // Handle the "url" field as well (it is still the one we generate). 287 // Later on when everyone is using this code we can switch the writing 288 // side to use the "identifier" field with its correct name. 289 if ((result = data->FindString(kURLField, &fIdentifier)) != B_OK) 290 return result; 291 } 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 result = data->FindUInt8(kArchitectureField, (uint8*)&fArchitecture); 299 if (result != B_OK) 300 return result; 301 if (fArchitecture == B_PACKAGE_ARCHITECTURE_ANY) 302 return B_BAD_DATA; 303 304 // Old packages had no base-url field, the "url" field acted both as an 305 // identifier and locator for the repository. 306 data->FindString(kBaseURLField, &fBaseURL); 307 if (fBaseURL.Length() == 0) { 308 fBaseURL = fIdentifier; 309 // In that case make sure the identifier is indeed an http URL 310 // (in the new format, the protocol is not required to be http anymore) 311 if (!fBaseURL.StartsWith("http")) 312 return B_BAD_DATA; 313 } 314 315 const char* licenseName; 316 const char* licenseText; 317 for (int i = 0; 318 data->FindString(kLicenseNameField, i, &licenseName) == B_OK 319 && data->FindString(kLicenseTextField, i, &licenseText) == B_OK; 320 ++i) { 321 if (!fLicenseNames.Add(licenseName) || !fLicenseTexts.Add(licenseText)) 322 return B_NO_MEMORY; 323 } 324 325 return B_OK; 326 } 327 328 329 status_t 330 BRepositoryInfo::_SetTo(const BEntry& entry) 331 { 332 BFile file(&entry, B_READ_ONLY); 333 status_t result = file.InitCheck(); 334 if (result != B_OK) 335 return result; 336 337 off_t size; 338 if ((result = file.GetSize(&size)) != B_OK) 339 return result; 340 341 BString configString; 342 char* buffer = configString.LockBuffer(size); 343 if (buffer == NULL) 344 return B_NO_MEMORY; 345 346 if ((result = file.Read(buffer, size)) < size) { 347 configString.UnlockBuffer(0); 348 return (result >= 0) ? B_IO_ERROR : result; 349 } 350 351 buffer[size] = '\0'; 352 configString.UnlockBuffer(size); 353 354 void* settingsHandle = parse_driver_settings_string(configString.String()); 355 if (settingsHandle == NULL) 356 return B_BAD_DATA; 357 CObjectDeleter<void, status_t> settingsHandleDeleter(settingsHandle, 358 &unload_driver_settings); 359 360 const char* name = get_driver_parameter(settingsHandle, "name", NULL, NULL); 361 const char* identifier = get_driver_parameter(settingsHandle, "identifier", NULL, NULL); 362 // Also handle the old name if the new one isn't found 363 if (identifier == NULL || *identifier == '\0') 364 identifier = get_driver_parameter(settingsHandle, "url", NULL, NULL); 365 const char* baseUrl = get_driver_parameter(settingsHandle, "baseurl", NULL, NULL); 366 const char* vendor 367 = get_driver_parameter(settingsHandle, "vendor", NULL, NULL); 368 const char* summary 369 = get_driver_parameter(settingsHandle, "summary", NULL, NULL); 370 const char* priorityString 371 = get_driver_parameter(settingsHandle, "priority", NULL, NULL); 372 const char* architectureString 373 = get_driver_parameter(settingsHandle, "architecture", NULL, NULL); 374 375 if (name == NULL || *name == '\0' 376 || identifier == NULL || *identifier == '\0' 377 || vendor == NULL || *vendor == '\0' 378 || summary == NULL || *summary == '\0' 379 || priorityString == NULL || *priorityString == '\0' 380 || architectureString == NULL || *architectureString == '\0') { 381 return B_BAD_DATA; 382 } 383 384 BPackageArchitecture architecture; 385 if (BPackageInfo::GetArchitectureByName(architectureString, architecture) 386 != B_OK || architecture == B_PACKAGE_ARCHITECTURE_ANY) { 387 return B_BAD_DATA; 388 } 389 390 fName = name; 391 fBaseURL = baseUrl; 392 fIdentifier = identifier; 393 fVendor = vendor; 394 fSummary = summary; 395 fPriority = atoi(priorityString); 396 fArchitecture = architecture; 397 398 return B_OK; 399 } 400 401 402 } // namespace BPackageKit 403