"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "qftp-0.98/ftpconn.cc" of archive qftp-0.98.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * qftp
3 * Copyright (C) 1997,1998 Peter Strand
4 * Distributed under the GNU Pulic Licence
5 */
6
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <time.h>
16 #include <ctype.h>
17
18 #include "net.h"
19 #include "ftpconn.h"
20 #include "misc.h"
21
22
23 FtpConn::FtpConn()
24 {
25 ctrl = new Socket;
26 data = NULL;
27 cwdch = 1;
28 conn = 0;
29 }
30
31 FtpConn::~FtpConn()
32 {
33 }
34
35 int FtpConn::Connect(char *host)
36 {
37 Host h(host);
38 if (!ctrl)
39 ctrl = new Socket;
40 cwdch = 1;
41 if (ctrl->Connect(h))
42 return -1;
43 if (!GetReply())
44 return 1;
45 conn = 1;
46 return 0;
47 }
48
49 void FtpConn::Close()
50 {
51 if (conn) {
52 Cmd("QUIT");
53 GetReply();
54 }
55 conn = 0;
56 if (ctrl) {
57 ctrl->Close();
58 ctrl = NULL;
59 }
60 if (data) {
61 data->Close();
62 data = NULL;
63 }
64 }
65
66 int FtpConn::Cmd(char *cm, char *arg = NULL)
67 {
68 char buf[1024];
69
70 if (arg && *arg)
71 sprintf(buf, "%s %s", cm, arg);
72 else
73 sprintf(buf, "%s", cm);
74 if (ctrl->Writeln(buf))
75 return -1;
76 return GetReply();
77 }
78
79 int FtpConn::GetReply()
80 {
81 int i;
82
83 if (ctrl->Readln(retmsg) == -1)
84 return -1;
85 retval = atoi(retmsg);
86 i = 0;
87 if (retmsg[3] == '-') {
88 do {
89 i += strlen(&retmsg[i]);
90 if (ctrl->Readln(&retmsg[i]) == -1)
91 return -1;
92 } while ((atoi(&retmsg[i]) == retval)?(retmsg[i + 3] == '-'):1);
93 }
94 i += strlen(retmsg);
95 return retval;
96 }
97
98 int FtpConn::Get(char *s, int fd, void (*cbf)(int,char *t=NULL) = NULL)
99 {
100 Socket *ns;
101 char buf[4096];
102 int n;
103
104 data = new Socket(ctrl);
105 if (data->Listen() == -1)
106 return -1;
107 if ((unsigned)Port() >= 400)
108 return -1;
109
110 if ((unsigned)Cmd("RETR", s) >= 400)
111 return -1;
112
113 if (!(ns = data->Accept()))
114 return -1;
115 if (cbf)
116 cbf(-1, s);
117 while ((n = ns->Read(buf, 4096))) {
118 write(fd, buf, n);
119 if (cbf)
120 cbf(n);
121 }
122 delete ns;
123 delete data;
124 return (GetReply() == -1)?-1:0;
125 }
126
127
128 int FtpConn::Put(char *s, int fd, void (*cbf)(int,char *t=NULL) = NULL)
129 {
130 Socket *ns;
131 char buf[4096];
132 int n;
133
134 data = new Socket(ctrl);
135 if (data->Listen() == -1)
136 return -1;
137 if ((unsigned)Port() >= 400)
138 return -1;
139
140 if ((unsigned)Cmd("STOR", s) >= 400)
141 return -1;
142
143 if (!(ns = data->Accept()))
144 return -1;
145 if (cbf)
146 cbf(-1,s);
147 while ((n = read(fd, buf, 4096)) > 0) {
148 ns->Write(buf, n);
149 if (cbf)
150 cbf(n);
151 }
152 delete ns;
153 delete data;
154 return (GetReply() == -1)?-1:0;
155 }
156
157
158 int FtpConn::Quote(char *s)
159 {
160 return Cmd(s, NULL);
161 }
162
163 int FtpConn::Cd(char *s = NULL)
164 {
165 cwdch = 1;
166 return Cmd("CWD", s);
167 }
168
169 int FtpConn::Size(char *s)
170 {
171 return Cmd("SIZE", s);
172 }
173
174 int FtpConn::MTime(char *s, time_t &t)
175 {
176 struct tm tmb;
177
178 if (Cmd("MDTM", s) > 300)
179 return -1;
180
181 tmb.tm_year = (retmsg[6] - 0x30) * 10 + retmsg[7] - 0x30;
182 tmb.tm_mon = (retmsg[8] - 0x30) * 10 + retmsg[9] - 0x31;
183 tmb.tm_mday = (retmsg[10] - 0x30) * 10 + retmsg[11] - 0x30;
184 tmb.tm_hour = (retmsg[12] - 0x30) * 10 + retmsg[13] - 0x31;
185 tmb.tm_min = (retmsg[14] - 0x30) * 10 + retmsg[15] - 0x30;
186 tmb.tm_sec = (retmsg[16] - 0x30) * 10 + retmsg[17] - 0x30;
187 t = mktime(&tmb);
188 return 0;
189 }
190
191 int FtpConn::Login(char *user, char *pass)
192 {
193 if ((unsigned)Cmd("USER", user) >= 400)
194 return -1;
195 if ((unsigned)Cmd("PASS", (*pass)?pass:"") >= 400)
196 return -1;
197 return 0;
198 }
199
200 DirList *FtpConn::clookup(char *s)
201 {
202 int i, n;
203
204 n = cache.size();
205 for (i = 0;i < n;i++)
206 if (!strcmp(cache[i]->path, s))
207 return cache[i];
208 return NULL;
209 }
210
211 void FtpConn::cset(char *s, DirList *dl)
212 {
213 int i, n;
214
215 n = cache.size();
216 for (i = 0;i < n;i++)
217 if (!strcmp(cache[i]->path, s))
218 break;
219 if (n == i) {
220 dl->path = strdup(s);
221 cache.push_back(dl);
222 } else {
223 free(cache[i]->path);
224 cache[i] = dl;
225 cache[i]->path = strdup(s);
226 }
227 }
228
229 int FtpConn::List(DirList &dl, char *s)
230 {
231 Entry e;
232 int i;
233 char *p, path[256];
234
235 DirList *t;
236
237 p = split(GetCwd(), s, path);
238
239 if (!(t = clookup(path))) {
240 t = new DirList;
241 list(t, path);
242 cset(path, t);
243 }
244 t->Reset();
245 i = 0;
246 while (!i && t->GetNext(e))
247 if (!strcmp(e.name, p))
248 i++;
249 if (i && e.type == 'd') {
250 strcat(path, "/");
251 strcat(path, p);
252 if (!(t = clookup(path))) {
253 t = new DirList;
254 list(t, path);
255 cset(path, t);
256 }
257 p = "";
258 }
259 t = clookup(path);
260 dl = *t;
261 return 0;
262 }
263
264
265 int FtpConn::list(DirList *dl, char *path)
266 {
267 Socket *ns;
268 char buf[500];
269 int i;
270 Entry e;
271 data = new Socket(ctrl);
272 if (data->Listen() == -1)
273 return -1;
274 if ((unsigned)Port() >= 400)
275 return -1;
276 if ((unsigned)Cmd("NLST -Fa", path) >= 400)
277 return -1;
278 if (!(ns = data->Accept()))
279 return -1;
280 dl->Flush();
281 dl->isused = 1;
282 if (!ns->Readln(buf))
283 return -1;
284 if (!ns->Readln(buf))
285 return -1;
286 while ((i = ns->Readln(buf))) {
287 if (i == -1)
288 return -1;
289 i = strlen(buf) - 1;
290 if (buf[i] == '\n' || buf[i] == '\r') {
291 buf[i] = 0;
292 i--;
293 }
294 if (buf[i] == '\n' || buf[i] == '\r') {
295 buf[i] = 0;
296 i--;
297 }
298 e.type = '-';
299 if (buf[i] == '/' || buf[i] == '*' || buf[i] == '@') {
300 if (buf[i] == '/')
301 e.type = 'd';
302 else if (buf[i] == '@')
303 e.type = 'l';
304 buf[i] = 0;
305 }
306 e.name = strdup(buf);
307 e.perm = -1;
308 e.date = NULL;
309 e.user = NULL;
310 e.group = NULL;
311 e.size = -1;
312 dl->Add(e);
313 }
314 GetReply();
315 delete ns;
316 delete data;
317 data = NULL;
318 return 0;
319 }
320
321 int FtpConn::LongList(DirList &dl, char *s = NULL)
322 {
323 Entry e;
324 int i;
325 char *p, path[256];
326
327 DirList *t;
328
329 p = split(GetCwd(), s, path);
330
331 if (!(t = clookup(path)) || !t->islong) {
332 t = new DirList;
333 longList(t, path);
334 cset(path, t);
335 }
336 t->Reset();
337 i = 0;
338 while (!i && t->GetNext(e))
339 if (!strcmp(e.name, p))
340 i++;
341 if (i && e.type == 'd') {
342 strcat(path, "/");
343 strcat(path, p);
344 if (!(t = clookup(path)) || !t->islong) {
345 t = new DirList;
346 longList(t, path);
347 cset(path, t);
348 }
349 p = "";
350 }
351 t = clookup(path);
352 dl = *t;
353 return 0;
354 }
355
356 int FtpConn::longList(DirList *dl, char *s = NULL)
357 {
358 Socket *ns;
359 char buf[500], *p1, *p2;
360 Entry e;
361 int i;
362
363 data = new Socket(ctrl);
364 if (data->Listen() == -1)
365 return -1;
366 if ((unsigned)Port() >= 400)
367 return -1;
368 if ((unsigned)Cmd("LIST -a", s) >= 400)
369 return -1;
370 if (!(ns = data->Accept()))
371 return -1;
372 if (!ns->Readln(buf))
373 return -1;
374 if (!ns->Readln(buf))
375 return -1;
376 if (!ns->Readln(buf))
377 return -1;
378 dl->Flush();
379 while ((i = ns->Readln(buf))) {
380 if (i == -1)
381 return -1;
382 i = strlen(buf) - 1;
383 if (buf[i] == '\n' || buf[i] == '\r') {
384 buf[i] = 0;
385 i--;
386 }
387 if (buf[i] == '\n' || buf[i] == '\r') {
388 buf[i] = 0;
389 i--;
390 }
391 e.type = buf[0];
392 e.perm = 0;
393 if (buf[1] == 'r')
394 e.perm |= 0400;
395 if (buf[2] == 'w')
396 e.perm |= 0200;
397 if (buf[3] == 'x')
398 e.perm |= 0100;
399 if (buf[4] == 'r')
400 e.perm |= 0040;
401 if (buf[5] == 'w')
402 e.perm |= 0020;
403 if (buf[6] == 'x')
404 e.perm |= 0010;
405 if (buf[7] == 'r')
406 e.perm |= 0004;
407 if (buf[8] == 'w')
408 e.perm |= 0002;
409 if (buf[9] == 'x')
410 e.perm |= 0001;
411 if (buf[3] == 's')
412 e.perm |= 04000;
413 if (buf[6] == 's')
414 e.perm |= 02000;
415 if (buf[9] == 's')
416 e.perm |= 01000;
417 p1 = &buf[10];
418
419 while (isspace(*p1)) p1++; while (!isspace(*p1)) p1++;
420 buf[10] = 0;
421 e.perms = strdup(buf);
422 while (isspace(*p1)) p1++; p2 = p1; while (!isspace(*p2)) p2++; *p2 = 0;
423 e.user = strdup(p1);
424 p1 = p2 + 1;
425
426 while (isspace(*p1)) p1++; p2 = p1; while (!isspace(*p2)) p2++; *p2 = 0;
427 e.group = strdup(p1);
428 p1 = p2 + 1;
429
430 while (isspace(*p1)) p1++; p2 = p1; while (!isspace(*p2)) p2++; *p2 = 0;
431 e.size = atol(p1);
432 p1 = p2 + 1;
433
434 while (isspace(*p1)) p1++;
435 p2 = p1;
436 while (!isspace(*p2)) p2++; while (isspace(*p2)) p2++;
437 while (!isspace(*p2)) p2++; while (isspace(*p2)) p2++;
438 while (!isspace(*p2)) p2++; while (isspace(*p2)) p2++;
439 *--p2 = 0;
440 e.date = strdup(p1);
441 p1 = p2 + 1;
442 while (isspace(*p1))
443 p1++;
444 p2 = p1;
445 while (*p2 && !isspace(*p2))
446 p2++;
447 *p2 = 0;
448 e.name = strdup(p1);
449 dl->Add(e);
450 }
451 dl->islong = 1;
452 delete ns;
453 delete data;
454 data = NULL;
455 return (GetReply() == -1)?-1:0;
456 }
457
458
459 char *FtpConn::GetHost()
460 {
461 return ctrl->GetRHost();
462 }
463
464 char *FtpConn::GetMsg()
465 {
466 return retmsg;
467 }
468
469 const char *FtpConn::GetError()
470 {
471 return ctrl->GetError();
472 }
473
474 char *FtpConn::GetCwd()
475 {
476 char *p;
477 int i;
478 if (cwdch) {
479 if ((unsigned)Cmd("PWD") >= 400)
480 return "";
481 p = strchr(retmsg, '"') + 1;
482 i = 0;
483 while ((cwd[i++] = *p++) != '"');
484 cwd[i - 1] = 0;
485 }
486 cwdch = 0;
487 return cwd;
488 }
489
490 int FtpConn::Port()
491 {
492 char buf[500];
493 long badr, bp;
494 badr = ntohl(data->GetLAddr());
495 bp = ntohs(data->GetLPort());
496 sprintf(buf, "%d,%d,%d,%d,%d,%d", (int) (badr >> 24) & 0xff,
497 (int) (badr >> 16) & 0xff, (int) (badr >> 8) & 0xff,
498 (int) badr & 0xff, (int) (bp >> 8) & 0xff, (int) bp & 0xff);
499 return Cmd("PORT", buf);
500 }
501