1# by Stefan 'tommie' Tomanek <stefan@pico.ruhr.de> 2use strict; 3 4use vars qw($VERSION %IRSSI); 5$VERSION = "20030208"; 6%IRSSI = ( 7 authors => "Stefan 'tommie' Tomanek", 8 contact => "stefan\@pico.ruhr.de", 9 name => "Xetra", 10 description => "brings the stock exchanges of the world to your irssi", 11 license => "GPLv2", 12 changed => "$VERSION", 13 sbitems => "xetra", 14 commands => "xetra" 15); 16 17 18use Irssi 20020324; 19use Irssi::TextUI; 20use LWP::Simple; 21use vars qw($forked @ticker $shift $timer); 22 23sub draw_box ($$$$) { 24 my ($title, $text, $footer, $colour) = @_; 25 my $box = ''; 26 $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; 27 foreach (split(/\n/, $text)) { 28 $box .= '%R|%n '.$_."\n"; 29 } 30 $box .= '%R`--<%n'.$footer.'%R>->%n'; 31 $box =~ s/%.//g unless $colour; 32 return $box; 33} 34 35sub show_help() { 36 my $help=$IRSSI{name}." ".$VERSION." 37/xetra update 38 Retrieve new stock information for ticker 39/xetra get WKN/EXC 40 Retrieve data for stock <WKN> at stock exchange <EXC> 41"; 42 my $text = ''; 43 foreach (split(/\n/, $help)) { 44 $_ =~ s/^\/(.*)$/%9\/$1%9/; 45 $text .= $_."\n"; 46 } 47 print CLIENTCRAP draw_box($IRSSI{name}." help", $text, "help", 1) ; 48} 49 50sub stock ($) { 51 if ($_[0] =~ /^(.*?)\/(.*?)$/) { 52 return $_[0]; 53 } elsif ($_[0] =~ /^(.*?)\.(.*?)$/) { 54 return $_[0].'/'.$2; 55 } else { 56 my $exchange = Irssi::settings_get_str('xetra_default_stock_exchange'); 57 return $_[0].'/'.$exchange if ($_[0] =~ /^\d+$/); 58 return $_[0].'.'.$exchange.'/'.$exchange; 59 } 60} 61 62sub get_stock ($$) { 63 my ($wkn, $exchange) = @_; 64 #my $data = get('http://informer2.comdirect.de/de/default/_pages/fokus/main.html?sSymbol='.$symbol); 65 my $data = get('http://informer2.comdirect.de/de/suche/main.html?nop=0&searchButton=Exakt&searchfor='.$wkn.'&XsearchBoersen='.$exchange); 66 my $stock; 67 if ($data =~ / WKN: (.*?) /) { 68 $stock->{wkn} = $1; 69 } 70 if ($data =~ /<th class="right">( |<img src="\/_common\/images\/pfeil_.*?\.gif" width=11 height=10 alt="">) (.*?)<\/th>/) { 71 $stock->{current} = $2; 72 } 73 if ($data =~ /<td align="right"><b><div class="color.*?"><nobr> (.*?) <\/nobr><\/div><\/b><\/td>/) { 74 $stock->{change} = $1; 75 } 76 if ($data =~ /Symbol: (.*?)</) { 77 $stock->{symbol} = $1; 78 } 79 if ($data =~ /Börse: (.*?) /) { 80 $stock->{exchange} = $1; 81 } 82 if ($data =~ /<nobr> ([0-9,+-]+\%) <\/nobr>/) { 83 $stock->{percent} = $1; 84 } 85 if ($data =~ /<td align="right">(\d+)\.(\d+)\. <\/td><td align="right">(\d+):(\d+) <\/td>/) { 86 $stock->{date} = $1.'.'.$2.'.'; 87 $stock->{time} = $3.':'.$4; 88 } 89 return $stock; 90} 91 92sub bg_fetch ($$) { 93 my ($symbols, $job) = @_; 94 my ($rh, $wh); 95 pipe($rh, $wh); 96 return if $forked > 3; 97 $forked++; 98 my $pid = fork(); 99 if ($pid > 0) { 100 close $wh; 101 Irssi::pidwait_add($pid); 102 my ($pipetag); 103 my @args = ($rh, \$pipetag, $job); 104 $pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args); 105 } else { 106 my $result; 107 foreach (@$symbols) { 108 $_ = stock($_); 109 my ($wkn, $exchange) = split('/', $_); 110 my $item = get_stock($wkn, $exchange); 111 push @$result, $item; 112 } 113 my $dumper = Data::Dumper->new([$result]); 114 $dumper->Purity(1)->Deepcopy(1); 115 my $data = $dumper->Dump; 116 print($wh $data); 117 close($wh); 118 POSIX::_exit(1); 119 } 120} 121 122sub pipe_input ($$$) { 123 my ($rh, $pipetag, $job) = @{$_[0]}; 124 $forked--; 125 my $text; 126 $text .= $_ foreach (<$rh>); 127 close($rh); 128 Irssi::input_remove($$pipetag); 129 return unless($text); 130 no strict; 131 my $result = eval "$text"; 132 return unless ref $result; 133 if ($job eq 'ticker') { 134 @ticker = @$result; 135 Irssi::statusbar_items_redraw('xetra'); 136 } elsif ($job eq 'get') { 137 foreach (@$result) { 138 show_stock($_); 139 } 140 } 141} 142 143sub show_stock ($) { 144 my ($stock) = @_; 145 my $text; 146 $text .= '%9WKN:%9 '.$stock->{wkn}." (".$stock->{exchange}.")\n"; 147 $text .= '%9Current:%9 '.$stock->{current}."\n"; 148 $text .= '%9Change:%9 '.$stock->{change}.' ('.$stock->{percent}.")\n\n"; 149 $text .= $stock->{date}.", ".$stock->{time}."\n"; 150 print CLIENTCRAP &draw_box('Xetra stockinfo', $text, $stock->{symbol}, 1); 151} 152 153sub update_ticker { 154 my @stocks = split(/ /, Irssi::settings_get_str('xetra_ticker_stocks')); 155 bg_fetch(\@stocks, 'ticker'); 156} 157 158sub show_ticker ($$) { 159 my ($item, $get_size_only) = @_; 160 $shift = 0 if $shift+1 > scalar(@ticker); 161 return unless defined $ticker[$shift]; 162 my $tape; 163 $_ = $ticker[$shift]; 164 $tape .= $_->{symbol}.': '; 165 $tape .= $_->{current}.' '; 166 if ($_->{change} =~ /^\+/) { 167 $tape .= '%g'; 168 } elsif ($_->{change} =~ /^\-/) { 169 $tape .= '%r'; 170 } 171 $tape .= $_->{change}.'%n'; 172 173 $shift++ unless $get_size_only; 174 my $format = "{sb ".$tape."}"; 175 $item->{min_size} = $item->{max_size} = length($tape); 176 $item->default_handler($get_size_only, $format, 0, 1); 177 Irssi::timeout_remove($timer); 178 $timer = Irssi::timeout_add(Irssi::settings_get_int('xetra_ticker_interval')*1000, 'update_ticker', undef); 179} 180 181sub cmd_xetra ($$$) { 182 my ($args, $server, $witem) = @_; 183 my @arg = split(/ /, $args); 184 return unless defined $arg[0]; 185 if ($arg[0] eq 'get' && defined $arg[1]) { 186 shift(@arg); 187 bg_fetch(\@arg, 'get'); 188 } elsif ($arg[0] eq 'update') { 189 update_ticker(); 190 } elsif ($arg[0] eq 'help') { 191 show_help(); 192 } 193} 194 195Irssi::statusbar_item_register('xetra', 0, 'show_ticker'); 196 197Irssi::settings_add_str($IRSSI{name}, 'xetra_default_stock_exchange', 'ETR'); 198Irssi::settings_add_str($IRSSI{name}, 'xetra_ticker_stocks', ''); 199Irssi::settings_add_int($IRSSI{name}, 'xetra_ticker_interval', 3); 200 201Irssi::command_bind('xetra' => \&cmd_xetra); 202foreach my $cmd ('get', 'update', 'help') { 203 Irssi::command_bind('xetra '.$cmd => sub { cmd_xetra("$cmd ".$_[0], $_[1], $_[2]);}); 204} 205 206$timer = Irssi::timeout_add(Irssi::settings_get_int('xetra_ticker_interval')*1000, 'update_ticker', undef); 207update_ticker(); 208 209print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /xetra help for help'; 210