#!/usr/bin/perl
#
#
# getNamesData.pl
#
#####################################################################
#
#   Grab content from the names.nsf database via HTTP
#
#   Copyright (C) 2007  JoMo-Kun / jmk@foofus.net
#
#####################################################################
#
#
#

use LWP::UserAgent;
use HTTP::Cookies;
use Getopt::Long;

my $VERSION = "0.2";
my $basic_auth = 1;
my $notes_method = 0;
my $ssl = 0;

my $ua = new LWP::UserAgent;
my $jar = HTTP::Cookies->new();
$ua->cookie_jar($jar);

GetOptions (
   'host=s'         => \$host,
   'username=s'   => \$username,
   'password=s'   => \$password,
   'no_basic'     => sub { $basic_auth = 0; },
   'ssl'        => sub { $ssl = 1; }
);
                                                                                                           
print "\nm0j0.j0j0 \n\n";

if (!defined($host)) {
   print "getNamesData V. $VERSION\n";
   print "Usage:\n";
   print " $0\n";
   print "   --host <IP Address>\n";
   print "   --username <username>\n";
   print "   --password <password>\n";
   print "   --no_basic\n";
   print "   --ssl\n";
   print "\n\n";
   exit(1);
}

#####################################################################
#  MAIN:
#
chomp($host, $username, $password);

print "Connecting to host: $host [$username, $password]\n";
my $id = &grabStartPage($host, $username, $password);

if ( defined($id) ) { print "Found (my) ID: $id\n"; }
else { print "Failed to find (my) ID.\n"; exit(1); }

my $num = 1;
#my $num = 233;
my @userIDs;
while ($userIDs[0] != -1) {
   print "Retrieving user listing. [starting ID: $num]\n";
   (my $uid, @userIDs) = &grabUserList($host, $username, $password, $id, $num);
   if ($userIDs[0] == -1) { exit(0); }   

   foreach $userID (@userIDs) {
      print "Retrieving User ID: $userID\n";
      my %userInfo = &grabUserInfo($host, $username, $password, $uid, $userID);

      print "$userID\t";   
      foreach $name (keys %{ $userInfo{"$userID"} }) {
         print $userInfo{"$userID"}{"$name"} . "\t";
      }

      print "\n";
   }

   $num = $num + 29;
}

exit(0);


#####################################################################
#  FUNCTIONS:
#

# initial page
#/names.nsf/People?OpenView
#
sub grabStartPage($) {
  my ($host, $user, $pass) = @_;
  my $req;

  if ($basic_auth == 0) {
    print "Retrieving logon form... ";
    my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
    
    if ($ssl) {
      $req = new HTTP::Request GET => "https://$host/names.nsf";
    } else {
      $req = new HTTP::Request GET => "http://$host/names.nsf";
    }
    
    $jar->add_cookie_header($req);
    my $res = $ua->request($req);
    $jar->extract_cookies($res);
    
    if ($res->is_success) {
      print "SUCCESS\n";
        ($ModDate) = $res->as_string =~ /name=\"%%ModDate\" value=\"(.*)\"></;
    } else {
        print "[ERROR] Code: " . $res->code . " Message: " . $res->message . "\n";
    }
    
    my $u_pass = uc($pass);
    $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
    
    if ($ssl) {
      $req = new HTTP::Request POST => "https://$host/names.nsf?Login";
    } else {
      $req = new HTTP::Request POST => "http://$host/names.nsf?Login";
    }
    
    $req->header('Referrer' => "$host");
    $req->content_type('application/x-www-form-urlencoded');
    $req->content("%%ModDate=$ModDate&Username=$user&Password=$u_pass&RedirectTo=/mailjump.nsf?Open");
    $jar->add_cookie_header($req);
    my $res = $ua->request($req);
    $jar->extract_cookies($res);
    
    #if ($res->is_success) {
    #} else {
      #  print "[ERROR] Code: " . $res->code . " Message: " . $res->message . "\n";
     #}
  }
   
  my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
  
  if ($ssl) {
    $req = new HTTP::Request GET => "https://$host/names.nsf/People?OpenView";
  } else {
    $req = new HTTP::Request GET => "http://$host/names.nsf/People?OpenView";
  }
  
  $req->authorization_basic($user, $pass);
  $jar->add_cookie_header($req);
  my $res = $ua->request($req);
  $jar->extract_cookies($res);

  if ($res->is_success) {
     if ($res->as_string =~ /action=\"\/names.nsf\/([a-z0-9]+)\?ReadForm/) { 
      $id = $1;
      $notes_method = 0;
      print "Retrieved ID: $id (ReadForm Method)\n";
    }
     elsif ($res->as_string =~ /\"ViewUNID\" VALUE=\"([A-Za-z0-9]+)\">/) {
      $id = $1;
      $notes_method = 1;
      print "Retrieved ID: $id (ViewUNID Method)\n";
    }
    else {
      print "Failed to retrieve ID.\n";
    }
   } else {
     print "[ERROR] Code: " . $res->code . " Message: " . $res->message . "\n";
   }
   return($id);
}


# user listing
# ReadForm Method
# increment Start by 29
# "No documents found" at end of user listing
# User list link: /names.nsf/74eeb4300584c7d885156a7d00693f20?ReadForm&Start=100&TemplateType=2
#
# ViewUNID Method 
# Increment Amount: Configurable
# User list link: /names.nsf/F5BDE2C5DCA76FCF8023698F00447F65?ReadViewEntries&PreFormat&Start=100&Navigate=15&Count=40&SkipNavigate=0&SkipCount=0
#
sub grabUserList($) {
  my ($host, $user, $pass, $id, $num) = @_;
  my ($uid, @luserIDs, $tmpstr);
  my $req;

  if ($notes_method == 0) {
     print "Retrieving user list (ReadForm Method)...\n";
    $tmpstr = 'names.nsf/' . $id . '?ReadForm&Start=' . $num . '&TemplateType=2';   
  }
  elsif ($notes_method == 1) {
     print "Retrieving user list (ReadViewEntries Method)...\n";
     $tmpstr = 'names.nsf/' . $id . '?ReadViewEntries&PreFormat&Start=' . $num . '&Navigate=15&Count=29&SkipNavigate=0&SkipCount=0';   
    $uid = $id;
  }
  
  my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
  if ($ssl) {
    $req = new HTTP::Request GET => "https://$host/$tmpstr";
  } else {
    $req = new HTTP::Request GET => "http://$host/$tmpstr";
  }
  $req->authorization_basic($user, $pass);
  $jar->add_cookie_header($req);
  my $res = $ua->request($req);
  $jar->extract_cookies($res);

   if ($res->is_success) {
    if ($notes_method == 0) {
        if ($res->as_string =~ /No documents found/) {
           $luserIDs[0] = -1;
        } else {
           my @resLines = split /\n/, $res->as_string;
           @luserIDtmp = grep /OpenDocument/, @resLines;
           foreach (@luserIDtmp) {
              ($uid, my $luserIDstr) = $_ =~ /names.nsf\/([a-z0-9]+)\/([a-z0-9]+)\?OpenDocument/;
              push @luserIDs, $luserIDstr;
           }
        }
    }
    if ($notes_method == 1) {
        if ($res->as_string =~ /viewentries toplevelentries="(\d+)"/i) {
           if ($num > $1) {
          $luserIDs[0] = -1;
        }
          else {
             my @resLines = split /\n/, $res->as_string;
             @luserIDtmp = grep /unid=/, @resLines;
             foreach (@luserIDtmp) {
                (my $luserIDstr) = $_ =~ /unid="([a-zA-Z0-9]+)" noteid/i;
                push @luserIDs, $luserIDstr;
            print "Extracting UNID: $luserIDstr\n";
             }
          }
      }
      else {
        print "[ERROR] Locating toplevelentries value.\n";
        $luserIDs[0] = -1;
      }
    }
   } else {
      print "[ERROR] Code: " . $res->code . " Message: " . $res->message . "\n";
    $luserIDs[0] = -1;
   }

   return($uid, @luserIDs);
}


# User info link: /names.nsf/85255e01001356a7752554c200753106/d6312f4cf39d5d758624675800770b3a?OpenDocument
# User info link: /names.nsf/*** my id ***/*** user id ***?OpenDocument
# <input name="DisplayName" type="hidden" value=": John Smith/FooBar">
#
sub grabUserInfo($) {
  my ($host, $user, $pass, $uid, $userid) = @_;
  my $tmpstr = 'names.nsf/' . $uid . '/' . $userid . '?OpenDocument';   
  my $req;

  my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
  if ($ssl) {
    $req = new HTTP::Request GET => "https://$host/$tmpstr";
  } else {
    $req = new HTTP::Request GET => "http://$host/$tmpstr";
  }
  $req->authorization_basic($user, $pass);
  $jar->add_cookie_header($req);
  my $res = $ua->request($req);
  $jar->extract_cookies($res);
 
  if ($res->is_success) {
     my @resLines = split /\n/, $res->as_string;
     foreach (@resLines) {
        if (/\$FILE\/UserID/)
        {
          print STDERR "Located UserID file for: $userid\n";
          my $tmpstr = 'names.nsf/' . $uid . '/' . $userid . '/$FILE/UserID';   
          my $file = $userid . "-userid";
          
          if ($ssl) {
            $req = new HTTP::Request GET => "https://$host/$tmpstr";
          } else {
            $req = new HTTP::Request GET => "http://$host/$tmpstr";
          }
          $req->authorization_basic($user, $pass);
          $jar->add_cookie_header($req);
          my $res = $ua->request($req, $file);
          $jar->extract_cookies($res);
 
          if ($res->is_success) {
            print STDERR "Saved UserID file to: $file\n";
          }
          else {
            print "[ERROR] Failed to download UserID file.\n";
          }
        }

        next unless /^<input name/i;
        my ($name, $value) = $_ =~ /input name="(.*)" type=.* value="(.*)">/i;
        $userInfo{"$userid"}{"$name"} = $value;
     }

  } else {
     print "[ERROR] Code: " . $res->code . " Message: " . $res->message . "\n";
  }

  return(%userInfo);
}
