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