Fix an uninitialized variable.
[MacTF.git] / TFUSBController.m
blobe063a5eb566fe65aa6f193cc730ac3ff9b254360
1 //
2 //  TFUSBController.m
3 //  MacTF
4 //
5 //  Created by Nathan Oates on Sun Aug 01 2004.
6 //  Copyright (c) 2004-7 Nathan Oates nathan@noates.com All rights reserved.
7 //
9 /* This file was modified by Kalle Olavi Niemitalo on 2007-10-18.  */
11 // includes code based on uproar, license noted below:
12 //  uproar 0.1
13 //  Copyright (c) 2001 Kasima Tharnpipitchai <me@kasima.org>
14 #import "TFUSBController.h"
15 #import "UIElements.h"
17 @implementation TFUSBController
19 /* 
20  *
21  * This source code is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU Public License as published
23  * by the Free Software Foundation; either version 2 of the License,
24  * or (at your option) any later version.
25  *
26  * This source code is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29  * Please refer to the GNU Public License for more details.
30  *
31  * You should have received a copy of the GNU Public License along with
32  * this source code; if not, write to:
33  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34  */
38 /* Much of the code that initializes and closes the device is from Apple
39  * and is released under the license below.
40  */
43  * © Copyright 2001 Apple Computer, Inc. All rights reserved.
44  *
45  * IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc. (“Apple”) in 
46  * consideration of your agreement to the following terms, and your use, installation, 
47  * modification or redistribution of this Apple software constitutes acceptance of these
48  * terms.  If you do not agree with these terms, please do not use, install, modify or 
49  * redistribute this Apple software.
50  *
51  * In consideration of your agreement to abide by the following terms, and subject to these 
52  * terms, Apple grants you a personal, non exclusive license, under Apple’s copyrights in this 
53  * original Apple software (the “Apple Software”), to use, reproduce, modify and redistribute 
54  * the Apple Software, with or without modifications, in source and/or binary forms; provided 
55  * that if you redistribute the Apple Software in its entirety and without modifications, you 
56  * must retain this notice and the following text and disclaimers in all such redistributions 
57  * of the Apple Software.  Neither the name, trademarks, service marks or logos of Apple 
58  * Computer, Inc. may be used to endorse or promote products derived from the Apple Software 
59  * without specific prior written permission from Apple. Except as expressly stated in this 
60  * notice, no other rights or licenses, express or implied, are granted by Apple herein, 
61  * including but not limited to any patent rights that may be infringed by your derivative 
62  * works or by other works in which the Apple Software may be incorporated.
63  * 
64  * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES, 
65  * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-
66  * INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE 
67  * SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 
68  *
69  * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
70  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
71  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
72  * REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
73  * WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
74  * OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75  */                     
78 #define         TopfieldVendorID        4571
79    //1317 for HC
80    //0x138c for humax
81    //4571 for toppy
82 #define         TF5kProdID      4096
83 //42514 for HC
84 //0x02ad for humax
85 //4096 for toppy
87 -(id) init {
88         if (self = [super init]) {
89                 debug = 0;
90                 rate = 0xfe00;
91                 transferQueue = [[NSMutableArray arrayWithCapacity:1] retain];
92                 pausedQueue = [[NSMutableArray arrayWithCapacity:1] retain];
93                 priorityTransferQueue = [[NSMutableArray arrayWithCapacity:1] retain];
94         }
95         return self;
98 void hexDump(UInt8 *buf, int len) {
99         int row, col, maxrows;
100         
101         maxrows = len/16;
102         if (len % 16) maxrows++;
103         for (row=0; row< maxrows; row++) {
104                 for (col=0; col<16; col++) {
105                         if (!(col%2)) printf(" ");
106                         printf("%02x", buf[row*16 + col] & 0xff);
107                 }
108                 printf("\t");   
109                 for (col=0; col<16; col++) {
110                         if ((buf[row*16 + col]>32) && (buf[row*16 + col]<126)) {
111                                 printf("%c", buf[row*16 + col]);
112                         }
113                         else { printf("."); }
114                 }
115                 printf("\n");
116         }
121 int doSend(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
122                 UInt8 *outBuf, UInt32 len, int type) 
124         IOReturn        err;
125         UInt32          sendLen;        
126         
127                 if (debug == 1){
128                         printf(("sending:\n"));
129             hexDump(outBuf, len);
130                 }
131                 sendLen = ((len/kBlockSize))*kBlockSize;
132         if (len % kBlockSize)
133             sendLen += kBlockSize;
134         if ((sendLen % 0x200) == 0)  
135                 sendLen += kBlockSize;
137         err = (*intf)->WritePipeTO(intf, 1, outBuf, sendLen, 1000, 20000);
138         if (err) {
139                 printf("write err: %08x\n", err);
140                 return err;
141         }
142         return err;
146 int doRecv(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
147             UInt8 *inBuf, UInt32 dataLen, int type) {
148         IOReturn        err;
149         UInt32          len;
150         
151         if (dataLen > kMaxXferSize) return 1;
152         
153         len = (dataLen/kBlockSize) * kBlockSize;
154         if (dataLen % kBlockSize)
155                 len += kBlockSize;
157                 err = (*intf)->ReadPipeTO(intf, 2, (void *)inBuf, &len,  1000, 20000);
158                 if (err) {
159                 printf("read err 2: %08x\n", err);
160                                 printf("resetting\n");
161                                 err = (*intf)->ClearPipeStallBothEnds(intf, 2); 
162                         return err;
163         }
164                 
165         if (debug == 1) {
166           printf(("receiving: \n")); 
167                         hexDump(inBuf, len);
168                 }
169         return err;
176 int dealWithInterface(io_service_t usbInterfaceRef, USBDeviceContext *device)
178     IOReturn                            err;
179     IOCFPlugInInterface                 **iodev;                // requires <IOKit/IOCFPlugIn.h>
180     IOUSBInterfaceInterface197          **intf;
181     IOUSBDeviceInterface197             **dev;
182     SInt32                              score;
183         UInt8                           numPipes, confNum, dSpeed;
186     err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
187     if (err || !iodev)
188     {
189         printf("dealWithInterface: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
190         return kUproarDeviceErr;
191     }
192     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&(device->intf));
193     (*iodev)->Release(iodev);                           // done with this
194     intf = device->intf;
195     if (err || !intf)
196     {
197         printf("dealWithInterface: unable to create a device interface. ret = %08x, intf = %p\n", err, intf);
198         return kUproarDeviceErr;
199     }
200     
201     dev = device->dev;
202     err = (*intf)->USBInterfaceOpen(intf);
203     if (err)
204     {
205         printf("dealWithInterface: unable to open interface. ret = %08x\n", err);
206         return kUproarDeviceErr;
207     }
208     err = (*intf)->GetNumEndpoints(intf, &numPipes);
209     if (err)
210     {
211         printf("dealWithInterface: unable to get number of endpoints. ret = %08x\n", err);
212         return kUproarDeviceErr;
213     }
214     
215     printf("dealWithInterface: found %d pipes\n", numPipes);
217     err = (*intf)->GetConfigurationValue(intf, &confNum);
218     err = (*dev)->GetDeviceSpeed(dev, &dSpeed);
219         if (dSpeed == 2) {
220                 kBlockSize = 0x40;
221         } else {
222                 kBlockSize = 0x4;
223         }
224     printf("confnum: %08x, dspeed: %08x, blockS:%i\n", confNum, dSpeed, kBlockSize);
225     connectedSpeed = dSpeed;
226     return kUproarSuccess;
230 int dealWithDevice(io_service_t usbDeviceRef, USBDeviceContext *device)
232     IOReturn                            err;
233     IOCFPlugInInterface                 **iodev;                // requires <IOKit/IOCFPlugIn.h>
234     IOUSBDeviceInterface197             **dev;
235     SInt32                              score;
236     UInt8                               numConf;
237     IOUSBConfigurationDescriptorPtr     confDesc;
238     IOUSBFindInterfaceRequest           interfaceRequest;
239     io_iterator_t                       iterator;
240     io_service_t                        usbInterfaceRef;
241     int                                 found=0;
242     
243     
244     err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
245     if (err || !iodev)
246     {
247         printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
248         return kUproarDeviceErr;
249     }
250     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&(device->dev));
251     (*iodev)->Release(iodev);                           
252     
253     dev = device->dev;
254     if (err || !dev)
255     {
256         printf("dealWithDevice: unable to create a device interface. ret = %08x, dev = %p\n", err, dev);
257         return kUproarDeviceErr;
258     }
259     err = (*dev)->USBDeviceOpen(dev);
260     if (err)
261     {
262         printf("dealWithDevice: unable to open device. ret = %08x\n", err);
263         return kUproarDeviceErr;
264     }
265     err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
266     if (err || !numConf)
267     {
268         printf("dealWithDevice: unable to obtain the number of configurations. ret = %08x\n", err);
269         return kUproarDeviceErr;
270     }
271     printf("dealWithDevice: found %d configurations\n", numConf);
272     err = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc);     // get the first config desc (index 0)
273     if (err)
274     {
275         printf("dealWithDevice:unable to get config descriptor for index 0\n");
276         return kUproarDeviceErr;
277     }
278     err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
279     if (err)
280     {
281         printf("dealWithDevice: unable to set the configuration\n");
282         return kUproarDeviceErr;
283     }
285     interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;             // requested class
286     interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;          // requested subclass
287     interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;          // requested protocol
288     interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;           // requested alt setting
289     
290     err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
291     if (err)
292     {
293         printf("dealWithDevice: unable to create interface iterator\n");
294         return kUproarDeviceErr;
295     }
296     
297     while (usbInterfaceRef = IOIteratorNext(iterator))
298     {
299         printf("found interface: %p\n", (void*)usbInterfaceRef);
300         err = dealWithInterface(usbInterfaceRef, device);
301         IOObjectRelease(usbInterfaceRef);       // no longer need this reference
302         found = 1;
303     }
304     
305     IOObjectRelease(iterator);
306     iterator = 0;
307     if ((!found) || (err))
308         return kUproarDeviceErr;
309     else
310         return kUproarSuccess;
314 int initDevice(USBDeviceContext *device){
315     mach_port_t         masterPort = 0;
316     kern_return_t               err;
317     CFMutableDictionaryRef      matchingDictionary = 0;         // requires <IOKit/IOKitLib.h>
318     short                       idVendor = TopfieldVendorID;
319     short                       idProduct = TF5kProdID;
320     CFNumberRef                 numberRef;
321     io_iterator_t               iterator = 0;
322     io_service_t                usbDeviceRef;
323     int                         found =0;
324     
325     err = IOMasterPort(bootstrap_port, &masterPort);                    
326     
327     if (err)
328     {
329         printf("Anchortest: could not create master port, err = %08x\n", err);
330         return err;
331     }
332     matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);      // requires <IOKit/usb/IOUSBLib.h>
333     if (!matchingDictionary)
334     {
335         printf("Anchortest: could not create matching dictionary\n");
336         return -1;
337     }
338     numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idVendor);
339     if (!numberRef)
340     {
341         printf("Anchortest: could not create CFNumberRef for vendor\n");
342         return -1;
343     }
344     CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorName), numberRef);
345     CFRelease(numberRef);
346     numberRef = 0;
347     numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idProduct);
348     if (!numberRef)
349     {
350         printf("Anchortest: could not create CFNumberRef for product\n");
351         return -1;
352     }
353     CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductName), numberRef);
354     CFRelease(numberRef);
355     numberRef = 0;
356     
357     err = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
358     matchingDictionary = 0;                     // this was consumed by the above call
359     
360     while (usbDeviceRef = IOIteratorNext(iterator))
361     {
362         printf("Found device %p\n", (void*)usbDeviceRef);
363         err = dealWithDevice(usbDeviceRef, device);
364         IOObjectRelease(usbDeviceRef);                  // no longer need this reference
365         found = 1;
366     }
367     
368     
369     IOObjectRelease(iterator);
370     iterator = 0;
371     mach_port_deallocate(mach_task_self(), masterPort);
372     if ((!found) || (err))
373         return kUproarDeviceErr;
374     else
375         return kUproarSuccess;
379 - (void) closeDevice:(USBDeviceContext *) device
381     IOUSBInterfaceInterface197  **intf;
382     IOUSBDeviceInterface197     **dev;
383     IOReturn                    err;
384     
385     intf = device->intf;
386     dev = device->dev;
387     
388     err = (*intf)->USBInterfaceClose(intf);
389     if (err)
390     {
391         printf("dealWithInterface: unable to close interface. ret = %08x\n", err);
392     }
393     err = (*intf)->Release(intf);
394     if (err)
395     {
396         printf("dealWithInterface: unable to release interface. ret = %08x\n", err);
397     }
398     
399     err = (*dev)->USBDeviceClose(dev);
400     if (err)
401     {
402         printf("dealWithDevice: error closing device - %08x\n", err);
403         (*dev)->Release(dev);
404     }
405     err = (*dev)->Release(dev);
406     if (err)
407     {
408         printf("dealWithDevice: error releasing device - %08x\n", err);
409     }
412 - (USBDeviceContext*) initializeUSB {
413         USBDeviceContext        *device;
414         int                     err;
415         kBlockSize = 0x08;
416         device = malloc(sizeof(USBDeviceContext));
417         err = initDevice(device);
418         if (err) {
419                 printf("Could not connect to Topfield\n");
420                 return nil;
421         }
422         printf("\n\n");
423         printf("Connected to Topfield\n\n");
424         myContext = device;
425         return device;
428 - (UIElements*) uiElements {
429         return [NSApp delegate];
432 - (id) getFileListForPath:(NSString*) path {    
433         if (myContext == nil)
434                 return nil;
435         
436         // turn path into data
437         NSMutableData *pathData = [NSMutableData dataWithData:[path dataUsingEncoding:NSISOLatin1StringEncoding]];
438         [pathData increaseLengthBy:1]; // not sure if need to pad here?
439         
440         //prepackage any commands needed
441         NSData* hddListCmd = [self prepareCommand:USB_CmdHddDir withData:pathData];
442         [self checkUSB:myContext];
443         NSData* hddFileData = [self sendCommand:hddListCmd toDevice:myContext expectResponse:YES careForReturn:YES];    
444         // deal with data recieved - in this case parse it and update display
445         if ([hddFileData length] < 8) return nil;
446         NSData* checkForError = [hddFileData subdataWithRange:(NSRange){4,4}];
447         const UInt32 check_bigendian = EndianU32_NtoB(USB_Fail);
448         const UInt32 check2_bigendian = EndianU32_NtoB(USB_DataHddDir);
449         if ([checkForError isEqualToData:[NSData dataWithBytes:&check_bigendian length:4]]) {
450 //              [statusField setStringValue:NSLocalizedString(@"LAST_ERROR", @"Error on last command.")];
451                 return nil;
452         }
453         if (! [checkForError isEqualToData:[NSData dataWithBytes:&check2_bigendian length:4]]) {
454                 [self getFileListForPath:path]; //try again - hmm since move this could be recursive!
455                 return nil;
456         }
457         hddFileData = [hddFileData subdataWithRange:(NSRange) {8, [hddFileData length]-8}]; // cut off header and cmd 
458         int i;
459         [[dh fileList] removeAllObjects];
460         for (i=0; i*114 < [hddFileData length]-4; i++) { // 4 is there cause swapping sometimes adds a byte of padding  
461                 NSData* temp = [hddFileData subdataWithRange:(NSRange) {i*114,114}];
462                 NSMutableDictionary* tfFile = [dh getTFFileFromSwappedHexData:temp];
463                 if (![[tfFile objectForKey:@"name"] isEqualToString:@".."]) {
464                         [dh convertRawDataToUseful:tfFile];
465                         [[dh fileList] addObject:tfFile];
466                 }
467         }
468         [tableView reloadData];
469         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]];
470         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]]; //twice so get the same sort as before
471         return nil;
474 -(UInt16) findCRC:(const UInt8*)p length:(size_t) n
476         UInt16 m_crc16 = 0x0000;
477         static const UInt16 crc16Tbl[256] = {
478                 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
479                 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
480                 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
481                 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
482                 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
483                 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
484                 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
485                 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
486                 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
487                 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
488                 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
489                 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
490                 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
491                 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
492                 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
493                 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
494                 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
495                 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
496                 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
497                 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
498                 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
499                 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
500                 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
501                 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
502                 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
503                 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
504                 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
505                 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
506                 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
507                 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
508                 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
509                 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
510         };
511         size_t i;       
512         for(i = 0; i < n; i++)
513                         m_crc16 = (m_crc16 >> 8) ^ crc16Tbl[*p++ ^ (m_crc16 & 0xFF)];
514         return m_crc16;
517 - (NSData*) prepareCommand:(unsigned int)cmd withData:(NSData*) inData {        
518                 // work out length
519                 unsigned short int length = 0;
520                 if (inData == nil)
521                         length = 8;
522                 else {
523                         unsigned short int l = [inData length];
524                         length = l + 8;
525                 }
526                 const UInt16 length_bigendian = EndianU16_NtoB(length);
527                 NSMutableData* toSend = [NSMutableData dataWithBytes:&length_bigendian length:2];
528                 const UInt32 cmd_bigendian = EndianU32_NtoB(cmd);
529                 NSMutableData* build = [NSMutableData dataWithBytes:&cmd_bigendian length:4];
530                 if (inData != nil)
531                         [build appendData:inData];
532                 // work out crc
533                 UInt8 test[length];
534                 memset(test, 0, length);
535                 [build getBytes:test length:[build length]];
536                 unsigned short int crc = [self findCRC:test length:[build length]];
537                 const UInt16 crc_bigendian = EndianU16_NtoB(crc);
538                 [toSend appendData:[NSMutableData dataWithBytes:&crc_bigendian length:2]];
539                 [toSend appendData:build];
540                 // reverse and send
541                 toSend = [self swap:toSend];
542                 return toSend;
545 - (int) getFile:(NSDictionary*)fileInfo forPath:(NSString*)currentPath
546                 toSaveTo:(NSString*)savePath beginAtOffset:(unsigned long long) offset
547                 withLooping:(BOOL)looping existingTime:(NSTimeInterval)existingTime {   
548 //      [progressBar setDoubleValue:0];
549 //      [progressTime setDoubleValue:0];
550         NSString* nameOnToppy = [fileInfo objectForKey:@"name"];
551         [[[self uiElements] currentlyField] setStringValue:
552                 [NSLocalizedString(@"DOWNLOADING", @"Downloading: ") stringByAppendingString:nameOnToppy]];
553         [[[self uiElements] connectLight] setImage:[NSImage imageNamed:@"blink.tiff"]];
554         [[[self uiElements] currentlyField] displayIfNeeded];
555         //construct file send request
556         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
557         NSNumber* fileSize = [fileInfo objectForKey:@"fileSize"];
558         char dir = USB_FileToHost;
559         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
560         short int nsize = [fname length]+[currentPath length]+2;// one for slash, one for padding 0x00
561         const SInt16 nsize_bigendian = EndianS16_NtoB(nsize);
562         [build appendData:[NSData dataWithBytes:&nsize_bigendian length:2]];
563         NSData* d = [currentPath dataUsingEncoding:NSISOLatin1StringEncoding];
564         [build appendData:d];   
565         dir = 0x5c; // 0x5c = "/"
566         [build appendData:[NSData dataWithBytes:&dir length:1]];
567         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
568         dir = 0x00;
569         [build appendData:[NSData dataWithBytes:&dir length:1]];
570         //add 8 byte offset here
571         const UInt64 offset_bigendian = EndianU64_NtoB(offset);
572         [build appendData:[NSData dataWithBytes:&offset_bigendian length:8]];
573         
574         //prepackage commands to send
575         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
576         NSData* usbSuccess = [self prepareCommand:USB_Success withData:nil];
577         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
578         
579         // send commands
580         
581         if ([turboCB state]) 
582                 [self turnTurboOn:YES];
583         else
584                 [self checkUSB:myContext]; //turbo has a check itself
585         [self sendCommand:fileSendCmd toDevice:myContext expectResponse:YES careForReturn:NO];
586         //start timer
587         NSDate* startTime = [NSDate date];
588         startTime = [startTime addTimeInterval:(0-existingTime)];
589         // send start request and get response
590         NSData *data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
591         const UInt32 rW_bigendian = EndianU32_NtoB(USB_DataHddFileData);
592         NSData *responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
593         if ([data length] < 16) {
594                 NSLog(@"Incorrect Data length");
595                 return 1;
596         }
597         NSData *responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
598         if (![responseWanted isEqualToData:responseToCheck]) {
599                 NSLog(@"Unexpected response from Toppy during download");
600                 return 1;
601         }
602         
603         // clean up data and prepare path to save it
604         NSData* header = [data subdataWithRange:(NSRange) {4,4}]; //cmd data
605         NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
606         
607         // first initialize a file of the right name, as NSFileHandle requires an existing file to work on
608         if (offset == 0)
609                 [[NSData dataWithBytes:&dir length:1] writeToFile:savePath atomically:NO]; // write 0x00 to initialize (overwritten later)
610         NSFileHandle* outFile = [NSFileHandle fileHandleForWritingAtPath:savePath];
611         [outFile seekToFileOffset:offset];
612         [outFile writeData:finalData];
613         if (looping) {  // loop for multiple data sends (ie files > 64k)
614                 int updateRate = 8; 
615                 if ([fileSize isGreaterThan:[NSNumber numberWithDouble:1048576]]) {
616                         updateRate = 24;
617                         NSLog(@"large file detected - low GUI update rate");
618                 }
619                 int timesAround = 0;
620                 const UInt32 test_bigendian = EndianU32_NtoB(USB_DataHddFileData);
621                 double amountReceived = 0xfe00 + offset;
622                 NSData* testData = [NSData dataWithBytes:&test_bigendian length:4];
623                 while ([header isEqualToData:testData] && [[[self uiElements] isConnected] intValue]) {
624                         if ([priorityTransferQueue count] != 0) {
625                                 [self addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:
626                                                 fileInfo,@"filename", currentPath,@"path", savePath,@"savePath",
627                                                 [NSNumber numberWithUnsignedLongLong:amountReceived],@"offset",
628                                                 @"download",@"transferType", [NSNumber numberWithBool:YES],@"looping",
629                                                 [NSNumber numberWithInt:[[NSDate date] timeIntervalSinceDate:startTime]],@"existingTime",
630                                                 nil]
631                                         atIndex:1]; // nb adding to index 1 as the current transfer lies at 0 and will be deleted soon
632                                 // send reset again     just to make sure!
633                                 [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO];
634                                 [outFile closeFile];
635                                 //now add the right modification date to the file
636                                 [[NSFileManager defaultManager]
637                                         changeFileAttributes:[NSDictionary
638                                                 dictionaryWithObject:[fileInfo objectForKey:@"date"]
639                                                 forKey:@"NSFileModificationDate"]
640                                         atPath:savePath];
641                                 [self turnTurboOn:NO];
642                                 return 0;
643                         }
644                         timesAround ++;
645                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];                             
646                         data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
647                         amountReceived += 0xfe00;
648                         if (timesAround < 8 || timesAround % updateRate == 0) {
649                                 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self
650                                         withObject:[NSDictionary dictionaryWithObjectsAndKeys:
651                                                 [NSNumber numberWithDouble:(double)amountReceived], @"offset",
652                                                 fileSize, @"size", startTime, @"startTime", nil]];
653                         }
654                         if ([data length] > 16){ //there is something to read 
655                                 header = [[data subdataWithRange:(NSRange) {4,4}] retain]; //cmd data
656                                 NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
657                                 [outFile writeData:finalData];
658                                 [outFile synchronizeFile];
659                         } 
660                         else break;
661                         [pool release];
662                 }
663         }
664         [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO]; // send reset again        just to make sure!
665         [outFile closeFile];
666     //now add the right modification date to the file
667         [[NSFileManager defaultManager]
668                 changeFileAttributes:[NSDictionary
669                         dictionaryWithObject:[fileInfo objectForKey:@"date"]
670                         forKey:@"NSFileModificationDate"]
671                 atPath:savePath];
672         [self turnTurboOn:NO];
673         if (looping) [[self uiElements] finishTransfer];
674         return 0;
677 - (NSData*) sendCommand:(NSData*) fullyPackagedCommand
678                 toDevice:(USBDeviceContext*)device expectResponse:(BOOL) getResponse
679                 careForReturn:(BOOL) careFactor{
680         IOReturn        err;
681         int cmdLength = [fullyPackagedCommand length];
682         unsigned char outBuffer[cmdLength];
683         memset(outBuffer, 0, cmdLength);
684 //      NSLog(@"send: %@", [fullyPackagedCommand description]);
685         [fullyPackagedCommand getBytes:outBuffer];
686         
687         err = doSend(device->dev, device->intf, outBuffer, cmdLength, 2);
688         if (err)
689                 NSLog(@"sendError: %08x\n");
690         
691         if (! getResponse) return nil;
692         
693         int inLen = 0xFFFF; // i think this is biggest needed?
694         unsigned char inBuf[inLen];
695         memset(inBuf, 0, inLen);
696         err = doRecv(device->dev, device->intf, inBuf, inLen, 2);
697         if (err)
698                 NSLog(@"inError: %08x\n", err);
699         
700         if (! careFactor) return nil;
701         NSMutableData* data = [NSMutableData dataWithBytes:inBuf length:inLen];
702         data = [self swap:data];
703         inLen = inBuf[1]*256 + inBuf[0]; // work out how long the response really is. NB data is flipped, but inBuf still isn't
704         return [data subdataWithRange:(NSRange) {0,inLen}];
707 -(NSMutableData*) swap: (NSData*) inData {
708         int len = [inData length];
709         int uneven = 0;
710         if (len % 2 != 0) {
711                 uneven = 1; // prepare space for padding
712         }
713         char *array;
714         char *outarray;
715         if ((array = calloc((len + uneven), sizeof(char))) == NULL) {
716                 NSLog(@"ERROR: Malloc failed");
717                 return [NSMutableData dataWithData:inData];
718         }
719         if ((outarray = calloc((len + uneven), sizeof(char))) == NULL) {
720                 NSLog(@"ERROR: Malloc failed");
721                 return [NSMutableData dataWithData:inData];
722         }
723         [inData getBytes:array length:len];
724         swab(array, outarray, len+uneven);
725         NSMutableData* ret = [NSMutableData dataWithCapacity:len+uneven];
726         [ret setData:[NSData dataWithBytes:outarray length:len+uneven]];
727         free(array);
728         free(outarray);
729         return ret; 
732 - (void) uploadFile:(NSString*) fileToUpload ofSize:(long long) size
733                 fromPath:(NSString*)curPath withAttributes:(NSData*) typeFile
734                 atOffset:(unsigned long long)offset existingTime:(NSTimeInterval)existingTime {
735         NSLog(@"upload: %@,%@,%qu", fileToUpload, curPath, offset);
736         USBDeviceContext* dev = myContext;
737         // prepare Send command
738         NSMutableArray* array = [NSMutableArray arrayWithArray:[fileToUpload componentsSeparatedByString:@"/"]];
739         NSMutableString* fname = [NSMutableString stringWithString:[array lastObject]];
740         char dir = USB_FileToDevice;
741         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
742         short int nsize = [fname length]+[curPath length]+2;// one for slash, one for padding 0x00
743         const UInt16 nsize_bigendian = EndianU16_NtoB(nsize);
744         [build appendData:[NSData dataWithBytes:&nsize_bigendian length:2]];
745         NSData* d = [curPath dataUsingEncoding:NSISOLatin1StringEncoding];
746         [build appendData:d];
747         dir = 0x5c; // 0x5c = "/"
748         [build appendData:[NSData dataWithBytes:&dir length:1]];
749         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];// may need to pad to 95...
750         if ([fname length] < 95)
751                 [build increaseLengthBy:95-[fname length]];
752         dir = 0x00;
753         [build appendData:[NSData dataWithBytes:&dir length:1]];
754         UInt64 offset_bigendian = EndianU64_NtoB(offset);
755         [build appendData:[NSData dataWithBytes:&offset_bigendian length:8]];
756         
757         // prepackage commands to send
758         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
759         NSData* fileStartCmd = [self prepareCommand:USB_DataHddFileStart withData:typeFile];
760         NSData* fileEndCmd = [self prepareCommand:USB_DataHddFileEnd withData:nil];
762         //start timer
763         NSDate* startTime = [NSDate date];
764         startTime = [startTime addTimeInterval:(0-existingTime)];
765         //send commands
766         if ([turboCB state]) 
767                 [self turnTurboOn:YES];
768         else
769                 [self checkUSB:dev];
770         // now the proper commands
771         NSData *data = [self sendCommand:fileSendCmd toDevice:dev expectResponse:YES careForReturn:YES];
772         data = [self sendCommand:fileStartCmd toDevice:dev expectResponse:YES careForReturn:YES];
773         const UInt32 rW_bigendian = EndianU32_NtoB(USB_Success);
774         NSData* responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
775         NSData* responseToCheck = nil;
777         NSFileHandle* fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileToUpload];
778         [fileHandle seekToFileOffset:offset];
779         do {
780                 if ([priorityTransferQueue count] != 0) {
781                         //break out and create a new transfer to continue it
782                         NSLog(@"pausing upload");
783                         [self addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:
784                                         fileToUpload,@"filename",
785                                         [NSNumber numberWithUnsignedLongLong:size],@"fileSize",
786                                         curPath,@"path",typeFile,@"attributes",@"upload",@"transferType",
787                                         [NSNumber numberWithUnsignedLongLong:offset],@"offset",
788                                         [NSNumber numberWithInt:[[NSDate date] timeIntervalSinceDate:startTime]],@"existingTime",
789                                         nil]
790                                 atIndex:1]; //nb use index 1 as current transfer is at 0 and will be deleted
791                         [self turnTurboOn:NO];
792                         break;
793                 } else {
794                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
795                 offset_bigendian = EndianU64_NtoB(offset);
796                 NSMutableData* fileData = [NSMutableData dataWithBytes:&offset_bigendian length:8];
797                 [fileData appendData:[fileHandle readDataOfLength:rate]];
798                 offset += rate;
799                 NSData* fileDataCmd = [self prepareCommand:USB_DataHddFileData withData:fileData];
800                 data = [self sendCommand:fileDataCmd toDevice:dev expectResponse:YES careForReturn:YES];
801                 if ([data length] >= 8) 
802                         responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
803                 else responseToCheck = nil;
804                 if (responseToCheck == nil || ![responseWanted isEqualToData:responseToCheck]) 
805                         break;
806                 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self
807                         withObject:[NSDictionary dictionaryWithObjectsAndKeys:
808                                 [NSNumber numberWithDouble:(double)offset], @"offset",
809                                 [NSNumber numberWithDouble:(double)size], @"size",
810                                 startTime, @"startTime", nil]];
811                 [pool release];
812                 }
813         } while (offset < size && [[[self uiElements] isConnected] intValue]);
814         if ([[[self uiElements] isConnected] intValue])
815                 data = [self sendCommand:fileEndCmd toDevice:dev expectResponse:YES careForReturn:YES];
816         [fileHandle closeFile]; 
817         [[self uiElements] goToPath:[[self uiElements]currentPath]];
818         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]];
819         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]]; //twice so get the same sort as before
820         [self turnTurboOn:NO];
821         [[self uiElements] finishTransfer];
825 - (void) turnTurboOn:(BOOL) turnOn {
826         if (![[[self uiElements] isConnected] intValue]) return;
827         [self checkUSB:myContext];
828         int mode = 0;
829         if (turnOn) 
830                 mode = 1;
831         const SInt32 mode_bigendian = EndianS32_NtoB(mode);
832         NSData* modeData = [NSData dataWithBytes:&mode_bigendian length:4];
833         NSLog([modeData description]); //debugging
834         NSData* turboCommand  = [self prepareCommand:USB_CmdTurbo withData:modeData];
835         [self sendCommand:turboCommand toDevice:myContext expectResponse:YES careForReturn:NO];
838 - (int) getSpeed {
839         return connectedSpeed;
842 -(void) setDebug:(int)mode {
843         debug = mode;
844         NSLog(@"Debug level: %i", debug);
847 -(void) setRate:(int) newRate {
848         rate = newRate;
849         NSLog(@"New rate set: %i", rate);
852 -(void) setProgressBar:(NSProgressIndicator*)bar time:(NSTextField*)timeField turbo:(NSButton*)turbo{
853         progressBar = bar;
854         progressTime = timeField;
855         turboCB = turbo;
858 -(void) updateProgress:(NSDictionary*) inDict {
859         NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
860         double offset = [[inDict objectForKey:@"offset"] doubleValue];
861         double size = [[inDict objectForKey:@"size"] doubleValue];
862         NSDate* startTime = [inDict objectForKey:@"startTime"];         
863         [progressBar setDoubleValue:((double)offset/size*100)];
864         [progressBar displayIfNeeded];
865         [progressTime setStringValue:[self elapsedTime:[[NSDate date] timeIntervalSinceDate:startTime]]];
866         [progressTime displayIfNeeded];
867         [pool release];
871 - (NSString*) elapsedTime:(NSTimeInterval) totalSeconds {
872         char hp = 20;
873         char mp = 20;
874         char sp = 20; //padding
875         int hours = (totalSeconds / 3600);  // returns number of whole hours fitted in totalSecs
876         if (hours < 10)
877                 hp = 48;
878         int minutes = ((totalSeconds / 60) - hours*60);  // Whole minutes
879         if (minutes < 10)
880                 mp = 48;
881         int seconds = ((long) totalSeconds % 60);       // Here we can use modulo to get num secs NOT fitting in whole minutes (60 secs)
882         if (seconds < 10)
883                 sp = 48;
884         return [NSString stringWithFormat:@"%c%i:%c%i:%c%i", hp, hours, mp, minutes, sp, seconds];
887 - (void) deleteFile:(NSDictionary*)fileInfo fromPath:(NSString*)currentPath {
888         [self checkUSB:myContext];
889         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
890         NSMutableData* build = [NSMutableData dataWithData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
891         char dir = 0x5c; // 0x5c = "\"
892         [build appendData:[NSData dataWithBytes:&dir length:1]];
893         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
894         dir = 0x00;
895         [build appendData:[NSData dataWithBytes:&dir length:1]];
896         NSData* fileDelCmd = [self prepareCommand:USB_CmdHddDel withData:build];
897         [self sendCommand:fileDelCmd toDevice:myContext expectResponse:YES careForReturn:NO];
900 - (void) renameFile:(NSString*) oldName withName:(NSString*)newName atPath:(NSString*)currentPath {
901         NSLog(@"%@,%@,%@", oldName, newName, currentPath);
902         [self checkUSB:myContext];
903         unsigned short int i = [oldName length]+[currentPath length]+2;
904         UInt16 i_bigendian = EndianU16_NtoB(i);
905         NSMutableData* build = [NSMutableData dataWithBytes:&i_bigendian length:2];
906         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
907         char dir = 0x5c;
908         [build appendData:[NSData dataWithBytes:&dir length:1]];
909         [build appendData:[oldName dataUsingEncoding:NSISOLatin1StringEncoding]];
910         dir = 0x00;
911         [build appendData:[NSData dataWithBytes:&dir length:1]];
912         i = [newName length]+[currentPath length]+2;
913         i_bigendian = EndianU16_NtoB(i);
914         [build appendData:[NSData dataWithBytes:&i_bigendian length:2]];
915         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
916         dir = 0x5c;
917         [build appendData:[NSData dataWithBytes:&dir length:1]];
918         [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
919         dir = 0x00;
920         [build appendData:[NSData dataWithBytes:&dir length:1]];
921         NSData* fileRenCmd = [self prepareCommand:USB_CmdHddRename withData:build];
922         [self sendCommand:fileRenCmd toDevice:myContext expectResponse:YES careForReturn:NO];
925 - (void) makeFolder:(NSString*)newName atPath:(NSString*)currentPath {
926         [self checkUSB:myContext];
927         unsigned short int i = [newName length]+[currentPath length]+2;
928         const UInt64 i_bigendian = EndianU16_NtoB(i);
929         NSMutableData* build = [NSMutableData dataWithBytes:&i_bigendian length:2];
930         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
931         char dir = 0x5c;
932         [build appendData:[NSData dataWithBytes:&dir length:1]];
933         [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
934         dir = 0x00;
935         [build appendData:[NSData dataWithBytes:&dir length:1]];
936         NSData* newFoldCmd = [self prepareCommand:USB_CmdHddCreateDir withData:build];
937         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
938         [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO];
939         [self sendCommand:newFoldCmd toDevice:myContext expectResponse:YES careForReturn:NO];
942 - (void) checkUSB:(USBDeviceContext*)device {
943         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
944         NSData* data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
945         const UInt32 rW_bigendian = EndianU32_NtoB(USB_Success);
946         int i = 0;
947         NSData* responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
948         while ((data == nil || [data length] < 8) && i < 8) {
949                 NSLog (@"incorrect response");
950                 i++;
951                 data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
952         }
953         if (!i<=8) {
954                 // tell someone that no longer connected here??
955                 return;
956                 }
957         NSData* responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
958         if (![responseWanted isEqualToData:responseToCheck]) {
959                 [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:NO]; // send reset again   
960         }
963 - (void) transfer:(id)sender {
964         while ([[[self uiElements] isConnected] intValue]) {
965                 NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
966                 if ([priorityTransferQueue count] != 0 ) {
967                         id currentTransfer = [priorityTransferQueue objectAtIndex:0];
968                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"fileList"]) {
969                                 [self getFileListForPath:[currentTransfer objectForKey:@"path"]];
970                                 [priorityTransferQueue removeObjectAtIndex:0];
971 //                              NSLog(@"fL fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
972                         }
973                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"turbo"]) {
974                 //              [self turnTurboOn:[[currentTransfer objectForKey:@"turboOn"] boolValue]];
975                                 [priorityTransferQueue removeObjectAtIndex:0];
976                         }
977                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"rename"]) {
978                                 [self renameFile:[currentTransfer objectForKey:@"oldName"]
979                                         withName:[currentTransfer objectForKey:@"newName"]
980                                         atPath:[currentTransfer objectForKey:@"path"]];
981                                 [priorityTransferQueue removeObjectAtIndex:0];
982                         }
983                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"newFolder"]) {
984                                 [self makeFolder:[currentTransfer objectForKey:@"newName"] atPath:[currentTransfer objectForKey:@"path"]];
985                                 [priorityTransferQueue removeObjectAtIndex:0];
986                         }
987                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"delete"]) {
988                                 [self deleteFile:[currentTransfer objectForKey:@"file"] fromPath:[currentTransfer objectForKey:@"path"]];
989                                 [priorityTransferQueue removeObjectAtIndex:0];
990                         }
991                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"pause"]) {
992                                 if ([transferQueue count] != 0) {
993                                         NSArray* toPause = [transferQueue filteredArrayUsingPredicate:
994                                                 [NSPredicate predicateWithFormat:@"(filename = %@)",
995                                                         [currentTransfer objectForKey:@"filename"]]];
996                                         if ([toPause count] > 1) NSLog(@"multiple pauses?");
997                                         else {
998                                                 [pausedQueue addObjectsFromArray:toPause];
999                                                 [transferQueue removeObjectsInArray:toPause];
1000                                         }
1001                                 }
1002                                 [priorityTransferQueue removeObjectAtIndex:0];
1003                         }
1004                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"resume"]) {
1005                                 if ([pausedQueue count] != 0) {
1006                                         NSArray* toResume = [pausedQueue filteredArrayUsingPredicate:
1007                                                 [NSPredicate predicateWithFormat:@"(filename = %@)",
1008                                                         [currentTransfer objectForKey:@"filename"]]];
1009                                         if ([toResume count] > 1) NSLog(@"multiple resumes?");
1010                                         else {
1011                                                 [transferQueue addObjectsFromArray:toResume];
1012                                                 [pausedQueue removeObjectsInArray:toResume];
1013                                         }
1014                                 }
1015                                 [priorityTransferQueue removeObjectAtIndex:0];
1016                         }
1017                 }
1018                 else if ([transferQueue count] != 0) {
1019                         id currentTransfer = [transferQueue objectAtIndex:0];
1020                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"download"]) {
1021                                 [self getFile:[currentTransfer objectForKey:@"filename"]
1022                                         forPath:[currentTransfer objectForKey:@"path"]
1023                                         toSaveTo:[currentTransfer objectForKey:@"savePath"]
1024                                         beginAtOffset:[[currentTransfer objectForKey:@"offset"] unsignedLongLongValue]
1025                                         withLooping:[[currentTransfer objectForKey:@"looping"] boolValue]
1026                                         existingTime:[[currentTransfer objectForKey:@"existingTime"] intValue]];
1027                                 [transferQueue removeObjectAtIndex:0];
1028 //                              NSLog(@"dl fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1029                         }
1030                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"upload"]) {
1031 //                              NSLog(@"ul start %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1032                                 [self uploadFile:[currentTransfer objectForKey:@"filename"]
1033                                         ofSize:[[currentTransfer objectForKey:@"fileSize"] unsignedLongLongValue]
1034                                         fromPath:[currentTransfer objectForKey:@"path"]
1035                                         withAttributes:[currentTransfer objectForKey:@"attributes"]
1036                                         atOffset:[[currentTransfer objectForKey:@"offset"] unsignedLongLongValue]
1037                                         existingTime:[[currentTransfer objectForKey:@"existingTime"] intValue]];
1038                                 [transferQueue removeObjectAtIndex:0];
1039 //                              NSLog(@"ul fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1040                         }
1041                 }
1042                 else usleep(100);
1043                 [pool release];
1044         }
1047 - (void) addPriorityTransfer:(id)newTransfer {
1048         [priorityTransferQueue addObject:newTransfer];
1049         NSLog(@"%i,p:%i-%@",[transferQueue count],[priorityTransferQueue count],[newTransfer objectForKey:@"transferType"]);
1052 - (void) addTransfer:(id)newTransfer atIndex:(int)front { //-1 for at end
1053         if (front>=0) [transferQueue insertObject:newTransfer atIndex:front];
1054         else [transferQueue addObject:newTransfer];
1055         NSLog(@"%i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1058 - (void) setDH:(id)newDH tableView:(id)tv {
1059         dh = newDH;
1060         tableView = tv;
1063 - (void) clearQueues {
1064         [priorityTransferQueue removeAllObjects];
1065         [transferQueue removeAllObjects];
1066         [pausedQueue removeAllObjects];
1069 - (id) transferQueue {
1070         return transferQueue;
1073 - (id) pausedQueue {
1074         return pausedQueue;
1077 @end