# gems # # Created by Tamara Temple on 2010-05-10. # Copyright (c) 2010 Tamara Temple Development. All rights reserved. # ## TODO: # Make net/channel specific, so channels don't share gems # Add option to turn off/silence gems # Change user function to follow hostmasks instead of nicks use Irssi qw(command_bind); use Env qw(HOME); use Data::Dumper::Names; use Date::Format; use File::Path; use strict; use vars qw($VERSION %IRSSI); $VERSION = "1.1"; %IRSSI = ( authors => 'Tamara Temple', contact => 'tamouse@gmail.com', name => 'gems', description => 'keep quotable quotes, i.e. "gems"', license => 'GPLv2', ); my $debug = 0; my $GEMDIR = $HOME . '/.gemirc/'; my $GEMFILE = $GEMDIR . 'gems_sep'; my $GEMUSERFILE = $GEMDIR . 'users'; my @defaultvalidusers = qw(tamara tamouse ruby); my @validusers; my @gems; sub cmd_gem { my ( $data, $server, $witem ) = @_; return 0 if ( !$witem ); Irssi::command_runsub "gem", $data, $server, $witem; } Irssi::command_bind( 'gem', 'cmd_gem' ); sub timestamp { # no params my $t = time2str( "%D", time, "GMT" ); return $t; } sub create_gemfile { # no params unless (-d $GEMDIR) { mkpath($GEMDIR); } unless (-e $GEMFILE) { open GEMFH,"+>$GEMFILE" or Irssi::active_win()->print("warn: Could not create $GEMFILE"); close GEMFH; } unless (-e $GEMUSERFILE) { open GEMUSERFH,"+>$GEMUSERFILE" or Irssi::active_win()->print("warn: Could not create $GEMUSERFILE"); close GEMUSERFH; } } sub load_gems { # no params open GEMFH, "< $GEMFILE" or do { create_gemfile(); return; }; @gems = (); # zero out gems for reloading while () { chomp(); push @gems, $_; } # suck up all the gems close GEMFH; if ($debug) { # Irssi::active_win->print( "[debug load_gems] " . Dumper(@gems) ); } } sub save_gems { # no params open GEMFH, "> $GEMFILE" or do { create_gemfile(); open GEMFH, "> $GEMFILE" or do { Irssi::active_win()->print("warn: Unable to open $GEMFILE for reading"); return; }; }; print GEMFH join("\n",@gems); close GEMFH; } sub show_gemcount { my ($server, $target) = @_; my $num_gems = $#gems+1; $server->command("msg $target Current number of gems: " . $num_gems ); } sub expand_gem { my ($gem) = @_; my ($gem_no, $gem_text, $gem_nick, $gem_ts) = split(/¶/, $gem); $gem = "Gem [#$gem_no]: " . $gem_text . " [$gem_nick at $gem_ts]"; return $gem; } sub select_gem { my ($gem_num_str) = @_; my $gem_num = int($gem_num_str); $gem_num--; # because we're zero-based in the array Irssi::active_win()->print("[debug select_gem] \$gem_num=$gem_num") if $debug; my $gem = "no gem"; if (@gems && $gem_num >= 0 && $gem_num <= $#gems) { $gem = $gems[$gem_num]; unless (defined($gem)) { $gem = "no gem" ; } else { $gem = expand_gem($gem); } } return $gem; } sub select_random_gem { my ($gems_p) = @_; my $gem = "no gem"; if (@$gems_p) { my @thesegems = @$gems_p; my $i = $#thesegems > 0 ? int(rand($#thesegems) + .5) : 0; Irssi::active_win()->print("[debug select_random_gem] \$#thesegems = $#thesegems ; \$i = $i ; \$thesegems[$i] = $thesegems[$i]") if $debug; $gem = $thesegems[$i]; unless (defined($gem)) { $gem = "no gem"; } else { $gem = expand_gem($gem); } } Irssi::active_win()->print("[debug select_random_gem] \$gem = $gem") if $debug; return $gem; } sub search_gems { my ($text) = @_; my @foundgems = grep( /$text/i, @gems ); return \@foundgems; } sub showgem { my ( $server, $matchtext, $target ) = @_; $_ = $matchtext; SWITCH: { /^\s*$/i && do { $server->command( "msg $target " . select_random_gem( \@gems ) ); last SWITCH; }; /^\s*([0-9]+)$/i && do { $server->command( "msg $target " . select_gem( $1 ) ); last SWITCH; }; /^\s*(.*)$/ && do { $server->command( "msg $target " . select_random_gem( search_gems($1) ) ); last SWITCH; }; } } sub cmd_showgems { my ( $data, $server, $witem ) = @_; return 0 if ( !$witem ); Irssi::print("Gems:"); foreach my $gem (@gems) { Irssi::print(expand_gem($gem)); } } Irssi::command_bind( 'gem showgems', 'cmd_showgems' ); sub addgem { my ( $server, $text, $nick, $target ) = @_; $text =~ s/[\n\r]/ /g; # get rid of new lines and returns $text =~ s/[[:cntrl:]]+//g; # get rid of any control characters in $text if ( $text =~ /^\s*$/ ) { $server->command("msg $target Usage: !addgem text"); } else { my $newgem = $#gems+2 . "¶" . $text . "¶" . $nick . "¶" . timestamp(); push @gems, $newgem; save_gems(); $server->command("msg $target added: " . expand_gem($newgem)); } } sub reload { my ( $server, $nick ) = @_; if ( valid_user($nick) ) { load_gems(); $server->command("msg $nick gems reloaded"); } else { $server->command("msg $nick not a valid user command"); } } sub cmd_reload { my ( $data, $server, $witem ) = @_; return 0 if ( !$witem ); load_gems(); Irssi::print("gems reloaded"); } Irssi::command_bind( 'gem reload', 'cmd_reload' ); sub grep_escape { my ($s) = @_; $s =~ s/[[:punct:]]+//g; return $s; } sub save_users { # no params unless ( @validusers ) { @validusers = @defaultvalidusers; } open USERFH, "> $GEMUSERFILE" or do { create_gemfile(); open USERFH, "> $GEMUSERFILE" or do { Irssi::active_win()->print("warn: Could not open $GEMUSERFILE for writing"); return; }; }; print USERFH join("\n",@validusers); close USERFH; } sub load_users { # no params open USERFH, "< $GEMUSERFILE" or do { create_gemfile(); open USERFH, "< $GEMUSERFILE" or do { Irssi::active_win()->print("warn: Could not open $GEMUSERFILE for reading"); return; }; }; while () { chomp(); push @validusers, $_; } close USERFH; unless ( @validusers ) { @validusers = @defaultvalidusers; } if ($debug) { Irssi::active_win() ->print( "[debug load_users] \n" . join("\n", @validusers) ); } } sub valid_user { my ($user) = @_; $user = grep_escape($user); return 0 if $user =~ /^$/; unless (@validusers) { @validusers = @defaultvalidusers; } my @foundusers = grep( /^$user$/, @validusers ); if (@foundusers) { return 1; } else { return 0; } } sub adduser { my ( $server, $nick, $text, $target ) = @_; if ( valid_user($nick) ) { $text =~ s/[[:punct:]]+//g; # remove any punctuation from nicks my @newusers = split( / /, $text ); if (@newusers) { foreach (@newusers) { push @validusers, $_; } save_users(); $server->command("msg " . $target . " Added users " . join(" ",@newusers) ); } else { $server->command("msg " . $target . " Usage: !gemadduser nick1 nick2 nick3 ..." ); } } } sub cmd_adduser { my ( $data, $server, $witem ) = @_; return 0 if ( !$witem ); $data =~ s/[[:punct:]]+//g; # remove any punctuation from nicks my @newusers = split( / /, $data ); if (@newusers) { foreach (@newusers) { push @validusers, $_; } save_users(); Irssi->print("Added users " . join(" ",@newusers)); } else { Irssi->print("Usage: /gem adduser nick1 nick2 nick3 ..."); } } Irssi::command_bind( 'gem adduser', 'cmd_adduser' ); sub showusers { my ($server, $nick) = @_; if (@validusers) { $server->command("msg $nick Valid Users:"); foreach my $user (@validusers) { $server->command("msg $nick $user"); } } else { $server->command("msg $nick no users!") } } sub cmd_show_users { my ( $data, $server, $witem ) = @_; return 0 if ( !$witem ); if (@validusers) { Irssi::print("Valid Users:"); foreach my $user (@validusers) { Irssi::print(" $user"); } } else { Irssi::print("no users!!"); } } Irssi::command_bind( 'gem showusers', 'cmd_show_users' ); sub gemhelp { my ($server, $nick, $target) = @_; my @help_msg = ( "Gem $VERSION Help", "", "Manage quotes (gems) in channel.", "", "Commands:", " !gem - display a random gem", " !gem num - display a specific gem", " !gem regex - display a gem that matches the regex", " !addgem text - add text as a gem", " !reload - reload the database (requires special permission)", " !gemadduser nick1 nick2 nick3 ... ", " - add a user to the permitted users list (requires special permission)", " !gemshowusers - show the user list", " !help - this message", "" ); foreach my $m (@help_msg) { $server->command("msg $nick [$IRSSI{name}] $m"); } $server->command("msg $target [$IRSSI{name}] help sent") } sub process_msg { my ( $server, $msg, $nick, $target ) = @_; $msg =~ /^!([^ ]+)(| .*)$/; my $cmd = lc $1; my $rest = $2; Irssi::print("[debug process_msg] \$msg=$msg \$cmd=$cmd \$rest=$rest") if $debug; $_ = $cmd; SWITCH: { /^ge?m?$/i && do { showgem( $server, $rest, $target ); last SWITCH; }; /^gems$/i && do { show_gemcount($server, $target); last SWITCH; }; /^ad?d?ge?m?$/i && do { addgem( $server, $rest, $nick, $target ); last SWITCH; }; /^reload$/i && do { reload( $server, $nick ); last SWITCH; }; /^ge?m?ad?d?us?e?r?$/i && do { adduser( $server, $nick, $rest ); last SWITCH; }; /^ge?m?sh?o?w?us?e?r?s?$/i && do { showusers($server, $nick); last SWITCH;}; /^he?l?p?$/i && do { gemhelp ($server, $nick, $target); last SWITCH;}; } } sub sig_publicmsg { my ( $server, $msg, $nick, $address, $target ) = @_; Irssi::signal_continue @_; $target = $nick if $target eq ""; process_msg( $server, $msg, $nick, $target ); } Irssi::signal_add_last( "message public", "sig_publicmsg" ); sub sig_own_publicmsg { my ( $server, $msg, $target ) = @_; Irssi::signal_continue @_; my $nick = $server->{nick}; process_msg( $server, $msg, $nick, $target ); } Irssi::signal_add_last( "message own_public", "sig_own_publicmsg" ); sub cmd_debug { my ($data, $server, $witem) = @_; if ($data =~ /\bon\b/i) { $debug = 1; } elsif ($data =~ /\boff\b/i) { $debug = 0; } elsif ($data =~ /^\s*$/) { $debug = $debug ? 0 : 1; } my $state = $debug ? "on" : "off"; Irssi::print("[$IRSSI{name}] Debug is " . $state ); } Irssi::command_bind('gemdebug', 'cmd_debug'); Irssi::active_win()->print( $IRSSI{name} . ' ' . $VERSION . ' loaded.' ); load_gems(); load_users();