Dean Bell / Mbed 2 deprecated FTP_Server_D1

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ftpd.c Source File

ftpd.c

00001 /*
00002  * Copyright (c) 2002 Florian Schulze.
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the authors nor the names of the contributors
00015  *    may be used to endorse or promote products derived from this software
00016  *    without specific prior written permission.
00017  * 
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
00022  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00023  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00024  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00026  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00027  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * ftpd.c - This file is part of the FTP daemon for lwIP
00031  *
00032  */
00033 
00034 #include "mbed.h"                  // DRB
00035 #include "SDFileSystem.h"          // DRB
00036 #include "EthernetNetIf.h"
00037 #include "HTTPServer.h"
00038 
00039 #include "lwip/debug.h"
00040 
00041 #include "lwip/stats.h"
00042 
00043 #include "ftpd.h"
00044 
00045 #include "lwip/tcp.h"
00046 
00047 #include <stdio.h>
00048 #include <stdarg.h>
00049 //..#include <malloc.h>
00050 #ifdef _WIN32
00051 #include <string.h>
00052 #endif
00053 #include <ctype.h>
00054 #include <errno.h>
00055 #include <time.h>
00056 
00057 #include "vfs.h"
00058 }
00059 
00060 
00061 extern void printit( char *p_buf );
00062 
00063 
00064 #ifdef FTPD_DEBUG
00065 int dbg_printf(const char *fmt, ...);
00066 #else
00067 #ifdef _MSC_VER
00068 #define dbg_printf(x) /* x */
00069 #else
00070 #define dbg_printf(f, ...) /* */
00071 #endif
00072 #endif
00073 
00074 #define msg110 "110 MARK %s = %s."
00075 /*
00076          110 Restart marker reply.
00077              In this case, the text is exact and not left to the
00078              particular implementation; it must read:
00079                   MARK yyyy = mmmm
00080              Where yyyy is User-process data stream marker, and mmmm
00081              server's equivalent marker (note the spaces between markers
00082              and "=").
00083 */
00084 #define msg120 "120 Service ready in nnn minutes."
00085 #define msg125 "125 Data connection already open; transfer starting."
00086 #define msg150 "150 File status okay; about to open data connection."
00087 #define msg150recv "150 Opening BINARY mode data connection for %s (%i bytes)."
00088 #define msg150stor "150 Opening BINARY mode data connection for %s."
00089 #define msg200 "200 Command okay."
00090 #define msg202 "202 Command not implemented, superfluous at this site."
00091 #define msg211 "211 System status, or system help reply."
00092 #define msg212 "212 Directory status."
00093 #define msg213 "213 File status."
00094 #define msg214 "214 %s."
00095 /*
00096              214 Help message.
00097              On how to use the server or the meaning of a particular
00098              non-standard command.  This reply is useful only to the
00099              human user.
00100 */
00101 #define msg214SYST "214 %s system type."
00102 /*
00103          215 NAME system type.
00104              Where NAME is an official system name from the list in the
00105              Assigned Numbers document.
00106 */
00107 #define msg220 "220 lwIP FTP Server ready."
00108 /*
00109          220 Service ready for new user.
00110 */
00111 #define msg221 "221 Goodbye."
00112 /*
00113          221 Service closing control connection.
00114              Logged out if appropriate.
00115 */
00116 #define msg225 "225 Data connection open; no transfer in progress."
00117 #define msg226 "226 Closing data connection."
00118 /*
00119              Requested file action successful (for example, file
00120              transfer or file abort).
00121 */
00122 #define msg227 "227 Entering Passive Mode (%i,%i,%i,%i,%i,%i)."
00123 /*
00124          227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
00125 */
00126 #define msg230 "230 User logged in, proceed."
00127 #define msg250 "250 Requested file action okay, completed."
00128 #define msg257PWD "257 \"%s\" is current directory."
00129 #define msg257 "257 \"%s\" created."
00130 /*
00131          257 "PATHNAME" created.
00132 */
00133 #define msg331 "331 User name okay, need password."
00134 #define msg332 "332 Need account for login."
00135 #define msg350 "350 Requested file action pending further information."
00136 #define msg421 "421 Service not available, closing control connection."
00137 /*
00138              This may be a reply to any command if the service knows it
00139              must shut down.
00140 */
00141 #define msg425 "425 Can't open data connection."
00142 #define msg426 "426 Connection closed; transfer aborted."
00143 #define msg450 "450 Requested file action not taken."
00144 /*
00145              File unavailable (e.g., file busy).
00146 */
00147 #define msg451 "451 Requested action aborted: local error in processing."
00148 #define msg452 "452 Requested action not taken."
00149 /*
00150              Insufficient storage space in system.
00151 */
00152 #define msg500 "500 Syntax error, command unrecognized."
00153 /*
00154              This may include errors such as command line too long.
00155 */
00156 #define msg501 "501 Syntax error in parameters or arguments."
00157 #define msg502 "502 Command not implemented."
00158 #define msg503 "503 Bad sequence of commands."
00159 #define msg504 "504 Command not implemented for that parameter."
00160 #define msg530 "530 Not logged in."
00161 #define msg532 "532 Need account for storing files."
00162 #define msg550 "550 Requested action not taken."
00163 /*
00164              File unavailable (e.g., file not found, no access).
00165 */
00166 #define msg551 "551 Requested action aborted: page type unknown."
00167 #define msg552 "552 Requested file action aborted."
00168 /*
00169              Exceeded storage allocation (for current directory or
00170              dataset).
00171 */
00172 #define msg553 "553 Requested action not taken."
00173 /*
00174              File name not allowed.
00175 */
00176 
00177 enum ftpd_state_e {
00178     FTPD_USER,
00179     FTPD_PASS,
00180     FTPD_IDLE,
00181     FTPD_NLST,
00182     FTPD_LIST,
00183     FTPD_RETR,
00184     FTPD_RNFR,
00185     FTPD_STOR,
00186     FTPD_QUIT
00187 };
00188 
00189 static const char *month_table[12] = {
00190     "Jan",
00191     "Feb",
00192     "Mar",
00193     "Apr",
00194     "May",
00195     "Jun",
00196     "Jul",
00197     "Aug",
00198     "Sep",
00199     "Oct",
00200     "Nov",
00201     "Dez"
00202 };
00203 
00204 /*
00205 ------------------------------------------------------------
00206     SFIFO 1.3
00207 ------------------------------------------------------------
00208  * Simple portable lock-free FIFO
00209  * (c) 2000-2002, David Olofson
00210  *
00211  * Platform support:
00212  *    gcc / Linux / x86:        Works
00213  *    gcc / Linux / x86 kernel:    Works
00214  *    gcc / FreeBSD / x86:        Works
00215  *    gcc / NetBSD / x86:        Works
00216  *    gcc / Mac OS X / PPC:        Works
00217  *    gcc / Win32 / x86:        Works
00218  *    Borland C++ / DOS / x86RM:    Works
00219  *    Borland C++ / Win32 / x86PM16:    Untested
00220  *    ? / Various Un*ces / ?:        Untested
00221  *    ? / Mac OS / PPC:        Untested
00222  *    gcc / BeOS / x86:        Untested
00223  *    gcc / BeOS / PPC:        Untested
00224  *    ? / ? / Alpha:            Untested
00225  *
00226  * 1.2: Max buffer size halved, to avoid problems with
00227  *    the sign bit...
00228  *
00229  * 1.3:    Critical buffer allocation bug fixed! For certain
00230  *    requested buffer sizes, older version would
00231  *    allocate a buffer of insufficient size, which
00232  *    would result in memory thrashing. (Amazing that
00233  *    I've manage to use this to the extent I have
00234  *    without running into this... *heh*)
00235  */
00236 
00237 /*
00238  * Porting note:
00239  *    Reads and writes of a variable of this type in memory
00240  *    must be *atomic*! 'int' is *not* atomic on all platforms.
00241  *    A safe type should be used, and  sfifo should limit the
00242  *    maximum buffer size accordingly.
00243  */
00244 typedef int sfifo_atomic_t;
00245 #ifdef __TURBOC__
00246 #    define    SFIFO_MAX_BUFFER_SIZE    0x7fff
00247 #else /* Kludge: Assume 32 bit platform */
00248 #    define    SFIFO_MAX_BUFFER_SIZE    0x7fffffff
00249 #endif
00250 
00251 typedef struct sfifo_t
00252 {
00253     char *buffer;
00254     int size;            /* Number of bytes */
00255     sfifo_atomic_t readpos;        /* Read position */
00256     sfifo_atomic_t writepos;    /* Write position */
00257 } sfifo_t;
00258 
00259 #define SFIFO_SIZEMASK(x)    ((x)->size - 1)
00260 
00261 #define sfifo_used(x)    (((x)->writepos - (x)->readpos) & SFIFO_SIZEMASK(x))
00262 #define sfifo_space(x)    ((x)->size - 1 - sfifo_used(x))
00263 
00264 //..DRB #define DBG(x)
00265 
00266 /*
00267  * Alloc buffer, init FIFO etc...
00268  */
00269 static int sfifo_init(sfifo_t *f, int size)
00270 {
00271     memset(f, 0, sizeof(sfifo_t));
00272 
00273     if(size > SFIFO_MAX_BUFFER_SIZE)
00274         return -EINVAL;
00275 
00276     /*
00277      * Set sufficient power-of-2 size.
00278      *
00279      * No, there's no bug. If you need
00280      * room for N bytes, the buffer must
00281      * be at least N+1 bytes. (The fifo
00282      * can't tell 'empty' from 'full'
00283      * without unsafe index manipulations
00284      * otherwise.)
00285      */
00286     f->size = 1;
00287     for(; f->size <= size; f->size <<= 1)
00288         ;
00289 
00290     /* Get buffer */
00291     if( 0 == (f->buffer = (char *)malloc(f->size)) )
00292         return -ENOMEM;
00293 
00294     return 0;
00295 }
00296 
00297 /*
00298  * Dealloc buffer etc...
00299  */
00300 static void sfifo_close(sfifo_t *f)
00301 {
00302     if(f->buffer)
00303         free(f->buffer);
00304 }
00305 
00306 /*
00307  * Empty FIFO buffer
00308  */
00309 static void sfifo_flush(sfifo_t *f)
00310 {
00311     /* Reset positions */
00312     f->readpos = 0;
00313     f->writepos = 0;
00314 }
00315 
00316 /*
00317  * Write bytes to a FIFO
00318  * Return number of bytes written, or an error code
00319  */
00320 static int sfifo_write(sfifo_t *f, const void *_buf, int len)
00321 {
00322     int total;
00323     int i;
00324     const char *buf = (const char *)_buf;
00325 
00326     if(!f->buffer)
00327         return -ENODEV;    /* No buffer! */
00328 
00329     /* total = len = min(space, len) */
00330     total = sfifo_space(f);
00331     DBG(dbg_printf("sfifo_space() = %d\n",total));
00332     if(len > total)
00333         len = total;
00334     else
00335         total = len;
00336 
00337     i = f->writepos;
00338     if(i + len > f->size)
00339     {
00340         memcpy(f->buffer + i, buf, f->size - i);
00341         buf += f->size - i;
00342         len -= f->size - i;
00343         i = 0;
00344     }
00345     memcpy(f->buffer + i, buf, len);
00346     f->writepos = i + len;
00347 
00348     return total;
00349 }
00350 
00351 /*
00352  * Read bytes from a FIFO
00353  * Return number of bytes read, or an error code
00354  */
00355 static int sfifo_read(sfifo_t *f, void *_buf, int len)
00356 {
00357     int total;
00358     int i;
00359     char *buf = (char *)_buf;
00360 
00361     if(!f->buffer)
00362         return -ENODEV;    /* No buffer! */
00363 
00364     /* total = len = min(used, len) */
00365     total = sfifo_used(f);
00366     DBG(dbg_printf("sfifo_used() = %d\n",total));
00367     if(len > total)
00368         len = total;
00369     else
00370         total = len;
00371 
00372     i = f->readpos;
00373     if(i + len > f->size)
00374     {
00375         memcpy(buf, f->buffer + i, f->size - i);
00376         buf += f->size - i;
00377         len -= f->size - i;
00378         i = 0;
00379     }
00380     memcpy(buf, f->buffer + i, len);
00381     f->readpos = i + len;
00382 
00383     return total;
00384 }
00385 
00386 struct ftpd_datastate {
00387     int connected;
00388     vfs_dir_t *vfs_dir;
00389     vfs_dirent_t *vfs_dirent;
00390     vfs_file_t *vfs_file;
00391     sfifo_t fifo;
00392     struct tcp_pcb *msgpcb;
00393     struct ftpd_msgstate *msgfs;
00394 };
00395 
00396 struct ftpd_msgstate {
00397     enum ftpd_state_e state;
00398     sfifo_t fifo;
00399     vfs_t *vfs;
00400     struct ip_addr dataip;
00401     u16_t dataport;
00402     struct tcp_pcb *datapcb;
00403     struct ftpd_datastate *datafs;
00404     int passive;
00405     char *renamefrom;
00406 };
00407 
00408 static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg, ...);
00409 
00410 static void ftpd_dataerr(void *arg, err_t err)
00411 {
00412     struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg;
00413 
00414     dbg_printf("ftpd_dataerr: %s (%i)\n", lwip_strerr(err), err);
00415     if (fsd == NULL)
00416         return;
00417     fsd->msgfs->datafs = NULL;
00418     fsd->msgfs->state = FTPD_IDLE;
00419     free(fsd);
00420 }
00421 
00422 static void ftpd_dataclose(struct tcp_pcb *pcb, struct ftpd_datastate *fsd)
00423 {
00424     tcp_arg(pcb, NULL);
00425     tcp_sent(pcb, NULL);
00426     tcp_recv(pcb, NULL);
00427     fsd->msgfs->datafs = NULL;
00428     sfifo_close(&fsd->fifo);
00429     free(fsd);
00430     tcp_arg(pcb, NULL);
00431     tcp_close(pcb);
00432 }
00433 
00434 static void send_data(struct tcp_pcb *pcb, struct ftpd_datastate *fsd)
00435 {
00436     err_t err;
00437     u16_t len;
00438 
00439     if (sfifo_used(&fsd->fifo) > 0) {
00440         int i;
00441 
00442         /* We cannot send more data than space available in the send
00443            buffer. */
00444         if (tcp_sndbuf(pcb) < sfifo_used(&fsd->fifo)) {
00445             len = tcp_sndbuf(pcb);
00446         } else {
00447             len = (u16_t) sfifo_used(&fsd->fifo);
00448         }
00449 
00450         i = fsd->fifo.readpos;
00451         if ((i + len) > fsd->fifo.size) {
00452             err = tcp_write(pcb, fsd->fifo.buffer + i, (u16_t)(fsd->fifo.size - i), 1);
00453             if (err != ERR_OK) {
00454                 dbg_printf("send_data: error writing!\n");
00455                 return;
00456             }
00457             len -= fsd->fifo.size - i;
00458             fsd->fifo.readpos = 0;
00459             i = 0;
00460         }
00461 
00462         err = tcp_write(pcb, fsd->fifo.buffer + i, len, 1);
00463         if (err != ERR_OK) {
00464             dbg_printf("send_data: error writing!\n");
00465             return;
00466         }
00467         fsd->fifo.readpos += len;
00468     }
00469 }
00470 
00471 static void send_file( struct ftpd_datastate *fsd, struct tcp_pcb *pcb )
00472 {
00473     if (!fsd->connected)
00474         return;
00475 
00476     if (fsd->vfs_file)
00477     {
00478         char buffer[ 2048 ];
00479         int len;
00480 
00481         len = sfifo_space( &fsd->fifo );
00482         if (len == 0)
00483         {
00484             send_data(pcb, fsd);
00485             return;
00486         }
00487         if (len > 2048)
00488             len = 2048;
00489         len = vfs_read( buffer, 1, len, fsd->vfs_file );
00490         if( len == 0 )
00491         {
00492             if( vfs_eof( fsd->vfs_file ) == 0)
00493                 return;
00494             vfs_close( fsd->vfs_file );
00495             fsd->vfs_file = NULL;
00496             return;
00497         }
00498         sfifo_write( &fsd->fifo, buffer, len );
00499         send_data( pcb, fsd );
00500     } else {
00501         struct ftpd_msgstate *fsm;
00502         struct tcp_pcb *msgpcb;
00503 
00504         if (sfifo_used(&fsd->fifo) > 0) {
00505             send_data(pcb, fsd);
00506             return;
00507         }
00508         fsm = fsd->msgfs;
00509         msgpcb = fsd->msgpcb;
00510 
00511         vfs_close( fsd->vfs_file );
00512         fsd->vfs_file = NULL;
00513         ftpd_dataclose( pcb, fsd );
00514         fsm->datapcb = NULL;
00515         fsm->datafs = NULL;
00516         fsm->state = FTPD_IDLE;
00517         send_msg( msgpcb, fsm, msg226 );
00518 //        printit( msg226 );
00519         return;
00520     }
00521 }
00522 
00523 static void send_next_directory(struct ftpd_datastate *fsd, struct tcp_pcb *pcb, int shortlist)
00524 {
00525     char buffer[1024];
00526     int len;
00527 
00528     while (1) {
00529     if (fsd->vfs_dirent == NULL)
00530         fsd->vfs_dirent = vfs_readdir(fsd->vfs_dir);
00531 
00532     if (fsd->vfs_dirent) {
00533         if (shortlist) {
00534             len = sprintf(buffer, "%s\r\n", fsd->vfs_dirent->name);
00535             if (sfifo_space(&fsd->fifo) < len) {
00536                 send_data(pcb, fsd);
00537                 return;
00538             }
00539             sfifo_write(&fsd->fifo, buffer, len);
00540             fsd->vfs_dirent = NULL;
00541         } else {
00542             vfs_stat_t st;
00543             time_t current_time;
00544             int current_year;
00545             struct tm *s_time;
00546 
00547             time(&current_time);
00548             s_time = gmtime(&current_time);
00549             current_year = s_time->tm_year;
00550 
00551 //..DRB            vfs_stat(fsd->msgfs->vfs, fsd->vfs_dirent->name, &st);
00552             s_time = gmtime(&st.st_mtime);
00553             if (s_time->tm_year == current_year)
00554                 len = sprintf(buffer, "-rw-rw-rw-   1 user     ftp  %11ld %s %02i %02i:%02i %s\r\n", st.st_size, month_table[s_time->tm_mon], s_time->tm_mday, s_time->tm_hour, s_time->tm_min, fsd->vfs_dirent->name);
00555             else
00556                 len = sprintf(buffer, "-rw-rw-rw-   1 user     ftp  %11ld %s %02i %5i %s\r\n", st.st_size, month_table[s_time->tm_mon], s_time->tm_mday, s_time->tm_year + 1900, fsd->vfs_dirent->name);
00557             if (VFS_ISDIR(st.st_mode))
00558                 buffer[0] = 'd';
00559             if (sfifo_space(&fsd->fifo) < len) {
00560                 send_data(pcb, fsd);
00561                 return;
00562             }
00563             sfifo_write(&fsd->fifo, buffer, len);
00564             fsd->vfs_dirent = NULL;
00565         }
00566     } else {
00567         struct ftpd_msgstate *fsm;
00568         struct tcp_pcb *msgpcb;
00569 
00570         if (sfifo_used(&fsd->fifo) > 0) {
00571             send_data(pcb, fsd);
00572             return;
00573         }
00574         fsm = fsd->msgfs;
00575         msgpcb = fsd->msgpcb;
00576 
00577         vfs_closedir(fsd->vfs_dir);
00578         fsd->vfs_dir = NULL;
00579         ftpd_dataclose(pcb, fsd);
00580         fsm->datapcb = NULL;
00581         fsm->datafs = NULL;
00582         fsm->state = FTPD_IDLE;
00583         send_msg(msgpcb, fsm, msg226);
00584         return;
00585     }
00586     }
00587 }
00588 
00589 static err_t ftpd_datasent(void *arg, struct tcp_pcb *pcb, u16_t len)
00590 {
00591     struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg;
00592 
00593     switch (fsd->msgfs->state) {
00594     case FTPD_LIST:
00595         send_next_directory(fsd, pcb, 0);
00596         break;
00597     case FTPD_NLST:
00598         send_next_directory(fsd, pcb, 1);
00599         break;
00600     case FTPD_RETR:
00601         send_file(fsd, pcb);
00602         break;
00603     default:
00604         break;
00605     }
00606 
00607     return ERR_OK;
00608 }
00609 
00610 static err_t ftpd_datarecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
00611 {
00612     struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg;
00613 
00614     if (err == ERR_OK && p != NULL) {
00615         struct pbuf *q;
00616         u16_t tot_len = 0;
00617 
00618         for (q = p; q != NULL; q = q->next) {
00619             int len;
00620 
00621             len = vfs_write(q->payload, 1, q->len, fsd->vfs_file);
00622             tot_len += len;
00623             if (len != q->len)
00624                 break;
00625         }
00626 
00627         /* Inform TCP that we have taken the data. */
00628         tcp_recved(pcb, tot_len);
00629 
00630         pbuf_free(p);
00631     }
00632     if (err == ERR_OK && p == NULL) {
00633         struct ftpd_msgstate *fsm;
00634         struct tcp_pcb *msgpcb;
00635 
00636         fsm = fsd->msgfs;
00637         msgpcb = fsd->msgpcb;
00638 
00639         vfs_close(fsd->vfs_file);
00640         fsd->vfs_file = NULL;
00641         ftpd_dataclose(pcb, fsd);
00642         fsm->datapcb = NULL;
00643         fsm->datafs = NULL;
00644         fsm->state = FTPD_IDLE;
00645         send_msg(msgpcb, fsm, msg226);
00646     }
00647 
00648     return ERR_OK;
00649 }
00650 
00651 static err_t ftpd_dataconnected(void *arg, struct tcp_pcb *pcb, err_t err)
00652 {
00653     struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg;
00654 
00655     fsd->msgfs->datapcb = pcb;
00656     fsd->connected = 1;
00657 
00658     /* Tell TCP that we wish to be informed of incoming data by a call
00659        to the http_recv() function. */
00660     tcp_recv(pcb, ftpd_datarecv);
00661 
00662     /* Tell TCP that we wish be to informed of data that has been
00663        successfully sent by a call to the ftpd_sent() function. */
00664     tcp_sent(pcb, ftpd_datasent);
00665 
00666     tcp_err(pcb, ftpd_dataerr);
00667 
00668     switch (fsd->msgfs->state) {
00669     case FTPD_LIST:
00670         send_next_directory(fsd, pcb, 0);
00671         break;
00672     case FTPD_NLST:
00673         send_next_directory(fsd, pcb, 1);
00674         break;
00675     case FTPD_RETR:
00676         send_file(fsd, pcb);
00677         break;
00678     default:
00679         break;
00680     }
00681 
00682     return ERR_OK;
00683 }
00684 
00685 static err_t ftpd_dataaccept(void *arg, struct tcp_pcb *pcb, err_t err)
00686 {
00687     struct ftpd_datastate *fsd = (struct ftpd_datastate*)arg;
00688 
00689     fsd->msgfs->datapcb = pcb;
00690     fsd->connected = 1;
00691 
00692     /* Tell TCP that we wish to be informed of incoming data by a call
00693        to the http_recv() function. */
00694     tcp_recv(pcb, ftpd_datarecv);
00695 
00696     /* Tell TCP that we wish be to informed of data that has been
00697        successfully sent by a call to the ftpd_sent() function. */
00698     tcp_sent(pcb, ftpd_datasent);
00699 
00700     tcp_err(pcb, ftpd_dataerr);
00701 
00702     switch (fsd->msgfs->state) {
00703     case FTPD_LIST:
00704         send_next_directory(fsd, pcb, 0);
00705         break;
00706     case FTPD_NLST:
00707         send_next_directory(fsd, pcb, 1);
00708         break;
00709     case FTPD_RETR:
00710         send_file(fsd, pcb);
00711         break;
00712     default:
00713         break;
00714     }
00715 
00716     return ERR_OK;
00717 }
00718 
00719 static int open_dataconnection(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00720 {
00721     if (fsm->passive)
00722         return 0;
00723 
00724     /* Allocate memory for the structure that holds the state of the connection. */
00725     fsm->datafs = (struct ftpd_datastate*)malloc(sizeof(struct ftpd_datastate));
00726 
00727     if (fsm->datafs == NULL) {
00728         send_msg(pcb, fsm, msg451);
00729         return 1;
00730     }
00731     memset(fsm->datafs, 0, sizeof(struct ftpd_datastate));
00732     fsm->datafs->msgfs = fsm;
00733     fsm->datafs->msgpcb = pcb;
00734     sfifo_init(&fsm->datafs->fifo, 2000);
00735 
00736     fsm->datapcb = tcp_new();
00737     tcp_bind(fsm->datapcb, &pcb->local_ip, 20);
00738     /* Tell TCP that this is the structure we wish to be passed for our
00739        callbacks. */
00740     tcp_arg(fsm->datapcb, fsm->datafs);
00741     tcp_connect(fsm->datapcb, &fsm->dataip, fsm->dataport, ftpd_dataconnected);
00742 
00743     return 0;
00744 }
00745 
00746 static void cmd_user(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00747 {
00748     send_msg(pcb, fsm, msg331);
00749     fsm->state = FTPD_PASS;
00750     /*
00751        send_msg(pcb, fs, msgLoginFailed);
00752        fs->state = FTPD_QUIT;
00753      */
00754 }
00755 
00756 static void cmd_pass(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00757 {
00758     send_msg(pcb, fsm, msg230);
00759     fsm->state = FTPD_IDLE;
00760     /*
00761        send_msg(pcb, fs, msgLoginFailed);
00762        fs->state = FTPD_QUIT;
00763      */
00764 }
00765 
00766 static void cmd_port(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00767 {
00768     int nr;
00769     unsigned pHi, pLo;
00770     unsigned ip[4];
00771 
00772     nr = sscanf(arg, "%u,%u,%u,%u,%u,%u", &(ip[0]), &(ip[1]), &(ip[2]), &(ip[3]), &pHi, &pLo);
00773     if (nr != 6) {
00774         send_msg(pcb, fsm, msg501);
00775     } else {
00776         IP4_ADDR(&fsm->dataip, (u8_t) ip[0], (u8_t) ip[1], (u8_t) ip[2], (u8_t) ip[3]);
00777         fsm->dataport = ((u16_t) pHi << 8) | (u16_t) pLo;
00778         send_msg(pcb, fsm, msg200);
00779     }
00780 }
00781 
00782 static void cmd_quit(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00783 {
00784     send_msg(pcb, fsm, msg221);
00785     fsm->state = FTPD_QUIT;
00786 }
00787 
00788 static void cmd_cwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00789 {
00790     if (!vfs_chdir(fsm->vfs, arg)) {
00791         send_msg(pcb, fsm, msg250);
00792     } else {
00793         send_msg(pcb, fsm, msg550);
00794     }
00795 }
00796 
00797 static void cmd_cdup(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00798 {
00799     if (!vfs_chdir(fsm->vfs, "..")) {
00800         send_msg(pcb, fsm, msg250);
00801     } else {
00802         send_msg(pcb, fsm, msg550);
00803     }
00804 }
00805 
00806 static void cmd_pwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00807 {
00808     char *path;
00809 
00810     path = vfs_getcwd( fsm->vfs, NULL, 0 );
00811     if( path )
00812     {
00813         send_msg(pcb, fsm, msg257PWD, path);
00814         free(path);
00815     }
00816 }
00817 
00818 static void cmd_list_common(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, int shortlist)
00819 {
00820     vfs_dir_t *vfs_dir;
00821     char *cwd;
00822 
00823 #if 0
00824     cwd = vfs_getcwd(fsm->vfs, NULL, 0);
00825     if ((!cwd)) {
00826         send_msg(pcb, fsm, msg451);
00827         return;
00828     }
00829 #endif
00830     vfs_dir = vfs_opendir(fsm->vfs, cwd);
00831     free(cwd);
00832     if (!vfs_dir) {
00833         send_msg(pcb, fsm, msg451);
00834         return;
00835     }
00836 
00837     if( open_dataconnection(pcb, fsm) != 0)
00838     {
00839         vfs_closedir(vfs_dir);
00840         return;
00841     }
00842 
00843     fsm->datafs->vfs_dir = vfs_dir;
00844     fsm->datafs->vfs_dirent = NULL;
00845     if (shortlist != 0)
00846     {
00847         fsm->state = FTPD_NLST;
00848     }
00849     else
00850     {
00851         fsm->state = FTPD_LIST;
00852     }
00853     send_msg(pcb, fsm, msg150);
00854 }
00855 
00856 
00857 static void cmd_nlst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00858 {
00859     cmd_list_common(arg, pcb, fsm, 1);
00860 }
00861 
00862 static void cmd_list(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00863 {
00864     cmd_list_common(arg, pcb, fsm, 0);
00865 }
00866 
00867 static void cmd_retr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00868 {
00869     vfs_file_t *vfs_file;
00870     vfs_stat_t st;
00871 
00872 #if 0
00873     vfs_stat(fsm->vfs, arg, &st);
00874     if (!VFS_ISREG(st.st_mode))
00875     {
00876         send_msg(pcb, fsm, msg550);
00877         return;
00878     }
00879 #endif
00880     vfs_file = vfs_open(fsm->vfs, arg, "rb");
00881     if (!vfs_file) {
00882         send_msg(pcb, fsm, msg550);
00883         return;
00884     }
00885 
00886     send_msg(pcb, fsm, msg150recv, arg, st.st_size);
00887 
00888     if (open_dataconnection(pcb, fsm) != 0) {
00889         vfs_close(vfs_file);
00890         return;
00891     }
00892 
00893     fsm->datafs->vfs_file = vfs_file;
00894     fsm->state = FTPD_RETR;
00895 }
00896 
00897 static void cmd_stor(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00898 {
00899     vfs_file_t *vfs_file;
00900 
00901     vfs_file = vfs_open(fsm->vfs, arg, "wb");
00902     if (!vfs_file) {
00903         send_msg(pcb, fsm, msg550);
00904         return;
00905     }
00906 
00907     send_msg(pcb, fsm, msg150stor, arg);
00908 
00909     if (open_dataconnection(pcb, fsm) != 0) {
00910         vfs_close(vfs_file);
00911         return;
00912     }
00913 
00914     fsm->datafs->vfs_file = vfs_file;
00915     fsm->state = FTPD_STOR;
00916 }
00917 
00918 static void cmd_noop(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00919 {
00920     send_msg(pcb, fsm, msg200);
00921 }
00922 
00923 static void cmd_syst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00924 {
00925     send_msg(pcb, fsm, msg214SYST, "UNIX");
00926 }
00927 
00928 static void cmd_pasv(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00929 {
00930     static u16_t port = 4096;
00931     static u16_t start_port = 4096;
00932     struct tcp_pcb *temppcb;
00933 
00934     /* Allocate memory for the structure that holds the state of the        connection. */
00935     fsm->datafs = (struct ftpd_datastate*)malloc(sizeof(struct ftpd_datastate));
00936 
00937     if (fsm->datafs == NULL) {
00938         send_msg(pcb, fsm, msg451);
00939         return;
00940     }
00941     memset(fsm->datafs, 0, sizeof(struct ftpd_datastate));
00942 
00943     fsm->datapcb = tcp_new();
00944     if (!fsm->datapcb) {
00945         free(fsm->datafs);
00946         send_msg(pcb, fsm, msg451);
00947         return;
00948     }
00949 
00950     sfifo_init(&fsm->datafs->fifo, 2000);
00951 
00952     start_port = port;
00953 
00954     while (1) {
00955         err_t err;
00956 
00957         if(++port > 0x7fff)
00958             port = 4096;
00959     
00960         fsm->dataport = port;
00961         err = tcp_bind(fsm->datapcb, &pcb->local_ip, fsm->dataport);
00962         if (err == ERR_OK)
00963             break;
00964         if (start_port == port)
00965             err = ERR_CLSD;
00966         if (err == ERR_USE)
00967             continue;
00968         if (err != ERR_OK) {
00969             ftpd_dataclose(fsm->datapcb, fsm->datafs);
00970             fsm->datapcb = NULL;
00971             fsm->datafs = NULL;
00972             return;
00973         }
00974     }
00975 
00976     temppcb = tcp_listen(fsm->datapcb);
00977     if (!temppcb) {
00978         ftpd_dataclose(fsm->datapcb, fsm->datafs);
00979         fsm->datapcb = NULL;
00980         fsm->datafs = NULL;
00981         return;
00982     }
00983     fsm->datapcb = temppcb;
00984 
00985     fsm->passive = 1;
00986     fsm->datafs->connected = 0;
00987     fsm->datafs->msgfs = fsm;
00988     fsm->datafs->msgpcb = pcb;
00989 
00990     /* Tell TCP that this is the structure we wish to be passed for our
00991        callbacks. */
00992     tcp_arg(fsm->datapcb, fsm->datafs);
00993 
00994     tcp_accept(fsm->datapcb, ftpd_dataaccept);
00995     send_msg(pcb, fsm, msg227, ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), (fsm->dataport >> 8) & 0xff, (fsm->dataport) & 0xff);
00996 }
00997 
00998 static void cmd_abrt(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
00999 {
01000     if (fsm->datafs != NULL) {
01001         tcp_arg(fsm->datapcb, NULL);
01002         tcp_sent(fsm->datapcb, NULL);
01003         tcp_recv(fsm->datapcb, NULL);
01004         tcp_arg(fsm->datapcb, NULL);
01005         tcp_abort(pcb);
01006         sfifo_close(&fsm->datafs->fifo);
01007         free(fsm->datafs);
01008         fsm->datafs = NULL;
01009     }
01010     fsm->state = FTPD_IDLE;
01011 }
01012 
01013 static void cmd_type(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01014 {
01015     dbg_printf("Got TYPE -%s-\n", arg);
01016     //printit( "Got TYPE -" );
01017     //printit( (char*)arg ); // ASCII text 
01018 
01019     if( *arg == 'A' )
01020     {
01021         send_msg(pcb, fsm, "200 Type set to A." );
01022     }
01023     else
01024     {
01025         send_msg(pcb, fsm, msg502);
01026     }
01027 }
01028 
01029 static void cmd_mode(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01030 {
01031     dbg_printf("Got MODE -%s-\n", arg);
01032     //printit( "Got MODE -" );
01033     //printit( (char*)arg );
01034     send_msg(pcb, fsm, msg502);
01035 }
01036 
01037 static void cmd_rnfr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01038 {
01039     if (arg == NULL) {
01040         send_msg(pcb, fsm, msg501);
01041         return;
01042     }
01043     if (*arg == '\0') {
01044         send_msg(pcb, fsm, msg501);
01045         return;
01046     }
01047     if (fsm->renamefrom)
01048         free(fsm->renamefrom);
01049     fsm->renamefrom = (char*)malloc(strlen(arg) + 1);
01050     if (fsm->renamefrom == NULL) {
01051         send_msg(pcb, fsm, msg451);
01052         return;
01053     }
01054     strcpy(fsm->renamefrom, arg);
01055     fsm->state = FTPD_RNFR;
01056     send_msg(pcb, fsm, msg350);
01057 }
01058 
01059 static void cmd_rnto(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01060 {
01061     if (fsm->state != FTPD_RNFR) {
01062         send_msg(pcb, fsm, msg503);
01063         return;
01064     }
01065     fsm->state = FTPD_IDLE;
01066     if (arg == NULL) {
01067         send_msg(pcb, fsm, msg501);
01068         return;
01069     }
01070     if (*arg == '\0') {
01071         send_msg(pcb, fsm, msg501);
01072         return;
01073     }
01074     if (vfs_rename(fsm->vfs, fsm->renamefrom, arg)) {
01075         send_msg(pcb, fsm, msg450);
01076     } else {
01077         send_msg(pcb, fsm, msg250);
01078     }
01079 }
01080 
01081 static void cmd_mkd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01082 {
01083     if (arg == NULL) {
01084         send_msg(pcb, fsm, msg501);
01085         return;
01086     }
01087     if (*arg == '\0') {
01088         send_msg(pcb, fsm, msg501);
01089         return;
01090     }
01091     if (vfs_mkdir(fsm->vfs, arg, VFS_IRWXU | VFS_IRWXG | VFS_IRWXO) != 0) {
01092         send_msg(pcb, fsm, msg550);
01093     } else {
01094         send_msg(pcb, fsm, msg257, arg);
01095     }
01096 }
01097 
01098 static void cmd_nill(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01099 {
01100     printit( "cmd_nill" );
01101 }
01102 
01103 
01104 static void cmd_rmd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01105 {
01106     vfs_stat_t st;
01107 
01108     if (arg == NULL) {
01109         send_msg(pcb, fsm, msg501);
01110         return;
01111     }
01112     if (*arg == '\0') {
01113         send_msg(pcb, fsm, msg501);
01114         return;
01115     }
01116     if (vfs_stat(fsm->vfs, arg, &st) != 0) {
01117         send_msg(pcb, fsm, msg550);
01118         return;
01119     }
01120     if (!VFS_ISDIR(st.st_mode)) {
01121         send_msg(pcb, fsm, msg550);
01122         return;
01123     }
01124     if (vfs_rmdir(fsm->vfs, arg) != 0) {
01125         send_msg(pcb, fsm, msg550);
01126     } else {
01127         send_msg(pcb, fsm, msg250);
01128     }
01129 }
01130 
01131 static void cmd_dele(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01132 {
01133     vfs_stat_t st;
01134 
01135     if (arg == NULL) {
01136         send_msg(pcb, fsm, msg501);
01137         return;
01138     }
01139     if (*arg == '\0') {
01140         send_msg(pcb, fsm, msg501);
01141         return;
01142     }
01143 #if 0
01144     if (vfs_stat(fsm->vfs, arg, &st) != 0)
01145     {
01146         send_msg(pcb, fsm, msg550);
01147         return;
01148     }
01149     if (!VFS_ISREG(st.st_mode))
01150     {
01151         send_msg(pcb, fsm, msg550);
01152         return;
01153     }
01154 #endif
01155     if (vfs_remove(fsm->vfs, arg) != 0)
01156     {
01157         send_msg(pcb, fsm, msg550);
01158     }
01159     else
01160     {
01161         send_msg(pcb, fsm, msg250);
01162     }
01163 }
01164 
01165 
01166 struct ftpd_command {
01167     char *cmd;
01168     void (*func) (const char *arg, struct tcp_pcb * pcb, struct ftpd_msgstate * fsm);
01169 };
01170 
01171 static struct ftpd_command ftpd_commands[] = {
01172     "USER", cmd_user,
01173     "PASS", cmd_pass,
01174     "PORT", cmd_port,
01175     "QUIT", cmd_quit,
01176     "CWD",  cmd_cwd,
01177     "CDUP", cmd_cdup,
01178     "PWD",  cmd_pwd,
01179     "XPWD", cmd_pwd,
01180     "NLST", cmd_nlst,
01181     "LIST", cmd_list,
01182     "RETR", cmd_retr,
01183     "STOR", cmd_stor,
01184     "NOOP", cmd_noop,
01185     "SYST", cmd_syst,
01186     "ABOR", cmd_abrt,
01187     "TYPE", cmd_type,
01188     "MODE", cmd_mode,
01189     "RNFR", cmd_rnfr,
01190     "RNTO", cmd_rnto,
01191     "MKD",  cmd_mkd,
01192     "XMKD", cmd_mkd,
01193     "RMD",  cmd_rmd,
01194     "XRMD", cmd_rmd,
01195     "DELE", cmd_dele,
01196     //"PASV", cmd_pasv,
01197     NULL
01198 };
01199 
01200 static void send_msgdata(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01201 {
01202     err_t err;
01203     u16_t len;
01204 
01205     if (sfifo_used(&fsm->fifo) > 0) {
01206         int i;
01207 
01208         /* We cannot send more data than space available in the send
01209            buffer. */
01210         if (tcp_sndbuf(pcb) < sfifo_used(&fsm->fifo)) {
01211             len = tcp_sndbuf(pcb);
01212         } else {
01213             len = (u16_t) sfifo_used(&fsm->fifo);
01214         }
01215 
01216         i = fsm->fifo.readpos;
01217         if ((i + len) > fsm->fifo.size) {
01218             err = tcp_write(pcb, fsm->fifo.buffer + i, (u16_t)(fsm->fifo.size - i), 1);
01219             if (err != ERR_OK) {
01220                 dbg_printf("send_msgdata: error writing!\n");
01221                 return;
01222             }
01223             len -= fsm->fifo.size - i;
01224             fsm->fifo.readpos = 0;
01225             i = 0;
01226         }
01227 
01228         err = tcp_write(pcb, fsm->fifo.buffer + i, len, 1);
01229         if (err != ERR_OK) {
01230             dbg_printf("send_msgdata: error writing!\n");
01231             return;
01232         }
01233         fsm->fifo.readpos += len;
01234     }
01235 }
01236 
01237 static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg, ...)
01238 {
01239     va_list arg;
01240     char buffer[1024];
01241     int len;
01242 
01243     va_start(arg, msg);
01244     vsprintf(buffer, msg, arg);
01245     va_end(arg);
01246     strcat(buffer, "\r\n");
01247     len = strlen(buffer);
01248     if (sfifo_space(&fsm->fifo) < len)
01249         return;
01250     sfifo_write(&fsm->fifo, buffer, len);
01251     dbg_printf("response: %s", buffer);
01252     //printit( buffer );
01253     send_msgdata(pcb, fsm);
01254 }
01255 
01256 static void ftpd_msgerr(void *arg, err_t err)
01257 {
01258     struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg;
01259 
01260 //    printit( "ftpd_msgerr" );
01261     dbg_printf("ftpd_msgerr: %s (%i)\n", lwip_strerr(err), err);
01262     if (fsm == NULL)
01263         return;
01264     if (fsm->datafs)
01265         ftpd_dataclose(fsm->datapcb, fsm->datafs);
01266     sfifo_close(&fsm->fifo);
01267     vfs_close( (vfs_file_t*)fsm->vfs);
01268     fsm->vfs = NULL;
01269     if (fsm->renamefrom)
01270         free(fsm->renamefrom);
01271     fsm->renamefrom = NULL;
01272     free(fsm);
01273 }
01274 
01275 static void ftpd_msgclose(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
01276 {
01277     //printit( "ftpd_msgclose" );
01278     tcp_arg(pcb, NULL);
01279     tcp_sent(pcb, NULL);
01280     tcp_recv(pcb, NULL);
01281     if (fsm->datafs)
01282         ftpd_dataclose(fsm->datapcb, fsm->datafs);
01283     sfifo_close(&fsm->fifo);
01284     vfs_close(  (vfs_file_t*)fsm->vfs);
01285     fsm->vfs = NULL;
01286     if (fsm->renamefrom)
01287         free(fsm->renamefrom);
01288     fsm->renamefrom = NULL;
01289     free(fsm);
01290     tcp_arg(pcb, NULL);
01291     tcp_close(pcb);
01292 }
01293 
01294 static err_t ftpd_msgsent(void *arg, struct tcp_pcb *pcb, u16_t len)
01295 {
01296     struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg;
01297 
01298 //    printit( "ftpd_msgsent" );
01299     if (pcb->state > ESTABLISHED)
01300         return ERR_OK;
01301 
01302     if ((sfifo_used(&fsm->fifo) == 0) && (fsm->state == FTPD_QUIT))
01303         ftpd_msgclose(pcb, fsm);
01304 
01305     send_msgdata(pcb, fsm);
01306 
01307     return ERR_OK;
01308 }
01309 
01310 
01311 void bcopy (char *src, char *dest, int len)
01312 {
01313   if (dest < src)
01314     while (len--)
01315       *dest++ = *src++;
01316   else
01317     {
01318       char *lasts = src + (len-1);
01319       char *lastd = dest + (len-1);
01320       while (len--)
01321         *(char *)lastd-- = *(char *)lasts--;
01322     }
01323 }
01324 
01325 static err_t ftpd_msgrecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
01326 {
01327     char *text;
01328     struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg;
01329 
01330 //    printit( "ftpd_msgrecv" );
01331     //printit( arg );
01332     if (err == ERR_OK && p != NULL) {
01333 
01334         /* Inform TCP that we have taken the data. */
01335         tcp_recved(pcb, p->tot_len);
01336 
01337         text = (char*)malloc(p->tot_len + 1);
01338         if (text) {
01339             char cmd[5];
01340             struct pbuf *q;
01341             char *pt = text;
01342             struct ftpd_command *ftpd_cmd;
01343 
01344             for (q = p; q != NULL; q = q->next)
01345             {
01346                 bcopy( (char*)q->payload, pt, q->len);
01347                 pt += q->len;
01348             }
01349             *pt = '\0';
01350 
01351             pt = &text[strlen(text) - 1];
01352             while (((*pt == '\r') || (*pt == '\n')) && pt >= text)
01353                 *pt-- = '\0';
01354 
01355             dbg_printf("query: %s\n", text);
01356             //printit( "query: " );
01357             //printit( text );
01358 
01359             strncpy(cmd, text, 4);
01360             for (pt = cmd; isalpha(*pt) && pt < &cmd[4]; pt++)
01361                 *pt = toupper(*pt);
01362             *pt = '\0';
01363 
01364             for (ftpd_cmd = ftpd_commands; ftpd_cmd->cmd != NULL; ftpd_cmd++) {
01365                 if (!strcmp(ftpd_cmd->cmd, cmd))
01366                     break;
01367             }
01368 
01369             if (strlen(text) < (strlen(cmd) + 1))
01370                 pt = "";
01371             else
01372                 pt = &text[strlen(cmd) + 1];
01373 
01374             if (ftpd_cmd->func)
01375                 ftpd_cmd->func(pt, pcb, fsm);
01376             else
01377                 send_msg(pcb, fsm, msg502);
01378 
01379             free(text);
01380         }
01381         pbuf_free(p);
01382     }
01383 
01384     return ERR_OK;
01385 }
01386 
01387 static err_t ftpd_msgpoll(void *arg, struct tcp_pcb *pcb)
01388 {
01389     struct ftpd_msgstate *fsm = (struct ftpd_msgstate*)arg;
01390 
01391     //printit( "ftpd_msgpoll" );
01392     if (fsm == NULL)
01393         return ERR_OK;
01394 
01395     if (fsm->datafs) {
01396         if (fsm->datafs->connected) {
01397             switch (fsm->state) {
01398             case FTPD_LIST:
01399                 send_next_directory(fsm->datafs, fsm->datapcb, 0);
01400                 break;
01401             case FTPD_NLST:
01402                 send_next_directory(fsm->datafs, fsm->datapcb, 1);
01403                 break;
01404             case FTPD_RETR:
01405                 send_file(fsm->datafs, fsm->datapcb);
01406                 break;
01407             default:
01408                 break;
01409             }
01410         }
01411     }
01412 
01413     return ERR_OK;
01414 }
01415 
01416 static err_t ftpd_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err)
01417 {
01418     struct ftpd_msgstate *fsm;
01419 
01420 
01421 //printit( "FTP call" );
01422     /* Allocate memory for the structure that holds the state of the
01423        connection. */
01424     fsm = (struct ftpd_msgstate*)malloc(sizeof(struct ftpd_msgstate));
01425 
01426     if (fsm == NULL) {
01427         dbg_printf("ftpd_msgaccept: Out of memory\n");
01428         return ERR_MEM;
01429     }
01430     memset(fsm, 0, sizeof(struct ftpd_msgstate));
01431 
01432     /* Initialize the structure. */
01433     sfifo_init(&fsm->fifo, 2000);
01434     fsm->state = FTPD_IDLE;
01435     fsm->vfs = vfs_openfs();
01436 #if 0
01437     if (!fsm->vfs)
01438     {
01439         free(fsm);
01440         return ERR_CLSD;
01441     }
01442 #endif
01443     /* Tell TCP that this is the structure we wish to be passed for our
01444        callbacks. */
01445     tcp_arg( pcb, fsm );
01446 
01447     /* Tell TCP that we wish to be informed of incoming data by a call
01448        to the http_recv() function. */
01449     tcp_recv( pcb, ftpd_msgrecv );
01450 
01451     /* Tell TCP that we wish be to informed of data that has been
01452        successfully sent by a call to the ftpd_sent() function. */
01453     tcp_sent( pcb, ftpd_msgsent );
01454 
01455     tcp_err( pcb, ftpd_msgerr );
01456 
01457     tcp_poll(pcb, ftpd_msgpoll, 1);
01458 
01459     send_msg(pcb, fsm, msg220);
01460 
01461     return ERR_OK;
01462 }
01463 
01464 
01465 void ftpd_init(void)
01466 {
01467     struct tcp_pcb *pcb;
01468 
01469 //..    vfs_load_plugin(vfs_default_fs);
01470 
01471     pcb = tcp_new();
01472     tcp_bind( pcb, IP_ADDR_ANY, 21 );
01473     pcb = tcp_listen( pcb );
01474     tcp_accept( pcb, ftpd_msgaccept );
01475 }
01476 
01477 
01478