The Battle for Wesnoth  1.15.7+dev
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 Iris Morelle <shadowm2006@gmail.com>
4  Part of the Battle for Wesnoth Project https://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/state.hpp"
19 #include "addon/validation.hpp"
20 #include "cursor.hpp"
21 #include "font/pango/escape.hpp"
22 #include "formula/string_utils.hpp"
23 #include "gettext.hpp"
25 #include "gui/dialogs/message.hpp"
26 #include "gui/widgets/retval.hpp"
27 #include "log.hpp"
28 #include "random.hpp"
29 #include "serialization/parser.hpp"
33 
34 #include <stdexcept>
35 
36 #include "addon/client.hpp"
37 
38 static lg::log_domain log_addons_client("addons-client");
39 #define ERR_ADDONS LOG_STREAM(err , log_addons_client)
40 #define WRN_ADDONS LOG_STREAM(warn, log_addons_client)
41 #define LOG_ADDONS LOG_STREAM(info, log_addons_client)
42 #define DBG_ADDONS LOG_STREAM(debug, log_addons_client)
43 
45 
47  : addr_(address)
48  , host_()
49  , port_()
50  , conn_(nullptr)
51  , last_error_()
52  , last_error_data_()
53 {
54  try {
55  std::tie(host_, port_) = parse_network_address(addr_, std::to_string(default_campaignd_port));
56  } catch(const std::runtime_error&) {
57  throw invalid_server_address();
58  }
59 }
60 
62 {
63  LOG_ADDONS << "connecting to server " << host_ << " on port " << port_ << '\n';
64 
65  utils::string_map i18n_symbols;
66  i18n_symbols["server_address"] = addr_;
67 
68  conn_.reset(new network_asio::connection(host_, port_));
69 
71  VGETTEXT("Connecting to $server_address|...", i18n_symbols),
73 }
74 
76 {
77  cfg.clear();
78 
79  config response_buf;
80 
81  /** @todo FIXME: get rid of this legacy "campaign"/"campaigns" silliness
82  */
83 
84  send_simple_request("request_campaign_list", response_buf);
85  wait_for_transfer_done(_("Downloading list of add-ons..."));
86 
87  std::swap(cfg, response_buf.child("campaigns"));
88 
89  return !update_last_error(response_buf);
90 }
91 
93 {
94  terms.clear();
95 
96  config response_buf;
97 
98  send_simple_request("request_terms", response_buf);
99  wait_for_transfer_done(_("Requesting distribution terms..."));
100 
101  if(const config& msg_cfg = response_buf.child("message")) {
102  terms = msg_cfg["message"].str();
103  }
104 
105  return !update_last_error(response_buf);
106 }
107 
108 bool addons_client::upload_addon(const std::string& id, std::string& response_message, config& cfg, bool local_only)
109 {
110  LOG_ADDONS << "preparing to upload " << id << '\n';
111 
112  response_message.clear();
113 
114  utils::string_map i18n_symbols;
115  i18n_symbols["addon_title"] = font::escape_text(cfg["title"]);
116  if(i18n_symbols["addon_title"].empty()) {
117  i18n_symbols["addon_title"] = font::escape_text(make_addon_title(id));
118  }
119 
120  if(!addon_name_legal(id)){
121  i18n_symbols["addon_id"] = font::escape_text(id);
122  last_error_ =
123  VGETTEXT("The add-on <i>$addon_title</i> has an invalid id '$addon_id' "
124  "and cannot be published.", i18n_symbols);
125  return false;
126  }
127 
128  std::string passphrase = cfg["passphrase"];
129  // generate a random passphrase and write it to disk
130  // if the .pbl file doesn't provide one already
131  if(passphrase.empty()) {
132  passphrase.resize(16);
133  for(std::size_t n = 0; n < passphrase.size(); ++n) {
134  passphrase[n] = randomness::generator->get_random_int('a', 'z');
135  }
136  cfg["passphrase"] = passphrase;
137  set_addon_pbl_info(id, cfg);
138 
139  LOG_ADDONS << "automatically generated an initial passphrase for " << id << '\n';
140  }
141 
142  cfg["name"] = id;
143 
144  config addon_data;
145  try {
146  archive_addon(id, addon_data);
147  } catch(const utf8::invalid_utf8_exception&){
148  last_error_ =
149  VGETTEXT("The add-on <i>$addon_title</i> has a file or directory "
150  "containing invalid characters and cannot be published.", i18n_symbols);
151  return false;
152  }
153 
154  std::vector<std::string> badnames;
155  if(!check_names_legal(addon_data, &badnames)){
156  last_error_ =
157  VGETTEXT("The add-on <i>$addon_title</i> has an invalid file or directory "
158  "name and cannot be published. "
159 
160  "File or directory names may not contain '..' or end with '.' or be longer than 255 characters. "
161  "It also may not contain whitespace, control characters, or any of the following characters:\n\n&quot; * / : &lt; &gt; ? \\ | ~"
162  , i18n_symbols);
164  return false;
165  }
166  if(!check_case_insensitive_duplicates(addon_data, &badnames)){
167  last_error_ =
168  VGETTEXT("The add-on <i>$addon_title</i> contains files or directories with case conflicts. "
169  "File or directory names may not be differently-cased versions of the same string.", i18n_symbols);
171  return false;
172  }
173 
174  if(!local_only) {
175  // Try to make an upload pack if it's avaible on the server
176  config hashlist, hash_request;
177  config& request_body = hash_request.add_child("request_campaign_hash");
178  // We're requesting the latest version of an addon, so we may not specify it
179  // #TODO: Make a selection of the base version for the update ?
180  request_body["name"] = cfg["name"];
181  // request_body["from"] = ???
182  send_request(hash_request, hashlist);
183  wait_for_transfer_done(_("Requesting file index..."));
184 
185  // A silent error check
186  if(!hashlist.child("error")) {
187  if(!contains_hashlist(addon_data, hashlist) || !contains_hashlist(hashlist, addon_data)) {
188  LOG_ADDONS << "making an update pack for the add-on " << id << '\n';
189  config updatepack;
190  // The client shouldn't send the pack if the server is old due to the previous check,
191  // so the server should handle the new format in the `upload` request
192  make_updatepack(updatepack, hashlist, addon_data);
193 
194  config request_buf, response_buf;
195  request_buf.add_child("upload", cfg).append(std::move(updatepack));
196  // #TODO: Make a selection of the base version for the update ? ,
197  // For now, if it's unspecified we'll use the latest avaible before the upload version
198  send_request(request_buf, response_buf);
199  wait_for_transfer_done(VGETTEXT("Sending an update pack for the add-on <i>$addon_title</i>...", i18n_symbols
201 
202  if(const config& message_cfg = response_buf.child("message")) {
203  response_message = message_cfg["message"].str();
204  LOG_ADDONS << "server response: " << response_message << '\n';
205  }
206 
207  if(!update_last_error(response_buf))
208  return true;
209  }
210  }
211  }
212  // If there is an error including an unrecognised request for old servers or no hash data for new uploads we'll just send a full pack
213 
214  config request_buf, response_buf;
215  request_buf.add_child("upload", cfg).add_child("data", std::move(addon_data));
216 
217  LOG_ADDONS << "sending " << id << '\n';
218 
219  send_request(request_buf, response_buf);
220  wait_for_transfer_done(VGETTEXT("Sending add-on <i>$addon_title</i>...", i18n_symbols
222 
223  if(const config& message_cfg = response_buf.child("message")) {
224  response_message = message_cfg["message"].str();
225  LOG_ADDONS << "server response: " << response_message << '\n';
226  }
227 
228  return !update_last_error(response_buf);
229 
230 }
231 
233 {
234  response_message.clear();
235 
236  config cfg = get_addon_pbl_info(id);
237 
238  utils::string_map i18n_symbols;
239  i18n_symbols["addon_title"] = font::escape_text(cfg["title"]);
240  if(i18n_symbols["addon_title"].empty()) {
241  i18n_symbols["addon_title"] = font::escape_text(make_addon_title(id));
242  }
243 
244  config request_buf, response_buf;
245  config& request_body = request_buf.add_child("delete");
246 
247  request_body["name"] = id;
248  request_body["passphrase"] = cfg["passphrase"];
249 
250  LOG_ADDONS << "requesting server to delete " << id << '\n';
251 
252  send_request(request_buf, response_buf);
253  wait_for_transfer_done(VGETTEXT("Removing add-on <i>$addon_title</i> from the server...", i18n_symbols
254  ));
255 
256  if(const config& message_cfg = response_buf.child("message")) {
257  response_message = message_cfg["message"].str();
258  LOG_ADDONS << "server response: " << response_message << '\n';
259  }
260 
261  return !update_last_error(response_buf);
262 }
263 
264 bool addons_client::download_addon(config& archive_cfg, const std::string& id, const std::string& title, const version_info& version, bool increase_downloads)
265 {
266  archive_cfg.clear();
267 
268  config request_buf;
269  config& request_body = request_buf.add_child("request_campaign");
270 
271  request_body["name"] = id;
272  request_body["increase_downloads"] = increase_downloads;
273  request_body["version"] = version.str();
274  request_body["from_version"] = get_addon_version_info(id);
275 
276  utils::string_map i18n_symbols;
277  i18n_symbols["addon_title"] = font::escape_text(title);
278 
279  LOG_ADDONS << "downloading " << id << '\n';
280 
281  send_request(request_buf, archive_cfg);
282  wait_for_transfer_done(VGETTEXT("Downloading add-on <i>$addon_title</i>...", i18n_symbols));
283 
284  return !update_last_error(archive_cfg);
285 }
286 
288 {
289  LOG_ADDONS << "generating version info for add-on '" << info.id << "'\n";
290 
291  std::ostringstream info_contents;
292  config wml;
293 
294  info_contents <<
295  "#\n"
296  "# File automatically generated by Wesnoth to keep track\n"
297  "# of version information on installed add-ons. DO NOT EDIT!\n"
298  "#\n";
299 
300  info.write_minimal(wml.add_child("info"));
301  write(info_contents, wml);
302 
303  return info_contents.str();
304 }
305 
307 {
308  const cursor::setter cursor_setter(cursor::WAIT);
309 
310  utils::string_map i18n_symbols;
311  i18n_symbols["addon_title"] = font::escape_text(info.title);
312 
313  if(archive_cfg.has_child("removelist") || archive_cfg.has_child("addlist")) {
314  LOG_ADDONS << "Received an updatepack for the addon '" << info.id << "'\n";
315 
316  // Update the version tracking file
317  config& info_remove = archive_cfg.add_child("removelist");
318  config& remove_maindir = info_remove.add_child("dir");
319  remove_maindir["name"] = info.id;
320  config file;
321  file["name"] = "_info.cfg";
322  remove_maindir.add_child("file", file);
323 
324  config& info_add = archive_cfg.add_child("addlist");
325  config& add_maindir = info_add.add_child("dir");
326  add_maindir["name"] = info.id;
327  file["contents"] = write_info_contents(info);
328  add_maindir.add_child("file", file);
329 
330  // A consistency check
331  for(const config::any_child entry : archive_cfg.all_children_range()) {
332  if(entry.key == "removelist" || entry.key == "addlist") {
333  if(!check_names_legal(entry.cfg)) {
334  gui2::show_error_message(VGETTEXT("The add-on <i>$addon_title</i> has an invalid file or directory "
335  "name and cannot be installed.", i18n_symbols));
336  return false;
337  }
338  if(!check_case_insensitive_duplicates(entry.cfg)) {
339  gui2::show_error_message(VGETTEXT("The add-on <i>$addon_title</i> has file or directory names "
340  "with case conflicts. This may cause problems.", i18n_symbols));
341  }
342  }
343  }
344 
345  for(const config::any_child entry : archive_cfg.all_children_range()) {
346  if(entry.key == "removelist") {
347  purge_addon(entry.cfg);
348  } else if(entry.key == "addlist") {
349  unarchive_addon(entry.cfg);
350  }
351  }
352 
353  LOG_ADDONS << "Update completed.\n";
354 
355  //#TODO: hash verification ???
356  } else {
357  LOG_ADDONS << "Received a full pack for the addon '" << info.id << "'\n";
358 
359  if(!check_names_legal(archive_cfg)) {
360  gui2::show_error_message(VGETTEXT("The add-on <i>$addon_title</i> has an invalid file or directory "
361  "name and cannot be installed.", i18n_symbols));
362  return false;
363  }
364  if(!check_case_insensitive_duplicates(archive_cfg)) {
365  gui2::show_error_message(VGETTEXT("The add-on <i>$addon_title</i> has file or directory names "
366  "with case conflicts. This may cause problems.", i18n_symbols));
367  }
368 
369  // Add local version information before unpacking
370  config* maindir = &archive_cfg.find_child("dir", "name", info.id);
371  if(!*maindir) {
372  LOG_ADDONS << "downloaded add-on '" << info.id
373  << "' is missing its directory in the archive; creating it\n";
374  maindir = &archive_cfg.add_child("dir");
375  (*maindir)["name"] = info.id;
376  }
377 
378  config file;
379  file["name"] = "_info.cfg";
380  file["contents"] = write_info_contents(info);
381 
382  maindir->add_child("file", file);
383 
384  LOG_ADDONS << "unpacking " << info.id << '\n';
385 
386  // Remove any previously installed versions
387  if(!remove_local_addon(info.id)) {
388  WRN_ADDONS << "failed to uninstall previous version of " << info.id << "; the add-on may not work properly!\n";
389  }
390 
391  unarchive_addon(archive_cfg);
392  LOG_ADDONS << "unpacking finished\n";
393  }
394 
395  return true;
396 }
397 
399 {
400  config archive;
401 
402  if(!(
403  download_addon(archive, addon.id, addon.display_title_full(), addon.current_version, !is_addon_installed(addon.id)) &&
404  install_addon(archive, addon)
405  )) {
406  const std::string& server_error = get_last_server_error();
407  if(!server_error.empty()) {
409  _("The server responded with an error:") + "\n" + server_error);
410  }
411  return false;
412  } else {
413  return true;
414  }
415 }
416 
418 {
419  install_result result;
421  result.wml_changed = false;
422 
423  auto cursor_setter = std::make_unique<cursor::setter>(cursor::WAIT);
424 
425  // TODO: We don't currently check for the need to upgrade. I'll probably
426  // work on that when implementing dependency tiers later.
427 
428  const std::set<std::string>& deps = addon.resolve_dependencies(addons);
429 
430  std::vector<std::string> missing_deps;
431  std::vector<std::string> broken_deps;
432 
433  for(const std::string& dep : deps) {
434  try {
436 
437  // ADDON_NONE means not installed.
438  if(info.state == ADDON_NONE) {
439  missing_deps.push_back(dep);
440  } else if(info.state == ADDON_INSTALLED_UPGRADABLE) {
441  // Tight now, we don't need to distinguish the lists of missing
442  // and outdated addons, so just add them to missing.
443  missing_deps.push_back(dep);
444  }
445  } catch(const std::out_of_range&) {
446  // Dependency wasn't found on server, check locally directly.
447  if(!is_addon_installed(dep)) {
448  broken_deps.push_back(dep);
449  }
450  }
451  }
452 
453  cursor_setter.reset();
454 
455  if(!broken_deps.empty()) {
456  std::string broken_deps_report;
457 
458  broken_deps_report = _n(
459  "The selected add-on has the following dependency, which is not currently installed or available from the server. Do you wish to continue?",
460  "The selected add-on has the following dependencies, which are not currently installed or available from the server. Do you wish to continue?",
461  broken_deps.size());
462  broken_deps_report += "\n";
463 
464  for(const std::string& broken_dep_id : broken_deps) {
465  broken_deps_report += "\n " + font::unicode_bullet + " " + make_addon_title(broken_dep_id);
466  }
467 
468  if(gui2::show_message(_("Broken Dependencies"), broken_deps_report, gui2::dialogs::message::yes_no_buttons) != gui2::retval::OK) {
470  return result; // canceled by user
471  }
472  }
473 
474  if(missing_deps.empty()) {
475  // No dependencies to install, carry on.
476  return result;
477  }
478 
479  {
481  for(const std::string& dep : missing_deps) {
482  options[dep] = addons.at(dep);
483  }
484 
486  return result; // the user has chosen to continue without installing anything.
487  }
488  }
489 
490  //
491  // Install dependencies now.
492  //
493 
494  std::vector<std::string> failed_titles;
495 
496  for(const std::string& dep : missing_deps) {
497  const addon_info& missing_addon = addons.at(dep);
498 
499  if(!try_fetch_addon(missing_addon)) {
500  failed_titles.push_back(missing_addon.title);
501  } else {
502  result.wml_changed = true;
503  }
504  }
505 
506  if(!failed_titles.empty()) {
507  const std::string& failed_deps_report = _n(
508  "The following dependency could not be installed. Do you still wish to continue?",
509  "The following dependencies could not be installed. Do you still wish to continue?",
510  failed_titles.size()) + std::string("\n\n") + utils::bullet_list(failed_titles);
511 
512  result.outcome = gui2::show_message(_("Dependencies Installation Failed"), failed_deps_report, gui2::dialogs::message::yes_no_buttons) == gui2::retval::OK ? install_outcome::success : install_outcome::abort; // If the user cancels, return abort. Otherwise, return success, since the user chose to ignore the failure.
513  return result;
514  }
515 
516  return result;
517 }
518 
520 {
521  const std::string& addon_id = addon.id;
522 
523  const bool pbl = have_addon_pbl_info(addon_id);
524  const bool vcs = have_addon_in_vcs_tree(addon_id);
525 
526  if(!pbl && !vcs) {
527  return true;
528  }
529 
530  utils::string_map symbols;
531  symbols["addon"] = font::escape_text(addon.title);
532  std::string text;
533  std::vector<std::string> extra_items;
534 
535  text = VGETTEXT("The add-on '$addon|' is already installed and contains additional information that will be permanently lost if you continue:", symbols);
536  text += "\n\n";
537 
538  if(pbl) {
539  extra_items.push_back(_("Publishing information file (.pbl)"));
540  }
541 
542  if(vcs) {
543  extra_items.push_back(_("Version control system (VCS) information"));
544  }
545 
546  text += utils::bullet_list(extra_items) + "\n\n";
547  text += _("Do you really wish to continue?");
548 
550 }
551 
553 {
554  if(!(do_check_before_overwriting_addon(addon))) {
555  // Just do nothing and leave.
556  install_result result;
558  result.wml_changed = false;
559 
560  return result;
561  }
562 
563  // Resolve any dependencies
564  install_result res = do_resolve_addon_dependencies(addons, addon);
565  if(res.outcome != install_outcome::success) { // this function only returns SUCCESS and ABORT as outcomes
566  return res; // user aborted
567  }
568 
569  if(!try_fetch_addon(addon)) {
571  return res; //wml_changed should have whatever value was obtained in resolving dependencies
572  } else {
573  res.wml_changed = true;
574  return res; //we successfully installed something, so now the wml was definitely changed
575  }
576 }
577 
579 {
580  if(const config& error = response_cfg.child("error")) {
581  if(error.has_attribute("status_code")) {
582  const auto& status_msg = translated_addon_check_status(error["status_code"].to_unsigned());
583  last_error_ = font::escape_text(status_msg);
584  } else {
585  last_error_ = font::escape_text(error["message"].str());
586  }
587  last_error_data_ = font::escape_text(error["extra_data"].str());
588  ERR_ADDONS << "server error: " << error << '\n';
589  return true;
590  } else {
591  last_error_.clear();
592  last_error_data_.clear();
593  return false;
594  }
595 }
596 
598 {
599  assert(conn_ != nullptr);
600  if(conn_ == nullptr) {
601  ERR_ADDONS << "not connected to server" << std::endl;
602  throw not_connected_to_server();
603  }
604 }
605 
606 void addons_client::send_request(const config& request, config& response)
607 {
608  check_connected();
609 
610  response.clear();
611  conn_->transfer(request, response);
612 }
613 
614 void addons_client::send_simple_request(const std::string& request_string, config& response)
615 {
616  config request;
617  request.add_child(request_string);
618  send_request(request, response);
619 }
620 struct read_addon_connection_data : public network_transmission::connection_data
621 {
623  : conn_(conn), client_(client) {}
624  std::size_t total() override { return conn_.bytes_to_read(); }
625  virtual std::size_t current() override { return conn_.bytes_read(); }
626  virtual bool finished() override { return conn_.done(); }
627  virtual void cancel() override { client_.connect(); }
628  virtual void poll() override { conn_.poll(); }
631 };
632 struct connect_connection_data : public network_transmission::connection_data
633 {
635  : conn_(conn), client_(client) {}
636  std::size_t total() override { return conn_.bytes_to_read(); }
637  std::size_t current() override { return conn_.bytes_read(); }
638  bool finished() override { return conn_.done(); }
639  void cancel() override { client_.disconnect(); }
640  void poll() override { conn_.poll(); }
643 };
644 struct write_addon_connection_data : public network_transmission::connection_data
645 {
647  : conn_(conn), client_(client) {}
648  std::size_t total() override { return conn_.bytes_to_write(); }
649  virtual std::size_t current() override { return conn_.bytes_written(); }
650  virtual bool finished() override { return conn_.done(); }
651  virtual void cancel() override { client_.connect(); }
652  virtual void poll() override { conn_.poll(); }
655 };
657 {
658  check_connected();
659  std::unique_ptr<network_transmission::connection_data> cd;
660  switch(mode) {
662  cd.reset(new read_addon_connection_data{*conn_, *this});
663  break;
665  cd.reset(new connect_connection_data{*conn_, *this});
666  break;
668  cd.reset(new write_addon_connection_data{*conn_, *this});
669  break;
670  default:
671  throw std::invalid_argument("Addon client: invalid transfer mode");
672  }
673 
674  gui2::dialogs::network_transmission stat(*cd, _("Add-ons Manager"), status_message);
675 
676  if(!stat.show()) {
677  // Notify the caller chain that the user aborted the operation.
678  if(mode == transfer_mode::connect) {
679  throw user_disconnect();
680  } else {
681  throw user_exit();
682  }
683  }
684 }
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:417
const std::string & get_last_server_error() const
Returns the last error message sent by the server, or an empty string.
Definition: client.hpp:66
bool check_names_legal(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for illegal names.
Definition: validation.cpp:227
ADDON_STATUS state
Definition: state.hpp:56
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
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:420
bool check_case_insensitive_duplicates(const config &dir, std::vector< std::string > *badlist)
Scans an add-on archive for case-conflicts.
Definition: validation.cpp:236
std::string port_
Definition: client.hpp:135
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:921
std::map< std::string, t_string > string_map
virtual bool finished() override
Definition: client.cpp:650
bool contains_hashlist(const config &from, const config &to)
Definition: validation.cpp:348
void purge_addon(const config &removelist)
Removes the listed files from the addon.
Definition: manager.cpp:327
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:287
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.
Definition: client.cpp:264
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:836
std::string host_
Definition: client.hpp:134
virtual void poll() override
Definition: client.cpp:652
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
logger & info()
Definition: log.cpp:91
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:412
bool try_fetch_addon(const addon_info &addon)
Definition: client.cpp:398
bool is_addon_installed(const std::string &addon_name)
Check whether the specified add-on is currently installed.
Definition: manager.cpp:186
bool update_last_error(config &response_cfg)
Definition: client.cpp:578
addons_client(const addons_client &)=delete
virtual std::size_t current() override
Definition: client.cpp:649
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.
#define ERR_ADDONS
Definition: client.cpp:39
virtual bool finished() override
Definition: client.cpp:626
std::string last_error_
Definition: client.hpp:137
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:306
void clear()
Definition: config.cpp:863
std::string str
Definition: statement.cpp:110
bool have_addon_in_vcs_tree(const std::string &addon_name)
Returns true if the specified add-ons appear to be managed by a &#39;supported&#39; VCS.
Definition: manager.cpp:66
void check_connected() const
Makes sure the add-ons server connection is working.
Definition: client.cpp:597
bool show(const unsigned auto_close_time=0)
Shows the window.
void write_minimal(config &cfg) const
Write only minimal WML used for state tracking (_info.cfg) files.
Definition: info.cpp:146
version_info get_addon_version_info(const std::string &addon)
Returns a particular installed add-on&#39;s version information.
Definition: manager.cpp:379
Add-on is not installed.
Definition: state.hpp:23
void send_request(const config &request, config &response)
Sends a request to the add-ons server.
Definition: client.cpp:606
void poll() override
Definition: client.cpp:640
connect_connection_data(network_asio::connection &conn, addons_client &client)
Definition: client.cpp:634
static lg::log_domain log_addons_client("addons-client")
#define LOG_ADDONS
Definition: client.cpp:41
static std::string write_info_contents(const addon_info &info)
Definition: client.cpp:287
const config & options()
Definition: game.cpp:582
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:762
virtual void poll() override
Definition: client.cpp:628
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:100
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.
addons_client & client_
Definition: client.cpp:654
read_addon_connection_data(network_asio::connection &conn, addons_client &client)
Definition: client.cpp:622
std::size_t current() override
Definition: client.cpp:637
virtual void cancel() override
Definition: client.cpp:651
std::string id
Definition: info.hpp:83
Version in the server is newer than local installation.
Definition: state.hpp:27
addons_client & client_
Definition: client.cpp:630
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:104
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.
Definition: client.cpp:656
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:629
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:61
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
Definition: config.cpp:1399
std::size_t total() override
Definition: client.cpp:636
Add-ons (campaignd) client class.
Definition: client.hpp:29
network_asio::connection & conn_
Definition: client.cpp:641
config get_addon_pbl_info(const std::string &addon_name)
Gets the publish information for an add-on.
Definition: manager.cpp:80
bool finished() override
Definition: client.cpp:638
std::string addr_
Definition: client.hpp:133
bool addon_name_legal(const std::string &name)
Checks whether an add-on id/name is legal or not.
Definition: validation.cpp:95
std::string escape_text(const std::string &text)
Escapes the pango markup characters in a text.
Definition: escape.hpp:32
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:519
Thrown by operations encountering invalid UTF-8 data.
network_asio::connection & conn_
Definition: client.cpp:653
bool have_addon_pbl_info(const std::string &addon_name)
Returns true if there&#39;s a local .pbl file stored for the specified add-on.
Definition: manager.cpp:75
void archive_addon(const std::string &addon_name, config &cfg)
Archives an add-on into a config object for campaignd transactions.
Definition: manager.cpp:264
std::size_t total() override
Definition: client.cpp:648
std::string translated_addon_check_status(unsigned int code)
Definition: validation.cpp:576
std::string display_title_full() const
Definition: info.cpp:225
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:43
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t total() override
Definition: client.cpp:624
write_addon_connection_data(network_asio::connection &conn, addons_client &client)
Definition: client.cpp:646
install_outcome outcome
Definition: client.hpp:36
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:60
Represents version numbers.
config & add_child(config_key_type key)
Definition: config.cpp:476
#define WRN_ADDONS
Definition: client.cpp:40
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
Definition: info.cpp:321
std::string last_error_data_
Definition: client.hpp:138
std::unique_ptr< network_asio::connection > conn_
Definition: client.hpp:136
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] ...
Definition: validation.cpp:430
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...
Definition: state.cpp:24
const unsigned short default_campaignd_port
Default port number for the addon server.
Definition: validation.cpp:27
void unarchive_addon(const config &cfg)
Definition: manager.cpp:296
std::string title
Definition: info.hpp:84
std::set< std::string > resolve_dependencies(const addons_list &addons) const
Resolve an add-on&#39;s dependency tree in a recursive fashion.
Definition: info.cpp:282
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)
Requests the specified add-on to be uploaded.
Definition: client.cpp:108
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
Stores additional status information about add-ons.
Definition: state.hpp:45
addons_client & client_
Definition: client.cpp:642
Dialog was closed with the OK button.
Definition: retval.hpp:34
virtual std::size_t current() override
Definition: client.cpp:625
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
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:232
bool request_distribution_terms(std::string &terms)
Request the add-ons server distribution terms message.
Definition: client.cpp:92
version_info current_version
Definition: info.hpp:89
static map_location::DIRECTION n
std::map< std::string, addon_info > addons_list
Definition: info.hpp:27
virtual void cancel() override
Definition: client.cpp:627
install_result install_addon_with_checks(const addons_list &addons, const addon_info &addon)
Do a &#39;smart&#39; fetch of an add-on, checking to avoid overwrites for devs and resolving dependencies...
Definition: client.cpp:552
bool request_addons_list(config &cfg)
Request the add-ons list from the server.
Definition: client.cpp:75
void send_simple_request(const std::string &request_string, config &response)
Sends a simple request message to the add-ons server.
Definition: client.cpp:614
void cancel() override
Definition: client.cpp:639