use Net::IRC; use Finance::Quote; use Geo::Weather; use strict; use HTML::Strip; use LWP::UserAgent; use XML::Simple; use Time::HiRes qw( usleep ); my $version = "18"; my $botnick = "StockBot_"; my @channel_list = ("#wipples"); my @server_list = ("irc.desync.com", "irc.blessed.net", "irc.foxlink.net"); my $passwd = "XXXXXXXX"; my $q = Finance::Quote->new; $q->timeout(60); my $irc = new Net::IRC; my $q = Finance::Quote->new; $q->timeout(60); my $w = new Geo::Weather; my $hs = HTML::Strip->new(); my $ua = LWP::UserAgent->new; $ua->timeout(30); $ua->env_proxy; my $server = select_server(); my $conn = $irc->newconn(Server => $server, Port => 6667, Nick => $botnick, Ircname => 'StockBot', Username => 'StockBot'); $conn->add_handler('cping', \&on_ping); $conn->add_handler('crping', \&on_ping_reply); $conn->add_handler('msg', \&on_msg); $conn->add_handler('chat', \&on_chat); $conn->add_handler('public', \&on_public); $conn->add_handler('caction', \&on_action); $conn->add_handler('join', \&on_join); $conn->add_handler('part', \&on_part); $conn->add_handler('cdcc', \&on_dcc); $conn->add_handler('topic', \&on_topic); $conn->add_handler('notopic', \&on_topic); $conn->add_global_handler([ 251,252,253,254,302,255 ], \&on_init); $conn->add_global_handler('disconnect', \&on_disconnect); $conn->add_global_handler(376, \&on_connect); $conn->add_global_handler(433, \&on_nick_taken); $conn->add_global_handler(353, \&on_names); $irc->start; sub on_ping { } sub on_ping_reply { } sub on_msg { my ($self, $event) = @_; my ($arg, $nick) = ($event->args, $event->nick); my @args = split(/ /, $arg); if ($nick == "_aa_") { if ($arg =~ /^join/i) { $self->join($args[1]); } if ($arg =~ /^part/i) { $self->part($args[1]); } if ($arg =~ /^nick/i) { $self->nick($args[1]); } if ($arg =~ /^quit/i) { quit(); } } if ($arg =~ /^op/i) { if ($args[2] eq $passwd) { $self->mode($args[1], "+o $nick"); } else { $self->notice($nick, "Incorrect passwERd, you CRAZY HAcKER!"); } } if ($arg =~ /^help/i) { help($self, $nick); } if ($arg =~ /^quote/i) { my ($exchange, $verbosity, $subarg, $symbol, @symbols); my @args = split(/ /, $arg); ($exchange, $verbosity, @symbols) = process_args(@args); foreach $symbol (@symbols) { quote($self, $nick, $nick, $symbol, $exchange, $verbosity); } } } sub on_chat { } sub on_public { my ($self, $event) = @_; my ($arg, $target, $nick, $mynick) = ($event->args, $event->to, $event->nick, $self->nick); my @args = split(/ /, $arg); foreach my $word (@args) { if ($word =~ /^http:\/\/.*\..*/i or $word =~ /^www.*\..*/i or $word =~ /^ftp:\/\/.*\..*/i) { add_url($nick, $word); } } if ($arg =~ /^quote/i) { my ($exchange, $verbosity, @symbols) = process_args(@args); foreach my $symbol (@symbols) { quote($self, $nick, $target, $symbol, $exchange, $verbosity); } } if ($arg =~ /^weather/i) { weather($self, $target, $nick, $args[1]); } if ($arg =~ /^forecast/i) { forecast($self, $target, $nick, $args[1]); } if ($arg =~ /^e2/i) { my $e2_args = $arg; $e2_args =~ s/e2\ //i; e2($self, $target, $nick, $e2_args); } if ($arg =~ /^help/i) { help($self, $nick); } } sub forecast { my ($self, $target, $nick, $zip) = @_; if ($zip > 10000 and $zip <= 99999) { my $c = $w->get_weather($zip); my $raw_forecast = $w->report_forecast(); my $forecast_string = $hs->parse($raw_forecast); $hs->eof; my @forecast = split(/\n/, $forecast_string); foreach my $line (@forecast) { if ($line ne "\n") { $line =~ s/\n//g; print "$line"; } } } } sub weather { my ($self, $target, $nick, $zip) = @_; my $temp_color; if ($zip > 10000 and $zip <= 99999) { my $c = $w->get_weather($zip); my ($city, $state, $temp, $cond, $wind, $humi) = ($c->{city}, $c->{state}, $c->{temp}, $c->{cond}, $c->{wind}, $c->{humi}); $wind =~ s/ \;//ig; $wind =~ s/<\/td>//ig; if ($temp > 32) { $temp_color = 4; } if ($temp <= 32) { $temp_color = 12; } $self->privmsg($target, "Current Conditions for $city, $state: Temp(\003$temp_color\002$temp\002\003) Condition(\002$cond\002) Wind(\002$wind\002) Humidity(\002$humi\002\%)"); } else { $self->privmsg($target, "Invalid Zipper Code, Foo!"); } } sub e2 { my ($self, $target, $nick, $node) = @_; my $count = 1; $node =~ s/ /\%20/g; my $url = "http://everything2.com/index.pl?displaytype=xmltrue&node=" . $node; my $response = $ua->get($url); if ($response->is_success) { my $data = $response->content; my $data_hash = XMLin($data); if (ref($data_hash->{writeup}) eq 'ARRAY') { foreach my $writeup (@{$data_hash->{writeup}}) { my $doctext = $hs->parse($writeup->{doctext}); $hs->eof; $doctext = e2_parse_doc($doctext); my $writeups = @{$data_hash->{writeup}}; $self->privmsg($nick, "$count of $writeups writeups:"); e2_display($self, $nick, $writeup->{author}->{content}, $writeup->{createtime}, $writeup->{title}, $doctext, $writeup->{node_id}, "1_000_000"); $count++; } } elsif ($data_hash->{writeup}) { foreach my $writeup ($data_hash->{writeup}) { my $doctext = $hs->parse($writeup->{doctext}); $hs->eof; $doctext = e2_parse_doc($doctext); e2_display($self, $target, $writeup->{author}->{content}, $writeup->{createtime}, $writeup->{title}, $doctext, $writeup->{node_id}, "4_000_000"); } } else { $node =~ s/\%20/ /g; $self->privmsg($target, "Nothing found for \002$node\002."); } } else { $self->privmsg($target, $response->status_line); } } sub e2_parse_doc { my $doc = shift; $doc =~ s/\ ,/,/g; $doc =~ s/\ \./\./g; $doc =~ s/\ \ /\ /g; $doc =~ s/\n\n/\n/gi; $doc =~ s/\ \;/\ /g; $doc =~ s/\©\;/\(c\)/gi; $doc =~ s/\&\#91\;/\[/g; $doc =~ s/\&\#93\;/\]/g; $doc =~ s/\ \'s/\'s/gi; return $doc; } sub e2_display { my ($self, $target, $author, $createtime, $title, $doctext, $node_id, $delay) = @_; my $display_lines = 5; my @lines = split(/\n/, $doctext); my $c = 0; $self->privmsg($target, "\002$title\002 by \002$author\002 on $createtime \003" . "12http://everything2.com/?node_id=$node_id\003"); while ($c < $display_lines) { $self->privmsg($target, "$lines[$c]"); $c++; usleep ($delay); } } sub on_action { } sub on_join { } sub on_part { } sub on_dcc { } sub on_topic { } sub on_init { } sub on_connect { my $self = shift; foreach my $channel (@channel_list) { $self->join($channel); } } sub on_diconnect { sleep 10; } sub on_nick_taken { } sub on_names { } sub quit { exit 0; } sub help { my ($self, $nick) = @_; $self->notice($nick, "Usage: /msg $botnick quote [-e exchange] [-v verbosity] SYMBOL[,SYMBOL2,...]"); $self->notice($nick, "Exchanges: austrailia, dwsfunds, fidelity, tiaacref, troweprice, europe, canada, usa (default), nyse, nasdaq, uk_unit_trusts, vanguard, vwd"); $self->notice($nick, "Indexes are prefixed with ^. See http://finance.yahoo.com/l?m=US&s=comp&t=I for available indexes"); } sub usage { my ($self, $nick) = @_; $self->notice($nick, "StockBot Version: $version '/msg $botnick help' for more help"); $self->notice($nick, "Usage: /msg $botnick quote [-e exchange] [-v verosity] SYMBOL[,SYMBOL2,...]"); } sub quote { my ($self, $nick, $target, $symbol, $exchange, $verbosity) = @_; my $netcolor; $symbol = process_symbol($symbol); my %stock = $q->fetch($exchange,$symbol); if ($stock{$symbol,'success'} == 1) { if ($stock{$symbol,'net'} =~ /^-/i) { $netcolor = 4; } elsif ($stock{$symbol,'net'} =~ /^\+/i) { $netcolor = 3; } if ($verbosity >= 1) { $self->privmsg($target, "$stock{$symbol,'name'} Price($stock{$symbol,'price'}) Change(\003" . "$netcolor" . "$stock{$symbol,'net'}\003) Volume($stock{$symbol,'volume'})"); } if ($verbosity >= 2) { $self->privmsg($target, "[$stock{$symbol,'name'}] 52 Week Range: $stock{$symbol,'year_range'} Today's Range: $stock{$symbol,'day_range'} Last Trade: $stock{$symbol,'date'} $stock{$symbol,'time'}"); } if ($verbosity >= 3) { $self->privmsg($target, "[$stock{$symbol,'name'}] P/E Ratio: $stock{$symbol,'pe'} Earnings Per Share: $stock{$symbol,'eps'} Net Asset Value: $stock{$symbol,'nav'}"); } if ($verbosity >= 4) { $self->privmsg($target, "[$stock{$symbol,'name'}] Debug Info: Method: $stock{$symbol,'method'} Exchange: $stock{$symbol,'exchange'}"); } } else { $self->privmsg($target, "$symbol: $stock{$symbol,'errormsg'}"); } } sub process_symbol { my $input_symbol = uc($_[0]); my $output_symbol; if ($input_symbol eq "NASDAQ") { $output_symbol = "^IXIC1"; } elsif ($input_symbol eq "DJIA" or $input_symbol eq "DOWJONES" or $input_symbol eq "DOW") { $output_symbol = "^DJI"; } elsif ($input_symbol eq "S&P") { $output_symbol = "^SPTSECP3"; } else { $output_symbol = $input_symbol; } return $output_symbol; } sub process_args { my ($arg, $count, $param, $exchange, $verbosity, @symbols); $count = 0; foreach $arg (@_) { $param = $count + 1; if ($arg eq "-e") { $exchange = $_[$param]; } elsif ($arg eq "-v") { $verbosity = $_[$param]; } $count = $count + 1; } my $arg_count = scalar(@_) - 1; @symbols = split(/,/, $_[$arg_count]); if (!$exchange) { $exchange = "usa"; } if (!$verbosity) { $verbosity = 1; } return($exchange, $verbosity, @symbols); } sub select_server { return $server_list[int(rand(@server_list))]; } sub add_url { my ($nick, $url) = @_; my $date = `date`; open(FILE, ">>urllog.dat"); print FILE "$nick^^$url^^$date"; close(FILE); }