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