Line No. | Rev | Author | Line |
---|---|---|---|
1 | 32 | kaklik | /********************************************************************* |
2 | * |
||
3 | * File Transfer Protocol (FTP) Client |
||
4 | * Module for Microchip TCP/IP Stack |
||
5 | * -Provides ability to remotely upload new MPFS image (web pages) |
||
6 | * to external EEPROM or external Flash memory |
||
7 | * -Reference: RFC 959 |
||
8 | * |
||
9 | ********************************************************************* |
||
10 | * FileName: FTP.c |
||
11 | * Dependencies: TCP, Tick, MPFS, FTPVerify() callback |
||
12 | * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32 |
||
13 | * Compiler: Microchip C32 v1.05 or higher |
||
14 | * Microchip C30 v3.12 or higher |
||
15 | * Microchip C18 v3.30 or higher |
||
16 | * HI-TECH PICC-18 PRO 9.63PL2 or higher |
||
17 | * Company: Microchip Technology, Inc. |
||
18 | * |
||
19 | * Software License Agreement |
||
20 | * |
||
21 | * Copyright (C) 2002-2009 Microchip Technology Inc. All rights |
||
22 | * reserved. |
||
23 | * |
||
24 | * Microchip licenses to you the right to use, modify, copy, and |
||
25 | * distribute: |
||
26 | * (i) the Software when embedded on a Microchip microcontroller or |
||
27 | * digital signal controller product ("Device") which is |
||
28 | * integrated into Licensee's product; or |
||
29 | * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h, |
||
30 | * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device |
||
31 | * used in conjunction with a Microchip ethernet controller for |
||
32 | * the sole purpose of interfacing with the ethernet controller. |
||
33 | * |
||
34 | * You should refer to the license agreement accompanying this |
||
35 | * Software for additional information regarding your rights and |
||
36 | * obligations. |
||
37 | * |
||
38 | * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT |
||
39 | * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT |
||
40 | * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
||
41 | * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
42 | * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR |
||
43 | * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF |
||
44 | * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS |
||
45 | * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE |
||
46 | * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER |
||
47 | * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT |
||
48 | * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE. |
||
49 | * |
||
50 | * |
||
51 | * Author Date Comment |
||
52 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
53 | * Nilesh Rajbharti 4/23/01 Original (Rev 1.0) |
||
54 | * Nilesh Rajbharti 11/13/02 Fixed FTPServer() |
||
55 | * Howard Schlunder 07/10/06 Added hash printing to FTP client |
||
56 | * Howard Schlunder 07/20/06 Added FTP_RESP_DATA_NO_SOCKET error message |
||
57 | * Elliott Wood 07/31/07 Minor updates for compatibility |
||
58 | ********************************************************************/ |
||
59 | #define __FTP_C |
||
60 | |||
61 | #include "TCPIPConfig.h" |
||
62 | |||
63 | #if defined(STACK_USE_FTP_SERVER) |
||
64 | |||
65 | #include "TCPIP Stack/TCPIP.h" |
||
66 | |||
67 | |||
68 | #define FTP_COMMAND_PORT (21u) |
||
69 | #define FTP_DATA_PORT (20u) |
||
70 | #define FTP_TIMEOUT (180ul * TICK_SECOND) |
||
71 | #define MAX_FTP_ARGS (7u) |
||
72 | #define MAX_FTP_CMD_STRING_LEN (31u) |
||
73 | |||
74 | typedef enum _SM_FTP |
||
75 | { |
||
76 | SM_FTP_NOT_CONNECTED, |
||
77 | SM_FTP_CONNECTED, |
||
78 | SM_FTP_USER_NAME, |
||
79 | SM_FTP_USER_PASS, |
||
80 | SM_FTP_RESPOND |
||
81 | } SM_FTP; |
||
82 | |||
83 | typedef enum _SM_FTP_CMD |
||
84 | { |
||
85 | SM_FTP_CMD_IDLE, |
||
86 | SM_FTP_CMD_WAIT, |
||
87 | SM_FTP_CMD_RECEIVE, |
||
88 | SM_FTP_CMD_WAIT_FOR_DISCONNECT |
||
89 | } SM_FTP_CMD; |
||
90 | |||
91 | typedef enum _FTP_COMMAND |
||
92 | { |
||
93 | FTP_CMD_USER, |
||
94 | FTP_CMD_PASS, |
||
95 | FTP_CMD_QUIT, |
||
96 | FTP_CMD_STOR, |
||
97 | FTP_CMD_PORT, |
||
98 | FTP_CMD_ABORT, |
||
99 | FTP_CMD_PWD, |
||
100 | FTP_CMD_CWD, |
||
101 | FTP_CMD_TYPE, |
||
102 | FTP_CMD_UNKNOWN, |
||
103 | FTP_CMD_NONE, |
||
104 | } FTP_COMMAND; |
||
105 | |||
106 | // Each entry in following table must match with that of FTP_COMMAND enum. |
||
107 | static ROM char * ROM FTPCommandString[] = |
||
108 | { |
||
109 | "USER", // FTP_CMD_USER |
||
110 | "PASS", // FTP_CMD_PASS |
||
111 | "QUIT", // FTP_CMD_QUIT |
||
112 | "STOR", // FTP_CMD_STOR |
||
113 | "PORT", // FTP_CMD_PORT |
||
114 | "ABOR", // FTP_CMD_ABORT |
||
115 | "PWD ", // FTP_CMD_PWD |
||
116 | "CWD ", // FTP_CMD_CWD |
||
117 | "TYPE" // FTP_CMD_TYPE |
||
118 | }; |
||
119 | #define FTP_COMMAND_TABLE_SIZE ( sizeof(FTPCommandString)/sizeof(FTPCommandString[0]) ) |
||
120 | |||
121 | |||
122 | typedef enum _FTP_RESPONSE |
||
123 | { |
||
124 | FTP_RESP_BANNER, |
||
125 | FTP_RESP_USER_OK, |
||
126 | FTP_RESP_PASS_OK, |
||
127 | FTP_RESP_QUIT_OK, |
||
128 | FTP_RESP_STOR_OK, |
||
129 | FTP_RESP_UNKNOWN, |
||
130 | FTP_RESP_LOGIN, |
||
131 | FTP_RESP_DATA_OPEN, |
||
132 | FTP_RESP_DATA_READY, |
||
133 | FTP_RESP_DATA_CLOSE, |
||
134 | FTP_RESP_DATA_NO_SOCKET, |
||
135 | FTP_RESP_PWD, |
||
136 | FTP_RESP_OK, |
||
137 | |||
138 | FTP_RESP_NONE // This must always be the last |
||
139 | // There is no corresponding string. |
||
140 | } FTP_RESPONSE; |
||
141 | |||
142 | // Each entry in following table must match with FTP_RESPONE enum |
||
143 | static ROM char * ROM FTPResponseString[] = |
||
144 | { |
||
145 | "220 Ready\r\n", // FTP_RESP_BANNER |
||
146 | "331 Password required\r\n", // FTP_RESP_USER_OK |
||
147 | "230 Logged in\r\n", // FTP_RESP_PASS_OK |
||
148 | "221 Bye\r\n", // FTP_RESP_QUIT_OK |
||
149 | "500 \r\n", // FTP_RESP_STOR_OK |
||
150 | "502 Not implemented\r\n", // FTP_RESP_UNKNOWN |
||
151 | "530 Login required\r\n", // FTP_RESP_LOGIN |
||
152 | "150 Transferring data...\r\n", // FTP_RESP_DATA_OPEN |
||
153 | "125 Done\r\n", // FTP_RESP_DATA_READY |
||
154 | "226 Transfer Complete\r\n", // FTP_RESP_DATA_CLOSE |
||
155 | "425 Can't create data socket.\r\n",// FTP_RESP_DATA_NO_SOCKET |
||
156 | "257 \"/\" is current\r\n", // FTP_RESP_PWD |
||
157 | "200 Ok\r\n" // FTP_RESP_OK |
||
158 | }; |
||
159 | |||
160 | |||
161 | static union |
||
162 | { |
||
163 | struct |
||
164 | { |
||
165 | unsigned char bUserSupplied : 1; |
||
166 | unsigned char bLoggedIn: 1; |
||
167 | } Bits; |
||
168 | BYTE Val; |
||
169 | } FTPFlags; |
||
170 | |||
171 | |||
172 | static TCP_SOCKET FTPSocket; // Main ftp command socket. |
||
173 | static TCP_SOCKET FTPDataSocket; // ftp data socket. |
||
174 | static WORD_VAL FTPDataPort; // ftp data port number as supplied by client |
||
175 | |||
176 | static SM_FTP smFTP; // ftp server FSM state |
||
177 | static SM_FTP_CMD smFTPCommand; // ftp command FSM state |
||
178 | |||
179 | static FTP_COMMAND FTPCommand; |
||
180 | static FTP_RESPONSE FTPResponse; |
||
181 | |||
182 | static BYTE FTPUser[FTP_USER_NAME_LEN]; |
||
183 | static BYTE FTPString[MAX_FTP_CMD_STRING_LEN+2]; |
||
184 | static BYTE FTPStringLen; |
||
185 | static BYTE *FTP_argv[MAX_FTP_ARGS]; // Parameters for a ftp command |
||
186 | static BYTE FTP_argc; // Total number of params for a ftp command |
||
187 | static DWORD lastActivity; // Timeout keeper. |
||
188 | |||
189 | |||
190 | static MPFS FTPFileHandle; |
||
191 | |||
192 | // Private helper functions. |
||
193 | static void ParseFTPString(void); |
||
194 | static FTP_COMMAND ParseFTPCommand(BYTE *cmd); |
||
195 | static void ParseFTPString(void); |
||
196 | static BOOL ExecuteFTPCommand(FTP_COMMAND cmd); |
||
197 | static BOOL PutFile(void); |
||
198 | static BOOL Quit(void); |
||
199 | |||
200 | |||
201 | #define FTP_PUT_ENABLED |
||
202 | |||
203 | |||
204 | /********************************************************************* |
||
205 | * Function: void FTPInit(void) |
||
206 | * |
||
207 | * PreCondition: TCP module is already initialized. |
||
208 | * |
||
209 | * Input: None |
||
210 | * |
||
211 | * Output: None |
||
212 | * |
||
213 | * Side Effects: None |
||
214 | * |
||
215 | * Overview: Initializes internal variables of FTP |
||
216 | * |
||
217 | * Note: |
||
218 | ********************************************************************/ |
||
219 | void FTPInit(void) |
||
220 | { |
||
221 | FTPSocket = TCPOpen(0, TCP_OPEN_SERVER, FTP_COMMAND_PORT, TCP_PURPOSE_FTP_COMMAND); |
||
222 | |||
223 | // If this trap ever gets entered, it means your TCPIPConfig.h file |
||
224 | // needs to be edited to make a TCP_PURPOSE_FTP_COMMAND socket |
||
225 | // available, as defined by the TCPSocketInitializer[] array. Make |
||
226 | // sure that a TCP_PURPOSE_FTP_DATA socket is also available to |
||
227 | // use the FTP Server. |
||
228 | if(FTPSocket == INVALID_SOCKET) |
||
229 | while(1); |
||
230 | |||
231 | FTPDataSocket = INVALID_SOCKET; |
||
232 | smFTP = SM_FTP_NOT_CONNECTED; |
||
233 | FTPStringLen = 0; |
||
234 | FTPFlags.Val = 0; |
||
235 | FTPDataPort.Val = FTP_DATA_PORT; |
||
236 | } |
||
237 | |||
238 | |||
239 | /********************************************************************* |
||
240 | * Function: void FTPServer(void) |
||
241 | * |
||
242 | * PreCondition: FTPInit() must already be called. |
||
243 | * |
||
244 | * Input: None |
||
245 | * |
||
246 | * Output: Opened FTP connections are served. |
||
247 | * |
||
248 | * Side Effects: None |
||
249 | * |
||
250 | * Overview: |
||
251 | * |
||
252 | * Note: This function acts as a task (similar to one in |
||
253 | * RTOS). This function performs its task in |
||
254 | * co-operative manner. Main application must call |
||
255 | * this function repeatdly to ensure all open |
||
256 | * or new connections are served on time. |
||
257 | ********************************************************************/ |
||
258 | BOOL FTPServer(void) |
||
259 | { |
||
260 | BYTE v; |
||
261 | DWORD currentTick; |
||
262 | |||
263 | if ( !TCPIsConnected(FTPSocket) ) |
||
264 | { |
||
265 | FTPStringLen = 0; |
||
266 | FTPCommand = FTP_CMD_NONE; |
||
267 | smFTP = SM_FTP_NOT_CONNECTED; |
||
268 | FTPFlags.Val = 0; |
||
269 | smFTPCommand = SM_FTP_CMD_IDLE; |
||
270 | if(FTPDataSocket != INVALID_SOCKET) |
||
271 | { |
||
272 | TCPDisconnect(FTPDataSocket); |
||
273 | FTPDataSocket = INVALID_SOCKET; |
||
274 | } |
||
275 | |||
276 | return TRUE; |
||
277 | } |
||
278 | |||
279 | if ( TCPIsGetReady(FTPSocket) ) |
||
280 | { |
||
281 | lastActivity = TickGet(); |
||
282 | |||
283 | while( TCPGet(FTPSocket, &v ) ) |
||
284 | { |
||
285 | FTPString[FTPStringLen++] = v; |
||
286 | if ( FTPStringLen == MAX_FTP_CMD_STRING_LEN ) |
||
287 | FTPStringLen = 0; |
||
288 | } |
||
289 | |||
290 | |||
291 | if ( v == '\n' ) |
||
292 | { |
||
293 | FTPString[FTPStringLen] = '\0'; |
||
294 | FTPStringLen = 0; |
||
295 | ParseFTPString(); |
||
296 | FTPCommand = ParseFTPCommand(FTP_argv[0]); |
||
297 | } |
||
298 | } |
||
299 | else if ( smFTP != SM_FTP_NOT_CONNECTED ) |
||
300 | { |
||
301 | currentTick = TickGet(); |
||
302 | currentTick = currentTick - lastActivity; |
||
303 | if ( currentTick >= FTP_TIMEOUT ) |
||
304 | { |
||
305 | lastActivity = TickGet(); |
||
306 | FTPCommand = FTP_CMD_QUIT; |
||
307 | smFTP = SM_FTP_CONNECTED; |
||
308 | } |
||
309 | } |
||
310 | |||
311 | switch(smFTP) |
||
312 | { |
||
313 | case SM_FTP_NOT_CONNECTED: |
||
314 | FTPResponse = FTP_RESP_BANNER; |
||
315 | lastActivity = TickGet(); |
||
316 | // No break - Continue... |
||
317 | |||
318 | case SM_FTP_RESPOND: |
||
319 | SM_FTP_RESPOND_Label: |
||
320 | // Make sure there is enough TCP TX FIFO space to put our response |
||
321 | if(TCPIsPutReady(FTPSocket) < strlenpgm(FTPResponseString[FTPResponse])) |
||
322 | return TRUE; |
||
323 | |||
324 | TCPPutROMString(FTPSocket, (ROM BYTE*)FTPResponseString[FTPResponse]); |
||
325 | TCPFlush(FTPSocket); |
||
326 | FTPResponse = FTP_RESP_NONE; |
||
327 | smFTP = SM_FTP_CONNECTED; |
||
328 | // No break - this will speed up little bit |
||
329 | |||
330 | case SM_FTP_CONNECTED: |
||
331 | if ( FTPCommand != FTP_CMD_NONE ) |
||
332 | { |
||
333 | if ( ExecuteFTPCommand(FTPCommand) ) |
||
334 | { |
||
335 | if ( FTPResponse != FTP_RESP_NONE ) |
||
336 | smFTP = SM_FTP_RESPOND; |
||
337 | else if ( FTPCommand == FTP_CMD_QUIT ) |
||
338 | smFTP = SM_FTP_NOT_CONNECTED; |
||
339 | |||
340 | FTPCommand = FTP_CMD_NONE; |
||
341 | smFTPCommand = SM_FTP_CMD_IDLE; |
||
342 | } |
||
343 | else if ( FTPResponse != FTP_RESP_NONE ) |
||
344 | { |
||
345 | smFTP = SM_FTP_RESPOND; |
||
346 | goto SM_FTP_RESPOND_Label; |
||
347 | } |
||
348 | } |
||
349 | break; |
||
350 | |||
351 | |||
352 | } |
||
353 | |||
354 | return TRUE; |
||
355 | } |
||
356 | |||
357 | static BOOL ExecuteFTPCommand(FTP_COMMAND cmd) |
||
358 | { |
||
359 | switch(cmd) |
||
360 | { |
||
361 | case FTP_CMD_USER: |
||
362 | FTPFlags.Bits.bUserSupplied = TRUE; |
||
363 | FTPFlags.Bits.bLoggedIn = FALSE; |
||
364 | FTPResponse = FTP_RESP_USER_OK; |
||
365 | strncpy((char*)FTPUser, (char*)FTP_argv[1], sizeof(FTPUser)); |
||
366 | break; |
||
367 | |||
368 | case FTP_CMD_PASS: |
||
369 | if ( !FTPFlags.Bits.bUserSupplied ) |
||
370 | FTPResponse = FTP_RESP_LOGIN; |
||
371 | else |
||
372 | { |
||
373 | if ( FTPVerify(FTPUser, FTP_argv[1]) ) |
||
374 | { |
||
375 | FTPFlags.Bits.bLoggedIn = TRUE; |
||
376 | FTPResponse = FTP_RESP_PASS_OK; |
||
377 | } |
||
378 | else |
||
379 | FTPResponse = FTP_RESP_LOGIN; |
||
380 | } |
||
381 | break; |
||
382 | |||
383 | case FTP_CMD_QUIT: |
||
384 | return Quit(); |
||
385 | |||
386 | case FTP_CMD_PORT: |
||
387 | FTPDataPort.v[1] = (BYTE)atoi((char*)FTP_argv[5]); |
||
388 | FTPDataPort.v[0] = (BYTE)atoi((char*)FTP_argv[6]); |
||
389 | FTPResponse = FTP_RESP_OK; |
||
390 | break; |
||
391 | |||
392 | case FTP_CMD_STOR: |
||
393 | return PutFile(); |
||
394 | |||
395 | case FTP_CMD_PWD: |
||
396 | FTPResponse = FTP_RESP_PWD; |
||
397 | break; |
||
398 | |||
399 | case FTP_CMD_CWD: |
||
400 | case FTP_CMD_TYPE: |
||
401 | FTPResponse = FTP_RESP_OK; |
||
402 | break; |
||
403 | |||
404 | case FTP_CMD_ABORT: |
||
405 | FTPResponse = FTP_RESP_OK; |
||
406 | if ( FTPDataSocket != INVALID_SOCKET ) |
||
407 | { |
||
408 | TCPDisconnect(FTPDataSocket); |
||
409 | FTPDataSocket = INVALID_SOCKET; |
||
410 | } |
||
411 | break; |
||
412 | |||
413 | default: |
||
414 | FTPResponse = FTP_RESP_UNKNOWN; |
||
415 | break; |
||
416 | } |
||
417 | return TRUE; |
||
418 | } |
||
419 | |||
420 | static BOOL Quit(void) |
||
421 | { |
||
422 | switch(smFTPCommand) |
||
423 | { |
||
424 | case SM_FTP_CMD_IDLE: |
||
425 | #if defined(FTP_PUT_ENABLED) |
||
426 | if ( smFTPCommand == SM_FTP_CMD_RECEIVE ) |
||
427 | MPFSClose(); |
||
428 | #endif |
||
429 | |||
430 | if ( FTPDataSocket != INVALID_SOCKET ) |
||
431 | { |
||
432 | #if defined(FTP_PUT_ENABLED) |
||
433 | MPFSClose(); |
||
434 | #endif |
||
435 | TCPDisconnect(FTPDataSocket); |
||
436 | smFTPCommand = SM_FTP_CMD_WAIT; |
||
437 | } |
||
438 | else |
||
439 | goto Quit_Done; |
||
440 | break; |
||
441 | |||
442 | case SM_FTP_CMD_WAIT: |
||
443 | if ( !TCPIsConnected(FTPDataSocket) ) |
||
444 | { |
||
445 | Quit_Done: |
||
446 | FTPResponse = FTP_RESP_QUIT_OK; |
||
447 | smFTPCommand = SM_FTP_CMD_WAIT_FOR_DISCONNECT; |
||
448 | } |
||
449 | break; |
||
450 | |||
451 | case SM_FTP_CMD_WAIT_FOR_DISCONNECT: |
||
452 | if ( TCPIsPutReady(FTPSocket) ) |
||
453 | { |
||
454 | if ( TCPIsConnected(FTPSocket) ) |
||
455 | TCPDisconnect(FTPSocket); |
||
456 | } |
||
457 | break; |
||
458 | |||
459 | } |
||
460 | return FALSE; |
||
461 | } |
||
462 | |||
463 | |||
464 | static BOOL PutFile(void) |
||
465 | { |
||
466 | BYTE v; |
||
467 | |||
468 | |||
469 | switch(smFTPCommand) |
||
470 | { |
||
471 | case SM_FTP_CMD_IDLE: |
||
472 | if ( !FTPFlags.Bits.bLoggedIn ) |
||
473 | { |
||
474 | FTPResponse = FTP_RESP_LOGIN; |
||
475 | return TRUE; |
||
476 | } |
||
477 | else |
||
478 | { |
||
479 | FTPResponse = FTP_RESP_DATA_OPEN; |
||
480 | FTPDataSocket = TCPOpen((PTR_BASE)&TCPGetRemoteInfo(FTPSocket)->remote, TCP_OPEN_NODE_INFO, FTPDataPort.Val, TCP_PURPOSE_FTP_DATA); |
||
481 | |||
482 | // Make sure that a valid socket was available and returned |
||
483 | // If not, return with an error |
||
484 | if(FTPDataSocket == INVALID_SOCKET) |
||
485 | { |
||
486 | FTPResponse = FTP_RESP_DATA_NO_SOCKET; |
||
487 | return TRUE; |
||
488 | } |
||
489 | |||
490 | smFTPCommand = SM_FTP_CMD_WAIT; |
||
491 | } |
||
492 | break; |
||
493 | |||
494 | case SM_FTP_CMD_WAIT: |
||
495 | if ( TCPIsConnected(FTPDataSocket) ) |
||
496 | { |
||
497 | #if defined(FTP_PUT_ENABLED) |
||
498 | FTPFileHandle = MPFSFormat(); |
||
499 | #endif |
||
500 | |||
501 | smFTPCommand = SM_FTP_CMD_RECEIVE; |
||
502 | } |
||
503 | break; |
||
504 | |||
505 | case SM_FTP_CMD_RECEIVE: |
||
506 | if ( TCPIsGetReady(FTPDataSocket) ) |
||
507 | { |
||
508 | // Reload timeout timer. |
||
509 | lastActivity = TickGet(); |
||
510 | MPFSPutBegin(FTPFileHandle); |
||
511 | while( TCPGet(FTPDataSocket, &v) ) |
||
512 | { |
||
513 | #if defined(FTP_PUT_ENABLED) |
||
514 | MPFSPut(v); |
||
515 | #endif |
||
516 | } |
||
517 | FTPFileHandle = MPFSPutEnd(); |
||
518 | |||
519 | } |
||
520 | else if ( !TCPIsConnected(FTPDataSocket) ) |
||
521 | { |
||
522 | #if defined(FTP_PUT_ENABLED) |
||
523 | MPFSClose(); |
||
524 | #endif |
||
525 | TCPDisconnect(FTPDataSocket); |
||
526 | FTPDataSocket = INVALID_SOCKET; |
||
527 | FTPResponse = FTP_RESP_DATA_CLOSE; |
||
528 | return TRUE; |
||
529 | } |
||
530 | } |
||
531 | return FALSE; |
||
532 | } |
||
533 | |||
534 | |||
535 | |||
536 | static FTP_COMMAND ParseFTPCommand(BYTE *cmd) |
||
537 | { |
||
538 | FTP_COMMAND i; |
||
539 | |||
540 | for ( i = 0; i < (FTP_COMMAND)FTP_COMMAND_TABLE_SIZE; i++ ) |
||
541 | { |
||
542 | if ( !memcmppgm2ram((void*)cmd, (ROM void*)FTPCommandString[i], 3) ) |
||
543 | return i; |
||
544 | } |
||
545 | |||
546 | return FTP_CMD_UNKNOWN; |
||
547 | } |
||
548 | |||
549 | static void ParseFTPString(void) |
||
550 | { |
||
551 | BYTE *p; |
||
552 | BYTE v; |
||
553 | enum { SM_FTP_PARSE_PARAM, SM_FTP_PARSE_SPACE } smParseFTP; |
||
554 | |||
555 | smParseFTP = SM_FTP_PARSE_PARAM; |
||
556 | p = (BYTE*)&FTPString[0]; |
||
557 | |||
558 | // Skip white blanks |
||
559 | while( *p == ' ' ) |
||
560 | p++; |
||
561 | |||
562 | FTP_argv[0] = (BYTE*)p; |
||
563 | FTP_argc = 1; |
||
564 | |||
565 | while( (v = *p) ) |
||
566 | { |
||
567 | switch(smParseFTP) |
||
568 | { |
||
569 | case SM_FTP_PARSE_PARAM: |
||
570 | if ( v == ' ' || v == ',' ) |
||
571 | { |
||
572 | *p = '\0'; |
||
573 | smParseFTP = SM_FTP_PARSE_SPACE; |
||
574 | } |
||
575 | else if ( v == '\r' || v == '\n' ) |
||
576 | *p = '\0'; |
||
577 | break; |
||
578 | |||
579 | case SM_FTP_PARSE_SPACE: |
||
580 | if ( v != ' ' ) |
||
581 | { |
||
582 | FTP_argv[FTP_argc++] = (BYTE*)p; |
||
583 | smParseFTP = SM_FTP_PARSE_PARAM; |
||
584 | } |
||
585 | break; |
||
586 | } |
||
587 | p++; |
||
588 | if(FTP_argc == MAX_FTP_ARGS) |
||
589 | break; |
||
590 | } |
||
591 | } |
||
592 | |||
593 | #endif // #if defined(STACK_USE_FTP_SERVER) |
Powered by WebSVN v2.8.3