#!/usr/bin/perl


use Net::FTP;

if ($ARGV[0]) {
  $config_file = $ARGV[0];
  &load_config;
  &login_to_host;

  @dir_list[0] = "/";
  $dir_list_currentloc = 0;
  $dir_list_addloc = 1;

  while (1 == 1) {
    &goto_path;
    &process_files;
  }
  &logout;
} else {
  print "Usage: $1 <config file>\n";
  exit 1;
}




sub process_files {
  foreach $element (@listing) {
    ($perm, $blocks, $owner, $group, $size, $month, $day, $time_or_year, $filename) = split /\s+/, $element, 9;
    if ($perm =~ /^d.*$/) {
# Add some checking for download
      mkdir "${filename}", 0755 unless (-d "${filename}");
      $dir_list[$dir_list_addloc] = "${current_path}${filename}/";
      $dir_list_addloc++;
      &set_perm if ($configuration{'permissions'} eq "save");
    } else {
      &get_file;
    }
  }
}


sub get_file {
  if (-f "$filename") {
    if ($configuration{'download'} eq "always") {
      $ftp->get("$filename", "$filename");
      &set_perm if ($configuration{'permissions'} eq "save");
    } else {
      if ($configuration{'download'} eq "differ") {
        $remote_size = $ftp->size("$filename");
        @tmparray = stat("$filename");
        $local_size = $tmparray[7];
        $ftp->get("$filename", "$filename") if ($remote_size != $local_size);
        &set_perm if ($configuration{'permissions'} eq "save");
      } else {
        if ($configuration{'download'} eq "newer") {
          $remote_mdtm = $ftp->mdtm("$filename");
          @tmparray = stat("$filename");
          $local_mdtm = $tmparray[9];
          $ftp->get("$filename", "$filename") if ($remote_mdtm > $local_mdtm);
          &set_perm if ($configuration{'permissions'} eq "save");
        }
      }
    }
  } else {
    $ftp->get("$filename", "$filename");
    &set_perm if ($configuration{'permissions'} eq "save");
  }
}


sub logout { $ftp->quit(); }


sub goto_path {
  $lpathokay = 0;
  $rpathokay = 0;
  if ($dir_list[$dir_list_currentloc]) {
    $current_path = $dir_list[$dir_list_currentloc];
    $local_path = "$configuration{'local_path'}$dir_list[$dir_list_currentloc]";
    $remote_path = "$configuration{'remote_path'}$dir_list[$dir_list_currentloc]";
    $dir_list_currentloc++;

    print "Changing local directory to: $local_path\n";
    print "Changing remote directory to: $remote_path\n\n";
    $lpathokay = chdir "$local_path";
    $rpathokay = $ftp->cwd($remote_path);

    undef @listing if (@listing);
    @listing = $ftp->dir() or warn "Could not get directory listing of $path\n";
  } else {
    &logout;
    exit 0;
  }
  if ($rpathokay) {
    &goto_path unless ($lpathokay);
  } else {
    &goto_path;
    rmdir "$local_path";
  }
}


sub login_to_host {
  $ftp = Net::FTP->new($configuration{'hostname'},
		 Timeout => $configuration{'timeout'},
		    Port => $configuration{'port'},
		 Passive => $configuration{'passive'},
		   Debug => $configuration{'show_debug'}) or die "Can't connect: $@\n";

  $ftp->login($configuration{'username'}, $configuration{'passwd'}) or die "Could not login.\n";
  $ftp->type($configuration{'transfer_type'}) or warn "Could not set transfer type to $configuration{'transfer_type'}\n";
}


sub load_config {
  if (-f "$config_file") {
    open configfile, "${config_file}" or die "Could not open configuration file ${config_file}: $!";
    foreach (<configfile>) {
      s/^\s*(.*?)\s*$/$1/;
      next if (/^#/);   # Skip comments
      ($key, $value) = split /=/;
      $key =~ s/^\s*(.*?)\s*$/$1/;
      $value =~ s/^\s*(.*?)\s*$/$1/;
      $key = lc $key;
      $configuration{$key} = $value;
    }
    close configfile;

    unless ($configuration{'hostname'}) {
      print "Could not find 'hostname' in configuration file ${config_file}\n";
      exit 1;
    }
    $configuration{'username'} = "anonymous" unless ($configuration{'username'});
    $configuration{'passwd'} = "guest\@host.com" unless ($configuration{'passwd'});
    $configuration{'remote_path'} = "/" unless ($configuration{'remote_path'});
     $configuration{'remote_path'} =~ s/^(.*?)\/$/$1/;
#     chop $configuration{'remote_path'} if (substr($configuration{'remote_path'}, length $configuration{'remote_path'}, 1) eq "/");
    $configuration{'local_path'} = "/tmp" unless ($configuration{'local_path'});
     $configuration{'local_path'} =~ s/^(.*?)\/$/$1/;
#     chop $configuration{'local_path'} if (substr($configuration{'local_path'}, length $configuration{'local_path'}, 1) eq "/");
    $configuration{'port'} = "21" unless ($configuration{'port'});
    $configuration{'transfer_type'} = "I" unless ($configuration{'transfer_type'});
    $configuration{'retry'} = "1" unless ($configuration{'retry'});
    $configuration{'timeout'} = "30" unless ($configuration{'timeout'});
    $configuration{'show_debug'} = "0" unless ($configuration{'show_debug'});
    $configuration{'passive'} = "0" unless ($configuration{'passive'});
    $configuration{'download'} = "differ" unless ($configuration{'download'});
    $configuration{'permissions'} = "save" unless ($configuration{'permissions'});
    $configuration{'ownership'} = "discard" unless ($configuration{'ownership'});
  } else {
    print "Configuration file not found: $config_file\n";
    exit 1;
  }
}



sub set_perm {
  $perm_bit1 = 0;
  $perm_bit2 = 0;
  $perm_bit3 = 0;
  $perm_bit4 = 0;

# Owner
  $perm_bit2 += 4 if (substr($perm, 1, 1) eq "r");
  $perm_bit2 += 2 if (substr($perm, 2, 1) eq "w");
  $perm_bit2 += 1 if (substr($perm, 3, 1) eq "x");
  if (substr($perm, 3, 1) eq "s") {
    $perm_bit1 += 2; 
    $perm_bit2 += 1; 
  }
  $perm_bit1 += 4 if (substr($perm, 3, 1) eq "S");

# Group
  $perm_bit3 += 4 if (substr($perm, 4, 1) eq "r");
  $perm_bit3 += 2 if (substr($perm, 5, 1) eq "w");
  $perm_bit3 += 1 if (substr($perm, 6, 1) eq "x");
  if (substr($perm, 6, 1) eq "s") {
    $perm_bit1 += 2;
    $perm_bit3 += 1;
  }
  $perm_bit1 += 2 if (substr($perm, 6, 1) eq "S");

# World
  $perm_bit4 += 4 if (substr($perm, 7, 1) eq "r");
  $perm_bit4 += 2 if (substr($perm, 8, 1) eq "w");
  $perm_bit4 += 1 if (substr($perm, 9, 1) eq "x");
  if (substr($perm, 9, 1) eq "t") {
    $perm_bit1 += 1;
    $perm_bit4 += 1;
  }
  $perm_bit1 += 1 if (substr($perm, 9, 1) eq "T");


  $perm_complete = "${perm_bit1}${perm_bit2}${perm_bit3}${perm_bit4}";
  chmod oct($perm_complete), $filename;


# Save group/ownership?
  if ($configuration{'ownership'} eq "save") {
    ($login, $pass, $uid, $junk) = getpwnam($owner);
    ($login, $pass, $junk, $gid) = getpwnam($group);
    chown $uid, $gid, $filename;
  }
}
