The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
client.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
3  2008 - 2015 by Ignacio Riquelme Morelle <shadowm2006@gmail.com>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "addon/info.hpp"
17 #include "addon/manager.hpp"
18 #include "addon/validation.hpp"
19 #include "cursor.hpp"
20 #include "font/pango/escape.hpp"
21 #include "formula/string_utils.hpp"
22 #include "gettext.hpp"
24 #include "gui/dialogs/message.hpp"
25 #include "gui/widgets/window.hpp"
26 #include "log.hpp"
27 #include "random.hpp"
28 #include "serialization/parser.hpp"
30 
31 #include "addon/client.hpp"
32 
33 static lg::log_domain log_addons_client("addons-client");
34 #define ERR_ADDONS LOG_STREAM(err , log_addons_client)
35 #define WRN_ADDONS LOG_STREAM(warn, log_addons_client)
36 #define LOG_ADDONS LOG_STREAM(info, log_addons_client)
37 #define DBG_ADDONS LOG_STREAM(debug, log_addons_client)
38 
40 
42  : addr_(address)
43  , host_()
44  , port_()
45  , conn_(nullptr)
46  , stat_(nullptr)
47  , last_error_()
48  , last_error_data_()
49 {
50  const std::vector<std::string>& address_components =
51  utils::split(addr_, ':');
52 
53  if(address_components.empty()) {
54  throw invalid_server_address();
55  }
56 
57  // FIXME: this parsing will break IPv6 numeric addresses! */
58  host_ = address_components[0];
59  port_ = address_components.size() == 2 ?
60  address_components[1] : std::to_string(default_campaignd_port);
61 }
62 
64 {
65  LOG_ADDONS << "connecting to server " << host_ << " on port " << port_ << '\n';
66 
67  utils::string_map i18n_symbols;
68  i18n_symbols["server_address"] = addr_;
69 
70  conn_.reset(new network_asio::connection(host_, port_));
71 
73  vgettext("Connecting to $server_address|...", i18n_symbols));
74 }
75 
77 {
78  cfg.clear();
79 
80  config response_buf;
81 
82  /** @todo FIXME: get rid of this legacy "campaign"/"campaigns" silliness
83  */
84 
85  this->send_simple_request("request_campaign_list", response_buf);
86  this->wait_for_transfer_done(_("Downloading list of add-ons..."));
87 
88  cfg = response_buf.child("campaigns");
89 
90  return !this->update_last_error(response_buf);
91 }
92 
94 {
95  terms.clear();
96 
97  config response_buf;
98 
99  this->send_simple_request("request_terms", response_buf);
100  this->wait_for_transfer_done(_("Requesting distribution terms..."));
101 
102  if(const config& msg_cfg = response_buf.child("message")) {
103  terms = msg_cfg["message"].str();
104  }
105 
106  return !this->update_last_error(response_buf);
107 }
108 
109 bool addons_client::upload_addon(const std::string& id, std::string& response_message, config& cfg)
110 {
111  LOG_ADDONS << "preparing to upload " << id << '\n';
112 
113  response_message.clear();
114 
115  utils::string_map i18n_symbols;
116  i18n_symbols["addon_title"] = font::escape_text(cfg["title"]);
117  if(i18n_symbols["addon_title"].empty()) {
118  i18n_symbols["addon_title"] = font::escape_text(make_addon_title(id));
119  }
120 
121  if(!addon_name_legal(id)){
122  i18n_symbols["addon_id"] = font::escape_text(id);
123  this->last_error_ =
124  vgettext("The add-on <i>$addon_title</i> has an invalid id '$addon_id' "
125  "and cannot be published.", i18n_symbols);
126  return false;
127  }
128 
129  std::string passphrase = cfg["passphrase"];
130  // generate a random passphrase and write it to disk
131  // if the .pbl file doesn't provide one already
132  if(passphrase.empty()) {
133  passphrase.resize(8);
134  for(size_t n = 0; n != 8; ++n) {
135  passphrase[n] = randomness::generator->get_random_int('a', 'z');
136  }
137  cfg["passphrase"] = passphrase;
138  set_addon_pbl_info(id, cfg);
139 
140  LOG_ADDONS << "automatically generated an initial passphrase for " << id << '\n';
141  }
142 
143  cfg["name"] = id;
144 
145  config addon_data;
146  try {
147  archive_addon(id, addon_data);
149  this->last_error_ =
150  vgettext("The add-on <i>$addon_title</i> has a file or directory "
151  "containing invalid characters and cannot be published.", i18n_symbols);
152  return false;
153  }
154 
155  std::vector<std::string> badnames;
156  if(!check_names_legal(addon_data, &badnames)){
157  this->last_error_ =
158  vgettext("The add-on <i>$addon_title</i> has an invalid file or directory "
159  "name and cannot be published. "
160 
161  "File or directory names may not contain whitespace, control characters or any of the following characters: '&quot; * / : &lt; &gt; ? \\ | ~'. "
162  "It also may not contain '..' end with '.' or be longer than 255 characters."
163  , i18n_symbols);
164  this->last_error_data_ = font::escape_text(utils::join(badnames, "\n"));
165  return false;
166  }
167  if(!check_case_insensitive_duplicates(addon_data, &badnames)){
168  this->last_error_ =
169  vgettext("The add-on <i>$addon_title</i> contains files or directories with case conflicts. "
170  "File or directory names may not be differently-cased versions of the same string.", i18n_symbols);
171  this->last_error_data_ = font::escape_text(utils::join(badnames, "\n"));
172  return false;
173  }
174 
175  config request_buf, response_buf;
176  request_buf.add_child("upload", cfg).add_child("data", std::move(addon_data));
177 
178  LOG_ADDONS << "sending " << id << '\n';
179 
180  this->send_request(request_buf, response_buf);
181  this->wait_for_transfer_done(vgettext("Sending add-on <i>$addon_title</i>...", i18n_symbols
182  ), true);
183 
184  if(const config& message_cfg = response_buf.child("message")) {
185  response_message = message_cfg["message"].str();
186  LOG_ADDONS << "server response: " << response_message << '\n';
187  }
188 
189  return !this->update_last_error(response_buf);
190 
191 }
192 
194 {
195  response_message.clear();
196 
197  config cfg = get_addon_pbl_info(id);
198 
199  utils::string_map i18n_symbols;
200  i18n_symbols["addon_title"] = font::escape_text(cfg["title"]);
201  if(i18n_symbols["addon_title"].empty()) {
202  i18n_symbols["addon_title"] = font::escape_text(make_addon_title(id));
203  }
204 
205  config request_buf, response_buf;
206  config& request_body = request_buf.add_child("delete");
207 
208  request_body["name"] = id;
209  request_body["passphrase"] = cfg["passphrase"];
210 
211  LOG_ADDONS << "requesting server to delete " << id << '\n';
212 
213  this->send_request(request_buf, response_buf);
214  this->wait_for_transfer_done(vgettext("Removing add-on <i>$addon_title</i> from the server...", i18n_symbols
215  ));
216 
217  if(const config& message_cfg = response_buf.child("message")) {
218  response_message = message_cfg["message"].str();
219  LOG_ADDONS << "server response: " << response_message << '\n';
220  }
221 
222  return !this->update_last_error(response_buf);
223 }
224 
225 bool addons_client::download_addon(config& archive_cfg, const std::string& id, const std::string& title, bool increase_downloads)
226 {
227  archive_cfg.clear();
228 
229  config request_buf;
230  config& request_body = request_buf.add_child("request_campaign");
231 
232  request_body["name"] = id;
233  request_body["increase_downloads"] = increase_downloads;
234 
235  utils::string_map i18n_symbols;
236  i18n_symbols["addon_title"] = font::escape_text(title);
237 
238  LOG_ADDONS << "downloading " << id << '\n';
239 
240  this->send_request(request_buf, archive_cfg);
241  this->wait_for_transfer_done(vgettext("Downloading add-on <i>$addon_title</i>...", i18n_symbols));
242 
243  return !this->update_last_error(archive_cfg);
244 }
245 
247 {
248  const cursor::setter cursor_setter(cursor::WAIT);
249 
250  utils::string_map i18n_symbols;
251  i18n_symbols["addon_title"] = font::escape_text(info.title);
252 
253  if(!check_names_legal(archive_cfg)) {
255  vgettext("The add-on <i>$addon_title</i> has an invalid file or directory "
256  "name and cannot be installed.", i18n_symbols));
257  return false;
258  }
259  if(!check_case_insensitive_duplicates(archive_cfg)){
261  vgettext("The add-on <i>$addon_title</i> has file or directory names "
262  "with case conflicts. This may cause problems.", i18n_symbols));
263  }
264 
265  // Add local version information before unpacking
266 
267  config* maindir = &archive_cfg.find_child("dir", "name", info.id);
268  if(!*maindir) {
269  LOG_ADDONS << "downloaded add-on '" << info.id << "' is missing its directory in the archive; creating it\n";
270  maindir = &archive_cfg.add_child("dir");
271  (*maindir)["name"] = info.id;
272  }
273 
274  LOG_ADDONS << "generating version info for add-on '" << info.id << "'\n";
275 
276  std::ostringstream info_contents;
277  config wml;
278 
279  info_contents <<
280  "#\n"
281  "# File automatically generated by Wesnoth to keep track\n"
282  "# of version information on installed add-ons. DO NOT EDIT!\n"
283  "#\n";
284 
285  info.write_minimal(wml.add_child("info"));
286  write(info_contents, wml);
287 
288  config file;
289  file["name"] = "_info.cfg";
290  file["contents"] = info_contents.str();
291 
292  maindir->add_child("file", file);
293 
294  LOG_ADDONS << "unpacking " << info.id << '\n';
295 
296  // Remove any previously installed versions
297  if(!remove_local_addon(info.id)) {
298  WRN_ADDONS << "failed to uninstall previous version of " << info.id << "; the add-on may not work properly!" << std::endl;
299  }
300 
301  unarchive_addon(archive_cfg);
302  LOG_ADDONS << "unpacking finished\n";
303 
304  return true;
305 }
306 
308 {
309  config archive;
310 
311  if(!(
312  download_addon(archive, addon.id, addon.title, !is_addon_installed(addon.id)) &&
313  install_addon(archive, addon)
314  )) {
315  const std::string& server_error = get_last_server_error();
316  if(!server_error.empty()) {
318  _("The server responded with an error:") + "\n" + server_error);
319  }
320  return false;
321  } else {
322  return true;
323  }
324 }
325 
327 {
328  install_result result;
330  result.wml_changed = false;
331 
332  std::unique_ptr<cursor::setter> cursor_setter(new cursor::setter(cursor::WAIT));
333 
334  // TODO: We don't currently check for the need to upgrade. I'll probably
335  // work on that when implementing dependency tiers later.
336 
337  const std::set<std::string>& deps = addon.resolve_dependencies(addons);
338 
339  std::vector<std::string> missing_deps;
340  std::vector<std::string> broken_deps;
341 
342  for(const std::string& dep : deps) {
343  if(!is_addon_installed(dep)) {
344  if(addons.find(dep) != addons.end()) {
345  missing_deps.push_back(dep);
346  } else {
347  broken_deps.push_back(dep);
348  }
349  }
350  }
351 
352  cursor_setter.reset();
353 
354  if(!broken_deps.empty()) {
355  std::string broken_deps_report;
356 
357  broken_deps_report = _n(
358  "The selected add-on has the following dependency, which is not currently installed or available from the server. Do you wish to continue?",
359  "The selected add-on has the following dependencies, which are not currently installed or available from the server. Do you wish to continue?",
360  broken_deps.size());
361  broken_deps_report += "\n";
362 
363  for(const std::string& broken_dep_id : broken_deps) {
364  broken_deps_report += "\n " + font::unicode_bullet + " " + make_addon_title(broken_dep_id);
365  }
366 
367  if(gui2::show_message(_("Broken Dependencies"), broken_deps_report, gui2::dialogs::message::yes_no_buttons) != gui2::window::OK) {
369  return result; // canceled by user
370  }
371  }
372 
373  if(missing_deps.empty()) {
374  // No dependencies to install, carry on.
375  return result;
376  }
377 
378  {
380  for(const std::string& dep : missing_deps) {
381  const addon_info& missing_addon = addons.at(dep);
382  options[dep] = missing_addon;
383  }
384 
386  bool cont = dlg.show();
387  if(!cont) {
388  return result; // the user has chosen to continue without installing anything.
389  }
390  }
391 
392  //
393  // Install dependencies now.
394  //
395 
396  std::vector<std::string> failed_titles;
397 
398  for(const std::string& dep : missing_deps) {
399  const addon_info& missing_addon = addons.at(dep);
400 
401  if(!try_fetch_addon(missing_addon)) {
402  failed_titles.push_back(missing_addon.title);
403  } else {
404  result.wml_changed = true;
405  }
406  }
407 
408  if(!failed_titles.empty()) {
409  const std::string& failed_deps_report = _n(
410  "The following dependency could not be installed. Do you still wish to continue?",
411  "The following dependencies could not be installed. Do you still wish to continue?",
412  failed_titles.size()) + std::string("\n\n") + utils::bullet_list(failed_titles);
413 
414  result.outcome = gui2::show_message(_("Dependencies Installation Failed"), failed_deps_report, gui2::dialogs::message::yes_no_buttons) == gui2::window::OK ? install_outcome::success : install_outcome::abort; // If the user cancels, return abort. Otherwise, return success, since the user chose to ignore the failure.
415  return result;
416  }
417 
418  return result;
419 }
420 
422 {
423  const std::string& addon_id = addon.id;
424 
425  const bool pbl = have_addon_pbl_info(addon_id);
426  const bool vcs = have_addon_in_vcs_tree(addon_id);
427 
428  if(!pbl && !vcs) {
429  return true;
430  }
431 
432  utils::string_map symbols;
433  symbols["addon"] = font::escape_text(addon.title);
434  std::string text;
435  std::vector<std::string> extra_items;
436 
437  text = vgettext("The add-on '$addon|' is already installed and contains additional information that will be permanently lost if you continue:", symbols);
438  text += "\n\n";
439 
440  if(pbl) {
441  extra_items.push_back(_("Publishing information file (.pbl)"));
442  }
443 
444  if(vcs) {
445  extra_items.push_back(_("Version control system (VCS) information"));
446  }
447 
448  text += utils::bullet_list(extra_items) + "\n\n";
449  text += _("Do you really wish to continue?");
450 
452 }
453 
455 {
456  if(!(do_check_before_overwriting_addon(addon))) {
457  // Just do nothing and leave.
458  install_result result;
460  result.wml_changed = false;
461 
462  return result;
463  }
464 
465  // Resolve any dependencies
466  install_result res = do_resolve_addon_dependencies(addons, addon);
467  if(res.outcome != install_outcome::success) { // this function only returns SUCCESS and ABORT as outcomes
468  return res; // user aborted
469  }
470 
471  if(!try_fetch_addon(addon)) {
473  return res; //wml_changed should have whatever value was obtained in resolving dependencies
474  } else {
475  res.wml_changed = true;
476  return res; //we successfully installed something, so now the wml was definitely changed
477  }
478 }
479 
481 {
482  if(config const &error = response_cfg.child("error")) {
483  this->last_error_ = font::escape_text(error["message"].str());
484  this->last_error_data_ = font::escape_text(error["extra_data"].str());
485  ERR_ADDONS << "server error: " << error << '\n';
486  return true;
487  } else {
488  this->last_error_.clear();
489  this->last_error_data_.clear();
490  return false;
491  }
492 }
493 
495 {
496  assert(conn_ != nullptr);
497  if(conn_ == nullptr) {
498  ERR_ADDONS << "not connected to server" << std::endl;
499  throw not_connected_to_server();
500  }
501 }
502 
503 void addons_client::send_request(const config& request, config& response)
504 {
505  check_connected();
506 
507  response.clear();
508  this->conn_->transfer(request, response);
509 }
510 
511 void addons_client::send_simple_request(const std::string& request_string, config& response)
512 {
513  config request;
514  request.add_child(request_string);
515  this->send_request(request, response);
516 }
517 struct read_addon_connection_data : public network_transmission::connection_data
518 {
520  size_t total() override { return conn_.bytes_to_read(); }
521  virtual size_t current() override { return conn_.bytes_read(); }
522  virtual bool finished() override { return conn_.done(); }
523  virtual void cancel() override { return conn_.cancel(); }
524  virtual void poll() override { conn_.poll(); }
526 };
527 struct write_addon_connection_data : public network_transmission::connection_data
528 {
530  size_t total() override { return conn_.bytes_to_write(); }
531  virtual size_t current() override { return conn_.bytes_written(); }
532  virtual bool finished() override { return conn_.done(); }
533  virtual void cancel() override { return conn_.cancel(); }
534  virtual void poll() override { conn_.poll(); }
536 };
537 void addons_client::wait_for_transfer_done(const std::string& status_message, bool track_upload)
538 {
539  check_connected();
540  std::unique_ptr<network_transmission::connection_data> cd;
541  if(track_upload)
542  cd.reset(new write_addon_connection_data{ *conn_ });
543  else
544  cd.reset(new read_addon_connection_data{ *conn_ });
545  if(!stat_) {
546  stat_.reset(new network_transmission(*cd, _("Add-ons Manager"), status_message));
547  } else {
548  stat_->set_subtitle(status_message);
549  stat_->set_connection_data(*cd);
550  }
551 
552  if(!stat_->show()) {
553  // Notify the caller chain that the user aborted the operation.
554  throw user_exit();
555  }
556 }
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...
Definition: client.cpp:326
bool check_names_legal(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for illegal names.
Definition: validation.cpp:222
write_addon_connection_data(network_asio::connection &conn)
Definition: client.cpp:529
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.
Definition: message.cpp:152
Dialog is closed with ok button.
Definition: window.hpp:111
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...
Definition: config.cpp:400
bool check_case_insensitive_duplicates(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for case-conflicts.
Definition: validation.cpp:231
std::string port_
Definition: client.hpp:123
std::vector< char_t > string
std::map< std::string, t_string > string_map
virtual bool finished() override
Definition: client.cpp:532
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
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.
Definition: config.cpp:763
bool download_addon(config &archive_cfg, const std::string &id, const std::string &title, bool increase_downloads=true)
Downloads the specified add-on from the server.
Definition: client.cpp:225
std::string host_
Definition: client.hpp:122
virtual void poll() override
Definition: client.cpp:534
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
logger & info()
Definition: log.cpp:91
bool try_fetch_addon(const addon_info &addon)
Definition: client.cpp:307
This file contains the window object, this object is a top level container which has the event manage...
bool is_addon_installed(const std::string &addon_name)
Check whether the specified add-on is currently installed.
Definition: manager.cpp:164
bool update_last_error(config &response_cfg)
Definition: client.cpp:480
addons_client(const addons_client &)=delete
size_t total() override
Definition: client.cpp:520
#define ERR_ADDONS
Definition: client.cpp:34
virtual bool finished() override
Definition: client.cpp:522
std::string last_error_
Definition: client.hpp:126
bool install_addon(config &archive_cfg, const addon_info &info)
Installs the specified add-on using an archive received from the server.
Definition: client.cpp:246
void clear()
Definition: config.cpp:790
bool have_addon_in_vcs_tree(const std::string &addon_name)
Returns true if the specified add-ons appear to be managed by a 'supported' VCS.
Definition: manager.cpp:66
bool show(const unsigned auto_close_time=0)
Shows the window.
std::size_t bytes_to_write() const
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
void write_minimal(config &cfg) const
Write only minimal WML used for state tracking (_info.cfg) files.
Definition: info.cpp:113
void send_request(const config &request, config &response)
Sends a request to the add-ons server.
Definition: client.cpp:503
std::size_t bytes_read() const
static lg::log_domain log_addons_client("addons-client")
#define LOG_ADDONS
Definition: client.cpp:36
virtual size_t current() override
Definition: client.cpp:521
virtual size_t current() override
Definition: client.cpp:531
const config & options()
Definition: game.cpp:570
virtual void poll() override
Definition: client.cpp:524
const std::string & get_last_server_error() const
Returns the last error message sent by the server, or an empty string.
Definition: client.hpp:60
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
virtual void cancel() override
Definition: client.cpp:533
void check_connected() const
Makes sure the add-ons server connection is working.
Definition: client.cpp:494
std::string id
Definition: info.hpp:31
void set_addon_pbl_info(const std::string &addon_name, const config &cfg)
Definition: manager.cpp:94
static UNUSEDNOWARN std::string _n(const char *str1, const char *str2, int n)
Definition: gettext.hpp:93
A class that represents a TCP/IP connection.
Shows a yes and no button.
Definition: message.hpp:79
network_asio::connection & conn_
Definition: client.cpp:525
std::size_t bytes_to_read() const
bool remove_local_addon(const std::string &addon)
Definition: manager.cpp:118
void connect()
Try to establish a connection to the add-ons server.
Definition: client.cpp:63
read_addon_connection_data(network_asio::connection &conn)
Definition: client.cpp:519
config get_addon_pbl_info(const std::string &addon_name)
Gets the publish information for an add-on.
Definition: manager.cpp:80
std::string addr_
Definition: client.hpp:121
bool addon_name_legal(const std::string &name)
Checks whether an add-on id/name is legal or not.
Definition: validation.cpp:90
std::string escape_text(const std::string &text)
Escapes the pango markup characters in a text.
Definition: escape.hpp:30
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...
Definition: client.cpp:421
Thrown by operations encountering invalid UTF-8 data.
network_asio::connection & conn_
Definition: client.cpp:535
bool have_addon_pbl_info(const std::string &addon_name)
Returns true if there's a local .pbl file stored for the specified add-on.
Definition: manager.cpp:75
void wait_for_transfer_done(const std::string &status_message, bool track_upload=false)
Waits for a network transfer, displaying a status window.
Definition: client.cpp:537
void archive_addon(const std::string &addon_name, config &cfg)
Archives an add-on into a config object for campaignd transactions.
Definition: manager.cpp:298
std::string bullet_list(const T &v, size_t indent=4, const std::string &bullet=font::unicode_bullet)
Generates a new string containing a bullet list.
bool done() const
True if connected and no high-level operation is in progress.
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
Definition: random.hpp:51
const std::string unicode_bullet
Definition: constants.cpp:42
install_outcome outcome
Definition: client.hpp:36
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:57
config & add_child(config_key_type key)
Definition: config.cpp:456
#define WRN_ADDONS
Definition: client.cpp:35
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
Definition: info.cpp:223
std::string vgettext(const char *msgid, const utils::string_map &symbols)
std::string last_error_data_
Definition: client.hpp:127
std::unique_ptr< network_asio::connection > conn_
Definition: client.hpp:124
const unsigned short default_campaignd_port
Default port number for the addon server.
Definition: validation.cpp:24
void write(std::ostream &out, configr_of const &cfg, unsigned int level)
Definition: parser.cpp:749
void unarchive_addon(const config &cfg)
Definition: manager.cpp:331
std::string title
Definition: info.hpp:32
std::unique_ptr< gui2::dialogs::network_transmission > stat_
Definition: client.hpp:125
bool upload_addon(const std::string &id, std::string &response_message, config &cfg)
Requests the specified add-on to be uploaded.
Definition: client.cpp:109
Standard logging facilities (interface).
std::size_t poll()
Handle all pending asynchronous events and return.
Dialog that tracks network transmissions.
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:205
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
bool delete_remote_addon(const std::string &id, std::string &response_message)
Requests the specified add-on to be removed from the server.
Definition: client.cpp:193
bool request_distribution_terms(std::string &terms)
Request the add-ons server distribution terms message.
Definition: client.cpp:93
size_t total() override
Definition: client.cpp:530
static map_location::DIRECTION n
std::map< std::string, addon_info > addons_list
Definition: info.hpp:26
virtual void cancel() override
Definition: client.cpp:523
install_result install_addon_with_checks(const addons_list &addons, const addon_info &addon)
Do a 'smart' fetch of an add-on, checking to avoid overwrites for devs and resolving dependencies...
Definition: client.cpp:454
std::size_t bytes_written() const
std::set< std::string > resolve_dependencies(const addons_list &addons) const
Resolve an add-on's dependency tree in a recursive fashion.
Definition: info.cpp:181
bool request_addons_list(config &cfg)
Request the add-ons list from the server.
Definition: client.cpp:76
void send_simple_request(const std::string &request_string, config &response)
Sends a simple request message to the add-ons server.
Definition: client.cpp:511