Logo Search packages:      
Sourcecode: waiho.app version File versions  Download package

ftp.m

/*
    This file is part of Waiho (http://info.xdev.org/projets/waiho)
    Copyright (C) 2001-2002 Nicolas Roard (nicolas@roard.com)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#import "ftp.h"

@implementation FTP

/* init functions */

+alloc {
      return [super alloc];
}
-init {
    [super init];
    PI = nil;
    DTP = nil;
    Login = nil;
    Password = nil;
    FileName = nil;
}

-initWithAddress: (NSString*) adr {
      int sd = [self createSocket: adr withPort: 21];
      NSLog (@"Adresse : %@ socket : %i\n", adr, sd);
      PI = [[NSFileHandle alloc] initWithFileDescriptor : sd];
      DTP = nil;
      Login = nil;
      Password = nil;
      FileName = nil;
      [self ret];
      return self;
}
-initWithAddress: (NSString*) adr withLogin: (NSString*) login withPassword: (NSString*) passwd {
      NSMutableString* loginStr = [[NSMutableString alloc] autorelease];
      NSMutableString* passwdStr = [[NSMutableString alloc] autorelease];
      [self initWithAddress: adr];
      Login = [[NSString alloc] initWithString: login];
      Password = [[NSString alloc] initWithString: passwd];
      FileName = nil;
      [loginStr appendString: @"USER "];
      [loginStr appendString: Login];
      [passwdStr appendString: @"PASS "];
      [passwdStr appendString: Password];
      [self command: loginStr];
      [self command: passwdStr];
      return self;
}
- (BOOL) isConnected {
    BOOL ret = NO;
    if (PI != nil) ret = YES;
    else NSLog (@"On est Deconnecte");
    return ret;
}

- (void) shutdown {
      [self command: @"TYPE" withParam: @"A"];
      [self command: @"QUIT"];
      [self close];
}

- (void) close {
    if (PI != nil) [PI closeFile];
    if (DTP != nil) [DTP closeFile];
      PI = nil;
      DTP = nil;
}

/* ftp functions */

- (int) ret {
      BOOL multiline = NO;
      NSString* str;
      int ret = -1;

      NS_DURING

          if ([self isConnected])
          {
            while (YES)
            {
                  str = [self readLineFrom: PI];
                  NSLog  (@"RET() ==> %@" ,str);
                  if ((str != nil) && ([str length] > 3))
                  {
                      ret = [[str substringFromRange: NSMakeRange (0, 3)] intValue];
                        NSLog (@"ret : %d", ret);
                        if (ret >= 400)   /* hmm... */ 
                        {
                              NSLog (@"CLOSING CONNECTION !");
                              [self close];
                              break;
                        }
                      if ([str characterAtIndex: 3] == '-') multiline = YES;
                      else multiline = NO;
                      if (!multiline) break;
                  }
                  else break;
            }
          }

      NS_HANDLER
          
          NSLog (@"Exception recue dans pasv ==> %@", [localException reason]);

      NS_ENDHANDLER

      return ret;
}
- (void) pasv {
      BOOL multiline = NO;
      NSString* str;
      NSArray* list;
      NSRange pos1;
      NSRange pos2;
      int ip1,ip2,ip3,ip4;
      int port1,port2;
      int port;
      int sd;

      NS_DURING

          if ([self isConnected])
          {
            NSLog (@"=> PASV\n");
            [PI writeData: [NSData dataWithBytes:  
                  length: ]];

            while (YES)
            {
                  str = [self readLineFrom: PI];
                  NSLog  (@"RET() ==> %@" ,str);
                  if ((str != nil) && ([str length] > 3))
                  {
                        int ret = [[str substringFromRange: NSMakeRange (0,3)] intValue];
                        if (ret >= 400)   /* hmm... */ 
                        {
                              NSLog (@"CLOSING CONNECTION !");
                              [self close];
                              break;
                        }
                      if ([str characterAtIndex: 3] == '-') multiline = YES;
                      else multiline = NO;
                      if (!multiline) break;
                  }
                  else break;
            }

            if ([self isConnected])
            {
                  pos1 = [str rangeOfString: @"("];
                  pos2 = [str rangeOfString: @")"];
                  str = [str substringFromRange: NSMakeRange (pos1.location+1,pos2.location-pos1.location)];

                  list = [str componentsSeparatedByString: @","];
                  if ([list count] == 6)
                  {
                        NSMutableString* adr = AUTORELEASE([[NSMutableString alloc] init]);
                        [adr appendString: [list objectAtIndex: 0]];
                        [adr appendString: @"."];
                        [adr appendString: [list objectAtIndex: 1]];
                        [adr appendString: @"."];
                        [adr appendString: [list objectAtIndex: 2]];
                        [adr appendString: @"."];
                        [adr appendString: [list objectAtIndex: 3]];

                        port1 = atoi ( [[list objectAtIndex: 4] cString] );
                        port2 = atoi ( [[list objectAtIndex: 5] cString] );
                        printf ("IP : %s\n", [adr cString]);

                        port = port1 << 8;
                        port += port2;

                        printf ("Port : %i \n", port);
                        sd = [self createSocket: adr withPort: port];
                        NSLog (@"Adresse : %@ socket : %i port : %i\n", adr, sd, port);
                        DTP = [[NSFileHandle alloc] initWithFileDescriptor : sd];
                  }
            }
          }

      NS_HANDLER
          
          NSLog (@"Exception recue dans pasv ==> %@", [localException reason]);

      NS_ENDHANDLER
}
- (int) command: (NSString*) str {
      return [self command: str withParam: @""];
}
- (int) command: (NSString*) str withParam: (NSString*) param {
      NSMutableString* mstr = AUTORELEASE([[NSMutableString alloc] initWithString: str]);
      int ret = -1;

      NS_DURING 

            if ([param compare: @""] != NSOrderedSame) // param null
            {
                [mstr appendString: @" "];
                [mstr appendString: param];
            }
            NSLog (@"=> >%@<", mstr);
            if ([mstr hasSuffix: @"\r"]) [mstr appendString: @"\n"];
            else [mstr appendString: @"\r\n"];
            if (PI != nil) [PI writeData: [NSData dataWithBytes: 
                  [mstr cString] length: [mstr cStringLength]]];
            ret = [self ret];

      NS_HANDLER
          
          NSLog (@"Exception recue dans command: %@ withParam: %@ ==> %@", str, param, [localException reason]);

      NS_ENDHANDLER

      return ret;
}
- (NSArray*) list: (NSString*) str {
      NSData* buf; 
      NSArray* list;
      NSMutableArray* files = nil;
      NSString* mstr;
      int i = 0;
      int j = 0;

      NSLog (@"On entre dans list()");

      NS_DURING

      if ([self isConnected])
      {
          [self pasv];
            
            if ([self isConnected])
            {

                [self command: @"TYPE" withParam: @"A"];
                [self command: @"LIST" withParam: str];

                if (DTP != nil) 
                {
                      buf = [DTP readDataToEndOfFile];

                      if (buf != nil)
                        {     
                            [self ret];
                            mstr = [NSString stringWithCString: [buf bytes]];
                            NSLog (@"Buf NLST : %@", mstr);
                            list = [mstr componentsSeparatedByString: @"\n"];

                        files = ([[NSMutableArray alloc] init]);

                        for (i = 0; i< (int)([list count]-1); i++)
                        {
                              File* mf;
                              NSString* name;
                              char* line = [[list objectAtIndex:i] cString];
                              struct ftpparse line_parse;
                              int type = 0;

                              // type 0 file, type 1 directory, type 2 link.

                              // Si la ligne se termine par un \r\n au lieu d'un \n on vire le \r pour ftpparse()
                              if (line [strlen (line)-1] == '\r') line  = '\0';
                              
                              ftpparse (&line_parse, line , strlen (line));
                              
                              name = [NSString stringWithCString: line_parse.name length: line_parse.namelen];
                              if (line_parse.flagtrycwd) type = 1;
                              if (line_parse.flagtrycwd && line_parse.flagtryretr) type = 2;

                              mf = [[File alloc] initWithName: name withSize: line_parse.size withType: type];
                              [mf print];
                              [files addObject: mf];
                         }
                      }
                }
            }
          }

      NS_HANDLER
          
          NSLog (@"Exception recue dans list: %@ ", str);

      NS_ENDHANDLER

      NSLog (@"Sortie de la fonction list()");

      return files;
}
- (int) get: (NSString*) str withID: (int) idfile {
    return [self get: str withSavedName: str withID: idfile];
}
- (int) get: (NSString*) str withSavedName: (NSString*) name withID: (int) idfile {
    int ret = -1;
    _idfile = idfile;
    masize = 0;
    if ([self isConnected])
    {
      FileName = [[NSString alloc] initWithString: name];
      [self pasv];
            
      if ([self isConnected])
      {
            [self command: @"TYPE" withParam: @"I"];
            ret = [self command: @"RETR" withParam: str];
            [NSThread detachNewThreadSelector: @selector (downloadThread:) 
                  toTarget: self withObject: FileName];
      }
            
    }
    return ret;
}
- (int) put: (NSString*) str withSavedName: (NSString*) name withID: (int) idfile {
      NSFileHandle* fd;
      NSData* data;
      int ret = -1;
      _idfile = idfile;

      if ([self isConnected])
      {
          fd = [NSFileHandle fileHandleForReadingAtPath: str];

          if (fd != nil) // The file exist
          {
            [self pasv];
            if ([self isConnected])
            {
                  [self command: @"TYPE" withParam: @"I"];
                  ret = [self command: @"STOR" withParam: name];
                  data = [fd readDataToEndOfFile];
                  [NSThread detachNewThreadSelector: @selector (uploadThread:) toTarget: self withObject: data];
            }
          }
          else
          {
            NSLog (@"Fichier %@ non trouve !", str);
          }
      }

      return ret;
}
- (int) cd: (NSString*) str {
      [self command: @"TYPE" withParam: @"A"];
      return [self command: @"CWD" withParam: str];
}
- (int) size: (NSString*) str {
    int isize = -1;

    if ([self isConnected])
    {
      NSArray* files = [self list: str];

      if (files != nil)
      {
            if ([files count] == 1)
            {
                File* file = [files objectAtIndex: 0];
                isize = [file size];
            }
      }
    }

    return isize;
}

/* utilities functions */

- (void) downloadThread: (NSString*) filename {
    int idfile = _idfile;
    NSDictionary* info;
    NSData* data;
    NSString* size;
    NSString* idoffile;
    NSMutableData* save = nil;

    NS_DURING

      int packetsize = 16384;
      NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];

      data = [DTP readDataOfLength: packetsize];
      idoffile = [NSString stringWithFormat: @"%d", idfile];
      save  = [[NSMutableData alloc] initWithData: data];
      while ([data length] > 0)
      {
          size = [NSString stringWithFormat: @"%d", [data length]];
          masize += [data length];
          NSLog (@"taille mise : %@ total : %i",size, masize);
          info = [NSDictionary dictionaryWithObjectsAndKeys: idoffile, @"ID", size, @"size", nil];
                      
          [[NSDistributedNotificationCenter defaultCenter] postNotificationName:
            @"ChunkOfFile" object: @"DataTransfert" userInfo: info];
          data = [DTP readDataOfLength: packetsize];
          [save appendData: data];
      }

      // Connection terminée, on a tout lu.

      [self ret];
      NSLog (@"fichier FileName : %@ telecharge", FileName);
      size = [NSString stringWithFormat: @"%d", [save length]];
      if ((save != nil) && (FileName != nil))
      {
          NSLog (@"on essaie de sauver %@ ...", FileName);
          [save writeToFile: FileName atomically: NO];
          NSLog (@"Fichier %@ sauve !", FileName);
      }
      else
      {
          NSLog (@"Fichier %@ impossible a sauver :-(");
      }
      NSLog (@"on fait la notification FileSaved");
      info = [NSDictionary dictionaryWithObjectsAndKeys: idoffile, @"ID", size, @"size", nil];
      [[NSDistributedNotificationCenter defaultCenter] postNotificationName:
          @"FileSaved" object: @"DataTransfert" userInfo: info];

    NS_HANDLER
      
      NSLog (@"Exception recue dans downloadThread: %@ ==> %@", filename, [localException reason]);

    NS_ENDHANDLER

    [NSThread exit];
}
- (void) uploadThread: (NSData*) data {
    int idfile = _idfile;
    NSDictionary* info;
    NSString* size;
    NSString* idoffile;
    int packetsize = 16384;
    NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
    long int send = 0;

    NS_DURING

      NSLog (@"Data length : %i", [data length]);
      idoffile = [NSString stringWithFormat: @"%d", idfile];

      while ((DTP != nil) && (send < [data length]))
      {
          int upto = packetsize;
          NSData* chunk;
          if ((send + upto) > [data length]) upto = [data length] - send;

          NSLog (@"send : %d upto : %d ", send, upto);
          chunk = [data subdataWithRange: NSMakeRange (send, upto)];
          NSLog (@"chunk (%i,%i) == %i ", send, upto + send , upto);
          [DTP writeData: chunk];
          size = [NSString stringWithFormat: @"%d", [chunk length]];
          info = [NSDictionary dictionaryWithObjectsAndKeys: size, @"size", nil];
          send += [chunk length];
          NSLog (@"nouvelle taille de send : %i (%i) ", send, upto);
          [[NSDistributedNotificationCenter defaultCenter] postNotificationName:
            @"ChunkOfFileUploaded" object: @"DataTransfert" userInfo: info];
      }
      
      [DTP closeFile]; 
      DTP = nil; 

      [self ret];
      size = [NSString stringWithFormat: @"%d", [data length]];

      // On a tout envoyé

      NSLog (@"on fait la notification FileSend");
      info = [NSDictionary dictionaryWithObjectsAndKeys: idoffile, @"ID", size, @"size", nil];
      [[NSDistributedNotificationCenter defaultCenter] postNotificationName:
          @"FileSend" object: @"DataTransfert" userInfo: info];

    NS_HANDLER
      
      NSLog (@"Exception recue dans uploadThread ==> %@", [localException reason]);

    NS_ENDHANDLER

    [NSThread exit];

}

- (int) createSocket: (NSString*) hostname withPort: (int) port {
    struct sockaddr_in address;
    struct linger ling;
    struct hostent *hp = 0;
    int size = sizeof (struct sockaddr_in);
    int type = SOCK_STREAM;
    int protocol = 0;
    int sd = -1;
    int ret = -1;
    
    sd = socket (AF_INET, type, protocol);

    if (sd == -1) RaiseNetworkException ("Socket Creation");

    bzero ((char*) &address, size);
    address.sin_family = AF_INET;
    address.sin_port = htons (port);
        
    hp = gethostbyname ( [hostname cString]);
    if (hp == 0) RaiseNetworkException ("gethostbyname");

    memmove(&address.sin_addr, 
          hp->h_addr,
          hp->h_length);

    ling.l_onoff = 1;
    ling.l_linger = 10;

    ret = setsockopt (sd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
    if (ret == -1) RaiseNetworkException ("Error with setsockopt");
    
    ret = connect (sd, (struct sockaddr*) &address, size);
    if (ret == -1) RaiseNetworkException ("connect");

    return sd;
}
- (NSString*) readLineFrom: (NSFileHandle*) FH {
      NSMutableData* buf = [NSMutableData dataWithLength: 0];
      char b;
      BOOL end = NO;
      BOOL preend = NO;
      int ret;

      if (FH != nil)
      {
          while (!end)
          {
                ret = read ([FH fileDescriptor], &b, 1);
                if (ret == 1)
                {
                      if (b == '\r')
                      {
                        preend = YES;
                      }
                      else if ((b == '\n') && (preend))
                      {
                        end = YES;
                      }
                      else
                      {
                        if (preend)
                        {
                            char c='\r';
                            [buf appendBytes: &c length: 1];
                            preend = NO;
                        }
                        [buf appendBytes: &b length: 1];
                      }
                }
                else end = YES;
          }
          //if ([buf length] == 0) [buf appendBytes: 0 length: 1];
      }
      return [[NSString alloc] initWithData: buf encoding: NSASCIIStringEncoding];
}

@end


Generated by  Doxygen 1.6.0   Back to index