18 #include "addon/manager.hpp" 44 #define ERR_ADDONS LOG_STREAM(err , log_addons_client) 45 #define WRN_ADDONS LOG_STREAM(warn, log_addons_client) 46 #define LOG_ADDONS LOG_STREAM(info, log_addons_client) 47 #define DBG_ADDONS LOG_STREAM(debug, log_addons_client) 60 , server_capabilities_()
66 }
catch(
const std::runtime_error&) {
76 i18n_symbols[
"server_address"] =
addr_;
80 const auto&
msg =
VGETTEXT(
"Connecting to $server_address|...", i18n_symbols);
90 if(
const auto&
info = response_buf.
child(
"server_id")) {
113 LOG_ADDONS <<
"Server " << id_desc <<
" version " << version_desc
150 if(
const config& msg_cfg = response_buf.
child(
"message")) {
151 terms = msg_cfg[
"message"].str();
159 LOG_ADDONS <<
"preparing to upload " <<
id <<
'\n';
161 response_message.clear();
165 if(i18n_symbols[
"addon_title"].empty()) {
172 VGETTEXT(
"The add-on <i>$addon_title</i> has an invalid id '$addon_id' " 173 "and cannot be published.", i18n_symbols);
184 VGETTEXT(
"The add-on <i>$addon_title</i> has a file or directory " 185 "containing invalid characters and cannot be published.", i18n_symbols);
189 std::vector<std::string> badnames;
192 VGETTEXT(
"The add-on <i>$addon_title</i> has an invalid file or directory " 193 "name and cannot be published. " 195 "File or directory names may not contain '..' or end with '.' or be longer than 255 characters. " 196 "It also may not contain whitespace, control characters, or any of the following characters:\n\n" * / : < > ? \\ | ~" 203 VGETTEXT(
"The add-on <i>$addon_title</i> contains files or directories with case conflicts. " 204 "File or directory names may not be differently-cased versions of the same string.", i18n_symbols);
210 last_error_ =
VGETTEXT(
"The connection to the remote server is not secure. The add-on <i>$addon_title</i> cannot be uploaded.", i18n_symbols);
216 config hashlist, hash_request;
217 config& request_body = hash_request.
add_child(
"request_campaign_hash");
220 request_body[
"name"] = cfg[
"name"];
226 if(!hashlist.
child(
"error")) {
228 LOG_ADDONS <<
"making an update pack for the add-on " <<
id <<
'\n';
234 config request_buf, response_buf;
242 if(
const config& message_cfg = response_buf.
child(
"message")) {
243 response_message = message_cfg[
"message"].str();
244 LOG_ADDONS <<
"server response: " << response_message <<
'\n';
254 config request_buf, response_buf;
263 if(
const config& message_cfg = response_buf.
child(
"message")) {
264 response_message = message_cfg[
"message"].str();
265 LOG_ADDONS <<
"server response: " << response_message <<
'\n';
274 response_message.clear();
280 if(i18n_symbols[
"addon_title"].empty()) {
284 config request_buf, response_buf;
288 if(cfg[
"passphrase"].empty()) {
290 if(!gui2::dialogs::addon_auth::execute(cfg)) {
293 error[
"message"] =
"Password not provided.";
300 request_body[
"name"] =
id;
301 request_body[
"passphrase"] = cfg[
"passphrase"];
303 LOG_ADDONS <<
"requesting server to delete " <<
id <<
'\n';
309 if(
const config& message_cfg = response_buf.
child(
"message")) {
310 response_message = message_cfg[
"message"].str();
311 LOG_ADDONS <<
"server response: " << response_message <<
'\n';
324 request_body[
"name"] =
id;
325 request_body[
"increase_downloads"] = increase_downloads;
326 request_body[
"version"] = version.
str();
348 LOG_ADDONS <<
"Received an updatepack for the addon '" << info.
id <<
"'\n";
352 if(entry.key ==
"removelist" || entry.key ==
"addlist") {
355 "name and cannot be installed.", i18n_symbols));
360 "with case conflicts. This may cause problems.", i18n_symbols));
366 if(entry.key ==
"removelist") {
368 }
else if(entry.key ==
"addlist") {
377 LOG_ADDONS <<
"Received a full pack for the addon '" << info.
id <<
"'\n";
381 "name and cannot be installed.", i18n_symbols));
386 "with case conflicts. This may cause problems.", i18n_symbols));
393 WRN_ADDONS <<
"failed to uninstall previous version of " << info.
id <<
"; the add-on may not work properly!\n";
416 if(!server_error.empty()) {
418 _(
"The server responded with an error:") +
"\n" + server_error);
432 auto cursor_setter = std::make_unique<cursor::setter>(
cursor::WAIT);
439 std::vector<std::string> missing_deps;
440 std::vector<std::string> broken_deps;
447 for(
const std::string& dep : deps) {
453 missing_deps.push_back(dep);
457 missing_deps.push_back(dep);
459 }
catch(
const std::out_of_range&) {
462 broken_deps.push_back(dep);
467 cursor_setter.reset();
469 if(!broken_deps.empty()) {
470 std::string broken_deps_report;
472 broken_deps_report =
_n(
473 "The selected add-on has the following dependency, which is not currently installed or available from the server. Do you wish to continue?",
474 "The selected add-on has the following dependencies, which are not currently installed or available from the server. Do you wish to continue?",
476 broken_deps_report +=
"\n";
478 for(
const std::string& broken_dep_id : broken_deps) {
488 if(missing_deps.empty()) {
495 for(
const std::string& dep : missing_deps) {
496 options[dep] = addons.at(dep);
499 if(!gui2::dialogs::install_dependencies::execute(options)) {
508 std::vector<std::string> failed_titles;
510 for(
const std::string& dep : missing_deps) {
511 const addon_info& missing_addon = addons.at(dep);
514 failed_titles.push_back(missing_addon.
title);
520 if(!failed_titles.empty()) {
521 const std::string& failed_deps_report =
_n(
522 "The following dependency could not be installed. Do you still wish to continue?",
523 "The following dependencies could not be installed. Do you still wish to continue?",
535 const std::string& addon_id = addon.
id;
547 std::vector<std::string> extra_items;
549 text =
VGETTEXT(
"The add-on '$addon|' is already installed and contains additional information that will be permanently lost if you continue:", symbols);
553 extra_items.push_back(
_(
"Publishing information file (.pbl)"));
557 extra_items.push_back(
_(
"Version control system (VCS) information"));
561 text +=
_(
"Do you really wish to continue?");
594 if(
const config& error = response_cfg.
child(
"error")) {
595 if(error.has_attribute(
"status_code")) {
602 ERR_ADDONS <<
"server error: " << error <<
'\n';
628 assert(
conn_ !=
nullptr);
629 if(
conn_ ==
nullptr) {
630 ERR_ADDONS <<
"not connected to server" << std::endl;
640 conn_->transfer(request, response);
652 :
conn_(conn), client_(client) {}
653 std::size_t
total()
override {
return conn_.bytes_to_read(); }
656 virtual void cancel()
override { client_.connect(); }
664 :
conn_(conn), client_(client) {}
665 std::size_t
total()
override {
return conn_.bytes_to_read(); }
668 void cancel()
override { client_.disconnect(); }
676 :
conn_(conn), client_(client) {}
677 std::size_t
total()
override {
return conn_.bytes_to_write(); }
678 virtual std::size_t
current()
override {
return conn_.bytes_written(); }
680 virtual void cancel()
override { client_.connect(); }
688 std::unique_ptr<network_transmission::connection_data> cd;
700 throw std::invalid_argument(
"Addon client: invalid transfer mode");
install_result do_resolve_addon_dependencies(const addons_list &addons, const addon_info &addon)
Warns the user about unresolved dependencies and installs them if they choose to do so...
const std::string & get_last_server_error() const
Returns the last error message sent by the server, or an empty string.
bool check_names_legal(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for illegal names.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
static std::string _n(const char *str1, const char *str2, int n)
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
bool check_case_insensitive_duplicates(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for case-conflicts.
const_all_children_itors all_children_range() const
In-order iteration over all children.
std::map< std::string, t_string > string_map
virtual bool finished() override
bool contains_hashlist(const config &from, const config &to)
void purge_addon(const config &removelist)
Removes the listed files from the addon.
void append(const config &cfg)
Append data from another config object to this one.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
bool download_addon(config &archive_cfg, const std::string &id, const std::string &title, const version_info &version, bool increase_downloads=true)
Downloads the specified add-on from the server.
std::string campaign_server()
void write_addon_install_info(const std::string &addon_name, const config &cfg)
virtual void poll() override
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
bool try_fetch_addon(const addon_info &addon)
bool is_addon_installed(const std::string &addon_name)
Check whether the specified add-on is currently installed.
bool update_last_error(config &response_cfg)
addons_client(const addons_client &)=delete
virtual std::size_t current() override
std::pair< std::string, std::string > parse_network_address(const std::string &address, const std::string &default_port)
Parse a host:port style network address, supporting [] notation for ipv6 addresses.
virtual bool finished() override
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
bool install_addon(config &archive_cfg, const addon_info &info)
Installs the specified add-on using an archive received from the server.
bool have_addon_in_vcs_tree(const std::string &addon_name)
Returns whether the specified add-on appears to be managed by a VCS or not.
static std::string _(const char *str)
void check_connected() const
Makes sure the add-ons server connection is working.
bool show(const unsigned auto_close_time=0)
Shows the window.
version_info installed_version
void write_minimal(config &cfg) const
Write only minimal WML used for state tracking (_info.cfg) files.
version_info get_addon_version_info(const std::string &addon)
Returns a particular installed add-on's version information.
void send_request(const config &request, config &response)
Sends a request to the add-ons server.
connect_connection_data(network_asio::connection &conn, addons_client &client)
static lg::log_domain log_addons_client("addons-client")
virtual void poll() override
std::string bullet_list(const T &v, std::size_t indent=4, const std::string &bullet=font::unicode_bullet)
Generates a new string containing a bullet list.
read_addon_connection_data(network_asio::connection &conn, addons_client &client)
std::size_t current() override
virtual void cancel() override
std::set< std::string > server_capabilities_
Version in the server is newer than local installation.
void wait_for_transfer_done(const std::string &status_message, transfer_mode mode=transfer_mode::download)
Waits for a network transfer, displaying a status window.
void set_password(const std::string &server, const std::string &login, const std::string &key)
A class that represents a TCP/IP connection.
Shows a yes and no button.
network_asio::connection & conn_
bool remove_local_addon(const std::string &addon)
Removes the specified add-on, deleting its full directory structure.
void connect()
Tries to establish a connection to the add-ons server.
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
std::size_t total() override
Add-ons (campaignd) client class.
The add-on was correctly installed.
network_asio::connection & conn_
config get_addon_pbl_info(const std::string &addon_name)
Gets the publish information for an add-on.
User aborted the operation because of an issue with dependencies or chose not to overwrite the add-on...
bool addon_name_legal(const std::string &name)
Checks whether an add-on id/name is legal or not.
std::string id
Text to match against addon_info.tags()
std::string escape_text(const std::string &text)
Escapes the pango markup characters in a text.
bool do_check_before_overwriting_addon(const addon_info &addon)
Checks whether the given add-on has local .pbl or VCS information and asks before overwriting it...
Thrown by operations encountering invalid UTF-8 data.
network_asio::connection & conn_
bool have_addon_pbl_info(const std::string &addon_name)
Returns whether a .pbl file is present for the specified add-on or not.
void archive_addon(const std::string &addon_name, config &cfg)
Archives an add-on into a config object for campaignd transactions.
std::string password(const std::string &server, const std::string &login)
std::size_t total() override
std::string translated_addon_check_status(unsigned int code)
std::string display_title_full() const
const std::string unicode_bullet
std::size_t total() override
write_addon_connection_data(network_asio::connection &conn, addons_client &client)
install_outcome outcome
Overall outcome of the operation.
Represents version numbers.
config & add_child(config_key_type key)
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
std::string last_error_data_
std::unique_ptr< network_asio::connection > conn_
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] ...
addon_tracking_info get_addon_tracking_info(const addon_info &addon)
Get information about an add-on comparing its local state with the add-ons server entry...
std::vector< std::string > split(const config_attribute_value &val)
const unsigned short default_campaignd_port
Default port number for the addon server.
bool wml_changed
Specifies if WML on disk was altered and needs to be reloaded.
void unarchive_addon(const config &cfg)
std::set< std::string > resolve_dependencies(const addons_list &addons) const
Resolve an add-on's dependency tree in a recursive fashion.
std::string server_version_
Standard logging facilities (interface).
std::string str() const
Serializes the version number into string form.
bool upload_addon(const std::string &id, std::string &response_message, config &cfg, bool local_only)
Uploads an add-on to the server.
Dialog that tracks network transmissions.
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
The add-on could not be downloaded from the server.
Stores additional status information about add-ons.
Dialog was closed with the OK button.
virtual std::size_t current() override
A config object defines a single node in a WML file, with access to child nodes.
bool delete_remote_addon(const std::string &id, std::string &response_message)
Requests the specified add-on to be removed from the server.
bool request_distribution_terms(std::string &terms)
Request the add-ons server distribution terms message.
Contains the outcome of an add-on install operation.
version_info current_version
std::map< std::string, addon_info > addons_list
virtual void cancel() override
install_result install_addon_with_checks(const addons_list &addons, const addon_info &addon)
Performs an add-on download and install cycle.
bool request_addons_list(config &cfg)
Request the add-ons list from the server.
void send_simple_request(const std::string &request_string, config &response)
Sends a simple request message to the add-ons server.
Networked add-ons (campaignd) client interface.
std::string license_notice_