ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ARDroneLib / Soft / Lib / utils / ardrone_ftp.c
1 /**
2  * @file ardrone_ftp.c
3  * @author nicolas.brulez@parrot.com
4  * @date 2011/04/06
5  * Copyright Parrot SA. 2011
6  */
7
8 #include <utils/ardrone_ftp.h>
9
10 #include <stdio.h>
11 #include <netdb.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16
17 #include <VP_Os/vp_os_thread.h>
18 #include <VP_Os/vp_os_malloc.h>
19 #include <VP_Os/vp_os_signal.h>
20
21 #include <errno.h>
22
23 /* CONFIGURATION */
24
25 // All following macros MUST be defined !
26 // To activate, define to (1)
27 // To deactivate, define to (0)
28
29 #ifdef DEBUG // Debug options
30 #define _FTP_DEBUG (1) // Common debug informations
31 #define _FTP_VERBOSE (0) // Extended debug information (many outputs on ftpList)
32 #define _FTP_ERRORS_PRINT (1) // Display of error messages
33 #else // Release options
34 #define _FTP_DEBUG (0)
35 #define _FTP_VERBOSE (0)
36 #define _FTP_ERRORS_PRINT (1)
37 #endif
38
39 #define FTP_PREFIX "FTP : "
40
41 /* LOCAL PRINT MACROS */
42
43 #if _FTP_ERRORS_PRINT
44 #define FTP_ERROR(...)                                                  \
45   do                                                                    \
46     {                                                                   \
47       fprintf (stderr, "Error in function %s at line %d : ", __FUNCTION__, __LINE__); \
48       fprintf (stderr, __VA_ARGS__);                                    \
49       char errorBuffer [512] = {0};                                     \
50       snprintf (errorBuffer, sizeof (errorBuffer)-1, __VA_ARGS__);      \
51       FTPlastErrorMessageSize = strlen (errorBuffer) + 1;               \
52       FTPlastErrorMessage = vp_os_realloc (FTPlastErrorMessage, FTPlastErrorMessageSize); \
53       if (NULL != FTPlastErrorMessage)                                  \
54         {                                                               \
55           strncpy (FTPlastErrorMessage, errorBuffer, FTPlastErrorMessageSize); \
56         }                                                               \
57     } while (0)
58 #else
59 #define FTP_ERROR(...)                                                  \
60   do                                                                    \
61     {                                                                   \
62       char errorBuffer [512] = {0};                                     \
63       snprintf (errorBuffer, sizeof (errorBuffer)-1, __VA_ARGS__);      \
64       FTPlastErrorMessageSize = strlen (errorBuffer) + 1;               \
65       FTPlastErrorMessage = vp_os_realloc (FTPlastErrorMessage, FTPlastErrorMessageSize); \
66       if (NULL != FTPlastErrorMessage)                                  \
67         {                                                               \
68           strncpy (FTPlastErrorMessage, errorBuffer, FTPlastErrorMessageSize); \
69         }                                                               \
70     } while (0)
71 #endif
72
73 #if _FTP_DEBUG
74 #define FTP_DEBUG(...)                                                  \
75   do                                                                    \
76     {                                                                   \
77       printf ("Debug from function %s at line %d : ", __FUNCTION__, __LINE__); \
78       printf (__VA_ARGS__);                                             \
79     } while (0)
80 #else
81 #define FTP_DEBUG(...)
82 #endif
83
84 #if _FTP_VERBOSE
85 #define FTP_PRINT(...)                          \
86   do                                            \
87     {                                           \
88       printf (FTP_PREFIX);                      \
89       printf (__VA_ARGS__);                     \
90     } while (0)
91 #else
92 #define FTP_PRINT(...)
93 #endif
94
95 /* SIZE MACROS */
96
97 #ifndef MAX_SIZE_MSG
98 #define MAX_SIZE_MSG 32768
99 #endif
100 #define IP_STRING_SIZE 16 // IP strings goes from 8 ("w.x.y.z\0") to 16 ("www.xxx.yyy.zzz\0") chars
101 #define LIST_BUFFER_BLOCKSIZE 1024
102 #define FILE_NAME_MAX_SIZE 512
103
104 /* TIMEOUT MACROS */
105
106 /* Total socket timeout : SOCK_TO_SEC + SOCK_TO_USEC */
107 #define SOCK_TO_SEC 1 // Socket timeout (seconds)
108 #define SOCK_TO_USEC 0 // Socket timeout (useconds)
109
110 /* GLOBAL ERROR MESSAGE STRING */
111 char *FTPlastErrorMessage = NULL;
112 int FTPlastErrorMessageSize = 0;
113
114 /* THREAD STRUCTURES */
115
116 typedef struct _ftp_list_param_s _ftp_list_param;
117 typedef struct _ftp_get_param_s _ftp_get_param;
118 typedef struct _ftp_put_param_s _ftp_put_param;
119
120 struct _ftp_put_param_s
121 {
122   _ftp_t *ftp;
123   char localName [FILE_NAME_MAX_SIZE];
124   char remoteName [FILE_NAME_MAX_SIZE];
125   int useResume;
126   ftp_callback callback;
127   char *fileList;
128 };
129
130 struct _ftp_get_param_s
131 {
132   _ftp_t *ftp;
133   char localName [FILE_NAME_MAX_SIZE];
134   char remoteName [FILE_NAME_MAX_SIZE];
135   int useResume;
136   ftp_callback callback;
137   char *fileList;
138 };
139
140 struct _ftp_list_param_s
141 {
142   _ftp_t *ftp;
143   char *fileList;
144   int listSize;
145   ftp_callback callback;
146 };
147
148 /* LOCAL FUNCTIONS PROTOTYPES */
149 void emptyCallback (_ftp_status status, void *arg, _ftp_t *callingFtp);
150 _ftp_status waitFor226Answer (_ftp_t *ftp);
151 int setSockTimeout (int socket, int timeoutSec, int timeoutUsec);
152 _ftp_status goToBinaryMode (_ftp_t *ftp);
153 void flushFtp (_ftp_t *ftp);
154 int getFileSize (_ftp_t *ftp, const char *distPath);
155 int getLocalFileSize (const char *localPath);
156 int getResponseCode (const char *response);
157 _ftp_status getPassiveIpAndPort (const char *response, char *ip, int *port, int ipLen);
158 _ftp_status ftpTransfert (_ftp_t *ftp, const char *message, char *answer, int answSize);
159 _ftp_status ftpSend (_ftp_t *ftp, const char *message);
160 _ftp_status ftpRecv (_ftp_t *ftp, char *answer, int answSize);
161 DEFINE_THREAD_ROUTINE (ftpGet, param);
162 DEFINE_THREAD_ROUTINE (ftpPut, param);
163 DEFINE_THREAD_ROUTINE (ftpList, param);
164
165 /* GLOBAL CALLBACK RESULT */
166 _ftp_status lastStatusFromEmptyCallback = FTP_FAIL;
167 char *lastFileListFromEmptyCallback = NULL;
168
169 /* FUNCTIONS IMPLEMENTATION */
170
171 void
172 emptyCallback (_ftp_status status, void *arg, _ftp_t *callingFtp)
173 {
174   FTP_PRINT ("Called with status %d\n", status);
175 #if _FTP_VERBOSE
176   if (FTP_PROGRESS == status)
177     {
178       FTP_PRINT ("Trying float arg : %f\n", (NULL != arg) ? *(float *)arg : -1.0);
179     }
180 #endif
181   lastStatusFromEmptyCallback = status;
182   if(FTP_SUCCESS == status && NULL != arg)
183     {
184       lastFileListFromEmptyCallback = (char *)arg;
185     }
186 }
187
188 #define FTP_MAX_NUM_RETRIES 5
189 _ftp_status
190 waitFor226Answer (_ftp_t *ftp)
191 {
192   char srvMsg[MAX_SIZE_MSG] = {0};
193   int repCode = 0;
194   int numretries = FTP_MAX_NUM_RETRIES;
195
196   _ftp_status ftp_result = FTP_SUCCESS;
197   while (226 != repCode && 0 < numretries)
198     {
199       ftp_result = ftpRecv (ftp, srvMsg, MAX_SIZE_MSG-1);
200       if (FTP_FAILED (ftp_result))
201         {
202           numretries--;
203         }
204       repCode = getResponseCode (srvMsg);
205     }
206   return ftp_result;
207 }
208
209 int
210 setSockTimeout (int socket, int timeoutSec, int timeoutUsec)
211 {
212 #ifdef _WIN32
213   int winTO = (1000 * timeoutSec) + (timeoutUsec / 1000);
214 #else
215   struct timeval posixTO;
216   posixTO.tv_sec = timeoutSec;
217   posixTO.tv_usec = timeoutUsec;
218 #endif
219
220   if (0 > setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO,
221 #ifdef _WIN32
222                       (const char *)&winTO, sizeof (winTO)
223 #else
224                       (const char *)&posixTO, sizeof (posixTO)
225 #endif
226                       ))
227     {
228       FTP_ERROR ("Unable to set recv timeout\n");
229       return -1;
230     }
231
232   if (0 > setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO,
233 #ifdef _WIN32
234                       (const char *)&winTO, sizeof (winTO)
235 #else
236                       (const char *)&posixTO, sizeof (posixTO)
237 #endif
238                       ))
239     {
240       FTP_ERROR ("Unable to set send timeout\n");
241       return -1;
242     }
243   return 0;
244 }
245
246 _ftp_status
247 goToBinaryMode (_ftp_t *ftp)
248 {
249   char ftpAnswer[256] = {0};
250   _ftp_status ftp_result = ftpTransfert (ftp, "TYPE I\r\n\0", ftpAnswer, 255);
251   if (FTP_FAILED (ftp_result))
252     {
253       FTP_ERROR ("Unable to go to binary mode\n");
254     }
255   return ftp_result;
256 }
257
258 void
259 flushFtp (_ftp_t *ftp)
260 {
261   FTP_DEBUG ("Starting flush\n");
262   char c = 0;
263   int bytes = 1;
264   int flushedBytes = 0;
265   VP_COM_SOCKET_BLOCKING_OPTIONS oldOptions = ftp->socket->block;
266   ftp->socket->block = VP_COM_DONTWAIT;
267   C_RESULT vp_result = ftp->readSock (ftp->socket, (int8_t *)&c, &bytes);
268   while (0 < bytes && VP_SUCCEEDED (vp_result))
269     {
270       flushedBytes++;
271 #if _FTP_DEBUG
272       printf ("%c", c);
273 #endif
274       vp_result = ftp->readSock (ftp->socket, (int8_t *)&c, &bytes);
275     }
276   FTP_DEBUG ("Flushed %d bytes\n", flushedBytes);
277   ftp->socket->block = oldOptions;
278 }
279
280 int
281 getFileSize (_ftp_t *ftp, const char *distPath)
282 {
283   char ftpCommand[256] = {0};
284   snprintf (ftpCommand, sizeof (ftpCommand)-1, "SIZE %s\r\n", distPath);
285   char ftpAnswer[256] = {0};
286   _ftp_status ftp_result = ftpTransfert (ftp, ftpCommand, ftpAnswer, sizeof (ftpAnswer)-1);
287   if (FTP_FAILED (ftp_result))
288     {
289       FTP_ERROR ("Unable to get file size\n");
290       return -1;
291     }
292   int size = -1;
293   int repCode = 0;
294   sscanf (ftpAnswer, "%d %d", &repCode, &size);
295   return size;
296 }
297
298 int
299 getLocalFileSize (const char *localPath)
300 {
301   FILE *localFile = fopen (localPath, "r");
302   if (NULL == localFile)
303     {
304       FTP_DEBUG ("File %s does not exist\n", localPath);
305       return -1;
306     }
307   fseek (localFile, 0, SEEK_END);
308   int size = (int)ftell (localFile);
309   FTP_DEBUG ("Size of file %s : %d o\n", localPath, size);
310   fclose (localFile);
311   return size;
312 }
313
314 int
315 getResponseCode (const char *response)
316 {
317   int retVal = -1;
318   sscanf (response, "%d", &retVal);
319   return retVal;
320 }
321
322 _ftp_status
323 getPassiveIpAndPort (const char *response, char *ip, int *port, int ipLen)
324 {
325   int ip1, ip2, ip3, ip4, port1, port2;
326   int indexOfFirstIpField = 0;
327   char atIndex = '\0';
328   int maxIndex = strlen (response);
329   while (indexOfFirstIpField < maxIndex && '(' != atIndex)
330     {
331       atIndex = response[indexOfFirstIpField++];
332     }
333   int numread = sscanf (&response[indexOfFirstIpField], "%d,%d,%d,%d,%d,%d)", &ip1, &ip2, &ip3, &ip4, &port1, &port2);
334   _ftp_status result = FTP_SUCCESS;
335   if (6 == numread)
336     {
337       snprintf (ip, ipLen-1, "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
338       *port = 256 * port1 + port2;
339       FTP_DEBUG ("IP : %s | Port : %d\n", ip, *port);
340     }
341   else
342     {
343       result = FTP_FAIL;
344     }
345   return result;
346 }
347
348 _ftp_status
349 ftpTransfert (_ftp_t *ftp, const char *message, char *answer, int answSize)
350 {
351   flushFtp (ftp);
352   _ftp_status ftp_result = ftpSend (ftp, message);
353   if (FTP_FAILED (ftp_result))
354     {
355       return ftp_result;
356     }
357   return ftpRecv (ftp, answer, answSize);
358 }
359
360 _ftp_status
361 ftpSend (_ftp_t *ftp, const char *message)
362 {
363   if (NULL == ftp)
364     {
365       FTP_ERROR ("FTP not open\n");
366       return FTP_FAIL;
367     }
368   FTP_DEBUG ("Sending %sto FTP at %s:%d\n", message, ftp->socket->serverHost, ftp->socket->port);
369
370   int bytes = strlen (message);
371   C_RESULT vp_result = ftp->writeSock (ftp->socket, (int8_t *)message, &bytes);
372   if (VP_FAILED (vp_result))
373     {
374       FTP_ERROR ("Error while sending data\n");
375       return FTP_FAIL;
376     }
377   if (0 == bytes)
378     {
379       FTP_ERROR ("Unable to send data\n");
380       return FTP_TIMEOUT;
381     }
382   return FTP_SUCCESS;
383 }
384
385 _ftp_status
386 ftpRecv (_ftp_t *ftp, char *answer, int answSize)
387 {
388   if (NULL == ftp)
389     {
390       FTP_ERROR ("FTP not open\n");
391       return FTP_FAIL;
392     }
393
394   vp_os_memset (answer, 0x0, answSize);
395   int index = 0;
396   do
397     {
398       int bytes = 1;
399       C_RESULT vp_result = ftp->readSock (ftp->socket, (int8_t *)(&answer [index]), &bytes);
400       if (VP_FAILED (vp_result))
401         {
402           FTP_ERROR ("Error while reading data\n");
403           return FTP_FAIL;
404         }
405       if (0 == bytes)
406         {
407           FTP_ERROR ("Recv timeout\n");
408           return FTP_TIMEOUT;
409         }
410     }
411   while (index < answSize && '\n' != answer [index++]);
412
413   FTP_DEBUG ("Answer:\n<---START--->\n%s\n<---END--->\n", answer);
414   return FTP_SUCCESS;
415 }
416
417 _ftp_status
418 ftpClose (_ftp_t **ftp)
419 {
420   FTP_DEBUG ("Closing ftp\n");
421   _ftp_status retVal = FTP_FAIL;
422   if (NULL != *ftp)
423     {
424       FTP_DEBUG ("Not null ftp\n");
425       if (NULL != (*ftp)->socket)
426         {
427           FTP_DEBUG ("Not null socket\n");
428           if (1 == (*ftp)->connected)
429             {
430               if (FTP_SUCCESS == ftpAbort ((*ftp))) // An operation was in progress, abort and let time to cleanup.
431               {
432                 usleep (100000); // 100ms
433               }
434               ftpSend ((*ftp), "QUIT\r\n\0");
435               (*ftp)->connected = 0;
436             }
437           vp_com_close_socket ((*ftp)->socket);
438           vp_os_free ((*ftp)->socket);
439           (*ftp)->socket = NULL;
440           retVal = FTP_SUCCESS;
441         }
442       vp_os_free (*ftp);
443       *ftp = NULL;
444     }
445   return retVal;
446 }
447
448 _ftp_t *
449 ftpConnectFromName (const char *name, int port, const char *username, const char *password, _ftp_status *status)
450 {
451         struct hostent *hostent = gethostbyname(name);
452         return ftpConnect(inet_ntoa( *( struct in_addr*)( hostent->h_addr)), port, username, password, status);
453 }
454
455 _ftp_t *
456 ftpConnect (const char *ip, int port, const char *username, const char *password, _ftp_status *status)
457 {
458   if (NULL == ip ||
459       NULL == username ||
460       NULL == password ||
461       NULL == status)
462     {
463       FTP_ERROR ("Must not pass NULL pointers to ftpConnect\n");
464       if (NULL != status) { *status = FTP_FAIL; }
465       return NULL;
466     }
467   int isAnonymous = ((0 == strcmp (username, "anonymous")) || (0 == strcmp (username, ""))) ? 1 : 0;
468   if (1 == isAnonymous)
469     {
470       FTP_DEBUG ("Connecting to %s:%d, anonymous\n", ip, port);
471     }
472   else
473     {
474       FTP_DEBUG ("Connecting to %s:%d, USER = %s, Password = %s\n", ip, port, username, password);
475     }
476
477   *status = FTP_FAIL;
478   _ftp_t *retFtp = vp_os_malloc (sizeof (_ftp_t));
479   if (NULL == retFtp)
480     {
481       FTP_ERROR ("Unable to allocate a ftp structure\n");
482       return NULL;
483     }
484   retFtp->socket = vp_os_malloc (sizeof (vp_com_socket_t));
485   if (NULL == retFtp->socket)
486     {
487       FTP_ERROR ("Unable to allocate socket filed of the ftp structure\n");
488       ftpClose (&retFtp);
489       return NULL;
490     }
491
492   retFtp->connected = 0;
493
494   retFtp->socket->type = VP_COM_CLIENT;
495   retFtp->socket->protocol = VP_COM_TCP;
496   retFtp->socket->port = port;
497   strncpy (retFtp->socket->serverHost, ip, VP_COM_NAME_MAXSIZE-1);
498   retFtp->socket->is_multicast = 0;
499   retFtp->socket->block = VP_COM_DEFAULT;
500
501   C_RESULT vp_result = vp_com_open_socket (retFtp->socket, &(retFtp->readSock), &(retFtp->writeSock));
502   if (VP_FAILED (vp_result))
503     {
504       FTP_ERROR ("Unable to connect\n");
505       ftpClose (&retFtp);
506       return NULL;
507     }
508   
509   int result = setSockTimeout ((int)retFtp->socket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
510   if (0 > result)
511     {
512       FTP_ERROR ("Unable to set socket timeout\n");
513       ftpClose (&retFtp);
514       return NULL;
515     }
516
517   char srvMsg[MAX_SIZE_MSG] = {0};
518   if (FTP_FAILED (ftpRecv (retFtp, srvMsg, MAX_SIZE_MSG-1)))
519     {
520       FTP_ERROR ("Unable to recieve data from server\n");
521       ftpClose (&retFtp);
522       return NULL;
523     }
524
525   int repCode = getResponseCode (srvMsg);
526   if (220 != repCode)
527     {
528       FTP_ERROR ("Bad response from server (%d, expected 220)\n", repCode);
529       ftpClose (&retFtp);
530       return NULL;
531     }
532
533
534   char buffer[256] = {0};
535   if (1 == isAnonymous)
536     {
537       snprintf (buffer, sizeof (buffer)-1, "USER anonymous\r\n");
538     }
539   else
540     {
541       snprintf (buffer, sizeof (buffer)-1, "USER %s\r\n", username);
542     }
543   if (FTP_FAILED (ftpTransfert (retFtp, buffer, srvMsg, MAX_SIZE_MSG-1)))
544     {
545       FTP_ERROR ("Error while sending command\n");
546       ftpClose (&retFtp);
547       return NULL;
548     }
549   repCode = getResponseCode (srvMsg);
550   int goodRepCode = 331;
551   if (1 == isAnonymous)
552     {
553       goodRepCode = 230;
554     }
555   if (goodRepCode != repCode)
556     {
557       FTP_ERROR ("Bad response from server (%d, expected %d)\n", repCode, goodRepCode);
558       ftpClose (&retFtp);
559       return NULL;
560     }
561
562   if (0 == isAnonymous)
563     {
564       vp_os_memset (buffer, 0x0, sizeof (buffer));
565       snprintf (buffer, sizeof (buffer)-1, "PASS %s\r\n", password);
566       if (FTP_FAILED (ftpTransfert (retFtp, buffer, srvMsg, MAX_SIZE_MSG-1)))
567         {
568           FTP_ERROR ("Error while sending command\n");
569           ftpClose (&retFtp);
570           return NULL;
571         }
572       repCode = getResponseCode (srvMsg);
573       if (230 != repCode)
574         {
575           FTP_ERROR ("Bad response from server (%d, expected 230)\n", repCode);
576           ftpClose (&retFtp);
577           return NULL;
578         }
579     }
580
581   *status = FTP_SUCCESS;
582   retFtp->connected = 1;
583   retFtp->opInProgress = 0;
584   retFtp->abortCurrentOp = 0;
585   return retFtp;
586 }
587
588
589 #undef CLEAN_PARAMS
590 #define CLEAN_PARAMS(status) CLEAN_PARAMS_WITH_ARG(status,NULL)
591 #undef CLEAN_PARAMS_WITH_ARG
592 #define CLEAN_PARAMS_WITH_ARG(status,arg)       \
593   do                                            \
594     {                                           \
595       params->ftp->opInProgress = 0;            \
596       CLEAN_PARAMS_ABORT (status,arg);          \
597     } while (0)
598 #undef CLEAN_PARAMS_ABORT
599 #define CLEAN_PARAMS_ABORT(status,arg)                                  \
600   do                                                                    \
601     {                                                                   \
602       _ftp_status locStat = (status);                                   \
603       if (NULL != localFile) fclose (localFile);                        \
604       if (NULL != dataSocket)                                           \
605         {                                                               \
606           vp_com_close_socket (dataSocket);                             \
607           vp_os_free (dataSocket);                                      \
608           dataSocket = NULL;                                            \
609         }                                                               \
610       params->callback (locStat, arg, params->ftp);                     \
611       if (FTP_SUCCESS != status && NULL != params->fileList)            \
612         {                                                               \
613           vp_os_free (params->fileList);                                \
614           params->fileList = NULL;                                      \
615         }                                                               \
616       vp_os_free (param);                                               \
617       FTP_DEBUG ("Returning from thread %s with status %d\n", __FUNCTION__, locStat); \
618       THREAD_RETURN (locStat);                                          \
619     }                                                                   \
620   while (0)
621 #undef CHECK_ABORT
622 #define CHECK_ABORT                                                     \
623   do                                                                    \
624     {                                                                   \
625       if (1 <= params->ftp->abortCurrentOp)                             \
626         {                                                               \
627           vp_os_memset (srvMsg, 0x0, MAX_SIZE_MSG);                     \
628           if (NULL != dataSocket)                                       \
629             {                                                           \
630               vp_com_close_socket (dataSocket);                         \
631               vp_os_free (dataSocket);                                  \
632               dataSocket = NULL;                                        \
633             }                                                           \
634           ftpTransfert (params->ftp, "ABOR\r\n\0", srvMsg, MAX_SIZE_MSG-1); \
635           flushFtp (params->ftp);                                       \
636           params->ftp->abortCurrentOp = 0;                              \
637           params->ftp->opInProgress = 0;                                \
638           CLEAN_PARAMS_ABORT (FTP_ABORT, NULL);                         \
639         }                                                               \
640     } while (0)
641
642 DEFINE_THREAD_ROUTINE (ftpList, param)
643 {
644   FILE *localFile = NULL; // Compatibilty with macros
645   vp_com_socket_t *dataSocket = NULL;
646   Read dataRead = NULL;
647   Write dataWrite = NULL;
648   _ftp_list_param *params = (_ftp_list_param *)param;
649   if (NULL == params->ftp)
650     {
651       FTP_ERROR ("FTP not open\n");
652       CLEAN_PARAMS (FTP_FAIL);
653     }
654   flushFtp (params->ftp);
655   
656   char srvMsg [MAX_SIZE_MSG] = {0};
657   _ftp_status ftp_result = ftpTransfert (params->ftp, "PASV\r\n\0", srvMsg, MAX_SIZE_MSG-1);
658   if (FTP_FAILED (ftp_result))
659     {
660       FTP_ERROR ("Error while sending command\n");
661       CLEAN_PARAMS (ftp_result);
662     }
663   int repCode = getResponseCode (srvMsg);
664   if (227 != repCode)
665     {
666       FTP_ERROR ("Bad response from server (%d, expected 227)\n", repCode);
667       CLEAN_PARAMS (FTP_FAIL);
668     }
669   
670   char dataIp [IP_STRING_SIZE] = {0};
671   int dataPort = 0;
672   getPassiveIpAndPort (srvMsg, dataIp, &dataPort, IP_STRING_SIZE);
673   
674   FTP_DEBUG ("Thread will connect to %s:%d\n", dataIp, dataPort);
675   dataSocket = vp_os_malloc (sizeof (vp_com_socket_t));
676   if (NULL == dataSocket)
677     {
678       FTP_ERROR ("Unable to allocate socket structure\n");
679       CLEAN_PARAMS (FTP_FAIL);
680     }
681   dataSocket->type = VP_COM_CLIENT;
682   dataSocket->protocol = VP_COM_TCP;
683   dataSocket->port = dataPort;
684   strncpy (dataSocket->serverHost, dataIp, VP_COM_NAME_MAXSIZE);
685   dataSocket->is_multicast = 0;
686   dataSocket->block = VP_COM_WAITALL;
687   
688   C_RESULT vp_result = vp_com_open_socket (dataSocket, &dataRead, &dataWrite);
689   if (VP_FAILED (vp_result))
690     {
691       FTP_ERROR ("Unable to connect\n");
692       CLEAN_PARAMS (FTP_FAIL);
693     }
694   
695   int result = setSockTimeout ((int)dataSocket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
696   if (0 > result)
697     {
698       FTP_ERROR ("Unable to set data socket timeout\n");
699       CLEAN_PARAMS (FTP_FAIL);
700     }
701   
702   CHECK_ABORT;
703   
704   ftp_result = ftpSend (params->ftp, "LIST\r\n\0");
705   if (FTP_FAILED (ftp_result))
706     {
707       FTP_ERROR ("Error while sending LIST command\n");
708       CLEAN_PARAMS (ftp_result);
709     }
710   
711   CHECK_ABORT;
712   char ftpData [2] = {0};
713   int bytes = 1, totalBytes;
714   vp_os_memset (params->fileList, 0x0, params->listSize);
715   vp_result = dataRead (dataSocket, (int8_t *)ftpData, &bytes);
716   if (VP_FAILED (vp_result))
717     {
718       FTP_ERROR ("Unable to receive data\n");
719       CLEAN_PARAMS (FTP_FAIL);
720     }
721   if(0 == bytes)
722     {
723       FTP_DEBUG ("Empty folder\n");
724       waitFor226Answer (params->ftp);
725       flushFtp (params->ftp);
726       CLEAN_PARAMS (FTP_SAMESIZE);
727     }
728
729   if (strlen (ftpData) > params->listSize - 1)
730     {
731       params->listSize += LIST_BUFFER_BLOCKSIZE;
732       params->fileList = vp_os_realloc(params->fileList, params->listSize);
733       if(NULL == params->fileList)
734         {
735           FTP_ERROR ("Not enough space in response string, can't reallocate buffer list\n");
736           CLEAN_PARAMS (FTP_FAIL);
737         }
738     }
739   snprintf (params->fileList, params->listSize-1, "%s", ftpData);
740   totalBytes = bytes;
741   while (1) // Loop is killed by a return or a break statement
742     {
743       CHECK_ABORT;
744       ftpData [0] = 0;
745       bytes = 1;
746       vp_result = dataRead (dataSocket, (int8_t *)ftpData, &bytes);
747       if (VP_FAILED (vp_result))
748         {
749           FTP_ERROR ("Unable to receive data\n");
750           CLEAN_PARAMS (FTP_FAIL);
751         }
752       if (0 == bytes && '\n' == params->fileList [totalBytes-1])
753         {
754           FTP_DEBUG ("Got all listing !\n");
755           // Timeouted. We got all the listing !
756           // Timeout is voluntary, so still return FTP_SUCCESS
757           break;
758         }
759       else if (0 == bytes)
760         {
761           // Timeout
762           FTP_ERROR ("Recv timeout\n");
763           CLEAN_PARAMS (FTP_TIMEOUT);
764         }
765       if (strlen (ftpData) > (params->listSize - 1 - strlen (params->fileList)))
766         {
767           params->listSize += LIST_BUFFER_BLOCKSIZE;
768           params->fileList = vp_os_realloc(params->fileList, params->listSize);
769           if(NULL == params->fileList)
770             {
771               FTP_ERROR ("Not enough space in response string, can't reallocate buffer list\n");
772               CLEAN_PARAMS (FTP_FAIL);
773             }
774         }
775       strcat (params->fileList, ftpData);
776       totalBytes += bytes;
777       FTP_PRINT ("Progress of listing : finished ? %d : (%d->%d bytes) %s\n", (params->response [totalBytes -1] == '\n') ? 1: 0, bytes, totalBytes, params->response);
778     }
779
780   ftp_result = ftpRecv (params->ftp, srvMsg, MAX_SIZE_MSG-1);
781   if (FTP_FAILED (ftp_result))
782     {
783       FTP_ERROR ("Error while getting answer\n"); 
784       CLEAN_PARAMS (ftp_result);
785     }
786   repCode = getResponseCode (srvMsg);
787   if (150 != repCode)
788     {
789       FTP_ERROR ("Bad response from server (%d, expected 150)\n", repCode);
790       CLEAN_PARAMS (FTP_FAIL);
791     }
792
793   /* Cleaning FTP */
794   if (NULL != dataSocket)
795     {
796       vp_com_close_socket (dataSocket);
797       vp_os_free (dataSocket);
798       dataSocket = NULL;
799     }
800   waitFor226Answer (params->ftp);
801   flushFtp (params->ftp);
802
803
804   CLEAN_PARAMS_WITH_ARG (FTP_SUCCESS, (void *)params->fileList);
805 }
806
807 DEFINE_THREAD_ROUTINE (ftpGet, param)
808 {
809   vp_com_socket_t *dataSocket = NULL;
810   Read dataRead = NULL;
811   Write dataWrite = NULL;
812   FILE *localFile = NULL;
813   _ftp_get_param *params = (_ftp_get_param *)param;
814   FTP_DEBUG ("Downloading %s to %s [resume : %c]\n", params->remoteName, params->localName, params->useResume ? 'y' : 'n');
815   if (NULL == params->ftp)
816     {
817       FTP_ERROR ("FTP not open\n");
818       CLEAN_PARAMS (FTP_FAIL);
819     }
820   flushFtp (params->ftp);
821
822   char buffer[512] = {0};
823   char srvMsg[MAX_SIZE_MSG] = {0};
824   snprintf (buffer, sizeof (buffer)-1, "PASV\r\n");
825   _ftp_status ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
826   if (FTP_FAILED (ftp_result))
827     {
828       FTP_ERROR ("Error while entering passive mode\n");
829       CLEAN_PARAMS (ftp_result);
830     }
831   int repCode = getResponseCode (srvMsg);
832   if (227 != repCode)
833     {
834       FTP_ERROR ("Bad response from server (%d, expected 227)\n", repCode);
835       CLEAN_PARAMS (FTP_FAIL);
836     }
837
838   ftp_result = goToBinaryMode (params->ftp);
839   if (FTP_FAILED (ftp_result))
840     {
841       FTP_ERROR ("Unable to go to binary mode\n");
842       CLEAN_PARAMS (ftp_result);
843     } 
844
845   int fileSize = getFileSize (params->ftp, params->remoteName);
846   if (0 >= fileSize)
847     {
848       FTP_ERROR ("File %s does not exist on server\n", params->remoteName);
849       CLEAN_PARAMS (FTP_FAIL);
850     }
851   int sizeToGet = fileSize;
852   int localFileSize = getLocalFileSize (params->localName);
853   int appendToFile = params->useResume;
854   int appendOffset = 0;
855   if (-1 == localFileSize && 1 == params->useResume)
856     {
857       FTP_DEBUG ("File does not exist ... full download\n");
858       appendToFile = 0;
859     }
860   if (1 == appendToFile)
861     {
862       if (localFileSize == fileSize)
863         {
864           FTP_DEBUG ("File already downloaded\n");
865           CLEAN_PARAMS (FTP_SAMESIZE);
866         }
867       else if (localFileSize > fileSize)
868         {
869           FTP_ERROR ("Local file (%s) is greater than distant file (%s)\n", params->localName, params->remoteName);
870           CLEAN_PARAMS (FTP_BADSIZE);
871         }
872       sizeToGet = fileSize - localFileSize;
873
874       char buffer[50] = {0};
875       appendOffset = fileSize - sizeToGet;
876       snprintf (buffer, sizeof (buffer)-1, "REST %d\r\n", appendOffset);
877       char srvAnsw[MAX_SIZE_MSG] = {0};
878       _ftp_status ftp_result = ftpTransfert (params->ftp, buffer, srvAnsw, MAX_SIZE_MSG-1);
879       if (FTP_FAILED (ftp_result))
880         {
881           FTP_ERROR ("Unable to set server offset\n");
882           CLEAN_PARAMS (ftp_result);
883         }
884     }
885
886   char dataIp [IP_STRING_SIZE] = {0};
887   int dataPort = 0;
888   getPassiveIpAndPort (srvMsg, dataIp, &dataPort, IP_STRING_SIZE);
889  
890   FTP_DEBUG ("Thread will connect to %s:%d\n", dataIp, dataPort);
891   dataSocket = vp_os_malloc (sizeof (vp_com_socket_t));
892   if (NULL == dataSocket)
893     {
894       FTP_ERROR ("Unable to allocate socket structure\n");
895       CLEAN_PARAMS (FTP_FAIL);
896     }
897   dataSocket->type = VP_COM_CLIENT;
898   dataSocket->protocol = VP_COM_TCP;
899   dataSocket->port = dataPort;
900   strncpy (dataSocket->serverHost, dataIp, VP_COM_NAME_MAXSIZE);
901   dataSocket->is_multicast = 0;
902   dataSocket->block = VP_COM_WAITALL;
903
904   C_RESULT vp_result = vp_com_open_socket (dataSocket, &dataRead, &dataWrite);
905   if (VP_FAILED (vp_result))
906     {
907       FTP_ERROR ("Unable to connect\n");
908       CLEAN_PARAMS (FTP_FAIL);
909     }
910
911   int result = setSockTimeout ((int)dataSocket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
912   if (0 > result)
913     {
914       FTP_ERROR ("Unable to set data socket timeout\n");
915       CLEAN_PARAMS (FTP_FAIL);
916     }
917
918   CHECK_ABORT;
919
920   vp_os_memset (buffer, 0x0, sizeof (buffer));
921   snprintf (buffer, sizeof (buffer)-1, "RETR %s\r\n", params->remoteName);
922   ftp_result = ftpSend (params->ftp, buffer);
923   if (FTP_FAILED (ftp_result))
924     {
925       FTP_ERROR ("Error while sending RETR command\n");
926       CLEAN_PARAMS (ftp_result);
927     }
928
929   int sizeGot = appendOffset;
930   float percentGot = (sizeGot * 100.0) / (fileSize *1.0);
931   params->callback (FTP_PROGRESS, (void *)&percentGot, params->ftp);
932   
933   char filePart [MAX_SIZE_MSG] = {0};
934
935
936   if (1 == appendToFile)
937     {
938       localFile = fopen (params->localName, "ab");
939     }
940   else
941     {
942       localFile = fopen (params->localName, "wb");
943     }
944   if (NULL == localFile)
945     {
946       FTP_ERROR ("Unable to open dest file %s\n", params->localName);
947       CLEAN_PARAMS (FTP_FAIL);
948     }
949   while (sizeGot < fileSize)
950     {
951       CHECK_ABORT;
952       int bytes = MAX_SIZE_MSG-1;
953       C_RESULT vp_result = dataRead (dataSocket, (int8_t *)filePart, &bytes);
954       if (VP_FAILED (vp_result))
955         {
956           FTP_ERROR ("Error while receiving data\n");
957           CLEAN_PARAMS (FTP_FAIL);
958         }
959       if (0 >= bytes)
960         {
961           FTP_ERROR ("Recv timeout\n");
962           CLEAN_PARAMS (FTP_TIMEOUT);
963         }
964       if (0 > fwrite (filePart, 1, bytes, localFile))
965         {
966           FTP_ERROR ("Unable to write to file\n");
967           CLEAN_PARAMS (FTP_FAIL);
968         }
969       sizeGot += bytes;
970       percentGot = (sizeGot * 100.0) / (fileSize * 1.0);
971       params->callback (FTP_PROGRESS, (void *)&percentGot, params->ftp);
972     }
973   ftp_result = ftpRecv (params->ftp, srvMsg, MAX_SIZE_MSG-1);
974   if (FTP_FAILED (ftp_result))
975     {
976       FTP_ERROR ("Error while getting answer\n"); 
977       CLEAN_PARAMS (ftp_result);
978     }
979   repCode = getResponseCode (srvMsg);
980   if (150 != repCode)
981     {
982       FTP_ERROR ("Bad response from server (%d, expected 150)\n", repCode);
983       CLEAN_PARAMS (FTP_FAIL);
984     }
985
986   /* Cleaning FTP */
987   if (NULL != dataSocket)
988     {
989       vp_com_close_socket (dataSocket);
990       vp_os_free (dataSocket);
991       dataSocket = NULL;
992     }
993   waitFor226Answer (params->ftp);
994   flushFtp (params->ftp);
995
996   CLEAN_PARAMS (FTP_SUCCESS);
997 }
998
999 DEFINE_THREAD_ROUTINE (ftpPut, param)
1000 {
1001   vp_com_socket_t *dataSocket = NULL;
1002   Read dataRead = NULL;
1003   Write dataWrite = NULL;
1004   FILE *localFile = NULL;
1005   _ftp_put_param *params = (_ftp_put_param *)param;
1006   FTP_DEBUG ("Uploading %s to %s [resume : %c]\n", params->localName, params->remoteName, params->useResume ? 'y' : 'n');
1007   if (NULL == params->ftp)
1008     {
1009       FTP_ERROR ("FTP not open\n");
1010       CLEAN_PARAMS (FTP_FAIL);
1011     }
1012   flushFtp (params->ftp);
1013
1014   char buffer[512] = {0};
1015   char srvMsg[MAX_SIZE_MSG] = {0};
1016   snprintf (buffer, sizeof (buffer)-1, "PASV\r\n");
1017   _ftp_status ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1018   if (FTP_FAILED (ftp_result))
1019     {
1020       FTP_ERROR ("Error while entering passive mode\n");
1021       CLEAN_PARAMS (ftp_result);
1022     }
1023   int repCode = getResponseCode (srvMsg);
1024   if (227 != repCode)
1025     {
1026       FTP_ERROR ("Bad response from server (%d, expected 227)\n", repCode);
1027       CLEAN_PARAMS (FTP_FAIL);
1028     }
1029
1030   ftp_result = goToBinaryMode (params->ftp);
1031   if (FTP_FAILED (ftp_result))
1032     {
1033       FTP_ERROR ("Unable to go to binary mode\n");
1034       CLEAN_PARAMS (ftp_result);
1035     }
1036   
1037   int localFileSize = getLocalFileSize (params->localName);
1038   if (0 >= localFileSize)
1039     {
1040       FTP_ERROR ("File %s does not exist on filesystem\n", params->localName);
1041       CLEAN_PARAMS (FTP_FAIL);
1042     }
1043   int fileSize = getFileSize (params->ftp, params->remoteName);
1044   int sizeToPut = localFileSize;
1045   int appendToFile = params->useResume;
1046   int appendOffset = 0;
1047   if (-1 == fileSize && 1 == params->useResume)
1048     {
1049       FTP_DEBUG ("File does not exist on server ... full upload\n");
1050       appendToFile = 0;
1051     }
1052   if (1 == appendToFile)
1053     {
1054       if (localFileSize == fileSize)
1055         {
1056           FTP_DEBUG ("File already uploaded\n");
1057           CLEAN_PARAMS (FTP_SAMESIZE);
1058         }
1059       else if (localFileSize < fileSize)
1060         {
1061           FTP_ERROR ("Distant file (%s) is greather than local file (%s)\n", params->remoteName, params->localName);
1062           CLEAN_PARAMS (FTP_BADSIZE);
1063         }
1064       sizeToPut = localFileSize - fileSize;
1065
1066       char buffer [50] = {0};
1067       appendOffset = localFileSize - sizeToPut;
1068       snprintf (buffer, sizeof (buffer)-1, "REST %d\r\n", appendOffset);
1069       char srvAnswer[MAX_SIZE_MSG] = {0};
1070       ftp_result = ftpTransfert (params->ftp, buffer, srvAnswer, MAX_SIZE_MSG-1);
1071       if (FTP_FAILED (ftp_result))
1072         {
1073           FTP_ERROR ("Unable to set server offset\n");
1074           CLEAN_PARAMS (ftp_result);
1075         }
1076     }
1077
1078   char dataIp [IP_STRING_SIZE] = {0};
1079   int dataPort = 0;
1080   getPassiveIpAndPort (srvMsg, dataIp, &dataPort, IP_STRING_SIZE);
1081
1082   FTP_DEBUG ("Thread will connect to %s:%d\n", dataIp, dataPort);
1083   dataSocket = vp_os_malloc (sizeof (vp_com_socket_t));
1084   if (NULL == dataSocket)
1085     {
1086       FTP_ERROR ("Unable to allocate socket structure\n");
1087       CLEAN_PARAMS (FTP_FAIL);
1088     }
1089   dataSocket->type = VP_COM_CLIENT;
1090   dataSocket->protocol = VP_COM_TCP;
1091   dataSocket->port = dataPort;
1092   strncpy (dataSocket->serverHost, dataIp, VP_COM_NAME_MAXSIZE);
1093   dataSocket->is_multicast = 0;
1094   dataSocket->block = VP_COM_DEFAULT;
1095
1096   C_RESULT vp_result = vp_com_open_socket (dataSocket, &dataRead, &dataWrite);
1097   if (VP_FAILED (vp_result))
1098     {
1099       FTP_ERROR ("Unable to connect\n");
1100       CLEAN_PARAMS (FTP_FAIL);
1101     }
1102
1103   int result = setSockTimeout ((int)dataSocket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
1104   if (0 > result)
1105     {
1106       FTP_ERROR ("Unable to set data socket timeout\n");
1107       CLEAN_PARAMS (FTP_FAIL);
1108     }
1109
1110   CHECK_ABORT;
1111
1112   vp_os_memset (buffer, 0x0, sizeof (buffer));
1113   snprintf (buffer, sizeof (buffer)-1, "STOR %s\r\n", params->remoteName);
1114   ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1115   if (FTP_FAILED (ftp_result))
1116     {
1117       FTP_ERROR ("Error while sending command\n");
1118       CLEAN_PARAMS (ftp_result);
1119     }
1120   repCode = getResponseCode (srvMsg);
1121   if (150 != repCode)
1122     {
1123       FTP_ERROR ("Bad response from server (%d, expected 150)\n", repCode);
1124       CLEAN_PARAMS (FTP_FAIL);
1125     }
1126
1127   int sizeSent = appendOffset;
1128   float percentSend = (sizeSent * 100.0) / (localFileSize *1.0);
1129   params->callback (FTP_PROGRESS, (void *)&percentSend, params->ftp);
1130
1131   int numberOfFullSendNeeded = (sizeToPut / (MAX_SIZE_MSG-1));
1132   int partialSendNeeded = (sizeToPut % (MAX_SIZE_MSG-1)); // Zero if not needed, non-zero if needed
1133   char filePart [MAX_SIZE_MSG] = {0};
1134
1135   localFile = fopen (params->localName, "rb");
1136   if (NULL == localFile)
1137     {
1138       FTP_ERROR ("Unable to open source file %s\n", params->localName);
1139       CLEAN_PARAMS (FTP_FAIL);
1140     }
1141   fseek (localFile, appendOffset, SEEK_SET);
1142
1143   int numSend = 0;
1144   for (numSend = 0; numSend < numberOfFullSendNeeded; numSend++)
1145     {
1146       CHECK_ABORT;
1147       int bytes = fread (filePart, 1, MAX_SIZE_MSG-1, localFile);
1148       if (0 > bytes)
1149         {
1150           FTP_ERROR ("Unable to read from file\n");
1151           CLEAN_PARAMS (FTP_FAIL);
1152         }
1153       bytes = MAX_SIZE_MSG-1;
1154       C_RESULT vp_result = dataWrite (dataSocket, (int8_t *)filePart, &bytes);
1155       if (VP_FAILED (vp_result))
1156         {
1157           FTP_ERROR ("Unable to send data\n");
1158           CLEAN_PARAMS (FTP_FAIL);
1159         }
1160       if (MAX_SIZE_MSG-1 > bytes)
1161         {
1162           FTP_ERROR ("Send timeout\n");
1163           CLEAN_PARAMS (FTP_TIMEOUT);
1164         }
1165       sizeSent += MAX_SIZE_MSG-1;
1166       percentSend = (sizeSent * 100.0) / (localFileSize * 1.0);
1167       params->callback (FTP_PROGRESS, (void *)&percentSend, params->ftp);
1168     }
1169   
1170   if (0 != partialSendNeeded)
1171     {
1172       CHECK_ABORT;
1173       vp_os_memset (filePart, 0x0, MAX_SIZE_MSG);
1174       int bytes = fread (filePart, 1, MAX_SIZE_MSG-1, localFile);
1175       FTP_DEBUG ("Read %d bytes\n", bytes);
1176       if (0 > bytes)
1177         {
1178           FTP_ERROR ("Unable to read from file\n");
1179           CLEAN_PARAMS (FTP_FAIL);
1180         }
1181       int sendBytes = bytes;
1182       C_RESULT vp_result = dataWrite (dataSocket, (int8_t *)filePart, &sendBytes);
1183       if (VP_FAILED (vp_result))
1184         {
1185           FTP_ERROR ("Unable to send data\n");
1186           CLEAN_PARAMS (FTP_FAIL);
1187         }
1188       if (bytes > sendBytes)
1189         {
1190           FTP_ERROR ("Send timeout\n");
1191           CLEAN_PARAMS (FTP_TIMEOUT);
1192         }
1193       sizeSent += bytes;
1194       percentSend = (sizeSent * 100.0) / (localFileSize * 1.0);
1195       params->callback (FTP_PROGRESS, (void *)&percentSend, params->ftp);
1196     }
1197
1198   /* Cleaning FTP */
1199   if (NULL != dataSocket)
1200     {
1201       vp_com_close_socket (dataSocket);
1202       vp_os_free (dataSocket);
1203       dataSocket = NULL;
1204     }
1205   waitFor226Answer (params->ftp);
1206   flushFtp (params->ftp);
1207
1208   CLEAN_PARAMS (FTP_SUCCESS);
1209 }
1210
1211
1212 _ftp_status
1213 ftpPut (_ftp_t *ftp, const char *localName, const char *remoteName, int useResume, ftp_callback callback)
1214 {
1215   THREAD_HANDLE putThread;
1216   ftp_callback actualCallback = (NULL != callback) ? callback : emptyCallback;
1217   if (NULL == ftp)
1218     {
1219       actualCallback (FTP_FAIL, NULL, ftp);
1220       return FTP_FAIL;
1221     }
1222   if (1 == ftp->opInProgress)
1223     {
1224       actualCallback (FTP_BUSY, NULL, ftp);
1225       return FTP_BUSY;
1226     }
1227   ftp->opInProgress = 1;
1228
1229   _ftp_put_param *param = vp_os_malloc (sizeof (_ftp_put_param));
1230
1231   if (NULL == param)
1232     {
1233       FTP_ERROR ("Unable to allocate thread param\n");
1234       actualCallback (FTP_FAIL, NULL, ftp);
1235       ftp->opInProgress = 0;
1236       return FTP_FAIL;
1237     }
1238
1239   param->ftp = ftp;
1240   strncpy (param->localName, localName, FILE_NAME_MAX_SIZE);
1241   param->localName [FILE_NAME_MAX_SIZE-1] = '\0';
1242   strncpy (param->remoteName, remoteName, FILE_NAME_MAX_SIZE);
1243   param->remoteName [FILE_NAME_MAX_SIZE-1] = '\0';
1244   param->useResume = useResume;
1245   param->callback = actualCallback;
1246   param->fileList = NULL;
1247   _ftp_status threadReturn = FTP_SUCCESS; 
1248
1249   vp_os_thread_create (thread_ftpPut, (THREAD_PARAMS)param, &putThread);
1250
1251   if (NULL == callback)
1252     {
1253       vp_os_thread_join (putThread);
1254       threadReturn = lastStatusFromEmptyCallback;
1255     }
1256
1257   return threadReturn; 
1258 }
1259
1260 _ftp_status
1261 ftpGet (_ftp_t *ftp, const char *remoteName, const char *localName, int useResume, ftp_callback callback)
1262 {
1263   THREAD_HANDLE getThread;
1264   ftp_callback actualCallback = (NULL != callback) ? callback : emptyCallback;
1265   if (NULL == ftp)
1266     {
1267       actualCallback (FTP_FAIL, NULL, ftp);
1268       return FTP_FAIL;
1269     }
1270   if (1 == ftp->opInProgress)
1271     {
1272       actualCallback (FTP_BUSY, NULL, ftp);
1273       return FTP_BUSY;
1274     }
1275   ftp->opInProgress = 1;
1276
1277   _ftp_get_param *param = vp_os_malloc (sizeof (_ftp_get_param));
1278
1279   if (NULL == param)
1280     {
1281       FTP_ERROR ("Unable to allocate thread param\n");
1282       actualCallback (FTP_FAIL, NULL, ftp);
1283       ftp->opInProgress = 0;
1284       return FTP_FAIL;
1285     }
1286
1287   param->ftp = ftp;
1288   strncpy (param->localName, localName, FILE_NAME_MAX_SIZE);
1289   param->localName [FILE_NAME_MAX_SIZE-1] = '\0';
1290   strncpy (param->remoteName, remoteName, FILE_NAME_MAX_SIZE);
1291   param->remoteName [FILE_NAME_MAX_SIZE-1] = '\0';
1292   param->useResume = useResume;
1293   param->callback = actualCallback;
1294   param->fileList = NULL;
1295   _ftp_status threadReturn = FTP_SUCCESS; 
1296
1297   vp_os_thread_create (thread_ftpGet, (THREAD_PARAMS)param, &getThread);
1298
1299   if (NULL == callback)
1300     {
1301       vp_os_thread_join (getThread);
1302       threadReturn = lastStatusFromEmptyCallback;
1303     }
1304
1305   return threadReturn;
1306 }
1307
1308 _ftp_status
1309 ftpList (_ftp_t *ftp, char **fileList,  ftp_callback callback)
1310 {
1311   if (NULL == fileList && NULL == callback)
1312     {
1313       FTP_ERROR ("file list and callback pointer must not be both NULL\n");
1314       return FTP_FAIL;
1315     }
1316   THREAD_HANDLE listThread;
1317   ftp_callback actualCallback = (NULL != callback) ? callback : emptyCallback;
1318   if (NULL == ftp)
1319     {
1320       actualCallback (FTP_FAIL, NULL, ftp);
1321       return FTP_FAIL;
1322     }
1323   if (1 == ftp->opInProgress)
1324     {
1325       actualCallback (FTP_BUSY, NULL, ftp);
1326       return FTP_BUSY;
1327     }
1328   ftp->opInProgress = 1;
1329
1330   _ftp_list_param *param = vp_os_malloc (sizeof (_ftp_list_param));
1331
1332   if (NULL == param)
1333     {
1334       FTP_ERROR ("Unable to allocate thread param\n");
1335       actualCallback (FTP_FAIL, NULL, ftp);
1336       ftp->opInProgress = 0;
1337       return FTP_FAIL;
1338     }
1339
1340   param->fileList = vp_os_malloc (sizeof (char) * LIST_BUFFER_BLOCKSIZE);
1341   if (NULL == param->fileList)
1342     {
1343       FTP_ERROR ("Unable to allocate list buffer\n");
1344       actualCallback (FTP_FAIL, NULL, ftp);
1345       ftp->opInProgress = 0;
1346       vp_os_free (param);
1347       return FTP_FAIL;
1348     }
1349
1350   param->ftp = ftp;
1351   param->listSize = LIST_BUFFER_BLOCKSIZE;
1352   param->callback = actualCallback;
1353   _ftp_status threadReturn = FTP_SUCCESS;
1354
1355   vp_os_thread_create (thread_ftpList, (THREAD_PARAMS)param, &listThread);
1356
1357   if (NULL == callback)
1358     {
1359       vp_os_thread_join (listThread);
1360       threadReturn = lastStatusFromEmptyCallback;
1361       if (FTP_SUCCESS == threadReturn)
1362         {
1363           *fileList = lastFileListFromEmptyCallback;
1364           lastFileListFromEmptyCallback = NULL;
1365         }
1366     }
1367
1368   return threadReturn;
1369 }
1370
1371 _ftp_status
1372 ftpRemove (_ftp_t *ftp, const char *remoteName)
1373 {
1374   _ftp_status ftp_result = FTP_FAIL;
1375   char buffer [256] = {0};
1376   char srvMsg [MAX_SIZE_MSG] = {0};
1377   if (NULL == remoteName)
1378     {
1379       FTP_ERROR ("remoteName must not be a NULL pointer\n");
1380       return FTP_FAIL;
1381     }
1382   if (NULL == ftp)
1383     {
1384       FTP_ERROR ("FTP not open\n");
1385       return FTP_FAIL;
1386     }
1387   snprintf (buffer, sizeof (buffer)-1, "DELE %s\r\n", remoteName);
1388   ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1389   if (FTP_FAILED (ftp_result))
1390     {
1391       FTP_ERROR ("Error while sending the delete command\n");
1392       return ftp_result;
1393     }
1394   int repCode = getResponseCode (srvMsg);
1395   if (250 != repCode && 550 != repCode)
1396     {
1397       FTP_ERROR ("Bad response from server (%d, expected 250 or 550)\n", repCode);
1398       ftp_result = FTP_FAIL;
1399     }
1400   return ftp_result;
1401 }
1402
1403 _ftp_status
1404 ftpRename (_ftp_t *ftp, const char *origin, const char *dest)
1405 {
1406   _ftp_status ftp_result = FTP_FAIL;
1407   char buffer [256] = {0};
1408   char srvMsg [MAX_SIZE_MSG] = {0};
1409   if (NULL == origin ||
1410       NULL == dest)
1411     {
1412       FTP_ERROR ("origin and dest pointers must not be NULL\n");
1413       return FTP_FAIL;
1414     }
1415   if (NULL == ftp)
1416     {
1417       FTP_ERROR ("FTP not open\n");
1418       return FTP_FAIL;
1419     }
1420   snprintf (buffer, sizeof (buffer)-1, "RNFR %s\r\n", origin);
1421   ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1422   if (FTP_FAILED (ftp_result))
1423     {
1424       FTP_ERROR ("Error while sending the RNFR command\n");
1425       return ftp_result;
1426     }
1427   int repCode = getResponseCode (srvMsg);
1428   if (350 != repCode)
1429     {
1430       FTP_ERROR ("Bad response from server (%d, expected 350)\n", repCode);
1431       ftp_result = FTP_FAIL;
1432     }
1433   
1434   vp_os_memset (buffer, 0x0, sizeof (buffer));
1435   vp_os_memset (srvMsg, 0x0, sizeof (srvMsg));
1436   
1437   snprintf (buffer, sizeof (buffer)-1, "RNTO %s\r\n", dest);
1438   ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1439   if (FTP_FAILED (ftp_result))
1440     {
1441       FTP_ERROR ("Error while sending the RNTO command\n");
1442       return ftp_result;
1443     }
1444   repCode = getResponseCode (srvMsg);
1445   if (250 == repCode) // Rename worked
1446     {
1447       ftp_result = FTP_SUCCESS;
1448     }
1449   else if (550 == repCode) // Source file don't exist
1450     {
1451       FTP_DEBUG ("File %s doest not exist on FTP\n", origin);
1452       ftp_result = FTP_SAMESIZE;
1453     }
1454   else
1455     {
1456       FTP_ERROR ("Bad response from server (%d, expected 250 or 550)\n", repCode);
1457       ftp_result = FTP_FAIL;
1458     }
1459   return ftp_result;
1460 }
1461
1462 _ftp_status
1463 ftpCd (_ftp_t *ftp, const char *nextDir)
1464 {
1465   _ftp_status ftp_result = FTP_FAIL;
1466   char buffer [256] = {0};
1467   char srvMsg [MAX_SIZE_MSG] = {0};
1468   if (NULL == nextDir)
1469     {
1470       FTP_ERROR ("nextDir must not be NULL\n");
1471       return FTP_FAIL;
1472     }
1473   if (NULL == ftp)
1474     {
1475       FTP_ERROR ("FTP not open\n");
1476       return FTP_FAIL;
1477     }
1478   snprintf (buffer, sizeof (buffer)-1, "CWD %s\r\n", nextDir);
1479   ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1480   if (FTP_FAILED (ftp_result))
1481     {
1482       FTP_ERROR ("Error while sending the CWD command\n");
1483       return ftp_result;
1484     }
1485   int repCode = getResponseCode (srvMsg);
1486   if (250 != repCode)
1487     {
1488       FTP_ERROR ("Bad response from server (%d, expected 250)\n", repCode);
1489       ftp_result = FTP_FAIL;
1490     }
1491   return ftp_result;
1492 }
1493
1494 _ftp_status
1495 ftpPwd (_ftp_t *ftp, char *workingDir, int wdLen)
1496 {
1497   _ftp_status ftp_result = FTP_FAIL;
1498   char srvMsg [MAX_SIZE_MSG] = {0};
1499   if (NULL == workingDir)
1500     {
1501       FTP_ERROR ("workingDir must not be NULL\n");
1502       return FTP_FAIL;
1503     }
1504   if (NULL == ftp)
1505     {
1506       FTP_ERROR ("FTP not open\n");
1507       return FTP_FAIL;
1508     }
1509   ftp_result = ftpTransfert (ftp, "PWD\r\n\0", srvMsg, MAX_SIZE_MSG-1);
1510   if (FTP_FAILED (ftp_result))
1511     {
1512       FTP_ERROR ("Error while sending the CWD command\n");
1513       return ftp_result;
1514     }
1515   int repCode = getResponseCode (srvMsg);
1516   if (257 != repCode)
1517     {
1518       FTP_ERROR ("Bad response from server (%d, expected 257)\n", repCode);
1519       ftp_result = FTP_FAIL;
1520     }
1521   else
1522     {
1523       int pwdStartIndex = 0;
1524       int pwdEndIndex = 0;
1525       for (pwdStartIndex = 0; (pwdStartIndex < MAX_SIZE_MSG) && (srvMsg[pwdStartIndex] != '\"'); pwdStartIndex++);
1526       for (pwdEndIndex = pwdStartIndex+1; (pwdEndIndex < MAX_SIZE_MSG) && (srvMsg[pwdEndIndex] != '\"'); pwdEndIndex++);
1527       if (MAX_SIZE_MSG == pwdStartIndex ||
1528           MAX_SIZE_MSG == pwdEndIndex)
1529         {
1530           FTP_ERROR ("FTP Answer does not conains PWD\n");
1531           ftp_result = FTP_FAIL;
1532         }
1533       else
1534         {
1535           int srvLen = pwdEndIndex - (pwdStartIndex + 1);
1536           int totalLen = (srvLen < wdLen) ? srvLen : wdLen;
1537           strncpy (workingDir, &(srvMsg[pwdStartIndex+1]), totalLen);
1538           FTP_DEBUG ("PWD is %s\n", workingDir);
1539         }
1540     }
1541   return ftp_result;
1542 }
1543
1544 _ftp_status
1545 ftpMkdir (_ftp_t *ftp, const char *dirName)
1546 {
1547   _ftp_status ftp_result = FTP_FAIL;
1548   char buffer [256] = {0};
1549   char srvMsg [MAX_SIZE_MSG] = {0};
1550   if (NULL == dirName)
1551     {
1552       FTP_ERROR ("dirName must not be NULL\n");
1553       return FTP_FAIL;
1554     }
1555   if (NULL == ftp)
1556     {
1557       FTP_ERROR ("FTP not open\n");
1558       return FTP_FAIL;
1559     }
1560   snprintf (buffer, sizeof (buffer)-1, "MKD %s\r\n", dirName);
1561   ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1562   if (FTP_FAILED (ftp_result))
1563     {
1564       FTP_ERROR ("Error while sending the MKD command\n");
1565       return ftp_result;
1566     }
1567   int repCode = getResponseCode (srvMsg);
1568   if (257 != repCode)
1569     {
1570       FTP_ERROR ("Bad response from server (%d, expected 257)\n", repCode);
1571       ftp_result = FTP_FAIL;
1572     }
1573   return ftp_result;
1574 }
1575
1576 _ftp_status
1577 ftpRmdir (_ftp_t *ftp, const char *dirName)
1578 {
1579   _ftp_status ftp_result = FTP_FAIL;
1580   char buffer [256] = {0};
1581   char srvMsg [MAX_SIZE_MSG] = {0};
1582   if (NULL == dirName)
1583     {
1584       FTP_ERROR ("dirName must not be NULL\n");
1585       return FTP_FAIL;
1586     }
1587   if (NULL == ftp)
1588     {
1589       FTP_ERROR ("FTP not open\n");
1590       return FTP_FAIL;
1591     }
1592   snprintf (buffer, sizeof (buffer)-1, "RMD %s\r\n", dirName);
1593   ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
1594   if (FTP_FAILED (ftp_result))
1595     {
1596       FTP_ERROR ("Error while sending the RMD command\n");
1597       return ftp_result;
1598     }
1599   int repCode = getResponseCode (srvMsg);
1600   if (250 == repCode) // Deleted
1601     {
1602       FTP_DEBUG ("Successfully deleted %s directory\n", dirName);
1603       ftp_result = FTP_SUCCESS;
1604     }
1605   else if (550 == repCode) // Didn't exist / not empty
1606     {
1607       FTP_DEBUG ("Did not delete directory %s : did not exist or was not empty\n", dirName);
1608       ftp_result = FTP_BADSIZE;
1609     }
1610   else
1611     {
1612       FTP_ERROR ("Bad response from server (%d, expected 250 or 550)\n", repCode);
1613       ftp_result = FTP_FAIL;
1614     }
1615   return ftp_result;
1616 }
1617
1618 _ftp_status ftpAbort (_ftp_t *ftp)
1619 {
1620   _ftp_status retVal = FTP_FAIL;
1621   if (NULL == ftp)
1622     {
1623       FTP_ERROR ("FTP not open\n");
1624     }
1625   else
1626     {
1627       if (1 == ftp->opInProgress)
1628         {
1629           ftp->abortCurrentOp = 1;
1630           retVal = FTP_SUCCESS;
1631         }
1632       else
1633         {
1634           retVal = FTP_SAMESIZE;
1635         }
1636     }
1637   return retVal;
1638 }