1 #include "ftp.h"
2 #include "lib/ftplib.h"
3
4 namespace Upp {
5
6 #define LLOGBLOCK(x) // LOGBLOCK(x)
7 #define LLOG(x) // DLOG(x)
8
9 static bool ftpinit = false;
10
FtpClient()11 FtpClient::FtpClient()
12 {
13 ftpconn = NULL;
14 if(!ftpinit) {
15 INTERLOCKED {
16 if(!ftpinit) {
17 FtpInit();
18 ftpinit = true;
19 }
20 }
21 }
22 }
23
~FtpClient()24 FtpClient::~FtpClient()
25 {
26 Close();
27 }
28
IsOpen() const29 bool FtpClient::IsOpen() const
30 {
31 return ftpconn;
32 }
33
Connect(const char * host,const char * user,const char * password,bool pasv,int idletimeout_secs)34 bool FtpClient::Connect(const char *host, const char *user, const char *password, bool pasv, int idletimeout_secs)
35 {
36 LOGBLOCK("FtpClient::Connect");
37 Close();
38 char perror[512];
39 LLOG("FtpConnect(" << host << ")");
40 if(WhenProgress(0,0)) {
41 error = "connect aborted";
42 return false;
43 }
44 if(!FtpConnect(host, &ftpconn, perror, &FtpClient::Callback, this, 200, idletimeout_secs)) {
45 error = perror;
46 return false;
47 }
48 LLOG("FtpLogin(" << user << ", " << password << ")");
49 if(!FtpLogin(user, password, ftpconn)) {
50 error = FtpError(ftpconn);
51 Close();
52 return false;
53 }
54 LLOG("FtpOptions(pasv = " << pasv << ")");
55 if(!FtpOptions(FTPLIB_CONNMODE, pasv ? FTPLIB_PASSIVE : FTPLIB_PORT, ftpconn)) {
56 error = FtpError(ftpconn);
57 Close();
58 return false;
59 }
60 return true;
61 }
62
Callback(netbuf * nControl,int xfered,void * arg)63 int FtpClient::Callback(netbuf *nControl, int xfered, void *arg)
64 {
65 FtpClient *ftp = (FtpClient *)arg;
66 return !ftp->WhenProgress(xfered, ftp->save_total);
67 }
68
Close()69 void FtpClient::Close()
70 {
71 if(ftpconn) {
72 FtpQuit(ftpconn);
73 ftpconn = NULL;
74 }
75 }
76
CheckOpen()77 bool FtpClient::CheckOpen()
78 {
79 if(!IsOpen()) {
80 error = t_("not connected");
81 return false;
82 }
83 return true;
84 }
85
Load(const char * path)86 String FtpClient::Load(const char *path)
87 {
88 LLOGBLOCK("FtpClient::Load");
89 if(!CheckOpen())
90 return String::GetVoid();
91 netbuf *ftpdata;
92 LLOG("FtpAccess(" << path << ")");
93 if(WhenProgress(0,0)) {
94 error = t_("aborted");
95 return String::GetVoid();
96 }
97 if(!FtpAccess(path, FTPLIB_FILE_READ, FTPLIB_IMAGE, ftpconn, &ftpdata)) {
98 error = FtpError(ftpconn);
99 return String::GetVoid();
100 }
101 load_data = Null;
102 while(!WhenProgress(load_data.GetLength(), 0)) {
103 byte buffer[1024];
104 int ndata = FtpRead(buffer, sizeof(buffer), ftpdata);
105 LLOG("FtpRead -> " << ndata);
106 if(ndata < 0) {
107 error = FtpError(ftpdata);
108 FtpClose(ftpdata);
109 return String::GetVoid();
110 }
111 if(ndata == 0) {
112 load_data.Shrink();
113 error = FtpError(ftpdata);
114 break;
115 }
116 load_data.Cat(buffer, ndata);
117 #ifdef SLOWTRANSFER
118 int end = GetTickCount() + SLOWTRANSFER;
119 for(int d; (d = end - GetTickCount()) > 0; Sleep(d))
120 ;
121 #endif
122 }
123 FtpClose(ftpdata);
124 return load_data;
125 }
126
Save(const char * path,String data)127 bool FtpClient::Save(const char *path, String data)
128 {
129 return SaveCount(path, data) == data.GetLength();
130 }
131
SaveCount(const char * path,String data)132 int FtpClient::SaveCount(const char *path, String data)
133 {
134 LLOGBLOCK("FtpClient::Save");
135 netbuf *ftpdata;
136 save_pos = 0;
137 save_total = data.GetLength();
138 if(!CheckOpen())
139 return 0;
140 LLOG("FtpAccess(" << path << ")");
141 if(WhenProgress(0,data.GetLength()))
142 return 0;
143 if(!FtpAccess(path, FTPLIB_FILE_WRITE, FTPLIB_IMAGE, ftpconn, &ftpdata)) {
144 error = FtpError(ftpconn);
145 return 0;
146 }
147 while(save_pos < data.GetLength()) {
148 if(WhenProgress(save_pos, data.GetLength())) {
149 error = NFormat(t_("write aborted after %d bytes(s)"), save_pos);
150 FtpClose(ftpdata);
151 return save_pos;
152 }
153 int chunk = min(data.GetLength() - save_pos, 1024);
154 int ndata = FtpWrite((void *)data.GetIter(save_pos), chunk, ftpdata);
155 LLOG("FtpWrite(" << chunk << ") -> " << ndata);
156 if(ndata <= 0 || ndata > chunk) {
157 error = FtpError(ftpdata);
158 FtpClose(ftpdata);
159 return save_pos;
160 }
161 save_pos += ndata;
162 #ifdef SLOWTRANSFER
163 int end = GetTickCount() + SLOWTRANSFER;
164 for(int d; (d = end - GetTickCount()) > 0; Sleep(d))
165 ;
166 #endif
167 }
168 WhenProgress(save_pos, data.GetLength());
169 LLOG("FtpClose");
170 FtpClose(ftpdata);
171 return save_pos;
172 }
173
Exists(const char * path)174 bool FtpClient::Exists(const char *path) {
175 LLOGBLOCK("FtpClient::Exists");
176 if(!CheckOpen())
177 return false;
178 netbuf *data;
179 LLOG("FtpAccess(" << path << ")");
180 if(!FtpAccess(path, FTPLIB_FILE_READ, FTPLIB_IMAGE, ftpconn, &data)) {
181 error = FtpError(ftpconn);
182 return false;
183 }
184 FtpClose(data);
185 return true;
186 }
187
Rename(const char * oldpath,const char * newpath)188 bool FtpClient::Rename(const char *oldpath, const char *newpath) {
189 LLOGBLOCK("FtpClient::Rename");
190 LLOG("FtpRename(oldname = " << oldpath << ", newname = " << newpath << ")");
191 return CheckOpen() && !!FtpRename(oldpath, newpath, ftpconn);
192 }
193
Cd(const char * path)194 bool FtpClient::Cd(const char *path) {
195 LLOGBLOCK("FtpClient::Cd");
196 LLOG("FtpChdir(" << path << ")");
197 return CheckOpen() && !!FtpChdir(path, ftpconn);
198 }
199
MkDir(const char * path)200 bool FtpClient::MkDir(const char *path) {
201 LLOGBLOCK("FtpClient::MkDir");
202 LLOG("FtpMkdir(" << path << ")");
203 return CheckOpen() && !!FtpMkdir(path, ftpconn);
204 }
205
RmDir(const char * path)206 bool FtpClient::RmDir(const char *path) {
207 LLOGBLOCK("FtpClient::RmDir");
208 LLOG("FtpRmdir(" << path << ")");
209 return CheckOpen() && !!FtpRmdir(path, ftpconn);
210 }
211
Delete(const char * path)212 bool FtpClient::Delete(const char *path) {
213 LLOGBLOCK("FtpClient::Delete");
214 LLOG("FtpDelete(" << path << ")");
215 return CheckOpen() && !!FtpDelete(path, ftpconn);
216 }
217
List(const char * path)218 String FtpClient::List(const char *path)
219 {
220 LLOGBLOCK("FtpClient::List");
221 load_data = Null;
222 if(!CheckOpen())
223 return String::GetVoid();
224 netbuf *ftpdata;
225 LLOG("FtpAccess(" << path << ")");
226 if(WhenProgress(0,0)) {
227 error = t_("aborted");
228 return String::GetVoid();
229 }
230 if(!FtpAccess(path, FTPLIB_DIR, FTPLIB_ASCII, ftpconn, &ftpdata)) {
231 error = FtpError(ftpconn);
232 return String::GetVoid();
233 }
234 while(!WhenProgress(load_data.GetLength(),0)) {
235 byte buffer[1024];
236 int ndata = FtpRead(buffer, sizeof(buffer), ftpdata);
237 LLOG("FtpRead -> " << ndata);
238 if(ndata < 0) {
239 error = FtpError(ftpdata);
240 FtpClose(ftpdata);
241 return String::GetVoid();
242 }
243 if(ndata == 0) {
244 load_data.Shrink();
245 break;
246 }
247 load_data.Cat(buffer, ndata);
248 #ifdef SLOWTRANSFER
249 int end = GetTickCount() + SLOWTRANSFER;
250 for(int d; (d = end - GetTickCount()) > 0; Sleep(d))
251 ;
252 #endif
253 }
254 FtpClose(ftpdata);
255 return load_data;
256 }
257
RealizePath(const char * path)258 void FtpClient::RealizePath(const char *path)
259 {
260 LLOGBLOCK("FtpClient::RealizePath");
261 const char *s = path;
262 if(*s == '\0') return;
263 for(;;) {
264 s = strchr(s + 1, '/');
265 if(!s) break;
266 MkDir(String(path, s));
267 }
268 }
269
FtpClientGet(String url,String * error)270 String FtpClientGet(String url, String *error)
271 {
272 const char *u = url, *t = u;
273 while(*t && *t != '?')
274 if(*t++ == '/') {
275 if(*t == '/')
276 u = ++t;
277 break;
278 }
279 t = u;
280 while(*u && *u != '@' && *u != '/')
281 u++;
282 String host = String(t, u);
283 String user, pwd;
284 if(*u == '@') {
285 t = ++u;
286 while(*u && *u != '/' && *u != ':')
287 u++;
288 user = String(t, u);
289 if(*u == ':') {
290 t = ++u;
291 while(*u && *u != '/')
292 u++;
293 pwd = String(t, u);
294 }
295 }
296 FtpClient ftp;
297 if(!ftp.Connect(host, user, pwd)) {
298 if(error)
299 *error = ftp.GetError();
300 return String::GetVoid();
301 }
302 String data = ftp.Load(u);
303 if(data.IsVoid()) {
304 if(error)
305 *error = ftp.GetError();
306 }
307 return data;
308 }
309
310 }
311