ManaPlus
updaterwindow.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 #include "client.h"
27 #include "configuration.h"
28 #include "main.h"
29 #include "settings.h"
30 
31 #include "enums/gui/layouttype.h"
32 
33 #include "fs/files.h"
34 #include "fs/mkdir.h"
35 #include "fs/paths.h"
36 
37 #include "fs/virtfs/fs.h"
38 
39 #include "gui/widgets/button.h"
42 #include "gui/widgets/label.h"
43 #include "gui/widgets/layout.h"
45 #include "gui/widgets/scrollarea.h"
47 
48 #include "net/download.h"
50 
51 #include "resources/db/moddb.h"
52 
53 #include "utils/delete2.h"
54 #include "utils/foreach.h"
55 #include "utils/gettext.h"
56 
57 #include <sys/stat.h>
58 
59 #include <fstream>
60 #include <sstream>
61 
62 #include "debug.h"
63 
65 
66 const std::string xmlUpdateFile("resources.xml");
67 const std::string txtUpdateFile("resources2.txt");
68 const std::string updateServer2
69  ("http://download.manaplus.org/manaplus/updates/");
70 const std::string updateServer3
71  ("http://download2.manaplus.org/manaplus/updates/");
72 const std::string updateServer4
73  ("http://download.evolonline.org/manaplus/updates/");
74 const std::string updateServer5
75  ("http://download3.manaplus.org/manaplus/updates/");
76 
80 static STD_VECTOR<UpdateFile> loadXMLFile(const std::string &fileName,
81  const bool loadMods)
82 {
83  STD_VECTOR<UpdateFile> files;
85  XmlNodeConstPtrConst rootNode = doc.rootNode();
86 
87  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "updates"))
88  {
89  logger->log("Error loading update file: %s", fileName.c_str());
90  return files;
91  }
92 
93  for_each_xml_child_node(fileNode, rootNode)
94  {
95  const bool isMod = xmlNameEqual(fileNode, "mod");
96  if (!xmlNameEqual(fileNode, "update") && !isMod)
97  continue;
98 
99  UpdateFile file;
100  file.name = XML::getProperty(fileNode, "file", "");
101  file.hash = XML::getProperty(fileNode, "hash", "");
102  file.type = XML::getProperty(fileNode, "type", "data");
103  file.desc = XML::getProperty(fileNode, "description", "");
104  file.group = XML::getProperty(fileNode, "group", "");
105  if (!file.group.empty() && (!isMod || !loadMods))
106  continue;
107 
108  const std::string version = XML::getProperty(
109  fileNode, "version", "");
110  if (!version.empty())
111  {
112  if (version > CHECK_VERSION)
113  continue;
114  }
115  const std::string notVersion = XML::getProperty(
116  fileNode, "notVersion", "");
117  if (!notVersion.empty())
118  {
119  if (notVersion <= CHECK_VERSION)
120  continue;
121  }
122  if (XML::getProperty(fileNode, "required", "yes") == "yes")
123  file.required = true;
124  else
125  file.required = false;
126 
127  if (checkPath(file.name))
128  files.push_back(file);
129  }
130 
131  return files;
132 }
133 
134 static STD_VECTOR<UpdateFile> loadTxtFile(const std::string &fileName)
135 {
136  STD_VECTOR<UpdateFile> files;
137  std::ifstream fileHandler;
138  fileHandler.open(fileName.c_str(), std::ios::in);
139 
140  if (fileHandler.is_open())
141  {
142  while (fileHandler.good())
143  {
144  char name[256];
145  char hash[50];
146  fileHandler.getline(name, 256, ' ');
147  fileHandler.getline(hash, 50);
148 
149  UpdateFile thisFile;
150  thisFile.name = name;
151  thisFile.hash = hash;
152  thisFile.type = "data";
153  thisFile.group.clear();
154  thisFile.required = true;
155  thisFile.desc.clear();
156 
157  if (!thisFile.name.empty() && checkPath(thisFile.name))
158  files.push_back(thisFile);
159  }
160  }
161  else
162  {
163  logger->log("Error loading update file: %s", fileName.c_str());
164  }
165  fileHandler.close();
166 
167  return files;
168 }
169 
170 UpdaterWindow::UpdaterWindow(const std::string &restrict updateHost,
171  const std::string &restrict updatesDir,
172  const bool applyUpdates,
173  const UpdateTypeT updateType) :
174  // TRANSLATORS: updater window name
175  Window(_("Updating..."), Modal_false, nullptr, "update.xml"),
176  ActionListener(),
177  KeyListener(),
178  mDownloadProgress(0.0F),
179  mUpdateHost(updateHost),
180  mUpdatesDir(updatesDir),
181  mUpdatesDirReal(updatesDir),
182  mCurrentFile("news.txt"),
183  mNewLabelCaption(),
184  mDownloadMutex(),
185  mCurrentChecksum(0),
186  mMemoryBuffer(nullptr),
187  mDownload(nullptr),
188  mUpdateFiles(),
189  mTempUpdateFiles(),
190  mUpdateServerPath(mUpdateHost),
191  mItemLinkHandler(new ItemLinkHandler),
192  // TRANSLATORS: updater window label
193  mLabel(new Label(this, _("Connecting..."))),
194  // TRANSLATORS: updater window button
195  mCancelButton(new Button(this, _("Cancel"), "cancel", BUTTON_SKIN, this)),
196  // TRANSLATORS: updater window button
197  mPlayButton(new Button(this, _("Play"), "play", BUTTON_SKIN, this)),
198  mProgressBar(new ProgressBar(this, 0.0, 310, 0,
200  "updateprogressbar.xml", "updateprogressbar_fill.xml")),
201  mBrowserBox(new StaticBrowserBox(this, Opaque_true,
202  "browserbox.xml")),
203  mScrollArea(new ScrollArea(this, mBrowserBox,
204  Opaque_true, "update_background.xml")),
205  mDownloadStatus(UpdateDownloadStatus::UPDATE_NEWS),
206  mDownloadedBytes(0),
207  mUpdateIndex(0),
208  mUpdateIndexOffset(0),
209  mUpdateType(updateType),
210  mStoreInMemory(true),
211  mDownloadComplete(true),
212  mUserCancel(false),
213  mLoadUpdates(applyUpdates),
214  mValidateXml(false),
215  mSkipPatches(false)
216 {
217  setWindowName("UpdaterWindow");
218  setResizable(true);
219  setDefaultSize(450, 400, ImagePosition::CENTER, 0, 0);
220  setMinWidth(310);
221  setMinHeight(220);
222 
227  mBrowserBox->setEnableKeys(true);
228  mBrowserBox->setEnableTabs(true);
230  mPlayButton->setEnabled(false);
231 
232  ContainerPlacer placer(nullptr, nullptr);
233  placer = getPlacer(0, 0);
234 
235  placer(0, 0, mScrollArea, 5, 3).setPadding(3);
236  placer(0, 3, mLabel, 5, 1);
237  placer(0, 4, mProgressBar, 5, 1);
238  placer(3, 5, mCancelButton, 1, 1);
239  placer(4, 5, mPlayButton, 1, 1);
240 
241  Layout &layout = getLayout();
242  layout.setRowHeight(0, LayoutType::SET);
243 
244  addKeyListener(this);
245 
246  if (mUpdateHost.empty())
247  {
248  const STD_VECTOR<std::string> &mirrors = settings.updateMirrors;
249  if (mirrors.begin() != mirrors.end())
250  mUpdateHost = *mirrors.begin();
251  mSkipPatches = true;
252  }
253 
254  loadWindowState();
255 }
256 
258 {
263 
264  download();
265 }
266 
268 {
269  if (mLoadUpdates)
270  loadUpdates();
271 
272  if (mDownload != nullptr)
273  {
274  mDownload->cancel();
275 
277  }
278  free(mMemoryBuffer);
280 }
281 
282 void UpdaterWindow::setProgress(const float p)
283 {
284  // Do delayed progress bar update, since Guichan isn't thread-safe
286  mDownloadProgress = p;
287 }
288 
289 void UpdaterWindow::setLabel(const std::string &str)
290 {
291  // Do delayed label text update, since Guichan isn't thread-safe
293  mNewLabelCaption = str;
294 }
295 
297 {
298  mCancelButton->setEnabled(false);
299  mPlayButton->setEnabled(true);
301 
302  if (client->getState() != State::GAME)
303  {
304  if ((mUpdateType & UpdateType::Close) != 0)
306  }
307  else
308  {
309  deleteSelf();
310  }
311 }
312 
314 {
315  const std::string &eventId = event.getId();
316  if (eventId == "cancel")
317  {
318  // Register the user cancel
319  mUserCancel = true;
320  // Skip the updating process
322  {
323  if (mDownload != nullptr)
324  mDownload->cancel();
326  }
327  }
328  else if (eventId == "play")
329  {
330  if (client->getState() != State::GAME)
332  else
333  deleteSelf();
334  }
335 }
336 
338 {
339  const InputActionT actionId = event.getActionId();
340  if (actionId == InputAction::GUI_CANCEL)
341  {
343  if (client->getState() != State::GAME)
345  else
346  deleteSelf();
347  }
348  else if (actionId == InputAction::GUI_SELECT ||
349  actionId == InputAction::GUI_SELECT2)
350  {
354  {
356  }
357  else
358  {
360  }
361  }
362 }
363 
365 {
366  if (mMemoryBuffer == nullptr)
367  {
368  logger->log1("Couldn't load news");
369  return;
370  }
371 
372  // Reallocate and include terminating 0 character
373  mMemoryBuffer = static_cast<char*>(realloc(
375  if (mMemoryBuffer == nullptr)
376  {
377  logger->log1("Couldn't load news");
378  return;
379  }
382 
383  std::string newsName = mUpdatesDir + "/local/help/news.txt";
384  mkdir_r((mUpdatesDir + "/local/help/").c_str());
385  bool firstLine(true);
386  std::ofstream file;
387  std::stringstream ss(mMemoryBuffer);
388  std::string line;
389  file.open(newsName.c_str(), std::ios::out);
390  int cnt = 0;
391  const int maxNews = 50;
392  while (std::getline(ss, line, '\n'))
393  {
394  cnt ++;
395  if (firstLine)
396  {
397  firstLine = false;
398  const size_t i = line.find("##9 Latest client version: ##6");
399  if (i == 0U)
400  continue;
401 
402  if (file.is_open())
403  file << line << std::endl;
404  if (cnt < maxNews)
405  mBrowserBox->addRow(line, false);
406  }
407  else
408  {
409  if (file.is_open())
410  file << line << std::endl;
411  if (cnt < maxNews)
412  mBrowserBox->addRow(line, false);
413  }
414  }
415 
416  file.close();
417  if (cnt > maxNews)
418  {
419  mBrowserBox->addRow("", false);
420  // TRANSLATORS: updater window checkbox
421  mBrowserBox->addRow("news", _("Show all news (can be slow)"));
422  mBrowserBox->addRow("", false);
423  }
424  // Free the memory buffer now that we don't need it anymore
425  free(mMemoryBuffer);
426  mMemoryBuffer = nullptr;
427  mDownloadedBytes = 0;
428 
431 }
432 
434 {
435  if (mMemoryBuffer == nullptr)
436  {
437  logger->log1("Couldn't load patch");
438  return;
439  }
440 
441  // Reallocate and include terminating 0 character
442  mMemoryBuffer = static_cast<char*>(
443  realloc(mMemoryBuffer, mDownloadedBytes + 1));
444  if (mMemoryBuffer == nullptr)
445  {
446  logger->log1("Couldn't load patch");
447  return;
448  }
450 
451  std::string version;
452 
453  // Tokenize and add each line separately
454  char *line = strtok(mMemoryBuffer, "\n");
455  if (line != nullptr)
456  {
457  version = line;
458  if (serverVersion == 0)
459  {
460  line = strtok(nullptr, "\n");
461  if (line != nullptr)
462  {
463  mBrowserBox->addRow(strprintf("##9 Latest client version: "
464  "##6ManaPlus %s##0", line), true);
465  }
466  }
467  if (version > CHECK_VERSION)
468  {
469  mBrowserBox->addRow("", true);
470 #if defined(ANDROID)
471  const std::string url = "androidDownloadUrl";
472  const std::string text = "androidDownloadUrl";
473 #elif defined(WIN32)
474  const std::string url = "windowsDownloadUrl";
475  const std::string text = "windowsDownloadUrl";
476 #else // defined(ANDROID)
477 
478  const std::string url = "otherDownloadUrl";
479  const std::string text = "otherDownloadUrl";
480 #endif // defined(ANDROID)
481 
482  mBrowserBox->addRow(std::string(" ##1[@@").append(
483  branding.getStringValue(url)).append("|").append(
484  branding.getStringValue(text)).append("@@]"), true);
485  mBrowserBox->addRow("##1You can download it from", true);
486  mBrowserBox->addRow("##1ManaPlus updated.", true);
487  }
488  else
489  {
490  mBrowserBox->addRow("You have latest client version.", true);
491  }
492  }
493 
494  // Free the memory buffer now that we don't need it anymore
495  free(mMemoryBuffer);
496  mMemoryBuffer = nullptr;
497  mDownloadedBytes = 0;
498 
501 }
502 
504  const DownloadStatusT status,
505  size_t dt,
506  const size_t dn)
507 {
508  UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(ptr);
509  if (uw == nullptr)
510  return -1;
511 
512  if (status == DownloadStatus::Complete)
513  {
514  uw->mDownloadComplete = true;
515  }
516  else if (status == DownloadStatus::Error ||
517  status == DownloadStatus::Cancelled)
518  {
521  { // ignoring error in last state (was UPDATE_PATCH)
523  uw->mDownloadComplete = true;
524  free(uw->mMemoryBuffer);
525  uw->mMemoryBuffer = nullptr;
526  }
527  else
528  {
530  }
531  }
532 
533  if (dt == 0U)
534  dt = 1;
535 
536  float progress = static_cast<float>(dn) /
537  static_cast<float>(dt);
538 
539  if (progress != progress)
540  progress = 0.0F; // check for NaN
541  if (progress < 0.0F)
542  progress = 0.0F; // no idea how this could ever happen,
543  // but why not check for it anyway.
544  if (progress > 1.0F)
545  progress = 1.0F;
546 
547  uw->setLabel(std::string(uw->mCurrentFile).append(" (")
548  .append(toString(CAST_S32(progress * 100))).append("%)"));
549 
550  uw->setProgress(progress);
551 
552  if ((client->getState() != State::UPDATE &&
553  client->getState() != State::GAME) ||
555  {
556  // If the action was canceled return an error code to stop the mThread
557  return -1;
558  }
559 
560  return 0;
561 }
562 
563 size_t UpdaterWindow::memoryWrite(void *ptr, size_t size,
564  size_t nmemb, void *stream)
565 {
566  UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(stream);
567  const size_t totalMem = size * nmemb;
568  if (uw == nullptr)
569  return 0;
570  uw->mMemoryBuffer = static_cast<char*>(realloc(uw->mMemoryBuffer,
571  CAST_SIZE(uw->mDownloadedBytes) + totalMem));
572  if (uw->mMemoryBuffer != nullptr)
573  {
574  memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem);
575  uw->mDownloadedBytes += CAST_S32(totalMem);
576  }
577 
578  return totalMem;
579 }
580 
582 {
583  if (mDownload != nullptr)
584  {
585  mDownload->cancel();
586  delete mDownload;
587  }
589  {
590  mDownload = new Net::Download(this,
591  branding.getStringValue("updateMirror1") + mCurrentFile,
593  true, false, mValidateXml);
594  for (int f = 2; f < 8; f ++)
595  {
596  const std::string url = branding.getStringValue(
597  "updateMirror" + toString(f));
598  if (!url.empty())
600  }
601  }
602  else
603  {
604  mDownload = new Net::Download(this,
607  false, false, mValidateXml);
608 
611  {
612  const std::string str = urlJoin(mUpdateServerPath, mCurrentFile);
616  }
617  else
618  {
619  const STD_VECTOR<std::string> &mirrors = settings.updateMirrors;
620  FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, mirrors)
621  {
623  mCurrentFile));
624  }
625  }
626  }
627 
628  if (mStoreInMemory)
629  {
631  }
632  else
633  {
635  {
638  }
639  else
640  {
642  mCurrentFile),
643  -1);
644  }
645  }
646 
648  mDownload->noCache();
649 
650  setLabel(mCurrentFile + " (0%)");
651  mDownloadComplete = false;
652 
653  mDownload->start();
654 }
655 
657 {
658  if (mUpdateFiles.empty())
659  { // updates not downloaded
661  false);
662  if (mUpdateFiles.empty())
663  {
664  logger->log("Warning this server does not have a"
665  " %s file falling back to %s", xmlUpdateFile.c_str(),
666  txtUpdateFile.c_str());
668  txtUpdateFile));
669  }
670  }
671 
672  std::string fixPath = mUpdatesDir + "/fix";
673  const unsigned sz = CAST_U32(mUpdateFiles.size());
674  for (mUpdateIndex = 0; mUpdateIndex < sz; mUpdateIndex++)
675  {
676  const UpdateFile &file = mUpdateFiles[mUpdateIndex];
677  if (!file.group.empty())
678  continue;
680  fixPath,
681  file.name,
682  Append_false);
683  }
686 }
687 
688 void UpdaterWindow::loadLocalUpdates(const std::string &dir)
689 {
690  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
691  pathJoin(dir, xmlUpdateFile),
692  false);
693 
694  if (updateFiles.empty())
695  {
696  logger->log("Warning this server does not have a"
697  " %s file falling back to %s", xmlUpdateFile.c_str(),
698  txtUpdateFile.c_str());
699  updateFiles = loadTxtFile(pathJoin(dir,
700  txtUpdateFile));
701  }
702 
703  const std::string fixPath = dir + "/fix";
704  for (unsigned int updateIndex = 0,
705  fsz = CAST_U32(updateFiles.size());
706  updateIndex < fsz;
707  updateIndex++)
708  {
709  const UpdateFile &file = updateFiles[updateIndex];
710  if (!file.group.empty())
711  continue;
713  fixPath,
714  file.name,
715  Append_false);
716  }
717  loadManaPlusUpdates(dir);
718  loadMods(dir, updateFiles);
719 }
720 
721 void UpdaterWindow::unloadUpdates(const std::string &dir)
722 {
723  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
724  pathJoin(dir, xmlUpdateFile),
725  true);
726 
727  if (updateFiles.empty())
728  {
729  updateFiles = loadTxtFile(pathJoin(dir,
730  txtUpdateFile));
731  }
732 
733  const std::string fixPath = dir + "/fix";
734  for (unsigned int updateIndex = 0,
735  fsz = CAST_U32(updateFiles.size());
736  updateIndex < fsz;
737  updateIndex++)
738  {
740  fixPath,
741  updateFiles[updateIndex].name);
742  }
744 }
745 
746 void UpdaterWindow::loadManaPlusUpdates(const std::string &dir)
747 {
748  std::string fixPath = dir + "/fix";
749  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
750  pathJoin(fixPath, xmlUpdateFile),
751  false);
752 
753  for (unsigned int updateIndex = 0,
754  fsz = CAST_U32(updateFiles.size());
755  updateIndex < fsz;
756  updateIndex++)
757  {
758  const UpdateFile &file = updateFiles[updateIndex];
759  if (!file.group.empty())
760  continue;
761  const std::string name = file.name;
762  if (strStartWith(name, "manaplus_"))
763  {
764  struct stat statbuf;
765  std::string fileName = pathJoin(fixPath,
766  name);
767  if (stat(fileName.c_str(), &statbuf) == 0)
768  {
770  Append_false);
771  }
772  }
773  }
774 }
775 
776 void UpdaterWindow::unloadManaPlusUpdates(const std::string &dir)
777 {
778  const std::string fixPath = dir + "/fix";
779  const STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
780  pathJoin(fixPath, xmlUpdateFile),
781  true);
782 
783  for (unsigned int updateIndex = 0,
784  fsz = CAST_U32(updateFiles.size());
785  updateIndex < fsz;
786  updateIndex++)
787  {
788  std::string name = updateFiles[updateIndex].name;
789  if (strStartWith(name, "manaplus_"))
790  {
791  struct stat statbuf;
792  const std::string file = pathJoin(
793  fixPath, name);
794  if (stat(file.c_str(), &statbuf) == 0)
795  VirtFs::unmountZip(file);
796  }
797  }
798 }
799 
800 void UpdaterWindow::addUpdateFile(const std::string &restrict path,
801  const std::string &restrict fixPath,
802  const std::string &restrict file,
803  const Append append)
804 {
805  const std::string tmpPath = pathJoin(path, file);
806  if (append == Append_false)
807  VirtFs::mountZip(tmpPath, append);
808 
809  const std::string fixFile = pathJoin(fixPath, file);
810  struct stat statbuf;
811  if (stat(fixFile.c_str(), &statbuf) == 0)
812  VirtFs::mountZip(fixFile, append);
813 
814  if (append == Append_true)
815  VirtFs::mountZip(tmpPath, append);
816 }
817 
818 void UpdaterWindow::removeUpdateFile(const std::string &restrict path,
819  const std::string &restrict fixPath,
820  const std::string &restrict file)
821 {
822  VirtFs::unmountZip(pathJoin(path, file));
823  const std::string fixFile = pathJoin(fixPath, file);
824  struct stat statbuf;
825  if (stat(fixFile.c_str(), &statbuf) == 0)
826  VirtFs::unmountZip(fixFile);
827 }
828 
830 {
831  BLOCK_START("UpdaterWindow::logic")
832  // Update Scroll logic
833  mScrollArea->logic();
834 
835  // Synchronize label caption when necessary
836  {
838 
840  {
842  mLabel->adjustSize();
843  }
844 
846  if (!mUpdateFiles.empty() &&
848  {
851  mUpdateFiles.size()) + CAST_S32(
852  mTempUpdateFiles.size()) + 1));
853  }
854  else
855  {
856  mProgressBar->setText("");
857  }
858  }
859 
860  switch (mDownloadStatus)
861  {
863  mBrowserBox->addRow("", false);
864  // TRANSLATORS: update message
865  mBrowserBox->addRow(_("##1 The update process is incomplete."),
866  false);
867  // TRANSLATORS: Continues "The update process is incomplete.".
868  mBrowserBox->addRow(_("##1 It is strongly recommended that"),
869  false);
870  // TRANSLATORS: Begins "It is strongly recommended that".
871  mBrowserBox->addRow(_("##1 you try again later."),
872  false);
873  if (mDownload != nullptr)
874  mBrowserBox->addRow(mDownload->getError(), false);
879  break;
881  if (mDownloadComplete)
882  {
883  // Parse current memory buffer as news and dispose of the data
884  loadNews();
885 
886  mValidateXml = true;
888  mStoreInMemory = false;
890  download(); // download() changes mDownloadComplete to false
891  }
892  break;
894  if (mDownloadComplete)
895  {
896  // Parse current memory buffer as news and dispose of the data
897  loadPatch();
898 
900  mUpdatesDir = pathJoin(mUpdatesDir, "fix");
902  mValidateXml = true;
903  mStoreInMemory = false;
905  download();
906  }
907  break;
908 
910  if (mDownloadComplete)
911  {
913  {
916  true);
917 
918  if (mUpdateFiles.empty())
919  {
920  logger->log("Warning this server does not have a %s"
921  " file falling back to %s",
922  xmlUpdateFile.c_str(),
923  txtUpdateFile.c_str());
924 
925  // If the resources.xml file fails,
926  // fall back onto a older version
928  mValidateXml = false;
929  mStoreInMemory = false;
931  download();
932  break;
933  }
934  }
935  else if (mCurrentFile == txtUpdateFile)
936  {
937  mValidateXml = true;
939  txtUpdateFile));
940  }
941  mStoreInMemory = false;
943  }
944  break;
946  if (mDownloadComplete)
947  {
948  if (CAST_SIZE(mUpdateIndex) < mUpdateFiles.size())
949  {
951  if (thisFile.type == "music"
952  && !config.getBoolValue("download-music"))
953  {
954  mUpdateIndex++;
955  break;
956  }
957  mCurrentFile = thisFile.name;
958  std::string checksum;
959  checksum = thisFile.hash;
960  std::stringstream ss(checksum);
961  ss >> std::hex >> mCurrentChecksum;
962 
963  std::ifstream temp(pathJoin(mUpdatesDir,
964  mCurrentFile).c_str());
965 
966  mValidateXml = false;
967  if (!temp.is_open() || !validateFile(pathJoin(
970  {
971  temp.close();
972  download();
973  }
974  else
975  {
976  temp.close();
977  logger->log("%s already here", mCurrentFile.c_str());
978  }
979  mUpdateIndex++;
980  }
981  else
982  {
983  if (!mSkipPatches)
984  {
985  // Download of updates completed
986  mCurrentFile = "latest.txt";
987  mStoreInMemory = true;
989  mValidateXml = false;
990  download(); // download() changes
991  // mDownloadComplete to false
992  }
993  else
994  {
997  }
998  }
999  }
1000  break;
1002  if (mDownloadComplete)
1003  {
1004  if (mCurrentFile == xmlUpdateFile)
1005  {
1008  true);
1009  }
1011  mUpdateIndex = 0;
1012  mValidateXml = true;
1013  mStoreInMemory = false;
1015  download();
1016  }
1017  break;
1019  if (mDownloadComplete)
1020  {
1021  mValidateXml = false;
1022  if (CAST_SIZE(mUpdateIndex)
1023  < mTempUpdateFiles.size())
1024  {
1025  const UpdateFile thisFile = mTempUpdateFiles[mUpdateIndex];
1026  mCurrentFile = thisFile.name;
1027  std::string checksum;
1028  checksum = thisFile.hash;
1029  std::stringstream ss(checksum);
1030  ss >> std::hex >> mCurrentChecksum;
1031 
1032  std::ifstream temp((pathJoin(mUpdatesDir,
1033  mCurrentFile)).c_str());
1034 
1035  if (!temp.is_open() || !validateFile(pathJoin(
1038  {
1039  temp.close();
1040  download();
1041  }
1042  else
1043  {
1044  temp.close();
1045  logger->log("%s already here", mCurrentFile.c_str());
1046  }
1047  mUpdateIndex++;
1048  }
1049  else
1050  {
1053  }
1054  }
1055  break;
1058  enable();
1059  // TRANSLATORS: updater window label
1060  setLabel(_("Completed"));
1062  break;
1064  break;
1065  default:
1066  logger->log("UpdaterWindow::logic unknown status: "
1068  break;
1069  }
1070  BLOCK_END("UpdaterWindow::logic")
1071 }
1072 
1073 bool UpdaterWindow::validateFile(const std::string &filePath,
1074  const unsigned long hash)
1075 {
1076  FILE *const file = fopen(filePath.c_str(), "rb");
1077  if (file == nullptr)
1078  return false;
1079 
1080  const unsigned long adler = Net::Download::fadler32(file);
1081  fclose(file);
1082  return adler == hash;
1083 }
1084 
1085 unsigned long UpdaterWindow::getFileHash(const std::string &filePath)
1086 {
1087  int size = 0;
1088  const char *const buf = VirtFs::loadFile(filePath, size);
1089  if (buf == nullptr)
1090  return 0;
1091  unsigned long res = Net::Download::adlerBuffer(buf, size);
1092  delete [] buf;
1093  return res;
1094 }
1095 
1096 void UpdaterWindow::loadFile(std::string file)
1097 {
1099  trim(file);
1100 
1101  StringVect lines;
1102  Files::loadTextFileLocal(mUpdatesDir + "/local/help/news.txt", lines);
1103 
1104  for (size_t i = 0, sz = lines.size(); i < sz; ++i)
1105  mBrowserBox->addRow(lines[i], false);
1107 }
1108 
1109 void UpdaterWindow::loadMods(const std::string &dir,
1110  const STD_VECTOR<UpdateFile> &updateFiles)
1111 {
1112  ModDB::load();
1113  std::string modsString = serverConfig.getValue("mods", "");
1114  std::set<std::string> modsList;
1115  splitToStringSet(modsList, modsString, '|');
1116 
1117  const std::string fixPath = dir + "/fix";
1118  for (unsigned int updateIndex = 0,
1119  fsz = CAST_U32(updateFiles.size());
1120  updateIndex < fsz;
1121  updateIndex ++)
1122  {
1123  const UpdateFile &file = updateFiles[updateIndex];
1124  if (file.group.empty())
1125  continue;
1126  const std::set<std::string>::const_iterator
1127  it = modsList.find(file.group);
1128  if (it != modsList.end())
1129  {
1131  fixPath,
1132  file.name,
1133  Append_false);
1134  }
1135  }
1136 
1137  STD_VECTOR<UpdateFile> updateFiles2 = loadXMLFile(
1138  pathJoin(fixPath, xmlUpdateFile),
1139  true);
1140 
1141  for (unsigned int updateIndex = 0,
1142  fsz = CAST_U32(updateFiles2.size());
1143  updateIndex < fsz;
1144  updateIndex++)
1145  {
1146  const UpdateFile &file = updateFiles2[updateIndex];
1147  if (file.group.empty())
1148  continue;
1149  std::string name = file.name;
1150  if (strStartWith(name, "manaplus_"))
1151  {
1152  const std::set<std::string>::const_iterator
1153  it = modsList.find(file.group);
1154  if (it != modsList.end())
1155  {
1156  struct stat statbuf;
1157  std::string fileName = pathJoin(fixPath,
1158  name);
1159  if (stat(fileName.c_str(), &statbuf) == 0)
1160  {
1162  Append_false);
1163  }
1164  }
1165  }
1166  }
1167 
1168  loadDirMods(dir + "/local/");
1169 }
1170 
1171 void UpdaterWindow::loadDirMods(const std::string &dir)
1172 {
1173  ModDB::load();
1174  const ModInfos &mods = ModDB::getAll();
1175 
1176  std::string modsString = serverConfig.getValue("mods", "");
1177  StringVect modsList;
1178  splitToStringVector(modsList, modsString, '|');
1179  FOR_EACH (StringVectCIter, it, modsList)
1180  {
1181  const std::string &name = *it;
1182  const ModInfoCIterator modIt = mods.find(name);
1183  if (modIt == mods.end())
1184  continue;
1185  const ModInfo *const mod = (*modIt).second;
1186  if (mod != nullptr)
1187  {
1188  const std::string &localDir = mod->getLocalDir();
1189  if (!localDir.empty())
1190  {
1191  VirtFs::mountDir(pathJoin(dir, localDir),
1192  Append_false);
1193  }
1194  }
1195  }
1196 }
1197 
1198 void UpdaterWindow::unloadMods(const std::string &dir)
1199 {
1200  const ModInfos &mods = ModDB::getAll();
1201  std::string modsString = serverConfig.getValue("mods", "");
1202  StringVect modsList;
1203  splitToStringVector(modsList, modsString, '|');
1204  FOR_EACH (StringVectCIter, it, modsList)
1205  {
1206  const std::string &name = *it;
1207  const ModInfoCIterator modIt = mods.find(name);
1208  if (modIt == mods.end())
1209  continue;
1210  const ModInfo *const mod = (*modIt).second;
1211  if (mod != nullptr)
1212  {
1213  const std::string &localDir = mod->getLocalDir();
1214  if (!localDir.empty())
1215  VirtFs::unmountDir(pathJoin(dir, localDir));
1216  }
1217  }
1218 }
1219 
1221 {
1222  scheduleDelete();
1223  updaterWindow = nullptr;
1224 }
const bool Append_true
Definition: append.h:30
bool Append
Definition: append.h:30
const bool Append_false
Definition: append.h:30
const std::string BUTTON_SKIN
Definition: button.h:89
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
Definition: button.h:102
void setState(const StateT state)
Definition: client.h:66
StateT getState() const
Definition: client.h:69
std::string getValue(const std::string &key, const std::string &deflt) const
bool getBoolValue(const std::string &key) const
std::string getStringValue(const std::string &key) const
Definition: label.h:91
void adjustSize()
Definition: label.cpp:200
const std::string & getCaption() const
Definition: label.h:133
void setCaption(const std::string &caption)
Definition: label.cpp:264
void setRowHeight(const int n, const int h)
Definition: layoutcell.cpp:128
Definition: layout.h:45
void log(const char *const log_text,...)
Definition: logger.cpp:269
void log1(const char *const log_text)
Definition: logger.cpp:238
const std::string & getLocalDir() const
Definition: modinfo.h:58
void setFile(const std::string &filename, const int64_t adler32)
Definition: download.cpp:166
static unsigned long fadler32(FILE *const file)
Definition: download.cpp:123
unsigned cancel
Definition: download.h:127
static unsigned long adlerBuffer(const char *const buffer, int size)
Definition: download.cpp:147
void addMirror(const std::string &str)
Definition: download.h:88
void setWriteFunction(WriteFunction write)
Definition: download.cpp:182
void noCache()
Definition: download.cpp:160
const char * getError() const
Definition: download.cpp:218
bool start()
Definition: download.cpp:188
void setProgress(const float progress)
void setSmoothProgress(bool smoothProgress)
Definition: progressbar.h:125
void setText(const std::string &str)
void setVerticalScrollAmount(const int vScroll)
int getVerticalMaxScroll()
void logic()
Definition: scrollarea.cpp:273
std::vector< std::string > updateMirrors
Definition: settings.h:129
void addRow(const std::string &row, const bool atTop)
void setOpaque(Opaque opaque)
void setEnableKeys(const bool n)
void setEnableImages(const bool n)
void setEnableTabs(const bool n)
void setProcessVars(const bool n)
void setLinkHandler(LinkHandler *linkHandler)
char * mMemoryBuffer
unsigned int mUpdateIndex
std::string mUpdateServerPath
Button * mPlayButton
void setProgress(const float p)
Mutex mDownloadMutex
UpdateTypeT mUpdateType
static void loadLocalUpdates(const std::string &dir)
std::string mUpdatesDir
static size_t memoryWrite(void *ptr, size_t size, size_t nmemb, void *stream)
ItemLinkHandler * mItemLinkHandler
std::vector< UpdateFile > mUpdateFiles
static bool validateFile(const std::string &filePath, const unsigned long hash)
static void removeUpdateFile(const std::string &path, const std::string &fixPath, const std::string &filerestrict)
static void loadMods(const std::string &dir, const std::vector< UpdateFile > &updateFiles)
UpdaterWindow(const std::string &updateHost, const std::string &updatesDir, const bool applyUpdates, const UpdateTypeT updateType)
void action(const ActionEvent &event)
static void unloadManaPlusUpdates(const std::string &dir)
static unsigned long getFileHash(const std::string &filePath)
static void loadDirMods(const std::string &dir)
void loadFile(std::string file)
std::string mCurrentFile
std::string mUpdateHost
StaticBrowserBox * mBrowserBox
ScrollArea * mScrollArea
static void unloadUpdates(const std::string &dir)
static void unloadMods(const std::string &dir)
std::vector< UpdateFile > mTempUpdateFiles
std::string mNewLabelCaption
unsigned long mCurrentChecksum
void keyPressed(KeyEvent &event)
ProgressBar * mProgressBar
Button * mCancelButton
static int updateProgress(void *ptr, const DownloadStatusT status, size_t dt, const size_t dn)
void setLabel(const std::string &)
UpdateDownloadStatusT mDownloadStatus
static void loadManaPlusUpdates(const std::string &dir)
Net::Download * mDownload
std::string mUpdatesDirReal
unsigned int mUpdateIndexOffset
bool mDownloadComplete
float mDownloadProgress
static void addUpdateFile(const std::string &path, const std::string &fixPath, const std::string &file, const Append append)
void setEnabled(const bool enabled)
Definition: widget.h:352
void addKeyListener(KeyListener *const keyListener)
Definition: widget.cpp:272
virtual void requestFocus()
Definition: widget.cpp:204
const std::string & getActionEventId() const
Definition: widget.h:605
Definition: window.h:102
void setResizable(const bool resize)
Definition: window.cpp:627
ContainerPlacer getPlacer(const int x, const int y)
Definition: window.cpp:1391
virtual void setVisible(Visible visible)
Definition: window.cpp:778
Layout & getLayout()
Definition: window.cpp:1365
void setWindowName(const std::string &name)
Definition: window.h:355
void setMinHeight(const int height)
Definition: window.cpp:604
void postInit()
Definition: window.cpp:249
void setMinWidth(const int width)
Definition: window.cpp:591
virtual void scheduleDelete()
Definition: window.cpp:831
void setDefaultSize()
Definition: window.cpp:1198
void loadWindowState()
Definition: window.cpp:1087
xmlNodePtr rootNode()
Definition: libxml.cpp:169
Configuration config
Configuration serverConfig
Configuration branding
#define new
Definition: debug_new.h:147
#define delete2(var)
Definition: delete2.h:25
DownloadStatus ::T DownloadStatusT
Client * client
Definition: client.cpp:118
int serverVersion
Definition: client.cpp:124
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define _(s)
Definition: gettext.h:35
InputAction ::T InputActionT
Definition: inputaction.h:717
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:161
#define restrict
Definition: localconsts.h:165
#define nullptr
Definition: localconsts.h:45
Logger * logger
Definition: logger.cpp:89
#define CHECK_VERSION
Definition: main.h:45
int mkdir_r(const char *const pathname)
Create a directory, making leading components first if necessary.
Definition: mkdir.cpp:109
const bool Modal_false
Definition: modal.h:30
ModInfos::const_iterator ModInfoCIterator
Definition: modinfo.h:70
std::map< std::string, ModInfo * > ModInfos
Definition: modinfo.h:68
bool url(InputEvent &event)
Definition: commands.cpp:64
std::string trim(std::string const &str)
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
std::string mUpdateHost
Definition: loginrecv.cpp:44
int size()
Definition: emotedb.cpp:306
bool loadTextFileLocal(const std::string &fileName, StringVect &lines)
Definition: files.cpp:229
void load()
Definition: moddb.cpp:42
const ModInfos & getAll()
Definition: moddb.cpp:116
@ GAME
Definition: state.h:49
@ UPDATE
Definition: state.h:44
@ LOAD_DATA
Definition: state.h:45
@ LOGIN
Definition: state.h:40
bool mountZip(std::string newDir, const Append append)
Definition: fs.cpp:590
bool unmountZip(std::string oldDir)
Definition: fs.cpp:675
const char * loadFile(std::string filename, int &fileSize)
Definition: fs.cpp:859
bool mountDir(std::string newDir, const Append append)
Definition: fs.cpp:393
bool unmountDir(std::string oldDir)
Definition: fs.cpp:518
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:174
const bool Opaque_false
Definition: opaque.h:30
const bool Opaque_true
Definition: opaque.h:30
bool checkPath(const std::string &path)
Definition: paths.cpp:121
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
Settings settings
Definition: settings.cpp:32
const bool SkipError_false
Definition: skiperror.h:30
std::string & removeProtocol(std::string &url)
std::string strprintf(const char *const format,...)
void splitToStringVector(StringVect &tokens, const std::string &text, const char separator)
void splitToStringSet(std::set< std::string > &tokens, const std::string &text, const char separator)
std::string pathJoin(std::string str1, const std::string &str2)
std::string urlJoin(std::string str1, const std::string &str2)
bool strStartWith(const std::string &str1, const std::string &str2)
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:31
std::vector< std::string > StringVect
Definition: stringvector.h:29
std::string group
Definition: updatefile.h:50
std::string type
Definition: updatefile.h:48
std::string hash
Definition: updatefile.h:47
std::string name
Definition: updatefile.h:46
bool required
Definition: updatefile.h:51
std::string desc
Definition: updatefile.h:49
std::string fileName
Definition: testmain.cpp:39
const std::string txtUpdateFile("resources2.txt")
const std::string updateServer5("http://download3.manaplus.org/manaplus/updates/")
UpdaterWindow * updaterWindow
const std::string xmlUpdateFile("resources.xml")
static std::vector< UpdateFile > loadTxtFile(const std::string &fileName)
const std::string updateServer4("http://download.evolonline.org/manaplus/updates/")
static std::vector< UpdateFile > loadXMLFile(const std::string &fileName, const bool loadMods)
const std::string updateServer2("http://download.manaplus.org/manaplus/updates/")
const std::string updateServer3("http://download2.manaplus.org/manaplus/updates/")
UpdateType ::T UpdateTypeT
Definition: updatetype.h:36
const bool UseVirtFs_false
Definition: usevirtfs.h:30
const bool Visible_true
Definition: visible.h:30