#!/usr/bin/perl use utf8; use Event; use AnyEvent; use XML::Twig; use Net::XMPP2::Client; use Net::XMPP2::Ext::Disco; use Net::XMPP2::Ext::Version; use Net::XMPP2::Namespaces qw/xmpp_ns/; use Weather::Underground; # This is where the bot lives $base_dir = '.'; $jid = 'serenity@jabber.sxrmedical.com'; $pw = 'PASSWORD'; # Random crap to say if the incoming message isn't a valid command. $random_file = "$base_dir/walrus.txt"; # These files end up world writeable. # File formart is: # JID&&MESSAGES&&\n # The bot will send any MESSAGE to JID. # This makes it easy for other scripts to generate messages. @message_files = ("$base_dir/messages.txt", "$base_dir/other_messages.txt"); my @msgs; ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); $curr_hour = 42; sub logger { $message = $_[0]; my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); $year = $year + 1900; $mon = $mon + 1; if($mday < 10) { $mday = "0$mday"; } if($mon < 10) { $mon = "0$mon"; } if($min < 10) { $min = "0$min"; } if($hour < 10) { $hour = "0$hour"; } my $did = "$year$mon$mday $hour:$min"; open(LOG, ">>/var/log/jabber_bot.txt"); my $to_log = "$did - $message\n"; print LOG "$to_log"; close(LOG); return($to_log); } sub read_messages { my ($msgs_file) = @_; open my $f, $msgs_file or die "Couldn't open messages file: '$msgs_file'\n"; (@msgs) = map { chomp; $_ } <$f>; close $f; } use XML::RSS; use LWP::Simple; sub go_rss { my $rss = new XML::RSS; $url = "http://rss.cnn.com/rss/cnn_topstories.rss"; $content = get($url); if(!$content) { $rss_string = "Couldn't get news.\n"; return; } $string = ''; $rss->parse($content); $rss_string = $rss->{'channel'}->{'title'} . ": " . $rss->{'channel'}->{'link'} . "\n\n"; $i = 0; foreach $item (@{$rss->{'items'}}) { next unless defined($item->{'title'}); if($i == 0) { $top_story = "Top Story: " . $item->{'title'}; } $rss_string .= "* " . $item->{'title'} . "\n"; $i++; } } sub go { # RESET THE TICKER THAT CALLS ME $w = AnyEvent->timer (after => 10, cb => sub { &go; }); if(!$ready) { return; } ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); # # EVERY HOUR # if($curr_hour != $hour || !$weather_message) { $weather = Weather::Underground->new( place => "Fort Smith, AR", debug => 0 ); $arrayref = $weather->get_weather(); $temp = $arrayref->[0]->{temperature_fahrenheit}; $condition = $arrayref->[0]->{conditions}; $weather_message = "Weather: $temp" . "F and $condition"; $weather_report = "The time is: $hour:$min. \n"; $weather_report .= "Current weather for $arrayref->[0]->{place}: \n"; $weather_report .= "$arrayref->[0]->{temperature_fahrenheit} degrees fahrenheit. \n"; $weather_report .= "Weather conditions are $arrayref->[0]->{conditions}. \n"; $weather_report .= "Winds $arrayref->[0]->{wind_direction} at $arrayref->[0]->{wind_milesperhour} MPH. \n"; $weather_report .= "Sunrise at $arrayref->[0]->{sunrise}. Sunset at $arrayref->[0]->{sunset}. \n"; $weather_report .= "Last updated: $arrayref->[0]->{updated}\n\n"; } # HOUR END foreach $file (@message_files) { if(-e $file) { open(FILE, $file); @all = ; close(FILE); if(!@all) { next; } $i = 0; foreach $line (@all) { $i++; if($i == 10) { logger("Too many messages to send."); next; } ($jid, $message) = split(/&&/, $line); $cl->send_message($message => $jid, undef, 'chat'); logger("Sent $jid: $message"); } unlink($file); # Touch/Create the file back so PHP can append without bitching utime(time, time, "$file") or ( open(F, ">$file") && close(F) ); chmod(0666, $file); } } $i++; } binmode STDOUT, ":utf8"; chdir($base_dir); read_messages($random_file); $j = AnyEvent->condvar; $cl = Net::XMPP2::Client->new (debug => 1); $disco = Net::XMPP2::Ext::Disco->new; $version = Net::XMPP2::Ext::Version->new; $cl->add_extension ($disco); $cl->add_extension ($version); $cl->set_presence (undef, "I'm just a bot...", 1); $cl->add_account ($jid, $pw); warn "connecting to $jid...\n"; $i = 0; $ready = 0; $cl->reg_cb ( message => sub { ($cl, $acc, $msg) = @_; $talkmsg = $msgs[int (rand (@msgs))]; $repl = $msg->make_reply; $r_message = ''; # THIS COULD USE A NICE LOOKUP TABLE OR SOMETHING if($msg->any_body =~ /help/i) { $r_message = "\nHELP:\nweather - A weather forcast.\nnews - Current news\n"; } elsif($msg->any_body =~ /weather/i) { $r_message = "$weather_report"; } elsif($msg->any_body =~ /news/i) { &go_rss; $r_message = $rss_string; $cl->set_presence (undef, $weather_message . " - " . $top_story, 1); } else { $r_message = "You said '".$msg->any_body."' but the walrus said, '" . $talkmsg . "'"; } if($msg->from !~ /serenity/) { $repl->add_body($r_message); logger("Got message: '".$msg->any_body."' from ".$msg->from); logger("Answered: $r_message"); $repl->send; } else { logger("Ignoring message from myself: ". $msg->any_body); } }, contact_request_subscribe => sub { ($cl, $acc, $roster, $contact) = @_; $contact->send_subscribed; logger("Subscribed to ".$contact->jid); }, error => sub { ($cl, $acc, $error) = @_; logger("Error encountered: ".$error->string); $j->broadcast; }, disconnect => sub { logger("Got disconnected: [@_]"); $j->broadcast; }, session_ready => sub { ($cl, $acc) = @_; print "session ready\n"; $cl->send_message("Ready!" => 'dean@jabber.sxrmedical.com', undef, 'chat'); logger("Connected, Session Ready."); $ready = 1; }, contact_subscribed => sub { ($cl, $acc, $roster, $contact) = @_; logger("Subscribed: " . $contact->jid); $cl->send_message("Hi! Thanks for being my friend!" => $contact->jid, undef, 'chat'); }, # roster_update => sub { # }, # presence_update => sub { # }, ); $w = AnyEvent->timer (after => 10, cb => sub { &go; }); $cl->start; $j->wait;