html/openurl.pl
1 # OpenURL by Stefan'tommie' Tomanek
2 #
3 # 05.06.2002
4 # * complete rewrite
5
6 use strict;
7
8 use 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
21 use Irssi 20020324;
22 use Irssi::TextUI;
23 use Irssi::UI;
24
25 use 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
34 sub 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
45 sub 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
68 sub 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
93 sub event_private_message {
94 my ($server, $text, $nick, $address) = @_;
95 process_line($server, $nick, $nick, $text);
96 }
97 sub event_public_message {
98 my ($server, $text, $nick, $address, $target) = @_;
99 process_line($server, $target, $nick, $text);
100 }
101 sub event_topic_changed {
102 my ($channel) = @_;
103 process_line($channel->{server}, $channel->{name}, "", $channel->{topic});
104 }
105
106 sub 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
116 sub get_url ($) {
117 my ($text) = @_;
118 foreach (keys %urltypes) {
119 return $1 if ($text =~ /$urltypes{$_}->{regexp}/);
120 }
121 }
122
123 sub url_type ($) {
124 my ($url) = @_;
125 foreach (keys %urltypes) {
126 return $_ if ($url =~ /$urltypes{$_}->{regexp}/);
127 }
128 }
129
130 sub 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
145 sub 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
173 sub 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
191 sub 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
209 sub 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
216 sub 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
250 foreach (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 }
254 Irssi::settings_add_int($IRSSI{'name'}, 'openurl_max_urls', 20);
255 Irssi::settings_add_bool($IRSSI{'name'}, 'openurl_display_context', 1);
256
257 Irssi::signal_add_last("message private", "event_private_message");
258 Irssi::signal_add_last("message public", "event_public_message");
259 Irssi::signal_add_last("channel topic changed", "event_topic_changed");
260
261 #Irssi::signal_add('open url', \&launch_url);
262
263 foreach my $cmd ('topics', 'clear', 'paste', 'help') {
264 Irssi::command_bind('openurl '.$cmd => sub {
265 cmd_openurl("$cmd ".$_[0], $_[1], $_[2]); });
266 }
267 Irssi::command_bind('openurl', 'cmd_openurl');
268
269 print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /openurl help for help';