|
@@ -1,3 +1,22 @@
|
|
1
|
+/*
|
|
2
|
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
|
3
|
+ *
|
|
4
|
+ * This program is free software; you can redistribute it and/or
|
|
5
|
+ * modify it under the terms of the GNU General Public License as
|
|
6
|
+ * published by the Free Software Foundation; either version 2 of the
|
|
7
|
+ * License, or any later version.
|
|
8
|
+ *
|
|
9
|
+ * This program is distributed in the hope that it will be useful, but
|
|
10
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+ * General Public License for more details.
|
|
13
|
+ *
|
|
14
|
+ * You should have received a copy of the GNU General Public License
|
|
15
|
+ * along with this program; if not, write to the Free Software
|
|
16
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
17
|
+ * 02110-1301, USA.
|
|
18
|
+ */
|
|
19
|
+
|
1
|
20
|
#include <stdint.h>
|
2
|
21
|
#include <stdlib.h>
|
3
|
22
|
#include <stdio.h>
|
|
@@ -34,6 +53,7 @@ enum ftp_state {
|
34
|
53
|
FTP_USER,
|
35
|
54
|
FTP_PASS,
|
36
|
55
|
FTP_TYPE,
|
|
56
|
+ FTP_SIZE,
|
37
|
57
|
FTP_PASV,
|
38
|
58
|
FTP_RETR,
|
39
|
59
|
FTP_WAIT,
|
|
@@ -68,6 +88,8 @@ struct ftp_request {
|
68
|
88
|
char status_text[5];
|
69
|
89
|
/** Passive-mode parameters, as text */
|
70
|
90
|
char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
|
|
91
|
+ /** File size, as text */
|
|
92
|
+ char filesize[20];
|
71
|
93
|
};
|
72
|
94
|
|
73
|
95
|
/**
|
|
@@ -157,6 +179,7 @@ static struct ftp_control_string ftp_strings[] = {
|
157
|
179
|
[FTP_USER] = { "USER ", ftp_user },
|
158
|
180
|
[FTP_PASS] = { "PASS ", ftp_password },
|
159
|
181
|
[FTP_TYPE] = { "TYPE I", NULL },
|
|
182
|
+ [FTP_SIZE] = { "SIZE ", ftp_uri_path },
|
160
|
183
|
[FTP_PASV] = { "PASV", NULL },
|
161
|
184
|
[FTP_RETR] = { "RETR ", ftp_uri_path },
|
162
|
185
|
[FTP_WAIT] = { NULL, NULL },
|
|
@@ -234,6 +257,14 @@ static void ftp_reply ( struct ftp_request *ftp ) {
|
234
|
257
|
if ( status_major == '1' )
|
235
|
258
|
return;
|
236
|
259
|
|
|
260
|
+ /* If the SIZE command is not supported by the server, we go to
|
|
261
|
+ * the next step.
|
|
262
|
+ */
|
|
263
|
+ if ( ( status_major == '5' ) && ( ftp->state == FTP_SIZE ) ) {
|
|
264
|
+ ftp_next_state ( ftp );
|
|
265
|
+ return;
|
|
266
|
+ }
|
|
267
|
+
|
237
|
268
|
/* Anything other than success (2xx) or, in the case of a
|
238
|
269
|
* repsonse to a "USER" command, a password prompt (3xx), is a
|
239
|
270
|
* fatal error.
|
|
@@ -245,6 +276,26 @@ static void ftp_reply ( struct ftp_request *ftp ) {
|
245
|
276
|
return;
|
246
|
277
|
}
|
247
|
278
|
|
|
279
|
+ /* Parse file size */
|
|
280
|
+ if ( ftp->state == FTP_SIZE ) {
|
|
281
|
+ size_t filesize;
|
|
282
|
+ char *endptr;
|
|
283
|
+
|
|
284
|
+ /* Parse size */
|
|
285
|
+ filesize = strtoul ( ftp->filesize, &endptr, 10 );
|
|
286
|
+ if ( *endptr != '\0' ) {
|
|
287
|
+ DBGC ( ftp, "FTP %p invalid SIZE \"%s\"\n",
|
|
288
|
+ ftp, ftp->filesize );
|
|
289
|
+ ftp_done ( ftp, -EPROTO );
|
|
290
|
+ return;
|
|
291
|
+ }
|
|
292
|
+
|
|
293
|
+ /* Use seek() to notify recipient of filesize */
|
|
294
|
+ DBGC ( ftp, "FTP %p file size is %zd bytes\n", ftp, filesize );
|
|
295
|
+ xfer_seek ( &ftp->xfer, filesize );
|
|
296
|
+ xfer_seek ( &ftp->xfer, 0 );
|
|
297
|
+ }
|
|
298
|
+
|
248
|
299
|
/* Open passive connection when we get "PASV" response */
|
249
|
300
|
if ( ftp->state == FTP_PASV ) {
|
250
|
301
|
char *ptr = ftp->passive_text;
|
|
@@ -295,35 +346,33 @@ static int ftp_control_deliver ( struct ftp_request *ftp,
|
295
|
346
|
|
296
|
347
|
while ( len-- ) {
|
297
|
348
|
c = *(data++);
|
298
|
|
- switch ( c ) {
|
299
|
|
- case '\r' :
|
300
|
|
- case '\n' :
|
|
349
|
+ if ( ( c == '\r' ) || ( c == '\n' ) ) {
|
301
|
350
|
/* End of line: call ftp_reply() to handle
|
302
|
351
|
* completed reply. Avoid calling ftp_reply()
|
303
|
352
|
* twice if we receive both \r and \n.
|
304
|
353
|
*/
|
305
|
|
- if ( recvsize == 0 )
|
|
354
|
+ if ( recvbuf != ftp->status_text )
|
306
|
355
|
ftp_reply ( ftp );
|
307
|
356
|
/* Start filling up the status code buffer */
|
308
|
357
|
recvbuf = ftp->status_text;
|
309
|
358
|
recvsize = sizeof ( ftp->status_text ) - 1;
|
310
|
|
- break;
|
311
|
|
- case '(' :
|
|
359
|
+ } else if ( ( ftp->state == FTP_PASV ) && ( c == '(' ) ) {
|
312
|
360
|
/* Start filling up the passive parameter buffer */
|
313
|
361
|
recvbuf = ftp->passive_text;
|
314
|
362
|
recvsize = sizeof ( ftp->passive_text ) - 1;
|
315
|
|
- break;
|
316
|
|
- case ')' :
|
|
363
|
+ } else if ( ( ftp->state == FTP_PASV ) && ( c == ')' ) ) {
|
317
|
364
|
/* Stop filling the passive parameter buffer */
|
318
|
365
|
recvsize = 0;
|
319
|
|
- break;
|
320
|
|
- default :
|
|
366
|
+ } else if ( ( ftp->state == FTP_SIZE ) && ( c == ' ' ) ) {
|
|
367
|
+ /* Start filling up the file size buffer */
|
|
368
|
+ recvbuf = ftp->filesize;
|
|
369
|
+ recvsize = sizeof ( ftp->filesize ) - 1;
|
|
370
|
+ } else {
|
321
|
371
|
/* Fill up buffer if applicable */
|
322
|
372
|
if ( recvsize > 0 ) {
|
323
|
373
|
*(recvbuf++) = c;
|
324
|
374
|
recvsize--;
|
325
|
375
|
}
|
326
|
|
- break;
|
327
|
376
|
}
|
328
|
377
|
}
|
329
|
378
|
|