/on command - this is very simple and not really designed to be the same as ircII - it tries to fit into Irssi's usage style more than emulating ircII.
This script allow you to bind Irssi commands or a piece of perl code to s particular signal with some forms of filtering.
A command can be set to run in a particular channel (nearly) and on a particular chatnet. The commands that you add are automatically saved into a file (usually ~/.irssi/on.save).
/on list /on add [-perl] [-server] [-channel #channel] [-stop] 'signal name' command /on remove signal name /on reload
-perl: Interpret command as perl instead of the default Irssi
-server: Only trigger for events from this chat network
-channel #channel: only trigger for events in #channel
(only works where $channel->{name} is present (message signals mostly)
-stop: Call Irssi::signal_stop() (probably not a good idea to use this)
If you supply a signal name then it must be quoted so it is interpeted as one, if you wish to bind to a numeric then just entering it will work.
Currently if you specify a Irssi command $0 and $$0 are escaped, $0 $1 and so on are the parameters sent to the signal (except the first REC), $$0 and so on are the results of spliting $0 on a space so if the signal is an event then $$0 will usually be your nickname, $$1 will be the channel or nickname the numeric is targeting and so on..
This removes *all* events from the signal specified (if you want to remove a numeric you must add event eg: /on remove event 401
Reloads the saved list from ~/.irssi/on.save into memory, useful if you have to edit it manually (and very useful during debugging :)
These are pretty generic examples, there are many more specific uses for the commands.
To automatically run a /whowas when the no such nick/channel event is recieved: /on add 401 /whowas $$0
To automatically run a command when you become an irc operator on this chatnet: /on add -server 381 /whatever
To automatically move to a window with activtiy in it on a hilight: /on add 'window hilight' /window goto active
Obviously perl commands could be used here or many different signals (see docs/signals.text in the irssi sources for a list of all the signals)
1 use Irssi 20011210.0000 (); 2 $VERSION = "1.12"; 3 %IRSSI = ( 4 authors => 'David Leadbeater', 5 contact => 'dgl@dgl.cx', 6 name => 'on.pl', 7 description => '/on command - this is very simple and not really designed to be the same as ircII - it tries to fit into Irssi\'s usage style more than emulating ircII.', 8 license => 'GNU GPLv2 or later', 9 url => 'http://irssi.dgl.yi.org/', 10 ); 11 12 use strict; 13 my %on; 14
88 89 Irssi::command_bind('on','cmd_on'); 90 # This makes tab completion work :) 91 Irssi::command_set_options('on','stop server perl +channel'); 92 load(); 93 add_signals(); 94 95 # Loads the saved on settings from the saved file 96 sub load { 97 my $file = Irssi::get_irssi_dir . '/on.save'; 98 return 0 unless -f $file; 99 open(ON, $file) or return 0; 100 while(<ON>) { 101 chomp; 102 my($event,$chatnet,$settings,$channel,$cmd) = split /\0/; 103 push(@{$on{$event}}, 104 { 105 'chatnet' => $chatnet || 'all', 106 'settings' => $settings, 107 'channel' => $channel, 108 'cmd' => $cmd, 109 } 110 ); 111 } 112 close(ON); 113 return 1; 114 } 115 116 # Saves the settings currently in the %on hash into the save file 117 sub save { 118 my $file = Irssi::get_irssi_dir . '/on.save'; 119 open(ON, ">$file") or return 0; 120 for my $event(keys %on) { 121 for(@{$on{$event}}) { 122 print ON join("\0", $event, @$_{'chatnet','settings','channel','cmd'}) . "\n"; 123 } 124 } 125 close(ON) or return 0; 126 return 1; 127 } 128 129 # Adds signals from the hash to irssi (only needs to be called once) 130 sub add_signals { 131 for(keys %on) { 132 Irssi::signal_add($_, 'signal_handler'); 133 } 134 } 135 136 # Irssi calls this and it figures out what to do with the event 137 sub signal_handler { 138 my($item, @stuff) = @_; 139 my $signal = Irssi::signal_get_emitted(); 140 141 if(exists $on{$signal}) { 142 for(@{$on{$signal}}) { 143 next if $_->{chatnet} ne 'all' and $_->{chatnet} ne $item->{chatnet}; 144 next if $_->{channel} and $item->{name} ne $_->{channel}; 145 event_handle(@$_{'settings','cmd'},$item,@stuff); 146 } 147 }else{ 148 Irssi::signal_remove($signal,'signal_handler'); 149 } 150 } 151 152 # Called with the params needed to handle an event from signal_handler 153 sub event_handle { 154 my($settings,$cmd,$item,@stuff) = @_; 155 my %settings = settings_to_hash($settings); 156 157 if($settings{type} == 1) { 158 local @_; 159 @_ = ($item,@stuff); 160 eval('no strict;' . $cmd); 161 }else{ 162 $cmd =~ s!\$\$(\d)!(split / /,$stuff[0])[$1]!ge; 163 $cmd =~ s/\$(\d)/$stuff[$1]/g; 164 $item->command($cmd); 165 } 166 167 Irssi::signal_stop() if $settings{stop}; 168 } 169 170 # Converts the settings string to a nice hash 171 sub settings_to_hash { 172 my $settings = shift; 173 my %settings; 174 @settings{'type','stop'} = split //, $settings; 175 return %settings; 176 } 177 178 # Converts a hash to the settings string 179 sub hash_to_settings { 180 my %settings = @_; 181 return join '', @settings{'type','stop'}; 182 } 183 184 # Called by the /on command 185 sub cmd_on { 186 my $text = shift; 187 188 if($text =~ s/^add //) { 189 my($cmd,%options) = option_parse($text); 190 if(!$options{event} || !$cmd) { 191 Irssi::print('No '.($cmd ? 'command' : 'event'). ' supplied'); 192 }else{ 193 my($chatnet,%settings,$channel,$event); 194 $chatnet = ($options{server} ? Irssi::active_server()->{chatnet} : 'all'); 195 $event = $options{event}; 196 $channel = $options{channel}; 197 $settings{type} = $options{perl}; 198 $settings{stop} = $options{stop}; 199 add_on($event,$cmd,$chatnet,$channel,%settings); 200 save(); 201 } 202 }elsif($text =~ s/^remove //) { 203 if(del_on($text)) { 204 Irssi::print("Event $text deleted",MSGLEVEL_CLIENTCRAP); 205 }else{ 206 Irssi::print("Event not found",MSGLEVEL_CLIENTCRAP); 207 } 208 save(); 209 }elsif($text =~ /^reload/) { 210 %on = (); 211 load(); 212 }elsif($text eq "help") { 213 Irssi::print( <<EOF 214 Usage: 215 /on list 216 /on add [-perl] [-server] [-channel #channel] [-stop] 'signal name' command 217 /on remove signal name 218 /on reload 219 EOF 220 ); 221 }else{ 222 Irssi::print("/on help for usage information"); 223 on_list(); 224 } 225 } 226 227 # Output a list of the current contents of %on 228 sub on_list { 229 if(!keys %on) { 230 Irssi::print("On list is empty", MSGLEVEL_CLIENTCRAP); 231 return; 232 } 233 for my $event(keys %on) { 234 for(@{$on{$event}}) { 235 Irssi::print("$event: " . 236 ($_->{chatnet} ne 'all' ? $_->{chatnet} : '') . 237 ' ' . $_->{cmd}, 238 MSGLEVEL_CLIENTCRAP 239 ); 240 } 241 } 242 } 243 244 # Adds into %on and adds a signal if needed. 245 sub add_on { 246 my($event,$cmd,$chatnet,$channel,%settings) = @_; 247 248 Irssi::signal_add($event, 'signal_handler') unless $on{$event}; 249 250 push(@{$on{$event}}, 251 { 252 'chatnet' => $chatnet || 'all', 253 'settings' => hash_to_settings(%settings), 254 'channel' => $channel, 255 'cmd' => $cmd, 256 } 257 ); 258 } 259 260 # Deletes all ons under the event 261 sub del_on { 262 my $on = shift; 263 Irssi::signal_remove($on, 'signal_handler'); 264 return delete($on{$on}); 265 } 266 267 # This is nasty. 268 # It would be nice if perl scripts could use Irssi's internal stuff for option 269 # parsing 270 sub option_parse { 271 my $text = shift; 272 my($last,%options,$cmd); 273 for(split(' ',$text)) { 274 if($cmd) { 275 $cmd .= " $_"; 276 }elsif(/^-(.+)$/) { 277 $last = 'channel' if $1 eq 'channel'; 278 $options{$1}++; 279 }elsif(/^["'0-9]/) { 280 if(/^\d+$/) { 281 $options{event} = "event $_" if /^\d+$/; 282 }else{ 283 $last = 'event'; 284 s/^['"]//; 285 $options{event} = $_; 286 } 287 }elsif($last eq 'event'){ 288 $last = "" if s/['"]$//; 289 $options{event} .= " $_"; 290 }elsif($last) { 291 $options{$last} = $_; 292 $last = ""; 293 }else{ 294 $cmd = $_; 295 } 296 } 297 return ($cmd,%options); 298 } 299