1 // This file may be redistributed and modified only under the terms of
2 // the GNU Lesser General Public License (See COPYING for details).
3 // Copyright (C) 2005 - 2007 Simon Goodall
4
5 #include "libwfut/WFUT.h"
6 #include "libwfut/types.h"
7 #include "libwfut/IO.h"
8 #include "libwfut/FileIO.h"
9 #include "libwfut/ChannelIO.h"
10 #include "libwfut/ChannelFileList.h"
11 #include "libwfut/crc32.h"
12 #include "libwfut/platform.h"
13
14 namespace WFUT {
15
onDownloadComplete(const std::string & u,const std::string & f)16 void WFUTClient::onDownloadComplete(const std::string &u, const std::string &f) {
17 DownloadComplete.emit(u, f);
18 }
onDownloadFailed(const std::string & u,const std::string & f,const std::string & r)19 void WFUTClient::onDownloadFailed(const std::string &u, const std::string &f, const std::string &r) {
20 DownloadFailed.emit(u,f,r);
21 }
22
init()23 WFUTError WFUTClient::init() {
24 assert (m_initialised == false);
25
26 m_io = new IO();
27 if (m_io->init()) {
28 delete m_io;
29 m_io = NULL;
30 return WFUT_GENERAL_ERROR;
31 }
32
33 m_io->DownloadComplete.connect(sigc::mem_fun(this, &WFUTClient::onDownloadComplete));
34 m_io->DownloadFailed.connect(sigc::mem_fun(this, &WFUTClient::onDownloadFailed));
35
36 m_initialised = true;
37
38 return WFUT_NO_ERROR;
39 }
40
shutdown()41 WFUTError WFUTClient::shutdown() {
42 assert (m_initialised == true);
43
44 m_io->shutdown();
45 delete m_io;
46 m_io = NULL;
47
48 m_initialised = false;
49
50 return WFUT_NO_ERROR;
51 }
52
updateChannel(const ChannelFileList & updates,const std::string & urlPrefix,const std::string & pathPrefix)53 void WFUTClient::updateChannel(const ChannelFileList &updates,
54 const std::string &urlPrefix,
55 const std::string &pathPrefix) {
56 assert (m_initialised == true);
57 const FileMap &files = updates.getFiles();
58
59 FileMap::const_iterator I = files.begin();
60 FileMap::const_iterator Iend = files.end();
61 while (I != Iend) {
62 const FileObject &f = (I++)->second;
63 if (f.deleted) continue;
64
65 const std::string &url = urlPrefix + updates.getName() + "/" + f.filename;
66 m_io->queueFile(pathPrefix, f.filename, url, f.crc32, f.execute);
67 }
68 }
69
70
updateFile(const FileObject & file,const std::string & urlPrefix,const std::string & pathPrefix)71 void WFUTClient::updateFile(const FileObject &file,
72 const std::string &urlPrefix,
73 const std::string &pathPrefix) {
74 assert (m_initialised == true);
75 if (file.deleted) return;
76
77 const std::string &url = urlPrefix + "/" + file.filename;
78 m_io->queueFile(pathPrefix, file.filename, url, file.crc32, false);
79 }
80
getMirrorList(const std::string & url,MirrorList & mirrors)81 WFUTError WFUTClient::getMirrorList(const std::string &url, MirrorList &mirrors) {
82 assert (m_initialised == true);
83
84 FILE *fp = os_create_tmpfile();
85 if (!fp) {
86 return WFUT_GENERAL_ERROR;
87 }
88
89 if (m_io->downloadFile(fp, url, 0)) {
90 // error
91 // fprintf(stderr, "Error downloading file list\n");
92 os_free_tmpfile(fp);
93 return WFUT_DOWNLOAD_ERROR;
94 }
95
96 std::string xml;
97 // Pre-allocate string memory
98 xml.reserve(ftell(fp));
99 rewind(fp);
100 char buf[1024];
101 size_t n;
102 while ((n = fread(buf, sizeof(char), 1024, fp) ) > 0) {
103 xml.append(buf, n);
104 }
105
106 os_free_tmpfile(fp);
107
108 if (parseMirrorListXML(xml, mirrors)) {
109 // Error
110 // fprintf(stderr, "Error parsing file list\n");
111 return WFUT_PARSE_ERROR;
112 }
113
114 return WFUT_NO_ERROR;
115 }
116
117
getChannelList(const std::string & url,ChannelList & channels)118 WFUTError WFUTClient::getChannelList(const std::string &url, ChannelList &channels) {
119 assert (m_initialised == true);
120
121 FILE *fp = os_create_tmpfile();
122 if (!fp) {
123 return WFUT_GENERAL_ERROR;
124 }
125
126 if (m_io->downloadFile(fp, url, 0)) {
127 // error
128 // fprintf(stderr, "Error downloading file list\n");
129 os_free_tmpfile(fp);
130 return WFUT_DOWNLOAD_ERROR;
131 }
132
133 std::string xml;
134 // Pre-allocate string memory
135 xml.reserve(ftell(fp));
136 rewind(fp);
137 char buf[1024];
138 size_t n;
139 while ((n = fread(buf, sizeof(char), 1024, fp) ) > 0) {
140 xml.append(buf, n);
141 }
142
143 os_free_tmpfile(fp);
144
145 if (parseChannelListXML(xml, channels)) {
146 // Error
147 // fprintf(stderr, "Error parsing file list\n");
148 return WFUT_PARSE_ERROR;
149 }
150
151 return WFUT_NO_ERROR;
152 }
153
getFileList(const std::string & url,ChannelFileList & files)154 WFUTError WFUTClient::getFileList(const std::string &url, ChannelFileList &files) {
155 assert (m_initialised == true);
156
157 FILE *fp = os_create_tmpfile();
158 if (!fp) {
159 // fprintf(stderr, "Unable to create temporary file\n");
160 // perror("");
161 return WFUT_GENERAL_ERROR;
162 }
163
164 if (m_io->downloadFile(fp, url, 0)) {
165 // error
166 // fprintf(stderr, "Error downloading file list\n");
167 os_free_tmpfile(fp);
168 return WFUT_DOWNLOAD_ERROR;
169 }
170
171 std::string xml;
172 // Pre-allocate string memory
173 xml.reserve(ftell(fp));
174 rewind(fp);
175 char buf[1024];
176 size_t n;
177 while ((n = fread(buf, sizeof(char), 1024, fp) ) > 0) {
178 xml.append(buf, n);
179 }
180
181 os_free_tmpfile(fp);
182
183 if (parseFileListXML(xml, files)) {
184 // Error
185 // fprintf(stderr, "Error parsing file list\n");
186 return WFUT_PARSE_ERROR;
187 }
188
189 return WFUT_NO_ERROR;
190 }
191
getLocalList(const std::string & filename,ChannelFileList & files)192 WFUTError WFUTClient::getLocalList(const std::string &filename, ChannelFileList &files) {
193 assert (m_initialised == true);
194 if (parseFileList(filename, files)) {
195 // printf("Error parsing local file list\n");
196 return WFUT_PARSE_ERROR;
197 }
198 return WFUT_NO_ERROR;
199 }
200
saveLocalList(const ChannelFileList & files,const std::string & filename)201 WFUTError WFUTClient::saveLocalList(const ChannelFileList &files, const std::string &filename) {
202 assert (m_initialised == true);
203 if (writeFileList(filename, files)) {
204 // Error
205 return WFUT_WRITE_ERROR;
206 }
207 return WFUT_NO_ERROR;
208 }
209
poll()210 int WFUTClient::poll() {
211 assert (m_initialised == true);
212 return m_io->poll();
213 }
214
calculateUpdates(const ChannelFileList & server,const ChannelFileList & system,const ChannelFileList & local,ChannelFileList & updates,const std::string & prefix)215 WFUTError WFUTClient::calculateUpdates(const ChannelFileList &server, const ChannelFileList &system, const ChannelFileList &local, ChannelFileList &updates, const std::string &prefix) {
216 const FileMap &server_map = server.getFiles();
217 const FileMap &system_map = system.getFiles();
218 const FileMap &local_map = local.getFiles();
219
220 FileMap::const_iterator I = server_map.begin();
221 FileMap::const_iterator Iend = server_map.end();
222
223 for (; I != Iend; ++I) {
224 const FileObject &server_obj = I->second;
225 // Server side deleted? Just ignore for now
226 if (server_obj.deleted) {
227 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_DELETED);
228 continue;
229 }
230 // find the matching local one
231 FileMap::const_iterator sys_iter = system_map.find(I->first);
232 FileMap::const_iterator loc_iter = local_map.find(I->first);
233
234 if (loc_iter == local_map.end()) {
235 if (sys_iter == system_map.end()) {
236 // No local version, or system version
237 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_NO_LOCAL);
238 updates.addFile(server_obj);
239 } else if (server_obj.version > sys_iter->second.version) {
240 // Servere version is newer than sys version, and no local version
241 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_SERVER_SYSTEM);
242 updates.addFile(server_obj);
243 } else {
244 // Assume the sys location is valid, so no need to update
245 // No update required
246 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_NONE);
247 }
248 } else if (server_obj.version > loc_iter->second.version) {
249 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_SERVER_LOCAL);
250 updates.addFile(server_obj);
251 } else {
252 // According to xml files, the local version is the same as the server
253 // Lets check that it exists and has a matching CRC value.
254 uLong crc32;
255 if (calcCRC32(prefix + loc_iter->second.filename.c_str(), crc32) == -1) {
256 // Can't read file, so lets add it
257 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_MISSING);
258 updates.addFile(server_obj);
259 } else {
260 // Do a CRC check and warn user that the file is modified.
261 if (crc32 != server_obj.crc32) {
262 // Modified!
263 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_MODIFIED);
264 } else {
265 // No update required
266 UpdateReason.emit(server_obj.filename, WFUT_UPDATE_NONE);
267 }
268 }
269 }
270 }
271 return WFUT_NO_ERROR;
272 }
273
abortDownload(const std::string & filename)274 void WFUTClient::abortDownload(const std::string &filename) {
275 m_io->abortDownload(filename);
276 }
277
abortAll()278 void WFUTClient::abortAll() {
279 m_io->abortAll();
280 }
281
282 }
283