0e23e6d921b0391bea0bfecc87f1f8a3448bd419
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ControlEngine / iPhone / Classes / ARDroneFTP.m
1 //
2 //  ARDroneFTP.m
3 //  ARDroneEngine
4 //
5 //  Created by Nicolas BRULEZ on 07/04/11.
6 //  Copyright 2011 Parrot. All rights reserved.
7 //
8
9 #import "ARDroneFTP.h"
10 #import <utils/ardrone_ftp.h>
11
12 #import "ConstantsAndMacros.h"
13 #import "wifi.h"
14
15 /**
16  * List of different FTPs opened, the key is the hex value of the ftp pointer
17  * Used inside "C to Obj-C callback to get the correct delegate/callback from
18  * multi-thread/multi-ftp contexts.
19  */
20 static NSMutableDictionary *listOfFtps = nil;
21
22 @implementation ARDroneFTPCallbackArg
23 @synthesize status;
24 @synthesize progress;
25 @synthesize operation;
26
27 - (id)initWithStatus:(ARDFTP_RESULT)_status withProgress:(float)_progress withFileList:(char *)_fileList withOperation:(FTP_OPERATION)_operation
28 {
29     self = [super init];
30     if (self)
31     {
32         status = _status;
33         progress = _progress;
34         if (nil != _fileList && 0 < strlen (_fileList))
35         {
36             fileList = [[NSString stringWithCString:_fileList encoding:NSASCIIStringEncoding] copy];
37         }
38         operation = _operation;
39     }
40     return self;
41 }
42
43 - (void)setFileList:(char *)_fileList
44 {
45     if (nil != _fileList && 0 < strlen (_fileList))
46     {
47         fileList = [[NSString stringWithCString:_fileList encoding:NSASCIIStringEncoding] copy];
48     }
49 }
50
51 - (void)dealloc
52 {
53         [fileList release];
54         
55         [super dealloc];
56 }
57
58 - (NSString *)fileList
59 {
60         return [[fileList copy] autorelease];
61 }
62
63 @end
64
65 ARDFTP_RESULT convertStatus (_ftp_status status)
66 {
67     ARDFTP_RESULT retVal = ARDFTP_FAIL;
68     switch (status)
69     {
70         case FTP_FAIL:
71             retVal = ARDFTP_FAIL;
72             break;
73         case FTP_SUCCESS:
74             retVal = ARDFTP_SUCCESS;
75             break;
76         case FTP_TIMEOUT:
77             retVal = ARDFTP_TIMEOUT;
78             break;
79         case FTP_BADSIZE:
80             retVal = ARDFTP_BADSIZE;
81             break;
82         case FTP_SAMESIZE:
83             retVal = ARDFTP_SAMESIZE;
84             break;
85         case FTP_PROGRESS:
86             retVal = ARDFTP_PROGRESS;
87             break;
88         case FTP_BUSY:
89             retVal = ARDFTP_BUSY;
90             break;
91         case FTP_ABORT:
92             retVal = ARDFTP_ABORT;
93             break;
94         default:
95             break;
96     }
97     return retVal;
98 }
99
100 void wrapperCallback (_ftp_status status, void *arg, _ftp_t *ftp)
101 {
102         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
103         
104     if (nil == listOfFtps) // Should never happen ... but just in case
105         {
106                 [pool drain];
107         return;
108         }
109     
110     ARDroneFTP *ardftp = [listOfFtps objectForKey:[NSString stringWithFormat:@"%x",ftp]];
111     if (nil != ardftp)
112     {
113         ARDFTP_RESULT locStat = convertStatus(status);
114         ARDroneFTPCallbackArg *callbackArg = nil;
115         if (ARDFTP_PROGRESS == locStat && NULL != arg)
116         {
117             callbackArg = [[ARDroneFTPCallbackArg alloc] initWithStatus:locStat withProgress:*(float *)arg withFileList:nil withOperation:ardftp.currentOperation];
118         }
119         else if (ARDFTP_SUCCESS == locStat && NULL != arg && FTP_LIST == ardftp.currentOperation)
120         { 
121             callbackArg = [[ARDroneFTPCallbackArg alloc] initWithStatus:locStat withProgress:0.0 withFileList:(char *)arg withOperation:ardftp.currentOperation];
122             vp_os_free (arg);
123         }
124         else
125         { 
126             callbackArg = [[ARDroneFTPCallbackArg alloc] initWithStatus:locStat withProgress:0.0 withFileList:nil withOperation:ardftp.currentOperation];
127         }
128                 
129         if (FTP_BUSY != locStat &&
130             FTP_PROGRESS != locStat) // Keep FTP busy if it was already busy before call, or if the current process is still in progress 
131         {
132             ardftp.isBusy = NO;
133         }
134                 
135         [ardftp.delegate performSelector:ardftp.currentOpCallback withObject:[callbackArg autorelease]];
136     }
137         
138         [pool drain];
139 }
140
141 extern char drone_address[];
142
143 @implementation ARDroneFTP
144 @synthesize currentOperation;
145 @synthesize currentOpCallback;
146 @synthesize delegate;
147 @synthesize isBusy;
148
149
150 + (id) anonymousUpdateFTPwithDelegate:(id)_delegate withDefaultCallback:(SEL)_callback
151 {
152     NSString *ip = [NSString stringWithCString:drone_address encoding:NSUTF8StringEncoding];
153     const int port = 5551;
154     
155     ARDroneFTP *ftp = [[ARDroneFTP alloc] initAnonymousWithIP:ip withPort:port withDelegate:_delegate withDefaultCallback:_callback];
156     
157     return [ftp autorelease];
158 }
159
160 + (id) updateFTPwithUser:(NSString *)user withPassword:(NSString *)password withDelegate:(id)_delegate withDefaultCallback:(SEL)_callback
161 {
162     NSString *ip = [NSString stringWithCString:drone_address encoding:NSUTF8StringEncoding];
163     const int port = 5551;
164     
165     ARDroneFTP *ftp = [[ARDroneFTP alloc] initWithIP:ip withPort:port withUser:user withPassword:password withDelegate:_delegate withDefaultCallback:_callback];
166     
167     return [ftp autorelease];
168 }
169
170 + (id) anonymousStandardFTPwithDelegate:(id)_delegate withDefaultCallback:(SEL)_callback
171 {
172     NSString *ip = [NSString stringWithCString:drone_address encoding:NSUTF8StringEncoding];
173     const int port = 21;
174     
175     ARDroneFTP *ftp = [[ARDroneFTP alloc] initAnonymousWithIP:ip withPort:port withDelegate:_delegate withDefaultCallback:_callback];
176     
177     return [ftp autorelease];
178 }
179
180 + (id) standardFTPwithUser:(NSString *)user withPassword:(NSString *)password withDelegate:(id)_delegate withDefaultCallback:(SEL)_callback
181 {
182     NSString *ip = [NSString stringWithCString:drone_address encoding:NSUTF8StringEncoding];
183     const int port = 21;
184     
185     ARDroneFTP *ftp = [[ARDroneFTP alloc] initWithIP:ip withPort:port withUser:user withPassword:password withDelegate:_delegate withDefaultCallback:_callback];
186     
187     return [ftp autorelease];
188 }
189
190 - (id)initAnonymousWithIP:(NSString *)ip withPort:(int)port withDelegate:(id)_delegate withDefaultCallback:(SEL)_callback
191 {
192     self = [super init];
193     if (self)
194     {
195         _ftp_status initResult = FTP_FAIL;
196         ftp = ftpConnect ([ip cStringUsingEncoding:NSASCIIStringEncoding],
197                           port,
198                           "anonymous",
199                           "",
200                           &initResult);
201         if (FTP_FAILED (initResult))
202         {
203             NSLog(@"Connexion to FTP anonymous@%@:%d failed\n", ip, port);
204         }
205         delegate = _delegate;
206         defaultCallback = _callback;
207         isBusy = NO;
208         currentOperation = FTP_NONE;
209         if (nil == listOfFtps)
210         {
211             listOfFtps = [[NSMutableDictionary alloc] initWithCapacity:1];
212         }
213         [listOfFtps setObject:self forKey:[NSString stringWithFormat:@"%x",ftp]];
214     }
215     return self;
216 }
217
218 - (id)initWithIP:(NSString *)ip withPort:(int)port withUser:(NSString *)user withPassword:(NSString *)password withDelegate:(id)_delegate withDefaultCallback:(SEL)_callback
219 {
220     self = [super init];
221     if (self)
222     {
223         _ftp_status initResult = FTP_FAIL;
224         ftp = ftpConnect ([ip cStringUsingEncoding:NSASCIIStringEncoding],
225                           port,
226                           [user cStringUsingEncoding:NSASCIIStringEncoding],
227                           [password cStringUsingEncoding:NSASCIIStringEncoding],
228                           &initResult);
229         if (FTP_FAILED (initResult))
230         {
231             NSLog(@"Connexion to FTP %@@%@:%d failed\n", user, ip, port);
232         }
233         delegate = _delegate;
234         defaultCallback = _callback;
235         isBusy = NO;
236         currentOperation = FTP_NONE;
237         if (nil == listOfFtps)
238         {
239             listOfFtps = [[NSMutableDictionary alloc] initWithCapacity:1];
240         }
241         [listOfFtps setObject:self forKey:[NSString stringWithFormat:@"%x",ftp]];
242     }
243     return self;
244 }
245
246 - (void)setDelegate:(id)_delegate
247 {
248     delegate = _delegate;
249 }
250
251 - (void)setDefaultCallback:(SEL)_callback
252 {
253     defaultCallback = _callback;
254 }
255
256 - (void)close
257 {
258     [listOfFtps removeObjectForKey:[NSString stringWithFormat:@"%x",ftp]];
259         
260         if (![listOfFtps count])
261         {
262                 [listOfFtps release];
263                 listOfFtps = nil;
264         }
265         
266     ftpClose (&ftp);
267 }
268
269 - (bool)keepConnexionAlive
270 {
271     return ARDFTP_SUCCEEDED([self changeDirectoryTo:@"."]);
272 }
273
274 - (ARDFTP_RESULT)sendLocalFile:(NSString *)local toDistantFile:(NSString *)distant withResume:(BOOL)resume
275 {
276     return [self sendLocalFile:local toDistantFile:distant withResume:resume withCallback:defaultCallback];
277 }
278
279 - (ARDFTP_RESULT)sendLocalFile:(NSString *)local toDistantFile:(NSString *)distant withResume:(BOOL)resume withCallback:(SEL)_callback
280 {
281     if (isBusy)
282     {
283         return ARDFTP_BUSY;
284     }
285     _ftp_status retVal = FTP_FAIL;
286     isBusy = YES;
287     currentOperation = FTP_SEND;
288     currentOpCallback = _callback;
289         
290     if (nil != currentOpCallback)
291     {
292         retVal = ftpPut (ftp,
293                          [local cStringUsingEncoding:NSASCIIStringEncoding],
294                          [distant cStringUsingEncoding:NSASCIIStringEncoding],
295                          (resume) ? 1 : 0,
296                          wrapperCallback);
297     }
298     return convertStatus(retVal);
299 }
300
301 - (ARDFTP_RESULT)sendSynchronouslyLocalFile:(NSString *)local toDistantFile:(NSString *)distant withResume:(BOOL)resume
302 {
303     if (isBusy)
304     {
305         return ARDFTP_BUSY;
306     }
307     _ftp_status retVal = FTP_FAIL;
308     isBusy = YES;
309     currentOperation = FTP_SEND;
310     retVal = ftpPut (ftp,
311                      [local cStringUsingEncoding:NSASCIIStringEncoding],
312                      [distant cStringUsingEncoding:NSASCIIStringEncoding],
313                      (resume) ? 1 : 0,
314                      NULL);
315     currentOperation = FTP_NONE;
316     isBusy = NO;
317     return convertStatus(retVal);
318 }
319
320 - (ARDFTP_RESULT)getDistantFile:(NSString *)distant toLocalFile:(NSString *)local withResume:(BOOL)resume
321 {
322     return [self getDistantFile:distant toLocalFile:local withResume:resume withCallback:defaultCallback];
323 }
324
325 - (ARDFTP_RESULT)getDistantFile:(NSString *)distant toLocalFile:(NSString *)local withResume:(BOOL)resume withCallback:(SEL)_callback
326 {
327     if (isBusy)
328     {
329         return ARDFTP_BUSY;
330     }
331     _ftp_status retVal = FTP_FAIL;
332     isBusy = YES;
333     currentOperation = FTP_GET;
334     currentOpCallback = _callback;
335     if (nil != currentOpCallback)
336     {
337         retVal = ftpGet(ftp,
338                         [distant cStringUsingEncoding:NSASCIIStringEncoding],
339                         [local cStringUsingEncoding:NSASCIIStringEncoding],
340                         (resume) ? 1 : 0,
341                         wrapperCallback);
342     }
343     return convertStatus(retVal);
344 }
345
346 - (ARDFTP_RESULT)getSynchronouslyDistantFile:(NSString *)distant toLocalFile:(NSString *)local withResume:(BOOL)resume
347 {
348     if (isBusy)
349     {
350         return ARDFTP_BUSY;
351     }
352     _ftp_status retVal = FTP_FAIL;
353     isBusy = YES;
354     currentOperation = FTP_GET;
355     retVal = ftpGet (ftp,
356                      [distant cStringUsingEncoding:NSASCIIStringEncoding],
357                      [local cStringUsingEncoding:NSASCIIStringEncoding],
358                      (resume) ? 1 : 0,
359                      NULL);
360     currentOperation = FTP_NONE;
361     isBusy = NO;
362     return convertStatus(retVal);
363 }
364
365 - (ARDFTP_RESULT)listCurrentDirectory
366 {
367     return [self listCurrentDirectoryWithCallback:defaultCallback];
368 }
369
370 - (ARDFTP_RESULT)listCurrentDirectoryWithCallback:(SEL)_callback
371 {
372     if (isBusy)
373     {
374         return ARDFTP_BUSY;
375     }
376     _ftp_status retVal = FTP_FAIL;
377     isBusy = YES;
378     currentOperation = FTP_LIST;
379     currentOpCallback = _callback;
380     if (nil != currentOpCallback)
381     {
382         retVal = ftpList(ftp,
383                          NULL,
384                          wrapperCallback);
385     }
386     return convertStatus (retVal);
387 }
388
389 - (ARDFTP_RESULT)listCurrentDirectoryIn:(NSString **)result
390 {
391     if (isBusy)
392     {
393         return ARDFTP_BUSY;
394     }
395     _ftp_status retVal = FTP_FAIL;
396     isBusy = YES;
397     currentOperation = FTP_LIST;
398     char *buffer = NULL;
399     retVal = ftpList (ftp,
400                       &buffer,
401                       NULL);
402     currentOperation = FTP_NONE;
403     isBusy = NO;
404     if (NULL != buffer)
405     {
406         *result = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding];
407     }
408     return convertStatus(retVal);
409 }
410
411 - (ARDFTP_RESULT)removeDistantFile:(NSString *)distant
412 {
413     return convertStatus (ftpRemove (ftp,
414                                      [distant cStringUsingEncoding:NSASCIIStringEncoding]));
415 }
416
417 - (ARDFTP_RESULT)renameDistantFileFrom:(NSString *)origin to:(NSString *)dest
418 {
419     return convertStatus (ftpRename (ftp,
420                                      [origin cStringUsingEncoding:NSASCIIStringEncoding],
421                                      [dest cStringUsingEncoding:NSASCIIStringEncoding]));
422 }
423
424 - (ARDFTP_RESULT)renameDistantDirectoryFrom:(NSString *)origin to:(NSString *)dest
425 {
426     return [self renameDistantFileFrom:origin to:dest];
427 }
428
429 - (ARDFTP_RESULT)changeDirectoryTo:(NSString *)nextDir
430 {
431     return convertStatus (ftpCd (ftp,
432                                  [nextDir cStringUsingEncoding:NSASCIIStringEncoding]));
433 }
434
435 - (ARDFTP_RESULT)getWorkingDirectoryTo:(NSString **)result
436 {
437     char buffer [1024] = {0};
438     _ftp_status retVal = ftpPwd (ftp,
439                                  buffer,
440                                  sizeof (buffer));
441     *result = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding];
442     return convertStatus (retVal);
443 }
444
445 - (ARDFTP_RESULT)createDirectoryNamed:(NSString *)dirName
446 {
447     return convertStatus (ftpMkdir (ftp,
448                                     [dirName cStringUsingEncoding:NSASCIIStringEncoding]));
449 }
450
451 - (ARDFTP_RESULT)removeDirectoryNamed:(NSString *)dirName
452 {
453     return convertStatus (ftpMkdir (ftp,
454                                     [dirName cStringUsingEncoding:NSASCIIStringEncoding]));
455 }
456
457 - (ARDFTP_RESULT)abortCurrentOperation
458 {
459     return convertStatus(ftpAbort (ftp));
460 }
461
462 - (void)dealloc
463 {
464     [self close];
465         
466     [super dealloc];
467 }
468
469 @end