summaryrefslogtreecommitdiff
path: root/src/update/UpdateActivity.cpp
blob: a8fb7fc794d39596f1e11542e3cc74c15d0fec45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * UpdateActivity.cpp
 *
 *  Created on: Jun 20, 2012
 *      Author: Simon
 */

#include <bzlib.h>
#include <sstream>
#include "interface/Engine.h"
#include "UpdateActivity.h"
#include "tasks/Task.h"
#include "client/HTTP.h"
#include "Update.h"


class UpdateDownloadTask : public Task
{
public:
	UpdateDownloadTask(std::string updateName, UpdateActivity * a) : updateName(updateName), a(a) {};
private:
	UpdateActivity * a;
	std::string updateName;
	virtual void notifyDone()
	{
		a->NotifyDone(this);
	}
	virtual void doWork()
	{
		std::stringstream errorStream;
		void * request = http_async_req_start(NULL, (char*)updateName.c_str(), NULL, 0, 0);
		notifyStatus("Downloading update");
		notifyProgress(-1);
		while(!http_async_req_status(request))
		{
			int total, done;
			http_async_get_length(request, &total, &done);
			notifyProgress((float(done)/float(total))*100.0f);
		}

		char * data;
		int dataLength, status;
		data = http_async_req_stop(request, &status, &dataLength);
		if (status!=200)
		{
			if (data)
				free(data);
			errorStream << "Server responded with Status " << status;
			notifyError("Could not download update");
			return;
		}
		if (!data)
		{
			errorStream << "Server responded with nothing";
			notifyError("Server did not return any data");
			return;
		}

		notifyStatus("Unpacking update");
		notifyProgress(-1);

		int uncompressedLength;

		if(dataLength<16)
		{
			errorStream << "Unsufficient data, got " << dataLength << " bytes";
			goto corrupt;
		}
		if (data[0]!=0x42 || data[1]!=0x75 || data[2]!=0x54 || data[3]!=0x54)
		{
			errorStream << "Invalid update format";
			goto corrupt;
		}

		uncompressedLength  = (unsigned char)data[4];
		uncompressedLength |= ((unsigned char)data[5])<<8;
		uncompressedLength |= ((unsigned char)data[6])<<16;
		uncompressedLength |= ((unsigned char)data[7])<<24;

		char * res;
		res = (char *)malloc(uncompressedLength);
		if (!res)
		{
			errorStream << "Unable to allocate " << uncompressedLength << " bytes of memory for decompression";
			goto corrupt;
		}

		int dstate;
		dstate = BZ2_bzBuffToBuffDecompress((char *)res, (unsigned *)&uncompressedLength, (char *)(data+8), dataLength-8, 0, 0);
		if (dstate)
		{
			errorStream << "Unable to decompress update: " << dstate;
			free(res);
			goto corrupt;
		}

		free(data);

		notifyStatus("Applying update");
		notifyProgress(-1);

		if (update_start(res, uncompressedLength))
		{
			update_cleanup();
			notifyError("Update failed - try downloading a new version.");
		}

		return;

	corrupt:
		notifyError("Downloaded update is corrupted\n" + errorStream.str());
		free(data);
		return;
	}
};

UpdateActivity::UpdateActivity() {
	char my_uri[] = "http://" SERVER "/Update.api?Action=Download&Architecture="
	#if defined WIN32
	                "Windows32"
	#elif defined LIN32
	                "Linux32"
	#elif defined LIN64
	                "Linux64"
	#elif defined MACOSX
	                "MacOSX"
	#else
	                "Unknown"
	#endif
	                "&InstructionSet="
	#if defined X86_SSE3
	                "SSE3"
	#elif defined X86_SSE2
	                "SSE2"
	#elif defined X86_SSE
	                "SSE"
	#else
	                "SSE"
	#endif
	                ;
	updateDownloadTask = new UpdateDownloadTask(my_uri, this);
	updateWindow = new TaskWindow("Downloading update...", updateDownloadTask, true);
}

void UpdateActivity::NotifyDone(Task * sender)
{
	updateWindow->Exit();
	ui::Engine::Ref().Exit();
	delete this;
}

UpdateActivity::~UpdateActivity() {
	// TODO Auto-generated destructor stub
}