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 <sstream>
59 
60 #include "debug.h"
61 
63 
64 const std::string xmlUpdateFile("resources.xml");
65 const std::string txtUpdateFile("resources2.txt");
66 const std::string updateServer2
67  ("http://download.manaplus.org/manaplus/updates/");
68 const std::string updateServer3
69  ("http://download2.manaplus.org/manaplus/updates/");
70 const std::string updateServer4
71  ("http://download.evolonline.org/manaplus/updates/");
72 const std::string updateServer5
73  ("http://download3.manaplus.org/manaplus/updates/");
74 
78 static STD_VECTOR<UpdateFile> loadXMLFile(const std::string &fileName,
79  const bool loadMods)
80 {
81  STD_VECTOR<UpdateFile> files;
83  XmlNodeConstPtrConst rootNode = doc.rootNode();
84 
85  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "updates"))
86  {
87  logger->log("Error loading update file: %s", fileName.c_str());
88  return files;
89  }
90 
91  for_each_xml_child_node(fileNode, rootNode)
92  {
93  const bool isMod = xmlNameEqual(fileNode, "mod");
94  if (!xmlNameEqual(fileNode, "update") && !isMod)
95  continue;
96 
97  UpdateFile file;
98  file.name = XML::getProperty(fileNode, "file", "");
99  file.hash = XML::getProperty(fileNode, "hash", "");
100  file.type = XML::getProperty(fileNode, "type", "data");
101  file.desc = XML::getProperty(fileNode, "description", "");
102  file.group = XML::getProperty(fileNode, "group", "");
103  if (!file.group.empty() && (!isMod || !loadMods))
104  continue;
105 
106  const std::string version = XML::getProperty(
107  fileNode, "version", "");
108  if (!version.empty())
109  {
110  if (version > CHECK_VERSION)
111  continue;
112  }
113  const std::string notVersion = XML::getProperty(
114  fileNode, "notVersion", "");
115  if (!notVersion.empty())
116  {
117  if (notVersion <= CHECK_VERSION)
118  continue;
119  }
120  if (XML::getProperty(fileNode, "required", "yes") == "yes")
121  file.required = true;
122  else
123  file.required = false;
124 
125  if (checkPath(file.name))
126  files.push_back(file);
127  }
128 
129  return files;
130 }
131 
132 static STD_VECTOR<UpdateFile> loadTxtFile(const std::string &fileName)
133 {
134  STD_VECTOR<UpdateFile> files;
135  std::ifstream fileHandler;
136  fileHandler.open(fileName.c_str(), std::ios::in);
137 
138  if (fileHandler.is_open())
139  {
140  while (fileHandler.good())
141  {
142  char name[256];
143  char hash[50];
144  fileHandler.getline(name, 256, ' ');
145  fileHandler.getline(hash, 50);
146 
147  UpdateFile thisFile;
148  thisFile.name = name;
149  thisFile.hash = hash;
150  thisFile.type = "data";
151  thisFile.group.clear();
152  thisFile.required = true;
153  thisFile.desc.clear();
154 
155  if (!thisFile.name.empty() && checkPath(thisFile.name))
156  files.push_back(thisFile);
157  }
158  }
159  else
160  {
161  logger->log("Error loading update file: %s", fileName.c_str());
162  }
163  fileHandler.close();
164 
165  return files;
166 }
167 
168 UpdaterWindow::UpdaterWindow(const std::string &restrict updateHost,
169  const std::string &restrict updatesDir,
170  const bool applyUpdates,
171  const UpdateTypeT updateType) :
172  // TRANSLATORS: updater window name
173  Window(_("Updating..."), Modal_false, nullptr, "update.xml"),
174  ActionListener(),
175  KeyListener(),
176  mDownloadProgress(0.0F),
177  mUpdateHost(updateHost),
178  mUpdatesDir(updatesDir),
179  mUpdatesDirReal(updatesDir),
180  mCurrentFile("news.txt"),
181  mNewLabelCaption(),
182  mDownloadMutex(),
183  mCurrentChecksum(0),
184  mMemoryBuffer(nullptr),
185  mDownload(nullptr),
186  mUpdateFiles(),
187  mTempUpdateFiles(),
188  mUpdateServerPath(mUpdateHost),
189  mItemLinkHandler(new ItemLinkHandler),
190  // TRANSLATORS: updater window label
191  mLabel(new Label(this, _("Connecting..."))),
192  // TRANSLATORS: updater window button
193  mCancelButton(new Button(this, _("Cancel"), "cancel", this)),
194  // TRANSLATORS: updater window button
195  mPlayButton(new Button(this, _("Play"), "play", this)),
196  mProgressBar(new ProgressBar(this, 0.0, 310, 0,
198  "updateprogressbar.xml", "updateprogressbar_fill.xml")),
199  mBrowserBox(new StaticBrowserBox(this, Opaque_true,
200  "browserbox.xml")),
201  mScrollArea(new ScrollArea(this, mBrowserBox,
202  Opaque_true, "update_background.xml")),
203  mDownloadStatus(UpdateDownloadStatus::UPDATE_NEWS),
204  mDownloadedBytes(0),
205  mUpdateIndex(0),
206  mUpdateIndexOffset(0),
207  mUpdateType(updateType),
208  mStoreInMemory(true),
209  mDownloadComplete(true),
210  mUserCancel(false),
211  mLoadUpdates(applyUpdates),
212  mValidateXml(false),
213  mSkipPatches(false)
214 {
215  setWindowName("UpdaterWindow");
216  setResizable(true);
217  setDefaultSize(450, 400, ImagePosition::CENTER, 0, 0);
218  setMinWidth(310);
219  setMinHeight(220);
220 
225  mBrowserBox->setEnableKeys(true);
226  mBrowserBox->setEnableTabs(true);
227  mPlayButton->setEnabled(false);
228 
229  ContainerPlacer placer(nullptr, nullptr);
230  placer = getPlacer(0, 0);
231 
232  placer(0, 0, mScrollArea, 5, 3).setPadding(3);
233  placer(0, 3, mLabel, 5, 1);
234  placer(0, 4, mProgressBar, 5, 1);
235  placer(3, 5, mCancelButton, 1, 1);
236  placer(4, 5, mPlayButton, 1, 1);
237 
238  Layout &layout = getLayout();
239  layout.setRowHeight(0, LayoutType::SET);
240 
241  addKeyListener(this);
242 
243  if (mUpdateHost.empty())
244  {
245  const STD_VECTOR<std::string> &mirrors = settings.updateMirrors;
246  if (mirrors.begin() != mirrors.end())
247  mUpdateHost = *mirrors.begin();
248  mSkipPatches = true;
249  }
250 
251  loadWindowState();
252 }
253 
255 {
260 
261  download();
262 }
263 
265 {
266  if (mLoadUpdates)
267  loadUpdates();
268 
269  if (mDownload != nullptr)
270  {
271  mDownload->cancel();
272 
274  }
275  free(mMemoryBuffer);
277 }
278 
279 void UpdaterWindow::setProgress(const float p)
280 {
281  // Do delayed progress bar update, since Guichan isn't thread-safe
283  mDownloadProgress = p;
284 }
285 
286 void UpdaterWindow::setLabel(const std::string &str)
287 {
288  // Do delayed label text update, since Guichan isn't thread-safe
291 }
292 
294 {
295  mCancelButton->setEnabled(false);
296  mPlayButton->setEnabled(true);
298 
299  if (client->getState() != State::GAME)
300  {
301  if ((mUpdateType & UpdateType::Close) != 0)
303  }
304  else
305  {
306  deleteSelf();
307  }
308 }
309 
311 {
312  const std::string &eventId = event.getId();
313  if (eventId == "cancel")
314  {
315  // Register the user cancel
316  mUserCancel = true;
317  // Skip the updating process
319  {
320  if (mDownload != nullptr)
321  mDownload->cancel();
323  }
324  }
325  else if (eventId == "play")
326  {
327  if (client->getState() != State::GAME)
329  else
330  deleteSelf();
331  }
332 }
333 
335 {
336  const InputActionT actionId = event.getActionId();
337  if (actionId == InputAction::GUI_CANCEL)
338  {
340  if (client->getState() != State::GAME)
342  else
343  deleteSelf();
344  }
345  else if (actionId == InputAction::GUI_SELECT ||
346  actionId == InputAction::GUI_SELECT2)
347  {
351  {
353  }
354  else
355  {
357  }
358  }
359 }
360 
362 {
363  if (mMemoryBuffer == nullptr)
364  {
365  logger->log1("Couldn't load news");
366  return;
367  }
368 
369  // Reallocate and include terminating 0 character
370  mMemoryBuffer = static_cast<char*>(realloc(
372  if (mMemoryBuffer == nullptr)
373  {
374  logger->log1("Couldn't load news");
375  return;
376  }
379 
380  std::string newsName = mUpdatesDir + "/local/help/news.txt";
381  mkdir_r((mUpdatesDir + "/local/help/").c_str());
382  bool firstLine(true);
383  std::ofstream file;
384  std::stringstream ss(mMemoryBuffer);
385  std::string line;
386  file.open(newsName.c_str(), std::ios::out);
387  int cnt = 0;
388  const int maxNews = 50;
389  while (std::getline(ss, line, '\n'))
390  {
391  cnt ++;
392  if (firstLine)
393  {
394  firstLine = false;
395  const size_t i = line.find("##9 Latest client version: ##6");
396  if (i == 0u)
397  continue;
398 
399  if (file.is_open())
400  file << line << std::endl;
401  if (cnt < maxNews)
402  mBrowserBox->addRow(line, false);
403  }
404  else
405  {
406  if (file.is_open())
407  file << line << std::endl;
408  if (cnt < maxNews)
409  mBrowserBox->addRow(line, false);
410  }
411  }
412 
413  file.close();
414  if (cnt > maxNews)
415  {
416  mBrowserBox->addRow("", false);
417  // TRANSLATORS: updater window checkbox
418  mBrowserBox->addRow("news", _("Show all news (can be slow)"));
419  mBrowserBox->addRow("", false);
420  }
421  // Free the memory buffer now that we don't need it anymore
422  free(mMemoryBuffer);
423  mMemoryBuffer = nullptr;
424  mDownloadedBytes = 0;
425 
428 }
429 
431 {
432  if (mMemoryBuffer == nullptr)
433  {
434  logger->log1("Couldn't load patch");
435  return;
436  }
437 
438  // Reallocate and include terminating 0 character
439  mMemoryBuffer = static_cast<char*>(
440  realloc(mMemoryBuffer, mDownloadedBytes + 1));
441  if (mMemoryBuffer == nullptr)
442  {
443  logger->log1("Couldn't load patch");
444  return;
445  }
447 
448  std::string version;
449 
450  // Tokenize and add each line separately
451  char *line = strtok(mMemoryBuffer, "\n");
452  if (line != nullptr)
453  {
454  version = line;
455  if (serverVersion < 1)
456  {
457  line = strtok(nullptr, "\n");
458  if (line != nullptr)
459  {
460  mBrowserBox->addRow(strprintf("##9 Latest client version: "
461  "##6ManaPlus %s##0", line), true);
462  }
463  }
464  if (version > CHECK_VERSION)
465  {
466  mBrowserBox->addRow("", true);
467 #if defined(ANDROID)
468  const std::string url = "androidDownloadUrl";
469  const std::string text = "androidDownloadUrl";
470 #elif defined(WIN32)
471  const std::string url = "windowsDownloadUrl";
472  const std::string text = "windowsDownloadUrl";
473 #else // defined(ANDROID)
474 
475  const std::string url = "otherDownloadUrl";
476  const std::string text = "otherDownloadUrl";
477 #endif // defined(ANDROID)
478 
479  mBrowserBox->addRow(std::string(" ##1[@@").append(
480  branding.getStringValue(url)).append("|").append(
481  branding.getStringValue(text)).append("@@]"), true);
482  mBrowserBox->addRow("##1You can download it from", true);
483  mBrowserBox->addRow("##1ManaPlus updated.", true);
484  }
485  else
486  {
487  mBrowserBox->addRow("You have latest client version.", true);
488  }
489  }
490 
491  // Free the memory buffer now that we don't need it anymore
492  free(mMemoryBuffer);
493  mMemoryBuffer = nullptr;
494  mDownloadedBytes = 0;
495 
498 }
499 
501  const DownloadStatusT status,
502  size_t dt,
503  const size_t dn)
504 {
505  UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(ptr);
506  if (uw == nullptr)
507  return -1;
508 
509  if (status == DownloadStatus::Complete)
510  {
511  uw->mDownloadComplete = true;
512  }
513  else if (status == DownloadStatus::Error ||
514  status == DownloadStatus::Cancelled)
515  {
518  { // ignoring error in last state (was UPDATE_PATCH)
520  uw->mDownloadComplete = true;
521  free(uw->mMemoryBuffer);
522  uw->mMemoryBuffer = nullptr;
523  }
524  else
525  {
527  }
528  }
529 
530  if (dt == 0u)
531  dt = 1;
532 
533  float progress = static_cast<float>(dn) /
534  static_cast<float>(dt);
535 
536  if (progress != progress)
537  progress = 0.0F; // check for NaN
538  if (progress < 0.0F)
539  progress = 0.0F; // no idea how this could ever happen,
540  // but why not check for it anyway.
541  if (progress > 1.0F)
542  progress = 1.0F;
543 
544  uw->setLabel(std::string(uw->mCurrentFile).append(" (")
545  .append(toString(CAST_S32(progress * 100))).append("%)"));
546 
547  uw->setProgress(progress);
548 
549  if ((client->getState() != State::UPDATE &&
550  client->getState() != State::GAME) ||
552  {
553  // If the action was canceled return an error code to stop the mThread
554  return -1;
555  }
556 
557  return 0;
558 }
559 
560 size_t UpdaterWindow::memoryWrite(void *ptr, size_t size,
561  size_t nmemb, void *stream)
562 {
563  UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(stream);
564  const size_t totalMem = size * nmemb;
565  if (uw == nullptr)
566  return 0;
567  uw->mMemoryBuffer = static_cast<char*>(realloc(uw->mMemoryBuffer,
568  CAST_SIZE(uw->mDownloadedBytes) + totalMem));
569  if (uw->mMemoryBuffer != nullptr)
570  {
571  memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem);
572  uw->mDownloadedBytes += CAST_S32(totalMem);
573  }
574 
575  return totalMem;
576 }
577 
579 {
580  if (mDownload != nullptr)
581  {
582  mDownload->cancel();
583  delete mDownload;
584  }
586  {
587  mDownload = new Net::Download(this,
588  branding.getStringValue("updateMirror1") + mCurrentFile,
590  true, false, mValidateXml);
591  for (int f = 2; f < 8; f ++)
592  {
593  const std::string url = branding.getStringValue(
594  "updateMirror" + toString(f));
595  if (!url.empty())
597  }
598  }
599  else
600  {
601  mDownload = new Net::Download(this,
604  false, false, mValidateXml);
605 
608  {
609  const std::string str = urlJoin(mUpdateServerPath, mCurrentFile);
613  }
614  else
615  {
616  const STD_VECTOR<std::string> &mirrors = settings.updateMirrors;
617  FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, mirrors)
618  {
620  mCurrentFile));
621  }
622  }
623  }
624 
625  if (mStoreInMemory)
626  {
628  }
629  else
630  {
632  {
635  }
636  else
637  {
639  mCurrentFile),
640  -1);
641  }
642  }
643 
645  mDownload->noCache();
646 
647  setLabel(mCurrentFile + " (0%)");
648  mDownloadComplete = false;
649 
650  mDownload->start();
651 }
652 
654 {
655  if (mUpdateFiles.empty())
656  { // updates not downloaded
658  false);
659  if (mUpdateFiles.empty())
660  {
661  logger->log("Warning this server does not have a"
662  " %s file falling back to %s", xmlUpdateFile.c_str(),
663  txtUpdateFile.c_str());
665  txtUpdateFile));
666  }
667  }
668 
669  std::string fixPath = mUpdatesDir + "/fix";
670  const unsigned sz = CAST_U32(mUpdateFiles.size());
671  for (mUpdateIndex = 0; mUpdateIndex < sz; mUpdateIndex++)
672  {
673  const UpdateFile &file = mUpdateFiles[mUpdateIndex];
674  if (!file.group.empty())
675  continue;
677  fixPath,
678  file.name,
679  Append_false);
680  }
683 }
684 
685 void UpdaterWindow::loadLocalUpdates(const std::string &dir)
686 {
687  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
688  pathJoin(dir, xmlUpdateFile),
689  false);
690 
691  if (updateFiles.empty())
692  {
693  logger->log("Warning this server does not have a"
694  " %s file falling back to %s", xmlUpdateFile.c_str(),
695  txtUpdateFile.c_str());
696  updateFiles = loadTxtFile(pathJoin(dir,
697  txtUpdateFile));
698  }
699 
700  const std::string fixPath = dir + "/fix";
701  for (unsigned int updateIndex = 0,
702  fsz = CAST_U32(updateFiles.size());
703  updateIndex < fsz;
704  updateIndex++)
705  {
706  const UpdateFile &file = updateFiles[updateIndex];
707  if (!file.group.empty())
708  continue;
710  fixPath,
711  file.name,
712  Append_false);
713  }
714  loadManaPlusUpdates(dir);
715  loadMods(dir, updateFiles);
716 }
717 
718 void UpdaterWindow::unloadUpdates(const std::string &dir)
719 {
720  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
721  pathJoin(dir, xmlUpdateFile),
722  true);
723 
724  if (updateFiles.empty())
725  {
726  updateFiles = loadTxtFile(pathJoin(dir,
727  txtUpdateFile));
728  }
729 
730  const std::string fixPath = dir + "/fix";
731  for (unsigned int updateIndex = 0,
732  fsz = CAST_U32(updateFiles.size());
733  updateIndex < fsz;
734  updateIndex++)
735  {
737  fixPath,
738  updateFiles[updateIndex].name);
739  }
741 }
742 
743 void UpdaterWindow::loadManaPlusUpdates(const std::string &dir)
744 {
745  std::string fixPath = dir + "/fix";
746  STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
747  pathJoin(fixPath, xmlUpdateFile),
748  false);
749 
750  for (unsigned int updateIndex = 0,
751  fsz = CAST_U32(updateFiles.size());
752  updateIndex < fsz;
753  updateIndex++)
754  {
755  const UpdateFile &file = updateFiles[updateIndex];
756  if (!file.group.empty())
757  continue;
758  const std::string name = file.name;
759  if (strStartWith(name, "manaplus_"))
760  {
761  struct stat statbuf;
762  std::string fileName = pathJoin(fixPath,
763  name);
764  if (stat(fileName.c_str(), &statbuf) == 0)
765  {
766  VirtFs::mountZip(fileName,
767  Append_false);
768  }
769  }
770  }
771 }
772 
773 void UpdaterWindow::unloadManaPlusUpdates(const std::string &dir)
774 {
775  const std::string fixPath = dir + "/fix";
776  const STD_VECTOR<UpdateFile> updateFiles = loadXMLFile(
777  pathJoin(fixPath, xmlUpdateFile),
778  true);
779 
780  for (unsigned int updateIndex = 0,
781  fsz = CAST_U32(updateFiles.size());
782  updateIndex < fsz;
783  updateIndex++)
784  {
785  std::string name = updateFiles[updateIndex].name;
786  if (strStartWith(name, "manaplus_"))
787  {
788  struct stat statbuf;
789  const std::string file = pathJoin(
790  fixPath, name);
791  if (stat(file.c_str(), &statbuf) == 0)
792  VirtFs::unmountZip(file);
793  }
794  }
795 }
796 
797 void UpdaterWindow::addUpdateFile(const std::string &restrict path,
798  const std::string &restrict fixPath,
799  const std::string &restrict file,
800  const Append append)
801 {
802  const std::string tmpPath = pathJoin(path, file);
803  if (append == Append_false)
804  VirtFs::mountZip(tmpPath, append);
805 
806  const std::string fixFile = pathJoin(fixPath, file);
807  struct stat statbuf;
808  if (stat(fixFile.c_str(), &statbuf) == 0)
809  VirtFs::mountZip(fixFile, append);
810 
811  if (append == Append_true)
812  VirtFs::mountZip(tmpPath, append);
813 }
814 
815 void UpdaterWindow::removeUpdateFile(const std::string &restrict path,
816  const std::string &restrict fixPath,
817  const std::string &restrict file)
818 {
819  VirtFs::unmountZip(pathJoin(path, file));
820  const std::string fixFile = pathJoin(fixPath, file);
821  struct stat statbuf;
822  if (stat(fixFile.c_str(), &statbuf) == 0)
823  VirtFs::unmountZip(fixFile);
824 }
825 
827 {
828  BLOCK_START("UpdaterWindow::logic")
829  // Update Scroll logic
830  mScrollArea->logic();
831 
832  // Synchronize label caption when necessary
833  {
835 
837  {
839  mLabel->adjustSize();
840  }
841 
843  if (!mUpdateFiles.empty() &&
845  {
848  mUpdateFiles.size()) + CAST_S32(
849  mTempUpdateFiles.size()) + 1));
850  }
851  else
852  {
853  mProgressBar->setText("");
854  }
855  }
856 
857  switch (mDownloadStatus)
858  {
860  mBrowserBox->addRow("", false);
861  // TRANSLATORS: update message
862  mBrowserBox->addRow(_("##1 The update process is incomplete."),
863  false);
864  // TRANSLATORS: Continues "The update process is incomplete.".
865  mBrowserBox->addRow(_("##1 It is strongly recommended that"),
866  false);
867  // TRANSLATORS: Begins "It is strongly recommended that".
868  mBrowserBox->addRow(_("##1 you try again later."),
869  false);
870  if (mDownload != nullptr)
871  mBrowserBox->addRow(mDownload->getError(), false);
876  break;
878  if (mDownloadComplete)
879  {
880  // Parse current memory buffer as news and dispose of the data
881  loadNews();
882 
883  mValidateXml = true;
885  mStoreInMemory = false;
887  download(); // download() changes mDownloadComplete to false
888  }
889  break;
891  if (mDownloadComplete)
892  {
893  // Parse current memory buffer as news and dispose of the data
894  loadPatch();
895 
897  mUpdatesDir = pathJoin(mUpdatesDir, "fix");
899  mValidateXml = true;
900  mStoreInMemory = false;
902  download();
903  }
904  break;
905 
907  if (mDownloadComplete)
908  {
910  {
913  true);
914 
915  if (mUpdateFiles.empty())
916  {
917  logger->log("Warning this server does not have a %s"
918  " file falling back to %s",
919  xmlUpdateFile.c_str(),
920  txtUpdateFile.c_str());
921 
922  // If the resources.xml file fails,
923  // fall back onto a older version
925  mValidateXml = false;
926  mStoreInMemory = false;
928  download();
929  break;
930  }
931  }
932  else if (mCurrentFile == txtUpdateFile)
933  {
934  mValidateXml = true;
936  txtUpdateFile));
937  }
938  mStoreInMemory = false;
940  }
941  break;
943  if (mDownloadComplete)
944  {
945  if (CAST_SIZE(mUpdateIndex) < mUpdateFiles.size())
946  {
948  if (thisFile.type == "music"
949  && !config.getBoolValue("download-music"))
950  {
951  mUpdateIndex++;
952  break;
953  }
954  mCurrentFile = thisFile.name;
955  std::string checksum;
956  checksum = thisFile.hash;
957  std::stringstream ss(checksum);
958  ss >> std::hex >> mCurrentChecksum;
959 
960  std::ifstream temp(pathJoin(mUpdatesDir,
961  mCurrentFile).c_str());
962 
963  mValidateXml = false;
964  if (!temp.is_open() || !validateFile(pathJoin(
966  mCurrentChecksum))
967  {
968  temp.close();
969  download();
970  }
971  else
972  {
973  temp.close();
974  logger->log("%s already here", mCurrentFile.c_str());
975  }
976  mUpdateIndex++;
977  }
978  else
979  {
980  if (!mSkipPatches)
981  {
982  // Download of updates completed
983  mCurrentFile = "latest.txt";
984  mStoreInMemory = true;
986  mValidateXml = false;
987  download(); // download() changes
988  // mDownloadComplete to false
989  }
990  else
991  {
994  }
995  }
996  }
997  break;
999  if (mDownloadComplete)
1000  {
1001  if (mCurrentFile == xmlUpdateFile)
1002  {
1005  true);
1006  }
1008  mUpdateIndex = 0;
1009  mValidateXml = true;
1010  mStoreInMemory = false;
1012  download();
1013  }
1014  break;
1016  if (mDownloadComplete)
1017  {
1018  mValidateXml = false;
1019  if (CAST_SIZE(mUpdateIndex)
1020  < mTempUpdateFiles.size())
1021  {
1022  const UpdateFile thisFile = mTempUpdateFiles[mUpdateIndex];
1023  mCurrentFile = thisFile.name;
1024  std::string checksum;
1025  checksum = thisFile.hash;
1026  std::stringstream ss(checksum);
1027  ss >> std::hex >> mCurrentChecksum;
1028 
1029  std::ifstream temp((pathJoin(mUpdatesDir,
1030  mCurrentFile)).c_str());
1031 
1032  if (!temp.is_open() || !validateFile(pathJoin(
1034  mCurrentChecksum))
1035  {
1036  temp.close();
1037  download();
1038  }
1039  else
1040  {
1041  temp.close();
1042  logger->log("%s already here", mCurrentFile.c_str());
1043  }
1044  mUpdateIndex++;
1045  }
1046  else
1047  {
1050  }
1051  }
1052  break;
1055  enable();
1056  // TRANSLATORS: updater window label
1057  setLabel(_("Completed"));
1059  break;
1061  break;
1062  default:
1063  logger->log("UpdaterWindow::logic unknown status: "
1065  break;
1066  }
1067  BLOCK_END("UpdaterWindow::logic")
1068 }
1069 
1070 bool UpdaterWindow::validateFile(const std::string &filePath,
1071  const unsigned long hash)
1072 {
1073  FILE *const file = fopen(filePath.c_str(), "rb");
1074  if (file == nullptr)
1075  return false;
1076 
1077  const unsigned long adler = Net::Download::fadler32(file);
1078  fclose(file);
1079  return adler == hash;
1080 }
1081 
1082 unsigned long UpdaterWindow::getFileHash(const std::string &filePath)
1083 {
1084  int size = 0;
1085  const char *const buf = VirtFs::loadFile(filePath, size);
1086  if (buf == nullptr)
1087  return 0;
1088  unsigned long res = Net::Download::adlerBuffer(buf, size);
1089  delete [] buf;
1090  return res;
1091 }
1092 
1093 void UpdaterWindow::loadFile(std::string file)
1094 {
1096  trim(file);
1097 
1098  StringVect lines;
1099  Files::loadTextFileLocal(mUpdatesDir + "/local/help/news.txt", lines);
1100 
1101  for (size_t i = 0, sz = lines.size(); i < sz; ++i)
1102  mBrowserBox->addRow(lines[i], false);
1104 }
1105 
1106 void UpdaterWindow::loadMods(const std::string &dir,
1107  const STD_VECTOR<UpdateFile> &updateFiles)
1108 {
1109  ModDB::load();
1110  std::string modsString = serverConfig.getValue("mods", "");
1111  std::set<std::string> modsList;
1112  splitToStringSet(modsList, modsString, '|');
1113 
1114  const std::string fixPath = dir + "/fix";
1115  for (unsigned int updateIndex = 0,
1116  fsz = CAST_U32(updateFiles.size());
1117  updateIndex < fsz;
1118  updateIndex ++)
1119  {
1120  const UpdateFile &file = updateFiles[updateIndex];
1121  if (file.group.empty())
1122  continue;
1123  const std::set<std::string>::const_iterator
1124  it = modsList.find(file.group);
1125  if (it != modsList.end())
1126  {
1128  fixPath,
1129  file.name,
1130  Append_false);
1131  }
1132  }
1133 
1134  STD_VECTOR<UpdateFile> updateFiles2 = loadXMLFile(
1135  pathJoin(fixPath, xmlUpdateFile),
1136  true);
1137 
1138  for (unsigned int updateIndex = 0,
1139  fsz = CAST_U32(updateFiles2.size());
1140  updateIndex < fsz;
1141  updateIndex++)
1142  {
1143  const UpdateFile &file = updateFiles2[updateIndex];
1144  if (file.group.empty())
1145  continue;
1146  std::string name = file.name;
1147  if (strStartWith(name, "manaplus_"))
1148  {
1149  const std::set<std::string>::const_iterator
1150  it = modsList.find(file.group);
1151  if (it != modsList.end())
1152  {
1153  struct stat statbuf;
1154  std::string fileName = pathJoin(fixPath,
1155  name);
1156  if (stat(fileName.c_str(), &statbuf) == 0)
1157  {
1158  VirtFs::mountZip(fileName,
1159  Append_false);
1160  }
1161  }
1162  }
1163  }
1164 
1165  loadDirMods(dir + "/local/");
1166 }
1167 
1168 void UpdaterWindow::loadDirMods(const std::string &dir)
1169 {
1170  ModDB::load();
1171  const ModInfos &mods = ModDB::getAll();
1172 
1173  std::string modsString = serverConfig.getValue("mods", "");
1174  StringVect modsList;
1175  splitToStringVector(modsList, modsString, '|');
1176  FOR_EACH (StringVectCIter, it, modsList)
1177  {
1178  const std::string &name = *it;
1179  const ModInfoCIterator modIt = mods.find(name);
1180  if (modIt == mods.end())
1181  continue;
1182  const ModInfo *const mod = (*modIt).second;
1183  if (mod != nullptr)
1184  {
1185  const std::string &localDir = mod->getLocalDir();
1186  if (!localDir.empty())
1187  {
1188  VirtFs::mountDir(pathJoin(dir, localDir),
1189  Append_false);
1190  }
1191  }
1192  }
1193 }
1194 
1195 void UpdaterWindow::unloadMods(const std::string &dir)
1196 {
1197  const ModInfos &mods = ModDB::getAll();
1198  std::string modsString = serverConfig.getValue("mods", "");
1199  StringVect modsList;
1200  splitToStringVector(modsList, modsString, '|');
1201  FOR_EACH (StringVectCIter, it, modsList)
1202  {
1203  const std::string &name = *it;
1204  const ModInfoCIterator modIt = mods.find(name);
1205  if (modIt == mods.end())
1206  continue;
1207  const ModInfo *const mod = (*modIt).second;
1208  if (mod != nullptr)
1209  {
1210  const std::string &localDir = mod->getLocalDir();
1211  if (!localDir.empty())
1212  VirtFs::unmountDir(pathJoin(dir, localDir));
1213  }
1214  }
1215 }
1216 
1218 {
1219  scheduleDelete();
1220  updaterWindow = nullptr;
1221 }
#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:222
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:121
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:36
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:227
void setWriteFunction(WriteFunction write)
Definition: download.cpp:180
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:119
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:94
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:171
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:113
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:127
Mutex mDownloadMutex
unsigned long mCurrentChecksum
int getVerticalMaxScroll()
Logger * logger
Definition: logger.cpp:95
void setFile(const std::string &filename, const int64_t adler32)
Definition: download.cpp:164
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
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:213
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:714
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:186
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:166
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:158
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:176
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:243
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:145
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