1# OpenURL by Stefan'tommie' Tomanek 2# 3# 05.06.2002 4# * complete rewrite 5 6use strict; 7 8use vars qw($VERSION %IRSSI); 9$VERSION = "20030208"; 10%IRSSI = ( 11 authors => "Stefan 'tommie' Tomanek", 12 contact => "stefan\@pico.ruhr.de", 13 name => "OpenURL", 14 description => "Stores URLs in a list and launches mail, web or ftp software", 15 license => "GPLv2", 16 url => "http://scripts.irssi.org", 17 changed => "$VERSION", 18 commands => "openurl" 19); 20 21use Irssi 20020324; 22use Irssi::TextUI; 23use Irssi::UI; 24 25use vars qw(@urls %urltypes $recent); 26$recent = 1; 27 28# RegExp & defaultcommands 29%urltypes = ( http => { regexp => qr#((?:https?://[^\s<>"]+|www\.[-a-z0-9.]+)[^\s.,;<">\):])#, cmd => 'w3m "$1"' }, 30 ftp => { regexp => qr#((?:ftp://[^\s<>"]+|ftp\.[-a-z0-9.]+)[^\s.,;<">\):])#, cmd => 'ncftp "$1"' }, 31 mail => { regexp => qr#([-_a-z0-9.]+\@[-a-z0-9.]+\.[-a-z0-9.]+)#, cmd => 'mutt "$1" -s "$2"' }, 32 ); 33 34sub draw_box ($$$$) { 35 my ($title, $text, $footer, $colour) = @_; 36 my $box = ''; 37 $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; 38 foreach (split(/\n/, $text)) { 39 $box .= '%R|%n '.$_."\n"; 40 } $box .= '%R`--<%n'.$footer.'%R>->%n'; 41 $box =~ s/%.//g unless $colour; 42 return $box; 43} 44 45sub show_help() { 46 my $help=$IRSSI{name}." ".$VERSION." 47/openurl 48 List the saved URLs 49/openurl <number> <number>... 50 Load the corresponding URLs in your browser/mailer 51/openurl paste <number> <number>... 52 Paste the selected URLs to the current channel/query 53/openurl topics 54 Look for URLs in channel topics 55/openurl clear 56 Clear all URLs 57/openurl help 58 Display this help 59"; 60 my $text = ''; 61 foreach (split(/\n/, $help)) { 62 $_ =~ s/^\/(.*)$/%9\/$1%9/; 63 $text .= $_."\n"; 64 } 65 print CLIENTCRAP draw_box($IRSSI{name}." help", $text, "help", 1) ; 66} 67 68sub list_urls { 69 my $string = ''; 70 my $i = 1; 71 foreach (@urls) { 72 my $text = $_->{url}; 73 my $url = $_->{url}; 74 $text = $_->{text} if Irssi::settings_get_bool('openurl_display_context'); 75 $url =~ s/%/%%/g; 76 $text =~ s/%/%%/g; 77 $text =~ s/\Q$url/%U$url%U/; 78 if ($recent-1 == $i) { 79 $string .= '%B�%n'; 80 } else { 81 $string .= ' '; 82 } 83 $string .= '%r['.$i.']%n '; 84 $string .= '<'.$_->{channel}; 85 $string .= '/'.$_->{nick} unless $_->{nick} eq ""; 86 $string .= '> '; 87 $string .= $text." %n\n"; 88 $i++; 89 } 90 print CLIENTCRAP draw_box("OpenURL", $string, "URLs", 1); 91} 92 93sub event_private_message { 94 my ($server, $text, $nick, $address) = @_; 95 process_line($server, $nick, $nick, $text); 96} 97sub event_public_message { 98 my ($server, $text, $nick, $address, $target) = @_; 99 process_line($server, $target, $nick, $text); 100} 101sub event_topic_changed { 102 my ($channel) = @_; 103 process_line($channel->{server}, $channel->{name}, "", $channel->{topic}); 104} 105 106sub process_line ($$$$) { 107 my ($server, $target, $nick, $line) = @_; 108 my $url = get_url($line); 109 if ($url) { 110 my $type = url_type($url); 111 return unless Irssi::settings_get_bool('openurl_watch_'.$type); 112 new_url($server, $target, $nick, $line, $url); 113 } 114} 115 116sub get_url ($) { 117 my ($text) = @_; 118 foreach (keys %urltypes) { 119 return $1 if ($text =~ /$urltypes{$_}->{regexp}/); 120 } 121} 122 123sub url_type ($) { 124 my ($url) = @_; 125 foreach (keys %urltypes) { 126 return $_ if ($url =~ /$urltypes{$_}->{regexp}/); 127 } 128} 129 130sub launch_url ($) { 131 my ($url) = @_; 132 my $type = url_type($url); 133 my $address = $url; 134 my $suffix= ""; 135 if ($type eq "mail") { 136 $address = $1 if $url =~ /(.*?@.*?)($|\?)/; 137 $suffix = $2 if $url =~ /(.*?@.*?)\?subject=(.*)/; 138 } 139 my $command = Irssi::settings_get_str("openurl_app_".$type); 140 $command =~ s/\$1/$address/; 141 $command =~ s/\$2/$suffix/; 142 system($command); 143} 144 145sub new_url ($$$$$) { 146 my ($server, $channel, $nick, $text, $url) = @_; 147 $recent = 1 if ($recent > Irssi::settings_get_int('openurl_max_urls')); 148 # Check for existance of URL 149 my $i = 1; 150 foreach (@urls) { 151 if ($text eq $_->{text} && $channel eq $_->{channel}) { 152 my $note_id = add_note($server, $channel, $i); 153 push @{$_->{notes}}, $note_id; 154 return(); 155 } 156 $i++; 157 } 158 if (defined $urls[$recent-1]) { 159 del_notes($recent); 160 } 161 $urls[$recent-1] = {channel => $channel, 162 text => $text, 163 nick => $nick, 164 url => $url, 165 notes => [], 166 }; 167 my $note_id = add_note($server, $channel, $recent); 168 push @{$urls[$recent-1]{notes}}, $note_id; 169 $recent++; 170} 171 172 173sub del_notes ($) { 174 my ($num) = @_; 175 my $view; 176 my $witem = Irssi::window_item_find($urls[$num-1]->{channel}); 177 if (defined $witem) { 178 $view = $witem->window()->view(); 179 } 180 if (defined $view) { 181 foreach (@{$urls[$num-1]->{notes}}) { 182 my $line = $view->get_bookmark($_); 183 $view->remove_line($line) if defined $line; 184 $view->set_bookmark($_, undef); 185 } 186 @{$urls[$num-1]->{notes}} = (); 187 $view->redraw(); 188 } 189} 190 191sub add_note ($$$) { 192 my ($server, $target, $num) = @_; 193 my $witem; 194 if (defined $server) { 195 $witem = $server->window_item_find($target); 196 } else { 197 $witem = Irssi::window_item_find($target); 198 } 199 if (defined $witem) { 200 $witem->print("%R>>%n OpenURL ".$num, MSGLEVEL_CLIENTCRAP); 201 # create a unique ID for the mark 202 my $foo = time().'-'.int(rand()*1000); 203 $witem->window()->view()->set_bookmark_bottom("openurl_".$num.'-'.$foo); 204 return("openurl_".$num.'-'.$foo); 205 } 206 return(undef); 207} 208 209sub clear_urls { 210 del_notes($_) foreach (0..scalar(@urls)-1); 211 pop(@urls) foreach (1..scalar(@urls)); 212 $recent = 1; 213 print CLIENTCRAP '%R>>%n URLs cleared'; 214} 215 216sub cmd_openurl ($$$) { 217 my ($arg, $server, $witem) = @_; 218 my @args = split(/ /, $arg); 219 if (scalar(@args) == 0) { 220 list_urls; 221 } elsif ($args[0] eq 'clear') { 222 clear_urls; 223 } elsif ($args[0] eq 'topics') { 224 event_topic_changed($_) foreach (Irssi::channels()); 225 } elsif ($args[0] eq 'help') { 226 show_help(); 227 } elsif ($args[0] eq 'open') { 228 launch_url($args[1]); 229 } else { 230 my $paste = 0; 231 if ($args[0] eq 'paste') { 232 $paste = 1; 233 shift(@args); 234 } 235 foreach (@args) { 236 next unless /\d+/; 237 next unless defined $urls[$_-1]; 238 my $url = $urls[$_-1]->{url}; 239 if ($paste == 1) { 240 if (ref $witem && ($witem->{type} eq "CHANNEL" || $witem->{type} eq "QUERY")) { 241 $witem->command("MSG ".$witem->{name}." ".$url); 242 } 243 } else { 244 launch_url($url); 245 } 246 } 247 } 248} 249 250foreach (keys %urltypes) { 251 Irssi::settings_add_str($IRSSI{'name'}, 'openurl_app_'.$_, "screen ".$urltypes{$_}->{cmd}); 252 Irssi::settings_add_bool($IRSSI{'name'}, 'openurl_watch_'.$_, 1); 253} 254Irssi::settings_add_int($IRSSI{'name'}, 'openurl_max_urls', 20); 255Irssi::settings_add_bool($IRSSI{'name'}, 'openurl_display_context', 1); 256 257Irssi::signal_add_last("message private", "event_private_message"); 258Irssi::signal_add_last("message public", "event_public_message"); 259Irssi::signal_add_last("channel topic changed", "event_topic_changed"); 260 261#Irssi::signal_add('open url', \&launch_url); 262 263foreach my $cmd ('topics', 'clear', 'paste', 'help') { 264 Irssi::command_bind('openurl '.$cmd => sub { 265 cmd_openurl("$cmd ".$_[0], $_[1], $_[2]); }); 266} 267Irssi::command_bind('openurl', 'cmd_openurl'); 268 269print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /openurl help for help'; 270