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 ) {
45 "Topic: we have found a dupe ($subtopic) in the topic, not adding."
50 push( @results, "$subtopic||$owner" );
57 # Usage: &topicCipher(@topics);
63 my ( $subtopic, $setby ) = split /\|\|/;
65 if ( $param{'topicAuthor'} eq '1' and ( !$setby =~ /^(unknown|)$/i ) ) {
66 push( @topic, "$subtopic ($setby)" );
69 push( @topic, "$subtopic" );
73 return join( ' || ', @topic );
77 # Usage: &topicNew($chan, $topic, $updateMsg);
79 my ( $chan, $topic, $updateMsg ) = @_;
82 if ( $channels{$chan}{t} and !$channels{$chan}{o}{$ident} ) {
84 "error: cannot change topic without ops. (channel is +t) :(" );
88 if ( defined $topiccmp{$chan} and $topiccmp{$chan} eq $topic ) {
90 "warning: action had no effect on topic; no change required." );
94 # bail out if the new topic is too long.
95 my $newlen = length( $chan . $topic );
96 if ( $newlen > $maxlen ) {
97 &msg( $who, "new topic will be too long. ($newlen > $maxlen)" );
101 $topic{$chan}{'Current'} = $topic;
103 if ( $cache{topicNotUpdate}{$chan} ) {
104 &msg( $who, "done. 'flush' to finalize changes." );
105 delete $cache{topicNotUpdate}{$chan};
109 if ( defined $updateMsg && $updateMsg ne '' ) {
110 &msg( $who, $updateMsg );
113 $topic{$chan}{'Last'} = $topic;
114 $topic{$chan}{'Who'} = $orig{who} . "!" . $uh;
115 $topic{$chan}{'Time'} = time();
118 $conn->topic( $chan, $topic );
119 &topicAddHistory( $chan, $topic );
122 $conn->topic( $chan, ' ' );
129 # Usage: &topicAddHistory($chan,$topic);
130 sub topicAddHistory {
131 my ( $chan, $topic ) = @_;
134 return 1 if ( $topic eq '' ); # required fix.
136 foreach ( @{ $topic{$chan}{'History'} } ) {
137 next if ( $_ ne '' and $_ ne $topic );
139 # checking length is required.
141 # slightly weird to put a return statement in a loop.
147 my @topics = @{ $topic{$chan}{'History'} };
148 unshift( @topics, $topic );
149 pop(@topics) while ( scalar @topics > 6 );
150 $topic{$chan}{'History'} = \@topics;
155 ###############################
156 ##### HELPER FUNCTIONS
157 ###############################
161 my ( $chan, $args ) = @_;
168 # heh, joeyh. 19990819. -xk
169 if ( $who =~ /\|\|/ ) {
170 &msg( $who, 'error: you have an invalid nick, loser!' );
174 return if ( $channels{$chan}{t} and !&hasFlag('T') );
176 my @prev = &topicDecipher($chan);
179 # If bot new to chan and topic is blank, it still got a (owner). This is fix
180 if ( $param{'topicAuthor'} eq '1' ) {
181 $new = "$args ($orig{who})";
186 $topic{$chan}{'What'} = "Added '$args'.";
188 if ( scalar @prev ) {
189 my $str = sprintf( "%s||%s", $args, $who );
190 $new = &topicCipher( @prev, $str );
193 &topicNew( $chan, $new, '' );
198 my ( $chan, $args ) = @_;
199 my @subtopics = &topicDecipher($chan);
200 my $topiccount = scalar @subtopics;
202 if ( $topiccount == 0 ) {
203 &msg( $who, 'No topic set.' );
213 $_ = sprintf( ",%s,", $args );
216 s/last/$topiccount/i;
218 s/(\d+)-,/,$1-$topiccount/;
221 if ( $args !~ /[\,\-\d]/ ) {
222 &msg( $who, "error: Invalid argument ($args)." );
227 foreach ( split ',', $args ) {
228 next if ( $_ eq '' );
230 # change to hash list instead of array?
231 if (/^(\d+)-(\d+)$/) {
232 my ( $from, $to ) = ( $1, $2 );
233 ( $from, $to ) = ( $2, $1 ) if ( $from > $to );
235 push( @delete, $1 .. $2 );
241 &msg( $who, "error: Invalid sub-argument ($_)." );
245 $topic{$chan}{'What'} = 'Deleted ' . join( "/", @delete );
249 if ( $_ > $topiccount || $_ < 1 ) {
250 &msg( $who, "error: argument out of range. (max: $topiccount)" );
254 # skip if already deleted.
255 # only checked if x-y range is given.
256 next unless ( defined( $subtopics[ $_ - 1 ] ) );
258 my ( $subtopic, $whoby ) = split( '\|\|', $subtopics[ $_ - 1 ] );
260 $whoby = 'unknown' if ( $whoby eq '' );
262 &msg( $who, "Deleting topic: $subtopic ($whoby)" );
263 undef $subtopics[ $_ - 1 ];
267 foreach (@subtopics) {
268 next unless ( defined $_ );
269 push( @newtopics, $_ );
272 &topicNew( $chan, &topicCipher(@newtopics), '' );
277 my ( $chan, $args ) = @_;
278 my @topics = &topicDecipher($chan);
280 if ( !scalar @topics ) {
281 &msg( $who, "No topics for \002$chan\002." );
285 &msg( $who, "Topics for \002$chan\002:" );
286 &msg( $who, "No \002[\002 Set by \002]\002 Topic" );
290 my ( $subtopic, $setby ) = split /\|\|/;
292 my $str = sprintf( " %d. [%-10s] %s", $i, $setby, $subtopic );
294 # is there a better way of doing this?
295 $str =~ s/ (\[)/ \002$1/g;
296 $str =~ s/ (\])/ \002$1/g;
302 &msg( $who, "End of Topics." );
307 my ( $chan, $args ) = @_;
314 # a warning message instead of halting. we kind of trust the user now.
315 if ( $args =~ /\|\|/ ) {
317 "warning: adding double pipes manually == evil. be warned." );
320 $topic{$chan}{'What'} = "SAR $args";
323 if ( $args =~ m|^\s*s([/,#])(.+?)\1(.*?)\1([a-z]*);?\s*$| ) {
324 my ( $delim, $op, $np, $flags ) = ( $1, $2, $3, $4 );
326 if ( $flags !~ /^(g)?$/ ) {
327 &msg( $who, "error: Invalid flags to regex." );
331 my $topic = $topic{$chan}{'Current'};
333 ### TODO: use m### to make code safe!
334 if ( ( $flags eq 'g' and $topic =~ s/\Q$op\E/$np/g )
335 || ( $flags eq '' and $topic =~ s/\Q$op\E/$np/ ) )
338 $_ = "Modifying topic with sar s/$op/$np/.";
339 &topicNew( $chan, $topic, $_ );
342 &msg( $who, "warning: regex not found in topic." );
348 &msg( $who, "error: Invalid regex. Try s/1/2/, s#3#4#..." );
353 my ( $chan, $args ) = @_;
360 my ( $from, $action, $to );
362 # better way of doing this?
364 /^(first|last|\d+)\s+(before|after|swap)\s+(first|last|\d+)$/i )
366 ( $from, $action, $to ) = ( $1, $2, $3 );
369 &msg( $who, "Invalid arguments." );
373 my @subtopics = &topicDecipher($chan);
375 my $topiccount = scalar @subtopics;
377 if ( $topiccount == 1 ) {
378 &msg( $who, "error: impossible to move the only subtopic, dumbass." );
382 # Is there an easier way to do this?
383 $from =~ s/first/1/i;
385 $from =~ s/last/$topiccount/i;
386 $to =~ s/last/$topiccount/i;
388 if ( $from > $topiccount || $to > $topiccount || $from < 1 || $to < 1 ) {
389 &msg( $who, "error: <from> or <to> is out of range." );
393 if ( $from == $to ) {
394 &msg( $who, "error: <from> and <to> are the same." );
398 $topic{$chan}{'What'} = "Move $from to $to";
400 if ( $action =~ /^(swap)$/i ) {
401 my $tmp = $subtopics[ $to - 1 ];
402 $subtopics[ $to - 1 ] = $subtopics[ $from - 1 ];
403 $subtopics[ $from - 1 ] = $tmp;
405 $_ = "Swapped #\002$from\002 with #\002$to\002.";
406 &topicNew( $chan, &topicCipher(@subtopics), $_ );
411 # Is there a better way to do this? guess not.
413 my $subtopic = $subtopics[ $from - 1 ];
414 foreach (@subtopics) {
416 $newtopics[$j] = $_ if ( $i != $from );
420 if ( $action =~ /^(before|b4)$/i ) {
421 $newtopics[ $to * 2 - 2 ] = $subtopic;
426 $newtopics[ $to * 2 ] = $subtopic;
429 undef @subtopics; # lets reuse this array.
430 foreach (@newtopics) {
431 next if ( !defined $_ or $_ eq '' );
432 push( @subtopics, $_ );
435 $_ = "Moved #\002$from\002 $action #\002$to\002.";
436 &topicNew( $chan, &topicCipher(@subtopics), $_ );
441 my ( $chan, $args ) = @_;
442 my @subtopics = &topicDecipher($chan);
445 $topic{$chan}{'What'} = 'shuffled';
447 foreach ( &makeRandom( scalar @subtopics ) ) {
448 push( @newtopics, $subtopics[$_] );
451 $_ = "Shuffling the bag of lollies.";
452 &topicNew( $chan, &topicCipher(@newtopics), $_ );
457 my ( $chan, $args ) = @_;
459 if ( !scalar @{ $topic{$chan}{'History'} } ) {
460 &msg( $who, "Sorry, no topics in history list." );
464 &msg( $who, "History of topics on \002$chan\002:" );
465 for ( 1 .. scalar @{ $topic{$chan}{'History'} } ) {
466 my $topic = ${ $topic{$chan}{'History'} }[ $_ - 1 ];
467 &msg( $who, " #\002$_\002: $topic" );
469 # To prevent excess floods.
470 sleep 1 if ( length($topic) > 160 );
473 &msg( $who, "End of list." );
478 my ( $chan, $args ) = @_;
481 &help('topic restore');
485 $topic{$chan}{'What'} = "Restore topic $args";
487 # following needs to be verified.
488 if ( $args =~ /^last$/i ) {
489 if ( ${ $topic{$chan}{'History'} }[0] eq $topic{$chan}{'Current'} ) {
490 &msg( $who, "error: cannot restore last topic because it's mine." );
496 if ( $args !~ /\d+/ ) {
497 &msg( $who, "error: argument is not positive integer." );
501 if ( $args > $#{ $topic{$chan}{'History'} } || $args < 1 ) {
502 &msg( $who, "error: argument is out of range." );
506 $_ = "Changing topic according to request.";
507 &topicNew( $chan, ${ $topic{$chan}{'History'} }[ $args - 1 ], $_ );
514 $_ = "Rehashing topic...";
515 $topic{$chan}{'What'} = 'Rehash';
516 &topicNew( $chan, $topic{$chan}{'Current'}, $_, 1 );
523 my $reply = "no topic info.";
524 if ( exists $topic{$chan}{'Who'} and exists $topic{$chan}{'Time'} ) {
526 "topic on \002$chan\002 was last set by "
527 . $topic{$chan}{'Who'}
529 . &Time2String( time() - $topic{$chan}{'Time'} ) . ' ago'
531 . length( $topic{$chan}{'Current'} );
532 my $change = $topic{$chan}{'What'};
533 $reply .= ". Change => $change" if ( defined $change );
536 &performStrictReply($reply);
539 ###############################
541 ###############################
544 # Usage: &Topic($cmd, $args);
546 my ( $chan, $cmd, $args ) = @_;
548 if ( $cmd =~ /^-(\S+)/ ) {
549 $cache{topicNotUpdate}{$chan} = 1;
553 if ( $cmd =~ /^(add)$/i ) {
554 &do_add( $chan, $args );
557 elsif ( $cmd =~ /^(del|delete|rm|remove|kill|purge)$/i ) {
558 &do_delete( $chan, $args );
561 elsif ( $cmd =~ /^list$/i ) {
562 &do_list( $chan, $args );
565 elsif ( $cmd =~ /^(mod|modify|change|alter)$/i ) {
566 &do_modify( $chan, $args );
569 elsif ( $cmd =~ /^(mv|move)$/i ) {
570 &do_move( $chan, $args );
573 elsif ( $cmd =~ /^shuffle$/i ) {
574 &do_shuffle( $chan, $args );
577 elsif ( $cmd =~ /^(history)$/i ) {
578 &do_history( $chan, $args );
581 elsif ( $cmd =~ /^restore$/i ) {
582 &do_restore( $chan, $args );
585 elsif ( $cmd =~ /^(flush|rehash)$/i ) {
589 elsif ( $cmd =~ /^info$/i ) {
595 if ( $cmd ne '' and $cmd !~ /^help/i ) {
596 &msg( $who, "Invalid command [$cmd]." );
597 &msg( $who, "Try 'help topic'." );
609 # vim:ts=4:sw=4:expandtab:tw=80