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