#!/usr/bin/perl -w
#use strict;
use vars qw/$AUTOLOAD/;

package Smbclient;

sub new {
   my $class = shift;
   my $fullshare = shift;
   my %options = @_;

   chomp $fullshare;

   if(!defined($fullshare)) {
      warn "No share!\n";
      return;
   }

   my $self = {} ;
   bless $self, ref $class || $class ;
   $self->fullshare($fullshare);
   foreach my $key ( keys %options ) {
      $lkey = lc($key);
      $self->$lkey( $options{$key} );
   }
   return $self;
}

sub AUTOLOAD {
   my $self = shift;
   my $var = shift;
   my $method = $AUTOLOAD;
   $method =~ s{^.*::}{};
   if ( defined($var) ) {
      $self->{data}{$method} = $var;
   }
   return $self->{data}{$method};
}

sub computer() {
   my $self = shift;
   my @comp = split /\//, $self->fullshare();
   return $comp[2];
}

sub share() {
   my $self = shift;
   my @comp = split /\//, $self->fullshare();
   return $comp[3];
}

sub directory() {
   my $self = shift;
   my @comp = split /\//, $self->fullshare();
   @comp = splice @comp, 4, -1;
   my $str = "/";
   $str .= $_."/" for(@comp);
   return $str;
}

sub localfilename() {
   my $self = shift;
   my $str = $self->target();
   $str =~ s/'//g;
   return $str;
}

sub target() {
   my $self = shift;
   my @comp = split /\//, $self->fullshare();
   return $comp[ $#comp ];
}

sub check() {
   my $self = shift;
}

sub smbclient() {
   my $self = shift;
   my $command     = shift;
   my $directory   = shift;
   if (!defined($directory)) {
      $directory = "";
   }

   if ( defined($self->{cache}{smbclient}{$command.$directory}) ) {
      return @{ $self->{cache}{smbclient}{$command.$directory} };
   }

   my $share = "\"//".$self->computer()."/";
   if ( defined($self->share()) ) {
      $share .= $self->share();
   }
   $share .= "\"";
   my @commands ;
   push @commands, "smbclient";
   push @commands, $share;
   push @commands, $self->password if defined($self->password());
   if ( $directory ne "" ) {
      push @commands, "-D \"".$directory."\"";
   } else {
      push @commands, "-D \"".$self->directory()."\"";
   }
   push @commands, "-I ".$self->ip() if defined($self->ip());
   push @commands, "-U ".$self->username() if defined($self->username());
   push @commands, "-N", if !defined($self->password());

   push @commands, $command;

   print STDERR "\e[31m\n","@commands","\e[0m\n" if $self->verbose() ;

   $self->{status}{smb_running} = 1;
   @result = qx/@commands/;
   $self->{status}{smb_running} = 0;

   @{ $self->{cache}{smbclient}{$command.$directory} } = @result;
   return @result;
}

sub printDebug() {
   my $self = shift;
   foreach my $key ( keys %{ $self->{data} } ) {
      print $key,"\t",$self->{data}{$key},"\n";
   }
   print "Computer:\t",$self->computer(),"\n";
   print "Share:\t\t",$self->share(),"\n";
   print "Directory:\t",$self->directory(),"\n";
   print "Target:\t\t",$self->target(),"\n";
}

sub parseListing {
   my $self = shift;
   my @lines = (@_);
   my @files = ();

   LOOP: foreach (@lines) {
      my $item;
      if ( m/^  ([\S ]*\S|\.+) {5,}([HDRSA]+) +(\d+)  (\S[\S ]+\S)$/ ||
           m/^  ([\S ]*\S|[\.]+) {6,}()([0-9]+)  (\S[\S ]+\S)$/ ) {
         $item->{name} = $1;
         $item->{attr} = $2;
         $item->{size} = $3;
         $item->{date} = $4;
      } elsif ( m/^\s+([\S ]+\S)\s+Disk\s+(([\S ]+\S)|)$/ ) {
         if ( $1 =~ /\$$/ ) {
            next LOOP;
         }
         $item->{name} = $1;
         $item->{attr} = "S";
         $item->{size} = "0";
         $item->{date} = "unknown";
      } else {
         next LOOP;
      }
      push @files, $item;
   }
   return @files;
}

sub online() {
   my $self = shift;
   my $item = $self->listself();
   return defined($item);
}

sub listself() {
   my $self = shift;
   if ( defined($self->{cache}{selflist}) ) {
      return $self->{cache}{selflist};
   }
   my @list = $self->smbclient("-c 'ls'",$self->directory() );
   my @files = $self->parseListing( @list );
   LOOP: foreach my $file (@files) {
      if ( $file->{name} eq $self->target() ) {
         $self->{cache}{selflist} = $file;
         last LOOP;
      }
   }
   return $self->{cache}{selflist};
}

sub type() {
   my $self = shift;
   my $item = $self->listself();
   if ( defined($item) ) {
      if ( $item->{attr} =~ /D/ ) {
         return "directory";
      } elsif ( $item->{attr} =~ /Service/ ) {
         return "service";
      } else {
         return "file";
      }
   }
}

sub list() {
   my $self = shift;
   if ( defined($self->share()) ) {
      my $dir = $self->directory();
      if ( $self->type() eq "directory" ) {
         $dir .= $self->target();
      }
      @files = $self->smbclient("-c ls", $dir);
   } else {
      @files = $self->smbclient("-L ".$self->computer(), "");
   }
   my @files = $self->parseListing(@result);
   return @files;
}

sub size() {
   my $self = shift;
   if ( $self->type() eq "directory" ) {
      return $self->recursive_size();
   } else {
      my $item = $self->listself();
      return $item->{size};
   }
}

sub recursive_size() {
   my $self = shift;
   my $dir = $self->directory.$self->target();

   my @output = $self->smbclient("-c 'recurse;ls'", $dir);
   my @files = $self->parseListing(@output);
   my $sum = 0;
   foreach (@files) {
      $sum += $_->{size};
   }
   return $sum;
}

sub get() {
   my $self = shift;
   my $target = $self->target();
   my @output;
   $target =~ s/'/'\\''/g;
   if ( $self->type() eq "directory" ) {
      @output = $self->smbclient("-c 'recurse; prompt; mget \"$target\"'");
   } else {
      @output = $self->smbclient("-c 'get \"$target\"'");
   }
   $self->parseGetOutput(@output);
}

sub parseGetOutput() {
   my $self = shift;
   my @output = (@_);
   $self->{lastdownload}{completed} = 1;
   print $_ for (@output);
}

sub tar() {
   my $self = shift;
   my $filename = shift;
   my $target = $self->target();
   if ( !defined($filename) ) {
      $filename = $self->localfilename().".tar";
   }
   $directory = $self->directory();
   if ($self->type() eq "directory") {
      $directory .= $self->target();
   }
   @output = $self->smbclient("-Tc \"$filename\"", $directory);
   print $_ for (@output);
}

sub showcache() {
   my $self = shift;
   foreach my $key ( keys %{ $self->{cache} } ) {
      print "Cache for $key:\n";
      foreach my $key2 ( keys %{ $self->{cache}{$key} } ) {
         print "\t$key2\t",$self->{cache}{$key}{$key2},"\n" ;
      }
   }
}

sub download_completed() {
   my $self = shift;
   return defined($self->{lastdownload}{completed});
}

sub speed() {
   my $self = shift;
   warn "speed() Not implemented\n";
   return 0.0;
}
1;