1 /* This file is part of pr-downloader (GPL v2 or later), see the LICENSE file */
2
3 #include "RapidDownloader.h"
4 #include "FileSystem/FileSystem.h"
5 #include "Util.h"
6 #include "Logger.h"
7 #include "Repo.h"
8 #include "Sdp.h"
9
10 #include <stdio.h>
11 #include <string>
12 #include <string.h>
13 #include <list>
14 #include <zlib.h>
15
16 #ifndef WIN32
17 #include <regex.h>
18 #endif
19
20
CRapidDownloader()21 CRapidDownloader::CRapidDownloader():
22 url(REPO_MASTER),
23 reposLoaded(false)
24 {
25 }
26
~CRapidDownloader()27 CRapidDownloader::~CRapidDownloader()
28 {
29 sdps.clear();
30 }
31
32
addRemoteDsp(CSdp & sdp)33 void CRapidDownloader::addRemoteDsp(CSdp& sdp)
34 {
35 sdps.push_back(sdp);
36 }
37
38
list_compare(CSdp & first,CSdp & second)39 bool CRapidDownloader::list_compare(CSdp& first ,CSdp& second)
40 {
41 std::string name1;
42 std::string name2;
43 name1.clear();
44 name2.clear();
45 name1=(first.getShortName());
46 name2=(second.getShortName());
47 unsigned int len;
48 len=std::min(name1.size(), name2.size());
49 for (unsigned int i=0; i<len; i++) {
50 if (tolower(name1[i])<tolower(name2[i])) {
51 return true;
52 }
53 }
54 return false;
55 }
56
reloadRepos()57 bool CRapidDownloader::reloadRepos()
58 {
59 if (reposLoaded)
60 return true;
61 updateRepos();
62 reposLoaded=true;
63 return true;
64 }
65
66
download_name(IDownload * download,int reccounter,std::string name)67 bool CRapidDownloader::download_name(IDownload* download, int reccounter,std::string name)
68 {
69 LOG_DEBUG("%s %s",name.c_str(),download->name.c_str());
70 std::list<CSdp>::iterator it;
71 if (reccounter>10)
72 return false;
73 LOG_DEBUG("Using rapid");
74 for (it=sdps.begin(); it!=sdps.end(); ++it) {
75 if (match_download_name((*it).getName(),name.length() == 0 ? download->name : name )) {
76
77 LOG_DOWNLOAD((it)->getName().c_str() );
78 if (!(*it).download(download))
79 return false;
80 if ((*it).getDepends().length()>0) {
81 if (!download_name(download,reccounter+1,(*it).getDepends()))
82 return false;
83 }
84 return true;
85 }
86 }
87 return false;
88 }
89
90
91
search(std::list<IDownload * > & result,const std::string & name,IDownload::category cat)92 bool CRapidDownloader::search(std::list<IDownload*>& result, const std::string& name, IDownload::category cat)
93 {
94 LOG_DEBUG("%s",name.c_str());
95 reloadRepos();
96 sdps.sort(list_compare);
97 std::list<CSdp>::iterator it;
98 for (it=sdps.begin(); it!=sdps.end(); ++it) {
99 if (match_download_name((*it).getShortName(),name)
100 || (match_download_name((*it).getName(),name))) {
101 IDownload* dl=new IDownload((*it).getName().c_str(), name, cat, IDownload::TYP_RAPID);
102 dl->addMirror((*it).getShortName().c_str());
103 result.push_back(dl);
104 }
105 }
106 return true;
107 }
108
download(IDownload * download,int)109 bool CRapidDownloader::download(IDownload* download, int /*max_parallel*/)
110 {
111 LOG_DEBUG("%s",download->name.c_str());
112 if (download->dltype != IDownload::TYP_RAPID) { //skip non-rapid downloads
113 LOG_DEBUG("skipping non rapid-dl");
114 return true;
115 }
116 reloadRepos();
117 return download_name(download,0);
118 }
119
match_download_name(const std::string & str1,const std::string & str2)120 bool CRapidDownloader::match_download_name(const std::string &str1,const std::string& str2)
121 {
122 if (str2=="") return true;
123 if (str1==str2) return true;
124 if (str2=="*") return true;
125 //FIXME: add regex support for win32
126 /*
127 #ifndef WIN32
128 regex_t regex;
129 if (regcomp(®ex, str2.c_str(), 0)==0) {
130 int res=regexec(®ex, str1.c_str(),0, NULL, 0 );
131 regfree(®ex);
132 if (res==0) {
133 return true;
134 }
135 }
136 #endif
137 */
138 return false;
139 }
140
setOption(const std::string & key,const std::string & value)141 bool CRapidDownloader::setOption(const std::string& key, const std::string& value)
142 {
143 if (key == "masterurl") {
144 url=value;
145 reposLoaded = false;
146 return true;
147 }
148 if (key == "forceupdate") {
149 reposLoaded = false;
150 return true;
151 }
152 return IDownloader::setOption(key, value);
153 }
154
155
download(const std::string & name)156 void CRapidDownloader::download(const std::string& name)
157 {
158 std::string tmp;
159 if (!urlToPath(name,tmp)){
160 LOG_ERROR("Invalid path: %s", tmp.c_str());
161 return;
162 }
163 path = fileSystem->getSpringDir() + PATH_DELIMITER +"rapid" +PATH_DELIMITER+ tmp;
164 fileSystem->createSubdirs(path);
165 LOG_DEBUG("%s",name.c_str());
166 //first try already downloaded file, as repo master file rarely changes
167 if ((fileSystem->fileExists(path)) && (fileSystem->isOlder(path,REPO_MASTER_RECHECK_TIME)) && parse())
168 return;
169 IDownload dl(path);
170 dl.addMirror(name);
171 httpDownload->download(&dl);
172 parse();
173 }
174
parse()175 bool CRapidDownloader::parse()
176 {
177 FILE* f = fileSystem->propen(path, "rb");
178 gzFile fp=gzdopen(fileno(f), "rb");
179 if (fp==Z_NULL) {
180 LOG_ERROR("Could not open %s", path.c_str());
181 return false;
182 }
183 char buf[IO_BUF_SIZE];
184 repos.clear();
185 int i=0;
186 while (gzgets(fp, buf, sizeof(buf))!=Z_NULL) {
187 std::string tmp=buf;
188 std::string url;
189 getStrByIdx(tmp,url, ',',1);
190 i++;
191 if (url.size()>0) { //create new repo from url
192 CRepo repotmp=CRepo(url, this);
193 repos.push_back(repotmp);
194 } else {
195 LOG_ERROR("Parse Error %s, Line %d: %s",path.c_str(),i,buf);
196 return false;
197 }
198 }
199 gzclose(fp);
200 fclose(f);
201 LOG_INFO("Found %d repos in %s",repos.size(),path.c_str());
202 return true;
203 }
204
updateRepos()205 void CRapidDownloader::updateRepos()
206 {
207 LOG_DEBUG("%s","Updating repos...");
208 download(url);
209 std::list<CRepo>::iterator it;
210 std::list<IDownload*> dls;
211 for (it = repos.begin(); it != repos.end(); ++it) {
212 IDownload* dl = new IDownload();
213 if ((*it).getDownload(*dl)) {
214 dls.push_back(dl);
215 } else {
216 delete dl;
217 }
218 }
219 httpDownload->download(dls);
220 for (it = repos.begin(); it != repos.end(); ++it) {
221 (*it).parse();
222 }
223 IDownloader::freeResult(dls);
224 }
225
226