]> git.donarmstrong.com Git - infobot.git/blobdiff - src/Modules/Topic.pl
take a few more things literally
[infobot.git] / src / Modules / Topic.pl
index 59ce3a84f8452184a07fc7b316843ba6d1185bdc..e12fc5d25761d8b9ff65208ad95beeb16bbc1e1f 100644 (file)
@@ -6,8 +6,8 @@
 #
 
 use strict;
-use vars qw(%topiccmp);
-no strict "refs";              ### FIXME!!!
+use vars qw(%topiccmp %topic %channels %cache %orig);
+use vars qw($who $chan $conn $uh $ident);
 
 ###############################
 ##### INTERNAL FUNCTIONS
@@ -16,211 +16,207 @@ no strict "refs";         ### FIXME!!!
 ###
 # Usage: &topicDecipher(chan);
 sub topicDecipher {
-  my $chan     = shift;
-  my @results;
+    my ($chan) = @_;
+    my @results;
 
-  if (!exists $topic{$chan}{'Current'}) {
-    &DEBUG("Topic: does not exist for $chan.");
-    return;
-  }
+    return if (!exists $topic{$chan});
+    return if (!exists $topic{$chan}{'Current'});
 
-  &DEBUG("Topic: hrm => '$topic{$chan}{'Current'}'.");
+    foreach (split /\|\|/, $topic{$chan}{'Current'}) {
+       s/^\s+//;
+       s/\s+$//;
 
-  foreach (split /\|\|/, $topic{$chan}{'Current'}) {
-    s/^\s+//;
-    s/\s+$//;
+       # very nice fix to solve the null subtopic problem.
+       # if nick contains a space, treat topic as ownerless.
+       if (/^\(.*?\)$/) {
+           next unless ($1 =~ /\s/);
+       }
 
-    # very nice fix to solve the null subtopic problem.
-    ### if nick contains a space, treat topic as ownerless.
-    if (/^\(.*?\)$/) {
-       next unless ($1 =~ /\s/);
-    }
+       my $subtopic    = $_;
+       my $owner       = 'Unknown';
 
-    my $subtopic       = $_;
-    my $owner          = "Unknown";
-    if (/(.*)\s+\((.*?)\)$/) {
-       $subtopic       = $1;
-       $owner          = $2;
-    }
+       if (/(.*)\s+\((.*?)\)$/) {
+           $subtopic   = $1;
+           $owner      = $2;
+       }
+
+       if (grep /^\Q$subtopic\E\|\|\Q$owner\E$/, @results) {
+           &status("Topic: we have found a dupe ($subtopic) in the topic, not adding.");
+           next;
+       }
 
-    push(@results, "$subtopic||$owner");
-  }
+       push(@results, "$subtopic||$owner");
+    }
 
-  return @results;
+    return @results;
 }
 
 ###
 # Usage: &topicCipher(@topics);
 sub topicCipher {
-  if (!@_) {
-    &DEBUG("topicCipher: topic is NULL.");
-    return;
-  }
-
-  my $result;
-  foreach (@_) {
-    my ($subtopic, $setby) = split /\|\|/;
+    return if (!@_);
 
-    $result .= " || $subtopic";
-    next if ($setby eq "" or $setby =~ /unknown/i);
+    my @topic;
+    foreach (@_) {
+       my ($subtopic, $setby) = split /\|\|/;
 
-    $result .= " (" . $setby . ")";
-  }
+       if ($param{'topicAuthor'} eq '1' and (!$setby =~ /^(unknown|)$/i)) {
+           push(@topic, "$subtopic ($setby)");
+       } else {
+           push(@topic, "$subtopic");
+       }
+    }
 
-  return substr($result, 4);
+    return join(' || ', @topic);
 }
 
 ###
-# Usage: &topicNew($chan, $topic, $updateMsg, $topicUpdate);
+# Usage: &topicNew($chan, $topic, $updateMsg);
 sub topicNew {
-  my ($chan, $topic, $updateMsg, $topicUpdate) = @_;
-  my $maxlen = 470;
-
-  if ($channels{$chan}{t} and !$channels{$chan}{o}{$ident}) {
-    &msg($who, "error: cannot change topic without ops. (channel is +t) :(");
-    return 0;
-  }
-
-  if (defined $topiccmp{$chan} and $topiccmp{$chan} eq $topic) {
-    &msg($who, "warning: action had no effect on topic; no change required.");
-    return 0;
-  }
-
-  # bail out if the new topic is too long.
-  my $newlen = length($chan.$topic);
-  if ($newlen > $maxlen) {
-    &msg($who, "new topic will be too long. ($newlen > $maxlen)");
-    return 0;
-  }
-
-  $topic{$chan}{'Current'} = $topic;
-
-  # notification that the topic was altered.
-  if (!$topicUpdate) {         # for cached changes with '-'.
-    &performReply("okay");
+    my ($chan, $topic, $updateMsg) = @_;
+    my $maxlen = 470;
+
+    if ($channels{$chan}{t} and !$channels{$chan}{o}{$ident}) {
+       &msg($who, "error: cannot change topic without ops. (channel is +t) :(");
+       return 0;
+    }
+
+    if (defined $topiccmp{$chan} and $topiccmp{$chan} eq $topic) {
+       &msg($who, "warning: action had no effect on topic; no change required.");
+       return 0;
+    }
+
+    # bail out if the new topic is too long.
+    my $newlen = length($chan.$topic);
+    if ($newlen > $maxlen) {
+       &msg($who, "new topic will be too long. ($newlen > $maxlen)");
+       return 0;
+    }
+
+    $topic{$chan}{'Current'} = $topic;
+
+    if ($cache{topicNotUpdate}{$chan}) {
+       &msg($who, "done. 'flush' to finalize changes.");
+       delete $cache{topicNotUpdate}{$chan};
+       return 1;
+    }
+
+    if (defined $updateMsg && $updateMsg ne '') {
+       &msg($who, $updateMsg);
+    }
+
+    $topic{$chan}{'Last'} = $topic;
+    $topic{$chan}{'Who'}  = $orig{who}."!".$uh;
+    $topic{$chan}{'Time'} = time();
+
+    if ($topic) {
+       $conn->topic($chan, $topic);
+       &topicAddHistory($chan, $topic);
+    } else {
+       $conn->topic($chan, ' ');
+    }
+
     return 1;
-  }
-
-  if ($updateMsg ne "") {
-    &msg($who, $updateMsg);
-  }
-
-  $topic{$chan}{'Last'} = $topic;
-  $topic{$chan}{'Who'}  = $orig{who}."!".$uh;
-  $topic{$chan}{'Time'} = time();
-  rawout("TOPIC $chan :$topic");
-  &topicAddHistory($chan,$topic);
-  return 1;
 }
 
 ###
 # Usage: &topicAddHistory($chan,$topic);
 sub topicAddHistory {
-  my ($chan, $topic)   = @_;
-  my $dupe             = 0;
+    my ($chan, $topic) = @_;
+    my $dupe           = 0;
 
-  return 1 if ($topic eq "");                  # required fix.
+    return 1 if ($topic eq '');                        # required fix.
 
-  foreach (@{ $topic{$chan}{'History'} }) {
-    next       if ($_ ne "" and $_ ne $topic);
-    # checking length is required.
+    foreach (@{ $topic{$chan}{'History'} }) {
+       next if ($_ ne '' and $_ ne $topic);
+       # checking length is required.
 
-    $dupe++;
-    last;
-  }
+       # slightly weird to put a return statement in a loop.
+       return 1;
+    }
 
-  return 1     if $dupe;
+    # WTF IS THIS FOR?
 
-  my @topics = @{ $topic{$chan}{'History'} };
-  unshift(@topics, $topic);
-  pop(@topics) while (scalar @topics > 6);
-  $topic{$chan}{'History'} = \@topics;
+    my @topics = @{ $topic{$chan}{'History'} };
+    unshift(@topics, $topic);
+    pop(@topics) while (scalar @topics > 6);
+    $topic{$chan}{'History'} = \@topics;
 
-  return $dupe;
+    return $dupe;
 }
 
 ###############################
 ##### HELPER FUNCTIONS
 ###############################
 
-### TODO.
-# sub topicNew {
-# sub topicDelete {
-# sub topicList {
-# sub topicModify {
-# sub topicMove {
-# sub topicShuffle {
-# sub topicHistory {
-# sub topicRestore {
-# sub topicRehash {
-# sub topicHelp {
-
-###############################
-##### MAIN
-###############################
+# cmd: add.
+sub do_add {
+    my ($chan, $args) = @_;
 
-###
-# Usage: &Topic($cmd, $args);
-sub Topic {
-  my ($chan, $cmd, $args) = @_;
-  my $topicUpdate = 1;
-
-  if ($cmd =~ /^-(\S+)/) {
-    $topicUpdate = 0;
-    $cmd = $1;
-  }
-
-  if ($cmd =~ /^(add)$/i) {
-    ### CMD: ADD:
-    if ($args eq "") {
-       &help("topic add");
-       return $noreply;
+    if ($args eq '') {
+       &help('topic add');
+       return;
     }
 
     # heh, joeyh. 19990819. -xk
     if ($who =~ /\|\|/) {
-       &msg($who, "error: you have an invalid nick, loser!");
-       return $noreply;
+       &msg($who, 'error: you have an invalid nick, loser!');
+       return;
     }
 
+    return if ($channels{$chan}{t} and !&hasFlag('T'));
+
     my @prev = &topicDecipher($chan);
-    my $new  = "$args ($orig{who})";
+    my $new;
+    # If bot new to chan and topic is blank, it still got a (owner). This is fix
+    if ($param{'topicAuthor'} eq '1') {
+       $new  = "$args ($orig{who})";
+    } else {
+       $new  = "$args";
+    }
     $topic{$chan}{'What'} = "Added '$args'.";
+
     if (scalar @prev) {
-      $new = &topicCipher(@prev, sprintf("%s||%s", $args, $who));
+       my $str = sprintf("%s||%s", $args, $who);
+       $new = &topicCipher(@prev, $str);
     }
-    &topicNew($chan, $new, "", $topicUpdate);
 
-  } elsif ($cmd =~ /^(del|delete|rm|remove|kill|purge)$/i) {
-    ### CMD: DEL:
+    &topicNew($chan, $new, '');
+}
+
+# cmd: delete.
+sub do_delete {
+    my ($chan, $args)  = @_;
     my @subtopics      = &topicDecipher($chan);
     my $topiccount     = scalar @subtopics;
 
     if ($topiccount == 0) {
-       &msg($who, "No topic set.");
-       return $noreply;
+       &msg($who, 'No topic set.');
+       return;
     }
 
-    if ($args eq "") {
-       &help("topic del");
-       return $noreply;
+    if ($args eq '') {
+       &help('topic del');
+       return;
     }
 
-    $args =  ",".$args.",";
-    $args =~ s/\s+//g;
-    $args =~ s/(first|1st)/1/i;
-    $args =~ s/last/$topiccount/i;
-    $args =~ s/,-(\d+)/,1-$1/;
-    $args =~ s/(\d+)-,/,$1-$topiccount/;
+    for ($args) {
+       $_ = sprintf(",%s,", $args);
+       s/\s+//g;
+       s/(first|1st)/1/i;
+       s/last/$topiccount/i;
+       s/,-(\d+)/,1-$1/;
+       s/(\d+)-,/,$1-$topiccount/;
+    }
 
     if ($args !~ /[\,\-\d]/) {
        &msg($who, "error: Invalid argument ($args).");
-       return $noreply;
+       return;
     }
 
-    foreach (split ",", $args) {
-       next if ($_ eq "");
-       my @delete;
+    my @delete;
+    foreach (split ',', $args) {
+       next if ($_ eq '');
 
        # change to hash list instead of array?
        if (/^(\d+)-(\d+)$/) {
@@ -232,25 +228,28 @@ sub Topic {
            push(@delete, $1);
        } else {
            &msg($who, "error: Invalid sub-argument ($_).");
-           return $noreply;
+           return;
        }
 
-       $topic{$chan}{'What'} = "Deleted ".join("/",@delete);
+       $topic{$chan}{'What'} = 'Deleted '.join("/",@delete);
+    }
 
-       foreach (@delete) {
-         if ($_ > $topiccount || $_ < 1) {
+    foreach (@delete) {
+       if ($_ > $topiccount || $_ < 1) {
            &msg($who, "error: argument out of range. (max: $topiccount)");
-           return $noreply;
-         }
-         # skip if already deleted.
-         # only checked if x-y range is given.
-         next unless (defined($subtopics[$_-1]));
-
-         my ($subtopic,$whoby) = split('\|\|', $subtopics[$_-1]);
-         $whoby                = "unknown"     if ($whoby eq "");
-         &msg($who, "Deleting topic: $subtopic ($whoby)");
-         undef $subtopics[$_-1];
+           return;
        }
+
+       # skip if already deleted.
+       # only checked if x-y range is given.
+       next unless (defined($subtopics[$_-1]));
+
+       my ($subtopic,$whoby) = split('\|\|', $subtopics[$_-1]);
+
+       $whoby = 'unknown' if ($whoby eq '');
+
+       &msg($who, "Deleting topic: $subtopic ($whoby)");
+       undef $subtopics[$_-1];
     }
 
     my @newtopics;
@@ -259,14 +258,17 @@ sub Topic {
        push(@newtopics, $_);
     }
 
-    &topicNew($chan, &topicCipher(@newtopics), "", $topicUpdate);
+    &topicNew($chan, &topicCipher(@newtopics), '');
+}
+
+# cmd: list
+sub do_list {
+    my ($chan, $args) = @_;
+    my @topics = &topicDecipher($chan);
 
-  } elsif ($cmd =~ /^list$/i) {
-    ### CMD: LIST:
-    my @topics = &topicDecipher($chan);
     if (!scalar @topics) {
        &msg($who, "No topics for \002$chan\002.");
-       return $noreply;
+       return;
     }
 
     &msg($who, "Topics for \002$chan\002:");
@@ -276,18 +278,25 @@ sub Topic {
     foreach (@topics) {
        my ($subtopic, $setby) = split /\|\|/;
 
-       &msg($who, sprintf(" %d. \002[\002%-10s\002]\002 %s",
-                               $i, $setby, $subtopic));
+       my $str = sprintf(" %d. [%-10s] %s", $i, $setby, $subtopic);
+       # is there a better way of doing this?
+       $str =~ s/ (\[)/ \002$1/g;
+       $str =~ s/ (\])/ \002$1/g;
+
+       &msg($who, $str);
        $i++;
     }
+
     &msg($who, "End of Topics.");
+}
 
-  } elsif ($cmd =~ /^(mod|modify|change|alter)$/i) {
-    ### CMD: MOD:
+# cmd: modify.
+sub do_modify {
+    my ($chan, $args) = @_;
 
-    if ($args eq "") {
-       &help("topic mod");
-       return $noreply;
+    if ($args eq '') {
+       &help('topic mod');
+       return;
     }
 
     # a warning message instead of halting. we kind of trust the user now.
@@ -299,199 +308,267 @@ sub Topic {
 
     # SAR patch. mu++
     if ($args =~ m|^\s*s([/,#])(.+?)\1(.*?)\1([a-z]*);?\s*$|) {
-       my ($delim, $op, $np, $flags) = ($1,quotemeta $2,$3,$4);
+       my ($delim, $op, $np, $flags) = ($1,$2,$3,$4);
 
        if ($flags !~ /^(g)?$/) {
-         &msg($who, "error: Invalid flags to regex.");
-         return $noreply;
+           &msg($who, "error: Invalid flags to regex.");
+           return;
        }
 
        my $topic = $topic{$chan}{'Current'};
 
-       if (($flags eq "g" and $topic =~ s/$op/$np/g) ||
-           ($flags eq ""  and $topic =~ s/$op/$np/)) {
+       ### TODO: use m### to make code safe!
+       if (($flags eq 'g' and $topic =~ s/\Q$op\E/$np/g) ||
+           ($flags eq ''  and $topic =~ s/\Q$op\E/$np/)
+       ) {
 
-         $_ = "Modifying topic with sar s/$op/$np/.";
-         &topicNew($chan, $topic, $_, $topicUpdate);
+           $_ = "Modifying topic with sar s/$op/$np/.";
+           &topicNew($chan, $topic, $_);
        } else {
-         &msg($who, "warning: regex not found in topic.");
+           &msg($who, "warning: regex not found in topic.");
        }
-       return $noreply;
+
+       return;
     }
 
     &msg($who, "error: Invalid regex. Try s/1/2/, s#3#4#...");
+}
 
-  } elsif ($cmd =~ /^(mv|move)$/i) {
-    ### CMD: MV:
+# cmd: move.
+sub do_move {
+    my ($chan, $args) = @_;
 
-    if ($args eq "") {
-       &help("topic mv");
-       return $noreply;
+    if ($args eq '') {
+       &help('topic mv');
+       return;
     }
 
+    my ($from, $action, $to);
+    # better way of doing this?
     if ($args =~ /^(first|last|\d+)\s+(before|after|swap)\s+(first|last|\d+)$/i) {
-       my ($from, $action, $to) = ($1,$2,$3);
-       my @subtopics  = &topicDecipher($chan);
-       my @newtopics;
-       my $topiccount = scalar @subtopics;
-
-       if ($topiccount == 1) {
-         &msg($who, "error: impossible to move the only subtopic, dumbass.");
-         return $noreply;
-       }
+       ($from, $action, $to) = ($1,$2,$3);
+    } else {
+       &msg($who, "Invalid arguments.");
+       return;
+    }
 
-       # Is there an easier way to do this?
-       $from =~ s/first/1/i;
-       $to   =~ s/first/1/i;
-       $from =~ s/last/$topiccount/i;
-       $to   =~ s/last/$topiccount/i;
+    my @subtopics  = &topicDecipher($chan);
+    my @newtopics;
+    my $topiccount = scalar @subtopics;
 
-       if ($from > $topiccount || $to > $topiccount || $from < 1 || $to < 1) {
-         &msg($who, "error: <from> or <to> is out of range.");
-         return $noreply;
-       }
+    if ($topiccount == 1) {
+       &msg($who, "error: impossible to move the only subtopic, dumbass.");
+       return;
+    }
 
-       if ($from == $to) {
-         &msg($who, "error: <from> and <to> are the same.");
-         return $noreply;
-       }
+    # Is there an easier way to do this?
+    $from =~ s/first/1/i;
+    $to   =~ s/first/1/i;
+    $from =~ s/last/$topiccount/i;
+    $to   =~ s/last/$topiccount/i;
 
-       $topic{$chan}{'What'} = "Move $from to $to";
+    if ($from > $topiccount || $to > $topiccount || $from < 1 || $to < 1) {
+       &msg($who, "error: <from> or <to> is out of range.");
+       return;
+    }
 
-       if ($action =~ /^(swap)$/i) {
-         my $tmp                       = $subtopics[$to   - 1];
-         $subtopics[$to   - 1]         = $subtopics[$from - 1];
-         $subtopics[$from - 1]         = $tmp;
+    if ($from == $to) {
+       &msg($who, "error: <from> and <to> are the same.");
+       return;
+    }
 
-         $_ = "Swapped #\002$from\002 with #\002$to\002.";
-         &topicNew($chan, &topicCipher(@subtopics), $_, $topicUpdate);
-         return $noreply;
-       }
+    $topic{$chan}{'What'} = "Move $from to $to";
 
-       # action != swap:
-       # Is there a better way to do this? guess not.
-       my $i           = 1;
-       my $subtopic    = $subtopics[$from - 1];
-       foreach (@subtopics) {
-         my $j = $i*2 - 1;
-         $newtopics[$j] = $_   if ($i != $from);
-         $i++;
-       }
+    if ($action =~ /^(swap)$/i) {
+       my $tmp                 = $subtopics[$to   - 1];
+       $subtopics[$to   - 1]   = $subtopics[$from - 1];
+       $subtopics[$from - 1]   = $tmp;
 
-       if ($action =~ /^(before|b4)$/i) {
-           $newtopics[$to*2-2] = $subtopic;
-       } else {
-           # action =~ /after/.
-           $newtopics[$to*2] = $subtopic;
-       }
+       $_ = "Swapped #\002$from\002 with #\002$to\002.";
+       &topicNew($chan, &topicCipher(@subtopics), $_);
+       return;
+    }
 
-       undef @subtopics;                       # lets reuse this array.
-       foreach (@newtopics) {
-         next if ($_ eq "");
-         push(@subtopics, $_);
-       }
+    # action != swap:
+    # Is there a better way to do this? guess not.
+    my $i              = 1;
+    my $subtopic       = $subtopics[$from - 1];
+    foreach (@subtopics) {
+       my $j = $i*2 - 1;
+       $newtopics[$j] = $_ if ($i != $from);
+       $i++;
+    }
 
-       $_ = "Moved #\002$from\002 $action #\002$to\002.";
-       &topicNew($chan, &topicCipher(@subtopics), $_, $topicUpdate);
+    if ($action =~ /^(before|b4)$/i) {
+       $newtopics[$to*2-2] = $subtopic;
+    } else {
+       # action =~ /after/.
+       $newtopics[$to*2] = $subtopic;
+    }
 
-       return $noreply;
+    undef @subtopics;                  # lets reuse this array.
+    foreach (@newtopics) {
+       next if (!defined $_ or $_ eq '');
+       push(@subtopics, $_);
     }
 
-    &msg($who, "Invalid arguments.");
+    $_ = "Moved #\002$from\002 $action #\002$to\002.";
+    &topicNew($chan, &topicCipher(@subtopics), $_);
+}
 
-  } elsif ($cmd =~ /^shuffle$/i) {
-    ### CMD: SHUFFLE:
-    my @subtopics  = &topicDecipher($chan);
+# cmd: shuffle.
+sub do_shuffle {
+    my ($chan, $args)  = @_;
+    my @subtopics      = &topicDecipher($chan);
     my @newtopics;
 
-    $topic{$chan}{'What'} = "shuffled";
+    $topic{$chan}{'What'} = 'shuffled';
 
     foreach (&makeRandom(scalar @subtopics)) {
        push(@newtopics, $subtopics[$_]);
     }
 
     $_ = "Shuffling the bag of lollies.";
-    &topicNew($chan, &topicCipher(@newtopics), $_, $topicUpdate);
+    &topicNew($chan, &topicCipher(@newtopics), $_);
+}
 
-  } elsif ($cmd =~ /^(history)$/i) {
-    ### CMD: HISTORY:
-    if (!scalar @{$topic{$chan}{'History'}}) {
+# cmd: history.
+sub do_history {
+    my ($chan, $args) = @_;
+
+    if (!scalar @{ $topic{$chan}{'History'} }) {
        &msg($who, "Sorry, no topics in history list.");
-       return $noreply;
+       return;
     }
 
     &msg($who, "History of topics on \002$chan\002:");
-    for (1 .. scalar @{$topic{$chan}{'History'}}) {
-       my $topic = ${$topic{$chan}{'History'}}[$_-1];
+    for (1 .. scalar @{ $topic{$chan}{'History'} }) {
+       my $topic = ${ $topic{$chan}{'History'} }[$_-1];
        &msg($who, "  #\002$_\002: $topic");
 
        # To prevent excess floods.
        sleep 1 if (length($topic) > 160);
     }
+
     &msg($who, "End of list.");
+}
+
+# cmd: restore.
+sub do_restore {
+    my ($chan, $args) = @_;
 
-  } elsif ($cmd =~ /^restore$/i) {
-    ### CMD: RESTORE:
-    if ($args eq "") {
-       &help("topic restore");
-       return $noreply;
+    if ($args eq '') {
+       &help('topic restore');
+       return;
     }
 
     $topic{$chan}{'What'} = "Restore topic $args";
 
     # following needs to be verified.
     if ($args =~ /^last$/i) {
-       if (${$topic{$chan}{'History'}}[0] eq $topic{$chan}{'Current'}) {
+       if (${ $topic{$chan}{'History'} }[0] eq $topic{$chan}{'Current'}) {
            &msg($who,"error: cannot restore last topic because it's mine.");
-           return $noreply;
+           return;
        }
        $args = 1;
     }
 
-    if ($args =~ /\d+/) {
-       if ($args > $#{$topic{$chan}{'History'}} || $args < 1) {
-           &msg($who, "error: argument is out of range.");
-           return $noreply;
-       }
-
-       $_ = "Changing topic according to request.";
-       &topicNew($chan, ${$topic{$chan}{'History'}}[$args-1], $_, $topicUpdate);
+    if ($args !~ /\d+/) {
+       &msg($who, "error: argument is not positive integer.");
+       return;
+    }
 
-       return $noreply;
+    if ($args > $#{ $topic{$chan}{'History'} } || $args < 1) {
+       &msg($who, "error: argument is out of range.");
+       return;
     }
 
-    &msg($who, "error: argument is not positive integer.");
+    $_ = "Changing topic according to request.";
+    &topicNew($chan, ${ $topic{$chan}{'History'} }[$args-1], $_);
+}
+
+# cmd: rehash.
+sub do_rehash {
+    my ($chan) = @_;
 
-  } elsif ($cmd =~ /^rehash$/i) {
-    ### CMD: REHASH.
     $_ = "Rehashing topic...";
-    $topic{$chan}{'What'} = "Rehash";
+    $topic{$chan}{'What'} = 'Rehash';
     &topicNew($chan, $topic{$chan}{'Current'}, $_, 1);
+}
+
+# cmd: info.
+sub do_info {
+    my ($chan) = @_;
 
-  } elsif ($cmd =~ /^info$/i) {
-    ### CMD: INFO.
     my $reply = "no topic info.";
     if (exists $topic{$chan}{'Who'} and exists $topic{$chan}{'Time'}) {
        $reply = "topic on \002$chan\002 was last set by ".
                $topic{$chan}{'Who'}. ".  This was done ".
-               &Time2String(time() - $topic{$chan}{'Time'}) ." ago.";
+               &Time2String(time() - $topic{$chan}{'Time'}) .' ago'.
+               ".  Length: ".length($topic{$chan}{'Current'});
        my $change = $topic{$chan}{'What'};
-       $reply .= "Change => $change" if (defined $change);
+       $reply .= ".  Change => $change" if (defined $change);
     }
 
     &performStrictReply($reply);
-  } else {
-    ### CMD: HELP:
-    if ($cmd ne "" and $cmd !~ /^help/i) {
-       &msg($who, "Invalid command [$cmd].");
-       &msg($who, "Try 'help topic'.");
-       return $noreply;
+}
+
+###############################
+##### MAIN
+###############################
+
+###
+# Usage: &Topic($cmd, $args);
+sub Topic {
+    my ($chan, $cmd, $args) = @_;
+
+    if ($cmd =~ /^-(\S+)/) {
+       $cache{topicNotUpdate}{$chan} = 1;
+       $cmd = $1;
     }
 
-    &help("topic");
-  }
+    if ($cmd =~ /^(add)$/i) {
+       &do_add($chan, $args);
 
-  return $noreply;
+    } elsif ($cmd =~ /^(del|delete|rm|remove|kill|purge)$/i) {
+       &do_delete($chan, $args);
+
+    } elsif ($cmd =~ /^list$/i) {
+       &do_list($chan, $args);
+
+    } elsif ($cmd =~ /^(mod|modify|change|alter)$/i) {
+       &do_modify($chan, $args);
+
+    } elsif ($cmd =~ /^(mv|move)$/i) {
+       &do_move($chan, $args);
+
+    } elsif ($cmd =~ /^shuffle$/i) {
+       &do_shuffle($chan, $args);
+
+    } elsif ($cmd =~ /^(history)$/i) {
+       &do_history($chan, $args);
+
+    } elsif ($cmd =~ /^restore$/i) {
+       &do_restore($chan, $args);
+
+    } elsif ($cmd =~ /^(flush|rehash)$/i) {
+       &do_rehash($chan);
+
+    } elsif ($cmd =~ /^info$/i) {
+       &do_info($chan);
+
+    } else {
+       ### HELP:
+       if ($cmd ne '' and $cmd !~ /^help/i) {
+           &msg($who, "Invalid command [$cmd].");
+           &msg($who, "Try 'help topic'.");
+           return;
+       }
+
+       &help('topic');
+    }
+
+    return;
 }
 
 1;