on.pl


Code Index:


on.pl

/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.


Features

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).


Usage

 /on list
 /on add [-perl] [-server] [-channel #channel]  [-stop] 'signal name' command
 /on remove signal name
 /on reload

ON ADD

 -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..

ON REMOVE

This removes *all* events from the signal specified (if you want to remove a numeric you must add event eg: /on remove event 401

ON RELOAD

Reloads the saved list from ~/.irssi/on.save into memory, useful if you have to edit it manually (and very useful during debugging :)


Examples

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