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);
229  mPlayButton->setEnabled(false);
230 
231  ContainerPlacer placer(nullptr, nullptr);
232  placer = getPlacer(0, 0);
233 
234  placer(0, 0, mScrollArea, 5, 3).setPadding(3);
235  placer(0, 3, mLabel, 5, 1);
236  placer(0, 4, mProgressBar, 5, 1);
237  placer(3, 5, mCancelButton, 1, 1);
238  placer(4, 5, mPlayButton, 1, 1);
239 
240  Layout &layout = getLayout();
241  layout.setRowHeight(0, LayoutType::SET);
242 
243  addKeyListener(this);
244 
245  if (mUpdateHost.empty())
246  {
247  const STD_VECTOR<std::string> &mirrors = settings.updateMirrors;
248  if (mirrors.begin() != mirrors.end())
249  mUpdateHost = *mirrors.begin();
250  mSkipPatches = true;
251  }
252 
253  loadWindowState();
254 }
255 
257 {
262 
263  download();
264 }
265 
267 {
268  if (mLoadUpdates)
269  loadUpdates();
270 
271  if (mDownload != nullptr)
272  {
273  mDownload->cancel();
274 
276  }
277  free(mMemoryBuffer);
279 }
280 
281 void UpdaterWindow::setProgress(const float p)
282 {
283  // Do delayed progress bar update, since Guichan isn't thread-safe
285  mDownloadProgress = p;
286 }
287 
288 void UpdaterWindow::setLabel(const std::string &str)
289 {
290  // Do delayed label text update, since Guichan isn't thread-safe
293 }
294 
296 {
297  mCancelButton->setEnabled(false);
298  mPlayButton->setEnabled(true);
300 
301  if (client->getState() != State::GAME)
302  {
303  if ((mUpdateType & UpdateType::Close) != 0)
305  }
306  else
307  {
308  deleteSelf();
309  }
310 }
311 
313 {
314  const std::string &eventId = event.getId();
315  if (eventId == "cancel")
316  {
317  // Register the user cancel
318  mUserCancel = true;
319  // Skip the updating process
321  {
322  if (mDownload != nullptr)
323  mDownload->cancel();
325  }
326  }
327  else if (eventId == "play")
328  {
329  if (client->getState() != State::GAME)
331  else
332  deleteSelf();
333  }
334 }
335 
337 {
338  const InputActionT actionId = event.getActionId();
339  if (actionId == InputAction::GUI_CANCEL)
340  {
342  if (client->getState() != State::GAME)
344  else
345  deleteSelf();
346  }
347  else if (actionId == InputAction::GUI_SELECT ||
348  actionId == InputAction::GUI_SELECT2)
349  {
353  {
355  }
356  else
357  {
359  }
360  }
361 }
362 
364 {
365  if (mMemoryBuffer == nullptr)
366  {
367  logger->log1("Couldn't load news");
368  return;
369  }
370 
371  // Reallocate and include terminating 0 character
372  mMemoryBuffer = static_cast<char*>(realloc(
374  if (mMemoryBuffer == nullptr)
375  {
376  logger->log1("Couldn't load news");
377  return;
378  }
381 
382  std::string newsName = mUpdatesDir + "/local/help/news.txt";
383  mkdir_r((mUpdatesDir + "/local/help/").c_str());
384  bool firstLine(true);
385  std::ofstream file;
386  std::stringstream ss(mMemoryBuffer);
387  std::string line;
388  file.open(newsName.c_str(), std::ios::out);
389  int cnt = 0;
390  const int maxNews = 50;
391  while (std::getline(ss, line, '\n'))
392  {
393  cnt ++;
394  if (firstLine)
395  {
396  firstLine = false;
397  const size_t i = line.find("##9 Latest client version: ##6");
398  if (i == 0u)
399  continue;
400 
401  if (file.is_open())
402  file << line << std::endl;
403  if (cnt < maxNews)
404  mBrowserBox->addRow(line, false);
405  }
406  else
407  {
408  if (file.is_open())
409  file << line << std::endl;
410  if (cnt < maxNews)
411  mBrowserBox->addRow(line, false);
412  }
413  }
414 
415  file.close();
416  if (cnt > maxNews)
417  {
418  mBrowserBox->addRow("", false);
419  // TRANSLATORS: updater window checkbox
420  mBrowserBox->addRow("news", _("Show all news (can be slow)"));
421  mBrowserBox->addRow("", false);
422  }
423  // Free the memory buffer now that we don't need it anymore
424  free(mMemoryBuffer);
425  mMemoryBuffer = nullptr;
426  mDownloadedBytes = 0;
427 
430 }
431 
433 {
434  if (mMemoryBuffer == nullptr)
435  {
436  logger->log1("Couldn't load patch");
437  return;
438  }
439 
440  // Reallocate and include terminating 0 character
441  mMemoryBuffer = static_cast<char*>(
442  realloc(mMemoryBuffer, mDownloadedBytes + 1));
443  if (mMemoryBuffer == nullptr)
444  {
445  logger->log1("Couldn't load patch");
446  return;
447  }
449 
450  std::string version;
451 
452  // Tokenize and add each line separately
453  char *line = strtok(mMemoryBuffer, "\n");
454  if (line != nullptr)
455  {
456  version = line;
457  if (serverVersion < 1)
458  {
459  line = strtok(nullptr, "\n");
460  if (line != nullptr)
461  {
462  mBrowserBox->addRow(strprintf("##9 Latest client version: "
463  "##6ManaPlus %s##0", line), true);
464  }
465  }
466  if (version > CHECK_VERSION)
467  {
468  mBrowserBox->addRow("", true);
469 #if defined(ANDROID)
470  const std::string url = "androidDownloadUrl";
471  const std::string text = "androidDownloadUrl";
472 #elif defined(WIN32)
473  const std::string url = "windowsDownloadUrl";
474  const std::string text = "windowsDownloadUrl";
475 #else // defined(ANDROID)
476 
477  const std::string url = "otherDownloadUrl";
478  const std::string text = "otherDownloadUrl";
479 #endif // defined(ANDROID)
480 
481  mBrowserBox->addRow(std::string(" ##1[@@").append(
482  branding.getStringValue(url)).append("|").append(
483  branding.getStringValue(text)).append("@@]"), true);
484  mBrowserBox->addRow("##1You can download it from", true);
485  mBrowserBox->addRow("##1ManaPlus updated.", true);
486  }
487  else
488  {
489  mBrowserBox->addRow("You have latest client version.", true);
490  }
491  }
492 
493  // Free the memory buffer now that we don't need it anymore
494  free(mMemoryBuffer);
495  mMemoryBuffer = nullptr;
496  mDownloadedBytes = 0;
497 
500 }
501 
503  const DownloadStatusT status,
504  size_t dt,
505  const size_t dn)
506 {
507  UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(ptr);
508  if (uw == nullptr)
509  return -1;
510 
511  if (status == DownloadStatus::Complete)
512  {
513  uw->mDownloadComplete = true;
514  }
515  else if (status == DownloadStatus::Error ||
516  status == DownloadStatus::Cancelled)
517  {
520  { // ignoring error in last state (was UPDATE_PATCH)
522  uw->mDownloadComplete = true;
523  free(uw->mMemoryBuffer);
524  uw->mMemoryBuffer = nullptr;
525  }
526  else
527  {
529  }
530  }
531 
532  if (dt == 0u)
533  dt = 1;
534 
535  float progress = static_cast<float>(dn) /
536  static_cast<float>(dt);
537 
538  if (progress != progress)
539  progress = 0.0F; // check for NaN
540  if (progress < 0.0F)
541  progress = 0.0F; // no idea how this could ever happen,
542  // but why not check for it anyway.
543  if (progress > 1.0F)
544  progress = 1.0F;
545 
546  uw->setLabel(std::string(uw->mCurrentFile).append(" (")
547  .append(toString(CAST_S32(progress * 100))).append("%)"));
548 
549  uw->setProgress(progress);
550 
551  if ((client->getState() != State::UPDATE &&
552  client->getState() != State::GAME) ||
554  {
555  // If the action was canceled return an error code to stop the mThread
556  return -1;
557  }
558 
559  return 0;
560 }
561 
562 size_t UpdaterWindow::memoryWrite(void *ptr, size_t size,
563  size_t nmemb, void *stream)
564 {
565  UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(stream);
566  const size_t totalMem = size * nmemb;
567  if (uw == nullptr)
568  return 0;
569  uw->mMemoryBuffer = static_cast<char*>(realloc(uw->mMemoryBuffer,
570  CAST_SIZE(uw->mDownloadedBytes) + totalMem));
571  if (uw->mMemoryBuffer != nullptr)
572  {
573  memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem);
574  uw->mDownloadedBytes += CAST_S32(totalMem);
575  }
576 
577  return totalMem;
578 }
579 
581 {
582  if (mDownload != nullptr)
583  {
584  mDownload->cancel();
585  delete mDownload;
586  }
588  {
589  mDownload = new Net::Download(this,
590  branding.getStringValue("updateMirror1") + mCurrentFile,
592  true, false, mValidateXml);
593  for (int f = 2; f < 8; f ++)
594  {
595  const std::string url = branding.getStringValue(
596  "updateMirror" + toString(f));
597  if (!url.empty())
599  }
600  }
601  else
602  {
603  mDownload = new Net::Download(this,
606  false, false, mValidateXml);
607 
610  {
611  const std::string str = urlJoin(mUpdateServerPath, mCurrentFile);
615  }
616  else
617  {
618  const STD_VECTOR<std::string> &mirrors = settings.updateMirrors;
619  FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, mirrors)
620  {
622  mCurrentFile));
623  }
624  }
625  }
626 
627  if (mStoreInMemory)
628  {
630  }
631  else
632  {
634  {
637  }
638  else
639  {
641  mCurrentFile),
642  -1);
643  }
644  }
645 
647  mDownload->noCache();
648 
649  setLabel(mCurrentFile + " (0%)");
650  mDownloadComplete = false;
651 
652  mDownload->start();
653 }
654 
656 {
657  if (mUpdateFiles.empty())
658  { // updates not downloaded
660  false);
661  if (mUpdateFiles.empty())
662  {
663  logger->log("Warning this server does not have a"
664  " %s file falling back to %s", xmlUpdateFile.c_str(),
665  txtUpdateFile.c_str());
667  txtUpdateFile));
668  }
669  }
670 
671  std::string fixPath = mUpdatesDir + "/fix";
672  const unsigned sz = CAST_U32(mUpdateFiles.size());
673  for (mUpdateIndex = 0; mUpdateIndex < sz; mUpdateIndex++)
674  {
675  const UpdateFile &file = mUpdateFiles[mUpdateIndex];
676  if (!file.group.empty())
677  continue;
679  fixPath,
680  file.name,
681  Append_false);
682  }
685 }
686 
687 void UpdaterWindow::loadLocalUpdates(const std::string &dir)
688 {
689  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
690  pathJoin(dir, xmlUpdateFile),
691  false);
692 
693  if (updateFiles.empty())
694  {
695  logger->log("Warning this server does not have a"
696  " %s file falling back to %s", xmlUpdateFile.c_str(),
697  txtUpdateFile.c_str());
698  updateFiles = loadTxtFile(pathJoin(dir,
699  txtUpdateFile));
700  }
701 
702  const std::string fixPath = dir + "/fix";
703  for (unsigned int updateIndex = 0,
704  fsz = CAST_U32(updateFiles.size());
705  updateIndex < fsz;
706  updateIndex++)
707  {
708  const UpdateFile &file = updateFiles[updateIndex];
709  if (!file.group.empty())
710  continue;
712  fixPath,
713  file.name,
714  Append_false);
715  }
716  loadManaPlusUpdates(dir);
717  loadMods(dir, updateFiles);
718 }
719 
720 void UpdaterWindow::unloadUpdates(const std::string &dir)
721 {
722  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
723  pathJoin(dir, xmlUpdateFile),
724  true);
725 
726  if (updateFiles.empty())
727  {
728  updateFiles = loadTxtFile(pathJoin(dir,
729  txtUpdateFile));
730  }
731 
732  const std::string fixPath = dir + "/fix";
733  for (unsigned int updateIndex = 0,
734  fsz = CAST_U32(updateFiles.size());
735  updateIndex < fsz;
736  updateIndex++)
737  {
739  fixPath,
740  updateFiles[updateIndex].name);
741  }
743 }
744 
745 void UpdaterWindow::loadManaPlusUpdates(const std::string &dir)
746 {
747  std::string fixPath = dir + "/fix";
748  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
749  pathJoin(fixPath, xmlUpdateFile),
750  false);
751 
752  for (unsigned int updateIndex = 0,
753  fsz = CAST_U32(updateFiles.size());
754  updateIndex < fsz;
755  updateIndex++)
756  {
757  const UpdateFile &file = updateFiles[updateIndex];
758  if (!file.group.empty())
759  continue;
760  const std::string name = file.name;
761  if (strStartWith(name, "manaplus_"))
762  {
763  struct stat statbuf;
764  std::string fileName = pathJoin(fixPath,
765  name);
766  if (stat(fileName.c_str(), &statbuf) == 0)
767  {
768  VirtFs::mountZip(fileName,
769  Append_false);
770  }
771  }
772  }
773 }
774 
775 void UpdaterWindow::unloadManaPlusUpdates(const std::string &dir)
776 {
777  const std::string fixPath = dir + "/fix";
778  const STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
779  pathJoin(fixPath, xmlUpdateFile),
780  true);
781 
782  for (unsigned int updateIndex = 0,
783  fsz = CAST_U32(updateFiles.size());
784  updateIndex < fsz;
785  updateIndex++)
786  {
787  std::string name = updateFiles[updateIndex].name;
788  if (strStartWith(name, "manaplus_"))
789  {
790  struct stat statbuf;
791  const std::string file = pathJoin(
792  fixPath, name);
793  if (stat(file.c_str(), &statbuf) == 0)
794  VirtFs::unmountZip(file);
795  }
796  }
797 }
798 
799 void UpdaterWindow::addUpdateFile(const std::string &restrict path,
800  const std::string &restrict fixPath,
801  const std::string &restrict file,
802  const Append append)
803 {
804  const std::string tmpPath = pathJoin(path, file);
805  if (append == Append_false)
806  VirtFs::mountZip(tmpPath, append);
807 
808  const std::string fixFile = pathJoin(fixPath, file);
809  struct stat statbuf;
810  if (stat(fixFile.c_str(), &statbuf) == 0)
811  VirtFs::mountZip(fixFile, append);
812 
813  if (append == Append_true)
814  VirtFs::mountZip(tmpPath, append);
815 }
816 
817 void UpdaterWindow::removeUpdateFile(const std::string &restrict path,
818  const std::string &restrict fixPath,
819  const std::string &restrict file)
820 {
821  VirtFs::unmountZip(pathJoin(path, file));
822  const std::string fixFile = pathJoin(fixPath, file);
823  struct stat statbuf;
824  if (stat(fixFile.c_str(), &statbuf) == 0)
825  VirtFs::unmountZip(fixFile);
826 }
827 
829 {
830  BLOCK_START("UpdaterWindow::logic")
831  // Update Scroll logic
832  mScrollArea->logic();
833 
834  // Synchronize label caption when necessary
835  {
837 
839  {
841  mLabel->adjustSize();
842  }
843 
845  if (!mUpdateFiles.empty() &&
847  {
850  mUpdateFiles.size()) + CAST_S32(
851  mTempUpdateFiles.size()) + 1));
852  }
853  else
854  {
855  mProgressBar->setText("");
856  }
857  }
858 
859  switch (mDownloadStatus)
860  {
862  mBrowserBox->addRow("", false);
863  // TRANSLATORS: update message
864  mBrowserBox->addRow(_("##1 The update process is incomplete."),
865  false);
866  // TRANSLATORS: Continues "The update process is incomplete.".
867  mBrowserBox->addRow(_("##1 It is strongly recommended that"),
868  false);
869  // TRANSLATORS: Begins "It is strongly recommended that".
870  mBrowserBox->addRow(_("##1 you try again later."),
871  false);
872  if (mDownload != nullptr)
873  mBrowserBox->addRow(mDownload->getError(), false);
878  break;
880  if (mDownloadComplete)
881  {
882  // Parse current memory buffer as news and dispose of the data
883  loadNews();
884 
885  mValidateXml = true;
887  mStoreInMemory = false;
889  download(); // download() changes mDownloadComplete to false
890  }
891  break;
893  if (mDownloadComplete)
894  {
895  // Parse current memory buffer as news and dispose of the data
896  loadPatch();
897 
899  mUpdatesDir = pathJoin(mUpdatesDir, "fix");
901  mValidateXml = true;
902  mStoreInMemory = false;
904  download();
905  }
906  break;
907 
909  if (mDownloadComplete)
910  {
912  {
915  true);
916 
917  if (mUpdateFiles.empty())
918  {
919  logger->log("Warning this server does not have a %s"
920  " file falling back to %s",
921  xmlUpdateFile.c_str(),
922  txtUpdateFile.c_str());
923 
924  // If the resources.xml file fails,
925  // fall back onto a older version
927  mValidateXml = false;
928  mStoreInMemory = false;
930  download();
931  break;
932  }
933  }
934  else if (mCurrentFile == txtUpdateFile)
935  {
936  mValidateXml = true;
938  txtUpdateFile));
939  }
940  mStoreInMemory = false;
942  }
943  break;
945  if (mDownloadComplete)
946  {
947  if (CAST_SIZE(mUpdateIndex) < mUpdateFiles.size())
948  {
950  if (thisFile.type == "music"
951  && !config.getBoolValue("download-music"))
952  {
953  mUpdateIndex++;
954  break;
955  }
956  mCurrentFile = thisFile.name;
957  std::string checksum;
958  checksum = thisFile.hash;
959  std::stringstream ss(checksum);
960  ss >> std::hex >> mCurrentChecksum;
961 
962  std::ifstream temp(pathJoin(mUpdatesDir,
963  mCurrentFile).c_str());
964 
965  mValidateXml = false;
966  if (!temp.is_open() || !validateFile(pathJoin(
968  mCurrentChecksum))
969  {
970  temp.close();
971  download();
972  }
973  else
974  {
975  temp.close();
976  logger->log("%s already here", mCurrentFile.c_str());
977  }
978  mUpdateIndex++;
979  }
980  else
981  {
982  if (!mSkipPatches)
983  {
984  // Download of updates completed
985  mCurrentFile = "latest.txt";
986  mStoreInMemory = true;
988  mValidateXml = false;
989  download(); // download() changes
990  // mDownloadComplete to false
991  }
992  else
993  {
996  }
997  }
998  }
999  break;
1001  if (mDownloadComplete)
1002  {
1003  if (mCurrentFile == xmlUpdateFile)
1004  {
1007  true);
1008  }
1010  mUpdateIndex = 0;
1011  mValidateXml = true;
1012  mStoreInMemory = false;
1014  download();
1015  }
1016  break;
1018  if (mDownloadComplete)
1019  {
1020  mValidateXml = false;
1021  if (CAST_SIZE(mUpdateIndex)
1022  < mTempUpdateFiles.size())
1023  {
1024  const UpdateFile thisFile = mTempUpdateFiles[mUpdateIndex];
1025  mCurrentFile = thisFile.name;
1026  std::string checksum;
1027  checksum = thisFile.hash;
1028  std::stringstream ss(checksum);
1029  ss >> std::hex >> mCurrentChecksum;
1030 
1031  std::ifstream temp((pathJoin(mUpdatesDir,
1032  mCurrentFile)).c_str());
1033 
1034  if (!temp.is_open() || !validateFile(pathJoin(
1036  mCurrentChecksum))
1037  {
1038  temp.close();
1039  download();
1040  }
1041  else
1042  {
1043  temp.close();
1044  logger->log("%s already here", mCurrentFile.c_str());
1045  }
1046  mUpdateIndex++;
1047  }
1048  else
1049  {
1052  }
1053  }
1054  break;
1057  enable();
1058  // TRANSLATORS: updater window label
1059  setLabel(_("Completed"));
1061  break;
1063  break;
1064  default:
1065  logger->log("UpdaterWindow::logic unknown status: "
1067  break;
1068  }
1069  BLOCK_END("UpdaterWindow::logic")
1070 }
1071 
1072 bool UpdaterWindow::validateFile(const std::string &filePath,
1073  const unsigned long hash)
1074 {
1075  FILE *const file = fopen(filePath.c_str(), "rb");
1076  if (file == nullptr)
1077  return false;
1078 
1079  const unsigned long adler = Net::Download::fadler32(file);
1080  fclose(file);
1081  return adler == hash;
1082 }
1083 
1084 unsigned long UpdaterWindow::getFileHash(const std::string &filePath)
1085 {
1086  int size = 0;
1087  const char *const buf = VirtFs::loadFile(filePath, size);
1088  if (buf == nullptr)
1089  return 0;
1090  unsigned long res = Net::Download::adlerBuffer(buf, size);
1091  delete [] buf;
1092  return res;
1093 }
1094 
1095 void UpdaterWindow::loadFile(std::string file)
1096 {
1098  trim(file);
1099 
1100  StringVect lines;
1101  Files::loadTextFileLocal(mUpdatesDir + "/local/help/news.txt", lines);
1102 
1103  for (size_t i = 0, sz = lines.size(); i < sz; ++i)
1104  mBrowserBox->addRow(lines[i], false);
1106 }
1107 
1108 void UpdaterWindow::loadMods(const std::string &dir,
1109  const STD_VECTOR<UpdateFile> &updateFiles)
1110 {
1111  ModDB::load();
1112  std::string modsString = serverConfig.getValue("mods", "");
1113  std::set<std::string> modsList;
1114  splitToStringSet(modsList, modsString, '|');
1115 
1116  const std::string fixPath = dir + "/fix";
1117  for (unsigned int updateIndex = 0,
1118  fsz = CAST_U32(updateFiles.size());
1119  updateIndex < fsz;
1120  updateIndex ++)
1121  {
1122  const UpdateFile &file = updateFiles[updateIndex];
1123  if (file.group.empty())
1124  continue;
1125  const std::set<std::string>::const_iterator
1126  it = modsList.find(file.group);
1127  if (it != modsList.end())
1128  {
1130  fixPath,
1131  file.name,
1132  Append_false);
1133  }
1134  }
1135 
1136  STD_VECTOR<UpdateFile> updateFiles2 = loadXMLFile(
1137  pathJoin(fixPath, xmlUpdateFile),
1138  true);
1139 
1140  for (unsigned int updateIndex = 0,
1141  fsz = CAST_U32(updateFiles2.size());
1142  updateIndex < fsz;
1143  updateIndex++)
1144  {
1145  const UpdateFile &file = updateFiles2[updateIndex];
1146  if (file.group.empty())
1147  continue;
1148  std::string name = file.name;
1149  if (strStartWith(name, "manaplus_"))
1150  {
1151  const std::set<std::string>::const_iterator
1152  it = modsList.find(file.group);
1153  if (it != modsList.end())
1154  {
1155  struct stat statbuf;
1156  std::string fileName = pathJoin(fixPath,
1157  name);
1158  if (stat(fileName.c_str(), &statbuf) == 0)
1159  {
1160  VirtFs::mountZip(fileName,
1161  Append_false);
1162  }
1163  }
1164  }
1165  }
1166 
1167  loadDirMods(dir + "/local/");
1168 }
1169 
1170 void UpdaterWindow::loadDirMods(const std::string &dir)
1171 {
1172  ModDB::load();
1173  const ModInfos &mods = ModDB::getAll();
1174 
1175  std::string modsString = serverConfig.getValue("mods", "");
1176  StringVect modsList;
1177  splitToStringVector(modsList, modsString, '|');
1178  FOR_EACH (StringVectCIter, it, modsList)
1179  {
1180  const std::string &name = *it;
1181  const ModInfoCIterator modIt = mods.find(name);
1182  if (modIt == mods.end())
1183  continue;
1184  const ModInfo *const mod = (*modIt).second;
1185  if (mod != nullptr)
1186  {
1187  const std::string &localDir = mod->getLocalDir();
1188  if (!localDir.empty())
1189  {
1190  VirtFs::mountDir(pathJoin(dir, localDir),
1191  Append_false);
1192  }
1193  }
1194  }
1195 }
1196 
1197 void UpdaterWindow::unloadMods(const std::string &dir)
1198 {
1199  const ModInfos &mods = ModDB::getAll();
1200  std::string modsString = serverConfig.getValue("mods", "");
1201  StringVect modsList;
1202  splitToStringVector(modsList, modsString, '|');
1203  FOR_EACH (StringVectCIter, it, modsList)
1204  {
1205  const std::string &name = *it;
1206  const ModInfoCIterator modIt = mods.find(name);
1207  if (modIt == mods.end())
1208  continue;
1209  const ModInfo *const mod = (*modIt).second;
1210  if (mod != nullptr)
1211  {
1212  const std::string &localDir = mod->getLocalDir();
1213  if (!localDir.empty())
1214  VirtFs::unmountDir(pathJoin(dir, localDir));
1215  }
1216  }
1217 }
1218 
1220 {
1221  scheduleDelete();
1222  updaterWindow = nullptr;
1223 }
#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:126
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)
void setEnableImages(const bool n)
std::vector< std::string > updateMirrors
Definition: settings.h:127
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