25 #include <boost/algorithm/string.hpp>
32 const std::array<std::string, ADDON_TYPES_COUNT> addon_type_strings {{
33 "unknown",
"core",
"campaign",
"scenario",
"campaign_sp_mp",
"campaign_mp",
34 "scenario_mp",
"map_pack",
"era",
"faction",
"mod_mp",
"media",
"theme",
"other"
37 struct addon_name_char_illegal
42 inline bool operator()(
char c)
const
59 std::find_if(name.begin(), name.end(), addon_name_char_illegal()) != name.end()) {
76 bool check_names_legal_internal(
const config& dir, std::string current_prefix, std::vector<std::string>* badlist)
78 if (!current_prefix.empty()) {
79 current_prefix +=
'/';
87 badlist->push_back(current_prefix +
filename);
95 const std::string& dirname =
path[
"name"];
96 const std::string& new_prefix = current_prefix + dirname;
100 badlist->push_back(new_prefix +
"/");
107 if(!check_names_legal_internal(
path, new_prefix, badlist) && !badlist) {
112 return badlist ? badlist->empty() :
true;
115 bool check_case_insensitive_duplicates_internal(
const config& dir,
const std::string& prefix, std::vector<std::string>* badlist){
116 typedef std::pair<bool, std::string> printed_and_original;
117 std::map<std::string, printed_and_original> filenames;
120 std::string original;
123 const std::string
lowercase = boost::algorithm::to_lower_copy(
filename.str(), std::locale::classic());
124 const std::string with_prefix = prefix +
filename.str();
125 std::tie(std::ignore, inserted) = filenames.emplace(
lowercase, std::pair(
false, with_prefix));
128 std::tie(printed, original) = filenames[
lowercase];
130 badlist->push_back(original);
131 filenames[
lowercase] = make_pair(
true, std::string());
133 badlist->push_back(with_prefix);
141 const std::string
lowercase = boost::algorithm::to_lower_copy(
filename.str(), std::locale::classic());
142 const std::string with_prefix = prefix +
filename.str();
143 std::tie(std::ignore, inserted) = filenames.emplace(
lowercase, std::pair(
false, with_prefix));
146 std::tie(printed, original) = filenames[
lowercase];
148 badlist->push_back(original);
149 filenames[
lowercase] = make_pair(
true, std::string());
151 badlist->push_back(with_prefix);
156 if(!check_case_insensitive_duplicates_internal(
path, with_prefix +
"/", badlist) && !badlist) {
161 return badlist ? badlist->empty() :
true;
172 return check_names_legal_internal(dir,
"", badlist);
177 return check_case_insensitive_duplicates_internal(dir,
"", badlist);
185 unsigned addon_type_num = 0;
188 if(str == addon_type_strings[addon_type_num]) {
199 return addon_type_strings[
type];
203 const char escape_char =
'\x01';
221 res.resize(str.size());
223 for(std::string::const_iterator j = str.begin(); j != str.end(); ++j) {
225 res.resize(res.size()+1);
226 res[
n++] = escape_char;
238 std::string res(str.size(),
'\0');
241 for(std::string::const_iterator j = str.begin(); j != str.end(); ) {
243 if((
c == escape_char) && (j != str.end())) {
260 std::string hash = file[
"hash"].str();
274 hashlist[
"name"] =
data[
"name"];
278 file[
"name"] =
f[
"name"];
303 auto origin_dir = from.
find_child(
"dir",
"name",
d[
"name"]);
323 pack[
"name"] = to[
"name"];
324 bool has_changes =
false;
335 file[
"name"] =
f[
"name"];
337 file[
"contents"] =
f[
"contents"];
345 auto origin_dir = from.
find_child(
"dir",
"name",
d[
"name"]);
380 static const std::map<ADDON_CHECK_STATUS, std::string> message_table = {
392 N_(
"Incorrect add-on passphrase.")
396 N_(
"Forum authentication was requested for a user that is not registered on the forums.")
400 N_(
"Upload denied. Please contact the server administration for assistance.")
404 N_(
"Attempted to upload an update pack for a non-existent add-on.")
413 N_(
"No add-on data was supplied by the client.")
417 N_(
"Invalid upload pack.")
421 N_(
"Invalid add-on name.")
425 N_(
"Formatting character in add-on name.")
429 N_(
"The add-on contains files or directories with illegal names.\n"
431 "Names containing whitespace, control characters, or any of the following symbols are not allowed:\n"
433 " \" * / : < > ? \\ | ~\n"
435 "Additionally, names may not be longer than 255 characters, contain '..', or end with '.'.")
439 N_(
"The add-on contains files or directories with case conflicts.\n"
441 "Names in the same directory may not be differently-cased versions of each other.")
445 N_(
"The add-on name contains an invalid UTF-8 sequence.")
454 N_(
"No add-on title specified.")
458 N_(
"No add-on author/maintainer name specified.")
462 N_(
"No add-on version specified.")
466 N_(
"No add-on description specified.")
470 N_(
"No add-on author/maintainer email specified.")
474 N_(
"Missing passphrase.")
478 N_(
"Formatting character in add-on title.")
482 N_(
"Invalid or unspecified add-on type.")
486 N_(
"Version number not greater than the latest uploaded version.")
490 N_(
"Feedback topic id is not a number.")
494 N_(
"Feedback topic does not exist.")
498 N_(
"The add-on publish information contains an invalid UTF-8 sequence.")
502 N_(
"The add-on’s forum_auth attribute does not match what was previously uploaded.")
511 N_(
"Unspecified server error.")
515 N_(
"Server is in read-only mode.")
519 N_(
"Corrupted server add-ons list.")
523 N_(
"Empty add-on version list on the server.")
527 N_(
"This server does not support using the forum_auth attribute in your pbl.")
531 for(
const auto& entry : message_table) {
532 if(
static_cast<unsigned int>(entry.first) == code) {
537 return N_(
"Unspecified validation failure.");
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
optional_config_impl< config > find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
child_itors child_range(config_key_type key)
config & add_child(config_key_type key)
virtual std::string base64_digest() const override
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
static std::string _(const char *str)
bool is_legal_user_file_name(const std::string &name, bool allow_whitespace=true)
Returns whether the given filename is a legal name for a user-created file.
std::string lowercase(std::string_view s)
Returns a lowercased version of the string.
std::string filename
Filename.
static map_location::direction n
bool addon_name_legal(const std::string &name)
Checks whether an add-on id/name is legal or not.
bool needs_escaping(char c)
std::string file_hash(const config &file)
std::string unencode_binary(const std::string &str)
void make_updatepack(config &pack, const config &from, const config &to)
&from, &to are the top directories of their structures; addlist/removelist tag is treated as [dir]
static bool write_difference(config &pack, const config &from, const config &to, bool with_content)
Surround with [dir][/dir].
ADDON_TYPE get_addon_type(const std::string &str)
bool addon_filename_legal(const std::string &name)
Checks whether an add-on file name is legal or not.
bool check_names_legal(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for illegal names.
void write_hashlist(config &hashlist, const config &data)
bool contains_hashlist(const config &from, const config &to)
const unsigned short default_campaignd_port
Default port number for the addon server.
std::string addon_check_status_desc(unsigned int code)
static std::string file_hash_raw(const config &file)
std::string translated_addon_check_status(unsigned int code)
std::string encode_binary(const std::string &str)
bool comp_file_hash(const config &file_a, const config &file_b)
std::string get_addon_type_string(ADDON_TYPE type)
bool check_case_insensitive_duplicates(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for case-conflicts.
@ SERVER_ADDONS_LIST
Corrupted server add-ons list.
@ UNAUTHORIZED
Authentication failed.
@ BAD_FEEDBACK_TOPIC_ID
The provided topic ID for the addon's feedback forum thread is invalid.
@ SERVER_DELTA_NO_VERSIONS
No versions to deltify against.
@ NO_TITLE
No title specified.
@ AUTH_TYPE_MISMATCH
The addon's forum_auth value does not match its previously set value.
@ ILLEGAL_FILENAME
Bad filename.
@ NO_PASSPHRASE
No passphrase specified.
@ UNEXPECTED_DELTA
Delta for a non-existent add-on.
@ VERSION_NOT_INCREMENTED
Version number is not an increment.
@ FILENAME_CASE_CONFLICT
Filename case conflict.
@ TITLE_HAS_MARKUP
Markup in add-on title.
@ BAD_DELTA
Bad delta pack.
@ SERVER_UNSPECIFIED
Unspecified server error.
@ BAD_TYPE
Bad add-on type.
@ NO_AUTHOR
No author specified.
@ NO_DESCRIPTION
No description specified.
@ NO_EMAIL
No email specified.
@ FEEDBACK_TOPIC_ID_NOT_FOUND
The provided topic ID for the addon's feedback forum thread wasn't found in the forum database.
@ INVALID_UTF8_NAME
Invalid UTF-8 sequence in add-on name.
@ USER_DOES_NOT_EXIST
Requested forum authentication for a user that doesn't exist on the forums.
@ INVALID_UTF8_ATTRIBUTE
Invalid UTF-8 sequence in add-on metadata.
@ BAD_NAME
Bad add-on name.
@ NAME_HAS_MARKUP
Markup in add-on name.
@ SERVER_FORUM_AUTH_DISABLED
The remote add-ons server does not support forum authorization.
@ SERVER_READ_ONLY
Server read-only mode on.
@ NO_VERSION
No version specified.
ADDON_TYPE
Values used for add-on classification; UI-only at the moment, in the future it could be used for dire...