2 # Topic.pl: Advanced topic management (maxtopiclen>=512)
4 # Version: v0.8 (19990919).
9 use vars qw(%topiccmp %topic %channels %cache %orig);
10 use vars qw($who $chan $conn $uh $ident);
12 ###############################
13 ##### INTERNAL FUNCTIONS
14 ###############################
17 # Usage: &topicDecipher(chan);
22 return if (!exists $topic{$chan});
23 return if (!exists $topic{$chan}{'Current'});
25 foreach (split /\|\|/, $topic{$chan}{'Current'}) {
29 # very nice fix to solve the null subtopic problem.
30 # if nick contains a space, treat topic as ownerless.
32 next unless ($1 =~ /\s/);
36 my $owner = 'Unknown';
38 if (/(.*)\s+\((.*?)\)$/) {
43 if (grep /^\Q$subtopic\E\|\|\Q$owner\E$/, @results) {
44 &status("Topic: we have found a dupe ($subtopic) in the topic, not adding.");
48 push(@results, "$subtopic||$owner");
55 # Usage: &topicCipher(@topics);
61 my ($subtopic, $setby) = split /\|\|/;
63 if ($param{'topicAuthor'} eq '1' and (!$setby =~ /^(unknown|)$/i)) {
64 push(@topic, "$subtopic ($setby)");
66 push(@topic, "$subtopic");
70 return join(' || ', @topic);
74 # Usage: &topicNew($chan, $topic, $updateMsg);
76 my ($chan, $topic, $updateMsg) = @_;
79 if ($channels{$chan}{t} and !$channels{$chan}{o}{$ident}) {
80 &msg($who, "error: cannot change topic without ops. (channel is +t) :(");
84 if (defined $topiccmp{$chan} and $topiccmp{$chan} eq $topic) {
85 &msg($who, "warning: action had no effect on topic; no change required.");
89 # bail out if the new topic is too long.
90 my $newlen = length($chan.$topic);
91 if ($newlen > $maxlen) {
92 &msg($who, "new topic will be too long. ($newlen > $maxlen)");
96 $topic{$chan}{'Current'} = $topic;
98 if ($cache{topicNotUpdate}{$chan}) {
99 &msg($who, "done. 'flush' to finalize changes.");
100 delete $cache{topicNotUpdate}{$chan};
104 if (defined $updateMsg && $updateMsg ne '') {
105 &msg($who, $updateMsg);
108 $topic{$chan}{'Last'} = $topic;
109 $topic{$chan}{'Who'} = $orig{who}."!".$uh;
110 $topic{$chan}{'Time'} = time();
113 $conn->topic($chan, $topic);
114 &topicAddHistory($chan, $topic);
116 $conn->topic($chan, ' ');
123 # Usage: &topicAddHistory($chan,$topic);
124 sub topicAddHistory {
125 my ($chan, $topic) = @_;
128 return 1 if ($topic eq ''); # required fix.
130 foreach (@{ $topic{$chan}{'History'} }) {
131 next if ($_ ne '' and $_ ne $topic);
132 # checking length is required.
134 # slightly weird to put a return statement in a loop.
140 my @topics = @{ $topic{$chan}{'History'} };
141 unshift(@topics, $topic);
142 pop(@topics) while (scalar @topics > 6);
143 $topic{$chan}{'History'} = \@topics;
148 ###############################
149 ##### HELPER FUNCTIONS
150 ###############################
154 my ($chan, $args) = @_;
161 # heh, joeyh. 19990819. -xk
162 if ($who =~ /\|\|/) {
163 &msg($who, 'error: you have an invalid nick, loser!');
167 return if ($channels{$chan}{t} and !&hasFlag('T'));
169 my @prev = &topicDecipher($chan);
171 # If bot new to chan and topic is blank, it still got a (owner). This is fix
172 if ($param{'topicAuthor'} eq '1') {
173 $new = "$args ($orig{who})";
177 $topic{$chan}{'What'} = "Added '$args'.";
180 my $str = sprintf("%s||%s", $args, $who);
181 $new = &topicCipher(@prev, $str);
184 &topicNew($chan, $new, '');
189 my ($chan, $args) = @_;
190 my @subtopics = &topicDecipher($chan);
191 my $topiccount = scalar @subtopics;
193 if ($topiccount == 0) {
194 &msg($who, 'No topic set.');
204 $_ = sprintf(",%s,", $args);
207 s/last/$topiccount/i;
209 s/(\d+)-,/,$1-$topiccount/;
212 if ($args !~ /[\,\-\d]/) {
213 &msg($who, "error: Invalid argument ($args).");
218 foreach (split ',', $args) {
221 # change to hash list instead of array?
222 if (/^(\d+)-(\d+)$/) {
223 my ($from,$to) = ($1,$2);
224 ($from,$to) = ($2,$1) if ($from > $to);
226 push(@delete, $1..$2);
227 } elsif (/^(\d+)$/) {
230 &msg($who, "error: Invalid sub-argument ($_).");
234 $topic{$chan}{'What'} = 'Deleted '.join("/",@delete);
238 if ($_ > $topiccount || $_ < 1) {
239 &msg($who, "error: argument out of range. (max: $topiccount)");
243 # skip if already deleted.
244 # only checked if x-y range is given.
245 next unless (defined($subtopics[$_-1]));
247 my ($subtopic,$whoby) = split('\|\|', $subtopics[$_-1]);
249 $whoby = 'unknown' if ($whoby eq '');
251 &msg($who, "Deleting topic: $subtopic ($whoby)");
252 undef $subtopics[$_-1];
256 foreach (@subtopics) {
257 next unless (defined $_);
258 push(@newtopics, $_);
261 &topicNew($chan, &topicCipher(@newtopics), '');
266 my ($chan, $args) = @_;
267 my @topics = &topicDecipher($chan);
269 if (!scalar @topics) {
270 &msg($who, "No topics for \002$chan\002.");
274 &msg($who, "Topics for \002$chan\002:");
275 &msg($who, "No \002[\002 Set by \002]\002 Topic");
279 my ($subtopic, $setby) = split /\|\|/;
281 my $str = sprintf(" %d. [%-10s] %s", $i, $setby, $subtopic);
282 # is there a better way of doing this?
283 $str =~ s/ (\[)/ \002$1/g;
284 $str =~ s/ (\])/ \002$1/g;
290 &msg($who, "End of Topics.");
295 my ($chan, $args) = @_;
302 # a warning message instead of halting. we kind of trust the user now.
303 if ($args =~ /\|\|/) {
304 &msg($who, "warning: adding double pipes manually == evil. be warned.");
307 $topic{$chan}{'What'} = "SAR $args";
310 if ($args =~ m|^\s*s([/,#])(.+?)\1(.*?)\1([a-z]*);?\s*$|) {
311 my ($delim, $op, $np, $flags) = ($1,$2,$3,$4);
313 if ($flags !~ /^(g)?$/) {
314 &msg($who, "error: Invalid flags to regex.");
318 my $topic = $topic{$chan}{'Current'};
320 ### TODO: use m### to make code safe!
321 if (($flags eq 'g' and $topic =~ s/\Q$op\E/$np/g) ||
322 ($flags eq '' and $topic =~ s/\Q$op\E/$np/)
325 $_ = "Modifying topic with sar s/$op/$np/.";
326 &topicNew($chan, $topic, $_);
328 &msg($who, "warning: regex not found in topic.");
334 &msg($who, "error: Invalid regex. Try s/1/2/, s#3#4#...");
339 my ($chan, $args) = @_;
346 my ($from, $action, $to);
347 # better way of doing this?
348 if ($args =~ /^(first|last|\d+)\s+(before|after|swap)\s+(first|last|\d+)$/i) {
349 ($from, $action, $to) = ($1,$2,$3);
351 &msg($who, "Invalid arguments.");
355 my @subtopics = &topicDecipher($chan);
357 my $topiccount = scalar @subtopics;
359 if ($topiccount == 1) {
360 &msg($who, "error: impossible to move the only subtopic, dumbass.");
364 # Is there an easier way to do this?
365 $from =~ s/first/1/i;
367 $from =~ s/last/$topiccount/i;
368 $to =~ s/last/$topiccount/i;
370 if ($from > $topiccount || $to > $topiccount || $from < 1 || $to < 1) {
371 &msg($who, "error: <from> or <to> is out of range.");
376 &msg($who, "error: <from> and <to> are the same.");
380 $topic{$chan}{'What'} = "Move $from to $to";
382 if ($action =~ /^(swap)$/i) {
383 my $tmp = $subtopics[$to - 1];
384 $subtopics[$to - 1] = $subtopics[$from - 1];
385 $subtopics[$from - 1] = $tmp;
387 $_ = "Swapped #\002$from\002 with #\002$to\002.";
388 &topicNew($chan, &topicCipher(@subtopics), $_);
393 # Is there a better way to do this? guess not.
395 my $subtopic = $subtopics[$from - 1];
396 foreach (@subtopics) {
398 $newtopics[$j] = $_ if ($i != $from);
402 if ($action =~ /^(before|b4)$/i) {
403 $newtopics[$to*2-2] = $subtopic;
406 $newtopics[$to*2] = $subtopic;
409 undef @subtopics; # lets reuse this array.
410 foreach (@newtopics) {
411 next if (!defined $_ or $_ eq '');
412 push(@subtopics, $_);
415 $_ = "Moved #\002$from\002 $action #\002$to\002.";
416 &topicNew($chan, &topicCipher(@subtopics), $_);
421 my ($chan, $args) = @_;
422 my @subtopics = &topicDecipher($chan);
425 $topic{$chan}{'What'} = 'shuffled';
427 foreach (&makeRandom(scalar @subtopics)) {
428 push(@newtopics, $subtopics[$_]);
431 $_ = "Shuffling the bag of lollies.";
432 &topicNew($chan, &topicCipher(@newtopics), $_);
437 my ($chan, $args) = @_;
439 if (!scalar @{ $topic{$chan}{'History'} }) {
440 &msg($who, "Sorry, no topics in history list.");
444 &msg($who, "History of topics on \002$chan\002:");
445 for (1 .. scalar @{ $topic{$chan}{'History'} }) {
446 my $topic = ${ $topic{$chan}{'History'} }[$_-1];
447 &msg($who, " #\002$_\002: $topic");
449 # To prevent excess floods.
450 sleep 1 if (length($topic) > 160);
453 &msg($who, "End of list.");
458 my ($chan, $args) = @_;
461 &help('topic restore');
465 $topic{$chan}{'What'} = "Restore topic $args";
467 # following needs to be verified.
468 if ($args =~ /^last$/i) {
469 if (${ $topic{$chan}{'History'} }[0] eq $topic{$chan}{'Current'}) {
470 &msg($who,"error: cannot restore last topic because it's mine.");
476 if ($args !~ /\d+/) {
477 &msg($who, "error: argument is not positive integer.");
481 if ($args > $#{ $topic{$chan}{'History'} } || $args < 1) {
482 &msg($who, "error: argument is out of range.");
486 $_ = "Changing topic according to request.";
487 &topicNew($chan, ${ $topic{$chan}{'History'} }[$args-1], $_);
494 $_ = "Rehashing topic...";
495 $topic{$chan}{'What'} = 'Rehash';
496 &topicNew($chan, $topic{$chan}{'Current'}, $_, 1);
503 my $reply = "no topic info.";
504 if (exists $topic{$chan}{'Who'} and exists $topic{$chan}{'Time'}) {
505 $reply = "topic on \002$chan\002 was last set by ".
506 $topic{$chan}{'Who'}. ". This was done ".
507 &Time2String(time() - $topic{$chan}{'Time'}) .' ago'.
508 ". Length: ".length($topic{$chan}{'Current'});
509 my $change = $topic{$chan}{'What'};
510 $reply .= ". Change => $change" if (defined $change);
513 &performStrictReply($reply);
516 ###############################
518 ###############################
521 # Usage: &Topic($cmd, $args);
523 my ($chan, $cmd, $args) = @_;
525 if ($cmd =~ /^-(\S+)/) {
526 $cache{topicNotUpdate}{$chan} = 1;
530 if ($cmd =~ /^(add)$/i) {
531 &do_add($chan, $args);
533 } elsif ($cmd =~ /^(del|delete|rm|remove|kill|purge)$/i) {
534 &do_delete($chan, $args);
536 } elsif ($cmd =~ /^list$/i) {
537 &do_list($chan, $args);
539 } elsif ($cmd =~ /^(mod|modify|change|alter)$/i) {
540 &do_modify($chan, $args);
542 } elsif ($cmd =~ /^(mv|move)$/i) {
543 &do_move($chan, $args);
545 } elsif ($cmd =~ /^shuffle$/i) {
546 &do_shuffle($chan, $args);
548 } elsif ($cmd =~ /^(history)$/i) {
549 &do_history($chan, $args);
551 } elsif ($cmd =~ /^restore$/i) {
552 &do_restore($chan, $args);
554 } elsif ($cmd =~ /^(flush|rehash)$/i) {
557 } elsif ($cmd =~ /^info$/i) {
562 if ($cmd ne '' and $cmd !~ /^help/i) {
563 &msg($who, "Invalid command [$cmd].");
564 &msg($who, "Try 'help topic'.");
576 # vim:ts=4:sw=4:expandtab:tw=80