releasing/cbrtools/perl/RemoteSite/FTP.pm
changeset 607 378360dbbdba
parent 602 3145852acc89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/cbrtools/perl/RemoteSite/FTP.pm	Wed Jun 30 11:35:58 2010 +0800
@@ -0,0 +1,867 @@
+# Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+# 
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+# 
+# Contributors:
+# 
+# Description:
+# 
+#
+# Description:
+# RemoteSite::FTP.pm
+#
+
+package RemoteSite::FTP;
+
+use strict;
+use Net::FTP;
+use File::Basename;
+use IO::File;
+
+use RemoteSite;
+use vars qw(@ISA);
+@ISA=("RemoteSite");
+
+#
+# Constants
+#
+
+use constant DEFAULTRECONNECTS => 5;
+use constant DEFAULTTIMEOUT => 30;
+use constant BLOCKSIZE => 32768;
+
+#
+# Initialization
+#
+
+sub Initialize {
+  my $self = shift;
+
+  my %args = @_;
+  $self->{username} = $args{username};
+  $self->{password} = $args{password};
+  $self->{passiveMode} = $args{passive_mode};
+  $self->{resumeMode} = $args{resume_mode};
+  $self->{timeout} = $args{timeout};
+  $self->{reconnects} = $args{reconnects};
+
+  #call base class initialization
+  $self->SUPER::Initialize(@_);
+
+  #if username or password not defined ask for them interactively
+  unless ($self->Username()) {
+    $self->HandleError("No remote host defined.") unless $self->Host();
+    print 'FTP username: ';
+    my $userName = <STDIN>;
+    if ($userName) {
+      chomp ($userName);
+      $self->Username($userName);
+    }
+  }
+  unless ($self->Password()) {
+    print 'FTP password: ';
+    $self->Password(Utils::QueryPassword());
+  }
+
+  #set timeout to default value if not set or not a positive integer
+  unless (defined $self->{timeout} and $self->{timeout} =~ /^\d+$/) {
+    $self->{timeout} = DEFAULTTIMEOUT;
+  }
+
+  #set reconnects to default value if not set or not a positive integer
+  unless (defined $self->{reconnects} and $self->{reconnects} =~ /^\d+$/) {
+    $self->{reconnects} = DEFAULTRECONNECTS;
+  }
+
+  #connect to FTP site, login and set to binary mode
+  $self->Connect();
+}
+
+#
+# Public getters/setters
+#
+
+sub Username {
+  my $self = shift;
+  if (defined $_[0]) {$self->{username} = shift;}
+  return $self->{username};
+}
+
+sub Password {
+  my $self = shift;
+  if (defined $_[0]) {$self->{password} = shift;}
+  return $self->{password};
+}
+
+sub PassiveMode {
+  my $self = shift;
+  if (defined $_[0]) {$self->{passiveMode} = shift;}
+  return $self->{passiveMode};
+}
+
+sub ResumeMode {
+  my $self = shift;
+  if (defined $_[0]) {$self->{resumeMode} = shift;}
+  return $self->{resumeMode};
+}
+
+sub Timeout {
+  my $self = shift;
+  return $self->{timeout};
+}
+
+sub Reconnects {
+  my $self = shift;
+  return $self->{reconnects};
+}
+
+#
+# Public (from RemoteSite)
+#
+
+sub SendFile {
+  my $self = shift;
+  my $localFile = shift;
+  my $remoteFile = shift;
+
+  unless (defined $localFile and defined $remoteFile) {
+    $self->HandleError("Incorrect args passed to ".ref($self)."::SendFile");
+  }
+  $remoteFile =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  my $localFileSize = Utils::FileSize($localFile);
+
+  if ($self->{verbose}) {
+    print 'Uploading '.basename($localFile).' to FTP site '.$self->Host()." ...\n";
+  }
+  elsif ($localFileSize) {
+    print 'Uploading '.basename($localFile).':    ';
+  }
+
+  #check the file to upload exists
+  unless (-e $localFile) {
+    $self->HandleError("Local file $localFile does not exist");
+  }
+
+  #check remote dir exists and create it if it doesn't
+  my $remoteDir = dirname($remoteFile);
+  unless ($self->DirExists($remoteDir)) {
+    $self->MakeDir($remoteDir);
+  }
+
+  #if a file with same name as the remote file already exists delete it (even if it has different case)
+  if (my $actualFileName = $self->FileExists($remoteFile)) {
+    $self->DeleteFile($actualFileName);
+  }
+
+  #create a temporary file name in the remote directory for uploading to
+  my $tmpFile = $self->CreateTemporaryFile($remoteDir);
+
+  #send the file
+  if ($self->ResumeMode()) {
+    $self->SendFileWithResume($localFile, $tmpFile);
+  }
+  else {
+    if ($self->{verbose} and $localFileSize) {
+      print "Upload progress: ";
+    }
+    $self->DisplayProgress($localFileSize);
+    $self->SendFileWithoutResume($localFile, $tmpFile);
+  }
+
+  #rename the temporary file to the final remote file name
+  $self->MoveFile($tmpFile, $remoteFile);
+
+  if ($self->{verbose} > 1) {
+    print "Upload successful. Stored as $remoteFile on FTP site.\n";
+  }
+}
+
+sub GetFile {
+  my $self = shift;
+  my $remoteFile = shift;
+  my $localFile = shift;
+
+  unless (defined $localFile and defined $remoteFile) {
+    $self->HandleError("Incorrect args passed to ".ref($self)."::GetFile");
+  }
+
+  $remoteFile =~ s{\\}{\/}g;     #convert back slashes to forward slashes
+
+  if ($self->{verbose}) {
+    print "Downloading ".$remoteFile." from FTP site ".$self->Host()." ...\n";
+  }
+  else {
+    print "Downloading ".basename($remoteFile).":    ";
+  }
+
+  #check that the file to download exists
+  my $actualFileName;
+  unless ($actualFileName = $self->FileExists($remoteFile)) {
+    $self->HandleError("Remote file $remoteFile does not exist");
+  }
+
+  $remoteFile = $actualFileName;  #handles case sensitivity correctly
+
+
+  #check local dir exists and create it if it doesn't
+  my $localDir = dirname($localFile);
+  unless (-e $localDir) {
+    Utils::MakeDir($localDir);
+    if ($self->{verbose}) {
+      print "Created directory $localDir on local drive\n";
+    }
+  }
+
+  my $remoteFileSize = $self->FileSize($remoteFile);
+
+  if ($self->{verbose} and $remoteFileSize) {
+    print "Download progress: ";
+  }
+
+  #get the file
+  if ($self->ResumeMode()) {
+    $self->DisplayProgress($remoteFileSize);
+    $self->GetFileWithResume($remoteFile, $localFile);
+  }
+  else {
+    $self->DisplayProgress($remoteFileSize);
+    $self->GetFileWithoutResume($remoteFile, $localFile);
+  }
+
+  if ($self->{verbose} > 1) {
+    print "Download successful. Stored as $localFile on local site.\n";
+  }
+}
+
+sub FileExists {
+  my $self = shift;
+  my $remoteFile = shift;
+
+  unless (defined $remoteFile) {
+    return 0;
+  }
+
+  #use Carp qw/cluck/;
+  #cluck "Called FileExists";
+
+  # List the directory the file is in, and see if the file name is in it.
+  $remoteFile =~ s{\/}{\\}g;     #convert forward slashes to back slashes
+  (my $path, my $baseName, my $ext) = Utils::SplitFileName($remoteFile);
+  my $fileName = $baseName . $ext;
+  $path =~ s/\\$//;       #remove trailing slash
+  $path =~ s/\\/\//g;     #convert back slashes to forward slashes
+  my $ls = $self->DirList($path);
+  print "Checking for existence of remote file \"$remoteFile\" by looking for \"$fileName\" in \"$path\".\n" if ($self->{verbose} && $ls);
+  return 0 unless $ls; # definitely doesn't exist if nothing in the directory
+
+  my @present = grep /(\/|\\|^\s*)\Q$fileName\E\s*$/i, @$ls;
+  if (@present) {
+    print "Have found file: YES\n" if ($self->{verbose});
+    $present[0] = $path."/".$present[0] if ( $present[0] !~ /\// );
+    return $present[0];
+  }
+  else {
+    print "Have found file: NO\n" if ($self->{verbose});
+    return 0;
+  }
+}
+
+sub DirList {
+  my $self = shift;
+  my $remoteDir = shift;
+
+  print "Listing FTP directory $remoteDir\n" if ($self->{verbose});
+
+  my $dirlist_retries = 3;
+
+  $remoteDir =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  my $retry;
+  for ($retry = 0; $retry < $dirlist_retries; $retry++) {
+
+    unless ($self->Connected()) {
+      $self->Connect();
+    }
+
+    # The Net::FTP module that we're using here has two options for listing the contents
+    # of a directory. They are the 'ls' and 'dir' calls.
+    # The 'ls' call is great, and just returns a list of the items. But, irritatingly, it
+    # misses out directories: the returned list just contains names of *files*.
+    # dir is better, in some ways, as it lists directories too, but its output format
+    # varies from one FTP site to the next. So we have to stick with ls.
+    print "About to call dir(\"$remoteDir\")\n" if ($self->{verbose});
+    my $ls = $self->{ftp}->ls($remoteDir);
+    my $resp = $self->{ftp}->message;
+    print "FTP response to list command was \"$resp\"\n" if ($self->{verbose});
+    if (ref $ls) {
+      print "FTP dir returned \"$ls\" which is a ".(ref $ls)." containing ".(scalar @$ls)." items\n" if ($self->{verbose});
+      $ls = undef if ($resp eq ""); # if we didn't get "Opening BINARY mode connection..." or something similar, then we've
+        # come across the problem where Net::FTP says Net::FTP: Unexpected EOF on command channel at d:/reltools/2.6x/personal/bin/Net
+        # /FTP/dataconn.pm line 73. Unfortunately, it doesn't die, and it returns an empty array, so the only way to find out this has
+        # happened is to check message.
+      $ls = undef if ($resp =~ m/^connection closed/i);
+    }
+    # $ls might now be undef
+    if (ref($ls)) {
+      return $ls;
+    }
+    else {
+      if ($self->Connected()) {
+        return undef;
+      }
+      else {
+        print "Warning: Listing of \"$remoteDir\" failed due to an FTP site problem: " . $self->{ftp}->message . ". ";
+        if ($self->PassiveMode()) {
+          print "PASV mode FTP is currently enabled. This can cause connectivity issues under certain circumstances. ",
+            "To disable, remove the pasv_transfer_mode directive from your reltools.ini file.\n";
+        }
+        else {
+          print "PASV mode FTP is currently disabled. Enabling it can prevent connectivity issues under certain circumstances. ",
+            "To enable, add the pasv_transfer_mode directive to your reltools.ini file.\n";
+        }
+        # Fall through to next loop iteration
+      }
+    }
+  }
+  die "Error: have tried to list \"$remoteDir\" $retry times with no success - giving up\n";
+}
+
+sub MakeDir {
+  my $self = shift;
+  my $remoteDir = shift;
+
+  $remoteDir =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  if ($self->{ftp}->mkdir($remoteDir, 1)) {
+    if ($self->{verbose}) {
+      print "Created directory $remoteDir on FTP site\n";
+    }
+  }
+  else {
+    if ($self->Connected()) {
+      $self->HandleError("Cannot make directory $remoteDir on FTP site");
+    }
+    else {
+      $self->MakeDir($remoteDir);
+    }
+  }
+}
+
+sub FileSize {
+  my $self = shift;
+  my $file = shift;
+
+  $file =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  my $size;
+  if (defined($size = $self->{ftp}->size($file))) {
+    return $size;
+  }
+  else {
+    if ($self->Connected()) {
+      return 0;
+    }
+    else {
+      $self->FileSize($file);  #try to get the size again after reconnecting
+    }
+  }
+}
+
+sub DeleteFile {
+  my $self = shift;
+  my $file = shift;
+
+  $file =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  if ($self->{ftp}->delete($file)) {
+    return;
+  }
+  elsif ($self->{ftp}->rmdir($file)) {
+    return;
+  }
+  else {
+    if ($self->Connected()) {
+      $self->HandleError("Cannot delete $file on FTP site");
+    }
+    else {
+      $self->DeleteFile($file);
+    }
+  }
+}
+
+sub MoveFile {
+  my $self = shift;
+  my $oldFile = shift;
+  my $newFile = shift;
+
+  $oldFile =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+  $newFile =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  if ($self->{ftp}->rename($oldFile, $newFile)) {
+    return;
+  }
+  else {
+    if ($self->Connected()) {
+      $self->HandleError("Cannot move $oldFile to $newFile on FTP site");
+    }
+    else {
+      $self->MoveFile($oldFile, $newFile);
+    }
+  }
+}
+
+sub FileModifiedTime {
+  my $self = shift;
+  my $file = shift;
+
+  $file =~ s{\\}{\/}g;   #convert back slashes to forward slashes
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  my $modifiedTime;
+  if (defined($modifiedTime = $self->{ftp}->mdtm($file))) {
+    return $modifiedTime;
+  }
+  else {
+    if ($self->Connected()) {
+      print "Warning: failed to find modified time for file \"$file\"\n";
+      return undef;
+    }
+    else {
+      $self->FileModifiedTime($file);
+    }
+  }
+}
+
+#
+# Private
+#
+
+sub Connect {
+  my $self = shift;
+
+  unless ($self->Host()) {
+    $self->HandleError("Cannot connect FTP host name not defined");
+  }
+  my $debug = (($self->{verbose} && $self->{verbose} > 1) ? 1 : 0);
+
+  #Attempt to connect (or reconnect if connection fails)
+  for (1..$self->Reconnects()) {
+    $self->{ftp} = undef;
+    if ($self->{verbose}) {
+      print "Connecting to FTP site ".$self->Host()."...\n";
+    }
+    $self->{ftp} = Net::FTP->new($self->Host(),
+				 Passive => $self->PassiveMode(),
+				 Debug => $debug,
+				 Timeout => $self->Timeout());
+    if (defined $self->{ftp}) {
+      #login to FTP site
+      $self->{ftp}->login($self->Username(), $self->Password())
+	or $self->HandleError("FTP login failed");
+
+      #change transfer mode to binary
+      $self->{ftp}->binary()
+	or $self->HandleError("Failed to set FTP server to binary transfer mode");
+      return;
+    }
+  }
+  $self->HandleError("Cannot connect to FTP site ".$self->Host());
+}
+
+sub Connected {
+  my $self = shift;
+  return (defined $self->{ftp} and defined $self->{ftp}->pwd);
+}
+
+sub SendFileWithResume {
+  my $self = shift;
+  my $localFile = shift;
+  my $remoteFile = shift;
+
+  #open the local file for reading
+  $self->{localfh} = IO::File->new("< $localFile");
+  binmode($self->{localfh});
+
+  my $localFileSize = Utils::FileSize($localFile);
+
+  my $buffer;
+  my $bytesSent;
+  my $totalBytesSent = 0;
+
+ RESUME:
+  #Open the temporary file on the FTP site for writing/appending
+  $self->{dataconn} = $self->OpenRemoteFileForAppending($remoteFile);
+
+  if ($self->{verbose} and $localFileSize) {
+    print "Upload progress:    ";
+  }
+
+  #upload temporary file in blocks
+  while ($self->{localfh}->read($buffer, BLOCKSIZE)) {
+    eval {
+      $bytesSent = $self->{dataconn}->write($buffer, length($buffer));
+    };
+    unless ($bytesSent) {
+      if (my $ftpResponse = $self->{ftp}->getline()) {
+        $self->{ftp}->ungetline($ftpResponse);
+        next if ($ftpResponse !~ m/^(3|4|5)/);
+        chomp $ftpResponse;
+        print "\nError: The FTP server returned \'$ftpResponse\'\n";
+      }
+      
+      if ($self->Connected()) {
+	$self->HandleError("Cannot append to remote file $remoteFile");
+      }
+      else {
+	#connection dropped. Reconnect and resume upload
+	if ($self->{verbose}) {print "\n"}
+	$self->Connect();
+	$totalBytesSent = $self->FileSize($remoteFile);
+	seek($self->{localfh}, $totalBytesSent, 0);
+	goto RESUME;
+      }
+    }
+    else {
+      $totalBytesSent += $bytesSent;
+      $self->UpdateProgress($totalBytesSent, $localFileSize);
+    }
+  }
+
+  #close the remote and local files now the transfer has finished
+  $self->CloseAllOpenFiles();
+}
+
+sub SendFileWithoutResume {
+  my $self = shift;
+  my $localFile = shift;
+  my $remoteFile = shift;
+
+  my $putSuccess;
+  eval {
+    $putSuccess = $self->{ftp}->put($localFile, $remoteFile);
+  };
+  unless ($putSuccess) {
+    $self->HandleError("Problem occurred during FTP upload of $localFile");
+  }
+}
+
+sub GetFileWithResume {
+  my $self = shift;
+  my $remoteFile = shift;
+  my $localFile = shift;
+
+  my $totalBytesReceived = 0;
+  my $getSuccess;
+
+ RESUME:
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  eval {
+    $getSuccess = $self->{ftp}->get($remoteFile, $localFile, $totalBytesReceived);
+  };
+
+  unless ($getSuccess or !$@) {
+    if ($self->Connected()) {
+      $self->HandleError("Problem occurred during FTP download of $remoteFile");
+    }
+    else {
+      $totalBytesReceived = Utils::FileSize($localFile);
+      goto RESUME;
+    }
+  }
+}
+
+sub GetFileWithoutResume {
+  my $self = shift;
+  my $remoteFile = shift;
+  my $localFile = shift;
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  my $getSuccess;
+  eval {
+    $getSuccess = $self->{ftp}->get($remoteFile, $localFile);
+  };
+  unless ($getSuccess) {
+    $self->HandleError("Problem occurred during FTP download of $remoteFile");
+  }
+}
+
+sub DirExists {
+  my $self = shift;
+  my $remoteDir = shift;
+
+  $remoteDir =~ s{\\}{\/}g;     #convert back slashes to forward slashes
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  my $pwd = $self->{ftp}->pwd() or $self->HandleError("Problem reading current working directory on FTP site\n");
+  my $exists = 0;
+  if ($self->{ftp}->cwd($remoteDir)) {
+    $exists = 1;
+    $self->{ftp}->cwd($pwd) or $self->HandleError("Problem changing current working directory back to $pwd on FTP site\n");
+  }
+
+  return $exists;
+}
+
+
+sub OpenRemoteFileForAppending {
+  my $self = shift;
+  my $remoteFile = shift;
+
+  unless ($self->Connected()) {
+    $self->Connect();
+  }
+
+  my $dataconn;
+  if (defined($dataconn = $self->{ftp}->appe($remoteFile))) {
+    return $dataconn;
+  }
+  else {
+    if ($self->Connected()) {
+      $self->HandleError("Cannot open $remoteFile for appending on FTP site");
+    }
+    else {
+      $self->OpenRemoteFileForAppending($remoteFile);
+    }
+  }
+}
+
+sub CloseAllOpenFiles {
+   my $self = shift;
+
+  if ($self->{localfh}) {
+    $self->{localfh}->close;
+    $self->{localfh} = undef;
+  }
+  if ($self->{dataconn}) {
+    $self->{dataconn}->close();
+    $self->{dataconn} = undef;
+  }
+}
+
+sub DisplayProgress {
+  my $self = shift;
+  my $total = shift;
+
+  my $numHashes = 50;
+  my $bytesPerHash = int $total / $numHashes;
+  if ($total) {
+    $self->{ftp}->hash(\*STDERR, $bytesPerHash);
+  }
+}
+
+sub UpdateProgress {
+  my $self = shift;
+  my $current = shift;
+  my $total = shift;
+
+  my $bytesPerPercent = int $total/100;
+  if ($current == $total) {
+    print "\b\b\b100%\n";
+  }
+  elsif ($bytesPerPercent == 0) {
+    print "\b\b0%";
+  }
+  else {
+    my $percentComplete = int $current/$bytesPerPercent;
+    if ($percentComplete < 10) {
+      print "\b\b$percentComplete%";
+    }
+    else {
+      print "\b\b\b$percentComplete%";
+    }
+  }
+}
+
+sub HandleError {
+  my $self = shift;
+  my $errorString = shift;
+
+  if (defined $self->{ftp}) {
+    $self->{ftp}->quit();
+    $self->{ftp} = undef;
+  }
+  $self->CloseAllOpenFiles();
+
+  #call the super class error handler
+  $self->SUPER::HandleError($errorString);
+}
+
+sub CreateTemporaryFile {
+  my $self = shift;
+  my $remoteDir = shift;
+
+  my $fileNum = 10000;
+  my $tmpFile = $remoteDir.'/lpdrt'.$fileNum.'.tmp';
+  while ($self->FileExists($tmpFile)) {
+    ++$fileNum;
+    $tmpFile = $remoteDir.'/lpdrt'.$fileNum.'.tmp';
+  }
+  return $tmpFile;
+}
+
+
+#
+# Destructor
+#
+
+sub DESTROY {
+  my $self = shift;
+
+  $self->CloseAllOpenFiles();
+
+  if (defined $self->{ftp}) {
+    if ($self->{verbose}) {
+      print "Dropping connection to FTP site ".$self->Host()."\n";
+    }
+    $self->{ftp}->quit();
+    $self->{ftp} = undef;
+  }
+}
+
+1;
+
+=head1 NAME
+
+RemoteSite::FTP.pm - Access a remote FTP site.
+
+=head1 SYNOPSIS
+
+ use RemoteSite::FTP;
+
+ $ftp = RemoteSite::FTP->New(host => 'ftp.somehost.com',
+	         	     username => 'myusername',
+			     password => 'mypassword',
+			     verbose => 1);
+
+ if ($ftp->FileExists('/somedir/someremotefile')) {
+   do something...
+ }
+ $ftp->SendFile('somelocalfile', 'someremotefile');
+ $ftp->GetFile('someremotefile', 'somelocalfile');
+
+=head1 DESCRIPTION
+
+C<RemoteSite::FTP> is inherited from the abstract base class C<RemoteSite>, implementing the abstract methods required for transfer of files to and from a remote site when the remote site is an FTP server.
+
+=head1 INTERFACE
+
+=head2 New
+
+Passed an argument list in the form of hash key value pairs. The supported arguments are...
+
+  host             => $host_address_string
+  username         => $user_name_string
+  password         => $pass_word_string
+  passiveMode      => $passive_mode_bool
+  resumeTransfers  => $resume_transfers_bool
+  timeout          => $timeout_integer
+  reconnects       => $reconnects_integer
+  verbose          => $verbosity_integer
+
+Returns a reference to a C<RemoteSite::FTP> object
+
+=head2 Host
+
+Returns the current value of the C<host> attribute which contains the host FTP address. If passed an argument sets the attribute to this new value.
+
+=head2 Username
+
+Returns the current value of the C<username> attribute which stores the user name required to access the FTP site. If passed an argument sets the attribute to this new value.
+
+=head2 Password
+
+Returns the current value of the C<password> attribute which stores the password required to access the FTP site. If passed an argument sets the attribute to this new value.
+
+=head2 SendFile
+
+Passed a local and a remote file name. Uploads the local file to the FTP site. Dies if upload fails
+
+=head2 GetFile
+
+Passed a remote and local file name. Downloads the remote file from the FTP site and stores it on the local drive. Dies if download fails.
+
+=head2 FileExists
+
+Passed a filename (with full path) on the FTP site. Returns a non zero value if the file exists.
+
+=head2 DirList
+
+Passed a directory name. Returns a list of files contained in the directory or undef if fails to read directory
+
+=head2 MakeDir
+
+Passed a directory name. Creates the directory on the FTP site
+
+=head2 DeleteFile
+
+Passed a file name. Deletes the file on the FTP site. Dies if fails
+
+=head2 FileSize
+
+Passed a file name. Returns the size of the file. Returns 0 if fails.
+
+=head2 FileModifiedTime
+
+Passed a file name. Returns the last modified time stamp of the file. Returns undef if fails
+
+=head2 MoveFile
+
+Passed two file names. Renames the first file to the second file name. Dies if fails.
+
+=head1 KNOWN BUGS
+
+None
+
+=head1 COPYRIGHT
+
+ Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+ All rights reserved.
+ This component and the accompanying materials are made available
+ under the terms of the License "Eclipse Public License v1.0"
+ which accompanies this distribution, and is available
+ at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ 
+ Initial Contributors:
+ Nokia Corporation - initial contribution.
+ 
+ Contributors:
+ 
+ Description:
+ 
+
+=cut