#!/usr/bin/perl

use EDF::Object qw(display pretty);
use EDF::Constants qw(Login Sex);
use EDF::Connect;
use Net::Dict;
use Net::Finger;
use WWW::Search;
use IO::Socket;
use Text::Bastardize;
use Net::Telnet;
use WWW::Babelfish;
use XML::RSS;
use HTTP::Request;

my $password = "white";
my $logfile = "./agent.log";

open(LOG, ">> $logfile") || print "Cannot open $logfile for append: $!\n";

select((select(LOG), $| = 1)[0]);
print LOG "\nThis is KahlUA. ", scalar(localtime), "\n";

$HANDLE = login(username => "kahlua", password => $password, host => "192.84.78.68", port => "3030", client1=> "qUAck");

vec($rin, fileno($HANDLE), 1) = 1;
$rout = undef;

($ein, $eout) = ($rin, $rout);

@STACK = ();

while (1) {
  $response   = shift(@STACK);
  $response ||= ($found = select($rout=$rin, undef, $eout=$ein, undef));
  $response ||= die "Lost connection\n";
  $response   = parseEDF EDF::Object($HANDLE) if ($found);
  $response ||= die "Lost connection\n";

  @folders    = &folders($response) if ( ($response->name eq "reply")    && ($response->value eq "user_login") );
                &process($response)  if ( ($response->name eq "announce") && ($response->value eq "user_page") );

  $response->DESTROY;
  $found      = undef;
}


sub process {

my $edf = shift;
my $reply = "";

$edf->child;
my $from = $edf->first("fromid")->value;
my $name = $edf->first("fromname")->value;
my $text = $edf->first("text")->value;

$CURRENT_USER = $from;

print LOG scalar(localtime), "!$name($from)!$text!";

$text =~ s/\n|\r/ /gs;
$text =~ s/^\s+//;
$text =~ s/\s+$//;


if ($text =~ /^(thanks|thank you|thankyou|cheers)/i) {

  $reply = qq~You're welcome.~;
  print LOG "W";

} elsif ($text =~ /^google (.*)$/i) {

  my $query = $1;
 
  $reply .= "You searched for '$query'.";
  $reply .= "\n";

  my $search = new WWW::Search('Google') or die $!;

  $search->native_query(WWW::Search::escape_query($query));
  my $counter = 0;

while (my $result = $search->next_result()) {
	if ($counter < 10) {
        	$result->{title} =~ s/<[^>]*>//g;
		$reply .= $result->title;
		$reply .= "\n  \\- ";
		$reply .= $result->url;
		$reply .= "\n\n";
		$counter++;
		}
	}

}
elsif ($text =~ /^excuse$/i) {
	my $t = Net::Telnet->new(Host => "bofh.engr.wisc.edu", Port => 666);
	$t->waitfor("/Your excuse is: /");
    	$reply .= "Excuse: ";
	$reply .= $t->get;
}

elsif ($text =~ /^sms (.*)$/i) {

	$query = $1;

	($number, $messagetext) = split (/ /, $query, 2);	

	if ($number =~ /^[A-Za-z]*$/) { lookup_number($number); }

        if ($number !~ /^0\d+$/) {
                        $reply .= "I, uh, didn't understand the number there. Don't use hyphens, don't use country codes.\n\n";
                }

	$reply .= "Number: $number\n";
	$reply .= "From:   $name\n";
	$reply .= "Text:   $messagetext\n\n";

	$messagesize = length($messagetext);
	
	if ( $messagesize > 110 ) {
		$reply .= "Your message contained $messagesize characters, which is more than 110 - which is the limit for KahlUA's SMSs. I'm going to send the message anyway, because I like making people look stupid. You might want to send another one and explain what happened.\n\n";
	}
	
	$reply .= "Sent successfully.\n\n";

	$message = "From: $name(UA) %0A";
	$message .= "$messagetext%0A";

	$message =~ s/ /\%20/g;

	my $request = 
    	`lynx -mime_header http://www.lycos.co.uk/service/sms/eingabe.html`;

	my ($nr)         = $request =~ m#value="([^"]+)" name="msgnr"#i;
	my ($submit)     = $request =~ m#name="SUBMIT" value="([^"]+)"#i;

	my $sock = IO::Socket::INET->new(PeerAddr => "wwwcache.btinternet.com",
                                 PeerPort => 3128,
                                 Proto    => 'tcp');
	my $EOL   = "\015\012";
	my $BLANK = $EOL x 2;
	$sock->autoflush(1);
	my $url = "http://smscgi02-1.lycos.de/uk/cgi-bin/sms/send_uk_sms5.cgi?msgnr=$nr&SUBMIT=$submit&ren=$number&prg=1&msg=$message";
	print $sock "GET $url HTTP/1.0".$EOL .
           "User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; FREESERVE_IE4; DigExt)".$EOL .
           "Referer: http://www.lycos.co.uk/service/sms/eingabe.html".$BLANK;

	$| = 1;
	close($sock);

	$reply .= "Debug: $url";
}

elsif ($text =~ /^babel (.*)$/i) {

  $obj = new WWW::Babelfish( 'agent' => 'Mozilla/8.0', );

  my $query = $1;
  ($source, $destination, $text) = split (/:/, $query);

  $source = ucfirst lc $source;
  $destination = ucfirst lc $destination;

  $new_text = $obj->translate( 'source' => $source,
                               'destination' => $destination,
                               'text' => $text,
                               'delimiter' => "\n\t" );

  $reply .= $new_text;

  @languages = $obj->languages;

}

elsif ($text =~ /^make l33t (.*)$/i) {
	my $query = $1;
	$reply .= "Your page in l33t is:\n\n";
	$query =~ tr/ieaslbgo/13457890/; 
	$reply .= "$query\n";
}

elsif ($text =~ /^make unl33t (.*)$/i) {
	my $query = $1;
	$reply .= "Your page in unl33t is:\n\n";
	$query =~ tr/13457890/ieaslbgo/;
	$reply .= "$query\n";
}

elsif ($text =~ /^make rot13 (.*)$/i) {

        my $query = $1;
        my $bast = new Text::Bastardize;
        $bast->charge($query);
        $reply .= "Your page in rot13 is:\n\n";
        $reply .= "@{[$bast->rot13()]}\n";

}

elsif ($text =~ /^make reverse (.*)$/i) {

        my $query = $1;
        my $bast = new Text::Bastardize;
        $bast->charge($query);
        $reply .= "Your page in reverse is:\n\n";
        $reply .= "@{[$bast->rev()]}\n";

}
elsif ($text =~ /^tv now/i) {

$tv = finger('tv@toth.org.uk');
$reply .= $tv;

}
elsif ($text =~ /^tv next/i) {

$tv = finger('next@toth.org.uk');
$reply .= $tv;

}

elsif ($text =~ /^rss (.*)$/i) {
	$query = $1;
	my $rss = XML::RSS->new;

	$query = 'http://www.theregister.co.uk/tonys/slashdot.rdf' if ($query eq lc "The Register" || $query eq lc "TheRegister");

	$query = "http://www.slashdot.org/slashdot.rdf" if $query eq lc "Slashdot";

	$ua = LWP::UserAgent->new;
	$req = HTTP::Request->new("GET", $query);

	$res = $ua->request($req);
	$content = $ua->request($req)->content();
	
	if ($res->is_success) {
		eval { $rss->parse( $ua->request($req)->content() ) };
			
		if( $@ ) {
			$reply .= "Parse error. Bad RDF file..";		
		}
	
		$reply .= $rss->channel('title');
		$reply .= "\n \\- " . $rss->channel('description');
		$reply .= "\n \\- " . $rss->channel('link');
		$reply .= "\n";

		foreach(@{$rss->items}) {
			$reply .= "\n" . $_->{title};
			$reply .= "\n \\- " . $_->{link};
			$reply .= "\n";
		}
	}
	else {
		$reply .= "There was an error fetching the .rdf file. Check your URL.\n";
	}

}

elsif ($text =~ /^dict (.*)$/i) {

	$query = $1; 
	$reply .= "You searched for '$query'.";
	$reply .= "\n\n";

 	$dict = Net::Dict->new('dict.org')
    	|| die "can't connect to dict.org: $!, " . $dict->errno() . "\n";

	$eref = $dict->define($query);

	if (@$eref == 0) {
        	$reply .= " \\- No definition for '$query'. Sorry.\n";
    	}
    	else
    	{ 
		foreach $entry (@$eref) {
        		($db, $definition) = @$entry;
        		$reply .= "\n-----(Definition - From: $db)---------------------\n";
			$reply .= "$definition\n";
        	}
    	}

	$dict->quit;
}

unless ($reply) {

  $reply = &instructions;
  print LOG "I";

}

send_reply($from, $reply);

print LOG "!\n";

}

sub error {

my $message = shift;

send_reply($CURRENT_USER, "ERROR: $message\r\n");

print LOG "E!\n";

return undef;

}

###

sub login {

my $handle;
my %values = @_;

$values{port} ||= 23;

#$handle = new EDF::Connect("192.84.78.66") || die "Cannot connect to UA";
$handle = new EDF::Connect($values{host}, $values{port}) || die "Cannot connect to $values{host}:$values{port}\n";

my $request = clean EDF::Object("request", \"user_login");
$request->addChild("name", \$values{username});
$request->addChild("password", \$values{password});
$request->addChild("force", 1);
$request->addChild("client", \"KahlUA");

$handle->write($request->toEDF);
$request->DESTROY;

display "Connected to $values{host}:$values{port}\n";

return $handle;

}

###

sub folders {

my $edf = shift;

my %folders = ();

$edf->child("folders");

if ($edf->child("subscriber")) {

  do {
    $folders{$edf->parent->value} = $edf->child("name")->value;
  } while ($edf->next("subscriber"));

}

#return sort { $folders{$a} cmp $folders{$b} } keys %folders;
return keys %folders;

}

###

sub messages {

my $edf = shift;

local @::messages = ();

if ($edf->child("message")) {
  messagesR($edf);
}

return @::messages;

}

###

sub messagesR {

my $edf = shift;

do {

  push(@::messages, $edf->value);

  if ($edf->child("subject")) {
    push(@::messages, $edf->value);
    $edf->parent;
  } else {
    push(@::messages, "[no subject]");
  }

  if ($edf->child("message")) {
    messagesR($edf);
    $edf->parent;
  }

} while ($edf->next("message"));


return;

}

###

sub send_reply {

my $from = shift;
my $output = shift;
my $response;
my $request;

$request = clean EDF::Object("request", \"user_contact");
$request->addChild("toid", $from);
$request->addChild("text", \"$output");
$HANDLE->write($request->toEDF);

# Get the reply
while (1) {
  $response = parseEDF EDF::Object($HANDLE);
  last if ($response->name eq "reply");
  push(@STACK, $response) if ( ($response->name eq "announce") && ($response->value eq "user_page") );
}

# If the user is busy, resend to private
if ($response->value eq "user_busy") {
  $request->addChild("contacttype", 3);
  $HANDLE->write($request->toEDF);
}

$request->DESTROY;
$response->DESTROY;

}

###

sub id_user {

my $username = shift;
my $request;
my $response;
my $userid;

$request = clean EDF::Object("request", \"user_list");
$request->addChild("searchtype", 0);
$request->addChild("name", \$username);
$HANDLE->write($request->toEDF);

while (1) {
  $response = parseEDF EDF::Object($HANDLE);
  last if ( ($response->name eq "reply") && ($response->value eq "user_list") ); 
  push(@STACK, $response) if ( ($response->name eq "announce") && ($response->value eq "user_page") );
}

$userid = $response->value if ($response->first("user"));

return $userid;

}

sub subscribe_all {

my $request;
my $response;

$request = clean EDF::Object("request", \"folder_list");
$request->addChild("searchtype", 2);
$HANDLE->write($request->toEDF);
$request->DESTROY;

while (1) {
  $response = parseEDF EDF::Object($HANDLE);
  last if ($response->name eq "reply");
  push(@STACK, $response) if ( ($response->name eq "announce") && ($response->value eq "user_page") );
}

local @::folders = ();

if ($response->child("folder")) {
  foldersR($response);
}

my $request = clean EDF::Object("request", \"folder_subscribe");
$request->add("folderid");

my $tick = 0;

foreach $folder (@::folders) {
  next if ($folder == 384); # Private;
  $request->value($folder);
  $HANDLE->write($request->toEDF);
  $tick++;
}

return "Subscribed to $tick folders";

}

###

sub foldersR {

my $edf = shift;

do {
  push(@::folders, $edf->value);
  if ($edf->child("folder")) {
    foldersR($edf);
    $edf->parent;
  }
} while ($edf->next("folder"));

return;

}

###

sub instructions {
$reply = "";
open(HELP, "instructions.txt");
while(<HELP>) {
	$reply .= $_;
	}
return $reply;
}

sub lookup_number { 

	$namesearch = $_[0];

	open (HASHFILE, "<lookup_book.txt");

	%lookup_book = ();		

	while(<HASHFILE>) {
	($name, $number) = split(/\t/, $_, 2);
	$lookup_book{$name} = $number;
	}
 	
	$_[0] = $lookup_book{lc $namesearch}; 
	$_[0] =~ s/\n//;	
}
