All pastes #1284447 Raw Edit

XTP 0.4.2-3

public text v1 · immutable
#1284447 ·published 2008-12-13 20:37 UTC
rendered paste body
#!/usr/bin/perl
################################################################################
#                                                                              #
# ############################################################################ #
# # Title       : xtp.pl                                                     # #
# # Description : Randomly picks and sets a topic for a channel from a file. # #
# # Coded by    : Justin "HEYO--!" Lee                                       # #
# # Version     : 0.4.2-3                                                    # #
# # Date        : 2008-12-13                                                 # #
# # License     : GNU General Public License v.2                             # #
# #               Copyright (C) 2008  Justin Lee  <kool.name at gmail.com>   # #
# ############################################################################ #
#                                                                              #
# ############################################################################ #
# # This program is free software; you can redistribute it and/or            # #
# # modify it under the terms of the GNU General Public License version 2    # #
# # as published by the Free Software Foundation.                            # #
# #                                                                          # #
# # This program is distributed in the hope that it will be useful,          # #
# # but WITHOUT ANY WARRANTY; without even the implied warranty of           # #
# # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            # #
# # GNU General Public License for more details.                             # #
# #                                                                          # #
# # You should have received a copy of the GNU General Public License        # #
# # along with this program; if not, write to the Free Software              # #
# # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA            # #
# # 02110-1301, USA.  Or, see: <http://www.gnu.org/licenses/>                # #
# ############################################################################ #
#                                                                              #
################################################################################

use strict;

Xchat::register('XTP', '0.4.2-3', 'Randomly picks and sets a topic for a channel from a file.');
Xchat::hook_print('Channel Message', 'channel_watch');
Xchat::hook_command('tcmd','command_wrapper');

## preferences ##
my $topic_dir = Xchat::get_info('xchatdir');
my $topic_file = 'rtopics.txt';
my $topic_set_time = '3600000'; # 60 minutes
my $topic_prefix = '#51: ';
my $channel = '#51';
my $topic_trigger = '!topic';
my $topic_autoset = 1;
## stop editing ##

# I hate global vars
my @topics;
my %prefix = (
  '~' => 5,
  '&' => 4,
  '@' => 3,
  '%' => 2,
  '+' => 1,
  ''  => 0
);

chdir($topic_dir) or die;

if ($topic_autoset) {
  # autoset in one minute
  # allows for time joining
  Xchat::hook_timer(60000,"topic_set");
} else {
  # don't autoset, set in $time ms
  timer_set();
}

Xchat::print('XTP: Loaded.');

sub topic_set {
  # reset the timer as long as
  # topic_set(1) is not called
  timer_set() unless shift;
  # build the queue if needed
  build_stack() unless @topics;

  Xchat::command("topic $channel $topic_prefix @{[ pop(@topics) ]}",$channel) or warn;
  return Xchat::EAT_NONE;
}


# watch for !topic <command> in $channel
sub channel_watch {
  # channel check
  return unless uc(Xchat::get_info('channel')) eq uc($channel);
  Xchat::set_context(Xchat::find_context($channel));

  # user check                                  # this section could be something like:
  my $user = Xchat::user_info($_[0][0]);        # return unless $prefix{$_[0][2]} > $val;
  # must have a voice or higher (>=1)           # but I don't know how reliable $_[0][2] is
  return unless $prefix{$user->{'prefix'}} > 0; # when compared with Xchat::user_info();

  #line check
  return unless $_[0][1] =~ /^$topic_trigger(?:\b.*)?$/oi;

  # pass the user's line ($_[0][1]) on as an array (split)
  unless (topic_command(split(/\s+/,$_[0][1]))) {
    # if t_command returned 0, print help
    Xchat::command("msg $channel XTP Basics: !topic ADD This is a new topic. && !topic",$channel) or warn;
    Xchat::command("msg $channel XTP: For command help, ask someone who knows.",$channel) or warn;
  }

  return Xchat::EAT_NONE;
}

sub command_wrapper {
  unless (topic_command(@{$_[0]})) {
    Xchat::print('XTP: Non-fatal error.');
  }
  return Xchat::EAT_XCHAT;
}

sub topic_command {
  # !topic
  if ($#_ == 0) {
    topic_set(1);
  }
  # !topic delete (not implemented)
  elsif ($_[1] =~ /^(?:(?:de|ba)l(?:eted?)?|rem(?:ove)?)$/oi) { # don't ask :)
    return 0;
  }
  # !topic update
  elsif ($_[1] =~ /^(?:update|refresh)$/oi) {
    build_stack();
  }
  # !topic add
  elsif ($_[1] =~ /^add$/oi) {
    add_topic(join(' ',@_[2..$#_]));
  }
  # !topic shuffle
  elsif ($_[1] =~ /^shuffle$/oi) {
    if (@topics > 1) {
      # needs @topics to contain 2+ entries
      fisher_yates_shuffle(\@topics);
    } else {
      # else it rebuilds the stack
      build_stack();
    }
  }
  # !topic clean
  elsif ($_[1] =~ /^clean(?:se)?$/oi) {
    topic_clean();
  }
  # !topic imabigdouche
  else {
    return 0;
  }

  return 1;
}

sub build_stack {
  # empty the topic stack
  @topics = ();

  open(TFILE,"<$topic_file") or die;

  while(<TFILE>) {
    chomp;
    # skip blank lines
    next if /^(\s*)$/o;

    # clean up the rest
    s/^\s+//o;
    s/\s+$//o;
    # add it to the stack
    push(@topics,$_);
  }

  close(TFILE) or die;

  # shuffle the stack
  fisher_yates_shuffle(\@topics);
}

sub add_topic {
  open(TFILE,">>$topic_file") or die;
  print TFILE "\n", shift;
  close(TFILE) or die;
}

# reset the timer if set time != and > 0
sub timer_set {
  if ( $topic_set_time and $topic_set_time > 0 ) {
    Xchat::hook_timer($topic_set_time,"topic_set");
  }
}

# cookbook
sub fisher_yates_shuffle {
  my $array = shift;
  my $i;
  for ($i = @$array; --$i; ) {
    my $j = int rand ($i+1);
    next if $i == $j;
    @$array[$i,$j] = @$array[$j,$i];
  }
}

# clean up the topic file
sub topic_clean {
  if (-f "$topic_file.bak") {
    # remove the old backup, if it exists, or abort (non-fatal)
    unless (unlink("$topic_file.bak")) {
      Xchat::print("XTP: Error: Unable to remove `$topic_file.bak', aborting re-write.");
      return 0;
    }
  }
  # backup the old file by renaming it to *.bak, or abort (non-fatal)
  unless (rename($topic_file,"$topic_file.bak")) {
    Xchat::print("XTP: Error: Unable to backup $topic_file by renaming, aborting re-write.");
    return 0;
  }
  # if the topic file can't be opened for re-writing, attempt recovery of old one
  unless (open(TFILE,">$topic_file")) {
    Xchat::print("XTP: Error: Wasn't able to open $topic_file for writing, attempting to recover $topic_file.bak...");
    # if it can't be recovered, we're screwed. drop a hint and die
    unless (rename("$topic_file.bak",$topic_file)) {
      Xchat::print('XTP: Fatal Error: Recovery failed, shit. You better fix it.');
      Xchat::print("XTP: Hint: Poke around `$topic_dir'.");
      die;
    }
  }
  # if it all works out, we're ready to write!
  print TFILE "$_\n" foreach @topics;
  close(TFILE) or die;
}